; Threads management. ; int create_thread(int (*proc)(void *param), void *param, int stack_size) ; Creates a thread that executes the given function proc(param). ; Returns -1 on error, TID otherwise. ; If proc(param) returns, the returned value is passed to exit_thread(). ; If stack_size is zero, uses the value from PE header of the executable. proc create_thread stdcall uses ebx, thread_proc, param, stack_size ; 1. Determine stack size. ; Align stack_size up to page boundary; mov ecx, [stack_size] add ecx, 0xFFF and ecx, not 0xFFF jnz .stack_size_ok ; if this results in zero, read the value from the header of main module. mov eax, [modules_list + MODULE.next] mov eax, [eax + MODULE.base] mov ecx, [eax+STRIPPED_PE_HEADER.SizeOfStackReserve] cmp byte [eax], 'M' jnz .stack_size_ok mov ecx, [eax+3Ch] mov ecx, [eax+ecx+IMAGE_NT_HEADERS.OptionalHeader.SizeOfStackReserve] .stack_size_ok: mov [stack_size], ecx ; 2. Allocate the stack. mov eax, 68 mov ebx, 12 call FS_SYSCALL_PTR test eax, eax jz .fail ; 3. Copy parameters to the stack. lea edx, [eax+ecx-16] mov [edx], ecx mov ebx, FS_SYSCALL_PTR mov [edx+4], ebx mov ebx, [thread_proc] mov [edx+8], ebx mov ebx, [param] mov [edx+12], ebx ; 4. Call the kernel to create the thread. mov eax, 51 mov ebx, 1 mov ecx, internal_thread_start call FS_SYSCALL_PTR cmp eax, -1 jz .fail_free ret .fail_free: mov eax, 68 mov ebx, 13 lea ecx, [edx+12] sub ecx, [stack_size] call FS_SYSCALL_PTR xor eax, eax .fail: dec eax ret endp ; void exit_thread(int exit_code) ; Terminates the current thread. ; exit_code is reserved; currently ignored proc exit_thread stdcall, exit_code ; Use int 0x40 instead of call FS_SYSCALL_PTR, because we are freeing the stack. mov eax, 68 mov ebx, 13 mov ecx, FS_STACK_MIN int 0x40 or eax, -1 int 0x40 endp ; Real entry point of threads created by create_thread. ; Provides user-space initialization of the thread, ; calls user-provided thread routine, ; passes the returned value to exit_thread. proc internal_thread_start pop eax ; stack_size lea ecx, [esp+12] mov FS_STACK_MAX, ecx sub ecx, eax mov FS_STACK_MIN, ecx pop FS_SYSCALL_PTR ; from caller's FS_SYSCALL_PTR pop eax ; thread_proc call eax ; param is still on the stack push eax ; exit_code push 0 ; no return address jmp exit_thread endp