1. Load and store instructions
    1. Exercise 1: ldr instruction
    2. Exercise 2: ldr pre-indexed and post-indexed addressing modes
    3. Exercise 3: str pre-indexed and post-indexed addressing modes
    4. ldr label (literal)
    5. Exercise 4: ldr pseudo-instruction
    6. Exercise 5: Implementing memcpy in assembly
    7. mov instruction
    8. LDP and STP
    9. Exercise 6: memset
    10. Exercise 7: Pitfall
    11. Store instruction variants
  2. Arithmetic and shift instructions
    1. add addition instruction
      1. The ordinary addition instruction add
      2. adds instruction - affects condition flags (carry)
    2. sub subtraction instruction
      1. The ordinary subtraction instruction
      2. subs instruction - affects condition flags (C flag)
    3. adc instruction (addition with carry)
    4. sbc instruction (subtraction with carry)
    5. cmp comparison instruction
    6. Exercise 1: C condition flags of adds and cmp instructions
    7. Exercise 2: cmp and sbc instructions
    8. shift operation
    9. Bitwise AND operation
    10. Bitwise OR operation
    11. Bitwise clear
    12. Exercise 3: Testing the ands instruction and the Z flag
    13. Bitfield insert operation
      1. bfi Bitfield insert instruction
      2. UBFX unsigned bitfield extract instruction
      3. SBFX signed bitfield extract instruction
    14. Exercise 4: Testing bitfield instructions
    15. Multiplication and division instructions
  3. Comparison and branch instructions
    1. Exercise 5: Using bitfield instructions to read registers
    2. Count leading zeros instruction clz
    3. Comparison instruction
      1. cmp
      2. cmn
      3. Conditional operation suffix
    4. Exercise 1: cmp/cmn instructions and conditional operation suffixes
    5. NZCV register structure diagram
    6. Conditional select instructions
      1. csel
      2. cset
      3. csinc
    7. Exercise 2: Conditional select instructions
    8. Branch instructions
      1. b unconditional branch
      2. b.cnd conditional branch instruction
      3. bx branch to the address specified by a register
      4. bl (Branch with Link) branch with return address
      5. blx (Branch with Link to Register)
    9. Return instruction.
      1. ret
      2. eret
    10. Exercise 3: Why does it run away after ret?
    11. Compare and branch instructions.
      1. cbz cbnz tbz tbnz
  4. Other important instructions.
    1. PC-relative address load instruction.
    2. Exercise 1: Testing the ADRP and LDR instructions
    3. What exactly is the difference between ADRP and LDR?
    4. Exercise 2: Pitfalls of the ADRP and LDR instructions
    5. Exclusive memory load and store instructions
    6. Exercise 3: Using the ldxr and stxr instructions
    7. Exception handling instructions
    8. System register access instructions
    9. Memory barrier instructions
  5. Overview Summary
  6. Pitfalls and traps: runs on QEMU but not on the board
    1. Pitfall 1: ldr instruction loads a macro
    2. Pitfall 2: ldr instruction loads a string
    3. Alignment access summary
    4. Pit 3: Data size of store instructions
    5. Pit 4: The big pitfall of ldxr
  7. Implement serial port printing in assembly
  8. Reference documentation
Cover image for AArch64 ASM

AArch64 ASM

Words 4.9k
Views
Visitors

Timeline

Timeline

2025-09-28

init

This article introduces the basics of AArch64 assembly language, systematically explains common ARM registers (such as the stack pointer) and instruction classification, and focuses on the multiple addressing modes (pre-index, post-index, literal) of load and store instructions (LDR/STR) and pseudo-instruction usage, as well as the sign extension rules for LDP/STP multi-byte access and store instruction variants (LDRB/LDRH/LDRSW, etc.). In addition, it covers core content such as arithmetic and shift instructions, bit-field operations (BFI/UBFX/SBFX), multiply and divide instructions, and discusses practical considerations such as memory alignment and little-endianness.

Common ARM Registers

ARM Registers
ARM Registers

sp(stack pointer) is a special register. Features:

  • Notx0~x30
  • Specifically used for Stack pointer
  • Points to the current stack top

Cortex-A Series Programmer's Guide for ARMv8-A Chapter 9.1
Cortex-A Series Programmer's Guide for ARMv8-A Chapter 9.1

Instruction classification

  1. Memory load and store instructions
  2. Multi-byte memory load and store
  3. Arithmetic and shift instructions
  4. shift operation
  5. Bit manipulation instructions
  6. Conditional operations
  7. Branch instructions
  8. Exclusive memory access instructions
  9. Memory barrier instructions
  10. Exception handling instructions
  11. System register access instructions

Load and store instructions

  1. LDR
  2. STR

Exercise 1: ldr instruction

