首页 > 系统相关 >Linux运行时动态库搜索路径优先级

Linux运行时动态库搜索路径优先级

时间:2024-10-23 17:01:07浏览次数:6  
标签:优先级 路径 搜索 Linux so 动态 加载

Windows运行时动态库搜索路径优先级:

在Windows运行时,动态库(通常指DLL文件)的搜索路径遵循一定的优先级顺序,以确保程序能够正确地加载所需的动态库。以下是对Windows运行时动态库搜索路径优先级的总结:

  1. 应用程序所在的目录
  • 当一个应用程序(如exe文件)尝试加载一个DLL时,它首先会在自己所在的目录中查找该DLL文件。这是搜索路径中的第一优先级。
  1. 系统目录(System32)
  • 如果在应用程序所在目录中没有找到DLL,系统接下来会在系统目录中查找。在Windows操作系统中,这通常是C:\Windows\System32目录。此目录包含了大量系统级的DLL文件,这些文件对于操作系统的正常运行至关重要。
  1. Windows目录
  • 如果系统目录中也没有找到所需的DLL,搜索会继续到Windows目录下,即C:\Windows
  1. 环境变量PATH中指定的目录
  • 如果以上三个位置都没有找到DLL,系统会检查环境变量PATH中列出的所有目录。PATH环境变量是一个系统级变量,它包含了多个目录的路径,用于指导系统在执行文件或脚本时搜索相关文件的路径。因此,用户可以通过修改PATH环境变量来添加额外的搜索路径。

一、Linux运行时动态库搜索路径优先级基础:

在Linux系统中,运行时动态库(shared libraries)的搜索路径优先级是由多个因素决定的。以下是这些因素的详细解释和优先级顺序:

1. RPATH

  • 定义:RPATH(也称为DT_RPATH)是在编译时设置在可执行文件中的路径,它指定了程序运行时应该搜索库文件的位置。
  • 优先级:如果可执行文件包含了RPATH,那么链接器会首先按照RPATH指定的路径来搜索所需的库。
  • 查看和修改方法:可以使用readelf -d xxx | grep rpath来查看库文件是否指定了rpath,可以在编译时设置RPATH。
// 在编译时设置rpath
if(OS_LINUX)
    set_target_properties(xxx PROPERTIES LINK_FLAGS "-Wl,-rpath='$ORIGIN' ")
endif()

备注:$ORIGIN是一个动态链接器的特殊变量,表示可执行文件或共享库文件所在的目录,可以用于指定相对路径。

2. LD_LIBRARY_PATH环境变量

  • 定义:LD_LIBRARY_PATH是一个环境变量,用户可以在运行时设置,以添加额外的库搜索路径。
  • 优先级:LD_LIBRARY_PATH中指定的路径会在系统默认路径之前进行查找,但其优先级低于RPATH。
  • 设置方法
    • 临时设置:可以通过export LD_LIBRARY_PATH=/my/lib/path/来设置环境变量;
    • 永久设置(不安全不推荐):可以添加到shell的配置文件中,如:~/.bashrc或~/.bash_profile,设置完后执行source命令即可立即生效。

3. RUNPATH

  • 定义:RUNPATH是另一个与RPATH相似的特性,同样是在可执行文件或共享库被链接时设置,用于指定运行时查找共享库的路径。值得注意的是,当RUNPATH存在时,它会覆盖RPATH的设置。
  • 优先级:RUNPATH中指定的路径会在系统默认路径之前进行查找,但其优先级低于LD_LIBRARY_PATH。
  • 查看和设置方法:可以使用readelf -d xxx | grep runpath来查看库文件是否指定了runpath,并使用工具如patchelf来设置和修改RUNPATH
// 使用工具修改runpath
patchelf --set-rpath '$ORIGIN' xxx

4. ld.so.cache

  • 定义:/etc/ld.so.cache是动态链接器ld.so的缓存文件,存储了系统中所有可用的共享库路径和名称信息。/etc/ld.so.cache由ldconfig命令生成,ldconfig会扫描系统中指定路径下的共享库文件,并更新/etc/ld.so.cache文件
  • 优先级:ld.so.cache的优先级低于LD_LIBRARY_PATH和RUNPATH,但高于其他,这是为了快速找到和加载需要的共享库。
  • 更新方法:运行sudo ldconfig命令来更新缓存。
