DLL匯出與呼叫約定

2022-03-10 17:43:32 字數 2063 閱讀 3516

一般來說,從dll匯出函式有兩種方法。一種是使用.def檔案;另一種是使用__declspec(dllexport)。

使用上面兩種方法各有優缺點。使用.def檔案就是需要額外維護,當匯出函式更改名字或者追加匯出函式。而使用__declspec(dllexport)則需要注意使用的呼叫約定,在使用c++編譯器時。

在使用c++或者在常見的windows api的宣告標頭檔案常見的winapi,而winapa就是__stdcall。在c++還有__cdecl。而__pascal和__thiscall都已忽略了。巨集pascal也用的是__stdcall。

一般來說,呼叫約定只關乎引數的壓棧和最後的清理工作。還有就是名字修飾。比如:

void func(char, short, int, double)
使用__cdecl呼叫:

使用c編譯器編譯後的修飾名字為:_func。清理棧的工作由呼叫方做。

使用__stdcall和__thiscall呼叫:

使用c編譯器編譯後的修飾名字為_func@20。清理棧的工作由被調方做。

使用__fastcall呼叫:

使用c編譯器編譯後的修飾名字為@func@20。清理棧的工作由被調方做。

從上面的圖也可看見,壓棧都是從右到左,而名字修飾的方法卻不一樣。c編譯器的修飾方法相對來說比較簡單。以_func@20為例,_是追加的,func就是函式的名字,@是追加的,20為引數的位元組數。c++的修飾方法相對來說比較複雜。下圖是使用c++編譯器產生的名字,使用__declspec(dllexport)和__stdcall。

下圖是使用__cdecl編譯:

大致一看都差不多,只是在名字後的有個字母不一樣,__stdcall得是yg,而__cdecl的是ya。而這也正好指明了c++的名字修飾的規則,簡單來說就是:

・名字(可以包含命名空間)

・呼叫約定

・返回值

・引數列表

呼叫約定修飾規則:

代號呼叫約定

@@yg

__stdcall

@@ya

__cdecl

@@yi

__fastcall

型別修飾規則:

代號含義

xvoid

dchar

eunsigned char

fshort

hint

iunsigned int

jlong

kunsigned long(dword)

mfloat

ndouble

_nbool

ustruct

papointer

pbconst pointer

參數列後以」@z」標示整個名字的結束,如果該函式無引數,則以」z」標識結束。

最後一點:如果我們直接使用__declspec(dllexport)匯出函式的話,最好使用c編譯器。如果直接用c++編譯器,匯出的函式名就像上面一樣。在動態使用dll時呼叫getprocaddress使用原始函式名稱一般來說會失敗。例如:

getprocaddress(handle, "

func

");

所以一般使用c編譯器,比如這樣:

#ifdef __cplusplus    //

if used by c++ code

extern"c

" #ifdef __cplusplus

}#endif

這時,修飾後的名字就是這樣:

一般匯入函式時也建議這樣:

#ifdef __cplusplus

extern"c

"#endif

第一種寫法在效率上來說會更好點。

參考:

DLL 中呼叫約定和名稱修飾

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

DLL中呼叫約定和名稱修飾

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

函式呼叫約定與名字修飾約定

在windows下,由於很多語言支援動態鏈結庫技術,因此動態鏈結庫是一種很好的混合程式設計方法。語言對函式的約定有兩種 函式呼叫約定和名字修飾約定。不同語言預設的呼叫呼叫約定和函式的命名方式是不同的,要想不同的語言開發的動態鏈結庫能夠相互呼叫,那麼開發動態鏈結庫的語言和呼叫鏈結庫的語言的函式約定必須...