Reading Assembly

Part 2 · The calling contract

Who saves what

Caller-saved, callee-saved, the red zone, and the alignment rule you only notice when it is broken.

30 mincontrasting casesbeacon training
What this lesson is trying to break (2)
  • A function call preserves all your registers.
  • Stack alignment is a detail the hardware handles.

A call is not transparent. Some registers survive it and some do not, and which is which is written into the ABI.

The two halves

Varies: only who is responsible for preserving the value

Caller-saved (volatile)Callee-saved (non-volatile)
SysV AMD64rax rcx rdx rsi rdi r8r11rbx rbp r12r15
ARM64x0x18x19x28, x29
Who preserves itThe caller, before the callThe callee, if it uses it
After a call returnsMay hold anythingGuaranteed unchanged
Good forShort-lived values, argumentsValues live across a call

Note that all six argument registers are caller-saved. A function that needs an argument after making a call must save it somewhere itself — which is why you see arguments copied into rbx or r12 early in functions that call other things.

This produces a readable pattern. A function that pushes rbx, r12, r13 in its prologue is telling you: I have several values that must survive calls I am about to make. The number of callee-saved pushes is a rough measure of how much state a function carries across its calls.

Beaconsee this → think this, without decoding it

push rbx / push r12 ... at the top, pop r12 / pop rbx at the bottom

This function makes calls and needs values to survive them.

The count tells you how much live state crosses call boundaries. A loop that calls something and accumulates a result will nearly always show this pattern, with the accumulator in a callee-saved register.

Conversely, a function using only rax, rcx, rdx and the argument registers, with no pushes, is very likely a leaf.

The red zone

SysV grants leaf functions 128 bytes below rsp for free — no sub rsp needed. Signal handlers and the kernel promise not to touch it.

Why only leaves: a call pushes a return address at [rsp-8], which is inside that region. Any call destroys it.

This is the explanation for a small mystery you will hit: a function that clearly uses stack memory (mov [rsp-8], edi) but never adjusts rsp. It is using the red zone. Windows x64 has no red zone — it has shadow space instead, 32 bytes that the caller allocates for the callee to spill into, which is the opposite arrangement.

The alignment rule

On SysV, rsp must be 16-byte aligned at the point of a call. Since call pushes 8 bytes, rsp is 8-mod-16 on function entry, and the standard push rbp brings it back to aligned.

This exists for historical SSE reasons — some instructions required 16-byte aligned memory operands — and it survives as a guarantee library code relies on.

The reason to care: violating it does not fail where you violated it. Your function works; then some library it calls uses an aligned SSE instruction on a stack address and crashes with no obvious connection to the cause. If you ever write assembly by hand or use inline asm, this is the mistake that costs an afternoon.

Predict firstcommit in writing, then look

A function that makes a call and has no locals still often contains:

        sub     rsp, 8
        call    something
        add     rsp, 8

Eight bytes are allocated and never used. Why?

Explain it to yourselfwrite it — thinking it does not count

Reading an unfamiliar function, you see its prologue push rbx, r12 and r13, and no sub rsp.

List everything you can infer about the function before reading a single line of its body. There are at least four inferences available.

What you should now be able to say

  • Caller-saved may be clobbered by a call; callee-saved is guaranteed preserved. The ABI decides which.
  • All argument registers are caller-saved, so values needed after a call get copied into rbx/r12-style registers — a readable signal.
  • The red zone is 128 bytes free to leaf functions only, and explains stack use with no sub rsp.
  • rsp must be 16-byte aligned at a call, and violations crash somewhere else entirely.
  • A lone sub rsp, 8 or a pointless push is alignment padding.

Next: 2.5 — Reading a call chain.