Dynamic-Linking

請問動態連結庫必須載入到RAM中嗎

  • April 17, 2018

眾所周知,任何正在執行的執行檔都會載入到 RAM 中。

另外,我們有兩種庫:靜態連結庫和動態連結庫。

這兩種庫也應該在需要時載入到 RAM 中。

據我所知,我們有兩種載入動態庫的方法:

  1. 在編譯時連結它,例如g++ -lsofile
  2. 在程式碼中動態載入,我們必須dlopen這樣做

我已經發布了這個問題,但我仍然不能確保我們可以列出所有的 lib 文件。對於上面的第一種情況,我認為我們可以使用ldd,或檢查來獲取連結文件/proc/{PID}/maps。但是對於第二種情況,我在想是否可以通過某種方法獲取連結文件,這是一個範例:

void SomeModule()
{
   //dlopen here to link mysofile
}

int main()
{
   if (user_enter == 'a')
   {
       printf("hello world");
   }
   else
   {
       SomeModule();
   }
}

在這個例子中,當我們執行它並輸入 alwaysa時,dlopen將永遠不會被呼叫,因此mysofile永遠不會被連結,這意味著mysofile永遠不會被載入到 RAM 中。我對嗎?

如果是這樣,除了閱讀原始碼之外,我怎樣才能獲得執行檔所需的lib文件?

你是對的,如果dlopen從不呼叫,則目標庫永遠不會載入到(程序的)記憶體中。

在不閱讀原始碼的情況下確定必要的庫感覺就像是停止問題的變體。您可以使用一些啟發式方法:如果程序沒有連結到libdl,那麼它就不能使用dlopen; 如果是這樣,那麼您可以使用strace(請參閱如何找出執行時載入的動態庫執行檔?)或嘗試找出dlopen使用靜態分析的參數。但是程序可以libdl直接包含(通過靜態連結或建構程式碼);並且由於動態連結器不是魔術,沒有什麼可以阻止程序自己重新實現它,所以你不能絕對確保您已經使用這些啟發式方法擷取了所有需要的庫。也許有些程序發現它們正在被跟踪,並跳過庫載入……

列出所有所需庫的唯一可靠方法是閱讀原始碼。

眾所周知,任何正在執行的執行檔都會載入到 RAM 中。

錯誤的 !

一個可執行文件被核心的虛擬記憶體子系統映射到執行它的程序的虛擬地址空間中。物理 RAM 僅由核心管理。閱讀作業系統:三個簡單的部分了解更多資訊。

並非該執行檔的所有程式碼段都被分頁(未載入!)到 RAM 中。特別是,一大段從未使用過的程式碼(例如,因為它包含一些從未呼叫過的大函式)不會進入 RAM。閱讀有關分頁頁面記憶體的資訊。

有時,沒有足夠的物理 RAM 來方便地處理所有需要的頁面。在那種情況下,您會觀察到顛簸

動態連結器(參見ld-linux(8))和dlopen(3)使用mmap(2)從共享庫中映射一些段。因此它不會將外掛的所有程式碼段載入到 RAM 中。另請閱讀 Drepper 的如何編寫共享庫論文。

當我們執行它並始終鍵入 a 時,dlopen 將永遠不會被呼叫,因此 mysofile 將永遠不會被連結,這意味著 mysofile 永遠不會被載入到 RAM 中。

一般來說,絕對沒有辦法預測未來將使用和編輯哪些共享庫dlopen。考慮以下兩種情況:

  • 一個持久的程序(可能是您的瀏覽器)要求它的使用者獲取一些共享庫(可能從網路下載它)然後dlopen它。
  • 一個程序在一個臨時文件中生成一些 C 程式碼,將該文件/tmp/emittedcode.c編譯(通過fork執行 some 的適當程序gcc -O -Wall -fPIC /tmp/emittedcode.c -shared -o /tmp/emittedcode.so)該文件到一個臨時外掛中/tmp/emittedcode.so,然後dlopen-s 該臨時外掛(當然稍後dlsym在那裡 -ing 適當的符號)。

我非常喜歡第二種方法。請注意,編譯為 C是一個很好的習慣。目前的編譯器速度足夠快,甚至可以在某些 REPL 互動中實現這一點。

順便說一句,在 Linux 桌面上,一個程序可能dlopen *有很多共享對象,*即外掛(至少數十萬,可能還有數百萬)。請參閱我的manydl.c範例(在臨時文件中生成“隨機”C 程式碼並重複)。

PS。還要注意Halting Problem,它與預測所有未來dlopen路徑的理論不可能性有關。

引用自:https://unix.stackexchange.com/questions/429188