diff options
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | src/user/lib/elfload.c | 28 | ||||
-rw-r--r-- | src/usertestelf.c | 64 | ||||
-rw-r--r-- | src/usertestelf.ld | 2 |
4 files changed, 85 insertions, 11 deletions
@@ -69,7 +69,7 @@ initrd/test.elf: out/test.elf out/test.elf: src/usertestelf.ld out/obj/usertestelf.c.o out/obj/user/lib/syscall.s.o $(call from_sources, src/shared/) @mkdir -p $(@D) - @$(CC) $(LFLAGS) -T $^ -o $@ + @$(CC) $(LFLAGS) -Wl,-pie -Wl,-no-dynamic-linker -T $^ -o $@ # TODO automatically resolve symlinks out/initrd.tar: $(shell find initrd/) out/test.elf 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); } diff --git a/src/usertestelf.c b/src/usertestelf.c index 19f0096..c3ab289 100644 --- a/src/usertestelf.c +++ b/src/usertestelf.c @@ -1,6 +1,68 @@ +#include <shared/printf.h> +#include <user/lib/elf.h> #include <user/lib/syscall.c> +const char *str = "Hello!\n", *str2 = "World.\n"; + +__attribute__((visibility("hidden"))) +extern struct Elf64_Dyn _DYNAMIC[]; + +__attribute__((visibility("hidden"))) +extern char _image_base; + +static void printf_backend(void *arg, const char *buf, size_t len) { + (void)arg; + _syscall_write(1, buf, len, -1); +} + +int printf(const char *fmt, ...) { + int ret = 0; + va_list argp; + va_start(argp, fmt); + ret = __printf_internal(fmt, argp, printf_backend, 0); + va_end(argp); + return ret; +} + + +static struct Elf64_Dyn *dyn_gettag(Elf64_Xword tag) { + for (size_t i = 0;; i++) { + if (_DYNAMIC[i].d_tag == tag) return &_DYNAMIC[i]; + if (_DYNAMIC[i].d_tag == DT_NULL) return NULL; + } +} + +static void reloc(void) { + printf("hi?\n"); + // TODO DT_REL + if (dyn_gettag(DT_PLTGOT) || dyn_gettag(DT_JMPREL)) { + printf("elf: unimplemented tag in _DYNAMIC\n"); + } + + struct Elf64_Dyn *rela_tag = dyn_gettag(DT_RELA); + if (rela_tag) { + /* not checking pointer validity, + * crashing on an invalid elf is fine */ + size_t relasz = dyn_gettag(DT_RELASZ)->d_val; + size_t relaent = dyn_gettag(DT_RELAENT)->d_val; + for (size_t o = 0; o < relasz; o += relaent) { + struct Elf64_Rela *r = &_image_base + rela_tag->d_ptr + o; + uintptr_t *target = &_image_base + r->r_offset; + + switch (ELF64_R_TYPE(r->r_info)) { + case R_X86_64_RELATIVE: + *target = &_image_base + r->r_addend; + break; + default: + printf("elf: unsupported relocation type\n"); + } + } + } +} + int main(void) { - _syscall_write(1, "Hello!", 6, 0); + reloc(); + printf(str); + printf(str2); _syscall_exit(0); } diff --git a/src/usertestelf.ld b/src/usertestelf.ld index 2567f77..fcb5fc8 100644 --- a/src/usertestelf.ld +++ b/src/usertestelf.ld @@ -2,7 +2,7 @@ ENTRY(main) SECTIONS { - . = 8M; + _image_base = .; .text BLOCK(4K) : ALIGN(4K) { *(.text) |