// /etc/ld.so.cache是二进制文件可以通过strings命令查看其内容,例如查看libstdc++.so的搜索路径
strings /etc/ld.so.cache | grep libstdc++.so

5. 配置文件/etc/ld.so.conf及/etc/ld.so.conf.d/目录

  • 定义:/etc/ld.so.conf是系统的库配置文件,包含了系统级别的库搜索路径。/etc/ld.so.conf.d/目录用于存放额外的配置文件。
  • 优先级:链接器会读取这些文件,并按照其中列出的路径来搜索库,其优先级低于LD_LIBRARY_PATH和RUNPATH。
  • 修改方法:修改这些文件后,可以运行sudo ldconfig命令来更新缓存。

6. 默认的系统路径

  • 定义:在大多数Linux系统中,/lib和/usr/lib目录(以及它们的64位对应目录/lib64和/usr/lib64)都是默认的库搜索路径。
  • 优先级:这些路径的优先级最低,如果在前面的路径中都没有找到所需的库,链接器会回退到这些默认路径。

总结

Linux运行时动态库的搜索路径优先级大致如下:

  1. RPATH(DT_RPATH)
  2. LD_LIBRARY_PATH环境变量
  3. RUNPATH(如果DT_RPATH为空)
  4. ld.so.cache
  5. 配置文件/etc/ld.so.conf及/etc/ld.so.conf.d/目录
  6. 默认的系统路径(/lib, /usr/lib, /lib64, /usr/lib64)
 1 开始
 2    ├──> 检查RPATH(DT_RPATH)
 3    │       ├──> 如果找到库,则加载并使用
 4    │       └──> 否则,继续
 5    ├──> 检查LD_LIBRARY_PATH环境变量
 6    │       ├──> 如果找到库,则加载并使用
 7    │       └──> 否则,继续
 8    ├──> 检查RUNPATH(如果DT_RPATH为空)
 9    │       ├──> 如果找到库,则加载并使用
10    │       └──> 否则,继续
11    ├──> 搜索ld.so.cache缓存
12    │       ├──> 如果找到库,则加载并使用
13    │       └──> 否则,继续
14    ├──> 读取配置文件/etc/ld.so.conf及/etc/ld.so.conf.d/目录
15    │       ├──> 对于每个配置文件中的路径
16    │       │       ├──> 搜索该路径
17    │       │       │       ├──> 如果找到库,则加载并使用
18    │       │       │       └──> 否则,继续搜索
19    │       │       └──> 结束搜索该路径
20    │       └──> 如果所有配置文件中均未找到,则继续
21    └──> 搜索默认的系统路径(/lib, /usr/lib, /lib64, /usr/lib64)
22         ├──> 如果找到库,则加载并使用
23         └──> 否则,报告错误,无法找到库

请注意,这个顺序可能会根据具体的Linux发行版和链接器实现而有所不同。在实际应用中,可以通过ldd命令来查看一个可执行文件或库文件的依赖关系,以及它们是如何被解析的。

补充说明:

$ORIGIN和./的区别

在Linux和其他类Unix系统中,当动态链接库(如.so文件)被加载时,系统需要知道从哪里查找这些库。rpath(运行时库搜索路径)是存储在可执行文件或库本身中的一种机制,用于指示动态链接器在哪些位置查找依赖的库。

Library rpath:[$ORIGIN/]和 Library rpath:[./]指定了两种不同的相对路径:

1. [$ORIGIN/]:

  • $ORIGIN 是一个特殊的占位符,代表可执行文件或库文件自身的目录;
  • 当设置为[$ORIGIN/]时,它告诉动态链接器在可执行文件或库所在的同一目录下查找依赖的库;
  • 这意味着,如果你的可执行文件位于/path/to/app/myapp,那么动态链接器会在 /path/to/app目录下查找依赖的库。

2. [. /]:

  • ./表示当前工作目录,即启动可执行文件时所在的目录;
  • 当设置为[./]时,它指示动态链接器在启动可执行文件的当前目录下查找依赖的库;
  • 这意味着,如果你在 /home/user/目录下运行/path/to/app/myapp,那么动态链接器会在/home/user/ 目录下查找依赖的库,而不是在可执行文件所在的 /path/to/app/目录下。

