浅谈函数栈帧(Stack Frame)
创始人
2024-05-10 21:12:54
0

💙作者:阿润菜菜

📖专栏:C++


本文目录

什么是栈帧

 在调试中观察

总结


什么是栈帧

那我们先来看看什么是

栈(stack)是限定仅在表尾进行插入或者删除的线性表。栈是一种数据结构,它按照后进先出的原则存储数据。把数据元素存放到栈顶时,叫压栈(push) ,从栈顶删除一个元素,叫出栈(pop)。那什么是栈帧(Stack Frame)呢?

预备知识:

 每一次函数的调用,都会在调用(call stack)上维护一个独立的栈帧空间(stack frame).每个独立的栈帧一般包括:

  • 函数的返回地址和参数
  • 临时变量: 包括函数的非静态局部变量以及编译器自动生成的其他临时变量
  • esp、ebp这两个寄存器中存放的是地址,这两个地址是用来维护函数栈帧的
  • .ebp(栈底指针):该指针永远指向系统栈最上面一个栈帧的底部
  • esp(栈顶指针):该指针永远指向系统栈最上面一个栈帧的栈顶
  • 栈是从高地址向低地址延伸,一个函数的栈帧用ebp 和 esp 这两个寄存器来划定范围.ebp 指向当前的栈帧的底部,esp 始终指向栈帧的顶部
  • 压栈push :esp上移朝低地址移动;出栈pop:栈顶元素弹出,esp下移高地址

 在调试中观察

 我们使用的环境是VS2013,由于函数栈帧是底层知识,而越高级的编译器越难以抽离出函数栈帧分装的过程,不容易学习和观察。同时在不同的编译器下,函数调用栈帧的创建也是略有差异的,但大体思路都是一样的。

每一个函数独占自己的栈帧空间。当前正在运行的函数的栈帧总是在栈顶。 

如图: 

 在调用main函数的时候,会在栈中开辟一块空间,由ebp和esp共同来维护(在调用哪个函数,ebp和esp就会维护哪块空间)

但main函数是被怎么调用的呢?是被系统内提前建立好的函数栈帧调用的:

通过反汇编可以看到main函数是被_tmainCRTStartup()函数调用的,通过一系列汇编指令调用main函数同时esp和ebp来进行维护:  我们来看下这些汇编指令走的过程

 当执行压栈push时, ebp压到esp顶部,esp上移

执行move时,mov ebp,esp 就是把esp的地址交给edp

此时ebp和esp指向了同一个地址

 下一步是sub  esp,0E4h 就是把esp减去0E4h使esp上移。也就是为main函数开辟了空间

下面就是三个push:分别压进了ebx,esi和edi三个值(具体是什么值,无需关心,后面会自动弹出)

 接下来lea (load effective address)  就是为edi加载有效地址 [ebp - 0E4h]

通过下面mov和rep stos三个命令,我们把ebx到ebp之间的栈空间初始化为eax里的内容 

此时main函数的栈帧空间已开辟好,开始执行真正的有内容的代码:

32位中,word是两个字节,dword(double word)四字节

mov 把0Ah(也就是10)放到ebp-8的位置上,而ebp-8实际上就是为int a开辟一个空间 (局部变量int b =20 ,c = 0 的创建 与变量a 类似)

接下来就是调用Add函数了,我们可以看到是一条mov 指令,把[ebp -14h]值(也就是变量b值)放到eax中;然后就是push,压栈eax(b =20), 下面接着一条mov和push命令,类似压栈将变量a的值压入ecx;

 那么刚刚做的步骤是在为Add函数传参吗?是的。接下来call 命令就是调用,通过调试窗口我们可以清楚的看到a上面就是call指令的下一条指令的地址。这一步是在调用函数的同时把下一条指令的地址压上去,作为函数回归的标记

至此就来到我们的Add函数栈帧,与上面讲的main函数栈帧开辟一样。参数是从右向左压栈的,从上面我们也可以清楚的看到形参不是在Add函数内部创建的,而是回来到我们传参的空间,这也直接证明了形参是实参的临时拷贝这句话 !

 那Add函数是如何带回返回值的呢?可以看到把[ebp-8]里的值也就是int z 放到eax里面,因为这里的eax是寄存器(硬件)啊,寄存器不会因为程序退出就销毁的,相当于拿一个(全局的)寄存器把返回值保存起来,等到执行main函数我们再把它拿出来。

那么函数怎么返回呢?

 在 return z执行后,我们pop弹出,把栈顶的元素取出放到edi里面去,依次pop三次,esp指针就往下走。当我们函数调用完了那这个空间就没必要存在了,所以mov把ebp的地址给esp。

此时esp指到ebp,pop一下把栈顶的元素弹出来,因为里面放的是main函数的栈底指针,把结果弹到ebp里面去就可以瞬间到main栈底了

