可以使用如下命令观看 elf 文件的信息
readelf -a build/ramdisk.img | vim -
在编写 elf loader 的时候,实际上只有下图这一部分 “Program Headers” 是有用的
凡是类型为 “LOAD” 的就是需要加载进内存的部分
所以,只要把这些部分加载进内存里,再跳转到 entrypoint 就完事了,是不是很容易啊?
如下,使用 PA3 中的 elf loader 代码:
static uintptr_t loader(PCB *pcb, const char *filename) {
// 1. read program from ramdisk to mem -- invoke ramdisk_read()
// 2. execute the program -- return the entryextern size_t ramdisk_read(void *buf, size_t offset, size_t len);Elf_Ehdr elfheader;// 从磁盘/elf文件中读取 elf 头,这部分元数据放在 elf 文件的头部ramdisk_read(&elfheader, 0, sizeof(Elf_Ehdr));// 检查这个 elf 文件针对的机器架构是否是我们这种架构assert(elfheader.e_machine == EXPECT_TYPE);// 检查 elf 魔数assert(*(uint64_t *)(elfheader.e_ident) == 0x00010102464c457f);// Elf_Phdr 的格式和大小刚好是 ELF Program Headers 中的一节 Elf_Phdr program_header;// 从磁盘/elf文件中 读取第一个 program_headerramdisk_read(&program_header, elfheader.e_phoff, sizeof(Elf_Phdr));// 进入循环,这个循环会遍历所有的 program_headerfor(int i = 1; i < elfheader.e_phnum; i++) {// 如果当前这节 program_header 的类型是 LOAD,那么把它装载进内存// 然后再把 program_header.memsize - program_header.filesize 这部分清零if(program_header.p_type == PT_LOAD) {ramdisk_read((void *)(program_header.p_vaddr), program_header.p_offset, program_header.p_filesz);memset((uint8_t *)(program_header.p_vaddr) + program_header.p_filesz, 0, program_header.p_memsz - program_header.p_filesz);}// 从磁盘/elf文件中 读取下一个 program_headerramdisk_read(&program_header, elfheader.e_phoff + i * elfheader.e_phentsize, sizeof(Elf_Phdr));}// 返回程序入点return elfheader.e_entry;
}