千家信息网

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

发表于:2025-02-08 作者:千家信息网编辑
千家信息网最后更新 2025年02月08日,这篇文章主要为大家展示了"C语言函数栈帧如何创建和销毁",内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下"C语言函数栈帧如何创建和销毁"这篇文章吧。写在前面我们
千家信息网最后更新 2025年02月08日C语言函数栈帧如何创建和销毁

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

    写在前面

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

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

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

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

    #include 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+b        printf("%d\n", ret);        return 0;}

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

    可以看出,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函数的那个函数的栈帧已经开辟好了。

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

    Add函数的调用

    函数传参

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

    Add函数栈帧的创建

    首先将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函数栈帧的销毁

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

    main函数栈帧的销毁

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

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

    函数 地址 指令 指向 寄存器 空间 内容 紧接着 过程 语言 三个 代码 底部 篇文章 有效 位置 变量 同时 就是 思想 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 陕西时代网络技术服务资费 网络安全监督检查方案 服务器raid卡是干嘛的 王者日服为什么登不上服务器 亿速云香港服务器 我的世界怎样建造生存服务器 威海集成科技互联网公司地址 南京通用软件开发使用方法 html 上传到服务器打印 班级与学生关系的数据库 服务器如何找到用户电脑 思度软件开发 郑州it软件开发集中在哪个区 一元夺车软件开发公司 微算互联arm服务器 软件开发Java方向就业 db2删除数据库的语句 从化app软件开发费用 铜陵点餐系统软件开发定制 网络安全教育班会的主持词 网络安全码农有责任吗 江苏应用刀片服务器哪家好 吉林棋牌游戏软件开发 腾讯云服务器学生信息怎么填 腾讯云服务器几个人玩的传奇 数据库调整因子什么意思 病历数据库表的内容 服务器的超融合集成项目 穿井得人翻译软件开发 用友服务器怎么设置数据库
    0