Alexandre Julliard : ntdll: Call the thread entry point through BaseThreadInitThunk().

Alexandre Julliard julliard at winehq.org
Tue Sep 1 15:43:30 CDT 2020


Module: wine
Branch: master
Commit: 1a9558cf9bda654950e389532b400023ecbd81c0
URL:    https://source.winehq.org/git/wine.git/?a=commit;h=1a9558cf9bda654950e389532b400023ecbd81c0

Author: Alexandre Julliard <julliard at winehq.org>
Date:   Tue Sep  1 12:48:04 2020 +0200

ntdll: Call the thread entry point through BaseThreadInitThunk().

Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 dlls/kernel32/kernel32.spec  |  2 +-
 dlls/kernel32/tests/thread.c | 18 ++++++++++++++++++
 dlls/kernel32/thread.c       | 29 +++++++++++++++++++++++++++++
 dlls/ntdll/loader.c          |  8 ++++++++
 dlls/ntdll/ntdll_misc.h      |  1 +
 dlls/ntdll/thread.c          | 37 ++++++++++++++++---------------------
 6 files changed, 73 insertions(+), 22 deletions(-)

diff --git a/dlls/kernel32/kernel32.spec b/dlls/kernel32/kernel32.spec
index 38eb1d5ece..e1c1319375 100644
--- a/dlls/kernel32/kernel32.spec
+++ b/dlls/kernel32/kernel32.spec
@@ -182,7 +182,7 @@
 @ stub BaseProcessInitPostImport
 # @ stub BaseQueryModuleData
 # @ stub BaseSetLastNTError
-# @ stub BaseThreadInitThunk
+@ stdcall -fastcall BaseThreadInitThunk(long ptr ptr)
 @ stub BaseUpdateAppcompatCache
 # @ stub BaseVerifyUnicodeString
 # @ stub Basep8BitStringToDynamicUnicodeString
diff --git a/dlls/kernel32/tests/thread.c b/dlls/kernel32/tests/thread.c
index bd9fe7fece..a6c923dc06 100644
--- a/dlls/kernel32/tests/thread.c
+++ b/dlls/kernel32/tests/thread.c
@@ -1176,10 +1176,24 @@ static void test_SetThreadContext(void)
     CloseHandle( thread );
 }
 
+static DWORD WINAPI test_stack( void *arg )
+{
+    DWORD *stack = (DWORD *)(((DWORD)&arg & ~0xfff) + 0x1000);
+
+    ok( stack == NtCurrentTeb()->Tib.StackBase, "wrong stack %p/%p\n",
+        stack, NtCurrentTeb()->Tib.StackBase );
+    ok( !stack[-1], "wrong data %p = %08x\n", stack - 1, stack[-1] );
+    ok( stack[-2] == (DWORD)arg, "wrong data %p = %08x\n", stack - 2, stack[-2] );
+    ok( stack[-3] == (DWORD)test_stack, "wrong data %p = %08x\n", stack - 3, stack[-3] );
+    ok( !stack[-4], "wrong data %p = %08x\n", stack - 4, stack[-4] );
+    return 0;
+}
+
 static void test_GetThreadContext(void)
 {
     CONTEXT ctx;
     BOOL ret;
+    HANDLE thread;
 
     memset(&ctx, 0xcc, sizeof(ctx));
     ctx.ContextFlags = CONTEXT_DEBUG_REGISTERS;
@@ -1188,6 +1202,10 @@ static void test_GetThreadContext(void)
     ok(ctx.ContextFlags == CONTEXT_DEBUG_REGISTERS, "ContextFlags = %x\n", ctx.ContextFlags);
     ok(!ctx.Dr0, "Dr0 = %x\n", ctx.Dr0);
     ok(!ctx.Dr1, "Dr0 = %x\n", ctx.Dr0);
+
+    thread = CreateThread( NULL, 0, test_stack, (void *)0x1234, 0, NULL );
+    WaitForSingleObject( thread, 1000 );
+    CloseHandle( thread );
 }
 
 static void test_GetThreadSelectorEntry(void)
