【链接装载与库】 Linux共享库的组织
Linux共享库的组织
由于动态链接的诸多优点,大量的程序开始使用动态链接机制,导致系统里面存在数量 极为庞大的共享对象。如果没有很好的方法将这些共享对象组织起来,整个系统中的共享对象文件则会散落在各个目录下,给长期的维护、升级造成了很大的问题。所以操作系统一般会对共享对象的目录组织和使用方法有一定的规则,我们将在这一章介绍Linux 下共享库的管理问题。
共享库版本
- 共享库兼容性
共享库的开发者会不停地更新共享库的版本,以修正原有的Bug、 增加新的功能或改进性能等。由于动态链接的灵活性,使得程序本身和程序所依赖的共享库可以分别独立开发和更新, 但是共享库版本的更新可能会导致接口的更改或删除,这可能导致依赖于该共享库的程序无法正常运行。最简单的情况下,共享库的更新可以被分为两类。
- 兼容更新。 所有的更新只是在原有的共享库基础上添加一些内容,所有原有的接口都 保持不变。
- 不兼容更新。 共享库更新改变了原有的接口,使用该共享库原有接口的程序可能不能 运行或运行不正常。
导致 C 语言的共享库ABI 改变的行为主要有如下4个
- 导出函数的行为发生改变,也就是说调用这个函数以后产生的结果与以前不一样。
- 导出函数被删除。
- 导出数据的结构发生变化,比如共享库定义的结构体变量的结构发生改变:结构成员 删除、顺序改变或其他引起结构体内存布局变化的行为
- 导出函数的接口发生变化,如函数返回值、参数被更改。
- 共享库版本命名
Linux 有一套规则来命名系统中的每一 个共享库,它规定共享库的文件名规则必须如下:
libname.so.x.y.z
最前面使用前缀“lib"、 中间是库的名字和后缀“.so”,最后面跟着的是三个数字组成 的版本号。“x”表示主版本号,“y”表示次版本号,“z” 表示发布版本号。 三个版本号的含义不一样。
主版本号表示库的重大升级,不同主版本号的库之间是不兼容的,依赖于旧的主版本号 的程序需要改动相应的部分,并且重新编译,才可以在新版的共享库中运行
次版本号表示库的增量升级,即增加一些新的接口符号,且保持原来的符号不变。在主 版本号相同的情况下,高的次版本号的库向后兼容低的次版本号的库。
发布版本号表示库的一些错误的修正、性能的改进等,并不添加任何新的接口,也不对接口进行更改。
- SO-NAME
共享库的主版本号和次版本号决定了一个共享库的接口。动态链接器怎样知道程序依赖于哪些共享库,它们的版本号又是什么?
Solaris 和Linux, 普遍采用一种叫做SO-NAME的命名机制来记录共享库的依赖关系。每个共享库都有一个对应的“SO-NAME”, 这个 SO-NAME即共享库的文件名去掉次版本号和发布版本号,保留主版本号。
系统会为每个共享库在它所在的目录创建一个跟 “SO-NAME” 相同的并且指向它的软链接
那么以“SO-NAME”为名字建立软链接有什么用处呢?
实际上这个软链接会指向目录 中主版本号相同、次版本号和发布版本号最新的共享库。
建立以SO-NAME为名字的软链接目的是,使得所有依赖某个共享库的模块,在编译、 链接和运行时,都使用共享库的SO-NAME,而不使用详细的版本号。
编译输出ELF文件时,将被依赖的共享库的SO-NAME保存到“.dynamic”中,这样当动态链接器进行共享库依赖文件查找时,就会根据系统中各种共享库目录中的SO-NAME软链接自动定向到最新版本的共享库。
Linux 中提供了一个工具叫做“ldconfig”, 当系统中安装或更新一个共享库时,就需要运行这个工具,它会遍历所有的默认共享库目录,比如/ib、/usr/ib 等,然后更新所有的软 链接,使它们指向最新版的共享库;如果安装了新的共享库,那么ldconfig会为其创建相应 的软链接。
符号版本
如果某个共享库在系统中存在相同主版本号不同次版本号的多个副本,那么动态链接器会使用那个最高次版本号的副本。如果找到的共享库次版本号低于所需要的版本, SunOS 4.x系统的策略是向用户发 出一个警告信息,表示系统中仅有低次版本号的共享库,但运行程序还是继续运行。有些采取更加保守策略的系统中,对于 这种系统中没有足够高的次版本号满足依赖关系的情况,程序将会被禁止运行,以防止出现意外情况。在采取第二种策略的系统中,如果系统中 只有低次版本号的共享库,那么这些程序就不能运行。我们可以把这个问题叫做次版本号交会问题
这种次版本号交会问题并没有因为SO-NAME 的存在而得到任何改善。 对于这个问题,现代的系统通过一种更加精巧的方式来解决,那就是符号版本机制。
- 基于符号的版本机制
Linux 下的Glibc 从版本2.1之后开始支持一种叫做基于符合的版本机制的方案。这个方案的基本思路是让每个导出和导入的符号都有一个相关联的版 本号,它的实际做法类似于名称修饰的方法。
当我们将libfoo.so.1.2升级至1.3时,仍然 保持 libfoo.so.1 这个 SO-NAME, 但是给在1.3这个新版中添加的那些全局符号打上一个标 记,比如“VERS 1.3”。那么,如果一个共享库每一次次版本号升级,我们都能给那些在新 的次版本号中添加的全局符号打上相应的标记,就可以清楚地看到共享库中的每个符号都拥 有相应的标签,比如“VERS 1.1”、“VERS 1.2”、“VERS 1.3”、“VERS 1.4”。
- Solaris 中的符号版本机制
Solaris 的ld链接器为共享库新增了版本机制和范围机制
版本机制的想法很简单,也就是定义一些符号的集合,这些集合本身都有名字,比如叫 “VERS 1.1”、“VERS 1.2”等,每个集合都包含一些指定的符号,除了可以拥有符号以外, 一个集合还可以包含另外一个集合,比如 “VERS 1.2”可以包含集合“VERS 1.1”。
在 Solaris 中,程序员可 以在链接共享库时编写一种叫做符号版本脚本的文件。链接器在链接时根据符号版本脚本中指定的关系来产 生共享库,并且设置符号的集合与它们之间的关系。
当共享库的符号都有了版本集合之后, 一个最明显的效果就是,当我们在构建(编译和 链接)应用程序的时候,链接器可以在程序的最终输出文件中记录下它所用到的版本符号集 合。
- GCC 对 Solaris 符号版本机制的扩展
GCC 还允许使用一个叫做“.symver”的汇编宏指令来指定符号的版本,这个汇编宏指令可以被用在GAS 汇编中,也可以在GCC的C/C++源代码中以嵌入汇编指令的模式使用。
asm(".symver add,addeVERS_1.1");
- Linux系统中符号版本机制实践
在 Linux下,当我们使用ld 链接一个共享库时,可以使用“-version-script”参数;如 果使用GCC, 则可以使用“-Xlinker”参数加“-version-script", 相当于把“-version-script” 传递给ld链接器。如编译源代码为“lib.c”, 符号版本脚本文件为"lib.ver":
gcc -shared -fpIC lib.c -Xlinker --version-script lib.ver -o lib.so
共享库系统路径
目前大多数包括 Linux在内的开源操作系统都遵守一个叫做 FHS的标准,这个标准规定了一个系统中的系统文件应该如何存放,包括各个目录的结构、组织和作用,这有利于促进各个开源操作系统之间的兼容性。
FHS 规定, 一个系统中主要有3个存放共享库的位置,它们分别如下:
- /ib,这个位置主要存放系统最关键和基础的共享库,比如动态链接器、 C 语言运行库、 数学库等
- /usr/lib,这个目录下主要保存的是一些非系统运行时所需要的关键性的共享库,主要是 一些开发时用到的共享库
- /usr/local/lib, 这个目录用来放置一些跟操作系统本身并不十分相关的库,主要是一些 第三方的应用程序的库
共享库查找过程
动态链接的ELF可执行文件在启动时同时会启动动态链接器。在Linux 系统中,动态链接器是/lib/ld-linux.so.X(X是版本号)。任何一个动态链接的模块所依赖的模块路径保存在“.dynamic” 段里面,由DT_NEED类型的项表示,如果DT_NEED里面保存的是绝对路径,那么动态链接器就按照这个路径去查找;如果DT_NEED里面保存的是相对路径,那么动态链接器会在/ib、/usr/lib 和由/etc/ld.so.conf 配置文件指定 的目录中查找共享库。
ld.so.conf 是一个文本配置文件,它可能包含其他的配置文件,这些配置文件中存放着 目录信息。
/usr/local/lib
/lib/i486-linux-gnu
/usr/lib/i486-linux-gnu
Linux 系统中都有一个叫做 ldconfig的程序,这个程序的作用是为共享库目录下的各个共享 库创建、删除或更新相应的SO-NAME (即相应的符号链接),这样每个共享库的 SO-NAME就能够指向正确的共享库文件;并且这个程序还会将这些SO-NAME收集起来,集中存放到letc/ld.so.cache 文件里面,并建立一个 SO-NAME的缓存。
环境变量
- LD_LIBRARY_PATH
Linux 系统提供了很多方法来改变动态链接器装载共享库路径的方法。改变共享库查找路径最简单的方法是使用LD_LIBRARY_PATH环境变量
- LD_PRELOAD
系统中另外还有一个环境变量叫做LD_PRELOAD,这个文件中我们可以指定预先装载 的一些共享库甚或是目标文件。在LD_PRELOAD里面指定的文件会在动态链接器按照固定 规则搜索共享库之前装载,它比LD_LIBRARY_PATH里面所指定的目录中的共享库还要优先。
- LD_DEBUG
另外还有一个非常有用的环境变量LD_DEBUG,这个变量可以打开动态链接器的调试功能,当我们设置这个变量时,动态链接器会在运行时打印出各种有用的信息,对于我们开发和调试共享库有很大的帮助。
LD_DEBUG=files ./HelloWorld.out
相关文章:
【链接装载与库】 Linux共享库的组织
Linux共享库的组织 由于动态链接的诸多优点,大量的程序开始使用动态链接机制,导致系统里面存在数量 极为庞大的共享对象。如果没有很好的方法将这些共享对象组织起来,整个系统中的共享对象文件则会散落在各个目录下,给长期的维护…...

