Appendix A: ARM64 reference

This appendix is a “cheat-sheet” reference, not a tutorial. We recommend that you consult the plentiful online materials and your favorite AI (or ask course staff!) to figure out questions about ARM64 that go beyond what’s described here.

Registers

Register(s)Role
x0–x3064-bit general-purpose registers. w0–w30 are their lower 32-bit halves (writing a w register zeroes the upper 32 bits).
x0–x7First eight function arguments; x0 (and x1) also hold return values.
x29 (fp)Frame pointer (by convention).
x30 (lr)Link register: holds the return address. bl writes it; ret reads it.
spStack pointer. Separate from x0–x30. The stack grows downward (towards lower addresses).
xzr / wzrThe zero register: always reads as 0, discards writes.
pcProgram counter; not a general-purpose register. Read a PC-relative address with adr.
system registersCPU control/status. Accessed only via mrs/msr.

Instructions you will encounter

InstructionMeaning
mov x0, #5Put an immediate value (i.e., a constant) into a register.
mov x0, x1Copy a value from a source register (x1) into a destination register (x0).
mrs x0, <sysreg>Move from system register into a general register.
msr <sysreg>, x0Move from a general register into a system register.
and x0, x0, #0xFFBitwise AND: x0 = x0 & $0xFF.
sub x1, x1, x0Subtract: x1 = x1 - x0.
subs x1, x1, #8Subtract and set the condition flags (N, Z, C, V).
add x0, x0, #8Add: x0 = x0 + 8.
cbz x0, labelCompare-and-branch if zero: branch to label if x0 == 0. (cbnz = if non-zero.)
b labelUnconditional branch (like a goto/jmp).
b.gt labelConditional branch, taken if the last flag-setting op was “greater than”. (b.eq, b.ne, … exist too.)
bl labelBranch with link: set x30 to the return address, then branch. This is a function call.
retReturn: branch to the address in x30.
adr x0, labelLoad the address of label (PC-relative) into x0.
ldr x0, [x1]Load 8 bytes from the address in x1 into x0.
str x0, [x1]Store the 8 bytes in x0 to the address in x1.
str xzr, [x0], #8Post-indexed store: store xzr to [x0], then set x0 = x0 + 8. Used by memzero.

Reading a tiny example

Here is memzero from kernel/mm.S, annotated. It zeroes len bytes (in x1) starting at ptr (in x0) — note the load/store style and the post-indexed store:

    .globl memzero
memzero:
    str    xzr, [x0], #8   // write 8 zero bytes at [x0], then advance x0 by 8
    subs   x1, x1, #8      // len -= 8, and update the condition flags
    b.gt   memzero         // if len is still > 0, loop
    ret                    // otherwise return (jump to x30)

Because ptr arrives in x0 and len in x1, this matches the C prototype void memzero(void *ptr, unsigned long len).