Registers are the CPU's working memory — the fastest storage that exists. Today you'll understand what they are, how many exist, and how the CPU moves data between registers and RAM.
x86-64 has 16 general-purpose 64-bit registers: RAX, RBX, RCX, RDX (general), RSP (stack pointer), RBP (base pointer), RSI, RDI (source/destination index), R8–R15 (added in x86-64). You can access lower-width slices: EAX (32-bit), AX (16-bit), AL (8-bit low), AH (8-bit high). Plus: RFLAGS (status flags), RIP (instruction pointer), 16 XMM/YMM/ZMM registers for SIMD.
The CPU can only do arithmetic on data that's in registers. To use RAM, you must first load it into a register, operate on it, then store the result back. MOV RAX, [address] — load 8 bytes from memory into RAX. MOV [address], RAX — store RAX to memory. Modern CPUs can have dozens of outstanding load/store operations in flight simultaneously (out-of-order memory operations).
The stack is a region of RAM used for function call frames, local variables, and return addresses. RSP always points to the top. PUSH RBX decrements RSP by 8, stores RBX. POP RBX loads from [RSP], increments RSP. CALL pushes the return address (RIP+instruction_size) and jumps to the function. RET pops the return address and jumps back. Stack frames hold local variables and saved registers — the debugger reads these to show you a stack trace.
; x86-64 registers and stack in action
; Compile: nasm -f elf64 regs.asm && ld regs.o && ./a.out
section .data
msg db "Result: ", 10, 0
section .text
global _start
; Function: adds two arguments, returns result in RAX
; Calling convention: args in RDI, RSI
add_two:
push rbp ; save caller's base pointer
mov rbp, rsp ; set up our stack frame
mov rax, rdi ; rax = first argument
add rax, rsi ; rax = rax + second argument
; rax now holds return value
pop rbp ; restore caller's base pointer
ret ; pop return address → jump back
_start:
; Call add_two(40, 2)
mov rdi, 40 ; first argument
mov rsi, 2 ; second argument
call add_two ; push RIP+next, jump to add_two
; rax = 42
; Exit
mov rdi, 0
mov rax, 60
syscall
int add(int a, int b){return a+b;} and compile with gcc -O0 -S add.cpush rbp, mov rbp,rsp, and pop rbp — that's the stack frame setup/teardown.gdb ./program and info registers to see live register values. Run bt to see the stack trace.Disassemble a function from a real program using objdump -d -M intel /usr/bin/ls | head -100. Find a function call, a branch, and a loop. Identify the CALL/RET pair, the Jcc instruction for the branch, and the backward jump for the loop. Write down what each instruction does.