Exercise 1: ldr instruction
Exercise 1: ldr instruction

Exercise 1 code
Exercise 1 code

Note: there should be no space in the middle of ‘lsl #3’.

When extended as lsl, the amount depends on the data width being accessed: #0 for 8-bit, #1 for 16-bit, #2 for 32-bit, #3 for 64-bit (as defined by the ARM documentation).

Exercise 2: ldr pre-indexed and post-indexed addressing modes

Exercise 2
Exercise 2

Exercise 2 code
Exercise 2 code

Exercise 3: str pre-indexed and post-indexed addressing modes

Exercise 3
Exercise 3

Exercise 3 debugging
Exercise 3 debugging

ldr label (literal)

ReadPC+labelthe value of

Exercise 4: ldr pseudo-instruction

Exercise 4: ldr pseudo-instruction
Exercise 4: ldr pseudo-instruction

Exercise 4 code
Exercise 4 code

  • Instruction: each instruction corresponds to a CPU operation
  • Pseudo-instruction: a command issued to the compiler; it is an operation processed by the assembler during assembly of the source program. It can perform functions such as processor selection, defining program modes, defining data, allocating storage areas, and indicating program termination. In short, it can be decomposed into a set of several instructions.
  • The ldr instruction can be either a large-range address-loading pseudo-instruction or a memory access instruction. When its second operand is preceded by ‘=’, it is a pseudo-instruction; otherwise, it is a memory access instruction.
  • The ldr pseudo-instruction has no immediate value access restriction.

ldr x6, MY_LABEL is a memory access instruction

ldr x7, =MY_LABEL is an ldr pseudo-instruction

Exercise 5: Implementing memcpy in assembly

Exercise 5
Exercise 5

Exercise 5 code
Exercise 5 code

Exercise 5 code and debugging
Exercise 5 code and debugging

It can be seen that 0xffffffff was not copied over, because the starting address is not four-byte aligned.

Exercise 5 code
Exercise 5 code

Align the starting address
Align the starting address

mov instruction

  1. 16-bit immediate

MOV instruction
MOV instruction

LDP and STP

Provided in the A32 instruction setLDMandSTMTo implement multi-byte memory load and store, in the A64 instruction set, LDM and STM instructions are no longer provided; instead, LDP and STP instructions are used.

  • LDP and STP can load and store 16 bytes with a single instruction.

LDP and STP
LDP and STP

Exercise 6: memset

Exercise 6
Exercise 6

Exercise 6 code
Exercise 6 code

Exercise 7: Pitfall

  1. Load a very large value into a general-purpose register, e.g., 0xffff_0000_ffff_ffff

  2. Load the value of a register, e.g., the sctrl_el1 register

SCTLR_EL1
SCTLR_EL1

Exercise 7: Pitfall 2
Exercise 7: Pitfall 2

Exercise 7: Pitfall 3
Exercise 7: Pitfall 3

Exercise 7: Pitfall 4
Exercise 7: Pitfall 4

Exercise 7: Pitfall 5
Exercise 7: Pitfall 5

Exercise 7: Pitfall 5 Debugging
Exercise 7: Pitfall 5 Debugging

Note that using ldr may generate a literal pool; it is better to use the adrp instruction.

Store instruction variants

InstructionMeaning (full name)Access sizeSign extension
LDRLoad Register32-bit (W register) or 64-bit (X register)Unsigned
LDRSWLoad Register Signed Word32-bit → sign-extend to 64-bitsigned
LDRBLoad Register Byte8-bit → zero-extend to 32/64-bitUnsigned
LDRSBLoad Register Signed Byte8-bit → sign-extend to 32/64-bitsigned
LDRHLoad Register Halfword16-bit → zero-extend to 32/64-bitUnsigned
LDRSHLoad Register Signed Halfword16-bit → sign-extend to 32/64-bitsigned
LDRQLoad Register Quadword (NEON/SIMD register)128-bit (V register)Unsigned
STRStore Register32-bit or 64-bitUnsigned
STRBStore Register Byte8-bitUnsigned
STRHStore Register Halfword16-bitUnsigned

Supplementary notes

  • Unsigned loads (LDR, LDRB, LDRH): high bits are zero-filled0
  • Signed loads (LDRSB, LDRSH, LDRSW): sign extension is performed (if the most significant bit is 1, it is extended to 1).
  • If accessing and storing 4 bytes or 8 bytes, both use ldr and str, except that the destination register uses wn or xn.
  • STRThe series of instructions has no signed version, because when storing, they are written to memory as-is,**No sign extension, zero extension, or any padding operation is performed.**But note the register bit width, e.g., xn and wn are different.
  • AArch64 defaults to little-endian (low address stores low byte).
  • There is also a categoryatomic load/store instructionsLDAXRSTLXRetc.) used for lock operations.

