Linux下库链接与RUNPATH,RPATH,LD_LBIRARY,LD_PRELOAD,ldconfig , ld.conf.d 及LD_DEBUG

简要说明下影响库搜索的命令及变量问题。

符号问题 readelf -wa /path/to/elf/exe

用以下的命令可以看到链接关系: readelf -d /path/to/elf/exe

--------------------------------------------------------------------------

动态链接器对共享库的查找顺序:

  1. LD_LIBRARY_PATH-L 和 -rpath
  2. /etc/ld.so.cache
  3. 默认共享库目录:/usr/lib/lib

-------------------------------------------------------------------------

链接时路径与运行时路径:

链接器ld的选项有 -L,-rpath 和 -rpath-link,看了下 man ld,大致是这个意思:

-L: “链接”的时候,去找的目录,也就是所有的 -lFOO 选项里的库,都会先从 -L 指定的目录去找,然后是默认的地方。编译时的-L选项并不影响环境变量LD_LIBRARY_PATH,-L只是指定了程序编译连接时库的路径,并不影响程序执行时库的路径,系统还是会到默认路径下查找该程序所需要的库,如果找不到,还是会报错,类似cannot open shared object file。

-rpath-link:这个也是用于“链接”的时候的,例如你显式指定的需要 FOO.so,但是 FOO.so 本身是需要 BAR.so 的,后者你并没有指定,而是 FOO.so 引用到它,这个时候,会先从 -rpath-link 给的路径里找。

-rpath: “运行”的时候,去找的目录。运行的时候,要找 .so 文件,会从这个选项里指定的地方去找。对于交叉编译,交叉编译链接器需已经配置 --with-sysroot 选项才能起作用。

总结 :

-rpath指定的路径会被记录在生成的可执行程序中,用于运行时查找需要加载的动态库。

-rpath-link 则只用于链接时查找。

--------------------------------------------------------------------------------------------------------------------

  1. 简单的路径依赖关系

通常,系统默认使用 /lib, /usr/lib, /usr/lib64,/usr/loca/lib/ 等位置搜索so文件, 如果我们需要添加其它路径,可以在 /etc/ld.conf.d/下写一个新的配置文件,比如 xx.conf , 然后在里面每行写一个路径,重启或ldconfig重新读取路径即可

2. 强制指定

但是好多时候我们需要让程序自己能查找路径而不是外部设置so搜索设置,这个时候需要链接命令中指定路径,这些路径包括:

--Wl, -rpath=xx/xx/lib

--Wl, -rpath=$$ORIGIN/xx/lib

之类,我们就需要好好说道了。 $$ORIGIN 会在运行时被替换为程序当前路径。

3. 程序相对路径

RUNPATH , 由--rpath指定的路径,运行时会被替换为运行时的路径(相对或绝对)

LD_LIBRARY_PATH  全局搜索路径(可用,但是不建议用)

使用  readelf -a  /path/to/lib |grep path  可以看到rpath之类信息。

4 :高优先级路径

LD_PRELOAD 设置此路会强制搜索里面的文件并用来替换同名函数,说白了就是用实现apihook

5 调试

LD_DEBUG  

LD_DEBUG=libs,symbols  a.out    #显式指定需要打印的信息

ldconfig /path/to/lib 强制将/path/to/lib添加到搜索路径中 但是不永久生效

### 关于 `ld_` 和动态链接的相关信息 #### LD_PRELOAD 的工作原理 在 Linux 系统中,`LD_PRELOAD` 是一种强大的机制,允许开发者通过设置该环境变量来指定额外的共享(`.so` 文件),这些会在程序启动时被优先加载。这种行为可以用来覆盖标准中的函数实现,从而达到拦截、修改或扩展功能的目的[^2]。 #### 动态链接器的工作流程 Linux 下的动态链接由动态链接器(通常是 `/lib/ld-linux.so.*` 或其变种)负责完成。当程序运行时,动态链接器会按照特定的搜索路径寻找所需的 `.so` 文件并将其加载到内存中。以下是动态链接的典型搜索路径及其优先级顺序: 1. **内置路径**:如 `/lib` 和 `/usr/lib`。 2. **配置文件定义的路径**:通常位于 `/etc/ld.so.conf` 中列出的目录。 3. **环境变量 `$LD_LIBRARY_PATH` 定义的路径**:此变量的内容会被解析为附加的搜索路径。 4. **可执行文件本身指定的路径**:某些二进制文件可能嵌入了自己的 RPATHRUNPATH 属性,指示动态链接器去哪里查找依赖项。 以上过程决定了动态链接的实际加载位置和方式[^1]。 #### 使用 `ldd` 查看动态依赖关系 为了了解某个可执行文件具体依赖哪些动态链接,可以使用命令行工具 `ldd`。例如: ```bash ldd /path/to/executable ``` 这将显示目标程序所需的所有 `.so` 文件以及它们的具体安装路径。这对于排查缺失或者版本冲突等问题非常有帮助。 #### 创建自定义共享 假如需要开发自己的共享供其他应用程序调用,则需遵循如下步骤创建 `.so` 文件: 1. 编写源代码; 2. 将其编译成共享对象形式的目标文件,例如: ```bash gcc -shared -fPIC source.c -o libexample.so ``` 3. 把生成好的 `.so` 放置到适当的位置,并更新系统的缓存表以便识别新加入的资源。 #### 实现简单的 HOOK 操作 利用前面提到过的 `LD_PRELOAD` 特性,我们可以轻松地重定向任何 C 标准里的公开接口至我们自己定制的行为逻辑里去。下面给出一段示范性的例子——打印每次打开文件的动作详情: 假设有一个名为 `my_open_hook.c` 的源码片段如下所示: ```c #include <stdio.h> #include <dlfcn.h> typedef int (*open_t)(const char *pathname, int flags); int open(const char *pathname, int flags){ static open_t real_open; if (!real_open) { real_open = (open_t)dlsym(RTLD_NEXT,"open"); } printf("Opening file '%s'\n", pathname); return real_open(pathname,flags); } ``` 接着按常规方法构建它成为独立的 SO 组件之后再结合实际测试场景加以运用即可达成目的。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值