大模型时代的机器人研究
机器人研究的一个长期目标是开发能够在物理上不同的环境中执行无数任务的“多面手”机器人。对语言和视觉领域而言,大量的原始数据可以训练这些模型,而且有虚拟应用程序可用于应用这些模型。与上述两个领域不同,机器人技术由于被锚定在物理世…...
devops步骤 -- jenkins安装
安装的docker-compose ##安装步骤参考: https://editor.csdn.net/md/?articleId133070011 编写docker-compose.yml version: 3 services: # 集合docker_jenkins:user: root # 为了避免一些…...

docker命令大全
1、查看Docker 容器占用的空间 docker ps -s2、查看所有容器 docker ps -a3、启动、关闭、重启一个已存在的容器 docker start <容器ID> docker stop <容器ID> docker restart <容器ID> 4、进入容器,退出终端的时候不会关闭container的ma…...

【EI会议征稿】第三届区块链、信息技术与智慧金融国际学术会议 (ICBIS2024)
第三届区块链、信息技术与智慧金融国际学术会议 (ICBIS2024) The 3rd International Academic Conference on Blockchain, Information Technology and Smart Finance 第三届区块链、信息技术与智慧金融国际学术会议 (ICBIS2024) 将于2024年2月23-25日在马来西亚举行。本次会…...
算法岗面经
诸神缄默不语-个人CSDN博文目录 呃这个是我之前写的,理论上我应该搜集题目→做出解答这样的,但是我现在不再继续找工作了,所以感觉这些题目用不到了,我就直接把之前整理的这些资料发出来得了。 以后有缘分的话会继续补的…...
Vue 事件修饰符
Vue 事件修饰符 在 Vue 中,事件修饰符允许我们在处理 DOM 事件时添加一些特殊的修饰符,以便更方便地控制事件的行为。以下是常用的 Vue 事件修饰符: .stop .stop 修饰符用于阻止事件冒泡,即停止事件在父元素之间的传播。 示例…...

