Skip to content

Instructions

arm64

AArch64 Common Instructions

Core ARM64 instructions — MOV, LDR/STR, B/BL/BLR, CMP, ADD/SUB, and RET — with their encodings and reverse-engineering patterns.

ARM64 instructions are all 32 bits wide (fixed-length), which makes disassembly trivial compared to x86-64. Instructions follow a destination-first, source-second convention in ARM syntax.

MOV

asm
MOV  X0, X1         ; X0 = X1  (alias for ORR X0, XZR, X1)
MOV  X0, #42        ; X0 = 42  (alias for MOVZ X0, #42)
MOVZ X1, #0x1234    ; X1 = 0x1234 (zero other halfwords)
MOVK X1, #0x5678, LSL #16  ; keep other bits, set bits 31:16

MOV is a pseudoinstruction; the assembler chooses ORR, MOVZ, or MOVN as appropriate.

LDR / STR (Load and Store)

asm
LDR  X0, [X1]          ; X0 = *(uint64_t*)X1
LDR  W0, [X1]          ; W0 = *(uint32_t*)X1  (zero-extends to X0)
LDRB W0, [X1]          ; W0 = *(uint8_t*)X1
LDRH W0, [X1]          ; W0 = *(uint16_t*)X1
LDRSB X0, [X1]         ; sign-extend byte → X0
LDRSH X0, [X1]         ; sign-extend halfword → X0

STR  X0, [X1]          ; *(uint64_t*)X1 = X0
STR  W0, [X1, #8]      ; *(uint32_t*)(X1+8) = W0

; Pre-index (update X1 before access)
LDR  X0, [X1, #8]!     ; X1 += 8; X0 = *X1

; Post-index (update X1 after access)
LDR  X0, [X1], #8      ; X0 = *X1; X1 += 8

; Pair
STP  X29, X30, [SP, #-16]!  ; push FP and LR (function prologue)
LDP  X29, X30, [SP], #16    ; pop FP and LR (function epilogue)

B / BL / BLR / BR (Branches)

InstructionOperation
B labelUnconditional branch (PC-relative ±128 MB)
BL labelBranch with Link: LR = PC+4; goto label (call)
BLR XnBranch with Link to Register (indirect call)
BR XnBranch to Register (indirect jump / tail call)
B.cond labelConditional branch (e.g. B.EQ, B.NE, B.LT)
CBZ Xn, labelBranch if Xn == 0 (compare-and-branch, no flags)
CBNZ Xn, labelBranch if Xn != 0
TBZ Xn, #bit, labelBranch if bit N of Xn == 0

CMP / TST

asm
CMP  X0, X1        ; flags ← X0 - X1  (alias: SUBS XZR, X0, X1)
CMP  X0, #100
TST  X0, #0xFF     ; flags ← X0 & 0xFF  (alias: ANDS XZR, X0, #0xFF)

ADD / SUB

asm
ADD  X0, X1, X2         ; X0 = X1 + X2
ADD  X0, X1, #16        ; X0 = X1 + 16
SUB  SP, SP, #32        ; allocate 32 bytes on stack
ADDS X0, X1, X2         ; ADD and set flags  (S suffix → update PSTATE)
SUBS X0, X1, X2         ; SUB and set flags

RET

asm
RET          ; branch to X30 (LR) — return to caller
RET X17      ; branch to X17 (used in veneers/PLT stubs)

RET is not a pop — it is BR LR. The return address must have been loaded into LR by a previous BL/BLR, or restored from the stack.

Reverse-engineering notes

  • The prologue STP X29, X30, [SP, #-16]! saves the frame pointer and link register; the matching epilogue is LDP X29, X30, [SP], #16; RET.
  • BLR X16 or BLR X17 in a PLT stub jumps through the GOT to a lazy-linked library function.
  • CBZ/CBNZ are compact null-pointer and boolean checks that produce no separate CMP instruction — decompilers render them as if (!x) / if (x).
  • Fixed-length encoding means you can reliably disassemble backwards: subtract 4 to get the previous instruction, unlike x86-64.