函数入栈出栈以及栈帧
来源:互联网 发布:90后创业开淘宝店 编辑:程序博客网 时间:2024/05/17 08:18
参考一
函数调用是程序设计中的重要环节,也是程序员应聘时常被问及的,本文就函数调用的过程进行分析。
一、堆和栈
首先要清楚的是程序对内存的使用分为以下几个区:
l 栈区(stack):由编译器自动分配和释放,存放函数的参数值,局部变量的值等。操作方式类似于数据结构中的栈。
l 堆区(heap):一般由程序员分配和释放,若程序员不释放,程序结束时可能由操作系统回收。与数据结构中的堆是两码事,分配方式类似于链表。
l 全局区(static):全局变量和静态变量存放在此。
l 文字常量区:常量字符串放在此,程序结束后由系统释放。
l 程序代码区:存放函数体的二进制代码。
典型的内存区域分配如图所示:
参考二
首先应该明白,栈是从高地址向低地址延伸的。每个函数的每次调用,都有它自己独立的一个栈帧,这个栈帧中维持着所需要的各种信息。寄存器ebp指向当前的栈帧的底部(高地址),寄存器esp指向当前的栈帧的顶部(地址地)。下图为典型的存取器安排,观察栈在其中的位置
入栈操作:push eax; 等价于 esp=esp-4,eax->[esp];如下图
出栈操作:pop eax; 等价于 [esp]->eax,esp=esp+4;如下图
我们来看下面这个C程序在执行过程中,栈的变化情况
void func(int m, int n) {
int a, b;
a = m;
b = n;
}
main() {
...
func(m, n);
L: 下一条语句
...
}
在main调用func函数前,栈的情况,也就是说main的栈帧:
从低地址esp到高地址ebp的这块区域,就是当前main函数的栈帧。当main中调用func时,写成汇编大致是:
push m
push n; 两个参数压入栈
call func; 调用func,将返回地址填入栈,并跳转到func
当跳转到了func,来看看func的汇编大致的样子:
__func:
push ebp; 这个很重要,因为现在到了一个新的函数,也就是说要有自己的栈帧了,那么,必须把上面的函数main的栈帧底部保存起 ; 来,栈顶是不用保存的,因为上一个栈帧的顶部讲会是func的栈帧底部。(两栈帧相邻的)
mov ebp, esp; 上一栈帧的顶部,就是这个栈帧的底部
;暂时先看现在的栈的情况
;到这里,新的栈帧开始了
sub esp, 8 ; int a, b 这里声明了两个int,所以esp减小8个字节来为a,b分配空间
mov dword ptr [esp+4], [ebp+12]; a=m
mov dword ptr [esp], [ebp+8]; b=n
这样,栈的情况变为:
ret 8 ; 返回,然后8是什么意思呢,就是参数占用的字节数,当返回后,esp-8,释放参数m,n的空间
由此可见,通过ebp,能够很容易定位到上面的参数。当从func函数返回时,首先esp移动到栈帧底部(即释放局部变量),然后把上一个函数的栈帧底部指针弹出到ebp,再弹出返回地址到cs:ip上,esp继续移动划过参数,这样,ebp,esp就回到了调用函数前的状态,即现在恢复了原来的main的栈帧。
链接:
http://blog.csdn.net/zhongguoren666/article/details/7586074
http://blog.csdn.net/yxysdcl/article/details/5569351
- 函数入栈出栈以及栈帧
- 函数栈帧的调用以及销毁
- 函数的调用过程、栈帧的创建以及销毁
- 程序运行 栈帧分析 以及 修改栈帧中数据以及函数地址
- 函数以及函数对象
- C++ STL栈容器以及 .front()函数
- 函数栈以及数据内存段
- 函数调用栈以及函数调用过程 for x86
- 函数调用时的栈帧结构以及临时变量的深入研究
- Linux中程序的栈帧分析以及修改函数地址
- 函数调用的具体过程以及栈帧的创建和销毁
- 浅谈函数的调用过程,栈帧的创建以及销毁
- send函数以及recv函数
- 虚函数 以及覆盖
- pthread_testcancel函数以及pthread_setcancelstate
- WaitForSingleObject以及WaitForMultipleObjects 函数
- Oracle查询以及函数
- feof()函数以及EOF
- hdu 5486 Difference of Clustering(暴力)
- 递归逆序字符串求字符串长度
- JAVA_SE基础——37.main方法的详解
- Git 更新操作
- 正则表达式详解——NSRegularExpression类和NSPredicate类的使用
- 函数入栈出栈以及栈帧
- Hibernate 抓取策略
- Mysql主从复制
- Git 执行更改 git commit
- redis教程(三):Redis数据类型及基本的使用
- 简介Python之super的用法及原理
- Java设计模式之封装算法的模板模式
- Git 管理分支
- XX-net部署技巧