函数在实现过程内存中的压栈和出栈
来源:互联网 发布:协方差矩阵的计算 编辑:程序博客网 时间:2024/05/20 13:18
关于函数在调用过程中的压栈和出栈问题在学习的时候就感觉很经典,对程序的把握可以提升一个台阶。
一.首先让我们写出一个简单的函数。(我是在vc6.0中实现,并不表示vs编译器底下不可以实现)。
#include<stdio.h>
int add(num1,num2)
{
int ret = 0;
ret = num1+num2;
return ret;
}
int main()
{
int num1 = 1;
int num2 = 2;
int ret = add(num1,num2);
printf("%d ",ret);
return 0;
}
1).需要声明是add函数中可以直接写成"return num1+num2",我在写博客的时候是故意写成这样,以便于后面的分析。
二.接下来,我们首先明确几个知识点。
1).栈
首先必须明确一点也是非常重要的一点,栈是向下生长的,所谓向下生长是指从内存高地址->低地址的路径延伸,那么就很明显了,栈有栈底和栈顶,那么栈顶的地址要比栈底低。对x86体系的CPU而言,其中
---> 寄存器ebp(base pointer )可称为“帧指针”或“基址指针”,其实语意是相同的。
---> 寄存器esp(stack pointer)可称为“ 栈指针”。
要知道的是:
--->ebp 在未受改变之前始终指向栈帧的开始,也就是栈底,所以ebp的用途是在堆栈中寻址用的。
—>esp是会随着数据的入栈和出栈移动的,也就是说,esp始终指向栈顶。
2).
假设函数A调用函数B,我们称A函数为"调用者",B函数为“被调用者”则函数调用过程可以这么描述:
(1)先将调用者(A)的堆栈的基址(ebp)入栈,以保存之前任务的信息。
(2)然后将调用者(A)的栈顶指针(esp)的值赋给ebp,作为新的基址(即被调用者B的栈底)。
(3)然后在这个基址(被调用者B的栈底)上开辟(一般用sub指令)相应的空间用作被调用者B的栈空间。
(4)函数B返回后,从当前栈帧的ebp即恢复为调用者A的栈顶(esp),使栈顶恢复函数B被调用前的位置;然后调用者A再从恢复后的栈顶可弹出之前的ebp值(可以这么做是因为这个值在函数调用前一步被压入堆栈)。这样,ebp和esp就都恢复了调用函数B前的位置,也就是栈恢复函数B调用前的状态。
如下图所示
三.在明确了这些知识之后,让我们返回上面那个简单的函数。
1).首先来看看我画出的图。
上面的图片能够粗略的表现函数调用的过程。
2).
所产生的汇编代码:
上面两幅图片是mian函数的栈帧。
上面的图片是add函数的栈帧。
3).在liunx平台下的汇编代码
以上为本人在学习函数在内存中的操作的一些经验,当然,本人才疏学浅,上述肯定会有纰漏,若有读者发现,请联系我及时改正。谢谢!
本文出自 “做一个小小小司机” 博客,请务必保留此出处http://10799170.blog.51cto.com/10789170/1715186
- 函数在实现过程内存中的压栈和出栈
- 函数在实现过程内存中的压栈和出栈
- C语言函数调用模型[调用过程中在堆栈中的出栈、进栈顺序]
- free函数在操作系统内存中的实现
- free函数在操作系统内存中的实现
- free函数在操作系统内存中的实现
- 函数中的栈内存
- 函数调用和栈的内存分配过程分析
- 运行过程中打印出函数调用栈
- 代码在内存中的分布。函数在栈中的调用过程,即函数的栈帧。
- 虚函数在子类和父类中的内存布局
- 虚函数在子类和父类中的内存布局
- 堆栈用链表实现压栈和出栈
- 顺序栈的C语言实现——初始化函数、入栈函数和出栈函数
- 栈和队列在java中的实现
- 共享内存在Java中的实现和应用
- 共享内存在Java中的实现和应用
- 函数的入栈和出栈,自定义函数
- PULPino在zedboard上的下载、测试
- API之家 http://www.apihome.cn
- 模拟三次密码输入
- 猴子吃桃问题
- 关于字符串的函数
- 函数在实现过程内存中的压栈和出栈
- 内存拷贝函数的实现
- 左旋字符串的三种实现
- 指针数组以及数组指针
- 测试计算机是小端存储还是大端存储
- js 中时间戳转换格式化日期
- 二维数组和二级指针作为参数传给参数的方式
- 理解数组与指针不可缺少的东西
- C#创建使用一般处理程序.ashx