FD-Align论文阅读
FD-Align: Feature Discrimination Alignment for Fine-tuning Pre-Trained Models in Few-Shot Learning(NeurIPS 2023) 主要工作是针对微调的和之前的prompt tuining,adapter系列对比 Motivation: 通过模型对虚假关联性的鲁棒…...
bug:Junit5报错,@SpringBootTest没有运行
1、首先解决Junit5报错 java.lang.NoClassDefFoundError: org/junit/platform/launcher/core/LauncherFactory 添加依赖 implementation org.junit.platform:junit-platform-launcher:1.8.2java.lang.IllegalArgumentException: Error: test loader org.eclipse.jdt.internal.…...

Clickhouse学习笔记(4)—— Clickhouse SQL
insert insert操作和mysql一致 标准语法:insert into [table_name] values(…),(….)从表到表的插入:insert into [table_name] select a,b,c from [table_name_2] update 和 delete ClickHouse 提供了 Delete 和 Update 的能力,这类操作…...

Centos, RockyLinux 常用软件安装汇总
一、基本指令: 命令作用clear清屏pwd显示当前路径cat / more显示文本文档uname -a查看当前版本hostnamectl查看当前版本cat /etc/redhat-release查看当前版本free查看剩余内存df -h[查看磁盘剩余空间]du -sh 查看文件夹名"dir"占用的空间lsof -i:8080查看…...

