diff --git a/cmake/wrap_elf.cmake b/cmake/wrap_elf.cmake index a5f32fb02..4b6488f19 100644 --- a/cmake/wrap_elf.cmake +++ b/cmake/wrap_elf.cmake @@ -6,7 +6,7 @@ function(wrap_elf name elfname) OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${name}.c COMMAND - ${CMAKE_BINARY_DIR}/src/libelfloader/wrapgen + ${CMAKE_BINARY_DIR}/src/libelfloader/wrapgen/wrapgen ${elfname} ${CMAKE_CURRENT_BINARY_DIR}/${name}.c DEPENDS diff --git a/src/kernel/emulation/linux/bsdthread/bsdthread_create.c b/src/kernel/emulation/linux/bsdthread/bsdthread_create.c index c6a53e68b..582c01a88 100644 --- a/src/kernel/emulation/linux/bsdthread/bsdthread_create.c +++ b/src/kernel/emulation/linux/bsdthread/bsdthread_create.c @@ -9,6 +9,7 @@ #include "../../../../../platform-include/sys/errno.h" #include "../mman/mman.h" #include "../simple.h" +#include "../elfcalls_wrapper.h" extern void *memset(void *s, int c, size_t n); diff --git a/src/kernel/emulation/linux/bsdthread/bsdthread_terminate.c b/src/kernel/emulation/linux/bsdthread/bsdthread_terminate.c index 8106b56f1..b00e62e4c 100644 --- a/src/kernel/emulation/linux/bsdthread/bsdthread_terminate.c +++ b/src/kernel/emulation/linux/bsdthread/bsdthread_terminate.c @@ -7,6 +7,7 @@ #include #include #include +#include "../elfcalls_wrapper.h" int bsdthread_terminate_trap( uintptr_t stackaddr, diff --git a/src/kernel/emulation/linux/elfcalls_wrapper.c b/src/kernel/emulation/linux/elfcalls_wrapper.c index f4fb8fa6d..45b285544 100644 --- a/src/kernel/emulation/linux/elfcalls_wrapper.c +++ b/src/kernel/emulation/linux/elfcalls_wrapper.c @@ -1,45 +1,68 @@ #include "elfcalls_wrapper.h" #include +#include -extern struct elf_calls* _elfcalls; +static struct elf_calls* _elfcalls; + +struct elf_calls* elfcalls(void) +{ + if (!_elfcalls) + { + void* module = dlopen("/usr/lib/libelfloader.dylib", RTLD_NOW); + // if (!module) + // __simple_printf("Load error: %s\n", dlerror()); + + // struct elf_calls** ptr = (struct elf_calls**) dlsym(module, "_elfcalls"); + // __simple_printf("_elfcalls is at %p\n", ptr); + // __simple_printf("*_elfcalls = %p\n", *ptr); + _elfcalls = *(struct elf_calls**) dlsym(module, "_elfcalls"); + } + return _elfcalls; +} + +void native_exit(int ec) +{ + if (_elfcalls) + _elfcalls->exit(ec); +} void* __darling_thread_create(unsigned long stack_size, unsigned long pthobj_size, void* entry_point, uintptr_t arg3, uintptr_t arg4, uintptr_t arg5, uintptr_t arg6, int (*thread_self_trap)()) { - return _elfcalls->darling_thread_create(stack_size, pthobj_size, entry_point, + return elfcalls()->darling_thread_create(stack_size, pthobj_size, entry_point, arg3, arg4, arg5, arg6, thread_self_trap); } int __darling_thread_terminate(void* stackaddr, unsigned long freesize, unsigned long pthobj_size) { - return _elfcalls->darling_thread_terminate(stackaddr, freesize, pthobj_size); + return elfcalls()->darling_thread_terminate(stackaddr, freesize, pthobj_size); } void* __darling_thread_get_stack(void) { - return _elfcalls->darling_thread_get_stack(); + return elfcalls()->darling_thread_get_stack(); } void* native_dlopen(const char* path) { - return _elfcalls->dlopen(path); + return elfcalls()->dlopen(path); } char* native_dlerror(void) { - return _elfcalls->dlerror(); + return elfcalls()->dlerror(); } void* native_dlsym(void* module, const char* name) { - return _elfcalls->dlsym(module, name); + return elfcalls()->dlsym(module, name); } int native_dlclose(void* module) { - return _elfcalls->dlclose(module); + return elfcalls()->dlclose(module); } diff --git a/src/kernel/emulation/linux/elfcalls_wrapper.h b/src/kernel/emulation/linux/elfcalls_wrapper.h index 558e1f841..9785dadf1 100644 --- a/src/kernel/emulation/linux/elfcalls_wrapper.h +++ b/src/kernel/emulation/linux/elfcalls_wrapper.h @@ -12,6 +12,8 @@ char* native_dlerror(void); void* native_dlsym(void* module, const char* name); int native_dlclose(void* module); +void native_exit(int ec); + // Native thread wrapping void* __darling_thread_create(unsigned long stack_size, unsigned long pthobj_size, void* entry_point, uintptr_t arg3, diff --git a/src/kernel/emulation/linux/unistd/exit.c b/src/kernel/emulation/linux/unistd/exit.c index e8ef86ca8..6e53dd4c6 100644 --- a/src/kernel/emulation/linux/unistd/exit.c +++ b/src/kernel/emulation/linux/unistd/exit.c @@ -2,11 +2,14 @@ #include "../base.h" #include "../errno.h" #include +#include "../elfcalls_wrapper.h" long sys_exit(int status) { int ret; + native_exit(status); + ret = LINUX_SYSCALL1(__NR_exit_group, status); if (ret < 0) ret = errno_linux_to_bsd(ret); diff --git a/src/kernel/emulation/linux/wrapped/sem_close.c b/src/kernel/emulation/linux/wrapped/sem_close.c index b3e4ec7c3..3f7e90db4 100644 --- a/src/kernel/emulation/linux/wrapped/sem_close.c +++ b/src/kernel/emulation/linux/wrapped/sem_close.c @@ -5,16 +5,16 @@ #include #include -extern struct elf_calls* _elfcalls; +extern struct elf_calls* elfcalls(void); long sys_sem_close(int sem) { #ifndef VARIANT_DYLD int ret; - ret = _elfcalls->sem_close(sem); + ret = elfcalls()->sem_close(sem); if (ret == -1) - ret = -errno_linux_to_bsd(_elfcalls->get_errno()); + ret = -errno_linux_to_bsd(elfcalls()->get_errno()); return ret; #else diff --git a/src/kernel/emulation/linux/wrapped/sem_open.c b/src/kernel/emulation/linux/wrapped/sem_open.c index 8d7ed1f6c..945fd17a8 100644 --- a/src/kernel/emulation/linux/wrapped/sem_open.c +++ b/src/kernel/emulation/linux/wrapped/sem_open.c @@ -6,7 +6,7 @@ #include #include -extern struct elf_calls* _elfcalls; +extern struct elf_calls* elfcalls(void); long sys_sem_open(const char* name, int oflag, int mode, int value) { @@ -16,13 +16,13 @@ long sys_sem_open(const char* name, int oflag, int mode, int value) // __simple_printf("sem_open %s, %d, %d, %d\n", name, oflag, mode, value); - ptr = _elfcalls->sem_open(name, oflags_bsd_to_linux(oflag), mode, value); + ptr = elfcalls()->sem_open(name, oflags_bsd_to_linux(oflag), mode, value); //__simple_printf("sem_open -> %p\n", ptr); if (!ptr) { - // __simple_printf("errno: %d\n", _elfcalls->get_errno()); - return -errno_linux_to_bsd(_elfcalls->get_errno()); + // __simple_printf("errno: %d\n", elfcalls()->get_errno()); + return -errno_linux_to_bsd(elfcalls()->get_errno()); } return (long) ptr; diff --git a/src/kernel/emulation/linux/wrapped/sem_post.c b/src/kernel/emulation/linux/wrapped/sem_post.c index 7863ff10e..75d6be3fa 100644 --- a/src/kernel/emulation/linux/wrapped/sem_post.c +++ b/src/kernel/emulation/linux/wrapped/sem_post.c @@ -5,7 +5,7 @@ #include #include -extern struct elf_calls* _elfcalls; +extern struct elf_calls* elfcalls(void); long sys_sem_post(int* sem) { @@ -13,9 +13,9 @@ long sys_sem_post(int* sem) int ret; // __simple_printf("sem_post(%p)\n", sem); - ret = _elfcalls->sem_post(sem); + ret = elfcalls()->sem_post(sem); if (ret == -1) - ret = -errno_linux_to_bsd(_elfcalls->get_errno()); + ret = -errno_linux_to_bsd(elfcalls()->get_errno()); return ret; #else diff --git a/src/kernel/emulation/linux/wrapped/sem_trywait.c b/src/kernel/emulation/linux/wrapped/sem_trywait.c index 7d42266b2..0936803cb 100644 --- a/src/kernel/emulation/linux/wrapped/sem_trywait.c +++ b/src/kernel/emulation/linux/wrapped/sem_trywait.c @@ -5,16 +5,16 @@ #include #include -extern struct elf_calls* _elfcalls; +extern struct elf_calls* elfcalls(void); long sys_sem_trywait(int* sem) { #ifndef VARIANT_DYLD int ret; - ret = _elfcalls->sem_trywait(sem); + ret = elfcalls()->sem_trywait(sem); if (ret == -1) - ret = -errno_linux_to_bsd(_elfcalls->get_errno()); + ret = -errno_linux_to_bsd(elfcalls()->get_errno()); return ret; #else diff --git a/src/kernel/emulation/linux/wrapped/sem_unlink.c b/src/kernel/emulation/linux/wrapped/sem_unlink.c index 03e1d3f9b..e1ab3d65e 100644 --- a/src/kernel/emulation/linux/wrapped/sem_unlink.c +++ b/src/kernel/emulation/linux/wrapped/sem_unlink.c @@ -5,16 +5,16 @@ #include #include -extern struct elf_calls* _elfcalls; +extern struct elf_calls* elfcalls(void); long sys_sem_unlink(const char* name) { #ifndef VARIANT_DYLD int ret; - ret = _elfcalls->sem_unlink(name); + ret = elfcalls()->sem_unlink(name); if (ret == -1) - ret = -errno_linux_to_bsd(_elfcalls->get_errno()); + ret = -errno_linux_to_bsd(elfcalls()->get_errno()); return ret; #else diff --git a/src/kernel/emulation/linux/wrapped/sem_wait.c b/src/kernel/emulation/linux/wrapped/sem_wait.c index b9893da80..6c009ce3b 100644 --- a/src/kernel/emulation/linux/wrapped/sem_wait.c +++ b/src/kernel/emulation/linux/wrapped/sem_wait.c @@ -6,7 +6,7 @@ #include #include "../bsdthread/cancelable.h" -extern struct elf_calls* _elfcalls; +extern struct elf_calls* elfcalls(void); long sys_sem_wait(int* sem) { @@ -19,9 +19,9 @@ long sys_sem_wait_nocancel(int* sem) #ifndef VARIANT_DYLD int ret; - ret = _elfcalls->sem_wait(sem); + ret = elfcalls()->sem_wait(sem); if (ret == -1) - ret = -errno_linux_to_bsd(_elfcalls->get_errno()); + ret = -errno_linux_to_bsd(elfcalls()->get_errno()); return ret; #else diff --git a/src/kernel/emulation/linux/wrapped/shm_open.c b/src/kernel/emulation/linux/wrapped/shm_open.c index affb3974f..9369eadfe 100644 --- a/src/kernel/emulation/linux/wrapped/shm_open.c +++ b/src/kernel/emulation/linux/wrapped/shm_open.c @@ -6,16 +6,16 @@ #include #include -extern struct elf_calls* _elfcalls; +extern struct elf_calls* elfcalls(void); long sys_shm_open(const char* name, int oflag, int mode) { #ifndef VARIANT_DYLD int ret; - ret = _elfcalls->shm_open(name, oflags_bsd_to_linux(oflag), mode); + ret = elfcalls()->shm_open(name, oflags_bsd_to_linux(oflag), mode); if (ret == -1) - ret = -errno_linux_to_bsd(_elfcalls->get_errno()); + ret = -errno_linux_to_bsd(elfcalls()->get_errno()); return ret; #else diff --git a/src/kernel/emulation/linux/wrapped/shm_unlink.c b/src/kernel/emulation/linux/wrapped/shm_unlink.c index 504c1a979..24ab23098 100644 --- a/src/kernel/emulation/linux/wrapped/shm_unlink.c +++ b/src/kernel/emulation/linux/wrapped/shm_unlink.c @@ -5,16 +5,16 @@ #include #include -extern struct elf_calls* _elfcalls; +extern struct elf_calls* elfcalls(void); long sys_shm_unlink(const char* name) { #ifndef VARIANT_DYLD int ret; - ret = _elfcalls->shm_unlink(name); + ret = elfcalls()->shm_unlink(name); if (ret == -1) - ret = -errno_linux_to_bsd(_elfcalls->get_errno()); + ret = -errno_linux_to_bsd(elfcalls()->get_errno()); return ret; #else diff --git a/src/libelfloader/loader.c b/src/libelfloader/loader.c index 21d26ae1e..6d7861513 100644 --- a/src/libelfloader/loader.c +++ b/src/libelfloader/loader.c @@ -179,7 +179,7 @@ void run(const char* path) JUMPX(stack, lc.interp_entry); else { - puts("Back from loaded binary"); + // puts("Back from loaded binary"); } } diff --git a/src/libelfloader/native/elfcalls.c b/src/libelfloader/native/elfcalls.c index 01e3cdff2..88763bb87 100644 --- a/src/libelfloader/native/elfcalls.c +++ b/src/libelfloader/native/elfcalls.c @@ -65,6 +65,7 @@ void elfcalls_make(struct elf_calls* calls) calls->darling_thread_get_stack = __darling_thread_get_stack; calls->get_errno = get_errno; + calls->exit = exit; *((void**)&calls->sem_open) = sem_open; *((void**)&calls->sem_wait) = sem_wait; *((void**)&calls->sem_trywait) = sem_trywait; @@ -80,20 +81,22 @@ int main(int argc, const char** argv) { typedef void (*retfunc)(void); + pthread_once(&once_control, once_test); + struct elf_calls* calls; retfunc ret; - for (int i = 0; i < argc; i++) - printf("arg %d: %s\n", i, argv[i]); + // for (int i = 0; i < argc; i++) + // printf("arg %d: %s\n", i, argv[i]); calls = (struct elf_calls*) strtoul(argv[1], NULL, 16); ret = (retfunc) strtoul(argv[2], NULL, 16); - puts("before elfcalls_make"); + // puts("before elfcalls_make"); elfcalls_make(calls); - puts("after elfcalls_make"); - printf("Will call %p\n", ret); + // puts("after elfcalls_make"); + // printf("Will call %p\n", ret); ret(); __builtin_unreachable(); diff --git a/src/libelfloader/native/elfcalls.h b/src/libelfloader/native/elfcalls.h index a2c856681..2476bd9a5 100644 --- a/src/libelfloader/native/elfcalls.h +++ b/src/libelfloader/native/elfcalls.h @@ -36,6 +36,8 @@ struct elf_calls // POSIX SHM APIs int (*shm_open)(const char* name, int oflag, unsigned short mode); int (*shm_unlink)(const char* name); + + void (*exit)(int ec); }; #endif diff --git a/src/libelfloader/native/threads.c b/src/libelfloader/native/threads.c index 9c9e886be..13749fe1c 100644 --- a/src/libelfloader/native/threads.c +++ b/src/libelfloader/native/threads.c @@ -1,7 +1,7 @@ /* This file is part of Darling. -Copyright (C) 2015 Lubos Dolezel +Copyright (C) 2015-2018 Lubos Dolezel Darling is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -27,6 +27,7 @@ along with Darling. If not, see . #include #include #include +#include // The point of this file is build macOS threads on top of native libc's threads, // otherwise it would not be possible to make native calls from these threads. @@ -46,23 +47,10 @@ struct arg_struct }; unsigned long pth_obj_size; void* pth; -}; -struct reaper_item -{ - struct reaper_item* next; - pthread_t thread; - void* stack; - size_t stacksize; + jmp_buf* jmpbuf; }; static void* darling_thread_entry(void* p); -static void start_reaper(); - -static sem_t reaper_sem; -static pthread_mutex_t reaper_mutex = PTHREAD_MUTEX_INITIALIZER; -static struct reaper_item *reaper_items_front = NULL, *reaper_items_end = NULL; -static void reaper_item_push(struct reaper_item* item); -static struct reaper_item* reaper_item_pop(void); #ifndef PTHREAD_STACK_MIN # define PTHREAD_STACK_MIN 16384 @@ -73,21 +61,17 @@ void* __darling_thread_create(unsigned long stack_size, unsigned long pth_obj_si uintptr_t arg4, uintptr_t arg5, uintptr_t arg6, int (*thread_self_trap)()) { - static pthread_once_t reaper_once = PTHREAD_ONCE_INIT; - struct arg_struct args = { (thread_ep) entry_point, arg3, arg4, arg5, arg6, thread_self_trap, pth_obj_size, NULL }; pthread_attr_t attr; pthread_t nativeLibcThread; void* pth; - pthread_once(&reaper_once, start_reaper); - pthread_attr_init(&attr); //pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); // pthread_attr_setstacksize(&attr, stack_size); - pth = mmap(NULL, stack_size + pth_obj_size + 0x1000, PROT_READ | PROT_WRITE, + pth = mmap(NULL, stack_size + pth_obj_size + 0x1000 + 0x1000, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); // pthread_attr_setstack is buggy. The documentation states we should provide the lowest @@ -97,7 +81,10 @@ void* __darling_thread_create(unsigned long stack_size, unsigned long pth_obj_si //pthread_attr_setstack(&attr, ((char*)pth) + pth_obj_size, stack_size - pth_obj_size - 0x1000); // std::cout << "Allocated stack at " << pth << ", size " << stack_size << std::endl; - pth = ((char*) pth) + stack_size + 0x1000; + + // We allocated an extra page for jmpbuf + args.jmpbuf = (jmp_buf*) pth; + pth = ((char*) pth) + stack_size + 0x2000; pthread_attr_setstacksize(&attr, 4096); args.pth = pth; @@ -120,6 +107,15 @@ static void* darling_thread_entry(void* p) args.port = args.thread_self_trap(); in_args->pth = NULL; + int freesize; + if ((freesize = setjmp(*args.jmpbuf)) != 0) + { + // Terminate the Linux thread + // +0x1000 is an extra page we allocated for the jmp_buf + munmap(args.jmpbuf, freesize + 0x1000); + return NULL; + } + #ifdef __x86_64__ __asm__ __volatile__ ( "movq %1, %%rdi\n" @@ -159,7 +155,7 @@ static void* darling_thread_entry(void* p) "ret\n" // Jump to the address pushed at the beginning :: "c" (&args), "d" (args.pth)); #endif - return NULL; + __builtin_unreachable(); } int __darling_thread_terminate(void* stackaddr, @@ -168,7 +164,7 @@ int __darling_thread_terminate(void* stackaddr, if (getpid() == syscall(SYS_gettid)) { // dispatch_main() calls pthread_exit(NULL) on the main thread, - // which turns the our process into a zombie. + // which turns our process into a zombie on Linux. // Let's just hang around forever. sigset_t mask; memset(&mask, 0, sizeof(mask)); @@ -176,16 +172,10 @@ int __darling_thread_terminate(void* stackaddr, while (1) sigsuspend(&mask); } - - struct reaper_item* item = (struct reaper_item*) malloc(sizeof(struct reaper_item)); - item->thread = pthread_self(); - item->stack = stackaddr; - item->stacksize = freesize; - reaper_item_push(item); - sem_post(&reaper_sem); - - pthread_exit(NULL); + // Jump back into darling_thread_entry() + jmp_buf* jmpbuf = (jmp_buf*) (((char*) stackaddr) - 0x1000); + longjmp(*jmpbuf, freesize); __builtin_unreachable(); } @@ -201,81 +191,3 @@ void* __darling_thread_get_stack(void) return ((char*)stackaddr) + stacksize - 0x2000; } - -static void* reaper_entry(void* unused) -{ - while (true) - { - struct reaper_item* item; - - sem_wait(&reaper_sem); - - item = reaper_item_pop(); - if (!item) - continue; // Should not happen! - - // std::cout << "Reaping thread " << (void*)item.thread << "; Free stack at " << item.stack << ", " << item.stacksize << " bytes\n"; - - // Wait for thread to terminate - pthread_join(item->thread, NULL); - - // Free its stack in the extended range requested by Darwin's libc - munmap(item->stack, item->stacksize); - - free(item); - } -} - -static void start_reaper() -{ - pthread_attr_t attr; - pthread_t thread; - - pthread_attr_init(&attr); - pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); - - sem_init(&reaper_sem, 0, 0); - pthread_create(&thread, &attr, reaper_entry, NULL); - pthread_attr_destroy(&attr); -} - -static void reaper_item_push(struct reaper_item* item) -{ - pthread_mutex_lock(&reaper_mutex); - - item->next = NULL; - if (reaper_items_end != NULL) - { - reaper_items_end->next = item; - reaper_items_end = item; - } - else - { - reaper_items_front = reaper_items_end = item; - } - - pthread_mutex_unlock(&reaper_mutex); -} - -static struct reaper_item* reaper_item_pop(void) -{ - struct reaper_item* e; - pthread_mutex_lock(&reaper_mutex); - - if (reaper_items_front != NULL) - { - e = reaper_items_front; - - if (reaper_items_front == reaper_items_end) - reaper_items_front = reaper_items_end = NULL; // The list is now empty - else - reaper_items_front = e->next; - } - else - e = NULL; - - pthread_mutex_unlock(&reaper_mutex); - - return e; -} - diff --git a/src/lkm b/src/lkm index dbede9eca..56f0a2d84 160000 --- a/src/lkm +++ b/src/lkm @@ -1 +1 @@ -Subproject commit dbede9ecaa789b8a8b869d8e2f38deb0d6262140 +Subproject commit 56f0a2d84783a26ef27e8dde0ba75f4d802be8cc