// read the 1st page off disk,读取内核elf文件的头部出来,这个地方只是读取了4KB
readseg((uintptr_t)ELFHDR, SECTSIZE * 8, 0);
我们查看一下制作内核的时候的文件是多大
dd if=bin/kernel of=bin/ucore.img seek=1 conv=notrunc
真实的文件大小差不多在29K左右
sgy@ubuntu:~/workspace/ucore_step_by_myself$ ls bin/kernel -lh
-rwxrwxr-x 1 sgy sgy 29K Apr 17 15:00 bin/kernel
所以真正读取的数据是在下面的这几行代码。
struct proghdr *ph, *eph;
// load each program segment (ignores ph flags)
ph = (struct proghdr *)((uintptr_t)ELFHDR + ELFHDR->e_phoff);
eph = ph + ELFHDR->e_phnum;
for (; ph < eph; ph ++) {
readseg(ph->p_va & 0xFFFFFF, ph->p_memsz, ph->p_offset);
}
// call the entry point from the ELF header
// note: does not return
((void (*)(void))(ELFHDR->e_entry & 0xFFFFFF))();
这几行代码什么意思,需要讲一下elf文件的格式。
程序员的自我修养—链接、装载与库.pdf-P94
ELF文件格式详解.pdf
elf文件的最开始是文件头。
elf文件中很重要的一个概念是段表,section header table
那么怎么来查看elf文件的头部呢?
readelf -h bin/kernel
sgy@ubuntu:~/workspace/ucore_step_by_myself$ readelf -h bin/kernel
ELF Header:
Magic: 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00
Class: ELF32
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: EXEC (Executable file)
Machine: Intel 80386
Version: 0x1
Entry point address: 0x100000
Start of program headers: 52 (bytes into file)
Start of section headers: 26828 (bytes into file)
Flags: 0x0
Size of this header: 52 (bytes)
Size of program headers: 32 (bytes)
Number of program headers: 3
Size of section headers: 40 (bytes)
Number of section headers: 16
Section header string table index: 13
sgy@ubuntu:~/workspace/ucore_step_by_myself$
对照elf文件头结构体的代码实现一起看会清晰一点
/* file header */
struct elfhdr {
uint32_t e_magic; // must equal ELF_MAGIC
uint8_t e_elf[12];
uint16_t e_type; // 1=relocatable, 2=executable, 3=shared object, 4=core image
uint16_t e_machine; // 3=x86, 4=68K, etc.
uint32_t e_version; // file version, always 1
uint32_t e_entry; // entry point if executable
uint32_t e_phoff; // file position of program header or 0
uint32_t e_shoff; // file position of section header or 0
uint32_t e_flags; // architecture-specific flags, usually 0
uint16_t e_ehsize; // size of this elf header
uint16_t e_phentsize; // size of an entry in program header
uint16_t e_phnum; // number of entries in program header or 0
uint16_t e_shentsize; // size of an entry in section header
uint16_t e_shnum; // number of entries in section header or 0
uint16_t e_shstrndx; // section number that contains section name strings
};
其中我感觉比较重要的几个变量
e_entry
程序的入口地址,操作系统在加载完elf可执行程序之后从这个地址开始执行指令。对应下面这个值
Entry point address: 0x100000
e_shoff
就是前面说的很重要的结构,段表。
Start of section headers: 26828 (bytes into file)---0x68cc