The GNU linker链接器搜索共享库的顺序

程序构建三剑客:编译器、链接器与加载器详解 程序构建是将源代码转换为可执行文件的关键过程,涉及编译器、链接器和加载器三大核心组件。编译器负责将高级语言翻译为机器码,经过预处理、词法分析、语法分析等多个阶段,生成优化后的目标文件。链接器则将这些目标文件与库文件合并,处理符号解析和重定位,支持静态链接和动态链接两种方式。加载器在程序运行时将其载入内存,处理动态库依赖和内存布局。理解这些底层机制对于性能优化、跨平台开发和嵌入式系统设计至关重要。现代工具链如GCC、Clang和CMake等,都基于这些原理构建,帮助开发者高效管理复杂项目的编译和链接过程。 阅读详情

ld - The GNU linker搜索共享库(shared library)的顺序。

更多详细信息可以参考man ld页面,关于一些动态库的知识可以参考另一篇博文“Linux ldd命令”

The linker uses the following search paths to locate required shared libraries:

  1. Any directories specified by -rpath-link options.
  2. Any directories specified by -rpath options.  The difference between -rpath and -rpath-link is that directories specified by-rpath options are included in the executable and used at runtime, whereas the-rpath-linkoption is only effective at link time. Searching-rpath in this way is only supported by native linkers and cross linkers which have been configured with the--with-sysroot option.
  3. On an ELF system, for native linkers, if the -rpath and -rpath-link options were not used, search the contents of the environment variable "LD_RUN_PATH".
  4. On SunOS, if the -rpath option was not used, search any directories specified using-L options.
  5. For a native linker, the search the contents of the environment variable "LD_LIBRARY_PATH".
  6. For a native ELF linker, the directories in "DT_RUNPATH" or "DT_RPATH" of a shared library are searched for shared libraries needed by it. The "DT_RPATH" entries are ignored if "DT_RUNPATH" entries exist.
  7. The default directories, normally /lib and /usr/lib.
  8. For a native linker on an ELF system, if the file/etc/ld.so.conf exists, the list of directories found in that file.

1. -rpath-link仅仅在link(链接)的时候有效。

2. -rapth将会存储在ELF文件里面,而且是在run(运行)的时候有效,-rpath仅仅支持native(本地) linker,和配置了--with-sysroot选项的cross(跨平台) linker。跨平台编译就是在一个平台上面编译了,在其他几个平台上也可以运行。

3. 在ELF系统里面,针对本地链接器,假如-rpath和-rpath-link选项都没有使用,将会搜索LD_RUN_PATH环境变量的内容。

4. 在SunOS系统里面,假如-rpath选项没有使用,将会搜索-L选项指定的内容。

5. 针对本地链接器,将会搜索LD_LIBRARY_PATH环境变量的内容。

6. 针对本地ELF链接器,将会搜索DT_RUNPATH和DT_RPATH环境变量的内容,如果DT_RUNPATH环境变量存在,那么DT_RPATH就会被忽略。

7. 默认的搜索路径是/lib和/usr/lib。

8. 针对在ELF系统里面的本地链接器,假如/etc/ld.so.conf存在,将会从里面包含的目录中搜索。

搜索顺序是从上到下,如果需要的共享库没有找到,链接器将会发出一个warning,并且继续后面的shared library的查询。


最近因为工作的需要研究了RPATH,现在给大家分享一下。以前我们编译的工具很多都是要依赖LD_LIBRARY_PATH来查找共享库,因为LD_LIBRARY_PATH不是那么好,所以就打算用利用RPATH把相关的共享库放到编译好的ELF里面。这里就举两个例子来说明怎么把RPATH加入到ELF里面,一个是编译cpp文件的时候加上RPATH,另外一个是在编译工具的时候,configure这步加上RPATH。

例子:

编译单个的cpp文件,加入RPATH

[root@rhel6164 test]# cat memleak.cpp
int main()
{
    int* k = new int[10]; // memleak!
    return 0;
}
[root@rhel6164 test]# g++ -Wl,-rpath=./lib memleak.cpp -o memleak #编译memleak可执行文件的时候,把-rpath参数加上,我这里就以当前路径下的lib目录为例,加入到rpath里面
[root@rhel6164 test]# readelf -d ./memleak #查看RPATH已经加入到memleak可执行文件里面,到时候在运行memleak的时候,就会首先到指定的目录去找相应的共享库

