Quiz Entry - updated: 2026.07.14
What are callee-saved vs caller-saved registers in x86-64?
Callee-saved registers (%rbx, %rbp, %r12–%r15) must be preserved by any function that uses them; caller-saved registers may be freely overwritten, so the caller must save anything it still needs.
The convention partitions the registers to settle "who is responsible for preserving what" across a call, preventing two functions from silently clobbering each other.
| Category | Registers | Responsibility |
|---|---|---|
| Callee-saved | %rbx, %rbp, %r12–%r15 | the callee must save/restore if it uses them |
| Caller-saved | %rax, %rcx, %rdx, %rsi, %rdi, %r8–%r11 | the caller must save them before a call if needed after |
| Special | %rsp | the stack pointer (always preserved) |
Why it matters, concretely:
void caller() {
long x = compute(); // suppose x lives in %rbx (callee-saved)
other_function(); // %rbx is guaranteed intact across this call
use(x); // x is still valid
}
If x had been in a caller-saved register like %rax, other_function() would have been free to overwrite it.
foo:
pushq %rbx # save callee-saved regs the function will use
pushq %r12
... # body
popq %r12 # restore before returning
popq %rbx
ret
Reverse-engineering tip: values placed in callee-saved registers are usually locals the function needs to keep across its own calls.
Go deeper:
x86 calling conventions (Wikipedia) — the caller/callee-saved register partition across ABIs.