rpath和runpath的区别
-
考慮翻譯Qt官方blog中的RPATH and RUNPATH這篇文章,在繼續(xù)之前,我需要先驗(yàn)證自己的理解是正確的,至少能自圓其說,能說服自己。
用例子說話
| ? | 二進(jìn)制 | 對(duì)應(yīng)源碼 |
| 有一個(gè)程序 | a.out | main.c |
| 需要加載插件A | libA.so | liba.c |
| A需要另一個(gè)動(dòng)態(tài)庫 | libB.so | libB1.c 或 libB2.c |
本文的關(guān)注點(diǎn)就是:到底是哪一個(gè)libB.so被加載
目錄結(jié)構(gòu):
/home/debao/ttt/a.out /home/debao/ttt/libA.so /home/debao/ttt/libB.so /usr/lib/libB.so
具體源碼
-
main.c?==>?./a.out
#include <stdio.h>
#include <dlfcn.h>
typedef int (*funcA)(int, int);
int main()
{
void * plugin = dlopen("./libA.so", RTLD_LAZY);
funcA f = (funcA)dlsym(plugin, "funcA");
printf("main: %d\n", f(3,4));
return 0;
}
-
liba.c?==>?./libA.so
#include <stdio.h>
int funcB(int, int);
int funcA(int a, int b)
{
printf("hello from funcA\n");
return funcB(a, b);
}
-
libb1.c?==>?./libB.so
#include <stdio.h>
int funcB(int a, int b)
{
printf("Hello from funcB 1\n");
return a*b;
}
-
libb2.c?==>?/usr/lib/libB.so
#include <stdio.h>
int funcB(int a, int b)
{
printf("Hello from funcB 2\n");
return a*b;
}
編譯庫文件
- 編譯動(dòng)態(tài)庫libB.so
$ gcc -shared -fPIC libb2.c -o libB2.so $ sudo mv libB2.so /usr/lib/libB.so $ gcc -shared -fPIC libb.c -o libB.so
- 編譯動(dòng)態(tài)庫libA.so
$ gcc -shared -fPIC liba.c -o libA.so -L. -lB
順便看看該elf文件的頭部信息:
$ readelf libA.so -d Dynamic section at offset 0xf20 contains 21 entries: Tag Type Name/Value 0x00000001 (NEEDED) Shared library: [libB.so] 0x00000001 (NEEDED) Shared library: [libc.so.6] ...
恩,只有庫的文件名信息,而沒有路徑信息。
編譯程序
- 第一次編譯運(yùn)行(什么路徑都不加)
$ gcc main.c -ldl $ ./a.out hello from funcA Hello from funcB 2 main: 12
程序:dlopen從當(dāng)前目錄找到libA.so,然后卻在/usr/lib/中找到libB.so(沒有使用當(dāng)前目錄的libB.so,這是我們需要的么?)
- 第二次編譯運(yùn)行(使用DT_RPATH)
$ gcc main.c -ldl -Wl,--rpath=. $ ./a.out hello from funcA Hello from funcB 1 main: 12
恩,使用當(dāng)前目錄的libB.so,很理想的東西
-
可是,由于DT_RPATH無法被環(huán)境變量LD_LIBRARY_PATH覆蓋,不是不建議被使用,而是建議使用DT_RUNPATH么?
- 第三次編譯運(yùn)行(使用DT_RUNPATH)
$ gcc main.c -ldl -Wl,--rpath=.,--enable-new-dtags $ ./a.out hello from funcA Hello from funcB 2 main: 12
問題重新出現(xiàn),使用的系統(tǒng)路徑中的libB.so 而不是當(dāng)前目錄下的。
程序頭部信息
通過下列命令可以查看:
$ readelf -d a.out
為了完整起見,列出前面3次編譯的程序的信息:
- 沒有rpath和runpath
Dynamic section at offset 0xf20 contains 21 entries: Tag Type Name/Value 0x00000001 (NEEDED) Shared library: [libdl.so.2] 0x00000001 (NEEDED) Shared library: [libc.so.6] 0x0000000c (INIT) 0x8048360 ...
- 包含rpath
Dynamic section at offset 0xf18 contains 22 entries: Tag Type Name/Value 0x00000001 (NEEDED) Shared library: [libdl.so.2] 0x00000001 (NEEDED) Shared library: [libc.so.6] 0x0000000f (RPATH) Library rpath: [.] 0x0000000c (INIT) 0x8048360 ....
- 包含rpath和runpath
Dynamic section at offset 0xf10 contains 23 entries: Tag Type Name/Value 0x00000001 (NEEDED) Shared library: [libdl.so.2] 0x00000001 (NEEDED) Shared library: [libc.so.6] 0x0000000f (RPATH) Library rpath: [.] 0x0000001d (RUNPATH) Library runpath: [.]
原因
RPATH and RUNPATH給出這個(gè)問題的答案:
Unless loading object has RUNPATH:
RPATH of the loading object,
then the RPATH of its loader (unless it has a RUNPATH), ...,
until the end of the chain, which is either the executable
or an object loaded by dlopen
Unless executable has RUNPATH:
RPATH of the executable
LD_LIBRARY_PATH
RUNPATH of the loading object
ld.so.cache
default dirs
用它解釋第一個(gè)程序:
- libA.so 沒有RUNPATH,故而
- 使用其RPATH (沒有)
- 遞歸查找其loader直到鏈條的頂端(可執(zhí)行程序或被dlopen打開的對(duì)象)的RPATH或者遇RUNPATH退出 (沒有命中)
- 可執(zhí)行程序沒有RUNPATH,故而
- 使用其RPATH (沒有)
- 環(huán)境變量LD_LIBRARY_PATH,(沒有)
- libA.so 的RUNPATH (沒有)
- ld.so.cache (沒有命中)
- 默認(rèn)路徑/usr/lib (命中)
用它解釋第二個(gè)程序:
- libA.so 沒有RUNPATH,故而
- 使用其RPATH (沒有)
- 遞歸查找其loader直到鏈條的頂端(可執(zhí)行程序或被dlopen打開的對(duì)象)的RPATH或者遇RUNPATH退出 (沒有命中)
- 可執(zhí)行程序沒有RUNPATH,故而
- 使用其RPATH (命中)
用它解釋第三個(gè)程序:
- libA.so 沒有RUNPATH,故而
- 使用其RPATH (沒有)
- 遞歸查找其loader直到鏈條的頂端(可執(zhí)行程序或被dlopen打開的對(duì)象)的RPATH或者遇RUNPATH退出 (沒有命中)
- 可執(zhí)行程序有RUNPATH,(繼續(xù)前行)
- 環(huán)境變量LD_LIBRARY_PATH,(沒有)
- libA.so 的RUNPATH (沒有)
- ld.so.cache (沒有命中)
- 默認(rèn)路徑/usr/lib (命中)
有意思的就是這個(gè)程序了,可執(zhí)行程序的RUNPATH是一個(gè)重要的判斷條件,卻并不被做為這兒搜索路徑!!
結(jié)束
本文是在kubuntu 11.10下編寫測(cè)試的。為了盡可能簡(jiǎn)單,例子也都是認(rèn)為制造的。而且我們看到,在使用RPATH的時(shí)候是正常的,RUNPATH一般來說,被推薦使用,但這兒它卻不能正常工作。
所以,當(dāng)使用RUNPATH時(shí),我們需要明白:某些情況下可能需要設(shè)置環(huán)境變量 LD_LIBRARY_PATH
總結(jié)
以上是生活随笔為你收集整理的rpath和runpath的区别的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 微信个性签名伤感短语
- 下一篇: UBUNTU adb连接android设