C语言函数栈帧的创建与销毁原理图解

什么是函数栈帧

我们在写C语言代码的时候,经常会把一个独立的功能抽象为函数,所以C程序是以函数为基本单位的。

那函数是如何调用的?函数的返回值又是如何待会的?函数参数是如何传递的?这些问题都和函数栈帧有关系。

函数栈帧(stack frame)就是函数调用过程中在程序的调用栈(call stack)所开辟的空间,这些空间是用来存放:

  • 函数参数和函数返回值
  • 临时变量(包括函数的非静态的局部变量以及编译器自动生产的其他临时变量)
  • 保存上下文信息(包括在函数调用前后需要保持不变的寄存器)。

什么是栈?

栈(stack)是现代计算机程序里最为重要的概念之一,几乎每一个程序都使用了栈,没有栈就没有函 数,没有局部变量,也就没有我们如今看到的所有的计算机语言。

与函数栈帧有关的汇编语句

eax:通用寄存器,保留临时数据,常用于返回值

ebx:通用寄存器,保留临时数据

ebp:栈底寄存器

esp:栈顶寄存器

eip:指令寄存器,保存当前指令的下一条指令的地址

mov:数据转移指令

push:数据入栈,同时esp栈顶寄存器也要发生改变

pop:数据弹出至指定位置,同时esp栈顶寄存器也要发生改变

sub:减法命令

add:加法命令

call:函数调用,1. 压入返回地址 2. 转入目标函数

jump:通过修改eip,转入目标函数,进行调用

ret:恢复返回地址,压入eip,类似pop eip命令(返回子程序)

函数如何创建栈帧并销毁

当程序进入main函数时,要给main函数在栈区创建空间,esp(栈顶)和ebp(栈底)对main函数进行维护

C语言函数栈帧的创建与销毁原理图解_第1张图片

当程序执行时,我们在调试窗口对堆栈段进行调用,我们可以看到main函数是被__tmainSRTStartup函数所调用,说明main函数是它的内部函数,而__tmainSRTStartup又是被mainCRStartup这个函数调用

C语言函数栈帧的创建与销毁原理图解_第2张图片

梳理一下上面的思路

C语言函数栈帧的创建与销毁原理图解_第3张图片

这些函数在堆栈当中的存储

C语言函数栈帧的创建与销毁原理图解_第4张图片

main函数栈帧开辟

接下来重新调试,我们转到反汇编

C语言函数栈帧的创建与销毁原理图解_第5张图片

调用main函数之前,esp和ebp对调用main函数的函数进行维护 ,当栈顶发生改变时,esp会指向新的栈顶

C语言函数栈帧的创建与销毁原理图解_第6张图片

003118B0 push ebp

003118B1 mov ebp,esp

先把ebp入栈,然后把ebp移动到esp的位置

C语言函数栈帧的创建与销毁原理图解_第7张图片

003118B3 sub esp,0E4h

003118B9 push ebx

003118BA push esi

003118BB push edi

之后又把esp往上移动,移动完把ebx,esi,edi压栈,esp和ebp现在指的这块空间是为main函数预先开辟好的

C语言函数栈帧的创建与销毁原理图解_第8张图片

C语言函数栈帧的创建与销毁原理图解_第9张图片

把edi-0EFH也就是main函数开始的这里的地址,放到edi里面去,然后从这个地址开始赋值39次的双字节数据,赋值为CCCC

C语言函数栈帧的创建与销毁原理图解_第10张图片

到这里main函数栈帧开辟完成

C语言函数栈帧的创建与销毁原理图解_第11张图片

接下来就是在main函数的空间里,创建三个变量,并给赋值

C语言函数栈帧的创建与销毁原理图解_第12张图片

调用Add函数

对函数进行传参,创建俩个临时变量,然后压栈进去

C语言函数栈帧的创建与销毁原理图解_第13张图片

接下来进入call开始调用函数call此时的地址是00C2144B

C语言函数栈帧的创建与销毁原理图解_第14张图片

此时按下F11,我们发现call指令的下一条地址被压到了栈区

C语言函数栈帧的创建与销毁原理图解_第15张图片

把call的下一个地址压栈,ps:后面会用到这条指令,可先放在这不管

C语言函数栈帧的创建与销毁原理图解_第16张图片

接下来进入Add函数,跟前面main函数一样,先开辟空间,然后赋值为CCCCCC,再为变量在函数里创建空间并赋值

C语言函数栈帧的创建与销毁原理图解_第17张图片

接下来执行加法运算,由于刚才已经创建好了零时变量,所以把他俩进行相加,加完之后把结果传过来就行,传过来之后把这个值放在eax里面去

C语言函数栈帧的创建与销毁原理图解_第18张图片

返回主函数

按顺序出栈,之后把ebp赋值给esp

C语言函数栈帧的创建与销毁原理图解_第19张图片

C语言函数栈帧的创建与销毁原理图解_第20张图片

之后pop,ebp把ebp进行出栈,ebp便回到main函数这里,ebp此时回到这里,esp也自然而然的往下指一个,ret指令是返回,然后esp来到了call指令的下一条指令

C语言函数栈帧的创建与销毁原理图解_第21张图片

C语言函数栈帧的创建与销毁原理图解_第22张图片

把栈顶指针弹出去,esp自然向下指一条

C语言函数栈帧的创建与销毁原理图解_第23张图片

C语言函数栈帧的创建与销毁原理图解_第24张图片

之后给esp加8即释放这俩个临时变量

C语言函数栈帧的创建与销毁原理图解_第25张图片

之后把eax放到ebp-20h,eax是存放刚才加法和的地方

C语言函数栈帧的创建与销毁原理图解_第26张图片

到此这篇关于C语言函数栈帧的创建与销毁原理图解的文章就介绍到这了,更多相关C语言函数栈帧内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

你可能感兴趣的:(C语言函数栈帧的创建与销毁原理图解)