Module: wine Branch: master Commit: 917a206b01c82170a862e8497cbe26b6f1bfade0 URL: https://source.winehq.org/git/wine.git/?a=commit;h=917a206b01c82170a862e8497...
Author: Alexandre Julliard julliard@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@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" );