DLL中调用约定和名称修饰

上传人:206****923 文档编号:37507231 上传时间:2018-04-17 格式:DOC 页数:14 大小:84.50KB
返回 下载 相关 举报
DLL中调用约定和名称修饰_第1页
第1页 / 共14页
DLL中调用约定和名称修饰_第2页
第2页 / 共14页
DLL中调用约定和名称修饰_第3页
第3页 / 共14页
DLL中调用约定和名称修饰_第4页
第4页 / 共14页
DLL中调用约定和名称修饰_第5页
第5页 / 共14页
点击查看更多>>
资源描述

《DLL中调用约定和名称修饰》由会员分享,可在线阅读,更多相关《DLL中调用约定和名称修饰(14页珍藏版)》请在金锄头文库上搜索。

1、DLL 中调用约定和名称修饰中调用约定和名称修饰调用约定(Calling Convention)是指在程序设计语言中为了实现函数调用而建立的一种协议。这种协议规定了该语言的函数中的参数传送方式、参数是否可变和由谁来处理堆栈等问题。不同的语言定义了不同的调用约定。在 C+中,为了允许操作符重载和函数重载,C+编译器往往按照某种规则改写每一个入口点的符号名,以便允许同一个名字(具有不同的参数类型或者是不同的作用域)有多个用法,而不会打破现有的基于 C 的链接器。这项技术通常被称为名称改编(Name Mangling)或者名称修饰(Name Decoration)。许多 C+编译器厂商选择了自己的名

