库的原理:目标文件,ELF格式,程序加载
个人主页:小则又沐风个人专栏:数据结构竞赛专栏C语言CLinux座右铭悟已往之不谏知来者之可追目录前言目标文件ELF文件ELF Header节头表(Section header table)节Section 程序头表(Program header table)ELF形成可执行文件静态链接ELF加载与进程地址空间动态链接前言上一篇的文章中我们知道了库文件的制作以及怎么使用我们自己制作的库文件,但是上述的内容只是停留在使用的层面上,今天我们来了解一下底层的知识.目标文件我们之前使用的编写代码的工具都是vs2022,在这上面上我们没有直观的看到代码的编译和链接在Linux下可以清楚的看到.//code.c #includestdio.h void run(); int main() { printf(hello,world\n); run(); return 0; } //hello.c #includestdio.h void run() { printf(i am runing...\n); }我们简单的编写这个代码,来看看这个代码的编译和链接的过程gcc -c code.c hello.c可以看到的是现在我们得到了两个.o后缀的文件,这两个文件就是目标文件,如果我们修改了一个目标文件的源文件的话我们只需要重新编译就可以了,不需要进行过多的操作我们打开目标文件就会发现这个文件是一个二进制的文件目标文件的格式是ELF格式ELF文件这张图中我们看到这个信息:relocatable这个代表的是这个文件是一个可重定向的文件(这个具体的含义之后会进行讲解)那么ELF文件的类型都有什么?可重定位⽂件Relocatable File xxx.o可执⾏⽂件Executable File共享⽬标⽂件Shared Object Filexxx.so内核转储(core dumps)如上图就是ELF格式的示意图ELF Header这个是ELF的表头,里面将会描述ELF文件的主要特征.主要的内容是:定位节头表,程序头表可执行程序的入口地址(在目标文件中是0)还有特定的内容来作为自己的标识符下面来简单的查看一下我们目录下的目标文件readelf -h code.o我们可以这样来理解Header这个表中的信息是来标识自己的特点的,并且指出了自己的ELF中节头表和程序表的地址和文件中偏移量,并且需要我们注意的是上面中的信息有一个Entry point address这个就是程序的入口地址(在之后会进行详细的讲解)节头表(Section header table)节头中会存储着我们ELF中主要的信息,可以理解为文件中的数据.程序中的数据根据着不同的特征划分在了不同的节中那么这个节头表的作用就是用来找到不同的节,有助于之后的不同的节的合并节Section 节就是存储着ELF文件的主要数据的部分,根据不同的数据类型会分成为许多不同的节例如:.text 代码节 存储可执行机器指令程序核心逻辑.data 数据节 存储已初始化的全局变量和局部静态变量.bss 未初始化数据节 为未初始化的全局变量 / 静态变量预留空间不占文件空间加载时分配内存.symtab 符号表 存储函数名、变量名与地址的映射关系.reloc 重定位表 记录需要链接时修正的地址如外部函数调用.rodata 只读数据节 存储字符串常量等只读数据如 printf 的字符串程序头表(Program header table)这个表仅存在于可执行文件和动态库中,因为在这些的文件中,才会进行合并的操作,这个就是文件进行合并操作的指南.拥有这个指南之后合并两个文件形同属性的内容,形成段(Segment)段和节的区别我们在上述讲解的过程中产生了两个名词------段和节那么这两个的区别是什么呢?首先节是产生在编译的环节中的,相对于段,节对数据的分类是更加的细致的.例如:代码节,数据节.....然而段是产生在执行的时候的,因为他是将多个ELF文件按照程序头表这个指南合并产生的段段对数据的分类并没有那么的细致了,比如:可读,不可读....那么为什么需要段,不能把节使用到底吗?段的使用会使内存得到更充分的利用假设我们的代码节的内存是4097个字节,数据段是127字节这时候就会导致有的页会有很多的内存空余,但是如果用段合并的话,就会大大的减少上述的情况解决了内存的碎片化ELF形成可执行文件编译形成ELF文件(将C/C源文件编译形成目标文件.o)将目标文件进行合并下面我们先来看看静态链接的过程静态链接首先我们现在手下有很多的.o文件,这些文件共同的特点就是他们都是ELF格式的在编译链接的时候这些.o文件会把相同的节进行合并例如:将多个的代码节合并成一个得到代码节但是他是怎么知道那些节存储的是什么呢??这时候通过查找节头表和表头就可以知道各个节的起始和大小了,进行合并就可以了然后将节合并之后,然后将函数的地址进行填写objdump -d code.o运行这个指令来看一下反汇编可以看到这个函数的回调的地址是一个0,这就是因为我们的code.c文件中没有这个函数的实现,但是当把目标文件进行合并之后就会有了函数的地址了,所以就要进行函数地址的填写可以看到在我们链接之后的可执行文件函数的地址的确是完成了填写的总结一下静态链接首先编译形成一个个的目标文件,这些的目标文件都是ELF格式,然后进行链接,将每个.o文件的相同的节进行合并,将静态库中嵌入到文件中,重定向函数的地址ELF加载与进程地址空间首先ELF在加载到内存的时候他是有地址的.在链接的时候会基于平坦模式对形成的段进行编址(平坦模式就是起始地址是0),因为初始地址是0所以逻辑地址是和虚拟地址相同的,然后在Header中会存储着各个段的起始地址和长度的,并且还存储着程序的入口地址,所以在加载到内存的时候需要做的就是填写进程的mm_struct表.因为在ELF中都存有各个段的起止地址直接复制就可以.拿着程序入口地址执行程序就可以了动态链接动态链接与静态链接不同就是静态链接是在链接的时候就把函数的地址进行了重定向了,然而动态链接的函数的重定向被推迟到了程序加载的时候了.那么动态库链接的详细的过程是什么呢??首先需要确定这个程序有什么动态库吧怎么确定的呢?我们需要知道的是一个程序的入口不是main函数,而是一个_start函数在这个_start函数中为程序准备堆栈环境初始化数据段最重要的就是检查这个程序依赖的动态库有什么,然后加载动态库文件到内存中.补充:加载动态库的实质就是打开这个动态库的文件,打开文件就是我们熟悉的文件操作了也就是通过目录查找文件名和inode的映射,查找目标文件的inode,找到文件的数据段在这里就是将动态库中需要的函数和方法加载到了内存中不过我们访问库函数通过虚拟地址进 ⾏跳转访问的所以需要把动态库映射到进程的地址空间中具体就是我们通过文件操作打开了对应的库文件,加载到物理内存之后,在页表中建立映射,填写虚拟地址表,得到初始虚拟地址那么进行库函数调用程序进行到了动态库函数的部分,这时候就从代码区跳转到共享区,拿到库函数的起始虚拟地址,方法的地址偏移量和起始地址就可以找到对应的方法函数动态库为了实现随时都可以加载,采用了相对编址的方法那么现在就是这样的过程了首先在_start函数中加载需要的库函数,然后在我们的代码中函数的地址进行二次定位但是有一个问题就是代码区的数据时只读的,我们没有权限对他进行修改所以动态链接采⽤的做法是在 .data 可执⾏程序或者库⾃⼰中专⻔预留⼀⽚区域⽤来存放函数 的跳转地址它也被叫做全局偏移表GOT表中每⼀项都是本运⾏模块要引⽤的⼀个全局变量或函数 的地址。所以动态库加载的完全体就是这样的过程:首先在_程序启动的时候加载需要的库函数,然后在数据区中的GOT表中填写动态库的地址我们的代码区的结构是这样的假设我们将要调用printf函数他会给出我们在GOT表中这个方法的位置然后再加载入动态库之后把printf函数的地址填写到这个GOT表中简单的来说GOT表相当于一个目录一样再加载的时候提供方法的地址代码运行到需要库函数的时候直接查表就行了

