Reading — step 1 of 5
Read
System V x86-64 Calling Convention
A calling convention is the contract between caller and callee: where do arguments live, where does the return value land, who saves which registers, how is the stack aligned. On Linux/macOS/BSD x86-64 we follow the System V AMD64 ABI (Windows uses a different one).
Argument passing — first six integer args in registers
Integer (and pointer) args 1..6 go in:
arg # 1 2 3 4 5 6
reg RDI RSI RDX RCX R8 R9
Args 7+ are pushed on the stack in right-to-left order (so the leftmost stack arg is at the lowest address on entry).
Return value
Integer/pointer return value in RAX (high half of a 128-bit return uses RDX).
Caller-saved vs callee-saved
| Caller-saved (volatile) | Callee-saved (preserved) |
|---|---|
| RAX, RCX, RDX, RSI, RDI, R8–R11 | RBX, RBP, R12–R15, RSP |
If you want a value to survive a call, either put it in a callee-saved reg, or spill it.
Stack alignment — the 16-byte rule
At the point of a call instruction, RSP must be 16-byte aligned modulo the return address. Concretely, after the call pushes the 8-byte return address, RSP will be 16-byte aligned inside the callee. Forgetting this manifests as crashes inside libc functions that use SSE.
Example: emit a call with N args
For f(1, 2, 3, 4, 5, 6, 7, 8):
mov rdi, 1
mov rsi, 2
mov rdx, 3
mov rcx, 4
mov r8, 5
mov r9, 6
push 8 ; stack args right-to-left
push 7
call f
add rsp, 16 ; clean up 2 stack args (2*8)
After the call, the caller is responsible for restoring RSP (the callee uses ret which only pops the return address).
What our exercise builds
Given lines <func> <argc>, emit the asm that loads args 1..argc (literal values) into the right registers/stack slots, calls func, then cleans up the stack if there were >6 args.
References: System V AMD64 ABI §3.2 (psABI document), chibicc codegen.c gen_args, Sandler Ch. 9 (functions).
Discussion
Ask a question, share an insight, or help someone who’s stuck.
Sign in to post a comment or reply.
Loading…