浅谈函数调用过程(栈帧)

浅谈函数调用过程(栈帧)

众所周知,计算机在编译或运行时,使用某个函数来完成相关命令。而函数之前则是相互调用的关系。
今天,我从栈空间的层面浅谈一下函数调用(栈帧)的具体过程,以加深对函数调用深层次的理解
接下来通过一个简单的程序来分析一下函数调用过程:
#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中进行栈帧观察的,不同的编译器可能存在些许差异,但是关于函数调用的思想是一致的。
了解函数调用过程(栈帧)中的具体步骤,能够加深我们对基础知识的充分理解和掌握,个人觉得还是挺有必要的。


  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,我会尽力解答你的问题。 在C++中,函数调用栈帧原理可以简单概括为:每个函数在调用时都会在上分配一段空间,用于保存函数的局部变量、参数、返回地址等信息。这个空间称为栈帧,也叫活动记录。 下面是一个示例程序,用于说明函数调用栈帧原理和流程: ```c++ void foo(int a, int b) { int c = a + b; printf("%d\n", c); } int main() { int x = 10, y = 20; foo(x, y); return 0; } ``` 当程序运行到 `main` 函数时,首先会在上分配一段空间,用于保存 `main` 函数的局部变量和参数。在本例中,变量 `x` 和 `y` 就是 `main` 函数的局部变量,它们会被分配到栈帧的某个位置。同时,因为 `main` 函数调用了 `foo` 函数,所以还需要在上分配一段空间用于保存 `foo` 函数栈帧。 具体流程如下: 1. `main` 函数开始执行,将参数 `x` 和 `y` 压入中。 | 栈帧 | | :--------: | | 参数 y | | 参数 x | | 返回地址 | | 基址指针 | | 变量和参数 | 2. `main` 函数调用 `foo` 函数,将控制权转移到 `foo` 函数。 | 栈帧 | | :--------: | | 参数 y | | 参数 x | | 返回地址 | | 基址指针 | | 变量和参数 | | 返回地址 | | 基址指针 | | 变量和参数 | 3. `foo` 函数开始执行,将参数 `a` 和 `b` 压入中,并在栈帧中分配一个变量 `c`。 | 栈帧 | | :--------: | | 参数 y | | 参数 x | | 返回地址 | | 基址指针 | | 变量和参数 | | 返回地址 | | 基址指针 | | 参数 b | | 参数 a | | 返回地址 | | 基址指针 | | 变量和参数 | | 变量 c | 4. `foo` 函数执行完毕,将返回值 `c` 压入中,并将控制权返回给 `main` 函数。 | 栈帧 | | :--------: | | 参数 y | | 参数 x | | 返回地址 | | 基址指针 | | 变量和参数 | | 返回地址 | | 基址指针 | | 参数 b | | 参数 a | | 返回地址 | | 基址指针 | | 变量和参数 | | 变量 c | | 返回值 | 5. `main` 函数继续执行,弹出 `foo` 函数栈帧,并输出 `foo` 函数的返回值。 | 栈帧 | | :--------: | | 参数 y | | 参数 x | | 返回地址 | | 基址指针 | | 变量和参数 | | 返回地址 | | 基址指针 | | 变量和参数 | 6. `main` 函数执行完毕,弹出 `main` 函数栈帧,程序结束。 在上面的示例程序中,我们可以看到函数调用栈帧原理和流程。具体寄存器的变化因为不同的编译器实现不同,所以无法给出具体的答案。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值