动态链接概述
目錄
動(dòng)態(tài)鏈接庫概述
相關(guān)函數(shù)
動(dòng)態(tài)鏈接庫編程
dumpbin工具
(本章節(jié)中例子都是用 VS2005 編譯調(diào)試的)
動(dòng)態(tài)鏈接概述
?
說明
所謂動(dòng)態(tài)鏈接,就是把一些經(jīng)常會(huì)共用的代碼(靜態(tài)鏈接的OBJ程序庫)制作成DLL檔,當(dāng)可執(zhí)行文件調(diào)用到DLL檔內(nèi)的函數(shù)時(shí),windows操作系統(tǒng)才會(huì)把DLL檔加載存儲(chǔ)器內(nèi),DLL檔本身的結(jié)構(gòu)就是可執(zhí)行文件,當(dāng)程序需求函數(shù)才進(jìn)行鏈接.通過動(dòng)態(tài)鏈接方式,存儲(chǔ)器浪費(fèi)的情形將可大幅降低.
DLL的文檔格式與視窗EXE文檔一樣——也就是說,等同于32位視窗的可移植執(zhí)行文檔(PE)和16位視窗的New Executable(NE).作為EXE格式,DLL可以包括源代碼、數(shù)據(jù)和資源的多種組合.
在使用動(dòng)態(tài)庫的時(shí)候,往往提供兩個(gè)文件:一個(gè)引入庫(LIB)和一個(gè)動(dòng)態(tài)鏈接庫(DLL).引入庫(LIB)包含被動(dòng)態(tài)連接庫(DLL)所導(dǎo)出的函數(shù)和變量的符號(hào)名,動(dòng)態(tài)連接庫(DLL)包含實(shí)際的函數(shù)和數(shù)據(jù).在編譯鏈接可執(zhí)行文件時(shí),只需要鏈接引入庫(LIB),動(dòng)態(tài)連接庫(DLL)中的函數(shù)代碼和數(shù)據(jù)并不復(fù)制到可執(zhí)行文件中,在運(yùn)行的時(shí)候,再去加載DLL,訪問動(dòng)態(tài)鏈接庫(DLL)中導(dǎo)出的函數(shù).
動(dòng)態(tài)鏈接庫(DLL)通常都不能直接運(yùn)行,也不能接收消息.它們是一些獨(dú)立的文件,其中包含能被可執(zhí)行程序或其它動(dòng)態(tài)連接庫(DLL)調(diào)用來完成某項(xiàng)工作的函數(shù).只有在其它模塊調(diào)用動(dòng)態(tài)鏈接庫(DLL)中的函數(shù)時(shí),它才發(fā)揮作用.但是動(dòng)態(tài)連接庫(DLL)被多進(jìn)程調(diào)用時(shí)候,動(dòng)態(tài)鏈接庫(DLL)中進(jìn)程訪問到動(dòng)態(tài)鏈接庫(DLL)的成員時(shí),系統(tǒng)會(huì)為它開辟一個(gè)新的數(shù)據(jù)成員頁面給訪問進(jìn)程提供單獨(dú)的動(dòng)態(tài)連接庫(DLL)數(shù)據(jù)區(qū).
特征(來自維基百科此處為鏈接)
- 內(nèi)存管理
在Win32中,DLL文檔按照片段(sections)進(jìn)行組織.每個(gè)片段有它自己的屬性,如可寫或是只讀、可執(zhí)行(代碼)或者不可執(zhí)行(數(shù)據(jù))等等.
DLL代碼段通常被使用這個(gè)DLL的進(jìn)程所共享;也就是說它們?cè)谖锢韮?nèi)存中占據(jù)一個(gè)地方,并且不會(huì)出現(xiàn)在頁面文檔中.如果代碼段所占據(jù)的物理內(nèi)存被收回,它的內(nèi)容就會(huì)被放棄,后面如果需要的話就直接從DLL文檔重新加載.
與代碼段不同,DLL的數(shù)據(jù)段通常是私有的;也就是說,每個(gè)使用DLL的進(jìn)程都有自己的DLL數(shù)據(jù)副本.作為選擇,數(shù)據(jù)段可以設(shè)置為共享,允許通過這個(gè)共享內(nèi)存區(qū)域進(jìn)行進(jìn)程間通信.但是,因?yàn)橛脩魴?quán)限不能應(yīng)用到這個(gè)共享DLL內(nèi)存,這將產(chǎn)生一個(gè)安全漏洞;也就是一個(gè)進(jìn)程能夠破壞共享數(shù)據(jù),這將導(dǎo)致其它的共享進(jìn)程異常.例如,一個(gè)使用訪客賬號(hào)的進(jìn)程將可能通過這種方式破壞其它運(yùn)行在特權(quán)賬號(hào)的進(jìn)程.這是在DLL中避免使用共享片段的一個(gè)重要原因.
當(dāng)DLL被如UPX這樣一個(gè)可執(zhí)行的packer壓縮時(shí),它的所有代碼段都標(biāo)記為可以讀寫并且是非共享的.可以讀寫的代碼段,類似于私有數(shù)據(jù)段,是每個(gè)進(jìn)程私有的并且被頁面文檔備份.這樣,壓縮DLL將同時(shí)增加內(nèi)存和磁盤空間消耗,所以共享DLL應(yīng)當(dāng)避免使用壓縮DLL. - 符號(hào)解析和綁定
DLL輸出的每個(gè)函數(shù)都由一個(gè)數(shù)字序號(hào)唯一標(biāo)識(shí),也可以由可選的名字標(biāo)識(shí).同樣,DLL引入的函數(shù)也可以由序號(hào)或者名字標(biāo)識(shí).對(duì)于內(nèi)部函數(shù)來說,只輸出序號(hào)的情形很常見.對(duì)于大多數(shù)視窗API函數(shù)來說名字是不同視窗版本之間保留不變的;序號(hào)有可能會(huì)發(fā)生變化.這樣,我們不能根據(jù)序號(hào)引用視窗API函數(shù).
按照序號(hào)引用函數(shù)并不一定比按照名字引用函數(shù)性能更好:DLL輸出表是按照名字排列的,所以對(duì)半查找可以用來在在這個(gè)表中根據(jù)名字查找這個(gè)函數(shù).另外一方面,只有線性查找才可以用于根據(jù)序號(hào)查找函數(shù).
將一個(gè)可執(zhí)行文件綁定到一個(gè)特定版本的DLL也是可能的,這也就是說,可以在編譯時(shí)解析輸入函數(shù)(imported functions)的地址.對(duì)于綁定的輸入函數(shù),連結(jié)工具保存了輸入函數(shù)綁定的DLL的時(shí)間戳和校驗(yàn)和.在運(yùn)行時(shí)Windows檢查是否正在使用同樣版本的庫,如果是的話,Windows將繞過處理輸入函數(shù);否則如果庫與綁定的庫不同,Windows將按照正常的方式處理輸入函數(shù).
綁定的可執(zhí)行文件如果運(yùn)行在與它們編譯所用的環(huán)境一樣,函數(shù)調(diào)用將會(huì)較快,如果是在一個(gè)不同的環(huán)境它們就等同于正常的調(diào)用,所以綁定輸入函數(shù)沒有任何的缺點(diǎn).例如,所有的標(biāo)準(zhǔn)Windows應(yīng)用程序都綁定到它們各自的Windows發(fā)布版本的系統(tǒng)DLL.將一個(gè)應(yīng)用程序輸入函數(shù)綁定到它的目的環(huán)境的好機(jī)會(huì)是在應(yīng)用程序安裝的過程. - 運(yùn)行時(shí)顯式鏈接
對(duì)每個(gè)DLL來說,Windows存儲(chǔ)了一個(gè)全局計(jì)數(shù)器,每多一個(gè)進(jìn)程使用便多額外一個(gè).LoadLibrary與FreeLibrary指令影響每一個(gè)進(jìn)程內(nèi)含的計(jì)數(shù)器;動(dòng)態(tài)鏈接則不影響.因此借由調(diào)用FreeLibrary多次,從存儲(chǔ)器反加載一DLL是很重要的.一個(gè)進(jìn)程可以從它自己的VAS注銷此計(jì)數(shù)器.
DLL文檔能夠在運(yùn)行時(shí)使用LoadLibrary(或者LoadLibraryEx)API函數(shù)進(jìn)行顯式調(diào)用,這個(gè)的過程微軟簡(jiǎn)單地稱為運(yùn)行時(shí)動(dòng)態(tài)調(diào)用.API函數(shù)GetProcAddress根據(jù)查找輸出名稱符號(hào)、FreeLibrary卸載DLL.這些函數(shù)類似于POSIX標(biāo)準(zhǔn)API中的dlopen、dlsym、和dlclose.
注意微軟簡(jiǎn)單稱為運(yùn)行時(shí)動(dòng)態(tài)鏈接的運(yùn)行時(shí)隱式鏈接,如果不能找到鏈接的DLL文檔,Windows將提示一個(gè)錯(cuò)誤消息并且調(diào)用應(yīng)用程序失敗.應(yīng)用程序開發(fā)人員不能通過編譯鏈接來處理這種缺少DLL文檔的隱式鏈接問題.另外一方面,對(duì)于顯式鏈接,開發(fā)人員有機(jī)會(huì)提供一個(gè)完善的出錯(cuò)處理機(jī)制.
運(yùn)行時(shí)顯式鏈接的過程在所有語言中都是相同的,因?yàn)樗蕾囉赪indows API而不是語言結(jié)構(gòu).
與靜態(tài)鏈接庫的區(qū)別
靜態(tài)庫本身就包含了實(shí)際執(zhí)行代碼、符號(hào)表等等,而對(duì)于導(dǎo)入庫而言,其實(shí)際的執(zhí)行代碼位于動(dòng)態(tài)庫中,動(dòng)態(tài)鏈接庫只包含了地址符號(hào)表等,確保程序找到對(duì)應(yīng)函數(shù)的一些基本地址信息.
Windows 下 3 個(gè)重要的 DLL
Windows API中的所有函數(shù)都包含在DLL中。其中有3個(gè)最重要的DLL
- Kernel32.dll,它包含用于管理內(nèi)存、進(jìn)程和線程的各個(gè)函數(shù)
- User32.dll,它包含用于執(zhí)行用戶界面任務(wù)(如窗口的創(chuàng)建和消息的傳送)的各個(gè)函數(shù)
- GDI32.dll,它包含用于畫圖和顯示文本的各個(gè)函數(shù)
動(dòng)態(tài)鏈接庫的優(yōu)點(diǎn)
- 可以采用多種編程語言來編寫
我們可以采用自己熟悉的開發(fā)語言編寫DLL,然后由其他語言編寫的可執(zhí)行程序來調(diào)用這些DLL.例如,可以利用VB來編寫程序界面,然后利用VC++或Delphi編寫的完成程序作業(yè)邏輯的DLL
- 增強(qiáng)產(chǎn)品的功能
在發(fā)布產(chǎn)品時(shí),可以發(fā)布產(chǎn)品功能實(shí)現(xiàn)的動(dòng)態(tài)鏈接庫規(guī)范,讓其他公司或個(gè)人遵照這種規(guī)范開發(fā)自己的DLL,以取代產(chǎn)品原有的DLL.讓產(chǎn)品調(diào)用新的DLL,從而實(shí)現(xiàn)功能的增強(qiáng),在實(shí)際工作中,我們看到許多產(chǎn)品都提供了界面插件功能,允許用戶動(dòng)態(tài)地更換程序的界面,這就可以通過更換界面DLL來實(shí)現(xiàn)
- 提供二次開發(fā)的平臺(tái)
在銷售產(chǎn)品時(shí),可以采用DLL的形式提供一個(gè)二次開發(fā)的平臺(tái),讓用戶可以利用該DLL調(diào)用其中實(shí)現(xiàn)的功能,編寫符合自己業(yè)務(wù)需要的產(chǎn)品,從而實(shí)現(xiàn)二次開發(fā)
- 簡(jiǎn)化項(xiàng)目管理
在一個(gè)大型項(xiàng)目開發(fā)中,通常都是由多個(gè)項(xiàng)目小組同時(shí)開發(fā),如果采用串行開發(fā),則效率非常低的,我們可以將項(xiàng)目細(xì)分,將不同功能交由各個(gè)項(xiàng)目小組以多個(gè)DLL方式實(shí)現(xiàn),這樣各個(gè)項(xiàng)目小組就可以同時(shí)進(jìn)行開發(fā)了
- 可以節(jié)省磁盤空間和內(nèi)存
如果多個(gè)應(yīng)用程序需要訪問同樣的功能,那么可以將該功能以DLL的形式提供,這樣在機(jī)器上只需要存在一份該DLL文件就可以了,從而節(jié)省了磁盤空間.另外如果多個(gè)應(yīng)用程序使用同一個(gè)DLL,該DLL的頁面只需要放入內(nèi)存一次,所有的應(yīng)用程序就都可以共享它的頁面了.這樣,內(nèi)存的使用將更加有效
如下圖所示就是一個(gè)動(dòng)態(tài)鏈接庫被兩個(gè)進(jìn)程調(diào)用時(shí)的內(nèi)存示意圖,當(dāng)進(jìn)程被加載時(shí),系統(tǒng)為它分配4GB的地址空間,接著分析該可執(zhí)行模塊,找到該程序要調(diào)用那些DLL模塊,然后系統(tǒng)搜索這些DLL,找到后就加載它們,并為它們分配虛擬的內(nèi)存空間,最后將DLL的頁面映射到進(jìn)程的地址空間.,從此可以導(dǎo)致多個(gè)程序中共享DLL的同一份代碼,這樣就可以節(jié)省空間 - 有助于資源的共享
DLL可以包含對(duì)話框模板,字符串,圖標(biāo)和位圖等多種資源,多個(gè)應(yīng)用程序可以使用DLL來共享這些資源.在實(shí)際工作中,可以寫一個(gè)純資源的動(dòng)態(tài)鏈接庫文件,供其他應(yīng)用程序訪問
- 有助于實(shí)現(xiàn)應(yīng)用程序的本地化
如果產(chǎn)品需要提供多語言版本,那么就可以使用DLL來支持多語言,可以為每種語言創(chuàng)建一個(gè)只支持這種語言的動(dòng)態(tài)鏈接庫
相關(guān)函數(shù)
顯示相關(guān)函數(shù)?
編寫動(dòng)態(tài)連接庫
本程序使用的編譯環(huán)境是VS2005,如果是使用VC6.0環(huán)境的可以去網(wǎng)上找孫鑫關(guān)于VC的視頻,視頻第19講講的就是動(dòng)態(tài)連接庫編寫.
[編寫動(dòng)態(tài)鏈接庫][加載動(dòng)態(tài)鏈接庫][C++命名改編][調(diào)用約定]
?
編寫動(dòng)態(tài)鏈接庫
建立DLL項(xiàng)目
- Win32 -> Win32項(xiàng)目 -> DLL(D)
- MFC -> MFC DLL
生成導(dǎo)出函數(shù),類,成員函數(shù)
- 生成導(dǎo)出函數(shù): 在函數(shù)前添加_declspec(dllexport)[導(dǎo)出標(biāo)示符]生成導(dǎo)出函數(shù),
- 生成導(dǎo)出類: 在class后類名前添加_declspec(dllexport)[[導(dǎo)出標(biāo)示符]這樣就可以導(dǎo)出整個(gè)類,但是訪問類的函數(shù)時(shí)候,仍然受限于函數(shù)自身的范圍權(quán)限.也就是說,如果該函數(shù)訪問權(quán)限是private或protect的話,那么外部程序仍然無法訪問這個(gè)函數(shù)
- 生成導(dǎo)出成員函數(shù): 在成員函數(shù)的返回類型后在函數(shù)的函數(shù)名前面加_declspec(dllexport)
代碼示例(例子鏈接)
?
加載動(dòng)態(tài)連接庫
隱式鏈接方式加載動(dòng)態(tài)庫(例子鏈接)
步驟:
- 加載dll.lib文件
- VC6.0: 點(diǎn)擊 Project/Settings后對(duì)話框下Link的Object/library modules下添加dll的lib文件
- VS/VC6.0: ? ?在文件中利用#pragma comment(lib,"鏈接庫地址")
- 加載dll.dll文件?
把dll文件放在下面路徑的一種中- 程序目錄
- 當(dāng)前目錄
- 系統(tǒng)目錄
- path環(huán)境變量中列出的路徑中
- 利用extern / _declspec(dllimport)[導(dǎo)出標(biāo)示符]聲明動(dòng)態(tài)鏈接庫的函數(shù)
- _declspec(dllimport) 可以調(diào)用dll中非導(dǎo)出函數(shù)[沒有_declspec(dllexport)的函數(shù)]
- extern ?只能調(diào)用dll中導(dǎo)出函數(shù)[有_declspec(dllexport)的函數(shù)]
流程圖:
顯示加載方式加載DLL(例子鏈接)
步驟:
- 將最新的dll文件復(fù)制到以下路徑中
- 程序目錄
- 當(dāng)前目錄
- 系統(tǒng)目錄
- path環(huán)境變量中列出的路徑中
- 調(diào)用LoadLibrary,加載動(dòng)態(tài)庫
- 聲明需要的動(dòng)態(tài)鏈接的函數(shù)指針類型(此處可以要可以不要,這樣只是方便以后定義相關(guān)函數(shù)指針) //例如下面要調(diào)用動(dòng)態(tài)鏈接庫中的 int max_dll(int a,int b) 函數(shù) //所以需要定義相關(guān)類型的指針聲明 typedef int (/*_stdcall*/ *INTMAX)(int a,int b);//以后就可以用INTMAX來定義相關(guān)指針如 INTMAX pMaxInt;
- 獲得函數(shù)地址GetProcAddress
- 調(diào)用FreeLibrary釋放動(dòng)態(tài)鏈接庫
流程圖:
兩種加載方式的比較
動(dòng)態(tài)加載和隱式鏈接這兩種加載DLL的方式各有優(yōu)點(diǎn).如果采用動(dòng)態(tài)加載的方式,那么可以在需要加載時(shí)才加載DLL.而隱式鏈接方式實(shí)現(xiàn)起來比較簡(jiǎn)單,在編寫客戶端代碼時(shí)就可以把鏈接工作做好,在程序中可以隨時(shí)調(diào)用DLL導(dǎo)出的函數(shù),但是訪問十多個(gè)DLL,如果都采用隱式鏈接的方式鏈接加載他們的話,那么在啟動(dòng)程序時(shí)候,這些DLL都需要加載到內(nèi)存中,并映射到調(diào)用進(jìn)程的地址空間,這樣將加大啟動(dòng)程序的時(shí)間,而且,一般來說,在程序運(yùn)行過程中只是在某個(gè)條件滿足時(shí)候,這時(shí)才會(huì)訪問某個(gè)DLL中的某個(gè)函數(shù),其他情況下都不需要訪問這些DLL,但是,這時(shí)所有的DLL都被已經(jīng)加載到內(nèi)存中,資源浪費(fèi)會(huì)比較嚴(yán)重,這種情況下,就可以采用動(dòng)態(tài)加載DLL技術(shù),也就是說,在需要時(shí),DLL才會(huì)被加載到內(nèi)存中,并被映射到進(jìn)程的地址空間中,有一點(diǎn)需要說明的是,實(shí)際上,采用隱式鏈接的方式訪問DLL時(shí),在啟動(dòng)時(shí)也是通過調(diào)用LoadLibrary函數(shù)加載到該進(jìn)程需要的動(dòng)態(tài)鏈接庫的
?
代碼示例
動(dòng)態(tài)連接庫源程序代碼
程序源碼
View Code隱式調(diào)用動(dòng)態(tài)鏈接
程序源碼
View Code運(yùn)行結(jié)果
顯示調(diào)用動(dòng)態(tài)鏈接庫
程序源碼
View Code運(yùn)行結(jié)果
dumpbin 工具
[概述][使用步驟][C++命名改編][調(diào)用約定]
?
概述
用途
查看dll與exe相關(guān)導(dǎo)入導(dǎo)出函數(shù)信息
dumpbin程序的文件位置
- VC6.0: VC98 \ bin
- VS2005: Microsoft Visual Studio 8\VC\bin
相關(guān)參數(shù)
- -exports 文件名.dll ? (查看導(dǎo)出函數(shù)和導(dǎo)出類)
- -imports 文件名.exe (查看導(dǎo)入函數(shù))
設(shè)置VC++使用環(huán)境信息
VCVAR32.bat 建立VC++使用環(huán)境信息,但是注意當(dāng)在命令行界面下執(zhí)行VCVARS32.bat文件后,該文件所設(shè)置的環(huán)境信息只是在當(dāng)前命令行窗口生效.如果關(guān)閉該窗口,再次啟動(dòng)一個(gè)新的命令行窗口后,仍需要運(yùn)行VCVAR32.bat文件
?
使用步驟
- 以上面的DLL源程序?yàn)槔?做個(gè)使用說明,先打開控制臺(tái)(如下圖)
- 然后,把建立VC++使用環(huán)境信息,把VCVAR32.bat(批處理的位置和dumpbin一樣)拖到控制臺(tái)界面中(如下圖).
- 然后回車,便建立好了VC++使用環(huán)境信息(如下圖).這樣就可以是用 dumpbin 這個(gè)命名了.
- 然后切換到工程目錄中的 debug 或 release 中去.(如下圖)
- 接著用 dumpbin 查看工程生成的 dll.dll 動(dòng)態(tài)鏈接庫的導(dǎo)出函數(shù)(如下圖)(注意:這個(gè)函數(shù)必須有_declspec(dllexport)修飾,否則在這里是看不到).
流程圖如下:
?
C++名字改編(C++名字粉碎)
在上面使用 dumpbin 程序查看 dll.dll 的導(dǎo)出函數(shù)發(fā)現(xiàn)函數(shù)名有點(diǎn)奇怪,我們定義的函數(shù)名max_dll兩個(gè)重載函數(shù)名在這里變成了 ?max_dll@@YAHHH@Z?與 ?max_dll@@YANNN@Z,因?yàn)?span style="color:#ff0000">C++支持函數(shù)重載,對(duì)于重載的多個(gè)函數(shù)來說,其函數(shù)名都是一樣的,為了加以區(qū)分,在編譯連接時(shí),C++會(huì)按照自己的規(guī)則篡改函數(shù)名字,這一過程為"名字改編".有的書中也稱為"名字粉碎".不同的C++編譯器會(huì)采用不同的規(guī)則進(jìn)行名字改編,這個(gè)的話,利用不同的C++編譯器生成的程序在調(diào)用對(duì)方提供的函數(shù)時(shí),可能會(huì)出現(xiàn)問題
解決名字改變問題
第一種
- 聲明:
- 在定義導(dǎo)出函數(shù)時(shí),需要加上限定符: extern"C" (雙引號(hào)中的C一定要大寫)
- 注意:
- 使動(dòng)態(tài)鏈接庫文件在鏈接時(shí),導(dǎo)出函數(shù)的函數(shù)名稱不發(fā)生改變.
- 利用 extern "C" 可以解決 C++ 和 C 語言之間相互調(diào)用時(shí)函數(shù)命名的問題.但是這種方法有一個(gè)缺陷,就是不能用于導(dǎo)出一個(gè)類成員函數(shù),只能導(dǎo)出全局函數(shù)這種情況
- 如果導(dǎo)出函數(shù)的調(diào)用約定發(fā)生了改變,那么即使使用了限定符: extern "C" ,該函數(shù)的名字仍然會(huì)發(fā)生改編.
- 記得導(dǎo)出和導(dǎo)入都要加入 extern "C" 否則在調(diào)用動(dòng)態(tài)鏈接庫時(shí)候會(huì)發(fā)生找不到函數(shù)這個(gè)現(xiàn)象.
代碼樣例:
利用 extern"C" 解決名字改編
動(dòng)態(tài)連接庫程序源碼
View Code主程序源碼
View Code利用 dumpbin 查看命名
?
調(diào)用約定
四種調(diào)用方式:
__cdecl
__cdecl調(diào)用約定又稱為 C 調(diào)用約定,是 C/C++ 語言缺省的調(diào)用約定。參數(shù)按照從右至左的方式入棧,函數(shù)本身不清理?xiàng)?#xff0c;此工作由調(diào)用者負(fù)責(zé),返回值在EAX中。由于由調(diào)用者清理?xiàng)?#xff0c;所以允許可變參數(shù)函數(shù)存在,如int sprintf(char* buffer,const char* format,...);。
__stdcall
__stdcall 很多時(shí)候被稱為 pascal 調(diào)用約定。pascal 語言是早期很常見的一種教學(xué)用計(jì)算機(jī)程序設(shè)計(jì)語言,其語法嚴(yán)謹(jǐn)。參數(shù)按照從右至左的方式入棧,函數(shù)自身清理堆棧,返回值在EAX中。
__fastcall
顧名思義,__fastcall 的特點(diǎn)就是快,因?yàn)樗ㄟ^ CPU 寄存器來傳遞參數(shù)。他用 ECX 和 EDX 傳送前兩個(gè)雙字(DWORD)或更小的參數(shù),剩下的參數(shù)按照從右至左的方式入棧,函數(shù)自身清理堆棧,返回值在 EAX 中。
__thiscall
這是 C++ 語言特有的一種調(diào)用方式,用于類成員函數(shù)的調(diào)用約定。如果參數(shù)確定,this 指針存放于 ECX 寄存器,函數(shù)自身清理堆棧;如果參數(shù)不確定,this指針在所有參數(shù)入棧后再入棧,調(diào)用者清理?xiàng)!_thiscall 不是關(guān)鍵字,程序員不能使用。參數(shù)按照從右至左的方式入棧。
相關(guān)鏈接:
- C/C++函數(shù)調(diào)用約定
- 剖析VC++函數(shù)調(diào)用約定
代碼示例(編譯環(huán)境VS2005):
使用 extern "C" 時(shí)
動(dòng)態(tài)連接庫源碼:
View Code用 dumpbin 查看導(dǎo)出函數(shù):
未使用 extern "C" 時(shí)
動(dòng)態(tài)連接庫源碼:
View Code用 dumpbin 查看導(dǎo)出函數(shù):
?
總結(jié)
- 上一篇: C语言的头文件和库文件(函数库)
- 下一篇: 年后开课 | 第 4 期临床基因组家系分