文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

C语言函数栈帧如何创建和销毁

2023-06-29 05:19

关注

这篇文章主要为大家展示了“C语言函数栈帧如何创建和销毁”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“C语言函数栈帧如何创建和销毁”这篇文章吧。

写在前面

我们知道,每一次函数调用都需要在栈区上为其开辟一块空间,这块空间就叫做这个函数的栈帧。

而栈是从高地址向低地址延伸的。每个函数的每次调用,都有它自己独立的一个栈帧,这个栈帧中维持着所需要的各种信息。寄存器ebp指向当前的栈帧的底部(高地址),寄存器esp指向当前的栈帧的顶部(低地址)。

这样我们就了解了寄存器ebp和寄存器esp中存放的是地址,这两个地址是用来维护函数栈帧的。比如:调用main函数, 我们为main函数分配栈帧空间, 那么栈帧维护如下:

C语言函数栈帧如何创建和销毁

下面我们通过一段代码分析一下,函数栈帧创建和销毁的过程:(栈帧这部分内容在不同的编译器上实现存在差异, 但是思想大致都是一致的。本文是在vs2013编译器下实现的。)

#include <stdio.h>int Add(int x, int y){int z = 0;z = x + y;return z;}int main(void){int a = 10;int b = 20;int ret = 0;ret = Add(a, b);//计算a+bprintf("%d\n", ret);return 0;}

我们在调试过程打开调用堆栈

C语言函数栈帧如何创建和销毁

可以看出,main函数是在__tmainCRTStartup函数内部被调用的,而__tmainCRTStartup函数又是在mainCRTStartup函数内部调用的。

为了能更加清楚的看到栈帧创建和销毁的过程,我们转到上面代码对应的反汇编代码:

int main(void){009D3F40  push        ebp  //将edp压入栈帧009D3F41  mov         ebp,esp  //将esp的值赋给edp009D3F43  sub         esp,0E4h  //esp-0E4h009D3F49  push        ebx  009D3F4A  push        esi  009D3F4B  push        edi  009D3F4C  lea         edi,[ebp+FFFFFF1Ch]  009D3F52  mov         ecx,39h  009D3F57  mov         eax,0CCCCCCCCh  009D3F5C  rep stos    dword ptr es:[edi]  int a = 10;009D3F5E  mov         dword ptr [ebp-8],0Ah  int b = 20;009D3F65  mov         dword ptr [ebp-14h],14h  int ret = 0;009D3F6C  mov         dword ptr [ebp-20h],0  ret = Add(a, b);//计算a+b009D3F73  mov         eax,dword ptr [ebp-14h]  009D3F76  push        eax  009D3F77  mov         ecx,dword ptr [ebp-8]  009D3F7A  push        ecx  009D3F7B  call        009D11F9  009D3F80  add         esp,8  009D3F83  mov         dword ptr [ebp-20h],eax  printf("%d\n", ret);009D3F86  mov         esi,esp  009D3F88  mov         eax,dword ptr [ebp-20h]  009D3F8B  push        eax  009D3F8C  push        9D5860h  009D3F91  call        dword ptr ds:[009D9118h]  009D3F97  add         esp,8  009D3F9A  cmp         esi,esp  009D3F9C  call        009D1140  return 0;009D3FA1  xor         eax,eax  }009D3FA3  pop         edi  009D3FA4  pop         esi  009D3FA5  pop         ebx  009D3FA6  add         esp,0E4h  009D3FAC  cmp         ebp,esp  009D3FAE  call        009D1140  009D3FB3  mov         esp,ebp  009D3FB5  pop         ebp  009D3FB6  ret

main函数的调用 main函数栈帧的创建

经过刚才我们的理解,在准备调用main函数的时候,调用main函数的那个函数的栈帧已经开辟好了。

C语言函数栈帧如何创建和销毁

然后将ebp压入栈帧,保存了指向栈底的ebp的地址,而此时esp指向新的栈顶位置;接着将esp的值赋给了ebp,产生了新的ebp;用esp减去一个16进制数0E4H(这里就是为main函数预开辟空间)。紧接着三个压栈指令,分别将ebx,esi,edi,压入栈帧。加载完有效地址以后,将为main函数预开辟空间全部初始化为0xCCCCCCCC。最后创建了三个局部变量a,b,ret并进行了初始化。

Add函数的调用

函数传参

C语言函数栈帧如何创建和销毁

将b的值存入寄存器eax中,再将eax压入栈中;将a的值存入寄存器ecx中,再将将ecx压入栈中;这里看出参数是从右向左传递的。紧接着执行call指令,这里就是调用Add函数,同时将call指令的下一条指令的地址压入栈中,然后执行call指令的时候按F11 , 就进入了Add函数内部。

Add函数栈帧的创建

C语言函数栈帧如何创建和销毁

首先将main()函数的ebp压入栈,保存指向main()函数栈帧底部的ebp的地址,此时esp指向新的栈顶位置;将esp的值赋给ebp,产生新的ebp,即Add()函数栈帧的ebp;给esp减去一个16进制数0E4H,这里是为Add()函数预开辟空间;紧接着三个压栈指令,分别将ebx,esi,edi,压入栈帧。加载完有效地址以后,将为Add函数预开辟空间全部初始化0xCCCCCCCC。在紧接着创建了变量z,将形参的a和b相加的结果存储到z中;最后将结果存储到eax寄存器中,通过寄存器带回了函数的返回值。

Add函数栈帧的销毁

C语言函数栈帧如何创建和销毁

edi、esi、ebx依次出栈,esp 会向下移动;然后将ebp的值赋给esp,使esp指向ebp指向的地方;接着ebp 出栈,同时将出栈的内容给ebp,此时ebp又指向了main函数栈帧的底部,最后执行ret 指令,表示出栈一次,并跳转到出栈的内容的地址处,也就是call指令的下一条指令处。

main函数栈帧的销毁

C语言函数栈帧如何创建和销毁

main函数栈帧的销毁和Add函数栈帧销毁的过程的思想都是一样的,这里就不做多赘述了。

以上是“C语言函数栈帧如何创建和销毁”这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注编程网行业资讯频道!

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     801人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     348人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     311人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     432人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     220人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