函数栈帧的创建与销毁
1.寄存器
寄存器分为eax、ebx、ecx、edx、ebp、esp
其中ebp和esp这两个寄存器中存放的是地址,而其余的寄存器的作用是存储数据
esp和ebp的作用就是维护函数栈帧
esp是栈顶指针
ebp是栈底指针
每一个函数调用,都要在栈区创建一个空间
2.实例分析(汇编代码)
下面以一个程序段为例子
int Add(int x,int y)
{
int z=0;
z=x+y;
return z;
}
int main()
{
int a=0;
int b=20;
int c=0;
c=Add(a,b);
printf("%d\n",c);
return 0;
}
在VS2013中,按下F10进入调试,然后点击进入反汇编,就可以调出该程序的汇编代码
**压栈(push):**给栈顶放一个元素
**出栈(pop):**从栈顶删除一个元素
代码解析:
push ebp
mov ebp,esp
sub esp,0E4h
push ebx
push esi
push edi
lea edi,[ebp-0E4h]
mov ecx,39h
mov eax,0CCCCCCCCh
rep stos dword ptr es:[edi]
int a=10; dword ptr [ebp-8],0Ah
int b=20; dword ptr [ebp-14h],14h
int c=0; dword ptr [ebp-20h],0
Add函数的压栈与main函数的压栈同理,就是为了给Add函数申请空间, 这里就不再赘述
Add函数的执行汇编代码如下:
mov eax,dword ptr[ebp+8]
add eax,dword ptr [ebp+0Ch]
mov ptr [ebp-8],eax
1.返回return 把ebp-8的值放到eax里面,而eax是个寄存器,可以存储数据
2.然后开始pop,就是弹出,或者说是出栈
3.此时Add的空间就可以销毁了,直接将ebp的值给esp就可以把栈顶指针下移
4.pop ebp使其回到main函数里面,当我们回到main函数的时候,再把所要的值放到eax里面去
问题答疑
局部变量是如何创建的?
首先为函数分配好栈帧空间,栈帧空间里面先初始化一部分空间,然后给局部变量在栈帧里面分配一点空间
为什么局部变量的值是随机值
因为随机变量是我们放进去的,如图
如果局部变量初始化,其实就是将局部变量的随机值给覆盖掉
函数是怎么传参的?传参的顺序是怎样的?
当我们要调用函数时,在调用之前,我们就已经通过push将参数压栈进入栈帧,之后在add里,通过指针的偏移量找到之前的形参
形参和实参是什么关系?
*形参是我们在压栈的时候开辟的空间,它和实参只是值是相同的,但是空间是独立的。*改变形参不会影响实参
函数调用后是怎么返回的?
当函数调用完要返回的时候,弹出ebp,就能够找到上一个函数调用的ebp,接着指针会往下走回到栈帧空间,简单来说就是通过寄存器的方式带回
我们在压栈的时候开辟的空间,它和实参只是值是相同的,但是空间是独立的。*改变形参不会影响实参
函数调用后是怎么返回的?
当函数调用完要返回的时候,弹出ebp,就能够找到上一个函数调用的ebp,接着指针会往下走回到栈帧空间,简单来说就是通过寄存器的方式带回