diff options
-rw-r--r-- | src/shared/include/camellia/syscalls.h | 2 | ||||
-rw-r--r-- | src/user/app/shell/shell.c | 4 | ||||
-rw-r--r-- | src/user/app/testelf/main.c | 9 | ||||
-rw-r--r-- | src/user/bootstrap/main.c | 2 | ||||
-rw-r--r-- | src/user/lib/crt0.c | 10 | ||||
-rw-r--r-- | src/user/lib/crt0.s | 18 | ||||
-rw-r--r-- | src/user/lib/elfload.c | 44 | ||||
-rw-r--r-- | src/user/lib/elfload.h | 4 | ||||
-rw-r--r-- | src/user/lib/elfload.s | 17 | ||||
-rw-r--r-- | src/user/lib/stdlib.c | 2 |
10 files changed, 85 insertions, 27 deletions
diff --git a/src/shared/include/camellia/syscalls.h b/src/shared/include/camellia/syscalls.h index e835c91..7864123 100644 --- a/src/shared/include/camellia/syscalls.h +++ b/src/shared/include/camellia/syscalls.h @@ -28,7 +28,7 @@ enum { _SYSCALL_MEMFLAG, _SYSCALL_PIPE, - _SYSCALL_EXECBUF, + _SYSCALL_EXECBUF = 100, _SYSCALL_DEBUG_KLOG, }; diff --git a/src/user/app/shell/shell.c b/src/user/app/shell/shell.c index d002b38..0196d5b 100644 --- a/src/user/app/shell/shell.c +++ b/src/user/app/shell/shell.c @@ -61,7 +61,9 @@ static void execp(const char *cmd) { memcpy(s, "/bin/", 5); memcpy(s + 5, cmd, cmdlen + 1); - execv(s, NULL); + char *argv[] = {(char*)cmd, NULL}; + + execv(s, argv); free(s); } diff --git a/src/user/app/testelf/main.c b/src/user/app/testelf/main.c index a3e54b8..5111791 100644 --- a/src/user/app/testelf/main.c +++ b/src/user/app/testelf/main.c @@ -1,9 +1,12 @@ #include <stdio.h> -const char *str = "Hello!\n", *str2 = "World.\n"; +const char *str = "Hello!", *str2 = "World."; -int main(void) { +int main(int argc, char **argv, char **envp) { printf("elftest's &main == 0x%x\n", &main); - printf("%s%s", str, str2); + printf("%s %s\n", str, str2); + printf("argc == 0x%x\n", argc); + for (int i = 0; i < argc; i++) + printf("argv[0x%x] == 0x%x == \"%s\"\n", i, argv[i], argv[i]); return 0; } diff --git a/src/user/bootstrap/main.c b/src/user/bootstrap/main.c index 9c08023..e877b64 100644 --- a/src/user/bootstrap/main.c +++ b/src/user/bootstrap/main.c @@ -27,7 +27,7 @@ void _start(void) { void *init = tar_find("bin/init", 8, &_initrd, ~0) + 512; if (init) { _klogf("execing init.elf"); - elf_exec(init); + elf_exec(init, NULL, NULL); _klogf("elf_exec failed"); } else { _klogf("couldn't find init.elf"); diff --git a/src/user/lib/crt0.c b/src/user/lib/crt0.c deleted file mode 100644 index 91bbb05..0000000 --- a/src/user/lib/crt0.c +++ /dev/null @@ -1,10 +0,0 @@ -#include "elfload.h" -#include <unistd.h> - -int main(); - -__attribute__((__weak__)) -void _start(void) { - elf_selfreloc(); - exit(main()); -} diff --git a/src/user/lib/crt0.s b/src/user/lib/crt0.s new file mode 100644 index 0000000..dd9ab1b --- /dev/null +++ b/src/user/lib/crt0.s @@ -0,0 +1,18 @@ +.section .text +.global _start +.type _start, @function +.weak _start +_start: + mov %rsp, %rbp + and $~0xF, %rsp + call elf_selfreloc + + mov %rbp, %rsp + /* pushed by _freejmp */ + pop %rdi + pop %rsi + pop %rdx + and $~0xF, %rsp + call main + mov %rax, %rdi + jmp exit diff --git a/src/user/lib/elfload.c b/src/user/lib/elfload.c index 5ba596f..6cf09c7 100644 --- a/src/user/lib/elfload.c +++ b/src/user/lib/elfload.c @@ -8,13 +8,14 @@ #include <user/lib/elf.h> #include <user/lib/elfload.h> -void elf_execf(FILE *f) { +void elf_execf(FILE *f, char **argv, char **envp) { const size_t cap = 0x60000; size_t pos = 0; void *buf = malloc(cap); // TODO a way to get file size fseek(f, 0, SEEK_SET); + if (buf && fread(buf, 1, cap - pos, f)) - elf_exec(buf); + elf_exec(buf, argv, envp); free(buf); } @@ -58,16 +59,40 @@ static size_t elf_spread(const void *elf) { return high - low; } -/* frees memory outside of [low; low + len] and jumps to *entry */ -static void freejmp(void *entry, void *low, size_t len) { +/* 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, 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 len, char **argv, char **envp) { + void *stack = (void*)~0; + size_t *stack_w; + int argc = 0; + if (argv) { + size_t len; + for (int i = 0; argv[i]; i++) { + len = strlen(argv[i]) + 1; // including the null byte + stack -= len; + memcpy(stack, argv[i], len); + argv[i] = stack; + argc++; + } + len = sizeof(char*) * argc; + stack -= len; + memcpy(stack, argv, len); + argv = stack; + } + stack_w = stack; + *--stack_w = (uintptr_t)envp; + *--stack_w = (uintptr_t)argv; + *--stack_w = argc; + uintptr_t high = (uintptr_t)low + len; uint64_t buf[] = { EXECBUF_SYSCALL, _SYSCALL_MEMFLAG, 0, (uintptr_t)low, 0, 0, EXECBUF_SYSCALL, _SYSCALL_MEMFLAG, high, ~0 - 0xF000 - high, 0, 0, EXECBUF_JMP, (uintptr_t)entry, }; - _syscall_execbuf(buf, sizeof buf); - // should never return + execbuf_chstack(stack_w, buf, sizeof buf); } static void *elf_loadmem(struct Elf64_Ehdr *ehdr) { @@ -94,14 +119,17 @@ static void *elf_loadmem(struct Elf64_Ehdr *ehdr) { return exebase; } -void elf_exec(void *base) { +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; - freejmp(exebase + ehdr->e_entry, exebase, elf_spread(ehdr) + 0x1000); + void *newstack = _syscall_memflag((void*)0x1000, 0x1000, MEMFLAG_FINDFREE | MEMFLAG_PRESENT); + if (!newstack) return; + + _freejmp_chstack(exebase + ehdr->e_entry, exebase, elf_spread(ehdr) + 0x1000, argv, envp, newstack); } void *elf_partialexec(void *base) { diff --git a/src/user/lib/elfload.h b/src/user/lib/elfload.h index d0fb29d..283efd8 100644 --- a/src/user/lib/elfload.h +++ b/src/user/lib/elfload.h @@ -1,8 +1,8 @@ #pragma once #include <bits/file.h> -void elf_execf(FILE *f); -void elf_exec(void *elf); +void elf_execf(FILE *f, char **argv, char **envp); +void elf_exec(void *base, char **argv, char **envp); void *elf_partialexec(void *elf); /* returns pointer to entry point */ void elf_selfreloc(void); // elfreloc.c diff --git a/src/user/lib/elfload.s b/src/user/lib/elfload.s new file mode 100644 index 0000000..faab85f --- /dev/null +++ b/src/user/lib/elfload.s @@ -0,0 +1,17 @@ +.section .text +.global _freejmp_chstack +.type _freejmp_chstack, @function +// void _freejmp_chstack(void *entry, void *low, size_t len, char **argv, char **envp, void *stack); +_freejmp_chstack: + mov %r9, %rsp + jmp _freejmp + +.section .text +.global execbuf_chstack +.type execbuf_chstack, @function +// _Noreturn void execbuf_chstack(void *stack, void __user *buf, size_t len); +execbuf_chstack: + mov %rdi, %rsp + mov $100, %rdi + syscall + jmp 0 // if execbuf failed we might as well crash diff --git a/src/user/lib/stdlib.c b/src/user/lib/stdlib.c index 179bd8f..0795d3d 100644 --- a/src/user/lib/stdlib.c +++ b/src/user/lib/stdlib.c @@ -25,7 +25,7 @@ int execv(const char *path, char *const argv[]) { if (!file) return -1; - elf_execf(file); + elf_execf(file, (void*)argv, NULL); fclose(file); errno = EINVAL; return -1; |