当前位置: 首页 > news >正文

Linux:库

目录

静态库

动态库

目标文件

ELF文件 

ELF形成可执行

ELF可执行加载

 ELF加载

全局偏移量表GOT(global offset table) 


库是写好的,成熟的,可以复用的代码

现实中每个程序都要依赖很多的基础的底层库,不可能都是从零开始的

库有两种:

  • 静态库 .a[Linux]、.lib[windows]
  • 动态库 .so[Linux]、.dll[windows]

静态库

程序在编译链接的时候把库的代码链接到可执行文件中,程序运行的时候将不再需要静态库

一个可执行程序可能用到多个库,这些库可能有的是静态库,有的是动态库,而我们编译默认链接为动态库,只有在该库下找不到动态.so的时候才会采用同名静态库。

若是想使用静态库我们可以使用gcc的 -static 强转设置链接静态库

 静态库的生成:

ar -rc libmylib.a mylib.o

 若我们有一个自己写的库叫mylib,那么我们该如何使用它呢?


若头文件和库文件都被我们安装到系统的路径下

/usr/lib、/usr/lib64、/usr/local/lib等等

gcc main.c -lmystdio

 头文件和库文件和我们自己的源文件在同一个路径下

gcc main.c -L. -lmylib

头文件和库文件都有自己独立的路径

gcc main.c -I头⽂件路径 -L库⽂件路径 -lmylib
  •  -L:指定库路径
  • -I:指定头文件搜索路径
  • -l:指定库名

动态库

程序在运行的时候才去链接动态库,多个程序可以共享使用库的代码

一个与动态库链接的可执行程序仅仅包含它用到的函数入口地址的一个表,而不是外部函数所在目标文件的整个机器码

在可执行文件开始运行以前,外部函数的机器码由操作系统从磁盘上的该动态库中复制到内存中,这个过程称为动态链接

动态库可以在多个程序间共享,所以动态链接使得可执行文件更小,节省了磁盘的空间。操作系统采用虚拟内存机制允许物理内存中的一份动态库被要用到该库的所有进程共用,节省了内存和磁盘空间

动态库的生成:

gcc -fPIC -c main.c -o mylib.o
gcc -o libmylib.so mylib.o -shared

动态库需要使用位置无关码PIC,因此需要加上 -fPIC选项

动态库的命名约定通常以lib开头,后缀为.so

  • shared:表示生成共享库格式
  • fPIC:产生位置无关码
  • 库名规则:libxxx.so

动态库使用:

若头文件和库文件都被我们安装到系统的路径下

gcc main.c -lmylib

头文件和库文件和我们自己的源文件在同一个路径下

gcc main.c -L. -lmylib

头文件和库文件都有自己独立的路径

gcc main.c -I头⽂件路径 -L库⽂件路径 -lmylib

我们可以使用ldd命令来查看库或者可执行程序的依赖

ldd libmylib.so

目标文件

在编译之后会产生扩展名为.o的文件,它们被称作目标文件 

若是我们有多个源文件,需要修改其中一个,那么我们只需要编译这一个为目标文件再一起链接,这样就不需要浪费时间重新编译整个工程

目标文件是一个二进制文件,文件的格式是ELF,是对二进制代码的一种封装 

ELF文件 

以下四种都是ELF文件

  • 可重定位文件:即xxx.o文件。包含适合于与其他⽬标⽂件链接来创建可执⾏⽂件或者共享⽬标⽂件的代码和数据
  • 可执行文件:即可执行程序
  • 共享目标文件:即 xxx.so⽂件
  • 内核转储:存放当前进程的执⾏上下⽂,⽤于dump信号触发

一个ELF文件由四个部分组成

  • ELF头(ELF header):描述⽂件的主要特性。其位于⽂件的开始位置,它的主要⽬的是定位⽂件的其他部分
  • 程序头表(Program header table):列举了所有有效的段(segments)和他们的属性。表⾥
    记着每个段的开始的位置和位移(offset)、⻓度,毕竟这些段,都是紧密的放在⼆进制⽂件中,需要段表的描述信息,才能把他们每个段分割开
  • 节头表(Section header table):包含对节(sections)的描述
  • 节(Section):ELF⽂件中的基本组成单位,包含了特定类型的数据。ELF⽂件的各种信息和数据都存储在不同的节中,如代码节存储了可执⾏代码,数据节存储了全局变量和静态数据等

常见的节有:

  • 代码节(.text):⽤于保存机器指令,是程序的主要执⾏部分
  • 数据节(.data):保存已初始化的全局变量和局部静态变量

