前言
本文将介绍函数栈帧是如何使用与回收的,将以图示的方式,来逐步展示函数栈帧的形成与销毁的整个过程。
一、预备知识
在理解函数关于栈帧的形成与销毁的整个过程中,我们需要明白一些相关的基础知识,才能更方便我们去理解本文的这个概念
1.什么是函数栈帧
函数栈帧(stack frame),即在调用函数时,为函数开辟的一块内存空间,由于该内存空间在栈区,因此该空间被称作函数栈帧,简称栈帧。
2.认识相关的寄存器
寄存器不属于内存,是单独的存储空间
相关寄存器
eax:通用寄存器,保留临时数据,常用于返回值
ebx:通用寄存器,保留临时数据
ebp:栈底寄存器,记录的是栈底的地址
esp:栈顶寄存器,记录的是栈底的地址
eip:指令寄存器,保存当前指令的下一条指令的地址
3. 相关的汇编命令
这部分不用很熟悉,但是需要大概了解
mov:数据转移指令
push:数据入栈,同时esp栈顶寄存器也要发生改变(esp存储地址减小,esp指向上移)
pop:数据弹出至指定位置,同时esp栈顶寄存器也要发生改变(esp存储地址增大,esp指向下移)
sub:减法命令
add:加法命令
call:函数调用,分为两步:1. 向栈压入返回地址 2. 指令转入目标函数
jump:通过修改eip,转入目标函数,进行调用
ret:恢复返回地址,向栈压入eip,类似pop eip命令
二、函数栈帧的创建和销毁
1.调试代码和编译器调试
本次演示的编译器为vs2019
调试代码
#include"stdio.h"
int add(int x, int y)
{
int z = 0;
z = x + y;
return z;
}
int main()
{
int a = 10;
int b = 20;
int c = 0;
c = add(a, b);
printf("%d\n", c);
return 0;
}
编译器调试
- 调用堆栈
按下F10,选择调试----窗口----调用堆栈
如果打开后只有main函数的话,右键选择“显示外部代码”即可
- 转到反汇编
右键选择反汇编,可以进入从汇编代码角度看看程序执行过程中,在内存里到底发生了什么
如下
总结
本文主要讲了函数栈帧的基础知识和相关的寄存器和汇编指令,以及在编译器上的调试说明,下文将继续讲解在调用堆栈和汇编代码的角度继续讲解函数栈帧的创建和销毁,有兴趣的读者可以继续阅读我的有关文章,如有什么问题也欢迎在评论区指正.