Lua更多语法与使用
文章目录 目的错误处理元表和元方法垃圾回收协程模块面向对象总结 目的 在前一篇文章: 《Lua入门使用与基础语法》 中介绍了一些基础的内容。这里将继续介绍Lua一些更多的内容。 同样的本文参考自官方手册: https://www.lua.org/manual/ 错误处理 下…...

探秘亚马逊云科技海外服务器 | 解析跨境云计算的前沿技术与应用
目录 一、什么是海外服务器 二、不同主流海外云服务器对比 三、海外服务器的创建(亚马逊为例) 四、个人总结 一、什么是海外服务器 亚马逊云科技海外服务器:指的是部署在世界各地的亚马逊数据中心中的服务器设备。这些服务器提供了计算、存储、数据库、网络等各…...
UnityAI——动物迁徙中的跟随实现实例
大家好,我是七七,今天来给大家介绍的是Unity中用操控行为实现的跟随领队行为。 看本文若是想了解和实现,只看本文即可,若是想彻底弄透,建议从七七的游戏AI专栏开始看。 废话不多说,先上视频: …...

堆的应用-----Top k 问题
目录 前言 Topk问题 1.问题描述 2.解决方法 3.代码实现(C/C) 前言 在人工智能算法岗位的面试中,TopK是问得最多的几个问题之一: 到底有几种方法? 这些方案里蕴含的优化思路究竟是怎么样的? 为啥T…...

11月14日星期二今日早报简报微语报早读
11月14日星期二,农历十月初二,早报微语早读。 1、江西南城县:限时发放购房补贴政策,三孩家庭每平方米最高补贴500元; 2、2023年中国内地电影市场累计票房突破500亿元; 3、市场监管总局:在全国…...

