参数入栈
寄存器:cpu中的变量
- esp:栈顶寄存器
- ebp:栈底寄存器
4字节整型参数入栈
顺序:从右往左,依次入栈
方式:使用寄存器push带入
8字节结构体参数入栈
顺序:从右往左,依次入栈
方式:使用寄存器push带入
struct Node
{
int _1;
int _2;
};
int fun1(struct Node a,struct Node b)
{
int c = 30;
return c;
}
int main()
{
struct Node a = { 10,20 };
struct Node b = { 20,30 };
fun1(a, b);
return 0;
}
12字节结构体参数
顺序:从右往左,依次入栈
方式:先在栈顶开辟足够该参数的空间,之后将数据复制进去。
注:C语言中只有参数字节数大于8字节才会采用此方式;C++中只要是自定义类型,无论多大字节都采用此方法
struct Node
{
int _1;
int _2;
int _3;
};
int fun1(struct Node a,struct Node b)
{
int c = 30;
return c;
}
int main()
{
struct Node a = { 10,20,30};
struct Node b = { 20,30,40};
fun1(a, b);
return 0;
}
函数栈帧开辟
- 1.将调用方函数下一行指令地址入栈
- 2.将调用方函数的栈底寄存器入栈
- 3.让ebp=esp:相当于将栈底上升到栈顶位置
- 4.让esp=esp - 0CC
- 5.将需要使用的寄存器入栈
- 6.循环将新开辟栈帧置为 cccc cccc
返回值返回
4字节返回值
方式:将返回值放入eax寄存器带回
8字节返回值
方式:将返回值放入2个寄存器带回
struct Node
{
int _1;
int _2;
};
struct Node fun1(struct Node a,struct Node b)
{
struct Node c = { 45,50 };
return c;
}
12字节返回值
C语言中返回值大于8字节都会以如下方式返回
C++中自定义类型都按如下方式返回
方式:
- 首先在函数参数入栈之后再入栈一个调用方栈帧上的地址(靠近栈顶的位置)
- 在返回值返回的时候,将返回数据写入到之前入栈的调用方栈帧地址上
- 返回后将从该地址上将数据取出
struct Node
{
int _1;
int _2;
int _3;
};
struct Node fun1(int a,int b)
{
struct Node c = { 45,50 ,60};
return c;
}
int main()
{
int a = 10;
int b = 20;
struct Node c = fun1(a, b);
return 0;
}
函数栈退出
- 进行当前函数栈帧的校验
- 将进行线程保护的寄存器出栈
- 让esp寄存器回到ebp寄存器的位置。即栈顶指向原栈底
- ebp=pop();栈底指针还原
- 将下一行指令的地址出栈
- 清除参数
fun函数栈帧回退
主函数栈帧回退