目录
前言
相信大家在初学c语言时都有很多的点不是很清楚,比如为什么函数传参时形参改变不了实参,为什么代码会出现烫烫烫,局部变量是怎么创建的?等等问题,带着这些问题,我们今天来研究研究函数的栈帧创建于销毁。
一、寄存器
寄存器是集成于cpu上的独立存储空间。
我们想要了解函数的栈帧创建于销毁,得先了解一下部分寄存器的名称于功能。
eax,ebx,ecx,edx等是用于存储数据的寄存器
ebp,esp这两个寄存器是用来存放地址的,这2个地址是用于维护函数栈帧的。
当某个函数被调用时,esp和ebp就会来维护这个函数。
二、演示代码(c语言)
int add(int x, int y)
{
int z = 0;
z = x + y;
return z;
}
int main()
{
int a = 10;
int b = 20;
int c = 0;
c = Add(a, b);
return c;
}
我将对如上代码分析,带你理解函数栈帧
二、汇编逐一分析函数的创建
1.main函数空间的开辟
esp和ebp先维护调用main函数的函数
接下来开始调用main函数:
逐一分析这些汇编代码
1.将ebp的值压入栈顶
2.将esp赋给ebp的位置
3.将esp中的值减去0E4h,esp是指针,减去0E4h后得到一个新的地址(栈区中数据是由高地址到低地址开辟空间,所以esp往栈顶移动)
4.将ebx的值压入栈顶
5.将esi的值压入栈顶
6.将edi的值压入栈顶
7.lea(load effective address) 将(ebp-0E4h)的有效地址加载到edi去
8.将9赋给ecx
9.将0CCCCCCCCh赋给eax
10.从(ebp-0E4h)地址处开始的39h的dword(4字节)的所有的值改为0CCCCCCCCh
如下图:
2.局部变量的创建![](https://img-blog.csdnimg.cn/2d4ff3b5b91146dc90d842f9155341c5.png)
1.将0Ah赋给(ebp-8)的4个字节处
2.将14h赋给(ebp-14h)的4个字节处
3.将0赋给(ebp-20h)的4个字节处
3.Add函数的创建
3.1形参的创建![](https://img-blog.csdnimg.cn/0d89115a63fa4f6cbd2f40dd6afdf5bd.png)
1.将(ebp-14h)地址处的值赋给eax
2.栈顶压入eax
3.将(ebp-8)地址处的值赋给ecx
4.栈顶压入ecx
3.2Add函数空间开辟
这条指令是调用Add函数的
在栈顶压入00c2144B的下一条指令00c21450,以便调用完Add函数以后能够继续下一步操作
这接下来的操作和开辟main函数一样,类比即可。
3.3实现函数内功能
1.将(ebp-8)的值改为0
2.将x值 赋给eax
3.将y值与eax相加并赋给eax
4.将eax的值赋给(ebp-8)
5.将(ebp-8)的值赋给eax寄存器(因为ebp-8这块空间随着Add函数栈帧的销毁也会随之还给操作系统,所以需要用eax寄存器来保存z的值,使得返回main函数后能够使用z的值)
三、函数栈帧的销毁
1.弹出edi
2.弹出esi
3.弹出ebx
4.将ebp的值赋给esp
5.弹出ebp
最终回到了最初调用Add的状态。