程序员内功修炼——函数栈帧的创建与销毁

一.什么是函数的栈帧

c语言是由函数构成的,那么函数是如何进行传参的?如何调用的?如何返回值的?这些问题与函数的栈帧有关。
函数栈帧:就是函数调用过程中程序的调用栈所开辟的空间,这些空间用来存放:
1.函数参数和返回值
2.临时变量
3.保存上下文信息

二.内存分布

要想明白函数怎么调用内存的,首先得知道内存的分布,如图:
在这里插入图片描述
知道了内存的分布,下面让我们认识寄存器ebp和esp。
在这里插入图片描述

ebp esp这2个寄存器是用来存放地址的,同时维护函数的栈帧。每一个函数的创建都要用到函数的栈帧。

三.函数栈帧创建的原理

我们先从一个简单的代码看起

#include<stdio.h>
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);
	printf("%d\n", c);
	return 0;
}

这是一个简单的计算两数之和的代码,他是怎么运行的呢?首先程序进入main函数,函数的调用都会在栈区上开辟一块内存空间。
esp:栈指针寄存器,其内存放着一个指针,该指针永远指向栈顶
ebp:内存也放着一个指针,指向栈低。

在这里插入图片描述
通过调试我们发现函数在创建main函数之前会调用二个函数
在这里插入图片描述
我们去找到这二个函数
在这里插入图片描述
在这里插入图片描述
通过调试我们发现 _tmain函数——>maincr——>main形成这样的调用逻辑关系。main函数开辟空间的时候会先调用前面二个函数,那么调用前二个函数有什么意义呢?
在开始调用前二个函数时候内存也会为它们开辟新的空间
在这里插入图片描述
我们转到反汇编上,从最底层看看是怎么创建出空间的。
在这里插入图片描述
这就是上述代码在反汇编下的运行逻辑。我们一步步的分析
在这里插入图片描述
开始时栈区如上图所示,接着我们看反汇编第一条指令,push意思是压栈
在这里插入图片描述
运行完第一条指令其结果如下
在这里插入图片描述
第二条指令mov ,意思是把esp的值给ebp
在这里插入图片描述
第三条指令sun,意思是给esp的值减上0E4h;esp是地址地址由高到底,减上一个数相当于把esp上移。
在这里插入图片描述
上述黄色部分就是main函数开辟的空间
在这里插入图片描述
第4,5,6条指令都是push压栈,3次push给顶上压元素。
在这里插入图片描述
第7,8,9行指令指把main函数空间全部初识化为cccc
在这里插入图片描述
这也充分的说明了如果不给局部变量初始化那么其存的是一个随机的值,所以在定义变量的时候一定要给变量初始化。
到目前为止,程序执行的准备工作已经结束,接下来是程序运行阶段我们继续看反汇编
在这里插入图片描述
这条指令的意思是把ebp的地址向上移8,同时放入值0ah(10进制为10)
在这里插入图片描述
同理接下来的指令把20放入内存中
在这里插入图片描述
到这里main函数内部的变量已经定义完成,接下来进入Add函数内部去看看函数是如何进行传参的。
在这里插入图片描述
第1,2,3条指令说明把ebp-14h放到eax,如何push压栈,接着找到main函数里面放20的地址,把20的地址放到eax,相当于eax里面放了20,同理ecx里面放入10。
在这里插入图片描述
然后到达call指令,call指令把下一条指令的地址存下,因为进入函数内部实现函数功能,等函数结束后会找到原来函数外部的地址,接着运行代码。

在这里插入图片描述
和main函数一样前面都是add函数的准备阶段接着要进入add函数内部了。
在这里插入图片描述
前面和main函数做法类似不在说明
在这里插入图片描述
首先把ebp-8的值放入eax,相当于eax里面放了10,接着ebp+0ch相当于把ebp+12的值放入eax,eax变为30,加起来后把eax放入ebp减8里面,把30放入ebp-8。接着返回call指令保存的地址。

总结:局部变量怎么创建的?
首先为函数开辟一块空间,再在空间里面为我的局部变量开辟一块小空间。
形参和实参怎么样的?
形参只是形参的一份临时拷贝,二者的空间不同。改变形参不影响实参。
函数调用结果怎么返回的?
通过call指令保存原来的地址,等函数调用结束后返回地址

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值