From a5b961c2b04e64b5c619dd39739f554b49cc5689 Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Mon, 25 Aug 2003 23:48:30 +0000 Subject: [PATCH] Moved selector fixup for the relay code to the callto16 exception handler. Make sure to only use pop instructions to modify segment registers in the relay code to simplify the selector fixup. --- dlls/kernel/wowthunk.c | 96 +++++++++++++++++++++++++++++++++++++++---------- memory/instr.c | 12 ------- tools/winebuild/relay.c | 44 ++++++++++++----------- 3 files changed, 100 insertions(+), 52 deletions(-) diff --git a/dlls/kernel/wowthunk.c b/dlls/kernel/wowthunk.c index 9ddd3ee7baa..c2b7b3cf3ea 100644 --- a/dlls/kernel/wowthunk.c +++ b/dlls/kernel/wowthunk.c @@ -74,6 +74,7 @@ static DWORD CALLBACK start_thread16( LPVOID threadArgs ) #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 ); @@ -84,16 +85,16 @@ extern void CALL32_CBClientEx_Ret(); extern DWORD CallTo16_DataSelector; extern SEGPTR CALL32_CBClient_RetAddr; extern SEGPTR CALL32_CBClientEx_RetAddr; +extern BYTE Call16_Start; +extern BYTE Call16_End; 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, @@ -108,7 +109,48 @@ BOOL WOWTHUNK_Init(void) 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; +} + + +/************************************************************* + * fix_selector + * + * Fix a selector load that caused an exception if it's in the + * 16-bit relay code. + */ +static BOOL fix_selector( CONTEXT *context ) +{ + WORD *stack; + BYTE *instr = (BYTE *)context->Eip; + + if (instr < &Call16_Start || instr >= &Call16_End) return FALSE; + + /* skip prefixes */ + while (*instr == 0x66 || *instr == 0x67) instr++; + + switch(instr[0]) + { + case 0x07: /* pop es */ + case 0x17: /* pop ss */ + case 0x1f: /* pop ds */ + break; + case 0x0f: /* extended instruction */ + switch(instr[1]) + { + case 0xa1: /* pop fs */ + case 0xa9: /* pop gs */ + break; + default: + return FALSE; + } + break; + default: + return FALSE; + } + stack = wine_ldt_get_ptr( context->SegSs, context->Esp ); + TRACE( "fixing up selector %x for pop instruction\n", *stack ); + *stack = 0; return TRUE; } @@ -128,29 +170,45 @@ static DWORD call16_handler( EXCEPTION_RECORD *record, EXCEPTION_FRAME *frame, NtCurrentTeb()->cur_stack = frame32->frame16; _LeaveWin16Lock(); } - else if (!IS_SELECTOR_SYSTEM(context->SegCs)) /* check for Win16 __GP handler */ + else { - SEGPTR gpHandler = HasGPHandler16( MAKESEGPTR( context->SegCs, context->Eip ) ); - if (gpHandler) + if (IS_SELECTOR_SYSTEM(context->SegCs)) { - 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; + if (fix_selector( context )) return ExceptionContinueExecution; + } + else /* 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; } +#else /* __i386__ */ + +BOOL WOWTHUNK_Init(void) +{ + return TRUE; +} + +#endif /* __i386__ */ + /* * 32-bit WOW routines (in WOW32, but actually forwarded to KERNEL32) diff --git a/memory/instr.c b/memory/instr.c index 219be5e5392..c5212ac2b52 100644 --- a/memory/instr.c +++ b/memory/instr.c @@ -87,18 +87,6 @@ static DWORD CALLBACK timer_thread( void *dummy ) */ static BOOL INSTR_ReplaceSelector( CONTEXT86 *context, WORD *sel ) { - extern char Call16_Start, Call16_End; - - if (IS_SELECTOR_SYSTEM(context->SegCs)) - if ( (char *)context->Eip >= &Call16_Start - && (char *)context->Eip < &Call16_End ) - { - /* Saved selector may have become invalid when the relay code */ - /* tries to restore it. We simply clear it. */ - *sel = 0; - return TRUE; - } - if (*sel == 0x40) { #if 0 /* hack until this is moved to kernel */ diff --git a/tools/winebuild/relay.c b/tools/winebuild/relay.c index 4066874a923..ca1bd22d684 100644 --- a/tools/winebuild/relay.c +++ b/tools/winebuild/relay.c @@ -401,9 +401,12 @@ static void BuildCallFrom16Core( FILE *outfile, int reg_func, int thunk, int sho fprintf( outfile, "\tpushl %d(%%ebx)\n", CONTEXTOFFSET(EFlags) ); fprintf( outfile, "\tpushl %d(%%ebx)\n", CONTEXTOFFSET(SegDs) ); - fprintf( outfile, "\tmovw %d(%%ebx), %%es\n", CONTEXTOFFSET(SegEs) ); - fprintf( outfile, "\tmovw %d(%%ebx), %%fs\n", CONTEXTOFFSET(SegFs) ); - fprintf( outfile, "\tmovw %d(%%ebx), %%gs\n", CONTEXTOFFSET(SegGs) ); + fprintf( outfile, "\tpushl %d(%%ebx)\n", CONTEXTOFFSET(SegEs) ); + fprintf( outfile, "\tpopl %%es\n" ); + fprintf( outfile, "\tpushl %d(%%ebx)\n", CONTEXTOFFSET(SegFs) ); + fprintf( outfile, "\tpopl %%fs\n" ); + fprintf( outfile, "\tpushl %d(%%ebx)\n", CONTEXTOFFSET(SegGs) ); + fprintf( outfile, "\tpopl %%gs\n" ); fprintf( outfile, "\tmovl %d(%%ebx), %%ebp\n", CONTEXTOFFSET(Ebp) ); fprintf( outfile, "\tmovl %d(%%ebx), %%esi\n", CONTEXTOFFSET(Esi) ); @@ -565,12 +568,12 @@ static void BuildCallTo16Core( FILE *outfile, int reg_func ) /* Get the registers */ fprintf( outfile, "\tpushw %d(%%edx)\n", CONTEXTOFFSET(SegDs) ); - fprintf( outfile, "\tmovl %d(%%edx),%%eax\n", CONTEXTOFFSET(SegEs) ); - fprintf( outfile, "\tmovw %%ax,%%es\n" ); - fprintf( outfile, "\tmovl %d(%%edx),%%eax\n", CONTEXTOFFSET(SegFs) ); - fprintf( outfile, "\tmovw %%ax,%%fs\n" ); - fprintf( outfile, "\tmovl %d(%%edx),%%eax\n", CONTEXTOFFSET(SegGs) ); - fprintf( outfile, "\tmovw %%ax,%%gs\n" ); + fprintf( outfile, "\tpushl %d(%%edx)\n", CONTEXTOFFSET(SegEs) ); + fprintf( outfile, "\tpopl %%es\n" ); + fprintf( outfile, "\tpushl %d(%%edx)\n", CONTEXTOFFSET(SegFs) ); + fprintf( outfile, "\tpopl %%fs\n" ); + fprintf( outfile, "\tpushl %d(%%edx)\n", CONTEXTOFFSET(SegGs) ); + fprintf( outfile, "\tpopl %%gs\n" ); fprintf( outfile, "\tmovl %d(%%edx),%%ebp\n", CONTEXTOFFSET(Ebp) ); fprintf( outfile, "\tmovl %d(%%edx),%%esi\n", CONTEXTOFFSET(Esi) ); fprintf( outfile, "\tmovl %d(%%edx),%%edi\n", CONTEXTOFFSET(Edi) ); @@ -588,10 +591,10 @@ static void BuildCallTo16Core( FILE *outfile, int reg_func ) fprintf( outfile, "\tpushl %d(%%edx)\n", STACK32OFFSET(target) ); /* Set %fs and %gs to the value saved by the last CallFrom16 */ - fprintf( outfile, "\tmovw %d(%%ebp),%%ax\n", STACK16OFFSET(fs)-STACK16OFFSET(bp) ); - fprintf( outfile, "\tmovw %%ax,%%fs\n" ); - fprintf( outfile, "\tmovw %d(%%ebp),%%ax\n", STACK16OFFSET(gs)-STACK16OFFSET(bp) ); - fprintf( outfile, "\tmovw %%ax,%%gs\n" ); + fprintf( outfile, "\tpushw %d(%%ebp)\n", STACK16OFFSET(fs)-STACK16OFFSET(bp) ); + fprintf( outfile, "\tpopw %%fs\n" ); + fprintf( outfile, "\tpushw %d(%%ebp)\n", STACK16OFFSET(gs)-STACK16OFFSET(bp) ); + fprintf( outfile, "\tpopw %%gs\n" ); /* Set %ds and %es (and %ax just in case) equal to %ss */ fprintf( outfile, "\tmovw %%ss,%%ax\n" ); @@ -1020,12 +1023,12 @@ static void BuildCallFrom32Regs( FILE *outfile ) /* Note: we don't bother to restore %cs, %ds and %ss * changing them in 32-bit code is a recipe for disaster anyway */ - fprintf( outfile, "\tmovl %d(%%ebp),%%eax\n", CONTEXTOFFSET(SegEs) - STACK_SPACE ); - fprintf( outfile, "\tmovw %%ax,%%es\n" ); - fprintf( outfile, "\tmovl %d(%%ebp),%%eax\n", CONTEXTOFFSET(SegFs) - STACK_SPACE ); - fprintf( outfile, "\tmovw %%ax,%%fs\n" ); - fprintf( outfile, "\tmovl %d(%%ebp),%%eax\n", CONTEXTOFFSET(SegGs) - STACK_SPACE ); - fprintf( outfile, "\tmovw %%ax,%%gs\n" ); + fprintf( outfile, "\tpushl %d(%%ebp)\n", CONTEXTOFFSET(SegEs) - STACK_SPACE ); + fprintf( outfile, "\tpopl %%es\n" ); + fprintf( outfile, "\tpushl %d(%%ebp)\n", CONTEXTOFFSET(SegFs) - STACK_SPACE ); + fprintf( outfile, "\tpopl %%fs\n" ); + fprintf( outfile, "\tpushl %d(%%ebp)\n", CONTEXTOFFSET(SegGs) - STACK_SPACE ); + fprintf( outfile, "\tpopl %%gs\n" ); fprintf( outfile, "\tmovl %d(%%ebp),%%edi\n", CONTEXTOFFSET(Edi) - STACK_SPACE ); fprintf( outfile, "\tmovl %d(%%ebp),%%esi\n", CONTEXTOFFSET(Esi) - STACK_SPACE ); @@ -1033,8 +1036,7 @@ static void BuildCallFrom32Regs( FILE *outfile ) fprintf( outfile, "\tmovl %d(%%ebp),%%ecx\n", CONTEXTOFFSET(Ecx) - STACK_SPACE ); fprintf( outfile, "\tmovl %d(%%ebp),%%ebx\n", CONTEXTOFFSET(Ebx) - STACK_SPACE ); - fprintf( outfile, "\tmovl %d(%%ebp),%%eax\n", CONTEXTOFFSET(EFlags) - STACK_SPACE ); - fprintf( outfile, "\tpushl %%eax\n" ); + fprintf( outfile, "\tpushl %d(%%ebp)\n", CONTEXTOFFSET(EFlags) - STACK_SPACE ); fprintf( outfile, "\tpopfl\n" ); fprintf( outfile, "\tmovl %d(%%ebp),%%eax\n", CONTEXTOFFSET(Eax) - STACK_SPACE ); -- 2.11.4.GIT