Implemented (partially) the KERNEL Thunklet API and Callback Client

API (KERNEL.560-568,604-612,619-622).
Added stubs for K228, K237, KERNEL.365, KERNEL.447.
This commit is contained in:
Ulrich Weigand 1998-10-11 19:26:00 +00:00 committed by Alexandre Julliard
parent f276a7d441
commit 5efaf50ed5
4 changed files with 587 additions and 28 deletions

View File

@ -234,7 +234,7 @@ file krnl386.exe
225 pascal RegQueryValueEx(long str ptr ptr ptr ptr) RegQueryValueEx16
226 pascal RegSetValueEx(long str long long ptr long) RegSetValueEx16
227 pascal RegFlushKey(long) RegFlushKey
228 stub K228
228 pascal16 K228(word) GetExePtr
229 pascal16 K229(long) Local32GetSegment
230 pascal GlobalSmartPageLock(word) GlobalPageLock #?
231 stub GlobalSmartPageUnlock
@ -243,7 +243,7 @@ file krnl386.exe
234 stub RegSaveKey
235 stub InvalidateNlsCache
236 stub GetProductName
237 stub K237
237 return K237 0 0
# 262-274 are WinNT extensions; those are not present in Win95
@ -307,7 +307,7 @@ file krnl386.exe
360 pascal16 OpenFileEx(str ptr word) OpenFile16
361 return PIGLET_361 0 0
362 stub ThunkTerminateProcess
365 stub KERNEL_365
365 register KERNEL_365(word word) KERNEL_365
# 403-404 are common to all versions
@ -351,13 +351,13 @@ file krnl386.exe
444 stub KERNEL_444 # Local32 ???
445 stub KERNEL_445 # Local32 ???
446 stub KERNEL_446 # Local32 ???
447 stub KERNEL_447
447 return KERNEL_447 0 0
448 stub KERNEL_448
449 pascal GetpWin16Lock() GetpWin16Lock16
450 pascal VWin32_EventWait(long) VWin32_EventWait
451 pascal VWin32_EventSet(long) VWin32_EventSet
452 pascal LoadLibrary32(str) LoadLibrary32A
453 pascal GetProcAddress32(long str) GetProcAddress32
453 pascal GetProcAddress32(long str) WIN16_GetProcAddress32
454 equate __FLATCS 0 # initialized by BUILTIN_Init()
455 equate __FLATDS 0 # initialized by BUILTIN_Init()
456 pascal DefResourceHandler(word word word) NE_DefResourceHandler
@ -455,15 +455,14 @@ file krnl386.exe
#541 stub KERNEL_541
542 stub KERNEL_542
543 stub KERNEL_543
560 stub KERNEL_560 # (thunklet) # InitThunkletHandler
561 stub KERNEL_561 # (thunklet) # AllocLSThunklet
562 stub KERNEL_562 # (thunklet) # AllocSLThunklet
563 stub KERNEL_563 # (thunklet) # FindSLThunklet
564 stub KERNEL_564 # (thunklet) # FindLSThunklet
565 stub KERNEL_565 # (thunklet) # AllocLSThunklet_Special
566 stub KERNEL_566 # (thunklet) # AllocSLThunklet_Special
567 stub KERNEL_567 # (thunklet) # AllocLSThunkletEx
568 stub KERNEL_568 # (thunklet) # AllocSLThunkletEx
560 pascal SetThunkletCallbackGlue(long segptr) SetThunkletCallbackGlue
561 pascal AllocLSThunkletCallback(segptr long) AllocLSThunkletCallback
562 pascal AllocSLThunkletCallback(long long) AllocSLThunkletCallback
563 pascal FindLSThunkletCallback(segptr long) FindLSThunkletCallback
564 pascal FindSLThunkletCallback(long long) FindSLThunkletCallback
566 stub KERNEL_566 # (thunklet) FIXME!!!
567 pascal AllocLSThunkletCallbackEx(segptr long word) AllocLSThunkletCallbackEx
568 pascal AllocSLThunkletCallbackEx(long long word) AllocSLThunkletCallbackEx
# 600-653 are Win95 only
@ -472,25 +471,25 @@ file krnl386.exe
601 stub KERNEL_601 # FreeSelector (?)
602 stub GetCurrentHInstanceDS
603 stub KERNEL_603 # OutputDebugString (?)
604 stub KERNEL_604 # (cbclient) # Thunk_CBClient
605 stub KERNEL_605 # (thunklet) # AllocSLThunklet
606 stub KERNEL_606 # (thunklet) # AllocLSThunklet
607 pascal KERNEL_607(long long long) _KERNEL_607 # AllocLSThunklet_Systhunk
608 pascal KERNEL_608(long long long) _KERNEL_608 # AllocSLThunklet_Systhunk
609 stub KERNEL_609 # (thunklet) # FindSLThunklet
610 stub KERNEL_610 # (thunklet) # FindLSThunklet
611 pascal16 KERNEL_611(long long) _KERNEL_611 # FreeThunklet
612 pascal16 KERNEL_612(ptr) _KERNEL_612 # IsSLThunklet
604 register CBClientGlueSL() CBClientGlueSL
605 pascal AllocSLThunkletCallback(long long) AllocSLThunkletCallback
606 pascal AllocLSThunkletCallback(segptr long) AllocLSThunkletCallback
607 pascal AllocLSThunkletSysthunk(segptr long long) AllocLSThunkletSysthunk
608 pascal AllocSLThunkletSysthunk(long segptr long) AllocSLThunkletSysthunk
609 pascal FindLSThunkletCallback(segptr long) FindLSThunkletCallback
610 pascal FindSLThunkletCallback(long long) FindSLThunkletCallback
611 return FreeThunklet 8 0
612 pascal16 IsSLThunklet(ptr) IsSLThunklet
613 stub KERNEL_613 # (cbclient)
614 stub KERNEL_614 # (cbclient)
615 stub KERNEL_615 # (cbclient)
616 stub KERNEL_616 # (cbclient)
617 stub KERNEL_617 # (cbclient)
618 stub KERNEL_618 # (cbclient)
619 pascal16 RegisterCBClient(word long long) RegisterCBClient
620 stub KERNEL_620 # (cbclient)
619 pascal16 RegisterCBClient(word ptr long) RegisterCBClient
620 register CBClientThunkSL() CBClientThunkSL
621 stub KERNEL_621 # (cbclient)
622 stub UnRegisterCBClient
622 pascal16 UnRegisterCBClient(word ptr long) UnRegisterCBClient
623 pascal16 InitCBClient(long) InitCBClient
624 pascal SetFastQueue(long long) SetFastQueue
625 pascal GetFastQueue() GetFastQueue