Arithmetic and shift instructions

The four condition code flags NZCV in the pstate processor state

NZCV condition flag field
NZCV condition flag field

add addition instruction

The ordinary addition instruction add
  • Addition using registers
  • Addition using immediate values
  • Addition using shift operations
adds instruction - affects condition flags (carry)

Mainly affects the C flag (unsigned overflow)

sub subtraction instruction

The ordinary subtraction instruction
subs instruction - affects condition flags (C flag)

adc instruction (addition with carry)

ADC instruction
ADC instruction

sbc instruction (subtraction with carry)

SBC instruction
SBC instruction

Wd = Wn - Wm - 1 + C

cmp comparison instruction

Compare the size of two numbers, implemented internally using the subs instruction, affecting the C flag.

Equivalent to

1
SUBS XZR, <Xn>, #<imm>

When both x1 and x2 are unsigned numbers

1
cmp x1, x2

x1-x2 = x1 + ~x2 + 1 (two’s complement subtraction, C=0 when borrow occurs)

When x1 >= x2 (unsigned), C=1 (no borrow)

When x1 < x2 (unsigned), C=0 (borrow occurs)

Exercise 1: C condition flags of adds and cmp instructions

Exercise 1: C condition flags of adds and cmp instructions
Exercise 1: C condition flags of adds and cmp instructions

Exercise 1 code
Exercise 1 code

bitNamemeaning
31NResult is negative
30ZResult is zero
29CUnsigned comparison: no borrow (Carry)
28VSigned overflow

Exercise 1 debugging
Exercise 1 debugging

Exercise 2: cmp and sbc instructions

Exercise 2: cmp and sbc instructions
Exercise 2: cmp and sbc instructions

Exercise 2 code
Exercise 2 code

shift operation

  • lsl logical left shift
  • lsr logical right shift
  • asr arithmetic right shift
  • ror rotate right

shift operation
shift operation

Bitwise AND operation

  • and AND operation
  • ands Bitwise AND operation and set flags (affects N/Z/C/V)

Bitwise OR operation

  • orr OR operation
  • eor XOR operation

XOR
XOR

Bitwise clear

  • bic Bit clear instruction

Uncommon

Exercise 3: Testing the ands instruction and the Z flag

Exercise 3: ands instruction and Z flag
Exercise 3: ands instruction and Z flag

Exercise 3 code
Exercise 3 code

Bitfield insert operation

Bitfield

Bitfield insert operation
Bitfield insert operation

bfi Bitfield insert instruction

bitfield insert

Bitfield insert instruction
Bitfield insert instruction

  • Xd: Destination register

  • Xn: Source register

  • lsbLeast Significant Bit, i.e. The index of the lowest bit position in the destination register Xd where insertion starts(counting from 0).

  • width: The bit width (number of bits) to insert.

BFI bitfield insert instruction
BFI bitfield insert instruction

UBFX unsigned bitfield extract instruction
SBFX signed bitfield extract instruction

SBFX signed bitfield extract instruction
SBFX signed bitfield extract instruction

Note: counting starts from 0.

Exercise 4: Testing bitfield instructions

Exercise 4: Testing bitfield instructions
Exercise 4: Testing bitfield instructions

Exercise 4 code and debugging
Exercise 4 code and debugging

Exercise 4 debugging
Exercise 4 debugging

Multiplication and division instructions

Multiplication:

InstructionDescription
MADDMultiply-Add:Xd = (Xn * Xm) + Xa
MNEGMultiply-Negate:Xd = -(Xn * Xm)
MSUBMultiply-Subtract:Xd = Xa - (Xn * Xm)
MULMultiply:Xd = Xn * Xm(low 64 bits of result)
SMADDLSigned Multiply-Add Long: 32-bit * 32-bit → 64-bit, plus addend
SMNEGLSigned Multiply-Negate Long: 32-bit * 32-bit → 64-bit, negate
SMSUBLSigned Multiply-Subtract Long: 32-bit * 32-bit → 64-bit, perform subtraction
SMULHSigned Multiply returning High half: take the high 64 bits of the 128-bit result (signed)
SMULLSigned Multiply Long: 32-bit * 32-bit → 64-bit
UMADDLUnsigned Multiply-Add Long: unsigned version
UMNEGLUnsigned Multiply-Negate Long: unsigned version
UMSUBLUnsigned Multiply-Subtract Long: unsigned version
UMULHUnsigned Multiply returning High half: take the high 64 bits (unsigned)
UMULLUnsigned Multiply Long: unsigned 32-bit * 32-bit → 64-bit

Division:

InstructionDescription
SDIVSigned Divide: signed division
UDIVUnsigned Divide: unsigned division

