通过VC学习反汇编——函数调用:调用约定
来源:互联网 发布:55寸国产电视 知乎 编辑:程序博客网 时间:2024/06/10 12:40
3 调用约定
调用约定决定了以下内容:函数参数的压栈顺序、由调用者还是被调用者平衡堆栈。
3.1 __cdecl
__cdecl是C和C++程序的默认调用约定:参数通过堆栈来传递,从右向左依次入栈,由调用者平衡堆栈。
同样的代码,我们在AddInt函数前面加上__cdecl调用约定
int __cdecl AddInt(int a, int b){ int c = a+b; return c;}
F5运行断下后,按“ALT+F8”打开反汇编窗口,没有任何变化,和没加__cdecl一样,说明默认调用约定就是__cdecl。
3.2 __stdcall
同样的代码,我们在AddInt函数前面加上__stdcall调用约定
int __stdcall AddInt(int a, int b){ int c = a+b; return c;}
再反汇编看看main函数里,调用的过程如下
9: int x = AddInt(1, 3);00401078 push 30040107A push 10040107C call @ILT+10(AddInt) (0040100f)
参数还是一样从右向左依次入栈,但是没有了add esp,8这句,那谁来平衡堆栈呢?看看AddInt函数的反汇编的最后一条指令:
0040104A ret 8
这一句就相当于
retadd esp,8
所以__stdcall的调用约定是参数通过堆栈来传递,从右向左依次入栈,由被调用者平衡堆栈。
一般Windows API函数都是__stdcall,在Windef.h中可以找到如下的定义:
#define WINAPI __stdcall
3.3 __fastcall
同样的代码,我们在AddInt函数前面加上__fastcall调用约定
int __fastcall AddInt(int a, int b){ int c = a+b; return c;}
再反汇编看看main函数里,调用的过程如下
9: int x = AddInt(1, 3); 00401078 mov edx,30040107D mov ecx,100401082 call @ILT+0(AddInt) (00401005)
可以看到,两个参数分别用ECX和EDX传递。如果更多参数会怎么样呢?
int __fastcall AddInt(int a, int b, int c, int d){ int e = a+b+c+d; return e;}
调用的过程如下:
9: int x = AddInt(1, 3, 7, 9);00401078 push 90040107A push 70040107C mov edx,300401081 mov ecx,100401086 call @ILT+15(AddInt) (00401014)
可以看出来,__fastcall的调用约定是:第一个参数通过ECX传递,第二个参数通过EDX传递,第三个参数起从右向左依次入栈,由被调用者平衡堆栈。
3.4 类的成员函数
对于类的成员函数来说,除了要传递普通的参数,还有一个隐藏的参数——this指针。
class Example{public:int AddInt(int a, int b){int c = a+b;return c;}};int main(){Example a;a.AddInt(1, 3);return 0;}反汇编看一下调用的过程:
16: a.AddInt(1, 3);0040B468 push 30040B46A push 10040B46C lea ecx,[ebp-4]0040B46F call @ILT+5(Example::AddInt) (0040100a)
在调用之前,多了一个指令lea ecx,[ebp-4],这一句实际上就是将this指针传递给ECX,可以看出来,类成员函数的默认调用约定是:参数通过堆栈来传递,从右向左依次入栈,由被调用者平衡堆栈栈,this指针通过ECX传递。除了this指针,其他都和__stdcall相同。
所以我们只要看到call调用前,某个地址传递给了ECX,就可以知道十有八九调用的是一个类成员函数。
值得注意的是VC编译器默认使用ECX传递this指针,但是Borland C++编译器却是用EAX,不同的编译器处理的方式不一样。
更进一步,如果指定类的成员函数调用约定为__cdecl、__stdcall或者是__fastcall,会是什么情况呢?
3.4.1 __cdecl
15: a.AddInt(1, 3);00401038 push 30040103A push 10040103C lea eax,[ebp-4]0040103F push eax00401040 call @ILT+20(Example::AddInt) (00401019)00401045 add esp,0Ch
3.4.2 __stdcall
15: a.AddInt(1, 3);00401038 push 30040103A push 10040103C lea eax,[ebp-4]0040103F push eax00401040 call @ILT+0(Example::AddInt) (00401005)
3.4.3 __fastcall
15: a.AddInt(1, 3);00401038 push 30040103A mov edx,10040103F lea ecx,[ebp-4]00401042 call @ILT+10(Example::AddInt) (0040100f)
可以看出,如果指定了调用约定,实际上编译器把this指针当成函数的第一个参数进行处理了。
- 通过VC学习反汇编——函数调用:调用约定
- 通过VC学习反汇编——函数调用
- VC++学习笔记之函数调用约定
- 通过VC学习反汇编——汇编初步
- 函数调用反汇编
- 函数调用反汇编
- 反汇编时的函数识别及各函数调用约定的汇编代码分析
- 反汇编时的函数识别及各函数调用约定的汇编代码分析
- 剖析VC++函数调用约定
- 剖析VC++函数调用约定
- 剖析VC++函数调用约定
- 剖析VC++函数调用约定
- 剖析VC++函数调用约定
- VC函数调用约定[转贴]
- 通过反汇编来分析简单函数调用过程(***)
- C++反汇编代码分析——函数调用
- 反汇编之函数调用
- C++反汇编学习笔记3——函数的调用方式
- 使用天乐软件加密狗(JDProtect)保护您的软件,防止程序被跟踪/逆向/反编译/破解
- http://poj.org/problem?id=1287&&prim
- 谈谈我对数据结构
- ubuntu是linux家族中的祸害
- 数据结构线性表习题(二)
- 通过VC学习反汇编——函数调用:调用约定
- 如何获取客户端浏览器类型(PHP)
- 腾讯笔试附加题(C/C++)2011-10-10
- oreilly java swing : JTable 之 Table Data
- Windows Phone 监视内存使用情况
- 用OnCreate()和OnInitDialog()在对话框上动态创建控件,但他们有什么不同吗?
- CMS Error 500
- 三级联动 修改部分
- 动态库编译 error LNK2019