diff --git a/dlls/kernel/thunk.c b/dlls/kernel/thunk.c index fefc65da60b..676f7b9f6c4 100644 --- a/dlls/kernel/thunk.c +++ b/dlls/kernel/thunk.c @@ -27,6 +27,7 @@ #include "windef.h" #include "winbase.h" #include "winerror.h" +#include "ntddk.h" #include "wine/winbase16.h" #include "wine/debug.h" @@ -2091,6 +2092,7 @@ void WINAPI Throw16( LPCATCHBUF lpbuf, INT16 retval, CONTEXT86 *context ) } frame32 = ((STACK16FRAME *)MapSL(frame32->frame16))->frame32; } + RtlUnwind( &pFrame->frame32->frame, NULL, NULL, 0 ); context->Eip = lpbuf[0]; context->SegCs = lpbuf[1]; diff --git a/dlls/ntdll/exception.c b/dlls/ntdll/exception.c index 4fe4454e3c8..9263728447b 100644 --- a/dlls/ntdll/exception.c +++ b/dlls/ntdll/exception.c @@ -403,10 +403,29 @@ DWORD __wine_exception_handler( EXCEPTION_RECORD *record, EXCEPTION_FRAME *frame DWORD __wine_finally_handler( EXCEPTION_RECORD *record, EXCEPTION_FRAME *frame, CONTEXT *context, LPVOID pdispatcher ) { - __WINE_FRAME *wine_frame = (__WINE_FRAME *)frame; - - if (!(record->ExceptionFlags & (EH_UNWINDING | EH_EXIT_UNWIND))) - return ExceptionContinueSearch; - wine_frame->u.finally_func( FALSE ); + if (record->ExceptionFlags & (EH_UNWINDING | EH_EXIT_UNWIND)) + { + __WINE_FRAME *wine_frame = (__WINE_FRAME *)frame; + wine_frame->u.finally_func( FALSE ); + } + return ExceptionContinueSearch; +} + + +/************************************************************* + * __wine_callto16_handler + * + * Handler for exceptions occuring 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/include/stackframe.h b/include/stackframe.h index 3ed5d84454b..8cb9c39a4d1 100644 --- a/include/stackframe.h +++ b/include/stackframe.h @@ -32,18 +32,19 @@ /* 32-bit stack layout after CallTo16() */ typedef struct _STACK32FRAME { - SEGPTR frame16; /* 00 16-bit frame from last CallFrom16() */ - DWORD restore_addr; /* 04 return address for restoring code selector */ - DWORD codeselector; /* 08 code selector to restore */ - DWORD edi; /* 0c saved registers */ - DWORD esi; /* 10 */ - DWORD edx; /* 14 */ - DWORD ecx; /* 18 */ - DWORD ebx; /* 1c */ - DWORD ebp; /* 20 saved 32-bit frame pointer */ - DWORD retaddr; /* 24 return address */ - DWORD target; /* 28 target address / CONTEXT86 pointer */ - DWORD nb_args; /* 2c number of 16-bit argument bytes */ + DWORD restore_addr; /* 00 return address for restoring code selector */ + DWORD codeselector; /* 04 code selector to restore */ + EXCEPTION_FRAME frame; /* 08 Exception frame */ + SEGPTR frame16; /* 10 16-bit frame from last CallFrom16() */ + DWORD edi; /* 14 saved registers */ + DWORD esi; /* 18 */ + DWORD edx; /* 1c */ + DWORD ecx; /* 20 */ + DWORD ebx; /* 24 */ + DWORD ebp; /* 28 saved 32-bit frame pointer */ + DWORD retaddr; /* 2c return address */ + DWORD target; /* 30 target address / CONTEXT86 pointer */ + DWORD nb_args; /* 34 number of 16-bit argument bytes */ } STACK32FRAME; /* 16-bit stack layout after CallFrom16() */ diff --git a/tools/winebuild/relay.c b/tools/winebuild/relay.c index c40239c284d..f9e48c8c363 100644 --- a/tools/winebuild/relay.c +++ b/tools/winebuild/relay.c @@ -501,12 +501,6 @@ static void BuildCallTo16Core( FILE *outfile, int short_ret, int reg_func ) fprintf( outfile, "\taddl $_GLOBAL_OFFSET_TABLE_+[.-.Lwine_call_to_16_%s.getgot1], %%ebx\n", name ); } - /* Enter Win16 Mutex */ - if ( UsePIC ) - fprintf( outfile, "\tcall " __ASM_NAME("_EnterWin16Lock@PLT") "\n" ); - else - fprintf( outfile, "\tcall " __ASM_NAME("_EnterWin16Lock") "\n" ); - /* Print debugging info */ if (debugging) { @@ -523,6 +517,21 @@ static void BuildCallTo16Core( FILE *outfile, int short_ret, int reg_func ) fprintf( outfile, "\taddl $12, %%esp\n" ); } + /* Enter Win16 Mutex */ + if ( UsePIC ) + fprintf( outfile, "\tcall " __ASM_NAME("_EnterWin16Lock@PLT") "\n" ); + else + fprintf( outfile, "\tcall " __ASM_NAME("_EnterWin16Lock") "\n" ); + + /* 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, "\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 ) { @@ -534,7 +543,12 @@ static void BuildCallTo16Core( FILE *outfile, int short_ret, int reg_func ) /* Call the actual CallTo16 routine (simulate a lcall) */ fprintf( outfile, "\tpushl %%cs\n" ); - fprintf( outfile, "\tcall .Lwine_call_to_16_%s\n", name ); + fprintf( outfile, "\tcall .Lwine_call_to_16_%s\n", reg_func ? name : "long" ); + + /* Remove exception frame */ + fprintf( outfile, "\t.byte 0x64\n\tpopl (%d)\n", STRUCTOFFSET(TEB,except) ); + fprintf( outfile, "\taddl $4, %%esp\n" ); + fprintf( outfile, "\t.byte 0x64\n\tpopl (%d)\n", STACKOFFSET ); if ( !reg_func ) { @@ -563,7 +577,9 @@ static void BuildCallTo16Core( FILE *outfile, int short_ret, int reg_func ) * at the cost of a somewhat less efficient return path.] */ - fprintf( outfile, "\tmovl %d(%%esp), %%edi\n", STACK32OFFSET(target)-12 ); + fprintf( outfile, "\tmovl %d(%%esp), %%edi\n", STACK32OFFSET(target) - STACK32OFFSET(edi)); + /* everything above edi has been popped already */ + fprintf( outfile, "\tmovl %%eax, %d(%%edi)\n", CONTEXTOFFSET(Eax) ); fprintf( outfile, "\tmovl %%ebx, %d(%%edi)\n", CONTEXTOFFSET(Ebx) ); fprintf( outfile, "\tmovl %%ecx, %d(%%edi)\n", CONTEXTOFFSET(Ecx) ); @@ -584,6 +600,12 @@ static void BuildCallTo16Core( FILE *outfile, int short_ret, int reg_func ) fprintf( outfile, "\taddl $_GLOBAL_OFFSET_TABLE_+[.-.Lwine_call_to_16_%s.getgot2], %%ebx\n", name ); } + /* Leave Win16 Mutex */ + if ( UsePIC ) + fprintf( outfile, "\tcall " __ASM_NAME("_LeaveWin16Lock@PLT") "\n" ); + else + fprintf( outfile, "\tcall " __ASM_NAME("_LeaveWin16Lock") "\n" ); + /* Print debugging info */ if (debugging) { @@ -597,12 +619,6 @@ static void BuildCallTo16Core( FILE *outfile, int short_ret, int reg_func ) fprintf( outfile, "\taddl $4, %%esp\n" ); } - /* Leave Win16 Mutex */ - if ( UsePIC ) - fprintf( outfile, "\tcall " __ASM_NAME("_LeaveWin16Lock@PLT") "\n" ); - else - fprintf( outfile, "\tcall " __ASM_NAME("_LeaveWin16Lock") "\n" ); - /* Get return value */ fprintf( outfile, "\tpopl %%eax\n" ); @@ -620,13 +636,12 @@ static void BuildCallTo16Core( FILE *outfile, int short_ret, int reg_func ) /* Start of the actual CallTo16 routine */ + if (!reg_func && short_ret) return; /* call_to_16_word uses call_to_16_long backend routine */ + fprintf( outfile, ".Lwine_call_to_16_%s:\n", name ); - /* Complete STACK32FRAME */ - fprintf( outfile, "\t.byte 0x64\n\tpushl (%d)\n", STACKOFFSET ); - fprintf( outfile, "\tmovl %%esp,%%edx\n" ); - /* Switch to the 16-bit stack */ + fprintf( outfile, "\tmovl %%esp,%%edx\n" ); #ifdef __svr4__ fprintf( outfile,"\tdata16\n"); #endif @@ -739,7 +754,6 @@ static void BuildRet16Func( FILE *outfile ) #endif fprintf( outfile, "\tmovw %%di,%%ss\n" ); fprintf( outfile, "\t.byte 0x64\n\tmovl (%d),%%esp\n", STACKOFFSET ); - fprintf( outfile, "\t.byte 0x64\n\tpopl (%d)\n", STACKOFFSET ); /* Return to caller */