linux下查看程序依賴的庫

在x86下,爲了查看程序所依賴的庫,可使用ldd命令linux

p_w_picpath thumb8 linux下查看程序依賴的庫

但若是是使用arm-linux-gcc 等交叉編譯環境編譯出來的程序,則要使用readelf命令來查看了web

p_w_picpath thumb9 linux下查看程序依賴的庫

 

庫用於將類似函數打包在一個單元中。而後這些單元就可爲其餘開發人員所共享,並所以有了模塊化編程這種說法 — 即,從模塊中構建程序。Linux 支持兩種類型的庫,每一種庫都有各自的優缺點。靜態庫包含在編譯時靜態綁定到一個程序的函數。動態庫則不一樣,它是在加載應用程序時被加載的,並且它與應用程序是在運行時綁定的。圖 1 展現了 Linux 中的庫的層次結構。shell

圖 1. Linux 中的庫層次結構編程

figure11 thumb linux下查看程序依賴的庫

使用共享庫的方法有兩種:您既能夠在運行時動態連接庫,也能夠動態加載庫並在程序控制之下使用它們。本文對這兩種方法都作了探討。ide

靜態庫較適宜於較小的應用程序,由於它們只須要最小限度的函數。而對於須要多個庫的應用程序來講,則適合使用共享庫,由於它們能夠減小應用程序對內存(包括運行時中的磁盤佔用和內存佔用)的佔用。這是由於多個應用程序能夠同時使用一個共享庫;所以,每次只須要在內存上覆制一個庫。要是靜態庫的話,每個運行的程序都要有一份庫的副本。模塊化

GNU/Linux 提供兩種處理共享庫的方法(每種方法都源於 Sun Solaris)。您能夠動態地將程序和共享庫連接並讓 Linux 在執行時加載庫(若是它已經在內存中了,則無需再加載)。另一種方法是使用一個稱爲動態加載的過程,這樣程序能夠有選擇地調用庫中的函數。使用動態加載過程,程序能夠先加載一個特定的庫(已加載則沒必要),而後調用該庫中的某一特定函數(圖 2 展現了這兩種方法)。這是構建支持插件的應用程序的一個廣泛的方法。函數

圖 2. 靜態連接與動態連接工具

figure21 thumb linux下查看程序依賴的庫

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命令也如此)。切記,它僅僅是一個用戶空間程序,是由內核在須要時引導的。

相關文章
相關標籤/搜索