diff options
Diffstat (limited to 'src/user')
-rw-r--r-- | src/user/lib/elfload.c | 28 |
1 files changed, 20 insertions, 8 deletions
diff --git a/src/user/lib/elfload.c b/src/user/lib/elfload.c index 67cef68..deb7b44 100644 --- a/src/user/lib/elfload.c +++ b/src/user/lib/elfload.c @@ -26,14 +26,15 @@ static bool valid_ehdr(const struct Elf64_Ehdr *h) { && h->e_ident[1] == 'E' && h->e_ident[2] == 'L' && h->e_ident[3] == 'F' - && h->e_type == ET_EXEC && h->e_machine == EM_X86_64 && h->e_version == 1; } -static bool load_phdr(const void *base, size_t idx) { - const struct Elf64_Ehdr *ehdr = base; - const struct Elf64_Phdr *phdr = base + ehdr->e_phoff + idx * ehdr->e_phentsize; +static bool load_phdr(const void *elf, void *exebase, size_t idx) { + const struct Elf64_Ehdr *ehdr = elf; + const struct Elf64_Phdr *phdr = elf + ehdr->e_phoff + idx * ehdr->e_phentsize; + + if (phdr->p_type == PT_DYNAMIC) return true; if (phdr->p_type != PT_LOAD) { printf("unknown type %x\n", phdr->p_type); @@ -41,19 +42,30 @@ static bool load_phdr(const void *base, size_t idx) { } // TODO overlap check // TODO don't ignore flags - _syscall_memflag((void*)phdr->p_vaddr, phdr->p_memsz, MEMFLAG_PRESENT); + _syscall_memflag(exebase + phdr->p_vaddr, phdr->p_memsz, MEMFLAG_PRESENT); // TODO check that filesz <= memsz - memcpy((void*)phdr->p_vaddr, base + phdr->p_offset, phdr->p_filesz); + memcpy(exebase + phdr->p_vaddr, elf + phdr->p_offset, phdr->p_filesz); return true; } void elf_exec(void *base) { struct Elf64_Ehdr *ehdr = base; + void *exebase; if (!valid_ehdr(ehdr)) return; + switch (ehdr->e_type) { + case ET_EXEC: + exebase = (void*)0; + break; + case ET_DYN: + exebase = (void*)0x800000; // TODO search for free memory + break; + default: + return; + } for (size_t phi = 0; phi < ehdr->e_phnum; phi++) { - if (!load_phdr(base, phi)) + if (!load_phdr(base, exebase, phi)) return; } - ((void(*)())ehdr->e_entry)(); + ((void(*)())exebase + ehdr->e_entry)(); _syscall_exit(1); } |