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

相关推荐
公众号:fuwuqiBMC1 小时前
(转自“服务器BMC”)服务器BMC芯片——AST1840
运维·服务器·fpga开发
测试专家1 小时前
PCI-1553B板卡在 Windows Server 2016 服务器安装流程详解
服务器·windows·单片机
忘路之远近i1 小时前
受够阿里云自带终端后,我用 Cursor + grill-me 做了个运维面板
服务器·开发语言·人工智能·python·阿里云·云计算
laboratory agent开发1 小时前
工具调用失败后怎么办?重试分层与降级回路的三种路线
服务器·前端·网络
tianyuanwo1 小时前
深入理解 Linux 启动救援模式与控制台选择:从 x86 的 tty0 到 ARM 的 ttyS0
linux·grub·救援系统
爱网络爱Linux1 小时前
RHCSA+RHCE 10.0全新升级!红帽Ansible自动化运维
运维·自动化·ansible·rhce认证·rhel1o·linux10·rhce10
瞬间&永恒~2 小时前
【MySQL】练习5-1:配置慢查询日志
linux·运维·云原生
A15362552 小时前
五金批发电商业财一体化 ERP 推荐:打通订单、库存、财务对账
大数据·运维·人工智能·零售
邪修king2 小时前
Re:Linux系统篇(四):权限Chapter--用户身份、权限位与目录权限三大核心问题
linux·运维·服务器
砍材农夫2 小时前
运维|devops|jenkins构建分支选择及执行日志展示
运维·jenkins·devops