函数调用约定
__cdecl 缺省调用方式,函数采用从右到左的压栈方式,调用方清理堆栈,注意可变参数
__stdcall 函数的参数自右向左通过栈传递,被调用方清理堆栈
__fastcall 通过寄存器来传送参数,被调用方清理堆栈
__thiscall用于C++成员函数,使用ecx存放this指针
naked call 裸函数,上面几种方式会产生保存一些寄存器的代码,这种不产生。naked call不是类型修饰符,必须和_declspec共同使用
__declspec(naked) 是告诉编译器 不要对函数进行优化 函数的所有实现包括堆栈的平衡 参数的压栈 ebp的赋值 还原 都要我们来做
决定以下内容:
1)函数参数的压栈顺序
2)由调用者还是被调用者把参数弹出栈
3)以及产生函数修饰名的方法
修饰名
1、修饰名(Decoration name):"C"或者"C++“函数在内部(编译和链接)通过修饰名识别
2、C编译时函数名修饰约定规则:
__stdcall调用约定在输出函数名前加上一个下划线前缀,后面加上一个”@"符号和其参数的字节数,格式为_functionname@number,
例如 :function(int a, int b),其修饰名为:_function@8
__cdecl调用约定仅在输出函数名前加上一个下划线前缀,格式为_functionname。
__fastcall调用约定在输出函数名前加上一个"@“符号,后面也是一个”@"符号和其参数的字节数,格式为@functionname@number。
注:
1 2 3
| 一般WIN32的函数都是__stdcall #define CALLBACK __stdcall #define WINAPI __stdcall
|
例子
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
| #include <stdio.h> #include <Windows.h>
int cAdd(int a, int b, int c) { return a + b + c; }
int __stdcall stdAdd(int a, int b, int c) { return a + b + c; }
int __fastcall fastAdd(int a, int b, int c) { return a + b + c; }
int __declspec(naked) nkAdd(int a, int b, int c) { __asm { push [esp + 0ch] push [esp + 0ch] push [esp + 0ch] call stdAdd mov eax,eax ret } }
int main(void) { int result; __asm { mov eax,eax mov eax,eax mov eax,eax } result = cAdd(1,2,3); printf("%d",result); stdAdd(1,2,3); printf("%d",result); fastAdd(1,2,3); printf("%d",result); nkAdd(1,2,3); printf("%d",result); system("pause"); return 0; }
|