Skip to content

05 — Registers

Registers are the CPU's internal storage — the fastest memory available. Every computation happens through registers. Understanding their names, sizes, and conventions is fundamental.


x86-64 General-Purpose Registers

There are 16 general-purpose 64-bit registers. Each has multiple sub-register names that access different portions:

64-bit   32-bit   16-bit   8-bit(high)  8-bit(low)
──────   ──────   ──────   ──────────   ──────────
RAX      EAX      AX       AH           AL
RBX      EBX      BX       BH           BL
RCX      ECX      CX       CH           CL
RDX      EDX      DX       DH           DL
RSI      ESI      SI                    SIL
RDI      EDI      DI                    DIL
RSP      ESP      SP                    SPL
RBP      EBP      BP                    BPL
R8       R8D      R8W                   R8B
R9       R9D      R9W                   R9B
R10      R10D     R10W                  R10B
R11      R11D     R11W                  R11B
R12      R12D     R12W                  R12B
R13      R13D     R13W                  R13B
R14      R14D     R14W                  R14B
R15      R15D     R15W                  R15B

Accessing Sub-Registers

block-beta
  columns 8
  RAX["RAX (64-bit)"]:8
  space:4 EAX["EAX (32-bit)"]:4
  space:6 AX["AX (16-bit)"]:2
  space:6 AH["AH (8-hi)"]:1 AL["AL (8-lo)"]:1

Important: Writing to 32-bit Zeros the Upper 32 Bits

mov rax, 0xFFFFFFFFFFFFFFFF   ; rax = all 1s
mov eax, 0                    ; rax = 0 (not just low 32 bits!)

Writing to EAX zero-extends into RAX. This is intentional x86-64 behavior. Writing to AX, AH, AL does NOT zero the upper bits — only the selected portion changes.


Special-Purpose Registers

Register Name Role
RSP Stack Pointer Points to the top of the stack
RBP Base Pointer Points to the base of the current stack frame
RIP Instruction Pointer Address of the next instruction to execute
RFLAGS Flags Register Status bits from arithmetic/logic operations

RSP — Stack Pointer

  • Always points to the last pushed value (top of stack)
  • Stack grows downward — push decrements RSP, pop increments RSP
  • Must be 16-byte aligned when calling external functions (System V ABI)

RBP — Base Pointer

  • In traditional stack frames, RBP points to the saved RBP of the caller
  • Modern code often uses frame pointer omission (-fomit-frame-pointer)
  • Makes it easy to access local variables at [rbp - offset]

Calling Convention Register Roles (System V AMD64 ABI)

When calling functions, registers have defined roles:

Argument Passing (first 6 integer arguments)

Argument Register
1st RDI
2nd RSI
3rd RDX
4th RCX
5th R8
6th R9
7th+ Pushed onto stack

Return Value

Register Usage
RAX Primary return value (integer/pointer)
RDX Secondary return value (128-bit results)

Caller-Saved (volatile) — Caller must save before calling

RAX, RCX, RDX, RSI, RDI, R8, R9, R10, R11
A called function may freely modify these.

Callee-Saved (non-volatile) — Callee must preserve

RBX, RBP, R12, R13, R14, R15
If your function uses these, save them (PUSH) at entry and restore (POP) before returning.


RFLAGS Register

RFLAGS is a 64-bit register where individual bits are meaningful:

Bit Flag Abbreviation Set When
0 Carry Flag CF Unsigned overflow
2 Parity Flag PF Even number of 1-bits in low byte
4 Auxiliary Carry AF Carry from bit 3
6 Zero Flag ZF Result is zero
7 Sign Flag SF Result's MSB is 1 (negative)
8 Trap Flag TF Single-step debugging
9 Interrupt Enable IF Interrupts enabled
10 Direction Flag DF String operation direction
11 Overflow Flag OF Signed overflow

You don't directly mov to RFLAGS. Arithmetic instructions set them automatically, and you read them with conditional jumps (je, jl, etc.) or setcc instructions.


Segment Registers (Legacy)

Register Name Modern Use
CS Code Segment Implicitly used for code
DS Data Segment Implicitly used for data
SS Stack Segment Implicitly used for stack
ES Extra Segment String operations
FS F Segment Thread-local storage (TLS)
GS G Segment TLS on Windows, kernel data on Linux

In 64-bit mode, segmentation is mostly disabled — CS, DS, SS, ES all have base 0. FS and GS are used for TLS by the OS/runtime.


SIMD Registers

Beyond general-purpose, x86-64 has wide registers for SIMD operations:

Register Set Width Count Extension
MMX (MM0MM7) 64-bit 8 MMX (legacy)
SSE (XMM0XMM15) 128-bit 16 SSE/SSE2–4
AVX (YMM0YMM15) 256-bit 16 AVX/AVX2
AVX-512 (ZMM0ZMM31) 512-bit 32 AVX-512

YMM0 contains XMM0 in its lower half. Writing XMM0 zeros the upper 128 bits of YMM0.


Register Usage in Practice

section .text
global _start

_start:
    ; Using sub-registers
    mov  rax, 0x1234567890ABCDEF

    mov  al,  0xFF    ; low byte: rax = 0x1234567890ABCDFF
    mov  ah,  0xFF    ; high byte of AX: rax = 0x1234567890ABFFFF
    mov  ax,  0xBEEF  ; low word: rax = 0x1234567890ABBEEF
    mov  eax, 0       ; zero-extends: rax = 0x0000000000000000

    ; Caller/callee save example
    push rbx          ; save callee-saved register
    mov  rbx, 42      ; use it freely
    pop  rbx          ; restore before returning

Checking Register State in GDB

(gdb) info registers              ; all registers
(gdb) info registers rax rbx rcx  ; specific registers
(gdb) p/x $rax                    ; print rax in hex
(gdb) p/d $rax                    ; print rax as signed decimal
(gdb) p/u $rax                    ; print rax as unsigned decimal

Key Takeaways

  • 16 general-purpose 64-bit registers; each accessible at 64/32/16/8-bit widths
  • Writing to 32-bit register (e.g., EAX) zero-extends to 64-bit (RAX)
  • Writing to 8/16-bit portions does NOT clear upper bits
  • RDI, RSI, RDX, RCX, R8, R9 pass the first 6 function arguments
  • RAX returns function results
  • RBX, RBP, R12–R15 must be preserved across function calls

Next: 06 — Memory and Addressing Modes