ntdll: Implement a faster Unix call dispatcher on i386.

Inspired by a patch from Rémi Bernon.
This commit is contained in:
Alexandre Julliard 2022-11-30 17:11:20 +01:00
parent 90adeb125f
commit 911789e757
3 changed files with 76 additions and 6 deletions

View file

@ -117,6 +117,7 @@ void (WINAPI *p__wine_ctrl_routine)(void*);
SYSTEM_DLL_INIT_BLOCK *pLdrSystemDllInitBlock = NULL;
static void *p__wine_syscall_dispatcher;
static void **p__wine_unix_call_dispatcher;
static void * const syscalls[] =
{
@ -1053,6 +1054,7 @@ static void load_ntdll_functions( HMODULE module )
GET_FUNC( RtlUserThreadStart );
GET_FUNC( __wine_ctrl_routine );
GET_FUNC( __wine_syscall_dispatcher );
GET_FUNC( __wine_unix_call_dispatcher );
#ifdef __aarch64__
{
void **p__wine_current_teb;
@ -2188,6 +2190,9 @@ static void start_main_thread(void)
if (main_image_info.Machine != current_machine) load_wow64_ntdll( main_image_info.Machine );
load_apiset_dll();
ntdll_init_syscalls( 0, &syscall_table, p__wine_syscall_dispatcher );
#if defined(__i386__)
*p__wine_unix_call_dispatcher = __wine_unix_call_dispatcher;
#endif
server_init_process_done();
}

View file

@ -1817,12 +1817,23 @@ static BOOL handle_syscall_fault( ucontext_t *sigcontext, void *stack_ptr,
*/
static BOOL handle_syscall_trap( ucontext_t *sigcontext )
{
extern void __wine_syscall_dispatcher_prolog_end(void) DECLSPEC_HIDDEN;
struct syscall_frame *frame = x86_thread_data()->syscall_frame;
/* disallow single-stepping through a syscall */
if ((void *)EIP_sig( sigcontext ) != __wine_syscall_dispatcher) return FALSE;
if ((void *)EIP_sig( sigcontext ) == __wine_syscall_dispatcher)
{
extern void __wine_syscall_dispatcher_prolog_end(void) DECLSPEC_HIDDEN;
EIP_sig( sigcontext ) = (ULONG)__wine_syscall_dispatcher_prolog_end;
}
else if ((void *)EIP_sig( sigcontext ) == __wine_unix_call_dispatcher)
{
extern void __wine_unix_call_dispatcher_prolog_end(void) DECLSPEC_HIDDEN;
EIP_sig( sigcontext ) = (ULONG)__wine_unix_call_dispatcher_prolog_end;
}
else return FALSE;
TRACE( "ignoring trap in syscall eip=%08x eflags=%08x\n", EIP_sig(sigcontext), EFL_sig(sigcontext) );
@ -1830,7 +1841,6 @@ static BOOL handle_syscall_trap( ucontext_t *sigcontext )
frame->eflags = EFL_sig(sigcontext);
frame->restore_flags = LOWORD(CONTEXT_CONTROL);
EIP_sig( sigcontext ) = (ULONG)__wine_syscall_dispatcher_prolog_end;
ECX_sig( sigcontext ) = (ULONG)frame;
ESP_sig( sigcontext ) += sizeof(ULONG);
EFL_sig( sigcontext ) &= ~0x100; /* clear single-step flag */
@ -2617,7 +2627,8 @@ __ASM_GLOBAL_FUNC( __wine_syscall_dispatcher,
"rep; movsl\n\t"
"call *(%eax,%edx,4)\n\t"
"leal -0x34(%ebp),%esp\n"
"5:\t"
".L__wine_syscall_dispatcher_return:\t"
__ASM_CFI_CFA_IS_AT1(esp, 0x0c)
__ASM_CFI_REG_IS_AT1(esp, esp, 0x0c)
__ASM_CFI_REG_IS_AT1(eip, esp, 0x08)
@ -2692,7 +2703,8 @@ __ASM_GLOBAL_FUNC( __wine_syscall_dispatcher,
"iret\n"
__ASM_CFI("\t.cfi_restore_state\n")
"6:\tmovl $0xc000000d,%eax\n\t" /* STATUS_INVALID_PARAMETER */
"jmp 5b\n\t"
"jmp .L__wine_syscall_dispatcher_return\n\t"
".globl " __ASM_NAME("__wine_syscall_dispatcher_return") "\n"
__ASM_NAME("__wine_syscall_dispatcher_return") ":\n\t"
__ASM_CFI(".cfi_remember_state\n\t")
@ -2706,7 +2718,59 @@ __ASM_GLOBAL_FUNC( __wine_syscall_dispatcher,
"movl 8(%esp),%eax\n\t"
"movl 4(%esp),%esp\n\t"
__ASM_CFI(".cfi_restore_state\n\t")
"jmp 5b" )
"jmp .L__wine_syscall_dispatcher_return" )
/***********************************************************************
* __wine_unix_call_dispatcher
*/
__ASM_GLOBAL_FUNC( __wine_unix_call_dispatcher,
"movl %fs:0x1f8,%ecx\n\t" /* x86_thread_data()->syscall_frame */
"movw $0,0x02(%ecx)\n\t" /* frame->restore_flags */
"popl 0x08(%ecx)\n\t" /* frame->eip */
__ASM_CFI(".cfi_adjust_cfa_offset -4\n\t")
__ASM_CFI_REG_IS_AT1(eip, ecx, 0x08)
".globl " __ASM_NAME("__wine_unix_call_dispatcher_prolog_end") "\n"
__ASM_NAME("__wine_unix_call_dispatcher_prolog_end") ":\n\t"
"leal 0x10(%esp),%edx\n\t"
"movl %edx,0x0c(%ecx)\n\t" /* frame->esp */
__ASM_CFI_CFA_IS_AT1(ecx, 0x0c)
__ASM_CFI_REG_IS_AT1(esp, ecx, 0x0c)
"movw %cs,0x10(%ecx)\n\t"
"movw %ss,0x12(%ecx)\n\t"
"movw %ds,0x14(%ecx)\n\t"
"movw %es,0x16(%ecx)\n\t"
"movw %fs,0x18(%ecx)\n\t"
"movw %gs,0x1a(%ecx)\n\t"
"movl %ebx,0x20(%ecx)\n\t"
__ASM_CFI_REG_IS_AT1(ebx, ecx, 0x20)
"movl %edi,0x2c(%ecx)\n\t"
__ASM_CFI_REG_IS_AT1(edi, ecx, 0x2c)
"movl %esi,0x30(%ecx)\n\t"
__ASM_CFI_REG_IS_AT1(esi, ecx, 0x30)
"movl %ebp,0x34(%ecx)\n\t"
__ASM_CFI_REG_IS_AT1(ebp, ecx, 0x34)
"movl 12(%esp),%edx\n\t" /* args */
"movl %edx,-16(%ecx)\n\t"
"movl (%esp),%eax\n\t" /* handle */
"movl 8(%esp),%edx\n\t" /* code */
"leal -16(%ecx),%esp\n\t"
"call *(%eax,%edx,4)\n\t"
"leal 16(%esp),%esp\n\t"
__ASM_CFI_CFA_IS_AT1(esp, 0x0c)
__ASM_CFI_REG_IS_AT1(esp, esp, 0x0c)
__ASM_CFI_REG_IS_AT1(eip, esp, 0x08)
__ASM_CFI_REG_IS_AT1(ebx, esp, 0x20)
__ASM_CFI_REG_IS_AT1(edi, esp, 0x2c)
__ASM_CFI_REG_IS_AT1(esi, esp, 0x30)
__ASM_CFI_REG_IS_AT1(ebp, esp, 0x34)
"testw $0xffff,2(%esp)\n\t" /* frame->restore_flags */
"jnz .L__wine_syscall_dispatcher_return\n\t"
"movl 0x08(%esp),%ecx\n\t" /* frame->eip */
__ASM_CFI(".cfi_register %eip, %ecx\n\t")
"movl 0x0c(%esp),%esp\n\t" /* frame->esp */
__ASM_CFI(".cfi_same_value %esp\n\t")
"jmpl *%ecx" )
/***********************************************************************

View file

@ -245,6 +245,7 @@ extern void DECLSPEC_NORETURN signal_exit_thread( int status, void (*func)(int),
extern SYSTEM_SERVICE_TABLE KeServiceDescriptorTable[4] DECLSPEC_HIDDEN;
extern void __wine_syscall_dispatcher(void) DECLSPEC_HIDDEN;
extern void WINAPI DECLSPEC_NORETURN __wine_syscall_dispatcher_return( void *frame, ULONG_PTR retval ) DECLSPEC_HIDDEN;
extern void __wine_unix_call_dispatcher(void) DECLSPEC_HIDDEN;
extern NTSTATUS signal_set_full_context( CONTEXT *context ) DECLSPEC_HIDDEN;
extern NTSTATUS get_thread_wow64_context( HANDLE handle, void *ctx, ULONG size ) DECLSPEC_HIDDEN;
extern NTSTATUS set_thread_wow64_context( HANDLE handle, const void *ctx, ULONG size ) DECLSPEC_HIDDEN;