动态库链接和加载时的路径搜索优先级

· 浏览次数 : 61

小编点评

动态库的链接和加载过程中库路径的搜索优先级是一个涉及程序链接和运行的重要概念。下面将详细解释这个过程。 一、链接阶段 在程序链接阶段,链接器会查找并链接所有必要的库文件。链接器在搜索库文件时,会按照一定的优先级进行搜索。 1. `-L` 选项:通过 `-L/path/to/libs` 指定链接器搜索库文件的路径。优先级高于默认库路径。 2. `liblog4cpp`:表示要链接的库文件名。链接器会在指定的路径和默认库路径下查找名为 `liblog4cpp` 的库文件。 二、加载阶段 在程序开始运行之前,动态链接器会读取可执行文件,并查找并加载所有必须的动态库。此时,搜索路径不包括链接阶段指定的 `-L` 选项中的路径,因为这一阶段只关心加载阶段所需的库文件。 1. `LD_LIBRARY_PATH` 环境变量:程序运行时,动态链接器会搜索这个环境变量指定的目录。可以临时设置或持久化设置。 2. `/etc/ld.so.cache` 文件:这是一个缓存文件,包含了已加载库文件的信息。当程序运行时,动态链接器会首先检查这个文件,以加速后续的库文件查找。 3. 默认库路径:如 `/usr/lib,/lib` 等。 三、如何指定库文件路径 若需要从指定的路径加载动态库,可以使用以下方法: 1. 手动设置 `LD_LIBRARY_PATH` 环境变量:在程序运行前,设置环境变量,指定动态库的搜索路径。例如: ```bash export LD_LIBRARY_PATH=/path/to/runtime_libs:$LD_LIBRARY_PATH ``` 注意,此方法设置环境变量是临时的,一旦终端关闭设置就会失效。若想使其持久化,需要特殊设置,如修改 `.bashrc` 文件或 `/etc/ld.so.conf` 配置文件。 2. 使用 `-rpath` 选项:在链接阶段,使用 `-Wl,-rpath,/path/to/runtime_libs` 选项将库路径硬编码到可执行文件中。例如: ```bash g++ main.o -o a.out -L/path/to/libs -llog4cpp -Wl,-rpath,/path/to/runtime_libs ``` 注意,若可执行文件中同时包含 `RPATH` 和 `RUNPATH`,那么 `RPATH` 将会被动态链接器忽略。 四、共享库的搜索优先级 1. `RPATH`:在程序加载阶段,共享库的搜索优先级高于 `LD_LIBRARY_PATH` 和 `RUNPATH`。 2. `LD_LIBRARY_PATH`:与链接阶段相同。 3. `RUNPATH`:与链接阶段相同。 4. `/etc/ld.so.conf` 和 `/etc/ld.so.conf.d/*` 配置文件:系统级别的库搜索路径,对所有用户和应用程序都有效。 综上所述,动态库的链接和加载过程中库路径的搜索优先级包括:链接阶段的 `-L` 选项、`LD_LIBRARY_PATH` 环境变量、`/etc/ld.so.cache` 文件、默认库路径以及程序运行时的 `LD_LIBRARY_PATH`、`RPATH` 和 `RUNPATH` 等。

正文

前言

在开发一个新项目时遇到了动态库加载异常的问题,因此在这里记录一下动态库的链接和加载过程中库路径的搜索优先级的相关知识。

动态库的链接

现在有一个main.o可重定位目标文件,其中需要用到开源库log4cpp。在链接的时候,我们可以这样链接:

g++ main.o -o a.out -L/path/to/libs -llog4cpp

其中:

  • -L/path/to/libs表示链接器去哪个目录下查找库文件。
    编译时库搜索优先级:-L指定的路径> LIBRARY_PATH>默认库路径

  • -llog4cpp表示要链接的库,在链接阶段,链接器一般会按照搜索优先级,从库路径中查找名为liblog4cpp.soliblog4cpp.a的文件进行链接。若不特殊说明,默认优先链接动态库。

动态库的加载

在程序开始运行前的加载阶段,动态链接器会读取可执行文件,查找并加载所有必须的动态库。注意此时的搜索路径并不包含/path/to/libs,因为它只作用于链接阶段。链接器搜索的路径有:LD_LIBRARY_PATH环境变量,/etc/ld.so.cache文件,默认库路径(/usr/lib,/lib等)。