Dynamic section at offset 0x7d8 contains 24 entries:
  Tag        Type                         Name/Value
 0x0000000000000001 (NEEDED)             Shared library: [libstdc++.so.6]
 0x0000000000000001 (NEEDED)             Shared library: [libm.so.6]
 0x0000000000000001 (NEEDED)             Shared library: [libgcc_s.so.1]
 0x0000000000000001 (NEEDED)             Shared library: [libc.so.6]
 0x000000000000000f (RPATH)              Library rpath: [./lib]
 0x000000000000000c (INIT)               0x400480
 0x000000000000000d (FINI)               0x4006c8
 0x000000006ffffef5 (GNU_HASH)           0x400260
 0x0000000000000005 (STRTAB)             0x400318
 0x0000000000000006 (SYMTAB)             0x400288
 0x000000000000000a (STRSZ)              171 (bytes)
 0x000000000000000b (SYMENT)             24 (bytes)
 0x0000000000000015 (DEBUG)              0x0
 0x0000000000000003 (PLTGOT)             0x6009b0
 0x0000000000000002 (PLTRELSZ)           72 (bytes)
 0x0000000000000014 (PLTREL)             RELA
 0x0000000000000017 (JMPREL)             0x400438
 0x0000000000000007 (RELA)               0x400420
 0x0000000000000008 (RELASZ)             24 (bytes)
 0x0000000000000009 (RELAENT)            24 (bytes)
 0x000000006ffffffe (VERNEED)            0x4003d0
 0x000000006fffffff (VERNEEDNUM)         2
 0x000000006ffffff0 (VERSYM)             0x4003c4
 0x0000000000000000 (NULL)               0x0

我这里以python为例,从源码编译、安装python的时候,加入RPATH

[root@rhel6164 2.7.2]#tar xjf Python-2.7.2.tar.bz2 && cd Python-2.7.2 #解压源码包
[root@rhel6164 2.7.2]#LDFLAGS='-Wl,-rpath=\$${ORIGIN}/../lib' ./configure --prefix=/root/package/python/2.7.2/install_with_rpath --enable-shared --enable-ipv6 --enable-unicode=ucs4 #定义LDFLAGS变量,这里用到了ORIGIN变量,意思是当前可执行文件所在的目录,也要enable共享库选项
[root@rhel6164 2.7.2]#make && make install
[root@rhel6164 2.7.2]# readelf -d ./install_with_rpath/bin/python2.7 #查看到RPATH已经加入到python2.7的可执行文件里面,到时候就不需要在设置LD_LIBRARY_PATH变量指定要找的共享库所在的目录

Dynamic section at offset 0x8f0 contains 26 entries:
  Tag        Type                         Name/Value
 0x0000000000000001 (NEEDED)             Shared library: [libpython2.7.so.1.0]
 0x0000000000000001 (NEEDED)             Shared library: [libpthread.so.0]
 0x0000000000000001 (NEEDED)             Shared library: [libdl.so.2]
 0x0000000000000001 (NEEDED)             Shared library: [libutil.so.1]
 0x0000000000000001 (NEEDED)             Shared library: [libm.so.6]
 0x0000000000000001 (NEEDED)             Shared library: [libc.so.6]
 0x000000000000000f (RPATH)              Library rpath: [${ORIGIN}/../lib]
 0x000000000000000c (INIT)               0x4005e8
 0x000000000000000d (FINI)               0x400808
 0x000000006ffffef5 (GNU_HASH)           0x400260
 0x0000000000000005 (STRTAB)             0x400458
 0x0000000000000006 (SYMTAB)             0x4002c0
 0x000000000000000a (STRSZ)              255 (bytes)
 0x000000000000000b (SYMENT)             24 (bytes)
 0x0000000000000015 (DEBUG)              0x0
 0x0000000000000003 (PLTGOT)             0x600ae8
 0x0000000000000002 (PLTRELSZ)           48 (bytes)
 0x0000000000000014 (PLTREL)             RELA
 0x0000000000000017 (JMPREL)             0x4005b8
 0x0000000000000007 (RELA)               0x4005a0
 0x0000000000000008 (RELASZ)             24 (bytes)
 0x0000000000000009 (RELAENT)            24 (bytes)
 0x000000006ffffffe (VERNEED)            0x400580
 0x000000006fffffff (VERNEEDNUM)         1
 0x000000006ffffff0 (VERSYM)             0x400558
 0x0000000000000000 (NULL)               0x0