diff --git a/dlls/kernel32/thread.c b/dlls/kernel32/thread.c
index 7fdec7b2ff..6e82a1e8c4 100644
--- a/dlls/kernel32/thread.c
+++ b/dlls/kernel32/thread.c
@@ -31,9 +31,38 @@
 #include "winerror.h"
 #include "winternl.h"
 
+#include "wine/asm.h"
 #include "kernel_private.h"
 
 
+#ifdef __i386__
+__ASM_STDCALL_FUNC( __fastcall_BaseThreadInitThunk, 12,
+                    "pushl %ebp\n\t"
+                    __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t")
+                    __ASM_CFI(".cfi_rel_offset %ebp,0\n\t")
+                    "movl %esp,%ebp\n\t"
+                    __ASM_CFI(".cfi_def_cfa_register %ebp\n\t")
+                    "pushl %ebx\n\t"
+                    __ASM_CFI(".cfi_rel_offset %ebx,-4\n\t")
+                    "movl 8(%ebp),%ebx\n\t"
+                    /* deliberately mis-align the stack by 8, Doom 3 needs this */
+                    "pushl 4(%ebp)\n\t"  /* Driller expects readable address at this offset */
+                    "pushl 4(%ebp)\n\t"
+                    "pushl %ebx\n\t"
+                    "call *%edx\n\t"
+                    "movl %eax,(%esp)\n\t"
+                    "call " __ASM_STDCALL( "RtlExitUserThread", 4 ))
+#endif
+
+/***********************************************************************
+ *           BaseThreadInitThunk (KERNEL32.@)
+ */
+void __fastcall BaseThreadInitThunk( DWORD unknown, LPTHREAD_START_ROUTINE entry, void *arg )
+{
+    RtlExitUserThread( entry( arg ) );
+}
+
+
 /***********************************************************************
  *           FreeLibraryAndExitThread (KERNEL32.@)
  */
diff --git a/dlls/ntdll/loader.c b/dlls/ntdll/loader.c
index 57fc75cef4..6d2115644f 100644
--- a/dlls/ntdll/loader.c
+++ b/dlls/ntdll/loader.c
@@ -58,6 +58,7 @@ WINE_DECLARE_DEBUG_CHANNEL(imports);
 typedef DWORD (CALLBACK *DLLENTRYPROC)(HMODULE,DWORD,LPVOID);
 typedef void  (CALLBACK *LDRENUMPROC)(LDR_DATA_TABLE_ENTRY *, void *, BOOLEAN *);
 
+void (FASTCALL *pBaseThreadInitThunk)(DWORD,LPTHREAD_START_ROUTINE,void *) = NULL;
 static void (WINAPI *kernel32_start_process)(LPTHREAD_START_ROUTINE,void *);
 
 const struct unix_funcs *unix_funcs = NULL;
@@ -4008,6 +4009,13 @@ static void process_init(void)
         MESSAGE( "wine: could not find __wine_start_process in kernel32.dll, status %x\n", status );
         NtTerminateProcess( GetCurrentProcess(), status );
     }
+    RtlInitAnsiString( &func_name, "BaseThreadInitThunk" );
+    if ((status = LdrGetProcedureAddress( wm->ldr.DllBase, &func_name,
+                                          0, (void **)&pBaseThreadInitThunk )) != STATUS_SUCCESS)
+    {
+        MESSAGE( "wine: could not find BaseThreadInitThunk in kernel32.dll, status %x\n", status );
+        NtTerminateProcess( GetCurrentProcess(), status );
+    }
 
     init_locale( wm->ldr.DllBase );
 
diff --git a/dlls/ntdll/ntdll_misc.h b/dlls/ntdll/ntdll_misc.h
index 86bdc9d44f..58e118011b 100644
--- a/dlls/ntdll/ntdll_misc.h
+++ b/dlls/ntdll/ntdll_misc.h
@@ -82,6 +82,7 @@ extern const WCHAR windows_dir[] DECLSPEC_HIDDEN;
 extern const WCHAR system_dir[] DECLSPEC_HIDDEN;
 extern const WCHAR syswow64_dir[] DECLSPEC_HIDDEN;
 