Spark读取excel文件
文章目录 一、excel数据源转成csv二、Spark读取csv文件(一)启动spark-shell(二)读取csv生成df(三)查看df内容一、excel数据源转成csv 集群bigdata - ubuntu: 192.168.191.19master(bigdata1) - centos: 192.168.23.78 slave1(bigdata2) - centos: 192.168.23.79 slave2(b…...

LLM大语言模型(典型ChatGPT)入门指南
文章目录 一、基础概念学习篇1.1 langchain视频学习笔记1.2 Finetune LLM视频学习笔记 二、实践篇2.1 预先下载模型:2.2 LangChain2.3 Colab demo2.3 text-generation-webui 三、国内项目实践langchain-chatchat 一、基础概念学习篇 1.1 langchain视频学习笔记 lan…...

Spring IOC - Bean的生命周期之实例化
在Spring启动流程文章中讲到,容器的初始化是从refresh方法开始的,其在初始化的过程中会调用finishBeanFactoryInitialization方法。 而在该方法中则会调用DefaultListableBeanFactory#preInstantiateSingletons方法,该方法的核心作用是初始化…...
前端 BUG 总结
文章目录 CSS 样式1、Chrome 89 版本期不再支持 /deep/,请勿使用嵌套 /deep/2、圆角按钮 button 点击后出现矩形框线3、怪异模式4、border 1 像素在手机上显示问题5、文本溢出问题 JavaScript 脚本1、移动端点击穿透2、使用parseInt时必须补全第二个参数 radix3、有…...
KubeSphere 容器平台高可用:环境搭建与可视化操作指南
Linux_k8s篇 欢迎来到Linux的世界,看笔记好好学多敲多打,每个人都是大神! 题目:KubeSphere 容器平台高可用:环境搭建与可视化操作指南 版本号: 1.0,0 作者: 老王要学习 日期: 2025.06.05 适用环境: Ubuntu22 文档说…...
Vue记事本应用实现教程
文章目录 1. 项目介绍2. 开发环境准备3. 设计应用界面4. 创建Vue实例和数据模型5. 实现记事本功能5.1 添加新记事项5.2 删除记事项5.3 清空所有记事 6. 添加样式7. 功能扩展:显示创建时间8. 功能扩展:记事项搜索9. 完整代码10. Vue知识点解析10.1 数据绑…...
React hook之useRef
React useRef 详解 useRef 是 React 提供的一个 Hook,用于在函数组件中创建可变的引用对象。它在 React 开发中有多种重要用途,下面我将全面详细地介绍它的特性和用法。 基本概念 1. 创建 ref const refContainer useRef(initialValue);initialValu…...

【大模型RAG】Docker 一键部署 Milvus 完整攻略
本文概要 Milvus 2.5 Stand-alone 版可通过 Docker 在几分钟内完成安装;只需暴露 19530(gRPC)与 9091(HTTP/WebUI)两个端口,即可让本地电脑通过 PyMilvus 或浏览器访问远程 Linux 服务器上的 Milvus。下面…...

抖音增长新引擎:品融电商,一站式全案代运营领跑者
抖音增长新引擎:品融电商,一站式全案代运营领跑者 在抖音这个日活超7亿的流量汪洋中,品牌如何破浪前行?自建团队成本高、效果难控;碎片化运营又难成合力——这正是许多企业面临的增长困局。品融电商以「抖音全案代运营…...
unix/linux,sudo,其发展历程详细时间线、由来、历史背景
sudo 的诞生和演化,本身就是一部 Unix/Linux 系统管理哲学变迁的微缩史。来,让我们拨开时间的迷雾,一同探寻 sudo 那波澜壮阔(也颇为实用主义)的发展历程。 历史背景:su的时代与困境 ( 20 世纪 70 年代 - 80 年代初) 在 sudo 出现之前,Unix 系统管理员和需要特权操作的…...
数据库分批入库
今天在工作中,遇到一个问题,就是分批查询的时候,由于批次过大导致出现了一些问题,一下是问题描述和解决方案: 示例: // 假设已有数据列表 dataList 和 PreparedStatement pstmt int batchSize 1000; // …...
在鸿蒙HarmonyOS 5中使用DevEco Studio实现录音机应用
1. 项目配置与权限设置 1.1 配置module.json5 {"module": {"requestPermissions": [{"name": "ohos.permission.MICROPHONE","reason": "录音需要麦克风权限"},{"name": "ohos.permission.WRITE…...
Spring AI与Spring Modulith核心技术解析
Spring AI核心架构解析 Spring AI(https://spring.io/projects/spring-ai)作为Spring生态中的AI集成框架,其核心设计理念是通过模块化架构降低AI应用的开发复杂度。与Python生态中的LangChain/LlamaIndex等工具类似,但特别为多语…...

有限自动机到正规文法转换器v1.0
1 项目简介 这是一个功能强大的有限自动机(Finite Automaton, FA)到正规文法(Regular Grammar)转换器,它配备了一个直观且完整的图形用户界面,使用户能够轻松地进行操作和观察。该程序基于编译原理中的经典…...