DLL中調(diào)用約定和名稱(chēng)修飾.doc_第1頁(yè)
DLL中調(diào)用約定和名稱(chēng)修飾.doc_第2頁(yè)
DLL中調(diào)用約定和名稱(chēng)修飾.doc_第3頁(yè)
DLL中調(diào)用約定和名稱(chēng)修飾.doc_第4頁(yè)
DLL中調(diào)用約定和名稱(chēng)修飾.doc_第5頁(yè)
已閱讀5頁(yè),還剩9頁(yè)未讀 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

DLL中調(diào)用約定和名稱(chēng)修飾調(diào)用約定(Calling Convention)是指在程序設(shè)計(jì)語(yǔ)言中為了實(shí)現(xiàn)函數(shù)調(diào)用而建立的一種協(xié)議。這種協(xié)議規(guī)定了該語(yǔ)言的函數(shù)中的參數(shù)傳送方式、參數(shù)是否可變和由誰(shuí)來(lái)處理堆棧等問(wèn)題。不同的語(yǔ)言定義了不同的調(diào)用約定。在C+中,為了允許操作符重載和函數(shù)重載,C+編譯器往往按照某種規(guī)則改寫(xiě)每一個(gè)入口點(diǎn)的符號(hào)名,以便允許同一個(gè)名字(具有不同的參數(shù)類(lèi)型或者是不同的作用域)有多個(gè)用法,而不會(huì)打破現(xiàn)有的基于C的鏈接器。這項(xiàng)技術(shù)通常被稱(chēng)為名稱(chēng)改編(Name Mangling)或者名稱(chēng)修飾(Name Decoration)。許多C+編譯器廠商選擇了自己的名稱(chēng)修飾方案。因此,為了使其它語(yǔ)言編寫(xiě)的模塊(如Visual Basic應(yīng)用程序、Pascal或Fortran的應(yīng)用程序等)可以調(diào)用C/C+編寫(xiě)的DLL的函數(shù),必須使用正確的調(diào)用約定來(lái)導(dǎo)出函數(shù),并且不要讓編譯器對(duì)要導(dǎo)出的函數(shù)進(jìn)行任何名稱(chēng)修飾。一調(diào)用約定(Calling Convention)調(diào)用約定用來(lái)處理決定函數(shù)參數(shù)傳送時(shí)入棧和出棧的順序(由調(diào)用者還是被調(diào)用者把參數(shù)彈出棧),以及編譯器用來(lái)識(shí)別函數(shù)名稱(chēng)的名稱(chēng)修飾約定等問(wèn)題。在Microsoft VC+ 6.0中定義了下面幾種調(diào)用約定,我們將結(jié)合匯編語(yǔ)言來(lái)一一分析它們:1、_cdecl_cdecl是C/C+和MFC程序默認(rèn)使用的調(diào)用約定,也可以在函數(shù)聲明時(shí)加上_cdecl關(guān)鍵字來(lái)手工指定。采用_cdecl約定時(shí),函數(shù)參數(shù)按照從右到左的順序入棧,并且由調(diào)用函數(shù)者把參數(shù)彈出棧以清理堆棧。因此,實(shí)現(xiàn)可變參數(shù)的函數(shù)只能使用該調(diào)用約定。由于每一個(gè)使用_cdecl約定的函數(shù)都要包含清理堆棧的代碼,所以產(chǎn)生的可執(zhí)行文件大小會(huì)比較大。_cdecl可以寫(xiě)成_cdecl。下面將通過(guò)一個(gè)具體實(shí)例來(lái)分析_cdecl約定:在VC+中新建一個(gè)Win32 Console工程,命名為cdecl。其代碼如下:int _cdecl Add(int a, int b); /函數(shù)聲明void main() Add(1,2); /函數(shù)調(diào)用int _cdecl Add(int a, int b) /函數(shù)實(shí)現(xiàn) return (a + b);函數(shù)調(diào)用處反匯編代碼如下:;Add(1,2);push 2 ;參數(shù)從右到左入棧,先壓入2push 1 ;壓入1call ILT+0(Add) (00401005) ;調(diào)用函數(shù)實(shí)現(xiàn)add esp,8 ;由函數(shù)調(diào)用清棧2、_stdcall_stdcall調(diào)用約定用于調(diào)用Win32 API函數(shù)。采用_stdcal約定時(shí),函數(shù)參數(shù)按照從右到左的順序入棧,被調(diào)用的函數(shù)在返回前清理傳送參數(shù)的棧,函數(shù)參數(shù)個(gè)數(shù)固定。由于函數(shù)體本身知道傳進(jìn)來(lái)的參數(shù)個(gè)數(shù),因此被調(diào)用的函數(shù)可以在返回前用一條ret n指令直接清理傳遞參數(shù)的堆棧。_stdcall可以寫(xiě)成_stdcall。還是那個(gè)例子,將_cdecl約定換成_stdcall:int _stdcall Add(int a, int b)return (a + b);函數(shù)調(diào)用處反匯編代碼: ; Add(1,2);push 2 ;參數(shù)從右到左入棧,先壓入2push 1 ;壓入1call ILT+10(Add) (0040100f) ;調(diào)用函數(shù)實(shí)現(xiàn)函數(shù)實(shí)現(xiàn)部分的反匯編代碼:;int _stdcall Add(int a, int b)push ebpmov ebp,espsub esp,40hpush ebxpush esipush 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約定用于對(duì)性能要求非常高的場(chǎng)合。_fastcall約定將函數(shù)的從左邊開(kāi)始的兩個(gè)大小不大于4個(gè)字節(jié)(DWORD)的參數(shù)分別放在ECX和EDX寄存器,其余的參數(shù)仍舊自右向左壓棧傳送,被調(diào)用的函數(shù)在返回前清理傳送參數(shù)的堆棧。_fastcall可以寫(xiě)成_fastcall。依舊是相類(lèi)似的例子,此時(shí)函數(shù)調(diào)用約定為_(kāi)fastcall,函數(shù)參數(shù)個(gè)數(shù)增加2個(gè):int _fastcall Add(int a, double b, int c, int d)return (a + b + c + d);函數(shù)調(diào)用部分的匯編代碼:;Add(1, 2, 3, 4);push 4 ;后兩個(gè)參數(shù)從右到左入棧,先壓入4mov edx,3 ;將int類(lèi)型的3放入edxpush 40000000h ;壓入double類(lèi)型的2push 0mov ecx,1 ;將int類(lèi)型的1放入ecxcall ILT+0(Add) (00401005) ;調(diào)用函數(shù)實(shí)現(xiàn)函數(shù)實(shí)現(xiàn)部分的反匯編代碼: ; 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 + 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 ;清棧關(guān)鍵字_cdecl、_stdcall和_fastcall可以直接加在要輸出的函數(shù)前,也可以在編譯環(huán)境的Setting.-C/C+-Code Generation項(xiàng)選擇。它們對(duì)應(yīng)的命令行參數(shù)分別為/Gd、/Gz和/Gr。缺省狀態(tài)為/Gd,即_cdecl。當(dāng)加在輸出函數(shù)前的關(guān)鍵字與編譯環(huán)境中的選擇不同時(shí),直接加在輸出函數(shù)前的關(guān)鍵字有效。4、thiscallthiscall調(diào)用約定是C+中的非靜態(tài)類(lèi)成員函數(shù)的默認(rèn)調(diào)用約定。thiscall只能被編譯器使用,沒(méi)有相應(yīng)的關(guān)鍵字,因此不能被程序員指定。采用thiscall約定時(shí),函數(shù)參數(shù)按照從右到左的順序入棧,被調(diào)用的函數(shù)在返回前清理傳送參數(shù)的棧,只是另外通過(guò)ECX寄存器傳送一個(gè)額外的參數(shù):this指針。這次的例子中將定義一個(gè)類(lèi),并在類(lèi)中定義一個(gè)成員函數(shù),代碼如下:class CSum public:int Add(int a, int b)return (a + b);void main() CSum sum; sum.Add(1, 2);函數(shù)調(diào)用部分匯編代碼:;CSumsum; ;sum.Add(1, 2); push 2 ;參數(shù)從右到左入棧,先壓入2 push 1 ;壓入1 lea ecx,ebp-4 ;ecx存放了this指針call ILT+5(CSum:Add) (0040100a) ;調(diào)用函數(shù)實(shí)現(xiàn)函數(shù)實(shí)現(xiàn)部分匯編代碼:;int Add(int a, int b) push ebpmov ebp,espsub esp,44h ;多用了一個(gè)4bytes的空間用于存放this指針push ebxpush esipush edipush ecxlea edi,ebp-44hmov ecx,11hmov eax,0CCCCCCCChrep stos dword ptr edipop ecxmov dword ptr ebp-4,ecx;return (a + b);mov eax,dword ptr ebp+8add eax,dword ptr ebp+0Chpop edipop esipop ebxmov esp,ebppop ebpret 8 ;清棧5、naked屬性采用上面所述的四種調(diào)用約定的函數(shù)在進(jìn)入函數(shù)時(shí),編譯器會(huì)產(chǎn)生代碼來(lái)保存ESI、EDI、EBX、EBP寄存器中的值,退出函數(shù)時(shí)則產(chǎn)生代碼恢復(fù)這些寄存器的內(nèi)容。對(duì)于定義了naked屬性的函數(shù),編譯器不會(huì)自動(dòng)產(chǎn)生這樣的代碼,需要你手工使用內(nèi)嵌匯編來(lái)控制函數(shù)實(shí)現(xiàn)中的堆棧管理。由于naked屬性并不是類(lèi)型修飾符,故必須和_declspec共同使用。下面的這段代碼定義了一個(gè)使用了naked屬性的函數(shù)及其實(shí)現(xiàn):_declspec ( naked ) func()int i; int j;_asmpush ebp mov ebp, esp sub esp, _LOCAL_SIZE _asm mov esp, ebp pop ebp ret naked屬性與本節(jié)關(guān)系不大,具體請(qǐng)參考MSDN。6、WINAPI還有一個(gè)值得一提的是WINAPI宏,它可以被翻譯成適當(dāng)?shù)恼{(diào)用約定以供函數(shù)使用。該宏定義于windef.h之中。下面是在windef.h中的部分內(nèi)容:#define CDECL _cdecl#define WINAPI CDECL#define CALLBACK _stdcall#define WINAPI _stdcall#define APIENTRY WINAPI由此可見(jiàn),WINAPI、CALLBACK、APIENTRY等宏的作用。二名稱(chēng)修飾(Name Decoration)C或C+函數(shù)在內(nèi)部(編譯和鏈接)通過(guò)修飾名(Decoration Name)識(shí)別。函數(shù)的修飾名是編譯器在編譯函數(shù)定義或者原型時(shí)生成的字符串。編譯器在創(chuàng)建.obj文件時(shí)對(duì)函數(shù)名稱(chēng)進(jìn)行修飾。有些情況下使用函數(shù)的修飾名是必要的,如在模塊定義文件里頭指定輸出C+重載函數(shù)、構(gòu)造函數(shù)、析構(gòu)函數(shù),又如在匯編代碼里調(diào)用C或C+函數(shù)等。在VC+中,函數(shù)修飾名由編譯類(lèi)型(C或C+)、函數(shù)名、類(lèi)名、調(diào)用約定、返回類(lèi)型、參數(shù)等多種因素共同決定。下面分C編譯、C+編譯(非類(lèi)成員函數(shù))和C+類(lèi)及其成員函數(shù)編譯三種情況說(shuō)明:1、C編譯時(shí)函數(shù)名稱(chēng)修飾當(dāng)函數(shù)使用_cdecl調(diào)用約定時(shí),編譯器僅在原函數(shù)名前加上一個(gè)下劃線前綴,格式為_(kāi)functionname。例如:函數(shù)int _cdecl Add(int a, int b),輸出后為:_Add。當(dāng)函數(shù)使用_stdcall調(diào)用約定時(shí),編譯器在原函數(shù)名前加上一個(gè)下劃線前綴,后面加上一個(gè)符號(hào)和函數(shù)參數(shù)的字節(jié)數(shù),格式為_(kāi)functionnamenumber。例如:函數(shù)int _stdcall Add(int a, int b),輸出后為:_Add8。當(dāng)函數(shù)是用_fastcall調(diào)用約定時(shí),編譯器在原函數(shù)名前加上一個(gè)符號(hào),后面是加一個(gè)符號(hào)和函數(shù)參數(shù)的字節(jié)數(shù),格式為functionnamenumber。例如:函數(shù)int _fastcall Add(int a, int b),輸出后為:Add8。以上改變均不會(huì)改變?cè)瘮?shù)名中的字符大小寫(xiě)。2、C+編譯時(shí)函數(shù)(非類(lèi)成員函數(shù))名稱(chēng)修飾當(dāng)函數(shù)使用_cdecl調(diào)用約定時(shí),編譯器進(jìn)行以下工作:1以?標(biāo)識(shí)函數(shù)名的開(kāi)始,后跟函數(shù)名;2函數(shù)名后面以YA標(biāo)識(shí)開(kāi)始,后跟返回值和參數(shù)表;3當(dāng)函數(shù)的返回值或者參數(shù)與C+類(lèi)無(wú)關(guān)的時(shí)候,返回值和參數(shù)表以下列代號(hào)表示: B:constD:charE:unsigned charF:shortG:unsigned shortH:intI:unsigned intJ:longK:unsigned longM:floatN:double_N:boolPA:指針(*,后面的代號(hào)表明指針類(lèi)型,如果相同類(lèi)型的指針連續(xù)出現(xiàn),以0代替,一個(gè)0代表一次重復(fù)) PB:const指針 AA:引用(&) AB:const引用U:類(lèi)或結(jié)構(gòu)體V:Interface(接口)W4:enumX:void4、YA標(biāo)識(shí)之后緊跟的是該函數(shù)的返回值類(lèi)型,其后依次為參數(shù)的數(shù)據(jù)類(lèi)型,指針標(biāo)識(shí)在其所指數(shù)據(jù)類(lèi)型前。當(dāng)函數(shù)的返回值或者參數(shù)與C+類(lèi)無(wú)關(guān)的時(shí)候,其處理符合本條規(guī)則,否則按照5、6規(guī)則處理;5、當(dāng)函數(shù)返回值為某個(gè)類(lèi)或帶有const性質(zhì)的類(lèi)的時(shí)候,返回值的命名為:?A/?B+V+類(lèi)名+(不帶加號(hào))。當(dāng)函數(shù)返回值為某個(gè)類(lèi)的指針/引用或者帶有const性質(zhì)的類(lèi)的指針/引用的時(shí)候,返回值的命名為:PA/AA或者PB/AB+V+類(lèi)名+(不帶加號(hào));6、函數(shù)參數(shù)為某個(gè)類(lèi)的時(shí)候,并且該參數(shù)所使用的類(lèi)曾經(jīng)出現(xiàn)過(guò)的話(也就是與函數(shù)返回值所使用的類(lèi)相同或者與前一個(gè)參數(shù)使用的類(lèi)相同),則該參數(shù)類(lèi)型格式為:V+1+(不帶加號(hào))。如果該參數(shù)所使用的類(lèi)沒(méi)有出現(xiàn)過(guò)的話,則該參數(shù)類(lèi)型格式為:V+類(lèi)名+(不帶加號(hào))。函數(shù)參數(shù)為某個(gè)類(lèi)的指針/引用或者帶有const性質(zhì)指針/引用的時(shí)候,則該參數(shù)類(lèi)型格式是在上述格式的基礎(chǔ)上在V前面加上代表指針/引用類(lèi)型或者帶有const性質(zhì)指針/引用類(lèi)型的標(biāo)識(shí)符(PA/AA或PB/AB);7、參數(shù)表后以Z標(biāo)識(shí)整個(gè)名字的結(jié)束,如果該函數(shù)無(wú)參數(shù),則以Z標(biāo)識(shí)結(jié)束。當(dāng)函數(shù)使用_stdcall調(diào)用約定時(shí),編譯器所做工作的規(guī)則同上面的_cdecl調(diào)用約定,只是參數(shù)表的開(kāi)始標(biāo)識(shí)由上面的YA變?yōu)閅G。當(dāng)函數(shù)使用_fastcall調(diào)用約定時(shí),編譯器所做工作的規(guī)則同上面的_cdecl調(diào)用約定,只是參數(shù)表的開(kāi)始標(biāo)識(shí)由上面的YA變?yōu)閅I。3、C+編譯類(lèi)及其成員函數(shù)時(shí)名稱(chēng)修飾對(duì)于導(dǎo)出的C+類(lèi),僅能使用_cdecl調(diào)用約定。在編譯器編譯過(guò)程中,編譯器會(huì)對(duì)C+類(lèi)進(jìn)行處理。如:class _declspec(dllexport) MyClass會(huì)被處理為class MyClass & MyClass:operator=(class MyClass const &)。在C+編譯器對(duì)C+類(lèi)進(jìn)行名稱(chēng)修飾的時(shí)候,編譯器進(jìn)行以下工作:1以?標(biāo)識(shí)函數(shù)名的開(kāi)始,后跟?4+類(lèi)名;2類(lèi)名后面跟QAE標(biāo)識(shí),對(duì)于導(dǎo)出類(lèi)來(lái)說(shuō)這是固定的;3QAE后面跟AAV0ABV0,即引用類(lèi)型標(biāo)識(shí)符AA+V+0(重復(fù)的類(lèi)的標(biāo)識(shí)符)+(不帶加號(hào))和const性質(zhì)的引用AB+V+ 0(重復(fù)的類(lèi)的標(biāo)識(shí)符)+(不帶加號(hào));4最后以Z標(biāo)識(shí)整個(gè)名字的結(jié)束。對(duì)于導(dǎo)出的C+類(lèi)中的成員函數(shù)(非構(gòu)造函數(shù)和析構(gòu)函數(shù)),可以使用不同的調(diào)用約定。當(dāng)導(dǎo)出的C+類(lèi)中的成員函數(shù)使用_cdecl調(diào)用約定時(shí),編譯器進(jìn)行以下工作:1以?標(biāo)識(shí)函數(shù)名的開(kāi)始,后跟函數(shù)名+類(lèi)名(不帶加號(hào));2之后以QAE標(biāo)識(shí)開(kāi)始,后跟返回值和參數(shù)表;3當(dāng)函數(shù)的返回值或者參數(shù)與C+類(lèi)無(wú)關(guān)的時(shí)候,返回值和參數(shù)表以下列代號(hào)表示: B:constD:charE:unsigned charF:shortG:unsigned shortH:intI:unsigned intJ:longK:unsigned longM:floatN:double_N:boolPA:指針(*,后面的代號(hào)表明指針類(lèi)型,如果相同類(lèi)型的指針連續(xù)出現(xiàn),以0代替,一個(gè)0代表一次重復(fù)) PB:const指針 AA:引用(&) AB:const引用U:類(lèi)或結(jié)構(gòu)體V:Interface(接口)W4:enumX:void4、QAE標(biāo)識(shí)之后緊跟的是該函數(shù)的返回值類(lèi)型,其后依次為參數(shù)的數(shù)據(jù)類(lèi)型,指針標(biāo)識(shí)在其所指數(shù)據(jù)類(lèi)型前。當(dāng)函數(shù)的返回值或者參數(shù)與C+類(lèi)無(wú)關(guān)的時(shí)候,其處理符合本條規(guī)則,否則按照5、6規(guī)則處理;5、當(dāng)函數(shù)返回值為當(dāng)前類(lèi)或帶有const性質(zhì)的當(dāng)前類(lèi)的時(shí)候,返回值的命名為:?A或?B+V+1+(不帶加號(hào))。當(dāng)函數(shù)返回值為當(dāng)前類(lèi)的指針/引用或者帶有const性質(zhì)的當(dāng)前類(lèi)的指針/引用的時(shí)候,返回值的命名為:PA/AA或PB/AB+V+1+(不帶加號(hào));6、當(dāng)函數(shù)返回值為某個(gè)類(lèi)或帶有const性質(zhì)的類(lèi)的時(shí)候,返回值的命名為:?A/?B+V+類(lèi)名+(不帶加號(hào))。當(dāng)函數(shù)返回值為某個(gè)類(lèi)的指針/引用或者帶有const性質(zhì)的類(lèi)的指針/引用的時(shí)候,返回值的命名為:PA/AA或者PB/AB+V+類(lèi)名+(不帶加號(hào));7、函數(shù)參數(shù)為某個(gè)類(lèi)的時(shí)候,并且該參數(shù)所使用的類(lèi)曾經(jīng)出現(xiàn)過(guò)的話(也就是當(dāng)前要導(dǎo)出的類(lèi)、與函數(shù)返回值所使用的類(lèi)相同或者與前一個(gè)參數(shù)使用的類(lèi)相同的類(lèi)),則該參數(shù)類(lèi)型格式為:V+1+(不帶加號(hào))。如果該參數(shù)所使用的類(lèi)不是當(dāng)前要導(dǎo)出的類(lèi)的話,則該參數(shù)類(lèi)型格式為:V+類(lèi)名+(不帶加號(hào))。函數(shù)參數(shù)為某個(gè)類(lèi)的指針/引用或者帶有const性質(zhì)指針/引用的時(shí)

溫馨提示

  • 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

評(píng)論

0/150

提交評(píng)論