【云计算摩尔狮】Linux 开发者必知:从 ELF 文件入手,看懂程序执行的底层逻辑

390 阅读13分钟

在 Linux 的世界里,程序的运行背后隐藏着许多神秘的机制。其中,ELF 文件格式扮演着至关重要的角色,它如同一个 “魔法盒子”,承载着程序从代码到可执行实体的关键信息。今天,就让我们一起深入探索 ELF 文件的奥秘,在五分钟内彻底搞懂它! 一、ELF 究竟是什么? ELF,即 Executable and Linkable Format(可执行与可链接格式) ,是 Linux 系统下用于表示可执行文件、目标文件和共享库等的标准文件格式。它就像是 Linux 世界里程序的 “灵魂容器”,包含了代码、数据以及程序运行所需的各种元信息 。简单来说,ELF 是 Linux 下的可执行文件格式,类似于 Windows 下的.exe,但 ELF 远比.exe 复杂且强大。

ELF 文件主要分为以下几种类型:

可执行文件:例如我们日常使用的各种命令行工具,像ls、cp等,它们包含了可以直接在系统上运行的机器指令。 目标文件:在编译过程中生成的.o文件,包含了尚未链接的代码和数据,可与其他目标文件合并生成可执行文件或共享目标文件。 共享库文件:也就是.so文件,类似于 Windows 下的.dll,多个程序可以共享同一个共享库,减少内存占用,提高代码复用性。 核心转储文件:当程序异常崩溃时生成的 core dump 文件,用于调试和分析程序崩溃的原因 。 本质上,ELF 就是一个按照特定格式组织起来的容器,里面装着程序运行所需的一切。

二、初见 ELF:快速识别 如何快速判断一个文件是否为 ELF 格式呢?很简单,使用file命令 。例如,查看/bin/ls文件:

$ file /bin/ls

/bin/ls: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.32, BuildID(sha1)=c8ada1f7095f6b2bb7ddc848e088c2d615c3743e, stripped

只要输出信息的开头是 “ELF”,那就说明它是 ELF 格式的文件。

再进一步,我们可以查看 ELF 文件的前几个字节,使用hexdump命令:

$ hexdump -C -n 16 /bin/ls

00000000 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 |.ELF............|

00000010

这里开头的7f 45 4c 46就是 ELF 文件的 “魔数”(Magic Number) 。其中45 4c 46对应 ASCII 码中的 “ELF” 三个字母,前面的7f是一个特殊字符。这四个字节就像是 ELF 文件的 “身份证”,操作系统在加载文件时,首先会检查这四个字节,以确认它是否为 ELF 文件。

三、ELF 文件的内部结构:化繁为简 ELF 文件的内部结构较为复杂,但我们可以通过一个简单的类比来理解 。把 ELF 文件想象成一本 “程序说明书”,它主要由以下三部分组成:

文件头(ELF Header):相当于书的封面和目录,包含了文件的基本信息,如文件类型、目标机器架构、ELF 版本等,以及指向其他重要部分的指针 。它告诉我们这本书有什么内容,该怎么去阅读它。 程序头表(Program Header Table):可以看作是给 “阅读器”(操作系统)看的指南,描述了可执行文件或共享库如何在内存中创建进程映像,也就是告诉操作系统如何把这本书变成一个可以运行的程序 。 节区头表(Section Header Table):类似于给 “编辑器”(链接器、调试器)看的指南,包含了文件中各个节区(Sections)的详细信息,如节区的名称、类型、在文件中的偏移、节区的大小等,帮助链接器和调试器理解这本书的内部结构 。 而书的主体内容就是各种节区(Sections)或段(Segments),里面装着代码、数据等实际内容 。用图表示如下:

+------------------+

| ELF Header | <-- 文件开始处的标识信息和总体布局

+------------------+

| 程序头表 | <-- 告诉操作系统如何加载

| Program Header 1 |

| Program Header 2 |

| ... |

+------------------+

| Section 1 | <-- 实际内容,如代码、数据等

| Section 2 |

| ... |

+------------------+

| 节区头表 | <-- 描述每个Section的信息

| Section Header 1 |

| Section Header 2 |

| ... |

+------------------+

这里可能会有人问:什么是节区(Section)?什么又是段(Segment)?它们有什么区别?

