80x86 Calling Convention
This section summarizes important points of the convention used for normal function calls on 32-bit 80x86 implementations of Unix. Some details are omitted for brevity. For a description of the x86 registers, please see here.
Calling a Function
The calling convention works like this:
- The caller pushes each of the function’s arguments on the stack one by one, normally using the
pushx86 instruction. Arguments are pushed in right-to-left order. The stack grows downward: eachpushdecrements the stack pointer, then stores into the location it now points to, like the C expression*--esp = value. - The caller pushes the address of its next instruction (the return address) on the stack and jumps to the first instruction of the callee. A single 80x86 instruction,
call, does both. - The callee executes. When it takes control, the stack pointer points to the return address, the first argument is just above it, the second argument is just above the first argument, and so on.
- If the callee has a return value, it stores it into register
eax. - The callee returns by popping the return address from the stack and jumping to the location it specifies, using the x86
retinstruction. - The caller pops the arguments off the stack, normally using the
popx86 instruction. Thepopis the exact opposite of apushas it reads the value from the location the stack pointer is referring to and increments it afterwards, like the C expressionvalue = *esp++.
Consider a function f that takes three int arguments. This diagram shows a sample stack frame as seen by the callee at the beginning of step 3 above, supposing that f is invoked as f(1, 2, 3). The initial stack address is arbitrary:
+----------------+
0xbffffe7c | 3 |
0xbffffe78 | 2 |
0xbffffe74 | 1 |
stack pointer --> 0xbffffe70 | return address |
+----------------+
The Called Function
Based on the above, the called function follows a certain structure as well that ensures accessing the arguments that were passed by the caller, etc. Here is what is happening in any called function:
- The prolog code pushes
%ebpto the stack using thepush %ebpx86 instruction. - The current value of the stack pointer
%espis stored in%ebp, the stack base pointer. All subsequent operations involving the function local stack segment will be performed relatively to%ebp. - The stack pointer
%espis adjusted as needed by function local operations (allocate function local variables, call other functions, etc.) - Other operations specific to the function are performed.
- The last operation before returning from the function executes a
leavex86 instruction, which restores the value of the stack pointer%espfrom%ebpand pops the previous value of%ebpfrom the stack. - The function executes the
retinstruction to return to its caller.
This shows the stack layout after executing a function prolog:
+----------------+
0xbffffe7c | 3 |
0xbffffe78 | 2 |
0xbffffe74 | 1 |
0xbffffe70 | return address |
+----------------+
stack pointer --> 0xbffffe6c | previous ebp | <-- ebp points here as well
+----------------+
Such a layout allows for accessing the function arguments relatively to %ebp, which has the value of 0xbffffe6c in the case shown above. For instance, loading the second argument (the 2) into %eax looks like: mov 0xc(%ebp),%eax (add 12 to %ebp and use the result as the pointer to the memory location the value should be loaded from).