1. Load and store instructions
    1. Exercise 1: ldr instruction
    2. Exercise 2: ldr pre-indexed and post-indexed modes
    3. Exercise 3: Pre-indexed and Post-indexed Modes of str
    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: pitfalls
    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. Ordinary subtraction instruction
      2. subs instruction - affects condition flags (C flag)
    3. adc instruction (add with carry)
    4. sbc instruction (subtract with carry)
    5. cmp compare instruction
    6. Exercise 1: C condition flag of adds and cmp instructions
    7. Exercise 2: cmp and sbc instructions
    8. Shift Operation
    9. Bitwise AND Operation
    10. Bitwise OR Operation
    11. Bit Clear
    12. Exercise 3: Testing the ANDS Instruction and the Z Flag
    13. Bitfield Insert Operation
      1. bfiBitfield Insert Instruction
      2. UBFX unsigned bit field extract instruction
      3. SBFX signed bit field extract instruction
    14. Exercise 4: Testing bitfield instructions
    15. Multiplication and division instructions
  3. Compare 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. Condition operation suffix
    4. Exercise 1: cmp/cmn Instructions and Conditional Operation Suffixes
    5. NZCV register structure diagram
    6. Conditional select instruction
      1. csel
      2. cset
      3. csinc
    7. Exercise 2: Conditional select instruction
    8. Branch instruction
      1. b unconditional branch
      2. b.cnd conditional branch instruction
      3. bx branch to address specified by 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 crash 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 is the difference between ADRP and LDR
    4. Exercise 2: Pitfalls of 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. Traps and pitfalls: runs on QEMU but not on the board
    1. Pitfall 1: ldr instruction loading macro
    2. Pitfall 2: ldr instruction loading string
    3. Summary of Aligned Access
    4. Pitfall 3: Size of stored instruction data
    5. Pitfall 4: The big pitfall of ldxr
  7. Implementing serial port printing functionality in assembly
  8. Reference Documentation
Cover image for AArch64 ASM

AArch64 ASM


Timeline

Timeline

2025-09-28

init

This article introduces the basics of AArch64 assembly language, discusses common ARM registers and instruction classifications in detail, and provides an in-depth explanation of the functional details and practical applications of core instructions such as memory load and store, arithmetic and shift, and bit-field operations.

Common ARM Registers

ARM Registers
ARM Registers

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

  • Notx0~x30
  • Specifically used forStack Pointer
  • Points to the current top of the stack

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 Operations
  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 semicolon between lsl and #3

When extended as lsl, the amount can only be #0 or #3 (as defined by ARM documentation)

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

Exercise 2
Exercise 2

Exercise 2 Code
Exercise 2 Code

Exercise 3: Pre-indexed and Post-indexed Modes of str

Exercise 3
Exercise 3

Exercise 3 Debugging
Exercise 3 Debugging

ldr Label (Literal)

ReadPC+labelValue

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 to the compiler, processed by the assembler during source program assembly. It can perform functions such as processor selection, defining program modes, defining data, allocating storage, indicating program end, etc. In short, it can be decomposed into a set of several instructions
  • The ldr instruction can be either a large-range address load pseudo-instruction or a memory access instruction. When its second parameter is preceded by ‘=’, it indicates a pseudo-instruction; otherwise, it indicates 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 the 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 4-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: pitfalls

  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’s 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 load (LDR, LDRB, LDRH): High bits filled with zeros0
  • Signed load (LDRSB, LDRSH, LDRSW): Sign-extended (if the most significant bit is 1, it is extended with 1s).
  • If accessing and storing 4 bytes or 8 bytes, both use ldr and str, except that the target register uses wn or xn
  • STRThe series of instructions does not have a signed version, because when storing, it is written to memory “as is”,without sign extension, zero extension, or any padding operation, but note the register bit width, such as xn and wn are different.
  • AArch64 defaults to little-endian (low address stores low byte).
  • There is also a category ofatomic load/store instructionsLDAXRSTLXRetc.) used for lock operations

Arithmetic and shift instructions

The four condition code bits 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

Ordinary subtraction instruction
subs instruction - affects condition flags (C flag)

