diff options
author | dzwdz | 2022-07-18 14:01:21 +0200 |
---|---|---|
committer | dzwdz | 2022-07-18 14:01:21 +0200 |
commit | d43c1af88b1834a00f8b5f09aa0af1a5e4f5b4aa (patch) | |
tree | 7743cd9eb761dee12711cf719ab846228a888dbd /src/user/lib/elfload.c | |
parent | 620bd6af8e005057e04c8a2891c7537ec3556345 (diff) |
user: a super primitive ELF loader
holy shit.
this was simpler than i expected it to be
Diffstat (limited to 'src/user/lib/elfload.c')
-rw-r--r-- | src/user/lib/elfload.c | 59 |
1 files changed, 59 insertions, 0 deletions
diff --git a/src/user/lib/elfload.c b/src/user/lib/elfload.c new file mode 100644 index 0000000..67cef68 --- /dev/null +++ b/src/user/lib/elfload.c @@ -0,0 +1,59 @@ +#include <shared/flags.h> +#include <shared/syscalls.h> +#include <user/lib/elf.h> +#include <user/lib/elfload.h> + +void elf_execf(libc_file *f) { + const size_t cap = 0x60000; + size_t pos = 0; + void *buf = malloc(cap); // TODO a way to get file size + if (!buf) goto fail; + + while (!f->eof) { + long ret = file_read(f, buf, cap - pos); + if (ret < 0) goto fail; + pos += ret; + if (pos >= cap) goto fail; + } + elf_exec(buf); + +fail: + free(buf); +} + +static bool valid_ehdr(const struct Elf64_Ehdr *h) { + return h->e_ident[0] == 0x7f + && 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; + + if (phdr->p_type != PT_LOAD) { + printf("unknown type %x\n", phdr->p_type); + return false; + } + // TODO overlap check + // TODO don't ignore flags + _syscall_memflag((void*)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); + return true; +} + +void elf_exec(void *base) { + struct Elf64_Ehdr *ehdr = base; + if (!valid_ehdr(ehdr)) return; + for (size_t phi = 0; phi < ehdr->e_phnum; phi++) { + if (!load_phdr(base, phi)) + return; + } + ((void(*)())ehdr->e_entry)(); + _syscall_exit(1); +} |