程序小白的c语言学习——函数栈帧的创建与销毁

前些阵子学的内容,拿出来作为复习,写一篇博客

一. 引入

前期学习c语言的时候,我们总是会有些困惑

  1. 局部变量是如何创建的?

  2. 为什么局部变量不初始化内容是随机的?

  3. 函数调用时参数时如何传递的?

  4. 传参的顺序是怎样的?

  5. 函数的形参和实参分别是怎样实例化的?

  6. 函数的返回值是如何带回的?

这些问题,当知道了函数的栈帧和销毁之后就可以解答了。


目录

一. 引入

二. 正文开始

2.1 使用的环境

2.2 寄存器的介绍

2.3 函数栈帧的创建

2.3.1 main 函数的创建

2.3.2 main函数中变量的创建

2.3.3 函数功能的实现

2.3.4 函数栈帧空间的销毁

2.3.5 形参的销毁,以及返回值的去处

三.解答开头的问题


二. 正文开始

2.1 使用的环境

对应函数栈帧的创建和销毁,不同编译器实现的过程不同,但大体逻辑是一样的

使用的环境是VS2013,不要使用太高级的编译器,越高级的编译器,越不容易学习和观察。

同时在不同的编译器下,函数调用过程中栈帧的创建是略有差异的,具体细节取决于编译器的实现。

2.2 寄存器的介绍

正如我笔记所写,eax 到 edx 都是一些普通的寄存器,用来存放值,不过多介绍

但是 下面的 ebp esp 就 稍稍不同了

ebp 栈低指针

esp 栈高指针

下面将用一张图片来引入

2.3 函数栈帧的创建

实际上,程序在运行的时候,main 函数并不是第一个运行的,它也是被其它函数调用的,如果你转到汇编的代码中,你就会发现main函数的调用前还有两个函数

这几个函数是一层层调用的,最终才到main函数

在main 函数的下方 也就是 我上述给的 函数的最上方,便是 寄存器 ebp 所在的位置,程序就从这里开始

每一个函数的创建都需要在栈区创建一个空间,那么这个空间的创建与 ebp esp 有很大的关系

2.3.1 main 函数的创建

1. 首先在这个函数的上方 push  压栈  ebp的值压在main函数的前置函数栈空间的上方

2.movesp的 值  放到刚刚创建的压栈空间中,

3. sub  因为栈区空间的创建从高地址到低地址,这里将 esp 的值减去 0E4H 相当于创建了空间

4.3个push,压入三个值,esp到了最顶。这三个压入的元素后续会弹出,不是很重要

5.这里就是相对重要的部分,将main函数栈顶的地址放入edi中

6.然后将从edi开始的39h的内容,以dword(double word)一个word两个字节,也就是4个字节的形式,用eax的内容进行替换,这就是这段的内容,最后的效果如下

ecx 放入的内容,在创建栈帧空间时,被用作一种计数器,用ecx的值的次数,放入ecx次eax的值

每个编译器里面放的内容不同,但总是会像这样对栈帧空间放东西进去,这就是为什么变量在使用的时候要进行初始化

2.3.2 main函数中变量的创建

注意看这里,a 是在ebp-8 的位置创建, 而 b 是在 ebp - 14h 的位置创建,隔了两个空间

2.3.3 函数的栈帧空间的创建

现在,我们说完了main函数的创建,那么现在来说一下函数栈帧的创建

注意一下左边的汇编代码

1.在函数的创建的首先,它将ebp-14h,ebp-8,也就是前面a,b变量放入eax,ecx中

然后将它们压到main函数的上面,这实际上是拷贝了前面的变量

2.随后它用了一条call指令,将call指令的下一条代码的地址放在ecx上,这有大用,后面将会讲到

3.call指令之后,进入函数的创建

4.进入函数的汇编代码,这里的代码类似main函数的栈帧创建,不过多说明了

2.3.3 函数功能的实现

然后这里有好几条汇编代码,

1.

z = x + y

1.这里,先把ebp - 8 也就是刚刚拷贝的 a 的值 10 放到 eax 寄存器中

2.然后,将 ebp - 12 的值,也就是 b 的值 加到 eax 寄存器中,

3.最后,就eax的值放到刚刚创建的 z 变量中

这样,就实现了函数的功能

4. return z  由于栈帧空间使用后会被销毁,于是将 z 的值 又返回到eax寄存器当中

5.最后,将刚刚创建的各种元素pop 弹出,准备销毁空间


2.3.4 函数栈帧空间的销毁

前面的元素弹出不重要,来看到代码的的第4行

1.将ebp的值赋给 esp ,这就使得esp到了ebp的位置,也就是回收了函数的栈帧空间

2.然后pop ebp ,ebp往下一格,到了ebp - main 的元素中,自然地回到了main函数的栈底

3.然后 ret,从之前存下的下一行的代码地址 回到了主函数中


2.3.5 形参的销毁,以及返回值的去处

1.将esp 加 8 ,相当于把形参给销毁掉,最后又回归到最初的形态

2.返回值 从 eax 中 放入之前创建的 变量 c 中,至此结束了整个函数

三.解答开头的问题

至此,完。

感谢观看

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值