调用规范
What happened in stack when a function is called?
#include <stdio.h>
int multiply(int a, int b) {
int multiplication = a * b;
return multiplication;
}
int main() {
int x = 5;
int y = 10;
int result = multiply(x, y);
printf("The result is: %d\n", result);
return 0;
}
compiled with:
Given that the ISA is 32bit x86:
- CALLER
push
the arguments into stack, from right to left. - CALLER
call
the target function, the%eip
is pushed into stack. - CALLEE
push
%ebp
into stack. - CALLEE sub
%esp
to reserve space for local variables and temporary variables. - CALLEE
leave
andret
,leave
->mov %ebp,%esp; pop %ebp;
. The%ebp
and%esp
of CALLER is restored.ret
->pop %eip
. The%eip
saved is restored.
- CALLEE add
%esp
to clear the space for argument passing.
int multiply(int a, int b) {
119d: 55 push %ebp
119e: 89 e5 mov %esp,%ebp
11a0: 83 ec 10 sub $0x10,%esp
11a3: e8 74 00 00 00 call 121c <__x86.get_pc_thunk.ax>
11a8: 05 30 2e 00 00 add $0x2e30,%eax
...
11ba: c9 leave
11bb: c3 ret
}
int result = multiply(x, y);
11e7: ff 75 f0 push -0x10(%ebp)
11ea: ff 75 ec push -0x14(%ebp)
11ed: e8 ab ff ff ff call 119d <multiply>
11f2: 83 c4 08 add $0x8,%esp
11f5: 89 45 f4 mov %eax,-0xc(%ebp)
We notice that there is a call to __x86.get_pc_thunk.ax
. The function is to transfer the contents of the %eip
register to the %eax
register. It is equivalent to mov %eip, %eax
.
This function is used in PIC (position independent code) on x86. It loads the location of %eip
into the %eax
register, thereby enabling access to the internal data of the module (such as global variables). The reason is that there is no instruction in the x86 instruction set to directly read %eip
.
What information does a function stack frame generally contain ?
- Return Address: The
call
instruction saves. This is the memory address of the instruction in the calling code where the program should resume execution after the function completes. When the function finishes, the CPU uses this address to transfer control back to the caller. - Parameters and Local Variables: The stack frame allocates space for the function's parameters (values passed from the CALLER) and local variables declared within the function (values created in CALLEE). These values are stored on the stack frame and can be accessed and modified by the function during its execution.
- Base Pointer: The base pointer (
%ebp
on x86 architectures) is a pointer that references the current stack frame's base address. It is useful for accessing local variables and function parameters through offsets from the base pointer. - Function State Information: (Not shown in the example code)Some additional information related to the function's state may be stored on the stack frame, such as callee-saved registers (registers whose values must be preserved across function calls) and other bookkeeping data.
C语言提供了稳定的ABI。C语言函数调用规范叫做
cdecl
,是被gcc, clang编译器默认被使用的。很多其他语言也依赖C语言的ABI和C编写的库进行交互。
还有其他的调用规范,如Pascal Call(stdcall
),fastcall
, linux system call...