函数栈帧的创建和销毁


涉及到函数栈帧的创建和销毁的问题

  1. 局部变量的创建

  1. 为什么局部变量的值是随机的

  1. 函数是怎么传参的,传参顺序是怎样的

  1. 函数调用是怎么做的

  1. 函数调用结束后怎么返回


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

那么什么是栈呢?

栈被定义为一种特殊的容器,我把它想象为一个盘子。

可以将数据压入栈中(push),也可以将已经压入栈中的数据弹出(pop

但是栈这个容器必须遵守一条规则:先入栈的数据后出栈(First In Last Out, FIFO

就像往盘子上一层一层地放松饼,最先放的在最底下,你只能先吃最上面那块。

举例用的代码

#include<stdio.h>
int Add(int x, int y) {

    int z = x + y;

    return z;
}
int main() {

    int a = 5;

    int b = 10;

    int c = 0;

     c = Add(a, b);

    printf("%d", c);

    return 0;
}

栈是从高地址向低地址延伸的。

但是这个栈帧是怎么开辟的呢?

这里就涉及到寄存器的知识,最开始只需要了解两个寄存器,多了记不住

esp(栈顶指针),ebp(栈底指针),他们是用来维护函数栈帧的

跟着教程调试一波就会发现main函数被另一个函数调用了,另一个函数又被另一个函数调用

无限套娃了纯属是

到这里我就很懵,但是其实这个没那么重要我觉得,所以不管他

总之main函数也是被调用的

首先来到调用main的函数的栈帧

esp减少四字节,因为栈是从高到低的,所以直观上来看就是往上移了一格

经过push操作,将ebp的值压入栈

再经过mov操作把esp的值赋给ebp,esp再往上移0E4h个字节

但是这还没完,还有好几个寄存器

ebx,esi,edi这三个值看上去就很难记,所以不用关心它们,只需要通通压上去

接着经过lea(load effctive address,加载有效地址)+mov+mov等一套组合拳

把一串数据赋给了从edi开始的为main函数开辟的空间

(这里我没有很懂)

这样main函数的栈帧就开辟好啦

这时候来到前三条赋值代码

如果没有赋值那么如果打印出来就会是随机值

(a和b应该间隔两个,但是我画不下了qwq)


然后又来到了Add函数,这里的重要问题是要搞清楚如何传参

这里并没有独立去开辟新的空间去接收形参

而是通过寄存器去找到我们之前在main函数里压栈进去的实参

所以说形参是实参的临时拷贝,改变形参是不会影响实参滴

并且参数是从右向左传的,Add(a,b)先传b再传a,这样找的时候也先找到a

拷贝好后就是基本重复开辟main函数栈帧的过程,

开辟Add函数的栈帧,在栈顶压入三个值并传值

然后找到事先拷贝好的形参,就是x和y


现在调用完了函数,该返回了

这里有一个比较容易钻牛角尖的点就是z也是要销毁的,它怎么能把值传回去捏

这里又要用到万能的寄存器了,用eax把值存起来

(eax是全局范围的,不用纠结具体作用)

接着就是销毁

销毁松饼也要从顶上开始,所以首先一连三个pop操作把edi,esi,ebx吃掉

再用mov把ebp的值赋给esp

再pop一个ebp(怎么创建就倒过来销毁嘛)

这个时候ebp和esp都返会到main函数里面去了

(这个点也不清楚,难点)

接着是一个ret指令,之前存的call指令的下一条指令的地址就用上了

之后的过程非常复杂,很多文章和视频都跳过了

反正就是返回值先给寄存器,回到主函数后再由寄存器赋给变量

  • 8
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值