Comparison and branch instructions

Exercise 5: Using bitfield instructions to read registers

Exercise 5
Exercise 5

Note that instructions like ubfx can only extract bit fields from ordinary register values, and cannot directly extract system registers, so you need to first use msr to store the system register into a general-purpose register.

Read system register (move register from system)

1
mrs x1, ID_AA64ISAR0_EL1

Write system register (move system from register)

1
msr ID_AA64ISAR0_EL1, x1

⚠️ But note: many CPU feature registers (such asID_AA64ISAR0_EL1) are read-only, soMSRWriting to this register usually triggers an exception, so it cannot be modified arbitrarily.

Exercise 5 code and debugging
Exercise 5 code and debugging

Count leading zeros instruction clz

clz: counts the number of leading zeros before the most significant set bit.

CLZ instruction
CLZ instruction

Comparison instruction

cmp

Compare two numbers

cmp x1, x2

x1-x2

cmn

Negative comparison

cmn x1, x2

x1+x2

Conditional operation suffix
Condition suffixmeaningFlagCondition codeAbbreviation description
EQEqualZ=10b0000Equal
NENot equalZ=00b0001Not Equal
CS/HSUnsigned greater than or equalC=10b0010Carry Set / Higher or Same
CC/LOUnsigned less thanC=00b0011Carry Clear / Lower
MINegativeN=10b0100Minus
PLPositive or zeroN=00b0101Plus
VSoverflowV=10b0110Overflow Set
VCNo overflowV=00b0111Overflow Clear
HIUnsigned greater than(C=1) && (Z=0)0b1000Higher
LSUnsigned less than or equal(C=0) ∨ (Z=1)0b1001Lower or Same
GESigned greater than or equalN = V0b1010Greater or Equal
LTSigned less thanN ≠ V0b1011Less Than
GTSigned greater than(Z=0) && (N=V)0b1100Greater Than
LESigned less than or equal(Z=1) ∨ (N≠V)0b1101Less or Equal
ALUnconditional execution0b1110Always
NVUnconditional execution0b1111Never (reserved, generally not used)

Exercise 1: cmp/cmn instructions and conditional operation suffixes

Lab 1: cmp/cmn instructions and conditional operation suffixes
Lab 1: cmp/cmn instructions and conditional operation suffixes

Exercise 1 code and debugging
Exercise 1 code and debugging

Exercise 1 code
Exercise 1 code

NZCV register structure diagram

NZCV register structure diagram
NZCV register structure diagram

1234
┌───┬───┬───┬───┐NZCV└───┴───┴───┴───┘ 31  30  29  28   ← 在 PSTATENZCV 系统寄存器的位位置

N (Negative flag)

  • Result is negative (most significant bit of signed number is 1) → N=1
  • Otherwise N=0

Z (Zero flag)

  • Result equals 0 → Z=1
  • Otherwise Z=0

C (Carry flag)

  • Addition: carry occurs → C=1
  • Subtraction: no borrow (i.e., operand 1 ≥ operand 2) → C=1
  • Otherwise C=0

V (Overflow flag)

  • Signed addition/subtraction overflow (result out of representable range) → V=1
  • Otherwise V=0

Conditional select instructions

Used with the cmp instruction

csel

Conditional select instruction csel
Conditional select instruction csel

cset

Conditional select instruction cset
Conditional select instruction cset

csinc

Conditional Select Increment

Conditional select instruction csinc
Conditional select instruction csinc

Exercise 2: Conditional select instructions

Exercise 2 Conditional select instructions
Exercise 2 Conditional select instructions

Exercise 2 code and debugging
Exercise 2 code and debugging

Branch instructions

b unconditional branch

Branch instruction, unconditional branch, does not return

Branch range: PC+/- 128MB

b.cnd conditional branch instruction

Conditional branch instruction, does not return

cnd is the condition code suffix

Branch range: PC+/- 1MB

bx branch to the address specified by a register

Branch to the address specified by a register, does not return

With return address (PC+4 => x30), suitable for calling subroutines

The return address is saved to x30; it stores the parent function’s PC+4.

Branch range: PC+/- 128MB

Jump to the address specified by the register, and can return.

The return address is saved to x30; it stores the parent function’s PC+4.

Return instruction.

ret

Return from a subroutine; usually the return address is stored in x30.

eret

Return from the current exception mode; this can usually achieve mode switching, e.g., switching from EL1 to EL0.

It returns from the current exception mode; it restores PSTATE from SPSR, obtains the jump address from ELR, and returns to that address.

Exercise 3: Why does it run away after ret?

Exercise 3: Why does it run away after ret?
Exercise 3: Why does it run away after ret?

Exercise 3 code
Exercise 3 code

Pitfalls and traps.

