日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 人文社科 > 生活经验 >内容正文

生活经验

rpath和runpath的区别

發(fā)布時(shí)間:2023/11/27 生活经验 38 豆豆
生活随笔 收集整理的這篇文章主要介紹了 rpath和runpath的区别 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
  • 考慮翻譯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)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。