在x86下,爲了查看程序所依賴的庫,可使用ldd命令linux
但若是是使用arm-linux-gcc 等交叉編譯環境編譯出來的程序,則要使用readelf命令來查看了web
庫用於將類似函數打包在一個單元中。而後這些單元就可爲其餘開發人員所共享,並所以有了模塊化編程這種說法 — 即,從模塊中構建程序。Linux 支持兩種類型的庫,每一種庫都有各自的優缺點。靜態庫包含在編譯時靜態綁定到一個程序的函數。動態庫則不一樣,它是在加載應用程序時被加載的,並且它與應用程序是在運行時綁定的。圖 1 展現了 Linux 中的庫的層次結構。shell
使用共享庫的方法有兩種:您既能夠在運行時動態連接庫,也能夠動態加載庫並在程序控制之下使用它們。本文對這兩種方法都作了探討。ide
靜態庫較適宜於較小的應用程序,由於它們只須要最小限度的函數。而對於須要多個庫的應用程序來講,則適合使用共享庫,由於它們能夠減小應用程序對內存(包括運行時中的磁盤佔用和內存佔用)的佔用。這是由於多個應用程序能夠同時使用一個共享庫;所以,每次只須要在內存上覆制一個庫。要是靜態庫的話,每個運行的程序都要有一份庫的副本。模塊化
GNU/Linux 提供兩種處理共享庫的方法(每種方法都源於 Sun Solaris)。您能夠動態地將程序和共享庫連接並讓 Linux 在執行時加載庫(若是它已經在內存中了,則無需再加載)。另一種方法是使用一個稱爲動態加載的過程,這樣程序能夠有選擇地調用庫中的函數。使用動態加載過程,程序能夠先加載一個特定的庫(已加載則沒必要),而後調用該庫中的某一特定函數(圖 2 展現了這兩種方法)。這是構建支持插件的應用程序的一個廣泛的方法。函數
Linux 提供了不少種查看和解析 ELF 對象(包括共享庫)的工具。其中最有用的一個當屬ldd
命令,您可使用它來發送共享庫依賴項。例如,在 dl
應用程序上使用 ldd
命令會顯示以下內容:spa
mtj@camus:~/dl$ ldd dl linux-gate.so.1 => (0xffffe000) libdl.so.2 => /lib/tls/i686/cmov/libdl.so.2 (0xb7fdb000) libc.so.6 => /lib/tls/i686/cmov/libc.so.6 (0xb7eac000) /lib/ld-linux.so.2 (0xb7fe7000) mtj@camus:~/dl$
ldd
所告訴您的是:該 ELF 映像依賴於 linux-gate.so(一個特殊的共享對象,它處理系統調用,它在文件系統中無關聯文件)、libdl.so(DL API)、GNU C
庫(libc.so)以及 Linux 動態加載器(由於它裏面有共享庫依賴項)。插件
readelf
命令是一個有不少特性的實用程序,它讓您可以解析和讀取 ELF 對象。readelf
有一個有趣的用途,就是用來識別對象內可再定位的項。對於咱們這個簡單的程序來講(清單 2展現的程序),您能夠看到須要再定位的符號爲:
mtj@camus:~/dl$ readelf -r dl Relocation section '.rel.dyn' at offset 0x520 contains 2 entries: Offset Info Type Sym.Value Sym. Name 08049a3c 00001806 R_386_GLOB_DAT 00000000 __gmon_start__ 08049a78 00001405 R_386_COPY 08049a78 stdin Relocation section '.rel.plt' at offset 0x530 contains 8 entries: Offset Info Type Sym.Value Sym. Name 08049a4c 00000207 R_386_JUMP_SLOT 00000000 dlsym 08049a50 00000607 R_386_JUMP_SLOT 00000000 fgets 08049a54 00000b07 R_386_JUMP_SLOT 00000000 dlerror 08049a58 00000c07 R_386_JUMP_SLOT 00000000 __libc_start_main 08049a5c 00000e07 R_386_JUMP_SLOT 00000000 printf 08049a60 00001007 R_386_JUMP_SLOT 00000000 dlclose 08049a64 00001107 R_386_JUMP_SLOT 00000000 sscanf 08049a68 00001907 R_386_JUMP_SLOT 00000000 dlopen mtj@camus:~/dl$
從這個列表中,您能夠看到各類各樣的須要再定位(到 libc.so)的 C
庫調用,包括對 DL API(libdl.so)的調用。函數 __libc_start_main
是一個 C
庫函數,它優先於程序的 main
函數(一個提供必要初始化的 shell)而被調用。
其餘操做對象文件的實用程序包括:objdump
,它展現了關於對象文件的信息;nm
,它列出來自對象文件(包括調試信息)的符號。還能夠將 EFL 程序做爲參數,直接調用 Linux 動態連接器,從而手動啓動映像:
mtj@camus:~/dl$ /lib/ld-linux.so.2 ./dl > libm.so expf 0.0 1.000000 >
另外,可使用 ld-linux.so 的 --list
選項來羅列 ELF 映像的依賴項(ldd
命令也如此)。切記,它僅僅是一個用戶空間程序,是由內核在須要時引導的。