diff options
Diffstat (limited to 'src/kernel/linker/elf.cpp')
-rw-r--r-- | src/kernel/linker/elf.cpp | 57 |
1 files changed, 57 insertions, 0 deletions
diff --git a/src/kernel/linker/elf.cpp b/src/kernel/linker/elf.cpp new file mode 100644 index 0000000..ab8e349 --- /dev/null +++ b/src/kernel/linker/elf.cpp @@ -0,0 +1,57 @@ +#include "elf.h" +#include <mem/paging.h> +#include <mem/seg.h> +#include <stdlib_common.h> +#include <core/sys.h> + +int elf_check(uint8_t *data) { + elf_ehdr *h = (elf_ehdr*)data; + if (h->e_ident[0] == 0x7F && h->e_ident[1] == 'E' && h->e_ident[2] == 'L' && h->e_ident[3] == 'F') return 0; + return 1; +} + +thread_entry elf_load(uint8_t *data, process* process) { + elf_ehdr *ehdr = (elf_ehdr*)data; + elf_phdr *phdr; + int i; + size_t dataseg = 0; + if (elf_check(data)) return 0; + + page_directory *r = current_pagedir; + cli(); + pagedir_switch(process->pagedir); + + phdr = (elf_phdr*)((uint8_t*)(data + ehdr->e_phoff)); + for (i = 0; i < ehdr->e_phnum; i++) { + if (phdr[i].p_type == PT_LOAD) { + seg_map(simpleseg_make(phdr[i].p_vaddr, phdr[i].p_memsz, (phdr[i].p_flags & PF_W) != 0), process->pagedir, 0); + memcpy((uint8_t*)phdr[i].p_vaddr, data + phdr[i].p_offset, phdr[i].p_filesz); + if (phdr[i].p_memsz > phdr[i].p_filesz) { + memset((uint8_t*)phdr[i].p_vaddr + phdr[i].p_memsz, 0, phdr[i].p_memsz - phdr[i].p_filesz); + } + if (phdr[i].p_vaddr + phdr[i].p_memsz > dataseg) { + dataseg = phdr[i].p_vaddr + phdr[i].p_memsz; + dataseg = (dataseg & 0xFFFFF000) + 0x1000; + } + } + } + + process->data = dataseg; + + pagedir_switch(r); + sti(); + + return (thread_entry)ehdr->e_entry; +} + +process* elf_exec(uint8_t *data, int privilege) { + if (elf_check(data)) return 0; + + process* p = process_new(0, 0, privilege); + + thread_entry e = elf_load(data, p); + + thread_new(p, e, 0, 0); + + return p; +} |