Windows NT 4.0 source code leak
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.
 
 
 
 
 
 

2563 lines
89 KiB

/*
* Thunk Compiler - Routines for Code Generator (32->16).
*
* This is a Win32 specific file
* Microsoft Confidential
*
* Copyright (c) Microsoft Corporation 1987, 1988, 1989, 1990
*
* All Rights Reserved
*
* Created 11/28/88 by Julie Bennett
* Revised 12/03/88 by Kevin Ross
* Adapted to Win32 by Kevin Ruddell 10/30/90
*/
#include <stdio.h>
#include "error.h"
#include "thunk.h"
#include "types.h"
#include "symtab.h"
#include "codegen.h"
#include "cod3216.h"
extern BOOL fMapTo16Used;
extern BOOL fGDIAllocUsed;
extern BOOL fLocalHeapUsed;
unsigned int gEDI, gESI;
unsigned int gTransferBytes = 0;
CHAR *pszGDISemName = "GDISERIAL";
FunctionNode *pGlobal_To, *pGlobal_From;
int fReAlignmentNeeded = 0;
int fCombined = 0,iCombinedOffset=0;
extern void cod_Entry32(MapNode *);
extern void cod32_HandleStructureBuffer(TypeNode *,TypeNode *);
extern void cod32_StructureRepack(TypeNode *,TypeNode *);
extern void cod32_HandleBoundaryCross(unsigned int,TypeNode *,unsigned int);
extern void cod32_HandleFixedSize(unsigned int,TypeNode *);
extern void cod32_CopyConvert(TypeNode *,TypeNode *);
extern void cod32_TransferBlock(int);
/*** cod_Handle3216()
*
* This routine will generate a thunk FROM a 0:32 routine to a 16:16
* routine.
*
* Entry: pMNode is a pointer to a MapNode.
*
* Exit: The thunk will have been written to the output file.
*
* 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:
* 29-Nov-1988 JulieB Changed parms. Added code gen routines.
*/
void
cod_Handle3216(MapNode *pMNode)
{
pGlobal_To = TONODE(pMNode);
pGlobal_From = FRNODE(pMNode);
fCombined = pMNode->pFamily != NULL;
cod_Entry32(pMNode);
if (FRNODE(pMNode)->iPointerCount > 32)
{
printf(".err Mapping %s => %s not generated\n",
FRNODE(pMNode)->pchFunctionName,
TONODE(pMNode)->pchFunctionName);
fprintf(stderr, "Mapping %s => %s not generated\n",
FRNODE(pMNode)->pchFunctionName,
TONODE(pMNode)->pchFunctionName);
return;
}
cod_CalcOffset(FRNODE(pMNode)->ParamList, 2 * DWORD_SIZE, DWORD_SIZE,
PUSH_LEFT);
cod_CalcOffset(TONODE(pMNode)->ParamList, 0, // beware: 0 !!!!!!!
WORD_SIZE,
PUSH_LEFT);
cod_CalcTempOffset(FRNODE(pMNode)->ParamList, iStackOverhead);
cod_CalcStructOffsets(TONODE(pMNode)->ParamList, WORD_SIZE);
cod_CalcStructOffsets(FRNODE(pMNode)->ParamList, iPackingSize);
/*
* Generate the thunk assembly code for the function.
*/
cod_PointerHandler32(pMNode);
cod_CallFrame32(pMNode);
//cod_UnpackStruct32(pMNode);
cod32_UnpackStructGDI(pMNode);
cod_Return32(pMNode);
cod_CallStub32(pMNode);
/*
* Dump the type nodes to the screen - used for debugging.
*/
if (DumpTables)
{
cod_DumpTypes(FRNODE(pMNode));
cod_DumpStructures(FRNODE(pMNode)->ParamList);
cod_DumpTypes(TONODE(pMNode));
cod_DumpStructures(TONODE(pMNode)->ParamList);
}
}
/*** cod_Entry32
*
* This function prints out the entry assembly code for the 32-bit
* routine.
*
* Entry: pMNode is the pointer to a MapNode.
*
* Exit: entry code is generated.
*
* History:
* 28-Nov-1988 JulieB Created it.
* 26-Dec-1988 KevinRo Saved pointer count in FNode
* Added temp storage for return code when
* pointers exist.
*/
void
cod_Entry32(MapNode *pMNode)
{
int iNumPtrs; /* number of pointer parameters */
register int i; /* loop counter */
/*
* Count the number of pointer parameters in the FromNode.
*/
iNumPtrs = cod_CountPointerParameters(pMNode->pFromNode->ParamList, FALSE);
pMNode->pToNode->iPointerCount = pMNode->pFromNode->iPointerCount = iNumPtrs;
if (iNumPtrs > 32)
return ;
/*
* Open a dummy label.
*/
printf("\n;Create a dummy label to trick MASM into correct fixups\n");
printf("\n%s\tSEGMENT\n\n",CODE16_NAME);
printf("T_%s\tLABEL FAR\n\n", pMNode->pToNode->pchFunctionName);
printf("%s\tENDS\n\n",CODE16_NAME);
printf("\n%s\tSEGMENT\n",CODE32_NAME);
printf("\tASSUME CS:FLAT\n");
//printf("\tASSUME DS:DGROUP,ES:nothing,SS:DGROUP\n");
printf("\tASSUME DS:FLAT,ES:FLAT\n");
/*
* Open procedure.
*/
printf("%s PROC\n\n", pMNode->pFromNode->pchFunctionName);
if (fCombined) {
printf("\txor\teax,eax\n");
printf("\nC_%s:\n\n", pMNode->pFromNode->pchFunctionName);
}
if (fBPEntry)
printf("\n\n;******* Break Point\n\n\tint\t3\n\n\n");
#if 0
printf( "\txor\tedx,edx\t\t\t;attempt to claim semaphore\n");
printf( "\tinc\tedx\n");
printf( "\txchg\tedx,%s\n", pszGDISemName);
printf( "\tor\tedx,edx\n");
printf( "\tjnz\tSEMEXIT_%s\n\n", pMNode->pFromNode->pchFunctionName);
#endif
printf("\tpush\tebp\n");
printf("\tmov\tebp,esp\n\n");
/*
* Allocate temporary storage on stack.
*/
iStackOverhead = 0;
iErrorOffset = iStackOverhead;
if (fCombined) {
printf("\tpush\teax\t\t;Save call number\n\n");
iStackOverhead += DWORD_SIZE;
iCombinedOffset = iStackOverhead;
}
if (iNumPtrs)
{
printf("\n\tcld\t\t\t;Assume direction flag clear\n");
printf("\txor\teax,eax\n");
iStackOverhead += DWORD_SIZE;
printf("\tpush\teax\t\t; temp storage for return value\n");
iReturnValOffset = iStackOverhead;
iStackOverhead += DWORD_SIZE;
printf("\tpush\tesi\n");
iStackOverhead += DWORD_SIZE;
printf("\tpush\tedi\n");
iSavedRegOffset = iStackOverhead;
iStackOverhead += DWORD_SIZE;
printf("\tpush\teax\t\t; temp storage \n");
iTempStoreOffset = iStackOverhead;
iStackOverhead += DWORD_SIZE;
printf("\tpush\teax\t\t; pointer thunk id\n");
iPtrThunkIDOffset = iStackOverhead;
//iStackOverhead += DWORD_SIZE;
//printf("\tpush\teax\t\t;Error flag for cleanup\n");
//iErrorOffset = iStackOverhead;
iErrorOffset = 0;
//iStackOverhead += DWORD_SIZE;
//printf("\tpush\teax\t\t; temp storage for Stack Allocation Flags\n");
//iAllocOffset = iStackOverhead;
iAllocOffset = 0;
//iStackOverhead += DWORD_SIZE;
//printf("\tpush\teax\t\t; temp storage for BMP Flags\n");
//iBMPOffset = iStackOverhead;
iBMPOffset = 0;
//iStackOverhead += DWORD_SIZE;
//printf("\tpush\teax\t\t; temp storage for Alias Flags\n");
//iAliasOffset = iStackOverhead;
iAliasOffset = 0;
}
iStackOverhead += DWORD_SIZE;
printf("\tpush\teax\t\t; stack thunk id\n");
iStackThunkIDOffset = iStackOverhead;
iStackOverhead += DWORD_SIZE;
for (i = 0; i < iNumPtrs; i++)
printf("\tpush\teax\t\t; temp storage for ptr param #%u\n", i + 1);
if (iNumPtrs)
{
printf( "\n\tcall\tGetThunkID32\n");
printf( "\tmov\t[ebp-%u],eax\t\t; pointer thunk id\n",
iPtrThunkIDOffset);
}
}
/*** cod_PointerHandler32
*
* This function traverses the list of parameters in the from node of the
* mapping, and emits code for boundary checking and structure repacking
* of pointer parameters.
*
* Entry: pMNode is the pointer to a MapNode.
*
* Exit: assembly code is emitted.
*
* History:
* 28-Nov-1988 JulieB Created it.
*/
cod_PointerHandler32(MapNode *pMNode)
{
TypeNode *pFromList, *pToList;
fGDIAllocUsed = FALSE;
fMapTo16Used = FALSE;
printf("\n; ****> BEGIN Pointer/Structure Section\n\n");
pFromList = pMNode->pFromNode->ParamList;
pToList = pMNode->pToNode->ParamList;
while (pFromList && pToList) {
if (pFromList->iPointerType) {
///*
// * Load source address into esi.
// */
//printf("\n\n\tmov\tesi,[ebp+%u]\t\t;%s base address\n",
// pFrom->iOffset, typ_NonNull(pFrom->pchIdent));
//cod32_HandlePointer(pFromList, pToList);
cod32_HandlePointerGDI( pFromList, pToList);
}
pFromList = pFromList->pNextNode;
pToList = pToList->pNextNode;
}
printf("\n; ****> END Pointer/Structure Section\n\n");
}
/*** cod32_HandlePointer(pFrom,pTo)
*
* This function will act on the two pointers accordingly.
* Structures will be repacked if needed, and buffers will be ensured
* not to cross 64k boundaries.
*
* Entry: pFromList - Parameter input to thunk.
* pToList - Parameter output from thunk.
* esi must be set up.
*
* Exit: pointers are handled and code is generated.
*
*/
int cod32_HandlePointer(TypeNode *pFrom,
TypeNode *pTo)
{
int iItemSize = -1;
TypeNode * pSizeP;
int NullLabel;
unsigned int JumpLabel;
unsigned int AllowLabel;
unsigned int SizeOkLabel;
unsigned int iTemp1, iTemp2;
printf("\n;Pointer %s --> %s\n",
typ_NonNull(pFrom->pchIdent), typ_NonNull(pTo->pchIdent));
printf("\tor\tesi,esi\n");
printf("\tjz\tL%u\n\n", NullLabel = gen_LabelCount++);
printf("\tmov\t[ebp-%u],esi\n", pFrom->iTempOffset);
/*
* If structures and (not identical or contain pointers), call
* structure repacking routine.
*/
iTemp1 = typ_TypeIdentical(pFrom, pTo);
iTemp2 = cod_CountPointerParameters(pFrom->pStructElems, FALSE);
if (pFrom->iBaseType == TYPE_STRUCT)
{
printf("\n;Structures %s Identical\n", (iTemp1) ? "are" : "are not");
printf(";Structures %s pointers\n\n", (iTemp2) ? "have" : "don't have");
}
gTransferBytes = 0;
if ((pFrom->iBaseType == TYPE_STRUCT) && (!iTemp1 || iTemp2))
{
if (pFrom->pSizeParam)
cod32_HandleStructureBuffer(pFrom,pTo);
else
cod32_StructureRepack(pFrom, pTo);
} else if (pFrom->iBaseType != pTo->iBaseType) {
/*
* If the types are not equal, then they must be shorts or longs.
* Call a routine suitable for copying and converting the buffer
*
* If there is no size parameter, then we are passing a long or a
* short. If the conversion is LONG to SHORT, then we can just use
* the existing long value as the buffer for the short. We will need
* to ensure that the copy out routine correctly extends the value.
*/
if ((pFrom->pSizeParam) || (pFrom->iArraySize > 1) ||
(pFrom->iBaseDataSize < pTo->iBaseDataSize))
cod32_CopyConvertBuffer(pFrom, pTo);
else {
unsigned int CheckLabel;
printf("\n;Have PU/LONG, want PU/SHORT\n");
printf(";Use the LONG as buffer, only if it doesn't\n");
printf(";cross boundary\n");
printf("\n;Check Boundary Crossing - fixed size item\n");
CheckLabel = gen_LabelCount++;
if (pFrom->fSemantics & SEMANTIC_INPUT) {
printf("\tmov\teax,[esi]\n");
printf("\tcmp\tsi,%lu\n",
(long)(0xffffL - (long)(typ_FullSize(pFrom) - 1)));
printf("\tjbe\tL%u\t\t\t;Enough room\n\n", CheckLabel);
} else {
printf("\tcmp\tsi,%lu\n",
(long)(0xffffL - (long)(typ_FullSize(pFrom) - 1)));
printf("\tjbe\tL%u\t\t\t;Enough room\n\n", NullLabel);
}
printf("; Allocate space on stack\n");
printf("\tsub\tesp,%u\t\t\t;Alloc Mem\n", typ_FullSize(pTo));
printf("\tand\tesp,0FFFFFFFCh\t\t;DWORD align\n");
printf("\tmov\tedi,esp\t\t\t;Points to new data area\n");
if (pFrom->fSemantics & SEMANTIC_INPUT)
printf("\tmov\t[edi],ax\n");
/*
* We have allocated space on the stack for the copy of the
* buffer. If the item is input only, then we don't need to
* deal with the buffer on output. In this special case, we
* can eliminate saving the new pointer, since we will never
* use it again anyway.
*/
if (pFrom->fSemantics & SEMANTIC_OUTPUT)
printf("\tmov\t[ebp-%u],edi\n", pFrom->iTempOffset);
else {
printf("\n;Item is input only. Not saving new pointer\n");
printf(";Deallocated implicitly\n");
}
if (pFrom->fSemantics & SEMANTIC_INPUT) {
printf("\nL%u:\n",CheckLabel);
if (pFrom->AllowList) {
AllowLabel = gen_LabelCount++;
cod32_HandleAllowList(pFrom->AllowList,AllowLabel);
}
switch (pFrom->iBaseType)
{
case TYPE_ULONG:
printf("\tcmp\teax,0ffffh\n");
printf("\tja\tINVP_%s\t\t;Jmp on large value\n\n",
pGlobal_From->pchFunctionName);
pGlobal_From->fInvalidParam = 1;
break;
case TYPE_LONG:
printf("\tmovsx\tecx,ax\n");
printf("\tcmp\teax,ecx\n");
printf("\tjne\tINVP_%s\t\t;\n\n",
pGlobal_From->pchFunctionName);
pGlobal_From->fInvalidParam = 1;
break;
default:
fatal("cod32_HandlePointer: Type assertion failed");
}
if (pFrom->AllowList)
printf("L%u:",AllowLabel);
}
}
}
/*
* If not a structure, or structure requires no repacking, then consider
* all other instances of pointers as buffers. If a pointer type has a
* Size Parameter, which is defined in a semantic block, then the size
* parameter will either be the size in bytes, or a count of the number
* items. If it is the count, then the size will be determined by
* multiplying the count by the size of the item.
*/
else {
if (pFrom->iBaseType == TYPE_STRUCT)
printf(";Treat structure same as buffer\n");
SizeOkLabel = NullLabel;
if (pSizeP = pFrom->pSizeParam)
{
printf("\tmov\tecx,[ebp+%u]\t\t;Get Size Parameter\n", pSizeP->iOffset);
if (pSizeP->iPointerType)
printf("\n;Check for NULL pointer\n");
printf("\tor\tecx,ecx\n");
printf("\tjz\tL%u\t\t;Nothing to check\n", NullLabel);
if (pSizeP->iPointerType)
{
printf("\t\t\t\t;ecx has pointer to size\n");
if (pSizeP->iBaseDataSize == WORD_SIZE)
printf("\tmovzx\tecx,WORD PTR [ecx]\t\t;Get Size\n");
else
printf("\tmov\tecx,[ecx]\t\t;Get Size\n");
printf("\tor\tecx,ecx\n");
printf("\tjz\tL%u\t\t;Nothing to check\n", NullLabel);
}
if ((pSizeP->iBaseDataSize == DWORD_SIZE) &&
(pTo->pSizeParam->iBaseDataSize < DWORD_SIZE)) {
printf("\n;DWORD --> WORD sized length. Error if Size > 64k\n");
if (pGlobal_From->fSemantics & SEMANTIC_TRUNC) {
printf("\tcmp\tecx,10000h\n");
printf("\tjae\tINVP_%s\t\t\t;jmp if too long\n",
pGlobal_From->pchFunctionName);
pGlobal_From->fInvalidParam = 1;
}
}
if (pSizeP->fSemantics & SEMANTIC_SIZE)
printf(";ECX holds size in bytes\n");
else if (pSizeP->fSemantics & SEMANTIC_COUNT) {
if (typ_FullSize(pFrom) > 1) {
printf(";ECX holds count of items\n");
printf("\tmov\teax,%d\t\t;Size of target data type\n",
typ_FullSize(pFrom));
printf("\tmul\tcx\n");
if (pGlobal_From->fSemantics & SEMANTIC_TRUNC) {
printf("\tjc\tINVP_%s\t\t\t;jmp if too long\n",
pGlobal_From->pchFunctionName);
pGlobal_From->fInvalidParam = 1;
}
printf("\tmovzx\tecx,ax\n\n");
}
else
printf("\n;The data size = 1, so the count == size of buf\n");
}
else
fatal("Internal Error: Size semantic not sizeof or countof");
printf("\n;Check Boundary Crossing\n");
printf("\tmov\teax,esi\n");
printf("\tneg\tax\n");
printf("\tjz\tL%u\t\t\t;0=full 64k of room\n\n", SizeOkLabel);
printf("\tcmp\tax,cx\n");
printf("\tjae\tL%u\t\t\t;Enough room\n\n", SizeOkLabel);
cod32_HandleBoundaryCross(SIZE_VARIABLE, pFrom, 0);
}
else {
/*
* No size parameter, assume fixed size parameter.
*/
switch (pFrom->iBaseType)
{
case TYPE_STRING:
printf(";Handle String Parameters\n");
printf("\n\tpush\t%d\t\t;Alias flag offset\n",
-iAliasOffset);
printf("\tpush\t%lu\t\t;Flag Mask\n",
(long)((long) 1 << pFrom->iPointerNumber));
printf("\tpop\tedx\n");
printf("\tcall\tTHK32HANDLESTRING\n");
printf("\tjc\tERR_%s\t\t\t;jmp if too long\n",
pGlobal_From->pchFunctionName);
printf("\tmov\t[ebp-%u],edi\n", pFrom->iTempOffset);
break;
default:
/*
* Static size.
*/
printf("\n;Check Boundary Crossing - fixed size item\n");
printf("\tcmp\tsi,%lu\n",
(long)(0xffffL - (typ_FullSize(pFrom) - 1)) );
printf("\tjbe\tL%u\t\t\t;Enough room\n\n", SizeOkLabel);
cod32_HandleBoundaryCross(SIZE_FIXED, pFrom,
typ_FullSize(pFrom));
}
}
}
printf("\nL%u:\n", NullLabel);
}
/*** cod32_HandleStructureBuffer(pFrom,pTo)
*
* This routine handles a buffer full of structures. The buffer has a
* variable length size which is given by either a sizeof semantic or
* by a countof semantic. This routine will convert the structure.
*
* This routine is only called when the structures are not identical,
* and therefore the buffer needs conversion.
*
* Entry: pFrom and pTo are the two type nodes to use.
*
* Exit: buffer is converted.
*/
void
cod32_HandleStructureBuffer(TypeNode *pFrom,
TypeNode *pTo)
{
TypeNode *pSizeP;
FixupRec *pFixupList = NULL;
unsigned int NullLabel;
unsigned int LoopLabel;
unsigned int iESI,iEDI;
iESI = gESI = 0;
iEDI = gEDI = 0;
pSizeP = pFrom->pSizeParam;
printf("\n;Parameter has size semantics. This is a buffer of structs\n");
/*
* The fact that we are in this routine means that there is a size
* parameter. Now the job is to figure out what type of size parameter
* it is, and calculate the appropriate buffer size.
*/
printf("\tmov\teax,[ebp+%u]\t\t;Get Size Parameter\n",
pSizeP->iOffset);
if (pSizeP->iPointerType)
printf("\n;Check for NULL pointer\n");
/* At this point, we know that the previous label handles the case
* where the buffer was empty (or pointer was NULL).
* Therefore, if we set out NullLabel to current -1, we get the
* correct fixup.
*/
NullLabel = gen_LabelCount - 1;
printf("\tor\teax,eax\n");
printf("\tjz\tL%u\t\t;Nothing to check\n", NullLabel);
if (pSizeP->iPointerType) {
printf("\t\t\t\t;eax has pointer to size\n");
if (pSizeP->iBaseDataSize == WORD_SIZE)
printf("\tmovzx\teax,WORD PTR [eax]\t\t;Get Size\n");
else
printf("\tmov\teax,[eax]\t\t;Get Size\n");
printf("\tor\teax,eax\n");
printf("\tjz\tL%u\t\t;Nothing to check\n", NullLabel);
}
if ((pSizeP->iBaseDataSize == DWORD_SIZE) &&
(pTo->pSizeParam->iBaseDataSize < DWORD_SIZE))
{
printf("\n;DWORD --> WORD sized length. Error if Size > 64k\n");
printf("\tcmp\teax,10000h\n");
printf("\tjae\tINVP_%s\t\t\t;jmp if too long\n",
pGlobal_From->pchFunctionName);
pGlobal_From->fInvalidParam = 1;
}
if (pSizeP->fSemantics & SEMANTIC_SIZE) {
printf(";ECX holds size in bytes\n");
printf(";We need to figure out the number of structures\n");
printf(";that will fit\n");
printf("\txor\tedx,edx\n");
printf("\tmov\tecx,%u\t\t;Source struct size\n",typ_FullSize(pFrom));
printf("\tdiv\tecx\n");
printf("\tmov\t[ebp-%u],eax\t;Save the count\n",iTempStoreOffset);
printf("\tmov\tcx,%u\t\t;target struct size\n",typ_FullSize(pTo));
printf("\tmul\tcx\t\t;Results in target buffer needed\n");
printf("\tjc\tINVP_%s\t\t;jmp if too long\n",
pGlobal_From->pchFunctionName);
pGlobal_From->fInvalidParam = 1;
}
else if (pSizeP->fSemantics & SEMANTIC_COUNT) {
printf(";EAX holds count of items\n");
printf("\n\ttest\teax,0ffff0000h\t;Must be < 64k\n");
printf("\tjnz\tINVP_%s\t\t;jmp if too many items\n",
pGlobal_From->pchFunctionName);
pGlobal_From->fInvalidParam = 1;
printf("\tmov\t[ebp-%u],eax\t\t;Save count\n",iTempStoreOffset);
printf("\tmov\tcx,%u\t\t;target struct size\n",typ_FullSize(pTo));
printf("\tmul\tcx\n");
printf("\tjc\tINVP_%s\t\t;jmp if too long\n",
pGlobal_From->pchFunctionName);
pGlobal_From->fInvalidParam = 1;
}
else
fatal("cod32_HandleStructureBuffer: Size semantic not sizeof|countof");
printf("\n\tmov\tecx,eax\t\t;Move size into ecx\n");
cod32_AllocateVariableSize(pFrom,0);
printf("\tmov\t[ebp-%u],edi\t\t;store new ptr\n",
pFrom->iTempOffset);
/*
* If semantics are not input, then don't emit copy in code.
*/
if (!(pFrom->fSemantics & SEMANTIC_INPUT))
return;
printf("\tmov\tecx,[ebp-%u]\t\t;restore count\n",iTempStoreOffset);
/*
* At this point, we know the following facts:
* 1 - The structures in this buffer contain no pointers
* and therefore will require no internal fixups.
* 2 - ESI holds the source address, EDI holds the destination
* 3 - ECX holds the count of structures to be converted
*/
gTransferBytes = 0;
LoopLabel = gen_LabelCount++;
printf("\n;Array of structures\n");
printf("\nL%u:\n", LoopLabel);
printf("\tpush\tecx\t\t;Save array count\n");
cod32_RepackElements(pFrom,pTo,
pFrom->pStructElems,
pTo->pStructElems, &pFixupList);
iESI = gESI;
iEDI = gEDI;
cod_AdjustReg("esi", &iESI, pFrom->iStructOffset + pFrom->iBaseDataSize);
cod_AdjustReg("edi", &iEDI, pTo->iStructOffset + pTo->iBaseDataSize);
printf("\n\tpop\tecx\t\t;Restore array count\n");
printf("\n\tloop\tL%u\n", LoopLabel);
gESI = pFrom->iStructOffset + typ_FullSize(pFrom);
gEDI = pTo->iStructOffset + typ_FullSize(pTo);
}
/*** cod32_HandleAllowList(AllowList,AllowLabel);
*
* This routine searches down the allowlist, printing out the
* appropriate assembler code for each entry.
*
* Entry: AllowList is the list to search.
* AllowLabel is the label to jump to.
*
* Exit: code for each entry in allowlist is generated.
*/
cod32_HandleAllowList(AllowNode *AllowList,
int AllowLabel)
{
if (AllowList)
printf("\n;Allowable Value List\n\n");
while (AllowList) {
printf("\n\tcmp\teax,0%lxh\n",AllowList->ulValue);
printf("\tje\tL%u\n",AllowLabel);
AllowList = AllowList->Next;
}
printf("\n");
}
/*** cod32_HandleRestricted(pFrom)
*
* This routine checks the from node for the restricted semantic.
* If the restricted semantic is set, then it will print out the
* allow list.
*
* Entry: pFrom is the typenode to check.
*
* Exit: allowlist code is generated if restricted semantic is set.
*/
cod32_HandleRestricted(TypeNode *pFrom)
{
unsigned int AllowLabel;
if (pFrom->fSemantics & SEMANTIC_RESTRICT) {
printf("\n\n;*** Parameter is restricted! ***\n");
printf("\n;Check for restricted values\n");
AllowLabel = gen_LabelCount++;
cod32_HandleAllowList(pFrom->AllowList,AllowLabel);
printf("\tjmp\tINVP_%s\t\t;Illegal value found\n",
pGlobal_From->pchFunctionName);
pGlobal_From->fInvalidParam = 1;
printf("\nL%u:\n",AllowLabel);
}
}
/*** cod32_CopyConvertBuffer(pFrom,pTo)
*
* This function will perform a copy/convert of a buffer.
* The buffer is presumed to be in the formal parameter list of the
* API declaration.
*
* Entry: pFrom and pTo are the typenodes to use.
*
* Exit: buffer is copied/converted.
*/
cod32_CopyConvertBuffer(TypeNode *pFrom,
TypeNode *pTo)
{
TypeNode * pSizeP;
unsigned int JumpLabel;
unsigned int NullLabel;
/*
* If there is a size parameter, then the buffer size is determined at
* run time. Otherwise, the buffer size is static.
*/
NullLabel = gen_LabelCount;
NullLabel--; /** The previous label handles NULL and zero lens **/
if (pSizeP = pFrom->pSizeParam) { /* Runtime */
printf("\tmov\tecx,[ebp+%u]\t\t;Get Size Parameter\n", pSizeP->iOffset);
if (pSizeP->iPointerType)
printf("\n;Check for NULL pointer\n");
printf("\tor\tecx,ecx\n");
printf("\tjz\tL%u\t\t;Nothing to check\n", NullLabel);
if (pSizeP->iPointerType)
{
printf("\t\t\t\t;ecx has pointer to size\n");
if (pSizeP->iBaseDataSize == WORD_SIZE)
printf("\tmovzx\tecx,WORD PTR [ecx]\t\t;Get Size\n");
else
printf("\tmov\tecx,[ecx]\t\t;Get Size\n");
printf("\tor\tecx,ecx\n");
printf("\tjz\tL%u\t\t;Nothing to check\n", NullLabel);
}
if ((pSizeP->iBaseDataSize == DWORD_SIZE) &&
(pTo->pSizeParam->iBaseDataSize < DWORD_SIZE) &&
pGlobal_From->fSemantics & SEMANTIC_TRUNC)
{
printf("\n;DWORD-->WORD sized length. Error if Size > 64k\n");
printf("\tcmp\tecx,10000h\n");
printf("\tjae\tINVP_%s\t\t\t;jmp if too long\n",
pGlobal_From->pchFunctionName);
pGlobal_From->fInvalidParam = 1;
}
if (pSizeP->fSemantics & SEMANTIC_SIZE)
{
printf(";ECX holds size in bytes\n");
printf(";We need to figure out the number of elements\n");
printf(";that will fit\n");
printf("\n\tmov\teax,ecx\n");
printf("\txor\tedx,edx\n");
printf("\tmov\tecx,%u\t\t;Source size\n",typ_FullSize(pFrom));
printf("\tdiv\tcx\n");
printf("\tmov\t[ebp-%u],eax\t;Save the count\n",iTempStoreOffset);
printf("\tmov\tcx,%u\t\t;target buffer size\n",typ_FullSize(pTo));
printf("\tmul\tcx\t\t;Results in target buffer needed\n");
printf("\tjc\tINVP_%s\t\t;jmp if too long\n",
pGlobal_From->pchFunctionName);
pGlobal_From->fInvalidParam = 1;
}
if (pSizeP->fSemantics & SEMANTIC_COUNT) {
if (typ_FullSize(pTo) > 1) {
printf(";ECX holds count of items\n");
printf(";Save count of items for later use\n");
printf("\n\tmov\t[ebp-%u],ecx\t\t;Temporary Storage\n",
iTempStoreOffset);
printf("\tmov\teax,%d\t\t;Size of target data type\n",
typ_FullSize(pTo));
printf("\tmul\tcx\n");
printf("\tjc\tINVP_%s\t;jmp if too long\n",
pGlobal_From->pchFunctionName);
pGlobal_From->fInvalidParam = 1;
}
else
printf("\n;The data size = 1, so the count == size of buf\n");
}
printf("\tmovzx\tecx,ax\n\n");
cod32_AllocateVariableSize(pFrom, 0);
printf("\tmov\t[ebp-%u],edi\n", pFrom->iTempOffset);
if (pFrom->fSemantics & SEMANTIC_INPUT) {
printf("\n\tmov\tecx,[ebp-%u]\t\t;Temporary Storage\n",
iTempStoreOffset);
gEDI = 0;
gESI = 0;
JumpLabel = gen_LabelCount++;
printf("\nL%u:\n", JumpLabel);
switch (pFrom->iBaseType)
{
case TYPE_UCHAR: /* UCHAR --> ULONG */
printf("\n;UCHAR --> ULONG\n\n");
printf("\tmovzx\teax,BYTE PTR[esi]\n");
printf("\tmov\t[edi],eax\n");
break;
case TYPE_SHORT: /* SHORT --> LONG */
printf("\n;SHORT --> LONG\n\n");
printf("\tmovsx\teax,WORD PTR[esi]\n");
printf("\tmov\t[edi],eax\n");
break;
case TYPE_USHORT: /* USHORT --> ULONG */
printf("\n;USHORT --> ULONG\n\n");
printf("\tmovzx\teax,WORD PTR[esi]\n");
printf("\tmov\t[edi],eax\n");
break;
case TYPE_LONG: /* LONG --> SHORT */
case TYPE_ULONG: /* ULONG --> USHORT */
printf("\n;U/LONG --> U/SHORT\n\n");
printf("\tmov\teax,DWORD PTR [esi]\n");
printf("\tmov\tWORD PTR [edi],ax\n");
break;
default:
fatal("cod32_CopyConvertBuffer: Tried converted %d to %d",
pFrom->iBaseType, pTo->iBaseType);
}
printf("\tadd\tesi,%u\n", pFrom->iBaseDataSize);
printf("\tadd\tedi,%u\n", pTo->iBaseDataSize);
printf("\tloop\tL%u\n", JumpLabel);
} else
printf("\n;Data item does not have input semantics\n");
}
else { /* Static */
cod32_AllocFixedSize(typ_FullSize(pTo), pFrom);
if (pFrom->fSemantics & SEMANTIC_INPUT) {
gEDI = 0;
gESI = 0;
cod32_CopyConvert(pFrom, pTo);
}
else
printf("\n;Data item does not have input semantics\n");
}
}
/*** cod32_StructureRepack(pFrom,pTo)
*
* This function generates the code that converts one structure
* to another structure.
*
* Entry: pFrom - pointer to the 32-bit structure.
* pTo - pointer to the 16-bit structure.
*
* Exit: structure repack code is generated.
*
* History:
* 23-Dec-1988 KevinRo Created It
*/
void
cod32_StructureRepack(TypeNode *pBaseFrom,
TypeNode *pBaseTo)
{
FixupRec *pFixupList = NULL, *pCurrent;
TypeNode *pFrom, *pTo;
TypeNode *ptFrom, *ptTo;
pFrom = pBaseFrom->pStructElems;
pTo = pBaseTo->pStructElems;
cod32_AllocFixedSize(typ_FullSize(pBaseTo), pBaseFrom);
gEDI = 0;
gESI = 0;
/*
* If the structure is not marked with the input semantic, then the
* structure does not contain any useful information. Therefore,
* we will assume that any substructures to this structure are
* not interesting, and may not actually exist.
*/
if (!(pBaseFrom->fSemantics & SEMANTIC_INPUT))
return;
printf(";Copy structure to new area\n\n");
cod32_RepackElements(pBaseFrom, pBaseTo, pFrom, pTo, &pFixupList);
/*
* Now, handle the fixups.
*/
while (pCurrent = cod_GetFixupRecord(&pFixupList)) {
printf("\n\n;Fixup imbedded pointer %s\n\n",
typ_NonNull(pCurrent->pFrom->pchIdent));
printf("\tmov\tesi,[ebp-%u]\t\t;Get parents pointer\n",
pCurrent->pParentFrom->iTempOffset);
printf("\tmov\tesi,[esi+%u]\t\t;Get Fixups pointer\n",
pCurrent->pTo->iStructOffset);
cod32_HandlePointer(pCurrent->pFrom, pCurrent->pTo);
printf("\n;Patch in new pointer value\n");
printf("\tmov\tedi,[ebp-%u]\t\t;Get parents pointer\n",
pCurrent->pParentFrom->iTempOffset);
printf("\tmov\tesi,[ebp-%u]\t\t;Get Fixups new pointer\n",
pCurrent->pFrom->iTempOffset);
if (pCurrent->pFrom->iPointerType != pCurrent->pTo->iPointerType) {
switch (pCurrent->pFrom->iPointerType)
{
case TYPE_FAR16:
printf(";Convert 16:16 --> 0:32\n");
printf("\tor\tesi,esi\n");
printf("\tjz\tshort L%u\n",gen_LabelCount);
printf("\tror\tesi,16\n");
printf("\tshr\tsi,3\n");
printf("\trol\tesi,16\n");
printf("L%u:\n",gen_LabelCount++);
break;
case TYPE_NEAR32:
printf(";Convert 0:32 --> 16:16\n");
printf("\tor\tesi,esi\n");
printf("\tjz\tshort L%u\n",gen_LabelCount);
printf("\tror\tesi,16\n");
printf("\tshl\tsi,3\n");
printf("\tmov\teax,ss\n");
printf("\tand\teax,3\n");
printf("\tor\tal,4\n");
printf("\tor\tsi,ax\n");
printf("\trol\tesi,16\n");
printf("L%u:\n",gen_LabelCount++);
break;
default:
fatal("Structure Repack: Unknown pointer type");
}
}
printf("\tmov\t[edi+%u],esi\t\t;Put Fixups pointer\n",
pCurrent->pTo->iStructOffset);
free(pCurrent);
}
}
/*** cod32_RepackElements(pParent,pFrom,pTo,pFixupList)
*
*
*
* Entry:
*
* Exit:
*/
cod32_RepackElements(TypeNode *pParentFrom,
TypeNode *pParentTo,
TypeNode *pFrom,
TypeNode *pTo,
FixupRec **pFixupList)
{
TypeNode * pToNode, *pFromNode;
unsigned int iEDI, iESI;
unsigned int JumpLabel;
fReAlignmentNeeded = 0;
for (pToNode = pTo, pFromNode = pFrom;
pFromNode;
pToNode = pToNode->pNextNode, pFromNode = pFromNode->pNextNode)
{
printf("\n;Element %s --> %s\n", typ_NonNull(pFromNode->pchIdent),
typ_NonNull(pToNode->pchIdent));
/*
* If the fReAlignmentNeeded flag is set, then the previous operation
* was a CopyConvert. The adjustment of the registers in that routine
* was moved here to optimize the increment of the registers.
* At the end of a CopyConvert, we only want to increment the
* registers in the cases when there are more elements in the
* structure. The fact that we have reached this statement implies
* that there are more elements in the structure.
*/
if (fReAlignmentNeeded) {
if (gTransferBytes)
fatal("RepackElements: gTransferBytes = %u", gTransferBytes);
printf("\n;Adjust registers after conversion\n");
cod_AdjustReg("esi", &gESI, pFromNode->iStructOffset);
cod_AdjustReg("edi", &gEDI, pToNode->iStructOffset);
fReAlignmentNeeded = 0;
}
/*
* This assignment optimizes the way that bytes are transferred,
* so that we don't need adjustments when bytes items precede
* larger sized items. This statement only has effect when a
* realignment is about to occur. This value is reset again a
* few lines down.
*/
gTransferBytes = MIN((pFromNode->iStructOffset - gESI),
pToNode->iStructOffset - gEDI);
/*
* If either the TO or FROM node is deleted, then we need to
* realign ESI and EDI.
*/
if ( (pFromNode->iDeleted) || (pToNode->iDeleted)) {
printf(";Deleted structure element\n");
if (gTransferBytes) {
printf(";Alignment Change\n");
cod32_TransferBlock(gTransferBytes);
gTransferBytes = 0;
printf("\n;ReAlignment\n");
}
if (pFromNode->iDeleted) {
printf(";Source element is deleted\n");
printf("\tmov\teax,%u\n",pFromNode->iFillValue);
switch (pToNode->iBaseType)
{
case TYPE_UCHAR:
printf(";Need a 8-bit value\n");
printf("\tstosb\n");
break;
case TYPE_USHORT:
case TYPE_SHORT:
printf(";Need a 16-bit value\n");
printf("\tstosw\n");
break;
case TYPE_LONG:
case TYPE_ULONG:
printf(";Need a 32-bit value\n");
printf("\tstosd\n");
break;
default:
fatal("Bad type for deleted struct element\n");
}
}
else {
/*
* In this case, the To node is deleted. This means that
* we don't want to copy the current element.
*/
switch (pFromNode->iBaseType)
{
case TYPE_UCHAR:
printf(";Deleting a 8-bit value\n");
break;
case TYPE_USHORT:
case TYPE_SHORT:
printf(";Deleting a 16-bit value\n");
break;
case TYPE_LONG:
case TYPE_ULONG:
printf(";Deleting a 32-bit value\n");
break;
default:
fatal("Bad type for deleted struct element\n");
}
}
goto DoneWithNodes; /** Avoid the rest of this loop **/
}
/*
* If the alignment is going to shift, then execute a block transfer,
* and realign ESI and EDI.
*/
if ((pFromNode->iStructOffset - gESI) != (pToNode->iStructOffset - gEDI)) {
if (gTransferBytes) {
printf(";Alignment Change\n");
cod32_TransferBlock(gTransferBytes);
gTransferBytes = 0;
printf("\n;ReAlignment\n");
}
cod_AdjustReg("esi", &gESI, pFromNode->iStructOffset);
cod_AdjustReg("edi", &gEDI, pToNode->iStructOffset);
}
switch (pFromNode->iPointerType)
{
/*
* If we find a pointer type, then it is an imbedded pointer.
* The data can be included into a block copy, since we are
* going to handle it later.
*/
case TYPE_NEAR32:
case TYPE_FAR16:
printf(";Pointer converted later\n");
cod_AddFixupRecord(pFixupList,
cod_MakeFixupRecord(pParentFrom, pParentTo,
pFromNode, pToNode));
gTransferBytes += DWORD_SIZE;
break;
/*
* If it wasn't one of the pointer types above, then it must be a
* non pointer parameter. Thus, it will be a long, short, ulong,
* ushort, or char.
*/
default:
if (pFromNode->iBaseType == TYPE_STRUCT) {
unsigned int LoopLabel;
unsigned int iESI = gESI, iEDI = gEDI;
if (pFromNode->iArraySize > 1) {
cod32_TransferBlock(gTransferBytes);
gTransferBytes = 0;
cod_AdjustReg("esi", &gESI, pFromNode->iStructOffset);
cod_AdjustReg("edi", &gEDI, pToNode->iStructOffset);
LoopLabel = gen_LabelCount++;
printf("\n;Array of structures\n");
printf("\n\tmov\tecx,%u\n", pFromNode->iArraySize);
printf("\nL%u:\n", LoopLabel);
printf("\tpush\tecx\t\t;Save array count\n");
}
cod32_RepackElements(pParentFrom, pParentTo,
pFromNode->pStructElems,
pToNode->pStructElems, pFixupList);
iESI = gESI;
iEDI = gEDI;
if (pFromNode->iArraySize > 1) {
cod_AdjustReg("esi", &iESI, pFromNode->iStructOffset +
pFromNode->iBaseDataSize);
cod_AdjustReg("edi", &iEDI, pToNode->iStructOffset +
pToNode->iBaseDataSize);
printf("\n\tpop\tecx\t\t;Restore array count\n");
printf("\n\tloop\tL%u\n", LoopLabel);
gESI = pFromNode->iStructOffset +
typ_FullSize(pFromNode);
gEDI = pToNode->iStructOffset + typ_FullSize(pToNode);
}
}
else {
fReAlignmentNeeded = 0;
cod32_CopyConvert(pFromNode, pToNode);
}
}
DoneWithNodes:
if ((pToNode->pNextNode == NULL) && (pParentTo->iPointerType)) {
cod32_TransferBlock(gTransferBytes);
gTransferBytes = 0;
}
}
}
/*** cod32_HandleBoundaryCross(fSize,pFrom,iSize)
*
* Emits code to handle boundary crossing of pFrom. This code assumes
* that esi holds the source address.
*
* Entry: fSize - either SIZE_FIXED or SIZE_VARIABLE.
* pFrom - typenode for From pointer.
* iSize - size of item with SIZE_FIXED, or maximum length of
* item when SIZE_VARIABLE.
*
* Notes:
* If fSize == SIZE_VARIABLE then the size of the data item is
* assumed to be in ECX.
*
* Exit: Code to allocate the appropriate amount of memory will be
* emitted, along with appropriate code to copy the data to
* the new location. Code to set the appropriate flags will
* also be set.
*/
unsigned int iCopyLabel;
unsigned int iNoCopyLabel, iNextSize;
void
cod32_HandleBoundaryCross(unsigned int fSize,
TypeNode *pFrom,
unsigned int iSize)
{
iCopyLabel = gen_LabelCount++;
iNoCopyLabel = gen_LabelCount++;
if (fSize == SIZE_FIXED) {
cod32_HandleFixedSize(iSize, pFrom);
return;
}
else {
if (!pGlobal_To->fInlineCode) {
printf("\tcall\tThk32HandleBoundary\n");
printf("\tor\teax,eax\n");
printf("\tjnz\tNOMEM_%s\t\t\t;\n", pGlobal_From->pchFunctionName);
printf("\tmov\t[ebp-%u],edi\n", pFrom->iTempOffset);
printf("\tor\tedx,edx\n");
printf("\tjs\tshort L%u\t\t;Alloced Mem \n", iCopyLabel);
printf("\tor\t%s PTR [ebp+(edx*4)-%u],%lu\t\t;Set Flag\n",
(pFrom->iPointerNumber > 7)?"DWORD":"BYTE",iAliasOffset,
(long) 1 << pFrom->iPointerNumber);
/*
* Don't need jump if semantics are not input. There will be no
* copy code output if semantics are input.
*/
if (pFrom->fSemantics & SEMANTIC_INPUT) {
printf("\tdec\tedx\n");
printf("\tjs\tshort L%u\t\t;Aliases not copied\n",
iNoCopyLabel);
}
}
else {
if (iSize == 0)
iSize--; /** Make iSize huge **/
pFrom->fTempAlloc |= ALLOC_STACK; /* Eligable for stack alloc */
printf("\tcmp\tecx,%u\n", SMALL_ITEM);
if (iSize >= MEDIUM_ITEM)
printf("\tja\tshort L%u\n\n", iNextSize = gen_LabelCount++);
else {
printf("\tja\tINVP_%s\t\t\t;jmp if too long\n",
pGlobal_From->pchFunctionName);
pGlobal_From->fInvalidParam = 1;
}
printf("; Allocate space on stack\n");
printf("\tsub\tesp,ecx\t\t\t;Alloc Mem\n");
printf("\tand\tesp,0FFFFFFFCh\t\t;DWORD align\n");
printf("\tmov\tedi,esp\t\t\t;Points to new data area\n");
printf("\tmov\t[ebp-%u],edi\n", pFrom->iTempOffset);
printf("\tmov\tesi,[ebp+%u]\n", pFrom->iOffset);
printf("\tor\t%s PTR [ebp-%u],%lu\t\t;Set Stack Alloc Flag\n",
(pFrom->iPointerNumber >7)?"DWORD":"BYTE",
iAllocOffset, (long) 1 << pFrom->iPointerNumber);
if (iSize >= MEDIUM_ITEM) {
printf("\tjmp\tshort L%u\n", iCopyLabel);
printf("\nL%u:\n", iNextSize);
printf("\tcmp\tecx,%u\n", MEDIUM_ITEM);
if (iSize >= LARGE_ITEM)
printf("\tja\tshort L%u\n\n", iNextSize = gen_LabelCount++);
else {
printf("\tja\tINVP_%s\t\t\t;jmp if too long\n",
pGlobal_From->pchFunctionName);
pGlobal_From->fInvalidParam = 1;
}
printf("; Allocate space in BMP area\n");
printf("\tcall\tThk32AllocBlock\n");
pFrom->fTempAlloc |= ALLOC_BMP; /* Eligable for BMP alloc*/
printf("\tmov\t[ebp-%u],edi\n", pFrom->iTempOffset);
printf("\tor\t%s PTR [ebp-%u],%lu\t\t;Set BMP Alloc Flag\n",
(pFrom->iPointerNumber >7)?"DWORD":"BYTE",
iBMPOffset, (long) 1 << pFrom->iPointerNumber);
}
if (iSize >= LARGE_ITEM) {
printf("\tjmp\tshort L%u\n\n", iCopyLabel);
printf("\nL%u:\n", iNextSize);
printf("\n;Ensure item spans 16 pages or less.\n");
printf("\tmov\teax,esi\n");
printf("\tand\teax,0fffh\n");
printf("\tmov\tedx,10000h\n");
printf("\tsub\tedx,eax\n");
printf("\tcmp\tecx,edx\n");
if (iSize > LARGE_ITEM)
printf("\tja\tshort L%u\n\n", iNextSize = gen_LabelCount++);
else {
printf("\tja\tINVP_%s\t\t\t;jmp if too long\n",
pGlobal_From->pchFunctionName);
pGlobal_From->fInvalidParam = 1;
}
printf(";Create Linear Alias to item\n");
printf("\tlea\tedi,[ebp-%u]\t\t;Temp storage\n",
pFrom->iTempOffset);
printf("\tcall\tThk32AliasMem\n");
printf("\tor\teax,eax\n");
printf("\tjnz\tNOMEM_%s\n\n",
pGlobal_From->pchFunctionName);
/*
* Eligable for linear alias.
*/
pFrom->fTempAlloc |= ALLOC_ALIAS;
printf("\tor\t%s PTR[ebp-%u],%lu\t\t;Set Alias Flag\n",
(pFrom->iPointerNumber >7)?"DWORD":"BYTE",
iAliasOffset, (long) 1 << pFrom->iPointerNumber);
printf("\tmov\tedi,[ebp-%u]\n", pFrom->iTempOffset);
printf("\tjmp\tshort L%u\n", iNoCopyLabel);
}
if (iSize > LARGE_ITEM) {
printf("\nL%u:\n", iNextSize);
printf(";Allocate Buffer to copy Data\n");
printf("\tlea\teax,[ebp-%u]\t\t;Buffer for address\n",
pFrom->iTempOffset);
printf("\tpush\teax\n");
printf("\tpush\tecx\n");
printf("\tpush\t%u\t\t;Allocation Flags\n",
gDosAllocFlags);
printf("\tcall\tDos32AllocMem\n");
printf("\tadd\tesp,12\n");
printf("\tor\teax,eax\n");
printf("\tjnz\tNOMEM_%s\n\n",
pGlobal_From->pchFunctionName);
pFrom->fTempAlloc |= ALLOC_MEMORY; /* Eligable for memory */
}
}
printf("\nL%u:\t\t\t;Variable Length Copy\n", iCopyLabel);
if (pFrom->fSemantics & SEMANTIC_INPUT)
cod32_VariableLengthCopy();
else
printf("\n;Item semantics are NOT input\n");
printf("\nL%u:\t\t\t;Variable Length No Copy\n", iNoCopyLabel);
}
}
/*** cod32_HandleFixedSize(iSize,pFrom)
*
* This worker routine to HandleBoundaryCrossing will output code
* to handle fixed size items that cross boundaries.
*
* Entry: iSize is the size of the item.
* pFrom is the typenode.
*
* Exit: boundary crossing code is generated.
*/
void
cod32_HandleFixedSize(unsigned int iSize,
TypeNode *pFrom)
{
if (!iSize)
fatal("cod32_HandleFixedSize: iSize = 0 \n");
if (iSize <= SMALL_ITEM) {
pFrom->fTempAlloc |= ALLOC_STACK; /* Eligable for stack alloc*/
printf("; Allocate space on stack\n");
printf("\tsub\tesp,%u\t\t\t;Alloc Mem\n", typ_FullSize(pFrom));
printf("\tand\tesp,0FFFFFFFCh\t\t;DWORD align\n");
printf("\tmov\tedi,esp\t\t\t;Points to new data area\n");
printf("\tmov\t[ebp-%u],edi\n", pFrom->iTempOffset);
}
else if (iSize <= MEDIUM_ITEM) {
printf("; Allocate space in BMP area\n");
printf(";Need block allocation\n");
printf(";Generate Allocation Call\n");
printf("\tcall\tThk32AllocBlock\n");
printf("\tor\teax,eax\n");
printf("\tjnz\tNOMEM_%s\n\n",
pGlobal_From->pchFunctionName);
printf("\tmov\t[ebp-%u],edi\n", pFrom->iTempOffset);
}
else if (iSize <= LARGE_ITEM) {
printf(";Create Linear Alias to item\n");
printf("\tlea\tedi,[ebp-%u]\t\t;Temp storage\n",
pFrom->iTempOffset);
printf("\tmov\tecx,%u\t\t;Length\n", typ_FullSize(pFrom));
printf("\tcall\tThk32AliasMem\n");
printf("\tor\teax,eax\n");
printf("\tjnz\tNOMEM_%s\n\n",
pGlobal_From->pchFunctionName);
/*
* If the item was aliased, then we return here to avoid the copy
* code at the end of this routine.
*/
printf(";Aliased: no copy required\n");
return;
}
else {
fprintf(stderr, "Fixed sized item > 60k\n");
printf(".err Fixed sized item > 60k\n");
}
if (pFrom->fSemantics & SEMANTIC_INPUT)
cod32_TransferBlock(iSize);
else
printf("\n;Semantics are NOT input\n");
}
/*** cod32_AllocateVariableSize(pFrom,iSize)
*
* This routine generates the code to allocate memory based
* on the size of the item.
*
* Entry: pFrom is the typenode.
* iSize is the size of the item.
*
* Exit: memory allocation code is generated.
*/
cod32_AllocateVariableSize(TypeNode *pFrom,
unsigned int iSize)
{
unsigned int templabel;
if (pGlobal_To->fInlineCode) {
if (iSize == 0)
iSize--; /** Make iSize huge **/
printf("\n;Variable Size Memory Allocator\n");
printf(";Allocate ECX bytes of memory\n");
printf("\tcmp\tecx,%u\n", SMALL_ITEM);
if (iSize >= MEDIUM_ITEM)
printf("\tja\tshort L%u\n\n", iNextSize = gen_LabelCount++);
else {
printf("\tja\tINVP_%s\t\t\t;jmp if too long\n",
pGlobal_From->pchFunctionName);
pGlobal_From->fInvalidParam = 1;
}
printf("; Allocate space on stack\n");
pFrom->fTempAlloc |= ALLOC_STACK; /* Eligable for stack alloc */
printf("\tsub\tesp,ecx\t\t\t;Alloc Mem\n");
printf("\tand\tesp,0FFFFFFFCh\t\t;DWORD align\n");
printf("\tmov\tedi,esp\t\t\t;Points to new data area\n");
printf("\tmov\t[ebp-%u],edi\n", pFrom->iTempOffset);
printf("\tor\t%s PTR [ebp-%u],%lu\t\t;Set Stack Alloc Flag\n",
(pFrom->iPointerNumber >7)?"DWORD":"BYTE",
iAllocOffset, (long) 1 << pFrom->iPointerNumber);
if (iSize >= MEDIUM_ITEM)
{
iCopyLabel = gen_LabelCount++;
printf("\tjmp\tshort L%u\n", iCopyLabel);
printf("\nL%u:\n", iNextSize);
printf("\tcmp\tecx,%u\n", MEDIUM_ITEM);
if (iSize >= LARGE_ITEM)
printf("\tja\tshort L%u\n\n", iNextSize = gen_LabelCount++);
else {
printf("\tja\tINVP_%s\t\t\t;jmp if too long\n",
pGlobal_From->pchFunctionName);
pGlobal_From->fInvalidParam = 1;
}
printf("; Allocate space in BMP area\n");
printf("\tcall\tThk32AllocBlock\n\n");
pFrom->fTempAlloc |= ALLOC_BMP; /* Eligable for BMP alloc*/
printf("\tmov\t[ebp-%u],edi\n", pFrom->iTempOffset);
printf("\tor\t%s PTR [ebp-%u],%lu\t\t;Set BMP Alloc Flag\n",
(pFrom->iPointerNumber >7)?"DWORD":"BYTE",
iBMPOffset, (long) 1 << pFrom->iPointerNumber);
}
if (iSize >= LARGE_ITEM) {
printf("\tjmp\tshort L%u\n\n", iCopyLabel);
printf("\nL%u:\n", iNextSize);
printf(";Allocate Buffer to copy Data\n");
printf("\tlea\teax,[ebp-%u]\t\t;Buffer for address\n",
pFrom->iTempOffset);
printf("\tpush\teax\n");
printf("\tpush\tecx\n");
printf("\tpush\t%u\t\t;Allocation Flags\n", gDosAllocFlags);
printf("\tcall\tDos32AllocMem\n");
printf("\tadd\tesp,12\n");
printf("\tor\teax,eax\n");
printf("\tjnz\tNOMEM_%s\n\n",
pGlobal_From->pchFunctionName);
pFrom->fTempAlloc |= ALLOC_MEMORY;/* Eligable for memory */
}
if (iSize >= MEDIUM_ITEM)
printf("\nL%u:\n", iCopyLabel);
}
else {
/*
* Generate a call to do the allocation. This calls a routine
* in the thunk runtime code.
*/
printf("\n;Generate call to allocate ECX bytes\n");
printf("\n\tcall\tThk32AllocVarLen\n");
templabel = gen_LabelCount++;
printf("\tor\teax,eax\t\t;Test error condition\n");
printf("\tjnz\tNOMEM_%s\n\n",
pGlobal_From->pchFunctionName);
printf("\n\tor\tedx,edx\n");
printf("\tjb\tshort L%u\t\t;Jump if DosAllocMem\n\n",templabel);
printf("\tlea\teax,[ebp-%u]\n", iBMPOffset);
printf("\tor\t%s PTR[eax+edx*4],%lu\t\t;Set alloc flag\n",
(pFrom->iPointerNumber >7)?"DWORD":"BYTE",
(long) 1 << pFrom->iPointerNumber );
printf("\nL%u:\n\n", templabel);
}
}
/*** cod32_AllocFixedSize(iSize)
*
* Emits code that allocates a fixed size buffer.
*
* The rule shall be:
* size <= SMALL_ITEM Allocate space on stack
* size <= MEDIUM_ITEM Allocate a block from BMP package
* size <= LARGE_ITEM Allocate an object using DosAllocMem
* size > LARGE_ITEM Error case: Not handled.
*
* Entry: iSize is length of buffer needed.
*
* Exit: Code will put address of new buffer in edi.
*/
cod32_AllocFixedSize(unsigned int iSize,
TypeNode *pFrom)
{
pFrom->fTempAlloc |= ALLOC_FIXED; /* Always allocates a fixed size item */
if (iSize <= SMALL_ITEM) {
printf( "; Allocate space on stack\n");
printf( "\tsub\tesp,%u\t\t\t;Alloc Mem\n", iSize);
printf( "\tand\tesp,0FFFFFFFCh\t\t;DWORD align\n");
printf( "\tmov\tedi,esp\t\t\t;Points to new data area\n");
printf( "\tmov\t[ebp-%u],edi\n", pFrom->iTempOffset);
printf( "\tmov\tesi,[ebp+%u]\n", pFrom->iOffset);
} else if (iSize <= MEDIUM_ITEM) {
printf( ";Need block allocation\n");
printf( ";Generate Allocation Call\n");
//printf("\tcall\tThk32AllocBlock\n");
printf( "\tmov\tecx,%u\n", iSize);
printf( "\tcall\tAllocBuff\n");
//printf("\tor\teax,eax\n");
//printf("\tjnz\tNOMEM_%s\n\n", pGlobal_From->pchFunctionName);
printf( "\tmov\t[ebp-%u],eax\t\t;16:16 address\n", pFrom->iTempOffset);
printf( "\tmov\tedi,edx\t\t;32-bit address\n");
printf( "\tmov\tesi,DWORD PTR [ebp+%u]\t\t;parameter\n", pFrom->iOffset);
} else {
cod_NotHandled( "Very Large Static Buffer Needed");
}
#if 0
else if (iSize <= LARGE_ITEM) {
printf(";Allocate memory using system call\n\n");
printf("\tpush\t%u\t\t;Allocation Flags\n", gDosAllocFlags);
printf("\tpush\t%u\t\t;# of bytes to allocate\n", iSize);
printf("\tlea\teax,[ebp-%u]\t\t;Buffer for address\n",
pFrom->iTempOffset);
printf("\tpush\teax\n");
printf("\tcall\tDos32AllocMem\n");
printf("\tadd\tesp,12\n");
printf("\tor\teax,eax\n");
printf("\tjnz\tNOMEM_%s\n\n", pGlobal_From->pchFunctionName);
printf("\tmov\tedi,[ebp-%u]\n", pFrom->iTempOffset);
}
else {
printf(".err ***** Very Large Static Buffer Needed *****\n\n");
fprintf(stderr, "warning: Very Large Static Buffer Needed *****\n\n");
}
#endif
}
/*** cod32_DeAllocFixedSize(iSize)
*
* Emits code the deallocates a fixed size buffer.
*
* The rule shall be:
* size <= SMALL_ITEM Deallocate space on stack
* size <= MEDIUM_ITEM Deallocate a block from BMP package
* size <= LARGE_ITEM Deallocate an object using DosAllocMem
* size > LARGE_ITEM Error case: Not handled.
*
* Entry: iSize is length of buffer to deallocate
* edi assumed to have address of allocated memory
*
* Exit: Code will put address of new buffer in edi.
*/
cod32_DeAllocFixedSize(unsigned int iSize,
TypeNode *pFromNode)
{
if (iSize <= SMALL_ITEM) {
printf("\n;Stack allocated memory deallocated implicitly\n");
}
else if (iSize <= MEDIUM_ITEM) {
printf(";Need block dallocation\n");
printf("\tmov\tesi,[ebp-%u]\n", pFromNode->iTempOffset);
printf("\tcall\tThk32FreeBlock\n\n");
}
else if (iSize <= LARGE_ITEM) {
printf(";Deallocate memory using system call\n\n");
printf("\tpush\tDWORD PTR [ebp-%u]\n", pFromNode->iTempOffset);
printf("\tcall\tDos32FreeMem\n");
printf("\tadd\tesp,4\n\n");
}
else {
printf(".err ***** Very Large Static Buffer dealloc *****\n\n");
fprintf(stderr, "warning: Very Large Static Buffer dealloc *****\n\n");
}
}
/*** cod32_CopyConvert(pFrom,pTo)
*
* This routine generates the copy and conversion code.
*
* Entry: pFrom and pTo are the typenodes to use.
*
* Exit: copy/convert code is generated.
*/
void
cod32_CopyConvert(TypeNode *pFromNode,
TypeNode *pToNode)
{
unsigned int iEDI, iESI;
unsigned int JumpLabel;
/*
* If it is a NULL type, then complete transfer, output a NULL
* type error, and realign the data pointers after the NULLTYPES.
*/
if (pFromNode->iBaseType == TYPE_NULLTYPE) {
/*
* Terminate Transfer Block.
*/
cod32_TransferBlock(gTransferBytes);
gTransferBytes = 0;
printf("\n;%d NULLTYPE(S)\n", pFromNode->iArraySize);
printf("\n\t.err **** NULLTYPE ****\n\n");
printf("\n\n;Move registers past NULLTYPE\n");
cod_AdjustReg("esi", &gESI, pFromNode->iStructOffset + typ_FullSize(pFromNode));
cod_AdjustReg("edi", &gEDI, pToNode->iStructOffset + typ_FullSize(pToNode));
return;
}
/*
* If types are equal, then no conversion needed.
* If no conversion is needed, then the bytes from the source can be copied
* directly to the destination. Therefore, we just collect the bytes into
* a 'pseudo buffer'. When we finally reach the point where a conversion
* is needed, or we run off the end of the base structure, we will emit
* a block copy of the appropriate number of bytes.
*/
if (pToNode->iBaseType == pFromNode->iBaseType) {
printf(";Add %u bytes of %s to transfer\n",
typ_FullSize(pToNode), pToNode->pchBaseTypeName);
gTransferBytes += typ_FullSize(pToNode);
return;
}
/*
* Here, we have determined that the two types are not compatible.
* Therefore, we are going to do a conversion.
*
* Complete pending transfer.
*/
cod32_TransferBlock(gTransferBytes);
gTransferBytes = 0;
/*
* Sanity check: offsets must be correct.
*/
if ((pFromNode->iStructOffset != gESI) ||
(pToNode->iStructOffset != gEDI))
{
fprintf(stderr, "cod_CopyConvert: Incorrect offset\n");
printf(".err cod_CopyConvert: Incorrect offset\n");
}
/*
* If item is an array, then setup loop.
*/
if (pFromNode->iArraySize > 1) {
JumpLabel = gen_LabelCount++;
printf("\n\tmov\tecx,%u\n", pFromNode->iArraySize);
printf("\nL%u:\n", JumpLabel);
}
/*
* Convert for specific types.
*/
switch (pFromNode->iBaseType)
{
case TYPE_UCHAR: /* USHORT --> ULONG */
printf("\n;UCHAR --> ULONG\n\n");
printf("\tmovzx\teax,BYTE PTR[esi]\n");
printf("\tmov\t[edi],eax\n");
break;
case TYPE_SHORT: /* SHORT --> LONG */
printf("\n;SHORT --> LONG\n\n");
printf("\tmovsx\teax,WORD PTR[esi]\n");
printf("\tmov\t[edi],eax\n");
break;
case TYPE_USHORT: /* USHORT --> ULONG */
printf("\n;USHORT --> ULONG\n\n");
printf("\tmovzx\teax,WORD PTR[esi]\n");
printf("\tmov\t[edi],eax\n");
break;
case TYPE_LONG: /* LONG --> SHORT */
printf("\n;LONG --> SHORT\n\n");
printf("\tmov\teax,DWORD PTR [esi]\n");
printf("\tmov\tWORD PTR [edi],ax\n");
break;
case TYPE_ULONG: /* ULONG --> USHORT */
printf("\n;ULONG --> USHORT\n\n");
printf("\tmov\teax,DWORD PTR [esi]\n");
if (pGlobal_From->fSemantics & SEMANTIC_TRUNC) {
printf("\tcmp\teax,0ffffh\n");
printf("\tja\tINVP_%s\n\n", pGlobal_From->pchFunctionName);
pGlobal_From->fInvalidParam = 1;
}
printf("\tmov\tWORD PTR [edi],ax\n");
break;
default:
fatal("cod32_CopyConvert: Tried converted %d to %d",
pFromNode->iBaseType, pToNode->iBaseType);
}
/*
* If data types is array, finish off loop.
*/
if (pFromNode->iArraySize > 1) {
iESI = gESI;
iEDI = gEDI;
cod_AdjustReg("esi", &iESI, gESI + pFromNode->iBaseDataSize);
cod_AdjustReg("edi", &iEDI, gEDI + pToNode->iBaseDataSize);
printf("\tloop\tL%u\n\n", JumpLabel);
gESI += typ_FullSize(pFromNode);
gEDI += typ_FullSize(pToNode);
}
else {
/*
* Adjust registers.
*
* When CopyConvert is done as part of a structure copy, then there
* are times when we can skip the adjustment of the registers in
* this case. The only other time CopyConvert is called is during
* a buffer transfer, in which case we don't really care about the
* registers after the copy convert is complete. Therefore, this
* code has been commented out, and moved into the RepackElements
* routine. This enables the Repack routine to adjust the registers
* only when needed.
*
* The fReAlignmentNeeded flag will indicate to the RepackElements
* routine that the current register values are incorrect, and need
* to be updated.
*/
fReAlignmentNeeded = 1;
}
}
/*** cod32_TransferBlock(Count)
*
* This routine will emit code for copying Count bytes of data from
* the current ESI to the current EDI. ESI and EDI will be adjusted to
* the first byte after the copy. This copy routine will produce a
* fixed size copy routine that has been optimized for speed.
*
* Entry: ESI and EDI must be setup to have the source and destination
* addresses.
* Count is the umber of bytes to copy.
*
* Exit: gESI and gEDI will be incremented by Count.
* Code for copy will be written.
*
* Note:
* If Count is 0, this routine returns without changing anything.
*/
void
cod32_TransferBlock(int Count)
{
int iRep;
if (!Count)
return;
printf("\n;Transfer %u bytes\n", Count);
iRep = Count / 4;
if (iRep > 1) {
printf("\n\tmov\tecx,%u\n", iRep);
printf("\trep");
}
if (iRep)
printf("\tmovsd\n");
iRep = Count % 4;
if (iRep > 1) {
printf("\tmovsw\n");
iRep -= 2;
}
if (iRep)
printf("\tmovsb\n");
gEDI += Count;
gESI += Count;
}
/*** cod32_VariableLengthCopy()
*
* Emits code for a variable length copy. Assumes that the source address
* is loaded into ESI, destination into EDI, and count of bytes into ECX
*
* Entry: none
*
* Exit: variable length copy code is generated.
*/
cod32_VariableLengthCopy()
{
if (pGlobal_To->fInlineCode) {
printf("\n; Copy ECX bytes from ESI to EDI\n");
printf("\tmov\teax,3\n");
printf("\tand\teax,ecx\n");
printf("\tshr\tecx,2\n");
printf("\trep movsd\n");
printf("\tmov\tecx,eax\n");
printf("\trep movsb\n\n");
}
else {
printf("\n; Copy ECX bytes from ESI to EDI\n");
printf("\tcall\tTHK32COPYBLOCK\n");
}
}
/*** cod_CallFrame32
*
* This function prints out the call frame assembly code for the 32-bit
* routine.
*
* Entry: pMNode is the pointer to a MapNode.
*
* Exit: call frame code is generated.
*
* History:
* 28-Nov-1988 JulieB Created it.
*/
cod_CallFrame32(MapNode *pMNode)
{
int i;
TypeNode *pFrom, *pTo;
unsigned int uiRetLabel;
pFrom = pMNode->pFromNode->ReturnType;
pTo = pMNode->pToNode->ReturnType;
if (fBPFrame)
printf("\n\n;******* Break Point\n\n\tint\t3\n\n\n");
/*
* Save the stack.
*/
printf(";* Create new call frame, using 16-bit semantics.\n\n");
if( typ_QuerySemanticsUsed( pMNode, SEMANTIC_LOCALHEAP)) {
printf( "\n\tpush\tds\t\t\t;16-bit will use local heap\n");
}
/*
* If SysCall, then the ToNode follows the System calling convention
* of saving ES. Therefore, we can skip the save.
*/
if (!pMNode->pToNode->fSysCall) {
printf("\tpush\tes\n");
printf("\tpush\tebx\n");
}
printf("\tpush\tebp\t\t\t; save ebp\n");
printf("\tmov\teax,esp\t\t\t; save current esp\n");
printf("\tpush\tss\n");
printf("\tpush\teax\n\n");
/*
* Convert and push all parameters as needed.
*/
//cod_PushParameters32( pMNode->pFromNode->ParamList,
// pMNode->pToNode->ParamList);
cod32_PushParametersGDI( pMNode->pFromNode->ParamList,
pMNode->pToNode->ParamList);
//if (fCombined) {
// printf("\n\t\t\t;Generic Routine: get function number into ecx\n");
// printf("\tmov\tecx,[ebp-%u]\n",iCombinedOffset);
//}
/*
* Convert SS:ESP to 16-bit SS:SP.
*/
printf("\n;* Convert SS:ESP to 16-bit SS:SP.\n\n");
#if 0
printf("\tmov\tax,WORD PTR STACK16SELECTOR\n");
printf("\tpush\tax\n");
printf("\tmov\teax,esp\n");
printf("\tsub\teax,DWORD PTR STACK16INITIALOFFSET\n");
printf("\tpush\teax\n");
printf("\tcall\tSETSELECTORBASE32\n\n");
#endif
#if 0
printf( "\tmov\tbx,WORD PTR STACK16SELECTOR\n");
printf( "\tmov\teax,esp\n");
printf( "\tsub\teax,DWORD PTR STACK16INITIALOFFSET\n");
printf( "\tmov\tecx,eax\n");
printf( "\tcall\tSetSelBase32\n\n");
//LATER: test for error
#endif
if (fCombined) {
printf( "\tmov\tecx,[ebp-%u]\t;Generic Routine: "
"get function number into ecx\n\n", iCombinedOffset);
}
printf( "\tpush\tesp\n");
printf( "\tlea\teax,[ebp-%u]\n", iStackThunkIDOffset);
printf( "\tpush\teax\t\t\t;address of stack thunk id\n");
printf( "\tcall\tGetStack32\n");
printf( "\tmov\tedx,eax\n");
printf( "\tror\tedx,16\n");
printf( "\tmov\tss,dx\n");
printf( "\tmov\tsp,ax\n");
#if 0
printf("\tmov\tax,WORD PTR STACK16SELECTOR\n");
printf("\tpush\tax\n");
printf("\tmov\teax,DWORD PTR STACK16INITIALOFFSET\n");
printf("\tpush\tax\n");
printf("\tlss\tsp,[esp]\n");
#endif
if( typ_QuerySemanticsUsed( pMNode, SEMANTIC_LOCALHEAP)) {
printf( "\tmov\tds,DS16LOCALHEAPSELECTOR\t\t;ds for local heap\n");
}
if (fBPCall)
printf("\n\n;******* Break Point\n\n\tint\t3\n\n\n");
/*
* Jump to 16-bit segment to issue call.
*/
printf("\n;* Jump to 16-bit segment to issue call");
printf(" (so that 16-bit API can RETF).\n");
printf(";* The following two lines are the same as:\n");
printf("; \tjmp\tFAR PTR T_%s\n", pMNode->pToNode->pchFunctionName);
printf("; but they trick masm into not generating nops.\n\n");
printf("\tdb\t66h,0eah\n");
printf("\tdw\toffset T_%s, seg T_%s\n\n",
pMNode->pToNode->pchFunctionName, pMNode->pToNode->pchFunctionName);
if (fCombined) {
MapNode *combnode;
combnode = pMNode->pFamily;
i = 1;
printf("\n;The following are entry points for routines that");
printf("\n;have the same semantics and parameters.\n\n");
for (;combnode;combnode=combnode->pNextMapping) {
printf("%s:\n", combnode->pFromNode->pchFunctionName);
//printf("\tpush\t%u\n",i++);
//printf("\tpop\teax\n");
printf("\tmov\teax,%u\n",i++);
printf("\tjmp\tC_%s\n\n", pMNode->pFromNode->pchFunctionName);
}
}
uiRetLabel = gen_LabelCount++;
/*
* Only print out the invalid parameter code if it was used.
* The fInvalidParam flag is set if the label is needed.
*/
if (pMNode->pFromNode->fInvalidParam) {
printf("\nINVP_%s:\n", pMNode->pFromNode->pchFunctionName);
if (fBPCall)
printf("\n\n;******* Break Point\n\n\tint\t3\n\n\n");
if( pMNode->pFromNode->ulErrBadParam) {
printf("\tmov\teax,%lu\n",pMNode->pFromNode->ulErrBadParam);
//printf("\tpush\tDWORD PTR %lu\n",pMNode->pFromNode->ulErrBadParam);
//printf("\tpop\teax\n");
} else {
printf("\txor\teax,eax\n");
}
/*
* If iErrorOffset is zero, then there was no space allocated for it.
* Therefore, only set the error flag if iErrorOffset != 0
*/
if (iErrorOffset)
printf("\tmov\tBYTE PTR [ebp-%u],1\t\t;Set flag\n", iErrorOffset);
printf("\tjmp\tshort L%u\n", uiRetLabel);
}
#if 0
if (pMNode->pFromNode->iPointerCount) {
if (pMNode->pFromNode->fErrUnknown) {
printf("\nERR_%s:\n", pMNode->pFromNode->pchFunctionName);
printf("\tmov\teax,%lu\n",pMNode->pFromNode->fErrUnknown);
printf("\tjmp\tshort L%u\n", gen_LabelCount);
}
printf("\nNOMEM_%s:\n", pMNode->pFromNode->pchFunctionName);
if (fBPCall)
printf("\n\n;******* Break Point\n\n\tint\t3\n\n\n");
printf("\tpush\t%lu\n",pMNode->pFromNode->ulErrNoMem);
printf("\tpop\teax\n");
if (!pMNode->pFromNode->fErrUnknown)
printf("\nERR_%s:\n", pMNode->pFromNode->pchFunctionName);
printf("\tmov\tBYTE PTR [ebp-%u],1\t\t;Set flag\n", iErrorOffset);
printf("\tjmp\tshort L%u\n", gen_LabelCount);
}
#endif
printf("\nR_%s:\t\t\t\t; label defining return jmp location\n",
pMNode->pToNode->pchFunctionName);
if (fBPCall)
printf("\n\n;******* Break Point\n\n\tint\t3\n\n\n");
/*
* Restore 32-bit SS:ESP.
*/
printf("\n\n;* Restore 32-bit SS:ESP - it is on top of stack.\n\n");
printf("\tmovzx\tebx,sp\t\t\t;esp may have garbage in hi word\n");
printf("\tlss\tesp,ss:[ebx]\n");
printf("\tpop\tebp\n");
if (!pMNode->pToNode->fSysCall) {
printf("\tpop\tebx\n");
printf("\tpop\tes\n\n");
}
if( typ_QuerySemanticsUsed( pMNode, SEMANTIC_LOCALHEAP)) {
printf( "\tpop\tds\n");
}
/*
* Convert return code into proper value to be returned in EAX.
*/
printf("\n;Convert Return Code\n");
/*
* If the return code is a pointer, then convert the pointer to
* 0:32 on the way out.
*/
if (pFrom->iPointerType) {
printf(";Return type is a pointer\n");
printf(";Convert 16:16 to 0:32\n\n");
printf("\trol\teax,16\n");
printf("\tmov\tax,dx\n");
printf("\trol\teax,16\n");
printf("\tcall\tSelToFlat\n");
}
else {
switch (pFrom->iBaseType)
{
case TYPE_LONG:
switch (pTo->iBaseType)
{
case TYPE_LONG:
printf(";LONG --> LONG\n");
printf("\trol\teax,16\n");
printf("\tmov\tax,dx\n");
printf("\trol\teax,16\n");
break;
case TYPE_SHORT:
printf(";SHORT --> LONG\n");
printf("\tmovsx\teax,ax\n");
break;
}
break;
case TYPE_ULONG:
switch (pTo->iBaseType)
{
case TYPE_ULONG:
printf(";ULONG --> ULONG\n");
printf("\trol\teax,16\n");
printf("\tmov\tax,dx\n");
printf("\trol\teax,16\n");
break;
case TYPE_USHORT:
printf(";USHORT --> ULONG\n");
printf("\tmovzx\teax,ax\n");
break;
case TYPE_UCHAR:
printf(";UCHAR --> ULONG\n");
printf("\tmovzx\teax,al\n");
break;
}
if( pTo->fSemantics & SEMANTIC_LOCALHEAP) {
printf( "\tor\teax,eax\n");
printf( "\tjz\tL%u\t\t;skip conversion if null\n",
uiRetLabel);
printf( "\tadd\teax,DS16LOCALHEAPBASE\n");
}
break;
default:
printf("\n;Return type maps directly.\n");
}
}
printf("L%u:\n", uiRetLabel);
if (pMNode->pFromNode->iPointerCount) {
printf(";Functions contain pointers, save return code\n");
printf("\tmov\t[ebp-%u],eax\t\t;Save return code\n", iReturnValOffset);
}
}
/*** cod_PushParameters32
*
* This function generates the code that pushes the 32-bit parameters
* onto the stack.
*
* Entry: pFromNode - pointer to the 32-bit function's parameter list.
* pToNode - pointer to the 16-bit function's parameter list.
*
* Exit: generates the code that pushes the 32-bit parameters.
*
* History:
* 29-Nov-1988 JulieB Created it.
*/
cod_PushParameters32(TypeNode *pFromNode,
TypeNode *pToNode)
{
int iStackOffset = DWORD_SIZE; /* offset to temp storage on stack */
unsigned int AllowLabel;
int fRestricted;
/*
* For each parameter, convert and push as needed.
*/
while (pFromNode) {
fRestricted = (pFromNode->fSemantics & SEMANTIC_RESTRICT);
printf("\n\n\t;From Name: %s Type: %s\n",
typ_NonNull(pFromNode->pchIdent),
typ_NonNull(pFromNode->pchBaseTypeName));
if (pFromNode->iBaseType == TYPE_NULLTYPE)
printf("\n\t.err **** NULLTYPE ****\n\n");
else if (pFromNode->iDeleted) {
/* If the iDeleted flag is set in the pFromNode, then this
* parameter does not exist in the original call frame.
* Therefore, we need to push a zero of the appropriate length.
*/
printf("\n;Extra parameter needed: Push a zero\n");
switch (pToNode->iBaseType)
{
case TYPE_UCHAR:
printf("\tpush\tBYTE PTR %u\t\t;Push u/byte\n",
pFromNode->iFillValue);
break;
case TYPE_SHORT:
case TYPE_USHORT:
printf("\tpush\tWORD PTR %u\t\t;Push u/short\n",
pFromNode->iFillValue);
break;
case TYPE_LONG:
case TYPE_ULONG:
printf("\tpush\t%u\t\t;Push U/LONG\n",
pFromNode->iFillValue);
break;
default:
fprintf(stderr, "\nInvalid type for DELETED\n");
printf("\n.err Invalid type for DELETED\n");
}
}
else if (pToNode->iDeleted) {
printf("\n;Parameter not needed in callee\n");
if (fRestricted)
cod32_HandleRestricted(pFromNode);
}
else {
switch (pFromNode->iPointerType)
{
case TYPE_NEAR32:
if (pToNode->iPointerType == TYPE_FAR16) {
printf("\tmov\teax,DWORD PTR [ebp-%u]\n",
pFromNode->iTempOffset);
printf("\tor\teax,eax\n");
printf("\tjz\tshort L%u\t\t\t;NULL pointer\n\n",
gen_LabelCount);
printf("\tror\teax,16\t\t\t; CRMA on structure pointer\n");
printf("\tshl\tax,3\n");
printf("\tor\tal,dl\n");
printf("\trol\teax,16\n");
printf("L%u:\tpush\teax\n\n", gen_LabelCount++);
}
else
printf("\tpush\tDWORD PTR [ebp-%u]\n", pFromNode->iTempOffset);
break;
case TYPE_FAR16:
if (pToNode->iPointerType == TYPE_NEAR32) {
printf("\tmov\teax,DWORD PTR [ebp-%u]\n",
pFromNode->iTempOffset);
printf("\tor\teax,eax\n");
printf("\tjz\tshort L%u\t\t\t;NULL pointer\n\n",
gen_LabelCount);
printf("\tror\teax,16\t\t\t; CRMA on structure pointer\n");
printf("\tshr\tax,3\n");
printf("\trol\teax,16\n");
printf("L%u:\tpush\teax\n\n", gen_LabelCount++);
}
else
printf("\tpush\tDWORD PTR [ebp-%u]\n", pFromNode->iTempOffset);
break;
/* If it wasn't one of the pointer types above, then it must
* be a non pointer parameter. Thus, it will be a long,
* short, ulong, ushort, or char.
*/
default:
/* If types are equal, then no conversion needed.
* If no conversion is needed, then just push the item
* onto new call frame. If conversion is needed, then
* use switch statement to emit the correct conversion.
*/
if (pToNode->iBaseType == pFromNode->iBaseType) {
if (pFromNode->iBaseDataSize <= WORD_SIZE) {
if (fRestricted) {
printf("\tmovzx\teax,WORD PTR [ebp+%u]\t; To: %s\n",
pFromNode->iOffset, pToNode->pchBaseTypeName);
cod32_HandleRestricted(pFromNode);
printf("\n\tpush\tax\n");
} else {
printf("\tpush\tWORD PTR [ebp+%u]\t; To: %s\n",
pFromNode->iOffset, pToNode->pchBaseTypeName);
}
}
else {
if (fRestricted) {
printf("\tmov\teax,[ebp+%u]\t; To: %s\n",
pFromNode->iOffset, pToNode->pchBaseTypeName);
cod32_HandleRestricted(pFromNode);
printf("\n\tpush\teax\n");
}
else {
printf("\tpush\tDWORD PTR [ebp+%u]\t; To: %s\n",
pFromNode->iOffset, pToNode->pchBaseTypeName);
}
}
}
else {
switch (pFromNode->iBaseType)
{
case TYPE_UCHAR: /* UCHAR --> ULONG */
printf("\tmovzx\teax,BYTE PTR[ebp+%u]\t;",
pFromNode->iOffset);
cod32_HandleRestricted(pFromNode);
printf("To: %s\n", pToNode->pchBaseTypeName);
printf("\tpush\teax\n");
break;
case TYPE_SHORT: /* SHORT --> LONG */
printf("\tmovsx\teax,WORD PTR[ebp+%u]\t;",
pFromNode->iOffset);
cod32_HandleRestricted(pFromNode);
printf("To: %s\n", pToNode->pchBaseTypeName);
printf("\tpush\teax\n");
break;
case TYPE_USHORT: /* USHORT --> ULONG */
printf("\tmovzx\teax,WORD PTR[ebp+%u]\t;",
pFromNode->iOffset);
cod32_HandleRestricted(pFromNode);
printf("To: %s\n", pToNode->pchBaseTypeName);
printf("\tpush\teax\n");
break;
case TYPE_LONG: /* LONG --> SHORT */
printf("\tmov\teax,[ebp+%u]\n", pFromNode->iOffset);
if (fRestricted) {
cod32_HandleRestricted(pFromNode);
}
else {
if (pGlobal_From->fSemantics & SEMANTIC_TRUNC) {
if (pFromNode->AllowList) {
AllowLabel = gen_LabelCount++;
cod32_HandleAllowList(pFromNode->AllowList,
AllowLabel);
}
printf("\tmovsx\tecx,ax\n");
printf("\tcmp\teax,ecx\n");
printf("\tjne\tINVP_%s\t\t;\n\n",
pGlobal_From->pchFunctionName);
pGlobal_From->fInvalidParam = 1;
if (pFromNode->AllowList)
printf("L%u:",AllowLabel);
}
}
printf("\tpush\tax\t;To:%s\n",pToNode->pchBaseTypeName);
break;
case TYPE_ULONG: /* ULONG --> USHORT */
printf("\tmov\teax,[ebp+%u]\n", pFromNode->iOffset);
if (fRestricted) {
cod32_HandleRestricted(pFromNode);
}
else {
if (pGlobal_From->fSemantics & SEMANTIC_TRUNC) {
if (pFromNode->AllowList) {
AllowLabel = gen_LabelCount++;
cod32_HandleAllowList(pFromNode->AllowList,
AllowLabel);
}
printf("\tcmp\teax,0ffffh\n");
printf("\tja\tINVP_%s\n\n",
pGlobal_From->pchFunctionName);
pGlobal_From->fInvalidParam = 1;
if (pFromNode->AllowList)
printf("L%u:",AllowLabel);
}
}
printf("\tpush\tax\t\t;To:%s\n",pToNode->pchBaseTypeName);
break;
default:
fatal("cod_PushParameters32: Tried converted %d to %d",
pFromNode->iBaseType, pToNode->iBaseType);
}
}
}
}
pToNode = pToNode->pNextNode;
pFromNode = pFromNode->pNextNode;
}
}
/*** cod_Return32
*
* This function prints out the return assembly code for the 32-bit
* routine.
*
* Entry: pMNode is the pointer to a MapNode.
*
* Exit: 32-bit routine code is generated.
*
* History:
* 28-Nov-1988 JulieB Created it.
*/
cod_Return32(MapNode *pMNode)
{
/*
* Exit the routine.
*/
printf(";* 32-bit return code.\n\n");
if (fBPExit)
printf("\n\n;******* Break Point\n\n\tint\t3\n\n\n");
if (pMNode->pFromNode->iPointerCount) {
printf("\tlea\tesp,[ebp-%u]\n", iSavedRegOffset);
printf("\tpop\tedi\n");
printf("\tpop\tesi\n");
printf("\tpop\teax\t\t\t;Pop saved return code\n");
}
printf("\tleave\t\t\t\t; Remove local variables\n\n");
#if 0
printf( "\txor\tedx,edx\n");
printf( "\txchg\tedx,%s\t\t;release semaphore\n", pszGDISemName);
printf( "SEMEXIT_%s:\n\n", pMNode->pFromNode->pchFunctionName);
#endif
printf( "\tret\t%d\t\t\t; Remove parameters\n\n",
cod_CountParameterBytes( pMNode->pFromNode->ParamList, DWORD_SIZE));
printf("%s endp\n\n", pMNode->pFromNode->pchFunctionName);
printf("%s\tENDS\n\n",CODE32_NAME);
}
/*** cod_CallStub32
*
* This function prints out the code16 segment assembly code stub for
* the 32-bit routine. This is the part of the assembly code that
* actually makes the call to the real function.
*
* Entry: pMNode is the pointer to a MapNode.
*
* Exit: call stub code is generated.
*
* History:
* 28-Nov-1988 JulieB Created it.
*/
cod_CallStub32(MapNode *pMNode)
{
unsigned int iJumpTarget;
MapNode *Diver;
printf(";* 16-bit code to make API call.\n\n");
printf("%s\tSEGMENT\n\n",CODE16_NAME);
printf("\tASSUME CS:%s\n",CODE16_NAME);
printf("\t.errnz ($ - T_%s)\n\n", pMNode->pToNode->pchFunctionName,
pMNode->pToNode->pchFunctionName);
if (fCombined) {
iJumpTarget = gen_LabelCount++;
printf("\n\n;Target is at L%u + (cx * 4)\n",iJumpTarget);
printf("\n\tmov\tdx,offset L%u\n",iJumpTarget);
printf("\tmovzx\tedx,dx\n");
printf("\n\tlea\tedx,[edx+(ecx*4)]\n");
printf("\tcall\tDWORD PTR CS:[EDX]\n");
printf("\tjmp\tFAR PTR FLAT:R_%s\t\t; jump back\n\n",
pMNode->pToNode->pchFunctionName);
printf("\nL%u:\n",iJumpTarget);
printf("\n\n;Jump table for thunk routine\n");
printf("\tdw\tOFFSET %s\n",pMNode->pToNode->pchFunctionName);
printf("\tdw\tSEG %s\n",pMNode->pToNode->pchFunctionName);
Diver = pMNode->pFamily;
for (;Diver;Diver=Diver->pNextMapping) {
printf("\tdw\tOFFSET %s\n",Diver->pToNode->pchFunctionName);
printf("\tdw\tSEG %s\n",Diver->pToNode->pchFunctionName);
}
}
else {
printf("\tcall\tFAR PTR %s\t\t; call 16-bit version\n",
pMNode->pToNode->pchFunctionName);
printf("\tjmp\tFAR PTR FLAT:R_%s\t\t; jump back\n\n",
pMNode->pToNode->pchFunctionName);
}
printf("%s\tENDS\n\n",CODE16_NAME);
}