mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1482 lines
48 KiB
1482 lines
48 KiB
/*
|
|
* Thunk Compiler - Routines for Code Generator (16=>32).
|
|
*
|
|
* This is a OS2/16 on NT specific file
|
|
* Microsoft Confidential
|
|
*
|
|
* Copyright (c) Microsoft Corporation 1991
|
|
*
|
|
* All Rights Reserved
|
|
*
|
|
* 04.11.91 YaronS Took from KevinR (WIN4), and Adopt for OS216/NT
|
|
* (many changes: calling convention, register usage)
|
|
* 8 Sep 92 PatrickQ Added support for PMNT
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include "error.h"
|
|
#include "thunk.h"
|
|
#include "types.h"
|
|
#include "symtab.h"
|
|
#include "codegen.h"
|
|
#include "globals.h"
|
|
#include "..\..\..\inc\os2tile.h"
|
|
|
|
extern FILE *StdDbg;
|
|
|
|
|
|
/*******************************************************************************
|
|
* cod16_EnableMapDirect()
|
|
*
|
|
* This routine
|
|
*
|
|
* Entry:
|
|
*
|
|
* Exit:
|
|
*
|
|
* PCode:
|
|
*
|
|
* History:
|
|
* 21mar91 KevinR wrote it
|
|
*
|
|
******************************************************************************/
|
|
|
|
void cod16_EnableMapDirect( INT iCallTypeFrom, INT iCallTypeTo)
|
|
{
|
|
PFUNCTIONNODE pfnnFrom, pfnnTo;
|
|
|
|
for( pfnnFrom = FunctionTable;
|
|
pfnnFrom;
|
|
pfnnFrom = pfnnFrom->pNextFunctionNode) {
|
|
|
|
pfnnTo = pfnnFrom->pMapsToFunction;
|
|
if( (pfnnFrom->iCallType == iCallTypeFrom) &&
|
|
(pfnnTo->iCallType == iCallTypeTo)) {
|
|
|
|
if( sym_FindFMapping( MapTable, pfnnFrom->pchFunctionName,
|
|
pfnnTo->pchFunctionName)) {
|
|
error( "A mapping %s <=> %s already defined",
|
|
pfnnFrom->pchFunctionName, pfnnTo->pchFunctionName);
|
|
} else {
|
|
sym_AddFMapping( &MapTable, pfnnFrom, pfnnTo);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/*******************************************************************************
|
|
* cod16_Handle16()
|
|
*
|
|
* This routine generates the 32-bit side of a 16=>32 thunk.
|
|
*
|
|
* Entry: pmnFirst is a pointer to the list of mapping nodes.
|
|
*
|
|
* Exit: code was emitted
|
|
*
|
|
* PCode:
|
|
* Traverse Parameter lists of both functions
|
|
* - Determine stack offsets of each parameter
|
|
* - Determine offsets for each structure field
|
|
* - Generate the thunk assembly code
|
|
*
|
|
* History:
|
|
* 20feb91 KevinR wrote it
|
|
*
|
|
******************************************************************************/
|
|
|
|
void cod16_Handle16( PMAPNODE pmnFirst)
|
|
{
|
|
PMAPNODE pmn;
|
|
|
|
/* YaronS - omit this line
|
|
* printf("\tOPTION READONLY\n");
|
|
*/
|
|
/*
|
|
* YaronS simplify - if GEN16 is not defined, then do GEN32
|
|
* printf("IFNDEF GEN16\n");
|
|
* printf("IFNDEF GEN32\n");
|
|
* printf("%sout command line error: specify one of -DGEN16 -DGEN32\n", "%");
|
|
* printf(".err\n");
|
|
* printf("ENDIF\n");
|
|
* printf("ENDIF\n");
|
|
*/
|
|
printf("IFDEF GEN16\n");
|
|
printf("IFDEF GEN32\n");
|
|
printf("%sout command line error: you can't specify both "
|
|
"-DGEN16 and -DGEN32\n", "%");
|
|
printf(".err\n");
|
|
printf("ENDIF\n\n");
|
|
|
|
printf("\tOPTION SEGMENT:USE16\n");
|
|
printf("\t.model LARGE,PASCAL\n\n");
|
|
|
|
for( pmn = pmnFirst; pmn; pmn = pmn->pNextMapping) {
|
|
printf("externDef %s:far16\n", pmn->pFromNode->pchFunctionName);
|
|
}
|
|
|
|
printf("externDef _EntryFlat@0:far32\n\n");
|
|
printf("\t.code %s\n\n", CODE16_NAME);
|
|
|
|
BIG_DIVIDE;
|
|
printf("; This is the table of 16-bit entry points.\n");
|
|
printf("; It must be at the beginning of its segment.\n");
|
|
printf("; The entries are each 4 bytes apart, and the effect of the\n");
|
|
printf("; call instruction is to push the offset (+4) into the flat\n");
|
|
printf("; thunk table, used after the jump to 32-bit-land.\n\n");
|
|
|
|
for( pmn = pmnFirst; pmn; pmn = pmn->pNextMapping) {
|
|
printf("%s label far16\n", pmn->pFromNode->pchFunctionName);
|
|
printf("\t%s\n", fBPEntry ? "int\t3" : "nop");
|
|
printf("\tcall\tEntryCommon16\n\n");
|
|
}
|
|
printf("\n; These are two global variables exported by doscalls\n\n");
|
|
printf("public DOSHUGEINCR\n");
|
|
printf("DOSHUGEINCR\tequ\t8\n");
|
|
printf("public DOSHUGESHIFT\n");
|
|
printf("DOSHUGESHIFT\tequ\t3\n\n");
|
|
|
|
BIG_DIVIDE;
|
|
printf("; This is the common setup code for 16=>32 thunks. It:\n");
|
|
printf("; 1. retrieves the 32-bit jump table offset from the stack\n");
|
|
printf("; 2. saves registers\n");
|
|
printf("; 3. saves ss:sp\n");
|
|
printf("; 4. jumps to 32-bit code\n");
|
|
printf(";\n");
|
|
printf("; Entry: flat jump table offset (+4) is on top of stack\n");
|
|
printf("; AX contains the DLL init routine ret value for the\n");
|
|
printf("; LDRLIBIRETURN entry, VOID otherwise.\n");
|
|
printf(";\n");
|
|
printf("; Exit: (eax[15-0]) == flat jump table offset (+4)\n");
|
|
printf("; (eax[31-16]) == return value of DLL init routine for LDRLIBIRETURN\n");
|
|
printf("; (ebx) == new esp\n\n");
|
|
|
|
printf("EntryCommon16:\n");
|
|
printf("\tshl\teax,16\t\t; 16 MSB of eax contain the DLL init ret value\n");
|
|
printf("\tpop\tax\t\t; 16 LSB of eax contain the offset in jump table\n\n");
|
|
|
|
printf("\tpush\tds\t\t; save ds\n");
|
|
printf("\tpush\tes\t\t; save es\n");
|
|
printf("\tpush\tdi\n");
|
|
printf("\tpush\tsi\n");
|
|
printf("\tpush\tcx\n");
|
|
printf("\tpush\tbx\n");
|
|
printf("\tpush\tdx\n");
|
|
printf("\tpush\tbp\n\n");
|
|
|
|
printf("\tmov\tbx,sp\t\t; save current ss:sp\n");
|
|
printf("\tpush\tss\n");
|
|
printf("\tpush\tbx\n\n");
|
|
|
|
/* YaronS - we do arithmetic instead of GetSelctorBase
|
|
*
|
|
*/
|
|
printf("; compute flat esp\n");
|
|
printf("; NOTE - we implement FARPTRTOFLAT by arith\n\n");
|
|
printf("\tmov\tbx,ss\n");
|
|
printf("\tshr\tbx,3\n");
|
|
printf("\tadd\tbx,%xH\n", (unsigned short)(BASE_TILE >> 16));
|
|
printf("\tshl\tebx,16\n");
|
|
printf("\tmov\tbx,sp\t\t; (ebx) == FLAT esp\n\n");
|
|
|
|
/*
|
|
* YaronS - Hardwire the jump address to the
|
|
* the NT OS2DLL.DLL place
|
|
*/
|
|
printf(";force a long, far jump into 32 bit thunks, where EntryFlat resides\n");
|
|
printf(";jmp\t1b:063023D80h\n\n");
|
|
printf("\tdb\t066h, 0eah, 0ddh, 01fh, 090h, 090h, 01bh, 00h\n\n");
|
|
|
|
}
|
|
|
|
/*******************************************************************************
|
|
* cod16_Prolog32()
|
|
*
|
|
* This routine generates the 32-bit prolog for 16=>32 thunks.
|
|
*
|
|
* Entry: pmnFirst is a pointer to the list of mapping nodes.
|
|
*
|
|
* Exit: code was emitted
|
|
*
|
|
* PCode:
|
|
*
|
|
* History:
|
|
* 21feb91 KevinR wrote it
|
|
* 11Apr91 YaronS Adapt to OS2/NT. we assemble it with a
|
|
* different assembler, different code seg etc.
|
|
*
|
|
******************************************************************************/
|
|
|
|
void cod16_Prolog32( PMAPNODE pmnFirst)
|
|
{
|
|
PMAPNODE pmn;
|
|
PSZ psz;
|
|
INT i;
|
|
USHORT icStackFrame;
|
|
|
|
|
|
printf("ELSE\t; GEN32\n");
|
|
|
|
/* YaronS - for 32 bit we don't use externDef (NT asm doesn't understand) */
|
|
|
|
for( pmn = pmnFirst; pmn; pmn = pmn->pNextMapping) {
|
|
icStackFrame = cod_CountParameterBytes(pmn->pToNode->ParamList,
|
|
DWORD_SIZE);
|
|
printf("extrn %s@%u:PROC\n", pmn->pToNode->pchFunctionName,
|
|
icStackFrame);
|
|
}
|
|
|
|
printf("extrn _GetSaved32Esp@0:PROC\n");
|
|
printf("extrn _Save16Esp@0:PROC\n");
|
|
// printf("IF DBG\n");
|
|
printf("extrn _Od216ApiPrint@4:PROC\n");
|
|
// printf("ENDIF DBG\n");
|
|
|
|
printf("\n_TEXT\tSEGMENT DWORD USE32 PUBLIC 'CODE'\n");
|
|
printf("\tASSUME CS:FLAT, DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING\n");
|
|
|
|
BIG_DIVIDE;
|
|
printf("; This is the common flat entry point for 16=>32 thunks. It:\n");
|
|
printf("; 1. makes ds, es, ss FLAT\n");
|
|
printf("; 2. saves esp in ebx\n");
|
|
printf("; 3. dword-aligns the stack\n");
|
|
printf("; 4. jumps to the API-specific thunk code indicated in ax\n");
|
|
printf(";\n");
|
|
printf("; Entry: (ax) == flat jump table offset (+4)\n");
|
|
printf("; (ebx) == flat esp\n\n");
|
|
|
|
printf("\tpublic\t_EntryFlat@0\n");
|
|
printf("\textrn\t_Od2Saved16Stack:DWORD\n");
|
|
printf("\textrn\t_MoveInfoSegintoTeb:PROC\n");
|
|
printf("\textrn\t_RestoreTeb:PROC\n\n");
|
|
|
|
printf("_EntryFlat@0\tproc\n\n");
|
|
|
|
printf("\tmov\tdx,023H\n");
|
|
printf("\tmov\tds,dx\t\t\t; FLAT ds\n");
|
|
printf("\tmov\tes,dx\t\t\t; FLAT es\n\n");
|
|
printf("\tpush\teax\n");
|
|
printf("\tcall\t_RestoreTeb\n\n");
|
|
|
|
printf("\t; 16bit stack must be saved to allow proper signal handler execution\n");
|
|
printf("\tcall\t_Save16Esp@0\n");
|
|
printf("\tor\tal,al\n");
|
|
printf("\tjz\tEntryFlat1\n");
|
|
printf("\tmov\t_Od2Saved16Stack,ebx\t; Save 16-bit stack\n\n");
|
|
|
|
printf("EntryFlat1:\n");
|
|
printf("\tcall\t_GetSaved32Esp@0\n");
|
|
printf("\tpop\tecx\t\t\t; restore the thunk index/LDRLIBIRETURN ret value\n\n");
|
|
|
|
printf("\tand\teax,0fffffffcH\t\t; dword-align the 32bit stack pointer\n");
|
|
printf("\tmov\tdx,23H\n");
|
|
printf("\tpush\tdx\t\t\t; flat SS\n");
|
|
printf("\tpush\teax\t\t\t; flat ESP\n");
|
|
printf("\tlss\tesp,[ebx-6]\t\t; switch to 32bit stack\n\n");
|
|
|
|
if( fUser) {
|
|
printf("\tsub\tesp,4\t\t\t; make room for old SS16\n");
|
|
printf("\tpush\teax\n");
|
|
printf("\tcall\tQuerySS16\n");
|
|
printf("\tmov\t[ebx-4],eax\t\t; old SS16\n");
|
|
printf("\tpush\t[ebx+2]\t\t\t; 16-bit SS\n");
|
|
printf("\tcall\tSetSS16\n");
|
|
printf("\tpop\teax\n\n");
|
|
}
|
|
|
|
// printf("IF DBG\n");
|
|
printf("\tpush\tecx\n");
|
|
printf("\tand\tecx,0ffffH\t\t; clear hi word\n");
|
|
printf("\tpush\tecx\n\n");
|
|
|
|
printf("\tcall\t_Od216ApiPrint@4\n");
|
|
printf("\tpop\tecx\n\n");
|
|
// printf("ENDIF DBG\n");
|
|
|
|
printf("\tmov\teax,ecx\n");
|
|
printf("\tshr\teax,16\t\t\t; (eax) contains the LDRLIBIRETURN ret value\n");
|
|
printf("\tand\tecx,0ffffH\n");
|
|
printf("\tmov\tebp,esp\t\t\t; Compiler assumes this for ebp elimination\n");
|
|
printf("\tjmp\tdword ptr FlatTable[ecx-4]\t; select specific thunk\n");
|
|
printf("_EntryFlat@0\tendp\n\n");
|
|
|
|
BIG_DIVIDE;
|
|
printf("; Common routines to restore the stack and registers\n");
|
|
printf("; and return to 16-bit code. There is one for each\n");
|
|
printf("; size of 16-bit parameter list in this script.\n\n");
|
|
|
|
printf("\tpublic _ExitFlatAreaBegin@0\n");
|
|
printf("_ExitFlatAreaBegin@0:\n\n");
|
|
|
|
for( i=0; i < sizeof( afFromNodeBytesUsed); i++)
|
|
afFromNodeBytesUsed[ i] = FALSE;
|
|
|
|
for( pmn = pmnFirst; pmn; pmn = pmn->pNextMapping) {
|
|
cod_CalcStructOffsets( pmn->pFromNode->ParamList, WORD_SIZE);
|
|
cod_CalcStructOffsets( pmn->pToNode->ParamList, iPackingSize);
|
|
cod_CalcOffset( pmn->pFromNode->ParamList, 24, WORD_SIZE, PUSH_LEFT);
|
|
|
|
afFromNodeBytesUsed[ cod_CountParameterBytes( pmn->pFromNode->ParamList,
|
|
WORD_SIZE)
|
|
/ WORD_SIZE] = TRUE;
|
|
}
|
|
|
|
for( i=0; i < sizeof( afFromNodeBytesUsed); i++) {
|
|
if( afFromNodeBytesUsed[ i]) {
|
|
printf("ExitFlat_%u:\n", i * WORD_SIZE);
|
|
printf("\tcall\t_MoveInfoSegintoTeb\n\n");
|
|
printf("\tmov\tcx,word ptr [ebx+16]\t; ES\n");
|
|
printf("\tshl\tecx,16\n");
|
|
printf("\tmov\tdx,word ptr [ebx+18]\t; DS\n");
|
|
printf("\tshl\tedx,16\n");
|
|
cod16_GenRet16( i * WORD_SIZE, TRUE, TRUE);
|
|
}
|
|
}
|
|
|
|
printf("\tpublic _ExitFlatAreaEnd@0\n");
|
|
printf("_ExitFlatAreaEnd@0:\n\n");
|
|
|
|
BIG_DIVIDE;
|
|
printf("; This is a jump table to API-specific flat thunk code.\n");
|
|
printf("; Each entry is a dword.\n\n");
|
|
printf("FlatTable label near\n");
|
|
|
|
for( pmn = pmnFirst; pmn; pmn = pmn->pNextMapping)
|
|
printf("\tdd\toffset _TEXT:T_%s\n", pmn->pToNode->pchFunctionName);
|
|
printf("\n");
|
|
|
|
/*
|
|
* YaronS - the following is a macro that replaces SelToFlat,
|
|
* since we can do tiling
|
|
*/
|
|
printf(";---- SelToFlat Macro ----\n");
|
|
printf(";\t On Entry:\t eax==Sel:Off\n");
|
|
printf(";\t On Exit:\t eax==Flat Offset\n");
|
|
printf("SelToFlat macro\n");
|
|
printf("\tpush\tecx\n");
|
|
printf("xor\tecx,ecx\n");
|
|
printf("mov\tcx,ax\t; ecx<-offset in segment\n");
|
|
printf("shr\teax,3\t\n");
|
|
printf("xor\tax,ax\t; eax now contains segment base\n");
|
|
printf("\tadd\teax,ecx\t; eax <- flat offset\n");
|
|
printf("\tadd\teax,%lxH\n", BASE_TILE);
|
|
printf("\tpop\tecx\n");
|
|
printf("endm\n\n");
|
|
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* cod16_Epilog32()
|
|
*
|
|
* This routine generates the 32-bit epilog for 16=>32 thunks.
|
|
*
|
|
* Entry: pmnFirst is a pointer to the list of mapping nodes.
|
|
*
|
|
* Exit: code was emitted
|
|
*
|
|
* PCode:
|
|
*
|
|
* History:
|
|
* 21feb91 KevinR wrote it
|
|
*
|
|
******************************************************************************/
|
|
|
|
void cod16_Epilog32( PMAPNODE pmnFirst)
|
|
{
|
|
printf("_TEXT ends\n");
|
|
printf("ENDIF\n");
|
|
printf("\tend\n");
|
|
}
|
|
|
|
/*******************************************************************************
|
|
* cod16_Handle32()
|
|
*
|
|
* This routine generates the 32-bit side of a 16=>32 thunk.
|
|
*
|
|
* Entry: pmn is a pointer to a MapNode.
|
|
*
|
|
* Exit: code was emitted
|
|
*
|
|
* PCode:
|
|
* Traverse Parameter lists of both functions
|
|
* - Determine stack offsets of each parameter
|
|
* - Determine offsets for each structure field
|
|
* - Generate the thunk assembly code
|
|
*
|
|
* History:
|
|
* 20feb91 KevinR wrote it
|
|
*
|
|
******************************************************************************/
|
|
|
|
void cod16_Handle32( PMAPNODE pmn)
|
|
{
|
|
iStackCurrent = 0;
|
|
|
|
cod16_Entry( pmn);
|
|
cod16_TempStorage( pmn);
|
|
cod16_PackParams( pmn);
|
|
cod16_CallFrame( pmn);
|
|
cod16_Return( pmn);
|
|
cod16_UnpackParams( pmn);
|
|
cod16_Exit( pmn, TRUE, TRUE);
|
|
}
|
|
|
|
/*******************************************************************************
|
|
* cod16_Entry()
|
|
*
|
|
* This routine will generate the entry code for one thunk.
|
|
*
|
|
* Entry: pmn is a pointer to a MapNode.
|
|
*
|
|
* Exit: Entry code will have been written to the output file.
|
|
*
|
|
* PCode: gen label
|
|
*
|
|
* History:
|
|
* 21feb91 KevinR wrote it
|
|
*
|
|
******************************************************************************/
|
|
|
|
void cod16_Entry( PMAPNODE pmn)
|
|
{
|
|
PTYPENODE ptn;
|
|
|
|
BIG_DIVIDE;
|
|
|
|
printf("T_%s label near\n\n", pmn->pToNode->pchFunctionName);
|
|
for( ptn = pmn->pFromNode->ParamList; ptn; ptn = ptn->pNextNode)
|
|
if( !ptn->iDeleted)
|
|
printf("; ebx+%-3u %s\n",
|
|
ptn->iOffset, typ_NonNull( ptn->pchIdent));
|
|
printf("\n");
|
|
}
|
|
|
|
/*******************************************************************************
|
|
* cod16_TempStorage()
|
|
*
|
|
* This routine will generate temporary storage code.
|
|
*
|
|
* Entry: pmn is a pointer to a MapNode.
|
|
*
|
|
* Exit: Temporary storage code will have been written to the output file.
|
|
*
|
|
* PCode:
|
|
*
|
|
* History:
|
|
* 21feb91 KevinR wrote it
|
|
*
|
|
******************************************************************************/
|
|
|
|
void cod16_TempStorage( PMAPNODE pmn)
|
|
{
|
|
INT i=1;
|
|
PTYPENODE ptn, ptnFirst;
|
|
|
|
if( ptnFirst = typ_FindFirstPointer( pmn->pFromNode->ParamList, TRUE)) {
|
|
|
|
SML_DIVIDE;
|
|
printf("; temp storage\n\n");
|
|
|
|
printf("\txor\teax,eax\n");
|
|
|
|
for( ptn=ptnFirst, i=1; ptn; ptn=typ_FindNextPointer( ptn, TRUE), i++) {
|
|
printf("\tpush\teax\t\t\t; ptr param #%u %s\n", i,
|
|
typ_NonNull( ptn->pchIdent));
|
|
ptn->iTempOffset = (iStackCurrent += DWORD_SIZE);
|
|
}
|
|
}
|
|
|
|
pmn->pToNode->iPointerCount = pmn->pFromNode->iPointerCount = i-1;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
* cod16_PackParams()
|
|
*
|
|
* This routine will generate parameter packing code.
|
|
*
|
|
* Entry: pmn is a pointer to a MapNode.
|
|
*
|
|
* Exit: Parameter packing code will have been written to the output file.
|
|
*
|
|
* PCode:
|
|
*
|
|
* History:
|
|
* 21feb91 KevinR wrote it
|
|
*
|
|
******************************************************************************/
|
|
|
|
void cod16_PackParams( PMAPNODE pmn)
|
|
{
|
|
PTYPENODE ptnFrom, ptnTo;
|
|
INT iBufferSize;
|
|
BOOL fDirectionFlagClear=FALSE;
|
|
|
|
if( ptnFrom = typ_FindFirstPointer( pmn->pFromNode->ParamList, FALSE)) {
|
|
SML_DIVIDE;
|
|
printf("; *** BEGIN parameter packing\n\n");
|
|
|
|
for( ptnTo = typ_FindFirstPointer( pmn->pToNode->ParamList, FALSE);
|
|
ptnFrom;
|
|
ptnFrom = typ_FindNextPointer( ptnFrom, FALSE),
|
|
ptnTo = typ_FindNextPointer( ptnTo, FALSE)) {
|
|
|
|
if( ptnFrom->fSemantics & SEMANTIC_SPECIAL) {
|
|
if( cod16_PackParamSpecial( pmn, ptnFrom, ptnTo))
|
|
continue;
|
|
}
|
|
|
|
if( (ptnTo->fSemantics & SEMANTIC_MAPTORETVAL) ||
|
|
(!typ_TypeIdentical( ptnFrom, ptnTo) &&
|
|
(ptnFrom->iBaseType == TYPE_STRUCT)
|
|
)) {
|
|
|
|
/*
|
|
* We only need to cld when we see the first structure
|
|
* needing repacking.
|
|
*/
|
|
if( (ptnFrom->fSemantics & SEMANTIC_INPUT) &&
|
|
!fDirectionFlagClear &&
|
|
!(ptnTo->fSemantics & SEMANTIC_MAPTORETVAL)) {
|
|
fDirectionFlagClear = TRUE;
|
|
printf("\tcld\t\t\t\t; esi, edi will increment\n\n");
|
|
}
|
|
|
|
iBufferSize = ROUND_UP_MOD( ptnTo->iBaseDataSize, DWORD_SIZE);
|
|
printf("\tsub\tesp,%u\t\t\t; %s alloc space on stack\n\n",
|
|
iBufferSize, typ_NonNull( ptnTo->pchIdent));
|
|
iStackCurrent += iBufferSize;
|
|
}
|
|
if( ptnTo->fSemantics & SEMANTIC_MAPTORETVAL) {
|
|
ptnTo->iTempOffset = iStackCurrent;
|
|
} else {
|
|
cod16_PackPointer( ptnFrom, ptnTo);
|
|
}
|
|
}
|
|
|
|
printf("; *** END parameter packing\n");
|
|
}
|
|
}
|
|
|
|
/*******************************************************************************
|
|
* cod16_PackPointer()
|
|
*
|
|
* This routine will generate pointer-handling code.
|
|
*
|
|
* Entry: ptnFrom - parameter input to thunk
|
|
* ptnTo - parameter output from thunk
|
|
*
|
|
* Exit: pointer-handling code was emitted
|
|
*
|
|
* PCode:
|
|
*
|
|
* History:
|
|
* 22feb91 KevinR wrote it
|
|
*
|
|
******************************************************************************/
|
|
|
|
void cod16_PackPointer( PTYPENODE ptnFrom, PTYPENODE ptnTo)
|
|
{
|
|
UINT uiNullLabel, uiStoreLabel;
|
|
BOOL fSameType, fEmbeddedPtr, fAddressSaved=FALSE;
|
|
CHAR *pch;
|
|
INT iSemanticMask;
|
|
|
|
fSameType = typ_TypeIdentical( ptnFrom, ptnTo);
|
|
fEmbeddedPtr = cod_CountPointerParameters( ptnFrom->pStructElems, FALSE);
|
|
|
|
if( strcmp( (pch = typ_NonNull( ptnFrom->pchIdent)), ""))
|
|
printf("; %s\n", pch);
|
|
printf("; pointer %s --> %s\n",
|
|
typ_NonNull( ptnFrom->pchBaseTypeName),
|
|
typ_NonNull( ptnTo->pchBaseTypeName));
|
|
printf("\tmov\teax,[ebx+%u]\t\t; base address\n", ptnFrom->iOffset);
|
|
printf("\tor\teax,eax\n");
|
|
printf("\tjz\tL%u\t\t\t; skip if null\n\n",
|
|
uiNullLabel = uiGenLabel++);
|
|
|
|
iSemanticMask = SEMANTIC_PASSIFHINULL | SEMANTIC_INPUT;
|
|
if( (ptnFrom->fSemantics & iSemanticMask) == iSemanticMask) {
|
|
printf("; special case of polymorphic parameter\n");
|
|
printf("; do no conversion if the high word is null\n");
|
|
printf("\trol\teax,16\n");
|
|
printf("\tor\tax,ax\n");
|
|
printf("\trol\teax,16\t\t\t; return eax to original state\n");
|
|
printf("\tjz\tL%u\t\t\t; no change if hi word null\n\n",
|
|
uiStoreLabel = uiGenLabel++);
|
|
}
|
|
|
|
if( ptnFrom->iBaseType == TYPE_STRUCT) {
|
|
printf("\n; structures are%s identical\n",
|
|
fSameType ? "" : " not");
|
|
printf("; structures %shave pointers\n\n",
|
|
fEmbeddedPtr ? "" : "don't ");
|
|
|
|
if( ptnFrom->iArraySize > 1) {
|
|
cod_NotHandled( "structure array");
|
|
} else if( fSameType) {
|
|
cod16_SelToFlat();
|
|
} else {
|
|
printf("\tmov\t[esp+%u],esp\t\t; save pointer to buffer\n\n",
|
|
iStackCurrent - ptnFrom->iTempOffset);
|
|
fAddressSaved = TRUE;
|
|
if( ptnFrom->fSemantics & SEMANTIC_INPUT) {
|
|
cod16_StructureRepack( ptnFrom, ptnTo);
|
|
}
|
|
}
|
|
} else if( fSameType) {
|
|
if( ptnFrom->iArraySize == 1) {
|
|
if( ptnFrom->iBaseType == TYPE_NULLTYPE) {
|
|
printf( "\t.err *** NULLTYPE ***\n");
|
|
} else {
|
|
cod16_SelToFlat();
|
|
}
|
|
} else {
|
|
if( ptnFrom->iBaseType == TYPE_CHAR) {
|
|
cod16_SelToFlat();
|
|
} else {
|
|
cod_NotHandled( "non-char buffer");
|
|
}
|
|
}
|
|
} else {
|
|
cod_NotHandled( "pointer to different non-structs");
|
|
}
|
|
|
|
if( ptnFrom->fSemantics & SEMANTIC_PASSIFHINULL)
|
|
printf("L%u:\n", uiStoreLabel);
|
|
|
|
if( !fAddressSaved)
|
|
printf("\tmov\t[esp+%u],eax\n", iStackCurrent - ptnFrom->iTempOffset);
|
|
|
|
printf("L%u:\n\n", uiNullLabel);
|
|
}
|
|
|
|
/*******************************************************************************
|
|
* cod16_SelToFlat()
|
|
*
|
|
* This routine will generate code to convert a 16:16 address to a 0:32 address
|
|
*
|
|
* Entry: in emitted code, (eax) == 16:16 address
|
|
*
|
|
* Exit: in emitted code, (eax) == 0:32 address
|
|
*
|
|
* PCode:
|
|
*
|
|
* History:
|
|
* 26feb91 KevinR wrote it
|
|
*
|
|
******************************************************************************/
|
|
|
|
void cod16_SelToFlat( void)
|
|
{
|
|
/* YaronS */
|
|
/*
|
|
printf("\tcall\tSelToFlat\n");
|
|
*/
|
|
printf("\tSelToFlat\n");
|
|
}
|
|
|
|
/*******************************************************************************
|
|
* cod16_StructureRepack()
|
|
*
|
|
* This routine will generate structure repacking code.
|
|
*
|
|
* Entry: ptnFrom - parameter input to thunk
|
|
* ptnTo - parameter output from thunk
|
|
*
|
|
* Exit: structure repacking code was emitted
|
|
*
|
|
* PCode:
|
|
*
|
|
* History:
|
|
* 22feb91 KevinR wrote it
|
|
*
|
|
******************************************************************************/
|
|
|
|
void cod16_StructureRepack( PTYPENODE ptnFrom, PTYPENODE ptnTo)
|
|
{
|
|
cod16_SelToFlat();
|
|
printf("\tmov\tesi,eax\t\t\t; source flat address\n");
|
|
printf("\tmov\tedi,esp\t\t\t; destination flat address\n\n");
|
|
|
|
cod16_RepackElems( ptnFrom->pStructElems, ptnTo->pStructElems);
|
|
}
|
|
|
|
/*******************************************************************************
|
|
* cod16_RepackElems()
|
|
*
|
|
* This routine will generate repacking code for the elems of a structure.
|
|
*
|
|
* Entry: ptnFrom - first elem of from struct
|
|
* ptnTo - first elem of to struct
|
|
*
|
|
* Exit: structure repacking code was emitted
|
|
*
|
|
* PCode:
|
|
*
|
|
* History:
|
|
* 07mar91 KevinR wrote it
|
|
*
|
|
******************************************************************************/
|
|
|
|
void cod16_RepackElems( PTYPENODE ptnFrom, PTYPENODE ptnTo)
|
|
{
|
|
UINT uiStoreLabel;
|
|
PTYPENODE ptnElemFrom, ptnElemTo;
|
|
ULONG fl;
|
|
|
|
for( ptnElemFrom = ptnFrom, ptnElemTo = ptnTo;
|
|
ptnElemFrom;
|
|
ptnElemFrom = ptnElemFrom->pNextNode,
|
|
ptnElemTo = ptnElemTo->pNextNode) {
|
|
|
|
printf("; %s\n", typ_NonNull( ptnElemFrom->pchIdent));
|
|
|
|
if( ptnElemFrom->iPointerType) {
|
|
|
|
printf("; pointer %s --> %s\n", ptnElemFrom->pchBaseTypeName,
|
|
ptnElemTo->pchBaseTypeName);
|
|
|
|
if( ptnElemFrom->iPointerType == ptnElemTo->iPointerType) {
|
|
printf("\tmovsd\t\t\t\t; no conversion\n\n");
|
|
|
|
} else if( (ptnElemFrom->iPointerType == TYPE_FAR16) &&
|
|
(ptnElemTo->iPointerType == TYPE_NEAR32)) {
|
|
|
|
printf("\tlodsd\n");
|
|
printf("\tor\teax,eax\n");
|
|
printf("\tjz\tL%u\n", uiStoreLabel = uiGenLabel++);
|
|
|
|
if( ptnElemFrom->fSemantics & SEMANTIC_PASSIFHINULL) {
|
|
printf("; no conversion if high word null\n");
|
|
printf("\trol\teax,16\n");
|
|
printf("\tor\tax,ax\n");
|
|
printf("\trol\teax,16\t\t\t; restore eax\n");
|
|
printf("\tjz\tL%u\n", uiStoreLabel);
|
|
}
|
|
|
|
cod16_SelToFlat();
|
|
printf("L%u:\n", uiStoreLabel);
|
|
printf("\tstosd\n\n");
|
|
|
|
} else {
|
|
cod_NotHandled( "cod16_RepackElems: unequal pointer types,"
|
|
" not 16:16 --> 0:32");
|
|
}
|
|
} else if( ptnElemFrom->iArraySize <= 1) {
|
|
printf("; %s --> %s\n", ptnElemFrom->pchBaseTypeName,
|
|
ptnElemTo->pchBaseTypeName);
|
|
|
|
if( ptnElemFrom->iBaseType == ptnElemTo->iBaseType) {
|
|
switch( ptnElemFrom->iBaseType) {
|
|
case TYPE_STRUCT:
|
|
cod16_RepackElems( ptnElemFrom->pStructElems,
|
|
ptnElemTo->pStructElems);
|
|
break;
|
|
|
|
case TYPE_LONG:
|
|
case TYPE_ULONG:
|
|
printf("\tmovsd\t\t\t\t; no conversion\n\n");
|
|
break;
|
|
|
|
case TYPE_SHORT:
|
|
case TYPE_USHORT:
|
|
/* Check for 2 contiguous WORDs mapping to WORDs */
|
|
if( typ_WordToWord( ptnElemFrom->pNextNode,
|
|
ptnElemTo->pNextNode)) {
|
|
ptnElemFrom = ptnElemFrom->pNextNode;
|
|
ptnElemTo = ptnElemTo->pNextNode;
|
|
printf("; %s --> %s\n",
|
|
ptnElemFrom->pchBaseTypeName,
|
|
ptnElemTo->pchBaseTypeName);
|
|
printf("\tmovsd\t\t\t\t; 2 words at once\n\n");
|
|
} else {
|
|
printf("\tlodsw\n");
|
|
printf("\tstosd\t\t\t\t; ignore hi word\n\n");
|
|
}
|
|
break;
|
|
|
|
case TYPE_CHAR:
|
|
case TYPE_UCHAR:
|
|
/* BUGBUG does not handle multiple contiguous bytes */
|
|
if( typ_ByteToByte( ptnElemFrom->pNextNode,
|
|
ptnElemTo->pNextNode)) {
|
|
cod_NotHandled( "cod16_RepackElems: contiguous BYTES");
|
|
} else if( typ_WordToWord( ptnElemFrom->pNextNode,
|
|
ptnElemTo->pNextNode)) {
|
|
ptnElemFrom = ptnElemFrom->pNextNode;
|
|
ptnElemTo = ptnElemTo->pNextNode;
|
|
printf("; %s --> %s\n",
|
|
ptnElemFrom->pchBaseTypeName,
|
|
ptnElemTo->pchBaseTypeName);
|
|
printf("\tmovsd\t\t\t\t; 1 byte + 1 word at once\n\n");
|
|
} else {
|
|
printf("\tlodsb\n");
|
|
printf("\tstosd\t\t\t\t; ignore hi 3 bytes\n\n");
|
|
}
|
|
break;
|
|
|
|
default:
|
|
cod_NotHandled( "structure repack, not word or dword");
|
|
fatal( "cod16_RepackElems: unexpected base type %s\n",
|
|
ptnElemFrom->pchBaseTypeName);
|
|
break;
|
|
}
|
|
} else {
|
|
switch( ptnElemFrom->iBaseType) {
|
|
case TYPE_SHORT: /* SHORT --> LONG */
|
|
printf("\tlodsw\n");
|
|
printf("\tcwde\n");
|
|
printf("\tstosd\n\n");
|
|
break;
|
|
|
|
case TYPE_USHORT: /* USHORT --> ULONG */
|
|
if( fl = ptnElemFrom->flHandleType) {
|
|
printf("\tlodsw\n");
|
|
printf("\tcall\tGetHandle32\t\t; %s\n",
|
|
typ_GetHandleTypeName( fl));
|
|
printf("\tstosd\n\n");
|
|
} else {
|
|
printf("\txor\teax,eax\n");
|
|
printf("\tlodsw\n");
|
|
printf("\tstosd\n\n");
|
|
}
|
|
break;
|
|
|
|
case TYPE_LONG: /* LONG --> SHORT */
|
|
case TYPE_ULONG: /* ULONG --> USHORT */
|
|
printf("\tlodsd\n");
|
|
printf("\tstosw\n\n");
|
|
break;
|
|
|
|
default:
|
|
cod_NotHandled( "structure repack, not (U)SHORT or (U)LONG");
|
|
fatal( "cod16_RepackElems: unexpected base type %s\n",
|
|
ptnElemFrom->pchBaseTypeName);
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
printf("; %s[%u] --> %s[%u]\n",
|
|
ptnElemFrom->pchBaseTypeName, ptnElemFrom->iArraySize,
|
|
ptnElemTo->pchBaseTypeName, ptnElemTo->iArraySize);
|
|
|
|
if( ptnElemFrom->iArraySize != ptnElemTo->iArraySize) {
|
|
cod_NotHandled( "FromArraySize != ToArraySize");
|
|
break;
|
|
}
|
|
|
|
if( ptnElemFrom->iBaseType == ptnElemTo->iBaseType) {
|
|
switch( ptnElemFrom->iBaseType) {
|
|
case TYPE_CHAR:
|
|
case TYPE_UCHAR:
|
|
cod16_CopyFixedBlock( ptnElemFrom->iArraySize);
|
|
break;
|
|
|
|
default:
|
|
cod_NotHandled( "non-BYTE array in struct");
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*******************************************************************************
|
|
* cod16_CopyFixedBlock()
|
|
*
|
|
* This routine will generate code to copy a fixed-sized block.
|
|
*
|
|
* Entry: uiSize = the number of bytes to copy.
|
|
* esi = source address
|
|
* edi = destination address
|
|
*
|
|
* Exit: Copy code will have been written to the output file.
|
|
*
|
|
* PCode:
|
|
*
|
|
* History:
|
|
* 07mar91 KevinR wrote it
|
|
*
|
|
******************************************************************************/
|
|
|
|
void cod16_CopyFixedBlock( UINT uiSize)
|
|
{
|
|
UINT uiBytesLeft=uiSize;
|
|
|
|
if( uiSize < 3*DWORD_SIZE) {
|
|
for( ; uiBytesLeft >= DWORD_SIZE; uiBytesLeft -= DWORD_SIZE)
|
|
printf("\tmovsd\n");
|
|
} else {
|
|
printf("\tmov\tecx,%u\n", uiSize / DWORD_SIZE);
|
|
printf("\trep\tmovsd\n");
|
|
uiBytesLeft %= DWORD_SIZE;
|
|
}
|
|
|
|
for( ; uiBytesLeft >= WORD_SIZE; uiBytesLeft -= WORD_SIZE)
|
|
printf("\tmovsw\n");
|
|
|
|
for( ; uiBytesLeft >= BYTE_SIZE; uiBytesLeft -= BYTE_SIZE)
|
|
printf("\tmovsb\n");
|
|
|
|
printf("\n");
|
|
}
|
|
|
|
/*******************************************************************************
|
|
* cod16_CallFrameWorker()
|
|
*
|
|
* This worker routine is invented to reverse the parameter order for, to
|
|
* match NT calling convention. It is recursive, and called only from
|
|
* cod16_CallFrame.
|
|
*
|
|
* Entry: ptnFrom ,ptnTo, &fDirectionFlagClear, pmn
|
|
* (see cod16_CallFrame for desciption)
|
|
*
|
|
*
|
|
* Exit: none
|
|
*
|
|
* PCode:
|
|
* if ptnFrom == NULL
|
|
* process parameter (eventually printf "push ...")
|
|
* else
|
|
* call cod16_CallFrameWorker with next couple on the chain.
|
|
*
|
|
* History:
|
|
* 01may91 YaronS wrote it
|
|
*
|
|
******************************************************************************/
|
|
|
|
void cod16_CallFrameWorker(
|
|
PTYPENODE ptnFrom,
|
|
PTYPENODE ptnTo,
|
|
BOOL *pfDirectionFlagClear,
|
|
PMAPNODE pmn
|
|
)
|
|
{
|
|
CHAR *pch;
|
|
ULONG fl;
|
|
INT iBufferSize;
|
|
|
|
|
|
//
|
|
// call recursive only if we are not the last
|
|
//
|
|
|
|
if (ptnFrom->pNextNode){
|
|
cod16_CallFrameWorker (
|
|
ptnFrom->pNextNode,
|
|
ptnTo->pNextNode,
|
|
pfDirectionFlagClear,
|
|
pmn);
|
|
}
|
|
|
|
//
|
|
// Now all links ahead were already processed,
|
|
// Go do the work for this parameter
|
|
//
|
|
|
|
if( ptnFrom->fSemantics & SEMANTIC_SPECIAL) {
|
|
if( cod16_PushParamSpecial( pmn, ptnFrom, ptnTo))
|
|
return;
|
|
}
|
|
|
|
if( ptnFrom->iDeleted) {
|
|
if( strcmp( (pch = typ_NonNull( ptnFrom->pchIdent)), ""))
|
|
printf("; %s\n", pch);
|
|
if( ptnTo->fSemantics & SEMANTIC_MAPTORETVAL) {
|
|
|
|
printf("\tlea\teax,[esp+%u]\n",
|
|
iStackCurrent - ptnTo->iTempOffset);
|
|
printf("\tpush\teax\t\t\t; output %s\n\n",
|
|
ptnTo->pchBaseTypeName);
|
|
iStackCurrent += DWORD_SIZE;
|
|
fPackedPointReturned = TRUE;
|
|
if( ptnTo->fSemantics & SEMANTIC_REVERSERC) {
|
|
iYRCTempOffset = ptnTo->iTempOffset;
|
|
iXRCTempOffset = ptnTo->iTempOffset - DWORD_SIZE;
|
|
} else {
|
|
iYRCTempOffset = ptnTo->iTempOffset - DWORD_SIZE;
|
|
iXRCTempOffset = ptnTo->iTempOffset;
|
|
}
|
|
|
|
} else if( ptnTo->iBaseDataSize == DWORD_SIZE) {
|
|
printf("\tpush\tdword ptr 0%lxh\t; extra parameter\n\n",
|
|
ptnFrom->iFillValue);
|
|
iStackCurrent += DWORD_SIZE;
|
|
} else {
|
|
printf("\tpush\tword ptr 0%xh\t\t; extra parameter\n\n",
|
|
ptnFrom->iFillValue);
|
|
iStackCurrent += WORD_SIZE;
|
|
}
|
|
return;
|
|
}
|
|
|
|
if( ptnTo->iDeleted)
|
|
return;
|
|
if( strcmp( (pch = typ_NonNull( ptnFrom->pchIdent)), ""))
|
|
printf("; %s from: %s\n",
|
|
pch, typ_NonNull( ptnFrom->pchBaseTypeName));
|
|
else
|
|
printf("; from: %s\n", typ_NonNull( ptnFrom->pchBaseTypeName));
|
|
|
|
switch( ptnFrom->iPointerType) {
|
|
case TYPE_NEAR32:
|
|
case TYPE_FAR16:
|
|
|
|
printf("\tpush\tdword ptr [esp+%u]\t; to: %s\n\n",
|
|
iStackCurrent - ptnFrom->iTempOffset,
|
|
typ_NonNull( ptnTo->pchBaseTypeName));
|
|
iStackCurrent += DWORD_SIZE;
|
|
break;
|
|
|
|
case 0:
|
|
if( ptnFrom->iBaseType == TYPE_STRUCT) {
|
|
/*
|
|
* The struct is on the stack. Repack it on the fly.
|
|
* We only need to cld when we see the first structure
|
|
* needing repacking.
|
|
*/
|
|
if( !*pfDirectionFlagClear) {
|
|
*pfDirectionFlagClear = TRUE;
|
|
printf("\tcld\t\t\t\t; esi, edi will increment\n\n");
|
|
}
|
|
iBufferSize = ROUND_UP_MOD( ptnTo->iBaseDataSize, DWORD_SIZE);
|
|
printf("\tsub\tesp,%u\n", iBufferSize);
|
|
iStackCurrent += iBufferSize;
|
|
|
|
printf("\tlea\tesi,[ebx+%u]\t\t; source flat address\n",
|
|
ptnFrom->iOffset);
|
|
printf("\tmov\tedi,esp\t\t\t; destination flat address\n\n");
|
|
|
|
cod16_RepackElems( ptnFrom->pStructElems, ptnTo->pStructElems);
|
|
|
|
} else if( ptnFrom->iBaseType == ptnTo->iBaseType) {
|
|
printf("\tpush\t%s ptr [ebx+%u]\t; to %s\n\n",
|
|
ptnFrom->iBaseDataSize <= WORD_SIZE ? "word" : "dword",
|
|
ptnFrom->iOffset,
|
|
typ_NonNull( ptnTo->pchBaseTypeName));
|
|
iStackCurrent += ptnFrom->iBaseDataSize <= WORD_SIZE ?
|
|
WORD_SIZE : DWORD_SIZE;
|
|
} else {
|
|
if( fl = ptnFrom->flHandleType) {
|
|
printf("\tmov\teax,[ebx+%u]\n", ptnFrom->iOffset);
|
|
printf("\tcall\tGetHandle32\t\t; %s\n",
|
|
typ_GetHandleTypeName( fl));
|
|
} else if (ptnFrom->iBaseType == TYPE_UCHAR) {
|
|
printf("\tmovzx\teax,byte ptr [ebx+%u]\n", ptnFrom->iOffset);
|
|
} else {
|
|
printf("\t%s\teax,word ptr [ebx+%u]\n",
|
|
ptnFrom->iBaseType == TYPE_SHORT ? "movsx" : "movzx",
|
|
ptnFrom->iOffset);
|
|
}
|
|
printf("\tpush\teax\t\t\t; to: %s\n\n",
|
|
typ_NonNull( ptnTo->pchBaseTypeName));
|
|
iStackCurrent += DWORD_SIZE;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
fatal( "unknown pointer type %u in mapping %s=>%s",
|
|
ptnFrom->iPointerType,
|
|
pmn->pFromNode->pchFunctionName,
|
|
pmn->pToNode->pchFunctionName);
|
|
}
|
|
}
|
|
/*******************************************************************************
|
|
* cod16_CallFrame()
|
|
*
|
|
* This routine will generate call frame code.
|
|
*
|
|
* Entry: pmn is a pointer to a MapNode.
|
|
*
|
|
* Exit: Call frame code will have been written to the output file.
|
|
*
|
|
* PCode:
|
|
*
|
|
* History:
|
|
* 21feb91 KevinR wrote it
|
|
*
|
|
******************************************************************************/
|
|
|
|
void cod16_CallFrame( PMAPNODE pmn)
|
|
{
|
|
PTYPENODE ptnFrom, ptnTo;
|
|
CHAR *pch;
|
|
ULONG fl;
|
|
INT iBufferSize;
|
|
BOOL fDirectionFlagClear=FALSE;
|
|
USHORT icStackFrame;
|
|
|
|
SML_DIVIDE;
|
|
printf("; create new call frame and make the call\n\n");
|
|
|
|
fPackedPointReturned = FALSE;
|
|
|
|
/*
|
|
* Instead of looping (commented, we call a recursive function,
|
|
* since we need the parameters printed in reverse
|
|
*
|
|
* for( ptnFrom = pmn->pFromNode->ParamList, ptnTo = pmn->pToNode->ParamList;
|
|
* ptnFrom;
|
|
* ptnFrom = ptnFrom->pNextNode, ptnTo = ptnTo->pNextNode) {
|
|
*/
|
|
ptnFrom = pmn->pFromNode->ParamList;
|
|
ptnTo = pmn->pToNode->ParamList;
|
|
if (ptnFrom)
|
|
|
|
//
|
|
// here is where all will be done
|
|
//
|
|
|
|
cod16_CallFrameWorker(ptnFrom, ptnTo, &fDirectionFlagClear, pmn);
|
|
|
|
if( fBPCall)
|
|
printf("\tint\t3\n");
|
|
icStackFrame = cod_CountParameterBytes( pmn->pToNode->ParamList,
|
|
DWORD_SIZE);
|
|
printf("\tcall\t%s@%u\t\t; call 32-bit version\n\n",
|
|
pmn->pToNode->pchFunctionName, icStackFrame);
|
|
iStackCurrent -= icStackFrame;
|
|
if( fBPExit)
|
|
printf("\tint\t3\n\n");
|
|
}
|
|
|
|
/*******************************************************************************
|
|
* cod16_Return()
|
|
*
|
|
* This routine will generate return code handling code.
|
|
*
|
|
* Entry: pmn is a pointer to a MapNode.
|
|
*
|
|
* Exit: code was emitted
|
|
*
|
|
* PCode:
|
|
*
|
|
* History:
|
|
* 20mar91 KevinR wrote it
|
|
*
|
|
******************************************************************************/
|
|
|
|
void cod16_Return( PMAPNODE pmn)
|
|
{
|
|
fSaveEAX = fSaveEDX = FALSE;
|
|
|
|
if( pmn->pFromNode->ReturnType->fSemantics & SEMANTIC_SPECIAL) {
|
|
if( cod16_ReturnSpecial( pmn))
|
|
return;
|
|
}
|
|
|
|
if( fPackedPointReturned) {
|
|
printf("; pack point into return code, ignoring 32-bit rc\n");
|
|
printf("\tmov\tedx,[esp+%u]\n",iStackCurrent - iYRCTempOffset);
|
|
printf("\tmov\teax,[esp+%u]\n\n",iStackCurrent - iXRCTempOffset);
|
|
fSaveEAX = TRUE;
|
|
fSaveEDX = TRUE;
|
|
|
|
} else if( pmn->pFromNode->ReturnType->flHandleType) {
|
|
printf("\tcall\tGetHandle16\t\t; convert handle\n\n");
|
|
fSaveEAX = TRUE;
|
|
|
|
} else if( pmn->pFromNode->ReturnType->iPointerType) {
|
|
cod_NotHandled( "cod16_Return: pointer return code");
|
|
|
|
} else if( typ_TypeIdentical( pmn->pFromNode->ReturnType,
|
|
pmn->pToNode->ReturnType)) {
|
|
printf("; return code %s --> %s\n",
|
|
pmn->pToNode->ReturnType->pchBaseTypeName,
|
|
pmn->pFromNode->ReturnType->pchBaseTypeName);
|
|
|
|
switch( pmn->pFromNode->ReturnType->iBaseType) {
|
|
case TYPE_LONG:
|
|
case TYPE_ULONG:
|
|
printf("\tmov\tedx,eax\n");
|
|
printf("\trol\tedx,16\n\n");
|
|
fSaveEAX = TRUE;
|
|
fSaveEDX = TRUE;
|
|
break;
|
|
|
|
case TYPE_SHORT:
|
|
case TYPE_USHORT:
|
|
fSaveEAX = TRUE;
|
|
printf("; no conversion needed\n\n");
|
|
break;
|
|
|
|
case TYPE_VOID:
|
|
printf("; no conversion needed\n\n");
|
|
break;
|
|
|
|
default:
|
|
cod_NotHandled( "cod16_Return: unknown same base type");
|
|
}
|
|
} else {
|
|
printf("; return code %s --> %s\n",
|
|
pmn->pToNode->ReturnType->pchBaseTypeName,
|
|
pmn->pFromNode->ReturnType->pchBaseTypeName);
|
|
|
|
switch( pmn->pFromNode->ReturnType->iBaseType) {
|
|
case TYPE_SHORT: /* LONG --> SHORT */
|
|
case TYPE_USHORT: /* ULONG --> USHORT */
|
|
/* BUGBUG no check for truncation */
|
|
printf("; no conversion needed\n\n");
|
|
fSaveEAX = TRUE;
|
|
break;
|
|
|
|
default:
|
|
cod_NotHandled( "cod16_Return: unknown different base type");
|
|
}
|
|
}
|
|
}
|
|
|
|
/*******************************************************************************
|
|
* cod16_UnpackParams()
|
|
*
|
|
* This routine will generate parameter unpacking code.
|
|
*
|
|
* Entry: pmn is a pointer to a MapNode.
|
|
*
|
|
* Exit: Parameter unpacking code will have been written to the output file.
|
|
*
|
|
* PCode:
|
|
*
|
|
* History:
|
|
* 21feb91 KevinR wrote it
|
|
*
|
|
******************************************************************************/
|
|
|
|
void cod16_UnpackParams( PMAPNODE pmn)
|
|
{
|
|
PTYPENODE ptnFrom, ptnTo;
|
|
BOOL fDirectionFlagClear=FALSE;
|
|
|
|
if( typ_QuerySemanticsUsed( pmn, SEMANTIC_OUTPUT) ||
|
|
typ_QuerySemanticsUsed( pmn, SEMANTIC_SPECIAL)) {
|
|
SML_DIVIDE;
|
|
printf("; *** BEGIN parameter unpacking\n\n");
|
|
|
|
if( fSaveEAX){
|
|
printf("\tpush\teax\t\t\t; save return code\n");
|
|
// YaronS fix bug, not counting for the above push
|
|
iStackCurrent+=4; // count for this push!
|
|
}
|
|
if( fSaveEDX){
|
|
printf("\tpush\tedx\t\t\t; save return code\n");
|
|
// YaronS fix bug, not counting for the above push
|
|
iStackCurrent+=4; // count for this push!
|
|
}
|
|
if( fSaveEAX || fSaveEDX)
|
|
printf("\n");
|
|
|
|
for( ptnFrom = typ_FindFirstPointer( pmn->pFromNode->ParamList, TRUE),
|
|
ptnTo = typ_FindFirstPointer( pmn->pToNode->ParamList, TRUE);
|
|
ptnFrom;
|
|
ptnFrom = typ_FindNextPointer( ptnFrom, TRUE),
|
|
ptnTo = typ_FindNextPointer( ptnTo, TRUE)) {
|
|
|
|
if( ptnFrom->fSemantics & SEMANTIC_SPECIAL) {
|
|
if( cod16_UnpackParamSpecial( pmn, ptnFrom, ptnTo))
|
|
continue;
|
|
}
|
|
|
|
if( ptnFrom->fSemantics & SEMANTIC_OUTPUT) {
|
|
|
|
if( !typ_TypeIdentical( ptnFrom, ptnTo) &&
|
|
(ptnFrom->iBaseType == TYPE_STRUCT) &&
|
|
!fDirectionFlagClear) {
|
|
fDirectionFlagClear = TRUE;
|
|
printf("\tcld\t\t\t\t; esi, edi will increment\n\n");
|
|
}
|
|
|
|
cod16_UnpackPointer( ptnFrom, ptnTo);
|
|
}
|
|
}
|
|
|
|
if( fSaveEDX)
|
|
printf("\tpop\tedx\t\t\t; restore return code\n");
|
|
if( fSaveEAX)
|
|
printf("\tpop\teax\t\t\t; restore return code\n");
|
|
if( fSaveEAX || fSaveEDX)
|
|
printf("\n");
|
|
|
|
printf("; *** END parameter packing\n");
|
|
}
|
|
}
|
|
|
|
/*******************************************************************************
|
|
* cod16_UnpackPointer()
|
|
*
|
|
* This routine will generate pointer-unpacking code.
|
|
*
|
|
* Entry: ptnFrom - parameter output from thunk
|
|
* ptnTo - parameter input to thunk
|
|
*
|
|
* Exit: pointer-unpacking code was emitted
|
|
*
|
|
* PCode:
|
|
*
|
|
* History:
|
|
* 07mar91 KevinR wrote it
|
|
*
|
|
******************************************************************************/
|
|
|
|
void cod16_UnpackPointer( PTYPENODE ptnFrom, PTYPENODE ptnTo)
|
|
{
|
|
UINT uiNullLabel;
|
|
BOOL fSameType, fEmbeddedPtr;
|
|
CHAR *pch;
|
|
|
|
fSameType = typ_TypeIdentical( ptnFrom, ptnTo);
|
|
fEmbeddedPtr = cod_CountPointerParameters( ptnFrom->pStructElems, FALSE);
|
|
|
|
if( strcmp( (pch = typ_NonNull( ptnFrom->pchIdent)), ""))
|
|
printf("; %s\n", pch);
|
|
printf("; pointer %s --> %s\n",
|
|
typ_NonNull( ptnTo->pchBaseTypeName),
|
|
typ_NonNull( ptnFrom->pchBaseTypeName));
|
|
printf("\tmov\teax,[ebx+%u]\t\t; base address\n", ptnFrom->iOffset);
|
|
printf("\tor\teax,eax\n");
|
|
printf("\tjz\tL%u\t\t\t; skip if null\n\n", uiNullLabel = uiGenLabel++);
|
|
|
|
if( ptnFrom->iBaseType == TYPE_STRUCT) {
|
|
printf("\n; structures are%s identical\n",
|
|
fSameType ? "" : " not");
|
|
printf("; structures %shave pointers\n\n",
|
|
fEmbeddedPtr ? "" : "don't ");
|
|
|
|
if( ptnFrom->pSizeParam && (!fSameType)) {
|
|
cod_NotHandled( "structure buffer");
|
|
} else if( !fSameType) {
|
|
cod16_StructureUnpack( ptnFrom, ptnTo);
|
|
}
|
|
} else if( !fSameType) {
|
|
cod_NotHandled( "output pointer to different non-structs");
|
|
}
|
|
|
|
printf("L%u:\n\n", uiNullLabel);
|
|
}
|
|
|
|
/*******************************************************************************
|
|
* cod16_StructureUnpack()
|
|
*
|
|
* This routine will generate structure unpacking code.
|
|
*
|
|
* Entry: ptnFrom - parameter output from thunk
|
|
* ptnTo - parameter input to thunk
|
|
*
|
|
* Exit: structure unpacking code was emitted
|
|
*
|
|
* PCode:
|
|
*
|
|
* History:
|
|
* 22feb91 KevinR wrote it
|
|
*
|
|
******************************************************************************/
|
|
|
|
void cod16_StructureUnpack( PTYPENODE ptnFrom, PTYPENODE ptnTo)
|
|
{
|
|
UINT uiStoreLabel;
|
|
INT iBufferSize;
|
|
ULONG fl;
|
|
|
|
cod16_SelToFlat();
|
|
printf("\tmov\tedi,eax\t\t\t; destination flat address\n");
|
|
printf("\tmov\tesi,[esp+%u]\t\t; source flat address\n\n",
|
|
iStackCurrent - ptnFrom->iTempOffset);
|
|
|
|
cod16_RepackElems( ptnTo->pStructElems, ptnFrom->pStructElems);
|
|
}
|
|
|
|
/*******************************************************************************
|
|
* cod16_Exit()
|
|
*
|
|
* This routine will generate the exit code for one thunk.
|
|
*
|
|
* Entry: pmn is a pointer to a MapNode.
|
|
*
|
|
* Exit: Exit code will have been written to the output file.
|
|
*
|
|
* PCode:
|
|
*
|
|
* History:
|
|
* 21feb91 KevinR wrote it
|
|
*
|
|
******************************************************************************/
|
|
|
|
void cod16_Exit( PMAPNODE pmn, BOOL fUseDI, BOOL fUseSI)
|
|
{
|
|
SML_DIVIDE;
|
|
|
|
printf("\tjmp\tExitFlat_%u\n\n",
|
|
cod_CountParameterBytes( pmn->pFromNode->ParamList, WORD_SIZE));
|
|
}
|
|
|
|
/*******************************************************************************
|
|
* cod16_GenRet16()
|
|
*
|
|
* This routine will generate the code to restore the stack & registers and ret
|
|
*
|
|
* Entry: uiParameterBytes is the number of paramater bytes to clear
|
|
*
|
|
* Exit: Exit code will have been written to the output file.
|
|
*
|
|
* PCode:
|
|
*
|
|
* History:
|
|
* 16mar91 KevinR wrote it
|
|
*
|
|
******************************************************************************/
|
|
|
|
void cod16_GenRet16( UINT uiParameterBytes, BOOL fUseDI, BOOL fUseSI)
|
|
{
|
|
if( fUser) {
|
|
printf("\txchg\teax,esi\t\t\t; save return code\n");
|
|
printf("\tpush\t[ebx-4]\t\t\t; old SS16\n");
|
|
printf("\tcall\tSetSS16\n");
|
|
printf("\txchg\teax,esi\t\t\t; restore return code\n\n");
|
|
}
|
|
|
|
printf("\tlss\tsp,[ebx]\t\t; restore 16-bit ss:sp\n\n");
|
|
|
|
printf("\tpop\tbp\n");
|
|
printf("\tpop\tdx\n");
|
|
printf("\tpop\tbx\n");
|
|
printf("\tpop\tcx\n");
|
|
if( fUseSI)
|
|
printf("\tpop\tsi\n");
|
|
if( fUseDI)
|
|
printf("\tpop\tdi\n");
|
|
|
|
printf(";\n; Performance HIT BUGBUG \n;\n");
|
|
printf("\tpush\teax\n");
|
|
printf("\tmov\teax,ecx\n");
|
|
printf("\tshr\teax,16\t\t; ES\n");
|
|
printf("\tverr\tax\t\t; see if the value is still valid!\n");
|
|
printf("\tjnz\tFixES_%u\n", uiParameterBytes);
|
|
printf("\tmov\tes,ax\n");
|
|
printf("\tjmp\tESFixed_%u\n", uiParameterBytes);
|
|
|
|
printf("FixES_%u:\n", uiParameterBytes);
|
|
printf("\txor\tax,ax\n");
|
|
printf("\tmov\tes,ax\n");
|
|
|
|
printf("ESFixed_%u:\n", uiParameterBytes);
|
|
|
|
printf("\tmov\teax,edx\n");
|
|
printf("\tshr\teax,16\t\t; DS\n");
|
|
printf("\tverr\tax\t\t; see if the value is still valid!\n");
|
|
printf("\tjnz\tFixDS_%u\n", uiParameterBytes);
|
|
printf("\tmov\tds,ax\n");
|
|
printf("\tjmp\tDSFixed_%u\n", uiParameterBytes);
|
|
|
|
printf("FixDS_%u:\n", uiParameterBytes);
|
|
printf("\txor\tax,ax\n");
|
|
printf("\tmov\tds,ax\n");
|
|
|
|
|
|
printf("DSFixed_%u:\n", uiParameterBytes);
|
|
|
|
printf(";\n;Now restore ax & di, and clean the stack\n");
|
|
printf("\tpop\teax\n");
|
|
printf("\tadd\tsp,4\t; es/ds are 2 byte each on the stack\n");
|
|
|
|
printf("\tdb\t66h, 0cah\t\t; 16-bit retf\n");
|
|
printf("\tdw\t%u\t\t\t; 16-bit parameters\n\n", uiParameterBytes);
|
|
}
|