您的位置:首页 > 其它

关于函数调用约定的学习笔记

2013-08-02 22:48 453 查看


总体概述:


关于调用约定中,主要涉及的内容就是不同的调用约定对于函数调用栈平衡是由调用者维护栈平衡还是被调用者自己维护栈平衡、传入参数的方向从右到左还是从左到右通过栈传参还是通过寄存器传参、还有一个就是关于不同调用约定方式对于函数名的修饰方式。总体上了解这些就差不多了。

----------------------------------------------------------------------

调用者自己恢复栈平衡,用于可变参函数,调用约定为__cdecl,汇编代码表现

push 参数

call 函数

add esp,4

被调用者自己恢复栈平衡__stdcall

push 参数

call 函数

采用寄存器传参__fastcall

mov edx,参数

mov ecx,参数

call 函数

以上各种调用约定对应的编译器选项 /Gz (stdcall)、/Gr (fastcall)、/Gd (cdecl)

说明:在MSDN帮助文档中可以搜关键字__cdcel

----------------------------------------------------------------------

关于使用不同调用约定的C函数名修饰:

C 函数的修饰形式取决于其声明中使用的调用约定,如下所示。

调用约定 修饰



__cdecl(默认值) 前导下划线 (_)



__stdcall 前导下划线 (_) 和结尾 at 符 (@),后面跟表示参数列表中的字节数的数字



__fastcall 与 __stdcall 相同,但前置符不是下划线,而是 @ 符

实例分析:(自己动手实践验证VS2010)

函数原型: 修饰后的名称:

int __fastcall fun3(int a, int b); @fun3@8

int __stdcall fun2(int a, int b); _fun2@8

int __cdecl fun1(int a, int b); _fun1

------------------------C++ 修饰名的格式----------------------------------------------

C++ 函数的修饰名包含下列信息:

函数名。

函数所属的类(如果函数是成员函数)。这可能包括封装函数的类的类,等等。

函数所属的命名空间(如果函数是某个命名空间的组成部分)。

函数的参数类型。

调用约定。

函数的返回类型。

函数名和类名在修饰名中以代码形式存在。修饰名的其余部分是仅对编译器和链接器具有内部意义的代码。下面是未修饰的和修饰的 C++ 名称的示例。

未修饰名 修饰名



int a(char){int i=3;return i;}; ?a@@YAHD@Z



void __stdcall b::c(float){}; ?c@b@@AAGXM@Z



------------Argument Passing and Naming Conventions---------------------------------

Microsoft Specific

All arguments are widened to 32 bits when they are passed. Return values are also widened to 32 bits and returned in the EAX register, except for 8-byte structures, which are returned in the EDX:EAX register pair. Larger structures are returned in the EAX register
as pointers to hidden return structures. Parameters are pushed onto the stack from right to left. Structures that are not PODs will not be returned in registers.

The compiler generates prolog and epilog code to save and restore the ESI, EDI, EBX, and EBP registers, if they are used in the function.

Note:

When a struct, union, or class is returned from a function by value, all definitions of the type need to be the same, else the program may fail at runtime.



For information on how to define your own function prolog and epilog code, see (Naked Function Calls).

The following calling conventions are supported by the Visual C/C++ compiler.

Keyword Stack cleanupParameter passing



__cdecl CallerPushes parameters on the stack, in reverse order (right to left)



__clrcall n/a
Load parameters onto CLR expression stack in order (left to right).



__stdcall CalleePushes parameters on the stack, in reverse order (right to left)



__fastcall CalleeStored in registers, then pushed on stack



__thiscall CalleePushed on stack; this pointer stored in ECX

最后补充一点就是关于调用约定在IPF处理器和X64处理器下的一些说明,以下引用自MSDN帮助手册中的原话:

On Itanium Processor Family (IPF) and x64 processors, __cdecl is accepted and ignored by the compiler; on IPF, by convention, parameters are passed in register.

On Itanium Processor Family (IPF) and x64 processors, __stdcall is accepted and ignored by the compiler; on IPF, by convention, parameters are passed in register.

On Itanium Processor Family (IPF) and AMD64 machines, __fastcall is accepted and ignored by the compiler; on an IPF chip, by convention, parameters are passed in register.

主要说的就是在这两种处理直接采用寄存器传参方式。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: