Master the fundamental concepts of arm assembly (aarch64) through this focused micro-challenge.
AArch64 exposes x0-x30 plus sp and xzr. More registers than x86 means Clang spills less often, part of why Apple Silicon feels fast at modest clocks. w0 is the low 32 bits of x0; writing w0 zero-extends into x64.
asmLoading…
For this exercise, you will move immediates through several registers and print results with sys_write. This task asks you to mix x and w forms deliberately, because ABI docs and crash logs report both names for the same physical register.
Keep the relevant man page, ABI doc, or Rust reference chapter open while you work. When your output disagrees with the reference implementation on the same machine, the mismatch is usually an alignment rule, an off-by-one terminator, or a register slot you misread in GDB. Skim the official documentation for the tool or ABI named in the exercise; the prose changes, but register roles, syscall numbers, and ownership rules stay stable across releases. Treat each failure as a contract test: the CPU, kernel, and borrow checker enforce rules whether or not the tutorial mentioned them explicitly.
Before you write AArch64 assembly that calls or is called by C, you need to know where every value lives. Build an AAPCS64 (the standard Linux AArch64 ABI) calculator. Given a C signature, print the register or stack slot of each argument and of the return value. Given a register name, print its role in the calling convention.
cLoading…
Types: char (1 byte), short (2), int (4), long (8), ptr (8), float (4), double (8), i128 (16, 16-byte aligned), and void (return type only).
Keep NGRN (the next general register, 0..8), NSRN (the next SIMD/FP register, 0..8) and NSAA (the next stack offset), all starting at 0. Assign the arguments left to right:
wN (size ≤ 4) or xN, then NGRN++. Otherwise use the stack: align NSAA up to 8, the slot is [sp, #NSAA], then NSAA += 8 (standard AAPCS64 rounds small stack arguments up to 8 bytes; Apple's variant does not).sN / dN, then NSRN++. Otherwise use an 8-byte stack slot as above.xN:xN+1 and NGRN += 2. Otherwise set NGRN = 8, align NSAA to 16, use a 16-byte stack slot, and NSAA += 16.Return values: w0/x0 for integers (by size), s0/d0, x0:x1 for i128, and none for void.
cLoading…
Register roles:
| Register | Role |
|---|---|
x0-x7 | argument/result register, caller-saved |
x8 | indirect result location, caller-saved |
x9-x15 | temporary, caller-saved |
x16 / x17 | IP0 / IP1 intra-procedure-call scratch, caller-saved |
x18 | platform register, do not use |
x19-x28 | callee-saved |
x29 | frame pointer, callee-saved |
x30 | link register (return address) |
v0-v7 | FP/SIMD argument/result register, caller-saved |
v8-v15 | callee-saved (low 64 bits only) |
v16-v31 | temporary, caller-saved |
These print as x19: callee-saved and v9: …. Aliases print as:
w5 = low 32 bits of x5 (writes zero the upper half): ROLE;d3 = low 64 bits of v3: ROLE (and sN with 32 bits);fp = x29: ROLE and lr = x30: ROLE;sp: stack pointer, 16-byte aligned at calls;xzr: zero register (reads 0, writes are discarded) (same for wzr).Errors:
error: unknown register R (including leading zeros, like x07);error: unknown type T;error: bad signature (missing parentheses or name, void among the arguments, or more than 16 arguments);error: bad command: LINE.Input:
cLoading…
Output:
cLoading…
Hidden tests cover more than 8 integer arguments, i128 alignment both in registers and on the stack, running out of FP registers while integer registers are still free, void functions, every register class, and malformed input.
Three hints are available for this task, revealed one at a time inside the code workspace so you can struggle productively before seeing them.
Every task includes starter code, theory, and hidden tests so you can implement and verify locally in the browser.
How it works