+extern void (FASTCALL *pBaseThreadInitThunk)(DWORD,LPTHREAD_START_ROUTINE,void *) DECLSPEC_HIDDEN;
 extern const struct unix_funcs *unix_funcs DECLSPEC_HIDDEN;
 
 extern void init_directories(void) DECLSPEC_HIDDEN;
diff --git a/dlls/ntdll/thread.c b/dlls/ntdll/thread.c
index ab34f0ba96..d718acd9d8 100644
--- a/dlls/ntdll/thread.c
+++ b/dlls/ntdll/thread.c
@@ -105,37 +105,32 @@ void WINAPI RtlExitUserThread( ULONG status )
  */
 #ifdef __i386__
 __ASM_STDCALL_FUNC( RtlUserThreadStart, 8,
-                   "pushl %ebp\n\t"
-                   __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t")
-                   __ASM_CFI(".cfi_rel_offset %ebp,0\n\t")
-                   "movl %esp,%ebp\n\t"
-                   __ASM_CFI(".cfi_def_cfa_register %ebp\n\t")
-                   "pushl %ebx\n\t"  /* arg */
-                   "pushl %eax\n\t"  /* entry */
-                   "call " __ASM_NAME("call_thread_func") )
-
-/* wrapper for apps that don't declare the thread function correctly */
-extern DWORD call_thread_func_wrapper( PRTL_THREAD_START_ROUTINE entry, void *arg );
-__ASM_GLOBAL_FUNC(call_thread_func_wrapper,
+                   "movl %ebx,8(%esp)\n\t"  /* arg */
+                   "movl %eax,4(%esp)\n\t"  /* entry */
+                   "jmp " __ASM_NAME("call_thread_func") )
+
+/* wrapper to call BaseThreadInitThunk */
+extern void DECLSPEC_NORETURN call_thread_func_wrapper( void *thunk, PRTL_THREAD_START_ROUTINE entry, void *arg );
+__ASM_GLOBAL_FUNC( call_thread_func_wrapper,
                   "pushl %ebp\n\t"
                   __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t")
                   __ASM_CFI(".cfi_rel_offset %ebp,0\n\t")
                   "movl %esp,%ebp\n\t"
                   __ASM_CFI(".cfi_def_cfa_register %ebp\n\t")
-                  "subl $4,%esp\n\t"
-                  "pushl 12(%ebp)\n\t"
-                  "call *8(%ebp)\n\t"
-                  "leave\n\t"
-                  __ASM_CFI(".cfi_def_cfa %esp,4\n\t")
-                  __ASM_CFI(".cfi_same_value %ebp\n\t")
-                  "ret" )
+                   "subl $4,%esp\n\t"
+                   "andl $~0xf,%esp\n\t"
+                   "xorl %ecx,%ecx\n\t"
+                   "movl 12(%ebp),%edx\n\t"
+                   "movl 16(%ebp),%eax\n\t"
+                   "movl %eax,(%esp)\n\t"
+                   "call *8(%ebp)" )
 
 void DECLSPEC_HIDDEN call_thread_func( PRTL_THREAD_START_ROUTINE entry, void *arg )
 {
     __TRY
     {
         TRACE_(relay)( "\1Starting thread proc %p (arg=%p)\n", entry, arg );
-        RtlExitUserThread( call_thread_func_wrapper( entry, arg ));
+        call_thread_func_wrapper( pBaseThreadInitThunk, entry, arg );
     }
     __EXCEPT(call_unhandled_exception_filter)
     {
@@ -151,7 +146,7 @@ void WINAPI RtlUserThreadStart( PRTL_THREAD_START_ROUTINE entry, void *arg )
     __TRY
     {
         TRACE_(relay)( "\1Starting thread proc %p (arg=%p)\n", entry, arg );
-        RtlExitUserThread( ((LPTHREAD_START_ROUTINE)entry)( arg ));
+        pBaseThreadInitThunk( 0, (LPTHREAD_START_ROUTINE)entry, arg );
     }
     __EXCEPT(call_unhandled_exception_filter)
     {




More information about the wine-cvs mailing list