From 5efaf50ed556f2d721580fcae6ba57151a7d1b18 Mon Sep 17 00:00:00 2001 From: Ulrich Weigand Date: Sun, 11 Oct 1998 19:26:00 +0000 Subject: [PATCH] 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. --- if1632/kernel.spec | 51 ++++--- if1632/relay.c | 4 + if1632/thunk.c | 402 ++++++++++++++++++++++++++++++++++++++++++++++++++++- tools/build.c | 158 +++++++++++++++++++++ 4 files changed, 587 insertions(+), 28 deletions(-) diff --git a/if1632/kernel.spec b/if1632/kernel.spec index 241aee5ed5a..f7aa7dd0a76 100644 --- a/if1632/kernel.spec +++ b/if1632/kernel.spec @@ -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 diff --git a/if1632/relay.c b/if1632/relay.c index ee7af275d1d..ab9b3ac4522 100644 --- a/if1632/relay.c +++ b/if1632/relay.c @@ -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; diff --git a/if1632/thunk.c b/if1632/thunk.c index f1f60d090b1..2ac70aabef1 100644 --- a/if1632/thunk.c +++ b/if1632/thunk.c @@ -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] ); +} + diff --git a/tools/build.c b/tools/build.c index f7b38850d21..24edf164774 100644 --- a/tools/build.c +++ b/tools/build.c @@ -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" ); -- 2.11.4.GIT