LAB-21Easy
ARM64 Register Trace
Trace a short AArch64 routine by hand and determine the final register state and how many times its loop executes.
15 min4 prerequisites6 tools
Disassembly
00: mov x0, #10
01: mov x1, #3
loop:
02: add x0, x0, x1
03: sub x1, x1, #1
04: cmp x1, #0
05: bne loop
06: mov x2, x0
07: ret Hints
Hint 1
AArch64 immediates use a # prefix (#10, #3) instead of x86's bare numbers — same idea, different syntax.
Hint 2
X0 accumulates X1 into itself each pass; X1 counts down from 3 to 0.
Hint 3
BNE branches while the result of the last CMP was not equal — that's the Z (zero) flag being clear.
Submit Findings
Solution
ARM64 Register Trace — Solution
| Pass | X0 (before → after ADD) | X1 (before → after SUB) | CMP X1, #0 | BNE |
|---|---|---|---|---|
| 1 | 10 → 13 | 3 → 2 | 2 ≠ 0 (Z=0) | taken |
| 2 | 13 → 15 | 2 → 1 | 1 ≠ 0 (Z=0) | taken |
| 3 | 15 → 16 | 1 → 0 | 0 = 0 (Z=1) | not taken |
After the third pass, cmp x1, #0 sets Z=1 (result was zero), so bne loop falls through instead of branching.
- X0 = 16 (10 + 3 + 2 + 1)
- The loop body runs 3 times
- Z — BNE branches when the zero flag is clear (last result ≠ 0)
Same reasoning as x86's ZF/JNE — AArch64 just names its flags N/Z/C/V and spells the mnemonic BNE instead of JNE.
Prerequisites
- arm1-arm64-architecture-basics
- arm2-arm64-calling-convention-and-the-stack
- AArch64 register names (X0-X30, W0-W30, SP, PC, NZCV)
- Conditional branch flags (N, Z, C, V)
Methodology
Investigation Methodology
1. AArch64 Instruction Syntax
mov x0, #10→ X0 = 10 (immediate with # prefix)add x0, x0, x1→ X0 = X0 + X1 (three-operand form)sub x1, x1, #1→ X1 = X1 - 1cmp x1, #0→ Compare X1 with 0, sets NZCV flagsbne loop→ Branch if Z=0 (Not Equal)ret→ Return (BR X30)
2. Register Mapping (ARM64 → x86-64)
| AArch64 | x86-64 | Role |
|---|---|---|
| X0-X7 | RDI, RSI, RDX, RCX, R8, R9 | Argument/Return registers |
| X8 | — | Indirect result |
| X9-X15 | R10, R11, R12, R13, R14, R15 | Caller-saved (volatile) |
| X16-X17 | — | Intra-procedure call scratch |
| X18 | — | Platform register (OS) |
| X19-X28 | RBX, RBP, R12, R13, R14, R15 | Callee-saved (non-volatile) |
| X29 (FP) | RBP | Frame pointer |
| X30 (LR) | — | Link register (return address) |
| SP | RSP | Stack pointer |
| PC | RIP | Program counter |
3. NZCV Condition Flags
| Flag | Bit | Set When |
|---|---|---|
| N (Negative) | 31 | Result MSB = 1 (negative) |
| Z (Zero) | 30 | Result = 0 |
| C (Carry) | 29 | Unsigned overflow (carry out) |
| V (Overflow) | 28 | Signed overflow |
Condition Codes:
EQ/NE: Z=1 / Z=0CS/CC: C=1 / C=0 (unsigned >= / <)MI/PL: N=1 / N=0 (negative / positive)VS/VC: V=1 / V=0 (overflow)HI: C=1 and Z=0 (unsigned >)LS: C=0 or Z=1 (unsigned <=)GE/LT: N=V / N≠V (signed >= / <)GT/LE: Z=0 and N=V / Z=1 or N≠V (signed > / <=)
4. Trace Execution
| Pass | X0 | X1 | CMP Result | Z | BNE |
|---|---|---|---|---|---|
| 1 | 10+3=13 | 3-1=2 | 2≠0 | 0 | taken |
| 2 | 13+2=15 | 2-1=1 | 1≠0 | 0 | taken |
| 3 | 15+1=16 | 1-1=0 | 0=0 | 1 | NOT taken |
5. Loop Analysis Pattern
- Counter in X1 starts at N (3)
- Decrements each iteration
- Loop runs while counter ≠ 0 → N iterations
- Accumulator X0 adds decreasing counter: N + (N-1) + ... + 1
6. Key Differences from x86
- Explicit immediates:
#10not10 - Three-operand ALU:
add dest, src1, src2(dest ≠ src1 allowed) - Flags only from CMP/CCMP: ALU ops don't set flags by default
- Condition suffixes:
b.ne= branch if not equal - No
retwith pop: Return address in X30 (LR),ret=br x30
Common Pitfalls
- Confusing AArch64 `bne` (branch if Z=0) with x86 `jne` (same logic, different name)
- Forgetting that ALU instructions (`add`, `sub`) DON'T set flags — only `cmp`/`ccmp` do
- Misreading `mov x0, #10` as move from register 10 (it's immediate 10)
- Assuming X0-X7 are callee-saved (they're volatile — caller-saved)
- Not knowing that `ret` uses X30 (Link Register), not stack
Tools
- Ghidra (AArch64 support)
- Binary Ninja (ARM64)
- IDA Pro (ARM64)
- GDB (aarch64-linux-gnu-gdb)
- ARM64 Assembly Reference Card
- Built-in Assembly Visualizer
References
- Lesson ARM1: ARM64 Architecture Basics
- Lesson ARM2: ARM64 Calling Convention & Stack
- ARM Architecture Reference Manual (ARMv8-A)
- AArch64 Quick Reference Card
- Procedure Call Standard for the ARM 64-bit Architecture (AAPCS64)
Extensions & Challenges
- Translate the loop to x86-64 assembly — compare instruction count
- Modify loop to sum 1..10 (change X1 initial value)
- Research: How does AArch64 handle function calls (BL/BLR) and LR?
- Analyze an Android ARM64 binary — find a loop, trace registers
- Compare: AArch64 conditional execution vs x86 flag-based jumps