From adac42bad659c3c1234b9f5eec6496058a1b50d0 Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Thu, 8 Aug 2019 12:09:34 +0200 Subject: [PATCH] kernel32: Reimplement fiber switching in assembly. Signed-off-by: Alexandre Julliard --- dlls/kernel32/fiber.c | 188 ++++++++++++++++++++++++++++++++++-------- 1 file changed, 153 insertions(+), 35 deletions(-) diff --git a/dlls/kernel32/fiber.c b/dlls/kernel32/fiber.c index 27abd78760c..c3373b8dbbc 100644 --- a/dlls/kernel32/fiber.c +++ b/dlls/kernel32/fiber.c @@ -21,14 +21,8 @@ * - proper handling of 16-bit stack and signal stack */ -/* Fortify source chokes on siglongjmp stack switching, so disable it */ -#undef _FORTIFY_SOURCE -#define _FORTIFY_SOURCE 0 - #include "config.h" -#include "wine/port.h" -#include #include #define NONAMELESSUNION @@ -37,31 +31,144 @@ #include "winerror.h" #include "winternl.h" #include "wine/exception.h" -#include "wine/library.h" +#include "wine/asm.h" struct fiber_data { - LPVOID param; /* 00 fiber param */ - void *except; /* 04 saved exception handlers list */ - void *stack_base; /* 08 top of fiber stack */ - void *stack_limit; /* 0c fiber stack low-water mark */ - void *stack_allocation; /* 10 base of the fiber stack allocation */ - sigjmp_buf jmpbuf; /* 14 setjmp buffer (on Windows: CONTEXT) */ - DWORD flags; /* fiber flags */ - LPFIBER_START_ROUTINE start; /* start routine */ - void **fls_slots; /* fiber storage slots */ + LPVOID param; /* 00/00 fiber param */ + void *except; /* 04/08 saved exception handlers list */ + void *stack_base; /* 08/10 top of fiber stack */ + void *stack_limit; /* 0c/18 fiber stack low-water mark */ + void *stack_allocation; /* 10/20 base of the fiber stack allocation */ + CONTEXT context; /* 14/30 fiber context */ + DWORD flags; /* fiber flags */ + LPFIBER_START_ROUTINE start; /* start routine */ + void **fls_slots; /* fiber storage slots */ }; -/* call the fiber initial function once we have switched stack */ -static void start_fiber( void *arg ) +extern void WINAPI switch_fiber( CONTEXT *old, CONTEXT *new ); +#ifdef __i386__ +__ASM_STDCALL_FUNC( switch_fiber, 8, + "movl 4(%esp),%ecx\n\t" /* old */ + "movl %edi,0x9c(%ecx)\n\t" /* old->Edi */ + "movl %esi,0xa0(%ecx)\n\t" /* old->Esi */ + "movl %ebx,0xa4(%ecx)\n\t" /* old->Ebx */ + "movl %ebp,0xb4(%ecx)\n\t" /* old->Ebp */ + "movl 0(%esp),%eax\n\t" + "movl %eax,0xb8(%ecx)\n\t" /* old->Eip */ + "leal 12(%esp),%eax\n\t" + "movl %eax,0xc4(%ecx)\n\t" /* old->Esp */ + "movl 8(%esp),%ecx\n\t" /* new */ + "movl 0x9c(%ecx),%edi\n\t" /* new->Edi */ + "movl 0xa0(%ecx),%esi\n\t" /* new->Esi */ + "movl 0xa4(%ecx),%ebx\n\t" /* new->Ebx */ + "movl 0xb4(%ecx),%ebp\n\t" /* new->Ebp */ + "movl 0xc4(%ecx),%esp\n\t" /* new->Esp */ + "jmp *0xb8(%ecx)" ) /* new->Eip */ +#elif defined(__x86_64__) +__ASM_STDCALL_FUNC( switch_fiber, 8, + "movq %rbx,0x90(%rcx)\n\t" /* old->Rbx */ + "leaq 0x8(%rsp),%rax\n\t" + "movq %rax,0x98(%rcx)\n\t" /* old->Rsp */ + "movq %rbp,0xa0(%rcx)\n\t" /* old->Rbp */ + "movq %rsi,0xa8(%rcx)\n\t" /* old->Rsi */ + "movq %rdi,0xb0(%rcx)\n\t" /* old->Rdi */ + "movq %r12,0xd8(%rcx)\n\t" /* old->R12 */ + "movq %r13,0xe0(%rcx)\n\t" /* old->R13 */ + "movq %r14,0xe8(%rcx)\n\t" /* old->R14 */ + "movq %r15,0xf0(%rcx)\n\t" /* old->R15 */ + "movq (%rsp),%rax\n\t" + "movq %rax,0xf8(%rcx)\n\t" /* old->Rip */ + "movdqa %xmm6,0x200(%rcx)\n\t" /* old->Xmm6 */ + "movdqa %xmm7,0x210(%rcx)\n\t" /* old->Xmm7 */ + "movdqa %xmm8,0x220(%rcx)\n\t" /* old->Xmm8 */ + "movdqa %xmm9,0x230(%rcx)\n\t" /* old->Xmm9 */ + "movdqa %xmm10,0x240(%rcx)\n\t" /* old->Xmm10 */ + "movdqa %xmm11,0x250(%rcx)\n\t" /* old->Xmm11 */ + "movdqa %xmm12,0x260(%rcx)\n\t" /* old->Xmm12 */ + "movdqa %xmm13,0x270(%rcx)\n\t" /* old->Xmm13 */ + "movdqa %xmm14,0x280(%rcx)\n\t" /* old->Xmm14 */ + "movdqa %xmm15,0x290(%rcx)\n\t" /* old->Xmm15 */ + "movq 0x90(%rdx),%rbx\n\t" /* new->Rbx */ + "movq 0xa0(%rdx),%rbp\n\t" /* new->Rbp */ + "movq 0xa8(%rdx),%rsi\n\t" /* new->Rsi */ + "movq 0xb0(%rdx),%rdi\n\t" /* new->Rdi */ + "movq 0xd8(%rdx),%r12\n\t" /* new->R12 */ + "movq 0xe0(%rdx),%r13\n\t" /* new->R13 */ + "movq 0xe8(%rdx),%r14\n\t" /* new->R14 */ + "movq 0xf0(%rdx),%r15\n\t" /* new->R15 */ + "movdqa 0x200(%rdx),%xmm6\n\t" /* new->Xmm6 */ + "movdqa 0x210(%rdx),%xmm7\n\t" /* new->Xmm7 */ + "movdqa 0x220(%rdx),%xmm8\n\t" /* new->Xmm8 */ + "movdqa 0x230(%rdx),%xmm9\n\t" /* new->Xmm9 */ + "movdqa 0x240(%rdx),%xmm10\n\t" /* new->Xmm10 */ + "movdqa 0x250(%rdx),%xmm11\n\t" /* new->Xmm11 */ + "movdqa 0x260(%rdx),%xmm12\n\t" /* new->Xmm12 */ + "movdqa 0x270(%rdx),%xmm13\n\t" /* new->Xmm13 */ + "movdqa 0x280(%rdx),%xmm14\n\t" /* new->Xmm14 */ + "movdqa 0x290(%rdx),%xmm15\n\t" /* new->Xmm15 */ + "movq 0x98(%rdx),%rsp\n\t" /* new->Rsp */ + "jmp *0xf8(%rdx)" ) /* new->Rip */ +#elif defined(__arm__) +__ASM_STDCALL_FUNC( switch_fiber, 8, + "str r4, [r0, #0x14]\n\t" /* old->R4 */ + "str r5, [r0, #0x18]\n\t" /* old->R5 */ + "str r6, [r0, #0x1c]\n\t" /* old->R6 */ + "str r7, [r0, #0x20]\n\t" /* old->R7 */ + "str r8, [r0, #0x24]\n\t" /* old->R8 */ + "str r9, [r0, #0x28]\n\t" /* old->R9 */ + "str r10, [r0, #0x2c]\n\t" /* old->R10 */ + "str r11, [r0, #0x30]\n\t" /* old->R11 */ + "str sp, [r0, #0x38]\n\t" /* old->Sp */ + "str lr, [r0, #0x40]\n\t" /* old->Pc */ + "ldr r4, [r1, #0x14]\n\t" /* new->R4 */ + "ldr r5, [r1, #0x18]\n\t" /* new->R5 */ + "ldr r6, [r1, #0x1c]\n\t" /* new->R6 */ + "ldr r7, [r1, #0x20]\n\t" /* new->R7 */ + "ldr r8, [r1, #0x24]\n\t" /* new->R8 */ + "ldr r9, [r1, #0x28]\n\t" /* new->R9 */ + "ldr r10, [r1, #0x2c]\n\t" /* new->R10 */ + "ldr r11, [r1, #0x30]\n\t" /* new->R11 */ + "ldr sp, [r1, #0x38]\n\t" /* new->Sp */ + "ldr r2, [r1, #0x40]\n\t" /* new->Pc */ + "bx r2" ) +#elif defined(__aarch64__) +__ASM_STDCALL_FUNC( switch_fiber, 8, + "stp x19, x20, [x0, #0xa0]\n\t" /* old->X19,X20 */ + "stp x21, x22, [x0, #0xb0]\n\t" /* old->X21,X22 */ + "stp x23, x24, [x0, #0xc0]\n\t" /* old->X23,X24 */ + "stp x25, x26, [x0, #0xd0]\n\t" /* old->X25,X26 */ + "stp x27, x28, [x0, #0xe0]\n\t" /* old->X27,X28 */ + "str x29, [x0, #0xf0]\n\t" /* old->Fp */ + "mov x2, sp\n\t" + "str x2, [x0, #0x100]\n\t" /* old->Sp */ + "str x30, [x0, #0x108]\n\t" /* old->Pc */ + "ldp x19, x20, [x1, #0xa0]\n\t" /* new->X19,X20 */ + "ldp x21, x22, [x1, #0xb0]\n\t" /* new->X21,X22 */ + "ldp x23, x24, [x1, #0xc0]\n\t" /* new->X23,X24 */ + "ldp x25, x26, [x1, #0xd0]\n\t" /* new->X25,X26 */ + "ldp x27, x28, [x1, #0xe0]\n\t" /* new->X27,X28 */ + "ldr x29, [x1, #0xf0]\n\t" /* new->Fp */ + "ldr x2, [x1, #0x100]\n\t" /* new->Sp */ + "ldr x30, [x1, #0x108]\n\t" /* new->Pc */ + "mov sp, x2\n\t" + "ret" ) +#else +void WINAPI switch_fiber( CONTEXT *old, CONTEXT *new ) { - struct fiber_data *fiber = arg; + DbgBreakPoint(); +} +#endif + +/* call the fiber initial function once we have switched stack */ +static void CDECL start_fiber(void) +{ + struct fiber_data *fiber = NtCurrentTeb()->Tib.u.FiberData; LPFIBER_START_ROUTINE start = fiber->start; __TRY { - fiber->start = NULL; start( fiber->param ); ExitThread( 1 ); } @@ -72,6 +179,23 @@ static void start_fiber( void *arg ) __ENDTRY } +static void init_fiber_context( struct fiber_data *fiber ) +{ +#ifdef __i386__ + fiber->context.Esp = (ULONG_PTR)fiber->stack_base - 4; + fiber->context.Eip = (ULONG_PTR)start_fiber; +#elif defined(__x86_64__) + fiber->context.Rsp = (ULONG_PTR)fiber->stack_base - 0x28; + fiber->context.Rip = (ULONG_PTR)start_fiber; +#elif defined(__arm__) + fiber->context.Sp = (ULONG_PTR)fiber->stack_base; + fiber->context.Pc = (ULONG_PTR)start_fiber; +#elif defined(__aarch64__) + fiber->context.Sp = (ULONG_PTR)fiber->stack_base; + fiber->context.Pc = (ULONG_PTR)start_fiber; +#endif +} + /*********************************************************************** * CreateFiber (KERNEL32.@) @@ -92,7 +216,7 @@ LPVOID WINAPI CreateFiberEx( SIZE_T stack_commit, SIZE_T stack_reserve, DWORD fl INITIAL_TEB stack; NTSTATUS status; - if (!(fiber = HeapAlloc( GetProcessHeap(), 0, sizeof(*fiber) ))) + if (!(fiber = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*fiber) ))) { SetLastError( ERROR_NOT_ENOUGH_MEMORY ); return NULL; @@ -111,7 +235,7 @@ LPVOID WINAPI CreateFiberEx( SIZE_T stack_commit, SIZE_T stack_reserve, DWORD fl fiber->except = (void *)-1; fiber->start = start; fiber->flags = flags; - fiber->fls_slots = NULL; + init_fiber_context( fiber ); return fiber; } @@ -199,19 +323,13 @@ void WINAPI SwitchToFiber( LPVOID fiber ) /* stack_allocation and stack_base never change */ /* FIXME: should save floating point context if requested in fiber->flags */ - if (!sigsetjmp( current_fiber->jmpbuf, 0 )) - { - NtCurrentTeb()->Tib.u.FiberData = new_fiber; - NtCurrentTeb()->Tib.ExceptionList = new_fiber->except; - NtCurrentTeb()->Tib.StackBase = new_fiber->stack_base; - NtCurrentTeb()->Tib.StackLimit = new_fiber->stack_limit; - NtCurrentTeb()->DeallocationStack = new_fiber->stack_allocation; - NtCurrentTeb()->FlsSlots = new_fiber->fls_slots; - if (new_fiber->start) /* first time */ - wine_switch_to_stack( start_fiber, new_fiber, new_fiber->stack_base ); - else - siglongjmp( new_fiber->jmpbuf, 1 ); - } + NtCurrentTeb()->Tib.u.FiberData = new_fiber; + NtCurrentTeb()->Tib.ExceptionList = new_fiber->except; + NtCurrentTeb()->Tib.StackBase = new_fiber->stack_base; + NtCurrentTeb()->Tib.StackLimit = new_fiber->stack_limit; + NtCurrentTeb()->DeallocationStack = new_fiber->stack_allocation; + NtCurrentTeb()->FlsSlots = new_fiber->fls_slots; + switch_fiber( ¤t_fiber->context, &new_fiber->context ); } /***********************************************************************