From: Rémi Bernon rbernon@codeweavers.com
Wrapping stack reads in a single place so we can silent Valgrind false positives when reading arguments from the user stack on x86_64. --- dlls/ntdll/unix/loader.c | 52 +++++++++++++++++++++++++++++++++ dlls/ntdll/unix/signal_i386.c | 33 +++++++++------------ dlls/ntdll/unix/signal_x86_64.c | 37 +++++++++-------------- dlls/ntdll/unix/unix_private.h | 1 + tools/valgrind.supp | 12 ++++++++ 5 files changed, 92 insertions(+), 43 deletions(-)
diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c index 9c29346c6d3..35bb4f6ac3f 100644 --- a/dlls/ntdll/unix/loader.c +++ b/dlls/ntdll/unix/loader.c @@ -1331,6 +1331,58 @@ already_loaded: }
+/*********************************************************************** + * ntdll_dispatch_syscall + */ +UINT_PTR ntdll_dispatch_syscall( SYSTEM_SERVICE_TABLE *tables, UINT_PTR code, UINT_PTR *arg03, UINT_PTR *arg4n ) +{ + UINT_PTR (WINAPIV *call_n)(UINT_PTR arg0, ...); + UINT_PTR (WINAPIV *call_0)(void); + + SYSTEM_SERVICE_TABLE *table = tables + (code & 0x3000) / 0x1000; + int argc, index = code & 0xfff; + + if (code >= 0x4000 || index >= table->ServiceLimit) return STATUS_INVALID_PARAMETER; + call_0 = (void *)table->ServiceTable[index]; + call_n = (void *)table->ServiceTable[index]; + + switch ((argc = table->ArgumentTable[index] / sizeof(UINT_PTR))) + { + case 0: return call_0(); + case 1: return call_n( arg03[0] ); + case 2: return call_n( arg03[0], arg03[1] ); + case 3: return call_n( arg03[0], arg03[1], arg03[2] ); + case 4: return call_n( arg03[0], arg03[1], arg03[2], arg03[3] ); + case 5: return call_n( arg03[0], arg03[1], arg03[2], arg03[3], arg4n[0] ); + case 6: return call_n( arg03[0], arg03[1], arg03[2], arg03[3], arg4n[0], arg4n[1] ); + case 7: return call_n( arg03[0], arg03[1], arg03[2], arg03[3], arg4n[0], arg4n[1], arg4n[2] ); + case 8: return call_n( arg03[0], arg03[1], arg03[2], arg03[3], arg4n[0], arg4n[1], arg4n[2], arg4n[3] ); + case 9: return call_n( arg03[0], arg03[1], arg03[2], arg03[3], arg4n[0], arg4n[1], arg4n[2], arg4n[3], + arg4n[4] ); + case 10: return call_n( arg03[0], arg03[1], arg03[2], arg03[3], arg4n[0], arg4n[1], arg4n[2], arg4n[3], + arg4n[4], arg4n[5] ); + case 11: return call_n( arg03[0], arg03[1], arg03[2], arg03[3], arg4n[0], arg4n[1], arg4n[2], arg4n[3], + arg4n[4], arg4n[5], arg4n[6] ); + case 12: return call_n( arg03[0], arg03[1], arg03[2], arg03[3], arg4n[0], arg4n[1], arg4n[2], arg4n[3], + arg4n[4], arg4n[5], arg4n[6], arg4n[7] ); + case 13: return call_n( arg03[0], arg03[1], arg03[2], arg03[3], arg4n[0], arg4n[1], arg4n[2], arg4n[3], + arg4n[4], arg4n[5], arg4n[6], arg4n[7], arg4n[8] ); + case 14: return call_n( arg03[0], arg03[1], arg03[2], arg03[3], arg4n[0], arg4n[1], arg4n[2], arg4n[3], + arg4n[4], arg4n[5], arg4n[6], arg4n[7], arg4n[8], arg4n[9] ); + case 15: return call_n( arg03[0], arg03[1], arg03[2], arg03[3], arg4n[0], arg4n[1], arg4n[2], arg4n[3], + arg4n[4], arg4n[5], arg4n[6], arg4n[7], arg4n[8], arg4n[9], arg4n[10] ); + case 16: return call_n( arg03[0], arg03[1], arg03[2], arg03[3], arg4n[0], arg4n[1], arg4n[2], arg4n[3], + arg4n[4], arg4n[5], arg4n[6], arg4n[7], arg4n[8], arg4n[9], arg4n[10], arg4n[11] ); + case 17: return call_n( arg03[0], arg03[1], arg03[2], arg03[3], arg4n[0], arg4n[1], arg4n[2], arg4n[3], + arg4n[4], arg4n[5], arg4n[6], arg4n[7], arg4n[8], arg4n[9], arg4n[10], arg4n[11], + arg4n[12] ); + default: ERR( "syscall with %u arguments, not implemented!\n", argc ); break; + } + + return STATUS_INVALID_PARAMETER; +} + + /*********************************************************************** * ntdll_init_syscalls */ diff --git a/dlls/ntdll/unix/signal_i386.c b/dlls/ntdll/unix/signal_i386.c index 1fc812f5a31..9ecd08320f1 100644 --- a/dlls/ntdll/unix/signal_i386.c +++ b/dlls/ntdll/unix/signal_i386.c @@ -2578,11 +2578,6 @@ __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 */ - "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 */ "testl $3,(%ecx)\n\t" /* frame->syscall_flags & (SYSCALL_HAVE_XSAVE | SYSCALL_HAVE_XSAVEC) */ "jz 2f\n\t" "movl $7,%eax\n\t" @@ -2615,21 +2610,21 @@ __ASM_GLOBAL_FUNC( __wine_syscall_dispatcher, "jmp 4f\n" "3:\tfnsave 0x40(%ecx)\n\t" "fwait\n" - "4:\tmovl %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" - "movl 12(%ebx),%eax\n\t" /* table->ArgumentTable */ - "movzbl (%eax,%edx,1),%ecx\n\t" - "movl (%ebx),%eax\n\t" /* table->ServiceTable */ - "subl %ecx,%esp\n\t" - "shrl $2,%ecx\n\t" + "4:\t" + + /* switch stack and dispatch syscall */ + "leal 4(%esp),%esi\n\t" /* 1st argument */ + "movl 0x1c(%ecx),%eax\n\t" /* frame->eax */ + "movl 0x38(%ecx),%ebx\n\t" /* frame->syscall_table */ + "movl %ecx,%esp\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" + "leal 16(%esi),%ecx\n\t" /* 5th, ... arguments */ + "pushl %ecx\n\t" + "pushl %esi\n\t" + "pushl %eax\n\t" + "pushl %ebx\n\t" + "call ntdll_dispatch_syscall\n\t" + "leal -0x34(%ebp),%esp\n" "5:\t" __ASM_CFI_CFA_IS_AT1(esp, 0x0c) diff --git a/dlls/ntdll/unix/signal_x86_64.c b/dlls/ntdll/unix/signal_x86_64.c index a8234701039..59f273b7381 100644 --- a/dlls/ntdll/unix/signal_x86_64.c +++ b/dlls/ntdll/unix/signal_x86_64.c @@ -2713,32 +2713,21 @@ __ASM_GLOBAL_FUNC( __wine_syscall_dispatcher, "leaq -0x98(%rbp),%rcx\n" "2:\n\t" #endif - "leaq 0x28(%rsp),%rsi\n\t" /* first argument */ + /* switch stack and dispatch syscall */ + "movq 0xa8(%rcx),%rdi\n\t" /* frame->syscall_table */ + "movq 0x00(%rcx),%rsi\n\t" + "movq 0x18(%rcx),%rdx\n\t" /* 2nd argument */ + "leaq 0x28(%rsp),%rax\n\t" /* 5th, ... arguments */ "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 5f\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" - "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" - "subq $0x20,%rsp\n\t" - "movq (%rbx),%r10\n\t" /* table->ServiceTable */ - "callq *(%r10,%rax,8)\n\t" + "movq %rax,%rcx\n\t" + "pushq %r9\n\t" + "pushq %r8\n\t" + "pushq %rdx\n\t" + "pushq %r10\n\t" + "movq %rsp,%rdx\n\t" + "callq ntdll_dispatch_syscall\n\t" + "leaq -0x98(%rbp),%rcx\n" /* $rcx is now pointing to "frame" again */ __ASM_CFI(".cfi_restore_state\n\t") diff --git a/dlls/ntdll/unix/unix_private.h b/dlls/ntdll/unix/unix_private.h index 72790605018..fa544e981ef 100644 --- a/dlls/ntdll/unix/unix_private.h +++ b/dlls/ntdll/unix/unix_private.h @@ -239,6 +239,7 @@ extern void DECLSPEC_NORETURN signal_start_thread( PRTL_THREAD_START_ROUTINE ent BOOL suspend, TEB *teb ) DECLSPEC_HIDDEN; extern void DECLSPEC_NORETURN signal_exit_thread( int status, void (*func)(int), TEB *teb ) DECLSPEC_HIDDEN; extern SYSTEM_SERVICE_TABLE KeServiceDescriptorTable[4] DECLSPEC_HIDDEN; +extern UINT_PTR ntdll_dispatch_syscall( SYSTEM_SERVICE_TABLE *tables, UINT_PTR code, UINT_PTR *arg03, UINT_PTR *arg4n ) DECLSPEC_HIDDEN; extern void __wine_syscall_dispatcher(void) DECLSPEC_HIDDEN; extern void WINAPI DECLSPEC_NORETURN __wine_syscall_dispatcher_return( void *frame, ULONG_PTR retval ) DECLSPEC_HIDDEN; extern NTSTATUS signal_set_full_context( CONTEXT *context ) DECLSPEC_HIDDEN; diff --git a/tools/valgrind.supp b/tools/valgrind.supp index c9d384297bc..a61767b56c8 100644 --- a/tools/valgrind.supp +++ b/tools/valgrind.supp @@ -20,6 +20,18 @@ Memcheck:Addr4 fun:__wine_syscall_dispatcher } +{ + wine_syscall_stack_args + Memcheck:Addr8 + fun:ntdll_dispatch_syscall + fun:__wine_syscall_dispatcher +} +{ + wine_syscall_stack_args + Memcheck:Addr4 + fun:ntdll_dispatch_syscall + fun:__wine_syscall_dispatcher +} { radeonsi_leaks Memcheck:Leak