Windows下GCC 15+CMake 4+Rust GNU工具链混合开发环境配置指南 在跨平台软件开发中,C/C++与Rust的混合编程已成为提升性能与安全性的重要模式。其核心原理是通过外部函数接口(FFI)实现语言间的互操作,关键在于构建工具链的兼容性。这种技术方案的价值在于能够结合C/C++的成熟生态与Rust的内存安全特性,广泛应用于系统编程、游戏引擎和基础设施软件等领域。本文聚焦于Windows平台,针对开发者在配置**GCC编译器**与**CMake构建系统**时常见的环境冲突问题,提供了一套基于WinLibs发行版的GCC 15与CMake 4的集成方案,并详细阐述了如何将其与R 阅读详情

相关推荐

C++静态链接与动态链接:原理、实战与选择指南

在软件构建过程中,链接是将多个编译单元组合成可执行程序的关键步骤。其核心原理在于解析符号引用,将分散的代码和数据整合为统一的地址空间。从技术价值看,链接方式直接影响程序的部署、运行效率和维护性。静态链接在编译时将库代码复制到可执行文件中,生成独立但体积较大的程序;动态链接则在运行时加载共享库,节省资源但依赖环境。这两种机制在工程实践中各有应用场景:静态链接适用于分发独立工具、嵌入式环境或需要固化依赖版本的场景;动态链接则广泛用于大型桌面应用、系统服务及支持插件架构的软件。理解静态链接与动态链接的差异,能帮助

weixin_34344403的博客 456

ld - The GNU linker

本文是翻译自man ld 名称 ld - The GNU linker 语法 ld [options] bobjfile … 描述 ld 连结许多对象和归档文件(.a),重定位他们的数据,绑定符号引用。通常,编译一个程序的最后一步是运行ld ld接受连接器命令行语言文本,提供对链接程序的显式和整体控制。 该版本ld使用通用目的的BFD库去操作对象文件。该库允许ld程序以多种不同的格式(例如,COFF或a.out)去读,连结,和写对象文件 .不同的格式可能会被链接到一起去产生任何可用类型的对象文件。 得益于它

weixin_41964962的博客 940

PowerPC Linux嵌入式开发:CodeWarrior一体化调试平台实战指南

在嵌入式系统开发中,交叉编译与远程调试是连接主机开发环境与目标硬件平台的核心技术。其原理在于通过专用的工具链将源代码编译为目标处理器架构的可执行文件,再借助调试代理实现主机IDE对目标板上运行程序的实时控制。这项技术的价值在于极大提升了资源受限、硬件依赖强的嵌入式环境下的开发效率与问题定位能力,广泛应用于工业控制、车载电子、网络设备等领域。本文聚焦于PowerPC架构的Linux嵌入式开发,深入解析如何利用CodeWarrior Development Studio这一一体化解决方案平台,高效完成从应用层到

weixin_33694172的博客 455

Using ld-The GNU linker阅读笔记(ld version 2)

本文主要是Using ld这篇英文文档的阅读笔记,部分内容引用自CSAPP的链接章节,作为总结和备忘,也分享给需要的人。部分我拿捏不准的词汇,将保留原文内容,以防止曲解。ld 包括.obj(object files)和.a(archive files), 主要作用是对这些文件内数据进行重定向,并进行完整的打包。通常来说,编译的最后阶段即是运行ld,而ld有着一套标准的语法,可以清晰明确的控制整个链接过程。

m0_47462420的博客 2121

嵌入式开发静态库实战:从原理到XMC项目应用

在嵌入式系统开发中,代码复用是提升效率和保证质量的关键。静态库作为一种编译后的代码打包方案,其核心原理在于将可复用的目标文件归档为单一文件,在链接阶段被完整拷贝到最终可执行程序中。这种机制确保了代码的封装性,保护了知识产权,同时避免了运行时依赖,特别适合对实时性要求高的嵌入式场景。从技术价值看,静态库能显著提升编译效率,减少重复编译开销,并简化项目管理。在英飞凌XMC等微控制器开发中,静态库广泛应用于驱动封装、算法模块化等场景。本文聚焦于静态库的创建与使用,深入探讨了链接顺序、符号解析等常见问题,并提供了在

