函数栈帧图文解释

在这篇文章之前,我想先一下声明我只是是一个初学者,如有错误,请指出,望评论区保持和谐。

注:本文章介绍栈帧使用的是 VS2013 编译器
不用VS2019是因为有些东西观察不到;
正文开始:
本文使用的源码:

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

int main()
{
	int a = 10;
	int b = 20;
	int c = 0;
	c = sum(a, b);
	printf("%d", c);
}

首先就是怎么调用堆栈

通过调用堆栈可以
在这里插入图片描述
在这里插入图片描述
按下F10之后

当我们走到箭头指向的位置的时候再按下F10,就会看到其实main函数也是由 __tmainCRTStartup 函数调用的.
其实 __tmainCRTStartup函数也是由其他函数调用的.
所以调用关系就是,如图所示
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这之前先介绍以下这些字母代表什么意思
push是压栈
pop是出栈
ebp是栈底指针
esp是栈顶指针

esp和pbp是用来维护函数栈帧的,他们之间的空间就是本次的函数栈帧
既然main函数是由别的函数调用的,所以在调用 main 函数之前 __tmainCRTStartup函数栈帧已经创建好了,如图
在这里插入图片描述

现在我们把目光转移到反汇编上
在这里插入图片描述
在这里插入图片描述

1.main 函数栈帧开辟

push

当进入mian函数就会压栈,把ebp的值压进栈中,随着压栈esp也会指向上面一位,如图:
在这里插入图片描述
接着,我们一步步看

mov

mov代表的是把后面的值赋给前面的值,在这里就是表示ebp此时指向了esp指向的位置
如图
在这里插入图片描述
在监视窗口,我们也可以看到他们两的值相同了
在这里插入图片描述
再接着下面的汇编代码

sub

在这里插入图片描述

sub就是前面的值减去后面的值,即esp的值减去0E4h所以esp会变小,即esp会向上移动,如图
在这里插入图片描述
可以看到此时ebpesp之间又有一块区域,这块空间就是为main函数开辟的空间

再之后就是三次push,这个东西与跟本文没什么太大关系,所以先略过…
在这里插入图片描述
push三次之后
在这里插入图片描述

lea,mov,mov,rep stos

load effective adress

004213CC  lea         edi,[ebp-0E4h]  
004213D2  mov         ecx,39h  
004213D7  mov         eax,0CCCCCCCCh  
004213DC  rep stos    dword ptr es:[edi]  

那个dword就是代表 double word 。而1word代表2字节,所以dword就代表4字节
即,
这段的作用就是把ebp - 0E4h的地址赋给edi39h(十六进制)赋给ecx,把0CCCCCCCCheax
并且从edi开始的以下39h个4字节都变成eax也就是CCCCCCCC

所以此时内存中如图所示
在这里插入图片描述
内存中的栈帧

赋值

	int a = 10;
004213DE  mov         dword ptr [ebp-8],0Ah  
	int b = 20;
004213E5  mov         dword ptr [ebp-14h],14h  
	int c = 0;
004213EC  mov         dword ptr [ebp-20h],0  

这里就是把 0Ah就是10的十六进制赋给ebp-8下面同理
如图
在这里插入图片描述

2.sum 函数栈帧的开辟

	c = sum(a, b);
004213F3  mov         eax,dword ptr [ebp-14h]  
004213F6  push        eax  
004213F7  mov         ecx,dword ptr [ebp-8]  
004213FA  push        ecx  
004213FB  call        004210FA  
00421400  sum         esp,8  
00421403  mov         dword ptr [ebp-20h],eax  

传参

004213F3  mov         eax,dword ptr [ebp-14h]  
004213F6  push        eax  
004213F7  mov         ecx,dword ptr [ebp-8]  
004213FA  push        ecx  

这里的把**[ebp-14]的地址的值赋给eax**,并且push(压栈)eax,以下都同理
如图所示
在这里插入图片描述

调用sum函数

004213FB  call        004210FA  

这里的调用取的是sum函数地址的下一个地址,为的是可以让函数用完可以继续向下执行

在这里插入图片描述
在这里插入图片描述

sum函数内部

int sum(int x, int y)
{
00421460 55                   push        ebp  
00421461 8B EC                mov         ebp,esp  
00421463 81 EC CC 00 00 00    sub         esp,0CCh  
00421469 53                   push        ebx  
0042146A 56                   push        esi  
0042146B 57                   push        edi  
0042146C 8D BD 34 FF FF FF    lea         edi,[ebp+FFFFFF34h]  
00421472 B9 33 00 00 00       mov         ecx,33h  
00421477 B8 CC CC CC CC       mov         eax,0CCCCCCCCh  
0042147C F3 AB                rep stos    dword ptr es:[edi]  
	int z = 0;
0042147E C7 45 F8 00 00 00 00 mov         dword ptr [ebp-8],0  
	z = x + y;
00421485 8B 45 08             mov         eax,dword ptr [ebp+8]  
00421488 03 45 0C             add         eax,dword ptr [ebp+0Ch]  
0042148B 89 45 F8             mov         dword ptr [ebp-8],eax  
	return z;
0042148E 8B 45 F8             mov         eax,dword ptr [ebp-8]  
}

这里有很多都是与上面main函数创建栈帧重复的过程,不知道朋友们看到这里是不是又对函数有更加深刻的理解了呢?

	int z = 0;
0042147E C7 45 F8 00 00 00 00 mov         dword ptr [ebp-8],0 

这里可以看到把 0 放到了 [ebp-8]
如图所示
在这里插入图片描述
有人可能要问:为什么这里没看见x,y?

	z = x + y;
00421485 8B 45 08             mov         eax,dword ptr [ebp+8]  
00421488 03 45 0C             add         eax,dword ptr [ebp+0Ch]  
0042148B 89 45 F8             mov         dword ptr [ebp-8],eax  

其实x,y就在这里
这段代码就是表示把 [ebp+8] 的值赋给eax,把 [ebp+0Ch] (就是+12)的值加到 eax 上,最后再把eax的值放到**[ebp-8]**里
如图所示
在这里插入图片描述

	return z;
0042148E 8B 45 F8             mov         eax,dword ptr [ebp-8]  

ebp +0Ch 的地址所对应 的值(也就是20)加到 eax 中返回去;
由于eax是寄存器,所以不会因为函数销毁而销毁.

3.sum 函数栈帧的销毁

00421491 5F                   pop         edi  
00421492 5E                   pop         esi  
00421493 5B                   pop         ebx  
00421494 8B E5                mov         esp,ebp  
00421496 5D                   pop         ebp  
00421497 C3                   ret

这里的 pop 其实和 push 就是相反的步骤把
没进行一次 esp 就要++一次,也就是向下移动一次
如图
在这里插入图片描述

00421494 8B E5                mov         esp,ebp  

这里就是把 ebp 的值赋给 esp
如图
在这里插入图片描述
接着继续

00421496 5D                   pop         ebp 

由于此时栈顶放的元素是 main 函数的栈底
所以 pop 之后直接 ebp 指向 mian 函数栈底
esp 向下走一格
如图
在这里插入图片描述

00421497 C3                   ret

这里的 ret 这条指令直接返回到 call 的下一条指令.
这是 ret 指令执行之后跳转的位置.
在这里插入图片描述
由这张图可以看到,现在是把 8 加到 esp 上去
如图
在这里插入图片描述
此时形参销毁.

——————————————————————————————————————

这就是函数栈帧的图文讲解。喜欢这篇文章的话点点赞哦.

  • 10
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

eptcup_

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

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

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

打赏作者

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

抵扣说明:

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

余额充值