bl instruction: used to call a subroutine; it writes the return address into the x30 register, and the return address is PC+4.

In a function, calling a subroutine with bl may clobber the parent function’s lr register, and then the parent function’s ret will run away.

Simply put, the subroutine changed the value of the x30 register and did not restore it when returning.

Compare and branch instructions.

cbz cbnz tbz tbnz
InstructionAbbreviation meaning.Description.
CBZCompare and Branch if ZeroChecks whether the value of the specified register is zero; if zero, jumps to the target address. Jump range is +/- 1MB.
CBNZCompare and Branch if Non-ZeroChecks whether the value of the specified register is non-zero; if non-zero, jumps to the target address. Jump range is +/- 1MB.
TBZTest Bit and Branch if ZeroChecks whether a certain bit of the specified register is 0; if that bit is 0, jumps to the target address. Jump range is +/- 32KB.
TBNZTest Bit and Branch if Non-ZeroChecks whether a certain bit of the specified register is 1; if that bit is 1, jumps to the target address. Jump range is +/- 32KB.

Other important instructions.

PC-relative address load instruction.

  • adr instruction: loads the address of a label relative to the PC, with a range of +/- 1MB.

adr instruction.
adr instruction.

  • adrp instruction: loads the address of a label relative to the PC; it only loads the 4KB-aligned address of the label, with a range of +/- 4GB.

ADRP instruction
ADRP instruction

ADRP instruction diagram
ADRP instruction diagram

Exercise 1: Testing the ADRP and LDR instructions

Exercise 1: Testing ADRP and LDR instructions
Exercise 1: Testing ADRP and LDR instructions

Exercise 1 code
Exercise 1 code

Exercise 1 debugging
Exercise 1 debugging

Exercise 1 debugging
Exercise 1 debugging

Exercise 1 debugging
Exercise 1 debugging

What exactly is the difference between ADRP and LDR?

Pitfalls and traps:

What exactly is the difference between ADRP and LDR?
What exactly is the difference between ADRP and LDR?

  • LDR pseudo-instruction: loads an absolute address

  • ADRP instruction: loads a PC-relative address

  • When the link address equals the run address

The address loaded by the LDR pseudo-instruction is the same as the address loaded by the ADRP instruction.

  • When the link address does not equal the run address

LDR pseudo-instruction address: loads the link address (also called virtual address)

ADRP instruction: loads the PC value at the current run address plus the label’s offset, i.e., the label’s address at runtime (also called physical memory).

Exercise 2: Pitfalls of the ADRP and LDR instructions

Exercise 2: Pitfalls of ADRP and LDR instructions
Exercise 2: Pitfalls of ADRP and LDR instructions

Exclusive memory load and store instructions

  • LDXR instruction

Exclusive memory load instruction: loads the memory address from memory to a general-purpose register in an exclusive manner.

  • STXR instruction

Exclusive memory store instruction

  1. ldxr loads memory, but it monitors access to this memory through an exclusive monitor. The monitor marks this memory address as exclusive access, ensuring that it is accessed in an exclusive manner.

Exclusive memory load instruction ldxr
Exclusive memory load instruction ldxr

  1. stxr is a conditional memory store. The memory address previously marked by ldxr is stored in an exclusive manner. Note that the first register is w0.

Exclusive memory store instruction stxr
Exclusive memory store instruction stxr

Principle of exclusive memory load and store instructions
Principle of exclusive memory load and store instructions

  • The ldxr and stxr instructions usually need to be used in pairs.
  • The Linux kernel often uses them to implement atomic access, such as atomic._write(),atomic_set_bit()
  • The spinlock mechanism can be simply implemented using the ldxr and stxr instructions.

Exercise 3: Using the ldxr and stxr instructions

Exercise 3: Using the ldxr and stxr instructions
Exercise 3: Using the ldxr and stxr instructions

Exercise 3 code
Exercise 3 code

Exception handling instructions

InstructionNameDescription
SVC #immSystem call instruction(Supervisor Call)The application, viaSVCThe instruction jumps from user mode to the kernel-mode operating system, usually entering EL1 exception level, to trigger a system call.
HVC #immVirtualization system call instruction(Hypervisor Call)The host operating system, viaHVCThe instruction goes from EL1 to EL2, invoking the hypervisor, for virtualization support scenarios.
SMC #immSecure monitor system call instruction(Secure Monitor Call)The host operating system or monitor program, viaSMCThe instruction goes from the Non-secure World to the Secure World, usually triggering an EL3 exception, for the TrustZone security mechanism.

System register access instructions

InstructionDescription
MRSRead the value of a system register into a general-purpose register (Move Register from System).
MSRWrite the value of a general-purpose register into a system register (Move Register to System).

Memory barrier instructions

