函数调用过程
寄存器:cpu 中的变量
esp:栈顶寄存器
ebp:栈顶寄存器
struct Node
{
int _1;
int _2;
int _3;
};
struct Node _cdecl fun(int a,int b)
{
int c=30;
//c=a+b;
struct Node c={10,20};
return c;
}
int main()
{
int a=10;
int b=20;
int c;
//struct Node a={10,20,30};
//struct Node b={40,50,60};
struct Node c=fun(a,b);
return 0;
}
-
参数入栈
4字节参数入栈;
顺序:从右向左;
方式:使用寄存器push带入;操作数据是通过CPU进行操作, 入栈顺序:从b地址中取dword 4字节放到eax寄存器中; move 取值; push入栈;
8字节参数入栈;
顺序:从右向左;
方式: 使用寄存器push 带入
12字节参数入栈
sub 减 //esp=esp-0c;
顺序:从右向左;
方式:先在栈顶开辟足够该参数的空间,之后将数据赋值进去;
C++中只要是自定义类型,无论多大字节,都采用先开辟空间,之后赋值的方式。
- 函数栈帧开辟
将调用方函数下一行指令地址入栈;
将调用方函数的栈底寄存器入栈;
让ebp=esp;
让esp=esp-***;
将其他使用的寄存器入栈;
将新开辟的栈帧空间中全部写为cccc cccc;
- 返回值返回
4字节返回值
方式:将返回值放入寄存器带回;
8字节返回值
方式:将返回值放在两个寄存器,带回
12字节返回值
方式:首先在函数参数入栈之后,入栈一个调用方栈帧上的地址(靠近栈顶位置);
在函数值返回的时候,将返回数据写入到之前入栈的地方地址上;
返回之后,将从该地址上将数据取出;
C++中,自定义类型都按照入栈调用方地址的方式。
- 函数栈退出
进行当前函数栈帧的校验;
将线程保护的寄存器出栈;
让esp=ebp;
ebp=pop;
将下一行指令的地址还原;
清楚参数。
当前演示的函数调用过程依赖于c语言默认的调用约定 _cdecl;
还有其他调用约定: _stdcall
_fastcall