浅谈函数调用过程(栈帧)
众所周知,计算机在编译或运行时,使用某个函数来完成相关命令。而函数之前则是相互调用的关系。
今天,我从栈空间的层面浅谈一下函数调用(栈帧)的具体过程,以加深对函数调用深层次的理解
。
接下来通过一个简单的程序来分析一下函数调用过程:
#include<stdio.h>
int Add(int, int);
int main()
{
int a = 5;
int b = 10;
int sum = 0;
sum = Add(a, b);
printf("%d\n", sum);
return 0;
}
int Add(int x, int y)
{
int ret = 0;
ret = x + y;
return ret;
}
首先来分析
main函数的调用,在编译器里通过调用堆栈不难查看到,
main函数是被
_tmainCRTStartup函数调用,而
_tmainCRTStartup则是被mainCRTStartup函数调用的。
每一次函数调用都是一个过程。这个过程称之为:函数的调用过程。
这个过程要为函数开辟栈空间,用于本次函数的调用中临时变量的保存、现场保护。
这块栈空间我们称之为函数栈帧。而栈帧的维护我们必须了解ebp和esp两个寄存器。在函数调用的过程中这两个寄存器存放了维护这个栈的栈底和栈顶指针。
如下图所示:
要详细研究函数调用过程,就要通过对应的汇编代码来分析。
1.从main函数开始
调用main函数,就为main函数创建栈帧,如下:
2.接下来就是Add函数的调用:
第一步参数传参过程:
第二步,来到指令call _Add (0D201E6h),执行
此时,通过监视可以发现内存中的变化:
第三步,Add函数内部执行代码:
第四步,Add函数返回部分:
以上即为一次完整的关于函数(Add)调用的过程。
我是在VS2013中进行栈帧观察的,不同的编译器可能存在些许差异,但是关于函数调用的思想是一致的。
了解函数调用过程(栈帧)中的具体步骤,能够加深我们对基础知识的充分理解和掌握,个人觉得还是挺有必要的。