InstructionFull nameFunctionStrengthExample usage
DMBData Memory BarrierGuaranteeExecution order of memory access instructions(e.g., read-after-write will not be reordered)MediumInter-core shared data communication
DSBData Synchronization BarrierWait for all memory accesses to completethen execute subsequent instructionsStrongCache synchronization before and after peripheral register reads/writes
ISBInstruction Synchronization BarrierClear instruction pipeline and cache, force refetchSpecialAfter changing system state registers, force instruction flush
  1. DMB

Effect: Guarantees the order of memory accesses, but does not block execution.
Example:

123
str x0, [x1]     // Write datadmb sy           // Ensure write operation completesldr x2, [x3]     // then read other data
  1. DSB

Effect: Must wait for all previous memory operations to complete before continuing with subsequent instructions.
Example:

123
str x0, [x1]     // Write datadsb sy           // Wait for write to completeisb              // Ensure that subsequent execution uses the latest code
  1. ISB

Effect: Clears the CPU instruction prefetch cache, usually used after modifying system control registers.
Example:

12
msr sctlr_el1, x0  // Modify system control registerisb                // Force instruction stream flush

Detailed explanation of DMB/DSB instruction parameters (granularity and scope of memory barriers)

ParametersAccess order controlShareabilityDescription
SYRead/WriteFull system shareableStrongest,All processors and devicesVisible, commonly used in device drivers or critical synchronization
STWriteFull system shareableOnly forWrite operationEstablish order
LDReadFull system shareableOnly forRead operationEstablish order
ISHRead/WriteInner Shareable (internal shareable)Used when multiple cores share the same L2 cache
ISHSTWriteInner ShareableInner shareable domain’sWrite barrier
ISHLDReadInner ShareableInner shareable domain’sRead operation barrier
NSHRead/WriteNon-shareable (not shared)This core’s private memory usage
NSHSTWriteNot sharedThis core’s private write barrier
NSHLDReadNot sharedThis core’s private read barrier
OSHRead/WriteOuter Shareable (externally shared)Used when sharing among multiple L2s
OSHSTWriteOuter ShareableOuter Shareable write barrier
OSHLTReadOuter ShareableOuter Shareable read barrier

Overview Summary

  • The instruction set running in the AArch64 execution state; 64 refers to its execution environment, not the instruction length.

  • The instruction length is 32 bits, not 64 bits.

  • 31 general-purpose registers; xn is 64-bit, wn is 32-bit.

  • Zero registers: xzr, wzr

  • PC is not a general-purpose register and cannot be directly accessed as a general-purpose register.

  • x30 is used as the link register (LR) for function return.

  • ELR_ELx is used to return from exceptions.

  • Each exception level has its own stack SP, e.g., SP_ELx_EL0, SP_EL1

  • SP is not a general-purpose register.

  • Registers for SIMD and floating-point operations.

  • Qn (128-bit, 16 bytes), Dn (64-bit), Sn (32-bit), Hn (16-bit), Bn (8-bit)

  • PSTATE(Processor State Register)It is not a standalone physical register., but rathera collection of processor states composed of multiple bit fields.

  • PSTATEThe value controls the current state of the CPU, including exception masking, current exception level, condition codes, etc.

fieldMeaning description
NZCVCondition code flags (ALU Flags) are used for conditional branches, etc.:N(negative),Z(zero),C(carry),V(overflow)
QSaturation overflow flag, set only when certain SIMD saturating operations overflow in AArch32.
DAIFException mask bits:D: debug exception maskA: SError maskI: IRQ interrupt maskF: FIQ interrupt mask
SPSelSP register selection (AArch64 only) controls whether to useSP_EL0orSP_ELx
CurrentELCurrent exception level (EL0/EL1/EL2/EL3) affects privileged access and execution.
EByte order selection (AArch32) controls whether data access is little-endian or big-endian.
ILWhen the illegal instruction flag is set to 1,all instructions will be executed as UNDEFINED, for debugging
SSThe single-step execution flag (Software Stepping) is used in conjunction with the debugger, triggering an exception after each instruction is executed.
  • Load and store instructions
InstructionTypeData sizeSign-extend?Store/Load target
LDRNormal loadBy registerNoAny width
LDRSWLoad signed word32-bit✔ (sign-extended to 64-bit)Xn only
LDRBLoad byte8-bitNoWn/Xn
LDRSBLoad signed byte8-bitWn or Xn
LDRHLoad halfword16-bitNoWn/Xn
LDRSHLoad signed halfword16-bitWn or Xn
STRBStore byte8-bitN/A
STRHStore halfword16-bitN/A

Instruction suffix meaning