2、称修饰方案。因此,为了使其它语言编写的模块(如 Visual Basic 应用程序、Pascal 或Fortran 的应用程序等)可以调用 C/C+编写的 DLL 的函数,必须使用正确的调用约定来导出函数,并且不要让编译器对要导出的函数进行任何名称修饰。一调用约定(一调用约定(Calling Convention)调用约定用来处理决定函数参数传送时入栈和出栈的顺序(由调用者还是被调用者把参数弹出栈),以及编译器用来识别函数名称的名称修饰约定等问题。在 Microsoft VC+ 6.0 中定义了下面几种调用约定,我们将结合汇编语言来一一分析它们:1、_cdecl_cdecl 是 C/C+和 M

3、FC 程序默认使用的调用约定,也可以在函数声明时加上_cdecl 关键字来手工指定。采用_cdecl 约定时,函数参数按照从右到左的顺序入栈,并且由调用函数者把参数弹出栈以清理堆栈。因此,实现可变参数的函数只能使用该调用约定。由于每一个使用_cdecl 约定的函数都要包含清理堆栈的代码,所以产生的可执行文件大小会比较大。_cdecl 可以写成_cdecl。下面将通过一个具体实例来分析_cdecl 约定:在 VC+中新建一个 Win32 Console 工程,命名为 cdecl。其代码如下:int _cdecl Add(int a, int b); /函数声明void main()Add(1,2

4、); /函数调用int _cdecl Add(int a, int b) /函数实现return (a + b);函数调用处反汇编代码如下:;Add(1,2);push 2 ;参数从右到左入栈,先压入 2push 1 ;压入 1call ILT+0(Add) (00401005) ;调用函数实现add esp,8 ;由函数调用清栈2、_stdcall_stdcall 调用约定用于调用 Win32 API 函数。采用_stdcal 约定时,函数参数按照从右到左的顺序入栈,被调用的函数在返回前清理传送参数的栈,函数参数个数固定。由于函数体本身知道传进来的参数个数,因此被调用的函数可以在返回前用一条

5、 ret n 指令直接清理传递参数的堆栈。_stdcall 可以写成_stdcall。还是那个例子,将_cdecl 约定换成_stdcall:int _stdcall Add(int a, int b)return (a + b);函数调用处反汇编代码:; Add(1,2);push 2 ;参数从右到左入栈,先压入 2push 1 ;压入 1call ILT+10(Add) (0040100f) ;调用函数实现函数实现部分的反汇编代码:;int _stdcall Add(int a, int b)push ebpmov ebp,espsub esp,40hpush ebxpush esipus

6、h edilea edi,ebp-40hmov ecx,10hmov eax,0CCCCCCCChrep stos dword ptr edi;return (a + b);mov eax,dword ptr ebp+8add eax,dword ptr ebp+0Chpop edipop esipop ebxmov esp,ebppop ebpret 8 ;清栈3、_fastcall_fastcall 约定用于对性能要求非常高的场合。_fastcall 约定将函数的从左边开始的两个大小不大于 4 个字节(DWORD)的参数分别放在 ECX 和EDX 寄存器,其余的参数仍旧自右向左压栈传送,被

7、调用的函数在返回前清理传送参数的堆栈。_fastcall 可以写成_fastcall。依旧是相类似的例子,此时函数调用约定为_fastcall,函数参数个数增加2 个:int _fastcall Add(int a, double b, int c, int d)return (a + b + c + d);函数调用部分的汇编代码:;Add(1, 2, 3, 4);push 4 ;后两个参数从右到左入栈,先压入 4mov edx,3 ;将 int 类型的 3 放入 eush 40000000h ;压入 double 类型的 2push 0mov ecx,1 ;将 int 类型的 1 放入 ec

8、xcall ILT+0(Add) (00401005) ;调用函数实现函数实现部分的反汇编代码:; int _fastcall Add(int a, double b, int c, int d)push ebpmov ebp,espsub esp,48hpush ebxpush esipush edipush ecxlea edi,ebp-48hmov ecx,12hmov eax,0CCCCCCCChrep stos dword ptr edipop ecxmov dword ptr ebp-8,edxmov dword ptr ebp-4,ecx;return (a + b + c +

9、d);fild dword ptr ebp-4fadd qword ptr ebp+8fiadd dword ptr ebp-8fiadd dword ptr ebp+10hcall _ftol (004011b8)pop edipop esipop ebxmov esp,ebppop ebpret 0Ch ;清栈关键字_cdecl、_stdcall 和_fastcall 可以直接加在要输出的函数前,也可以在编译环境的 Setting.-C/C+-Code Generation 项选择。它们对应的命令行参数分别为/Gd、/Gz 和/Gr。缺省状态为/Gd,即_cdecl。当加在输出函数前的关键

10、字与编译环境中的选择不同时,直接加在输出函数前的关键字有效。4、thiscallthiscallthiscall 调用约定是 C+中的非静态类成员函数的默认调用约定。thiscall 只能被编译器使用,没有相应的关键字,因此不能被程序员指定。采用 thiscall 约定时,函数参数按照从右到左的顺序入栈,被调用的函数在返回前 清理传送参数的栈,只是另外通过 ECX 寄存器传送一个额外的参数:this 指针。这次的例子中将定义一个类,并在类中定义一个成员函数,代码如下:class CSumpublic: int Add(int a, int b) return (a + b); ;void ma

11、in() CSum sum;sum.Add(1, 2); 函数调用部分汇编代码:;CSum sum;sum.Add(1, 2);push 2 ;参数从右到左入栈, 先压入 2push 1 ;压入 1lea ecx,ebp-4 ;ecx 存放了 this 指针call ILT+5(CSum:Add) (0040100a) ;调用函数实 现函数实现部分汇编代码:;int Add(int a, int b)push ebpmov ebp,esp sub esp,44h ;多用了一个 4bytes 的 空间用于存放 this 指针 push ebx push esi push edi push ecx lea edi,ebp-44h mov ecx,11h mov eax,0CCCCCCCCh rep stos dword ptr edi pop ecx mov dword ptr ebp-4,ecx ;return (a + b); mov eax,dword ptr ebp+8 add eax,dword ptr ebp+0Ch pop edi pop esi pop ebx mov esp,ebp pop ebp ret 8

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 行业资料 > 其它行业文档

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号