当前位置:网站首页>函数栈帧的形成和销毁(26张图助你深入理解函数栈帧)
函数栈帧的形成和销毁(26张图助你深入理解函数栈帧)
2022-07-21 17:08:00 【沙漠下的胡杨】
个人主页:欢迎大家光临——>沙漠下的胡杨
各位大帅哥,大漂亮
如果觉得文章对自己有帮助
可以一键三连支持博主
你的每一分关心都是我坚持的动力
![]()
:本期重点:我们今天讲解下函数栈帧的形成和销毁
希望大家每天都心情愉悦的学习工作
函数栈帧讲解我们通过汇编的一些分析讲解,所以我们先了解下一些寄存器和汇编指令来进一步学习栈帧吧。
相关的寄存器:
eax:通用寄存器,保留临时数据,常用于返回值
ebx:通用寄存器,保留临时数据
ebp:栈低寄存器
esp:栈顶寄存器
eip:指令寄存器,保留当前指令的下一条指令地址。
相关的汇编命令:
mov:数据转移指令
push:数据入栈,同时esp栈顶寄存器发生改变
pop:数据弹出至指定位置,同时esp栈顶寄存器也要发生改变
sub:减法命令
add:加法命令
call:函数调用 1.压入返回值 2.转入目标函数
jmp:通过修改eip,转入目标函数,进行调用
ret :恢复返回值地址,压入eip,类似pop eip命令
首先我们了解下C程序地址空间(VS版)
C程序地址空间的图如下:
不同的编译器可能方向不同,增长方向是一样的,必如栈都是向低地址去,堆区向高地址去。
接着我们看下函数调用的逻辑
main函数也是函数,是被谁调用的呢?
是被 __tmainCRTStartup()这个函数调用的,
然后这个函数 __tmainCRTStartup()又被 mainCRTStartup()这个函数调用
这个函数 mainCRTStartup() 是被操作系统进行直接调用的。
![]()
下面我们以一个简单的例子来进行理解:
int MyAdd(int x, int y) { int c = 0; c = x + y; return c; } int main() { int a = 0xA; int b = 0xB; int z = 0; z = MyAdd(a, b); printf("z = %x\n", z); return 0; }
很简单的一个函数,就是两数之和然后封装为一个函数来进行调用。
创建main函数栈帧
这是上面就是main函数的栈帧的创建,但是不重要。
分析main函数中的代码
代码进行汇编分析:
先看a变量,是把 0A的值赋给 ebp - 8这个空间,同理 b 和 z 也是。
看图解:
调用MyAdd函数前的准备:
我们看下调用函数前,汇编指令都做些什么吧。
首先是把ebp - 14h(变量b的值)的值放入eax中,其实就是b的值放入寄存器中,然后压入eax,同理压入ebp - 8(变量 a的值)。
看示意图,观察此时的寄存器的指向,最下面为内存布局:
![]()
上面的过程证明了:
1.函数调用前,就已经形成了临时变量。
2.形参实例化的顺序是从右向左的。
进行函数调用:
执行 call 命令,进入函数体内。
call要做的是 :
1:压入返回值 2.转入目标函数
为什么要压入返回值呢?因为函数可能会调用结束,那么就需要返回了。
压入返回值,就是压入 call 指令的下一条指令的地址。
看下压入前的内存和地址:
压入后内存,重点看是不是 call 的下一条指令的地址是否压入了:
如下图所示,确实已经压入啦
另外说一下,jmp 后的值,就是MyAdd函数的地址,就是跳转到该函数处。
所以eip的值也就由原来的 main函数值 变为 MyAdd函数的值啦。
看示意图:
开辟MyAdd的栈帧空间:
我们 jmp 之后就该进入函数中了,也就是执行函数啦,
我们先看下汇编:
这些汇编就是为MyAdd开辟战帧空间
首先逐步分析,push ebp,把ebp压入栈中,ebp就是main函数的栈低位置,mov 把 esp的地址移动到ebp中,ebp其实是MyAdd的栈顶,最后把 esp 的值减去0CC。其实就是把esp的当前位置向上移动,然后和 ebp 围成一段空间,为了MyAdd函数使用。
如图所示:
示意图为:
其中 ebp 和 esp围成的空间就是MyAdd函数的栈帧。
这是 esp 和 ebp 都指向了,main函数的栈顶,那么栈低指针呢?
不用担心main函数栈低的地址找不到,我们刚才把main函数栈低指针压入了MyAdd的栈帧空间中啦,到时候可以直接返回了。
分析MyAdd代码
还是先进行反汇编代码查看:
逐个分析:
mov ebp - 8, 0,其实就是在ebp -8的位置处赋值为0,接着把 ebp + 8的值放入eax中,再把ebp + 0C 的值和原来eax中的值相加,最后把eax中的值放入ebp - 8空间中去。
翻译下就是:
开辟空间 c 变量,初始化为0,把原来形参实例化中的a的值放入eax中,把形参实例化中的b也放进去与a相加,最后的结果在eax中,把eax的值放入变量 c 的空间中。这就是上述的汇编。下面看下示意图:
准备返回
说下返回值把,返回值其实是别放在了eax寄存器中进行了返回,所以eax的值,就是0xC
接着我们继续分析汇编:
分析下:首先是把变量 c 的值放入eax寄存器中,接着我们弹出edi,esi,ebx这些都不管,重点看下,mov esp ,ebp这句代码,这个就是把ebp的地址赋值给esp,相当于esp 和 ebp同时指向了MyAdd的栈低处,也就是释放了栈帧空间, 然后pop ebp,就是弹栈,ebp处是栈底,栈底就是main函数的栈底,也就是说pop后,ebp又回到了main函数的栈底,而esp就在call的下一条指令处啦。
如图所示:
ret之后
ret其实就是类似pop一样,就是把esp的值再向下移动
如图:
返回call的下一条指令处
我们ret之后返回到了call的下一条指令处
接着看汇编,把esp的值加 8 ,其实就是把所形成的临时变量销毁。
把eax的值移动到 ebp - 20,其实上就是把寄存器中0xC的值移动到变量z中去。
看示意图:
剩下的打印不在叙述啦。
剩下一个有意思的证明:
形参实例化时,是从左到右,连续排布的。
int MyAdd(int x, int y) { printf("Before:%d\n", y); *(&x + 1) = 100; printf("After: %d\n", y); return 0; }
本篇总结:
首先我们从汇编底层来看和了解了函数栈帧的创建和销毁,其中每个细节,每个汇编指令做出了解释和相对性的示意图,希望大家有所收获吧。
下期预告:
下期会更新可变参数列表的相管内容。
边栏推荐
- 软考中级【数据库系统工程师】第0章:如何自学备考,考试介绍考什么,备考教材,上午和下午的体型分数分布,备考课程链接,个人备考感谢
- Redis的经典三问以及哨兵
- 不断提升认知,从而达到交易的最高级别——稳定盈利(终)
- 自学golang【3.2go语言变量的类型与条件语句,常量,变量,枚举,if语句与switch语句的应用】
- Self study golang [Chapter 3: the first go language program] use GoLand to create the first go program, the main function and init function, and use go to run Windows commands and realize the data out
- 量化交易日记-2021年02月总结
- Error: L6200E: Symbol keyflag multiply defined (by main.o and key.o).
- excel 如何根据身份证号自动匹配性别代码
- 编码之前先保证你的硬件稳定连接!!!
- 量化交易日记-回撤分析-2021年02月6日
猜你喜欢
職業交易者自用多年的終極突破策略分享(附全套交易模板)
软考中级【数据库系统工程师】第0章:如何自学备考,考试介绍考什么,备考教材,上午和下午的体型分数分布,备考课程链接,个人备考感谢
excel 中粘贴时怎么不覆盖
自学golang【3.4go语言的函数和指针】定义一个函数返回一个或多个值,go语言的指针,指针不能运算,go语言参数传递只有值传递,通过指针实现地址传递,函数返回2个值,如何只接受一个值
Alibaba cloud technology expert haochendong: cloud observability - problem discovery and positioning practice
Why not overwrite when pasting in excel
量化交易日记-2021年01月总结
Write the first myshell program (computer experiment report II)
MySQL事务
自学golang【第三章:第一个go语言程序】使用goland创建第一个go程序,main函数与init函数,使用go实现运行windows命令,实现cmd的数据输出
随机推荐
十年交易员重磅推荐:简单易操作的突破回调策略
Analysis of location cache module and detailed explanation of OCP monitoring and alarm
How does pytorch convert a variable or tensor to numpy?
自学golang【3.1定义变量】使用var关键字定义变量,使用var()集中定义变量,省略int等关键字以及省略var关键字,用冒号:替代定义
“珠峰”架构强势赋能 第三代荣威RX5/超混eRX5刷新产品力“天花板”
农产品期货怎么开户,找谁能开光大期货啊?
Collection和Map总结
自学golang【3.5go语言数组,range关键字】数组的定义方式,使用for循环遍历一维数组
excel 如何根据身份证号自动匹配性别代码
Original one bit multiplier
Partage de la stratégie de percée ultime des commerçants professionnels pendant de nombreuses années (avec un ensemble complet de modèles de transaction)
MySQL stored procedure
Verilog——74HC194多功能双向移位寄存器
Airflow scheduling start_ Date explanation
How to add text before and after text in batch in Excel
STM32 SPI 读取数据不准确,只有第一次对,后边均不对
SPI debugging is not successful, it is likely that you connected the wrong cable!!
MySQL binlog
The use of comma expression in C language
How to put the horizontal flashing cursor (_) in notepad++ Change to vertical flashing cursor style (|)?