adc instruction (add with carry)

ADC instruction
ADC instruction

sbc instruction (subtract with carry)

SBC instruction
SBC instruction

Wd = Wn - Wm-1+ C

cmp compare instruction

Compares two numbers, internally implemented using the subs instruction, affects 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 (overflow occurs)

When x1 >= x2, C=1

When x1 < x2, C=0

Exercise 1: C condition flag of adds and cmp instructions

Exercise 1: C condition flag of adds and cmp instructions
Exercise 1: C condition flag 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 Shift Left
  • LSR Logical Shift Right
  • ASR Arithmetic Shift Right
  • ROR Rotate Right

Shift Operation
Shift Operation

Bitwise AND Operation

  • andAND Operation
  • andsAND with Carry, Affects Z Flag

Bitwise OR Operation

  • orrOR Operation
  • eorXOR Operation

XOR
XOR

Bit Clear

  • bicBit 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

bfiBitfield 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 begins(counting from 0).

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

BFI bit field insert instruction
BFI bit field insert instruction

UBFX unsigned bit field extract instruction
SBFX signed bit field extract instruction

SBFX signed bit field extract instruction
SBFX signed bit field 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:

InstructionFunction description
MADDMultiply-Add:Xd = (Xn * Xm) + Xa
MNEGMultiply-Negate:Xd = -(Xn * Xm)
MSUBMultiply-Subtract:Xd = Xa - (Xn * Xm)
MULMultiply:Xd = Xn * Xm(lower 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 high 64 bits of 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 high 64 bits (unsigned)
UMULLUnsigned Multiply Long: unsigned 32-bit * 32-bit → 64-bit

Division:

InstructionFunction Description
SDIVSigned Divide: signed division
UDIVUnsigned Divide: unsigned division

Compare and branch instructions

Exercise 5: Using bitfield instructions to read registers

Exercise 5
Exercise 5

Note that instructions like ubfx can only extract bitfields from general-purpose registers, not directly from system registers. Therefore, 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) areread-only, soMSRwriting to this register usually triggers an exception and cannot be modified arbitrarily.

Exercise 5 code and debugging
Exercise 5 code and debugging

Count leading zeros instruction clz

clz: Counts the number of zeros before the highest 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

Condition 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

Experiment 1: cmp/cmn Instructions and Conditional Operation Suffixes
Experiment 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

1
2
3
4
┌───┬───┬───┬───┐
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 exceeds representable range) → V=1
  • Otherwise V=0

Conditional select instruction

Used with the cmp instruction

csel

Conditional select instruction csel
Conditional select instruction csel

cset

Conditional set instruction cset
Conditional set instruction cset

csinc

Conditional Select Increment

Conditional select instruction csinc
Conditional select instruction csinc

Exercise 2: Conditional select instruction

Exercise 2 Conditional select instruction
Exercise 2 Conditional select instruction

Exercise 2 code and its debugging
Exercise 2 code and its debugging

Branch instruction

b unconditional branch

Branch instruction, unconditional branch instruction, does not return

Branch range: PC +/- 128MB

b.cnd conditional branch instruction

Conditional branch instruction, does not return

cnd is the condition operation suffix

Branch range: PC +/- 1MB

bx branch to address specified by register

Branch to address specified by register, does not return

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

The return address is saved to x30, which stores the parent function’s PC+4

Jump range: PC +/- 128MB

Jump to the address specified by the register, can return

The return address is saved to x30, which stores the parent function’s PC+4

Return instruction

ret

Return from a subroutine, typically with the return address stored in x30

eret

Return from the current exception mode, typically allowing mode switching, e.g., from EL1 to EL0

It returns from the current exception mode, restoring PSTATE from SPSR, obtaining the jump address from ELR, and returning to that address

Exercise 3: Why does it crash after ret

Exercise 3: Why does it crash after ret
Exercise 3: Why does it crash after ret

Exercise 3 code
Exercise 3 code

Traps and pitfalls

bl instruction: used to call a subroutine, it writes the return address to the x30 register, with the return address being PC+4

When calling bl to call a subroutine within a function, it may overwrite the parent function’s lr register, causing the parent function’s ret to crash

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

