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.
This commit is contained in:
Alexandre Julliard 2003-08-25 00:56:37 +00:00
parent d631f30945
commit 3be5d62b29
8 changed files with 122 additions and 156 deletions

View file

@ -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;

View file

@ -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

View file

@ -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();

View file

@ -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;
}

View file

@ -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 ...)

View file

@ -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 */

View file

@ -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 */
}

View file

@ -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 );