深度剖析函数的调用过程
2017-11-05 21:53
260 查看
我们先从一个简单的小程序看起
在函数的执行期间,我们可以打开调用堆栈
我们可以看到其实main函数并不是第一个被调用的函数,程序在运行时第一个被调用的函数是mainCRTStartup,然后mainCRTStartup 函数在调用 ___tmainCRTStartup 函数,之后__tmainCRTStartup函数在调用main函数,由此可见我们知道函数其实是一级一级调用的,这个过程就叫做函数的调用,在函数调用的过程中会开辟栈空间,用来保护函数参数,这就叫做函数的栈桢。
在正式开始分析函数调用之前,我们先来了解几个寄存器
ebp:保存指向栈底指针的寄存器
esp:保存指向栈顶指针的寄存器
eip/pc/ip:程序计数器(永远指向下一条指令(即下一条指令的地址))
eap:临时寄存器
我们用汇编语言来分析,先来了解几个汇编指令的作用
call:通过修改ip来实现函数跳转(当前正在执行指令的下一条指令的地址保存起来)
jmp:将当前正在执行指令的下一条指令的地址压入栈中
pop:单独为出栈后加寄存器为将值放入寄存器中
ret:弹出栈顶返回值到eap
sub:
_ asm _:写汇编(用c控制汇编)
1.先来看main函数的调用(main函数栈桢的调用)
main函数被-tmainCRTStartup调用,栈是自下往上生长,下面是高地址,上面是低地址,所以main函数的栈桢应在-tmainCRTStartup函数栈桢的上面。
main函数栈桢形成时,ebp指向栈底,之后ebx,esi,ebi相继入栈,此时ebi保存三个寄存器入栈之前的指向地址,然后给main函数预开辟空间,然后实参相继入栈,先a后b
2.Add函数的调用
之后形参压栈,从右往左先b后a
之后call指令将函数跳转到Add函数处,执行Add函数
3.Add函数的创建和返回过程
Add函数先将main函数给Add函数预开辟的空间初始化为0xcccccccch
ebx,esi,ebi相继如何入栈
之后首先入栈并初始化为0之后,获取形参x和y相加将结果保存到z中放在eax中,通过eax带回函数的返回值
开始出栈:esp下移,ebi,esi,ebx相继出栈
将ebp的值赋给esp,即都指向Add函数的栈底,之后出栈将出栈的内容保存在ebp中之后回到main函数的栈桢
至此,函数的调用已经全部完成
#define _CRT_SECURE_NO_WARNINGS 1 #include<stdio.h> int Add(int x, int y) { int z = 0; z = x + y; return z; } int main() { int a = 10; int b = 20; int ret = Add(a, b); printf("%d", ret); system("pause"); return 0; }
在函数的执行期间,我们可以打开调用堆栈
我们可以看到其实main函数并不是第一个被调用的函数,程序在运行时第一个被调用的函数是mainCRTStartup,然后mainCRTStartup 函数在调用 ___tmainCRTStartup 函数,之后__tmainCRTStartup函数在调用main函数,由此可见我们知道函数其实是一级一级调用的,这个过程就叫做函数的调用,在函数调用的过程中会开辟栈空间,用来保护函数参数,这就叫做函数的栈桢。
在正式开始分析函数调用之前,我们先来了解几个寄存器
ebp:保存指向栈底指针的寄存器
esp:保存指向栈顶指针的寄存器
eip/pc/ip:程序计数器(永远指向下一条指令(即下一条指令的地址))
eap:临时寄存器
我们用汇编语言来分析,先来了解几个汇编指令的作用
call:通过修改ip来实现函数跳转(当前正在执行指令的下一条指令的地址保存起来)
jmp:将当前正在执行指令的下一条指令的地址压入栈中
pop:单独为出栈后加寄存器为将值放入寄存器中
ret:弹出栈顶返回值到eap
sub:
_ asm _:写汇编(用c控制汇编)
1.先来看main函数的调用(main函数栈桢的调用)
main函数被-tmainCRTStartup调用,栈是自下往上生长,下面是高地址,上面是低地址,所以main函数的栈桢应在-tmainCRTStartup函数栈桢的上面。
main函数栈桢形成时,ebp指向栈底,之后ebx,esi,ebi相继入栈,此时ebi保存三个寄存器入栈之前的指向地址,然后给main函数预开辟空间,然后实参相继入栈,先a后b
2.Add函数的调用
之后形参压栈,从右往左先b后a
之后call指令将函数跳转到Add函数处,执行Add函数
3.Add函数的创建和返回过程
Add函数先将main函数给Add函数预开辟的空间初始化为0xcccccccch
ebx,esi,ebi相继如何入栈
之后首先入栈并初始化为0之后,获取形参x和y相加将结果保存到z中放在eax中,通过eax带回函数的返回值
开始出栈:esp下移,ebi,esi,ebx相继出栈
将ebp的值赋给esp,即都指向Add函数的栈底,之后出栈将出栈的内容保存在ebp中之后回到main函数的栈桢
至此,函数的调用已经全部完成
相关文章推荐
- 函数调用过程(栈帧)的剖析和图解
- 666深度讲解函数调用过程
- 函数调用过程栈帧变化详解
- 调用PostgreSQL存储过程,找不到函数名的问题
- MyBatis中调用存储过程和函数
- 分析linux下的进程地址空间,以及c语言的函数调用过程
- 函数调用的过程
- 函数调用过程中所有参数的提取
- java调用存储过程和函数
- java中使用jdbc和mybatis调用数据库中的存储过程和函数
- 深入理解计算机系统(3.7)------过程(函数的调用原理)
- Delphi MDI程序 父窗体如何调用当前活动子窗体的函数/过程
- 深度剖析WinPcap之(九)——数据包的发送过程(3)
- OTL调用存储过程和函数
- 深度剖析WinPcap之(九)――数据包的发送过程(10)
- 小结 | 函数的调用过程(栈帧)
- nginx 源码学习笔记(十九)—— nginx启动过程函数调用图
- C 函数调用过程Ollydbg 反汇编分析 Demo int add(int,int)
- 栈帧与函数调用过程分析
- 函数调用的过程