DLL中呼叫約定和名稱修飾(一)

2022-07-26 03:12:09 字數 4487 閱讀 8131

dll中呼叫約定和名稱修飾(一)

呼叫約定(calling convention)是指在程式語言中為了實現函式呼叫而建立的一種協議。這種協議規定了該語言的函式中的引數傳送方式、引數是否可變和由誰來處理堆疊等問題。不同的語言定義了不同的呼叫約定。

在c++中,為了允許操作符過載和函式過載,c++編譯器往往按照某種規則改寫每乙個入口點的符號名,以便允許同乙個名字(具有不同的引數型別或者是不同的作用域)有多個用法,而不會打破現有的基於c的鏈結器。這項技術通常被稱為名稱改編(name mangling)或者名稱修飾(name decoration)。許多c++編譯器廠商選擇了自己的名稱修飾方案。

因此,為了使其它語言編寫的模組(如visual basic應用程式、pascal或fortran的應用程式等)可以呼叫c/c++編寫的dll的函式,必須使用正確的呼叫約定來匯出函式,並且不要讓編譯器對要匯出的函式進行任何名稱修飾。

1.呼叫約定(calling convention)

呼叫約定用來處理決定函式引數傳送時入棧和出棧的順序(由呼叫者還是被呼叫者把引數彈出棧),以及編譯器用來識別函式名稱的名稱修飾約定等問題。在microsoft vc++ 6.0中定義了下面幾種呼叫約定,我們將結合組合語言來一一分析它們:

1、__cdecl

__cdecl是c/c++和mfc程式預設使用的呼叫約定,也可以在函式宣告時加上__cdecl關鍵字來手工指定。採用__cdecl約定時,函式引數按照從右到左的順序入棧,並且由呼叫函式者把引數彈出棧以清理堆疊。因此,實現可變引數的函式只能使用該呼叫約定。由於每乙個使用__cdecl約定的函式都要包含清理堆疊的**,所以產生的可執行檔案大小會比較大。__cdecl可以寫成_cdecl。

下面將通過乙個具體例項來分析__cdecl約定:

在vc++中新建乙個win32 console工程,命名為cdecl。其**如下:

int __cdecl add(int a, int b);         //函式宣告

void main()

int __cdecl add(int a, int b)          //函式實現

函式呼叫處反彙編**如下:

;add(1,2);

push                     2                                        ;引數從右到左入棧,先壓入2

push        1                                         ;壓入1

call         @ilt+0(add) (00401005)    ;呼叫函式實現

add           esp,8                                   ;由函式呼叫清棧

2、__stdcall

__stdcall呼叫約定用於呼叫win32 api函式。採用__stdcal約定時,函式引數按照從右到左的順序入棧,被呼叫的函式在返回前清理傳送引數的棧,函式引數個數固定。由於函式體本身知道傳進來的引數個數,因此被呼叫的函式可以在返回前用一條ret n指令直接清理傳遞引數的堆疊。__stdcall可以寫成_stdcall。

還是那個例子,將__cdecl約定換成__stdcall:

int __stdcall add(int a, int b)

函式呼叫處反彙編**:

; add(1,2);

push                     2                                               ;引數從右到左入棧,先壓入2

push        1                                                ;壓入1

call         @ilt+10(add) (0040100f)          ;呼叫函式實現

函式實現部分的反彙編**:

;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約定用於對效能要求非常高的場合。__fastcall約定將函式的從左邊開始的兩個大小不大於4個位元組(dword)的引數分別放在ecx和edx暫存器,其餘的引數仍舊自右向左壓棧傳送,被呼叫的函式在返回前清理傳送引數的堆疊。__fastcall可以寫成_fastcall。

依舊是相類似的例子,此時函式呼叫約定為__fastcall,函式引數個數增加2個:

int __fastcall add(int a, double b, int c, int d)

函式呼叫部分的彙編**:

;add(1, 2, 3, 4);

push                     4                          ;後兩個引數從右到左入棧,先壓入4

mov          edx,3                    ;將int型別的3放入edx

push        40000000h            ;壓入double型別的2

push        0

mov          ecx,1                    ;將int型別的1放入ecx

call         @ilt+0(add) (00401005)               ;呼叫函式實現

函式實現部分的反彙編**:

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

關鍵字__cdecl、__stdcall和__fastcall可以直接加在要輸出的函式前,也可以在編譯環境的setting...->c/c++->code generation項選擇。它們對應的命令列引數分別為/gd、/gz和/gr。預設狀態為/gd,即__cdecl。當加在輸出函式前的關鍵字與編譯環境中的選擇不同時,直接加在輸出函式前的關鍵字有效。

來自:

DLL中呼叫約定和名稱修飾(一)

dll中呼叫約定和名稱修飾 一 呼叫約定 calling convention 是指在程式語言中為了實現函式呼叫而建立的一種協議。這種協議規定了該語言的函式中的引數傳送方式 引數是否可變和由誰來處理堆疊等問題。不同的語言定義了不同的呼叫約定。在c 中,為了允許操作符過載和函式過載,c 編譯器往往按照...

DLL中呼叫約定和名稱修飾(一)

呼叫約定 calling convention 是指在程式語言中為了實現函式呼叫而建立的一種協議。這種協議規定了該語言的函式中的引數傳送方式 引數是否可變和由誰來處理堆疊等問題。不同的語言定義了不同的呼叫約定。在c 中,為了允許操作符過載和函式過載,c 編譯器往往按照某種規則改寫每乙個入口點的符號名...

DLL 中呼叫約定和名稱修飾

呼叫約定 calling convention 是指在程式語言中為了實現函式呼叫而建立的一種協議。這種協議規定了該語言的函式中的引數傳送方式 引數是否可變和由誰來處理堆疊等問題。不同的語言定義了不同的呼叫約定。在c 中,為了允許操作符過載和函式過載,c 編譯器往往按照某種規則改寫每乙個入口點的符號名...