关于linux下使用动态库

转自:

http://blog.csdn.net/dbzhang800/article/details/6918413


动态库常规的搜索路径:


程序构建时通过 RPATH 指定的目录
LD_LIBRARY_PATH 环境变量中冒号分割的目录
文件 /etc/ld.so.cache列出的库(使用工具ldconfig维护)
程序构建时 RUNPATH 指定的目录(fix me)
目录 /lib

目录 /usr/lib


 

二进制

对应源码

有一个程序

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 -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]
...

恩,只有库的文件名信息,而没有路径信息。

编译程序

  • 第一次编译运行(什么路径都不加)

$ gcc main.c -ldl
$ ./a.out 
hello from funcA
Hello from funcB 2
main: 12

程序:dlopen从当前目录找到libA.so,然后却在/usr/lib/中找到libB.so(没有使用当前目录的libB.so,这是我们需要的么?)

  • 第二次编译运行(使用DT_RPATH)

$ gcc main.c -ldl  -Wl,--rpath=.
$ ./a.out 
hello from funcA
Hello from funcB 1
main: 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 funcA
Hello from funcB 2
main: 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 executable
LD_LIBRARY_PATH
RUNPATH of the loading object
ld.so.cache
default 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


man gcc

Wl是作为参数传递给ld

The -Wl,xxx option for gcc passes a comma-separated list of tokens as a space-separated list of arguments to the linker. So

gcc -Wl,aaa,bbb,ccc
eventually becomes a linker call

ld aaa bbb ccc

-rpath=dir

Add a directory to the runtime library search path. This is used when linking an ELF executable with shared objects. All -rpath arguments are concatenated and passed to the runtime linker, which uses them to locate shared objects at runtime. The -rpath option is also used when locating shared objects which are needed by shared objects explicitly included in the link;



  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值