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 | 71 +++++++++++++++++++++++++++++++++ dlls/ntdll/unix/signal_i386.c | 33 +++++++-------- dlls/ntdll/unix/signal_x86_64.c | 38 +++++++----------- dlls/ntdll/unix/unix_private.h | 1 + tools/valgrind.supp | 12 ++++++ 5 files changed, 112 insertions(+), 43 deletions(-)
diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c index 500c9884121..aaf47ad69cc 100644 --- a/dlls/ntdll/unix/loader.c +++ b/dlls/ntdll/unix/loader.c @@ -1330,6 +1330,77 @@ already_loaded: }
+/*********************************************************************** + * ntdll_dispatch_syscall + */ +UINT_PTR ntdll_dispatch_syscall( SYSTEM_SERVICE_TABLE *tables, UINT_PTR code, UINT_PTR *arg03, UINT_PTR *arg4n ) +{ + typedef UINT_PTR (WINAPIV *syscall_n)(UINT_PTR arg0, ...); + typedef UINT_PTR (WINAPIV *syscall_0)(void); + + SYSTEM_SERVICE_TABLE *table = tables + (code & 0x3000) / 0x1000; + UINT_PTR ret = STATUS_INVALID_PARAMETER; + int argc, index = code & 0xfff; + syscall_n call; + + if (code >= 0x4000 || index >= table->ServiceLimit) return STATUS_INVALID_PARAMETER; + call = (syscall_n)table->ServiceTable[index]; + + switch ((argc = table->ArgumentTable[index] / sizeof(UINT_PTR))) + { + case 0: ret = ((syscall_0)table->ServiceTable[index])(); break; + case 1: ret = call( arg03[0] ); break; + case 2: ret = call( arg03[0], arg03[1] ); break; + case 3: ret = call( arg03[0], arg03[1], arg03[2] ); break; + case 4: ret = call( arg03[0], arg03[1], arg03[2], arg03[3] ); break; + case 5: ret = call( arg03[0], arg03[1], arg03[2], arg03[3], arg4n[0] ); break; + case 6: ret = call( arg03[0], arg03[1], arg03[2], arg03[3], arg4n[0], arg4n[1] ); break; + case 7: ret = call( arg03[0], arg03[1], arg03[2], arg03[3], arg4n[0], arg4n[1], arg4n[2] ); break; + case 8: ret = call( arg03[0], arg03[1], arg03[2], arg03[3], arg4n[0], arg4n[1], arg4n[2], arg4n[3] ); break; + case 9: + ret = call( arg03[0], arg03[1], arg03[2], arg03[3], arg4n[0], arg4n[1], arg4n[2], arg4n[3], + arg4n[4] ); + break; + case 10: + ret = call( arg03[0], arg03[1], arg03[2], arg03[3], arg4n[0], arg4n[1], arg4n[2], arg4n[3], + arg4n[4], arg4n[5] ); + break; + case 11: + ret = call( arg03[0], arg03[1], arg03[2], arg03[3], arg4n[0], arg4n[1], arg4n[2], arg4n[3], + arg4n[4], arg4n[5], arg4n[6] ); + break; + case 12: + ret = call( arg03[0], arg03[1], arg03[2], arg03[3], arg4n[0], arg4n[1], arg4n[2], arg4n[3], + arg4n[4], arg4n[5], arg4n[6], arg4n[7] ); + break; + case 13: + ret = call( 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] ); + break; + case 14: + ret = call( 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] ); + break; + case 15: + ret = call( 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] ); + break; + case 16: + ret = call( 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] ); + break; + case 17: + ret = call( 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] ); + break; + default: ERR( "syscall with %u arguments, not implemented!\n", argc ); break; + } + + return ret; +} + + /*********************************************************************** * ntdll_init_syscalls */ diff --git a/dlls/ntdll/unix/signal_i386.c b/dlls/ntdll/unix/signal_i386.c index d5dd77b43ff..9250f863145 100644 --- a/dlls/ntdll/unix/signal_i386.c +++ b/dlls/ntdll/unix/signal_i386.c @@ -2499,11 +2499,6 @@ __ASM_GLOBAL_FUNC( __wine_syscall_dispatcher, __ASM_CFI(".cfi_rel_offset %edi,-0x08\n\t") __ASM_CFI(".cfi_rel_offset %esi,-0x04\n\t") __ASM_CFI(".cfi_rel_offset %ebp,-0x00\n\t") - "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" @@ -2536,21 +2531,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:\tmovl 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 */ diff --git a/dlls/ntdll/unix/signal_x86_64.c b/dlls/ntdll/unix/signal_x86_64.c index e2b7fa73a36..98152194e5f 100644 --- a/dlls/ntdll/unix/signal_x86_64.c +++ b/dlls/ntdll/unix/signal_x86_64.c @@ -3407,32 +3407,22 @@ __ASM_GLOBAL_FUNC( __wine_syscall_dispatcher, __ASM_CFI(".cfi_rel_offset %rip,-0x28\n\t") __ASM_CFI(".cfi_rel_offset %rsp,-0x10\n\t") __ASM_CFI(".cfi_rel_offset %rbp,-0x00\n\t") - "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" __ASM_CFI(".cfi_endproc\n\t") __ASM_CFI(".cfi_startproc\n\t") diff --git a/dlls/ntdll/unix/unix_private.h b/dlls/ntdll/unix/unix_private.h index 7165dd694a9..fbb4c5151c3 100644 --- a/dlls/ntdll/unix/unix_private.h +++ b/dlls/ntdll/unix/unix_private.h @@ -241,6 +241,7 @@ extern void DECLSPEC_NORETURN signal_start_thread( PRTL_THREAD_START_ROUTINE ent extern void thread_start( PRTL_THREAD_START_ROUTINE entry, void *arg, BOOL suspend, 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