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

相关推荐
执笔仗剑天涯2 小时前
CentOS 7上离线安装Claude Code
linux·centos·claude code
南境十里·墨染春水2 小时前
linux学习进展 mysql数据库
linux·数据库·学习
liuluyang5302 小时前
linux kernel CONFIG_FHANDLE解析
linux·运维·服务器
2601_958320573 小时前
【详细版教程】Windows/macOS/Linux 安装 OpenClaw 2.6.6 指南(包含安装包)
linux·运维·windows·macos·小龙虾·open claw一键安装
霜落花轻扬3 小时前
在 Rails 中指定端口和 IP 地址
服务器·ruby on rails
HackTwoHub3 小时前
可视化未授权访问批量探测工具、支持批量目标、并发扫描、SOCKS5 全局代理、CSV 导出
linux·windows·macos·网络安全·网络攻击模型
一只专注api接口开发的技术猿3 小时前
京东商品实时监控选品实战:用 Open Claw API 快速搭建自动化工具
运维·数据库·自动化
ACP广源盛139246256733 小时前
磐石 100 :IX6012 :ASM1812@ACP#国产 PCIe 2.0 交换芯片,轻量级算力扩展应用分享
大数据·linux·运维·网络·人工智能·嵌入式硬件·电脑
H Journey3 小时前
网络编程:服务器监听+非阻塞设置
服务器·网络·服务器监听+非阻塞设置