-- v5: ntdll: Inline __wine_unix_call(_fast) dispatch in the syscall dispatcher. ntdll: Restore frame in return path of the x86 syscall dispatchers. winecrt0: Inline PE __wine_unix_call(_fast) function calls. ntdll: Only save non-volatile FPU registers for -nofpu syscalls. opengl32: Use __wine_unix_call_fast instead of __wine_unix_call. ntdll: Introduce a new __wine_unix_call_fast syscall. ntdll: Use -nofpu for NtQueryPerformanceCounter and NtYieldExecution. winebuild: Introduce a new -nofpu syscall spec flag. ntdll: Add support for syscall flags in the service CounterTable. ntdll: Avoid double indirection to get x86_64 syscall_frame pointer. ntdll: Check SYSCALL_HAVE_WRFSGSBASE syscall flag only for wrfsbase. ntdll: Swap %eax and %edx registers in the i386 syscall dispatcher. ntdll: Check syscall table and syscall number before saving FPU. ntdll: Use named labels for jumps in the syscall dispatcher.
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/ntdll/unix/signal_i386.c | 105 ++++++++++++++++++++------------ dlls/ntdll/unix/signal_x86_64.c | 103 +++++++++++++++++++------------ 2 files changed, 129 insertions(+), 79 deletions(-)
diff --git a/dlls/ntdll/unix/signal_i386.c b/dlls/ntdll/unix/signal_i386.c index 02322accf9e..2505575b343 100644 --- a/dlls/ntdll/unix/signal_i386.c +++ b/dlls/ntdll/unix/signal_i386.c @@ -2536,8 +2536,9 @@ __ASM_GLOBAL_FUNC( __wine_syscall_dispatcher, __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t") "popl 0x04(%ecx)\n\t" /* frame->eflags */ __ASM_CFI(".cfi_adjust_cfa_offset -4\n\t") - ".globl " __ASM_NAME("__wine_syscall_dispatcher_prolog_end") "\n" - __ASM_NAME("__wine_syscall_dispatcher_prolog_end") ":\n\t" + + ".globl " __ASM_NAME("__wine_syscall_dispatcher_prolog_end") "\n" + __ASM_NAME("__wine_syscall_dispatcher_prolog_end") ":\n\t" "movl %esp,0x0c(%ecx)\n\t" /* frame->esp */ __ASM_CFI_CFA_IS_AT1(ecx, 0x0c) __ASM_CFI_REG_IS_AT1(esp, ecx, 0x0c) @@ -2569,8 +2570,10 @@ __ASM_GLOBAL_FUNC( __wine_syscall_dispatcher, "shrl $8,%ebx\n\t" "andl $0x30,%ebx\n\t" /* syscall table number */ "addl 0x38(%ecx),%ebx\n\t" /* frame->syscall_table */ + + "\n.L__wine_syscall_dispatcher_save_fpu:\n\t" "testl $3,(%ecx)\n\t" /* frame->syscall_flags & (SYSCALL_HAVE_XSAVE | SYSCALL_HAVE_XSAVEC) */ - "jz 2f\n\t" + "jz .L__wine_syscall_dispatcher_no_xsave\n\t" "movl $7,%eax\n\t" "xorl %edx,%edx\n\t" "movl %edx,0x240(%ecx)\n\t" @@ -2580,7 +2583,7 @@ __ASM_GLOBAL_FUNC( __wine_syscall_dispatcher, "movl %edx,0x250(%ecx)\n\t" "movl %edx,0x254(%ecx)\n\t" "testl $2,(%ecx)\n\t" /* frame->syscall_flags & SYSCALL_HAVE_XSAVEC */ - "jz 1f\n\t" + "jz .L__wine_syscall_dispatcher_no_xsavec\n\t" "movl %edx,0x258(%ecx)\n\t" "movl %edx,0x25c(%ecx)\n\t" "movl %edx,0x260(%ecx)\n\t" @@ -2592,20 +2595,25 @@ __ASM_GLOBAL_FUNC( __wine_syscall_dispatcher, "movl %edx,0x278(%ecx)\n\t" "movl %edx,0x27c(%ecx)\n\t" "xsavec 0x40(%ecx)\n\t" - "jmp 4f\n" - "1:\txsave 0x40(%ecx)\n\t" - "jmp 4f\n" - "2:\ttestl $4,(%ecx)\n\t" /* frame->syscall_flags & SYSCALL_HAVE_FXSAVE */ - "jz 3f\n\t" + "jmp .L__wine_syscall_dispatcher_fpu_saved\n\t" + "\n.L__wine_syscall_dispatcher_no_xsavec:\n\t" + "xsave 0x40(%ecx)\n\t" + "jmp .L__wine_syscall_dispatcher_fpu_saved\n\t" + "\n.L__wine_syscall_dispatcher_no_xsave:\n\t" + "testl $4,(%ecx)\n\t" /* frame->syscall_flags & SYSCALL_HAVE_FXSAVE */ + "jz .L__wine_syscall_dispatcher_no_fxsave\n\t" "fxsave 0x40(%ecx)\n\t" - "jmp 4f\n" - "3:\tfnsave 0x40(%ecx)\n\t" - "fwait\n" - "4:\tmovl %ecx,%esp\n\t" + "jmp .L__wine_syscall_dispatcher_fpu_saved\n\t" + "\n.L__wine_syscall_dispatcher_no_fxsave:\n\t" + "fnsave 0x40(%ecx)\n\t" + "fwait\n\t" + + "\n.L__wine_syscall_dispatcher_fpu_saved:\n\t" + "movl %ecx,%esp\n\t" "movl 0x1c(%esp),%edx\n\t" /* frame->eax */ "andl $0xfff,%edx\n\t" /* syscall number */ "cmpl 8(%ebx),%edx\n\t" /* table->ServiceLimit */ - "jae 6f\n\t" + "jae .L__wine_syscall_dispatcher_invalid_arg\n\t" "movl 12(%ebx),%eax\n\t" /* table->ArgumentTable */ "movzbl (%eax,%edx,1),%ecx\n\t" "movl (%ebx),%eax\n\t" /* table->ServiceTable */ @@ -2616,8 +2624,9 @@ __ASM_GLOBAL_FUNC( __wine_syscall_dispatcher, "cld\n\t" "rep; movsl\n\t" "call *(%eax,%edx,4)\n\t" - "leal -0x34(%ebp),%esp\n" - "5:\t" + "leal -0x34(%ebp),%esp\n\t" + + "\n.L__wine_syscall_dispatcher_restore:\n\t" __ASM_CFI_CFA_IS_AT1(esp, 0x0c) __ASM_CFI_REG_IS_AT1(esp, esp, 0x0c) __ASM_CFI_REG_IS_AT1(eip, esp, 0x08) @@ -2627,22 +2636,29 @@ __ASM_GLOBAL_FUNC( __wine_syscall_dispatcher, __ASM_CFI_REG_IS_AT1(ebp, esp, 0x34) "movl 0(%esp),%ecx\n\t" /* frame->syscall_flags + (frame->restore_flags << 16) */ "testl $0x68 << 16,%ecx\n\t" /* CONTEXT_FLOATING_POINT | CONTEXT_EXTENDED_REGISTERS | CONTEXT_XSAVE */ - "jz 3f\n\t" + "jz .L__wine_syscall_dispatcher_fpu_restored\n\t" + + "\n.L__wine_syscall_dispatcher_restore_fpu:\n\t" "testl $3,%ecx\n\t" /* SYSCALL_HAVE_XSAVE | SYSCALL_HAVE_XSAVEC */ - "jz 1f\n\t" + "jz .L__wine_syscall_dispatcher_no_xrstor\n\t" "movl %eax,%esi\n\t" "movl $7,%eax\n\t" "xorl %edx,%edx\n\t" "xrstor 0x40(%esp)\n\t" "movl %esi,%eax\n\t" - "jmp 3f\n" - "1:\ttestl $4,%ecx\n\t" /* SYSCALL_HAVE_FXSAVE */ - "jz 2f\n\t" + "jmp .L__wine_syscall_dispatcher_fpu_restored\n\t" + "\n.L__wine_syscall_dispatcher_no_xrstor:\n\t" + "testl $4,%ecx\n\t" /* SYSCALL_HAVE_FXSAVE */ + "jz .L__wine_syscall_dispatcher_no_fxrstor\n\t" "fxrstor 0x40(%esp)\n\t" - "jmp 3f\n" - "2:\tfrstor 0x40(%esp)\n\t" - "fwait\n" - "3:\tmovl 0x2c(%esp),%edi\n\t" + "jmp .L__wine_syscall_dispatcher_fpu_restored\n\t" + "\n.L__wine_syscall_dispatcher_no_fxrstor:\n\t" + "frstor 0x40(%esp)\n\t" + "fwait\n\t" + + "\n.L__wine_syscall_dispatcher_fpu_restored:\n\t" + "movl 0x2c(%esp),%edi\n\t" + /* remember state when $esp is pointing to "frame" */ __ASM_CFI(".cfi_remember_state\n\t") __ASM_CFI(".cfi_same_value %edi\n\t") "movl 0x30(%esp),%esi\n\t" @@ -2650,22 +2666,27 @@ __ASM_GLOBAL_FUNC( __wine_syscall_dispatcher, "movl 0x34(%esp),%ebp\n\t" __ASM_CFI(".cfi_same_value %ebp\n\t") "testl $0x7 << 16,%ecx\n\t" /* CONTEXT_CONTROL | CONTEXT_SEGMENTS | CONTEXT_INTEGER */ - "jnz 1f\n\t" + "jnz .L__wine_syscall_dispatcher_restore_integer\n\t" "movl 0x20(%esp),%ebx\n\t" + /* remember state when $esp is pointing to partially restored "frame" */ __ASM_CFI(".cfi_remember_state\n\t") __ASM_CFI(".cfi_same_value %ebx\n\t") "movl 0x08(%esp),%ecx\n\t" /* frame->eip */ __ASM_CFI(".cfi_register %eip, %ecx\n\t") "movl 0x0c(%esp),%esp\n\t" /* frame->esp */ __ASM_CFI(".cfi_same_value %esp\n\t") - "jmpl *%ecx\n" - __ASM_CFI("\t.cfi_restore_state\n") - "1:\ttestl $0x2 << 16,%ecx\n\t" /* CONTEXT_INTEGER */ - "jz 1f\n\t" + "jmpl *%ecx\n\t" + + "\n.L__wine_syscall_dispatcher_restore_integer:\n\t" + /* $esp is now pointing to partially restored "frame" again */ + __ASM_CFI("\t.cfi_restore_state\n\t") + "testl $0x2 << 16,%ecx\n\t" /* CONTEXT_INTEGER */ + "jz .L__wine_syscall_dispatcher_restore_control\n\t" "movl 0x1c(%esp),%eax\n\t" "movl 0x24(%esp),%ecx\n\t" - "movl 0x28(%esp),%edx\n" - "1:\tmovl 0x0c(%esp),%ebx\n\t" /* frame->esp */ + "movl 0x28(%esp),%edx\n\t" + "\n.L__wine_syscall_dispatcher_restore_control:\n\t" + "movl 0x0c(%esp),%ebx\n\t" /* frame->esp */ __ASM_CFI(".cfi_register %esp, %ebx\n\t") "movw 0x12(%esp),%ss\n\t" "xchgl %ebx,%esp\n\t" @@ -2689,12 +2710,17 @@ __ASM_GLOBAL_FUNC( __wine_syscall_dispatcher, __ASM_CFI(".cfi_same_value %ebx\n\t") "popl %ds\n\t" __ASM_CFI(".cfi_adjust_cfa_offset -4\n\t") - "iret\n" - __ASM_CFI("\t.cfi_restore_state\n") - "6:\tmovl $0xc000000d,%eax\n\t" /* STATUS_INVALID_PARAMETER */ - "jmp 5b\n\t" - ".globl " __ASM_NAME("__wine_syscall_dispatcher_return") "\n" - __ASM_NAME("__wine_syscall_dispatcher_return") ":\n\t" + "iret\n\t" + + "\n.L__wine_syscall_dispatcher_invalid_arg:\n\t" + /* $esp is now pointing to "frame" again */ + __ASM_CFI("\t.cfi_restore_state\n\t") + "movl $0xc000000d,%eax\n\t" /* STATUS_INVALID_PARAMETER */ + "jmp .L__wine_syscall_dispatcher_restore\n\t" + + ".globl " __ASM_NAME("__wine_syscall_dispatcher_return") "\n" + __ASM_NAME("__wine_syscall_dispatcher_return") ":\n\t" + /* remember state when $esp is pointing to "frame" */ __ASM_CFI(".cfi_remember_state\n\t") __ASM_CFI(".cfi_def_cfa %esp, 4\n\t") __ASM_CFI(".cfi_restore %esp\n\t") @@ -2705,8 +2731,9 @@ __ASM_GLOBAL_FUNC( __wine_syscall_dispatcher, __ASM_CFI(".cfi_restore %ebp\n\t") "movl 8(%esp),%eax\n\t" "movl 4(%esp),%esp\n\t" + /* $esp is now pointing to "frame" again */ __ASM_CFI(".cfi_restore_state\n\t") - "jmp 5b" ) + "jmp .L__wine_syscall_dispatcher_restore\n\t" )
/*********************************************************************** diff --git a/dlls/ntdll/unix/signal_x86_64.c b/dlls/ntdll/unix/signal_x86_64.c index cc070dda5ae..6af8aa1a31d 100644 --- a/dlls/ntdll/unix/signal_x86_64.c +++ b/dlls/ntdll/unix/signal_x86_64.c @@ -2615,8 +2615,9 @@ __ASM_GLOBAL_FUNC( __wine_syscall_dispatcher, "popq 0x80(%rcx)\n\t" __ASM_CFI(".cfi_adjust_cfa_offset -8\n\t") "movl $0,0x94(%rcx)\n\t" /* frame->restore_flags */ - ".globl " __ASM_NAME("__wine_syscall_dispatcher_prolog_end") "\n" - __ASM_NAME("__wine_syscall_dispatcher_prolog_end") ":\n\t" + + ".globl " __ASM_NAME("__wine_syscall_dispatcher_prolog_end") "\n" + __ASM_NAME("__wine_syscall_dispatcher_prolog_end") ":\n\t" "movq %rax,0x00(%rcx)\n\t" "movq %rbx,0x08(%rcx)\n\t" __ASM_CFI_REG_IS_AT1(rbx, rcx, 0x08) @@ -2648,28 +2649,34 @@ __ASM_GLOBAL_FUNC( __wine_syscall_dispatcher, * depends on us returning to it. Adjust the return address accordingly. */ "subq $0xb,0x70(%rcx)\n\t" "movl 0xb0(%rcx),%r14d\n\t" /* frame->syscall_flags */ + + "\n.L__wine_syscall_dispatcher_save_fpu:\n\t" "testl $3,%r14d\n\t" /* SYSCALL_HAVE_XSAVE | SYSCALL_HAVE_XSAVEC */ - "jz 2f\n\t" + "jz .L__wine_syscall_dispatcher_no_xsave\n\t" "movl $7,%eax\n\t" "xorl %edx,%edx\n\t" "movq %rdx,0x2c0(%rcx)\n\t" "movq %rdx,0x2c8(%rcx)\n\t" "movq %rdx,0x2d0(%rcx)\n\t" "testl $2,%r14d\n\t" /* SYSCALL_HAVE_XSAVEC */ - "jz 1f\n\t" + "jz .L__wine_syscall_dispatcher_no_xsavec\n\t" "movq %rdx,0x2d8(%rcx)\n\t" "movq %rdx,0x2e0(%rcx)\n\t" "movq %rdx,0x2e8(%rcx)\n\t" "movq %rdx,0x2f0(%rcx)\n\t" "movq %rdx,0x2f8(%rcx)\n\t" "xsavec64 0xc0(%rcx)\n\t" - "jmp 3f\n" - "1:\txsave64 0xc0(%rcx)\n\t" - "jmp 3f\n" - "2:\tfxsave64 0xc0(%rcx)\n" + "jmp .L__wine_syscall_dispatcher_fpu_saved\n\t" + "\n.L__wine_syscall_dispatcher_no_xsavec:\n\t" + "xsave64 0xc0(%rcx)\n\t" + "jmp .L__wine_syscall_dispatcher_fpu_saved\n\t" + "\n.L__wine_syscall_dispatcher_no_xsave:\n\t" + "fxsave64 0xc0(%rcx)\n\t" + + "\n.L__wine_syscall_dispatcher_fpu_saved:\n\t" /* remember state when $rcx is pointing to "frame" */ __ASM_CFI(".cfi_remember_state\n\t") - "3:\tleaq 0x98(%rcx),%rbp\n\t" + "leaq 0x98(%rcx),%rbp\n\t" __ASM_CFI_CFA_IS_AT1(rbp, 0x70) __ASM_CFI_REG_IS_AT1(rsp, rbp, 0x70) __ASM_CFI_REG_IS_AT1(rip, rbp, 0x58) @@ -2683,17 +2690,18 @@ __ASM_GLOBAL_FUNC( __wine_syscall_dispatcher, __ASM_CFI_REG_IS_AT1(rbp, rbp, 0x00) #ifdef __linux__ "testl $12,%r14d\n\t" /* SYSCALL_HAVE_PTHREAD_TEB | SYSCALL_HAVE_WRFSGSBASE */ - "jz 2f\n\t" + "jz .L__wine_syscall_dispatcher_fsgs_swapped\n\t" "movq %gs:0x330,%rsi\n\t" /* amd64_thread_data()->pthread_teb */ "testl $8,%r14d\n\t" /* SYSCALL_HAVE_WRFSGSBASE */ - "jz 1f\n\t" + "jz .L__wine_syscall_dispatcher_no_wrfsbase\n\t" "wrfsbase %rsi\n\t" - "jmp 2f\n" - "1:\tmov $0x1002,%edi\n\t" /* ARCH_SET_FS */ + "jmp .L__wine_syscall_dispatcher_fsgs_swapped\n\t" + "\n.L__wine_syscall_dispatcher_no_wrfsbase:\n\t" + "mov $0x1002,%edi\n\t" /* ARCH_SET_FS */ "mov $158,%eax\n\t" /* SYS_arch_prctl */ "syscall\n\t" - "leaq -0x98(%rbp),%rcx\n" - "2:\n\t" + "leaq -0x98(%rbp),%rcx\n\t" + "\n.L__wine_syscall_dispatcher_fsgs_swapped:\n\t" #endif "leaq 0x28(%rsp),%rsi\n\t" /* first argument */ "movq %rcx,%rsp\n\t" @@ -2706,44 +2714,52 @@ __ASM_GLOBAL_FUNC( __wine_syscall_dispatcher, "leaq (%rcx,%rbx,2),%rbx\n\t" "andl $0xfff,%eax\n\t" /* syscall number */ "cmpq 16(%rbx),%rax\n\t" /* table->ServiceLimit */ - "jae 5f\n\t" + "jae .L__wine_syscall_dispatcher_invalid_arg\n\t" "movq 24(%rbx),%rcx\n\t" /* table->ArgumentTable */ "movzbl (%rcx,%rax),%ecx\n\t" "subq $0x20,%rcx\n\t" - "jbe 1f\n\t" + "jbe .L__wine_syscall_dispatcher_args_copied\n\t" "subq %rcx,%rsp\n\t" "shrq $3,%rcx\n\t" "andq $~15,%rsp\n\t" "movq %rsp,%rdi\n\t" "cld\n\t" - "rep; movsq\n" - "1:\tmovq %r10,%rcx\n\t" + "rep; movsq\n\t" + "\n.L__wine_syscall_dispatcher_args_copied:\n\t" + "movq %r10,%rcx\n\t" "subq $0x20,%rsp\n\t" "movq (%rbx),%r10\n\t" /* table->ServiceTable */ "callq *(%r10,%rax,8)\n\t" - "leaq -0x98(%rbp),%rcx\n" + "leaq -0x98(%rbp),%rcx\n\t" /* $rcx is now pointing to "frame" again */ __ASM_CFI(".cfi_restore_state\n\t") - "2:\tmovl 0x94(%rcx),%edx\n\t" /* frame->restore_flags */ + + "\n.L__wine_syscall_dispatcher_restore:\n\t" + "movl 0x94(%rcx),%edx\n\t" /* frame->restore_flags */ #ifdef __linux__ "testl $12,%r14d\n\t" /* SYSCALL_HAVE_PTHREAD_TEB | SYSCALL_HAVE_WRFSGSBASE */ - "jz 1f\n\t" - "movw 0x7e(%rcx),%fs\n" - "1:\n\t" + "jz .L__wine_syscall_dispatcher_fsgs_restored\n\t" + "movw 0x7e(%rcx),%fs\n\t" + "\n.L__wine_syscall_dispatcher_fsgs_restored:\n\t" #endif "testl $0x48,%edx\n\t" /* CONTEXT_FLOATING_POINT | CONTEXT_XSTATE */ - "jz 4f\n\t" + "jz .L__wine_syscall_dispatcher_fpu_restored\n\t" + + "\n.L__wine_syscall_dispatcher_restore_fpu:\n\t" "testl $3,%r14d\n\t" /* SYSCALL_HAVE_XSAVE | SYSCALL_HAVE_XSAVEC */ - "jz 3f\n\t" + "jz .L__wine_syscall_dispatcher_no_xrstor\n\t" "movq %rax,%r11\n\t" "movl $7,%eax\n\t" "xorl %edx,%edx\n\t" "xrstor64 0xc0(%rcx)\n\t" "movq %r11,%rax\n\t" "movl 0x94(%rcx),%edx\n\t" - "jmp 4f\n" - "3:\tfxrstor64 0xc0(%rcx)\n" - "4:\tmovq 0x98(%rcx),%rbp\n\t" + "jmp .L__wine_syscall_dispatcher_fpu_restored\n\t" + "\n.L__wine_syscall_dispatcher_no_xrstor:\n\t" + "fxrstor64 0xc0(%rcx)\n\t" + + "\n.L__wine_syscall_dispatcher_fpu_restored:\n\t" + "movq 0x98(%rcx),%rbp\n\t" __ASM_CFI(".cfi_same_value rbp\n\t") "movq 0x68(%rcx),%r15\n\t" __ASM_CFI(".cfi_same_value r15\n\t") @@ -2760,7 +2776,7 @@ __ASM_GLOBAL_FUNC( __wine_syscall_dispatcher, "movq 0x08(%rcx),%rbx\n\t" __ASM_CFI(".cfi_same_value rbx\n\t") "testl $0x3,%edx\n\t" /* CONTEXT_CONTROL | CONTEXT_INTEGER */ - "jnz 1f\n\t" + "jnz .L__wine_syscall_dispatcher_restore_control\n\t" __ASM_CFI(".cfi_remember_state\n\t") "movq 0x80(%rcx),%r11\n\t" /* frame->eflags */ "pushq %r11\n\t" @@ -2775,25 +2791,29 @@ __ASM_GLOBAL_FUNC( __wine_syscall_dispatcher, __ASM_CFI(".cfi_restore_state\n\t") /* remember state when $rcx is pointing to "frame" */ __ASM_CFI(".cfi_remember_state\n\t") - "1:\tleaq 0x70(%rcx),%rsp\n\t" + + "\n.L__wine_syscall_dispatcher_restore_control:\n\t" + "leaq 0x70(%rcx),%rsp\n\t" __ASM_CFI_CFA_IS_AT1(rsp, 0x18) __ASM_CFI_REG_IS_AT1(rsp, rsp, 0x18) __ASM_CFI_REG_IS_AT1(rip, rsp, 0x00) "testl $0x2,%edx\n\t" /* CONTEXT_INTEGER */ - "jnz 1f\n\t" + "jnz .L__wine_syscall_dispatcher_restore_integer\n\t" "movq 0x10(%rsp),%r11\n\t" /* frame->eflags */ "movq (%rsp),%rcx\n\t" /* frame->rip */ __ASM_CFI(".cfi_register rip, rcx\n\t") - "iretq\n" + "iretq\n\t" __ASM_CFI_REG_IS_AT1(rip, rsp, 0x00) - "1:\tmovq 0x00(%rcx),%rax\n\t" + + "\n.L__wine_syscall_dispatcher_restore_integer:\n\t" + "movq 0x00(%rcx),%rax\n\t" "movq 0x18(%rcx),%rdx\n\t" "movq 0x30(%rcx),%r8\n\t" "movq 0x38(%rcx),%r9\n\t" "movq 0x40(%rcx),%r10\n\t" "movq 0x48(%rcx),%r11\n\t" - "movq 0x10(%rcx),%rcx\n" - "iretq\n" + "movq 0x10(%rcx),%rcx\n\t" + "iretq\n\t" __ASM_CFI_CFA_IS_AT1(rbp, 0x70) __ASM_CFI_REG_IS_AT1(rsp, rbp, 0x70) __ASM_CFI_REG_IS_AT1(rip, rbp, 0x58) @@ -2805,15 +2825,18 @@ __ASM_GLOBAL_FUNC( __wine_syscall_dispatcher, __ASM_CFI_REG_IS_AT1(r14, rbp, 0x48) __ASM_CFI_REG_IS_AT1(r15, rbp, 0x50) __ASM_CFI_REG_IS_AT1(rbp, rbp, 0x00) - "5:\tmovl $0xc000000d,%edx\n\t" /* STATUS_INVALID_PARAMETER */ + + "\n.L__wine_syscall_dispatcher_invalid_arg:\n\t" + "movl $0xc000000d,%edx\n\t" /* STATUS_INVALID_PARAMETER */ "movq %rsp,%rcx\n\t" /* $rcx is now pointing to "frame" again */ __ASM_CFI(".cfi_restore_state\n\t") - ".globl " __ASM_NAME("__wine_syscall_dispatcher_return") "\n" - __ASM_NAME("__wine_syscall_dispatcher_return") ":\n\t" + + ".globl " __ASM_NAME("__wine_syscall_dispatcher_return") "\n" + __ASM_NAME("__wine_syscall_dispatcher_return") ":\n\t" "movl 0xb0(%rcx),%r14d\n\t" /* frame->syscall_flags */ "movq %rdx,%rax\n\t" - "jmp 2b" ) + "jmp .L__wine_syscall_dispatcher_restore\n\t" )
/***********************************************************************
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/ntdll/unix/signal_i386.c | 10 +++++++--- dlls/ntdll/unix/signal_x86_64.c | 33 ++++++++++----------------------- 2 files changed, 17 insertions(+), 26 deletions(-)
diff --git a/dlls/ntdll/unix/signal_i386.c b/dlls/ntdll/unix/signal_i386.c index 2505575b343..babc4190cff 100644 --- a/dlls/ntdll/unix/signal_i386.c +++ b/dlls/ntdll/unix/signal_i386.c @@ -2565,11 +2565,16 @@ __ASM_GLOBAL_FUNC( __wine_syscall_dispatcher, __ASM_CFI_REG_IS_AT1(edi, ebp, 0x78) __ASM_CFI_REG_IS_AT1(esi, ebp, 0x7c) __ASM_CFI_REG_IS_AT1(ebp, ebp, 0x00) - "leal 4(%esp),%esi\n\t" /* first argument */ + + "\n.L__wine_syscall_dispatcher_check_syscall:\n\t" "movl %eax,%ebx\n\t" "shrl $8,%ebx\n\t" "andl $0x30,%ebx\n\t" /* syscall table number */ "addl 0x38(%ecx),%ebx\n\t" /* frame->syscall_table */ + "movl 0x1c(%ecx),%eax\n\t" /* frame->eax */ + "andl $0xfff,%eax\n\t" /* syscall number */ + "cmpl 8(%ebx),%eax\n\t" /* table->ServiceLimit */ + "jae .L__wine_syscall_dispatcher_invalid_arg\n\t"
"\n.L__wine_syscall_dispatcher_save_fpu:\n\t" "testl $3,(%ecx)\n\t" /* frame->syscall_flags & (SYSCALL_HAVE_XSAVE | SYSCALL_HAVE_XSAVEC) */ @@ -2609,11 +2614,10 @@ __ASM_GLOBAL_FUNC( __wine_syscall_dispatcher, "fwait\n\t"
"\n.L__wine_syscall_dispatcher_fpu_saved:\n\t" + "leal 4(%esp),%esi\n\t" /* first argument */ "movl %ecx,%esp\n\t" "movl 0x1c(%esp),%edx\n\t" /* frame->eax */ "andl $0xfff,%edx\n\t" /* syscall number */ - "cmpl 8(%ebx),%edx\n\t" /* table->ServiceLimit */ - "jae .L__wine_syscall_dispatcher_invalid_arg\n\t" "movl 12(%ebx),%eax\n\t" /* table->ArgumentTable */ "movzbl (%eax,%edx,1),%ecx\n\t" "movl (%ebx),%eax\n\t" /* table->ServiceTable */ diff --git a/dlls/ntdll/unix/signal_x86_64.c b/dlls/ntdll/unix/signal_x86_64.c index 6af8aa1a31d..abf96a9f740 100644 --- a/dlls/ntdll/unix/signal_x86_64.c +++ b/dlls/ntdll/unix/signal_x86_64.c @@ -2648,7 +2648,17 @@ __ASM_GLOBAL_FUNC( __wine_syscall_dispatcher, /* Legends of Runeterra hooks the first system call return instruction, and * depends on us returning to it. Adjust the return address accordingly. */ "subq $0xb,0x70(%rcx)\n\t" + + "\n.L__wine_syscall_dispatcher_check_syscall:\n\t" + "movl %eax,%ebx\n\t" "movl 0xb0(%rcx),%r14d\n\t" /* frame->syscall_flags */ + "shrl $7,%ebx\n\t" + "andl $0x60,%ebx\n\t" /* syscall table number */ + "movq 0xa8(%rcx),%rdx\n\t" /* frame->syscall_table */ + "leaq (%rdx,%rbx),%rbx\n\t" + "andl $0xfff,%eax\n\t" /* syscall number */ + "cmpq 16(%rbx),%rax\n\t" /* table->ServiceLimit */ + "jae .L__wine_syscall_dispatcher_invalid_arg\n\t"
"\n.L__wine_syscall_dispatcher_save_fpu:\n\t" "testl $3,%r14d\n\t" /* SYSCALL_HAVE_XSAVE | SYSCALL_HAVE_XSAVEC */ @@ -2707,14 +2717,7 @@ __ASM_GLOBAL_FUNC( __wine_syscall_dispatcher, "movq %rcx,%rsp\n\t" "movq 0x00(%rcx),%rax\n\t" "movq 0x18(%rcx),%rdx\n\t" - "movl %eax,%ebx\n\t" - "shrl $8,%ebx\n\t" - "andl $0x30,%ebx\n\t" /* syscall table number */ - "movq 0xa8(%rcx),%rcx\n\t" /* frame->syscall_table */ - "leaq (%rcx,%rbx,2),%rbx\n\t" "andl $0xfff,%eax\n\t" /* syscall number */ - "cmpq 16(%rbx),%rax\n\t" /* table->ServiceLimit */ - "jae .L__wine_syscall_dispatcher_invalid_arg\n\t" "movq 24(%rbx),%rcx\n\t" /* table->ArgumentTable */ "movzbl (%rcx,%rax),%ecx\n\t" "subq $0x20,%rcx\n\t" @@ -2789,8 +2792,6 @@ __ASM_GLOBAL_FUNC( __wine_syscall_dispatcher, "jmpq *%rcx\n\t" /* $rcx is now pointing to "frame" again */ __ASM_CFI(".cfi_restore_state\n\t") - /* remember state when $rcx is pointing to "frame" */ - __ASM_CFI(".cfi_remember_state\n\t")
"\n.L__wine_syscall_dispatcher_restore_control:\n\t" "leaq 0x70(%rcx),%rsp\n\t" @@ -2814,23 +2815,9 @@ __ASM_GLOBAL_FUNC( __wine_syscall_dispatcher, "movq 0x48(%rcx),%r11\n\t" "movq 0x10(%rcx),%rcx\n\t" "iretq\n\t" - __ASM_CFI_CFA_IS_AT1(rbp, 0x70) - __ASM_CFI_REG_IS_AT1(rsp, rbp, 0x70) - __ASM_CFI_REG_IS_AT1(rip, rbp, 0x58) - __ASM_CFI_REG_IS_AT2(rbx, rbp, 0xf0, 0x7e) - __ASM_CFI_REG_IS_AT2(rsi, rbp, 0x88, 0x7f) - __ASM_CFI_REG_IS_AT2(rdi, rbp, 0x90, 0x7f) - __ASM_CFI_REG_IS_AT2(r12, rbp, 0xb8, 0x7f) - __ASM_CFI_REG_IS_AT1(r13, rbp, 0x40) - __ASM_CFI_REG_IS_AT1(r14, rbp, 0x48) - __ASM_CFI_REG_IS_AT1(r15, rbp, 0x50) - __ASM_CFI_REG_IS_AT1(rbp, rbp, 0x00)
"\n.L__wine_syscall_dispatcher_invalid_arg:\n\t" "movl $0xc000000d,%edx\n\t" /* STATUS_INVALID_PARAMETER */ - "movq %rsp,%rcx\n\t" - /* $rcx is now pointing to "frame" again */ - __ASM_CFI(".cfi_restore_state\n\t")
".globl " __ASM_NAME("__wine_syscall_dispatcher_return") "\n" __ASM_NAME("__wine_syscall_dispatcher_return") ":\n\t"
From: Rémi Bernon rbernon@codeweavers.com
Using %eax more consistently as the syscall number. --- dlls/ntdll/unix/signal_i386.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/dlls/ntdll/unix/signal_i386.c b/dlls/ntdll/unix/signal_i386.c index babc4190cff..ed344d11e1b 100644 --- a/dlls/ntdll/unix/signal_i386.c +++ b/dlls/ntdll/unix/signal_i386.c @@ -2616,18 +2616,18 @@ __ASM_GLOBAL_FUNC( __wine_syscall_dispatcher, "\n.L__wine_syscall_dispatcher_fpu_saved:\n\t" "leal 4(%esp),%esi\n\t" /* first argument */ "movl %ecx,%esp\n\t" - "movl 0x1c(%esp),%edx\n\t" /* frame->eax */ - "andl $0xfff,%edx\n\t" /* syscall number */ - "movl 12(%ebx),%eax\n\t" /* table->ArgumentTable */ - "movzbl (%eax,%edx,1),%ecx\n\t" - "movl (%ebx),%eax\n\t" /* table->ServiceTable */ + "movl 0x1c(%esp),%eax\n\t" /* frame->eax */ + "andl $0xfff,%eax\n\t" /* syscall number */ + "movl 12(%ebx),%edx\n\t" /* table->ArgumentTable */ + "movzbl (%edx,%eax,1),%ecx\n\t" + "movl (%ebx),%edx\n\t" /* table->ServiceTable */ "subl %ecx,%esp\n\t" "shrl $2,%ecx\n\t" "andl $~15,%esp\n\t" "movl %esp,%edi\n\t" "cld\n\t" "rep; movsl\n\t" - "call *(%eax,%edx,4)\n\t" + "call *(%edx,%eax,4)\n\t" "leal -0x34(%ebp),%esp\n\t"
"\n.L__wine_syscall_dispatcher_restore:\n\t"
From: Rémi Bernon rbernon@codeweavers.com
SYSCALL_HAVE_PTHREAD_TEB is always set when SYSCALL_HAVE_WRFSGSBASE is, there is no point testing both flags at once. --- dlls/ntdll/unix/signal_x86_64.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/dlls/ntdll/unix/signal_x86_64.c b/dlls/ntdll/unix/signal_x86_64.c index abf96a9f740..9e4f4046d43 100644 --- a/dlls/ntdll/unix/signal_x86_64.c +++ b/dlls/ntdll/unix/signal_x86_64.c @@ -1613,7 +1613,7 @@ __ASM_GLOBAL_FUNC( call_user_mode_callback, "movq %r10,0xa0(%rsp)\n\t" /* frame->prev_frame */ "movq %rsp,0x328(%r11)\n\t" /* amd64_thread_data()->syscall_frame */ #ifdef __linux__ - "testl $12,%r14d\n\t" /* SYSCALL_HAVE_PTHREAD_TEB | SYSCALL_HAVE_WRFSGSBASE */ + "testl $4,%r14d\n\t" /* SYSCALL_HAVE_PTHREAD_TEB */ "jz 1f\n\t" "movw 0x338(%r11),%fs\n" /* amd64_thread_data()->fs */ "1:\n\t" @@ -2699,7 +2699,7 @@ __ASM_GLOBAL_FUNC( __wine_syscall_dispatcher, __ASM_CFI_REG_IS_AT1(r15, rbp, 0x50) __ASM_CFI_REG_IS_AT1(rbp, rbp, 0x00) #ifdef __linux__ - "testl $12,%r14d\n\t" /* SYSCALL_HAVE_PTHREAD_TEB | SYSCALL_HAVE_WRFSGSBASE */ + "testl $4,%r14d\n\t" /* SYSCALL_HAVE_PTHREAD_TEB */ "jz .L__wine_syscall_dispatcher_fsgs_swapped\n\t" "movq %gs:0x330,%rsi\n\t" /* amd64_thread_data()->pthread_teb */ "testl $8,%r14d\n\t" /* SYSCALL_HAVE_WRFSGSBASE */ @@ -2740,7 +2740,7 @@ __ASM_GLOBAL_FUNC( __wine_syscall_dispatcher, "\n.L__wine_syscall_dispatcher_restore:\n\t" "movl 0x94(%rcx),%edx\n\t" /* frame->restore_flags */ #ifdef __linux__ - "testl $12,%r14d\n\t" /* SYSCALL_HAVE_PTHREAD_TEB | SYSCALL_HAVE_WRFSGSBASE */ + "testl $4,%r14d\n\t" /* SYSCALL_HAVE_PTHREAD_TEB */ "jz .L__wine_syscall_dispatcher_fsgs_restored\n\t" "movw 0x7e(%rcx),%fs\n\t" "\n.L__wine_syscall_dispatcher_fsgs_restored:\n\t"
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/ntdll/unix/signal_x86_64.c | 4 ++++ 1 file changed, 4 insertions(+)
diff --git a/dlls/ntdll/unix/signal_x86_64.c b/dlls/ntdll/unix/signal_x86_64.c index 9e4f4046d43..798de6d6c28 100644 --- a/dlls/ntdll/unix/signal_x86_64.c +++ b/dlls/ntdll/unix/signal_x86_64.c @@ -2605,8 +2605,12 @@ __ASM_GLOBAL_FUNC( signal_exit_thread, * __wine_syscall_dispatcher */ __ASM_GLOBAL_FUNC( __wine_syscall_dispatcher, +#ifdef __linux__ + "movq %gs:0x328,%rcx\n\t" /* amd64_thread_data()->syscall_frame */ +#else "movq %gs:0x30,%rcx\n\t" "movq 0x328(%rcx),%rcx\n\t" /* amd64_thread_data()->syscall_frame */ +#endif "popq 0x70(%rcx)\n\t" /* frame->rip */ __ASM_CFI(".cfi_adjust_cfa_offset -8\n\t") __ASM_CFI_REG_IS_AT2(rip, rcx, 0xf0,0x00)
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/ntdll/unix/loader.c | 25 ++++++++++++++++++------- dlls/win32u/syscall.c | 3 ++- 2 files changed, 20 insertions(+), 8 deletions(-)
diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c index 3bb7f056b2a..cbfd1dacc90 100644 --- a/dlls/ntdll/unix/loader.c +++ b/dlls/ntdll/unix/loader.c @@ -364,6 +364,7 @@ static void * const syscalls[] = wine_unix_to_nt_file_name, };
+static ULONG_PTR syscall_flags[ARRAY_SIZE(syscalls)]; static BYTE syscall_args[ARRAY_SIZE(syscalls)];
SYSTEM_SERVICE_TABLE KeServiceDescriptorTable[4]; @@ -1335,20 +1336,30 @@ already_loaded: NTSTATUS ntdll_init_syscalls( ULONG id, SYSTEM_SERVICE_TABLE *table, void **dispatcher ) { struct syscall_info + { + BYTE syscall_args; + }; + struct syscall_table_info { void *dispatcher; USHORT limit; - BYTE args[1]; - } *info = (struct syscall_info *)dispatcher; + struct syscall_info info[1]; + } *table_info = (struct syscall_table_info *)dispatcher; + USHORT i;
if (id > 3) return STATUS_INVALID_PARAMETER; - if (info->limit != table->ServiceLimit) + if (table_info->limit != table->ServiceLimit) { - ERR( "syscall count mismatch %u / %lu\n", info->limit, table->ServiceLimit ); + ERR( "syscall count mismatch %u / %lu\n", table_info->limit, table->ServiceLimit ); NtTerminateProcess( GetCurrentProcess(), STATUS_INVALID_PARAMETER ); } - info->dispatcher = __wine_syscall_dispatcher; - memcpy( table->ArgumentTable, info->args, table->ServiceLimit ); + table_info->dispatcher = __wine_syscall_dispatcher; + + for (i = 0; i < table_info->limit; ++i) + { + table->ArgumentTable[i] = table_info->info[i].syscall_args; + } + KeServiceDescriptorTable[id] = *table; return STATUS_SUCCESS; } @@ -2174,7 +2185,7 @@ const unixlib_entry_t __wine_unix_call_wow64_funcs[] = */ static void start_main_thread(void) { - SYSTEM_SERVICE_TABLE syscall_table = { (ULONG_PTR *)syscalls, NULL, ARRAY_SIZE(syscalls), syscall_args }; + SYSTEM_SERVICE_TABLE syscall_table = { (ULONG_PTR *)syscalls, syscall_flags, ARRAY_SIZE(syscalls), syscall_args }; TEB *teb = virtual_alloc_first_teb();
signal_init_threading(); diff --git a/dlls/win32u/syscall.c b/dlls/win32u/syscall.c index ec6cd859ff6..e6e0de2f07c 100644 --- a/dlls/win32u/syscall.c +++ b/dlls/win32u/syscall.c @@ -306,12 +306,13 @@ static void * const syscalls[] = NtUserWindowFromPoint, };
+static ULONG_PTR syscall_flags[ARRAY_SIZE(syscalls)]; static BYTE arguments[ARRAY_SIZE(syscalls)];
static SYSTEM_SERVICE_TABLE syscall_table = { (ULONG_PTR *)syscalls, - 0, + syscall_flags, ARRAY_SIZE(syscalls), arguments };
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/ntdll/unix/loader.c | 2 ++ dlls/ntdll/unix/unix_private.h | 2 ++ tools/winebuild/build.h | 1 + tools/winebuild/import.c | 9 ++++++++- tools/winebuild/parser.c | 6 ++++++ tools/winebuild/winebuild.man.in | 4 ++++ 6 files changed, 23 insertions(+), 1 deletion(-)
diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c index cbfd1dacc90..72727d3d789 100644 --- a/dlls/ntdll/unix/loader.c +++ b/dlls/ntdll/unix/loader.c @@ -1338,6 +1338,7 @@ NTSTATUS ntdll_init_syscalls( ULONG id, SYSTEM_SERVICE_TABLE *table, void **disp struct syscall_info { BYTE syscall_args; + BYTE syscall_nofpu; }; struct syscall_table_info { @@ -1358,6 +1359,7 @@ NTSTATUS ntdll_init_syscalls( ULONG id, SYSTEM_SERVICE_TABLE *table, void **disp for (i = 0; i < table_info->limit; ++i) { table->ArgumentTable[i] = table_info->info[i].syscall_args; + if (table_info->info[i].syscall_nofpu) table->CounterTable[i] |= SYSCALL_FLAG_NOFPU; }
KeServiceDescriptorTable[id] = *table; diff --git a/dlls/ntdll/unix/unix_private.h b/dlls/ntdll/unix/unix_private.h index a7fae7ab7ab..c34ce872930 100644 --- a/dlls/ntdll/unix/unix_private.h +++ b/dlls/ntdll/unix/unix_private.h @@ -96,6 +96,8 @@ static const LONG teb_offset = 0x2000; #define FILE_WRITE_TO_END_OF_FILE ((LONGLONG)-1) #define FILE_USE_FILE_POINTER_POSITION ((LONGLONG)-2)
+#define SYSCALL_FLAG_NOFPU 0x80000000 + /* callbacks to PE ntdll from the Unix side */ extern void (WINAPI *pDbgUiRemoteBreakin)( void *arg ) DECLSPEC_HIDDEN; extern NTSTATUS (WINAPI *pKiRaiseUserExceptionDispatcher)(void) DECLSPEC_HIDDEN; diff --git a/tools/winebuild/build.h b/tools/winebuild/build.h index 576304cd2b8..216f6859fe7 100644 --- a/tools/winebuild/build.h +++ b/tools/winebuild/build.h @@ -189,6 +189,7 @@ static inline int is_pe(void) #define FLAG_FASTCALL 0x0100 /* function uses fastcall calling convention */ #define FLAG_SYSCALL 0x0200 /* function is a system call */ #define FLAG_IMPORT 0x0400 /* export is imported from another module */ +#define FLAG_NOFPU 0x0800 /* function skips default syscall FPU save / restore */
#define FLAG_FORWARD 0x1000 /* function is a forwarded name */ #define FLAG_EXT_LINK 0x2000 /* function links to an external symbol */ diff --git a/tools/winebuild/import.c b/tools/winebuild/import.c index 9f87adcf593..905e6262650 100644 --- a/tools/winebuild/import.c +++ b/tools/winebuild/import.c @@ -1495,12 +1495,19 @@ void output_syscalls( DLLSPEC *spec ) default: break; } + + /* struct syscall_table_info */ output( "\t.data\n" ); output( "\t.align %d\n", get_alignment( get_ptr_size() ) ); output( "%s\n", asm_globl("__wine_syscall_dispatcher") ); output( "\t%s 0\n", get_asm_ptr_keyword() ); output( "\t.short %u\n", count ); - for (i = 0; i < count; i++) output( "\t.byte %u\n", get_args_size( syscalls[i] )); + + for (i = 0; i < count; i++) /* struct syscall_info */ + { + output( "\t.byte %u\n", get_args_size( syscalls[i] )); /* syscall_args */ + output( "\t.byte %u\n", !!(syscalls[i]->flags & FLAG_NOFPU) ); /* syscall_nofpu */ + } }
diff --git a/tools/winebuild/parser.c b/tools/winebuild/parser.c index 11b422bd435..0a1fbe52e62 100644 --- a/tools/winebuild/parser.c +++ b/tools/winebuild/parser.c @@ -71,6 +71,7 @@ static const char * const FlagNames[] = "fastcall", /* FLAG_FASTCALL */ "syscall", /* FLAG_SYSCALL */ "import", /* FLAG_IMPORT */ + "nofpu", /* FLAG_NOFPU */ NULL };
@@ -328,6 +329,11 @@ static int parse_spec_arguments( ORDDEF *odp, DLLSPEC *spec, int optional ) return 0; } } + else if (odp->flags & FLAG_NOFPU) + { + error( "The nofpu flag can only be used on a syscall function\n" ); + return 0; + } return 1; }
diff --git a/tools/winebuild/winebuild.man.in b/tools/winebuild/winebuild.man.in index 23ef3495744..ce016b542fb 100644 --- a/tools/winebuild/winebuild.man.in +++ b/tools/winebuild/winebuild.man.in @@ -324,6 +324,10 @@ only). The entry point will be exported by ordinal instead of by name. The name is still available for importing. .TP +.B -nofpu +The entry point is a NT syscall which does not save or restore the +FPU state and assumes it will not be modified by the call. +.TP .B -ret16 The function returns a 16-bit value (Win16 only). .TP
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/ntdll/ntdll.spec | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec index 1d4218e7b52..878f48e90f0 100644 --- a/dlls/ntdll/ntdll.spec +++ b/dlls/ntdll/ntdll.spec @@ -317,7 +317,7 @@ @ stdcall -syscall NtQueryMutant(long long ptr long ptr) @ stdcall -syscall NtQueryObject(long long ptr long ptr) # @ stub NtQueryOpenSubKeys -@ stdcall -syscall NtQueryPerformanceCounter(ptr ptr) +@ stdcall -syscall -nofpu NtQueryPerformanceCounter(ptr ptr) # @ stub NtQueryPortInformationProcess # @ stub NtQueryQuotaInformationFile @ stdcall -syscall NtQuerySection(long long ptr long ptr) @@ -449,7 +449,7 @@ @ stdcall -syscall NtWriteFileGather(long long ptr ptr ptr ptr long ptr ptr) # @ stub NtWriteRequestData @ stdcall -syscall NtWriteVirtualMemory(long ptr ptr long ptr) -@ stdcall -syscall NtYieldExecution() +@ stdcall -syscall -nofpu NtYieldExecution() @ stub PfxFindPrefix @ stub PfxInitialize @ stub PfxInsertPrefix
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/ntdll/ntdll.spec | 1 + dlls/ntdll/unix/loader.c | 1 + dlls/winecrt0/unix_lib.c | 12 ++++++++++++ include/wine/unixlib.h | 1 + 4 files changed, 15 insertions(+)
diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec index 878f48e90f0..8e3e73a4432 100644 --- a/dlls/ntdll/ntdll.spec +++ b/dlls/ntdll/ntdll.spec @@ -1690,6 +1690,7 @@ @ cdecl -syscall wine_server_handle_to_fd(long long ptr ptr)
# Unix interface +@ stdcall -syscall -nofpu __wine_unix_call_fast(int64 long ptr) @ stdcall -syscall __wine_unix_call(int64 long ptr) @ stdcall -syscall __wine_unix_spawnvp(long ptr) @ stdcall __wine_ctrl_routine(ptr) diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c index 72727d3d789..ffd0bdf57a1 100644 --- a/dlls/ntdll/unix/loader.c +++ b/dlls/ntdll/unix/loader.c @@ -356,6 +356,7 @@ static void * const syscalls[] = NtYieldExecution, __wine_dbg_write, __wine_unix_call, + __wine_unix_call /* __wine_unix_call_fast */, __wine_unix_spawnvp, wine_nt_to_unix_file_name, wine_server_call, diff --git a/dlls/winecrt0/unix_lib.c b/dlls/winecrt0/unix_lib.c index c86897b9905..816be88edcc 100644 --- a/dlls/winecrt0/unix_lib.c +++ b/dlls/winecrt0/unix_lib.c @@ -30,6 +30,7 @@ #include "wine/unixlib.h"
static NTSTATUS (WINAPI *p__wine_unix_call)( unixlib_handle_t, unsigned int, void * ); +static NTSTATUS (WINAPI *p__wine_unix_call_fast)( unixlib_handle_t, unsigned int, void * );
static void load_func( void **func, const char *name, void *def ) { @@ -47,10 +48,21 @@ static NTSTATUS __cdecl fallback__wine_unix_call( unixlib_handle_t handle, unsig return STATUS_DLL_NOT_FOUND; }
+static NTSTATUS __cdecl fallback__wine_unix_call_fast( unixlib_handle_t handle, unsigned int code, void *args ) +{ + return STATUS_DLL_NOT_FOUND; +} + NTSTATUS WINAPI __wine_unix_call( unixlib_handle_t handle, unsigned int code, void *args ) { LOAD_FUNC( __wine_unix_call ); return p__wine_unix_call( handle, code, args ); }
+NTSTATUS WINAPI __wine_unix_call_fast( unixlib_handle_t handle, unsigned int code, void *args ) +{ + LOAD_FUNC( __wine_unix_call_fast ); + return p__wine_unix_call_fast( handle, code, args ); +} + #endif /* __WINE_PE_BUILD */ diff --git a/include/wine/unixlib.h b/include/wine/unixlib.h index ef60b32184c..581790516a5 100644 --- a/include/wine/unixlib.h +++ b/include/wine/unixlib.h @@ -25,6 +25,7 @@ typedef NTSTATUS (*unixlib_entry_t)( void *args ); typedef UINT64 unixlib_handle_t;
extern NTSTATUS WINAPI __wine_unix_call( unixlib_handle_t handle, unsigned int code, void *args ); +extern NTSTATUS WINAPI __wine_unix_call_fast( unixlib_handle_t handle, unsigned int code, void *args );
#ifdef WINE_UNIX_LIB
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/opengl32/make_opengl | 3 --- dlls/opengl32/private.h | 5 +++++ dlls/opengl32/unixlib.h | 3 --- 3 files changed, 5 insertions(+), 6 deletions(-)
diff --git a/dlls/opengl32/make_opengl b/dlls/opengl32/make_opengl index 5654ddfa824..9bef645382d 100755 --- a/dlls/opengl32/make_opengl +++ b/dlls/opengl32/make_opengl @@ -1054,9 +1054,6 @@ print OUT " GLsizei length;\n"; print OUT " const GLchar *message;\n"; print OUT "};\n\n";
-print OUT "extern unixlib_handle_t unixlib_handle DECLSPEC_HIDDEN;\n"; -print OUT "#define UNIX_CALL( func, params ) __wine_unix_call( unixlib_handle, unix_ ## func, params )\n\n"; - print OUT "#endif /* __WINE_OPENGL32_UNIXLIB_H */\n"; close OUT;
diff --git a/dlls/opengl32/private.h b/dlls/opengl32/private.h index 06a97b43987..3b06266950b 100644 --- a/dlls/opengl32/private.h +++ b/dlls/opengl32/private.h @@ -28,8 +28,13 @@ #include "winternl.h" #include "wingdi.h"
+#include "wine/unixlib.h" + extern const void *extension_procs[] DECLSPEC_HIDDEN;
extern int WINAPI wglDescribePixelFormat( HDC hdc, int ipfd, UINT cjpfd, PIXELFORMATDESCRIPTOR *ppfd );
+extern unixlib_handle_t unixlib_handle DECLSPEC_HIDDEN; +#define UNIX_CALL( func, params ) __wine_unix_call_fast( unixlib_handle, unix_ ## func, params ) + #endif /* __WINE_OPENGL32_PRIVATE_H */ diff --git a/dlls/opengl32/unixlib.h b/dlls/opengl32/unixlib.h index e7f21383f86..9bd22f9f874 100644 --- a/dlls/opengl32/unixlib.h +++ b/dlls/opengl32/unixlib.h @@ -25351,7 +25351,4 @@ struct wine_gl_debug_message_params const GLchar *message; };
-extern unixlib_handle_t unixlib_handle DECLSPEC_HIDDEN; -#define UNIX_CALL( func, params ) __wine_unix_call( unixlib_handle, unix_ ## func, params ) - #endif /* __WINE_OPENGL32_UNIXLIB_H */
From: Rémi Bernon rbernon@codeweavers.com
Using the signal context for the volatile FPU state, assuming that it hasn't been modified by the unix call. --- dlls/ntdll/unix/signal_i386.c | 41 ++++++++++++++++++++++++ dlls/ntdll/unix/signal_x86_64.c | 56 +++++++++++++++++++++++++++++++++ 2 files changed, 97 insertions(+)
diff --git a/dlls/ntdll/unix/signal_i386.c b/dlls/ntdll/unix/signal_i386.c index ed344d11e1b..a321562c21c 100644 --- a/dlls/ntdll/unix/signal_i386.c +++ b/dlls/ntdll/unix/signal_i386.c @@ -741,6 +741,38 @@ static inline void restore_fpu( const CONTEXT *context ) }
+/*********************************************************************** + * update_frame_context + * + * Update current syscall frame context from a sigcontext. + */ +static void update_frame_context( const ucontext_t *sigcontext ) +{ + struct syscall_frame *frame = x86_thread_data()->syscall_frame; + + if (frame->syscall_flags & SYSCALL_FLAG_NOFPU) + { + FLOATING_SAVE_AREA *fpu = FPU_sig(sigcontext); + XSAVE_FORMAT *fpux = FPUX_sig(sigcontext); + + if (fpu) fpu_to_fpux( &frame->u.xsave, fpu ); + if (fpux) + { + XSTATE *xs; + if (!fpu) frame->u.xsave = *fpux; + if ((cpu_info.ProcessorFeatureBits & CPU_FEATURE_AVX) && (xs = XState_sig(fpux))) + frame->xstate = *xs; + } + if (!fpu && !fpux) + { + CONTEXT context; + save_fpu( &context ); + fpu_to_fpux( &frame->u.xsave, &context.FloatSave ); + } + } +} + + /*********************************************************************** * save_context * @@ -1595,6 +1627,7 @@ __ASM_GLOBAL_FUNC( call_user_mode_callback, "movl %ebp,0x380(%esp)\n\t" "movl 0x1f8(%edx),%ecx\n\t" /* x86_thread_data()->syscall_frame */ "movl (%ecx),%eax\n\t" /* frame->syscall_flags */ + "andl $~0x80000000,%eax\n\t" /* syscall_flags &= ~SYSCALL_FLAG_NOFPU */ "movl %eax,(%esp)\n\t" "movl 0x38(%ecx),%eax\n\t" /* frame->syscall_table */ "movl %eax,0x38(%esp)\n\t" @@ -2076,6 +2109,7 @@ static void usr1_handler( int signal, siginfo_t *siginfo, void *sigcontext ) DECLSPEC_ALIGN(64) XSTATE xs; xcontext.c.ContextFlags = CONTEXT_FULL; context_init_xstate( &xcontext.c, &xs ); + update_frame_context( sigcontext );
NtGetContextThread( GetCurrentThread(), &xcontext.c ); wait_suspend( &xcontext.c ); @@ -2575,6 +2609,12 @@ __ASM_GLOBAL_FUNC( __wine_syscall_dispatcher, "andl $0xfff,%eax\n\t" /* syscall number */ "cmpl 8(%ebx),%eax\n\t" /* table->ServiceLimit */ "jae .L__wine_syscall_dispatcher_invalid_arg\n\t" + "movl 4(%ebx),%edx\n\t" /* table->CounterTable */ + "movl (%edx,%eax,4),%edx\n\t" + "orl %edx,(%ecx)\n\t" /* frame->syscall_flags |= syscall_flags */ + "testl $0x80000000,(%ecx)\n\t" /* frame->syscall_flags & SYSCALL_FLAG_NOFPU */ + "jz .L__wine_syscall_dispatcher_save_fpu\n\t" + "jmp .L__wine_syscall_dispatcher_fpu_saved\n\t"
"\n.L__wine_syscall_dispatcher_save_fpu:\n\t" "testl $3,(%ecx)\n\t" /* frame->syscall_flags & (SYSCALL_HAVE_XSAVE | SYSCALL_HAVE_XSAVEC) */ @@ -2661,6 +2701,7 @@ __ASM_GLOBAL_FUNC( __wine_syscall_dispatcher, "fwait\n\t"
"\n.L__wine_syscall_dispatcher_fpu_restored:\n\t" + "andl $~0x80000000,0(%esp)\n\t" /* frame->syscall_flags &= ~SYSCALL_FLAG_NOFPU */ "movl 0x2c(%esp),%edi\n\t" /* remember state when $esp is pointing to "frame" */ __ASM_CFI(".cfi_remember_state\n\t") diff --git a/dlls/ntdll/unix/signal_x86_64.c b/dlls/ntdll/unix/signal_x86_64.c index 798de6d6c28..9472acdbb26 100644 --- a/dlls/ntdll/unix/signal_x86_64.c +++ b/dlls/ntdll/unix/signal_x86_64.c @@ -823,6 +823,30 @@ static inline void leave_handler( const ucontext_t *sigcontext ) }
+/*********************************************************************** + * update_frame_context + * + * Update current syscall frame context from a sigcontext. + */ +static void update_frame_context( const ucontext_t *sigcontext ) +{ + struct syscall_frame *frame = amd64_thread_data()->syscall_frame; + + if ((frame->syscall_flags & SYSCALL_FLAG_NOFPU) && FPU_sig(sigcontext)) + { + M128A tmp[10]; + XSTATE *xs; + + memcpy( &tmp, frame->xsave.XmmRegisters + 6, sizeof(tmp) ); + frame->xsave = *FPU_sig(sigcontext); + memcpy( frame->xsave.XmmRegisters + 6, &tmp, sizeof(tmp) ); + + if ((cpu_info.ProcessorFeatureBits & CPU_FEATURE_AVX) && (xs = XState_sig(FPU_sig(sigcontext)))) + frame->xstate = *xs; + } +} + + /*********************************************************************** * save_context * @@ -1609,6 +1633,7 @@ __ASM_GLOBAL_FUNC( call_user_mode_callback, "movq 0xa8(%r10),%rax\n\t" /* prev_frame->syscall_table */ "movq %rax,0xa8(%rsp)\n\t" /* frame->syscall_table */ "movl 0xb0(%r10),%r14d\n\t" /* prev_frame->syscall_flags */ + "andl $~0x80000000,%r14d\n\t" /* syscall_flags &= ~SYSCALL_FLAG_NOFPU */ "movl %r14d,0xb0(%rsp)\n\t" /* frame->syscall_flags */ "movq %r10,0xa0(%rsp)\n\t" /* frame->prev_frame */ "movq %rsp,0x328(%r11)\n\t" /* amd64_thread_data()->syscall_frame */ @@ -2152,6 +2177,7 @@ static void usr1_handler( int signal, siginfo_t *siginfo, void *ucontext ) DECLSPEC_ALIGN(64) XSTATE xs; context.c.ContextFlags = CONTEXT_FULL; context_init_xstate( &context.c, &xs ); + update_frame_context( ucontext );
NtGetContextThread( GetCurrentThread(), &context.c ); wait_suspend( &context.c ); @@ -2663,6 +2689,22 @@ __ASM_GLOBAL_FUNC( __wine_syscall_dispatcher, "andl $0xfff,%eax\n\t" /* syscall number */ "cmpq 16(%rbx),%rax\n\t" /* table->ServiceLimit */ "jae .L__wine_syscall_dispatcher_invalid_arg\n\t" + "movq 8(%rbx),%rdx\n\t" /* table->CounterTable */ + "orq (%rdx,%rax,8),%r14\n\t" + "movq %r14,0xb0(%rcx)\n\t" /* frame->syscall_flags |= syscall_flags */ + "testl $0x80000000,%r14d\n\t" /* SYSCALL_FLAG_NOFPU */ + "jz .L__wine_syscall_dispatcher_save_fpu\n\t" + "movdqa %xmm6,0x1c0(%rcx)\n\t" + "movdqa %xmm7,0x1d0(%rcx)\n\t" + "movdqa %xmm8,0x1e0(%rcx)\n\t" + "movdqa %xmm9,0x1f0(%rcx)\n\t" + "movdqa %xmm10,0x200(%rcx)\n\t" + "movdqa %xmm11,0x210(%rcx)\n\t" + "movdqa %xmm12,0x220(%rcx)\n\t" + "movdqa %xmm13,0x230(%rcx)\n\t" + "movdqa %xmm14,0x240(%rcx)\n\t" + "movdqa %xmm15,0x250(%rcx)\n\t" + "jmp .L__wine_syscall_dispatcher_fpu_saved\n\t"
"\n.L__wine_syscall_dispatcher_save_fpu:\n\t" "testl $3,%r14d\n\t" /* SYSCALL_HAVE_XSAVE | SYSCALL_HAVE_XSAVEC */ @@ -2750,7 +2792,20 @@ __ASM_GLOBAL_FUNC( __wine_syscall_dispatcher, "\n.L__wine_syscall_dispatcher_fsgs_restored:\n\t" #endif "testl $0x48,%edx\n\t" /* CONTEXT_FLOATING_POINT | CONTEXT_XSTATE */ + "jnz .L__wine_syscall_dispatcher_restore_fpu\n\t" + "testl $0x80000000,%r14d\n\t" /* SYSCALL_FLAG_NOFPU */ "jz .L__wine_syscall_dispatcher_fpu_restored\n\t" + "movdqa 0x1c0(%rcx),%xmm6\n\t" + "movdqa 0x1d0(%rcx),%xmm7\n\t" + "movdqa 0x1e0(%rcx),%xmm8\n\t" + "movdqa 0x1f0(%rcx),%xmm9\n\t" + "movdqa 0x200(%rcx),%xmm10\n\t" + "movdqa 0x210(%rcx),%xmm11\n\t" + "movdqa 0x220(%rcx),%xmm12\n\t" + "movdqa 0x230(%rcx),%xmm13\n\t" + "movdqa 0x240(%rcx),%xmm14\n\t" + "movdqa 0x250(%rcx),%xmm15\n\t" + "jmp .L__wine_syscall_dispatcher_fpu_restored\n\t"
"\n.L__wine_syscall_dispatcher_restore_fpu:\n\t" "testl $3,%r14d\n\t" /* SYSCALL_HAVE_XSAVE | SYSCALL_HAVE_XSAVEC */ @@ -2766,6 +2821,7 @@ __ASM_GLOBAL_FUNC( __wine_syscall_dispatcher, "fxrstor64 0xc0(%rcx)\n\t"
"\n.L__wine_syscall_dispatcher_fpu_restored:\n\t" + "andl $~0x80000000,0xb0(%rcx)\n\t" /* frame->syscall_flags &= ~SYSCALL_FLAG_NOFPU */ "movq 0x98(%rcx),%rbp\n\t" __ASM_CFI(".cfi_same_value rbp\n\t") "movq 0x68(%rcx),%r15\n\t"
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/win32u/Makefile.in | 2 +- dlls/winecrt0/unix_lib.c | 45 ++++++++++++++++++++-------------------- dlls/winevulkan/loader.c | 3 ++- include/wine/unixlib.h | 5 +++++ 4 files changed, 31 insertions(+), 24 deletions(-)
diff --git a/dlls/win32u/Makefile.in b/dlls/win32u/Makefile.in index 692b2d5c9f2..ba6915d91d8 100644 --- a/dlls/win32u/Makefile.in +++ b/dlls/win32u/Makefile.in @@ -2,7 +2,7 @@ EXTRADEFS = -DWINE_NO_LONG_TYPES MODULE = win32u.dll UNIXLIB = win32u.so IMPORTLIB = win32u -IMPORTS = ntdll winecrt0 +IMPORTS = winecrt0 ntdll UNIX_CFLAGS = $(FREETYPE_CFLAGS) $(FONTCONFIG_CFLAGS) UNIX_LIBS = $(CARBON_LIBS) $(APPKIT_LIBS) $(PTHREAD_LIBS) -lm
diff --git a/dlls/winecrt0/unix_lib.c b/dlls/winecrt0/unix_lib.c index 816be88edcc..9f7518ee314 100644 --- a/dlls/winecrt0/unix_lib.c +++ b/dlls/winecrt0/unix_lib.c @@ -29,40 +29,41 @@ #include "winternl.h" #include "wine/unixlib.h"
-static NTSTATUS (WINAPI *p__wine_unix_call)( unixlib_handle_t, unsigned int, void * ); -static NTSTATUS (WINAPI *p__wine_unix_call_fast)( unixlib_handle_t, unsigned int, void * ); - -static void load_func( void **func, const char *name, void *def ) +static void *load_func( const char *name ) { - if (!*func) - { - HMODULE module = GetModuleHandleW( L"ntdll.dll" ); - void *proc = GetProcAddress( module, name ); - InterlockedExchangePointer( func, proc ? proc : def ); - } -} -#define LOAD_FUNC(name) load_func( (void **)&p ## name, #name, fallback ## name ) + UNICODE_STRING ntdll_str; + ANSI_STRING name_str; + HMODULE module; + void *proc;
-static NTSTATUS __cdecl fallback__wine_unix_call( unixlib_handle_t handle, unsigned int code, void *args ) -{ - return STATUS_DLL_NOT_FOUND; + RtlInitUnicodeString( &ntdll_str, L"ntdll.dll" ); + RtlInitAnsiString( &name_str, name ); + + if (LdrGetDllHandleEx( LDR_GET_DLL_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, NULL, NULL, &ntdll_str, &module )) return NULL; + if (LdrGetProcedureAddress( module, &name_str, 0, &proc )) return NULL; + return proc; }
-static NTSTATUS __cdecl fallback__wine_unix_call_fast( unixlib_handle_t handle, unsigned int code, void *args ) +static NTSTATUS WINAPI fallback___wine_unix_call( unixlib_handle_t handle, unsigned int code, void *args ) { return STATUS_DLL_NOT_FOUND; }
-NTSTATUS WINAPI __wine_unix_call( unixlib_handle_t handle, unsigned int code, void *args ) +static NTSTATUS WINAPI delayload___wine_unix_call( unixlib_handle_t handle, unsigned int code, void *args ) { - LOAD_FUNC( __wine_unix_call ); - return p__wine_unix_call( handle, code, args ); + void *proc = load_func( "__wine_unix_call" ); + InterlockedExchangePointer( (void *)&__wine_unix_call, proc ? proc : (void *)fallback___wine_unix_call ); + return __wine_unix_call( handle, code, args ); }
-NTSTATUS WINAPI __wine_unix_call_fast( unixlib_handle_t handle, unsigned int code, void *args ) +static NTSTATUS WINAPI delayload___wine_unix_call_fast( unixlib_handle_t handle, unsigned int code, void *args ) { - LOAD_FUNC( __wine_unix_call_fast ); - return p__wine_unix_call_fast( handle, code, args ); + void *proc = load_func( "__wine_unix_call_fast" ); + InterlockedExchangePointer( (void *)&__wine_unix_call_fast, proc ? proc : (void *)fallback___wine_unix_call ); + return __wine_unix_call_fast( handle, code, args ); }
+NTSTATUS (WINAPI *__wine_unix_call)( unixlib_handle_t, unsigned int, void * ) = delayload___wine_unix_call; +NTSTATUS (WINAPI *__wine_unix_call_fast)( unixlib_handle_t, unsigned int, void * ) = delayload___wine_unix_call_fast; + #endif /* __WINE_PE_BUILD */ diff --git a/dlls/winevulkan/loader.c b/dlls/winevulkan/loader.c index a86a35b0d40..5006cb444d6 100644 --- a/dlls/winevulkan/loader.c +++ b/dlls/winevulkan/loader.c @@ -35,7 +35,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(vulkan); DEFINE_DEVPROPKEY(DEVPROPKEY_GPU_LUID, 0x60b193cb, 0x5276, 0x4d0f, 0x96, 0xfc, 0xf1, 0x73, 0xab, 0xad, 0x3e, 0xc6, 2); DEFINE_DEVPROPKEY(WINE_DEVPROPKEY_GPU_VULKAN_UUID, 0x233a9ef3, 0xafc4, 0x4abd, 0xb5, 0x64, 0xc3, 0x2f, 0x21, 0xf1, 0x53, 0x5c, 2);
-NTSTATUS (WINAPI *p_vk_direct_unix_call)(unixlib_handle_t handle, unsigned int code, void *args) = __wine_unix_call; +NTSTATUS (WINAPI *p_vk_direct_unix_call)(unixlib_handle_t handle, unsigned int code, void *args); unixlib_handle_t unix_handle;
static HINSTANCE hinstance; @@ -239,6 +239,7 @@ static BOOL WINAPI wine_vk_init(INIT_ONCE *once, void *param, void **context) &unix_handle, sizeof(unix_handle), NULL)) return FALSE;
+ p_vk_direct_unix_call = __wine_unix_call; return !vk_unix_call(unix_init, &p_vk_direct_unix_call); }
diff --git a/include/wine/unixlib.h b/include/wine/unixlib.h index 581790516a5..86372ad25d3 100644 --- a/include/wine/unixlib.h +++ b/include/wine/unixlib.h @@ -24,8 +24,13 @@ typedef NTSTATUS (*unixlib_entry_t)( void *args ); typedef UINT64 unixlib_handle_t;
+#if defined(WINE_UNIX_LIB) || defined(_NTSYSTEM_) extern NTSTATUS WINAPI __wine_unix_call( unixlib_handle_t handle, unsigned int code, void *args ); extern NTSTATUS WINAPI __wine_unix_call_fast( unixlib_handle_t handle, unsigned int code, void *args ); +#else +extern NTSTATUS (WINAPI *__wine_unix_call)( unixlib_handle_t handle, unsigned int code, void *args ); +extern NTSTATUS (WINAPI *__wine_unix_call_fast)( unixlib_handle_t handle, unsigned int code, void *args ); +#endif
#ifdef WINE_UNIX_LIB
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/ntdll/unix/signal_i386.c | 13 +++++++------ dlls/ntdll/unix/signal_x86_64.c | 5 +++-- 2 files changed, 10 insertions(+), 8 deletions(-)
diff --git a/dlls/ntdll/unix/signal_i386.c b/dlls/ntdll/unix/signal_i386.c index a321562c21c..e599ed1898d 100644 --- a/dlls/ntdll/unix/signal_i386.c +++ b/dlls/ntdll/unix/signal_i386.c @@ -2668,9 +2668,11 @@ __ASM_GLOBAL_FUNC( __wine_syscall_dispatcher, "cld\n\t" "rep; movsl\n\t" "call *(%edx,%eax,4)\n\t" - "leal -0x34(%ebp),%esp\n\t"
"\n.L__wine_syscall_dispatcher_restore:\n\t" + "leal -0x34(%ebp),%esp\n\t" + /* remember state when $ebp is pointing to "frame" */ + __ASM_CFI(".cfi_remember_state\n\t") __ASM_CFI_CFA_IS_AT1(esp, 0x0c) __ASM_CFI_REG_IS_AT1(esp, esp, 0x0c) __ASM_CFI_REG_IS_AT1(eip, esp, 0x08) @@ -2703,8 +2705,6 @@ __ASM_GLOBAL_FUNC( __wine_syscall_dispatcher, "\n.L__wine_syscall_dispatcher_fpu_restored:\n\t" "andl $~0x80000000,0(%esp)\n\t" /* frame->syscall_flags &= ~SYSCALL_FLAG_NOFPU */ "movl 0x2c(%esp),%edi\n\t" - /* remember state when $esp is pointing to "frame" */ - __ASM_CFI(".cfi_remember_state\n\t") __ASM_CFI(".cfi_same_value %edi\n\t") "movl 0x30(%esp),%esi\n\t" __ASM_CFI(".cfi_same_value %esi\n\t") @@ -2758,14 +2758,14 @@ __ASM_GLOBAL_FUNC( __wine_syscall_dispatcher, "iret\n\t"
"\n.L__wine_syscall_dispatcher_invalid_arg:\n\t" - /* $esp is now pointing to "frame" again */ + /* $ebp is now pointing to "frame" again */ __ASM_CFI("\t.cfi_restore_state\n\t") "movl $0xc000000d,%eax\n\t" /* STATUS_INVALID_PARAMETER */ "jmp .L__wine_syscall_dispatcher_restore\n\t"
".globl " __ASM_NAME("__wine_syscall_dispatcher_return") "\n" __ASM_NAME("__wine_syscall_dispatcher_return") ":\n\t" - /* remember state when $esp is pointing to "frame" */ + /* remember state when $ebp is pointing to "frame" */ __ASM_CFI(".cfi_remember_state\n\t") __ASM_CFI(".cfi_def_cfa %esp, 4\n\t") __ASM_CFI(".cfi_restore %esp\n\t") @@ -2776,7 +2776,8 @@ __ASM_GLOBAL_FUNC( __wine_syscall_dispatcher, __ASM_CFI(".cfi_restore %ebp\n\t") "movl 8(%esp),%eax\n\t" "movl 4(%esp),%esp\n\t" - /* $esp is now pointing to "frame" again */ + "leal 0x34(%esp),%ebp\n\t" + /* $ebp is now pointing to "frame" again */ __ASM_CFI(".cfi_restore_state\n\t") "jmp .L__wine_syscall_dispatcher_restore\n\t" )
diff --git a/dlls/ntdll/unix/signal_x86_64.c b/dlls/ntdll/unix/signal_x86_64.c index 9472acdbb26..6b8def37a7d 100644 --- a/dlls/ntdll/unix/signal_x86_64.c +++ b/dlls/ntdll/unix/signal_x86_64.c @@ -2779,11 +2779,11 @@ __ASM_GLOBAL_FUNC( __wine_syscall_dispatcher, "subq $0x20,%rsp\n\t" "movq (%rbx),%r10\n\t" /* table->ServiceTable */ "callq *(%r10,%rax,8)\n\t" + + "\n.L__wine_syscall_dispatcher_restore:\n\t" "leaq -0x98(%rbp),%rcx\n\t" /* $rcx is now pointing to "frame" again */ __ASM_CFI(".cfi_restore_state\n\t") - - "\n.L__wine_syscall_dispatcher_restore:\n\t" "movl 0x94(%rcx),%edx\n\t" /* frame->restore_flags */ #ifdef __linux__ "testl $4,%r14d\n\t" /* SYSCALL_HAVE_PTHREAD_TEB */ @@ -2883,6 +2883,7 @@ __ASM_GLOBAL_FUNC( __wine_syscall_dispatcher, __ASM_NAME("__wine_syscall_dispatcher_return") ":\n\t" "movl 0xb0(%rcx),%r14d\n\t" /* frame->syscall_flags */ "movq %rdx,%rax\n\t" + "leaq 0x98(%rcx),%rbp\n\t" "jmp .L__wine_syscall_dispatcher_restore\n\t" )
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/ntdll/unix/loader.c | 2 ++ dlls/ntdll/unix/signal_i386.c | 18 ++++++++++++++++-- dlls/ntdll/unix/signal_x86_64.c | 13 +++++++++++-- dlls/ntdll/unix/unix_private.h | 1 + tools/winebuild/import.c | 1 + 5 files changed, 31 insertions(+), 4 deletions(-)
diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c index ffd0bdf57a1..378410ff760 100644 --- a/dlls/ntdll/unix/loader.c +++ b/dlls/ntdll/unix/loader.c @@ -1340,6 +1340,7 @@ NTSTATUS ntdll_init_syscalls( ULONG id, SYSTEM_SERVICE_TABLE *table, void **disp { BYTE syscall_args; BYTE syscall_nofpu; + BYTE syscall_unix; }; struct syscall_table_info { @@ -1361,6 +1362,7 @@ NTSTATUS ntdll_init_syscalls( ULONG id, SYSTEM_SERVICE_TABLE *table, void **disp { table->ArgumentTable[i] = table_info->info[i].syscall_args; if (table_info->info[i].syscall_nofpu) table->CounterTable[i] |= SYSCALL_FLAG_NOFPU; + if (table_info->info[i].syscall_unix) table->CounterTable[i] |= SYSCALL_FLAG_UNIX; }
KeServiceDescriptorTable[id] = *table; diff --git a/dlls/ntdll/unix/signal_i386.c b/dlls/ntdll/unix/signal_i386.c index e599ed1898d..4bf5cc0517b 100644 --- a/dlls/ntdll/unix/signal_i386.c +++ b/dlls/ntdll/unix/signal_i386.c @@ -1627,7 +1627,7 @@ __ASM_GLOBAL_FUNC( call_user_mode_callback, "movl %ebp,0x380(%esp)\n\t" "movl 0x1f8(%edx),%ecx\n\t" /* x86_thread_data()->syscall_frame */ "movl (%ecx),%eax\n\t" /* frame->syscall_flags */ - "andl $~0x80000000,%eax\n\t" /* syscall_flags &= ~SYSCALL_FLAG_NOFPU */ + "andl $~0xc0000000,%eax\n\t" /* syscall_flags &= ~(SYSCALL_FLAG_NOFPU | SYSCALL_FLAG_UNIX) */ "movl %eax,(%esp)\n\t" "movl 0x38(%ecx),%eax\n\t" /* frame->syscall_table */ "movl %eax,0x38(%esp)\n\t" @@ -2614,6 +2614,8 @@ __ASM_GLOBAL_FUNC( __wine_syscall_dispatcher, "orl %edx,(%ecx)\n\t" /* frame->syscall_flags |= syscall_flags */ "testl $0x80000000,(%ecx)\n\t" /* frame->syscall_flags & SYSCALL_FLAG_NOFPU */ "jz .L__wine_syscall_dispatcher_save_fpu\n\t" + "testl $0x40000000,(%ecx)\n\t" /* frame->syscall_flags & SYSCALL_FLAG_UNIX */ + "jnz .L__wine_unix_call\n\t" "jmp .L__wine_syscall_dispatcher_fpu_saved\n\t"
"\n.L__wine_syscall_dispatcher_save_fpu:\n\t" @@ -2668,6 +2670,18 @@ __ASM_GLOBAL_FUNC( __wine_syscall_dispatcher, "cld\n\t" "rep; movsl\n\t" "call *(%edx,%eax,4)\n\t" + "jmp .L__wine_syscall_dispatcher_restore\n\t" + + "\n.L__wine_unix_call:\n\t" + "leal 4(%esp),%esi\n\t" /* first argument */ + "movl %ecx,%esp\n\t" + "subl $4,%esp\n\t" + "andl $~15,%esp\n\t" + "movl 0xc(%esi),%eax\n\t" + "movl %eax,(%esp)\n\t" + "movl 0x8(%esi),%eax\n\t" + "movl (%esi),%edx\n\t" + "call *(%edx,%eax,4)\n\t"
"\n.L__wine_syscall_dispatcher_restore:\n\t" "leal -0x34(%ebp),%esp\n\t" @@ -2703,7 +2717,7 @@ __ASM_GLOBAL_FUNC( __wine_syscall_dispatcher, "fwait\n\t"
"\n.L__wine_syscall_dispatcher_fpu_restored:\n\t" - "andl $~0x80000000,0(%esp)\n\t" /* frame->syscall_flags &= ~SYSCALL_FLAG_NOFPU */ + "andl $~0xc0000000,0(%esp)\n\t" /* frame->syscall_flags &= ~(SYSCALL_FLAG_NOFPU | SYSCALL_FLAG_UNIX) */ "movl 0x2c(%esp),%edi\n\t" __ASM_CFI(".cfi_same_value %edi\n\t") "movl 0x30(%esp),%esi\n\t" diff --git a/dlls/ntdll/unix/signal_x86_64.c b/dlls/ntdll/unix/signal_x86_64.c index 6b8def37a7d..c3de1e040b6 100644 --- a/dlls/ntdll/unix/signal_x86_64.c +++ b/dlls/ntdll/unix/signal_x86_64.c @@ -1633,7 +1633,7 @@ __ASM_GLOBAL_FUNC( call_user_mode_callback, "movq 0xa8(%r10),%rax\n\t" /* prev_frame->syscall_table */ "movq %rax,0xa8(%rsp)\n\t" /* frame->syscall_table */ "movl 0xb0(%r10),%r14d\n\t" /* prev_frame->syscall_flags */ - "andl $~0x80000000,%r14d\n\t" /* syscall_flags &= ~SYSCALL_FLAG_NOFPU */ + "andl $~0xc0000000,%r14d\n\t" /* syscall_flags &= ~(SYSCALL_FLAG_NOFPU | SYSCALL_FLAG_UNIX) */ "movl %r14d,0xb0(%rsp)\n\t" /* frame->syscall_flags */ "movq %r10,0xa0(%rsp)\n\t" /* frame->prev_frame */ "movq %rsp,0x328(%r11)\n\t" /* amd64_thread_data()->syscall_frame */ @@ -2763,6 +2763,8 @@ __ASM_GLOBAL_FUNC( __wine_syscall_dispatcher, "movq %rcx,%rsp\n\t" "movq 0x00(%rcx),%rax\n\t" "movq 0x18(%rcx),%rdx\n\t" + "testl $0x40000000,%r14d\n\t" /* SYSCALL_FLAG_UNIX */ + "jnz .L__wine_unix_call\n\t" "andl $0xfff,%eax\n\t" /* syscall number */ "movq 24(%rbx),%rcx\n\t" /* table->ArgumentTable */ "movzbl (%rcx,%rax),%ecx\n\t" @@ -2779,6 +2781,13 @@ __ASM_GLOBAL_FUNC( __wine_syscall_dispatcher, "subq $0x20,%rsp\n\t" "movq (%rbx),%r10\n\t" /* table->ServiceTable */ "callq *(%r10,%rax,8)\n\t" + "jmp .L__wine_syscall_dispatcher_restore\n" + + "\n.L__wine_unix_call:\n\t" + "movq %r8,%rdi\n\t" + "subq $0x20,%rsp\n\t" + "andq $~15,%rsp\n\t" + "callq *(%r10,%rdx,8)\n\t"
"\n.L__wine_syscall_dispatcher_restore:\n\t" "leaq -0x98(%rbp),%rcx\n\t" @@ -2821,7 +2830,7 @@ __ASM_GLOBAL_FUNC( __wine_syscall_dispatcher, "fxrstor64 0xc0(%rcx)\n\t"
"\n.L__wine_syscall_dispatcher_fpu_restored:\n\t" - "andl $~0x80000000,0xb0(%rcx)\n\t" /* frame->syscall_flags &= ~SYSCALL_FLAG_NOFPU */ + "andl $~0xc0000000,0xb0(%rcx)\n\t" /* frame->syscall_flags &= ~(SYSCALL_FLAG_NOFPU | SYSCALL_FLAG_UNIX) */ "movq 0x98(%rcx),%rbp\n\t" __ASM_CFI(".cfi_same_value rbp\n\t") "movq 0x68(%rcx),%r15\n\t" diff --git a/dlls/ntdll/unix/unix_private.h b/dlls/ntdll/unix/unix_private.h index c34ce872930..44e63502505 100644 --- a/dlls/ntdll/unix/unix_private.h +++ b/dlls/ntdll/unix/unix_private.h @@ -97,6 +97,7 @@ static const LONG teb_offset = 0x2000; #define FILE_USE_FILE_POINTER_POSITION ((LONGLONG)-2)
#define SYSCALL_FLAG_NOFPU 0x80000000 +#define SYSCALL_FLAG_UNIX 0x40000000
/* callbacks to PE ntdll from the Unix side */ extern void (WINAPI *pDbgUiRemoteBreakin)( void *arg ) DECLSPEC_HIDDEN; diff --git a/tools/winebuild/import.c b/tools/winebuild/import.c index 905e6262650..ea48b6ea9ff 100644 --- a/tools/winebuild/import.c +++ b/tools/winebuild/import.c @@ -1507,6 +1507,7 @@ void output_syscalls( DLLSPEC *spec ) { output( "\t.byte %u\n", get_args_size( syscalls[i] )); /* syscall_args */ output( "\t.byte %u\n", !!(syscalls[i]->flags & FLAG_NOFPU) ); /* syscall_nofpu */ + output( "\t.byte %u\n", !!(strstr( get_link_name( syscalls[i] ), "__wine_unix_call" )) ); /* syscall_unix */ } }
Updated to a version using the CounterTable to keep syscall flags, rather than overusing syscall number high bits. This should be safer and the performance is the same.
This merge request was closed by Rémi Bernon.
A different version is upstream, from a quick look is seems to be doing a great job.