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 打開特定的動態函式庫,另外這也可以用來延遲載入動態函式庫,也可以用來設計程式的外掛之類的東西