ELF 格式的文件支持编译链接。编译输出的 ELF 文件称为目标文件,主要利用其中的 “节” 来组织管理内部的代码和数据,而链接后输出的可执行 ELF 文件主要利用其中的 “段” 的信息来组织。
ELF 格式内容主要用在可执行文件装入内存的过程中,并不影响对 XV6 其他环节的学习。 读者也可以先跳过这里的内容,继续学习启动过程的其他环节。
在 bootblock
载入 kernel 时、执行磁盘上的可执行文件时的 exec() 系统调用,都会涉及 ELF 文件格式。由于我们只装载 ELF 可执行文件而不关心其生成过程,因此只关注其 ELF 程序头表及其所描述的段(完全不用处理里面的节)。
在 elf.h 文件中,定义了 ELF 可执行文件的文件头(file header)和程序头(program section header)。 其中文件头是 ELF 文件整体性的信息,由 elfhdr 结构体所描述。elfhdr->entry 是程序入口地址,对于 kernel 的 ELF 文件而言,该入口地址被链接器脚本 kernel.ld
设置为 _start
符号,对应 0x10000c
。bootblock
最后就是通过它进入到 kernel 代码的。
文件头将通过 elfhdr->phoff 指出程序头表的位置。程序头表则跟程序装入有关, 所有的 ELF 段使用程序头表管理,其类型为 LOAD 段需要装入内存。每个程序头表中的一个项描述了一个段,对应一个 proghdr 结构体。将 kernel 的 LOAD 类型段装入内存,就是使用了对应的程序头表项的信息,段装入时的段的大小和偏移就是来源于 proghdr
结构体的 filesz
、off
成员。
由于程序装入运行并不需要了解 “节” 的概念(节是编译链接环节的概念),因此 XV6 对节头表并不感兴趣。