简单来说,节区(Section)是 ELF 文件存储的基本单位,主要用于链接过程;而段(Segment)是运行时内存的基本单位,主要用于加载过程 。一个段通常包含多个功能相似的节区,比如,所有包含代码的节区会被归入到一个叫做 “TEXT” 的段中。

四、深入解剖 ELF 文件:逐层剥开 (一)ELF 头(ELF Header) ELF 头是整个文件的 “门面”,包含了文件的基本信息和指向其他部分的指针 。我们可以使用readelf -h命令来查看 ELF 头的详细信息 。例如,查看/bin/ls的 ELF 头:

$ readelf -h /bin/ls

ELF Header:

Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00

Class: ELF64

Data: 2's complement, little endian

Version: 1 (current)

OS/ABI: UNIX - System V

ABI Version: 0

Type: EXEC (Executable file)

Machine: Advanced Micro Devices X86-64

Version: 0x1

Entry point address: 0x4006a0

Start of program headers: 64 (bytes into file)

Start of section headers: 5288 (bytes into file)

Flags: 0x0

Size of this header: 64 (bytes)

Size of program headers: 56 (bytes)

Number of program headers: 9

Size of section headers: 64 (bytes)

Number of section headers: 30

Section header string table index: 27

这里面最重要的信息包括:

Entry point address:程序执行的入口点地址,也就是程序开始执行的地方。 Start of program headers:程序头表在文件中的位置。 Start of section headers:节区头表在文件中的位置。 (二)程序头表(Program Header Table) 程序头表告诉操作系统如何创建进程映像,我们可以使用readelf -l命令来查看 。继续以/bin/ls为例:

$ readelf -l /bin/ls

Elf file type is EXEC (Executable file)

Entry point 0x4006a0

There are 9 program headers, starting at offset 64

Program Headers:

Type Offset VirtAddr PhysAddr

FileSiz MemSiz Flags Align

PHDR 0x0000000000000040 0x0000000000400040 0x0000000000400040

0x00000000000001f8 0x00000000000001f8 R 8

INTERP 0x0000000000000238 0x0000000000400238 0x0000000000400238

0x000000000000001c 0x000000000000001c R 1

[Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]

LOAD 0x0000000000000000 0x0000000000400000 0x0000000000400000

0x0000000000087868 0x0000000000087868 R E 200000

LOAD 0x00000000000e9000 0x00000000006e9000 0x00000000006e9000

0x0000000000019808 0x000000000001a440 RW 200000

DYNAMIC 0x00000000000ea288 0x00000000006ea288 0x00000000006ea288

0x0000000000000210 0x0000000000000210 RW 8

NOTE 0x0000000000000254 0x0000000000400254 0x0000000000400254

0x0000000000000044 0x0000000000000044 R 4

GNU_EH_FRAME 0x000000000007d294 0x000000000047d294 0x000000000047d294

0x0000000000008044 0x0000000000008044 R 4

GNU_STACK 0x0000000000000000 0x0000000000000000 0x0000000000000000

0x0000000000000000 0x0000000000000000 RW 10

GNU_RELRO 0x00000000000e9000 0x00000000006e9000 0x00000000006e9000

0x0000000000001000 0x0000000000001000 R 1

在程序头表中,最重要的是那些类型为LOAD的段,它们会被加载到内存中 。注意看Flags字段:

R表示可读(Read) W表示可写(Write) E表示可执行(Execute) 这些权限在 ELF 文件里就已经定义好了,这也就解释了为什么在内存中有的区域可执行,有的区域只能读不能写 。

(三)节区头表(Section Header Table) 节区头表描述了文件中各个节区的信息,使用readelf -S命令查看 。同样以/bin/ls为例:

$ readelf -S /bin/ls

There are 30 section headers, starting at offset 0x1428:

Section Headers:

[Nr] Name Type Address Offset

Size EntSize Flags Link Info Align

[ 0] NULL 0000000000000000 00000000

0000000000000000 0000000000000000 0 0 0

[ 1] .interp PROGBITS 0000000000400238 0x00000238

000000000000001c 0x0000000000000000 A 0 0 1

[ 2] .note.ABI-tag NOTE 0000000000400254 0x00000254

0000000000000020 0x0000000000000000 A 0 0 4

[ 3] .note.gnu.build - id NOTE 0000000000400274 0x00000274

0000000000000024 0x0000000000000000 A 0 0 4

