程序跑起来之前,它只是个文件一串暗号:每个 ELF 的前 4 个字节64 字节的「身份证」:ELF Header三种形态:.o、可执行文件、.so 是一家两张地图:链接看节表,运行看程序头符号表:链接器的电话簿手写一个 ELF 解析器
在 Windows 上双击一个 .exe,在 Linux 上敲一个 ls,你有没有想过一个问题:这个程序在「跑起来」之前,到底是什么?答案很朴素——就是磁盘上的一堆字节。但 Linux 有个非常硬核的约定:所有能被执行的文件,都得遵守同一种格式,叫ELF(Executable and Linkable Format,可执行与可链接格式)。从最简单的 hello world 到浏览器、数据库,无一例外。
这个格式从上世纪九十年代的 Unix 体系一路沿用至今,三十多年了还在服役。看懂它,等于拿到了 Linux 程序世界的「通用说明书」——编译、链接、加载这三步是怎么串起来的,全写在文件的字节里。
ELF 的规矩从第 1 个字节就开始了:任何 ELF 文件的开头,永远是同一串十六进制7f 45 4c 46。翻译成字符,就是 E、L、F——加上最前面那个不可打印的 0x7f,合起来是「0x7fELF」。
用 xxd 随便看一个目标文件的开头:
![]()
为什么要放一个「暗号」在开头?因为内核加载程序时,第一件事就是验证身份:读前 4 个字节对不上 0x7fELF,直接拒绝执行。那个 0x7f 也有讲究——它不在任何可打印字符范围内,能防止这串魔数被当成普通文本混淆。
接下来的 16 字节叫 e_ident,是文件的「身份卡」,信息密度极高:
- • 第 4 个字节是位数:1 表示 32 位,2 表示 64 位;
- • 第 5 个字节是字节序:1 表示小端(x86 机器的标配);
- • 其余是版本、ABI 等标识。内核只看这 16 个字节,就知道该按哪套规则往下读。
魔数之后是 ELF Header,64 位系统下固定 64 字节,相当于整份文件的目录索引。用 readelf 一条命令就能把字节翻译成人话:
![]()
这 64 字节里有几个关键字段,值得单独认识一下:
![]()
e_type 字段揭示了一个有趣的事实:你平时写的 .o 目标文件、跑的可执行程序、链接的 .so 动态库,其实是同一种格式的三种形态,内核用同一个数字区分它们:
![]()
这里藏着一个当代 Linux 的细节:现在 gcc 编译出来的可执行文件,类型其实是 DYN 而不是 EXEC——这叫 PIE(位置无关可执行)。ELF Header 里能直接看到这个差别:非 PIE 程序的代码段固定从 0x400000 开始,而 PIE 程序的基址是加载时随机分配的,黑客想猜中你的函数在哪,难度陡增。ASLR 地址随机化防攻击,靠的就是这一手。
ELF 文件里其实同时存在两套「地图」,服务两个完全不同的阶段:
![]()
最好玩的是 .bss 段:它专门装那些「声明了但没赋初值」的全局变量。这些变量全都是零,所以在文件里一个字节都不占——ELF 只记录「运行时需要 4 字节清零空间」,真正的空间由内核在加载时分配并填零。文件更小,加载更快,这就是格式的精明之处。
那链接器怎么知道「add 函数」在哪个文件里?靠符号表——一张「名字 → 地址」的映射表。用 objdump 查看:
![]()
每一行的含义一目了然:g 表示全局符号,F 是函数、O 是对象(变量),后面跟着所在节、大小。编译器只负责在调用别人的函数处「留个坑」,写上「此处要跳去 add,地址待定」;链接器拿着符号表查电话簿,把这些坑一个个填上——这个过程叫重定位,是链接的全部意义。
理解格式最好的办法是自己动手拆一遍。核心思路就一句话:按字段表用 struct 逐字节解包。十几行 Python 就能把 ELF Header 和节表读出来:
![]()
跑在一个真实目标文件上,输出和 readelf 对照完全一致——节表里能看到 .text、.data、.bss 各自的位置和大小,.bss 的类型是 NOBITS,文件里确实没有它的内容。到这一步,「读懂每一字节」就不再是修辞了。
回头看,ELF 其实就干了一件事:把「程序怎么从源码变成进程」这件事,用一种几十年来不变的字节布局固化下来。魔数负责验明正身,Header 负责当目录,节和段分别服务链接与加载,符号表串起整个拼装过程。下次在 Linux 上跑任何一个程序,不妨随手 readelf 一下——那串熟悉的 7f 45 4c 46,就是整个用户态世界的开场白。
你用 readelf / objdump 排查过什么灵异问题?或者第一次见到 0x7fELF 是在什么场景?评论区聊聊~
特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。
Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.