栈帧步骤解读

本文详细解析了栈帧的工作原理,包括ebp、esp和eip寄存器的作用,以及函数调用过程中的入栈、出栈、call和ret指令的执行。通过实例演示了main函数调用fun函数时栈帧的创建、形参传递和恢复过程,展示了如何在函数调用结束后正确返回主调函数的执行流程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

各寄存器,指令:
ebp:栈底指针
esp:栈顶指针
eip:程序计数器,为cpu指向下一条应该执行的语句
move:后值赋给前值
push:入栈
pop+ ? :出栈,并将出栈内容赋给后面的寄存器
call:(1)将当前call命令的下一条指令的地址以入栈的方式保存起来,用作恢复
(2)以jmp方式跳转
ret:将当前元素进行出栈处理,并将值赋给eip

下面以一段代码为例:

#include<stdio.h>
int fun(int a,int b)
{
   int c=a+b;
   return c;
}
int main()
{  int a=10;
   int b=20;
   int c=fun(a,b);
   printf("hehe\n");
   return 0;
}

1.对ebp进行入栈操作,令esp先等于ebp,再另esp减16进制数字0e4h,在esp与ebp之间形成了一段数据空间,此段空间为main函数的栈帧空间。
这里写图片描述
2.依次初始化元素a,b,并存储在ebp-4,ebp-8处(先定义的元素存在高地址,后定义的元素存在低地址)。
这里写图片描述
3.接下来就到了调用函数fun这一步了,在调用函数前,先要定义形参(形参实体化),定义的形参以入栈的形式存在main函数栈帧的下方。
(1);定义形参时,总是从右向左定义,即先b后a
(2);每进行一次入栈操作,栈顶指针均下移,根据不同的数据类型下移不同的字节大小,此处均为4字节

这里写图片描述

4.为了保证函数调用结束以后cpu仍然能执行main函数的下一步语句,此处故使用call指令
call:(1)将当前call命令的下一条指令的地址以入栈的方式保存起来,用作恢复(2)以jmp方式跳转。
此处call存储了printf(“hehe\n”);语句的地址。

5.上述步骤均做完以后,就可以正式的进入函数调用了,首先与main函数一样,只要函数被调用,就要为他分配一段空间作为栈帧空间:
(1)先对ebp做入栈操作,ebp是指向main函数栈底的指针,此处入栈就是为了保存main函数栈底的位置,为ebp后期返回原处做好标记
这里写图片描述
(2)令ebp指向esp所指向的位置
(3)esp减OCCh。(add----加 sub----减 mul----乘 div----除)
此时fun函数的栈帧空间也就分配完毕了。
这里写图片描述
6.令a的值存入寄存器,在用add指令将a与b加起来,仍然存在寄存器中

7.将a+b的值存在ebp+4处,此句即int c=a+b;

8将c存入寄存器,用做返回值。
这里写图片描述
9.进行到这一步,fun函数的调用就算结束了。接下来要释放fun函数占用的栈帧空间:令esp指向ebp所指向的地址。
这里写图片描述
10.做出栈操作,并将出栈元素存储在ebp中(刚好,栈顶元素为最初main函数栈底的地址,此处出栈,令ebp还原的最初的状态----指向main函数的栈底)

这里写图片描述

11.最后执行ret操作,刚好栈顶元素是在调用fun函数前存的main函数中的下一条地址。所以cpu会重新返回到main函数执行调用fun的下一条语句,esp+8是栈顶指针也还原到调用函数之前的位置。
这里写图片描述

这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值