ELF文件 && 链接与加载

在上一篇文章中,我们学习了动静态库的制作和使用,但在制作和使用的背后,更重要的

是如何理解这个过程,究竟是如何完成的呢?

ELF文件:

要理解编译链链接的细节,我们不得不了解⼀下ELF⽂件。其实有以下四种⽂件其实都是ELF⽂件:
• 可重定位⽂件(Relocatable File) :即 xxx.o ⽂件。包含适合于与其他⽬标⽂件链接来创
建可执⾏⽂件或者共享⽬标⽂件的代码和数据。
• 可执⾏⽂件(Executable File) :即可执⾏程序。
• 共享⽬标⽂件(Shared Object File) :即 xxx.so⽂件。
• 内核转储(core dumps) ,存放当前进程的执⾏上下⽂,⽤于dump信号触发。
⼀个ELF⽂件由以下四部分组成:
• ELF头(ELF header) :描述⽂件的主要特性。其位于⽂件的开始位置,它的主要⽬的是定位⽂
件的其他部分。
• 程序头表(Program header table) :列举了所有有效的段(segments)和他们的属性。表⾥
记着每个段的开始的位置和位移(offset)、⻓度,毕竟这些段,都是紧密的放在⼆进制⽂件中,
需要段表的描述信息,才能把他们每个段分割开。
• 节头表(Section header table) :包含对节(sections)的描述。
• 节(Section ):ELF⽂件中的基本组成单位,包含了特定类型的数据。ELF⽂件的各种信息和
数据都存储在不同的节中,如代码节存储了可执⾏代码,数据节存储了全局变量和静态数据等。
不难看出,ELF文件拥有规定好的格式,而这个格式也就奠定了ELF文件可以被不同文件链接的本质了。

ELFheader

描述⽂件的主要特性。其位于⽂件的开始位置,它的主要⽬的是定位⽂件的其他部分。

Section

ELF⽂件中的基本组成单位,包含了特定类型的数据。不同类型的数据存放在不同的节中

Program Header Table(PHT)

给操作系统看,按照"段(Segment)"管理,决定如何把文件映射到内存中。

段:

• ⼀个ELF会有多种不同的Section,在加载到内存的时候,也会进⾏Section合并,形成segment
• 合并原则:相同属性,⽐如:可读,可写,可执⾏,需要加载时申请空间等.
• 这样,即便是不同的Section,在加载到内存中,可能会以segment的形式,加载到⼀起
• 很显然,这个合并⼯作也已经在形成 ELF 的时候,合并⽅式已经确定了,具体合并原则被记录在
了 ELF 的 程序头表(Program header table) 中

段由多个Section组成,将权限相同的节统一组织起来。

  1. ELF文件中只有节,没有段

  2. 段只是节的一种表现形式,将权限相同的节统一组织起来

  3. 节的大小不一,但权限有相同

以上,我们就把ELF文件的本质理解清楚了,接下来我们将去探究链接与加载的过程。

链接:

静态链接:

静态链接的本质是拷贝,会直接将方法拷贝进来

链接过程的本质,实际上就是找到目标函数地址的过程:

静态链接则在链接完成后就确定了每个函数的地址,并且不会改变

动态链接:

动态链接和静态链接一样,也是在同一个虚拟地址空间中实现的,只不过动态链接是将函数映射到虚拟地址空间的共享区中:

为什么将链接推迟到加载时?

因为多个进程可能会共用同一个库,所以为了高效利用资源,避免重复加载,就将链接过程推迟到了加载进行

加载:

什么是加载?简单来说,加载就是 OS 上的加载器(Loader) **把磁盘上的可执行程序读取到内存中,再为这个程序做好环境 ,终止能使CPU运行**

所以:

  1. 创建一个进程,是先创建进程相关的数据结构,还是先加载ELF文件格式的二进制文件?

  2. 程序在没有被加载到内存中时,程序是否拥有自己的地址?

1:一定是先要创建相关的数据结构(PCB + 页表)再加载二进制文件

2:程序在加载到内存之前就拥有地址:

其地址的分配在 gcc xxx.c -o xxx 时就完成了地址分配,也就是在"编译和链接"时。

接下来我将用一张图完整地给大家演示加载的过程,可能有点难以读图

CPU在寻址时,100% 是通过CR3寄存器寻址的。

综上,在整个加载形成虚拟地址空间的过程中,不仅仅有 OS 的参与,编译器(ELF文件)也要参与此过程

动态库加载:

动态链接:编译链接阶段,库函数的真实虚拟地址是不确定的、是空坑;

只有到程序加载运行那一刻,把 .so 映射进虚拟地址共享区,才把函数真实虚拟地址填好,才能正常调用。也就是说,动态链接的地址是可修改的,将0x00占位地址修改为真实的有效地址

结语:

恭喜你,学到这里就基本掌握了ELF文件的知识并且深刻理解了动静态链接和加载的过程,对了,链接过程一定是在加载之前进行的,静态链接:将所以的.o文件和库链接,此时会将库直接拷贝;动态链接:也会将所有的.o文件和库链接,但并不会直接拷贝库

相关推荐
第404号工位1 小时前
40块钱二手瘦客户端,如何跑满家庭物联网中枢?(拒绝Docker爆盘实录)
linux·架构·node.js
对象存储与RustFS1 小时前
网盘限速逼你开会员?用 RustFS 自己搭一个不限速的“私人网盘
服务器·后端·docker
骑着蜗牛撵大象3272 小时前
Linux 进程间通信之管道:从 pipe() 的内核语义到 FIFO 落地排错
android·java·linux·系统编程·fifo·管道·进程间通信
众壹新能源科技3 小时前
逆变器自带无功不够用,加装5MVar SVG后功率因数从0.85回到0.99
运维·人工智能·自动化
..Dauntless..3 小时前
【Linux】一切皆文件和缓冲区
linux·运维·服务器
裕晟资质规划3 小时前
三类资质变更报告时限差在哪?军工 15 日、集成印制 10 日
大数据·服务器·网络
QMCY_jason3 小时前
x86 ubuntu2204 无gui 安装 openeuler 2203 aarch64版本
linux·运维·服务器
重生之小比特3 小时前
【Linux系统】12 进程程序替换 自定义Shell 命令行解释器
linux·运维·服务器
轻舟技术A3 小时前
Provider 不属于 Agent 核心:rpi 的分层理由与收益
服务器·网络
考拉讲支付3 小时前
母婴亲子服务平台分账架构设计:多场景多方分账与合规清结算实践
大数据·运维·人工智能·微信小程序·架构·微信公众平台