函数栈帧的创建和销毁(C语言)

news2024/9/24 7:19:57

函数栈帧的创建和销毁(C语言)

  • 前言
  • 主体

前言

函数栈帧是一个非常重要的概念,是重点也是难点,当然涉及底层方面的知识都会很难,但是对我们理解函数的创建和运用有非常重要的作用。本篇博客的目的就是了解函数栈帧的创建和销毁过程,以及帮助我们细化下面几个问题:

  • 局部变量的怎么创建?
  • 局部变量的值不初始化为什么是随机值?
  • 函数如何传参?
  • 形参与实参是怎样的关系?
  • 函数调用是怎样做的?
  • 函数调用怎样返回?

所以这次的博客能看完读懂肯定收获满满。(采用C语言和VS2013编译器讲解)

主体

在学函数栈帧之前我们需要简单介绍一下栈的概念:栈是一种数据结构,特点就是先进后出,什么意思呢?举一个例子:我们将1,2,3分别先后入栈,那么拿出栈只能先出3,再出2,最后出1。学习函数栈帧我们需要着重介绍ebp和esp这两个寄存器,这两个寄存器中存放的是地址,这两个地址是用来维护函数栈帧的。我们举个例子:

#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()函数时会为main()函数开辟main()函数栈帧,此时esp和ebp指针维护main()函数栈帧,当main()函数调用Add()函数时,操作系统又会为Add()函数开辟函数栈帧,此时esp和ebp指针又会维护Add()函数栈帧。
在这里插入图片描述
了解完esp和ebp指针我们进入正题,代码还是采用上面的代码,其实在编译器VS2013中,main()函数也是被调用的。在整个过程中是mainCRTStartup()函数调用_tmainCRTStartup()函数再然后__tmainCRTStartup()调用main()函数,main()函数在调用Add()函数也就是说栈空间应该是这样分配的。
在这里插入图片描述
细心的同学已经注意到了栈帧之间存在这空隙,这些空隙是用来干什么的呢?我们打开此代码的反汇编。
在这里插入图片描述
序号①~序号⑥都是为开辟main()函数栈帧做准备,上面我们讲过调用main()函数之前就开辟过了_tmainCRTStartup()函数栈帧,而序号①代码的意思是将ebp压入栈,我们知道ebp栈底指针,存放的是地址,也就是将ebp的值存入栈中(esp永远指向栈顶)。如图:
在这里插入图片描述
序号②代码的意思是将esp的值赋值给ebp,也就是说ebp和esp的值相同,指向用一个位置。如图:
在这里插入图片描述
序号③代码的意思是:esp减去0E4H(H表示16进制),函数栈帧是从高地址到低地址使用的,从图上来看就是esp指针往上移动,而这时候的esp到ebp就是为main()函数开辟的函数栈帧,如图:
在这里插入图片描述
序号④~⑥代码的意思是:将ebx、esi、edi压入栈中,esp(栈顶指针)也随之移动,如图:
在这里插入图片描述
完成了上面的操作,我们接下来再看反汇编代码:
在这里插入图片描述
红框框代码比较难以理解,简单来讲就是将为main()函数开辟的函数栈帧空间全部赋值为cccccccc,也就是初始化操作,如图:
在这里插入图片描述
当一切准备就绪,可以说也就完成了main()函数栈帧的所有准备工作,我们再看分汇编代码:
在这里插入图片描述
序号①~序号②分别代表着:在ebp-8的位置放入10(16进制0Ah),在ebp-14h的位置放入20(16进制14h),在ebp-20h的位置放入0,如图(左图:概念图,右图:内存图):
在这里插入图片描述
接下来,我们再看反汇编代码:
在这里插入图片描述