两者的主要区别在于它们所引用的基准点不同:[$ORIGIN/]是相对于可执行文件或库的位置,而[./]是相对于当前工作目录。在实际应用中,选择哪种方式取决于你的具体需求,比如你的应用程序和库是如何被部署和使用的。通常,[$ORIGIN/]更为灵活和可靠,因为它不依赖于用户从哪个日录启动应用程序。

2)确认动态库优先级常用到的几个命令

ldd:ldd 是一个工具,用于显示可执行文件或共享库所依赖的共享库。其使用方法为:ldd xxx 或者 ldd libA.so

readelf:readelf 是一个命令行工具,专门用于查看ELF(Executable and Linkable Format)文件的信息。其用法包括:readelf -d xxx 或者 readelf -d libA.so

ps和lsof:在结合使用ps和lsof时,首先需要利用 ps -ef | grep xxx 命令来查找符合要求的进程ID,然后利用 lsof -p [PID] 命令来查看该进程打开的所有文件,从而确认模块加载的路径。

strace:strace 是一个强大的工具,能够通过打印出可执行程序的加载路径来确定优先级。其使用示例为:strace -e open,openat -o xxx.log ./xxx。该命令将执行名为xxx的可执行程序,并捕获所有open和openat系统调用,将相关信息输出到xxx.log文件中,通过查看日志也能确认模块加载的路径。

二、Linux运行时动态库搜索路径优先级规则探索:

在充分掌握动态库搜索路径优先级的基石概念之后,我们能够初步预估程序执行过程中如何精确定位并加载特定的动态库。然而,在错综复杂的大型项目背景下,时常遭遇同一动态库存在多个版本的场景。为确保程序准确无误地加载所需版本的库,深化对搜索路径优先级原则的理解显得尤为重要。

核心议题探讨

利用ldd命令检视一个可执行文件或动态库所依赖的共享库清单时,此清单是否必然反映程序运行时将加载的动态库?

针对此议题,可进一步细化为两个关键问题进行剖析:

1. 双重依赖下的优先级:若可执行文件与动态库均对某一动态库存在依赖,其搜索与加载的优先级机制如何?
2. 间接依赖的优先级:在多个动态库均依赖于同一动态库,而该依赖链不直接关联至可执行文件时,其搜索与加载的优先级又将如何确定?

规则总结

  • 基础步骤优先:总体上,遵循既定的优先级基础步骤进行搜索。
  • 架构特定路径优先:在每个搜索路径下,结合系统架构、线程局部存储等特性(如glibc-hwcaps/x86-64-v4、tls/x86_64/x86_64等),优先在经此拼接后的路径中查找。
  • 时序原则:依据动态库加载的先后顺序进行。
  • 同级动态库优先原则:是指当动态库依赖某一动态库,而在其加载之前未加载其所依赖的动态库,那么同级别优先级下,会优先按照动态库自身指定的路径查找,然后再去可执行程序指定的路径查找。
  • 路径去重:值得注意的是,对于已确认不存在的路径,系统将避免重复搜索。

实例分析

为增进理解,我们将通过具体实例进行预测与验证,以直观展示上述原则的应用与实践。

此处省略实例分析图片......

通过上图可以看到动态库的加载路径与我们分析的结果一致,详细的搜索步骤可以通过strace命令验证。

总结

本文详尽地梳理了Linux系统中运行时动态库(shared libraries)搜索路径优先级的基本规则,并在此基础上,借助具体实例深入剖析并总结了这些优先级规则的运作机理。此外,本文还针对实际项目中可能遇到的动态库加载问题,提出了具有实用价值的排查参考方案。期望本文能为各位在未来工作中遭遇的动态库依赖问题(诸如版本兼容性问题等)提供有力支持与帮助。

标签:优先级,路径,搜索,Linux,so,动态,加载
From: https://www.cnblogs.com/ForestCherry/p/18497797

