LD_PRELOAD
是個用來控制 ld.so
的行為的環境變數之一,它的效果是讓 ld.so
先載入變數中指定的動態函式庫,而因為動態函式庫的符號在解析時的特性,後面的不會覆蓋掉前面的,於是就可以透過 LD_PRELOAD
蓋掉自己想覆寫的函式了
比如說像上次的範例中透過 LD_PRELOAD
來覆寫函式:
$ ./demo
Hello from libfoo
$ LD_PRELOAD="./libbar.so" ./demo
Hello from libbar
這樣的環境變數還有很多,其中有幾個比較有用的比如:
LD_LIBRARY_PATH
: 把路徑加進 ld.so
的搜尋路徑裡,預設 ld.so
只會找 /etc/ld.so.cache
與系統的 library 的位置 (/lib
和 /usr/lib
,如果 64 位元還會加上 64 位元的版本)LD_DEBUG
: 可以用來看 ld.so
的搜尋與解析過程,它有幾個參數可選另外 LD_LIBRARY_PATH
也能透過從命令列指定的方式來使用:
$ /lib64/ld-linux-x86-64.so.2 --library-path <path> <exe>
另外有趣的是用 ld.so
來執行的程式可以不用有執行的權限
不過在上面那個利用 LD_PRELOAD
的 hook ,如果想要呼叫原本的函式該怎麼辦呢,可以用 dlsym
來取得下一個函式:
use libc::dlsym;
use std::mem;
#[no_mangle]
pub extern "C" fn foo() {
println!("Hello from libbar");
let f = unsafe {
mem::transmute::<_, extern "C" fn()>(dlsym(libc::RTLD_NEXT, "foo\0".as_ptr() as _))
};
f();
}
或是你也可以用 dlopen
打開特定的動態函式庫,另外這也可以用來延遲載入動態函式庫,也可以用來設計程式的外掛之類的東西