序号①代码的意思是将ebp-14h地址的值放到eax中去,我们回头来看ebp-14h中存放的就是b的值(20),也就是将20赋值给eax;序号②代码的意思是将eax压入栈中,同理序号③和序号④也是将(10)放入ecx中,再将ecx压入栈中,这就是实参的传参和形参的创建。如图所示:
在这里插入图片描述
序号⑤中call指令是将下一条指令的地址(00C21450)压入栈中,如图所示:(至于为什么这么做,我们接着往下看)
在这里插入图片描述
接下来就是就是调用add()函数
在这里插入图片描述
红框框中的代码就是为Add()函数开辟栈帧,我们就不再赘述。如图:
在这里插入图片描述
序号①代码的意思就是将0放入ebp-8(z)的位置,序号②代码的意思就是将ebp+8中的内容(10),也就是形参x,和ebp+0Ch(ebp+12)中的内容(20),也就是形参y,相加得到30再放到eax中去,最后将eax的值赋值给ebp-8的位置(也就是z)。如图所示:
在这里插入图片描述
序号③中的代码意思是将ebp-8(z)中的值存放再eax寄存器中(为了返回z的值),这时候我们再看反汇编:
在这里插入图片描述
红框框中表示依次弹出edi,esi,ebx,代码①表示将ebp的值赋值给esp,也就是将Add()内容释放掉,如图所示:
在这里插入图片描述
序号②代码表示弹出栈顶元素,并存放到ebp中,我们知道此时的栈顶存的是main()函数栈帧底的地址,因此此时ebp就可以回到main()函数的栈底,如图所示:
在这里插入图片描述
序号③中ret指令表示的是return并弹出栈顶,也就是返回到原来main()函数执行的位置,而因为调用过Add()函数,编译器并不知道main()函数原来的执行到哪呢,此时的ret指令就是解决这个问题,此时栈顶就是下一条指令的地址(00C21450),这也回答了我们上面设下的悬念。如图所示:
在这里插入图片描述
这时我们再看反汇编代码:
在这里插入图片描述
序号①代码表示:esp的地址加上8,也就是说,esp往下移2个整型,即销毁形参x和y。序号②则表示将eax中的值(z传回来的30)传到ebp-20h中(c)如图所示:
在这里插入图片描述
红框框则表示调用了printf()函数,当然也需要栈帧创建销毁返回等过程,最后就是main()函数的销毁,原理与Add()函数的销毁一样,这里也就不再赘述。那么有关函数栈帧的创建和销毁就全部讲解完了。
现在我们再回头看那几个问题:

  • 局部变量的怎么创建?
  • 局部变量的值不初始化为什么是随机值?
  • 函数如何传参?
  • 形参与实参是怎样的关系?
  • 函数调用是怎样做的?
  • 函数调用怎样返回?

这几个问题是不是都能够回答了。
局部变量的创建:首先我们为这个函数分配好栈帧空间,初始化一部分空间之后,在这栈帧空间给局部变量分配一定的空间。
局部变量不初始化是随机值:因为随机值是编译器放进去的(VS2013是cccccccc),如果初始化,就会把随机值覆盖掉。
函数如何传参:在没有调用函数的时候,就已经将两个参数放入栈中了,并且是从右向左压栈,并且可以通过esp指针的偏移量找回形参。
形参和实参的关系:形参是在压栈时开辟的空间,它和实参只是值是相同的,空间是独立的,形参是实参的一份临时拷贝,形参不会影响实参(只是数值上不会影响)。
函数调用与函数返回:上面也已经详细介绍了,主要要注意函数的返回,特别是call指令的作用。
如果看到这里,先给自己鼓个掌吧,这部分处于底层,非常的抽象,因此晦涩难懂,当然如果搞懂带来的好处也是非常大的,如果有什么问题,或者建议也非常希望留言告诉我,谢谢大家了!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/340852.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

go 命令行工具整理

这里会整理可能会使用到的命令行参数&#xff0c;比如 go build、go run&#xff0c;诸如此类。了解这些内容对我们工作会有什么帮助吗&#xff1f;更多的时候&#xff0c;是能让我们理解代码编译的意图&#xff0c;或者&#xff0c;给我们一种排查问题的手段。 比方说&#x…

电子学会2022年12月青少年软件编程(图形化)等级考试试卷(一级)答案解析