相关文章

  • 全方位解析直播美颜SDK:打造高效视频美颜平台的技术路径详解
    今天,小编将深入讲解直播美颜SDK的核心技术、架构设计和应用场景,帮助开发者理解如何构建高效的视频美颜平台。 一、直播美颜SDK的核心技术直播美颜SDK其核心功能包括实时美颜、磨皮、祛斑、瘦脸和眼部美化等。这些技术通常结合深度学习算法,通过对用户面部特征的实时分析,快速应用美......
  • wsl ubuntu20.04设置core文件生成路径
    1.首先要确定允许生成core文件#在终端执行下列命令,执行后仅本次会话有效,如需每次都生效,可以添加到~/.bashrc文件中ulimit-cunlimited2.查看core文件的生成目录cat/proc/sys/kernel/core_pattern3.临时设置core文件的生成目录#先切换到root用户,然后输入,其中./表示生......
  • C 语言中,如果函数声明了返回类型,但执行路径中没有 return 语句,则返回什么数据值呢?
    u8PID_Ctrl(floatsetVal,floatCurVal){ staticunsignedintCnt=0; staticu8JSVal=0; if(++Cnt>=100) { Cnt=0; JSVal=(u8)PID_SF(setVal,CurVal); returnJSVal; }}//主函数中存在:PWM_ZB_Val=PID_Ctrl(60,JRL_Real_Temp); Q:当Cnt<100时,......
  • Linux常用命令(自用记录)
    CentOS添加用户useradd-d/home/testuser-mtestuserpasswdtestuserroot修改/etc/sudoers文件AllowroottorunanycommandsanywhereusernameALL=(ALL)ALL切换ROOT权限suexit退出root文件目录相关操作cd/切换到根目录cd/home切换到根目录下的......
  • C#实现信创国产Linux麦克风摄像头推流(源码,银河麒麟、统信UOS)
    随着国际政治经济形势的变化,尤其是中美科技竞争日益激烈,软件信创国产化已经迫在眉睫。在这种大环境下,我们将现有的Windows版软件逐步迁移到信创国产化基础设施上,适配国产操作系统(如银河麒麟、统信UOS)、国信芯片(如飞腾、鲲鹏、海光、龙芯、麒麟)以及国产DB。我们经常有这样的需求,比......
  • CH397 USB转网卡--嵌入式Linux下修改网卡名称
    修改CH397USB转网卡芯片网络名称在使用Linux系统时候,接入CH397USB转网卡芯片之后,发现网卡名称并非按照eth1、eth2这种命名,而是enx+MAC如下图所示:多网卡应用场景下此类网卡名称可能不方便管理,需要进行统一修改,可先通过日志查看其命名规则受什么影响:可见网卡默认生成的名......
  • FFmpeg开发笔记(五十九)Linux编译ijkplayer的Android平台so库LD
    ijkplayer是一款由B站研发的移动端国产播放器,它基于FFmpeg3.4版本,同时兼容Android和iOS两大移动操作系统。ijkplayer的源码托管地址为https://github.com/bilibili/ijkplayer,截止2024年9月15日,ijkplayer获得3.24万星标数,以及0.81万个分支数,而这还是ijkplayer停止更新6年之后的数据......
  • FFmpeg开发笔记(五十九)Linux编译ijkplayer的Android平台so库
    ijkplayer是一款由B站研发的移动端国产播放器,它基于FFmpeg3.4版本,同时兼容Android和iOS两大移动操作系统。ijkplayer的源码托管地址为https://github.com/bilibili/ijkplayer,截止2024年9月15日,ijkplayer获得3.24万星标数,以及0.81万个分支数,而这还是ijkplayer停止更新6年之后的数据......
  • Linux操作系统如何制作U盘启动盘
    在麒麟系统中有一款U盘启动器软件,它是用于制作系统启动U盘的工具,方便无光驱的电脑安装操作系统,也可以反复使用一个U盘,避免光盘的浪费。下面对该U盘启动器使用方法做详细讲解。1.准备需要安装的系统镜像文件。图12.准备1个空U盘,大小在8GB以上。图23.在开始菜单中打开U......
  • linux安装ssh
    xshell连接ubuntu背景:xshell连接ubuntu,但是怎么连都连不通,便开启了和ssh想杀相爱的一生1.查看ssh服务的状态sudoservicesshdstatus2.安装ssh服务如果执行````sudoservicesshdstatus出现了Loaded:error(Reason:Nosuchfileordirectory)```,就说明没有安装ssh服务......