summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/shared/include/camellia/syscalls.h2
-rw-r--r--src/user/app/shell/shell.c4
-rw-r--r--src/user/app/testelf/main.c9
-rw-r--r--src/user/bootstrap/main.c2
-rw-r--r--src/user/lib/crt0.c10
-rw-r--r--src/user/lib/crt0.s18
-rw-r--r--src/user/lib/elfload.c44
-rw-r--r--src/user/lib/elfload.h4
-rw-r--r--src/user/lib/elfload.s17
-rw-r--r--src/user/lib/stdlib.c2
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;