x86-64 Registers

The Register File

All x86-64 registers
GENERAL PURPOSE (16 registers × 64-bit):
┌────────┬────────┬───────┬──────┬───────────────────────────────────┐
│ 64-bit │ 32-bit │ 16-bit│ 8-bit│ System V ABI Role                │
├────────┼────────┼───────┼──────┼───────────────────────────────────┤
│ RAX    │ EAX    │ AX    │ AL   │ Return value, syscall number     │
│ RBX    │ EBX    │ BX    │ BL   │ Callee-saved (preserved)         │
│ RCX    │ ECX    │ CX    │ CL   │ 4th arg, shift count, loop ctr  │
│ RDX    │ EDX    │ DX    │ DL   │ 3rd arg, I/O port, mul/div high │
│ RSI    │ ESI    │ SI    │ SIL  │ 2nd arg, source index            │
│ RDI    │ EDI    │ DI    │ DIL  │ 1st arg, destination index       │
│ RBP    │ EBP    │ BP    │ BPL  │ Base pointer (callee-saved)      │
│ RSP    │ ESP    │ SP    │ SPL  │ Stack pointer (callee-saved)     │
│ R8     │ R8D    │ R8W   │ R8B  │ 5th arg                          │
│ R9     │ R9D    │ R9W   │ R9B  │ 6th arg                          │
│ R10    │ R10D   │ R10W  │ R10B │ Scratch, 4th syscall arg         │
│ R11    │ R11D   │ R11W  │ R11B │ Scratch, clobbered by syscall    │
│ R12    │ R12D   │ R12W  │ R12B │ Callee-saved                     │
│ R13    │ R13D   │ R13W  │ R13B │ Callee-saved                     │
│ R14    │ R14D   │ R14W  │ R14B │ Callee-saved                     │
│ R15    │ R15D   │ R15W  │ R15B │ Callee-saved                     │
└────────┴────────┴───────┴──────┴───────────────────────────────────┘

SPECIAL PURPOSE:
  RIP    - Instruction pointer (cannot mov to it directly)
  RFLAGS - Status flags register
  FS/GS  - Segment registers (TLS, stack canary)

SSE/AVX (16 registers × 128/256-bit):
  XMM0-XMM15  (128-bit, SSE)
  YMM0-YMM15  (256-bit, AVX — extends XMM)
  Float args: XMM0-XMM7
  Float return: XMM0

Sub-Register Access

How sub-registers map
RAX (64-bit):
  ┌──────────────────────────────────────────────────────────────────┐
  │                              RAX                                 │
  │                    ┌─────────────────────────────────────────────┤
  │                    │                 EAX                         │
  │                    │                    ┌────────────────────────┤
  │                    │                    │         AX             │
  │                    │                    ├───────────┬────────────┤
  │                    │                    │    AH     │     AL     │
  └────────────────────┴────────────────────┴───────────┴────────────┘
   63                 32                   16          8            0

R8 (64-bit):
  ┌──────────────────────────────────────────────────────────────────┐
  │                              R8                                  │
  │                    ┌─────────────────────────────────────────────┤
  │                    │                 R8D                         │
  │                    │                    ┌────────────────────────┤
  │                    │                    │        R8W             │
  │                    │                    │            ┌───────────┤
  │                    │                    │            │    R8B    │
  └────────────────────┴────────────────────┴────────────┴───────────┘

NOTE: R8-R15 do NOT have AH-equivalent high-byte access.
Critical zero-extension rule
; Writing to 32-bit register ZEROS upper 32 bits
mov rax, 0xFFFFFFFFFFFFFFFF
mov eax, 0x00000001          ; RAX = 0x0000000000000001 (zeroed!)

; Writing to 16-bit or 8-bit does NOT zero upper bits
mov rax, 0xFFFFFFFFFFFFFFFF
mov ax, 0x0001               ; RAX = 0xFFFFFFFFFFFF0001 (preserved!)
mov al, 0x02                 ; RAX = 0xFFFFFFFFFFFF0002 (preserved!)

; This is WHY compilers prefer 32-bit operations:
; xor eax, eax is better than xor rax, rax (smaller encoding, same effect)

RFLAGS Register

Flag bits
Bit   Name   Full Name           Set When
──────────────────────────────────────────────────────────────
0     CF     Carry Flag          Unsigned overflow/underflow
2     PF     Parity Flag         Low byte has even number of 1s
4     AF     Adjust Flag         BCD carry from bit 3
6     ZF     Zero Flag           Result is zero
7     SF     Sign Flag           Result MSB is 1 (negative signed)
10    DF     Direction Flag      String ops decrement (std/cld)
11    OF     Overflow Flag       Signed overflow
Which instructions affect which flags
; Instructions that SET flags:
;   add, sub, cmp, test, and, or, xor, inc, dec, neg, shl, shr, sar, mul, imul

; Instructions that DO NOT affect flags:
;   mov, lea, push, pop, call, ret, jmp, nop

; INC/DEC do NOT affect CF (carry flag) — use ADD/SUB if you need CF

; TEST sets flags like AND but discards result:
test rax, rax       ; ZF=1 if RAX==0, SF=1 if negative

; CMP sets flags like SUB but discards result:
cmp rax, 10         ; ZF=1 if RAX==10, CF=1 if RAX < 10 (unsigned)

Segment Registers (FS/GS)

Thread-local storage
; FS and GS are used for thread-local storage in Linux

; Stack canary (loaded from TLS via FS)
mov rax, QWORD PTR fs:[0x28]    ; Load canary value
; This is why buffer overflows are detected — canary changes per thread

; GS is used in kernel mode for per-CPU data

; In GDB:
; (gdb) print/x $fs_base    — show FS base address
; (gdb) x/gx $fs_base+0x28  — show canary value

Register Usage Conventions

System V AMD64 ABI summary
CALLER-SAVED (scratch — function may destroy):
  RAX  - return value
  RCX  - 4th integer argument
  RDX  - 3rd integer argument
  RSI  - 2nd integer argument
  RDI  - 1st integer argument
  R8   - 5th integer argument
  R9   - 6th integer argument
  R10  - scratch
  R11  - scratch

CALLEE-SAVED (preserved — function must restore):
  RBX, RBP, R12, R13, R14, R15, RSP

SYSCALL CONVENTION (different from function calls!):
  RAX  - syscall number / return value
  RDI  - 1st argument
  RSI  - 2nd argument
  RDX  - 3rd argument
  R10  - 4th argument (NOT RCX!)
  R8   - 5th argument
  R9   - 6th argument
  RCX, R11 - clobbered by syscall instruction
Choosing registers
; Need to survive a function call? Use callee-saved:
push r12
mov r12, rdi        ; Save argument in r12
call some_function  ; r12 survives!
mov rdi, r12        ; Use saved value
pop r12

; Quick scratch work? Use caller-saved:
mov r10, rax        ; Temporary, no need to save
shl r10, 3
add rax, r10        ; rax = rax * 9