码迷,mamicode.com
首页 > 其他好文 > 详细

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

时间:2015-07-29 19:06:53      阅读:213      评论:0      收藏:0      [点我收藏+]

标签:

何为调用约定

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

 
何为函数导出名
    同一个函数,在不同的编译器编译出来的符号名是不一样的,程序目标文件链接的时候不知道源程序的函数名,而是通过目标文件(.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工具即可获得对应目标文件的内容。
 
技术分享
    int __cdecl f1(int a)
    {
    return a +1;
    }
    int __stdcall f2(int b)
    {
    return b +1;
    }
    int __fastcall f3(int c)
    {
    return c +1;
    }
    int main()
    {
    //函数导出名为_f1、_f2@4、@f3@4
    int i = f1(1);
    int j = f2(2);
    int k = f3(3);
    return0;
    }
    @f3@4:
    00000000:55 push ebp
    00000001:8B EC mov ebp,esp
    00000003:81 EC CC 000000 sub esp,0CCh
    00000009:53 push ebx
    0000000A:56 push esi
    0000000B:57 push edi
    0000000C:51 push ecx
    0000000D:8D BD 34 FF FF FF lea edi,[ebp+FFFFFF34h]
    00000013: B9 33000000 mov ecx,33h
    00000018: B8 CC CC CC CC mov eax,0CCCCCCCCh
    0000001D: F3 AB rep stos dword ptr es:[edi]
    0000001F:59 pop ecx
    00000020:894D F8 mov dword ptr [ebp-8],ecx
    00000023:8B45 F8 mov eax,dword ptr [ebp-8]
    00000026:83 C0 01 add eax,1
    00000029:5F pop edi
    0000002A:5E pop esi
    0000002B:5B pop ebx
    0000002C:8B E5 mov esp,ebp
    0000002E:5D pop ebp
    0000002F: C3 ret
    _f1:
    00000000:55 push ebp
    00000001:8B EC mov ebp,esp
    00000003:81 EC C0 000000 sub esp,0C0h
    00000009:53 push ebx
    0000000A:56 push esi
    0000000B:57 push edi
    0000000C:8D BD 40 FF FF FF lea edi,[ebp+FFFFFF40h]
    00000012: B9 30000000 mov ecx,30h
    00000017: B8 CC CC CC CC mov eax,0CCCCCCCCh
    0000001C: F3 AB rep stos dword ptr es:[edi]
    0000001E:8B4508 mov eax,dword ptr [ebp+8]
    00000021:83 C0 01 add eax,1
    00000024:5F pop edi
    00000025:5E pop esi
    00000026:5B pop ebx
    00000027:8B E5 mov esp,ebp
    00000029:5D pop ebp
    0000002A: C3 ret
    _f2@4:
    00000000:55 push ebp
    00000001:8B EC mov ebp,esp
    00000003:81 EC C0 000000 sub esp,0C0h
    00000009:53 push ebx
    0000000A:56 push esi
    0000000B:57 push edi
    0000000C:8D BD 40 FF FF FF lea edi,[ebp+FFFFFF40h]
    00000012: B9 30000000 mov ecx,30h
    00000017: B8 CC CC CC CC mov eax,0CCCCCCCCh
    0000001C: F3 AB rep stos dword ptr es:[edi]
    0000001E:8B4508 mov eax,dword ptr [ebp+8]
    00000021:83 C0 01 add eax,1
    00000024:5F pop edi
    00000025:5E pop esi
    00000026:5B pop ebx
    00000027:8B E5 mov esp,ebp
    00000029:5D pop ebp
    0000002A: C2 0400 ret 4
    _main:
    00000000:55 push ebp
    00000001:8B EC mov ebp,esp
    00000003:81 EC E4 000000 sub esp,0E4h
    00000009:53 push ebx
    0000000A:56 push esi
    0000000B:57 push edi
    0000000C:8D BD 1C FF FF FF lea edi,[ebp-0E4h]
    00000012: B9 39000000 mov ecx,39h
    00000017: B8 CC CC CC CC mov eax,0CCCCCCCCh
    0000001C: F3 AB rep stos dword ptr es:[edi]
    0000001E:6A01 push 1
    00000020: E8 00000000 call _f1
    00000025:83 C4 04 add esp,4
    00000028:8945 F8 mov dword ptr [ebp-8],eax
    0000002B:6A02 push 2
    0000002D: E8 00000000 call _f2@4
    00000032:8945 EC mov dword ptr [ebp-14h],eax
    00000035: B9 03000000 mov ecx,3
    0000003A: E8 00000000 call @f3@4
    0000003F:8945 E0 mov dword ptr [ebp-20h],eax
    00000042:33 C0 xor eax,eax
    00000044:5F pop edi
    00000045:5E pop esi
    00000046:5B pop ebx
    00000047:81 C4 E4 000000 add esp,0E4h
    0000004D:3B EC cmp ebp,esp
    0000004F: E8 00000000 call __RTC_CheckEsp
    00000054:8B E5 mov esp,ebp
    00000056:5D pop ebp
    00000057: C3 ret
View Code
 
相关命令是:
技术分享
1 //把获得obj函数导出名,存储到d:\\1.txt文件
2 dumpbin OBJ文件路径/all /rawdata:none > d:\\1.txt
3 
4 //获得汇编代码,存储到d:\\2.txt
5 dumpbin OBJ文件路径/disasm d:\\2.txt
View Code
    
C编译的函数如何在C++中使用
    解决办法是采用extern "C"修饰符。使用方法是,把该修饰符添加到调用约定必须是__cdecl的C函数前,如DriverEntry,windows驱动函数入口函数规定为_DriverEntry@8,因此用C++编译器
一些库是用C编译而成的,而在C++平台想要使用这些库,我们可以这样引入C库函数头文件
  1. 1 extern"C" NTSTATUS DriverEntry(IN PDRIVER_OBJECT pDriverObject,IN PUNICODE_STRING pRegistry)
    2  {
    3     //do something
    4     return STATUS_SUCCESS;
    5  }

     

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

     

参考链接:
 

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

标签:

原文地址:http://www.cnblogs.com/cposture/p/4686480.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!