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.
1015 lines
37 KiB
1015 lines
37 KiB
#define SCCSID "@(#)cod3216b.c 13.21 90/08/28"
|
|
|
|
/*
|
|
* Thunk Compiler - Routines for Dealing with Types.
|
|
*
|
|
* This is a Win32 specific file
|
|
* Microsoft Confidential
|
|
*
|
|
* Copyright (c) Microsoft Corporation 1987, 1988, 1989, 1990
|
|
*
|
|
* All Rights Reserved
|
|
*
|
|
* Written 12/03/88 by Kevin Ross for OS/2 2.x
|
|
* 11.06.90 Kevin Ruddell adapted to Win32
|
|
*/
|
|
|
|
|
|
#include <stdio.h>
|
|
#include "error.h"
|
|
#include "thunk.h"
|
|
#include "types.h"
|
|
#include "symtab.h"
|
|
#include "codegen.h"
|
|
#include "cod3216.h"
|
|
|
|
|
|
unsigned int fgOutputFlag = 0;
|
|
|
|
unsigned int gEDI,gESI;
|
|
unsigned int iTransferBytes = 0;
|
|
|
|
extern int fReAlignmentNeeded;
|
|
|
|
extern void cod32_UnHandleBoundaryCross(unsigned int, TypeNode *, unsigned int);
|
|
extern void cod32_UnHandleFixedSize(unsigned int,TypeNode *);
|
|
|
|
|
|
/*** cod_UnpackStruct32(pMNode)
|
|
*
|
|
* This function will unwind any pointer manipulation done to make
|
|
* the call.
|
|
*
|
|
* Entry: pMNode - pointer to a MapNode.
|
|
*
|
|
* Exit: generates code to unpack structures.
|
|
*
|
|
* History:
|
|
* 28-Nov-1988 JulieB Created it.
|
|
*/
|
|
|
|
cod_UnpackStruct32(MapNode *pMNode)
|
|
|
|
{
|
|
unsigned int NullLabel;
|
|
TypeNode *pFromList, *pToList;
|
|
|
|
|
|
printf("\n; ****> BEGIN Pointer/Structure Unpack Section\n\n");
|
|
pFromList = pMNode->pFromNode->ParamList;
|
|
pToList = pMNode->pToNode->ParamList;
|
|
|
|
while (pFromList && pToList) {
|
|
if (pFromList->iPointerType) {
|
|
fgOutputFlag = pFromList->fSemantics & SEMANTIC_OUTPUT;
|
|
|
|
printf("\n;Undo Pointer %s --> %s\n",
|
|
typ_NonNull(pFromList->pchIdent),typ_NonNull(pToList->pchIdent));
|
|
|
|
/*
|
|
* Load source address into esi.
|
|
*/
|
|
printf("\n\n\tmov\tesi,[ebp-%u]\t\t;%s temp address\n",
|
|
pFromList->iTempOffset,typ_NonNull(pFromList->pchIdent));
|
|
printf("\tor\tesi,esi\n");
|
|
printf("\tjz\tL%u\n\n",NullLabel=gen_LabelCount++);
|
|
|
|
/*
|
|
* Load destination address into edi.
|
|
*/
|
|
printf("\n\n\tmov\tedi,[ebp+%u]\t\t;%s original address\n",
|
|
pFromList->iOffset,typ_NonNull(pFromList->pchIdent));
|
|
|
|
cod32_UnHandlePointer(pFromList,pToList);
|
|
printf("\nL%u:\t\t;No action required\n",NullLabel);
|
|
}
|
|
pFromList = pFromList->pNextNode;
|
|
pToList = pToList->pNextNode;
|
|
}
|
|
printf("\n; ****> END Pointer/Structure Unpack Section\n\n");
|
|
}
|
|
|
|
|
|
/*** cod32_UnHandlePointer(pFrom, pTo)
|
|
*
|
|
* This function generates code for unhandling the pointers.
|
|
*
|
|
* Entry: pFrom and pTo are the type nodes.
|
|
*
|
|
* Exit: unhandle pointer code is generated.
|
|
*/
|
|
|
|
int cod32_UnHandlePointer(TypeNode *pFrom,
|
|
TypeNode *pTo)
|
|
|
|
{
|
|
int iItemSize = -1;
|
|
TypeNode *pSizeP;
|
|
unsigned int NullLabel;
|
|
unsigned int ErrorLabel;
|
|
unsigned int AliasedLabel;
|
|
unsigned int JumpLabel;
|
|
unsigned int SizeOkLabel;
|
|
unsigned int iTemp1, iTemp2;
|
|
|
|
|
|
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",(iTemp2)?"have":"don't have");
|
|
printf(";Structure %s output semantics\n",
|
|
(fgOutputFlag)?"has":"doesn't have");
|
|
}
|
|
|
|
if ((pFrom->iBaseType == TYPE_STRUCT) && (!iTemp1 || iTemp2)) {
|
|
if (pFrom->pSizeParam)
|
|
cod32_UnHandleStructureBuffer(pFrom,pTo);
|
|
else
|
|
cod32_UnStructureRepack(pFrom, pTo);
|
|
}
|
|
else if (pFrom->iBaseType != pTo->iBaseType) {
|
|
/*
|
|
* 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 insure that the copy out routine correctly extends the
|
|
* value.
|
|
*/
|
|
if ((pFrom->pSizeParam) || (pFrom->iArraySize > 1) ||
|
|
(pFrom->iBaseDataSize < pTo->iBaseDataSize))
|
|
cod32_UnCopyConvertBuffer(pFrom,pTo);
|
|
else {
|
|
printf("\n;This item is either on the stack, or is still\n");
|
|
printf(";in its original position.\n");
|
|
|
|
if (pFrom->fSemantics & SEMANTIC_OUTPUT) {
|
|
printf(";Output semantics convert in place\n\n");
|
|
switch(pFrom->iBaseType)
|
|
{
|
|
case TYPE_ULONG:
|
|
printf("\tmovzx\teax,WORD PTR[esi]\n");
|
|
printf("\tmov\t[edi],eax\n");
|
|
break;
|
|
case TYPE_LONG:
|
|
printf("\tmovsx\teax,WORD PTR[esi]\n");
|
|
printf("\tmov\t[edi],eax\n");
|
|
break;
|
|
default:
|
|
fatal("cod32_UnHandlePointer: Type assertion failed");
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
else {
|
|
/*
|
|
* 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.
|
|
*/
|
|
if (pFrom->iBaseType == TYPE_STRUCT)
|
|
printf(";Treat structure same as buffer\n");
|
|
printf(";Types are identical and no imbedded pointers exist\n");
|
|
printf(";This means that we treated the pointer as a buffer\n");
|
|
printf(";If temp address == original address then no work required\n");
|
|
printf("\tcmp\tesi,edi\n");
|
|
printf("\tje\tL%u\n",gen_LabelCount-1);
|
|
|
|
if (pSizeP = pFrom->pSizeParam) {
|
|
if (fgOutputFlag) {
|
|
ErrorLabel = gen_LabelCount++;
|
|
printf("\n\ttest\tBYTE PTR[ebp-%u],1\t\t;Check for errors A\n",
|
|
iErrorOffset);
|
|
printf("\tjnz\tL%u\t\t\t;No copy if error\n",ErrorLabel);
|
|
printf("\n;Get size for copy out\n");
|
|
|
|
if (pSizeP->iPointerType) {
|
|
/*
|
|
* The original size parameter pointer is not null. This
|
|
* is implicit in the fact that the address of the
|
|
* temporary pointer is different than the original
|
|
* pointer. This also implies that the original size
|
|
* is non zero.
|
|
*/
|
|
printf("\n;Size was referenced by a pointer.\n");
|
|
printf(";Since only shorts/longs are used as sizeof\n");
|
|
printf(";parameters, the space allocated for the temporary\n");
|
|
printf(";location is on the stack. It still exists, so it\n");
|
|
printf(";is still safe to use the temporary pointer\n\n");
|
|
printf("\tmov\tecx,[ebp-%u]\t\t;Get Size Pointer\n",
|
|
pSizeP->iTempOffset);
|
|
|
|
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");
|
|
}
|
|
else
|
|
printf("\tmov\tecx,[ebp+%u]\t\t;Get Size \n",
|
|
pSizeP->iOffset);
|
|
|
|
if (pSizeP->fSemantics & SEMANTIC_SIZE)
|
|
printf(";ECX holds size in bytes\n");
|
|
else if (pSizeP->fSemantics & SEMANTIC_COUNT) {
|
|
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");
|
|
printf("\tmovzx\tecx,ax\n\n");
|
|
}
|
|
else
|
|
fatal("Internal Error: Size semantic not sizeof or countof");
|
|
}
|
|
/*
|
|
* Do a deallocate for variable sized data.
|
|
*/
|
|
cod32_UnHandleBoundaryCross(SIZE_VARIABLE,pFrom,0);
|
|
if (fgOutputFlag)
|
|
printf("\n\nL%u:\t\t\t;ErrorLabel A\n",ErrorLabel);
|
|
}
|
|
else {
|
|
/*
|
|
* No size parameter, assume fixed size parameter.
|
|
*/
|
|
switch(pFrom->iBaseType)
|
|
{
|
|
case TYPE_STRING:
|
|
printf(";Handle String Parameters\n");
|
|
printf(";Strings are never copied out\n");
|
|
|
|
/*
|
|
* Ensure that we don't try to copy out a string.
|
|
*/
|
|
iTemp1 = fgOutputFlag;
|
|
fgOutputFlag = FALSE;
|
|
|
|
cod32_UnHandleBoundaryCross(SIZE_VARIABLE,pFrom,0);
|
|
|
|
fgOutputFlag = iTemp1;
|
|
break;
|
|
default:
|
|
/*
|
|
* Static size.
|
|
*/
|
|
printf("\n;Item is fixed size\n");
|
|
cod32_UnHandleBoundaryCross(SIZE_FIXED,pFrom,typ_FullSize(pFrom));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/*** 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 type nodes.
|
|
*
|
|
* Exit: structure is converted.
|
|
*/
|
|
|
|
cod32_UnHandleStructureBuffer(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;
|
|
|
|
if (pFrom->fSemantics & SEMANTIC_OUTPUT) {
|
|
/*
|
|
* 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("\n;Parameter has size semantics. This is a buffer of structs.\n");
|
|
printf(";If temp address == original address then no work required\n");
|
|
printf("\tcmp\tesi,edi\t\t\t;if temp address == original address\n");
|
|
printf("\tje\tL%u\t\t\t; skip deallocation\n",NullLabel);
|
|
|
|
/*
|
|
* 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");
|
|
|
|
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->fSemantics & SEMANTIC_SIZE) {
|
|
printf(";EAX 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");
|
|
}
|
|
else if (pSizeP->fSemantics & SEMANTIC_COUNT)
|
|
printf(";EAX holds count of items\n");
|
|
else
|
|
fatal("cod32_UnHandleStructureBuffer: Size semantic not sizeof|countof");
|
|
|
|
printf("\n\tmov\tecx,eax\t\t;Move count into ecx\n");
|
|
|
|
/*
|
|
* 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_UnRepackElements(pFrom,pTo, pFrom->pStructElems,
|
|
pTo->pStructElems, &pFixupList);
|
|
|
|
iESI = gESI;
|
|
iEDI = gEDI;
|
|
|
|
cod_AdjustReg("edi", &iEDI, pFrom->iStructOffset + pFrom->iBaseDataSize);
|
|
cod_AdjustReg("esi", &iESI, pTo->iStructOffset + pTo->iBaseDataSize);
|
|
|
|
printf("\n\tpop\tecx\t\t;Restore array count\n");
|
|
printf("\n\tloop\tL%u\n", LoopLabel);
|
|
gEDI = pFrom->iStructOffset + typ_FullSize(pFrom);
|
|
gESI = pTo->iStructOffset + typ_FullSize(pTo);
|
|
|
|
printf("\n\tmov\tesi,[ebp-%u]\n",pFrom->iTempOffset);
|
|
}
|
|
printf("\tpush\t%d\t\t;Alloc Flag Offset\n", - iAliasOffset);
|
|
printf("\tmov\tedx,%lu\n",(long)1<<pFrom->iPointerNumber);
|
|
printf("\n\tcall\tTHK32DEALLOC\n\n");
|
|
}
|
|
|
|
|
|
/*** cod32_UnHandleBoundaryCross(fSize,pFrom,iSize)
|
|
*
|
|
* Emits code to unhandle boundary crossing of pFrom.
|
|
*
|
|
* 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.
|
|
*
|
|
* Exit: unhandle boundary crossing code is generated.
|
|
*/
|
|
|
|
extern unsigned int iCopyLabel;
|
|
extern unsigned int iNoCopyLabel,iNextSize;
|
|
|
|
void
|
|
cod32_UnHandleBoundaryCross(unsigned int fSize,
|
|
TypeNode *pFrom,
|
|
unsigned int iSize)
|
|
|
|
{
|
|
unsigned int DoneLabel, AliasedLabel;
|
|
|
|
|
|
AliasedLabel = gen_LabelCount++;
|
|
DoneLabel = gen_LabelCount++;
|
|
iCopyLabel = gen_LabelCount++;
|
|
|
|
/*
|
|
* If iSize = 0, then assume largest possible size.
|
|
*/
|
|
if (iSize == 0)
|
|
iSize = iSize - 1;
|
|
|
|
if (fSize == SIZE_FIXED) {
|
|
cod32_UnHandleFixedSize(iSize,pFrom);
|
|
return;
|
|
}
|
|
else {
|
|
if (fgOutputFlag) {
|
|
if (iSize > (unsigned short) MEDIUM_ITEM) {
|
|
printf("\n;If aliased, then skip over possible copyout\n");
|
|
printf("\ttest\t%s PTR[ebp-%u],%lu\t\t;Test Alias Flag\n",
|
|
(pFrom->iPointerNumber >7)?"DWORD":"BYTE",
|
|
iAliasOffset, (long) 1 << pFrom->iPointerNumber);
|
|
printf("\tjnz\tL%u",AliasedLabel);
|
|
}
|
|
printf("\n;Copy out ecx bytes\n");
|
|
printf("\tpush\tesi\t\t;Save ptr to temp object\n");
|
|
cod32_VariableLengthCopy();
|
|
printf("\tpop\tesi\t\t;Get ptr to temp object\n");
|
|
}
|
|
if (iSize == 0) /* Make iSize huge */
|
|
iSize--;
|
|
|
|
if (pGlobal_To->fInlineCode) {
|
|
printf("\ttest\t%s PTR[ebp-%u],%lu\t\t;Test Stack Alloc Flag\n",
|
|
(pFrom->iPointerNumber >7)?"DWORD":"BYTE",
|
|
iAllocOffset, (long) 1 << pFrom->iPointerNumber);
|
|
printf("\n; DeAllocate space on stack: Done implicitly\n");
|
|
printf("\tjnz\tL%u\n\n",DoneLabel);
|
|
|
|
if (iSize >= MEDIUM_ITEM) {
|
|
printf("\ttest\t%s PTR [ebp-%u],%lu\t\t;Test BMP Flag\n",
|
|
(pFrom->iPointerNumber >7)?"DWORD":"BYTE",
|
|
iBMPOffset,(long) 1 << pFrom->iPointerNumber);
|
|
|
|
if (iSize >= LARGE_ITEM) {
|
|
iNextSize=gen_LabelCount++;
|
|
printf("\tjz\tL%u\n\n",iNextSize);
|
|
}
|
|
else
|
|
printf("\tjz\tL%u\n\n",DoneLabel);
|
|
|
|
printf("; DeAllocate space in BMP area\n");
|
|
printf("; ESI holds address of block\n");
|
|
printf("\tcall\tThk32FreeBlock\n");
|
|
|
|
if (iSize >= LARGE_ITEM)
|
|
printf("\tjmp\tL%u\n\n",DoneLabel);
|
|
}
|
|
/*
|
|
* The operation of freeing a linear alias is the same as
|
|
* freeing a large buffer allocated for a huge (> 60k) copy.
|
|
*/
|
|
if (iSize >= LARGE_ITEM) {
|
|
if (fgOutputFlag)
|
|
printf("L%u:\t\t\t;Aliased Label\n",AliasedLabel);
|
|
|
|
printf("L%u:\n",iNextSize);
|
|
printf(";Free Linear Alias/ Large Buffer \n");
|
|
printf("\tcall\tThk32FreeAlias\n");
|
|
}
|
|
printf("\nL%u:\t\t;Deallocation Done Label\n\n",DoneLabel);
|
|
}
|
|
else {
|
|
if (fgOutputFlag && (iSize > (unsigned short) MEDIUM_ITEM))
|
|
printf("L%u:\t\t\t;Aliased Label\n",AliasedLabel);
|
|
|
|
printf("\tpush\t%d\t\t;Alloc Flag Offset\n", - iAliasOffset);
|
|
printf("\tmov\tedx,%lu\n",(long)1<<pFrom->iPointerNumber);
|
|
printf("\n\tcall\tTHK32DEALLOC\n\n");
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/*** cod32_UnHandleFixedSize(iSize,pFrom)
|
|
*
|
|
* This worker routine to HandleBoundaryCrossing will output code
|
|
* to handle fixed size items that cross boundaries.
|
|
*
|
|
* Entry: iSize - fixed size of item.
|
|
* pFrom - pointer to type node.
|
|
*
|
|
* Exit: generates code for fixed size item boundary crossing.
|
|
*/
|
|
|
|
void
|
|
cod32_UnHandleFixedSize(unsigned int iSize,
|
|
TypeNode *pFrom)
|
|
|
|
{
|
|
unsigned int ErrorLabel;
|
|
|
|
|
|
if (fgOutputFlag) {
|
|
ErrorLabel = gen_LabelCount++;
|
|
printf("\n\ttest\tBYTE PTR[ebp-%u],1\t\t;Check for errors C\n",iErrorOffset);
|
|
printf("\tjnz\tL%u\t\t\t;No copy if error\n",ErrorLabel);
|
|
}
|
|
|
|
if (! iSize)
|
|
fatal("cod32_UnHandleFixedSize: iSize = 0 \n");
|
|
|
|
if ((iSize <= SMALL_ITEM) && fgOutputFlag) {
|
|
printf("\n;Space was allocated on stack\n");
|
|
cod32_TransferBlock(iSize);
|
|
}
|
|
else if (fgOutputFlag && (iSize <= MEDIUM_ITEM)) {
|
|
printf("\n;Copy out ecx bytes\n");
|
|
printf("\tpush\tesi\t\t;Save ptr to temp object\n");
|
|
cod32_TransferBlock(iSize);
|
|
printf("\tpop\tesi\t\t;Get ptr to temp object\n");
|
|
}
|
|
|
|
if (fgOutputFlag)
|
|
printf("\nL%u:\t\t\t;ErrorLabel C\n",ErrorLabel);
|
|
|
|
if (iSize <= SMALL_ITEM)
|
|
printf(";stack deallocated implicitly\n");
|
|
else if(iSize <= MEDIUM_ITEM) {
|
|
printf("; DeAllocate space in BMP area\n");
|
|
printf("; ESI holds address of block\n");
|
|
printf("\tcall\tThk32FreeBlock\n");
|
|
}
|
|
else if (iSize <= LARGE_ITEM) {
|
|
printf(";Free Linear Alias\n");
|
|
printf("; ESI holds address of block\n");
|
|
printf("\tcall\tThk32FreeAlias\n");
|
|
return;
|
|
}
|
|
else {
|
|
fprintf(stderr,"Fixed sized item > 60k\n");
|
|
printf(".err Fixed sized item > 60k\n");
|
|
}
|
|
}
|
|
|
|
|
|
/*** cod32_UnStructureRepack(pFrom,pTo)
|
|
*
|
|
* This function generates the code that converts one structure
|
|
* to another structure. Specifically, it unpacks structures back to
|
|
* their original positions.
|
|
*
|
|
* Entry: pFrom - pointer to the 32-bit structure
|
|
* pTo - pointer to the 16-bit structure
|
|
*
|
|
* Exit: structure unpacking code is generated.
|
|
*
|
|
* History:
|
|
* 10-Jan-1989 KevinRo Created It.
|
|
*/
|
|
|
|
int cod32_UnStructureRepack(TypeNode *pBaseFrom,
|
|
TypeNode *pBaseTo)
|
|
|
|
{
|
|
unsigned int NullLabel;
|
|
unsigned int ErrorLabel;
|
|
FixupRec *pFixupList = NULL, *pCurrent;
|
|
TypeNode *pFrom,*pTo;
|
|
TypeNode *ptFrom,*ptTo;
|
|
|
|
|
|
pFrom = pBaseFrom->pStructElems;
|
|
pTo = pBaseTo->pStructElems;
|
|
|
|
gEDI = 0;
|
|
gESI = 0;
|
|
|
|
printf(";Return structure to original area\n\n");
|
|
|
|
if (fgOutputFlag) {
|
|
ErrorLabel = gen_LabelCount++;
|
|
printf("\n\ttest\tBYTE PTR[ebp-%u],1\t\t;Check for errors D\n",iErrorOffset);
|
|
printf("\tjnz\tL%u\t\t\t;No copy if error\n",ErrorLabel);
|
|
}
|
|
|
|
cod32_UnRepackElements(pBaseFrom,pBaseTo,pFrom,pTo,&pFixupList);
|
|
|
|
if (fgOutputFlag)
|
|
printf("\nL%u:\t\t\t;ErrorLabel D\n",ErrorLabel);
|
|
|
|
/*
|
|
* Now, handle the fixups.
|
|
*/
|
|
while (pCurrent = cod_GetFixupRecord(&pFixupList)) {
|
|
printf("\n\n;Unpack imbedded pointer %s\n\n",
|
|
typ_NonNull(pCurrent->pFrom->pchIdent));
|
|
printf("\tmov\tesi,[ebp-%u]\t\t;Get pointer to temporary\n",
|
|
pCurrent->pFrom->iTempOffset);
|
|
printf("\tor\tesi,esi\t\t;Ignore if NULL\n");
|
|
printf("\tjz\tL%u\n\n",NullLabel=gen_LabelCount++);
|
|
printf("\tmov\tedi,[ebp+%u]\t\t;Get parents original pointer\n",
|
|
pCurrent->pParentFrom->iOffset);
|
|
printf("\tmov\tedi,[edi+%u]\t\t;Get Fixups original address\n",
|
|
pCurrent->pFrom->iStructOffset);
|
|
|
|
cod32_UnHandlePointer(pCurrent->pFrom,pCurrent->pTo);
|
|
|
|
printf("L%u:\n\n",NullLabel);
|
|
free(pCurrent);
|
|
}
|
|
printf(";Deallocate Temporary Structure \n\n");
|
|
cod32_DeAllocFixedSize(typ_FullSize(pBaseTo),pBaseFrom);
|
|
}
|
|
|
|
|
|
/*** cod32_UnRepackElements(pParentFrom,pParentTo,pFrom,pTo,pFixupList)
|
|
*
|
|
* This function generates the code that undoes the repacking of
|
|
* the elements.
|
|
*
|
|
* Entry: pParentFrom - pointer to parent of 'from' node.
|
|
* pParentTo - pointer to parent of 'to' node.
|
|
* pFrom - pointer to 'from' node.
|
|
* pTo - pointer to 'to' node.
|
|
* pFixupList - pointer to fixup record list.
|
|
*
|
|
* Exit: code for undoing repacking of elements is generated.
|
|
*/
|
|
|
|
cod32_UnRepackElements(TypeNode *pParentFrom,
|
|
TypeNode *pParentTo,
|
|
TypeNode *pFrom,
|
|
TypeNode *pTo,
|
|
FixupRec **pFixupList)
|
|
|
|
{
|
|
TypeNode *pToNode,*pFromNode;
|
|
unsigned int iEDI,iESI;
|
|
unsigned int JumpLabel;
|
|
|
|
|
|
pToNode = pTo;
|
|
pFromNode = pFrom;
|
|
|
|
fReAlignmentNeeded = 0;
|
|
|
|
if (!fgOutputFlag) {
|
|
while (pFromNode) {
|
|
if (pFromNode->iPointerType) {
|
|
cod_AddFixupRecord(pFixupList,
|
|
cod_MakeFixupRecord(pParentFrom,pParentTo,
|
|
pFromNode,pToNode));
|
|
}
|
|
else if (pFromNode->iBaseType == TYPE_STRUCT) {
|
|
cod32_UnRepackElements(pParentFrom,pParentTo,
|
|
pFromNode->pStructElems,
|
|
pToNode->pStructElems,pFixupList);
|
|
}
|
|
pFromNode = pFromNode->pNextNode;
|
|
pToNode = pToNode->pNextNode;
|
|
}
|
|
}
|
|
else {
|
|
while (pFromNode) {
|
|
printf("\n;Element %s --> %s\n", typ_NonNull(pToNode->pchIdent),
|
|
typ_NonNull(pFromNode->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,pToNode->iStructOffset);
|
|
cod_AdjustReg("edi",&gEDI,pFromNode->iStructOffset);
|
|
|
|
fReAlignmentNeeded = 0;
|
|
}
|
|
/*
|
|
* This assignment optimizes the way that bytes are transferred,
|
|
* so that we don't need adjustments when bytes items preceed
|
|
* 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 - gEDI),
|
|
pToNode->iStructOffset - gESI);
|
|
|
|
/*
|
|
* 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 (pToNode->iDeleted) {
|
|
printf(";Source element is deleted\n");
|
|
switch(pToNode->fSemantics & SEMANTIC_INOUT)
|
|
{
|
|
case SEMANTIC_INOUT:
|
|
case SEMANTIC_INPUT:
|
|
printf(";Parameter had input semantic\n");
|
|
printf(";Do not copy it out.\n");
|
|
break;
|
|
case SEMANTIC_OUTPUT:
|
|
printf(";\n");
|
|
printf("\tmov\teax,%u",pToNode->iFillValue);
|
|
switch (pFromNode->iBaseType) {
|
|
case TYPE_USHORT:
|
|
case TYPE_SHORT:
|
|
printf("\t\t;Need a 16-bit value\n");
|
|
printf("\tstosw\n");
|
|
break;
|
|
case TYPE_LONG:
|
|
case TYPE_ULONG:
|
|
printf("\t\t;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 (pToNode->iBaseType) {
|
|
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. Alignment here will
|
|
* always shift when a pointer is encountered.
|
|
*/
|
|
if ((pFromNode->iStructOffset - gEDI) !=
|
|
(pToNode->iStructOffset - gESI) ||
|
|
(pFromNode->iPointerType)) {
|
|
|
|
if (gTransferBytes) {
|
|
printf(";Alignment Change\n");
|
|
cod32_TransferBlock(gTransferBytes);
|
|
gTransferBytes = 0;
|
|
printf("\n;ReAlignment\n");
|
|
}
|
|
cod_AdjustReg("esi",&gESI,pToNode->iStructOffset);
|
|
cod_AdjustReg("edi",&gEDI,pFromNode->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 elements not copied out\n");
|
|
cod32_TransferBlock(gTransferBytes);
|
|
gTransferBytes = 0;
|
|
cod_AdjustReg("esi",&gESI,pToNode->iStructOffset + DWORD_SIZE);
|
|
cod_AdjustReg("edi",&gEDI,pFromNode->iStructOffset + DWORD_SIZE);
|
|
cod_AddFixupRecord(pFixupList,
|
|
cod_MakeFixupRecord(pParentFrom,pParentTo,pFromNode,pToNode));
|
|
break;
|
|
default:
|
|
/*
|
|
* 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
|
|
*/
|
|
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,pToNode->iStructOffset);
|
|
cod_AdjustReg("edi",&gEDI,pFromNode->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_UnRepackElements(pParentFrom,pParentTo,
|
|
pFromNode->pStructElems,
|
|
pToNode->pStructElems,pFixupList);
|
|
iESI = gESI;
|
|
iEDI = gEDI;
|
|
|
|
if (pFromNode->iArraySize > 1) {
|
|
cod_AdjustReg("esi",&iESI,
|
|
pToNode->iStructOffset +
|
|
pToNode->iBaseDataSize);
|
|
cod_AdjustReg("edi",&iEDI,
|
|
pFromNode->iStructOffset +
|
|
pFromNode->iBaseDataSize);
|
|
|
|
printf("\n\tpop\tecx\t\t;Restore array count\n");
|
|
printf("\n\tloop\tL%u\n",LoopLabel);
|
|
gESI = pToNode->iStructOffset +
|
|
typ_FullSize(pToNode);
|
|
gEDI = pFromNode->iStructOffset +
|
|
typ_FullSize(pFromNode);
|
|
}
|
|
}
|
|
else {
|
|
fReAlignmentNeeded = 0;
|
|
/*
|
|
* Reversing the parameters allows CopyConvert to
|
|
* be used for both pack and repack.
|
|
*/
|
|
cod32_CopyConvert(pToNode,pFromNode);
|
|
}
|
|
}
|
|
|
|
DoneWithNodes:
|
|
if (pToNode->pNextNode == NULL) {
|
|
cod32_TransferBlock(gTransferBytes);
|
|
gTransferBytes = 0;
|
|
}
|
|
pToNode = pToNode->pNextNode;
|
|
pFromNode = pFromNode->pNextNode;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/*** cod32_UnCopyConvertBuffer(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 type nodes.
|
|
*
|
|
* Exit: copy/convert of a buffer is performed.
|
|
*/
|
|
|
|
cod32_UnCopyConvertBuffer(TypeNode *pFrom,
|
|
TypeNode *pTo)
|
|
|
|
{
|
|
TypeNode *pSizeP;
|
|
unsigned int JumpLabel;
|
|
unsigned int NullLabel;
|
|
unsigned int ErrorLabel;
|
|
unsigned int DoneLabel;
|
|
unsigned int iNextSize;
|
|
|
|
|
|
/*
|
|
* If there is a size parameter, then the buffer size is determined at
|
|
* run time. Otherwise, the buffer size is static.
|
|
*/
|
|
NullLabel = gen_LabelCount;
|
|
|
|
/*
|
|
* The previous label handles NULL and zero lens.
|
|
*/
|
|
NullLabel--;
|
|
|
|
printf("\n;We have two buffers with different types in them\n");
|
|
printf("\n;If the buffer was output, then we need to copy out\n");
|
|
|
|
if (pSizeP = pFrom->pSizeParam) { /* Runtime */
|
|
if (fgOutputFlag) {
|
|
ErrorLabel = gen_LabelCount++;
|
|
printf("\n\ttest\tBYTE PTR[ebp-%u],1\t\t;Check for errors E\n",iErrorOffset);
|
|
printf("\tjnz\tL%u\t\t\t;No copy if error\n",ErrorLabel);
|
|
}
|
|
if (pSizeP->iPointerType) {
|
|
/*
|
|
* The original size parameter pointer is not null. This is
|
|
* implicit in the fact that the address of the temporary
|
|
* pointer is different than the original pointer. This also
|
|
* implies that the original size is non zero.
|
|
*/
|
|
printf("\n;Size was referenced by a pointer.\n");
|
|
printf(";Since only shorts/longs are used as sizeof\n");
|
|
printf(";parameters, the space allocated for the temporary\n");
|
|
printf(";location is on the stack. It still exists, so it is\n");
|
|
printf(";still safe to use the temporary pointer\n\n");
|
|
|
|
printf("\tmov\tecx,[ebp-%u]\t\t;Get Size Pointer\n",
|
|
pSizeP->iTempOffset);
|
|
|
|
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");
|
|
}
|
|
else
|
|
printf("\tmov\tecx,[ebp+%u]\t\t;Get Size \n",pSizeP->iOffset);
|
|
|
|
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\tecx,eax\t;The count\n",iTempStoreOffset);
|
|
}
|
|
|
|
if (pSizeP->fSemantics & SEMANTIC_COUNT)
|
|
printf(";ECX holds count of items\n");
|
|
|
|
gEDI = 0;
|
|
gESI = 0;
|
|
|
|
JumpLabel = gen_LabelCount++;
|
|
printf("\nL%u:\n",JumpLabel);
|
|
|
|
switch (pTo->iBaseType)
|
|
{
|
|
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",
|
|
pTo->iBaseType,pFrom->iBaseType);
|
|
}
|
|
|
|
printf("\tadd\tesi,%u\n",pTo->iBaseDataSize);
|
|
printf("\tadd\tedi,%u\n",pFrom->iBaseDataSize);
|
|
printf("\tloop\tL%u\n",JumpLabel);
|
|
|
|
if (fgOutputFlag)
|
|
printf("\n\nL%u:\t\t\t;ErrorLabel E\n",ErrorLabel);
|
|
|
|
printf("\n\n;Deallocate Variable Size Block\n");
|
|
printf("\tmov\tesi,[ebp-%u]\n",pFrom->iTempOffset);
|
|
printf("\tpush\t%d\t\t;Alloc Flag Offset\n", - iAliasOffset);
|
|
printf("\tmov\tedx,%lu\n",(long)1<<pFrom->iPointerNumber);
|
|
printf("\n\tcall\tTHK32DEALLOC\n\n");
|
|
}
|
|
else { /* Static */
|
|
gEDI = 0;
|
|
gESI = 0;
|
|
|
|
/*
|
|
* Reversing the order for a CopyConvert is OK.
|
|
*/
|
|
if (fgOutputFlag) {
|
|
ErrorLabel = gen_LabelCount++;
|
|
printf("\n\ttest\tBYTE PTR[ebp-%u],1\t\t;Check for errors F\n",iErrorOffset);
|
|
printf("\tjnz\tL%u\t\t\t;No copy if error\n",ErrorLabel);
|
|
}
|
|
|
|
cod32_CopyConvert(pTo,pFrom);
|
|
|
|
if (fgOutputFlag)
|
|
printf("\n\nL%u:\t\t\t;ErrorLabel F\n",ErrorLabel);
|
|
|
|
cod32_DeAllocFixedSize(typ_FullSize(pTo),pFrom);
|
|
}
|
|
}
|