Linux运行时动态库搜索路径优先级
Windows运行时动态库搜索路径优先级:
在Windows运行时,动态库(通常指DLL文件)的搜索路径遵循一定的优先级顺序,以确保程序能够正确地加载所需的动态库。以下是对Windows运行时动态库搜索路径优先级的总结:
- 应用程序所在的目录:
- 当一个应用程序(如exe文件)尝试加载一个DLL时,它首先会在自己所在的目录中查找该DLL文件。这是搜索路径中的第一优先级。
- 系统目录(System32):
- 如果在应用程序所在目录中没有找到DLL,系统接下来会在系统目录中查找。在Windows操作系统中,这通常是
C:\Windows\System32
目录。此目录包含了大量系统级的DLL文件,这些文件对于操作系统的正常运行至关重要。
- Windows目录:
- 如果系统目录中也没有找到所需的DLL,搜索会继续到Windows目录下,即
C:\Windows
。
- 环境变量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运行时动态库的搜索路径优先级大致如下:
- RPATH(DT_RPATH)
- LD_LIBRARY_PATH环境变量
- RUNPATH(如果DT_RPATH为空)
- ld.so.cache
- 配置文件/etc/ld.so.conf及/etc/ld.so.conf.d/目录
- 默认的系统路径(/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运行时动态库搜索路径优先级的更多相关文章
- Linux 指定运行时动态库路径【转】
转自:http://www.cnblogs.com/cute/archive/2011/02/24/1963957.html 众所周知, Linux 动态库的默认搜索路径是 /lib 和 /usr/l ...
- 【转载】Linux动态库搜索路径的技巧
转自:http://soft.chinabyte.com/os/232/11488732_2.shtml 众所周知,Linux动 态库的默认搜索路径是/lib和/usr/lib.动态库被创建后,一般都 ...
- 运行时动态库:not found 及介绍-linux的-Wl,-rpath命令
---此文章同步自我的CSDN博客--- 一.运行时动态库:not found 今天在使用linux编写c/c++程序时,需要用到第三方的动态库文件.刚开始编译完后,运行提示找不到动态库文件.我就 ...
- 转: gcc 指定运行时动态库路径
gcc 指定运行时动态库路径 Leave a reply 由于种种原因,Linux 下写 c 代码时要用到一些外部库(不属于标准C的库),可是由于没有权限,无法将这写库安装到系统目录,只好安装用户目录 ...
- Linux动态库搜索路径的技巧
众所周知,Linux动态库的默认搜索路径是/lib和/usr/lib.动态库被创建后,一般都复制到这两个目录中.当程序执行时需要某动态库,并且该动态库还未加载到内存中,则系统会自动到这两个默认搜索路径 ...
- Linux 静态库与动态库搜索路径设置详解【转】
原文地址:http://blog.chinaunix.net/uid-29025972-id-3855495.html 1. 连接和运行时库文件搜索路径的设置 库文件在连接(静态库和共享库)和运行(仅 ...
- Linux 静态库与动态库搜索路径设置详解
转载:http://blog.chinaunix.net/uid-29025972-id-3855495.html 1. 连接和运行时库文件搜索路径的设置 库文件在连接(静态库和共享库)和运行(仅限于 ...
- GDB动态库搜索路径
当GDB无法显示so动态库的信息或者显示信息有误时,通常是由于库搜索路径错误导致的,可使用set sysroot.set solib-absolute-prefix.set solib-search- ...
- linux添加动态库搜索路径
在有时运行程序出现动态库找不着的问题,而明明装了的.这时候可能是没有将相应的路径添加到系统中去. 具体说:cd /etc/ld.so.conf.d/ 可以发现里面有一堆*.conf的文件 我们要做的就 ...
- Windows平台LoadLibrary加载动态库搜索路径的问题
一.背景 在给Adobe Premiere/After Effects等后期制作软件开发第三方插件的时候,我们总希望插件依赖的动态库能够脱离插件的位置,单独存储到另外一个地方.这样一方面可以与其他程序 ...
随机推荐
- 苹果系统Mac升级后之前的网络软件不可用——Mac系统维护——Mac系统升级后软件报错——mac系统升级后导致软件兼容报错
========================================== 博士同学最近联系我,说是自己的mac系统升级后之前可以用的网络软件不可用使用了,由于平时工作需要,这个网络软件如果 ...
- cdq分治 提高篇
优化动态规划 序列 首先要会最长上升子序列的转移,这里就不说了. 我们 \(i\) 位置的初始值为 \(a_i\),可能变成的最大值为 \(mx_i\),可能变成的最小值为 \(mn_i\). 然后如 ...
- 为啥动态显示的名字就显示了undefined?
看不懂了昂,记录一下,慢慢理解吧 <!DOCTYPE html> <html> <head> <meta charset="utf-8"& ...
- 旧物利用 - 将机顶盒改造为一台Linux开发机!
前言 机顶盒型号:移动魔百盒CM201-2(CH),芯片组: hi3798mv300(hi3798mv3dmm),其他型号类似 理论上适用于以下SOC:Hi3798Mv100 / Hi3798Cv20 ...
- 跨越时空的对话:如何使用AI阅读工具ChatDOC快速建立数字化身?
跨越时空的对话:如何使用 ChatDOC 快速建立数字化身?以史蒂夫·乔布斯 AI 为例 开门见山,这篇文章主要介绍如何将 AI 改造为靠谱.好用.基于某个人物的数字化身.比如,乔布斯 AI.马斯克 ...
- 【粉丝问答19】Linux内核中为啥变量没初始化就用了?你确定了解宏定义?
@ 目录 一.问题 二.分析 三.宏定义的注意点 1. 只占用编译时间 2. 宏替换发生时机 3. 预处理包括哪些工作 四.如何快速展开复杂的宏定义? 第一步 第二步 五.练习 六.15个经典宏定义小 ...
- Linux下常用组件镜像源、smaba、gcc、ssh、mysql安装
Linux安装 博主使用的是ubuntu 16.04 apt更换镜像源 这里以更换阿里云镜像源为例. 首先去阿里云官方网站找对应版本系统的镜像源https://developer.aliyun.com ...
- NYX靶机笔记
NYX靶机笔记 概述 VulnHub里的简单靶机 靶机地址:https://download.vulnhub.com/nyx/nyxvm.zip 1.nmap扫描 1)主机发现 # -sn 只做pin ...
- /etc/shells 文件解释
/etc/shells 文件是 UNIX 和类 UNIX 操作系统中的一个文本文件,它列出了系统上认为是合法的.用户可以选择的 shell 的完整路径.这个文件对于系统安全和用户环境配置很重要. 以下 ...
- Dash 2.18版本新特性介绍
本文示例代码已上传至我的Github仓库:https://github.com/CNFeffery/dash-master Gitee同步仓库地址:https://gitee.com/cnfeffer ...