您的位置:首页 > 其它

【原创+整理】简述何为调用约定,函数导出名以及extern C

2015-07-29 17:09 218 查看
何为调用约定
调用约定指的是函数在调用时会按照不同规则,翻译成不同的汇编代码。这和参数的压栈顺序和栈的清理方式相关,也就是说不同的调用约定,这些方式会做相应改变。一般编译器是以默认的调用约定编译一份代码,但当一个项目使用不同调用约定的库会产生链接错误。

何为函数导出名
同一个函数,在不同的编译器编译出来的符号名是不一样的,程序目标文件链接的时候不知道源程序的函数名,而是通过目标文件(.obj)中寻找相应的函数符号表。在下面中会指出不同调用约定对应的函数导出名。

三种调用约定

(1)__fastcall

特点:快
参数传递方式:前两个参数-寄存器,剩余参数-栈(右到左)
栈的清理者:被调函数
函数导出名:
按C的编译方式:@函数名@参数字节数
按C++的编译方式:

(2)__cdecl
特点:C语言调用约定,文件比__stdcall大
参数传递方式:栈(右到左)
栈的清理者:调用者
函数导出名:
按C的编译方式:_函数名

按C++的编译方式:规则同下面的_stdcall调用约定,只是参数表的开始标识由上面的"@@YG"变为"@@YA"。
(3)__stdcall
特点:标准调用约定, Pascal程序的缺省调用方式,通常用于Win32 Api中

参数传递方式:栈(右到左)
栈的清理者:被调用者
函数导出名:
按C的编译方式:_函数名@参数字节数
按C++的编译方式:

1)、以"?"标识函数名的开始,后跟函数名;
2)、函数名后面以"@@YG"标识参数表的开始,后跟参数表;
3)、参数表以代号表示:
  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"代表一次重复;
4)、参数表的第一项为该函数的返回值类型,其后依次为参数的数据类型,指针标识在其所指数据类型前;
5)、参数表后以"@Z"标识整个名字的结束,如果该函数无参数,则以"Z"标识结束。

上面这段代码,源文件后缀必须是.c,同时使用windows系统的dumpbin工具即可获得对应目标文件的内容。

//把获得obj函数导出名,存储到d:\\1.txt文件
dumpbin OBJ文件路径/all /rawdata:none > d:\\1.txt

//获得汇编代码,存储到d:\\2.txt
dumpbin OBJ文件路径/disasm d:\\2.txt


View Code

C编译的函数如何在C++中使用
解决办法是采用extern "C"修饰符。使用方法是,把该修饰符添加到调用约定必须是__cdecl的C函数前,如DriverEntry,windows驱动函数入口函数规定为_DriverEntry@8,因此用C++编译器

一些库是用C编译而成的,而在C++平台想要使用这些库,我们可以这样引入C库函数头文件

extern"C" NTSTATUS DriverEntry(IN PDRIVER_OBJECT pDriverObject,IN PUNICODE_STRING pRegistry)
{
//do something
return STATUS_SUCCESS;
}


#ifdef __cplusplus
extern"C"
{
#endif
#include<NTDDK.h>
#ifdef __cplusplus
}
#endif


参考链接:

/article/5207917.html
/article/2577929.html
http://www.2cto.com/kf/201405/301756.html

本文链接:/article/7044976.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: