man ld.so(8)說,如果庫依賴不包括“/”,那麼它將按照下面的規則按順序搜索:
- (僅對ELF格式)如果可執行文件包含DT_RPATH標籤,並且不包含DT_RUNPATH標籤,將從DT_RPATH列出的路徑搜索。(DT_RPATH已經被廢棄,請用DT_RUNPATH)
- 如果LD_LIBRARY_PATH在程序運行時被定義,那麼將從它包含的路徑開始。安全起見,對於set-user-ID或者set-group-ID的程序,這個變量將被忽略。
- (僅對ELF格式)如果可執行文件包含DT_RUNPATH標籤,將從這個標籤列出的路徑開始搜索。
- 從 /etc/ld.so.cache(運行ldconfig產生)中查找文件
- 從/lib以及/urs/lib,按順序搜索。如果鏈接時指定-z nodefaultlib,這個步驟將被忽略。
#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;
}
ld_lib.c:
#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;
}
編譯這兩個文件:
接下來將生成的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的加載路徑)