函数的__cdecl、__stdcall、__fastcall、__thiscall、naked call介绍
2016-05-10 10:22
691 查看
调用方式:
__cdecl 是 C Declaration 的缩写,表示C语言默认的函数调用方法:所有参数从右到左依次入栈。这些参数在函数返回后由外部调用者清除,称为手动清栈。在外部使用addesp,x 平衡堆栈,x是参数所占的总字节数。利用此特性可以实现可变参数的函数功能。
__stdcall 是 Standard Call 的缩写,是C++的标准调用方式:所有参数从右到左依次入栈。如果用此方法调用类成员函数,最后一个入栈的是this指针。这些参数由函数自己内部在返回时清除,称为自动清栈。返回时使用retn
x 平衡堆栈,x表示参数所占的总字节数。
__fastcall 是通过寄存器来传递参数的,利用 ECX 和 EDX 传送前两个双字(DWORD)或更小的参数。如果还有更多的参数,则从右到左依次入栈。这些由堆栈传送的参数,由函数自己内部在返回时清除,即自动清栈。返回时使用retn
x 平衡堆栈,x表示使用堆栈传送的参数的总字节数。
__thsicall 是仅仅应用于C++成员函数。this指针存放于 ECX 寄存器(该寄存器由编译器指定),参数从右到左依次入栈,与__stdcall相同,返回时自动清栈。__thiscall
不是关键词,因此不能被程序员指定。在VC中编译器使用 ECX 传递,在Borland中使用 EAX 传递。
nake call 是裸函数调用方式。不对EBP、ESP做处理,函数体不做任何附带操作。用 __declspec(nake) 定义,调用方式依据编译器中,设定的默认调用约定方式设定。
调用名称约定:
__cdecl 是在函数名前加上一个下划线前缀,格式为_functionname。__stdcall 是在函数名前加上一个下划线前缀,在后边加上一个@符号和其参数的总字节数。
__fastcall 是在函数名前加上一个@符号,在后边也加上一个@符号和其参数的总字节数。
__thiscall 是在函数名前加上类名和::符号。
nake call 是依据编译器设定的调用约定方式。
调用方式设定:
在VS中编译器缺省状态为/Gd,即__cdecl方式。__stdcall对应为/Gz,__fastcall对应为/Gr。我们写段程序对比一下反汇编代码就能明白:
#define EXPORT __declspec(dllexport) extern "C"{ EXPORT void __cdecl FunA(int a, int b, int c){} EXPORT void __stdcall FunB(int a, int b, int c){} EXPORT void __fastcall FunC(int a, int b, int c){} class CClassA { public: void EXPORT __thiscall FunD(int a, int b, int c){} }; EXPORT void __declspec(naked) FunE(int a, int b, int c){} } int __cdecl main(int argc, char* argv[]) { CClassA obj; FunA(1, 2, 3); // __cdecl FunB(1, 2, 3); // __stdcall FunC(1, 2, 3); // __fastcall obj.FunD(1, 2, 3); // __thiscall FunE(1, 2, 3); // naked call return 0; }
对应的反汇编代码是:
CClassA obj; FunA(1, 2, 3); // __cdecl 011514F8 6A 03 push 3 011514FA 6A 02 push 2 011514FC 6A 01 push 1 011514FE E8 42 FC FF FF call _FunA (01151145h) 01151503 83 C4 0C add esp,0Ch FunB(1, 2, 3); // __stdcall 01151506 6A 03 push 3 01151508 6A 02 push 2 0115150A 6A 01 push 1 0115150C E8 02 FC FF FF call _FunB@12 (01151113h) FunC(1, 2, 3); // __fastcall 01151511 6A 03 push 3 01151513 BA 02 00 00 00 mov edx,2 01151518 B9 01 00 00 00 mov ecx,1 0115151D E8 C9 FB FF FF call @FunC@12 (011510EBh) obj.FunD(1, 2, 3); // __thiscall 01151522 6A 03 push 3 01151524 6A 02 push 2 01151526 6A 01 push 1 01151528 8D 4D F7 lea ecx,[obj] 0115152B E8 B1 FB FF FF call CClassA::FunD (011510E1h) FunE(1, 2, 3); // naked call 01151530 6A 03 push 3 01151532 6A 02 push 2 01151534 6A 01 push 1 01151536 E8 14 FC FF FF call _FunE (0115114Fh) 0115153B 83 C4 0C add esp,0Ch
相关文章推荐
- pods 常用
- APP引导页我的初稿
- 一次失败的刷题经历:[LeetCode]292之尼姆游戏(Nim Game)
- caffe如何将图片数据写成lmdb格式
- Java BIO、NIO、AIO基础概念
- jQuery分析(1) - 介绍
- MHA参数 转
- targetSdkVersion 23以下6.0中调用requestPermissions()的问题
- 使用Spring进行远程访问与Web服务[转]
- 微信公众号开发踩坑记录(二)
- 待后续了解
- 总结1
- 第五届河南省acm省赛 奇怪的排序
- 设置不同jdbc的MaxActive数,吞吐量会有差异
- Apache与tomcat整合配置
- thinkphp 分组、页面跳转与ajax
- 数据分析/数据挖掘/机器学习---- 必读书目
- java集合类深入分析之List篇
- 【动态规划】最长公共子序列问题(LCS)
- 学会自己测天气系列八卦基础 01