函数栈帧的创建和销毁详解 - 带你深入认识底层

本文深入剖析了X86环境下函数栈帧的创建和销毁过程,通过汇编代码展示了如何使用ebp和esp寄存器管理栈,详细解释了push、pop、mov等指令的作用,并探讨了局部变量的创建、函数调用时参数的传递和返回值的处理。

先奉上代码:(X86环境运行!X64会不一样哦!)

#include <stdio.h>

int Add(int x, int y)
{
	int z = x + y;
	return z;
}

int main()
{
	int a = 66;
	int b = 34;
	int c = 0;

	c = a + b;

	printf("%d\n", c);
	return 0;
}

这里仅涉及到了简单的变量创建和函数调用,以此我们来深入剖析其背后的实现原理。

如果看一眼堆栈:

可知 main 函数也被其他函数调用,但这不必过度分析,只需要了解即可。 

目录

认识寄存器

认识汇编指令

汇编代码一览

汇编剖析(执行前)

第一行:push ebp

第二行:mov ebp, esp

第三行:sub esp, 0E4h 

第四、五、六行:push ebx; push esi; push edi

 第七、八、九行:lea edi, [ebp-24h]; mov ecx, 9; mov eax, 0CCCCCCCCh

第十行:rep stos dword ptr es:[edi]

 调试行:

代码执行

第一行:mov dword ptr [ebp-8],42h

第二、三行:mov dword ptr [ebp-14h],22h; mov dword ptr [ebp-20h],0

 第四、五、六、七行:mov; push

CALL调用 

进入CALL

1.ebp 压栈

2.esp 赋值给 ebp

3.esp 上移开空间

4.ebx esi edi 压栈

5.初始化空间

6.相加

 7.返回

pop ebp

ret

 再回 main 函数:

add esp, 8

mov dword ptr [ebp-20h],eax


认识寄存器

大家都知道在CPU内集成了很多寄存器,例如:eax,ebx,ecx,edx,ebp,esp等等

这里我们主要关注的是 ebp 和 esp 两个寄存器:

ebp - 储存了栈底地址;esp - 储存了栈顶地址

认识汇编指令

push - 入栈操作

pop - 出栈操作

mov - 移动操作

sub - 减法

add - 加法

lea - load effective address - 加载有效地址

rep stos - 填充

call - 函数调用

jmp - 跳转

ret - 返回到地址处执行

当然不理解也没关系,接下来会详细讲解。

汇编代码一览

005718B0  push        ebp  
005718B1  mov         ebp,esp  
005718B3  sub         esp,0E4h  
005718B9  push        ebx  
005718BA  push        esi  
005718BB  push        edi  
005718BC  lea         edi,[ebp-24h]  
005718BF  mov         ecx,9  
005718C4  mov         eax,0CCCCCCCCh  
005718C9  rep stos    dword ptr es:[edi]  
005718CB  mov         ecx,57C008h  
005718D0  call        0057131B  
	int a = 66;
005718D5  mov         dword ptr [ebp-8],42h  
	int b = 34;
005718DC  mov         dword ptr [ebp-14h],22h  
	int c = 0;
005718E3  mov         dword ptr [ebp-20h],0  

	c = Add(a, b);
005718EA  mov         eax,dword ptr [ebp-14h]  
005718ED  push        eax  
005718EE  mov         ecx,dword ptr [ebp-8]  
005718F1  push        ecx  
005718F2  call        005710B4  
005718F7  add         esp,8  
005718FA  mov         dword ptr [ebp-20h],eax  

	printf("%d\n", c);
005718FD  mov         eax,dword ptr [ebp-20h]  
00571900  push        eax  
00571901  push        577B30h  
00571906  call        005710D2  
0057190B  add         esp,8  

	return 0;
0057190E  xor         eax,eax  
}
00571910  pop         edi  
00571911  pop         esi  
00571912  pop         ebx  
00571913  add         esp,0E4h  
00571919  cmp         ebp,esp  
0057191B  call        00571244  
00571920  mov         esp,ebp  
00571922  pop         ebp  
00571923  ret  

汇编剖析(执行前)

由于调用 main 函数的函数没必要展开描述,所以下文只是简述。可知 ebp 和 esp 对栈是这样维护的:

 所以如果我们假设调用 main 函数的函数统称为 startmain 函数(纯编造,勿当真)

其准备执行第一行汇编代码时,堆栈情况如下:

第一行:push ebp

即入栈,注意:入栈 esp 会跟随向上移动,所以这一步执行后,栈情况如下:

push 前:(地址仅起演示作用)

push 后: (地址仅起演示作用)

注:内存的使用是从高地址到低地址,所以这里 esp 减少但实际是在向上移 

第二行:mov ebp, esp

mov 指令是将后者的值给前者,即这里把 esp 的值给了 ebp,这个时候 esp 和 ebp 指向同一位置:

 

第三行:sub esp, 0E4h 

这里 esp 的减少,实际上是在向上开空间,栈空间如下:

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Thepale2022

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值