相关新闻

终极指南:3个技巧让IINA播放器性能翻倍,告别4K卡顿

终极指南:3个技巧让IINA播放器性能翻倍,告别4K卡顿

终极指南:3个技巧让IINA播放器性能翻倍,告别4K卡顿 【免费下载链接】iina The modern video player for macOS. 项目地址: https://gitcode.com/gh_mirrors/iin/iina 还在为macOS播放器卡顿、HDR色彩失真而烦恼吗?IINA作为macOS平台最…

2026/10/2 13:59:41 阅读更多 →
第17章:复制集基础——从单机到高可用

第17章:复制集基础——从单机到高可用

1. 项目背景 业务场景:本地生活电商上线三个月,单台 MongoDB 开始力不从心。某天凌晨 2 点,服务器突然宕机——只是普通的内存故障,但因为只有一台 MongoDB,整个系统直接不可用,直到早上 8 点运维重启服务…

2026/10/6 9:59:20 阅读更多 →
G-Helper终极指南:三步释放华硕笔记本隐藏性能的免费轻量工具

G-Helper终极指南:三步释放华硕笔记本隐藏性能的免费轻量工具

G-Helper终极指南:三步释放华硕笔记本隐藏性能的免费轻量工具 【免费下载链接】g-helper Lightweight Armoury Crate alternative for Asus laptops with nearly the same functionality. Works with ROG Zephyrus, Flow, TUF, Strix, Scar, ProArt, Vivobook, Zenb…

2026/10/4 18:14:32 阅读更多 →

最新新闻

Arthas v3.7.2:Java线上诊断与字节码热修改实战指南

Arthas v3.7.2:Java线上诊断与字节码热修改实战指南