最后ret这条指令就是栈顶弹出call下一条指令地址然后跳过去,回来后就到了call下一条指令地方。此时add 就把形参的空间还给操作系统,然后把eax的值给[ebp-32]空间就是变量int c的空间。

觉得配合图示很难理解,大家可以结合实操快速掌握函数栈帧的创建和销毁过程

总结

在函数调用的过程中,有函数的调用者(caller)和被调用的函数(callee). 调用者需要知道被调用者函数返回值; 被调用者需要知道传入的参数和返回的地址

函数调用:

  • 参数入栈: 将参数按照调用约定(C语言是从右向左)依次压入系统栈中
  • 返回地址入栈: 将当前代码区调用指令的下一条指令地址压入栈中,供函数返回时继续执行
  • 代码跳转: 处理器将代码区跳转到被调用函数的入口处;
  • 栈帧调整:
    1.将调用者的ebp压栈处理,保存指向栈底的ebp的地址(方便函数返回之后的现场恢复),此时esp指向新的栈顶位置; push ebp
    2.将当前栈帧切换到新栈帧(将eps值装入ebp,更新栈帧底部), 这时ebp指向栈顶,而此时栈顶就是old ebp mov ebp, esp
    3.给新栈帧分配空间 sub esp, XXX

函数返回: 

  • 保存被调用函数的返回值到 eax 寄存器中 mov eax, xxx
  • 恢复 esp 同时回收局部变量空间 mov ebp, esp
  • 将上一个栈帧底部位置恢复到 ebp pop ebp
  • 弹出当前栈顶元素,从栈中取到返回地址,并跳转到该位置 ret

内容参考:系统栈的工作原理


 本文完。如有建议或问题欢迎评论区讨论

相关内容

热门资讯

常用商务英语口语   商务英语是以适应职场生活的语言要求为目的,内容涉及到商务活动的方方面面。下面是小编收集的常用商务...
六年级上册英语第一单元练习题   一、根据要求写单词。  1.dry(反义词)__________________  2.writ...
复活节英文怎么说 复活节英文怎么说?复活节的英语翻译是什么?复活节:Easter;"Easter,anniversar...
2008年北京奥运会主题曲 2008年北京奥运会(第29届夏季奥林匹克运动会),2008年8月8日到2008年8月24日在中华人...
英语道歉信 英语道歉信15篇  在日常生活中,道歉信的使用频率越来越高,通过道歉信,我们可以更好地解释事情发生的...
六年级英语专题训练(连词成句... 六年级英语专题训练(连词成句30题)  1. have,playhouse,many,I,toy,i...
上班迟到情况说明英语   每个人都或多或少的迟到过那么几次,因为各种原因,可能生病,可能因为交通堵车,可能是因为天气冷,有...
小学英语教学论文 小学英语教学论文范文  引导语:英语教育一直都是每个家长所器重的,那么有关小学英语教学论文要怎么写呢...
英语口语学习必看的方法技巧 英语口语学习必看的方法技巧如何才能说流利的英语? 说外语时,我们主要应做到四件事:理解、回答、提问、...
四级英语作文选:Birth ... 四级英语作文范文选:Birth controlSince the Chinese Governmen...
金融专业英语面试自我介绍 金融专业英语面试自我介绍3篇  金融专业的学生面试时,面试官要求用英语做自我介绍该怎么说。下面是小编...
我的李老师走了四年级英语日记... 我的李老师走了四年级英语日记带翻译  我上了五个学期的小学却换了六任老师,李老师是带我们班最长的语文...
小学三年级英语日记带翻译捡玉... 小学三年级英语日记带翻译捡玉米  今天,我和妈妈去外婆家,外婆家有刚剥的`玉米棒上带有玉米籽,好大的...
七年级英语优秀教学设计 七年级英语优秀教学设计  作为一位兢兢业业的人民教师,常常要写一份优秀的教学设计,教学设计是把教学原...
我的英语老师作文 我的英语老师作文(通用21篇)  在日常生活或是工作学习中,大家都有写作文的经历,对作文很是熟悉吧,...
英语老师教学经验总结 英语老师教学经验总结(通用19篇)  总结是指社会团体、企业单位和个人对某一阶段的学习、工作或其完成...
初一英语暑假作业答案 初一英语暑假作业答案  英语练习一(基础训练)第一题1.D2.H3.E4.F5.I6.A7.J8.C...
大学生的英语演讲稿 大学生的英语演讲稿范文(精选10篇)  使用正确的写作思路书写演讲稿会更加事半功倍。在现实社会中,越...
VOA美国之音英语学习网址 VOA美国之音英语学习推荐网址 美国之音网站已经成为语言学习最重要的资源站点,在互联网上还有若干网站...
商务英语期末试卷 Part I Term Translation (20%)Section A: Translate ...