ELF形成可执行

1. 首先将多份C/C++源代码翻译称为目标.o文件

2. 将多份.o文件Section进行合并

ELF可执行加载

⼀个ELF会有多种不同的Section,在加载到内存的时候,也会进⾏Section合并,形成segment

合并原则:相同属性,⽐如:可读,可写,可执⾏,需要加载时申请空间等。这样,即便是不同的Section,在加载到内存中,可能会以segment的形式,加载到⼀起

很显然,这个合并⼯作也已经在形成ELF的时候,合并⽅式已经确定了,具体合并原则被记录在了
ELF的 程序头表 (Program header table) 中

 

Section合并的主要原因是为了减少⻚⾯碎⽚,提⾼内存使⽤效率 

 ELF加载

⼀个ELF程序,在没有被加载到内存的时候,本来就有地址,当代计算机⼯作的时候,都采⽤"平坦
模式"进⾏⼯作。

 

用来初始化的数据也是从ELF的各个segment来,每个segment有自己的起始地址和长度,用来初始化内核结构中[start, end]等范围的数据

 

程序调用库方法:只需要知道库的起始虚拟地址+方法偏移量即可定位库中的⽅法

我们的程序运⾏之前,先把所有库加载并映射,所有库的起始虚拟地址都应该提前知道 
对我们加载到内存中的程序的库函数调⽤进⾏地址修改,在内存中⼆次完成地址设置(这个叫做加载地址重定位)
但是代码区是可读的,怎么能修改呢?

全局偏移量表GOT(global offset table) 

动态链接采⽤的做法是在 .data (可执⾏程序或者库⾃⼰)中专⻔预留⼀⽚区域⽤来存放函数的跳转地址,它也被叫做全局偏移表GOT,表中每⼀项都是本运⾏模块要引⽤的⼀个全局变量或函数的地址

因为.data区域是可读写的,所以可以⽀持动态进⾏修改 

有了GOT表,代码便可以被所有进程共享。但在不同进程的地址空间中,各动态库的绝对地址、相对位置都不同。每个动态库都有独⽴的GOT表,所以进程间不能共享GOT表

 

 


完 

http://www.lryc.cn/news/534697.html

相关文章:

  • 向量数据库简单对比
  • 大模型基本原理(四)——如何武装ChatGPT
  • 从零开始:使用Jenkins实现高效自动化部署
  • Spring Cloud工程完善
  • SSM仓库物品管理系统 附带详细运行指导视频
  • UI自动化测试中如何处理验证码?
  • 华为交换机堆叠配置
  • Vue 和 dhtmlx-gantt 实现图表构建动态多级甘特图效果 ,横坐标为动态刻度不是日期
  • collabora online+nextcloud+mariadb在线文档协助
  • “可通过HTTP获取远端WWW服务信息”漏洞修复
  • 【AI时代】-开发环境准备 之 Conda 创建 Python 环境 (含pip常用命令、jupyter 安装及汉化、自定义文档位置等配置)
  • [LeetCode] day19 454. 四数相加 II
  • LeetCodehot 力扣热题100 验证二叉搜索树
  • 四次挥手详解
  • Deepseek-v3 / Dify api接入飞书机器人go程序
  • 2025.2.9 每日学习记录2:技术报告写了一半+一点点读后感
  • qml ToolBar详解
  • 机器学习在癌症分子亚型分类中的应用
  • Ansible自动化部署K8s集群一 Ansible的基础使用实战
  • ZooKeeper Watcher 机制详解:从注册到回调的全过程
  • flutter_tools/gradle Unsupported class file major version 65 问题解决
  • C++设计模式 - 模板模式
  • mysql查缺补漏
  • 跨越边界,大模型如何助推科技与社会的完美结合?
  • 哪吒闹海!SCI算法+分解组合+四模型原创对比首发!SGMD-FATA-Transformer-LSTM多变量时序预测
  • 前端【技术方案】浏览器兼容问题(含解决方案、CSS Hacks、条件注释、特性检测、Polyfill 等)
  • 荣耀手机Magic3系列、Magic4系列、Magic5系列、Magic6系列、Magic7系列详情对比以及最新二手价格预测
  • 后盾人JS -- 模块化开发
  • CNN卷积神经网络多变量多步预测,光伏功率预测(Matlab完整源码和数据)
  • 深入 JVM 虚拟机:字符串常量池演变与 intern() 方法工作原理解析