[ 4] .gnu.hash GNU_HASH 00000000004002a0 0x000002a0

0000000000005520 0x0000000000000000 A 5 0 8

[ 5] .dynsym DYNSYM 00000000004057c0 0x000057c0

0000000000016c18 0x0000000000000018 A 6 1 8

[ 6] .dynstr STRTAB 000000000041c3dc 0x0000c3dc

000000000000c98a 0x0000000000000000 A 0 0 1

[ 7] .g

每日课堂Top1-课程大纲:

Linux 系统管理 -Kubernetes 课程大纲 课程内容 (一)Kubernetes 基础(6 学时) Kubernetes 简介 Kubernetes 起源与发展,为何成为容器编排领域的事实标准。 Kubernetes 解决的容器化应用管理痛点,如应用部署、扩展、自愈等。 Kubernetes 核心概念 Pod:最小部署单元,理解 Pod 中容器共享网络与存储命名空间,多容器协同工作场景。 Service:服务抽象,ClusterIP、NodePort、LoadBalancer 等类型,服务发现与负载均衡原理。 Deployment:无状态应用部署控制器,滚动升级、回滚机制。 ReplicaSet:确保指定数量 Pod 副本运行,与 Deployment 关系。 StatefulSet:有状态应用部署控制器,Pod 的顺序性与唯一性。 DaemonSet:保证每个 Node 运行一个 Pod 副本,适用于日志收集、监控代理等场景。 Job 与 CronJob:一次性任务与定时任务管理。 Namespace:资源隔离,多租户环境下的应用场景。 Label 与 Selector:资源分组与筛选机制,用于灵活管理资源。 实践操作 使用 kubectl 命令行工具创建、查看、删除各类资源对象。 通过 yaml 文件定义并部署简单的 Pod、Service、Deployment。 (二)Kubernetes 架构与组件(6 学时) Kubernetes 架构剖析 Master - Node 架构模型,Master 节点与 Node 节点的职责分工。 控制平面与数据平面的概念与功能。 Master 组件详解 kube - apiserver:API 服务入口,提供 RESTful 接口用于资源操作,认证、授权与准入控制机制。 kube - controller - manager:集群状态维护核心,包含多种控制器(如节点控制器、副本控制器等)及其工作原理。 kube - scheduler:资源调度器,调度算法(如资源优先级、亲和性与反亲和性等)与调度流程。 etcd:分布式键值存储,保存集群状态数据,数据一致性与高可用性保障。 Node 组件详解 kubelet:Node 节点上的代理,负责管理容器生命周期,与 Master 通信汇报节点状态。 kube - proxy:实现 Service 的网络代理与负载均衡,通过 iptables 或 ipvs 规则实现。 容器运行时(如 Docker):负责镜像拉取、容器创建与运行。 实践操作 分析 Kubernetes 集群架构拓扑,理解各组件间通信流程。 模拟部分组件故障,观察集群自愈机制。

摩尔狮机构背景:

传知成立于 2006 年,深耕 ICT 职业教育领域十七载,始终以 “传播知识·成就未来” 为使命,持续探索教材教法创新与教学资源整合,通过自主研发的数字化学习服务平台,系统性推动数字化人才的能力进阶与职业发展。

「摩尔狮」是其旗下 2C 教育品牌,作为阿里云认证 TOP 级战略合作伙伴,聚焦AI云计算、云原生、云架构等高潜力技术领域,构建了覆盖 “学习 — 认证 — 就业” 全链路的实战型课程体系,每年为阿里云生态企业赋能及输送5000+的专业人才,是国内最具影响力的AI云计算人才服务生态圈之一。

想打破失业壁垒,斩获高薪 offer?摩尔狮教育用实力说话!联合行业头部企业定制课程,一线大厂讲师亲授实战经验,小班教学 + 一对一辅导精准提升。从课程研发到就业全流程护航,简历优化、模拟面试、企业内推一站式服务,无数专科生在此逆袭,成功入职名企拿下高薪。靠谱教育,值得信赖,摩尔狮教育,助你开启职业新征程! 找靠谱教育机构,就选摩尔狮!课程由行业头部企业联研,紧跟市场需求,所学即企业所需;一线大厂讲师亲自授课,实战经验倾囊相授。从课程学习到就业指导全程护航,用无数学员高薪就业的成果,证明其超高可信度,助你无忧提升技能、开启理想职业道路!