Compare and branch instructions

cbz cbnz tbz tbnz
InstructionAbbreviation meaningDescription
CBZCompare and Branch if ZeroChecks if the value of the specified register is zero; if zero, branches to the target address with a range of +/- 1MB.
CBNZCompare and Branch if Non-ZeroChecks if the value of the specified register is non-zero; if non-zero, branches to the target address with a range of +/- 1MB.
TBZTest Bit and Branch if ZeroChecks if a specific bit of the specified register is 0; if that bit is 0, branches to the target address with a range of +/- 32KB.
TBNZTest Bit and Branch if Non-ZeroChecks if a specific bit of the specified register is 1; if that bit is 1, branches to the target address with a range of +/- 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 the ADRP and LDR instructions
Exercise 1: Testing the 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 is the difference between ADRP and LDR

Pitfalls and traps:

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

  • LDR pseudo-instruction: loads absolute address

  • ADRP instruction: loads PC-relative address

  • When link address equals run address

Address loaded by LDR pseudo-instruction equals address loaded by ADRP instruction

  • When link address does not equal run address

ldr pseudo-instruction address: loads the link address (also known as virtual address)

adrp instruction: loads the PC value of the current runtime address plus the offset of the label, i.e., the address of the label at runtime (also known as physical memory)

Exercise 2: Pitfalls of 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 in an exclusive manner into a general-purpose register

  • stxr instruction

Exclusive memory store instruction

  1. ldrx loads memory, but it monitors access to this memory through an exclusive monitor, which marks the memory address as exclusive access, ensuring it is accessed in an exclusive manner

Exclusive memory load instruction ldrx
Exclusive memory load instruction ldrx

  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 are typically used in pairs
  • The Linux kernel often uses atomic operations, 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 uses theSVCinstruction to jump from user mode to kernel mode, typically entering EL1 exception level, used to trigger system calls
HVC #immVirtualization system call instruction(Hypervisor Call)The host operating system uses theHVCinstruction to enter EL2 from EL1, invoking the hypervisor, used in virtualization support scenarios
SMC #immSecure Monitor System Call Instruction(Secure Monitor Call)The host OS or monitor program uses theSMCinstruction to transition from the Non-secure World to the Secure World, typically triggering an EL3 exception, used in 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 to a system register (Move Register to System)

Memory Barrier Instructions

InstructionFull NameFunctionStrengthExample Use
DMBData Memory BarrierGuaranteeExecution order of memory access instructions(e.g., read-after-write will not be reordered)MediumShared data communication between multiple cores
DSBData Synchronization BarrierWait for all memory accesses to completebefore executing subsequent instructionsStrongCache synchronization before and after reading/writing peripheral registers
ISBInstruction Synchronization BarrierClear instruction pipeline and cache, force re-fetching instructionsSpecialForce instruction refresh after changing system status registers
  1. DMB

Function: Ensures the order of memory accesses without blocking execution.
Example:

1
2
3
str x0, [x1]     // Write data
dmb sy // Ensure write operation completes
ldr x2, [x3] // Then read other data
  1. DSB

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

1
2
3
str x0, [x1]     // Write data
dsb sy // Wait for write to complete
isb // Ensure that the latest code is executed subsequently
  1. ISB

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

1
2
msr sctlr_el1, x0  // Modify system control register
isb // Force instruction stream flush

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

ParameterAccess order controlShare domainDescription
SYRead/WriteFull System SharingStrongest,All processors and devicesVisible, commonly used in device drivers or critical synchronization
STWriteFull System SharingOnly forWrite operationsEstablish order
LDReadFull System SharingOnly forRead operationsEstablish order
ISHRead/WriteInner ShareableUsed when multiple cores share the same L2 cache
ISHSTWriteInner Shareableof the inner shareable domainWrite barrier
ISHLDReadInner Shareableof the inner shareable domainRead barrier
NSHRead/WriteNon-shareableUsed for private memory of this core
NSHSTWriteNon-shareableThis core private write barrier
NSHLDReadNon-shareableThis core private read barrier
OSHRead/WriteOuter ShareableUsed 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 bits, wn is 32 bits.

  • Zero registers: xzr, wzr.

  • PC is not a general-purpose register and generally cannot be directly returned.

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

  • ELR_ELx is used for returning from exceptions.

  • Each exception level has its own stack SP, for example SP._EL0, SP_EL1

  • SP is not a general-purpose register.

  • Registers for SIMD and floating-point operations.

  • Qn (128 bits, 16 bytes), Dn (64 bits), Sn (32 bits), Hn (16 bits), Bn (8 bits).

  • PSTATE(Processor State Register)It is not a single physical register that exists independently., 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.

