summaryrefslogtreecommitdiff
path: root/src/user/lib
diff options
context:
space:
mode:
authordzwdz2022-07-27 13:59:52 +0200
committerdzwdz2022-07-27 13:59:52 +0200
commitc77b0fa7916f79c099ee4a6a80a093334e9090ac (patch)
tree19eaedcecaa1584b83342853f1616975b50cad97 /src/user/lib
parent55b3a04e97b7ddd0db17a4fc3ba35461b106b92f (diff)
user/libc: execve() supports passing argv now
Diffstat (limited to 'src/user/lib')
-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
6 files changed, 74 insertions, 21 deletions
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;