有時候程序運行在不同的linux發行版本上一個正常,一個出錯,引起的原因可能是某個共享庫比較老舊,對比它在不同的系統上運行時依賴的庫版本就可以知道引起錯誤可能的原因。那么如何知道一個程序運行時依賴哪些共享庫呢?
一.查看程序依賴的共享庫
1.使用ldd命令
首先得了解ldd是用來做什么的,需要注意什么,直接man,
描述:
ldd用來打印程序運行時的依賴的共享庫,或者打印一個指定的共享庫它又依賴於哪些共享庫。
注意事項:
通常情況下,ldd調用標准的動態鏈接器(linux下的ld-linux.so.xx,它一般是一個位於/lib目錄下的符號鏈接文件),將環境變量中 LD_TRACE_LOADED_OBJECTS 值為1,看名字就直到,它是控制允許跟蹤加載對象的一個變量。但是需要注意的是,某些版本的ldd它獲取依賴庫信息時是通過直接執行程序的方式。也就是說,你最好不要將ldd用在一個不可信任的可執行程序上,因為這可能會由於執行這個不可信的程序引發安全問題。一個更安全的方法是通過使用objdump來獲取信息:
objdump -p /path/to/program | grep NEEDED
常用選項:
--version Print the version number of ldd. -v --verbose Print all information, including, for example, symbol versioning information. -u --unused Print unused direct dependencies. (Since glibc 2.3.4.) -d --data-relocs Perform relocations and report any missing objects (ELF only). -r --function-relocs Perform relocations for both data objects and functions, and report any missing objects or functions (ELF only). --help Usage information.
注意到上面紅色文字,在看看ldd程序的本質:
thomas@thomas-laptop:~/test/libld$ whereis ldd ldd: /usr/bin/ldd /usr/bin/X11/ldd /usr/share/man/man1/ldd.1.gz thomas@thomas-laptop:~/test/libld$ file /usr/bin/ldd /usr/bin/ldd: Bourne-Again shell script, ASCII text executable
它其實就是一個shell腳本,通過調用ld-linux.so.xx,並將環境變量 LD_TRACE_LOADED_OBJECTS設置為1,使用完畢后,再將這個環境變量unset,對應的其他選項諸如-v -u -d -r都是通過設置 LD_VERBOSE LD_WARN LD_BIND_NOW 這些個環境變量或者它們的組合來實現的,分析下ldd這個腳本就知道了。
2.使用ld-linux.so.x
可能不同的平台這個文件路徑和名字不一樣,man下ld.so可以看到詳細信息。基本用法:
ld-linux.so.x [OPTIONS] [PROGRAM [ARGUMENTS]]
這里稍微需要注意下,program可以是elf文件,或者一個so庫,必須指定其路徑,絕對路徑或者相對路徑均可。主要用的選項是 --list
3.使用objdump
objdump可以分析對象文件的信息,或者反匯編對象文件。既然是可以反匯編對象文件,那么可以猜測對象文件必須是包含一堆機器碼的文件,所謂object文件,參見wiki上的定義Object file,大致就是說一堆機器碼再加一些描述信息,而機器碼呢又是relocatable,就是說機器碼的各個模塊最終在內存中如何分布可以通過描述信息來確定。一般linux下就是elf格式的文件,比如編譯形成的可執行文件,*.o *.a *.so ,這一類的文件。
通過 objdump -p objectfile | grep NEEDED來獲得運行時所需共享庫。
4. readelf
objdump用法類似,不過參數是 -d
5.pmap
只是不知道arm是否可以移植這個命令,它可以查看一個正在運行的進程的內存使用情況,那么也就看到了加載到內存中的共享庫,只是它可能看不到完整的依賴庫,這要看程序是怎么鏈接共享庫的。共享庫分為2種加載方式,1.程序運行前一次性全部加載完畢 2.當程序運行到某個點時,通過調用一些API來加載所需動態庫。其實這里的這個動態庫和共享庫格式無區別,只是加載方式,時間點,不同罷了。如果是采用第一種方式,那么pmap可以看到完整的依賴,若是后者則可能看到的依賴庫不完整。
二.查找庫的位置
使用ldconfig -p | grep "your lib",ldconfig也是一個shell腳本,查看這個腳本可以看出真正執行的是ldconfig.real這個文件,它可以獲取緩沖在/etc/ld.so.cache中的的庫信息。
