x86-64 Quick Reference
A cheat sheet of the general-purpose registers, the common instructions, the condition codes and their flags, and the System V argument registers. Keep it open while you read listings.
The General-Purpose Registers
All 16 general-purpose registers, their smaller sub-register names, and the role the System V convention assigns to each. The 32/16/8-bit names refer to the lower portion of the same physical register.
| 64-bit | 32-bit | 16-bit | 8-bit | System V role | Saved by |
|---|---|---|---|---|---|
rax |
eax |
ax |
al |
Return value | Caller |
rbx |
ebx |
bx |
bl |
Scratch | Callee |
rcx |
ecx |
cx |
cl |
4th argument | Caller |
rdx |
edx |
dx |
dl |
3rd argument; return-value helper | Caller |
rsi |
esi |
si |
sil |
2nd argument | Caller |
rdi |
edi |
di |
dil |
1st argument | Caller |
rbp |
ebp |
bp |
bpl |
Frame pointer | Callee |
rsp |
esp |
sp |
spl |
Stack pointer | Callee |
r8 |
r8d |
r8w |
r8b |
5th argument | Caller |
r9 |
r9d |
r9w |
r9b |
6th argument | Caller |
r10 |
r10d |
r10w |
r10b |
Scratch | Caller |
r11 |
r11d |
r11w |
r11b |
Scratch | Caller |
r12 |
r12d |
r12w |
r12b |
Scratch | Callee |
r13 |
r13d |
r13w |
r13b |
Scratch | Callee |
r14 |
r14d |
r14w |
r14b |
Scratch | Callee |
r15 |
r15d |
r15w |
r15b |
Scratch | Callee |
Writing to a 32-bit name (eax, edi, ...) zeroes the upper 32 bits of the full register; writing to a 16-bit or 8-bit name leaves the rest untouched.
The Common Instructions
The core instruction set, grouped by job. In Intel syntax the destination is always the first operand.
Data Movement
| Instruction | What it does | Example |
|---|---|---|
mov |
Copy source into destination (source unchanged) | mov eax, edi |
movzx |
Copy a smaller value, zero-extending it to fill the destination | movzx eax, al |
movsx |
Copy a smaller value, sign-extending it to fill the destination | movsx eax, WORD PTR [rdi] |
lea |
Compute an address expression; never reads memory | lea rax, [rdi+rsi*4] |
push |
Put a value on the stack (rsp -= 8, then store) |
push rbp |
pop |
Take a value off the stack (load, then rsp += 8) |
pop rbp |
Arithmetic
| Instruction | What it does | Example |
|---|---|---|
add |
Destination = destination + source | add eax, edx |
sub |
Destination = destination - source | sub rsp, 16 |
imul |
Signed multiply | imul eax, edx |
idiv |
Signed divide edx:eax by operand; quotient in eax, remainder in edx |
idiv ecx |
inc |
Add one | inc eax |
dec |
Subtract one | dec eax |
neg |
Flip the sign (two's complement negate) | neg eax |
Bitwise and Logic
| Instruction | What it does | Example |
|---|---|---|
and |
Bitwise AND | and eax, 15 |
or |
Bitwise OR | or eax, edx |
xor |
Bitwise XOR; xor eax, eax is the idiom for "set to zero" |
xor eax, eax |
not |
Flip every bit | not eax |
shl |
Shift left (multiply by powers of two) | shl eax, 2 |
shr |
Logical shift right, filling with zeros (unsigned divide) | shr eax, 1 |
sar |
Arithmetic shift right, copying the sign bit (signed divide) | sar eax, 1 |
Comparison
| Instruction | What it does | Example |
|---|---|---|
cmp |
Compute destination minus source, set flags, discard result | cmp edi, 10 |
test |
Bitwise AND, set flags, discard result; test eax, eax asks "is eax zero?" |
test eax, eax |
Control Flow
| Instruction | What it does | Example |
|---|---|---|
jmp |
Jump to a label, always | jmp .L3 |
jcc |
Jump only if the flags match the condition (see the table below) | je .L2 |
call |
Push the return address and jump to a function | call square(int) |
ret |
Pop the return address and jump back to the caller | ret |
Condition Codes
The conditional jump family. Each acts on the flags left behind by the most recent cmp, test, or arithmetic instruction. Less/greater means signed; below/above means unsigned.
| Mnemonic | Meaning | Signed / unsigned | Flags read |
|---|---|---|---|
je / jz |
Equal / zero | Either | ZF = 1 |
jne / jnz |
Not equal / not zero | Either | ZF = 0 |
jl |
Less than | Signed | SF != OF |
jle |
Less than or equal | Signed | ZF = 1 or SF != OF |
jg |
Greater than | Signed | ZF = 0 and SF = OF |
jge |
Greater than or equal | Signed | SF = OF |
jb |
Below | Unsigned | CF = 1 |
jbe |
Below or equal | Unsigned | CF = 1 or ZF = 1 |
ja |
Above | Unsigned | CF = 0 and ZF = 0 |
jae |
Above or equal | Unsigned | CF = 0 |
js |
Negative (sign set) | Either | SF = 1 |
jns |
Not negative | Either | SF = 0 |
Every condition above also exists as setcc (write 1 or 0 into an 8-bit register, e.g. setl al) and cmovcc (copy only if the condition holds, e.g. cmovge eax, edx). Same suffixes, same flag logic, no jump.
The System V Calling Convention at a Glance
The rulebook for function calls on Linux, macOS, and the BSDs.
| Rule | Detail |
|---|---|
| Integer/pointer arguments | rdi, rsi, rdx, rcx, r8, r9, in that order; the 7th and beyond go on the stack |
| Floating-point arguments | xmm0 through xmm7, in that order |
| Integer/pointer return value | rax (eax for int) |
| Floating-point return value | xmm0 |
| Caller-saved (a call may clobber these) | rax, rdi, rsi, rdx, rcx, r8, r9, r10, r11 |
| Callee-saved (a function must restore these) | rbx, rbp, r12, r13, r14, r15 |
| Stack alignment | rsp must be 16-byte aligned at the point of a call |
The Flags Register
The four flags that comparisons and conditional jumps care about. cmp, test, and most arithmetic instructions set them; mov and lea do not.
| Flag | Name | Set when... |
|---|---|---|
ZF |
Zero flag | The result was zero (for cmp a, b: when a == b) |
SF |
Sign flag | The result's top bit was 1, i.e. negative as a signed value |
OF |
Overflow flag | The result overflowed as a signed value |
CF |
Carry flag | The operation carried or borrowed, i.e. overflowed as an unsigned value |
Sizes and Type Widths
How C++ types map to operand sizes on x86-64 System V. The PTR keyword appears when an instruction touches memory and the size is not implied by a register operand.
| C++ type | Size | Memory operand | Register width |
|---|---|---|---|
bool, char, signed char, unsigned char |
1 byte | BYTE PTR |
al |
short, unsigned short |
2 bytes | WORD PTR |
ax |
int, unsigned int |
4 bytes | DWORD PTR |
eax |
long, long long, pointers, std::size_t |
8 bytes | QWORD PTR |
rax |
float |
4 bytes | DWORD PTR |
xmm0 (scalar) |
double |
8 bytes | QWORD PTR |
xmm0 (scalar) |
Reading a Memory Operand
Every memory operand is built from the same recipe: displacement[base + index*scale], where the displacement is a constant offset, base and index are registers, and scale is 1, 2, 4, or 8. Any part may be omitted; the parts that are present are simply added together to form the address.
mov eax, DWORD PTR -4[rbp] ; address = rbp - 4 (a local variable in the frame)
mov eax, DWORD PTR [rdi+rsi*4] ; address = rdi + rsi*4 (element rsi of an int array at rdi)
The scale exists for array indexing: multiplying the index by the element size (4 for int, 8 for pointers) turns "element number" into "byte offset" in a single operand.
How to Use This Page
Keep this page open in another tab while you read listings. When a register, instruction, or jump mnemonic does not ring a bell, look it up here first; the lesson that introduced it has the full explanation if you need more.
Create an account to track your progress and access interactive exercises. Already have one? Sign in.
Lesson Discussion
Share your thoughts and questions
No comments yet. Be the first to share your thoughts!