// 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