FieldDescription
NZCVCondition code flags (ALU Flags) used for conditional jumps, etc.:N(Negative),Z(Zero),C(Carry),V(Overflow)
QOverflow flag bit, set only in AArch32 when certain SIMD operations overflow
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
CurrentELThe current exception level (EL0/EL1/EL2/EL3) affects privileged access and execution
EEndianness selection (AArch32) controls whether data access is little-endian or big-endian
ILWhen the illegal instruction flag is set to 1,all instructions are executed as UNDEFINED, for debugging
SSThe single-step execution flag (Software Stepping) is used with the debugger, triggering an exception after each instruction execution
  • Load and store instructions
InstructionTypeData sizeSign extensionStore/Load target
LDRNormal loadPer registerNoAny bit width
LDRSWLoad signed word32-bit✔ (sign-extend 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 suffixDefault load or store according to target register bit width
  • Multi-byte load and store instructions
    • The A64 instruction set has removed ldm, stm, push, and pop instructions
    • ldp and stp 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 generate a constant table in the.rodataarea,ldractually loads the address from the constant table.
  • Applicable scenario: Can be used anywhere, butdepends on link-time address information, caution is needed in systems that support relocation.

ldr x0, label

  • Meaning: Load the value at addresslabelintox0.
  • Note: Here,labelis an address, and the data it points to will be loaded into the register (not the address itself).
  • Different from above: This is not a load address, but ratherreading data through the address

adr x0, .

  • Meaning: Load the current PC value intox0.
  • Common scenarios: Locate the current code position (e.g., implementing Position-Independent Code).

adrp x0, label

  • Meaning: Load thelabelpage where**page start address (4KB aligned)**intox0.
  • Usage
    • Often used forPosition-Independent Code (PIC)
    • Combined withaddto achieve full address loading:
FlagMeaningCommon Triggering Conditions
NNegative Flag: Set when the result is negativee.g.,subs x0, x1, x2yields a negative number
ZZero Flag: Set when the result is zeroe.g.,subs x0, x1, x1, result is 0
CCarry Flag: Carry from unsigned addition / borrow from unsigned subtractione.g.,adds,subs,adc,sbc
VOverflow flag: overflow during signed addition/subtractione.g.adds,subsoverflow

Recommended to consult documentation

arm8.6 Chapter C3 A64 Instruction Set Overview

Traps and pitfalls: runs on QEMU but not on the board

Pitfall 1: ldr instruction loading macro

Pitfall 1: ldr instruction loading macro
Pitfall 1: ldr instruction loading macro

Debugging ldr instruction loading macro issue
Debugging 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., Data abort

Solution:

1
2
3
ldr x6, MY_LABEL
// Modify
ldr w6, MY_LABEL

Pitfall 2: ldr instruction loading string

Pitfall 2: ldr instruction loading string
Pitfall 2: ldr instruction loading 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 for Pitfall 2
Solution for Pitfall 2

Summary of Aligned Access

  • For normal memory, unaligned access is supported. (Requires enabling MMU and setting the memory attribute to normal.)
  • You can separately configure an exception to be triggered on unaligned access (by setting SCTLR_Elx.A).
  • For Device memory, unaligned access triggers a Data Abort exception.
    • In systems without MMU enabled, such as our experimental DDR programming, access is treated as device memory.
  • Instruction prefetch requires 4-byte alignment; otherwise, an exception is triggered.
  1. Normal memory supports unaligned access.
  • Condition
    • MMU is enabledMMU(Memory Management Unit);
    • and the memory region’s attribute is set toNormal memory
  • Result
    • Supports unaligned access to words (4 bytes), halfwords (2 bytes), and bytes (1 byte).
    • Cross-boundary access is possible without triggering an exception;
  1. Configure unaligned access exception (SCTLR_ELx.A bit)
  • SCTLR_EL1.AControls whether to allowunaligned access(Alignment Check):
    • A = 0(default): Allow unaligned access (if the memory type permits);
    • A = 1Force aligned access, once an unaligned access occurs, it triggersAlignment fault exception (Data Abort)
  1. Device memory does not support unaligned access
  • Characteristics
    • Regardless of whether the MMU is enabled, the Device memory typedoes not allow unaligned access
  • Consequences
    • Once an unaligned address is accessed (e.g., accessing0x100332-bit data), it will triggerData Abort exception
  • Application example
    • Direct-mapped access in experimental environmentDDR, peripheral registers, etc., are typically 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 prefetch requirements
  • Instruction fetch addressmust be4-byte aligned(i.e., the lowest two bits of the address must be 0);
  • Otherwise, it triggers anInstruction Abort exception
  • Reason: ARMv8 instructions are stored and fetched in 4-byte units, and cannot be decoded or executed from an unaligned address.

Pitfall 3: Size of stored instruction data

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

The register bit width on the Raspberry Pi 4b is 32 bits, which is 4 bytes.

Pitfall 3: Store instruction data size
Pitfall 3: Store instruction data size

Pitfall 4: The big pitfall of ldxr

Pitfall 4: The big pitfall of ldxr
Pitfall 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, for example when the MMU is not enabled, then the CPU IP core needs to support exclusive access to device memory. This requires consulting the specific CPU IP manual’s description.

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

Accessing device memory exclusively on the Cortex-A72 without enabling the MMU will cause errors.
Accessing device memory exclusively on the Cortex-A72 without enabling the MMU will cause errors.

Solution:

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

Implementing serial port printing functionality in assembly

Major assignment: Implementing serial port printing functionality in assembly
Major assignment: Implementing serial port printing functionality in assembly

Expected results of the major assignment
Expected results of the major assignment

🧱 1. GPIO Initialization (Pin Multiplexing Configuration)

1
2
3
4
5
6
7
ldr x1, =GPFSEL1
ldr 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 Configuration Only)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#ifdef CONFIG_BOARD_PI3B
ldr x1, =GPPUD
str wzr,[x1]

