又菜又爱玩的函数栈帧的创建与销毁

寄存器

  • 寄存器

    eax;ebx;ecx;edx

    特别的 esp;ebp

  • esp,ebp这两个寄存器是用来存放地址,来维护函数开辟的栈帧

  • 函数每一次的调用都会在栈区开辟新的空间

调用逻辑

整体调用的逻辑

这里以一个简单程序为例子

#include<stdio.h>
int Add(int x, int y)
{
    int z = 0;
    z = x + y;
    return z;
}
int main()
{
    int a = 10;
    int b = 20;
    int c = 0;
    c = Add(a, b);
    printf("%d\n", c);
    return 0;
}

找到调用 堆栈能够清晰的看出整个程序函数调用的逻辑

 

 

不难发现整个程序的运行

_tmainCRTStartup()调用了mainCRTStartup()

mainCRTStartup()调用了main()

main()调用Add

main()函数的栈帧

首先在文章的开头我说过esp,ebp这两个寄存器是存放地址的用来维护函数开辟的栈帧的,那调用main函数的之前其实_tmainCRTStartup()和mainCRTStartup()的空间其实应该已经开辟好了,并且esp,ebp也是维mainCRTStartup()创建的空间

 

 

push ebp

push为压栈pop为出栈,在栈区数据的创建都是从上往下的,同样的删除数据也是从最顶上的先删除。

每次push的时候我们的esp就会自动跳转到顶上

 

那事实上是不是这样呢?我们可以通过监视来查看

esp的地址0x0077FEBC

ebp的地址0x0077FF08

 

当我们进行push操作的时候发现,在栈顶上开辟了新的空间(4字节)并且将esp的地址0x0077FEBC(4字节)存放了进去,同时esp变量现在的0x0077FEB8(栈区是先先使用高地址再使用低地址)所以此时esp的位置应该往上

esp的地址0x0077FEB8

ebp的地址0x0077FF08

 

move ebp,esp

move ebp,esp意思为将esp赋值给ebp

 

esp=0x0077FEB8

ebp=0x0077FEB8

这里其实也看出了ebp从原来的0x0077FF08变成了和esp一样的0x0077FEB8

 

sub esp,0E4H

esp的值减去0e4h

esp=0x0077FDD4

ebp=0x0077FEB8

因为栈区的地址是先用高地址再用低地址,所以地址越小就越靠经顶部。

esp+0e4h=0x0077FEB8

也就是说esp,ebp现在维护着0e4h个空间,这个新开辟出的空间就是为main函数开辟的栈帧

 

 

push ebx /esi/ edi

这里三次push操作和最开始的一样

push ebx

esp=0x0077FDD0

ebp=0x0077FEB8

ebx=0x008E2000

 

esp由原来的0x0077FDD4变成0x0077FDD0,比原先多了4字节的空间且多的空间存放的是ebx的值

 

同理push esi

esp=0x0077FDCC

ebp=0x0077FEB8

esi=0x0067110E

 

同理push edi

esp=0x0077FDC8

ebp=0x0077FEB8

edi=0x0067110E

 

 

 

lea edi,[ebp-0E4h]

lea为加载有效地址其实就是ebp-0e4h的这个地址存放到寄存器edi中

特别的ebp-0e4h的地址其实就main函数栈顶地址

 

就是说现在的edi=0x0077FDD4 指向的其实是图中绿色esp的位置

mov ecx,39h

 

mov eax,0CCCCCCCCh

 

rep stos dword ptr es:[edi]

从edi里地址的位置开始向下的ecx(39h)次这么多双子的数据都赋值eax的值

 

 

 

main函数中变量的初始化

mov dword ptr [ebp-8],0Ah

将0Ah就是10放到ebp-8的位置

 

 

mov dword ptr [ebp-14h],14h

 

 

​mov dword ptr [ebp-20h],0

 

 

调用add函数栈帧变化

mov eax,dword ptr [ebp-14h]

将ebp-14h中的值赋值给eax

也就是说将b的值20赋值给了eax

 

push eax

同样进行压栈操作在栈顶将eax的值放入并且esp维护栈顶

 

 

mov ecx,dword ptr [ebp-8]

 同样的道理这两部就是创建空间将a的值创建进去

 

call

call指令其实是将一下条指令的地址进行压栈

 

 

进入Add函数

首先还是push ebp这里不在解释直接截图了  

 

 mov ebp,esp

 sub esp,0CCh

 

 三次压栈不过多赘述

 

lea edi,[ebp-0CCh]

ebp-0CCh其实是粉红色esp的位置

 将edi里的地址向下ecx次(33h)的双字赋值0CCCCCCCCh

 

 

 mov dword ptr [ebp-8],0

 

 

mov eax,dword ptr [ebp+8]

add eax,dword ptr [ebp+0Ch]

ebp+8其实就是变量a传的参数

ebp+12其实就是变量b传的参数

将a的值放入eax ,再将b的值加到eax也就是10+20=30

 

 

mov dword ptr [ebp-8],eax

eax存放的是30,将30放到ebp-8的位置就是z的位置

 

 这里当出了函数,变量就应该销毁所有要把返回值再次放入寄存器中

 

pop edi

 发现esp的值变大也就是说栈区在变小 edi这块空间消失了

 pop esi和pop ebx同理

 

 

mov esp,ebp

 

 

这里其实就看出为add函数开辟的栈帧正在销毁

pop ebx

 

 

 到这个时候esp ebp由回到了main函数了

call汇编指令结束

 call汇编指令结束,此时esp指向得空间存放的是call下面一条指令的地址

 

 

 

add esp,8

 

 

 

mov dword ptr [ebp-20h],eax

 

 

 

剩下的栈帧的销毁其实都是一样的就不多赘述了

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值