栈帧——函数调用,变量在内存中如何存取
来源:互联网 发布:淘宝买家修改评价链接 编辑:程序博客网 时间:2024/06/06 07:51
首先我们先要搞懂程序的地址空间是怎样的。
堆区和栈区相对生长,而我们的变量是存在栈区,接下来我们就要对程序运行时的栈区进行讨论。
用以下程序为例:
#include<stdio.h>#include<windows.h>int add(int a,int b){int z=a+b;return z;}int main(){int a=1;int b=1;int z=add(a,b);printf("%d\n",z);system("pause");return 0;}
我们通过转到汇编语言来更好的观察程序的每一步。
每进入一个函数我们就需要给这个函数开辟一个空间,而这个空间我们叫栈帧。
从地址00401060到00401076,这一段是给开辟的空间先进行初始化。
首先我们得了解一些寄存器:ebp叫做栈底,esp为栈顶,eip为存储下一条指令地址的寄存器。
然后我们程序再往下走,分别在栈底以4字节为单位,开辟空间分别保存a=1,b=1。
然后对a,b两个变量进行压栈。其中压栈是压从esp栈顶开始的。
00401086~0040108D的示意图如下:
(绿色块为main函数的栈帧)
然后我们来到了call命令处,继续按F11往下走。
其中call有如下两个功能:
1.将当前正在执行指令的下一条指令的地址,压入栈中。
2.jmp,跳转到指定函数。
然后我们进入了add函数,同样会给add这个函数开辟一个空间。如图的蓝色块,称为add的栈帧。
通过call命令将当时的下一条指令的地址压入栈中(00401093),其目的是当add函数调用结束时,返回main。
00401020的意思是将main函数的ebp地址也压入栈中。
00401021~00401036,同样是给add函数开辟空间并初始化。
然后对z=a+b;进行操作。由示意图我们可以看到,我们用的形参a,b并不在add函数内部,而在main与add之间。
将相加的结果2保存在eax寄存器中。
程序结束后,还有一堆pop弹出栈的操作,00401044~0040104A。add函数的栈空间(栈帧)销毁。
ret的功能有2个:
1.弹出栈顶
2.弹出的值放入EIP中。
跳回主函数后,将eax寄存器中的值2继续存入main函数的栈空间,也就是得到add函数的返回值。
调用add函数的过程,到此已经全部结束。
总结:
1.我们可以看到形参是保存在栈帧与栈帧之间的。
2.形参的存储顺序与实参相反(先压栈的后出)。
3.临时变量的生命周期伴随着栈帧的开始而开始,结束而结束。
4.返回值以寄存器的形式返回。
- 栈帧——函数调用,变量在内存中如何存取
- 变量和数据是如何存储在内存中
- 学习心得——整型数据在内存中如何存储?
- java中变量在内存中的分配
- java中变量在内存中的分配
- PHP变量在内存中释放问题
- 方法中的变量在调用该方法前在内存中并不存在
- 如何在Visual Basic 中取得变量在内存中的地址(Address of Variables)
- 如何在Visual Basic 中取得变量在内存中的地址(Address of Variables)
- 如何在Visual Basic 中取得变量在内存中的地址(Address of Variables)
- 如何在Visual Basic 中取得变量在内存中的地址(Addre
- 如何在Visual Basic 中取得变量在内存中的地址(Address of Variables)
- 细看代码在内存中如何存储
- 进程在内存中如何表示
- 列存储在内存中如何管理
- 整型数据在内存中如何存储?
- -128在内存中如何存储
- 函数、对象在内存中存在形式
- 语音购票、刷脸进站:上海联手阿里打造全球首个AI地铁之城
- jsonp详解
- C# TableLayoutPanel 一个很实用的案例
- 盘点•GitHub最著名的20个Python机器学习项目
- C语言实现二叉排序树的基本运算算法
- 栈帧——函数调用,变量在内存中如何存取
- 【脑洞】人工智能是否能主宰未来战争!
- mybatis批量更新 allowMultiQueries
- IDC:2017年Q3全球可穿戴设备总出货量2630万台 小米Fitbit并列第一
- 微信官方提供的生成二维码接口得到的是当前公众号的二维码。
- Uiautomator小记之 Uidevice
- 在此行找到多个注释:
- Caffe源码:relu_layer.cpp
- 安装虚拟机出现的一些问题,总是会让人不知所措。下面总结了几点