ELF格式解析
看《操作系统真相还原》一书,觉得需要好好学习一下elf结构,光看书上的例子还是有隔岸观火的感觉,还是要亲眼见证一下,眼见为实才对。
生成elf可执行文件:
在ubuntu下创建一个简单的.c,gcc编译链接成可执行文件,好好学习一下。
一个无限的while循环:
使用 gcc -static test.c -o test.elf命令生成可执行文件(不加static,gcc test.c -o test.elf的话生成的不是可执行文件!)
将生成的test.elf可执行文件拖入Hexeditor,查看二进制编码:
ELF整体结构header解析:
(1)header结构:
不过在文件中实际看到的header结构与上面这段结构体中的顺序不一样,可能是硬件平台的原因,上面的header结构是针对32位linux平台?具体的位置在下图中做了标注。
e_type为02,表示可执行代码段;e_machine为3E,表示Advanced Micro Devices X86-64(readelf -e命令查看)。
比较重要的是e_entry,也就是程序的入口地址为0x400A30。
用objdump反汇编查看一下0x400A30处是什么:
在编译的过程中将0x400a30编译为了程序的入口虚拟地址,并写在了header的e_entry字段中。
program header(程序头表):
《操作系统真相还原》中提到了一个有意思的情况,就是第一个程序头表在文件的起始offset为0,这里看的确是。这是什么意思?offset为0的地方难道不是elf header吗?
在《真相还原》一书中,作者做了下验证,我也重复了一下。
思路就是按照给出的数据计算e_entry在文件中的偏移量,因为段在文件中的偏移量为0,所以e_entry在文件中的偏移量就是在段中的偏移量。
e_entry在段中的偏移 = e_entry(0x400A30) - p_vaddr(p_vaddr = 0x400000)(段起始虚拟地址) 。
=0xA30 2608个字节(10进制)
接下来去查看在段中偏移2608个字节的数据。
和反汇编文件的对比可以看到偏移offset=2608处的二进制代码和<_start>
处的代码相同,说明是e_entry的代码数据,说明offset = 0没有错。
但有一点不明白,第一个程序段在文件中的偏移为什么要设为0呢?明明前面有elf header和program header啊,所以怎么也得是size(elf header) + size(program header) * e_phnum…可能是硬性规定?
暂时不纠结了。
动态段和栈段的留待之后补充