Linux:环境动态链接库的搜索路径

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,这个步骤将被忽略。

看起来够简洁的,当做休闲,写个程序验证一下。但在这之前,先介绍一个Glibc扩展的函数(POSIX中没有)

#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;

下面是程序以及需要加载的动态库的代码:

ld_main.c:

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;
}

编译这两个文件:
1、动态库:gcc --shared -fPIC ld_lib.c -o libld_lib.so -ldl
2、主程序:gcc ld_main.c -o ld_main -Wl,-rpath,./  -ldl -lld_lib -L./

-Wl,-rpath编译选项将在程序中生成DT_RPATH节点,使用readelf会看到Library rpath被设为当前目录:

接下来将生成的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,否则会找不到文件,如上图)。

看来它真起作用了

关于DT_RUNPATH,需要用到--enable-new-dtags链接选项:

(linux下程序默认不会从当前路径搜索.so文件,这对于自行开发的分为很多模块,要安装在同一目录的“程序”来说不是个优点。还好可以用DT_RUNPATH指定.so的加载路径)。

小结一下一个ELF 文件自身加载 so的情况:

其实这三者的关系概括起来没有几点:

  1. LD_LIBRARY_PATH 是个环境变量 可以用来指定加载so 的路径,并且优先级高于系统默认的。
  2. RPATH 是 ELF 格式里面的一个数据,他的优先级比 LD_LIBRARY_PATH 还要高
  3. 但是有一个很二 的 RUNPATH,也是 ELF 格式中的,如果他出现了 RPATH 就躲起来了,LD_LIBRARY_PATH 又成了首选

整理出了一张表,供参考

ELF 中 RPATHELF 中 RUNPATHLD_LIBRARY_PATH 变量尝试加载目录的顺序
未设置未设置未设置/lib => /usr/lib 
未设置未设置设置${LD_LIBRARY_PATH} => /lib => /usr/lib
设置未设置未设置${RPATH} => /lib => /usr/lib
设置未设置设置${RPATH} => ${LD_LIBRARY_PATH} => /lib => /usr/lib
设置 或 未设置设置 设置 ${LD_LIBRARY_PATH} => ${RUN_PATH} =>  /lib => /usr/lib
设置 或 未设置设置 未设置 ${RUN_PATH} =>  /lib => /usr/lib 
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

技术探索者

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值