详解函数栈帧

目录

  1. 源码
  2. 分析
  3. 全过程图示
  4. 总结

函数栈帧讲解

函数栈帧初解

1. 源码

函数栈帧包括了函数的调用,栈的开辟,参数的使用,栈空间的分配等,理解了函数栈帧,有助于我们写出更规范的代码,了解和观察内存的使用情况,本文将基于上一章函数栈帧的解释,更详细,复杂的讲解函数栈帧的情况,有些简单的过程上一章已经一句一句的分析了,将一笔带过,讲解重要的部分

环境基于 vc6.0

#include 

int fun3(int x,int y)
{
	return x+y;
}

void fun2(int x,float y)
{
	float fcnt=0;
	fcnt=x+y;
	fun3(3,(int)fcnt);
}
int fun1(int x,int y)
{
	int z=0;
	float f=3.5f;
	z=x+y;
	fun2(z,f);
	return z;
}

int main()
{
	int a=5;
	int b=6;
	fun1(a,b);

}

源码有三层函数调用,分别是fun1(),fun2(),fun3(),其中涉及有参无参的多种情况,较为简单,当学会了简单代码的分析,就可以看更复杂的

2. 分析

按F10进入调试,函数运行到main函数左花的位置,打开反汇编和内存监视窗口,内存窗口取main函数的a变量地址,监视窗口取栈顶和栈底,开始观察

详解函数栈帧_第1张图片
栈窗口可以看出main函数的上一层调用函数maincrt,调用了main函数

main函数

汇编代码

详解函数栈帧_第2张图片
在这里插入图片描述

监视窗口

详解函数栈帧_第3张图片
此时显示maincrt函数的栈顶和栈底

图示

详解函数栈帧_第4张图片
上面的代码完成了main函数的栈空间开辟和初始化

图示

详解函数栈帧_第5张图片

汇编代码

详解函数栈帧_第6张图片
现在开始mian函数中代码的执行

详解函数栈帧_第7张图片
图示

详解函数栈帧_第8张图片

fun1函数

汇编代码详解函数栈帧_第9张图片
开始为调用fun1函数准备,此时栈顶压入调用fun1函数下一条代码的位置

图示

详解函数栈帧_第10张图片

main内存

详解函数栈帧_第11张图片
上面颜色依次为,红色部分是mian函数的三个参数,粉红是maincrt的返回地址,深红是maincrt的栈底,深绿部分局部变量空间,橙色部分是保存的寄存器环境,上面蓝色部分是用来传递参数的两个寄存器eax和ecx

之后执行跳转到调用fun1函数的地址,按F11跟进

详解函数栈帧_第12张图片汇编代码

详解函数栈帧_第13张图片

上面部分和main函数空间开辟一样

图示

详解函数栈帧_第14张图片
汇编代码

详解函数栈帧_第15张图片
在这里插入图片描述
执行fun1函数的代码,代码在汇编中已显示

图示

详解函数栈帧_第16张图片

fun2函数

汇编

详解函数栈帧_第17张图片
传递参数,压入返回地址004010fc,调用函数

图示

详解函数栈帧_第18张图片

fun1内存

详解函数栈帧_第19张图片
从下往上
红色: 参数
粉红: 返回地址
深红: main函数栈底
绿色: 申请的空间
橙色: 寄存器环境

汇编

详解函数栈帧_第20张图片
开辟fun2函数空间

图示

详解函数栈帧_第21张图片

汇编

详解函数栈帧_第22张图片
执行代码

fun3函数

汇编

详解函数栈帧_第23张图片
这里调用了一个函数,该函数的功能是将st0寄存器的浮点数去尾取0,也就是吧浮点数强转为int,这里暂略过该过程,从下一条开始

传递浮点去整结果和常量参数3,继续压入返回地址,开始函数调用开辟空间

图示

详解函数栈帧_第24张图片
汇编

详解函数栈帧_第25张图片

图示

详解函数栈帧_第26张图片
汇编

详解函数栈帧_第27张图片
取得返回地址,函数返回,释放空间,edcel调用约定调用方清理参数

在这里插入图片描述
返回到401095,并清理参数空间

图示

详解函数栈帧_第28张图片
汇编

详解函数栈帧_第29张图片
弹出寄存器,释放局部变量空间,在debug模式下,函数有时会调用chkesp函数,该函数的功能是用来检查栈是否平衡,如果不平衡会报错,此处先略过,栈顶到返回地址处,栈底回到fun1函数栈底

图示

详解函数栈帧_第30张图片

汇编

详解函数栈帧_第31张图片
继续回到上一层

图示

详解函数栈帧_第32张图片
汇编

详解函数栈帧_第33张图片
此时将返回到maincrt函数,之后过程相似,不做赘述

3. 全过程图示

详解函数栈帧_第34张图片

4, 总结

  1. edecl调用约定从右往左传递参数,参数空间由调用方清理
  2. 函数返回值一般由eax寄存器带回
  3. debug模式局部变量空间会初始化为cccccccc,申请的空间大于需要使用的
  4. 变量空间释放并不会使数据发生变化,只会将空间标位未使用,然后挪栈的位置。所以内存仍有残留数据

你可能感兴趣的:(c语言,开发语言)