午夜视频在线网站,日韩视频精品在线,中文字幕精品一区二区三区在线,在线播放精品,1024你懂我懂的旧版人,欧美日韩一级黄色片,一区二区三区在线观看视频

分享

DLL中調(diào)用約定和名稱(chēng)修飾(一)

 fandy 2008-12-28

原創(chuàng) DLL中調(diào)用約定和名稱(chēng)修飾(一)收藏

新一篇: DLL中調(diào)用約定和名稱(chēng)修飾(三) | 舊一篇: DLL中調(diào)用約定和名稱(chēng)修飾(二)

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)用程序、PascalFortran的應(yīng)用程序等)可以調(diào)用C/C++編寫(xiě)的DLL的函數(shù),必須使用正確的調(diào)用約定來(lái)導(dǎo)出函數(shù),并且不要讓編譯器對(duì)要導(dǎo)出的函數(shù)進(jìn)行任何名稱(chēng)修飾。

1.調(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

__cdeclC/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ù)從右到左入棧,先壓入2

push        1                                         ;壓入1

call          @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ù)從右到左入棧,先壓入2

push        1                                                ;壓入1

call          @ILT+10(Add) (0040100f)          ;調(diào)用函數(shù)實(shí)現(xiàn)

 

函數(shù)實(shí)現(xiàn)部分的反匯編代碼:

 

;int __stdcall Add(int a, int b)

push                     ebp

mov          ebp,esp

sub                esp,40h

push               ebx

push               esi

push               edi

lea           edi,[ebp-40h]

mov          ecx,10h

mov        eax,0CCCCCCCCh

rep stos       dword ptr [edi]

;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                 ;清棧

3、__fastcall

__fastcall約定用于對(duì)性能要求非常高的場(chǎng)合。__fastcall約定將函數(shù)的從左邊開(kāi)始的兩個(gè)大小不大于4個(gè)字節(jié)(DWORD)的參數(shù)分別放在ECXEDX寄存器,其余的參數(shù)仍舊自右向左壓棧傳送,被調(diào)用的函數(shù)在返回前清理傳送參數(shù)的堆棧。__fastcall可以寫(xiě)成_fastcall。

 

依舊是相類(lèi)似的例子,此時(shí)函數(shù)調(diào)用約定為__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ù)從右到左入棧,先壓入4

mov          edx,3                    ;int類(lèi)型的3放入edx

push         40000000h            ;壓入double類(lèi)型的2

push         0

mov          ecx,1                    ;int類(lèi)型的1放入ecx

call          @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                     ebp

mov        ebp,esp

sub          esp,48h

push               ebx

push               esi

push               edi

push               ecx

lea           edi,[ebp-48h]

mov          ecx,12h

mov           eax,0CCCCCCCCh

rep stos       dword ptr [edi]

pop          ecx

mov        dword ptr [ebp-8],edx

mov        dword ptr [ebp-4],ecx

;return (a + b + c + d);

fild           dword ptr [ebp-4]

fadd          qword ptr [ebp+8]

fiadd         dword ptr [ebp-8]

fiadd         dword ptr [ebp+10h]

call          __ftol (004011b8)

pop          edi

pop          esi

pop          ebx

mov          esp,ebp

pop          ebp

ret           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)鍵字有效。

 

后續(xù):DLL中調(diào)用約定和名稱(chēng)修飾(二)

      DLL中調(diào)用約定和名稱(chēng)修飾(三)

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶(hù)發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買(mǎi)等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶(hù) 評(píng)論公約

    類(lèi)似文章 更多