View File

@ -29,9 +29,11 @@ BOOL32 RELAY_Init(void)
extern void CALLTO16_Start(), CALLTO16_End();
extern void CALLTO16_Ret_word(), CALLTO16_Ret_long();
extern void CALLTO16_Ret_eax();
extern void CALL32_CBClient_Ret();
extern DWORD CALLTO16_RetAddr_word;
extern DWORD CALLTO16_RetAddr_long;
extern DWORD CALLTO16_RetAddr_eax;
extern DWORD CALL32_CBClient_RetAddr;
codesel = GLOBAL_CreateBlock( GMEM_FIXED, (void *)CALLTO16_Start,
(int)CALLTO16_End - (int)CALLTO16_Start,
@ -46,6 +48,8 @@ BOOL32 RELAY_Init(void)
codesel );
CALLTO16_RetAddr_eax =MAKELONG( (int)CALLTO16_Ret_eax -(int)CALLTO16_Start,
codesel );
CALL32_CBClient_RetAddr =
MAKELONG( (int)CALL32_CBClient_Ret -(int)CALLTO16_Start, codesel );
/* Create built-in modules */
if (!BUILTIN_Init()) return FALSE;

View File

@ -134,6 +134,8 @@ static BOOL32 WINAPI THUNK_WOWCallback16Ex( FARPROC16,DWORD,DWORD,
/* TASK_Reschedule() 16-bit entry point */
static FARPROC16 TASK_RescheduleProc;
static BOOL32 THUNK_ThunkletInit( void );
extern void CallFrom16_p_long_wwwll(void);
/* Callbacks function table for the emulator */
@ -177,10 +179,10 @@ BOOL32 THUNK_Init(void)
Callbacks = &CALLBACK_EmulatorTable;
/* Get the 16-bit reschedule function pointer */
TASK_RescheduleProc = MODULE_GetWndProcEntry16( "TASK_Reschedule" );
return TRUE;
/* Initialize Thunklets */
return THUNK_ThunkletInit();
}
/***********************************************************************
* THUNK_Alloc
*/
@ -935,3 +937,399 @@ WOW16Call(WORD x,WORD y,WORD z) {
DPRINTF(") calling address was 0x%08lx\n",calladdr);
return 0;
}
/***********************************************************************
* 16<->32 Thunklet/Callback API:
*/
#pragma pack(1)
typedef struct _THUNKLET
{
BYTE prefix_target;
BYTE pushl_target;
DWORD target;
BYTE prefix_relay;
BYTE pushl_relay;
DWORD relay;
BYTE jmp_glue;
DWORD glue;
BYTE type;
HINSTANCE16 owner;
struct _THUNKLET *next;
} THUNKLET;
#pragma pack(4)
#define THUNKLET_TYPE_LS 1
#define THUNKLET_TYPE_SL 2
static HANDLE32 ThunkletHeap = 0;
static THUNKLET *ThunkletAnchor = NULL;
static FARPROC32 ThunkletSysthunkGlueLS = 0;
static SEGPTR ThunkletSysthunkGlueSL = 0;
static FARPROC32 ThunkletCallbackGlueLS = 0;
static SEGPTR ThunkletCallbackGlueSL = 0;
/***********************************************************************
* THUNK_ThunkletInit
*/
static BOOL32 THUNK_ThunkletInit( void )
{
LPBYTE thunk;
ThunkletHeap = HeapCreate(HEAP_WINE_SEGPTR | HEAP_WINE_CODE16SEG, 0, 0);
if (!ThunkletHeap) return FALSE;
thunk = HeapAlloc( ThunkletHeap, 0, 5 );
if (!thunk) return FALSE;
ThunkletSysthunkGlueLS = (FARPROC32)thunk;
*thunk++ = 0x58; /* popl eax */
*thunk++ = 0xC3; /* ret */
ThunkletSysthunkGlueSL = HEAP_GetSegptr( ThunkletHeap, 0, thunk );
*thunk++ = 0x66; *thunk++ = 0x58; /* popl eax */
*thunk++ = 0xCB; /* lret */
return TRUE;
}
/***********************************************************************
* SetThunkletCallbackGlue (KERNEL.560)
*/
void WINAPI SetThunkletCallbackGlue( FARPROC32 glueLS, SEGPTR glueSL )
{
ThunkletCallbackGlueLS = glueLS;
ThunkletCallbackGlueSL = glueSL;
}
/***********************************************************************
* THUNK_FindThunklet
*/
THUNKLET *THUNK_FindThunklet( DWORD target, DWORD relay,
DWORD glue, BYTE type )
{
THUNKLET *thunk;
for (thunk = ThunkletAnchor; thunk; thunk = thunk->next)
if ( thunk->type == type
&& thunk->target == target
&& thunk->relay == relay
&& thunk->glue == glue )
return thunk;
return NULL;
}
/***********************************************************************
* THUNK_AllocLSThunklet
*/
FARPROC32 THUNK_AllocLSThunklet( SEGPTR target, DWORD relay,
FARPROC32 glue, HTASK16 owner )
{
THUNKLET *thunk = THUNK_FindThunklet( (DWORD)target, relay, (DWORD)glue,
THUNKLET_TYPE_LS );
if (!thunk)
{
TDB *pTask = (TDB*)GlobalLock16( owner );
if ( !(thunk = HeapAlloc( ThunkletHeap, 0, sizeof(THUNKLET) )) )
return 0;
thunk->prefix_target = thunk->prefix_relay = 0x90;
thunk->pushl_target = thunk->pushl_relay = 0x68;
thunk->jmp_glue = 0xE9;
thunk->target = (DWORD)target;
thunk->relay = (DWORD)relay;
thunk->glue = (DWORD)glue - (DWORD)&thunk->owner;
thunk->type = THUNKLET_TYPE_LS;
thunk->owner = pTask? pTask->hInstance : 0;
thunk->next = ThunkletAnchor;
ThunkletAnchor = thunk;
}
return (FARPROC32)thunk;
}
/***********************************************************************
* THUNK_AllocSLThunklet
*/
SEGPTR THUNK_AllocSLThunklet( FARPROC32 target, DWORD relay,
SEGPTR glue, HTASK16 owner )
{
THUNKLET *thunk = THUNK_FindThunklet( (DWORD)target, relay, (DWORD)glue,
THUNKLET_TYPE_SL );
if (!thunk)
{
TDB *pTask = (TDB*)GlobalLock16( owner );
if ( !(thunk = HeapAlloc( ThunkletHeap, 0, sizeof(THUNKLET) )) )
return 0;
thunk->prefix_target = thunk->prefix_relay = 0x66;
thunk->pushl_target = thunk->pushl_relay = 0x68;
thunk->jmp_glue = 0xEA;
thunk->target = (DWORD)target;
thunk->relay = (DWORD)relay;
thunk->glue = (DWORD)glue;
thunk->type = THUNKLET_TYPE_SL;
thunk->owner = pTask? pTask->hInstance : 0;
thunk->next = ThunkletAnchor;
ThunkletAnchor = thunk;
}
return HEAP_GetSegptr( ThunkletHeap, 0, thunk );
}
/**********************************************************************
* IsLSThunklet
*/
BOOL16 WINAPI IsLSThunklet( THUNKLET *thunk )
{
return thunk->prefix_target == 0x90 && thunk->pushl_target == 0x68
&& thunk->prefix_relay == 0x90 && thunk->pushl_relay == 0x68
&& thunk->jmp_glue == 0xE9 && thunk->type == THUNKLET_TYPE_LS;
}
/**********************************************************************
* IsSLThunklet (KERNEL.612)
*/
BOOL16 WINAPI IsSLThunklet( THUNKLET *thunk )
{
return thunk->prefix_target == 0x66 && thunk->pushl_target == 0x68
&& thunk->prefix_relay == 0x66 && thunk->pushl_relay == 0x68
&& thunk->jmp_glue == 0xEA && thunk->type == THUNKLET_TYPE_SL;
}
/***********************************************************************
* AllocLSThunkletSysthunk (KERNEL.607)
*/
FARPROC32 WINAPI AllocLSThunkletSysthunk( SEGPTR target,
FARPROC32 relay, DWORD dummy )
{
return THUNK_AllocLSThunklet( (SEGPTR)relay, (DWORD)target,
ThunkletSysthunkGlueLS, GetCurrentTask() );
}
/***********************************************************************
* AllocSLThunkletSysthunk (KERNEL.608)
*/
SEGPTR WINAPI AllocSLThunkletSysthunk( FARPROC32 target,
SEGPTR relay, DWORD dummy )
{
return THUNK_AllocSLThunklet( (FARPROC32)relay, (DWORD)target,
ThunkletSysthunkGlueSL, GetCurrentTask() );
}
/***********************************************************************
* AllocLSThunkletCallbackEx (KERNEL.567)
*/
FARPROC32 WINAPI AllocLSThunkletCallbackEx( SEGPTR target,
DWORD relay, HTASK16 task )
{
THUNKLET *thunk = (THUNKLET *)target;
if ( IsSLThunklet( thunk ) && thunk->relay == relay
&& thunk->glue == (DWORD)ThunkletCallbackGlueSL )
return (FARPROC32)thunk->target;
return THUNK_AllocLSThunklet( target, relay,
ThunkletCallbackGlueLS, task );
}
/***********************************************************************
* AllocSLThunkletCallbackEx (KERNEL.568)
*/
SEGPTR WINAPI AllocSLThunkletCallbackEx( FARPROC32 target,
DWORD relay, HTASK16 task )
{
THUNKLET *thunk = (THUNKLET *)target;
if ( IsLSThunklet( thunk ) && thunk->relay == relay
&& thunk->glue == (DWORD)ThunkletCallbackGlueLS )
return (SEGPTR)thunk->target;
return THUNK_AllocSLThunklet( target, relay,
ThunkletCallbackGlueSL, task );
}
/***********************************************************************
* AllocLSThunkletCallback (KERNEL.561) (KERNEL.606)
*/
FARPROC32 WINAPI AllocLSThunkletCallback( SEGPTR target, DWORD relay )
{
return AllocLSThunkletCallbackEx( target, relay, GetCurrentTask() );
}
/***********************************************************************
* AllocSLThunkletCallback (KERNEL.562) (KERNEL.605)
*/
SEGPTR WINAPI AllocSLThunkletCallback( FARPROC32 target, DWORD relay )
{
return AllocSLThunkletCallbackEx( target, relay, GetCurrentTask() );
}
/***********************************************************************
* FindLSThunkletCallback (KERNEL.563) (KERNEL.609)
*/
FARPROC32 WINAPI FindLSThunkletCallback( SEGPTR target, DWORD relay )
{
THUNKLET *thunk = (THUNKLET *)PTR_SEG_TO_LIN( target );
if ( thunk && IsSLThunklet( thunk ) && thunk->relay == relay
&& thunk->glue == (DWORD)ThunkletCallbackGlueSL )
return (FARPROC32)thunk->target;
thunk = THUNK_FindThunklet( (DWORD)target, relay,
(DWORD)ThunkletCallbackGlueLS,
THUNKLET_TYPE_LS );
return (FARPROC32)thunk;
}
/***********************************************************************
* FindSLThunkletCallback (KERNEL.564) (KERNEL.610)
*/
SEGPTR WINAPI FindSLThunkletCallback( FARPROC32 target, DWORD relay )
{
THUNKLET *thunk = (THUNKLET *)target;
if ( thunk && IsLSThunklet( thunk ) && thunk->relay == relay
&& thunk->glue == (DWORD)ThunkletCallbackGlueLS )
return (SEGPTR)thunk->target;
thunk = THUNK_FindThunklet( (DWORD)target, relay,
(DWORD)ThunkletCallbackGlueSL,
THUNKLET_TYPE_SL );
return HEAP_GetSegptr( ThunkletHeap, 0, thunk );
}
/***********************************************************************
* Callback Client API
*/
#define N_CBC_FIXED 20
#define N_CBC_VARIABLE 10
#define N_CBC_TOTAL (N_CBC_FIXED + N_CBC_VARIABLE)
static SEGPTR *CBClientRelay16[ N_CBC_TOTAL ];
static FARPROC32 *CBClientRelay32[ N_CBC_TOTAL ];
/***********************************************************************
* RegisterCBClient (KERNEL.619)
*/
INT16 WINAPI RegisterCBClient( INT16 wCBCId,
SEGPTR *relay16, FARPROC32 *relay32 )
{
/* Search for free Callback ID */
if ( wCBCId == -1 )
for ( wCBCId = N_CBC_FIXED; wCBCId < N_CBC_TOTAL; wCBCId++ )
if ( !CBClientRelay16[ wCBCId ] )
break;
/* Register Callback ID */
if ( wCBCId > 0 && wCBCId < N_CBC_TOTAL )
{
CBClientRelay16[ wCBCId ] = relay16;
CBClientRelay32[ wCBCId ] = relay32;
}
else
wCBCId = 0;
return wCBCId;
}
/***********************************************************************
* UnRegisterCBClient (KERNEL.622)
*/
INT16 WINAPI UnRegisterCBClient( INT16 wCBCId,
SEGPTR *relay16, FARPROC32 *relay32 )
{
if ( wCBCId >= N_CBC_FIXED && wCBCId < N_CBC_TOTAL
&& CBClientRelay16[ wCBCId ] == relay16
&& CBClientRelay32[ wCBCId ] == relay32 )
{
CBClientRelay16[ wCBCId ] = 0;
CBClientRelay32[ wCBCId ] = 0;
}
else
wCBCId = 0;
return wCBCId;
}
/***********************************************************************
* InitCBClient (KERNEL.623)
*/
void WINAPI InitCBClient( FARPROC32 glueLS )
{
HMODULE16 kernel = GetModuleHandle16( "KERNEL" );
SEGPTR glueSL = (SEGPTR)WIN32_GetProcAddress16( kernel, (LPCSTR)604 );
SetThunkletCallbackGlue( glueLS, glueSL );
}
/***********************************************************************
* CBClientGlueSL (KERNEL.604)
*/
void WINAPI CBClientGlueSL( CONTEXT *context )
{
/* Create stack frame */
SEGPTR stackSeg = STACK16_PUSH( THREAD_Current(), 12 );
LPWORD stackLin = PTR_SEG_TO_LIN( stackSeg );
SEGPTR glue;
stackLin[3] = BP_reg( context );
stackLin[2] = SI_reg( context );
stackLin[1] = DI_reg( context );
stackLin[0] = DS_reg( context );
BP_reg( context ) = OFFSETOF( stackSeg ) + 6;
SP_reg( context ) = OFFSETOF( stackSeg ) - 4;
GS_reg( context ) = 0;
/* Jump to 16-bit relay code */
glue = CBClientRelay16[ stackLin[5] ][ stackLin[4] ];
CS_reg ( context ) = SELECTOROF( glue );
EIP_reg( context ) = OFFSETOF ( glue );
}
/***********************************************************************
* CBClientThunkSL (KERNEL.620)
*/
void WINAPI CBClientThunkSL( CONTEXT *context )
{
/* Call 32-bit relay code */
extern DWORD WINAPI CALL32_CBClient( FARPROC32 proc, LPWORD args );
LPWORD args = PTR_SEG_OFF_TO_LIN( SS_reg( context ), BP_reg( context ) );
FARPROC32 proc = CBClientRelay32[ args[2] ][ args[1] ];
EAX_reg(context) = CALL32_CBClient( proc, args );
}
/***********************************************************************
* KERNEL_365 (KERNEL.365)
*
* This is declared as a register function as it has to preserve
* *all* registers, even AX/DX !
*
*/
void WINAPI KERNEL_365( CONTEXT *context )
{
LPWORD args = PTR_SEG_OFF_TO_LIN( SS_reg( context ), SP_reg( context ) );
FIXME( thunk, "(%04X, %d): stub!\n", args[3], (INT16)args[2] );
}

