有關DLL的幾個問題

2021-06-06 10:08:44 字數 2041 閱讀 2226

一、dll被多個程序呼叫問題

win32系統會確保記憶體中只有乙個該dll的拷貝,這是通過記憶體對映檔案來實現的。不同的程序分別將這份dll的**段位址對映到自己的程序空間中,同時不同的程序在自己的程序空間分別有各自的乙份該dll的資料段拷貝。

這是因為,在win32環境中,每個程序都有了它自己的位址空間,dll函式中的**所建立的任何物件(包括變數)都歸呼叫它的程序所有。當程序在載入dll時,作業系統自動把dll記憶體位址對映到該程序的私有空間,也就是程序的虛擬位址空間,而且也複製該dll的全域性資料的乙份拷貝到該程序空間。(在物理記憶體中,多程序載入dll時,dll的**段實際上是只載入了一次,只是將物理位址對映到了各個呼叫它的程序的虛擬位址空間中,而全域性資料會在每個程序都分別載入)。也就是說每個程序所擁有的相同的dll的全域性資料,它們的名稱相同,但其值卻並不一定是相同的,而且是互不干涉的。因此,如果不採取特別的措施,dll中的資料段不能跨程序共享。如果將將資料段的屬性修改為共享的,這樣該資料將被映像到所有的使用到該dll的程序,即多個程序將共享該資料段

二、既然**段共享,如果程序a中修改dll的**內容,使用同一dll的其它程序b是否受影響?

不會!這就涉及到乙個記憶體的copy on write 機制問題。

乙個dll,被很多程序呼叫,為什麼**段共享,資料段不共享?就是因為 程序a呼叫這個dll,執行過程中,dll的資料段肯定會改變,那資料段就會被copy乙份,原來的依然存在不受影響。

當程序b呼叫這個dll,仍然用的是最開始的資料段,它往裡寫時再copy乙份到自己的程序空間,這就保證了兩個程序a和b互不影響。

而由於**段一般是不會被更改的,所以才提到**段共享這個概念。但如果用hook等技術,把**改了,**同樣會被copy乙份之後再改,所以不會影響其它的程序,只會影響你改的程序。於是可以解釋下面某位同學所做的實驗了:

在這裡我做了乙個試驗,編寫乙個dll和乙個載入dll並呼叫dll中乙個函式的程式,分別用二個od載入這二個可執行程式呼叫dll中的函式,為了說明載入的這個dll分別位於不同的程序,沒有任何的共享關係,我把二個程序同時一步一步除錯,都執行到載入完dll後,dll的載入位址是一樣的都0x10000000,接著我在第乙個程序中轉到dll載入的地方,把mz頭用00填充,再一下f9,結果程式顯示找不到呼叫的函式,接著再轉到第二個程序,也轉到0x10000000去看一下,這裡沒有被改動的跡象。f9一下,可以執行成功。說明載入的dll雖然都在0x10000000,但是它們位於不同的程序,是不會相互干擾的

概括來說,copy-on-write機制,無論是**段還是資料區,在一般情況下,如果沒有被修改,都會被對映到相同的記憶體上,因此當載入同乙個dll的時候,記憶體中只有乙份dll。如果有內容被修改後,會構造副本,重新對映

三、dll中在堆上分配的空間,能否在主程式中直接釋放?

通常不行,誰負責分配,誰就必須負責釋放

原因之一就是因為dll的呼叫是有被計數的,為了防止還有呼叫程式正在引用dll,你不應該在程式中釋放記憶體. 比如有一部分共享記憶體的資料,在程序a中釋放了,程序b任然在使用,肯定會出問題。所以讓dll自己來釋放,自己來管理。

原因之二就是因為   malloc/free,   new/delete   都是呼叫   heapalloc/heapfree   來實現來實現記憶體分配是釋放的。檢視windows的 api可以看到,這兩個函式都需要乙個heap的handle做為引數。crt庫採用了全域性變數來儲存這個handle。如果是靜態鏈結,crt庫的**會鏈結到各個dll中去,也包括這個全域性變數。也就是說,每個靜態鏈結的   dll或exe   都有乙個自己的全域性堆控制代碼,他們都在自己的這個控制代碼上使用記憶體。當在乙個 dll或exe中釋放另外乙個dll分配的記憶體時,由於使用的堆控制代碼不一致於是出錯。當使用動態鏈結時,由於每個dll都是去呼叫crt庫的dll函式來分配和釋放記憶體的,使用的是同乙個控制代碼,所以就沒有這個問題。

四、dll載入的順序

乙個程序開始執行時,先會檢查自己的匯入表,看一下依賴的dll有哪些,發現有依賴的dll,那麼就檢查記憶體中是否有這個dll了。如果沒有,dll首先被調入win32系統的全域性堆疊,然後對映到呼叫這個dll的程序的位址空間。如果存在了,直接對映該dll的**段位址。因此不管該程序有多少乙個例項,這個過程都是要做的。然後涉及到dll的初始化問題,參考寫的很好。

有關c 的幾個問題

1.在物件導向中既然結構體中可以有成員變數也可以有方法等,那為什麼還要有類的存在呢?結構體是值型別,而類是引用型別。然後就是值型別和引用型別之間的區別了。2.string 和 string 有何區別?通過typeof 的測試可以發現兩者的結果都是 system.string 型別。其實 string...

有關Xshell的幾個問題

用xshell登入虛擬機器中的kali系統時,有時會出現登入不上,但你之前是能成功登入上的,此時,你因該從以下幾點考慮以下 1.sshd服務是否開啟 我用service sshd start 是無法開啟的,同時這條命令也不能很好的執行下去,我用的命令是 etc init.d ssh start 或 ...

有關GitHub倉庫分支的幾個問題

眾所周知,github通過fork成為一種超級儲存庫,讓你可以看到fork網路中的所有提交,對私人倉庫也是如此。舉個例子 如果你 bob 從alice那fork了乙個倉庫p,alice在你fork後使用雜湊x進行 提交,你就可以通過 github.com bob p tree x 訪問這些提交。即使...