函数的调用过程,栈桢的创建和销毁。
来源:互联网 发布:2017美剧 知乎 编辑:程序博客网 时间:2024/06/05 06:58
函数的调用过程,栈桢的创建和销毁
我们首先要知道关于函数的调用,我们知道main函数也是要被调用的,在_tmainCRTStartup函数中调用,而_tmainCRTStartup函数是在mainCRTStartup中被调用的。
函数调用过程要为函数开辟栈空间,用于本次函数调用中临时变量的保存,称为函数栈桢。
下面我用一个简单的程序说明函数的调用过程:
#include<stdio.h>#include<string>int Add(int x, int y){int sum = 0;sum = x + y;return sum;}int main(){int a = 1;int b = 2;int ret = 0;ret = Add(a, b);printf("%d", ret);system("pause");return 0;}
在这个程序里,主函数定义了3个局部变量,然后调用了Add函数。三个局部变量都在栈空间上存放。
可是当程序运行起来后,main函数是如何实现对Add函数的调用过程呢?我们转到反汇编一步步分析一下。
下面是main函数的汇编代码(在VS2013平台下):
int main(){009253D0 push ebp 009253D1 mov ebp,esp 009253D3 sub esp,0E4h 009253D9 push ebx 009253DA push esi 009253DB push edi 009253DC lea edi,[ebp-0E4h] 009253E2 mov ecx,39h 009253E7 mov eax,0CCCCCCCCh 009253EC rep stos dword ptr es:[edi] int a = 1;009253EE mov dword ptr [a],1 int b = 2;009253F5 mov dword ptr [b],2 int ret = 0;009253FC mov dword ptr [ret],0 ret = Add(a, b);00925403 mov eax,dword ptr [b] 00925406 push eax 00925407 mov ecx,dword ptr [a] 0092540A push ecx 0092540B call Add (0921113h) 00925410 add esp,8 00925413 mov dword ptr [ret],eax printf("%d", ret);00925416 mov esi,esp 00925418 mov eax,dword ptr [ret] 0092541B push eax 0092541C push 92CC7Ch 00925421 call dword ptr ds:[93019Ch] 00925427 add esp,8 0092542A cmp esi,esp 0092542C call __RTC_CheckEsp (09212E4h) system("pause");00925431 mov esi,esp 00925433 push 92CD34h 00925438 call dword ptr ds:[930184h] 0092543E add esp,4 00925441 cmp esi,esp 00925443 call __RTC_CheckEsp (09212E4h) return 0;00925448 xor eax,eax }0092544A pop edi }0092544B pop esi 0092544C pop ebx 0092544D add esp,0E4h 00925453 cmp ebp,esp 00925455 call __RTC_CheckEsp (09212E4h) 0092545A mov esp,ebp 0092545C pop ebp 0092545D ret
1、从main函数的调用开始,需要为main函数创建函数栈桢。
int main(){009253D0 push ebp //将ebp压入栈底009253D1 mov ebp,esp //将esp的值赋给ebp,得到新的ebp009253D3 sub esp,0E4h //将esp的值减去0E4h,得到新的esp009253D9 push ebx //从低地址到高地址三次压栈压入三个寄存器ebx、009253DA push esi //esi、 009253DB push edi //edi009253DC lea edi,[ebp-0E4h] //加载有效地址009253E2 mov ecx,39h //将加载到edi的地址重复拷贝ecx次,009253E7 mov eax,0CCCCCCCCh //即把main函数预开辟的空间全部初始化为0CCCCCCCCh009253EC rep stos dword ptr es:[edi] //重复拷贝int a = 1;009253EE mov dword ptr [a],1 //处理局部变量a,把1赋给aint b = 2;009253F5 mov dword ptr [b],2 // 处理局部变量b,把2赋给bint ret = 0;009253FC mov dword ptr [ret],0 ret = Add(a, b);00925403 mov eax,dword ptr [b] 00925406 push eax 00925407 mov ecx初始化如下,调试可知:
2、Add函数的调用,参数传递过程如下:
int ret = 0;011C540C mov dword ptr [ret],0 //ret的初始化ret = Add(a, b);011C5413 mov eax,dword ptr [b] //将b的值赋给eax,压栈eax,形参b的实例化011C5416 push eax 011C5417 mov ecx,dword ptr [a] //将a的值赋给ecx,压栈ecx,形参a的实例化011C541A push ecx 011C541B call Add (011C1113h) //调用,压栈call指令的下一条指令的地址,再跳转到Add函数的地方011C5420 add esp,8 011C5423 mov dword ptr [ret],eax printf("%d", ret);
继续调试,进入Add函数:
#include<stdio.h>#include<string>int Add(int x, int y){011C3860 push ebp //压入ebp011C3861 mov ebp,esp //将esp的值赋给ebp011C3863 sub esp,0CCh //将esp的值减去0CCh011C3869 push ebx 011C386A push esi 011C386B push edi 011C386C lea edi,[ebp-0CCh] //加载有效地址011C3872 mov ecx,33h 011C3877 mov eax,0CCCCCCCCh //初始化开辟的空间011C387C rep stos dword ptr es:[edi] //重复拷贝int sum = 0;011C387E mov dword ptr [sum],0 //创建sum,并初始化sum = x + y;011C3885 mov eax,dword ptr [x] //将形参x的值赋给eax011C3888 add eax,dword ptr [y] //将形参y的值赋给eax011C388B mov dword ptr [sum],eax //将相加后的值存储到sum中return sum;011C388E mov eax,dword ptr [sum] //将sum的值赋给eax,即将结果存储到寄存器中}011C3891 pop edi //出栈011C3892 pop esi //出栈 011C3893 pop ebx //出栈 011C3894 mov esp,ebp //将ebp的值赋给esp,使esp向下移动011C3896 pop ebp //出栈,将出栈的内容保存在ebp中,回到main的栈桢011C3897 ret //出栈一次,并将出栈的内容当做地址,将程序执行跳转到该地址处
跳转到Add函数处,
以上是简单的过程介绍,下面是栈桢创建的模拟过程图:
阅读全文
3 0
- 函数的调用过程,栈桢的创建和销毁
- 函数的调用过程,栈桢的创建和销毁。
- 函数的调用过程,栈帧的创建和销毁
- 函数的调用过程,栈帧的创建和销毁。
- 函数的调用过程,栈帧的创建和销毁
- 函数的调用过程,栈帧的创建和销毁。
- 函数的调用过程,栈帧的创建和销毁
- 函数的调用过程,栈帧的创建和销毁
- 函数调用过程,栈帧的创建和销毁
- 函数调用过程,栈帧的创建和销毁
- 从最简单的add函数调用过程分析函数栈桢创建和销毁的过程
- 函数的调用过程、栈帧的创建以及销毁
- 函数的调用过程,栈帧的创建与销毁
- 【C】函数的调用过程,栈帧的创建和销毁
- 谈谈函数的调用过程,栈帧的创建和销毁。
- 函数的调用过程(栈帧的创建和销毁)
- 浅谈函数的调用过程,栈帧的创建和销毁,附图讲解
- 函数调用的具体过程以及栈帧的创建和销毁
- 《Ray Tracing in One Weekend》——Chapter 5: Surface normals and multiple objects
- 一步步搭建Spring+Spring MVC+Hibernate系统框架+登录与注册功能
- 面向对象的三大特性之一封装
- Java实现无向无权图的邻接矩阵的存储
- 图的广度优先遍历-数据结构(21)
- 函数的调用过程,栈桢的创建和销毁。
- PHP中的"@"符号
- 汇编--进制
- unity简单的聊天socket编程
- linux下socket函数总结
- 打包pod的命令集合
- libevent windows vs2010
- POJ 3984 迷宫问题
- 使用Git进行产品代码管理的总结