summaryrefslogtreecommitdiff
path: root/src/user/lib/elfload.c
diff options
context:
space:
mode:
authordzwdz2023-08-14 18:51:07 +0200
committerdzwdz2023-08-14 18:51:07 +0200
commit642b5fb0007b64c77d186fcb018d571152ee1d47 (patch)
tree1c466461f3602d306be309a053edae558ef2568e /src/user/lib/elfload.c
parent8050069c57b729c18c19b1a03ab6e4bf63b4735e (diff)
reorganization: first steps
Diffstat (limited to 'src/user/lib/elfload.c')
-rw-r--r--src/user/lib/elfload.c182
1 files changed, 0 insertions, 182 deletions
diff --git a/src/user/lib/elfload.c b/src/user/lib/elfload.c
deleted file mode 100644
index c1a08f8..0000000
--- a/src/user/lib/elfload.c
+++ /dev/null
@@ -1,182 +0,0 @@
-#include <camellia/execbuf.h>
-#include <camellia/flags.h>
-#include <camellia/syscalls.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include "elf.h"
-#include <elfload.h>
-
-void elf_execf(FILE *f, char **argv, char **envp) {
- size_t ret;
- void *buf;
- long buflen;
-
- fseek(f, 0, SEEK_END);
- buflen = ftell(f);
- if (buflen < 0) return; /* errno set by fseek */
- buf = malloc(buflen);
-
- // TODO don't read the entire file into memory
- fseek(f, 0, SEEK_SET);
- if (!buf) return;
- ret = fread(buf, buflen, 1, f);
- fclose(f);
- if (ret == 1) {
- elf_exec(buf, argv, envp);
- }
- 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_machine == EM_X86_64
- && h->e_version == 1;
-}
-
-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);
- return false;
- }
- // TODO overlap check
- // TODO don't ignore flags
- _sys_memflag(exebase + phdr->p_vaddr, phdr->p_memsz, MEMFLAG_PRESENT);
- // TODO check that filesz <= memsz
- memcpy(exebase + phdr->p_vaddr, elf + phdr->p_offset, phdr->p_filesz);
- return true;
-}
-
-static size_t elf_spread(const void *elf) {
- const struct Elf64_Ehdr *ehdr = elf;
- uintptr_t high = 0, low = ~0;
- for (size_t phi = 0; phi < ehdr->e_phnum; phi++) {
- const struct Elf64_Phdr *phdr = elf + ehdr->e_phoff + phi * ehdr->e_phentsize;
- if (high < phdr->p_vaddr + phdr->p_memsz)
- high = phdr->p_vaddr + phdr->p_memsz;
- if (low > phdr->p_vaddr)
- low = phdr->p_vaddr;
- }
- return high - low;
-}
-
-static void *memdup(const void *orig, size_t len) {
- void *n = malloc(len);
- if (n) memcpy(n, orig, len);
- return n;
-}
-
-static const char *default_argv[] = {NULL};
-
-/* frees memory outside of [low; low + len] and jumps to *entry
- * also sets up main's stack */
-void _freejmp_chstack(void *entry, void *low, size_t len, const char **argv, char **envp, void *stack); // elfload.s
-_Noreturn void execbuf_chstack(void *stack, void __user *buf, size_t len);
-void _freejmp(void *entry, void *low, size_t imglen, const char **argv, char **envp) {
- // TODO error checking
- // although i guess it's fine for it to crash
- // also TODO just alloc a new stack
- void *stack = (void*)~0;
- struct execdata ed;
- size_t argv_len;
- size_t cwd_len = absolutepath(NULL, NULL, 0);
-
- if (!argv) argv = default_argv;
-
- ed.argc = 0;
- while (argv[ed.argc]) ed.argc++;
- argv_len = (ed.argc+1) * sizeof(char *);
-
- /* make a copy of argv, so it doesn't get overridden
- * if it overlaps with the new stack. */
- argv = memdup(argv, argv_len);
- for (int i = 0; i < ed.argc; i++) {
- argv[i] = strdup(argv[i]);
- }
- ed.cwd = malloc(cwd_len);
- getcwd(ed.cwd, cwd_len);
-
- stack -= argv_len;
- ed.argv = stack;
-
- for (int i = 0; i < ed.argc; i++) {
- size_t len = strlen(argv[i]) + 1;
- stack -= len;
- memcpy(stack, argv[i], len);
- ed.argv[i] = stack;
- }
- ed.argv[ed.argc] = NULL;
-
- /* push cwd */
- stack -= cwd_len;
- memcpy(stack, ed.cwd, cwd_len);
- ed.cwd = stack;
-
- stack -= sizeof ed;
- memcpy(stack, &ed, sizeof ed);
-
- uintptr_t high = (uintptr_t)low + imglen;
- uint64_t buf[] = {
- EXECBUF_SYSCALL, _SYS_MEMFLAG, 0, (uintptr_t)low, 0, 0, 0,
- EXECBUF_SYSCALL, _SYS_MEMFLAG, high, ~0 - 0xF000 - high, 0, 0, 0,
- EXECBUF_JMP, (uintptr_t)entry,
- };
- execbuf_chstack(stack, buf, sizeof buf);
-}
-
-static void *elf_loadmem(struct Elf64_Ehdr *ehdr) {
- void *exebase;
- size_t spread = elf_spread(ehdr);
- switch (ehdr->e_type) {
- case ET_EXEC:
- exebase = (void*)0;
- break;
- case ET_DYN:
- exebase = _sys_memflag((void*)0x1000, spread, MEMFLAG_FINDFREE);
- if (!exebase)
- return NULL;
- break;
- default:
- return NULL;
- }
- for (size_t phi = 0; phi < ehdr->e_phnum; phi++) {
- if (!load_phdr((void*)ehdr, exebase, phi)) {
- _sys_memflag(exebase, spread, 0);
- return NULL;
- }
- }
- return exebase;
-}
-
-void elf_exec(void *base, char **argv, char **envp) {
- struct Elf64_Ehdr *ehdr = base;
- if (!valid_ehdr(ehdr)) return;
-
- void *exebase = elf_loadmem(ehdr);
- if (!exebase) return;
-
- void *newstack = _sys_memflag((void*)0x11000, 0x1000, MEMFLAG_FINDFREE | MEMFLAG_PRESENT) + 0x1000 - 8;
- if (!newstack) return;
-
- _freejmp_chstack(exebase + ehdr->e_entry, exebase, elf_spread(ehdr) + 0x1000, (const char**)argv, envp, newstack);
-}
-
-void *elf_partialexec(void *base) {
- struct Elf64_Ehdr *ehdr = base;
- if (!valid_ehdr(ehdr)) return NULL;
-
- void *exebase = elf_loadmem(ehdr);
- if (!exebase) return NULL;
-
- return exebase + ehdr->e_entry;
-}