目录 一、单选题(共25题&#xff0c;共50分) 二、判断题(共10题&#xff0c;共20分) 三、编程题(共2题&#xff0c;共30分) 青少年软件编程&#xff08;图形化&#xff09;等级考试试卷&#xff08;一级&#xff09; 一、单选题(共25题&#xff0c;共50分) 1. 小明想在开始…

【博学谷学习记录】超强总结,用心分享 | 架构师 Spring源码学习总结

文章目录Spring的循环依赖1.循环依赖的定义&&原因2.循环依赖的场景1.构造器注入引起循环依赖2.Field属性setter注入的循环依赖3.循环依赖解决思路4.三级缓存5.面试题[三级缓存]AOP源码深度剖析概述Spring AOP的前世今生实现机制**JDK 动态代理****CGLIB 代理**流程总结…

六十分之十三——黎明前

目录一、目标二、计划三、完成情况四、提升改进(最少3点)五、意外之喜(最少2点)六、总结一、目标 明确可落地&#xff0c;对于自身执行完成需要一定的努力才可以完成的 1.8本技术管理书籍阅读(使用番茄、快速阅读、最后输出思维导图)2.吴军系列硅谷来信1听书、香帅的北大金融…

成都哪家机构的Java培训比较好,求一个不坑的?

关于这个问题&#xff0c;相信你会得到很多条答案&#xff0c;以及很多家机构的自荐。既然如此&#xff0c;不如也了解一下老牌IT职业教育机构&#xff1a;有足够丰富的教学经验&#xff0c;丰富的教学产品资源以及成熟的就业保障体系&#xff0c;还有就是承担风险的能力。 很…

计算机网络7:传输层相关

目录1-传输层1.1 UDP 和 TCP 的特点1.1.1 UDP用户数据报格式1.1.2 TCP首部格式1.1.2.1 常用端口号1.2 TCP的三次握手1.2.1 三次握手的原因1.3 TCP四次挥手1.3.1 四次挥手的原因1.3.2 TIME_WAIT为什么是2MSL1.4 TCP的可靠传输有效机制1.4.1 TCP可靠传输-超时重传1.4.2 TCP流量控…

封装、继承、Super、重写、多态instanceof类型转换的使用以及个人见解

这里写目录标题封装继承supersuper和this的区别重写多态instanceof类型转换封装 之前我们调用共有的属性&#xff0c;是直接可以调用的 但是属性私有后&#xff0c;无法在直接.调用 只能通过getset调用 继承 super 可以直接调用父类中属性和方法&#xff0c;私有的无法做 其…

TCP详解及面试相关问题

文章目录1、计算机模型2、客户端和服务端通信——TCP协议&#xff08;1&#xff09;socket套接字&#xff08;2&#xff09;TCP三次握手——创建socket&#xff08;3&#xff09;连接的本质&#xff08;4&#xff09;TCP四次挥手——释放socket资源&#xff08;5&#xff09;TC…

如何用PHP实现消息推送

什么是消息推送 通过服务器自动推送消息到客户端(浏览器&#xff0c;APP&#xff0c;微信)的应用技术。 2. 为什么要使用消息推送技术 通常情况下都是用户发送请求浏览器显示用户需要的信息。推送技术通过自动传送信息给用户&#xff0c;来减少用于网络上搜索的时间。它根据…

SSH 服务详解 (八)-- vscode 通过 SSH 远程连接 linux 服务器

vscode 通过 SSH 远程连接 linux 服务器 SSH服务详解(一)–Linux SSH 服务器与客户端的安装与启动 SSH服务详解(二)–使用私钥登录 SSH 服务器(免密登录) SSH 服务详解 (三)-- 使用 SSH 代理 SSH 服务详解 (四)-- 本地调用远程主机的命令 SSH 服务详解 (五)-- 远程文件拷贝…

零信任-微软零信任介绍(2)

微软零信任是什么&#xff1f; Microsoft Zero Trust 是一种安全架构&#xff0c;旨在在没有信任任何设备、用户或网络的情况下保护网络。这种架构使用多重验证和分段技术&#xff0c;以确保每个请求和资源的安全性。 零信任不假定任何内部用户或设备是安全的&#xff…

硬件工程师入门基础知识(一)基础元器件认识(一)

硬件工程师入门基础知识 &#xff08;一&#xff09;基础元器件认识&#xff08;一&#xff09; 今天水一篇hhh。介绍点基础但是实用的东西。 tips&#xff1a;学习资料和数据来自《硬件工程师炼成之路》、百度百科、网上资料。 1.贴片电阻 2.电容 3.电感 4.磁珠 1.贴片电…

Android 基础知识4-2.4程序签名打包

Android APP都需要我们用一个证书对应用进行数字签名&#xff0c;不然的话是无法安装到Android手机上的&#xff0c;平时我们调试运行时到手机上时&#xff0c;是AS会自动用默认的密钥和证书来进行签名&#xff1b;但是我们实际发布编译时&#xff0c;则不会自动签名&#xff0…

IDEA设置只格式化本次迭代变更的代码

趁着上海梅雨季节&#xff0c;周末狠狠更新一下。平常工作在CR的时候&#xff0c;经常发现会有新同事出现大量代码变更行..一看原因竟是在格式化代码时把历史代码也格式化掉了这样不仅坑了自己&#xff08;覆盖率问题等&#xff09;&#xff0c;也可能会影响原始代码责任到人&a…

python 字典的概念叙述和使用方法

文章目录1. 一个简单的字典2. 使用字典2.1 访问字典中的值2.2 添加键-值对2.3 修改字典中的值2.4 删除键-值对3. 遍历字典3.1 遍历所有键-值对3.2 遍历字典中的所有键3.3 按顺序遍历字典中的所有键3.4 遍历字典中的所有值4.嵌套4.1 字典列表4.2 range() 函数4.3 在字典中存储列…

Java中导入、导出Excel——HSSFWorkbook 使用

一、介绍 当前B/S模式已成为应用开发的主流&#xff0c;而在企业办公系统中&#xff0c;常常有客户这样子要求&#xff1a;你要把我们的报表直接用Excel打开(电信系统、银行系统)。或者是&#xff1a;我们已经习惯用Excel打印。这样在我们实际的开发中&#xff0c;很多时候需要…

自动化测试岗位求职简历编写规范+注意事项,让你的简历脱颖而出

目录 前言 1.个人信息 2.教育背景(写最高学历) 3.个人技能(按精通/掌握/熟练/了解层次来写) 4.工作经历 5.工作经验/项目经历 6.自我评价 总结 前言 挑选一个阅读舒适度不错的模板 HR和面试官看的简历多&#xff0c;都是快速阅读&#xff0c;舒适度特别重要&#xff1b…

ctfshow 每周大挑战 极限命令执行

《简单的命令执行题目》 这里感叹一下&#xff0c;g4佬是真好厉害&#xff0c;这次题目十分的难&#xff0c;嗯&#xff0c;对我这种菜鸡来说是这样的&#xff0c;想了一天&#xff0c;最后结束了&#xff0c;也还是没有想明白第五题的解法&#xff0c;我真是fw&#xff0c;到最…

Oracle Trace File Analyzer 介绍及简单使用

一、什么是Oracle Trace File Analyzer Oracle Autonomous Health Framework(AHF) 包含 Oracle ORAchk, Oracle EXAchk, and Oracle Trace File Analyzer(TFA). AHF工具包包含了Oracle常用的多种诊断工具&#xff0c;如 ORAchk, Oracle EXAchk, and Oracle Trace File Analyzer…

简单的密码加密

用户的密码必须被加密后再存储到数据库, 否则就存在用户账号安全问题用户使用的原始密码通常称之为"原文"或"明文", 经过算法的运算, 得到的结果通常称之为"密文"在处理密码加密时, 不可以使用任何加密算法, 因为所有加密算法都是可以被逆向运算…