从汇编的角度分析函数调用过程(1)
2018-02-12 11:08
519 查看
一. 函数参数传递形式
函数的参数传递有2种方式:堆栈方式、
寄存器方式。
如果是堆栈方式传递的,就需要定义函数参数在堆栈中的传递顺序,并约定函数被调用之后,由谁来平衡堆栈;
如果是寄存器方式传递的,就需要确定参数存放在哪个寄存器中。
每一种方式都有其优缺点,而且与使用的编程语言有关系,不存在哪种方式好与坏。
我们在开发中经常遇到
调用约定类型,如
__cdecl、
stdcall、
PASCAL、
fastcall。这些调用约定类型就用来指定函数参数的传递方式的。上面几种约定类型,除了
fastcall是使用寄存器方式传递参数外,其他的都是使用堆栈传递参数的。
Visual Studio中的C++工程,可以
C++–>
高级–>
调用约定中进行调用约定的设置:
二. 使用堆栈方式传递函数参数
堆栈是一种“后进先出”的数据结构,ESP寄存器始终指向栈顶。栈中数据地址从底部到顶部依次减小,也就是说,栈底对应高地址,栈顶对应低地址。
调用函数时,调用者依次把参数压栈,然后调用函数,函数被调用之后,在堆栈中取得参数数据。函数调用结束以后,堆栈需要恢复到函数调用之前的样子,而到底是由调用者来恢复还是由函数自身来恢复,根据不同的调用约定类型采用不同的方式。
约定类型 | __cdecl | stdcall | PASCAL | fastcall |
---|---|---|---|---|
参数传递顺序 | 从右到左 | 从右到左 | 从左到右 | 使用寄存器 |
堆栈平衡者 | 调用者 | 函数自身 | 函数自身 | 函数自身 |
__cdcel是C/C++/MFC程序默认的调用约定。
stdcall是绝大多数Win32 API函数的约定方式,也有少部分使用
__cdcel约定方式(如wsprintf等)。
在Windows C/C++开发中常用的就是
__cdecl和
stdcall这2种调用约定。
按照不同的
调用约定来调用函数
int add(int a, int b)。从调用者的视角来看,其汇编代码分别表示如下:
__cdecl
push b ;参数按从右到左传递 push a call add add esp, 8 ;调用者在函数外部平衡堆栈
stdcall
push b ;参数按从右到左传递 push a call add ;函数自己内部平衡堆栈,调用者不需要平衡堆栈
在函数调用过程中,参数入栈的过程如图:
上图中,
EBP和
函数返回地址ret都是32位地址。因为函数调用完之后会将
EBP恢复为暂存在堆栈中的原
EBP值,所以从调用者角度来看,在函数的一次调用过程中
EBP是不会变化的。
我们可以在函数中通过新的
EBP获取函数各个参数的值:
参数a = EBP + 0x8 参数b = EBP + 0xC
相关文章推荐
- 从汇编的角度分析函数调用过程(2)
- c语言内部(汇编代码分析)函数调用过程探究
- 函数调用过程-汇编代码分析
- 汇编学习笔记:函数调用过程中的堆栈分析
- 从汇编角度分析C语言的过程调用
- 汇编代码分析----函数的调用堆栈过程(进程内核栈的切换过程)
- 汇编学习:函数调用过程中的堆栈分析
- IDA 汇编命令分析以及函数调用过程
- 献给汇编初学者-函数调用堆栈变化分析
- C/C++—— 在构造函数中调用虚函数能实现多态吗(Vptr指针初始化的过程分析)
- 驱动调试之段错误分析_根据栈信息确定函数调用过程
- win32汇编一定要记住的函数调用过程
- C函数调用过程原理及函数栈帧分析
- 反汇编深入分析函数调用
- 从汇编角度来理解linux下多层函数调用堆栈运行状态
- lua2.1函数调用过程分析(完善中)
- c函数调用过程原理及函数栈帧分析
- 献给汇编初学者-函数调用堆栈变化分析
- 关于 接口与对象指针对成员函数的调用时的汇编执行行为分析
- Linux汇编---函数调用过程