Alexandre Julliard : winebuild: Generate Windows-style syscall thunks on x86_64.

Alexandre Julliard julliard at winehq.org
Wed Jul 8 15:34:35 CDT 2020


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

Author: Alexandre Julliard <julliard at winehq.org>
Date:   Wed Jul  8 09:20:57 2020 +0200

winebuild: Generate Windows-style syscall thunks on x86_64.

Based on patches by Michael Müller.

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

---

 server/mapping.c         |  6 ++++-
 tools/winebuild/import.c | 68 +++++++++++++++++++++++++++++++++++++++++++-----
 2 files changed, 67 insertions(+), 7 deletions(-)

diff --git a/server/mapping.c b/server/mapping.c
index 07c51c246d..ce70b696bd 100644
--- a/server/mapping.c
+++ b/server/mapping.c
@@ -964,7 +964,11 @@ struct object *create_user_data_mapping( struct object *root, const struct unico
     if (!(mapping = create_mapping( root, name, OBJ_OPENIF, sizeof(KSHARED_USER_DATA),
                                     SEC_COMMIT, 0, FILE_READ_DATA | FILE_WRITE_DATA, NULL ))) return NULL;
     ptr = mmap( NULL, mapping->size, PROT_WRITE, MAP_SHARED, get_unix_fd( mapping->fd ), 0 );
-    if (ptr != MAP_FAILED) user_shared_data = ptr;
+    if (ptr != MAP_FAILED)
+    {
+        user_shared_data = ptr;
+        user_shared_data->SystemCallPad[0] = 1;
+    }
     return &mapping->obj;
 }
 
diff --git a/tools/winebuild/import.c b/tools/winebuild/import.c
index b40c2c3107..b725e81163 100644
--- a/tools/winebuild/import.c
+++ b/tools/winebuild/import.c
@@ -1484,12 +1484,46 @@ void output_syscalls( DLLSPEC *spec )
             output( "\tjmp 2b\n" );
             break;
         case CPU_x86_64:
+            output( "\tpushq %%rbp\n" );
+            output_cfi( ".cfi_adjust_cfa_offset 8" );
+            output_cfi( ".cfi_rel_offset %%rbp,0" );
+            output( "\tmovq %%rsp,%%rbp\n" );
+            output_cfi( ".cfi_def_cfa_register %%rbp" );
+            output( "\tpushq %%rsi\n" );
+            output_cfi( ".cfi_rel_offset %%rsi,-8" );
+            output( "\tpushq %%rdi\n" );
+            output_cfi( ".cfi_rel_offset %%rdi,-16" );
+            /* Legends of Runeterra hooks the first system call return instruction, and
+             * depends on us returning to it. Adjust the return address accordingly. */
+            output( "\tsubq $0xb,0x8(%%rbp)\n" );
             output( "\tcmpq $%u,%%rax\n", count );
-            output( "\tjae 1f\n" );
+            output( "\tjae 3f\n" );
+            output( "\tmovzbq .Lsyscall_args(%%rip),%%rcx\n" );
+            output( "\tsubq $0x20,%%rcx\n" );
+            output( "\tjbe 1f\n" );
+            output( "\tsubq %%rcx,%%rsp\n" );
+            output( "\tshrq $3,%%rcx\n" );
+            output( "\tleaq 0x38(%%rbp),%%rsi\n" );
+            output( "\tandq $~15,%%rsp\n\t" );
+            output( "\tmovq %%rsp,%%rdi\n" );
+            output( "\tcld\n" );
+            output( "\trep; movsq\n" );
+            output( "1:\tmovq %%r10,%%rcx\n" );
+            output( "\tsubq $0x20,%%rsp\n" );
             output( "\tleaq .Lsyscall_table(%%rip),%%r10\n" );
-            output( "\tjmpq *(%%r10,%%rax,8)\n" );
-            output( "1:\tmovl $0x%x,%%eax\n", invalid_param );
+            output( "\tcallq *(%%r10,%%rax,8)\n" );
+            output( "2:\tleaq -0x10(%%rbp),%%rsp\n" );
+            output( "\tpopq %%rdi\n" );
+            output_cfi( ".cfi_same_value %%rdi" );
+            output( "\tpopq %%rsi\n" );
+            output_cfi( ".cfi_same_value %%rsi" );
+            output_cfi( ".cfi_def_cfa_register %%rsp" );
+            output( "\tpopq %%rbp\n" );
+            output_cfi( ".cfi_adjust_cfa_offset -8" );
+            output_cfi( ".cfi_same_value %%rbp" );
             output( "\tret\n" );
+            output( "3:\tmovl $0x%x,%%eax\n", invalid_param );
+            output( "\tjmp 2b\n" );
             break;
         case CPU_ARM:
             output( "\tldr r1, 4f\n" );
@@ -1562,9 +1596,31 @@ void output_syscalls( DLLSPEC *spec )
             output( "\tret $%u\n", get_args_size( odp ));
             break;
         case CPU_x86_64:
-            /* FIXME: syscall thunks not binary-compatible yet */
-            output( "\tmovl $%u,%%eax\n", i );
-            output( "\tjmpq *%s(%%rip)\n", asm_name("__wine_syscall_dispatcher") );
+            /* Chromium depends on syscall thunks having the same form as on
+             * Windows. For 64-bit systems the only viable form we can emulate is
+             * having an int $0x2e fallback. Since actually using an interrupt is
+             * expensive, and since for some reason Chromium doesn't actually
+             * validate that instruction, we can just put a jmp there instead. */
+            output( "\t.byte 0x4c,0x8b,0xd1\n" ); /* movq %rcx,%r10 */
+            output( "\t.byte 0xb8\n" );           /* movl $i,%eax */
+            output( "\t.long %u\n", i );
+            output( "\t.byte 0xf6,0x04,0x25,0x08,0x03,0xfe,0x7f,0x01\n" ); /* testb $1,0x7ffe0308 */
+            output( "\t.byte 0x75,0x03\n" );      /* jne 1f */
+            output( "\t.byte 0x0f,0x05\n" );      /* syscall */
+            output( "\t.byte 0xc3\n" );           /* ret */
+            output( "\tjmp 1f\n" );
+            output( "\t.byte 0xc3\n" );           /* ret */
+            if (target_platform == PLATFORM_WINDOWS)
+            {
+                output( "1:\t.byte 0xff,0x14,0x25\n" ); /* 2: callq *(__wine_syscall_dispatcher) */
+                output( "\t.long __wine_syscall_dispatcher\n" );
+            }
+            else
+            {
+                output( "\tnop\n" );
+                output( "1:\tcallq *%s(%%rip)\n", asm_name("__wine_syscall_dispatcher") );
+            }
+            output( "\tret\n" );
             break;
         case CPU_ARM:
             output( "\tpush {r0-r1}\n" );




More information about the wine-cvs mailing list