函数栈帧的创建于销毁(个人理解)

为了探究函数创建与销毁在内存里的变化,做以下文章,个人理解

    • 首先了解寄存器

寄存器有:eax ebx ecx edx ebp esp

这里我们只需要关系ebp与esp寄存器

这两个寄存器是用来存放地址的 ,而存放的两个地址用来维护函数栈帧的;

这里我们要知道main函数也是被其他函数调用

mainCRTStartup调用__tmainCRTStartup函数

而__tmainCRTStartup调用main函数才开始工作

程序流程

先写流程所需代码

#include<stdio.h>
#include<stdlib.h>
#include<string.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函数使用。

  • ebp指向栈底

  • esp指向栈顶

首先知道开辟空间为从高地址向低地址开辟

main函数的空间创建

先将ebp的地址压栈在tmain..

ps:压栈也会让esp向低地址移动4个地址

然后在将esp的地址赋给ebp,将esp与ebp内地址相同

然后esp得到一个更低的地址,然后esp到ebp就是main函数所开辟的栈帧

在eax esi edi依次压栈

edi为ebp偏移的距离也是函数的栈帧空间

ecx为0x39次数

eax为一个16进制值

最后的rep stos步骤是将每四个字节放入eax内的值,放0x39次;

初始化main栈帧内的值

现在才开始走main函数内的代码汇编;

变量a b c分别以ebp为参考偏移几个字节保存在所开辟的栈帧内

为准备进入add函数准备

将a,b以ebp偏移的地址内的数据存入2个其他的寄存器通过寄存器压栈在main栈帧上

call指令为转入函数 在传入函数前会先将call下一汇编地址压栈在main栈帧上

然后再将ebp在main函数栈帧的底传给一个寄存器然后压栈(为了保存main的栈底)如准备创建main函数栈帧前保存tmain..的栈底。

进入add函数:

如开辟main函数栈帧一样,开辟add函数的栈帧空间,初始化内部参数

在函数add栈帧内创建一个变量z的空间

在函数内计算,汇编代码如下

z = x + y;
00FA187C 8B 45 08             mov         eax,dword ptr [ebp+8]  
00FA187F 03 45 0C             add         eax,dword ptr [ebp+0Ch]  
00FA1882 89 45 F8             mov         dword ptr [ebp-8],eax  
  1. 为函数代码

  1. 为将ebp偏移+8个字节的数据保存在eax寄存器中

  1. add为将后一个寄存器中地址值加到前一个寄存器中地址值,将ebp偏移+0xc中的值加上eax寄存器中原先保存的值最后相加保存在eax。

  1. 将eax寄存器中地址内的值传给ebp偏移-8的地址中保存----这是变量z的空间.

return z;
00FA1885 8B 45 F8             mov         eax,dword ptr [ebp-8]  
  1. 函数代码

  1. 将ebp偏移-8的的地址的值(z的值)拷贝到eax

接下来是add函数的销栈

00FA1888 5F                   pop         edi  
00FA1889 5E                   pop         esi  
00FA188A 5B                   pop         ebx 

1.2.3.这三条代码将栈顶的三行代码块出栈,出栈后数据保存在edi esi ebx 寄存器中,

esp向下加0x0c的地址(向高地址移动)

接下来将esp指向ebp保存的地址

00FA189A 5D                   pop         ebp  
00FA189B C3                   ret  

1.将保存main-ebp值的地址出栈,出栈的数据保存在ebp中,覆盖ebp原先保存的地址

2.ret然后结束add函数的调用,并且保存的main函数汇编地址的下一条指令生效,009418f7内容出栈

esp+0x4,函数销毁完毕;

add传回值的接收

首先将esp偏移+0x8地址--将形参x,y出栈

00FA18F7 83 C4 08             add         esp,8  

然后再将eax中的值拷贝到ebp偏移量-0x20处

00FA18FA 89 45 E0             mov         dword ptr [ebp-20h],eax

此刻函数的调用结束,返回函数成功

这里有几个点要注意 esp ebp eax等等是寄存器不会因为函数的销毁而销毁

在函数的创建与销栈过程就是将开辟空间然后重新赋值,覆盖掉原先的值,不论曾经是否被调用过

函数的空间开辟,压栈都是高地址到低地址的,所以压栈都是地址偏移负数 出栈都是正数

为了分别看到我将bit鹏哥的截图拿来使用,仅供参考函数栈帧的创建.png · 比特鹏哥/class108 - Gitee.com

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

云的小站

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

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

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

打赏作者

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

抵扣说明:

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

余额充值