函数的调用过程,栈帧的创建和销毁
来源:互联网 发布:c语言getch和getchar 编辑:程序博客网 时间:2024/06/05 05:25
我在通过调试时,看反汇编上的步骤来分析函数的调用过程,栈帧的创建和销毁。
原码如下:
#include <stdio.h>int Add(int x,int y){int sum = 0;sum = x+y;return (sum);}int main(){int a = 2;int b = 3;int ret = 0;ret = Add(a,b);return 0;}
按f10,并转到反汇编
转到反汇编时,看到各种没见过的标识符,一脸蒙蔽,所以我们先了解这些标识符都是干嘛的。
esp:esp寄存器里存储的是在调用函数之后,栈的栈顶。并且始终指向栈顶。
ebp:ebp寄存器里存储的是是栈的栈底指针,通常叫栈基址,这个是一开始进行函数调用之前,由esp传递给ebp的。(在函数调用前你可以这么理解:esp存储的是栈顶地址,也是栈底地址。)
push:压入操作,把一个32位的操作数压入堆栈中,这个操作在32位机中会使得esp被减4(字节),esp通常是指向栈顶的,这里顶部是地址小的区域,那么,压入堆栈的数据越多,esp也就越来越小
mov:数据传送。第一个参数是目的操作数,第二个参数是源操作数,就是把源操作数拷贝到目的一份。
lea:取得第二个参数地址后放入到前面的寄存器(第一个参数)中。
rep stos:rep指令的目的是重复其上面的指令.ECX的值是重复的次数.
STOS指令的作用是将eax中的值拷贝到ES:EDI指向的地址
———————————————————————————————————————————————————
这些简单的指令了解了以后我们来用图片和文字解释
1.
2.开始调用main函数;执行第一条指令
push ebp //压栈,放入一个ebp在栈顶,而esp始终指向栈顶,所以如图
3.执行第二条语句
mov ebp,esp //将esp赋予ebp ,ebp和esp暂时指向同一位置。
4.执行第三条语句
sub esp,0E4h //将esp减去0E4h,0E4h是16进制数,由于开辟的栈空间是由高到低,所以esp往上走0E4h.
5.执行push ebx
push esi
push edi //这里的 ebx,esi ,edi,为三个寄存器,分别压栈。此时为main开辟的空间不够了,就再往上加三块。
6.接下来执行
leaedi,[ebp-0E4h] //看上图,将ebx的地址传到edi中
movecx,39h//将39h数值传给ecx寄存器中
moveax,0CCCCCCCCh//将0CCCCCCCCh传给eax寄存器中
rep stosdword ptr es:[edi]//从edi中的地址(相当于ebx)向下拷贝eax中内容,ecx次
到这里main 函数调用完成。
———————————————————————————————————————————————————
再看自己想写出的逻辑
1.当给a赋值2时,我们看一下内存变化
在ebp-4位置上赋值2。而此时a=2局部变量已经创建,局部变量在栈上创建,说明现在开辟的空间就在栈上,所以这块空间叫做栈帧。
依次给变量b,ret赋值3,0.
2.准备调用Add函数
将b变量的值赋给eax,并将eax压栈,将a变量值赋给ecx,并压栈,
call指令下一条指令的地址,并压栈(函数调用完用它返回)
此时按F11进入Add函数。
———————————————————————————————————————————————————
1.执行前10条指令(和开辟main函数空间类似)
push ebp//ebp压栈,此时ebp为main函数栈帧中的ebp
mov ebp,esp //将esp传给ebp
sub esp,0cch//给Add函数预开辟一块空间
//...//初始化空间0ccccccccch
2.给变量sum初始化并传值。
mov dword ptr [epb-8],0 //给ebp-8处给sum初始化0,为什么是ebp-8不是ebp-4呢,这是因为VS2010在Debug模式下,int变量占用12个字节。可以这样认为,Debug模式下,在int变量的附近增加了8个字节,用于存储调试信息。当我们把模式设为Release,就会发现栈上连续定义的int变量,地址相差4个字节。
moveax,dword ptr [epb+8]//把eax+8处的值(看上图ebp下两格处a),传给eax
addeax,dword ptr [epb+0ch]//把eax加上 ebp+0ch处的值(看上图ebp下三格处b),传给eax
movdword ptr [epb-8],eax//把eax的值传给sum
给sum传值完成
此时 return (sum),并且
moveax,dword ptr [epb-8]//将sum的值存在寄存器eax中
接下来出栈。。不容易。。。
———————————————————————————————————————————————————
前三行指令,分别将寄存器pop出栈,
movesp,ebp//将esp栈顶下移
popebp//将ebp出栈,此时下面还有一ebp,相当于下移。
ret//回到call指令的下一条指令。相当于将call指令pop出栈。
此时转跳到了esp指向处(call指令下条指令)
———————————————————————————————————————————————————
addesp,8//esp向下跳两格
movdword ptr [ebp-20h],eax//将eax,也就是之前sum的值5传给ebp-20h处,看之前的图,ret就是ebp-20处。所以就酱sum的值传给了ret
———————————————————————————————————————————————————
就算完成了吧。
小结:仔细思考,慢慢推,规律就出来了。最重要就是耐心。
- 函数的调用过程,栈帧的创建和销毁
- 函数的调用过程,栈帧的创建和销毁。
- 函数的调用过程,栈帧的创建和销毁
- 函数的调用过程,栈帧的创建和销毁。
- 函数的调用过程,栈帧的创建和销毁
- 函数的调用过程,栈帧的创建和销毁
- 函数调用过程,栈帧的创建和销毁
- 函数调用过程,栈帧的创建和销毁
- 函数的调用过程,栈桢的创建和销毁
- 函数的调用过程,栈桢的创建和销毁。
- 函数的调用过程、栈帧的创建以及销毁
- 函数的调用过程,栈帧的创建与销毁
- 【C】函数的调用过程,栈帧的创建和销毁
- 谈谈函数的调用过程,栈帧的创建和销毁。
- 函数的调用过程(栈帧的创建和销毁)
- 浅谈函数的调用过程,栈帧的创建和销毁,附图讲解
- 函数调用的具体过程以及栈帧的创建和销毁
- 第三篇 函数的调用过程 栈帧的创建和销毁
- 输入URL到展现页面的全过程
- java学习笔记一
- windows下安装Python
- 训练营第二天学习笔记
- 基于java的socket编程
- 函数的调用过程,栈帧的创建和销毁
- 串口通信
- Ambiguous mapping found. Cannot map 'xx' method
- 逻辑思维题之分桃问题
- shell 中 贪婪匹配 和 非贪婪匹配
- Direct3D学习笔记(三)——精灵变换(Srote_Scale)
- 指针小笔记1
- c++智能指针
- 5分钟OracleDBA--搜索技能