wow64cpu: Add a custom 32->64 thunk for Unix calls.

This commit is contained in:
Alexandre Julliard 2022-12-01 16:03:06 +01:00
parent a6bb3662dc
commit 7e680152d4
3 changed files with 92 additions and 9 deletions

View file

@ -94,6 +94,7 @@ static void * (WINAPI *pBTCpuGetBopCode)(void);
static void (WINAPI *pBTCpuProcessInit)(void); static void (WINAPI *pBTCpuProcessInit)(void);
static void (WINAPI *pBTCpuSimulate)(void); static void (WINAPI *pBTCpuSimulate)(void);
static NTSTATUS (WINAPI *pBTCpuResetToConsistentState)( EXCEPTION_POINTERS * ); static NTSTATUS (WINAPI *pBTCpuResetToConsistentState)( EXCEPTION_POINTERS * );
static void * (WINAPI *p__wine_get_unix_opcode)(void);
void *dummy = RtlUnwind; 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( BTCpuProcessInit );
GET_PTR( BTCpuResetToConsistentState ); GET_PTR( BTCpuResetToConsistentState );
GET_PTR( BTCpuSimulate ); GET_PTR( BTCpuSimulate );
GET_PTR( __wine_get_unix_opcode );
module = load_64bit_module( L"wow64win.dll" ); module = load_64bit_module( L"wow64win.dll" );
GET_PTR( sdwhwin32 ); 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_image_mapping( module );
init_syscall_table( module, 0, &ntdll_syscall_table ); init_syscall_table( module, 0, &ntdll_syscall_table );
*(void **)RtlFindExportedRoutineByName( module, "__wine_syscall_dispatcher" ) = pBTCpuGetBopCode(); *(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" ); module = load_32bit_module( L"win32u.dll" );
init_syscall_table( module, 1, psdwhwin32 ); init_syscall_table( module, 1, psdwhwin32 );

View file

@ -39,6 +39,18 @@ struct thunk_32to64
DWORD addr; DWORD addr;
WORD cs; 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" #include "poppack.h"
static BYTE DECLSPEC_ALIGN(4096) code_buffer[0x1000]; 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 0xa4(%r13),%ebx\n\t" /* context->Ebx */
"movl 0xb4(%r13),%ebp\n\t" /* context->Ebp */ "movl 0xb4(%r13),%ebp\n\t" /* context->Ebp */
"btrl $0,-4(%r13)\n\t" /* cpu->Flags & WOW64_CPURESERVED_FLAG_RESET_STATE */ "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 0xb8(%r13),%edx\n\t" /* context->Eip */
"movl %edx,(%rsp)\n\t" "movl %edx,(%rsp)\n\t"
"movl 0xbc(%r13),%edx\n\t" /* context->SegCs */ "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 */ "movl 0xc4(%r13),%r14d\n\t" /* context->Esp */
"xchgq %r14,%rsp\n\t" "xchgq %r14,%rsp\n\t"
"ljmp *(%r14)\n" "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 0xa8(%r13),%edx\n\t" /* context->Edx */
"movl 0xac(%r13),%ecx\n\t" /* context->Ecx */ "movl 0xac(%r13),%ecx\n\t" /* context->Ecx */
"movl 0xc8(%r13),%eax\n\t" /* context->SegSs */ "movl 0xc8(%r13),%eax\n\t" /* context->SegSs */
@ -215,6 +228,41 @@ __ASM_GLOBAL_FUNC( syscall_32to64,
"iretq" ) "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.@) * BTCpuSimulate (wow64cpu.@)
*/ */
@ -234,10 +282,13 @@ __ASM_STDCALL_FUNC( BTCpuSimulate, 0,
*/ */
NTSTATUS WINAPI BTCpuProcessInit(void) 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); SIZE_T size = sizeof(*thunk);
ULONG old_prot; ULONG old_prot;
CONTEXT context; CONTEXT context;
HMODULE module;
UNICODE_STRING str;
void **p__wine_unix_call_dispatcher;
if ((ULONG_PTR)syscall_32to64 >> 32) if ((ULONG_PTR)syscall_32to64 >> 32)
{ {
@ -245,16 +296,31 @@ NTSTATUS WINAPI BTCpuProcessInit(void)
return STATUS_INVALID_ADDRESS; 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 ); RtlCaptureContext( &context );
cs64_sel = context.SegCs; cs64_sel = context.SegCs;
ds64_sel = context.SegDs; ds64_sel = context.SegDs;
fs32_sel = context.SegFs; fs32_sel = context.SegFs;
thunk->ljmp = 0xff; thunk->syscall_thunk.ljmp = 0xff;
thunk->modrm = 0x2d; thunk->syscall_thunk.modrm = 0x2d;
thunk->op = PtrToUlong( &thunk->addr ); thunk->syscall_thunk.op = PtrToUlong( &thunk->syscall_thunk.addr );
thunk->addr = PtrToUlong( syscall_32to64 ); thunk->syscall_thunk.addr = PtrToUlong( syscall_32to64 );
thunk->cs = cs64_sel; 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 ); NtProtectVirtualMemory( GetCurrentProcess(), (void **)&thunk, &size, PAGE_EXECUTE_READ, &old_prot );
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
@ -265,7 +331,20 @@ NTSTATUS WINAPI BTCpuProcessInit(void)
*/ */
void * WINAPI BTCpuGetBopCode(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;
} }

View file

@ -7,3 +7,4 @@
@ stdcall BTCpuTurboThunkControl(long) @ stdcall BTCpuTurboThunkControl(long)
#@ stub TurboDispatchJumpAddressEnd #@ stub TurboDispatchJumpAddressEnd
#@ stub TurboDispatchJumpAddressStart #@ stub TurboDispatchJumpAddressStart
@ stdcall __wine_get_unix_opcode()