当前位置:主页 > 软件编程 > C代码 >

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

时间:2022-09-26 09:36:18 | 栏目: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函数进行维护

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

梳理一下上面的思路

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

main函数栈帧开辟

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

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

003118B0 push ebp

003118B1 mov ebp,esp

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

003118B3 sub esp,0E4h

003118B9 push ebx

003118BA push esi

003118BB push edi

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

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

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

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

调用Add函数

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

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

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

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

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

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

返回主函数

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

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

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

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

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

您可能感兴趣的文章:

相关文章