weixin_33767813的博客 303

深入解析C语言编译与链接:从源代码到可执行文件的完整流程

在软件开发中,编译与链接是将高级语言源代码转换为机器可执行代码的核心过程。其基本原理涉及多个阶段:预处理展开宏和头文件,编译进行语法分析和优化生成汇编代码,汇编将助记符转换为机器码,最后链接器解决符号引用并合并目标文件。这一流程的技术价值在于,它直接决定了程序的性能、体积和可移植性,是优化和调试的底层基础。在实际应用场景中,开发者常需处理静态链接与动态链接的选择、解决符号未定义或重复定义等常见问题,并借助构建系统如Makefile或CMake管理复杂项目。本文聚焦于GCC工具链下的具体实践,通过命令行操作逐

weixin_30765505的博客 418

ld命令

概念: The GNU linker 作用: ld combines a number of object and archive files, relocates their data and ties up symbol references. Usually the last step in compiling a program is to run ld. 全称 l...

mongoose的专栏 487

Power Architecture嵌入式开发:CodeWarrior与GCC构建工具链配置实战指南

在嵌入式系统开发中,构建工具链是连接高级语言源代码与底层硬件架构的关键桥梁,其核心作用是将C/C++代码翻译并优化为目标处理器可执行的机器指令。其工作原理涉及编译器、汇编器、链接器的协同工作,通过处理器架构选项、ABI规范、内存布局配置等参数,确保生成代码与特定硬件(如Power Architecture处理器)的指令集、内存模型完全匹配。这一过程的技术价值在于直接影响最终固件的性能、尺寸和可靠性,尤其在工业控制、汽车电子等对实时性和稳定性要求极高的领域。应用场景广泛覆盖从传统PowerPC到现代QorIQ

weixin_34112181的博客 321

linux共享库链接,linux共享库链接过程

一 与静态库链接1 符号解析(symbol resolution)将符号的引用与定义联系在一起。#引用信息和定义信息在哪儿,怎么联系在一起的1)内部符号解析-编译器2)外部符号解析-连接器 与静态库链接:链接器维护三个集合(E:可执行文件集合(U:未解析的符号集合(D:已定义的符号集合对于每一个输入的目标文件,通过里面的符号引用与定义信息来修改U、D中的值。对于库文件,若库中的文件成员m中含有对...

weixin_34431256的博客 305

嵌入式IDE插件化架构解析:从CodeWarrior看统一开发环境设计

在嵌入式系统开发中,集成开发环境(IDE)是连接硬件与软件的关键桥梁。其核心原理在于通过模块化架构,将编译器、调试器、构建系统等工具整合,实现跨平台、多处理器的统一开发体验。这种设计的技术价值在于显著提升开发效率,降低学习成本,并支持复杂的异构系统开发。应用场景广泛覆盖从微控制器到多核处理器的嵌入式设备,如物联网终端、工业控制和汽车电子。本文以经典的CodeWarrior IDE为例,深入剖析其以项目管理器为核心的插件化架构,以及三段式编译器设计,展示了如何通过可插拔的组件灵活适配PowerPC、ARM等不

weixin_34341117的博客 471

The GNU linker.pdf

ld combines a number of object and archive files, relocates their data and ties up symbol references. Usually the last step in compiling a program is to run ld. ld accepts Linker Command Language files written in a superset of AT&T’s Link Editor Command Language syntax, to provide explicit and total control over the linking process. This version of ld uses the general purpose BFD libraries to operate on object files. This allows ld to read, combine, and write object files in many different formats—for example, COFF or a.out. Different formats may be linked together to produce any available kind of object file. See Chapter 5 [BFD], page 93, for more information. Aside from its flexibility, the gnu linker is more helpful than other linkers in providing diagnostic information. Many linkers abandon execution immediately upon encountering an error; whenever possible, ld continues executing, allowing you to identify other errors (or, in some cases, to get an output file in spite of the error).

linux连接器ld

http://blog.youkuaiyun.com/fisher_jiang/article/details/4193368 描述 (DESCRIPTION) ld 合并 一组 目标文件(object) 和 库文件(archive), 重定位 数据部分, 构建 符号引用(symbol reference). 一般说来, 编译 生成 可执行文件 的 最后步骤 就是 调用 ld. ld 可以读取

