- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章c语言函数栈帧的创建和销毁过程详解由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
。
。
一般计算机内通用寄存器包括eax,ebx,ecx,edx,esi,edi,esp,edp,其中esp,ebp这两个寄存器是用来存放地址的,这两个地址就是用来维护函数栈帧的 。
。
我们知道c语言中函数都是被调用的,main函数里面能调用其他函数,其实main函数也是被别的函数调用的。main函数是在 _tmainCRTSartup 函数中被调用的,_tmainCRTSartup函数又是在mainCRTSartup函数中被调用。 每一次函数调用都是一个函数调用过程,这个过程要为函数开辟栈空间,用于本次函数的调用中临时变量的保存、现场保护,也叫函数栈帧。栈帧也叫过程活动记录,是编译器用来实现过程/函数调用的一种数据结构.
push 压栈:给栈顶放上一个元素 pop 出栈:从栈顶删除一个元素 。
函数栈帧结构如下: 其中esp为栈顶指针,ebp为栈底指针,他们共同来维护函数栈帧.
。
为了描述函数栈帧的创建和销毁我们以一个简单程序为例 。
#define _CRT_SECURE_NO_WARNINGS 1#include <stdio.h>int add(int x, int y){ int z = 0; z = x + y; return z;}int main(){ int a = 20; int b = 10; int c = 0; c = add(a, b); printf("%d", c); return 0;}
当进入main函数前,esp,ebp在如下位置 。
我们此时可以进入调试模式然后进入反汇编模式看下汇编代码从而观察main函数栈帧的创建 。
这里是将ebp压栈(用来记录上一个ebp方便函数销毁时找到上一个函数的位置),然后将esp的值传给ebp,在将esp的内容减去0E4h,从而为main函数创建了一个栈帧,并且将ebx,sei,edi的值进行压栈。效果如下 。
这里是将ebp-0E4h的值加载到edi里面,然后将39h放到ecx寄存器里,再将0CCCCCCCCh放到eax寄存器里,最后将edi这个地址下面的39h个字节数据的值全部置为CCCCCCCC. 。
这段汇编代码时将14h赋值到ebp-8的空间里面,将0Ah赋值到ebp-14h的空间里面,将0赋值到ebp-20h的空间里面. 。
然后进入c = add(a,b)语句,首先将ebp-14h的值放到eax寄存器中在将eax的值进行压栈操作,再将ebp-8的值放到ecx寄存器中在将ecx的值进行压栈操作.
下面图片中绿色框里eax应该是10,ecx是20,画图时写反了实在是抱歉 。
这里是跳转到add函数,并将下一条语句的地址压入栈内 。
000E17C0 push ebp //记录上一个ebp内容000E17C1 mov ebp,esp //将esp的值赋给ebp000E17C3 sub esp,0CCh //将0CCh赋给esp,为add创建栈帧000E17C9 push ebx 000E17CA push esi 000E17CB push edi 000E17CC lea edi,[ebp+FFFFFF34h] 000E17D2 mov ecx,33h 000E17D7 mov eax,0CCCCCCCCh 000E17DC rep stos dword ptr es:[edi] 000E17DE mov ecx,0EC003h //与前面类似000E17E3 call 000E1307 //进入add函数 7: int z = 0;000E17E8 mov dword ptr [ebp-8],0 //将0赋给ebp-8的内容 8: z = x + y;000E17EF mov eax,dword ptr [ebp+8] //将a的值赋给eax寄存器000E17F2 add eax,dword ptr [ebp+0Ch] //将b+a的值赋给eax000E17F5 mov dword ptr [ebp-8],eax //将eax的值赋给ebp-8的内容里面 9: return z;000E17F8 mov eax,dword ptr [ebp-8] //将ebp-8的内容里面赋给eax
至此add函数功能执行完成,接下来开始返回,也就是进行add函数栈帧销毁 。
首先分别将edi,esi,ebx进行出栈,然后将esp加上0CCh也就是回到ebp的位置,然后将ebp的值赋给esp,再将ebp进行出栈操作(这样就能回到原来的main函数的ebp位置从而将add的栈帧空间还给操作系统) 。
后面是main函数的销毁过程,流程和add销毁一样,这里就不在过多赘述.
到此这篇关于c语言函数栈帧的创建和销毁的文章就介绍到这了,更多相关c语言函数栈帧内容请搜索我以前的文章或继续浏览下面的相关文章希望大家以后多多支持我! 。
原文链接:https://blog.csdn.net/weixin_52134286/article/details/119511664 。
最后此篇关于c语言函数栈帧的创建和销毁过程详解的文章就讲到这里了,如果你想了解更多关于c语言函数栈帧的创建和销毁过程详解的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
栈一种常见的特殊线性数据结构,其特殊之处在于其操作顺序,下面会详细介绍,也正因为其特性,因此栈可以轻松解决表达式求值、括号匹配、递归算法、回溯算法等等问题。 01、定义 栈的特殊性表现为操作受
目录 实践1 —— 从字符串中移除星号 栈和数组存储数据的方式一样,它们都只是元素的列表。不同之处在于栈的以下3个限制: 数据只能从栈末插入; 数据只
准备工作 工具:idea+jdk8 技术要求:java基础语法 编码环节 首先,我们得先确定下来,用什么数据来模拟栈的操作。由于是一个一个的元素放入栈里面,我们可以考虑用数组来实现。
0. 学习目标 栈和队列是在程序设计中常见的数据类型,从数据结构的角度来讲,栈和队列也是线性表,是操作受限的线性表,它们的基本操作是线性表操作的子集,但从数据类型的角度来讲,它们与线性表又有着巨大的不
在可以使用递归(在堆栈中存储状态)和对象创建(在堆中创建新对象)的场景中。 问题 在对象创建和递归之间进行选择时应考虑哪些参数? 我的研究得出以下结论(需要验证这一点) 当可用内存较少时:使用递归 可
下面是我编写的用于检查内存对齐的示例程序。 Pavan@Pavan-pc:~/working_dir/pavan/C$ cat mem3.c #include #include
Instapaper 和 Twitterrific 等应用启动的 View 不是其导航堆栈的 Root View 。我们知道这一点,因为初始 View 已经有一个后退按钮。 Instapaper 推出
有没有办法在调试或正常运行期间的某个时刻可视化 Activity 堆栈? 最佳答案 您可以通过 Activity 管理器获取一些有用的信息。 ActivityManager manag
我想编写一个应用层协议(protocol),在发送 GET 请求时使用 TCP 返回特定的 ASCII 文本。我读了第一HTTP specification和 the SMTP specificati
1、堆和栈的速度性能分析 堆和栈是jvm内存模型中的2个重要组成部分,自己很早以前也总结过堆和栈的区别,基本都是从存储内
一: 概念 栈,同样是一种特殊的线性表,是一种last in first out(lifo)的形式,现实中有很多这样的例子,
java中stack类继承于vector,其特性为后进先出(lastinfirstout). 入栈和出栈实例图: 实例图的java代码实例: ?
1、单链表 1、在我们数据结构中,单链表非常重要。它里面的数据元素是以结点为单位,每个结点是由数据元素的数据和下一个结点的地址组成,在java集合框架里面 LinkedList、Ha
本文实例讲述了Python编程实现双链表,栈,队列及二叉树的方法。分享给大家供大家参考,具体如下: 1.双链表 ?
我一遍又一遍地阅读定义,但我仍然不明白ARM中的SP和LR是什么?我了解PC(它显示下一条指令的地址),SP和LR可能类似,但我只是不明白它是什么。你能帮我一下吗? 编辑:如果你能用例子来解释它,那就
我必须使用索引 0 作为堆栈的顶部,并且在实现此操作时遇到问题。我得到了所有 null,但输出 100、200 和 300 是我得到的唯一数字。我忽略的实现有什么问题吗? push 方法应该实现 Ar
我正在用 Java 解决汉诺塔问题。我选择使用 Stacks 作为钉子,除了 move 方法之外,一切都正常。我有规范和 JUnit 测试类,目前通过了 7 项测试中的 6 项,但在移动测试中失败了。
这个问题在这里已经有了答案: 关闭 11 年前。 Possible Duplicate: Does this type of memory get allocated on the heap or
首先,抱歉我的英语不好。我将尝试解释我的问题: 我有一个 RootViewController(基于导航的项目)。因此,它显示了表格 View ,当用户选择表格的一行 (didSelectRowAtI
我有一个看起来像这样的类 class A { int b; void B() { int c; } } int main() { A asdf;
我是一名优秀的程序员,十分优秀!