XV6

ELF 格式的文件支持编译链接。编译输出的 ELF 文件称为目标文件,主要利用其中的 “节” 来组织管理内部的代码和数据,而链接后输出的可执行 ELF 文件主要利用其中的 “段” 的信息来组织。

ELF 格式内容主要用在可执行文件装入内存的过程中,并不影响对 XV6 其他环节的学习。 读者也可以先跳过这里的内容,继续学习启动过程的其他环节。

1. 涉及 ELF 的代码

bootblock 载入 kernel 时、执行磁盘上的可执行文件时的 exec() 系统调用,都会涉及 ELF 文件格式。由于我们只装载 ELF 可执行文件而不关心其生成过程,因此只关注其 ELF 程序头表及其所描述的段(完全不用处理里面的节)。

1.1 elf.h

elf.h 文件中,定义了 ELF 可执行文件的文件头(file header)和程序头(program section header)。 其中文件头是 ELF 文件整体性的信息,由 elfhdr 结构体所描述。elfhdr->entry 是程序入口地址,对于 kernel 的 ELF 文件而言,该入口地址被链接器脚本 kernel.ld 设置为 _start 符号,对应 0x10000cbootblock 最后就是通过它进入到 kernel 代码的。

文件头将通过 elfhdr->phoff 指出程序头表的位置。程序头表则跟程序装入有关, 所有的 ELF 段使用程序头表管理,其类型为 LOAD 段需要装入内存。每个程序头表中的一个项描述了一个段,对应一个 proghdr 结构体。将 kernel 的 LOAD 类型段装入内存,就是使用了对应的程序头表项的信息,段装入时的段的大小和偏移就是来源于 proghdr 结构体的 fileszoff 成员。

由于程序装入运行并不需要了解 “节” 的概念(节是编译链接环节的概念),因此 XV6 对节头表并不感兴趣。