man ld.so(8)說,如果庫依賴不包括“/”,那麼它將按照下面的規則按順序搜索:
看起來夠簡潔的,當做休閒,寫個程序驗證一下。但在這之前,先介紹一個Glibc擴展的函數(POSIX中沒有)
#define _GNU_SOURCE
#include <dlfcn.h>
int dladdr(void* addr, Dl_info *info);
這個函數解析傳入的函數指針(第一個參數),將信息填充到Dl_info的結構體
typedef struct {
const char *dli_fname; /* Pathname of shared object that contains address */
void *dli_fbase; /* Address at which shared object is loaded */
const char *dli_sname; /* Name of nearest symbol with addresslower than addr */
void *dli_saddr; /* Exact address of symbol named in dli_sname */
} Dl_info;
下面是程序以及需要加載的動態庫的代碼:
int main()
{
lib_fun();
return 0;
}
#define _GNU_SOURCE
#include <stdio.h>
#include <dlfcn.h>
int lib_fun()
{
Dl_info dl_info;
dladdr((void*)lib_fun, &dl_info);
fprintf(stdout, ".so@ %s.\n", dl_info.dli_fname);
return 0;
}
編譯這兩個文件:
1、動態庫:gcc --shared -fPIC ld_lib.c -o libld_lib.so -ldl
2、主程序:gcc ld_main.c -o ld_main -Wl,-rpath,./ -ldl -lld_lib -L./
-Wl,-rpath編譯選項將在程序中生成DT_RPATH節點,使用readelf會看到Library rpath被設為當前目錄:
接下來將生成的libld_lib.so拷貝到前面介紹到的搜索路徑:
對於LD_LIBRARY_PATH,隨便設置:export LD_LIBRARY_PATH=../
對於ld.so.conf提到的路徑,在/etc/ld.so.conf.d/下面隨便找一個,或者自己建立一個,這裡用系統自帶的libc.conf
中提到的路徑:/usr/local/lib
然後運行(每次都刪除程序優先加載的so文件):
(ld.so.conf路徑更新文件後需要運行ldconfig更新cache,否則會找不到文件,如上圖)。
關於-z nodefaultlib鏈接選項:
看來它真起作用了 關於DT_RUNPATH,需要用到--enable-new-dtags鏈接選項:
(Linux下程序默認不會從當前路徑搜索.so文件
,這對於自行開發的分為很多模塊,要安裝在同一目錄的“程序”來說不是個優點。還好可以用DT_RUNPATH指定.so的加載路徑)