summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordzwdz2022-10-18 18:41:22 +0200
committerdzwdz2022-10-18 23:01:28 +0200
commit753d43d349bfde6b83cff650c9354c4a0442a3ae (patch)
tree1bb20c6f37c57bb957c9f96bc13eafc6a1f54f72
parent6bb22b0a144646788f8c14bce1bde147693da780 (diff)
user/libc: rework exec(), use a C _start2
-rw-r--r--src/user/lib/_start.s11
-rw-r--r--src/user/lib/_start2.c13
-rw-r--r--src/user/lib/crt0.s21
-rw-r--r--src/user/lib/elfload.c73
-rw-r--r--src/user/lib/elfload.h6
5 files changed, 62 insertions, 62 deletions
diff --git a/src/user/lib/_start.s b/src/user/lib/_start.s
new file mode 100644
index 0000000..0d5b5de
--- /dev/null
+++ b/src/user/lib/_start.s
@@ -0,0 +1,11 @@
+.section .text
+.global _start
+.type _start, @function
+.weak _start
+_start:
+ mov %rsp, %rdi
+ and $~0xF, %rsp
+ call _start2
+ hlt
+ /* the call shouldn't return, thus the hlt.
+ * using a call instead of jmp for stack alignment */
diff --git a/src/user/lib/_start2.c b/src/user/lib/_start2.c
new file mode 100644
index 0000000..6d1431f
--- /dev/null
+++ b/src/user/lib/_start2.c
@@ -0,0 +1,13 @@
+#include <camellia/syscalls.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <user/lib/elfload.h>
+
+int main(int argc, char **argv, char **envp);
+
+_Noreturn void _start2(struct execdata *ed) {
+ elf_selfreloc();
+ __setinitialcwd(ed->cwd);
+ exit(main(ed->argc, ed->argv, ed->envp));
+}
diff --git a/src/user/lib/crt0.s b/src/user/lib/crt0.s
deleted file mode 100644
index 3548264..0000000
--- a/src/user/lib/crt0.s
+++ /dev/null
@@ -1,21 +0,0 @@
-.section .text
-.global _start
-.type _start, @function
-.weak _start
-_start:
- mov %rsp, %rbp
- and $~0xF, %rsp
- call elf_selfreloc
-
- mov %rbp, %rsp
-
- pop %rdi
- call __setinitialcwd
-
- 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 777c8b8..9776a13 100644
--- a/src/user/lib/elfload.c
+++ b/src/user/lib/elfload.c
@@ -65,9 +65,9 @@ static size_t elf_spread(const void *elf) {
return high - low;
}
-static void *malloccpy(const void *orig, size_t len) {
+static void *memdup(const void *orig, size_t len) {
void *n = malloc(len);
- memcpy(n, orig, len);
+ if (n) memcpy(n, orig, len);
return n;
}
@@ -76,50 +76,41 @@ static void *malloccpy(const void *orig, size_t len) {
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) {
- size_t len;
- union {void *b; void **ptr; uintptr_t *n;} stack;
- stack.b = (void*)~0; /* default stack location */
- void *stack_start = stack.b - 0x1000;
- void *cwd;
-
- /* copy argv off the stack */
- int argc = 0;
- size_t argv_len;
- if (argv) {
- while (argv[argc]) argc++;
- argv_len = argc * sizeof(char *);
- if ((void*)argv > stack_start)
- argv = malloccpy(argv, argv_len);
- for (int i = 0; argv[i]; i++)
- if ((void*)argv[i] > stack_start)
- argv[i] = malloccpy(argv[i], strlen(argv[i]) + 1);
- }
+ void *stack = (void*)~0;
+ struct execdata ed;
- /* push cwd */
- len = absolutepath(NULL, NULL, 0);
- stack.b -= len;
- cwd = stack.b;
- getcwd(cwd, len);
-
- /* push argv */
if (argv) {
- for (int i = 0; i < argc; i++) {
- len = strlen(argv[i]) + 1;
- stack.b -= len;
- memcpy(stack.b, argv[i], len);
- argv[i] = stack.b;
+ size_t argv_len;
+ 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]);
+
+ 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;
}
- *--(stack.ptr) = NULL; /* NULL terminate argv */
- stack.b -= argv_len;
- memcpy(stack.b, argv, argv_len);
- argv = stack.b;
+ ed.argv[ed.argc] = NULL;
}
- *--(stack.ptr) = envp;
- *--(stack.ptr) = argv;
- *--(stack.n) = argc;
+ /* push cwd */
+ size_t len = absolutepath(NULL, NULL, 0);
+ stack -= len;
+ getcwd(stack, len);
+ ed.cwd = stack;
- *--(stack.ptr) = cwd;
+ stack -= sizeof ed;
+ memcpy(stack, &ed, sizeof ed);
uintptr_t high = (uintptr_t)low + imglen;
uint64_t buf[] = {
@@ -127,7 +118,7 @@ void _freejmp(void *entry, void *low, size_t imglen, const char **argv, char **e
EXECBUF_SYSCALL, _SYSCALL_MEMFLAG, high, ~0 - 0xF000 - high, 0, 0, 0,
EXECBUF_JMP, (uintptr_t)entry,
};
- execbuf_chstack(stack.b, buf, sizeof buf);
+ execbuf_chstack(stack, buf, sizeof buf);
}
static void *elf_loadmem(struct Elf64_Ehdr *ehdr) {
diff --git a/src/user/lib/elfload.h b/src/user/lib/elfload.h
index 283efd8..825f765 100644
--- a/src/user/lib/elfload.h
+++ b/src/user/lib/elfload.h
@@ -1,6 +1,12 @@
#pragma once
#include <bits/file.h>
+struct execdata {
+ int argc;
+ char **argv, **envp;
+ char *cwd;
+};
+
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 */