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–x30 | 64-bit general-purpose registers. w0–w30 are their lower 32-bit halves (writing a w register zeroes the upper 32 bits). |
x0–x7 | First 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. |
sp | Stack pointer. Separate from x0–x30. The stack grows downward (towards lower addresses). |
xzr / wzr | The zero register: always reads as 0, discards writes. |
pc | Program counter; not a general-purpose register. Read a PC-relative address with adr. |
| system registers | CPU control/status. Accessed only via mrs/msr. |
Instructions you will encounter
| Instruction | Meaning |
|---|---|
mov x0, #5 | Put an immediate value (i.e., a constant) into a register. |
mov x0, x1 | Copy 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>, x0 | Move from a general register into a system register. |
and x0, x0, #0xFF | Bitwise AND: x0 = x0 & $0xFF. |
sub x1, x1, x0 | Subtract: x1 = x1 - x0. |
subs x1, x1, #8 | Subtract and set the condition flags (N, Z, C, V). |
add x0, x0, #8 | Add: x0 = x0 + 8. |
cbz x0, label | Compare-and-branch if zero: branch to label if x0 == 0. (cbnz = if non-zero.) |
b label | Unconditional branch (like a goto/jmp). |
b.gt label | Conditional branch, taken if the last flag-setting op was “greater than”. (b.eq, b.ne, … exist too.) |
bl label | Branch with link: set x30 to the return address, then branch. This is a function call. |
ret | Return: branch to the address in x30. |
adr x0, label | Load 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], #8 | Post-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).