文法:ldd參數 檔案
作用: 輸出共用庫的依賴資訊
例如:
# ldd /bin/cat libc.so.6 => /lib/tls/libc.so.6 (0x42000000) /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000)
說明:ldd參數較少,其實ldd不是一個程式,僅僅是一個指令碼,通過設定一系列環境變數實現。其實質是通過ld-linux.so(elf動態庫的裝載器)來實現的。我們知道,ld-linux.so模組會先於可執行模組程式工作,並獲得控制權,因此當上述的那些環境變數被設定時,ld-linux.so選擇了顯示可執行模組的依賴。如果其注意到環境變數LD_TRACE_LOADED_OBJECTS 被設定了,那麼它就不會去執行那個可啟動並執行程式,而去輸出這個可執行程式所依賴的動態連結程式庫 (在BSD 系統上的`ldd` 是一個C 程式)。
例如:
# export LD_TRACE_LOADED_OBJECTS=1
# ls
librt.so.1 => /lib64/librt.so.1 (0x0000002a9566d000)
libc.so.6 => /lib64/libc.so.6 (0x0000002a95786000)
libpthread.so.0 => /lib64/libpthread.so.0 (0x0000002a959a8000)
/lib64/ld-linux-x86-64.so.2 (0x0000002a95556000)
# unset LD_TRACE_LOADED_OBJECTS
# ls
bin dev home ...
參數:
-d –data-relocs 輸出資料重定位資訊。並報告缺少的目標對象(only for ELF) ; LD_WARN=yes
-r --function-relocs 輸出資料和函數重定位資訊。並報告缺少的目標對象和函數(只對ELF格式適用) ; LD_WARN和LD_BIND_NOW=yes
-u, --unused 輸出未使用的直接依賴 LD_DEBUG=“unused”
-v, --verbose 列印所有資訊; LD_VERBOSE=yes
環境變數:
LD_TRACE_LOADED_OBJECTS
LD_LIBRARY_PATH:
LD_WARN
LD_BIND_NOW
LD_LIBRARY_VERSION
LD_VERBOS
樣本:
定義兩個檔案:
fun.c 中有一個函數 int fun();
main.c調用 fun.c中的函數fun();
將fun.c編譯成動態庫:
# gcc -fPIC -shared fun.c -o fun.so
編譯main.c
# gcc main.c ./fun.so -o main
查看用到的共用庫:
# ldd main
linux-gate.so.1 => (0x00970000)
./fun.so (0x00871000)
libc.so.6 => /lib/i686/nosegneg/libc.so.6 (0x00339000)
/lib/ld-linux.so.2 (0x0031a000)
其它: Linux庫管理命令
- ldconfig: 例如替換了庫的連結 /lib/libc.so.6 -> libc-2.3.2.so => /lib/libc.so.6 -> libc-2.3.4.so,就需要使用ldconfig命令更新。相關檔案ld.so.conf, ld.so.cache。
- ldd : Tells what libraries a given program needs to run.
- ld.so/ld-linux.so: Dynamic linker/loader.
nm
nm:用來列出目標檔案的符號清單。所謂符號,通常指定義出的函數,全域變數等等。
文法:
nm 參數 對象檔案
描述:
nm列出目標檔案的符號,如果沒有目標檔案,預設是a.out檔案。輸出內容包括3個內容:
- 符號值:以選項選定基數輸出符號值,預設是16進位。
- 符號類型:
- A 該符號的值是絕對的,在以後的連結過程中,不允許進行改變。(如符號__bss_start)
- B 符號位於未初始化資料區段(BSS)
- C 符號該符號為common。common symbol是未初始話資料區段。
- D 該符號處於初始化資料區段(如定義個全域變數: char * str = “hello”; 符號:str)
- T 該符號位於代碼區text section。(如符號:main)
- N 該符號是一個debugging符號。
- U 該符號未定義過,需要自其他對象檔案中連結進來;
- W 未明確指定的弱連結符號;同連結的其他對象檔案中有它的定義就用上,否則就用一個系統特別指定的預設值。
- ...
- 符號名稱
參數:
- -a或--debug-syms:顯示偵錯符號。
- -B:等同於--format=bsd,用來相容MIPS的nm。
- -C或--demangle:將低級符號名解碼(demangle)成使用者級名字。這樣能夠使得C++函數名具備可讀性。
- -D或--dynamic:顯示動態符號。該任選項僅對於動態目標(例如特定類型的共用庫)有意義。
- -f format:使用format格式輸出。format能夠選取bsd、sysv或posix,該選項在GNU的nm中有用。預設為bsd。
- -g或--extern-only:僅顯示外部符號。
- -n、-v或--numeric-sort:按符號對應地址的順序排序,而非按符號名的字元順序。
- -p或--no-sort:按目的文件中碰到的符號順序顯示,不排序。
- -P或--portability:使用POSIX.2標準輸出格式代替預設的輸出格式。等同於使用任選項-f posix。
- -s或--print-armap:當列出庫中成員的符號時,包含索引。索引的內容包含:哪些模組包含哪些名字的映射。
- -r或--reverse-sort:反轉排序的順序(例如,升序變為降序)。
- --size-sort:按大小排列符號順序。該大小是按照一個符號的值和他下一個符號的值進行計算的。
- -t radix或--radix=radix:使用radix進位顯示符號值。radix只能為"d"表示十進位、"o"表示八進位或"x"表示十六進位。
- --target=bfdname:指定一個目標代碼的格式,而非使用系統的預設格式。
- -u或--undefined-only:僅顯示沒有定義的符號(那些外部符號)。
- -l或--line-numbers:對每個符號,使用調試資訊來試圖找到文檔名和行號。對於已定義的符號,尋找符號地址的行號。對於未定義符號,尋找指向符號重定位入口的行號。假如能夠找到行號資訊,顯示在符號資訊之後。
注意幾點:
- -C 總是適用於c++編譯出來的對象檔案。還記得c++中有重載嗎?為了區分重載函數,c++編譯器會將函數傳回值/參數等資訊附加到函數名稱中去形成一個mangle過的符號,那用這個選項列出符號的時候,做一個逆操作,輸出那些原始的、我們可理解的符號名稱。
- 使用 -l 時,必須保證你的對象檔案中帶有符號調式資訊,這一般要求你在編譯的時候指定一個 -g 選項,見 Linux:Gcc。
- 使用nm前,最好先用Linux:File查看對象檔案所屬處理器架構,然後再用相應交叉版本的nm工具。
舉例
更詳細的內容見man page。這裡舉例說明:
-
nm -u hello.o
-
顯示hello.o 中的未定義符號,需要和其他對象檔案進行連結.
-
nm -A /usr/lib/* 2>/dev/null | grep "T memset"
-
在 /usr/lib/ 目錄下找出哪個庫檔案定義了memset函數.