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文件和库链接,但并不会直接拷贝库

相关推荐
xingyuzhisuan2 小时前
网络 Token 常见故障原理,基础排查科普
运维·服务器·网络·php
APIshop3 小时前
Python 获取 1688 商品采集 API 接口 | 工厂货源自动化对接商品信息 | 无需选品
运维·python·自动化
wljy13 小时前
二、进制状态转换
linux·运维·服务器·c语言·c++
handler013 小时前
【MySQL】常用命令总结(库与表增删查改)
运维·数据库·mysql·命令·总结
week@eight3 小时前
Linux - Doris
linux·运维·数据库·mysql
平行云4 小时前
实时云渲染预启动技术解析:UE数字孪生应用的延迟优化机制(二)
linux·unity·ue5·webgl·实时云渲染·云桌面·像素流
看到代码头都是大的4 小时前
CentOS环境下手动升级openssl、openssh
linux·运维·centos
浮生若城4 小时前
Linux——Ext系列文件系统
linux·运维·服务器
ITyunwei09874 小时前
主流 SaaS 工单系统对比
运维·服务器·人工智能
weixin_548444265 小时前
爆红处理APK 自动化编译流水线 v2026(英文名:APK AutoPipeline)
运维·自动化