summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/user/lib/crt0.s5
-rw-r--r--src/user/lib/elfload.c46
-rw-r--r--src/user/lib/include/unistd.h6
-rw-r--r--src/user/lib/stdlib.c33
4 files changed, 62 insertions, 28 deletions
diff --git a/src/user/lib/crt0.s b/src/user/lib/crt0.s
index dd9ab1b..3548264 100644
--- a/src/user/lib/crt0.s
+++ b/src/user/lib/crt0.s
@@ -8,7 +8,10 @@ _start:
call elf_selfreloc
mov %rbp, %rsp
- /* pushed by _freejmp */
+
+ pop %rdi
+ call __setinitialcwd
+
pop %rdi
pop %rsi
pop %rdx
diff --git a/src/user/lib/elfload.c b/src/user/lib/elfload.c
index 7c84f45..b4987f4 100644
--- a/src/user/lib/elfload.c
+++ b/src/user/lib/elfload.c
@@ -5,6 +5,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <unistd.h>
#include <user/lib/elf.h>
#include <user/lib/elfload.h>
@@ -68,36 +69,47 @@ static size_t elf_spread(const void *elf) {
* 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;
+void _freejmp(void *entry, void *low, size_t imglen, char **argv, char **envp) {
+ size_t len;
+ union {void *b; void **ptr; uintptr_t *n;} stack;
+ stack.b = (void*)~0; /* default stack location */
+ void *cwd;
+
+ /* push cwd */
+ len = absolutepath(NULL, NULL, 0);
+ stack.b -= len;
+ cwd = stack.b;
+ getcwd(cwd, len);
+
+ /* push argv */
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;
+ len = strlen(argv[i]) + 1;
+ stack.b -= len;
+ memcpy(stack.b, argv[i], len);
+ argv[i] = stack.b;
argc++;
}
len = sizeof(char*) * argc;
- stack -= len;
- memcpy(stack, argv, len);
- argv = stack;
+ stack.b -= len;
+ memcpy(stack.b, argv, len);
+ argv = stack.b;
}
- stack_w = stack;
- *--stack_w = (uintptr_t)envp;
- *--stack_w = (uintptr_t)argv;
- *--stack_w = argc;
- uintptr_t high = (uintptr_t)low + len;
+ *--(stack.ptr) = envp;
+ *--(stack.ptr) = argv;
+ *--(stack.n) = argc;
+
+ *--(stack.ptr) = cwd;
+
+ uintptr_t high = (uintptr_t)low + imglen;
uint64_t buf[] = {
EXECBUF_SYSCALL, _SYSCALL_MEMFLAG, 0, (uintptr_t)low, 0, 0, 0,
EXECBUF_SYSCALL, _SYSCALL_MEMFLAG, high, ~0 - 0xF000 - high, 0, 0, 0,
EXECBUF_JMP, (uintptr_t)entry,
};
- execbuf_chstack(stack_w, buf, sizeof buf);
+ execbuf_chstack(stack.b, buf, sizeof buf);
}
static void *elf_loadmem(struct Elf64_Ehdr *ehdr) {
diff --git a/src/user/lib/include/unistd.h b/src/user/lib/include/unistd.h
index aedca1b..2b75a13 100644
--- a/src/user/lib/include/unistd.h
+++ b/src/user/lib/include/unistd.h
@@ -10,8 +10,12 @@ int execv(const char *path, char *const argv[]);
int chdir(const char *path);
char *getcwd(char *buf, size_t size);
/* Converts a relative path to an absolute one, simplifying it if possible.
- * If in == NULL - return the length of cwd (without a trailing slash)
+ * If in == NULL - return the length of cwd. Doesn't include the trailing slash,
+ * except for the root dir. Includes the null byte.
* If size isn't enough to fit the path, returns the amount of bytes needed to fit
* it, including the null byte.
* @return 0 on failure, length of the path otherwise */
size_t absolutepath(char *out, const char *in, size_t size);
+
+// TODO put in an internal libc header
+void __setinitialcwd(const char *c);
diff --git a/src/user/lib/stdlib.c b/src/user/lib/stdlib.c
index 566eb3e..a5d2d9b 100644
--- a/src/user/lib/stdlib.c
+++ b/src/user/lib/stdlib.c
@@ -53,9 +53,19 @@ _Noreturn void abort(void) {
}
+static const char *__initialcwd;
static char *cwd = NULL, *cwd2 = NULL;
static size_t cwdcapacity = 0;
+static const char *getrealcwd(void) {
+ /* __initialcwd can't just be initialized with "/" because ld has seemingly
+ * started to revolt against humanity and not process half the relocations
+ * it sees. */
+ if (cwd) return cwd;
+ if (__initialcwd) return __initialcwd;
+ return "/";
+}
+
int chdir(const char *path) {
handle_t h;
char *tmp;
@@ -66,12 +76,12 @@ int chdir(const char *path) {
cwd = realloc(cwd, len);
cwd2 = realloc(cwd2, len);
} else {
- cwd = malloc(len);
- cwd[0] = '/';
- cwd[1] = '\0';
- cwd2 = malloc(len);
- cwd2[0] = '/';
- cwd2[1] = '\0';
+ size_t initlen = strlen(__initialcwd) + 1;
+ if (len < initlen)
+ len = initlen;
+ cwd = malloc(initlen);
+ cwd2 = malloc(initlen);
+ memcpy(cwd, __initialcwd, initlen);
}
}
absolutepath(cwd2, path, cwdcapacity);
@@ -95,16 +105,17 @@ int chdir(const char *path) {
}
char *getcwd(char *buf, size_t size) {
- const char *realcwd = cwd ? cwd : "/";
+ const char *realcwd = getrealcwd();
// TODO bounds checking
memcpy(buf, realcwd, strlen(realcwd) + 1);
return buf;
}
size_t absolutepath(char *out, const char *in, size_t size) {
- const char *realcwd = cwd ? cwd : "/";
+ const char *realcwd = getrealcwd();
size_t len, pos = 0;
- if (!in) return strlen(realcwd);
+ _klogf("realcwd == %x\n", (long)__initialcwd);
+ if (!in) return strlen(realcwd) + 1;
if (!(in[0] == '/')) {
len = strlen(realcwd);
@@ -133,3 +144,7 @@ size_t absolutepath(char *out, const char *in, size_t size) {
return pos;
}
+
+void __setinitialcwd(const char *s) {
+ __initialcwd = s;
+}