C语言——栈帧的创建和销毁

在写代码的时候,有时候在想哪些函数是怎么实现的呢?

哪些变量是如何奉陪空间的呢?

参数是怎么传递的?

在代码上写int =a就分配了内存,那么分配的过程是如何实现的,代码是如何运行的?接下来细说一下这个问题。

栈帧

寄存器中有eax,ebx,ecx,edx,...ebp,esp.

研究栈帧主要研究ebp和esp这两个寄存器,这两个寄存器中是用来存储地址的,用来维护函数栈帧。

esp——栈顶指针,ebp——栈底指针。

每一个函数调用都要在栈区创建一块空间

测试环境VS2022

测试代码

#define _CRT_SECURE_NO_WARNINGS 1
#include
int add(int a, int b)
{
	int c = 0;
	c = a + b;
	return 0;
}
int main()
{
	int a = 10;
	int b = 20;
	int c = 0;
	c=add(10, 20);
	return 0;
}

C语言——栈帧的创建和销毁_第1张图片这里可以看到min函数被调用,但是不知道被谁调用了一直下一步,知道最后此刻按F10下一步。此刻发现min函数被调用了

 然后上翻会发现这个被调用的main函数是在一个叫__tmainCRTStartup的函数内部被调用了

C语言——栈帧的创建和销毁_第2张图片

 而__tmainCRTStartup这个函数上翻会发现这个函数在mainCRTStartup这个函数里面被调用,也就说说调用顺序为mainCRTStartup——>--tmainCRTStartup——>main这样的调用顺序。接下来具体研究

在函数调用开始的时候转到反汇编。

最先开始的是min函数的调用,这也说明调用main函数的__tmainCRTStartup函数栈帧已经创建好,

epb和esp分别指向函数的栈底和栈顶

C语言——栈帧的创建和销毁_第3张图片

 可以看到首先执行的是push就是压栈,将epb压栈压到栈顶。esp本来指向__tmainCRTStartup的栈顶,但是因为esp维护栈顶,压了元素之后向上到达新的栈顶,esp的地址指向新的栈顶

然后是mov这样就是将esp的值黑了ebp这样就ebp也指向了现在的栈顶,之后是sub,减,给esp(栈顶)减去0e4h,此刻esp指向了现在的位置减去0e4h的地址。此刻他们有了新维护的空间。此刻就是为main函数预开辟的空间。之后是push将ebx,esi,edi,分别压进去此刻在main函数开辟的空间栈顶压了3个元素ebx,esi,edi.压一个esp上挪一次,最后挪到edi的栈顶。此刻esp指向edi的上面,栈顶。接下来是lea

lea这个是将里面的ebp-0e4h地址添加到edi里面。点击显示符号名会发现里面的地址就是之前的0e4h此刻本来指向为main函数开辟空间的栈底,赚到了为main函数开辟空间的栈顶,ebx的下面。

接下来是2个mov将39h放到ecx里面,eax里面放了0ccccccch;

之后下一股句是将

ecx里面方的39h个dword的数据全部改为0ccccccch完成了数据初始化,此刻为main函数开辟的栈帧空间就完成了初始化全部都是cccccccc 

接下来开始初始化Int a=10;

将10放入ebp-8(dword张整形)的位置中,将20放到ebp-14里面去,将0放到ebp-20里面去,第一个元素和第二个元素之间空2个字节,abc的局部变量初始化完成了。接下来是调用add函数。

C语言——栈帧的创建和销毁_第4张图片

接下来是ADD函数初始化,将ebp-14的值20放到eax里面,然后push,在最顶上放eax压栈。此刻esp指向eax上面 .把ebp-8的10值放到ecx里面,然后压栈压到eax里面esp指向ecx栈顶.此刻完成了函数参数的传递。

接下里要call调用函数  此刻call的地址是00c210E1

call指令调用的时候将call指令的下一条指令00c21450的地址压到了,此刻栈顶的上面,即eax的栈顶上方压入了00c21450esp指向新的栈顶。接下来是add函数的初始化

C语言——栈帧的创建和销毁_第5张图片

 可以看到首先就是push压栈将ebpmain函数栈底的值压到main栈顶之后将esp的值给ebp指向栈顶位置成为add函数的栈底。esp指向esp-0cch的位置。为add函数开辟了栈帧,再次压栈将ebx,esi,edi,压到栈顶,esp移动到新的栈顶,将ffffff34放到edi里,再把33放到ecx里面,cccc放到eacx里面,接下来将edi指向的位置(非压入栈地位置,edi此刻在ebx地下方)下面33h地位置初始化为cccccc.

之后ebp-8放z地值。

ebp+8指向ecx里面存放了10a的值放到eax里然后将和Epb+12的值20也放入eax里面,之后将eax的值放到ebp-8里面C语言——栈帧的创建和销毁_第6张图片        ·

然后将ebp-8(30)放到eax里面 

C语言——栈帧的创建和销毁_第7张图片

之后是3个pop 将edi,esi,ebx弹出去mov把ebp的值给esp此刻esp指向了ecp的位置栈底然后弹出pop esp和ebp。到main函数栈顶下一个。ebp回到当时压栈的ebp的位置。esp指向存放ebp值的下一挑指令的位置。pop ret后指向了ecx栈顶

C语言——栈帧的创建和销毁_第8张图片

C语言——栈帧的创建和销毁_第9张图片

add esp 8 移除ecx和eax销毁行参然后把eax的值放到ebp-20(C的位置里面)函数调用完毕

你可能感兴趣的:(c语言,开发语言)