From 94e3e3652f9f04810126ee754fa9a788289e2897 Mon Sep 17 00:00:00 2001 From: Prefetch Date: Mon, 24 Jul 2023 19:21:30 +0200 Subject: Reduce total code size by 53 bytes (big deal, right?) --- src/thread_create.asm | 52 +++++++++++++++++++++++++++++++-------------------- 1 file changed, 32 insertions(+), 20 deletions(-) (limited to 'src/thread_create.asm') diff --git a/src/thread_create.asm b/src/thread_create.asm index 9a6fe78..8dc8813 100644 --- a/src/thread_create.asm +++ b/src/thread_create.asm @@ -72,12 +72,16 @@ linen_thread_create: ; Callee-save registers push rbx + ; It's handy to have a register that's 0 for a while + xor ecx, ecx + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;; Check validity of arguments ;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - ; Return EINVAL if any argument is NULL - mov eax, -22 ; (EINVAL = -22) + ; Return EINVAL (-22) if any argument is NULL + lea eax, [rcx - 22] ; mov eax, -22 + test rdi, rdi jz create_return ; Nowhere to store the thread handle test rsi, rsi @@ -91,9 +95,9 @@ linen_thread_create: ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Save these registers: we'll clobber them for the mmap call - mov rbx, rdi - push rdx - push rsi + push rdx ; argument + push rsi ; function + push rdi ; thread handle destination ; The mmap system call does many things, in this case allocate memory. ; See: man 2 mmap @@ -103,25 +107,26 @@ linen_thread_create: ; mmap: rsi = length: size of buffer to allocate mov esi, (STACK_SIZE + GUARD_PAGE) ; mmap: rdx = prot: mprotect-style access permissions - mov edx, (PROT_WRITE | PROT_READ) + lea edx, [rcx + 3] ; mov edx, (PROT_READ | PROT_WRITE) ; mmap: r10 = flags: configuration flags for mapping: ; - MAP_ANONYMOUS: there is no file backing this buffer ; - MAP_PRIVATE: only this process can see thread's stack ; - MAP_STACK: no-op; inform kernel that this is a stack - mov r10, (MAP_ANONYMOUS | MAP_PRIVATE | MAP_STACK) + mov r10d, (MAP_ANONYMOUS | MAP_PRIVATE | MAP_STACK) ; mmap: r8 = fd: ignored for MAP_ANONYMOUS, recommended -1 - mov r8, -1 + lea r8, [rcx - 1] ; mov r8, -1 ; mmap: r9 = offset: should be 0 when MAP_ANONYMOUS is used xor r9, r9 ; mmap: rax = system call ID - mov eax, SYS_MMAP - ; mmap: rax = mmap(rdi, rsi, rdx, r10, r8, 9) + lea eax, [rcx + SYS_MMAP] ; mov eax, SYS_MMAP + ; mmap: rax = mmap(rdi, rsi, rdx, r10, (r8), (r9)) syscall ; Pop these now before we start branching. Those registers ; won't be used by the next system calls, so they're safe. - pop r8 ; function - pop r9 ; argument + pop rbx ; thread handle destination + pop r8 ; function + pop r9 ; argument ; Check result of mmap: negative means failure, ; otherwise rax is the address of the new mapping. @@ -145,12 +150,13 @@ linen_thread_create: ; mprotect: rdx = prot: access permissions; zero for none xor edx, edx ; mprotect: rax = system call ID - mov eax, SYS_MPROTECT + xor eax, eax + mov al, SYS_MPROTECT ; mprotect: rax = mprotect(rdi, rsi, rdx) syscall ; Check result of mprotect: nonzero means failure - test rax, rax + test eax, eax jnz create_return ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -162,7 +168,7 @@ linen_thread_create: ; once in the parent (0 if success) and once in the child (the TID). ; See: man 2 clone - ; clone: rsi = stack + ; clone: rsi = stack: pointer for child's initial rsp ; Currently rdi points to the lowest byte of the stack area. ; Again, stacks grow downward, so we calculate the address of ; the top qword to use as the child thread's starting point. @@ -194,14 +200,14 @@ linen_thread_create: ; clone: r8 = tls: ignored unless CLONE_SETTLS is used ; clone: rax = system call ID - mov eax, SYS_CLONE + mov al, SYS_CLONE ; clone: rax = clone(rdi, rsi, (rdx), r10, (r8)); syscall ; Ideally, both parent and new-born child are executing this code now. ; Check result of clone: - test rax, rax + test eax, eax js create_return ; Negative means failure jnz create_success ; Positive means we're in the parent thread ; Zero means we're in the child thread @@ -220,10 +226,16 @@ linen_thread_create: ; Once done, leave function's return value lying around push rax - ; Exit the thread with return value 0 + ; Exit the thread with status 0 using the exit system call. + ; See: man 2 exit + + ; exit: rdi = status to report xor edi, edi - mov rax, SYS_EXIT - syscall ; (never returns) + ; exit: rax = system call ID + xor eax, eax + mov al, SYS_EXIT + ; exit: call never returns + syscall ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;; Clean up in parent thread ;;;; -- cgit v1.2.3