Article by Ayman Alheraki in October 30 2024 01:16 PM
Command | Description | Example |
---|---|---|
mov | Moves an immediate or register value to a register. | mov x0, #5 |
ldr | Loads a value from memory into a register. | ldr x0, [x1] |
str | Stores a value from a register into memory. | str x0, [x1] |
ldp | Loads a pair of registers from memory. | ldp x0, x1, [sp] |
stp | Stores a pair of registers to memory. | stp x0, x1, [sp, #-16]! |
adr | Loads a label address (relative) into a register. | adr x0, label |
Command | Description | Example |
---|---|---|
add | Adds two registers or a register and an immediate. | add x0, x1, #10 |
sub | Subtracts two registers or a register and an immediate. | sub x0, x1, #5 |
mul | Multiplies two registers. | mul x0, x1, x2 |
udiv | Unsigned division of two registers. | udiv x0, x1, x2 |
neg | Negates a register. | neg x0, x1 |
Command | Description | Example |
---|---|---|
and | Bitwise AND between two registers. | and x0, x1, x2 |
orr | Bitwise OR between two registers. | orr x0, x1, x2 |
eor | Bitwise XOR between two registers. | eor x0, x1, x2 |
lsl | Logical shift left. | lsl x0, x1, #2 |
lsr | Logical shift right. | lsr x0, x1, #2 |
not | Bitwise NOT. | mvn x0, x1 (ARM equivalent) |
Command | Description | Example |
---|---|---|
cmp | Compares two registers, updating flags. | cmp x0, x1 |
cmn | Adds two registers and updates flags. | cmn x0, x1 |
tst | Performs bitwise AND and updates flags. | tst x0, x1 |
Command | Description | Example |
---|---|---|
b | Unconditional branch to a label. | b label |
bl | Branch with link (for function calls). | bl func |
ret | Returns from a function. | ret |
cbz | Branch if register is zero. | cbz x0, label |
cbnz | Branch if register is not zero. | cbnz x0, label |
b.eq | Branch if equal (zero flag set). | b.eq label |
b.ne | Branch if not equal (zero flag clear). | b.ne label |
Command | Description | Example |
---|---|---|
ldr | Load register from memory with offset. | ldr x0, [x1, #8] |
str | Store register to memory with offset. | str x0, [x1, #8] |
ldrb | Load byte from memory. | ldrb w0, [x1] |
strb | Store byte to memory. | strb w0, [x1] |
ldrsw | Load signed word (32-bit) and sign-extend to 64-bit. | ldrsw x0, [x1, #4] |
stp | Store pair of registers to memory. | stp x0, x1, [sp, #-16]! |
mov x0, #10 ; Load 10 into x0
mov x1, #20 ; Load 20 into x1
add x2, x0, x1 ; Add x0 and x1, store result in x2
cmp x2, #30 ; Compare x2 with 30
b.eq equal_label ; Branch to equal_label if x2 is 30
mov x0, #5 ; Argument for function
bl my_function ; Call my_function
...
my_function:
add x0, x0, #10 ; Add 10 to x0
ret ; Return to caller
xxxxxxxxxx
ldr x0, [x1, #8] ; Load x0 from memory address at (x1 + 8)
str x2, [x1, #-4] ; Store x2 to memory address at (x1 - 4)
Each of these commands is essential in ARM64 assembly, providing fundamental control over data manipulation, memory access, and program flow. Let me know if you’d like more in-depth examples for specific commands or applications!
Instruction | Assembly Syntax | Machine Code (Hex) | Description |
---|---|---|---|
MOV | MOV x0, x1 | E1 00 00 00 | Move the value from x1 to x0 |
MOV Immediate | MOV x0, #5 | D2 80 00 05 | Move immediate value 5 into x0 |
ADD | ADD x0, x1, x2 | 0B 00 00 00 | Add x1 and x2 , store result in x0 |
SUB | SUB x0, x1, x2 | 4B 00 00 00 | Subtract x2 from x1 , store in x0 |
AND | AND x0, x1, x2 | 0A 00 00 00 | Bitwise AND of x1 and x2 , result in x0 |
ORR | ORR x0, x1, x2 | 2A 00 00 00 | Bitwise OR of x1 and x2 , result in x0 |
EOR | EOR x0, x1, x2 | 2A 00 00 00 | Bitwise XOR of x1 and x2 , result in x0 |
LDR | LDR x0, [x1] | B9 40 00 00 | Load word from address in x1 to x0 |
STR | STR x0, [x1] | B9 00 00 00 | Store word from x0 to address in x1 |
B | B label | Varies | Unconditional branch to label |
BL | BL label | Varies | Branch with link to label |
CMP | CMP x0, x1 | 2A 00 00 01 | Compare x0 and x1 |
TST | TST x0, x1 | 3A 00 00 00 | Test x0 against x1 |
CBZ | CBZ x0, label | Varies | Compare x0 to zero, branch if zero |
CBNZ | CBNZ x0, label | Varies | Compare x0 to zero, branch if not zero |
LDRB | LDRB x0, [x1] | B9 40 00 00 | Load byte from address in x1 to x0 |
STRB | STRB x0, [x1] | B9 00 00 00 | Store byte from x0 to address in x1 |
LDUR | LDUR x0, [x1, #4] | B9 40 00 00 | Load word from address in x1 with offset |
STUR | STUR x0, [x1, #4] | B9 00 00 00 | Store word to address in x1 with offset |
MUL | MUL x0, x1, x2 | 0B 00 00 00 | Multiply x1 and x2 , store result in x0 |
SDIV | SDIV x0, x1, x2 | 4B 00 00 00 | Signed divide x1 by x2 , store result in x0 |
UDIV | UDIV x0, x1, x2 | 4B 00 00 00 | Unsigned divide x1 by x2 , store result in x0 |
LSR | LSR x0, x1, #3 | 2A 00 00 00 | Logical shift right x1 by 3 , result in x0 |
LSL | LSL x0, x1, #3 | 2A 00 00 00 | Logical shift left x1 by 3 , result in x0 |
ROR | ROR x0, x1, #3 | 2A 00 00 00 | Rotate right x1 by 3 , result in x0 |
ROR | ROR x0, x1, #3 | 2A 00 00 00 | Rotate right x1 by 3 , result in x0 |
BIC | BIC x0, x1, x2 | 0A 00 00 00 | Bit clear (AND NOT) of x1 with x2 |
POP | POP {x0, x1} | A9 01 01 00 | Pop registers x0 and x1 from the stack |
PUSH | PUSH {x0, x1} | A9 01 00 00 | Push registers x0 and x1 onto the stack |
RET | RET | C0 03 5F D6 | Return from a function |
MOV: Move data from one register to another or load an immediate value.
ADD/SUB: Basic arithmetic operations for addition and subtraction.
AND/ORR/EOR: Bitwise operations for logical AND, OR, and XOR.
LDR/STR: Load and store operations for transferring data between memory and registers.
B/BL: Control flow operations for branching and function calls.
CMP/TST: Comparison operations for setting condition flags.
CBZ/CBNZ: Conditional branches based on the zero flag.
MUL/SDIV/UDIV: Multiplication and division operations.
LSR/LSL/ROR: Bitwise shifting operations for logical shifts and rotations.
PUSH/POP: Stack operations for managing function calls and local variables.
Variability: The machine code for branch instructions (like B
and BL
) will depend on the address of the label they point to, so it will vary based on the code context.
Pseudo-instructions: Some assembly commands may be pseudo-instructions that are translated into one or more actual machine instructions by the assembler.
Register | Name | Description | Example Usage |
---|---|---|---|
X0-X7 | Argument/Return | Used to pass the first 8 arguments to functions and to hold return values. | mov x0, #10 |
X8 | Indirect Result | Used to pass an additional return value or hold a pointer for indirect results. | mov x8, x0 |
X9-X15 | Temporary | Temporary registers for general use within functions (caller-saved). | add x9, x10, x11 |
X16, X17 | IP0, IP1 | Intra-procedure call temporary registers, used for procedure linkage. | mov x16, #1 |
X18 | Platform Register | Reserved for platform-specific usage (varies by OS, e.g., in iOS/macOS it’s used as the "thread register"). | mov x18, xzr |
X19-X28 | Callee-Saved | Preserved across function calls (callee-saved), used to hold values that need to persist. | mov x19, x0 |
X29 | Frame Pointer (FP) | Points to the base of the current stack frame, often used to access local variables. | stp x29, x30, [sp, #-16]! |
X30 | Link Register (LR) | Holds the return address for function calls. | blr x30 |
X31 (XZR) | Zero Register / Stack Pointer (SP) | Reads as zero (XZR) when used as X31, or as the Stack Pointer (SP) in special instructions. | mov x0, xzr |
Register | Name | Description | Example Usage |
---|---|---|---|
SP | Stack Pointer | Points to the top of the stack, used for managing stack frames. | stp x29, x30, [sp, #-16]! |
PC | Program Counter | Holds the current program address, generally not directly modified in AArch64. | Implicit in branches |
NZCV | Flags Register | Holds condition flags (Negative, Zero, Carry, Overflow) set by operations like comparisons. | cmp x0, x1 |
Passing arguments and returning values using X0-X7.
xmov x0, #5 ; Load 5 into X0 (first argument)
mov x1, #10 ; Load 10 into X1 (second argument)
bl add_numbers ; Branch with link to `add_numbers`, storing return address in X30
add_numbers:
add x0, x0, x1 ; X0 = X0 + X1, result in X0 (return result)
ret ; Return to caller, using address in X30
Setting up and tearing down a stack frame.
xxxxxxxxxx
stp x29, x30, [sp, #-16]! ; Push FP and LR to stack and update SP
mov x29, sp ; Update FP to point to new stack location
...
ldp x29, x30, [sp], #16 ; Pop FP and LR from stack, restore SP
ret ; Return to caller
Using NZCV flags with conditional instructions.
xxxxxxxxxx
mov x0, #10 ; Load 10 into X0
mov x1, #15 ; Load 15 into X1
cmp x0, x1 ; Compare X0 and X1, sets NZCV
csel x2, x1, x0, gt ; Select X1 if X0 > X1, else select X0, store in X2
These registers and examples showcase AArch64’s streamlined, efficient design, especially useful for high-performance applications, embedded systems, and modern operating systems.