栈帧步骤解读

来源:互联网 发布:unity3d控制物体跳跃 编辑:程序博客网 时间:2024/06/05 10:46

各寄存器,指令:
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是栈顶指针也还原到调用函数之前的位置。

原创粉丝点击