Suffixmeaning
BByte(8-bit)
HHalfword(16-bit)
WWord(32-bit)
SSign-extended
No suffixBy default, load or store according to the bit width of the destination register.
  • Multi-byte load and store instructions
    • The A64 instruction set has removed the ldm, stm, push, and pop instructions.
    • ldp and stp are used to implement multi-byte load and store instructions.

PC-relative instructions

ldr x0, =label(pseudo-instruction)

  • meaning: loadlabelthe address of (link address) tox0
  • Implementation method: the assembler will.rodatagenerate a constant table in the region,ldrin fact, it loads the address from the constant table.
  • Applicable scenarios: can be used anywhere, butit depends on link-time address information, and caution is needed in systems that support relocation.

ldr x0, label

  • meaning: loadlabelthe value at the address intox0Middle.
  • Note: herelabelis an address; the data it points to is loaded into the register (not the address itself).
  • Unlike the above: this is not a load address, butreading data through the address

adr x0, .

  • meaning: load the current PC value intox0Middle.
  • Common scenarios: locate the current code position (e.g., for implementing Position-Independent Code).

adrp x0, label

  • meaning: loadlabelof the page where it resides**page start address (4KB aligned)**load intox0Middle.
  • Purpose
    • often used for position-independent code (PIC)
    • combined withaddto implement full address loading:
FlagsmeaningCommon triggering conditions
NNegative (sign) flag: set when the result is negative.such assubs x0, x1, x2getting a negative number
ZZero flag: set when the result is zero.such assubs x0, x1, x1, the result is 0
CCarry flag: set when there is a carry in unsigned addition, or no borrow in unsigned subtraction (C=1 means no borrow).such asadds,subs,adc,sbc
VOverflow flag: set when signed addition or subtraction overflows.such asadds,subsoverflow

Recommended documentation

arm8.6 Chapter C3 A64 Instruction Set Overview

Pitfalls and traps: runs on QEMU but not on the board

Pitfall 1: ldr instruction loads a macro

Pitfall 1: ldr instruction loads macro
Pitfall 1: ldr instruction loads macro

Debugging the ldr instruction loading macro issue
Debugging the ldr instruction loading macro issue

ARM documentation explanation
ARM documentation explanation

In bare-metal programming, the MMU is not enabled, so memory attributes are always treated as Device memory.

The ldr instruction accesses 8 bytes. If the address is not 8-byte aligned, it triggers an alignment exception, i.e., a Data Abort.

Solution:

123
ldr x6, MY_LABEL// Modifyldr w6, MY_LABEL

Pitfall 2: ldr instruction loads a string

Pitfall 2: ldr instruction loads a string
Pitfall 2: ldr instruction loads a string

This is also caused by alignment, because the starting address of string1 cannot be guaranteed to be 8-byte aligned.

Solution: align string1 to 8 bytes.

Solution to Pitfall 2
Solution to Pitfall 2

Alignment access summary

  • For normal memory, unaligned access is supported. (The MMU needs to be enabled and the memory attribute set to normal.)
  • You can separately configure unaligned access to trigger an exception (by setting SCTLR_Elx.A).
  • For Device memory, unaligned access triggers a Data Abort exception.
    • On systems without the MMU enabled, for example, our experimental code directly accessing DDR is treated as device memory.
  • Instruction prefetch requires 4-byte alignment; otherwise, an exception is triggered.
  1. Normal memory supports unaligned access.
  • Condition
    • MMU enabled MMU(Memory Management Unit);
    • and the memory region’s attribute is set to Normal memory
  • Result
    • Supports unaligned access to words (4 bytes), half-words (2 bytes), and bytes (1 byte);
    • Can perform cross-boundary access without triggering an exception;
  1. Unaligned access exception configuration (SCTLR_ELx.A bit)
  • SCTLR_ELx.A Controls whether to check unaligned access(Alignment Check):
    • A = 0(Default): Does not check unaligned access (proceeds normally if the memory type allows it);
    • A = 1Force alignment checkingOnce an unaligned access occurs, it triggers Alignment fault exception (Data Abort)
  1. Device memory does not support unaligned access
  • Features
    • Regardless of whether MMU is enabled, Device memory type alwaysdoes not allow unaligned access
  • Consequence
    • Once an unaligned address is accessed (e.g., accessing0x100332-bit data), it will trigger Data Abort exception
  • Application example
    • In the experimental environment, direct mapping access DDR, peripheral registers etc., are usually defined as Device memory type;
    • Access to these regions must be aligned; for example, accessing 32-bit data must be 4-byte aligned;
  1. Instruction fetch requires
  • instruction address must be 4-byte aligned(i.e., the lowest two bits of the address must be 0);
  • otherwise it will trigger Instruction Abort exception
  • Reason: ARMv8 instructions are stored and fetched in 4-byte units, and cannot be decoded and executed from an unaligned position.

