diff --git a/arch/x86-64/loader-entry.asm b/arch/sysv_x86-64/loader-entry.asm similarity index 100% rename from arch/x86-64/loader-entry.asm rename to arch/sysv_x86-64/loader-entry.asm diff --git a/arch/sysv_x86-64/thread-entry.asm b/arch/sysv_x86-64/thread-entry.asm new file mode 100644 index 0000000..6605efb --- /dev/null +++ b/arch/sysv_x86-64/thread-entry.asm @@ -0,0 +1,42 @@ + +bits 64 + +section .text +global _cia_clone + +; flags, &stack[-2], &parent_tid, &child_tid, 0 + +; DESCRIPTION: +; Function to be called when using the _clone syscall +; We don't just call the _clone syscall directly because +; if we call the clone syscall wrapper that's defined in +; linux/sys, our stack will be bad and we won't be able +; to return from the syscall wrapper +; PARAMETERS: +; rdi - flags +; rsi - stack_base +; rdx - parent_tid_ptr +; rcx - child_tid_ptr +; r8 - tls +; RETURNS: +; i64 value +; 0 if returning as a parent +; 1 if returning as a child +; negative value if there was an error making the thread +_cia_clone: + mov r10, rcx + sub rsi, 8 + ; As a child thread we wanna return to the same place as the parent + mov rax, qword [rsp] + mov qword [rsi], rax + ; ; Copy child tid ptr + ; mov qword [rsi + 0], rcx + ; Call syscall right away, since the order of the first 5 arguments + ; matches with the argument order of the function + mov rax, 56 ; SYS_CLONE + syscall + ; Check to see if we're child + test eax, eax + jnz .exit +.exit: + ret diff --git a/arch/x86-64/chkstk.asm b/arch/x64_x86-64/chkstk.asm similarity index 92% rename from arch/x86-64/chkstk.asm rename to arch/x64_x86-64/chkstk.asm index d3dfb6d..fa03d93 100644 --- a/arch/x86-64/chkstk.asm +++ b/arch/x64_x86-64/chkstk.asm @@ -1,3 +1,4 @@ + bits 64 segment .text diff --git a/build.py b/build.py index d05b757..5b00abd 100755 --- a/build.py +++ b/build.py @@ -75,16 +75,7 @@ if not os.path.exists('lib'): if not os.path.exists('bin'): os.mkdir('bin') -loader_flags = [ - '-Wl,-e,_dlstart', - '-Wl,--sort-section,alignment', - '-Wl,--sort-common', - '-Wl,--gc-sections', - '-Wl,--hash-style=both', - '-Wl,--no-undefined', - '-Wl,--exclude-libs=ALL' -] - +target_abi = 'sysv' target_arch = 'x86-64' target_os = 'linux' @@ -97,13 +88,24 @@ cc_includes.append('include') cc_includes.append('include/linux') # Build the dynamic loader +loader_flags = [ + '-Wl,-e,_dlstart', + '-Wl,--sort-section,alignment', + '-Wl,--sort-common', + '-Wl,--gc-sections', + '-Wl,--hash-style=both', + '-Wl,--no-undefined', + '-Wl,--exclude-libs=ALL' +] print_step("Building lib/ld-cia.so\n") -assemble_obj('bin/loader-entry.o', [f'arch/{target_arch}/loader-entry.asm'], ['-f "elf64"']) +assemble_obj('bin/loader-entry.o', [f'arch/{target_abi}_{target_arch}/loader-entry.asm'], ['-f "elf64"']) compile_shared('lib/ld-cia.so', ['bin/loader-entry.o','loader/loader-self-reloc.c','loader/loader.c'], loader_flags) # Build the ciabatta +print_step("Building lib/cia.a\n") +assemble_obj('bin/thread-entry.o', [f'arch/{target_abi}_{target_arch}/thread-entry.asm'], ['-f "elf64"']) compile_obj('bin/cia.o', ['cia.c']) -archive('lib/cia.a', ['bin/cia.o']) +archive('lib/cia.a', ['bin/cia.o', 'bin/thread-entry.o']) # Build the test -compile_exe('a', ['tests/hello.c', 'lib/cia.a'], ['-Wl,-dynamic-linker,lib/ld-cia.so']) +compile_exe('a', ['tests/threaded.c', 'lib/cia.a'], ['-Wl,-dynamic-linker,lib/ld-cia.so']) diff --git a/os/linux/tinyrt.c b/os/linux/tinyrt.c index 8d41864..9c40c8d 100644 --- a/os/linux/tinyrt.c +++ b/os/linux/tinyrt.c @@ -1,6 +1,15 @@ // See src/tinyrt.h file for the interface this file implements +extern i64 _cia_clone( + u64 flags, + void *stack_base, + int *parent_tid, + int *child_tid, + void *tls, + u64 stack_size +); + _Noreturn static void _rt_program_exit(int code) { sys_exit(code); } @@ -18,26 +27,27 @@ static _RT_Status _rt_thread_create(_RT_Thread *thread, void (*thread_fn)(void * if((i64)stack_base < 0) { return _RT_ERROR_GENERIC; } - u64 *stack = (void *)((u8 *)stack_base + stack_size); - stack[-1] = (u64)&&thread_return; - stack[-2] = 0; + void *stack = (u8*)stack_base + stack_size; // Create the new thread u64 flags = 0; - flags |= CLONE_CHILD_CLEARTID; - flags |= CLONE_PARENT_SETTID; + // flags |= CLONE_CHILD_CLEARTID; + // flags |= CLONE_PARENT_SETTID; flags |= CLONE_FS; flags |= CLONE_FILES; flags |= CLONE_SIGHAND; flags |= CLONE_THREAD; flags |= CLONE_VM; - int parent_tid = 0; - int child_tid = 0; - i64 cur_tid = sys_clone(flags, &stack[-2], &parent_tid, &child_tid, 0); -thread_return: - if(cur_tid < 0) { + flags |= CLONE_SYSVSEM; + int *temp_permanent_storage = stack_base; + int *child_tid = &temp_permanent_storage[0]; + int *parent_tid = &temp_permanent_storage[1]; + *child_tid = 1; + *parent_tid = 0; + i64 ret = _cia_clone(flags, stack, parent_tid, child_tid, 0, stack_size); + if(ret < 0) { return _RT_ERROR_GENERIC; } - if(cur_tid == child_tid) { + if(!ret) { thread_fn(ctx); } return _RT_STATUS_OK; diff --git a/tests/threaded.c b/tests/threaded.c index 089b374..8623306 100644 --- a/tests/threaded.c +++ b/tests/threaded.c @@ -12,11 +12,14 @@ int thrd_func(void *arg) { } int main() { - {char string[] = "main thred: before\n"; + {char string[] = "main thread: before!\n"; fwrite(string, 1, sizeof string-1, stdout);} + thrd_t thrd; thrd_create(&thrd, thrd_func, NULL); + {char string[] = "main thread: after!\n"; fwrite(string, 1, sizeof string-1, stdout);} + for(;;); return 0; }