本文整理大家的建議和自己實際操作的心得。新手上路, 有錯還請指正。
static library 就是一包 object file, 沒什麼需要提的, static library 沒有記錄其它資訊。所以, 編 shared library 或 executable 時要自行處理好 static library 的相依性, 在前篇有提到一點資訊。
shared library 有兩種, 一種在 linking 時要指定好 shared library 用到的 undefined symbol 放在那些 shared library 裡, 待執行時再載入到記憶體使用; 另一種用 dlopen() 和 dlsym() 載入 (這兩個函式存在 libdl 內)。
前者比較單純, 可用 ldd 透過靜態分析了解用到那些 shared library, 且各自實際指到的檔案。ldd 本身是一個 shell script, 用到 ld.so 事先定義的一些機制 (LD_TRACE_LOADED_OBJECTS) 來讀取資料, man ld.so 裡有相關的說明。其中 LD_LIBRARY_PATH 和 LD_PRELOAD 相當實用, 無法在連結時解決問題時, 至少還有這招可在載入時處理。
若想分析透過 dlopen() 載入的動態函式庫, 有幾個做法
- 在程式執行中觀察 /proc/PID/maps, 這個檔案記錄 process 用到的各區段記憶體為何, 可從對應到的檔案看出有載入的 shared library。必要時可配合 gdb 在想觀察的部份停住, 再從外部看 /proc/PID/maps。這裡或 man proc 有相關說明。
- 用 strace 執行程式, 觀察開啟的檔案: strace -f -e open PROGRAM 2>&1 | grep "\.so"
就我自己小試的心得, 看 /proc/PID/maps 最穩, 且方便看各別 process、thread 載入的函式庫, 也不會拖慢觀察目標的執行程式。不過 strace 不需配合 gdb 停在該停的地方, 就「快篩」的角度來看, 也滿有用的, 加上 -f 後方便追蹤 multi-process、multi-thread, 不過執行速度好像有慢一些, 不太確定。之後再比較看看兩者適合的使用時機。
參考資料
2011-12-22 更新
- 依 wens 和 Scott 的留言更新上面 strace 的例子。
- strace -e 的參數看來頗有用的, 之後有需求時再來研究。
Use: strace -e trace=open,mmap 省掉grep
回覆刪除謝啦, 已更新
回覆刪除這篇已經相當完整了! :)
回覆刪除我最常用的就是 /proc/PID/maps 和類似 wens 上面留言中那樣用 strace. 你 strace 的用法有一點點鱉腳:
1. 因為 mmap 需要 file descriptor 所以一定會先呼叫 open
2. 故 strace -eopen -f PROGRAM | grep '\.so' 即可(除非有類似 Python 在 Windows 下將 .dll 改名成 .pyd 的奇怪命名規則)
你看到的 ldd 是 glibc 的版本。
glibc 內的動態連結器 (/lib64/ld-linux.so.2) 可用:
LD_DEBUG=all MY-PROGRAM
看 runtime 每個 symbol 怎麼找的。
但 Anroid 、或用 uClibc 的 Linux 系統上不是用 glibc 所以不適用。
ldd 會遞迴列出 dependency, i.e.: EXE -> libA -> libB 會連間接依賴的 libB 也列出,要分辨直接依賴的可用:
eu-readelf -d MY-LIB | grep NEEDED
在 Linux 下開發程式會用到的 package manager 指令我有張 RPM 與 DPKG 的對照表,寫在:
http://itrs.tw/wiki/RPM_DPKG_Rosetta_Stone
另一個好玩的基礎問題是:一個 .so,/proc/PID/maps 為何會出現多次?
(嚴格說 Posix 中傳回 file descriptor 的函式除了 open 還有:
http://udrepper.livejournal.com/20407.html
但會用來 mmap 的 file descriptor 都是 open 傳回的)
真多資訊啊, 之後有用到時再來慢慢消化, 謝啦
回覆刪除btw, 這張表真不錯, 每次重讀都會多學到一點指令, 之前什麼都 apt-file search, 不知道有 dpkg --search 可找已裝的套件
http://itrs.tw/wiki/RPM_DPKG_Rosetta_Stone
@Scott, /proc/PID/maps .so會出現多次是為甚饃阿, 難道他在memory當中不連續? 有分segment?
回覆刪除@Yu-Teh Shen: 提示:權限不同,你要不要自己研究看看?
回覆刪除你將
$ cat /proc/PID/maps
與
$ eu-readelf -a PROGRAM
(找 Section Headers)
對著看,猜的應該差不多。
我們 1/8 見面可對對答案 :)
@Scott: .so 也是ELF type, 所以也有.data, .bss, .text 這些section, 而這些section權限也不一樣 (.text .init r+x, .bss r+w), 但是load進來的時候他會按照permission來切割, 而不是直接照section分page, 這應該就是/proc/PID/maps 所對應到的.
回覆刪除