Alexandre Julliard : wow64: Add support for multiple syscall tables.

Alexandre Julliard julliard at winehq.org
Tue Aug 31 15:40:22 CDT 2021


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

Author: Alexandre Julliard <julliard at winehq.org>
Date:   Tue Aug 31 11:31:04 2021 +0200

wow64: Add support for multiple syscall tables.

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

---

 dlls/wow64/syscall.c | 66 +++++++++++++++++++++++++++++++++++-----------------
 1 file changed, 45 insertions(+), 21 deletions(-)

diff --git a/dlls/wow64/syscall.c b/dlls/wow64/syscall.c
index 0df1dfc143b..feda6bf348c 100644
--- a/dlls/wow64/syscall.c
+++ b/dlls/wow64/syscall.c
@@ -53,7 +53,14 @@ static const char *syscall_names[] =
 #undef SYSCALL_ENTRY
 };
 
-static unsigned short syscall_map[1024];
+static const SYSTEM_SERVICE_TABLE ntdll_syscall_table =
+{
+    (ULONG_PTR *)syscall_thunks,
+    (ULONG_PTR *)syscall_names,
+    ARRAY_SIZE(syscall_thunks)
+};
+
+static SYSTEM_SERVICE_TABLE syscall_tables[4];
 
 /* header for Wow64AllocTemp blocks; probably not the right layout */
 struct mem_header
@@ -330,50 +337,64 @@ static DWORD get_syscall_num( const BYTE *syscall )
 /**********************************************************************
  *           init_syscall_table
  */
-static void init_syscall_table( HMODULE ntdll )
+static void init_syscall_table( HMODULE module, ULONG idx, const SYSTEM_SERVICE_TABLE *orig_table )
 {
+    static syscall_thunk thunks[2048];
+    static ULONG start_pos;
+
     const IMAGE_EXPORT_DIRECTORY *exports;
     const ULONG *functions, *names;
     const USHORT *ordinals;
-    ULONG id, exp_size, exp_pos, wrap_pos;
+    ULONG id, exp_size, exp_pos, wrap_pos, max_pos = 0;
+    const char **syscall_names = (const char **)orig_table->CounterTable;
 
-    args_alignment = (current_machine == IMAGE_FILE_MACHINE_I386) ? sizeof(ULONG) : sizeof(ULONG64);
-
-    exports = RtlImageDirectoryEntryToData( ntdll, TRUE, IMAGE_DIRECTORY_ENTRY_EXPORT, &exp_size );
-    ordinals = get_rva( ntdll, exports->AddressOfNameOrdinals );
-    functions = get_rva( ntdll, exports->AddressOfFunctions );
-    names = get_rva( ntdll, exports->AddressOfNames );
+    exports = RtlImageDirectoryEntryToData( module, TRUE, IMAGE_DIRECTORY_ENTRY_EXPORT, &exp_size );
+    ordinals = get_rva( module, exports->AddressOfNameOrdinals );
+    functions = get_rva( module, exports->AddressOfFunctions );
+    names = get_rva( module, exports->AddressOfNames );
 
     for (exp_pos = wrap_pos = 0; exp_pos < exports->NumberOfNames; exp_pos++)
     {
-        char *name = get_rva( ntdll, names[exp_pos] );
+        char *name = get_rva( module, names[exp_pos] );
         int res = -1;
 
         if (strncmp( name, "Nt", 2 ) && strncmp( name, "wine", 4 ) && strncmp( name, "__wine", 6 ))
             continue;  /* not a syscall */
 
-        if ((id = get_syscall_num( get_rva( ntdll, functions[ordinals[exp_pos]] ))) == ~0u)
+        if ((id = get_syscall_num( get_rva( module, functions[ordinals[exp_pos]] ))) == ~0u)
             continue; /* not a syscall */
 
-        if (wrap_pos < ARRAY_SIZE(syscall_names))
-            res = strcmp( name, syscall_names[wrap_pos] );
+        if (wrap_pos < orig_table->ServiceLimit) res = strcmp( name, syscall_names[wrap_pos] );
 
         if (!res)  /* got a match */
         {
-            if (id < ARRAY_SIZE(syscall_map)) syscall_map[id] = wrap_pos++;
-            else ERR( "invalid syscall id %04x for %s\n", id, name );
+            ULONG table_idx = (id >> 12) & 3, table_pos = id & 0xfff;
+            if (table_idx == idx)
+            {
+                if (start_pos + table_pos < ARRAY_SIZE(thunks))
+                {
+                    thunks[start_pos + table_pos] = (syscall_thunk)orig_table->ServiceTable[wrap_pos++];
+                    max_pos = max( table_pos, max_pos );
+                }
+                else ERR( "invalid syscall id %04x for %s\n", id, name );
+            }
+            else ERR( "wrong syscall table id %04x for %s\n", id, name );
         }
         else if (res > 0)
         {
-            FIXME( "no ntdll export for syscall %s\n", syscall_names[wrap_pos] );
+            FIXME( "no export for syscall %s\n", syscall_names[wrap_pos] );
             wrap_pos++;
             exp_pos--;  /* try again */
         }
         else FIXME( "missing wrapper for syscall %04x %s\n", id, name );
     }
 
-    for ( ; wrap_pos < ARRAY_SIZE(syscall_thunks); wrap_pos++)
-        FIXME( "no ntdll export for syscall %s\n", syscall_names[wrap_pos] );
+    for ( ; wrap_pos < orig_table->ServiceLimit; wrap_pos++)
+        FIXME( "no export for syscall %s\n", syscall_names[wrap_pos] );
+
+    syscall_tables[idx].ServiceTable = (ULONG_PTR *)(thunks + start_pos);
+    syscall_tables[idx].ServiceLimit = max_pos + 1;
+    start_pos += max_pos + 1;
 }
 
 
