From 3be5d62b294a279246c9ed839bb61e6e36c17627 Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Mon, 25 Aug 2003 00:56:37 +0000 Subject: [PATCH] Moved 16-bit calls initialization and exception handling to kernel32. Store the call_to_16 return address on the stack from the C code so that we don't need two variants of call_to_16_regs. --- dlls/kernel/kernel_main.c | 6 +- dlls/kernel/kernel_private.h | 2 + dlls/kernel/wowthunk.c | 118 +++++++++++++++++++++++++++++++---- dlls/ntdll/exception.c | 22 ------- if1632/relay.c | 37 ----------- include/module.h | 1 - memory/instr.c | 18 ------ tools/winebuild/relay.c | 74 ++++------------------ 8 files changed, 122 insertions(+), 156 deletions(-) diff --git a/dlls/kernel/kernel_main.c b/dlls/kernel/kernel_main.c index c756968ecea..34dd9b1f1f0 100644 --- a/dlls/kernel/kernel_main.c +++ b/dlls/kernel/kernel_main.c @@ -41,10 +41,10 @@ #include "thread.h" #include "stackframe.h" #include "wincon.h" +#include "kernel_private.h" #include "console_private.h" extern void LOCALE_Init(void); -extern BOOL RELAY_Init(void); extern void COMPUTERNAME_Init(void); extern int __wine_set_signal_handler(unsigned, int (*)(unsigned)); @@ -115,8 +115,8 @@ static BOOL process_attach(void) /* Setup codepage info */ LOCALE_Init(); - /* Initialize relay entry points */ - if (!RELAY_Init()) return FALSE; + /* Initialize 16-bit thunking entry points */ + if (!WOWTHUNK_Init()) return FALSE; /* Initialize DOS memory */ if (!DOSMEM_Init(0)) return FALSE; diff --git a/dlls/kernel/kernel_private.h b/dlls/kernel/kernel_private.h index 2662e2eccf0..33acbe885bd 100644 --- a/dlls/kernel/kernel_private.h +++ b/dlls/kernel/kernel_private.h @@ -49,4 +49,6 @@ static inline HANDLE console_handle_unmap(HANDLE h) extern HANDLE dos_handles[DOS_TABLE_SIZE]; void FILE_ConvertOFMode( INT mode, DWORD *access, DWORD *sharing ); +extern BOOL WOWTHUNK_Init(void); + #endif diff --git a/dlls/kernel/wowthunk.c b/dlls/kernel/wowthunk.c index 6ee21d88dba..9ddd3ee7baa 100644 --- a/dlls/kernel/wowthunk.c +++ b/dlls/kernel/wowthunk.c @@ -27,12 +27,14 @@ #include "winbase.h" #include "winerror.h" #include "wownt32.h" +#include "excpt.h" #include "winternl.h" #include "syslevel.h" #include "file.h" #include "task.h" #include "miscemu.h" #include "stackframe.h" +#include "wine/exception.h" #include "wine/debug.h" WINE_DEFAULT_DEBUG_CHANNEL(thunk); @@ -70,6 +72,86 @@ static DWORD CALLBACK start_thread16( LPVOID threadArgs ) return K32WOWCallback16( (DWORD)args.proc, args.param ); } + +#ifdef __i386__ +/* symbols exported from relay16.s */ +extern DWORD WINAPI wine_call_to_16( FARPROC16 target, DWORD cbArgs, PEXCEPTION_HANDLER handler ); +extern void WINAPI wine_call_to_16_regs( CONTEXT86 *context, DWORD cbArgs, PEXCEPTION_HANDLER handler ); +extern void Call16_Ret_Start(), Call16_Ret_End(); +extern void CallTo16_Ret(); +extern void CALL32_CBClient_Ret(); +extern void CALL32_CBClientEx_Ret(); +extern DWORD CallTo16_DataSelector; +extern SEGPTR CALL32_CBClient_RetAddr; +extern SEGPTR CALL32_CBClientEx_RetAddr; + +static SEGPTR call16_ret_addr; /* segptr to CallTo16_Ret routine */ +#endif + +/*********************************************************************** + * WOWTHUNK_Init + */ +BOOL WOWTHUNK_Init(void) +{ +#ifdef __i386__ + /* allocate the code selector for CallTo16 routines */ + WORD codesel = SELECTOR_AllocBlock( (void *)Call16_Ret_Start, + (char *)Call16_Ret_End - (char *)Call16_Ret_Start, + WINE_LDT_FLAGS_CODE | WINE_LDT_FLAGS_32BIT ); + if (!codesel) return FALSE; + + /* Patch the return addresses for CallTo16 routines */ + + CallTo16_DataSelector = wine_get_ds(); + call16_ret_addr = MAKESEGPTR( codesel, (char*)CallTo16_Ret - (char*)Call16_Ret_Start ); + CALL32_CBClient_RetAddr = + MAKESEGPTR( codesel, (char*)CALL32_CBClient_Ret - (char*)Call16_Ret_Start ); + CALL32_CBClientEx_RetAddr = + MAKESEGPTR( codesel, (char*)CALL32_CBClientEx_Ret - (char*)Call16_Ret_Start ); +#endif + return TRUE; +} + + +/************************************************************* + * call16_handler + * + * Handler for exceptions occurring in 16-bit code. + */ +static DWORD call16_handler( EXCEPTION_RECORD *record, EXCEPTION_FRAME *frame, + CONTEXT *context, EXCEPTION_FRAME **pdispatcher ) +{ + if (record->ExceptionFlags & (EH_UNWINDING | EH_EXIT_UNWIND)) + { + /* unwinding: restore the stack pointer in the TEB, and leave the Win16 mutex */ + STACK32FRAME *frame32 = (STACK32FRAME *)((char *)frame - offsetof(STACK32FRAME,frame)); + NtCurrentTeb()->cur_stack = frame32->frame16; + _LeaveWin16Lock(); + } + else if (!IS_SELECTOR_SYSTEM(context->SegCs)) /* check for Win16 __GP handler */ + { + SEGPTR gpHandler = HasGPHandler16( MAKESEGPTR( context->SegCs, context->Eip ) ); + if (gpHandler) + { + WORD *stack = wine_ldt_get_ptr( context->SegSs, context->Esp ); + *--stack = context->SegCs; + *--stack = context->Eip; + + if (!IS_SELECTOR_32BIT(context->SegSs)) + context->Esp = MAKELONG( LOWORD(context->Esp - 2*sizeof(WORD)), + HIWORD(context->Esp) ); + else + context->Esp -= 2*sizeof(WORD); + + context->SegCs = SELECTOROF( gpHandler ); + context->Eip = OFFSETOF( gpHandler ); + return ExceptionContinueExecution; + } + } + return ExceptionContinueSearch; +} + + /* * 32-bit WOW routines (in WOW32, but actually forwarded to KERNEL32) */ @@ -295,16 +377,14 @@ BOOL WINAPI K32WOWCallback16Ex( DWORD vpfn16, DWORD dwFlags, DWORD cbArgs, LPVOID pArgs, LPDWORD pdwRetCode ) { #ifdef __i386__ - extern DWORD WINAPI wine_call_to_16( FARPROC16 target, DWORD cbArgs ); - extern void WINAPI wine_call_to_16_regs_short( CONTEXT86 *context, DWORD cbArgs ); - extern void WINAPI wine_call_to_16_regs_long ( CONTEXT86 *context, DWORD cbArgs ); - /* * Arguments must be prepared in the correct order by the caller * (both for PASCAL and CDECL calling convention), so we simply * copy them to the 16-bit stack ... */ - memcpy( (LPBYTE)CURRENT_STACK16 - cbArgs, (LPBYTE)pArgs, cbArgs ); + WORD *stack = (WORD *)CURRENT_STACK16 - cbArgs / sizeof(WORD); + + memcpy( stack, pArgs, cbArgs ); if (dwFlags & (WCB16_REGS|WCB16_REGS_LONG)) { @@ -312,13 +392,12 @@ BOOL WINAPI K32WOWCallback16Ex( DWORD vpfn16, DWORD dwFlags, if (TRACE_ON(relay)) { - WORD *stack16 = (WORD *)CURRENT_STACK16; DWORD count = cbArgs / sizeof(WORD); DPRINTF("%04lx:CallTo16(func=%04lx:%04x,ds=%04lx", GetCurrentThreadId(), context->SegCs, LOWORD(context->Eip), context->SegDs ); - while (count--) DPRINTF( ",%04x", *--stack16 ); + while (count) DPRINTF( ",%04x", stack[--count] ); DPRINTF(") ss:sp=%04x:%04x", SELECTOROF(NtCurrentTeb()->cur_stack), OFFSETOF(NtCurrentTeb()->cur_stack) ); DPRINTF(" ax=%04x bx=%04x cx=%04x dx=%04x si=%04x di=%04x bp=%04x es=%04x fs=%04x\n", @@ -328,11 +407,21 @@ BOOL WINAPI K32WOWCallback16Ex( DWORD vpfn16, DWORD dwFlags, SYSLEVEL_CheckNotLevel( 2 ); } - _EnterWin16Lock(); + /* push return address */ if (dwFlags & WCB16_REGS_LONG) - wine_call_to_16_regs_long( context, cbArgs ); + { + *((DWORD *)stack - 1) = HIWORD(call16_ret_addr); + *((DWORD *)stack - 2) = LOWORD(call16_ret_addr); + cbArgs += 2 * sizeof(DWORD); + } else - wine_call_to_16_regs_short( context, cbArgs ); + { + *((SEGPTR *)stack - 1) = call16_ret_addr; + cbArgs += sizeof(SEGPTR); + } + + _EnterWin16Lock(); + wine_call_to_16_regs( context, cbArgs, call16_handler ); _LeaveWin16Lock(); if (TRACE_ON(relay)) @@ -352,18 +441,21 @@ BOOL WINAPI K32WOWCallback16Ex( DWORD vpfn16, DWORD dwFlags, if (TRACE_ON(relay)) { - WORD *stack16 = (WORD *)CURRENT_STACK16; DWORD count = cbArgs / sizeof(WORD); DPRINTF("%04lx:CallTo16(func=%04x:%04x,ds=%04x", GetCurrentThreadId(), HIWORD(vpfn16), LOWORD(vpfn16), SELECTOROF(NtCurrentTeb()->cur_stack) ); - while (count--) DPRINTF( ",%04x", *--stack16 ); + while (count) DPRINTF( ",%04x", stack[--count] ); DPRINTF(") ss:sp=%04x:%04x\n", SELECTOROF(NtCurrentTeb()->cur_stack), OFFSETOF(NtCurrentTeb()->cur_stack) ); SYSLEVEL_CheckNotLevel( 2 ); } + /* push return address */ + *((SEGPTR *)stack - 1) = call16_ret_addr; + cbArgs += sizeof(SEGPTR); + /* * Actually, we should take care whether the called routine cleans up * its stack or not. Fortunately, our wine_call_to_16 core doesn't rely on @@ -371,7 +463,7 @@ BOOL WINAPI K32WOWCallback16Ex( DWORD vpfn16, DWORD dwFlags, * stack pointer is always reset to the position it had before. */ _EnterWin16Lock(); - ret = wine_call_to_16( (FARPROC16)vpfn16, cbArgs ); + ret = wine_call_to_16( (FARPROC16)vpfn16, cbArgs, call16_handler ); if (pdwRetCode) *pdwRetCode = ret; _LeaveWin16Lock(); diff --git a/dlls/ntdll/exception.c b/dlls/ntdll/exception.c index 6a2c5797d66..c0a6f939a22 100644 --- a/dlls/ntdll/exception.c +++ b/dlls/ntdll/exception.c @@ -27,10 +27,7 @@ #include "windef.h" #include "winternl.h" -#include "global.h" #include "wine/exception.h" -#include "stackframe.h" -#include "miscemu.h" #include "wine/server.h" #include "wine/debug.h" #include "excpt.h" @@ -410,22 +407,3 @@ DWORD __wine_finally_handler( EXCEPTION_RECORD *record, EXCEPTION_FRAME *frame, } return ExceptionContinueSearch; } - - -/************************************************************* - * __wine_callto16_handler - * - * Handler for exceptions occurring in 16-bit code. - */ -DWORD __wine_callto16_handler( EXCEPTION_RECORD *record, EXCEPTION_FRAME *frame, - CONTEXT *context, LPVOID pdispatcher ) -{ - if (record->ExceptionFlags & (EH_UNWINDING | EH_EXIT_UNWIND)) - { - /* unwinding: restore the stack pointer in the TEB, and leave the Win16 mutex */ - STACK32FRAME *frame32 = (STACK32FRAME *)((char *)frame - offsetof(STACK32FRAME,frame)); - NtCurrentTeb()->cur_stack = frame32->frame16; - _LeaveWin16Lock(); - } - return ExceptionContinueSearch; -} diff --git a/if1632/relay.c b/if1632/relay.c index bca70f91065..7fdd1276de1 100644 --- a/if1632/relay.c +++ b/if1632/relay.c @@ -37,43 +37,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(relay); -/*********************************************************************** - * RELAY_Init - */ -BOOL RELAY_Init(void) -{ -#ifdef __i386__ - WORD codesel; - - /* Allocate the code selector for CallTo16 routines */ - - extern void Call16_Ret_Start(), Call16_Ret_End(); - extern void CallTo16_Ret(); - extern void CALL32_CBClient_Ret(); - extern void CALL32_CBClientEx_Ret(); - extern SEGPTR CallTo16_RetAddr; - extern DWORD CallTo16_DataSelector; - extern SEGPTR CALL32_CBClient_RetAddr; - extern SEGPTR CALL32_CBClientEx_RetAddr; - - codesel = SELECTOR_AllocBlock( (void *)Call16_Ret_Start, - (char *)Call16_Ret_End - (char *)Call16_Ret_Start, - WINE_LDT_FLAGS_CODE | WINE_LDT_FLAGS_32BIT ); - if (!codesel) return FALSE; - - /* Patch the return addresses for CallTo16 routines */ - - CallTo16_DataSelector = wine_get_ds(); - CallTo16_RetAddr = - MAKESEGPTR( codesel, (char*)CallTo16_Ret - (char*)Call16_Ret_Start ); - CALL32_CBClient_RetAddr = - MAKESEGPTR( codesel, (char*)CALL32_CBClient_Ret - (char*)Call16_Ret_Start ); - CALL32_CBClientEx_RetAddr = - MAKESEGPTR( codesel, (char*)CALL32_CBClientEx_Ret - (char*)Call16_Ret_Start ); -#endif - return TRUE; -} - /* * Stubs for the CallTo16/CallFrom16 routines on non-Intel architectures * (these will never be called but need to be present to satisfy the linker ...) diff --git a/include/module.h b/include/module.h index 73ca4271978..954ad0fa464 100644 --- a/include/module.h +++ b/include/module.h @@ -181,7 +181,6 @@ extern NTSTATUS MODULE_DllThreadAttach( LPVOID lpReserved ); extern WINE_MODREF *MODULE_FindModule( LPCSTR path ); extern enum binary_type MODULE_GetBinaryType( HANDLE hfile ); extern FARPROC16 WINAPI WIN32_GetProcAddress16( HMODULE hmodule, LPCSTR name ); -extern SEGPTR WINAPI HasGPHandler16( SEGPTR address ); extern void MODULE_WalkModref( DWORD id ); /* loader/ne/module.c */ diff --git a/memory/instr.c b/memory/instr.c index 380ae6cc5d3..219be5e5392 100644 --- a/memory/instr.c +++ b/memory/instr.c @@ -810,24 +810,6 @@ DWORD INSTR_EmulateInstruction( CONTEXT86 *context ) } return 0; } - - - /* Check for Win16 __GP handler */ - if (!IS_SELECTOR_SYSTEM(context->SegCs)) - { - SEGPTR gpHandler = HasGPHandler16( MAKESEGPTR( context->SegCs, context->Eip ) ); - if (gpHandler) - { - WORD *stack = get_stack( context ); - *--stack = context->SegCs; - *--stack = context->Eip; - add_stack(context, -2*sizeof(WORD)); - - context->SegCs = SELECTOROF( gpHandler ); - context->Eip = OFFSETOF( gpHandler ); - return 0; - } - } return ret; /* Unable to emulate it */ } diff --git a/tools/winebuild/relay.c b/tools/winebuild/relay.c index c0f7ab257d6..4066874a923 100644 --- a/tools/winebuild/relay.c +++ b/tools/winebuild/relay.c @@ -449,32 +449,23 @@ static void BuildCallFrom16Core( FILE *outfile, int reg_func, int thunk, int sho * * This routine builds the core routines used in 32->16 thunks: * - * extern LONG WINAPI wine_call_to_16( SEGPTR target, int nb_args ); - * extern void WINAPI wine_call_to_16_regs_short( const CONTEXT86 *context, int nb_args ); - * extern void WINAPI wine_call_to_16_regs_long ( const CONTEXT86 *context, int nb_args ); + * extern DWORD WINAPI wine_call_to_16( FARPROC16 target, DWORD cbArgs, PEXCEPTION_HANDLER handler ); + * extern void WINAPI wine_call_to_16_regs( CONTEXT86 *context, DWORD cbArgs, PEXCEPTION_HANDLER handler ); * * These routines can be called directly from 32-bit code. * - * All routines expect that the 16-bit stack contents (arguments) were - * already set up by the caller; nb_args must contain the number of bytes - * to be conserved. The 16-bit SS:SP will be set accordinly. + * All routines expect that the 16-bit stack contents (arguments) and the + * return address (segptr to CallTo16_Ret) were already set up by the + * caller; nb_args must contain the number of bytes to be conserved. The + * 16-bit SS:SP will be set accordinly. * * All other registers are either taken from the CONTEXT86 structure * or else set to default values. The target routine address is either * given directly or taken from the CONTEXT86. - * - * If you want to call a 16-bit routine taking only standard argument types - * (WORD and LONG), you can also have an appropriate argument conversion - * stub automatically generated (see BuildCallTo16); you'd then call this - * stub, which in turn would prepare the 16-bit stack and call the appropiate - * core routine. - * */ static void BuildCallTo16Core( FILE *outfile, int reg_func ) { - const char *name = reg_func == 2 ? "wine_call_to_16_regs_long" : - reg_func == 1 ? "wine_call_to_16_regs_short" : - "wine_call_to_16"; + const char *name = reg_func ? "wine_call_to_16_regs" : "wine_call_to_16"; /* Function header */ function_header( outfile, name ); @@ -489,33 +480,12 @@ static void BuildCallTo16Core( FILE *outfile, int reg_func ) fprintf( outfile, "\tpushl %%edi\n" ); fprintf( outfile, "\t.byte 0x64\n\tmovl %%gs,(%d)\n", STRUCTOFFSET(TEB,gs_sel) ); - if ( UsePIC ) - { - /* Get Global Offset Table into %ebx */ - fprintf( outfile, "\tcall .L%s.getgot1\n", name ); - fprintf( outfile, ".L%s.getgot1:\n", name ); - fprintf( outfile, "\tpopl %%ebx\n" ); - fprintf( outfile, "\taddl $_GLOBAL_OFFSET_TABLE_+[.-.L%s.getgot1], %%ebx\n", name ); - } - /* Setup exception frame */ fprintf( outfile, "\t.byte 0x64\n\tpushl (%d)\n", STACKOFFSET ); - if (UsePIC) - fprintf( outfile, "\tpushl " __ASM_NAME("__wine_callto16_handler@GOT") "(%%ebx)\n" ); - else - fprintf( outfile, "\tpushl $" __ASM_NAME("__wine_callto16_handler") "\n" ); + fprintf( outfile, "\tpushl 16(%%ebp)\n" ); /* handler */ fprintf( outfile, "\t.byte 0x64\n\tpushl (%d)\n", STRUCTOFFSET(TEB,except) ); fprintf( outfile, "\t.byte 0x64\n\tmovl %%esp,(%d)\n", STRUCTOFFSET(TEB,except) ); - /* Get return address */ - if ( UsePIC ) - { - fprintf( outfile, "\tmovl " __ASM_NAME("CallTo16_RetAddr@GOT") "(%%ebx), %%ecx\n" ); - fprintf( outfile, "\tmovl (%%ecx), %%ecx\n" ); - } - else - fprintf( outfile, "\tmovl " __ASM_NAME("CallTo16_RetAddr") ", %%ecx\n" ); - /* Call the actual CallTo16 routine (simulate a lcall) */ fprintf( outfile, "\tpushl %%cs\n" ); fprintf( outfile, "\tcall .L%s\n", name ); @@ -528,9 +498,9 @@ static void BuildCallTo16Core( FILE *outfile, int reg_func ) if ( !reg_func ) { /* Convert return value */ + fprintf( outfile, "\tandl $0xffff,%%eax\n" ); fprintf( outfile, "\tshll $16,%%edx\n" ); - fprintf( outfile, "\tmovw %%ax,%%dx\n" ); - fprintf( outfile, "\tmovl %%edx,%%eax\n" ); + fprintf( outfile, "\torl %%edx,%%eax\n" ); } else { @@ -563,7 +533,7 @@ static void BuildCallTo16Core( FILE *outfile, int reg_func ) /* Function exit sequence */ fprintf( outfile, "\tpopl %%ebp\n" ); - fprintf( outfile, "\tret $8\n" ); + fprintf( outfile, "\tret $12\n" ); /* Start of the actual CallTo16 routine */ @@ -586,21 +556,6 @@ static void BuildCallTo16Core( FILE *outfile, int reg_func ) /* Add the specified offset to the new sp */ fprintf( outfile, "\tsubw %d(%%edx), %%sp\n", STACK32OFFSET(nb_args) ); - /* Push the return address - * With sreg suffix, we push 16:16 address (normal lret) - * With lreg suffix, we push 16:32 address (0x66 lret, for KERNEL32_45) - */ - if (reg_func != 2) - fprintf( outfile, "\tpushl %%ecx\n" ); - else - { - fprintf( outfile, "\tshldl $16, %%ecx, %%eax\n" ); - fprintf( outfile, "\tpushw $0\n" ); - fprintf( outfile, "\tpushw %%ax\n" ); - fprintf( outfile, "\tpushw $0\n" ); - fprintf( outfile, "\tpushw %%cx\n" ); - } - if (reg_func) { /* Push the called routine address */ @@ -700,8 +655,6 @@ static void BuildRet16Func( FILE *outfile ) fprintf( outfile, "\n\t.align %d\n", get_alignment(4) ); fprintf( outfile, "\t.globl " __ASM_NAME("CallTo16_DataSelector") "\n" ); fprintf( outfile, __ASM_NAME("CallTo16_DataSelector") ":\t.long 0\n" ); - fprintf( outfile, "\t.globl " __ASM_NAME("CallTo16_RetAddr") "\n" ); - fprintf( outfile, __ASM_NAME("CallTo16_RetAddr") ":\t.long 0\n" ); } @@ -1139,12 +1092,9 @@ void BuildRelays16( FILE *outfile ) /* Standard CallTo16 routine */ BuildCallTo16Core( outfile, 0 ); - /* Register CallTo16 routine (16:16 retf) */ + /* Register CallTo16 routine */ BuildCallTo16Core( outfile, 1 ); - /* Register CallTo16 routine (16:32 retf) */ - BuildCallTo16Core( outfile, 2 ); - /* CBClientThunkSL routine */ BuildCallTo32CBClient( outfile, FALSE );