【18.7.27】函数调用过程的深度理解(栈帧)

版权声明:Oce2ns的大板 https://blog.csdn.net/weixin_39392653/article/details/81265889
函数可以大大减少我们程序的代码量,使代码写起来更加的简洁,使代码思路更加清晰。是我们程序猿在编写代码时必不可少的。
那么函数的调用过程就非常的重要,今天让我们来从一个深的角度去了解一下函数的调用过程。

函数的调用过程也可以叫做栈帧

栈帧的定义是:栈帧也叫过程活动记录,是编译器用来实现过程/函数调用的一种数据结构。
每一次函数的调用,都会在内存中为自己申请一块空间,这个空间就叫函数运行时堆栈,也就是栈帧。这里写图片描述
这块空间就像栈一样,都需要去维护,栈顶又寄存器ESP去维护,栈底呢就又寄存器EBP去维护。
接下来我们写一个简单的代码,去更加具体的了解我们的函数调用过程。
#include<stdio.h>
int main()
{
    int i = 20;
    int j = 30;
    int k = 0;
    k = Add(i,j);
    printf("%d\n",k);
    return 0;
}
int Add(int x,int y)
{//主函数调用Add函数去实现加法的功能
    int z = 0;
    z = x + y;
    return z;
}
打开调试,进入调用堆栈,看看函数的调用逻辑。这里写图片描述
根据内存中栈的特点是由低到高,我们看出,main函数是被mainCRTStartup函数调用。打开反汇编代码。在进去main函数到开始我们的代码前有这样一段反汇编代码。

这里写图片描述

我们把这段反汇编代码用图像形象的描述一下。这里写图片描述
我们把E4转化成十进制,就是228,也就是说,把EBP-228的位置的地址给EDI,然后从EDI开始向高地址存放CCCCCCCC,一次4个字节,存放39次,十进制的57次,大小正好也是228.就是把这E4的空间大小,放57个CCCCCC进去,每个4字节。这里写图片描述
看一下内存,我们看一下这样的结果,是不是我们所说的样子

这里写图片描述

然后我们接着看反汇编代码

这里写图片描述

继续画图

这里写图片描述

进入CALL指令,我们就进入的Add函数的内部

这里写图片描述

我们发现和调用main函数前,的准备工作几乎是一致的。那就说明刚才main函数开始前的操作,是开辟函数空间时的准备工作。

这里写图片描述
这里写图片描述

从进入Add函数,为Add函数开辟了一块空间,然后一顿操作,然后弹弹弹,就是将Add函数进行销毁,这就是Add函数栈帧的销毁。

这里写图片描述

当Add函数执行完成以后,全部被弹出,ESP和EBP寄存器存储的地址指向同一块地区,执行EBP–main,把EBP直接弹回main函数中他需要维护的地方。EBP就继续维护他的main函数去了。那我们就不难想,在main函数开始时,存的EBP就是为了,在main函数结束后,返回mainCRT函数中去,让EBP继续去维护mainCRT函数。然后call指令,将我们继续带回,刚才的的地方,完成下面的指令。走到这里。一个函数的完整调用也就结束了。

猜你喜欢

转载自blog.csdn.net/weixin_39392653/article/details/81265889