=========调用约定整理总=================================
调用约定可以在Project->Setting...->C/C++->Code Generation中的
Calling convention中进行设置,缺省状态为__cdecl
例如对于函数:
void func(int a,int b,int c,int d)
{
///////////
}
int main()
{
func(1, 2, 3, 4);
}
1.如果函数func是__cdecl,调用时情况如下
int main()
{
//参数从右到左压栈
push 4
push 3
push 2
push 1
call func
add esp 0x10 //调用者恢复堆栈指针esp,4个参数的大小是0x10(4x4)
}
C编译时函数名的转换:_function
其中function为函数名
例:int MyFunc(int a,int b)
_MyFucn
C++编译时函数名的转换:同__stdcall,把YG改为YA
注意:对于可变参数的成员函数,始终使用__cdecl的转换方式
========================================================
2.如果函数func是__stdcall,调用时情况如下
int main()
{
//参数从右到左压栈
push 4
push 3
push 2
push 1
call func //恢复堆栈指针:由被调用函数func负责,方法是 "ret 0x10 "
}
C编译时函数名的转换:_function@number
其中function为函数名,number为参数的字节数
例:int MyFunc(int a,int b)
_MyFucn@8
C++编译时函数名的转换:?function@@YG****@Z或者?function@@YG*XZ
若函数有参数,以@Z结束;若函数无参数,则以Z结束
其中function为函数名,*代表参数表,为下列值:
X--void,
D--char,
E--unsigned char,
F--short,
H--int,
I--unsigned int,
J--long,
K--unsigned long,
M--float,
N--double,
_N--bool,
PA--表示指针,后面的代号表明指针类型,如果相同类型的指针连续出现,
以"0"代替,一个"0"代表一次重复
参数表第一项为返回类型,其后跟参数的类型,指针标识在其所指数据类型前
例:int MyFunc1(unsigned char*arg1, unsigned long arg2)
?MyFunc1@@YGHPAEK@Z
void MyFunc2(char*arg1,char*arg2,char*arg3)
?MyFunc2@@YGXPAD00@Z
void MyFunc3()
?MyFunc3@@YGXXZ
C++编译器转换函数名时更多的考虑了参数,主要是为了方便函数重载,而C语言则不存在函数重载问题
========================================================
3.如果函数func是__pascal,调用情况如下
int main()
{
//参数从左到右压栈
push 1
push 2
push 3
push 4
call func //恢复堆栈指针:由被调用函数func负责,方法是 "ret 0x10 "
}
========================================================
4.如果函数func是__fastcall,调用情况如下
int main()
{
//规定将前两个(或若干个)参数由寄存器传递,其余参数还是通过堆栈传递(从右到左)。
//不同编译器编译的程序规定的寄存器不同。在Intel 386平台上,使用ECX和EDX寄存器。
//使用__fastcall方式无法用作跨编译器的接口。
//如果以2个参数进栈为例
//使用ECX传递第一个参数,EDX传递第二个参数,其余2个参数自右向左压栈
push 4
push 3
mov edx 2
mov ecx 1
call func //恢复堆栈指针:由被调用函数func负责,方法是 "ret 0x08 ",
//因为只进栈一个参数,其余用寄存器传递,所以用ret 0x08恢复
}
C编译时函数名的转换:@function@number
其中function为函数名,number为参数的字节数
例:int MyFunc(int a,int b)
@MyFucn@8
C++编译时函数名的转换:同__stdcall,把YG改为YI
========================================================
5.thiscall
thiscall不是一个关键字,因此不能在程序中明确指定,它是C++类成员函数缺省的调用约定。
由于成员函数调用涉及到一个this指针,因此必须进行特殊处理。
参数自右向左压栈
如果参数个数确定,this指针通过ECX传递给被调用者, 由被调用函数func清理入栈参数
如果参数个数不定,this指针在所有参数压栈后被压入堆栈,由调用者清理堆栈
可见,对于参数个数固定情况下,它类似于__stdcall,不定时则类似__cdecl
6.naked call
使用前四种调用约定时,在进入函数时编译器会产生代码来保存ESI,EDI,EBX,EBP寄存器,
退出函数时则产生代码恢复这些寄存器的内容。naked call不产生这样的代码。更特殊的是,
不能用return返回返回值,返回值存放在eax中,
__asm ret
00401026 ret 只能用插入汇编返回结果。
naked call必须和__declspec连用,即__declspec(naked),naked call还可以和其他调用约定联用,如:
__declspec(naked)int __stdcall function(int a,int b)
使用场合:
1 _beginthread需要__cdecl的线程函数地址,_beginthreadex和CreateThread需要__stdcall的线程函数地址。
2 main函数必须是__cdecl,一般的WIN32函数和回调函数都是__stdcall,并且专门定义了宏来标识:
#define CALLBACK __stdcall
#define WINAPI __stdcall
3.如果某函数在C语言编译器中编译,而在C++文件使用,由于两种编译器对函数名的解析不一样,
因此需要在C++文件中使用extern "C"进行声明,否则会发生链接错误:
#ifdef _cplusplus
extern "C"{
#endif
int func(int a,int b);
#ifdef _cplusplus
}
#endif
========================================================
其他:
注意:在Win32 API中,很多函数都有WINAPI修饰符,
但WINAPI实际上不是调用约定,而是使用默认调用约定。
例如:在Windows上默认为__stdcall,在WinCE.NET上默认为__cdecl。
========================================================
相关推荐
【汇编语言学习整理笔记】 汇编语言,作为计算机科学的基础,是计算机系统与程序员之间的桥梁,它是一种低级编程语言,直接对应机器指令。在Windows环境下,特别是win32平台,汇编语言的应用主要集中在系统级编程、...
### Go语言学习笔记知识点概述 #### 一、Go语言基础 **1.1 变量** - **定义**: 在Go语言中,变量用于存储数据。可以通过`var`关键字声明一个或多个变量,也可以通过短变量声明`:=`来声明并初始化变量。 - **示例*...
这份“Objective-C学习资料”包含了内置的学习笔记和各内容源码,是作者在近两个月的学习过程中整理出来的成果,旨在为初学者提供有价值的指导。 首先,让我们深入了解一下Objective-C的基本概念。Objective-C是在...
`Ruby 学习笔记.txt`文件可能是作者在学习Ruby过程中整理的一些笔记或者教程。这可能涵盖Ruby的基础知识,如变量、控制结构、类和对象、模块、方法、异常处理、文件I/O以及Ruby on Rails框架的入门等内容。Ruby语言...
这份"Spring学习思维笔记"很可能是整理了Spring框架的关键概念、核心组件以及实际应用中的最佳实践,通过思维导图的形式帮助学习者理解和记忆。 首先,让我们来看看Spring框架的核心知识点: 1. **控制反转(IoC)...
例如,系统调用通常遵循这一约定,如`fork()`成功返回子进程ID,失败返回-1。 8. **常用函数**:C标准库提供了许多实用的函数,如`printf()`用于输出,`scanf()`用于输入,`malloc()`和`free()`用于动态内存分配与...
这份笔记不仅包含了作者的学习历程和个人体会,还汇集了他在学习过程中遇到的问题及其解决方案。作者提到,“读不如做,做不如写”的理念驱使他将学到的知识整理成文,以便日后查阅回顾。这样的学习方式不仅有助于...
根据提供的信息,我们可以总结出以下关于C++ Primer的...以上是基于提供的部分笔记内容整理的关键知识点。这些知识点对于初学者理解和掌握C++的基本概念至关重要,并且能够帮助开发者更好地编写高质量、高效的C++程序。
x86 / x64汇编程序,调用约定 EXE / DLL的构建方法和文件格式(PE格式) 如何使用调试器 API挂钩 为此,我们进行了以下研究: 安装Visual Studio 2017和WinDbg,并研究如何构建EXE / DLL,在x86 / x64上调用约定,...