View File

@ -2131,6 +2131,156 @@ static void BuildRet16Func( FILE *outfile )
fprintf( outfile, "\t.text\n" );
}
/*******************************************************************
* BuildCallTo32CBClient
*
* Call a CBClient relay stub from 32-bit code (KERNEL.620).
*
* Since the relay stub is itself 32-bit, this should not be a problem;
* unfortunately, the relay stubs are expected to switch back to a
* 16-bit stack (and 16-bit code) after completion :-(
*
* This would conflict with our 16- vs. 32-bit stack handling, so
* we simply switch *back* to our 32-bit stack before returning to
* the caller ...
*
* The CBClient relay stub expects to be called with:
* - ebp pointing to the 16-bit stack at ss:bp
* - ebx pointing to a buffer containing the saved 16-bit ss:sp
*
* After completion, the stub will load ss:sp from the buffer at ebx
* and perform a far return to 16-bit code.
*
* To trick the relay stub into returning to us, we push a 16-bit
* cs:ip pair pointing to out return entry point onto the 16-bit stack,
* followed by a ss:sp pair pointing to *that* cs:ip pair.
* Our return stub thus called will then reload the 32-bit ss:esp and
* return to 32-bit code (by using and ss:esp value that we have also
* pushed onto the 16-bit stack before and a cs:eip values found at
* that position on the 32-bit stack). The layout of our
* temporary area used on the 16-bit stack is thus as follows:
*
* (ebx+12) 32-bit ss (flat)
* (ebx+8) 32-bit sp (32-bit stack pointer)
* (ebx+6) 16-bit cs (this segment)
* (ebx+4) 16-bit ip ('16-bit' return entry point)
* (ebx+2) 16-bit ss (16-bit stack segment)
* (ebx+0) 16-bit sp (points to ebx+4)
*
* The stack layout of this function:
* (ebp+12) arg ebp value to be set for relay stub
* (ebp+8) func CBClient relay stub address
* (ebp+4) ret addr
* (ebp) ebp
*/
static void BuildCallTo32CBClient( FILE *outfile )
{
/* Function header */
fprintf( outfile, "\n\t.align 4\n" );
#ifdef USE_STABS
fprintf( outfile, ".stabs \"CALL32_CBClient:F1\",36,0,0," PREFIX "CALL32_CBClient\n" );
#endif
fprintf( outfile, "\t.globl " PREFIX "CALL32_CBClient\n" );
fprintf( outfile, PREFIX "CALL32_CBClient:\n" );
/* Entry code */
fprintf( outfile, "\tpushl %%ebp\n" );
fprintf( outfile, "\tmovl %%esp,%%ebp\n" );
fprintf( outfile, "\tpushl %%edi\n" );
fprintf( outfile, "\tpushl %%esi\n" );
fprintf( outfile, "\tpushl %%ebx\n" );
/* Get the 16-bit stack */
fprintf( outfile, "\t.byte 0x64\n\tmovl (%d),%%ebx\n", STACKOFFSET);
/* Convert it to a flat address */
fprintf( outfile, "\tshldl $16,%%ebx,%%eax\n" );
fprintf( outfile, "\tandl $0xfff8,%%eax\n" );
fprintf( outfile, "\tmovl " PREFIX "ldt_copy(%%eax),%%esi\n" );
fprintf( outfile, "\tmovw %%bx,%%ax\n" );
fprintf( outfile, "\taddl %%eax,%%esi\n" );
/* Allocate temporary area (simulate STACK16_PUSH) */
fprintf( outfile, "\tpushf\n" );
fprintf( outfile, "\tcld\n" );
fprintf( outfile, "\tleal -16(%%esi), %%edi\n" );
fprintf( outfile, "\tmovl $%d, %%ecx\n", sizeof(STACK16FRAME) );
fprintf( outfile, "\trep\n\tmovsb\n" );
fprintf( outfile, "\tpopf\n" );
fprintf( outfile, "\t.byte 0x64\n\tsubw $16,(%d)\n", STACKOFFSET );
fprintf( outfile, "\tpushl %%edi\n" ); /* remember address */
/* Set up temporary area */
fprintf( outfile, "\taddl $%d, %%ebx\n", sizeof(STACK16FRAME)-16+4 );
fprintf( outfile, "\tmovl %%ebx, (%%edi)\n" );
fprintf( outfile, "\tmovl " PREFIX "CALL32_CBClient_RetAddr, %%eax\n" );
fprintf( outfile, "\tmovl %%eax, 4(%%edi)\n" );
fprintf( outfile, "\tleal -8(%%esp), %%eax\n" );
fprintf( outfile, "\tmovl %%eax, 8(%%edi)\n" );
fprintf( outfile, "\tmovl %%ss, %%ax\n" );
fprintf( outfile, "\tandl $0x0000ffff, %%eax\n" );
fprintf( outfile, "\tmovl %%eax, 12(%%edi)\n" );
/* Setup registers and call CBClient relay stub (simulating a far call) */
fprintf( outfile, "\tmovl %%edi, %%ebx\n" );
fprintf( outfile, "\tmovl 8(%%ebp), %%eax\n" );
fprintf( outfile, "\tmovl 12(%%ebp), %%ebp\n" );
fprintf( outfile, "\tpushl %%cs\n" );
fprintf( outfile, "\tcall *%%eax\n" );
/* Cleanup temporary area (simulate STACK16_POP) */
fprintf( outfile, "\tpop %%esi\n" );
fprintf( outfile, "\tpushf\n" );
fprintf( outfile, "\tstd\n" );
fprintf( outfile, "\tdec %%esi\n" );
fprintf( outfile, "\tleal 16(%%esi), %%edi\n" );
fprintf( outfile, "\tmovl $%d, %%ecx\n", sizeof(STACK16FRAME) );
fprintf( outfile, "\trep\n\tmovsb\n" );
fprintf( outfile, "\tpopf\n" );
fprintf( outfile, "\t.byte 0x64\n\taddw $16,(%d)\n", STACKOFFSET );
/* Restore registers and return */
fprintf( outfile, "\tpopl %%ebx\n" );
fprintf( outfile, "\tpopl %%esi\n" );
fprintf( outfile, "\tpopl %%edi\n" );
fprintf( outfile, "\tpopl %%ebp\n" );
fprintf( outfile, "\tret\n" );
/* '16-bit' return stub */
fprintf( outfile, "\t.globl " PREFIX "CALL32_CBClient_Ret\n" );
fprintf( outfile, PREFIX "CALL32_CBClient_Ret:\n" );
fprintf( outfile, "\tmovzwl %%sp, %%ebx\n" );
fprintf( outfile, "\tlssl %%ss:(%%ebx), %%esp\n" );
fprintf( outfile, "\tlret\n" );
/* Declare the return address variable */
fprintf( outfile, "\t.data\n" );
fprintf( outfile, "\t.globl " PREFIX "CALL32_CBClient_RetAddr\n" );
fprintf( outfile, PREFIX "CALL32_CBClient_RetAddr:\t.long 0\n" );
fprintf( outfile, "\t.text\n" );
}
/*******************************************************************
* BuildCallTo32LargeStack
@ -2455,6 +2605,14 @@ static int BuildCallTo16( FILE *outfile, char * outname, int argc, char *argv[]
BuildRet16Func( outfile );
/* Output the CBClient callback function
* (while this does not really 'call to 16-bit' code, it is placed
* here so that its 16-bit return stub is defined within the CALLTO16
* 16-bit segment)
*/
BuildCallTo32CBClient( outfile );
fprintf( outfile, "\t.globl " PREFIX "CALLTO16_End\n" );
fprintf( outfile, PREFIX "CALLTO16_End:\n" );