x86 Calling Conventions: cdecl vs stdcall
A calling convention is the contract between a caller and a callee that answers two questions:
- How are arguments passed?
- Who cleans up the arguments after the function returns?
In almost all x86 conventions, arguments are pushed onto the stack right-to-left (the last argument is pushed first). The return value is placed in eax.
cdecl (C declaration)
- The default for most C code on x86.
- The caller is responsible for cleaning up the stack.
- Look for
add esp, XXimmediately after thecall.
push 3
push 2
push 1
call foo
add esp, 0Ch ; caller cleans up 3 args * 4 bytes
stdcall (standard call)
- Common for many Windows APIs (
win32functions). - The callee is responsible for cleaning up the stack.
- Look for
retn XXinside the called function.
push 3
push 2
push 1
call foo
; no cleanup here
; inside foo:
retn 0Ch ; callee cleans up 3 args * 4 bytes
Reading a function call in assembly
Because arguments are pushed right-to-left, the first push before the call is the last argument of the C function, and the last push before the call is the first argument.
For memset(void *s, int c, size_t n):
push 104h ; size_t n
push esi ; int c
push eax ; void *s
call _memset
add esp, 0Ch ; confirms cdecl
This corresponds to memset(eax, esi, 0x104).
Why this matters
Calling conventions are the key to translating a list of push instructions into a real function call. Without knowing the convention, the pushes are just numbers; with it, they become named arguments in the correct order.
Key takeaways
| Convention | Argument order | Who cleans up | Stack cleanup |
|---|---|---|---|
| cdecl | Right-to-left | Caller | add esp, XX after call |
| stdcall | Right-to-left | Callee | retn XX inside function |
- Return value is always in
eaxfor both conventions (for 32-bit integer/pointer returns). add esp, 0Chmeans 3 × 4 byte arguments were passed (12 = 0xC).retn 0Chmeans the same, but the function cleans up for itself.