How are function arguments passed in x86-64, and where does the return value go?
The first six integer/pointer arguments go in %rdi, %rsi, %rdx, %rcx, %r8, %r9 (in that order); any beyond the sixth go on the stack, and the return value comes back in %rax.
This register-based convention is a defining feature of the x86-64 ABI and a major reason its calls are faster than IA-32's, which passed everything through memory.
| Argument | Register |
|---|---|
| 1st | %rdi |
| 2nd | %rsi |
| 3rd | %rdx |
| 4th | %rcx |
| 5th | %r8 |
| 6th | %r9 |
| 7th+ | stack |
long foo(long a, long b, long c, long d, long e, long f, long g);
a→%rdi, b→%rsi, c→%rdx, d→%rcx, e→%r8, f→%r9, and g is pushed on the stack.
Why registers? Register access is far faster than memory, so the convention deliberately minimizes stack traffic — a clean improvement over IA-32.
Note: floating-point arguments use a separate bank of registers, %xmm0–%xmm7, not the integer registers above.
Go deeper:
x86 calling conventions (Wikipedia) — the System V AMD64 register-argument and return-value rule.