[英]Is Dynamic Linker part of Kernel or GCC Library on Linux Systems?
動態鏈接器(又名程序解釋器,鏈接加載器)是內核或GCC庫的一部分嗎?
更新 (28-08-16):
我發現每個二進制文件(即鏈接到共享庫)使用/lib64/ld-linux-x86-64.so.2
動態鏈接器的默認路徑是指向共享庫/lib/x86_64-linux-gnu/ld-2.23.so
這是實際的動態鏈接器。
它是libc6 (2.23-0ubuntu3)
包的一部分。 GNU C Library: ubuntu中用於AMD64體系結構的共享庫 。
我的實際問題是
如果這個幫助程序( ld-2.23.so )不存在,那么動態鏈接的所有應用程序(所有,現在是幾天)會發生什么?
答案是“沒有應用程序會運行,甚至是shell程序”。 我在虛擬機器上嘗試過它。
在ELF可執行文件中,這被稱為“ELF解釋器”。 在linux(例如)上,這是/lib64/ld-linux-x86-64.so.2
這不是內核的一部分,[通常]與glibc
等。 人。
當內核執行ELF可執行文件時,它必須將可執行文件映射到用戶空間內存。 然后它在內部尋找一個稱為INTERP
的特殊子部分[其中包含一個完整路徑的字符串]。
然后,內核將解釋器映射到用戶空間內存並將控制權轉移給它。 然后,解釋器執行必要的鏈接/加載並啟動程序。
因為ELF
代表“可擴展的鏈接器格式”,所以這允許許多不同的子部分與ELF文件。
與文件配對的ELF解釋器知道,而不是讓內核不必知道所有無數的擴展。
雖然通常在給定系統上只使用一種格式,但系統上可能有幾種不同的ELF文件變體,每種變體都有自己的ELF解釋器。
這將允許[說] BSD ELF文件在Linux系統上運行[與其他調整/支持]因為ELF文件將指向BSD ELF解釋器而不是linux。
更新:
每個進程(vlc播放器,chrome)都有共享庫ld.so作為其地址空間的一部分。
是。 我假設您正在查看/proc/<pid>/maps
。 這些是對文件的映射 (例如使用mmap
)。 這與“加載”有些不同,這可能意味着[符號] 鏈接 。
因此,在將可執行文件(代碼和數據)加載到內存之后,它主要是加載器,它將動態鏈接器(.so)加載並映射到其地址空間
了解這一點的最好方法是改寫你剛才說的話:
所以主要是在將可執行文件(代碼和數據)映射到內存之后的內核 , 內核將動態鏈接器(.so)映射到程序地址空間
這基本上是正確的。 內核還映射其他內容,例如bss
段和堆棧。 然后它將argc
, argv
和envp
[環境變量的空間]“推”到堆棧上。
然后,確定了ld.so
的起始地址[通過讀取文件的特殊部分],它將其設置為恢復地址並啟動線程。
到目前為止,它一直是內核做事。 內核幾乎沒有符號鏈接 。
現在, ld.so
接管......
這進一步加載共享庫,映射和解析對庫的引用。 然后它調用入口函數(_start)
由於原始可執行文件(例如vlc
)已映射到內存中,因此ld.so
可以檢查它所需的共享庫列表。 它映射到這些記憶,但不將符號鏈接不一定馬上。
映射簡單快捷 - 只需調用mmap
。
可執行文件的起始地址[ 不與起始地址混淆ld.so
],從ELF可執行的一個特殊的部分采取。 雖然,與此起始地址關聯的符號傳統上稱為_start
,但它實際上可以命名為任何內容(例如__my_start
),因為它是在區段數據中確定起始地址而不是符號_start
地址。
將符號引用鏈接到符號定義是一個耗時的過程。 因此,這是推遲到符號實際使用之前。 也就是說,如果一個程序引用了printf
,那么鏈接器實際上並沒有嘗試在printf
鏈接,直到程序第一次實際調用 printf
為止。
這有時被稱為“按需鏈接”或“按需鏈接”。 請在此處查看我的答案: 寫入時復制會影響哪些細分受眾群? 有關該問題的更詳細說明以及將可執行文件映射到用戶空間時實際發生的情況。
如果您有興趣,可以使用ldd /usr/bin/vlc
來獲取它使用的共享庫列表。 如果查看readelf -a /usr/bin/vlc
的輸出,您將看到這些相同的共享庫。 此外,您將獲得ELF解釋器的完整路徑,並可以執行readelf -a <full_path_to_interpreter>
並注意一些差異。 您可以為vlc
想要的任何.so
文件重復此過程。
將所有這些與/proc/<pid>maps
等結合起來。 人。 可能有助於你的理解。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.