函数在实现过程内存中的压栈和出栈
来源:互联网 发布:mysql 断电 无法启动 编辑:程序博客网 时间:2024/06/06 00:12
关于函数在调用过程中的压栈和出栈问题在学习的时候就感觉很经典,对程序的把握可以提升一个台阶。
一.首先让我们写出一个简单的函数。(我是在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平台下的汇编代码
- 函数在实现过程内存中的压栈和出栈
- 函数在实现过程内存中的压栈和出栈
- C语言函数调用模型[调用过程中在堆栈中的出栈、进栈顺序]
- free函数在操作系统内存中的实现
- free函数在操作系统内存中的实现
- free函数在操作系统内存中的实现
- 函数中的栈内存
- 函数调用和栈的内存分配过程分析
- 运行过程中打印出函数调用栈
- 代码在内存中的分布。函数在栈中的调用过程,即函数的栈帧。
- 虚函数在子类和父类中的内存布局
- 虚函数在子类和父类中的内存布局
- 堆栈用链表实现压栈和出栈
- 顺序栈的C语言实现——初始化函数、入栈函数和出栈函数
- 栈和队列在java中的实现
- 共享内存在Java中的实现和应用
- 共享内存在Java中的实现和应用
- 函数的入栈和出栈,自定义函数
- java 计算两字符串的最大子字符串
- FullCalendar – jQuery Event Calendar in ASP.NET
- cc2540 usb hid升级
- 电子元件的学习
- 算法导论 RandomizedSelect
- 函数在实现过程内存中的压栈和出栈
- LeetCode-494. Target Sum (JAVA) (目标和)
- HDU 4675
- 矩阵的加法、减法、乘法、转置
- spring 获取上下文applicationContext
- [BZOJ 1207][HNOI2004]打鼹鼠:DP
- 动态规划练习一—14怪盗基德的滑翔翼
- 浅谈 Java 字符串(String, StringBuffer, StringBuilder)
- 软件开发生命周期模型 瀑布模型、增量模型、原型模型、螺旋模型、喷泉模型总结