rpath和runpath的区别
来源:互联网 发布:lol老是网络断开连接 编辑:程序博客网 时间:2024/05/22 08:22
考虑翻译Qt官方blog中的RPATH and RUNPATH这篇文章,在继续之前,我需要先验证自己的理解是正确的,至少能自圆其说,能说服自己。
用例子说话
二进制
对应源码
有一个程序
a.out
main.c
需要加载插件A
libA.so
liba.c
A需要另一个动态库
libB.so
libB1.c 或 libB2.c
本文的关注点就是:到底是哪一个libB.so被加载
目录结构:
/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;}
编译库文件
- 编译动态库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
- 编译动态库libA.so
$ gcc -shared -fPIC liba.c -o libA.so -L. -lB
顺便看看该elf文件的头部信息:
$ readelf libA.so -dDynamic section at offset 0xf20 contains 21 entries: Tag Type Name/Value 0x00000001 (NEEDED) Shared library: [libB.so] 0x00000001 (NEEDED) Shared library: [libc.so.6]...
恩,只有库的文件名信息,而没有路径信息。
编译程序
- 第一次编译运行(什么路径都不加)
$ gcc main.c -ldl$ ./a.out hello from funcAHello from funcB 2main: 12
程序:dlopen从当前目录找到libA.so,然后却在/usr/lib/中找到libB.so(没有使用当前目录的libB.so,这是我们需要的么?)
- 第二次编译运行(使用DT_RPATH)
$ gcc main.c -ldl -Wl,--rpath=.$ ./a.out hello from funcAHello from funcB 1main: 12
恩,使用当前目录的libB.so,很理想的东西
可是,由于DT_RPATH无法被环境变量LD_LIBRARY_PATH覆盖,不是不建议被使用,而是建议使用DT_RUNPATH么?
- 第三次编译运行(使用DT_RUNPATH)
$ gcc main.c -ldl -Wl,--rpath=.,--enable-new-dtags $ ./a.out hello from funcAHello from funcB 2main: 12
问题重新出现,使用的系统路径中的libB.so 而不是当前目录下的。
程序头部信息
通过下列命令可以查看:
$ 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给出这个问题的答案:
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 executableLD_LIBRARY_PATHRUNPATH of the loading objectld.so.cachedefault dirs
用它解释第一个程序:
- libA.so 没有RUNPATH,故而
- 使用其RPATH (没有)
- 递归查找其loader直到链条的顶端(可执行程序或被dlopen打开的对象)的RPATH或者遇RUNPATH退出 (没有命中)
- 可执行程序没有RUNPATH,故而
- 使用其RPATH (没有)
- 环境变量LD_LIBRARY_PATH,(没有)
- libA.so 的RUNPATH (没有)
- ld.so.cache (没有命中)
- 默认路径/usr/lib (命中)
用它解释第二个程序:
- libA.so 没有RUNPATH,故而
- 使用其RPATH (没有)
- 递归查找其loader直到链条的顶端(可执行程序或被dlopen打开的对象)的RPATH或者遇RUNPATH退出 (没有命中)
- 可执行程序没有RUNPATH,故而
- 使用其RPATH (命中)
用它解释第三个程序:
- libA.so 没有RUNPATH,故而
- 使用其RPATH (没有)
- 递归查找其loader直到链条的顶端(可执行程序或被dlopen打开的对象)的RPATH或者遇RUNPATH退出 (没有命中)
- 可执行程序有RUNPATH,(继续前行)
- 环境变量LD_LIBRARY_PATH,(没有)
- libA.so 的RUNPATH (没有)
- ld.so.cache (没有命中)
- 默认路径/usr/lib (命中)
有意思的就是这个程序了,可执行程序的RUNPATH是一个重要的判断条件,却并不被做为这儿搜索路径!!
结束
本文是在kubuntu 11.10下编写测试的。为了尽可能简单,例子也都是认为制造的。而且我们看到,在使用RPATH的时候是正常的,RUNPATH一般来说,被推荐使用,但这儿它却不能正常工作。
所以,当使用RUNPATH时,我们需要明白:某些情况下可能需要设置环境变量 LD_LIBRARY_PATH
- rpath和runpath的区别
- rpath和runpath的区别
- - RPATH RUNPATH 和 LD_LIBRARY_PATH
- 动态链接库的RPATH和RUNPATH解惑
- -L、-rpath和-rpath-link的区别
- 动态库加载路径之RPATH与RUNPATH(小记)
- rpath-link和rpath使用
- LD的-rpath,-rpath-link
- 动态库的链接和链接选项-L,-rpath-link,-rpath
- 动态库的链接和链接选项-L,-rpath-link,-rpath
- 动态库的链接和链接选项-L,-rpath-link,-rpath
- 动态库的链接和链接选项-L,-rpath-link,-rpath
- 动态库的链接和链接选项-L,-rpath-link,-rpath
- 动态库的链接和链接选项-L,-rpath-link,-rpath
- 动态库的链接和链接选项-L,-rpath-link,-rpath
- 动态库的链接和链接选项-L,-rpath-link,-rpath
- 动态库的链接和链接选项-L,-rpath-link,-rpath
- 动态库的链接和链接选项-L,-rpath-link,-rpath
- mysql 主备
- hive中的分析函数的典型应用
- 双重while循环实现打印数字11-99
- iLnkView隐私政策
- linux用户管理
- rpath和runpath的区别
- Magento获取商品CategoryIds
- ArrayList源码分析
- CAS客户端使用Ajax登陆(即保留原有客户端登录页面)
- 单精度实型和双精度实型的有效位数
- (linux下windows下一样)mysql如何插入中文,解决插入中文报错,ERROR 1366 (HY000):Incorrect string value
- Kmeans算法
- 基于Django的微信公众号开发(3) -- 通过微信公众号开发者认证
- SSM框架-MyBatis篇