分享

动态库链接的优先级以及如何修改rpath

 石头爱学习 2023-08-25 发布于贵州

动态库链接的优先级以及如何修改动态库链接

最近工作中遇到了一个问题,启动nginx时,链接动态库的路径与预想的路径不同,应该链接同目录下的动态库,但是却链接了系统中同名但不同版本的库,导致无法启动,在经过查询与多方案尝试后,最终解决了该问题,将解决过程与大家分享一下

首先,先了解一下动态库的链接优先级,在运行可执行文件时,可能会链接一些动态库,系统在链接这些动态库时会有一个顺序,下面按优先级顺序说一下各链接方式

一、动态库链接的优先级

  1. RPATH

rpath全称是run-time search path。Linux下所有elf格式的文件都包含它,特别是可执行文件。它规定了可执行文件在寻找.so文件时的第一优先位置

rpath一般可以在编译时指定,在Linux下,执行./configure时就有-Wl,-rpath,选项,可以将rpath的路径指定到所需动态库的路径下

-wl这是个gcc的参数,表示编译器会将后面的参数传递给链接器ld

  • rpath只能是绝对路径,不能是相对路径。使用相对路径是没有意义的,因为相对路径将相对于运行程序时的当前工作目录,而不是相对于找到二进制文件/库的目录。 因此,在几乎任何情况下,它对于$PATH或库中的可执行文件都根本不起作用

比如你的可执行文件在/usr/bin/exe,动态库在/usr/lib/路径下,rpath被指定为../lib,那么只有进入/usr/bin/路径下执行exe时,才能找到正确的动态库,在其他目录下调用该程序就无法定位到正确的动态库路径下

  1. LD_LIBRARY_PATH

修改环境变量的方式

#修改环境变量是第二优先级,在没有指定rpath的情况下,则会寻找该路径
export LD_LIBRARY_PATH=LDpath

#以下命令可以查看目前的环境变量路径是什么
echo $LD_LIBRARY_PATH
  • 修改环境变量不是永久性的。只在执行export LD_LIBRARY_PATH=LDpath命令的当前bash有效,在其他的bash中则不起效果

由于该原因,export命令在脚本中执行是无效的,因为在执行shell脚本时,是先创建一个子进程shell,然后运行脚本程序,执行结束后子进程退出,返回父进程shell,因此子shell中对环境变量的改变并不影响父进程看到的环境变量。
如果脚本中包含export LD_LIBRARY_PATH,那么执行脚本时应该使用source,比如source test.sh

  • 如果想永久性修改环境变量,可以选择以下方案
#需要在root下执行
vi + /etc/profile
将export LD_LIBRARY_PATH=LDpath语句追加到打开的profile文件中
保存后重启虚拟机,这样的修改方式为永久修改
  1. ldconfig的缓存: 配置/etc/ld.so.conf可改变

#需要在root下执行
vi /etc/ld.so.conf
将需要添加的动态库路径追加到该文件中,保存后退出,执行以下命令让修改生效
/sbin/ldconfig
  1. 默认的/lib, /usr/lib路径

优先级最低的是系统默认的路径,一般为/lib/usr/lib/usr/local/lib等系统库的路径

二、如何修改动态库链接

#查看程序的动态库链接
ldd application
#查看rpath
readelf -d XXX

在修改动态库链接路径时,应该按照上文的优先级顺序进行修改,第一方案就是修改可执行文件的rpath,有以下几种方案供大家参考

  1. 下载源码重新编译该程序,在编译时执行./configure-Wl,-rpath=LDpath,可以设置多个rpath路径,多个路径之间用冒号:隔开,优先级为路径书写顺序
  2. 使用chrpath工具
##### 安装 #####
apt-get install chrpath

#删除编译时的rpath
chrpath -d application
#修改rpath为新路径
########### 注意,该工具只能修改为比原来路径短或者长度一样的rpath #############
chrpath -r '/usr/local/lib/' application
 -r <path> | --replace <path>
      Replace current rpath or runpath setting with the path given.  
      The new path must be shorter or the same length as the current path.

#可使用man chrpath查看各参数作用
  1. 使用patchelf工具
##### 安装 #####
apt-get install patchelf
# 或者下面的安装方式
wget http:///releases/patchelf/patchelf-0.8/patchelf-0.8.tar.bz2
tar -zxf patchelf-0.8.tar.bz2 && cd patchelf-0.8
./configure --prefix=/usr
make && make install

##### 使用 #####
#修改RUNPATH
patchelf --set-rpath /usr/local/lib/ application
--set-rpath RPATH
     Change the RPATH of the executable or library to RPATH.

#可使用man patchelf查看各参数作用
  • 该工具可以修改更长的路径,也可以为没有rpath的程序直接添加上RUNPATH

patchelf工具修改的可执行文件的RUNPATH,我没太搞懂rpathRUNPATH的区别,查看patchelf工具参数作用时,描述的是修改RPATH;但是使用readelf -d XXX命令查看修改后的可执行文件时,显示的为RUNPATH,并且chrpath工具中有一个-c参数的描述为

-c | --convert Convert the rpath setting into a runpath setting

所以两者应该还是略有区别,下面贴上我搜索的两者区别的链接,大家可以参考一下

RPATH和RUNPATH的区别

  1. 接下来的方案就不用具体说了,上面优先级中已经有描述,可以修改环境变量,或者修改ldconfig来修改动态库的链接路径

全文为自己查询并尝试过的方案以及自己的理解,所以会有一些理解不全或者错误的地方,大家参考即可,如发现有误请指出,谢谢;如觉得有用,在标明出处后可随意转载

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多