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

相关推荐
大树8813 小时前
金刚石散热越强,管路越先见顶
大数据·运维·服务器·人工智能·ai
摇滚侠13 小时前
Linux CentOS7 rpm 安装 MySQL 5.7
linux·运维·mysql
霸道流氓气质14 小时前
领域驱动设计(DDD)在 Spring Boot 微服务中的实践指南
运维·spring boot·微服务
bush414 小时前
嵌入式linux学习记录十四、术语
linux·嵌入式
载数而行52014 小时前
Linux 11 动态监控指令top
linux
小宇宙Zz14 小时前
Maven依赖冲突
java·服务器·maven
Inhand陈工15 小时前
基于台达PLC与映翰通IG502的智慧水产养殖精准投喂与远程运维解决方案
运维·人工智能·物联网·阿里云·信息与通信
酣大智15 小时前
ARP代理--工作原理
运维·网络·arp·arp代理
不会C语言的男孩15 小时前
Linux 系统编程 · 第 8 章:进程基础
linux·c语言
shushangyun_15 小时前
2026年快消品B2B系统推荐:支持终端门店订货、促销政策自动化的工具?
java·运维·网络·数据库·人工智能·spring·自动化