函数的调用过程,栈帧的创建和销毁

来源:互联网 发布:爱情电影推荐知乎 编辑:程序博客网 时间:2024/06/06 01:02

为了更好的认识函数的调用过程,我以最简单的的加法函数Add为例解释了函数的栈帧;

首先我们应该理解以下内容:

堆区(stack):由编译器自动分配和释放,存放函数的参数值,局部变量的值等。操作方式类似于数据结构中栈;

栈区(heap):一般由程序员分配和释放,若程序员不释放,程序结束时可能由操作系统回收。与数据结构中的堆是两码事,分配方式类似于链表;

全局区(static):全局变量和静态变量存放在此;

文字常量区:常量字符串放在此,程序结束后由系统释放;

程序代码区(code):存放函数体的二进制代码;

在函数的调用过程中,函数的调用过程叫栈帧,那么栈区在哪???看下图:

一·基本的概念

1)栈帧(过程活动记录):是编码器用来实现函数调用的一种数据结构,每个栈帧对应一个未运行完的函数,栈帧中保存了该函数的返回地址和局部变量。

2)ebp:栈底指针,即指向栈帧底部的指针。

3)esp:栈顶指针,栈帧指针只有一对。

4)call:将当前正在执行指令的下一条指令压入栈中;随即call会跳转到指定函数(jmp)。

5)push:入栈(push寄存器,用来保护数据)压入操作,把一个32位的操作数压入栈中,这个操作数会使得esp被减4(字节),esp通常是指向栈顶的,这里的顶部是指地址小的区域,那么,压入栈帧的数据越多,esp也就越来越小。

6)pop:出栈。

7)mov:类似于赋值操作符,进行数据的传送。第一个参数是目的操作数,第二个参数是源操作数,就是把源操作数拷贝到目的的一份。

8)add:加法操作。

9)sub:减法操作。

10)ret:弹出pop栈顶;弹出栈顶值的地址,并且将弹出的值写入EIP中。

二·让我们通过下面的代码来一起看看栈帧是如何具体形成并实现相关的功能的  调用Add函数的代码如下:

#define _CRT_SECURE_NO_WARNINGS#include <stdio.h>#include <Windows.h>int Add(int x, int y){int tmp = 0;tmp = x + y;return tmp;}int main(){int a = 2;int b = 3;int ret = 0;ret = Add(a, b);printf("%d\n", ret);getchar();return 0;}

要详细的研究函数的调用过程,就要通过对应的汇编代码来分析:

1)从main函数的地方开始,要展开main函数的调用就得为main函数创建栈帧,那我们先来看看main函数的栈帧的创建;


2)接下来就是Add函数的调用过程了:


剩下的是函数返回部分:


至此在main中调用fun的整个过程都已经完成。

三·总结:这就是整个过程可能理解的的不够到位,请大家随时提出意见。


阅读全文
0 0