什么是函数栈帧
我们在写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函数的空间里,创建三个变量,并给赋值