bytxl的专栏 1207

GNU linker

GNU linker 官方说明文档 (Sourcery G++ Lite 2010q1-188) Version 2.19.51

深入ELF文件:从rpath和interpreter看懂Linux程序如何‘找到家’

本文深入解析Linux系统中ELF文件的rpath和interpreter机制,揭示程序加载和动态链接的核心原理。通过分析ELF文件结构、动态链接库搜索路径以及glibc兼容性问题,帮助开发者理解并解决Linux程序运行时的库依赖问题。

weixin_30919429的博客 370

gnu linker manual

take some time to find it. Open share and this is the GNU linker manual. V2.0 version.

The GNU Linker V2.19.51

此版本修正了 《Using ld》(The GNU Linker (ld version 2) v2.14版本)里的错误,同时新增了一些内容,更易于理解. The GNU Linker (ld) 官方说明文档 (Sourcery G++ Lite 2010q1-188) Version 2.19.51.

深入解析链接器报错:ld.lld找不到库文件的原理与解决方案

在C/C++、Rust等系统级编程中,链接器是构建过程中的关键组件,负责将多个目标文件与库文件合并生成最终可执行程序。其核心原理在于符号解析与重定位,通过搜索预定义路径来定位静态库(.a/.lib)或动态库(.so/.dll)。理解链接器工作流程对解决构建错误至关重要,尤其在跨平台开发和复杂依赖管理中。当链接器报出“unable to find library”错误时,通常意味着库搜索路径配置不当或库文件缺失。这一问题的技术价值在于保障项目构建的可靠性,避免因依赖问题导致编译中断或运行时异常。常见应用场景包

weixin_34166847的博客 364

LLC混合滞回控制 vs 电压模/电流模:UCC25640x仿真对比与选型指南

在开关电源设计中,LLC谐振变换器的环路补偿是核心难点。传统电压模控制(VMC)和电流模控制(CMC)在LLC拓扑上存在环路增益漂移、动态响应慢等局限。混合滞回控制通过滞回比较器直接调制开关频率,并融合输出电压与谐振腔电流信息,实现了自适应环路增益和快速瞬态响应。该技术显著提升轻载效率与动态性能,适用于高密度适配器、快充及车载充电机等场景。本文基于UCC25640x系列,通过仿真对比三种控制策略,为工程选型与调试提供实践参考。

weixin_33925615的博客 334

彻底解决ld.lld链接错误:库文件搜索路径与系统性排查指南

在C/C++程序开发中,链接器是将多个目标文件与库文件合并生成可执行程序的关键组件。其核心原理在于按照预设的搜索路径规则解析符号引用,完成地址重定位。理解链接器工作机制对于解决构建失败、提升工程效率至关重要,尤其在大型项目与交叉编译场景中。本文聚焦于LLVM生态下的高性能链接器ld.lld,针对其常见的“unable to find library”错误,从库文件搜索路径机制切入,深入剖析了环境变量LIBRARY_PATH与链接参数-L的作用差异,并提供了从库名校验、路径验证到构建系统调试的完整排查链路。通

congbao6525的博客 455

SOI技术解析:绝缘体上硅的结构优势与应用场景

本文深入解析了SOI(绝缘体上硅)技术的核心结构、性能优势与应用场景。SOI通过在硅衬底与器件层之间引入绝缘的埋氧层,实现了优异的电隔离,从而显著降低芯片功耗、提升工作频率并增强抗干扰能力。该技术已广泛应用于5G射频前端、高性能计算、汽车电子及MEMS传感器等关键领域,是推动半导体性能持续提升的重要技术路径。

jj890的博客 403

Nacos启动报错No DataSource set?5分钟搞定standalone模式配置

本文针对Nacos启动时常见的“No DataSource set”报错,深入解析了其根源在于默认集群模式与外部数据库依赖。提供了两种快速解决方案:通过命令行参数“-m standalone”启动,或直接修改启动脚本配置文件,从而在5分钟内以单机模式成功启动Nacos,无需配置MySQL数据库。

weixin_29234509的博客 465
上一篇: Linux readelf命令
下一篇: Linux tr命令
Clef
博客等级 码龄12年 125粉丝 121原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值