新聞中心
?當(dāng)程序啟動或加載 DLL 時,加載器將生成該程序/DLL 引用的所有 DLL、該 DLL 的依賴項等的依賴項樹。然后,它確定初始化這些 DLL 的正確順序,以便在初始化它所依賴的所有 DLL 之前,不會初始化任何 DLL。(當(dāng)然,如果你有一個循環(huán)依賴關(guān)系,那么它就會崩潰。眾所周知,從 DLL 的DLL_PROCESS_ATTACH 通知中調(diào)用加載庫函數(shù)或 LoadLibraryEx 函數(shù)也會弄亂這些依賴項的計算過程。)

花山ssl適用于網(wǎng)站、小程序/APP、API接口等需要進行數(shù)據(jù)傳輸應(yīng)用場景,ssl證書未來市場廣闊!成為成都創(chuàng)新互聯(lián)公司的ssl證書銷售渠道,可以享受市場價格4-6折優(yōu)惠!如果有意向歡迎電話聯(lián)系或者加微信:18980820575(備注:SSL證書合作)期待與您的合作!
同樣,當(dāng)卸載 DLL 或程序終止時,將進行反初始化,以便在 DLL 的所有依賴項之后反初始化該 DLL。
但是,當(dāng)你手動加載 DLL 時,關(guān)鍵信息會丟失:即調(diào)用 LoadLibrary 的 DLL 取決于正在被加載的 DLL。因此,如果 A.DLL 手動加載 B.DLL,則不能保證 A.DLL 將在 B.DLL 之前卸載。這意味著,例如,像下面這樣的代碼是不可靠的:
在標記為 “oops” 的行中,不能保證 B.DLL 仍在內(nèi)存中,因為 B.DLL 不會出現(xiàn)在 A.DLL 的依賴項列表中,即使存在由對 LoadLibrary 的調(diào)用導(dǎo)致的運行時生成的動態(tài)依賴項。
為什么加載器無法跟蹤此動態(tài)依賴項?換句話說,當(dāng)A.DLL調(diào)用LoadLibrary(“B.DLL”) 時,為什么加載器不能自動說“好吧,現(xiàn)在A.DLL依賴于B.DLL”?
首先,因為正如我在之前的文章中所指出的,你不能相信返回地址。
其次,即使你可以相信返回地址,你仍然不能相信返回地址。我們看看下面的代碼:
在這種情況下,B.DLL 的加載不是直接從A.DLL發(fā)生的,而是通過中間(在本例中為中間函數(shù))發(fā)生的。即使你可以相信返回地址,依賴項也會分配給 MID.DLL 而不是A.DLL。
你可能會問,”什么樣的人會寫出像中函數(shù)這樣的函數(shù)呢?”。這種中間函數(shù)在幫助函數(shù)/包裝器函數(shù)很常見,或者為了提供額外的生存期管理功能(盡管它現(xiàn)在不再這樣做了,但是它曾經(jīng)這樣做過)。
第三,有調(diào)用 GetModuleHandle 函數(shù)的情況。我們看看下面的代碼:
我們對 GetModuleHandle 的調(diào)用,是否應(yīng)創(chuàng)建依賴項呢?
另請注意,DLL 之間存在的依賴關(guān)系不僅僅是對 LoadLibrary 的調(diào)用。例如,如果將回調(diào)函數(shù)指針傳遞給另一個 DLL,則就會創(chuàng)建一個反向依賴項。
最后要注意的是,這種隱式依賴關(guān)系,就像上面寫的那樣很難看到,一旦你把全局析構(gòu)函數(shù)扔進去,情況就更糟了。例如下面的代碼:
DLL 依賴項現(xiàn)在隱藏在 SomethingHolder 類中,當(dāng) A.DLL 卸載時,g_SomethingHolder的析構(gòu)函數(shù)將運行并嘗試與 B.DLL 通信。隨之而來的,是程序的不可預(yù)知的行為。
總結(jié)
盡量不對系統(tǒng)運行行為做出過多的假設(shè),嚴格按照 MSDN 所說的,老老實實寫你的代碼,基本不會有大錯誤。
本文名稱:為什么動態(tài)鏈接庫以"錯誤"的方式被卸載?
網(wǎng)頁路徑:http://m.5511xx.com/article/ccdippo.html


咨詢
建站咨詢