@@ -425,6 +446,7 @@ static DWORD WINAPI process_init( RTL_RUN_ONCE *once, void *param, void **contex
 
     RtlWow64GetProcessMachines( GetCurrentProcess(), &current_machine, &native_machine );
     if (!current_machine) current_machine = native_machine;
+    args_alignment = (current_machine == IMAGE_FILE_MACHINE_I386) ? sizeof(ULONG) : sizeof(ULONG64);
 
 #define GET_PTR(name) p ## name = RtlFindExportedRoutineByName( module, #name )
 
@@ -435,7 +457,7 @@ static DWORD WINAPI process_init( RTL_RUN_ONCE *once, void *param, void **contex
     module = (HMODULE)(ULONG_PTR)pLdrSystemDllInitBlock->ntdll_handle;
     GET_PTR( Wow64Transition );
     GET_PTR( __wine_syscall_dispatcher );
-    init_syscall_table( module );
+    init_syscall_table( module, 0, &ntdll_syscall_table );
 
     module = load_cpu_dll();
     GET_PTR( BTCpuGetBopCode );
@@ -540,15 +562,17 @@ static LONG CALLBACK syscall_filter( EXCEPTION_POINTERS *ptrs )
 NTSTATUS WINAPI Wow64SystemServiceEx( UINT num, UINT *args )
 {
     NTSTATUS status;
+    UINT id = num & 0xfff;
+    const SYSTEM_SERVICE_TABLE *table = &syscall_tables[(num >> 12) & 3];
 
-    if (num >= ARRAY_SIZE( syscall_map ) || !syscall_map[num])
+    if (id >= table->ServiceLimit || !table->ServiceTable[id])
     {
         ERR( "unsupported syscall %04x\n", num );
         return STATUS_INVALID_SYSTEM_SERVICE;
     }
     __TRY
     {
-        syscall_thunk thunk = syscall_thunks[syscall_map[num]];
+        syscall_thunk thunk = (syscall_thunk)table->ServiceTable[id];
         status = thunk( args );
     }
     __EXCEPT( syscall_filter )




More information about the wine-cvs mailing list