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.
1000 lines
27 KiB
1000 lines
27 KiB
#define SCCSID "@(#)codegen.c 13.26 90/08/28"
|
|
|
|
/*
|
|
* Thunk Compiler - Code Generator.
|
|
*
|
|
* This is a Windows 3.2 specific file
|
|
* Microsoft Confidential
|
|
*
|
|
* Copyright (c) Microsoft Corporation 1987, 1988, 1989
|
|
*
|
|
* All Rights Reserved
|
|
*
|
|
* Written 10/15/88 by Kevin Ross [for OS/2 2.x]
|
|
* 10.16.90 Kevin Ruddell ported to Windows 3.2, 16=>32
|
|
* 02.20.91 Kevin Ruddell re-wrote 16=>32 code
|
|
*/
|
|
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include "error.h"
|
|
#include "thunk.h"
|
|
#include "types.h"
|
|
#include "symtab.h"
|
|
#include "codegen.h"
|
|
|
|
extern CHAR *pszGDISemName;
|
|
extern BOOL fLocalHeapUsed;
|
|
|
|
static FixupRec *FixUps = NULL;
|
|
unsigned int iStackOverhead;
|
|
unsigned int iAllocOffset,iBMPOffset,iAliasOffset,iTempStoreOffset,
|
|
iReturnValOffset,iSavedRegOffset,iErrorOffset,
|
|
iStackThunkIDOffset, iPtrThunkIDOffset;
|
|
|
|
|
|
/*** cod_GenerateCode(pmnFirst)
|
|
*
|
|
* This function generates the appropriate code for all of the
|
|
* given mappings.
|
|
*
|
|
* Entry: pmnFirst - a pointer to a list of mapping nodes.
|
|
*
|
|
* Exit: code is generated for all mappings.
|
|
*
|
|
* PCode:
|
|
* Scan list and convert names where needed
|
|
* Output Assembler File Prolog
|
|
* - Define all segments, and groups
|
|
* For (each function mapping in pMT) {
|
|
* switch (mapping type) {
|
|
* case 16 -> 32: gen_Handle1632(pMT);
|
|
* break;
|
|
* case 32 -> 16: gen_Handle3216(pMT);
|
|
* break;
|
|
* default: fatal("unknown mapping type");
|
|
* }
|
|
* }
|
|
*
|
|
* History:
|
|
* 29-Nov-1988 JulieB Restructured FOR loop for cod_Handle routines
|
|
* 28-Nov-1988 JulieB Init gen_LabelCount. Added inline comments.
|
|
* 04-Apr-1989 KevinRo Added Undercase/Underscore routine
|
|
*/
|
|
|
|
void cod_GenerateCode( PMAPNODE pmnFirst)
|
|
{
|
|
PMAPNODE pmn;
|
|
BOOL fExistsTo16, fExistsTo32;
|
|
|
|
fExistsTo16 = cod_ExistsToType( pmnFirst, TYPE_API16);
|
|
fExistsTo32 = cod_ExistsToType( pmnFirst, TYPE_API32);
|
|
|
|
if( (fExistsTo16 = cod_ExistsToType( pmnFirst, TYPE_API16)) &&
|
|
(fExistsTo32 = cod_ExistsToType( pmnFirst, TYPE_API32))) {
|
|
cod_NotHandled( "both 16=>32 and 32=>16 thunks in same script");
|
|
return;
|
|
}
|
|
|
|
cod_ConvertNames( pmnFirst); /* Fixup changes in names */
|
|
|
|
if( fExistsTo16) {
|
|
//
|
|
// YaronS - take this out to reduce size
|
|
//
|
|
;
|
|
/*
|
|
* cod_OutputProlog( pmnFirst);
|
|
*
|
|
* if( fGlobalCombine)
|
|
* cod_CombineFunctions( pmnFirst);
|
|
*
|
|
* if( DumpTables)
|
|
* cod_DumpMapTable( pmnFirst);
|
|
*
|
|
* for( pmn = pmnFirst; pmn; pmn = pmn->pNextMapping)
|
|
* cod_Handle3216( pmn);
|
|
*
|
|
* cod_OutputEpilog( pmn);
|
|
*/
|
|
} else if( fExistsTo32) {
|
|
|
|
cod16_Handle16( pmnFirst);
|
|
|
|
cod16_Prolog32( pmnFirst);
|
|
|
|
for( pmn = pmnFirst; pmn; pmn = pmn->pNextMapping)
|
|
cod16_Handle32( pmn);
|
|
|
|
cod16_Epilog32( pmnFirst);
|
|
}
|
|
}
|
|
|
|
|
|
/*** cod_ConvertNames(pMN)
|
|
*
|
|
*
|
|
*
|
|
* Entry:
|
|
*
|
|
* Exit:
|
|
*/
|
|
|
|
void cod_ConvertNames( MapNode *pMT)
|
|
|
|
{
|
|
for( ; pMT; pMT = pMT->pNextMapping) {
|
|
/*
|
|
* If fUnderScore32 is set true, then prefix an underscore to the
|
|
* 32-bit function name.
|
|
*/
|
|
if (fUnderScore32) {
|
|
cod_PrefixUnderscore((pMT->pFromNode->iCallType==TYPE_API32) ?
|
|
pMT->pFromNode : pMT->pToNode);
|
|
}
|
|
|
|
/*
|
|
* If fUpperCase16 is set true, then force the 16bit function to
|
|
* be all upper case.
|
|
*/
|
|
if (fUpperCase16) {
|
|
cod_ToUpper((pMT->pFromNode->iCallType==TYPE_API16) ?
|
|
pMT->pFromNode->pchFunctionName :
|
|
pMT->pToNode->pchFunctionName);
|
|
}
|
|
|
|
/*
|
|
* If fUpperCase32 is set, then force the 32 bit name to be
|
|
* uppercase.
|
|
*/
|
|
if (fUpperCase32) {
|
|
cod_ToUpper((pMT->pFromNode->iCallType==TYPE_API32) ?
|
|
pMT->pFromNode->pchFunctionName :
|
|
pMT->pToNode->pchFunctionName);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/*** cod_StructOffset()
|
|
*
|
|
* This routine will traverse the StructElems of a typenode,
|
|
* calculating both the offset and size of each element of the
|
|
* structure. Size is only calculated for elements that are structures.
|
|
*
|
|
* Entry: pTNode - pointer to the structure element list.
|
|
* iPrev - the offset of any previous elements in element list.
|
|
* iAlign - the alignment value for the structure. Either
|
|
* 1,2 or 4, determines the packing for calculating
|
|
* offsets.
|
|
*
|
|
* Exit: Each element in the structure will have its StructOffset
|
|
* field set correctly.
|
|
*
|
|
* Returns the size of the structure as defined in 'C'.
|
|
*
|
|
* PCode:
|
|
* For (Each element in element list) {
|
|
* If (Element is a pointer type) {
|
|
* Element offset Aligned Offset
|
|
* Next offset = current + 4 * Array size
|
|
* If (Element type is structure)
|
|
* StructOffset(Element,Zero offset,Current Alignment)
|
|
* } Else if (Element is a structure) {
|
|
* Save previous offset
|
|
* Current offset =
|
|
* StructOffset(Element,Current offset,Current Alignment)
|
|
* Struct size = Current offset - Previous offset
|
|
* } Else {
|
|
* Align current offset according to data size
|
|
* Struct offset = current offset
|
|
* Current offset+= Datasize * ArraySize
|
|
* }
|
|
* }
|
|
* return (CurrentOffset which is same as structure size)
|
|
*/
|
|
|
|
int cod_StructOffset(TypeNode *pTNode,
|
|
int iPrev,
|
|
int iAlign)
|
|
|
|
{
|
|
TypeNode *pTN;
|
|
int iSize=0;
|
|
int iLargest;
|
|
int tmpAlign;
|
|
|
|
/*
|
|
* Preset the alignment for the first item in structure.
|
|
*/
|
|
iLargest = cod_FindLargestSize(pTNode);
|
|
tmpAlign = MIN(iLargest,iAlign);
|
|
iPrev = Align(iPrev,tmpAlign);
|
|
|
|
for (pTN = pTNode; pTN; pTN = pTN->pNextNode) {
|
|
if (pTN->iDeleted) {
|
|
pTN->iStructOffset = iPrev;
|
|
} else if (pTN->iPointerType) {
|
|
iPrev = Align(iPrev,tmpAlign);
|
|
pTN->iStructOffset = iPrev;
|
|
iPrev += DWORD_SIZE * pTN->iArraySize;
|
|
|
|
if (pTN->iBaseType == TYPE_STRUCT) {
|
|
pTN->iBaseDataSize = cod_StructOffset(pTN->pStructElems,0,iAlign);
|
|
}
|
|
} else if (pTN->iBaseType == TYPE_STRUCT) {
|
|
iSize = iPrev;
|
|
pTN->iStructOffset = iPrev;
|
|
iPrev = cod_StructOffset(pTN->pStructElems,iPrev,tmpAlign);
|
|
|
|
if (pTN->pStructElems) {
|
|
pTN->iStructOffset = pTN->pStructElems->iStructOffset;
|
|
}
|
|
|
|
pTN->iBaseDataSize = (iPrev - pTN->iStructOffset) ;
|
|
iPrev += pTN->iBaseDataSize * (pTN->iArraySize - 1);
|
|
} else {
|
|
switch(pTN->iBaseDataSize)
|
|
{
|
|
case 1:
|
|
/*
|
|
* Byte size items are always Byte aligned.
|
|
*/
|
|
break;
|
|
case 2:
|
|
if (tmpAlign >= 2) {
|
|
/*
|
|
* Word size items are always WORD aligned.
|
|
*/
|
|
iPrev = Align(iPrev,WORD_SIZE);
|
|
}
|
|
break;
|
|
case 4:
|
|
iPrev = Align(iPrev,tmpAlign);
|
|
break;
|
|
default:
|
|
fatal("cod_StructOffset: iBaseDataSize = %d",
|
|
pTN->iBaseDataSize);
|
|
}
|
|
pTN->iStructOffset = iPrev;
|
|
iPrev += pTN->iBaseDataSize * pTN->iArraySize;
|
|
}
|
|
}
|
|
iPrev = Align( iPrev, tmpAlign);
|
|
return (iPrev);
|
|
}
|
|
|
|
|
|
/*** cod_FindLargestSize(pTN)
|
|
*
|
|
* This little routine returns the size of the largest item in the
|
|
* TypeNode list pTN. The largest size refers to the largest
|
|
* value in iBaseDataSize. A pointer is considered the largest, at
|
|
* 4 bytes. If an item of 4 byte size is found, this routine returns
|
|
* 4 immediately.
|
|
*
|
|
* This routine is used by StructOffset as a worker routine.
|
|
*
|
|
* Entry: pTN - pointer to the type node.
|
|
*
|
|
* Exit: returns the size of the largest item in pTN.
|
|
*/
|
|
|
|
int cod_FindLargestSize(TypeNode *pTN)
|
|
|
|
{
|
|
int maxsize = 0;
|
|
|
|
|
|
if (!pTN)
|
|
fatal("cod_FindLargestItem(pTN) Null Parameter");
|
|
|
|
for (; pTN; pTN = pTN->pNextNode) {
|
|
/*
|
|
* If item is deleted, then ignore it.
|
|
*/
|
|
if (pTN->iDeleted)
|
|
continue;
|
|
|
|
/*
|
|
* Pointers are the largest items of interest. If we find one, then
|
|
* cut the search off, and return its size. Pointers are always DWORDs.
|
|
*/
|
|
if (pTN->iPointerType)
|
|
return DWORD_SIZE;
|
|
|
|
if (pTN->iBaseType == TYPE_STRUCT) {
|
|
maxsize = MAX(maxsize,cod_FindLargestSize(pTN->pStructElems));
|
|
}
|
|
maxsize = MAX( maxsize, (int)(pTN->iBaseDataSize));
|
|
}
|
|
return (maxsize);
|
|
}
|
|
|
|
|
|
/*** cod_CalcStructOffsets()
|
|
*
|
|
* Entry: pTNode - List of parameters from a function node.
|
|
* iAlign - Alignment default value.
|
|
*
|
|
* Exit: structure offsets are calculated.
|
|
*
|
|
* PCode:
|
|
* For (Each parameter in list) {
|
|
* If (Parameter is a structure) {
|
|
* If (Alignment < 1)
|
|
* Assign default alignment to parameter
|
|
* ParameterSize = StructOffset(StructElems,0,Struct Align)
|
|
* }
|
|
* }
|
|
*/
|
|
|
|
void cod_CalcStructOffsets( TypeNode *pTNode, int iAlign)
|
|
|
|
{
|
|
for( ; pTNode; pTNode = pTNode->pNextNode) {
|
|
if( pTNode->iBaseType == TYPE_STRUCT) {
|
|
if( pTNode->iAlignment < 1)
|
|
pTNode->iAlignment = iAlign;
|
|
pTNode->iBaseDataSize =
|
|
cod_StructOffset( pTNode->pStructElems, 0, pTNode->iAlignment);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/*** cod_CalcTempOffset(pTL, iStart)
|
|
*
|
|
* This routine will traverse a list of formal parameters, pTL,
|
|
* and calculate the stack offset for each temporary pointer.
|
|
* Temporary pointers will be assigned for every pointer in the
|
|
* type list, including pointers imbedded in structures.
|
|
*
|
|
* Entry: pTL - typeNode pointing to remainder of parameter list.
|
|
* iStart - the first available place for the temp pointers on
|
|
* the stack
|
|
*
|
|
* Exit: Each node in the pTL list will have its iTempOffset field
|
|
* filled in with the offset from eBP on the stack. The value
|
|
* returned by this function is the next available position
|
|
* on the stack.
|
|
*
|
|
* History:
|
|
* 26-Dec-1988 KevinRo Created
|
|
*/
|
|
|
|
int cod_CalcTempOffset(TypeNode *pTL,
|
|
unsigned int iStart)
|
|
|
|
{
|
|
while (pTL) {
|
|
if (pTL->iPointerType) {
|
|
pTL->iTempOffset = iStart;
|
|
iStart += DWORD_SIZE;
|
|
}
|
|
if (pTL->iBaseType == TYPE_STRUCT) {
|
|
iStart = cod_CalcTempOffset(pTL->pStructElems,iStart);
|
|
}
|
|
pTL = pTL->pNextNode;
|
|
}
|
|
return (iStart);
|
|
}
|
|
|
|
|
|
/*** cod_CalcOffset(pTL, start, iPSize, fPushDir)
|
|
*
|
|
* This routine will traverse a list of formal parameters, pTL,
|
|
* and calculate the stack offset for each parameter. This routine
|
|
* will handle the calculation for stack offsets regardless of
|
|
* push direction (left to right, or right to left).
|
|
*
|
|
* Entry: pTL - typenode pointing to remainder of parameter list.
|
|
* start - bytes between top of stack and first parameter.
|
|
* iPSize - default size of parameters on stack. 16:16 routines
|
|
* pass WORD parameters, 0:32 DWORD parameters.
|
|
* fPushDir - direction of push (PUSH_LEFT = left to right).
|
|
*
|
|
* Exit: Each node in the pTL list will have its iOffset field filled
|
|
* in with the offset from eBP on the stack.
|
|
*
|
|
* PCode: (This routine is recursive)
|
|
* If (push left to right) { // push left to right
|
|
* If (pTL not NULL) {
|
|
* Current offset = return from CalcOffset of next parameter in list
|
|
* return Current Offset + size of current parameter
|
|
* } Else {
|
|
* return starting offset.
|
|
* }
|
|
* } Else { // push right to left
|
|
* If (pTL) {
|
|
* Current Offset = starting offset
|
|
* starting offset += Size of parameter on stack
|
|
* CalcOffset rest of list, using new starting offset
|
|
* }
|
|
* }
|
|
*
|
|
* History:
|
|
* 30-Nov-1988 JulieB Added use of MAX macro.
|
|
*/
|
|
|
|
int cod_CalcOffset(TypeNode *pTL,
|
|
int start,
|
|
int iPSize,
|
|
int fPushDir)
|
|
|
|
{
|
|
if (fPushDir == PUSH_LEFT) {
|
|
if (pTL) {
|
|
start = pTL->iOffset
|
|
= cod_CalcOffset( pTL->pNextNode, start, iPSize, fPushDir);
|
|
/*
|
|
* If the parameter is flagged as deleted, then don't add
|
|
* its size to the offset.
|
|
*/
|
|
if( !(pTL->iDeleted)) {
|
|
start += (pTL->iPointerType) ?
|
|
4 :
|
|
MAX( (int)(pTL->iBaseDataSize), iPSize);
|
|
}
|
|
}
|
|
return start;
|
|
} else {
|
|
if (pTL) {
|
|
pTL->iOffset = start;
|
|
/*
|
|
* If the parameter is flagged as deleted, then don't add
|
|
* its size to the offset.
|
|
*/
|
|
if( !pTL->iDeleted) {
|
|
start += (pTL->iPointerType) ?
|
|
4 :
|
|
MAX( (int)(pTL->iBaseDataSize), iPSize);
|
|
}
|
|
cod_CalcOffset( pTL->pNextNode, start, iPSize, fPushDir);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/*** cod_OutputProlog( pmnFirst)
|
|
*
|
|
* This routine will output a masm header.
|
|
*
|
|
* Entry: pmnFirst - linked lists of mapping nodes.
|
|
*
|
|
* Exit:
|
|
*
|
|
* PCode:
|
|
* Output masm header
|
|
* For (each entry point)
|
|
* Declare symbol as public
|
|
* Open segment
|
|
* For (each called routine)
|
|
* If (routine is 32 bit)
|
|
* Output external
|
|
*/
|
|
|
|
static void
|
|
cod_OutputProlog( MapNode *pmnFirst)
|
|
|
|
{
|
|
register MapNode *pmn;
|
|
FunctionNode *pFNode;
|
|
BOOL fExistsTo16, fExistsTo32;
|
|
|
|
fExistsTo16 = cod_ExistsToType( pmnFirst, TYPE_API16);
|
|
fExistsTo32 = cod_ExistsToType( pmnFirst, TYPE_API32);
|
|
|
|
for( pmn = pmnFirst, fLocalHeapUsed = FALSE; pmn; pmn = pmn->pNextMapping)
|
|
if( typ_QuerySemanticsUsed( pmn, SEMANTIC_LOCALHEAP))
|
|
fLocalHeapUsed = TRUE;
|
|
|
|
for( pmn = pmnFirst; pmn; pmn = pmn->pNextMapping)
|
|
printf( "PUBLIC\t%s\n", pmn->pFromNode->pchFunctionName);
|
|
|
|
//printf( "\nDGROUP\tGROUP\t_DATA\n");
|
|
|
|
printf( "\n%s\tSEGMENT\tDWORD USE32 PUBLIC '%s'\n",
|
|
CODE32_NAME, CODE32_CLASS);
|
|
for( pmn = pmnFirst; pmn; pmn = pmn->pNextMapping) {
|
|
pFNode = pmn->pToNode;
|
|
if( pFNode->iCallType == TYPE_API32)
|
|
printf( "EXTRN\t%s:NEAR\n", pFNode->pchFunctionName);
|
|
}
|
|
printf( "EXTRN\tSELTOFLAT:NEAR\n");
|
|
if( fExistsTo16) {
|
|
printf( "EXTRN\tGETTHUNKID32:NEAR\n");
|
|
printf( "EXTRN\tMAPLS32:NEAR\n");
|
|
printf( "EXTRN\tUNMAPLS32:NEAR\n");
|
|
printf( "EXTRN\tGETSTACK32:NEAR\n");
|
|
printf( "EXTRN\tRELEASESTACK32:NEAR\n");
|
|
}
|
|
printf( "%s\tENDS\n\n", CODE32_NAME);
|
|
|
|
printf( "%s\tSEGMENT\tDWORD USE32 PUBLIC '%s'\n",DATA32_NAME, DATA32_CLASS);
|
|
if( fExistsTo16) {
|
|
printf( "EXTRN\tSTACK16SELECTOR:WORD\n");
|
|
printf( "EXTRN\tSTACK16INITIALOFFSET:DWORD\n");
|
|
//printf( "EXTRN\t%s:DWORD\n", pszGDISemName);
|
|
}
|
|
if( fLocalHeapUsed) {
|
|
printf( "EXTRN\tDS16LOCALHEAPSELECTOR:WORD\n");
|
|
printf( "EXTRN\tDS16LOCALHEAPBASE:DWORD\n");
|
|
|
|
}
|
|
printf( "%s\tENDS\n\n",DATA32_NAME);
|
|
|
|
printf( "%s\tSEGMENT\tWORD USE16 PUBLIC '%s'\n",CODE16_NAME,CODE16_CLASS);
|
|
for( pmn = pmnFirst; pmn; pmn = pmn->pNextMapping) {
|
|
pFNode = pmn->pToNode;
|
|
if( pFNode->iCallType == TYPE_API16)
|
|
printf( "EXTRN\t%s:FAR\n", pFNode->pchFunctionName);
|
|
}
|
|
printf( "%s\tENDS\n\n", CODE16_NAME);
|
|
}
|
|
|
|
|
|
/*** cod_OutputEpilog(pMT)
|
|
*
|
|
* Outputs any code that belongs at the end of the source file.
|
|
*
|
|
* Entry: pMT - pointer to the list of mapnodes.
|
|
*
|
|
* Exit: code for end of source file is generated.
|
|
*/
|
|
|
|
void cod_OutputEpilog( MapNode *pMT)
|
|
|
|
{
|
|
printf("\n\n\tEND\n");
|
|
}
|
|
|
|
|
|
/*** cod_ExistsToType
|
|
*
|
|
* This function returns TRUE iff one of the mapnodes in the list
|
|
* has a ToNode of the indicated type.
|
|
*
|
|
*/
|
|
|
|
BOOL
|
|
cod_ExistsToType( MapNode *pmnFirst, // pointer to the list of mapnodes
|
|
int iCallType) // type of sought ToNode
|
|
{
|
|
register MapNode *pmn;
|
|
|
|
for( pmn = pmnFirst; pmn; pmn = pmn->pNextMapping) {
|
|
if( pmn->pToNode->iCallType == iCallType)
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
|
|
/*** cod_CountPointerParameters
|
|
*
|
|
* This function returns the number of pointers in a procedure. If the
|
|
* fStructOnly is set, it will only return the number of pointers to
|
|
* structures.
|
|
*
|
|
* Entry: pTT - pointer to the first TypeNode in the type table.
|
|
* fStructOnly - 1 = only count structure pointers.
|
|
* 0 = count all pointers.
|
|
*
|
|
* Exit: returns the number of pointers in a procedure.
|
|
*
|
|
* History:
|
|
* 28-Nov-1988 JulieB Created it.
|
|
* 14-Dec-1988 Kevinro Added recursion to include imbedded pointers
|
|
* 02-Feb-1989 Kevinro Added structure flag
|
|
*/
|
|
|
|
int cod_CountPointerParameters(TypeNode *pTT,
|
|
int fStructOnly)
|
|
|
|
{
|
|
register TypeNode *pTNode; /* pointer to a TypeNode */
|
|
register int iNumPtrs = 0; /* number of pointer parameters */
|
|
|
|
|
|
for (pTNode = pTT; pTNode != NULL; pTNode = pTNode->pNextNode) {
|
|
if (pTNode->iPointerType) {
|
|
if (!fStructOnly) {
|
|
pTNode->iPointerNumber=iNumPtrs++;
|
|
}
|
|
else if (pTNode->iBaseType == TYPE_STRUCT) {
|
|
pTNode->iPointerNumber=iNumPtrs++;
|
|
}
|
|
}
|
|
if (pTNode->iBaseType == TYPE_STRUCT) {
|
|
iNumPtrs +=
|
|
cod_CountPointerParameters(pTNode->pStructElems,fStructOnly);
|
|
}
|
|
if (iNumPtrs > 32) {
|
|
fprintf(stderr,"Too many pointer parameters - limit is 32\n");
|
|
break;
|
|
}
|
|
}
|
|
return (iNumPtrs);
|
|
}
|
|
|
|
|
|
/*** cod_CountParameterBytes(pTT, iDefSize)
|
|
*
|
|
* This function returns the number of bytes in a parameter list.
|
|
*
|
|
* Entry: pTT - pointer to the first TypeNode in the type table.
|
|
* DefSize - parameter default size - based on whether API16 (2)
|
|
* or API32 (4).
|
|
*
|
|
* Exit: returns number of bytes in parameter list.
|
|
*
|
|
* History:
|
|
* 28-Nov-1988 JulieB Created it.
|
|
* 08-Mar-1991 KevinR skip deleted nodes
|
|
*/
|
|
|
|
unsigned int cod_CountParameterBytes( TypeNode *pTT, unsigned int uiDefSize)
|
|
|
|
{
|
|
register TypeNode *pTNode; /* pointer to a TypeNode */
|
|
register unsigned int uiNumBytes = 0; /* number of parameter bytes */
|
|
|
|
|
|
for (pTNode = pTT; pTNode; pTNode = pTNode->pNextNode) {
|
|
if( !pTNode->iDeleted) {
|
|
uiNumBytes += pTNode->iPointerType ?
|
|
DWORD_SIZE :
|
|
MAX( pTNode->iBaseDataSize, uiDefSize);
|
|
}
|
|
}
|
|
return uiNumBytes;
|
|
}
|
|
|
|
|
|
/*** cod_MakeFixupRecord(pParent,pFrom,pTo)
|
|
*
|
|
* This function will allocate and fill in a FixupRec. It will then
|
|
* return a pointer to the new record.
|
|
*
|
|
* Entry: pParent - Parent Node
|
|
* pFrom - From node
|
|
* pTo - To Node
|
|
*
|
|
* Exit: Returns the pointer to the new fixup record.
|
|
*/
|
|
|
|
FixupRec *cod_MakeFixupRecord(TypeNode *pParentFrom,
|
|
TypeNode *pParentTo,
|
|
TypeNode *pFrom,
|
|
TypeNode *pTo)
|
|
|
|
{
|
|
FixupRec *temp = NULL;
|
|
|
|
|
|
temp = (FixupRec *) malloc(sizeof(FixupRec));
|
|
if (temp) {
|
|
temp->pParentFrom = pParentFrom;
|
|
temp->pParentTo = pParentTo;
|
|
temp->pFrom = pFrom;
|
|
temp->pTo = pTo;
|
|
temp->pNextRec = NULL;
|
|
} else {
|
|
fatal("cod_MakeFixupRecord failed memory allocation");
|
|
}
|
|
return (temp);
|
|
}
|
|
|
|
|
|
/*** cod_AddFixupRecord(ppList, pFR)
|
|
*
|
|
* This routine will add the fixup record pFR to the end of the current
|
|
* fixup record list.
|
|
*
|
|
* Entry: ppList - points to the address of a fixup record list.
|
|
* pFR - points to an allocated fixup record.
|
|
*
|
|
* Exit: pFR - will be appended to the end of the static list FixUps.
|
|
*/
|
|
|
|
void cod_AddFixupRecord( FixupRec **ppList, FixupRec *pFR)
|
|
|
|
{
|
|
FixupRec *index = *ppList;
|
|
|
|
|
|
pFR->pNextRec = NULL;
|
|
|
|
if (index == NULL) {
|
|
*ppList = pFR;
|
|
}
|
|
else {
|
|
while (index->pNextRec)
|
|
index = index->pNextRec;
|
|
index->pNextRec = pFR;
|
|
}
|
|
}
|
|
|
|
|
|
/*** cod_GetFixupRecord(ppList)
|
|
*
|
|
* This function removes and returns the head of the ppList list.
|
|
*
|
|
* Entry: ppList - pointer to address of fixup record list.
|
|
*
|
|
* Exit: returns the pointer to the node removed from ppList. If
|
|
* list was empty, then it returns NULL.
|
|
*/
|
|
|
|
FixupRec * cod_GetFixupRecord( FixupRec **ppList)
|
|
|
|
{
|
|
FixupRec *index = *ppList;
|
|
|
|
|
|
if (index)
|
|
*ppList = (*ppList)->pNextRec;
|
|
return (index);
|
|
}
|
|
|
|
|
|
/*** cod_AdjustReg(pchReg,iCurrent,iWanted)
|
|
*
|
|
* This routine will emit code that will ensure that the register named in
|
|
* pchReg will have the value in iWanted, based on the current value in
|
|
* iCurrent. This includes the ability to add or subtract from pchReg.
|
|
*
|
|
* Entry: pchReg - register name.
|
|
* iCurrent - pointer to current value.
|
|
* iWanted - value to be placed in iCurrent.
|
|
*
|
|
* Exit: generates code to adjust registers.
|
|
*/
|
|
|
|
void
|
|
cod_AdjustReg(char *pchReg,
|
|
int *iCurrent,
|
|
int iWanted)
|
|
|
|
{
|
|
int Delta;
|
|
|
|
|
|
if (*iCurrent == iWanted)
|
|
return;
|
|
|
|
Delta = iWanted - *iCurrent;
|
|
if (Delta < 0) {
|
|
if (Delta == -1)
|
|
printf("\tdec\t%s\n",pchReg);
|
|
else
|
|
printf("\tsub\t%s,%d\n",pchReg,-Delta);
|
|
}
|
|
else {
|
|
if (Delta == 1)
|
|
printf("\tinc\t%s\n",pchReg);
|
|
else
|
|
printf("\tadd\t%s,%d\n",pchReg,Delta);
|
|
}
|
|
*iCurrent = iWanted;
|
|
}
|
|
|
|
|
|
/*** cod_ToUpper(s)
|
|
*
|
|
* Convert string s to all upper case.
|
|
*
|
|
* Entry: s == string to convert.
|
|
*
|
|
* Exit: s == converted string.
|
|
*/
|
|
|
|
void cod_ToUpper(char *s)
|
|
|
|
{
|
|
for( ; *s; s++)
|
|
*s = (char)toupper(*s);
|
|
}
|
|
|
|
|
|
/*** cod_PrefixUnderscore(F)
|
|
*
|
|
* Insert an underscore in front of node name.
|
|
*
|
|
* Entry: F - function node to change.
|
|
*
|
|
* Exit: underscore is inserted in front of node name.
|
|
*/
|
|
|
|
void cod_PrefixUnderscore(FunctionNode *F)
|
|
|
|
{
|
|
char *temp;
|
|
|
|
|
|
if (!F)
|
|
fatal("cod_PrefixUnderscore(F): F is NULL");
|
|
temp = (char *) malloc(strlen(F->pchFunctionName) + 3);
|
|
sprintf(temp,"_%s",F->pchFunctionName);
|
|
free(F->pchFunctionName);
|
|
F->pchFunctionName = temp;
|
|
}
|
|
|
|
|
|
/*** cod_NotHandled(CHAR *pszMessage)
|
|
*
|
|
* Warn that a case is not handled by the thunk compiler.
|
|
* Output to stderr and the asm file.
|
|
*
|
|
* Entry: pszMessage - null-terminated message.
|
|
*
|
|
* Exit: the warning has been emitted.
|
|
*/
|
|
|
|
void cod_NotHandled(CHAR *pszMessage)
|
|
|
|
{
|
|
fprintf( stderr, "%s, not handled\n", pszMessage);
|
|
printf( "\t.err\t\t\t;%s, not handled\n", pszMessage);
|
|
}
|
|
|
|
|
|
|
|
/***************************************************************************/
|
|
/* Debugging routines */
|
|
/***************************************************************************/
|
|
|
|
|
|
/*** cod_DumpAllowNodes(A)
|
|
*
|
|
* This function dumps the allow node list.
|
|
*
|
|
* Entry: A - pointer to allow node.
|
|
*
|
|
* Exit: allow nodes are dumped.
|
|
*/
|
|
|
|
void cod_DumpAllowNodes(AllowNode *A)
|
|
|
|
{
|
|
if (!A)
|
|
return;
|
|
fprintf(StdDbg,"AV: ");
|
|
while (A) {
|
|
fprintf(StdDbg,"%lxh, ",A->ulValue);
|
|
A = A->Next;
|
|
}
|
|
}
|
|
|
|
|
|
/*** cod_DumpTNode(T)
|
|
*
|
|
* This function dumps a type node.
|
|
*
|
|
* Entry: T - pointer to type node.
|
|
*
|
|
* Exit: type node is dumped.
|
|
*/
|
|
|
|
void cod_DumpTNode(TypeNode *T)
|
|
|
|
{
|
|
fprintf(StdDbg,"\n%s",T->pchBaseTypeName);
|
|
if (T->pchIdent)
|
|
fprintf(StdDbg,"\t%s", T->pchIdent);
|
|
if (T->iArraySize > 1)
|
|
fprintf(StdDbg,"[%u]",T->iArraySize);
|
|
fprintf(StdDbg,"\tStructOffset = %u",T->iStructOffset);
|
|
if (T->iBaseType == TYPE_STRUCT)
|
|
cod_DumpTNodeList(T->pStructElems);
|
|
if (T->fSemantics != SEMANTIC_INPUT)
|
|
fprintf(StdDbg, "\tfSemantics = 0x%x", T->fSemantics);
|
|
}
|
|
|
|
|
|
/*** cod_DumpTNodeList(T)
|
|
*
|
|
* This function dumps the list of type nodes.
|
|
*
|
|
* Entry: T - pointer to type node list.
|
|
*
|
|
* Exit: type nodes are dumped.
|
|
*/
|
|
|
|
void cod_DumpTNodeList(TypeNode *T)
|
|
|
|
{
|
|
while (T) {
|
|
cod_DumpTNode(T);
|
|
T = T->pNextNode;
|
|
}
|
|
}
|
|
|
|
|
|
/*** cod_DumpStructures(T)
|
|
*
|
|
* This function dumps the structures of a given type node.
|
|
*
|
|
* Entry: T - pointer to type node.
|
|
*
|
|
* Exit: type node structures are dumped.
|
|
*/
|
|
|
|
void cod_DumpStructures(TypeNode *T)
|
|
|
|
{
|
|
sym_DumpTNodeList(T);
|
|
}
|
|
|
|
|
|
/*** cod_DumpTypes(F)
|
|
*
|
|
* This function dumps all types associated with function node.
|
|
*
|
|
* Entry: F - pointer to function node.
|
|
*
|
|
* Exit: type nodes associated with given function node are dumped.
|
|
*/
|
|
|
|
void cod_DumpTypes(FunctionNode *F)
|
|
|
|
{
|
|
TypeNode *t;
|
|
|
|
|
|
fprintf(StdDbg,"\n\ncod_DumpTypes for function %s\n\n",F->pchFunctionName);
|
|
|
|
t = F->ParamList;
|
|
while (t) {
|
|
fprintf(StdDbg,"%s offset = %u",typ_NonNull(t->pchIdent),t->iOffset);
|
|
if (t->iPointerType)
|
|
fprintf(StdDbg,"\ttemp offset = %u ",t->iTempOffset);
|
|
fprintf(StdDbg,"\tiBaseDataSize = %u",t->iBaseDataSize);
|
|
fprintf(StdDbg,"\t%s",t->iDeleted?"DELETED\t":"");
|
|
cod_DumpAllowNodes(t->AllowList);
|
|
t = t->pNextNode;
|
|
}
|
|
fprintf(StdDbg,"\n");
|
|
}
|
|
|
|
|
|
/*** cod_DumpMapTable(pMT)
|
|
*
|
|
* This function dumps the map table.
|
|
*
|
|
* Entry: pMT - pointer to map table.
|
|
*
|
|
* Exit: map table is dumped.
|
|
*/
|
|
|
|
void cod_DumpMapTable(MapNode *pMT)
|
|
|
|
{
|
|
MapNode *Diver;
|
|
|
|
|
|
fprintf(StdDbg,"\n\nDump of Mapping Table\n");
|
|
|
|
for (; pMT; pMT = pMT->pNextMapping) {
|
|
fprintf(StdDbg,"\nParent %s => %s\n",
|
|
pMT->pFromNode->pchFunctionName,
|
|
pMT->pToNode->pchFunctionName);
|
|
|
|
Diver = pMT->pFamily;
|
|
|
|
for (; Diver; Diver = Diver->pNextMapping) {
|
|
fprintf(StdDbg,"\tChild %s => %s\n",
|
|
Diver->pFromNode->pchFunctionName,
|
|
Diver->pToNode->pchFunctionName);
|
|
|
|
if (Diver->pFamily) {
|
|
fprintf(StdDbg,"**** Error: Child has children *****");
|
|
cod_DumpMapTable(Diver->pFamily);
|
|
fprintf(StdDbg,"**** End Error Message *****");
|
|
}
|
|
}
|
|
}
|
|
}
|