What is the difference between caller-saved and callee-saved registers, and when do you use each?
Caller-saved: the called function is free to clobber them, so the caller must save anything it still needs. Callee-saved: the function must preserve them, restoring their original values before returning.
* Caller-saved may be clobbered by the callee (temporaries); callee-saved must be preserved (values that survive a call). *
This convention answers "who is responsible for a register's value across a call?" — and getting it right is what lets independently-compiled functions cooperate.
| Type | Who saves it | Best used for |
|---|---|---|
| Caller-saved | The caller, before the call (if it still needs the value) | Short-lived temporaries within one function |
| Callee-saved | The callee, which must restore it before returning | Values that must survive across calls to other functions |
x86_64:
- Caller-saved:
%rax, %rcx, %rdx, %rsi, %rdi, %r8–%r11 - Callee-saved:
%rbx, %rbp, %r12–%r15
Preserving a callee-saved register:
my_func:
pushq %rbx # save it because we're about to use it
...
movq $42, %rbx # now safe to clobber
...
popq %rbx # restore caller's value
ret
Practical rule: if you need a value to outlive a call you make, put it in a callee-saved register (the convention guarantees the callee preserves it). For scratch values used only between calls, caller-saved registers are cheaper (no save/restore unless a call intervenes).
Tip: A function that opens with push %rbx/push %r12 is announcing it intends to use those callee-saved registers and is dutifully preserving them.
Go deeper:
x86 calling conventions (Wikipedia) — the x86-64 register-saving convention.
Eli Bendersky — Stack frame layout on x86-64 — how stack frames actually use these registers.