Pit 3: Data size of store instructions

When using the str instruction to set registers, be sure to pay attention to the bit width of the register, otherwise a system crash may occur.

The peripheral register bit width on the Raspberry Pi 4B is 32-bit, i.e., 4 bytes.

Pit 3: Data size of store instructions
Pit 3: Data size of store instructions

Pit 4: The big pitfall of ldxr

Pit 4: The big pitfall of ldxr
Pit 4: The big pitfall of ldxr

The use of the ldxr instruction has many restrictions.

  1. First, ensure that the accessed memory is normal memory and is shareable.

The ldxr instruction requires the memory to be normal memory and shareable.
The ldxr instruction requires the memory to be normal memory and shareable.

  1. If accessing device memory, such as when the MMU is not enabled, then the CPU IP core must support exclusive access to device memory. This requires consulting the description in the specific CPU IP manual.

For example: Cortex-A72 MPCore Processor Technical Reference Manual, Section 6.45

Accessing device memory exclusively when the MMU is not enabled on the Cortex-A72 will cause an error.
Accessing device memory exclusively when the MMU is not enabled on the Cortex-A72 will cause an error.

Solution:

Fill in the page table properly, enable MMU and cache, and then you can use ldxr and stxr.

Implement serial port printing in assembly

Big assignment: Implement serial port printing in assembly
Big assignment: Implement serial port printing in assembly

Expected results of the big assignment
Expected results of the big assignment

🧱 1. GPIO initialization (pin multiplexing configuration)

1234567
ldr x1, =GPFSEL1ldr w0, [x1]and w0, w0, #0xffff8fff    // Clear GPIO14 function select bits (bits 12-14)orr w0, w0, #0x4000        // Set GPIO14 to ALT0 (UART0_TXD)and w0, w0, #0xfffc7fff    // Clear GPIO15 function select bits (bits 15-17)orr w0, w0, #0x20000       // Set GPIO15 to ALT0 (UART0_RXD)str w0, [x1]

✅ Effect: Set GPIO14 and GPIO15 to UART function (ALT0 mode).
🧱 2. Disable pull-up/pull-down (Pi 3B only)

1234567891011121314151617181920212223242526
#ifdef CONFIG_BOARD_PI3B	ldr x1, =GPPUD	str wzr,[x1]	// delay 150 cycles	mov x0, #1501:	sub x0, x0, #1	cmp x0, #0	bne 1b	ldr x1, =GPPUDCLK0	ldr w2, #0xc000   // Applies to GPIO14 and GPIO15	str w2, [x1]	// delay again	mov x0, #1502:	sub x0, x0, #1	cmp x0, #0	bne 2b	ldr x1, =GPPUDCLK0	str wzr, [x1]	isb#endif

✅ Disable pull-up/pull-down on GPIO14/15, matching the BCM2837 initialization flow.
🧱 3. UART initialization

123456789101112131415161718192021222324252627
// Disable UARTldr x1, =U_CR_REGstr wzr, [x1]// Set baud rateldr x1, =U_IBRD_REGmov w2, #26          // Integer Baud Rate Divisorstr w2, [x1]ldr x1, =U_FBRD_REGmov w2, #3           // Fractional Baud Rate Divisorstr w2, [x1]// Set data formatldr x1, =U_LCRH_REGmov w2, #0x70        // FIFO enable + 8-bit word lengthstr w2, [x1]// Disable interruptsldr x1, =U_IMSC_REGstr wzr, [x1]// Enable UART (TX/RX/UART enable)ldr x1, =U_CR_REGmov w2, #0x301       // UARTEN | TXE | RXEstr w2, [x1]isb

✅ Correctly configure baud rate and data format (8N1, FIFO), then enable UART.

You are using:

Baud rate = UARTCLK / (16 * (IBRD + FBRD/64))
Assuming UARTCLK = 48 MHz, the baud rate is approximately 115200.

🧱 4. Single character output function put_uart

1234567891011
put_uart:	ldr x1, =U_FR_REG1:	ldr w2, [x1]	and w2, w2, #0x20       // Check TXFF (Transmit FIFO full)	cmp w2, #0	b.ne 1b                 // If FIFO is full, wait	ldr x1, =U_DATA_REG	str w0, [x1]            // Write character	ret

✅ Waits for FIFO availability before sending the character.

🧱 5. String output function put_string_uart

1234567891011
put_string_uart:	mov x4, x0              // x0: pointer to string	mov x6, x30             // Save return address1:	ldrb w0, [x4]           // Read one byte (character)	bl put_uart	add x4, x4, 1	cmp w0, #0	bne 1b	mov x30, x6	ret

✅ Input: x0 = string address, prints it until NULL (0x00) is encountered.

Reference documentation

Loading comments…