如果需要从指定的路径加载动态库,则可以使用下述方法:

  • 手动设置LD_LIBRARY_PATH环境变量:在程序运行前设置环境变量,指定动态库的搜索路径:
    export LD_LIBRARY_PATH=/path/to/runtime_libs:$LD_LIBRARY_PATH
    
    注意,此方法设置环境变量是临时的,一旦终端关闭设置就会失效。若想使其持久化,需要特殊设置,方法包括但不限于:修改.bashrc文件,修改rc.loacl文件。
  • 修改/etc/ld.so.conf/etc/ld.so.conf.d/*配置:
    这些文件提供了系统级别的库搜索路径。系统管理员可以在这些文件中定义默认的库搜索路径,这些设置对所有用户和应用程序都有效。
  • 在链接阶段使用-rpath:
    在链接阶段,设置RPATH或RUNPATH,将库路径硬编码到可执行文件中
    g++ main.o -o a.out -L/path/to/libs -llog4cpp -Wl,-rpath,/path/to/runtime_libs
    
    注意若可执行文件中同时包含RPATH和RUNPATH,那么RPATH将会被动态链接器忽略。

加载时共享库的搜索优先级为:
RPATH>LD_LIBRARY_PATH>RUNPATH>/etc/ld.so.conf/etc/ld.so.conf.d/*>默认库路径

与动态库链接和加载时的路径搜索优先级相似的内容:

动态库链接和加载时的路径搜索优先级

目录前言动态库的链接动态库的加载 前言 在开发一个新项目时遇到了动态库加载异常的问题,因此在这里记录一下动态库的链接和加载过程中库路径的搜索优先级的相关知识。 动态库的链接 现在有一个main.o可重定位目标文件,其中需要用到开源库log4cpp。在链接的时候,我们可以这样链接: g++ main.

驱动开发:内核无痕隐藏自身分析

在笔者前面有一篇文章`《驱动开发:断链隐藏驱动程序自身》`通过摘除驱动的链表实现了断链隐藏自身的目的,但此方法恢复时会触发PG会蓝屏,偶然间在网上找到了一个作者介绍的一种方法,觉得有必要详细分析一下他是如何实现的驱动隐藏的,总体来说作者的思路是最终寻找到`MiProcessLoaderEntry`的入口地址,该函数的作用是将驱动信息加入链表和移除链表,运用这个函数即可动态处理驱动的添加和移除问题。

.Net Core 3.0 对 MongoDB 的多条件查询(两种)操作

前言 在日常开发中,偶尔会用到 MongoDB 的数据操作,也花费了一些时间调试,因此在此处记录一下,共同进步。 废话少说,出招吧! 正文 2.1 准备工作 首先需要引入 .Net 平台链接 MongoDB 的动态库:MongoDB.Driver; 然后创建默认 DBContext 实体类: (将数

7.2 C/C++ 实现动态链表

动态链表是一种常用的动态数据结构,可以在运行时动态地申请内存空间来存储数据,相比于静态数组和静态链表,更加灵活和高效。在动态链表中,数据元素被组织成一条链表,每个元素包含了指向下一个元素的指针,这样就可以通过指针将所有元素串联起来。使用动态链表存储数据时,不需要预先申请内存空间,而是在需要的时候才向内存申请。当需要添加新的元素时,可以使用`malloc`函数动态地申请内存空间,然后将新的元素插入到

4.1 C++ STL 动态链表容器

List和SList都是C++ STL中的容器,都是基于双向链表实现的,可以存储可重复元素的特点。其中,List内部的节点结构包含两个指针一个指向前一个节点,一个指向后一个节点,而SList只有一个指针指向后一个节点,因此相对来说更节省存储空间,但不支持反向遍历,同时也没有List的排序功能。双向链表的数据元素可以通过链表指针串接成逻辑意义上的线性表,不同于采用线性表顺序存储结构的`Vector`

7.5 C/C++ 实现链表队列

链表队列是一种基于链表实现的队列,相比于顺序队列而言,链表队列不需要预先申请固定大小的内存空间,可以根据需要动态申请和释放内存。在链表队列中,每个节点包含一个数据元素和一个指向下一个节点的指针,头节点表示队头,尾节点表示队尾,入队操作在队尾插入元素,出队操作在队头删除元素,队列的长度由节点数量决定。由于链表队列没有容量限制,因此可以处理任意数量的元素,但是相比于顺序队列,链表队列的访问速度较慢,因

说一下 ArrayList 和 LinkedList 的区别?

本文已收录到 AndroidFamily,技术和职场问题,请关注公众号 [彭旭锐] 提问。 前言 大家好,我是小彭。 在上一篇文章里,我们聊到了基于动态数组 ArrayList 线性表,今天我们来讨论一个基于链表的线性表 —— LinkedList。 小彭的 Android 交流群 02 群已经建立

LSP 链路状态协议

转载请注明出处: 链路状态协议(Link State Protocol)是一种在计算机网络中用于动态计算路由的协议。它的主要作用是收集网络拓扑信息,为每个节点构建一个准确的网络图,并基于这些信息计算出最短路径。常见的链路状态协议有OSPF(开放最短路径优先)和IS-IS(中间系统到中间系统)。 链路

文心一言 VS 讯飞星火 VS chatgpt (110)-- 算法导论10.2 1题

一、用go语言,单链表上的动态集合操作 INSERT 能否在 O(1)时间内实现?DELETE 操作呢? 文心一言: 在单链表中,INSERT 和 DELETE 操作的时间复杂度通常是 O(n),其中 n 是链表中的元素数量。这主要是因为当你插入或删除元素时,你需要遍历链表来找到正确的插入或删除位置

【转帖】15.JVM栈帧的内部结构

目录 1.JVM栈帧的内部结构 1.JVM栈帧的内部结构 栈帧存储的数据可以分为下面的5个部分: 1.局部变量表(重点) 2.操作数栈(重点) 3.动态链接,也称为指向运行时常量池的方法引用 4.方法返回地址,也称为方法退出或者异常退出的定义 5.一些附加信息 每个栈帧都有自己的大小,各个栈帧的大小