简介:Arthas v3.7.2 是一款面向Java开发者、运维工程师及计算机专业学生的开源诊断工具,专为线上Java应用的无侵入式问题定位、性能分析与热调试设计,广泛适用于毕业设计、系统软件开发、模板建站及计算机案例研究等实践场景。资源包共2000个…

2026/10/9 12:28:46 阅读更多 →
Cognex Deep Learning GPU Allocation:GPU分配机制详解

Cognex Deep Learning GPU Allocation:GPU分配机制详解

Cognex Deep Learning GPU Allocation:GPU分配机制详解大家好 这里是「代码简单说」 记录 Cognex Deep Learning 4.2 中 GPU Allocation(GPU 分配)机制,方便后续配置多 GPU 环境、训练工具以及分析 GPU 利用率时快速查阅。SEO关键…

2026/10/9 12:28:46 阅读更多 →
基于Docker的分布式爬虫服务:架构、编排与踩坑实战

基于Docker的分布式爬虫服务:架构、编排与踩坑实战

简介:一份基于Docker的分布式爬虫服务项目资料,面向Python与爬虫方向的学习者、毕业设计及课程设计使用者。资源以Go语言实现核心爬虫服务,配套Docker容器化部署方案,涵盖单机抓取、客户端调用、服务端调度等完整模块,…

2026/10/9 12:28:46 阅读更多 →
JavaWeb蛋糕店源码跑通全流程:JSP+Servlet+MySQL实战解析

JavaWeb蛋糕店源码跑通全流程:JSP+Servlet+MySQL实战解析

简介:一份基于JavaWeb的蛋糕店网站系统源码,面向计算机专业学生的课程设计、毕业设计或期末大作业场景,项目经导师指导并获得97分好评,整体完整、可直接运行。系统采用Servlet/JSP与JavaBean分层设计,覆盖商品展示、购…

2026/10/9 12:28:46 阅读更多 →
DRNN动态递归神经网络:面向工业控制的自适应时序建模

DRNN动态递归神经网络:面向工业控制的自适应时序建模

简介:本资源是一篇聚焦非线性系统智能控制的学术论文,面向自动化、控制工程及人工智能方向的研究生、科研人员与工程师,重点解决传统线性模型难以建模的复杂系统控制难题。论文提出一种融合DRNN回归神经网络与自适应PID策略的新型控制算法&am…

2026/10/9 12:28:46 阅读更多 →
全国省份城市数据库表:MySQL行政区划表设计与导入实战

全国省份城市数据库表:MySQL行政区划表设计与导入实战

简介:这份资源面向需要在中国行政区划数据上做开发的 MySQL 使用者,提供一份可直接导入的全国省份城市数据库表脚本,适合搭建地理信息系统、物流管理、人口统计分析等需要地域信息的应用场景,也适合作为学习 SQL 建表与层级数据设…

2026/10/9 12:27:45 阅读更多 →

日新闻

Java时间API实战:LocalDate、Date与ZonedDateTime的转换与避坑指南

Java时间API实战:LocalDate、Date与ZonedDateTime的转换与避坑指南

Java时间API这个话题,隔三差五就会在群里被翻出来讨论一次。上周还有个同事线上处理一个订单超时问题,排查到最后发现是ZonedDateTime序列化后时区丢了,用户在下单当天晚上看到的时间整整差了8个小时。这类问题几乎每个做Java开发的人都遇到过…

2026/10/9 0:00:49 阅读更多 →
EasyTier实践:从NAT穿透到子网代理的异地组网部署与排错

EasyTier实践:从NAT穿透到子网代理的异地组网部署与排错

前几个月我手头有好几台机器需要互相访问:办公室台式机、家里 NAS、还有一台云主机。如果只是偶尔传个文件倒还好,问题是工作场景经常要在几处环境之间来回切换,每次都先登录跳板机再层层代理,实在折腾。我先后试过端口映射、自建…

2026/10/9 0:00:49 阅读更多 →
AI Agent工程实战:从七要素到七个决策点的系统设计指南

AI Agent工程实战:从七要素到七个决策点的系统设计指南

AI Agent 这个词在过去一年里被反复提及,但真正动手搭过一套能跑起来的 Agent 系统的人都知道,从"知道它是什么"到"让它稳定干活"之间隔着一整套工程决策。我前后参与过几个 Agent 项目的落地,从最初用现成框架拼装&…

2026/10/9 0:01:50 阅读更多 →

周新闻

KT148A语音芯片外挂8002D功放的工程实践指南

KT148A语音芯片外挂8002D功放的工程实践指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/8 15:26:32 阅读更多 →
LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/8 15:26:40 阅读更多 →
ARM架构深度解析:从RISC设计理念到交叉编译实战

ARM架构深度解析:从RISC设计理念到交叉编译实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/9 10:11:06 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/8 21:13:17 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/8 15:26:17 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/9 6:17:20 阅读更多 →