我有一個關於當我運行二進制依賴於共享 庫(.so)誰將載入共享庫共享庫問題關於共享庫
一些問題?
共享庫在哪裏加載?
如果共享庫已經加載,我運行二進制文件取決於加載的庫,在這種情況下共享庫將被加載 或二進制將使用加載的庫?
我有一個關於當我運行二進制依賴於共享 庫(.so)誰將載入共享庫共享庫問題關於共享庫
一些問題?
共享庫在哪裏加載?
如果共享庫已經加載,我運行二進制文件取決於加載的庫,在這種情況下共享庫將被加載 或二進制將使用加載的庫?
當我運行二進制文件時,誰將加載共享庫取決於共享庫(.so)?
當您的exec
是二進制文件時,Linux內核將讀取文件的elf標頭。所有動態鏈接的ELF文件都在ELF文件中的程序標頭.interp
(解釋程序)中註冊了/lib/ld-linux.so.2
(運行時動態鏈接程序)。當解釋器出現時,Linux內核將加載解釋器的ELF(通過將其翻譯成內存,並根據其頭文件),並跳入其入口點。
運行時動態鏈接器將讀取您的動態鏈接程序,查找所有需要的共享庫並將它們加載到內存中(同樣使用mmap
和ELF頭信息)。
共享庫在哪裏加載?
共享庫中搜索所有目錄中,在運行時庫搜索路徑($LD_LIBRARY_PATH
和/etc/ld.so.conf
)上市。
用於加載每個庫的內存地址由ld-linux.so.2
(也可能由內核來確定,例如用於隨機化起始地址)確定。
庫加載的實際代碼是glibc的,elf/rtld.c
文件http://fxr.watson.org/fxr/source/elf/rtld.c?v=GLIBC27#L1731:
1731 /* Load all the libraries specified by DT_NEEDED entries. .... */
1735 _dl_map_object_deps (main_map, preloads, npreloads, mode == trace, 0);
然後連接器將連接的目標文件之間的符號引用(搬遷過程中,有時完成後,如果延遲綁定是符號實際引用活性)。
如果共享庫已經加載,我運行二進制文件取決於加載的庫,在這種情況下,共享庫將被加載或二進制文件將使用加載庫?
你應該知道mmap
如何處理文件。硬盤(HDD或SSD)上存儲有文件,應將其加載到要執行的存儲器中。鏈接器不會mmap
整個庫文件;只有具有庫數據和代碼的部分。而且,mmap
系統調用是懶惰的,它不會將所有請求的文件加載到內存中,而只是記住相應的虛擬頁面和文件偏移量。在首次訪問虛擬頁面時,會發生pagefault
(主要頁面錯誤),並且將從HDD中讀取文件的部分(Linux可能會從磁盤加載更多頁面;也有預取程序可在引導過程中儘早將庫讀入內存) 。
如果幾個進程mmap
是同一個文件,則將使用寫入時複製機制。這意味着:如果內存頁面只被讀取,則會有一個物理頁面。幾個虛擬頁面將被映射到它;所有都不允許「寫入」訪問。對於頁面上的每次寫入訪問,複製將完成(通過次要頁面錯誤),原始物理頁面(如果複製到新物理頁面中);並且映射將針對寫入訪問的進程而改變。從頁面錯誤中斷返回後,寫入指令將重新開始,執行寫入頁面的副本。
共享庫的大部分可執行代碼都未寫入,因此它在所有進程之間共享。數據段(.data,.bss,.tdata,.bss)將不會被共享,因爲有寫入。重定位也將取消共享某些頁面。
您的問題1和2的答案是:它取決於(您所使用的操作系統)。在大多數UNIX操作系統上,運行時加載程序(通常爲ld.so
或ld-linux.so
)將在任何需要的地方加載共享庫。
對於問題3,通常共享庫進程之間共享,所以是:一個新加載的可執行將重新使用共享庫那些已經通過某些其它過程加載。注意:只有代碼(和只讀數據)段是共享的;每個進程都有自己的可寫數據段副本。
尋找來自可信和/或官方消息來源的答案。
對於Linux,this guide詳細介紹了共享庫加載過程(可能包含比您更關注的細節)。
此外,this book有一個early draft可在線。
數據是COW共享的。 – ninjalj