初步了解函数栈帧的创建和销毁

发布于:2022-12-30 ⋅ 阅读:(649) ⋅ 点赞:(0)

学习链接:函数栈帧的创建和销毁

注:结合上方学习链接阅读本文

下面深入讨论几个很基础的问题:

目录

1.在函数里面局部变量是怎么创建的?(局部变量的创建方式)

2.为什么局部变量不初始化的时候值是随机值呢?

3.函数是怎么传参的?以及他的使用 传参的顺序是怎样的?

4.形参和实参是什么关系?

5.函数调用结束后怎么返回的?

1.在函数里面局部变量是怎么创建的?(局部变量的创建方式)

首先要为这次函数调用创建函数栈帧 有了这个函数栈帧 在函数栈帧里面找到一些空间把局部变量放入

2.为什么局部变量不初始化的时候值是随机值呢?

通过调试 反汇编可以观察到,这个随机值是开辟函数栈帧的时候放入的(CCCCCCCC),如果把局部变量初始化了,其实就是把随机值覆盖了

3.函数是怎么传参的?以及他的使用 传参的顺序是怎样的?

形式参数并不是在Add函数(见文首学习链接中Add函数)内部创建的,即不是在Add函数的函数栈帧里创建的,而是在还没有调用该函数的时候 通过push指令把参数按照从右向左的顺序压栈。当我们真正进入Add函数的时候 其实是在Add函数的函数栈帧里面 通过指针的偏移量找到了形参

下图是在主函数中的指令

先在主函数中为变量分配空间

然后压栈

然后call指令调用函数 同时把 call指令的下一条指令的地址(00461E7A) 压栈

 

4.形参和实参是什么关系?

形参是在压栈的时候开辟的空间,他和我们的实参只是值上是相同的,但空间是独立的,所以形参是实参的一份临时拷贝,改变形参不会影响实参

形参并没有在Add函数的函数栈帧里边,是在main函数和Add函数这两个函数的函数栈帧之间开辟的空间,或者也可以认为这块空间是在main函数的栈帧里边

5.函数调用结束后怎么返回的?

我们在调用Add函数之前:

1.就已经把 call指令的下一条指令的地址 压栈了,

2.把 上一个函数(main函数)的 栈帧的ebp 压栈压进去了(如下图)

上面这两步非常重要 当我们函数调用完要返回的时候:

1.pop指令将esp所指地址处的值(main函数的栈帧的ebp)赋给ebp,这样就回到了main函数的栈帧空间

 2.ret指令终止当前函数的执行,因为我们之前记住了call指令下一条指令的地址,往回返的时候就可以跳转到该地址,让我们函数调用之后可以返回,进而继续执行main函数

返回值是通过寄存器的方式带回来的,寄存器不会被销毁:

Add函数的返回值先放到寄存器(eax)里面去

回到main函数之后mov指令再把这个值放到局部变量c([ebp-20h])里面去

本文含有隐藏内容,请 开通VIP 后查看