diff --git a/dlls/wow64/syscall.c b/dlls/wow64/syscall.c index 86c5b61157e..a521c8c16c5 100644 --- a/dlls/wow64/syscall.c +++ b/dlls/wow64/syscall.c @@ -94,6 +94,7 @@ static void * (WINAPI *pBTCpuGetBopCode)(void); static void (WINAPI *pBTCpuProcessInit)(void); static void (WINAPI *pBTCpuSimulate)(void); static NTSTATUS (WINAPI *pBTCpuResetToConsistentState)( EXCEPTION_POINTERS * ); +static void * (WINAPI *p__wine_get_unix_opcode)(void); void *dummy = RtlUnwind; @@ -588,6 +589,7 @@ static DWORD WINAPI process_init( RTL_RUN_ONCE *once, void *param, void **contex GET_PTR( BTCpuProcessInit ); GET_PTR( BTCpuResetToConsistentState ); GET_PTR( BTCpuSimulate ); + GET_PTR( __wine_get_unix_opcode ); module = load_64bit_module( L"wow64win.dll" ); GET_PTR( sdwhwin32 ); @@ -598,6 +600,7 @@ static DWORD WINAPI process_init( RTL_RUN_ONCE *once, void *param, void **contex init_image_mapping( module ); init_syscall_table( module, 0, &ntdll_syscall_table ); *(void **)RtlFindExportedRoutineByName( module, "__wine_syscall_dispatcher" ) = pBTCpuGetBopCode(); + *(void **)RtlFindExportedRoutineByName( module, "__wine_unix_call_dispatcher" ) = p__wine_get_unix_opcode(); module = load_32bit_module( L"win32u.dll" ); init_syscall_table( module, 1, psdwhwin32 ); diff --git a/dlls/wow64cpu/cpu.c b/dlls/wow64cpu/cpu.c index fa1c22aafc6..750ab68d071 100644 --- a/dlls/wow64cpu/cpu.c +++ b/dlls/wow64cpu/cpu.c @@ -39,6 +39,18 @@ struct thunk_32to64 DWORD addr; WORD cs; }; +struct thunk_opcodes +{ + struct thunk_32to64 syscall_thunk; + struct + { + BYTE pushl; /* pushl $dispatcher_high */ + DWORD dispatcher_high; + BYTE pushl2; /* pushl $dispatcher_low */ + DWORD dispatcher_low; + struct thunk_32to64 t; + } unix_thunk; +}; #include "poppack.h" static BYTE DECLSPEC_ALIGN(4096) code_buffer[0x1000]; @@ -187,7 +199,7 @@ __ASM_GLOBAL_FUNC( syscall_32to64, "movl 0xa4(%r13),%ebx\n\t" /* context->Ebx */ "movl 0xb4(%r13),%ebp\n\t" /* context->Ebp */ "btrl $0,-4(%r13)\n\t" /* cpu->Flags & WOW64_CPURESERVED_FLAG_RESET_STATE */ - "jc 1f\n\t" + "jc .Lsyscall_32to64_return\n\t" "movl 0xb8(%r13),%edx\n\t" /* context->Eip */ "movl %edx,(%rsp)\n\t" "movl 0xbc(%r13),%edx\n\t" /* context->SegCs */ @@ -195,7 +207,8 @@ __ASM_GLOBAL_FUNC( syscall_32to64, "movl 0xc4(%r13),%r14d\n\t" /* context->Esp */ "xchgq %r14,%rsp\n\t" "ljmp *(%r14)\n" - "1:\tmovq %rsp,%r14\n\t" + ".Lsyscall_32to64_return:\n\t" + "movq %rsp,%r14\n\t" "movl 0xa8(%r13),%edx\n\t" /* context->Edx */ "movl 0xac(%r13),%ecx\n\t" /* context->Ecx */ "movl 0xc8(%r13),%eax\n\t" /* context->SegSs */ @@ -215,6 +228,41 @@ __ASM_GLOBAL_FUNC( syscall_32to64, "iretq" ) +/********************************************************************** + * unix_call_32to64 + * + * Execute a 64-bit Unix call from 32-bit code, then return to 32-bit. + */ +extern void WINAPI unix_call_32to64(void) DECLSPEC_HIDDEN; +__ASM_GLOBAL_FUNC( unix_call_32to64, + /* cf. BTCpuSimulate prolog */ + __ASM_SEH(".seh_stackalloc 0x28\n\t") + __ASM_SEH(".seh_endprologue\n\t") + __ASM_CFI(".cfi_adjust_cfa_offset 0x28\n\t") + "xchgq %r14,%rsp\n\t" + "movl %edi,0x9c(%r13)\n\t" /* context->Edi */ + "movl %esi,0xa0(%r13)\n\t" /* context->Esi */ + "movl %ebx,0xa4(%r13)\n\t" /* context->Ebx */ + "movl %ebp,0xb4(%r13)\n\t" /* context->Ebp */ + "movl 8(%r14),%edx\n\t" + "movl %edx,0xb8(%r13)\n\t" /* context->Eip */ + "leaq 28(%r14),%rdx\n\t" + "movl %edx,0xc4(%r13)\n\t" /* context->Esp */ + "movq 12(%r14),%rcx\n\t" /* handle */ + "movl 20(%r14),%edx\n\t" /* code */ + "movl 24(%r14),%r8d\n\t" /* args */ + "callq *(%r14)\n\t" + "btrl $0,-4(%r13)\n\t" /* cpu->Flags & WOW64_CPURESERVED_FLAG_RESET_STATE */ + "jc .Lsyscall_32to64_return\n\t" + "movl 0xb8(%r13),%edx\n\t" /* context->Eip */ + "movl %edx,(%rsp)\n\t" + "movl 0xbc(%r13),%edx\n\t" /* context->SegCs */ + "movl %edx,4(%rsp)\n\t" + "movl 0xc4(%r13),%r14d\n\t" /* context->Esp */ + "xchgq %r14,%rsp\n\t" + "ljmp *(%r14)" ) + + /********************************************************************** * BTCpuSimulate (wow64cpu.@) */ @@ -234,10 +282,13 @@ __ASM_STDCALL_FUNC( BTCpuSimulate, 0, */ NTSTATUS WINAPI BTCpuProcessInit(void) { - struct thunk_32to64 *thunk = (struct thunk_32to64 *)code_buffer; + struct thunk_opcodes *thunk = (struct thunk_opcodes *)code_buffer; SIZE_T size = sizeof(*thunk); ULONG old_prot; CONTEXT context; + HMODULE module; + UNICODE_STRING str; + void **p__wine_unix_call_dispatcher; if ((ULONG_PTR)syscall_32to64 >> 32) { @@ -245,16 +296,31 @@ NTSTATUS WINAPI BTCpuProcessInit(void) return STATUS_INVALID_ADDRESS; } + RtlInitUnicodeString( &str, L"ntdll.dll" ); + LdrGetDllHandle( NULL, 0, &str, &module ); + p__wine_unix_call_dispatcher = RtlFindExportedRoutineByName( module, "__wine_unix_call_dispatcher" ); + RtlCaptureContext( &context ); cs64_sel = context.SegCs; ds64_sel = context.SegDs; fs32_sel = context.SegFs; - thunk->ljmp = 0xff; - thunk->modrm = 0x2d; - thunk->op = PtrToUlong( &thunk->addr ); - thunk->addr = PtrToUlong( syscall_32to64 ); - thunk->cs = cs64_sel; + thunk->syscall_thunk.ljmp = 0xff; + thunk->syscall_thunk.modrm = 0x2d; + thunk->syscall_thunk.op = PtrToUlong( &thunk->syscall_thunk.addr ); + thunk->syscall_thunk.addr = PtrToUlong( syscall_32to64 ); + thunk->syscall_thunk.cs = cs64_sel; + + thunk->unix_thunk.pushl = 0x68; + thunk->unix_thunk.dispatcher_high = (ULONG_PTR)*p__wine_unix_call_dispatcher >> 32; + thunk->unix_thunk.pushl2 = 0x68; + thunk->unix_thunk.dispatcher_low = (ULONG_PTR)*p__wine_unix_call_dispatcher; + thunk->unix_thunk.t.ljmp = 0xff; + thunk->unix_thunk.t.modrm = 0x2d; + thunk->unix_thunk.t.op = PtrToUlong( &thunk->unix_thunk.t.addr ); + thunk->unix_thunk.t.addr = PtrToUlong( unix_call_32to64 ); + thunk->unix_thunk.t.cs = cs64_sel; + NtProtectVirtualMemory( GetCurrentProcess(), (void **)&thunk, &size, PAGE_EXECUTE_READ, &old_prot ); return STATUS_SUCCESS; } @@ -265,7 +331,20 @@ NTSTATUS WINAPI BTCpuProcessInit(void) */ void * WINAPI BTCpuGetBopCode(void) { - return code_buffer; + struct thunk_opcodes *thunk = (struct thunk_opcodes *)code_buffer; + + return &thunk->syscall_thunk; +} + + +/********************************************************************** + * __wine_get_unix_opcode (wow64cpu.@) + */ +void * WINAPI __wine_get_unix_opcode(void) +{ + struct thunk_opcodes *thunk = (struct thunk_opcodes *)code_buffer; + + return &thunk->unix_thunk; } diff --git a/dlls/wow64cpu/wow64cpu.spec b/dlls/wow64cpu/wow64cpu.spec index 6346cc54733..48c4800a611 100644 --- a/dlls/wow64cpu/wow64cpu.spec +++ b/dlls/wow64cpu/wow64cpu.spec @@ -7,3 +7,4 @@ @ stdcall BTCpuTurboThunkControl(long) #@ stub TurboDispatchJumpAddressEnd #@ stub TurboDispatchJumpAddressStart +@ stdcall __wine_get_unix_opcode()