【函数栈帧】

函数栈帧

  • 函数栈
  • 栈顶指针与栈底指针
  • 函数栈帧的创建与销毁

函数栈

在计算机程序中,内存通常被存储在三个区域–栈区,堆区,静态区,栈区用来存储局部变量如mian函数,以及其他函数的调用;堆区用来存储动态变量,比如malloc函数申请的便是堆区的空间。为什么要分开存放?是因为局部变量在函数调用完后会立马进行销毁,在下次调用时便会再次创建,而动态变量则不会,一旦申请空间后除非手动释放,否则程序不会自己销毁。这两者有着本质的区别,因此需存放在不同的区里。至于静态区,存放的是静态变量即全局变量,无法对其进行修改。请添加图片描述

栈顶指针与栈底指针

在这里插入图片描述

esp与ebp分别为栈顶指针和栈底指针,他们在处理函数调用和局部变量储存时扮演非常重要的角色,其中esp与ebp所指向的地址会随调用函数而发生变化,当程序运行到调用函数时,esp与ebp会重新的改变所指向的地址为调用函数的地址,等到函数调用结束后就会重新返回。esp所指向的地址通过上图可以发现位于函数的最低的地址处,而ebp则是指向函数的最高地址处。

函数栈帧的创建与销毁

接下来我们深入分析函数栈帧的创建与销毁。我们先写一段简单的函数,其中包含了调用函数。

#include<stdio.h>
int ADD(int x, int y)
{
	return x + y;
}
int main()
{
	int a = 3;
	int b = 4;
	int z = ADD(a, b);
	printf("%d", z);
	return 0;
}

运行结果:在这里插入图片描述
打开调用堆栈,我们可以看出即使为mian函数,也并非第一个函数,而是被static int __cdecl invoke_main函数所调用的,所以esp与ebp最先所指向的是static int __cdecl invoke_main函数的栈顶与栈底,其次等到调用mian函数时才开始指向mian函数的栈顶与栈底。在这里插入图片描述接着再打开反汇编,观察esp与ebp的位置:在这里插入图片描述
可以看出,esp与ebp并非一成不变的,而是随着函数的调用,其所指的地址也会发生改变。第一步中push的意思是压栈:将ebp的地址压在static int __cdecl invoke_main的栈顶指针上,即esp的地址加一,在这里插入图片描述
然后第二步mov:将ebp所指向的地址改为esp,在这里插入图片描述
第三步sub:将esp的地址减去04Eh,因为多个函数调用的地址是由高到底,所以减去04Eh就是为下一个函数的调用增加空间,对04Eh进行监视得出字节大小为78。
在这里插入图片描述
第四,五,六步:对ebx,esi,sdi进行压栈。在这里插入图片描述
第七步lea:将ebp-24h的地址保存在edi中。第八步,第九步mov:分别将9和0CCCCCCCCh存入寄存器ecx,eax中。第十步rep stos:将ebp到ebp-24h的地址中的数据全部初始化为0CCCCCCCCh,一共占了9个整型的大小。在这里插入图片描述
在这里插入图片描述
现在已经完成了mian函数的调用,开始执行main函数内的程序,对变量a进行赋值为3,接着对变量b进行赋值为4.
在这里插入图片描述

a与b的地址分别为ebp-8,ebp-14.
开始函数调用,首先要将a与b的值存入寄存器eax,ecx中,并将eax,ecx按顺序进行压栈,然后进行call指令:将call指令的下一条指令的地址进行压栈,在进入到调用函数ADD中在这里插入图片描述
与main函数的函数栈帧的创建一样,这里不再细说。在这里插入图片描述
接下来是对调用函数中z的计算:形参的调用就是将在寄存器eax与ecx的值拿出,进行加减等一系列操作,x与y并没有在调用函数的函数栈帧中占用内存,只有z占用了内存,再将计算好的值传给eax,再传给z,在返回调用函数时,
在这里插入图片描述
在return z后就是对调用函数的函数栈帧的销毁了,首先将z的值传给寄存器eax,将edi,esi,ebx进行pop操作,意思为弹出,将他们弹出后,将esp的地址加上0CCh,弹出ebp与esp此时所指向的main函数的原ebp,使ebp回到main函数的栈底,最后进行ret 使原先存下来的地址发挥用途,重新来到main函数中,并进行剩下的操作。
至此已经完成了main函数的函数栈帧的创建和ADD调用函数的函数栈帧的创建和销毁。我们发现,函数栈帧的销毁并不需要对内容进行删除,只需要将栈底指针与栈顶指针返回致原来的位置即可,等到下次调用其他函数时,函数栈帧的创建会对所占用的空间重新初始化即可。

评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值