// delay 150 cycles
mov x0, #150
1:
sub x0, x0, #1
cmp x0, #0
bne 1b

ldr x1, =GPPUDCLK0
ldr w2, #0xc000 // Apply to GPIO14 and GPIO15
str w2, [x1]

// delay again
mov x0, #150
2:
sub x0, x0, #1
cmp x0, #0
bne 2b

ldr x1, =GPPUDCLK0
str wzr, [x1]
isb
#endif

✅ Disable pull-up/pull-down for GPIO14/15, consistent with BCM2837 initialization flow.
🧱 3. UART Initialization

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// Disable UART
ldr x1, =U_CR_REG
str wzr, [x1]

// Set baud rate
ldr x1, =U_IBRD_REG
mov w2, #26 // Integer Baud Rate Divisor
str w2, [x1]

ldr x1, =U_FBRD_REG
mov w2, #3 // Fractional Baud Rate Divisor
str w2, [x1]

// Set data format
ldr x1, =U_LCRH_REG
mov w2, #0x70 // FIFO enable + 8-bit word length
str w2, [x1]

// Disable interrupts
ldr x1, =U_IMSC_REG
str wzr, [x1]

// Enable UART (TX/RX/UART enable)
ldr x1, =U_CR_REG
mov w2, #0x301 // UARTEN | TXE | RXE
str 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

1
2
3
4
5
6
7
8
9
10
11
put_uart:
ldr x1, =U_FR_REG
1:
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 to be available before sending the character.

🧱 5. String output function put_string_uart

1
2
3
4
5
6
7
8
9
10
11
put_string_uart:
mov x4, x0 // x0: pointer to string
mov x6, x30 // Save return address
1:
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, print it until NULL (0x00) is encountered.

Reference Documentation