/** tables.c - build and maintain internal tables * * string hash routines, type hash routines, and * compacted segment information * * History: * 01-Feb-1994 HV Move messages to external file. * */ #include "compact.h" #include <getmsg.h> // external error message file #include "writebuf.h" #include "pdb.h" #define CB_ATOMIC 8100 // 8100 gives room for 8 allocs + header in 1 segment #define INITMODTABSIZE 12000 // initial entries #define REALLOCMODTABSIZE 6000 // additional entries #define TYPEBLOCKSIZE 0x10000 // size of compacted types sub table #define SYMBLOCKSIZE 4096 // #define NameHashBlockSize 4096 #define OffHashBlockSize 4096 #define MINHASH 6 // minimum size of hash table #define HASH_STRING 4096 // String hash table size #define HASH_TYPE 4096 // Type hash table size #define HASH_SYM 4096 // Symbol hash table size #define HASH_COMDAT 4096 // ComDat hash table size #define HASH_NAME 4096 // Globals subsection hash size #define DLIST_INC 20 // number of derived classes #define DCLASS_INC 128 // number of structures // This hash table is used to hash local structures, class, unions // and enums so that they can be quickly found for satisfying forward // references. The hash is the sum of characters in the name. HSFWD **HTLocalFwd = NULL; HSFWD **HTGlobalFwd = NULL; // This hash table is used to hash recursive type records that have // been added to the global symbol table. The hash is the sum of bytes // of all bytes that do not contain a recursive type index. typedef struct HSTYPE { uchar *Type; CV_typ_t GlobalIndex; struct HSTYPE *Next; } HSTYPE; HSTYPE **HTType = NULL; ushort *HTTypeCnt = NULL; // This hash table is used to hash non-recursive type records that have // been added to the global symbol table. The hasf is the sum of bytes // of all bytes in the type record. typedef struct HSSTRING { CV_typ_t CompactedIndex; TYPPTR TypeString; struct HSSTRING *Next; } HSSTRING; HSSTRING **HPDBtring = NULL; ushort *HPDBtringCnt = NULL; // These hash tables are used to hash the public symbols and the module // level symbols that have been moved from the module to the global // symbol table. typedef struct GLOBALSYM { struct GLOBALSYM *Next; ulong sumName; ulong uoff; ushort indName; ushort seg; uchar Sym[]; } GLOBALSYM; GLOBALSYM **HPDBym = NULL; GLOBALSYM **HTPub = NULL; GLOBALSYM **HTLoc = NULL; typedef struct HSCOMDAT { struct HSCOMDAT *Next; ulong Offset; ushort Seg; ushort Type; ushort Sum; uchar Name[1]; } HSCOMDAT; HSCOMDAT **HTComDat = NULL; typedef struct DCLASS { ushort BClass; // base class type index ushort Count; // number of classes derived from this class ushort Max; // maximum list size ushort *List; // pointer to list of derived classes } DCLASS; typedef DCLASS *PDCLASS; // This structure is the primary module level type index table. There is // a list of these that points to the secondary tables. Each entry in the // secondary table points to the type record for the corresponding type // index. Initially the type record as read in from the exe file is // is pointed to. As type records are entered into or found in the global // types table, the type record in the global table is pointed to by the // secondary table entry. This double table format is used because some // compilers emit a skip record for reservind space in the types table. struct BlockListEntry { ushort Low; // low type index in the seconday table ushort High; // high type index in the seconday table TENTRY *ModuleIndexTable; // pointer to the seconday table struct BlockListEntry *Next; // pointer to the next primary table }; #define cBucketSize 10 #define cbMaxAlloc 0xFFE0 #define culEct (cBucketSize + cBucketSize / 4) #define OVFL_C (cBucketSize / 2) typedef struct _SOH { ulong uoff; ulong ulHash; } SOH; // Symbol Offset/Hash structure // Entry in the Chain Overflow Table // This structure is used when the number of entries hashed to a // single bucket exceeds the estimate of cBucketSize typedef struct _OVFL { struct _OVFL *pOvflNext; // pointer to next chain SOH rgsoh [OVFL_C]; // array of symbol offsets } OVFL; typedef OVFL *POVFL; // Entry int the Chain Table typedef struct _ECT { ushort culSymbol; // count of symbols in chain POVFL pOvflNext; // pointer to overflow chain SOH rgsoh[culEct]; // array of symbol offsets } ECT; typedef ECT *PECT; #define cectMax (cbMaxAlloc / sizeof (ECT)) // maximum chains per segment #define cecetMax (cbMaxAlloc / sizeof (OVFL)) // maximum extended chains per seg #define cpecetMax 10 bool_t NoMoTypes = FALSE; LOCAL void AddDerivationListsToTypeSegment (void); LOCAL ushort _fastcall StringHash (uchar *); LOCAL void AddToDerivationList (CV_typ_t, CV_typ_t); LOCAL int _fastcall TypeHash (TENTRY *); LOCAL void CleanUpModuleIndexTable (void); LOCAL GPS_t InGlobalSym (SYMPTR); LOCAL void BuildHash (LPFNHASH, ushort *, ulong *, VBuf *, ulong, GLOBALSYM **); LOCAL void BuildSort (ushort *, ulong *, VBuf *, ulong, GLOBALSYM **); INLINE void _fastcall AddTypeEntry (uchar *, bool_t, bool_t, CV_typ_t, ushort); LOCAL void MapPreComp (plfPreComp); LOCAL PMOD FindModule (char *); LOCAL FWD_t FindLocalFwd (ushort, char *, HSFWD **, bool_t isnested); LOCAL FWD_t FindGlobalFwd (ushort, char *, HSFWD **); INLINE void HashFwdGlobal (TYPPTR, CV_typ_t); LOCAL ushort _fastcall SubHash (TENTRY *OldEntry, ushort iitem); LOCAL BOOL fAssert; LOCAL PDB *ppdb; // current database LOCAL TPI *ptpi; PDCLASS DLists; ushort NextInDerivation; ushort MaxDerivation; uchar **pGType[65536 / GTYPE_INC]; CV_typ_t NewIndex = CV_FIRST_NONPRIM; // start for new types ushort LastGlobalTableIndex; // last possible index ushort AddNewSymbols; // need to add typedefs? ulong cGlobalSym; // total number of global symbols ulong cbGlobalSym; // total number of bytes in global symbols ulong cPublics; // total number of publics ulong cbPublics; // total number of bytes in publics ulong cGlobalDel; // total number of global symbols ushort cSeg; ushort segnum[MAXCDF]; ulong cStaticSym; // total number of static symbols refs ulong cbStaticSym; // total number of bytes in static ref table ulong AlignTable ( GLOBALSYM **, int ); ushort usInitCount; extern uchar **ExtraSymbolLink; extern uchar *ExtraSymbols; extern ushort UDTAdd; extern CV_typ_t usCurFirstNonPrim; // The current first non primitive type index extern ulong ulCVTypeSignature; // The signature from the modules type segment ulong InitialTypeInfoSize; CV_typ_t MaxIndex; // Maximum index for module TENTRY *ModNdxTab; CV_typ_t SizeModNdxTab; VBuf SymBuf; VBuf TypeBuf; // A null LF_ARGLIST entry created at init time. TENTRY *ZeroArg; CV_typ_t PreviousMaxIndex; INLINE void PostClearModNdx(void) { if (PreviousMaxIndex) { memset(ModNdxTab, 0, PreviousMaxIndex * sizeof(TENTRY)); PreviousMaxIndex = 0; } } /** InitializeTables * * Initialize the various tables and allocate space on the heap * for them * * Entry none * * Exit tables initialized * * Returns none * */ void InitializeTables (void) { plfArgList plf; HTType = (HSTYPE **) CAlloc (HASH_TYPE * sizeof (HSTYPE *)); HTTypeCnt = (ushort *) CAlloc (HASH_TYPE * sizeof (ushort)); HPDBtring = (HSSTRING **) CAlloc (HASH_STRING * sizeof (HSSTRING *)); HPDBtringCnt = (ushort *) CAlloc (HASH_STRING * sizeof (ushort)); HPDBym = (GLOBALSYM **) CAlloc (HASH_SYM * sizeof (GLOBALSYM *)); HTPub = (GLOBALSYM **) CAlloc (HASH_SYM * sizeof (GLOBALSYM *)); HTLoc = (GLOBALSYM **) CAlloc (HASH_SYM * sizeof (GLOBALSYM *)); HTComDat = (HSCOMDAT **) CAlloc (HASH_COMDAT * sizeof (HSCOMDAT *)); DLists = (PDCLASS) CAlloc (DCLASS_INC * sizeof (DCLASS)); HTLocalFwd = (HSFWD **)CAlloc (HASH_FWD * sizeof (HSFWD *)); HTGlobalFwd = (HSFWD **)CAlloc (HASH_FWD * sizeof (HSFWD *)); MaxDerivation = DCLASS_INC; LastGlobalTableIndex = 0; VBufInit (&SymBuf, SYMBLOCKSIZE); VBufInit (&TypeBuf, TYPEBLOCKSIZE); // create and initialize the null argument list ZeroArg = CAlloc (sizeof (TENTRY)); ZeroArg->TypeString = Alloc (offsetof (lfArgList, arg) + LNGTHSZ); ZeroArg->flags.IsNewFormat = TRUE; // Create the type string ((TYPPTR)(ZeroArg->TypeString))->len = offsetof (lfArgList, arg) + LNGTHSZ; plf = (plfArgList) (ZeroArg->TypeString + LNGTHSZ); plf->leaf = LF_ARGLIST; plf->count = 0; } /** * * CleanUpTables * * Free the various tables that have been allocated * */ void CleanUpTables (void) { AddDerivationListsToTypeSegment (); free (DLists); free (HTType); free (HPDBtring); // free (HPDBym); free (HTComDat); CleanUpModuleIndexTable(); if (ppdb) { if (ptpi) { fAssert = TypesClose(ptpi); } fAssert |= PDBClose(ppdb); DASSERT(fAssert); } } void *AllocForHT ( uint cb ) { void *pvRet = NULL; static uint cbLocal = 0; static uchar *pbLocal = NULL; if ( cbLocal < cb ) { DASSERT ( cb < CB_ATOMIC ); pbLocal = Alloc ( CB_ATOMIC ); cbLocal = CB_ATOMIC; } pvRet = pbLocal; cbLocal -= cb; pbLocal += cb; return pvRet; } /** MatchIndex - find the compacted index of a non-recursive type * * MatchIndex (OldEntry) * * Entry OldEntry = pointer to type entry * * Exit OldEntry->TypeString added to global type table if not present * OldEntry->CompactedIndex = global type index */ COUNTER (cnt_MatchIndex1); COUNTER (cnt_MatchIndex2); void _fastcall MatchIndex (TENTRY *OldEntry) { ushort i; HSSTRING *j; plfClass plf; TYPPTR pType; uchar *pName; HSFWD *pHash; DASSERT (OldEntry->flags.IsNewFormat); // search through nonrecursive hash list looking for matching entry i = StringHash (OldEntry->TypeString); for (j = HPDBtring[i]; j != NULL; j = j->Next) { if (j->TypeString != NULL) { // a intermodule forward reference will end up having a // null pointer to the type string when it is replaced if (memcmp ((uchar *)j->TypeString, OldEntry->TypeString, j->TypeString->len + LNGTHSZ) == 0) { OldEntry->CompactedIndex = j->CompactedIndex; OldEntry->flags.IsMatched = TRUE; FreeAllocStrings (OldEntry); if (OldEntry->flags.LargeList) { free (OldEntry->IndexUnion.IndexString); free (OldEntry->GlobalIndexString); OldEntry->flags.LargeList = FALSE; } return; } } } // we did not find the type string in the non-recursive hash table. We // now look to see if there is a forward reference that was added by some // other module. If we find one, we will overwrite the forward reference // type string with this one and then rehash the string. COUNT (cnt_MatchIndex2); pType = (TYPPTR)OldEntry->TypeString; switch (pType->leaf) { case LF_CLASS: case LF_STRUCTURE: pName = (uchar *)&((plfClass)&(pType->leaf))->data; pName += C7SizeOfNumeric (pName); break; case LF_UNION: pName = (uchar *)&((plfUnion)&(pType->leaf))->data; pName += C7SizeOfNumeric (pName); break; case LF_ENUM: pName = (uchar *)&((plfEnum)&(pType->leaf))->Name; break; default: pName = NULL; } if (pName != NULL) { switch (FindGlobalFwd (pType->leaf, pName, &pHash)) { case FWD_none: // this is OK since we may not have added this list yet break; case FWD_local: // we should never have looked in the module list DASSERT (FALSE); break; case FWD_global: // we do not need to do any thing here but add the new type break; case FWD_globalfwd: OldEntry->CompactedIndex = pHash->index; memmove (pHash->pType, pType, pType->len + LNGTHSZ); OldEntry->TypeString = (uchar *)pHash->pType; goto fwdreplaced; } } // No matching type string found so we add the type to the global types // table and add it to the string (non-recursive) hash table, Note that // InsertIntoTypeSegment frees the local type string if it is in // allocated memory. InsertIntoTypeSegment (OldEntry); fwdreplaced: j = (HSSTRING *)Alloc (sizeof (HSSTRING)); j->TypeString = (TYPPTR)OldEntry->TypeString; j->CompactedIndex = OldEntry->CompactedIndex; j->Next = HPDBtring[i]; HPDBtring[i] = j; HPDBtringCnt[i]++; if ((j->TypeString->leaf == LF_CLASS) || (j->TypeString->leaf == LF_STRUCTURE)) { plf = (plfClass)&(j ->TypeString->leaf); if (plf->property.fwdref == FALSE) { // if we have a forward reference, then the field list // was null. DoDerivationList (j->CompactedIndex, plf->field); } } } /** * * DoDerivationList * * Takes a field specification list and the derived class and adds * it to all the inherited classes given by the list. * */ void DoDerivationList (CV_typ_t DerivedClass, CV_typ_t FieldSpecList) { TYPPTR typptr; uchar *plf; uchar **pBuf; bool_t Loop = TRUE; if (FieldSpecList == T_NOTYPE) return; // Get the field list type string pBuf = pGType[(FieldSpecList - CV_FIRST_NONPRIM) / GTYPE_INC]; typptr = (TYPPTR)(pBuf[(FieldSpecList - CV_FIRST_NONPRIM) % GTYPE_INC]); DASSERT (typptr->leaf == LF_FIELDLIST); // Loop through the real and direct virtual base classes plf = (uchar *)&(typptr->data); while (Loop) { if (*plf >= LF_PAD0) { plf += *plf & 0x0f; } switch (((plfEasy)plf)->leaf) { case LF_BCLASS: AddToDerivationList (DerivedClass, ((plfBClass)plf)->index); plf = (uchar *)&((plfBClass)plf)->offset; plf += C7SizeOfNumeric (plf); break; case LF_VBCLASS: AddToDerivationList (DerivedClass, ((plfVBClass)plf)->index); plf = (uchar *)&((plfVBClass)plf)->vbpoff; plf += C7SizeOfNumeric (plf); plf += C7SizeOfNumeric (plf); break; case LF_INDEX: DASSERT (FALSE); default: Loop = FALSE; break; } } } /** * * InsertIntoTypeSegment * * Inserts a type string into the compacted segment and assigns * it a new index * Uses C7 format type strings * */ void _fastcall InsertIntoTypeSegment (TENTRY *OldEntry) { ushort length; TYPPTR pType; plfStructure plf; UDTPTR pSym; uint usSymLen; uchar *Name; uchar *NewSymbol; uchar *pchDest; unsigned int iPad; // Number of pad bytes needed. uint usNewLength; // Symbol length - LNGTHSZ including pad bytes. uchar **pBuf; DASSERT (OldEntry->flags.IsNewFormat); BreakOnIndex (NewIndex); if (NoMoTypes) { OldEntry->CompactedIndex = T_NOTYPE; #if DBG if (DbArray[3]) { DumpPartialType (NewIndex, (TYPPTR)(OldEntry->TypeString), FALSE); } #endif fflush(stdout); return; } pType = (TYPPTR)(OldEntry->TypeString); plf = (plfStructure)&pType->leaf; #if DBG if (DbArray[2]) DumpPartialType (NewIndex, pType, FALSE); #endif // add in symbol typedefs for structures; maintaining it as // a linked list with ExtraSymbols as the head and ExtraSymbolLink // to point to the next symbol. The link field preceeds the actual // symbol in memory. if ((plf->leaf == LF_STRUCTURE) && AddNewSymbols) { Name = ((uchar *)plf) + offsetof (lfStructure, data); Name += C7SizeOfNumeric (Name); // go to the name if (*Name != 0 && ((*Name != sizeof ("(untagged)") - 1) || (memcmp ((_TCHAR *)(Name + 1), "(untagged)", sizeof ("(untagged)") - 1) != 0))){ // name present, and isn't "(untagged)" // calculate the size of the symbol; usSymLen = sizeof (UDTSYM) + *Name; iPad = PAD4 (usSymLen); usNewLength = usSymLen + (ushort)iPad - LNGTHSZ; // allocate space for a new UDT Symbol NewSymbol = Alloc (usNewLength + LNGTHSZ + sizeof(char *)); if (ExtraSymbols == NULL) { ExtraSymbols = NewSymbol;// head of list } else { // Change "next" field of the last sybol to point to the new one *ExtraSymbolLink = NewSymbol; } // Create the User Defined Type symbol pSym = (UDTPTR)(NewSymbol + sizeof(char *)); DASSERT (usNewLength <= USHRT_MAX); pSym->reclen = (ushort)usNewLength; pSym->rectyp = S_UDT; pSym->typind = NewIndex; memcpy (pSym->name, Name, *Name + 1); // Copy the name pchDest = ((uchar *)&(pSym->name)) + *Name + 1; PADLOOP (iPad, pchDest); // Store address of this symbol for next time ExtraSymbolLink = (uchar **)NewSymbol; // Set the "next" field of this symbol to NULL *ExtraSymbolLink = NULL; } } if ((NewIndex - CV_FIRST_NONPRIM) == LastGlobalTableIndex) { LastGlobalTableIndex += GTYPE_INC; pBuf = Alloc (GTYPE_INC * sizeof (uchar *)); pGType[(NewIndex - CV_FIRST_NONPRIM) / GTYPE_INC] = pBuf; } length = C7LENGTH (pType) + LNGTHSZ; #if DBG if (length % 2) { if (verbose) { printf("Leaf: 0x%X in module: %s is not a multiple of 2. Rounding up.\n", pType->leaf, FormatMod(pCurMod)); } length = (length + 1) & ~1; // Ensure proper alignment pType->len = (pType->len + 1) & ~1; } #endif if ( length > cbTypeAlign ) { // type exceeds demand load alignment limitation convert it to nil // sps 12/3/92 *((ushort *)pType) = 2; // Length of leaf *((ushort *)pType + 1) = LF_NULL; // The leaf length = 4; Warn ( WARN_TYPELONG, NULL, NULL ); } pBuf = pGType[(NewIndex - CV_FIRST_NONPRIM) / GTYPE_INC]; pBuf[(NewIndex - CV_FIRST_NONPRIM) % GTYPE_INC] = VBufCpy (&TypeBuf, (uchar *)pType, length); FreeAllocStrings (OldEntry); OldEntry->TypeString = pBuf[(NewIndex - CV_FIRST_NONPRIM) % GTYPE_INC]; OldEntry->CompactedIndex = NewIndex++; // we need to keep track of the following type records that were added // to the global types table. The forward reference entries will // later be backpatched to the correct type. We keep track of the // non-forward references so we know to ignore forward references // in later modules. HashFwdGlobal ((TYPPTR)(OldEntry->TypeString), (ushort)(NewIndex - 1)); if (NewIndex == 0) { #if DBG if (DbArray[3]) DumpPartialType (NewIndex, (TYPPTR)(OldEntry->TypeString), FALSE); #endif Warn (WARN_65KTYPES, FormatMod (pCurMod), NULL); NoMoTypes = TRUE; } } /** * * AddTypeToStringTable * * Adds a type string to the global hash table * Uses C7 format type strings * */ void _fastcall AddTypeToStringTable (uchar *TypeString, CV_typ_t GlobalIndex) { static uint cStringsAvail; static HSSTRING *hstrAvail; ushort i; HSSTRING *j; if (cStringsAvail == 0) { hstrAvail = (HSSTRING *)Alloc(sizeof(HSSTRING) * 1024); cStringsAvail = 1024; } cStringsAvail--; j = hstrAvail++; i = StringHash (TypeString); j->TypeString = (TYPPTR) TypeString; j->CompactedIndex = GlobalIndex; j->Next = HPDBtring[i]; HPDBtring[i] = j; HPDBtringCnt[i]++; } const char *PstGetLibPath(ushort iLib) { const char *pstName = (char *) Libraries; for (;;) { size_t cbName; cbName = (size_t) *(unsigned char *) pstName; if (iLib-- == 0) { break; } pstName += cbName + 1; } return(pstName); } void GetCurModReferenceDir(char *szRefDir) { const OMFModule *psstMod = (OMFModule *) ModAddr; const char *pstName; size_t cbName; char szPath[_MAX_PATH]; char szDrive[_MAX_DRIVE]; char szDir[_MAX_DIR]; extern BYTE MajorLinkerVersion; extern BYTE MinorLinkerVersion; if (psstMod->iLib == 0) { pstName = (char *) &psstMod->SegInfo[psstMod->cSeg]; } else if (!fLinearExe && (psstMod->iLib == 256)) { // Link 5.x mistakenly assigns 256 instead of 0 pstName = (char *) &psstMod->SegInfo[psstMod->cSeg]; } else if (fLinearExe && (MajorLinkerVersion == 2) && (MinorLinkerVersion < 60)) { // LINK 2.x before 2.60 mistakenly assign a value one too high pstName = PstGetLibPath((ushort) (psstMod->iLib - 1)); } else { pstName = PstGetLibPath(psstMod->iLib); } cbName = (size_t) *(unsigned char *) pstName; memcpy(szPath, pstName + 1, cbName); szPath[cbName] = '\0'; _splitpath(szPath, szDrive, szDir, NULL, NULL); _makepath(szRefDir, szDrive, szDir, NULL, NULL); if (szRefDir[0] == '\0') { // Never return an empty path szRefDir[0] = '.'; szRefDir[1] = '\0'; } } int TDBStayedResident; int NeedToClearTDB; LOCAL char szPDBCur[_MAX_PATH + _MAX_EXT]; LOCAL CV_typ_t MaxIndexLast; // saved MaxIndex value LOCAL EC dummyEC; LOCAL void ReadTDB(char* szPDBToRead) { TI ti, tiMin, tiMac; uchar *pType; static char szPDBLast[_MAX_PATH + _MAX_EXT]; if (szPDBToRead == NULL) { // if nothing to read - ropen the last one we read if (ppdb) { if (ptpi) { fAssert = TypesClose(ptpi); } fAssert |= PDBClose(ppdb); DASSERT(fAssert); } szPDBToRead = szPDBLast; if (!PDBOpen(szPDBToRead, pdbRead pdbGetRecordsOnly, 0, &dummyEC, NULL, &ppdb) || !PDBOpenTpi(ppdb, pdbRead pdbGetRecordsOnly, &ptpi)) { ErrorExit(ERR_TDBOPEN, szPDBLast, NULL); } } else { _tcscpy(szPDBLast, szPDBToRead); } if (verbose) { printf(get_err(MSG_READPDB), szPDBCur, '\n'); } // clear the whole local type table PostClearModNdx(); // now install all the types from the TDB tiMin = TypesQueryTiMin(ptpi); tiMac = TypesQueryTiMac(ptpi); // printf("types: min = %d, max = %d\n", tiMin, tiMac); // loop through the indices... for (ti = tiMin; ti < tiMac; ti++) { fAssert = TypesQueryPbCVRecordForTi(ptpi, ti, &pType); DASSERT(fAssert); #if DBG if (DbArray[9]) DumpPartialType (ti, (TYPPTR) pType, FALSE); #endif AddTypeEntry (pType, /* GTW: FALSE, */ TRUE, FALSE, T_NOTYPE, 0); } MaxIndexLast = MaxIndex; } /** MapTDB - map in program database information * * MapTDB (plf) * * Entry plf = pointer to LF_TDB type record up to name field * * Exit types from database inserted into this modules type entries * * Returns none */ LOCAL void MapTDB(plfTypeServer plf) { static char szPDBLast[_MAX_PATH]; static ushort usPDB; BOOL fOpenPdb; char szPath[_MAX_PATH]; char szExt[_MAX_EXT]; char *pch; int ch; // copy and null terminate memcpy(szPDBCur, plf->name+1, plf->name[0]); szPDBCur[plf->name[0]] = 0; // check if there were no intervening initializations and if // the same database is being access as last time... if (usInitCount == usPDB + 1 && !_tcsicmp(szPDBLast, szPDBCur)) { DASSERT(ppdb); if (PDBQuerySignature(ppdb) != plf->signature) { ErrorExit(ERR_TDBSIG, FormatMod (pCurMod), szPDBCur); } if (PDBQueryAge(ppdb) < plf->age) { ErrorExit(ERR_TDBSYNC, FormatMod (pCurMod), szPDBCur); } // we're doing the same pdb as last time... // let's short circuit everything usPDB = usInitCount; MaxIndex = MaxIndexLast; TDBStayedResident = TRUE; if (PreviousMaxIndex > MaxIndex) { memset(ModNdxTab + MaxIndex, 0 , (PreviousMaxIndex - MaxIndex) * sizeof(TENTRY)); } PreviousMaxIndex = 0; return; } // Remember the last pdb name input not where we found it _tcscpy(szPDBLast, szPDBCur); usPDB = usInitCount; // we have to re-open the database just in case we have written // on the types that it returned last time... if (ppdb) { if (ptpi) { fAssert = TypesClose(ptpi); } fAssert |= PDBClose(ppdb); DASSERT(fAssert); } if (!PDBValidateInterface()) { ErrorExit(ERR_WRONGDBI, NULL, NULL); } // Try to open the PDB in the reference directory _splitpath(szPDBCur, NULL, NULL, szPath, szExt); _tcscat(szPath, szExt); GetCurModReferenceDir(szPDBCur); pch = szPDBCur + _tcslen(szPDBCur); if (((ch = pch[-1]) != '/') && (ch != '\\') && (ch != ':')) { // Add a trailing '\' *pch++ = '\\'; } _tcscpy(pch, szPath); fOpenPdb = PDBOpen(szPDBCur, pdbRead pdbGetRecordsOnly, 0, &dummyEC, NULL, &ppdb); if (fOpenPdb && (PDBQuerySignature(ppdb) != plf->signature)) { PDBClose(ppdb); fOpenPdb = FALSE; } #if 0 if (!fOpenPdb) { char LibPath[4 * _MAX_PATH]; char *plibenv; // look along lib path first - this was done to prevent troubles profiling // staticly linked mfc apps - which are built on e: plibenv = getenv("LIB"); if (plibenv == NULL) { plibenv = ""; } _tcscpy(LibPath, ".;"); _tcscat(LibPath, plibenv); plibenv = LibPath; while (!fOpenPdb) { char *plibsemi; if (*plibenv == 0) { break; } // Try to open the file along the next directory in the LIB path if ((plibsemi = _tcschr(plibenv, ';')) != NULL) { *plibsemi = 0; _tcscpy(szPDBCur, plibenv); plibenv = plibsemi + 1; } else { _tcscpy(szPDBCur, plibenv); *plibenv = 0; } pch = szPDBCur + _tcslen(szPDBCur); if (((ch = pch[-1]) != '/') && (ch != '\\') && (ch != ':')) { // Add a trailing '\' *pch++ = '\\'; } _tcscpy(pch, szPath); fOpenPdb = PDBOpen(szPDBCur, pdbRead pdbGetRecordsOnly, 0, &dummyEC, NULL, &ppdb); if (fOpenPdb && (PDBQuerySignature(ppdb) != plf->signature)) { PDBClose(ppdb); fOpenPdb = FALSE; } } } #endif if (!fOpenPdb) { // Try to open the PDB using the given location _tcscpy(szPDBCur, szPDBLast); fOpenPdb = PDBOpen(szPDBCur, pdbRead pdbGetRecordsOnly, 0, &dummyEC, NULL, &ppdb); if (fOpenPdb && (PDBQuerySignature(ppdb) != plf->signature)) { PDBClose(ppdb); fOpenPdb = FALSE; } } if (!fOpenPdb) { ErrorExit(ERR_TDBOPEN, szPDBCur, NULL); } if (PDBQueryAge(ppdb) < plf->age) { ErrorExit(ERR_TDBSYNC, FormatMod(pCurMod), szPDBCur); } if (!PDBOpenTpi(ppdb, pdbRead pdbGetRecordsOnly, &ptpi)) { ErrorExit(ERR_TDBOPEN, szPDBCur, NULL); } ReadTDB(szPDBCur); } /** * * AddTypeToTypeTable * * Add a type string to the type table for recursive types * Uses C7 format type strings * */ void _fastcall AddTypeToTypeTable (TENTRY *OldEntry) { static uint cTypesAvail; static HSTYPE *hstAvail; HSTYPE *new; int index; if (cTypesAvail == 0) { hstAvail = (HSTYPE *)Alloc(sizeof(HSTYPE) * 1024); cTypesAvail = 1024; } index = TypeHash (OldEntry); cTypesAvail--; new = hstAvail++; new->Type = OldEntry->TypeString; new->GlobalIndex = OldEntry->CompactedIndex; // add it to the head of the bucket new->Next = HTType[index]; HTType[index] = new; HTTypeCnt[index]++; } /** C7ReadTypes - read C7 formatted types table * * C7ReadTypes (cbTypes, fPreComp) * * Entry cbTypes = count of bytes in types table excluding the * byte count of the signature * fPreComp = TRUE if precompiled types table allowed * */ void C7ReadTypes (ulong cbTypeSeg, bool_t fPreComp) { ulong cbCur; // Number of bytes currently read from file ushort cbRecLen; // The current record's length ushort RecType; // The current record's length uchar *pCurType; // Points to the current type string uchar *pEnd; // Points to the of type segment int remainder = 0; ushort cSkip; uint cbRead; InitModTypeTable (); cbCur = 0; iTypeSeg = 0; while (cbCur < cbTypeSeg) { pCurType = pTypeSeg[iTypeSeg]; cbRead = (uint)(min (cbTypeSeg - cbCur, _HEAP_MAXREQ)) - remainder; if (cbRead == 0) cbRead = remainder; //printf("cbRead %u\tRemain: %u\t", cbRead, remainder); if (link_read (exefile, pCurType + remainder, cbRead) != cbRead) { ErrorExit (ERR_INVALIDTABLE, "Types", FormatMod (pCurMod)); } pEnd = pCurType + cbRead + remainder; //printf("pEnd: %d\tpCur: %d\n", pEnd, pCurType); while ((size_t)(pEnd - pCurType) >= offsetof (TYPTYPE, data)) { // we have at least the length and record type in memory cbRecLen = ((TYPPTR)pCurType)->len; RecType = ((TYPPTR)pCurType)->leaf; if ((size_t)(pEnd - pCurType) < (cbRecLen + sizeof (((TYPPTR)pCurType)->len))) { // the type record is split across this and the next buffer break; } switch (RecType) { case LF_TYPESERVER: #pragma message("M00TODO - remove when compiler doesn't mark tdb as pct") MapTDB((plfTypeServer) (pCurType + LNGTHSZ)); // REVIEW -- workaround! [rm] // compiler must never mark a TDB as a PCT // REMOVE THIS WHEN COMPILER FIXED maxPreComp = MaxIndex + CV_FIRST_NONPRIM; break; case LF_PRECOMP: if(fPreComp) ErrorExit (ERR_2LevelPch, FormatMod (pCurMod), 0); MapPreComp ((plfPreComp)(pCurType + LNGTHSZ)); break; case LF_ENDPRECOMP: // we have found the type record that specifies // the end of the precompiled types for this module. // Set maxPreComp to MaxIndex (really current index) // so the precompiled types packer knows how far // to pack before the publics and symbols are packed. DASSERT(fPreComp); maxPreComp = MaxIndex + CV_FIRST_NONPRIM; #pragma inline_depth(0) // don't inline this occurence AddTypeEntry (NULL, TRUE, FALSE, T_NOTYPE, 0); #pragma inline_depth() pCurMod->signature = ((plfEndPreComp)(pCurType + LNGTHSZ))->signature; break; default: if (RecType == LF_SKIP) { cSkip = ((plfSkip)(pCurType + LNGTHSZ))->type - MaxIndex - CV_FIRST_NONPRIM; } else { cSkip = 0; } #if DBG if ((ULONG) pCurType % 2) { uchar *pTypeNew; if (verbose) { printf("Leaf: 0x%X in module: %s doens't start on a word boundary.\n", ((TYPTYPE UNALIGNED *)pCurType)->leaf, FormatMod(pCurMod)); } pTypeNew = CAlloc((((TYPTYPE UNALIGNED *)pCurType)->len+4+3)& ~3); memcpy(pTypeNew, pCurType, ((TYPTYPE UNALIGNED *)pCurType)->len + 4); AddTypeEntry(pTypeNew, TRUE, FALSE, T_NOTYPE, cSkip); } else #endif AddTypeEntry (pCurType, TRUE, FALSE, T_NOTYPE, cSkip); break; } pCurType += cbRecLen + LNGTHSZ; cbCur += cbRecLen + LNGTHSZ; } // we have reached the point where we are either at the end of types // or the next type record does not fit within the current buffer //printf("cbCur: %d\tcbType: %d\n", cbCur, cbTypeSeg); if (cbCur < cbTypeSeg) { // we have not reached the end of the types so we allocate and // read another buffer // Range check (ReadDir s/b correct here) if (iTypeSeg > cTypeSeg) { ErrorExit (ERR_TYPE, FormatMod(pCurMod), NULL); } if (pTypeSeg[iTypeSeg + 1] == NULL) { if ((pTypeSeg[iTypeSeg + 1] = TrapMalloc (_HEAP_MAXREQ)) == 0) { ErrorExit (ERR_NOMEM, NULL, NULL); } } remainder = pEnd - pCurType; memmove (pTypeSeg[iTypeSeg + 1], pCurType, remainder); iTypeSeg++; } } InitialTypeInfoSize += cbTypeSeg; // update size info } /** C6ReadTypes - read C6 types table * * Purpose : Given a Type segment and its size, initialize the * module type index table and set all global indices to * zero */ void C6ReadTypes (uchar *TypeSegment, ulong Size) { uchar *End = TypeSegment + Size; ushort cSkip; InitModTypeTable (); while (TypeSegment < End) { if (TypeSegment[3] == OLF_SKIP) { cSkip = (*(CV_typ_t *)(TypeSegment + 4)) - MaxIndex - 512; } else { cSkip = 0; } #pragma inline_depth(0) // don't inline this occurence AddTypeEntry (TypeSegment, FALSE, FALSE, T_NOTYPE, cSkip); #pragma inline_depth() if (TypeSegment[3] == OLF_STRUCTURE) { // We have to add a symbol for each C6 UDT found. We // are deliberately overestimating the size of the symbol // because it takes too much time to do an accurate estimate UDTAdd += MAXPAD + sizeof (UDTSYM) + *(ushort UNALIGNED *)&TypeSegment[1]; } TypeSegment += LENGTH (TypeSegment) + 3; // on to next string } InitialTypeInfoSize += (unsigned long) Size; // update size info } /** InitModTypeTable - initialize/reset module type table * * InitModTypeTable () * * Entry BlockList = head of first level index structure * * Exit cur = pointer to first level index structure * MaxIndex = 0 * if BlockList = NULL, then a first level index structure is * allocated and initialized. If BlockList is not NULL, then * the first level index structure is initialized. */ void InitModTypeTable (void) { usInitCount++; if (ModNdxTab == NULL) { ModNdxTab = CAlloc((SizeModNdxTab = INITMODTABSIZE) * sizeof(TENTRY)); } MaxIndex = 0; } // ClearHashFwdLocal - clear out the hash table for forward reference resolution void ClearHashFwdLocal() { HSFWD *pHash; uint i; for (i = 0; i < HASH_FWD; i++) { pHash = HTLocalFwd[i]; while (pHash != NULL) { pHash->index = T_NOTYPE; pHash->pType = NULL; free (pHash->pName); pHash->pName = NULL; pHash = pHash->Next; } } } /** AddTypeEntry - add type descriptor to local table * * AddTypeEntry (pType, IsNewFormat, IsPrecomp, type, cSkip) * * Entry pType = pointer to type string * IsNewFormat = TRUE if type is CV4 format * IsPreComp = TRUE if precompile type from another module * cSkip = number of indices to skip before adding this type * * Exit type added to local type descriptors * * Return none * * Note: MapPreComp contains an inlined/simplified version of this * function, if AddTypeEntry ever changes semantics then * the inline code in MapPreComp should be examined [rm] * */ INLINE void _fastcall AddTypeEntry ( uchar *pType, bool_t IsNewFormat, bool_t IsPreComp, CV_typ_t type, ushort cSkip ) { CV_typ_t insertHere = MaxIndex; PostClearModNdx(); if ((MaxIndex += (cSkip) ? cSkip : 1) >= SizeModNdxTab) { if ((ModNdxTab = realloc(ModNdxTab, (SizeModNdxTab += REALLOCMODTABSIZE + cSkip) * sizeof(TENTRY))) == NULL){ ErrorExit(ERR_NOMEM, NULL, NULL); } memset(ModNdxTab + insertHere, 0,(REALLOCMODTABSIZE + cSkip) * sizeof(TENTRY)); } ModNdxTab[insertHere].TypeString = pType; ModNdxTab[insertHere].CompactedIndex = type; DASSERT(ModNdxTab[insertHere].flags.IsMalloced == FALSE); ModNdxTab[insertHere].flags.IsNewFormat = IsNewFormat; ModNdxTab[insertHere].flags.IsPreComp = IsPreComp; ModNdxTab[insertHere].flags.InputWasFwd = IsFwdRef ((TYPPTR) pType); } /** MapPreComp - map in precompiled types from creator module * * MapPreComp (plf) * * Entry plf = pointer to LF_PRECOMP type record up to name field * * Exit types from creator file inserted into this modules type entries * * Returns none */ LOCAL void MapPreComp (plfPreComp plf) { PMOD pMod; ushort j; OMFPreCompMap *pMap; static PMOD pModLast; // last module we installed static ushort usPreCompCount; static CV_typ_t MaxIndexLast; // saved MaxIndex value pMod = FindModule ((char *)&plf->name); if ((pMap = (OMFPreCompMap *) pMod->PreCompAddr) == NULL) { ErrorExit (ERR_NOMEM, NULL, NULL); } if (pMod->signature != plf->signature) { ErrorExit (ERR_PCTSIG, FormatMod (pCurMod), FormatMod(pMod)); } if ((pMap->cTypes != plf->count) || (MaxIndex + CV_FIRST_NONPRIM != plf->start)) { ErrorExit (ERR_PRECOMPERR, FormatMod (pCurMod), FormatMod (pMod)); } if (usInitCount == usPreCompCount + 1 && pMod == pModLast) { // we're doing the same module as last time... // let's short circuit everything usPreCompCount = usInitCount; MaxIndex = MaxIndexLast; if (PreviousMaxIndex > MaxIndex) { memset(ModNdxTab + MaxIndex, 0 , (PreviousMaxIndex - MaxIndex) * sizeof(TENTRY)); } PreviousMaxIndex = 0; return; } PostClearModNdx(); for (j = 0; j < plf->count; j++) { ModNdxTab[MaxIndex].CompactedIndex = pMap->map[j]; ModNdxTab[MaxIndex].flags.IsNewFormat = TRUE; ModNdxTab[MaxIndex++].flags.IsPreComp = TRUE; } usPreCompCount = usInitCount; MaxIndexLast = MaxIndex; pModLast = pMod; } LOCAL PMOD FindModule (char *pName) { PMOD pMod = ModuleList; char Name[257]; // search to end of module list while (pMod != NULL) { if ((pMod->pName != NULL) && (*pName == *pMod->pName)) { if (_tcsnicmp(pName + 1, pMod->pName + 1, (size_t)*pName) == 0) { return (pMod); } } pMod = pMod->next; } _tcsncpy(Name, pName + 1, (size_t)*pName); Name[*pName] = 0; ErrorExit (ERR_REFPRECOMP, Name, NULL); } COUNTER (cnt_GetTypeEntry); COUNTER (cnt_GetTypeEntry2); /** GetRecursiveIndex - * * Given a local index to a recursive structure, consults the * hash table to see if another similar structure is present * or not. If yes, return the global index, else insert the * structure into the compacted segment and return its index * */ COUNTER (cnt_GetRecursiveIndex); CV_typ_t GetRecursiveIndex (TENTRY *OldEntry, CV_typ_t OldIndex) { HSTYPE *j; TYPPTR pType; COUNT (cnt_GetRecursiveIndex); DASSERT (OldIndex >= usCurFirstNonPrim); DASSERT (MaxIndex > OldIndex - usCurFirstNonPrim); pType = (TYPPTR)OldEntry->TypeString; DASSERT(OldEntry->Count != 0); j = HTType[TypeHash (OldEntry)]; while (j != NULL) { if (IdenticalTree (OldEntry, OldIndex, (TYPPTR)j->Type, j->GlobalIndex)) { return (j->GlobalIndex); } else { j = j->Next; } } return (AddRecursiveType (OldIndex)); } /** FindFwdRef - find definition of forward reference * * * state = FindFwdRef (OldEntry, HSFWD **ppHash, fLocal) * * Entry OldEntry = pointer to index structure * fLocal = TRUE of local table to be searched * * Exit **ppHash = pointer to hash entry * * Return FWD_none if definition not found * FWD_local if definition found in local table * FWD_global if definition found in global table * FWD_globalfwd if forward reference found in global table */ FWD_t _fastcall FindFwdRef (TENTRY *OldEntry, HSFWD **ppHash, bool_t fLocal) { uchar *pName; TYPPTR pType = (TYPPTR)OldEntry->TypeString; FWD_t retval = FWD_none; switch (pType->leaf) { case LF_CLASS: case LF_STRUCTURE: pName = (uchar *)&((plfClass)&(pType->leaf))->data; pName += C7SizeOfNumeric (pName); break; case LF_UNION: pName = (uchar *)&((plfUnion)&(pType->leaf))->data; pName += C7SizeOfNumeric (pName); break; case LF_ENUM: pName = (uchar *)&((plfEnum)&(pType->leaf))->Name; break; default: return (retval); } if (fLocal) { if ((retval = FindLocalFwd (pType->leaf, pName, ppHash, IsUdtNested(pType))) != FWD_local) { retval = FindGlobalFwd (pType->leaf, pName, ppHash); } } else { retval = FindGlobalFwd (pType->leaf, pName, ppHash); } return (retval); } /** FindLocalFwd - find local definition of forward reference * * status = FindLocalFwd (leaf, pName, ppHash) * * Entry leaf = leaf type * pName = pointer to name string * pIndex = pointer to replacement index * * Exit **ppHash = pointer to hash entry * * Return FWD_none if definition not found * FWD_local if definition found in local table */ COUNTER (cnt_FindLocalFwd); LOCAL FWD_t FindLocalFwd (ushort leaf, char *pName, HSFWD **ppHash, bool_t isNested) { uchar *pc; uint Sum; uint i; uint hash; HSFWD *pHash; COUNT (cnt_FindLocalFwd); pc = pName; Sum = *pc; for (i = *pc++; i > 0; i--) { Sum += *pc++; } hash = Sum % HASH_FWD; pHash = HTLocalFwd[hash]; while ((pHash != NULL) && (pHash->pType != 0)) { DASSERT (pHash->index >= CV_FIRST_NONPRIM); if ((leaf == pHash->pType->leaf) && (pHash->pName[0] == pName[0]) && (memcmp(pHash->pName+1, pName+1, pName[0]) == 0) && (isNested == IsUdtNested(pHash->pType))) { *ppHash = pHash; return(FWD_local); } pHash = pHash->Next; } return (FWD_none); } /** FindGlobalFwd - find global definition of forward reference * * status = FindGlobalFwd (leaf, pName, pIndex) * * Entry leaf = leaf type * pName = pointer to name string * pIndex = pointer to replacement index * * Exit *pIndex = replacement index * * Return FWD_none if definition not found * FWD_global if definition found in global table * FWD_globalfwd if forward reference found in global table */ COUNTER (cnt_FindGlobalFwd); LOCAL FWD_t FindGlobalFwd (ushort leaf, char *pName, HSFWD **ppHash) { uchar *pc; uint Sum; uint i; uint hash; HSFWD *pHash; uchar **pBuf; FWD_t retval = FWD_none; TYPPTR pType; COUNT (cnt_FindGlobalFwd); pc = pName; Sum = *pc; for (i = *pc++; i > 0; i--) { Sum += *pc++; } hash = Sum % HASH_FWD; pHash = HTGlobalFwd[hash]; while ((pHash != NULL) && (pHash->pType != 0)) { DASSERT (pHash->index >= CV_FIRST_NONPRIM); if ((leaf == pHash->pType->leaf) && (pHash->pName[0] == pName[0]) && (memcmp(pHash->pName+1, pName+1, pName[0]) == 0)) { // the names and record types are identical. we now need // to check to see if this is a forward reference or a // definition pBuf = pGType[(pHash->index - CV_FIRST_NONPRIM) / GTYPE_INC]; pType = (TYPPTR)pBuf[(pHash->index - CV_FIRST_NONPRIM) % GTYPE_INC]; *ppHash = pHash; return(IsFwdRef(pHash->pType) ? FWD_globalfwd : FWD_global); } pHash = pHash->Next; } return (FWD_none); } /** HashFwdGlobal - hash type strings for forward ref resolution * * HashFwdGlobal (pType, pTable) * * Entry pType = pointer to type string * pTable = hash table to add string to * * Exit type string hashed into table * * Returns none */ COUNTER (cnt_HashFwd); INLINE void HashFwdGlobal (TYPPTR pType, CV_typ_t index) { uchar *pName; uchar *pc; uint Sum; uint hash; uint i; HSFWD *pHash; COUNT (cnt_HashFwd); switch (pType->leaf) { case LF_CLASS: case LF_STRUCTURE: pName = (uchar *)&((plfClass)&(pType->leaf))->data; pName += C7SizeOfNumeric (pName); break; case LF_UNION: pName = (uchar *)&((plfUnion)&(pType->leaf))->data; pName += C7SizeOfNumeric (pName); break; case LF_ENUM: pName = (uchar *)&((plfEnum)&(pType->leaf))->Name; break; default: // don't care about any of these just return; return; } pc = pName; Sum = *pc; for (i = *pc++; i > 0; i--) { Sum += *pc++; } DASSERT (index >= CV_FIRST_NONPRIM); hash = Sum % HASH_FWD; pHash = HTGlobalFwd[hash]; while ((pHash != NULL) && (pHash->pType != 0)) { DASSERT (pHash->index >= CV_FIRST_NONPRIM); if ((pType->leaf == pHash->pType->leaf) && (pHash->pName[0] == pName[0]) && (memcmp(pHash->pName+1, pName+1, pName[0]) == 0)) { return; } pHash = pHash->Next; } if (pHash == NULL) { // add new entry to table since we are at then end if ((pHash = (HSFWD *) CAlloc(sizeof (HSFWD))) == NULL) { ErrorExit(ERR_NOMEM, NULL, NULL); } pHash->Next = HTGlobalFwd[hash]; HTGlobalFwd[hash] = pHash; } pHash->pType = pType; pHash->pName = pName; pHash->index = index; } /** SumUCChar - generate sum of upper case character hash * * hash = SumUCChar (pSym, pSum, pLen, modulo) * * Entry pSym = pointer to symbol * pSum = pointer to sum * pLen = pointer of offset of length prefixed name * modulo = hash table size * * Exit *sum = sum of characters (upper cased) in name * * Returns *sum / modulo */ #define dwrd_toupper(dw) (dw & 0xDFDFDFDF) #define byt_toupper(b) (b & 0xDF) ushort NEAR DWordXorShift ( SYMPTR pSym, ulong *pSum, ushort *pLen, ushort *pSeg, ulong *pOff, ushort modulo ) { uchar *pbName; ulong UNALIGNED *pulName; int cb; int cul; int iul; ulong ulSum = 0; ulong ulEnd = 0; ushort seg = 0; ulong off = 0; switch (pSym->rectyp) { case S_CONSTANT: pbName = (uchar *)(&((CONSTPTR)pSym)->value); pbName += C7SizeOfNumeric (pbName); break; case S_GDATA16: case S_LDATA16: case S_PUB16: // Note that the structure pub16==data16 pbName = (uchar *)(&((DATAPTR16)pSym)->name); seg = ((DATAPTR16)pSym)->seg; off = ((DATAPTR16)pSym)->off; break; case S_GDATA32: case S_LDATA32: case S_PUB32: case S_GTHREAD32: case S_LTHREAD32: // Note that the structure pub32==data32==thread32 pbName = (uchar *)(&((DATAPTR32)pSym)->name); seg = ((DATAPTR32)pSym)->seg; off = ((DATAPTR32)pSym)->off; break; case S_UDT: pbName = (uchar *)(&((UDTPTR)pSym)->name); break; case S_GPROC16: case S_LPROC16: pbName = (uchar *)(&((PROCPTR16)pSym)->name); seg = ((PROCPTR16)pSym)->seg; off = ((PROCPTR16)pSym)->off; break; case S_GPROC32: case S_LPROC32: pbName = (uchar *)(&((PROCPTR32)pSym)->name); seg = ((PROCPTR32)pSym)->seg; off = ((PROCPTR32)pSym)->off; break; case S_GPROCMIPS: case S_LPROCMIPS: pbName = (uchar *)(&((PROCSYMMIPS *)pSym)->name); seg = ((PROCSYMMIPS *)pSym)->seg; off = ((PROCSYMMIPS *)pSym)->off; break; default: DASSERT ( FALSE ); *pSeg = 0; *pOff = 0; *pSum = 0; return (0); } *pLen = pbName - (uchar *)pSym; cb = *pbName++; pulName = (ulong UNALIGNED *) pbName; while ( cb & 3 ) { ulEnd |= byt_toupper ( pbName [ cb - 1 ] ); ulEnd <<= 8; cb -= 1; } cul = cb / 4; for ( iul = 0; iul < cul; iul++ ) { ulSum ^= dwrd_toupper(pulName[iul]); ulSum = _lrotl ( ulSum, 4 ); } ulSum ^= ulEnd; *pSeg = seg; *pOff = off; *pSum = ulSum; return (ushort) (ulSum % modulo); } /** PrepareGlobalTypeTable * * Entry TypeBuf - Linked list of blocks containing Global types. * The global type strings are unpadded. * * Exit GlobalTypeTable contains an array of offsets to the types. * These offsets are calculated on the assumption that at write * time the strings will be placed on 4 word bounderies. * */ void PrepareGlobalTypeTable () { ushort usTotal; // Length of record including size of length field ushort i; uchar *Types; ulong *pBuf; ulong Offset = 0; ushort cb = 0; for (i = 0; i < (CV_typ_t)(NewIndex - (CV_typ_t)CV_FIRST_NONPRIM); i++) { pBuf = (ulong *)pGType[i / GTYPE_INC]; Types = (uchar *) pBuf[i % GTYPE_INC]; // Get the length of this record usTotal = ((SYMPTR)Types)->reclen + LNGTHSZ; DASSERT( usTotal <= cbTypeAlign ); if ( cb + usTotal + PAD4 ( usTotal ) > cbTypeAlign ) { Offset += cbTypeAlign - cb; cb = 0; } cb += usTotal + PAD4 ( usTotal ); // Set offset in table pBuf[i % GTYPE_INC] = Offset; // Move to the next type Types += usTotal; // Calculate the address of the next type string after padding Offset += usTotal + PAD4 (usTotal); } DASSERT (i == (ushort)(NewIndex - CV_FIRST_NONPRIM)); } /** PackPublic - pack public symbol into list if possible * * flag = PackPublic (pSym, lpfnHash) * * Entry pSym = pointer to symbol * lpfnHash = pointer to hash function * * Exit symbol added to global symbol table if possible * original symbol type changed to S_CVRESERVE if packed * * Returns GPS_intable if symbol is in the global symbol table * GPS_added if symbol can be added to the global table * GPS_noadd if symbol of same name but different type in table * */ GPS_t PackPublic (SYMPTR pSym, LPFNHASH lpfnHash) { uchar *pName; uchar *pTemp; ushort hashName; ushort indName; GLOBALSYM *p; GLOBALSYM *pNew; ushort len; ushort iPad; uint cbReqd; ulong sumName; ushort seg = 0; ulong uoff = 0; iPad = PAD4 (pSym->reclen + LNGTHSZ); hashName = lpfnHash ( (SYMPTR)pSym, &sumName, &indName, &seg, &uoff, HASH_SYM ); pName = (uchar *)pSym + indName; len = *pName; for (p = HTPub[hashName]; p != NULL; p = p->Next) { pTemp = p->Sym + p->indName; if (sumName == p->sumName) { if (memcmp(pName, pTemp, len + 1) == 0) { // name is in global symbol table. Now make sure the // symbol record is identical. PCHAR arg1 = (PCHAR) (((PCHAR) pSym) + LNGTHSZ); PCHAR arg2 = (PCHAR) (((PCHAR) p->Sym) + LNGTHSZ); // Add the padding (otherwise, length may not match). int Length = (int) (pSym->reclen - p->indName - LNGTHSZ + iPad); if (memcmp (arg1, arg2, Length) == 0) { pSym->rectyp = S_CVRESERVE; cGlobalDel++; return (GPS_intable); } else { // the name is in the table, but the record is different PCHAR SymbolName = calloc(1, len+1); memcpy(SymbolName, pName+1, len); Warn (WARN_DUPPUBLIC, SymbolName, FormatMod (pCurMod)); free(SymbolName); return (GPS_noadd); } } } } cbReqd = (sizeof (GLOBALSYM) + pSym->reclen + LNGTHSZ + iPad); pNew = AllocForHT ( cbReqd ); pNew->sumName = sumName; pNew->indName = indName; pNew->seg = seg; pNew->uoff = uoff; memcpy (pNew->Sym, pSym, pSym->reclen + LNGTHSZ); pTemp = pNew->Sym + pSym->reclen + LNGTHSZ; ((SYMPTR)&(pNew->Sym))->reclen += iPad; cbPublics += pSym->reclen + LNGTHSZ + iPad; cPublics++; PADLOOP (iPad, pTemp); pNew->Next = HTPub[hashName]; HTPub[hashName] = pNew; pSym->rectyp = S_CVRESERVE; return (GPS_added); } /** PackSymbol - pack symbol into global symbol list if possible * * flag = PackSymbol (pSym, lpfnHash) * * Entry pSym = pointer to symbol * lpfnHash = pointer to hash function * * Exit symbol added to global symbol table if possible * original symbol type changed to S_CVRESERVE if packed * * Returns GPS_intable if symbol is in the global symbol table * GPS_added if symbol can be added to the global table * GPS_noadd if symbol of same name but different type in table * */ GPS_t _fastcall PackSymbol (SYMPTR pSym, LPFNHASH lpfnHash) { uchar *pName; uchar *pTemp; ushort hashName; ushort indName; GLOBALSYM *p; GLOBALSYM *pNew; ushort len; ushort iPad; uint cbReqd; ulong sumName; ushort seg = 0; ulong uoff = 0; hashName = lpfnHash ( (SYMPTR)pSym, &sumName, &indName, &seg, &uoff, HASH_SYM ); pName = (uchar *)pSym + indName; len = *pName; for (p = HPDBym[hashName]; p != NULL; p = p->Next) { pTemp = p->Sym + p->indName; if (sumName == p->sumName) { if (memcmp (pName, pTemp, len + 1) == 0) { // name is in global symbol table. Now make sure the // symbol record is identical. if (memcmp ((uchar *)pSym + LNGTHSZ, (uchar *)(&p->Sym) + LNGTHSZ, pSym->reclen) == 0) { pSym->rectyp = S_CVRESERVE; cGlobalDel++; return (GPS_intable); } else { // the name is in the table, but the record is different return (GPS_noadd); } } } } iPad = PAD4 (pSym->reclen + LNGTHSZ); cbReqd = sizeof (GLOBALSYM) + pSym->reclen + LNGTHSZ + iPad; pNew = AllocForHT ( cbReqd ); pNew->sumName = sumName; pNew->indName = indName; pNew->seg = seg; pNew->uoff = uoff; memcpy (pNew->Sym, pSym, pSym->reclen + LNGTHSZ); pTemp = pNew->Sym + pSym->reclen + LNGTHSZ; ((SYMPTR)&(pNew->Sym))->reclen += iPad; cbGlobalSym += pSym->reclen + LNGTHSZ + iPad; cGlobalSym++; PADLOOP (iPad, pTemp); pNew->Next = HPDBym[hashName]; HPDBym[hashName] = pNew; pSym->rectyp = S_CVRESERVE; return (GPS_added); } void WritePublics (OMFDirEntry *Dir, long lfoStart) { OMFSymHash hash; GLOBALSYM *p; VBuf NameHashBuf; VBlock *NameHashBlock; VBuf AddrHashBuf; VBlock *AddrHashBlock; ushort iHash; int PadCount; ulong Zero = 0; memset ( &hash, 0, sizeof (hash) ); cbPublics += AlignTable ( HTPub, sizeof ( long ) ); hash.cbSymbol = cbPublics; BuildHash ( &HASHFUNC, &hash.symhash, &hash.cbHSym, &NameHashBuf, cPublics, HTPub ); BuildSort ( &hash.addrhash, &hash.cbHAddr, &AddrHashBuf, cPublics, HTPub ); Dir->SubSection = sstGlobalPub; Dir->iMod = 0xffff; Dir->lfo = lfoStart; Dir->cb = sizeof (OMFSymHash) + hash.cbSymbol + hash.cbHSym + hash.cbHAddr; // write out global symbols if (!BWrite ((char *)&hash, sizeof (hash))) { ErrorExit (ERR_NOSPACE, NULL, NULL); } for (iHash = 0; iHash < HASH_SYM; iHash++) { for (p = HTPub[iHash]; p != NULL; p = p->Next) { DASSERT ( ((SYMPTR)(&(p->Sym)))->reclen < 1000 ); if (!BWrite (&p->Sym, ((SYMPTR)(&(p->Sym)))->reclen + LNGTHSZ)) { ErrorExit (ERR_NOSPACE, NULL, NULL); } } } // write out the hash table if ( hash.symhash != 0 ) { for ( NameHashBlock = VBufFirstBlock (&NameHashBuf); NameHashBlock != NULL; NameHashBlock = VBufNextBlock (NameHashBlock) ) { if (!BWrite (NameHashBlock->Address, NameHashBlock->Size)) { ErrorExit (ERR_NOSPACE, NULL, NULL); } } } if ( hash.addrhash != 0 ) { for ( AddrHashBlock = VBufFirstBlock (&AddrHashBuf); AddrHashBlock != NULL; AddrHashBlock = VBufNextBlock (AddrHashBlock) ) { if (!BWrite (AddrHashBlock->Address, AddrHashBlock->Size)) { ErrorExit (ERR_NOSPACE, NULL, NULL); } } } PadCount = (int)(sizeof (ulong) - (Dir->cb % sizeof (ulong))); if ((PadCount != 4) && (!BWrite (&Zero, PadCount))) { ErrorExit (ERR_NOSPACE, NULL, NULL); } if (verbose) { printf(get_err(MSG_PSYMSIZE), "\t\t", hash.cbSymbol, '\n'); } } void WriteGlobalSym (OMFDirEntry *Dir, long lfoStart) { OMFSymHash hash; GLOBALSYM *p; VBuf NameHashBuf; VBlock *NameHashBlock; VBuf AddrHashBuf; VBlock *AddrHashBlock; ushort iHash; int PadCount; ulong Zero = 0; #if 0 DASSERT(_heapchk() == _HEAPOK); #endif memset ( &hash, 0, sizeof (hash) ); cbGlobalSym += AlignTable ( HPDBym, sizeof ( long ) ); hash.cbSymbol = cbGlobalSym; BuildHash ( &HASHFUNC, &hash.symhash, &hash.cbHSym, &NameHashBuf, cGlobalSym, HPDBym ); #if 0 DASSERT(_heapchk() == _HEAPOK); #endif BuildSort ( &hash.addrhash, &hash.cbHAddr, &AddrHashBuf, cGlobalSym, HPDBym ); #if 0 DASSERT(_heapchk() == _HEAPOK); #endif Dir->SubSection = sstGlobalSym; Dir->iMod = 0xffff; Dir->lfo = lfoStart; Dir->cb = sizeof (OMFSymHash) + hash.cbSymbol + hash.cbHSym + hash.cbHAddr; // write out global symbols if (!BWrite ((char *)&hash, sizeof (hash))) { ErrorExit (ERR_NOSPACE, NULL, NULL); } for (iHash = 0; iHash < HASH_SYM; iHash++) { if (iHash == 0x205) { int i = 0; } for (p = HPDBym[iHash]; p != NULL; p = p->Next) { if (!BWrite (&p->Sym, ((SYMPTR)(&(p->Sym)))->reclen + LNGTHSZ)) { ErrorExit (ERR_NOSPACE, NULL, NULL); } } } // write out the hash table if ( hash.symhash != 0 ) { for ( NameHashBlock = VBufFirstBlock (&NameHashBuf); NameHashBlock != NULL; NameHashBlock = VBufNextBlock (NameHashBlock) ) { if (!BWrite (NameHashBlock->Address, NameHashBlock->Size)) { ErrorExit (ERR_NOSPACE, NULL, NULL); } } } if ( hash.addrhash != 0 ) { for ( AddrHashBlock = VBufFirstBlock (&AddrHashBuf); AddrHashBlock != NULL; AddrHashBlock = VBufNextBlock (AddrHashBlock) ) { if (!BWrite (AddrHashBlock->Address, AddrHashBlock->Size)) { ErrorExit (ERR_NOSPACE, NULL, NULL); } } } PadCount = (int)(sizeof (ulong) - (Dir->cb % sizeof (ulong))); if ((PadCount != 4) && (!BWrite (&Zero, PadCount))) { ErrorExit (ERR_NOSPACE, NULL, NULL); } if (verbose) { printf(get_err(MSG_SYMSIZE), "\t\t", InitialSymInfoSize, '\n', "\t\t", FinalSymInfoSize, '\n', "\t\t", hash.cbSymbol, '\n'); } } /** LinkScope - link lexicals scope * * LinkScope (pSym, cbSym) * * Entry pSym = pointer to symbol table * cbSym = count of bytes in symbol table * * Exit lexical scopes in symbol table linked * * Returns TRUE if scopes linked * FALSE if error linking scopes */ bool_t LinkScope (uchar *pStart, ulong cbSym) { SYMPTR pEnd; SYMPTR pPrev; SYMPTR pSym; SYMPTR pInit; SEARCHPTR pSearch; ulong offParent = 0; long Level = 0; // fill in the parent and end fields pSym = (SYMPTR)(pStart + sizeof (long)); pSearch = (SEARCHPTR)pSym; pEnd = (SYMPTR)(pStart + cbSym); while( pSym < pEnd ) { switch( ((SYMPTR)pSym)->rectyp) { case S_LPROC16: case S_GPROC16: case S_THUNK16: case S_BLOCK16: case S_WITH16: case S_LPROC32: case S_GPROC32: case S_THUNK32: case S_BLOCK32: case S_WITH32: case S_LPROCMIPS: case S_GPROCMIPS: // note that this works because all of these symbols // have a common format for the first fields. The // address variants follow the link fields. // put in the parent ((BLOCKPTR)pSym)->pParent = offParent; offParent = (uchar *)pSym - pStart; Level++; break; case S_END: if (Level > 0) { // fill in the end record to the parent ((BLOCKPTR)(pStart + offParent))->pEnd = (ulong)((uchar *)pSym - pStart); // reclaim his parent as the parent offParent = ((BLOCKPTR)(pStart + offParent))->pParent; Level--; } else { puts("Unbalanced S_END record encountered"); } break; } pSym = (SYMPTR)((uchar *)pSym + pSym->reclen + LNGTHSZ); } // Go to the end of the Search part of the symbols table pInit = (SYMPTR)pSearch; while (pInit < pEnd && pInit->rectyp == S_SSEARCH) { pInit = (SYMPTR)((uchar *)pInit + pInit->reclen + LNGTHSZ); } // Fill in the next fields while (((SYMPTR)pSearch < pEnd) && (pSearch->rectyp == S_SSEARCH)) { pPrev = (SYMPTR) pSearch; pSym = pInit; offParent = 0; while (pSym < pEnd) { switch ( ((SYMPTR)pSym)->rectyp ) { case S_LPROC16: case S_GPROC16: case S_THUNK16: case S_LPROC32: case S_GPROC32: case S_THUNK32: if (((PROCPTR)pSym)->pEnd == 0) { // bad lexical scope data return (FALSE); } if (((SYMPTR)pPrev)->rectyp == S_SSEARCH) { ((SEARCHPTR)pPrev)->startsym = (ulong)((uchar *)pSym - pStart); } else { ((PROCPTR)pPrev)->pNext = (ulong)((uchar *)pSym - pStart); } pPrev = pSym; pSym = (SYMPTR)((uchar *)pSym + pSym->reclen + LNGTHSZ); break; default: pSym = (SYMPTR)((uchar *)pSym + pSym->reclen + LNGTHSZ); } } pSearch = (SEARCHPTR)((uchar *)pSearch + pSearch->reclen + LNGTHSZ); } return (TRUE); } bool_t SegmentPresent (ushort defaultseg) { ushort i; for (i = 0; i < cSeg; i ++) { if (segnum[i] == defaultseg) { return (TRUE); } } return (FALSE); } ushort AddSearchSym (uchar *pSym, ushort seg) { uchar *pPad; int iPad; int len; len = ALIGN4 (sizeof (SEARCHSYM)); ((SEARCHPTR)pSym)->reclen = len - LNGTHSZ; iPad = PAD4 (sizeof (SEARCHSYM)); // Fill in all the fields with the data passed. ((SEARCHPTR)pSym)->rectyp = S_SSEARCH; ((SEARCHPTR)pSym)->seg = seg; ((SEARCHPTR)pSym)->startsym = 0; pPad = pSym + len - LNGTHSZ; PADLOOP (iPad, pPad); return (len); } /** * * AddDerivationListsToTypeSegment * * Finally put the lists into the type segment * */ LOCAL void AddDerivationListsToTypeSegment (void) { ushort i,j,l,m; plfClass BaseClassString; uchar *ScratchString; uchar *NewString; HSSTRING *k; plfDerived plfDer; PDCLASS DerivStructure; uchar **pBuf; if (NoMoTypes) { return; } for (i = 0; i < NextInDerivation; i ++) { DerivStructure = &DLists[i]; j = DerivStructure->Count; ScratchString = GetScratchString (2 * j + offsetof (lfDerived, drvdcls) + LNGTHSZ); NewString = ScratchString; // Set Length of type record and make pointer to derived leaf and // fill in the derived record ((TYPPTR)ScratchString)->len = 2 * j + offsetof (lfDerived, drvdcls); plfDer = (plfDerived)&(((TYPPTR)ScratchString)->leaf); plfDer->leaf = LF_DERIVED; plfDer->count = j; m = 0; for (; j > 0; j --) { plfDer->drvdcls[m++] = DerivStructure->List[j - 1]; } free (DerivStructure->List); // Check for a matching LF_DERIVED record l = StringHash (NewString); for (k = HPDBtring[l]; k != NULL; k = k->Next) { if (memcmp ((uchar *)k->TypeString, NewString, k->TypeString->len + LNGTHSZ) == 0) { break; } } // Add the new record to the global index table if there wasn't a match // Then store the new record index in the base class. pBuf = pGType[(DerivStructure->BClass - CV_FIRST_NONPRIM) / GTYPE_INC]; BaseClassString = (plfClass)(pBuf[(DerivStructure->BClass - CV_FIRST_NONPRIM) % GTYPE_INC] + LNGTHSZ); if (k == NULL) { k = (HSSTRING *) Alloc (sizeof (HSSTRING)); k->CompactedIndex = NewIndex; k->TypeString = (TYPPTR) VBufCpy (&TypeBuf, NewString, ((TYPPTR)NewString)->len + LNGTHSZ); k->Next = HPDBtring[l]; HPDBtring[l] = k; HPDBtringCnt[l]++; if ((NewIndex - CV_FIRST_NONPRIM) == LastGlobalTableIndex) { LastGlobalTableIndex += GTYPE_INC; pBuf = Alloc (GTYPE_INC * sizeof (uchar *)); pGType[(NewIndex - CV_FIRST_NONPRIM) / GTYPE_INC] = pBuf; } pBuf = pGType[(NewIndex - CV_FIRST_NONPRIM) / GTYPE_INC]; pBuf[(NewIndex - CV_FIRST_NONPRIM) % GTYPE_INC] = (uchar *)(k->TypeString); BaseClassString->derived = NewIndex++; if (NewIndex == 0) { Warn (WARN_65KTYPES, FormatMod (pCurMod), NULL); NoMoTypes = TRUE; return; } } else { BaseClassString->derived = k->CompactedIndex; } } } /** * * StringHash * * Hash a typestring as a string by adding in all the bytes except * the linkage. If the record type is LF_STRUCTURE, LF_CLASS, LF_UNION or * LF_ENUM, only the name is used for the hash. */ COUNTER (cnt_StringHash); #if DBG // { LOCAL ushort SHHits[HASH_STRING] = {HASH_STRING * 0}; void DumpStringHashHits() { ushort i; if (DbArray[7]) { printf("StringHash Hits\n"); for (i=0; i < HASH_STRING; i++) { if (SHHits[i]) { printf("%u\t%u\n", i, SHHits[i]); } } } } #endif // } static unsigned char const rgbTl[256] = { 0, 1, 3, 2, 6, 7, 5, 4, 13, 12, 14, 15, 11, 10, 8, 9, 26, 27, 25, 24, 28, 29, 31, 30, 23, 22, 20, 21, 17, 16, 18, 19, 52, 53, 55, 54, 50, 51, 49, 48, 57, 56, 58, 59, 63, 62, 60, 61, 46, 47, 45, 44, 40, 41, 43, 42, 35, 34, 32, 33, 37, 36, 38, 39, 105, 104, 106, 107, 111, 110, 108, 109, 100, 101, 103, 102, 98, 99, 97, 96, 115, 114, 112, 113, 117, 116, 118, 119, 126, 127, 125, 124, 120, 121, 123, 122, 93, 92, 94, 95, 91, 90, 88, 89, 80, 81, 83, 82, 86, 87, 85, 84, 71, 70, 68, 69, 65, 64, 66, 67, 74, 75, 73, 72, 76, 77, 79, 78, 210, 211, 209, 208, 212, 213, 215, 214, 223, 222, 220, 221, 217, 216, 218, 219, 200, 201, 203, 202, 206, 207, 205, 204, 197, 196, 198, 199, 195, 194, 192, 193, 230, 231, 229, 228, 224, 225, 227, 226, 235, 234, 232, 233, 237, 236, 238, 239, 252, 253, 255, 254, 250, 251, 249, 248, 241, 240, 242, 243, 247, 246, 244, 245, 187, 186, 184, 185, 189, 188, 190, 191, 182, 183, 181, 180, 176, 177, 179, 178, 161, 160, 162, 163, 167, 166, 164, 165, 172, 173, 175, 174, 170, 171, 169, 168, 143, 142, 140, 141, 137, 136, 138, 139, 130, 131, 129, 128, 132, 133, 135, 134, 149, 148, 150, 151, 147, 146, 144, 145, 152, 153, 155, 154, 158, 159, 157, 156 }; static unsigned char const rgbTh[256] = { 0, 165, 74, 239, 148, 49, 222, 123, 40, 141, 98, 199, 188, 25, 246, 83, 80, 245, 26, 191, 196, 97, 142, 43, 120, 221, 50, 151, 236, 73, 166, 3, 161, 4, 235, 78, 53, 144, 127, 218, 137, 44, 195, 102, 29, 184, 87, 242, 241, 84, 187, 30, 101, 192, 47, 138, 217, 124, 147, 54, 77, 232, 7, 162, 66, 231, 8, 173, 214, 115, 156, 57, 106, 207, 32, 133, 254, 91, 180, 17, 18, 183, 88, 253, 134, 35, 204, 105, 58, 159, 112, 213, 174, 11, 228, 65, 227, 70, 169, 12, 119, 210, 61, 152, 203, 110, 129, 36, 95, 250, 21, 176, 179, 22, 249, 92, 39, 130, 109, 200, 155, 62, 209, 116, 15, 170, 69, 224, 133, 32, 207, 106, 17, 180, 91, 254, 173, 8, 231, 66, 57, 156, 115, 214, 213, 112, 159, 58, 65, 228, 11, 174, 253, 88, 183, 18, 105, 204, 35, 134, 36, 129, 110, 203, 176, 21, 250, 95, 12, 169, 70, 227, 152, 61, 210, 119, 116, 209, 62, 155, 224, 69, 170, 15, 92, 249, 22, 179, 200, 109, 130, 39, 199, 98, 141, 40, 83, 246, 25, 188, 239, 74, 165, 0, 123, 222, 49, 148, 151, 50, 221, 120, 3, 166, 73, 236, 191, 26, 245, 80, 43, 142, 97, 196, 102, 195, 44, 137, 242, 87, 184, 29, 78, 235, 4, 161, 218, 127, 144, 53, 54, 147, 124, 217, 162, 7, 232, 77, 30, 187, 84, 241, 138, 47, 192, 101}; static unsigned char const rgbTea[256] = { 0, 151, 46, 185, 92, 203, 114, 229, 184, 47, 150, 1, 228, 115, 202, 93, 112, 231, 94, 201, 44, 187, 2, 149, 200, 95, 230, 113, 148, 3, 186, 45, 224, 119, 206, 89, 188, 43, 146, 5, 88, 207, 118, 225, 4, 147, 42, 189, 144, 7, 190, 41, 204, 91, 226, 117, 40, 191, 6, 145, 116, 227, 90, 205, 192, 87, 238, 121, 156, 11, 178, 37, 120, 239, 86, 193, 36, 179, 10, 157, 176, 39, 158, 9, 236, 123, 194, 85, 8, 159, 38, 177, 84, 195, 122, 237, 32, 183, 14, 153, 124, 235, 82, 197, 152, 15, 182, 33, 196, 83, 234, 125, 80, 199, 126, 233, 12, 155, 34, 181, 232, 127, 198, 81, 180, 35, 154, 13, 128, 23, 174, 57, 220, 75, 242, 101, 56, 175, 22, 129, 100, 243, 74, 221, 240, 103, 222, 73, 172, 59, 130, 21, 72, 223, 102, 241, 20, 131, 58, 173, 96, 247, 78, 217, 60, 171, 18, 133, 216, 79, 246, 97, 132, 19, 170, 61, 16, 135, 62, 169, 76, 219, 98, 245, 168, 63, 134, 17, 244, 99, 218, 77, 64, 215, 110, 249, 28, 139, 50, 165, 248, 111, 214, 65, 164, 51, 138, 29, 48, 167, 30, 137, 108, 251, 66, 213, 136, 31, 166, 49, 212, 67, 250, 109, 160, 55, 142, 25, 252, 107, 210, 69, 24, 143, 54, 161, 68, 211, 106, 253, 208, 71, 254, 105, 140, 27, 162, 53, 104, 255, 70, 209, 52, 163, 26, 141}; static uchar bHigh; static uchar bLow; static uchar bRes; INLINE void HashFun(uchar *pin) { bRes = rgbTl[bLow] ^ rgbTh[bHigh]; bLow = bHigh; bHigh = rgbTea[(uchar)(*pin ^ bRes)]; } LOCAL ushort _fastcall StringHash (uchar *TypeString) { ushort j, k; uchar *puc; uchar *pucEnd; TYPPTR pType = (TYPPTR)TypeString; COUNT (cnt_StringHash); j = 0; pucEnd = TypeString + pType->len + sizeof (pType->len); switch (pType->leaf) { case LF_STRUCTURE: case LF_CLASS: puc = (uchar *)&(((plfClass)&pType->leaf)->data); puc += C7SizeOfNumeric (puc); break; case LF_UNION: puc = (uchar *)&(((plfUnion)&pType->leaf)->data); puc += C7SizeOfNumeric (puc); break; case LF_ENUM: puc = (uchar *)&(((plfEnum)&pType->leaf)->Name); break; default: puc = TypeString; break; } k = pucEnd - puc; bHigh = 0; bLow = 0; DASSERT(k <= 65535); // what we are doing here is a loop unrolling of the CRC16 tea-leaf // algorithm, i decided to go this way because so many of the type records // are nearly identical // sps - 9/3/92 while (k) { ushort kMod8; kMod8 = ((k + 7) % 8); switch (kMod8) { case 7: HashFun (puc + 7); case 6: HashFun (puc + 6); case 5: HashFun (puc + 5); case 4: HashFun (puc + 4); case 3: HashFun (puc + 3); case 2: HashFun (puc + 2); case 1: HashFun (puc + 1); case 0: HashFun (puc + 0); } puc += kMod8 + 1; k = pucEnd - puc; } j = (ushort)((bHigh << 8) | bLow) % HASH_STRING; #if DBG // { SHHits[j]++; #endif // } return (j); } /** * * AddToDerivationList * * Adds a derived class to the derivation list of a base class * */ LOCAL void AddToDerivationList (CV_typ_t DerivedClass, CV_typ_t BaseClass) { plfClass BClassStr; ushort i; uchar **pBuf; pBuf = pGType[(BaseClass - CV_FIRST_NONPRIM) / GTYPE_INC]; BClassStr = (plfClass)(pBuf[(BaseClass - CV_FIRST_NONPRIM) % GTYPE_INC] + LNGTHSZ); DASSERT ((BClassStr->leaf == LF_CLASS) || (BClassStr->leaf == LF_STRUCTURE)); for (i = 0; i < NextInDerivation; i++) { if (DLists[i].BClass == BaseClass) { break; } } if (i == NextInDerivation) { // This is the first derivation for this class if (NextInDerivation == MaxDerivation) { // It won't fit in our current list, so lengthen the list. MaxDerivation += DCLASS_INC; DLists = (PDCLASS)NoErrorRealloc (DLists, MaxDerivation * sizeof (DCLASS)); } DLists[i].Count = 0; DLists[i].Max = DLIST_INC; DLists[i].BClass = BaseClass; DLists[i].List = (CV_typ_t *)Alloc (DLIST_INC * sizeof (CV_typ_t)); NextInDerivation++; } // Add the derived class if (DLists[i].Count == DLists[i].Max) { DLists[i].Max += DLIST_INC; DLists[i].List = (CV_typ_t *)NoErrorRealloc ( DLists[i].List, DLists[i].Max * sizeof (CV_typ_t)); } DLists[i].List[DLists[i].Count++] = DerivedClass; } /** * * TypeHash * * Map a type string to an integer without including the lower level * type indices * Uses C7 format type strings * */ COUNTER (cnt_TypeHash); LOCAL int _fastcall TypeHash (TENTRY *OldEntry) { int i; ushort j; int length; int index; uchar *TypeString; ushort hashval = 0; uchar *puc; TYPPTR pType = (TYPPTR)OldEntry->TypeString; if (OldEntry->Hash) return OldEntry->Hash; OldEntry->Hash = HASH_TYPE - 1; // set tmp hash so we don't recurse COUNT (cnt_TypeHash); hashval = (pType->leaf); switch (pType->leaf) { case LF_STRUCTURE: case LF_CLASS: puc = (uchar *)&(((plfClass)&pType->leaf)->data); puc += C7SizeOfNumeric (puc); break; case LF_UNION: puc = (uchar *)&(((plfUnion)&pType->leaf)->data); puc += C7SizeOfNumeric (puc); break; case LF_ENUM: puc = (uchar *)&(((plfEnum)&pType->leaf)->Name); break; case LF_MEMBER: puc = (uchar *)&(((plfMember)&pType->leaf)->offset); puc += C7SizeOfNumeric (puc); break; case LF_STMEMBER: puc = (uchar *)&(((plfSTMember)&pType->leaf)->Name); break; default: TypeString = OldEntry->TypeString; length = C7LENGTH (TypeString) + LNGTHSZ; j = 0; i = 0; while (i < length) { if (j == OldEntry->Count) { index = length; } else { if (OldEntry->flags.LargeList) { index = OldEntry->IndexUnion.IndexString[j]; } else { index = OldEntry->IndexUnion.Index[j]; } j ++; } while (i < index) { hashval = (hashval << 2) ^ TypeString[i++] ^ (hashval >> 14); } i += sizeof (CV_typ_t); } // check no more than 3 nested subtypes... i = OldEntry->Count; if (i > 3) { i = 3; } while (--i >= 0) { if (!IndexIsGlobal(OldEntry, (ushort) i)) { hashval ^= SubHash(OldEntry, (ushort) i); } } OldEntry->Hash = (hashval % HASH_TYPE); return OldEntry->Hash; } length = *puc++; while (--length > 0) { hashval = (hashval << 2) ^ (*puc++) ^ (hashval >> 14); } OldEntry->Hash = (hashval % HASH_TYPE); return OldEntry->Hash; } LOCAL ushort _fastcall SubHash (TENTRY *OldEntry, ushort iitem) { TYPPTR pType = (TYPPTR)OldEntry->TypeString; CV_typ_t forward; CV_typ_t next; TENTRY * TmpLocalEntry; ushort index; if (OldEntry->flags.LargeList) { index = OldEntry->IndexUnion.IndexString[iitem]; } else { index = OldEntry->IndexUnion.Index[iitem]; } next = *(CV_typ_t *)((uchar *)pType + index); if (next < usCurFirstNonPrim) return next; next -= usCurFirstNonPrim; TmpLocalEntry = GetTypeEntry (next, &forward); if (TmpLocalEntry->flags.IsInserted) return (TmpLocalEntry->Hash); else return (TypeHash(TmpLocalEntry)); } INLINE void CleanUpModuleIndexTable (void) { free(ModNdxTab); } #if 1 // { GTW: inline guard condition to FreeAllocStrings. void FreeAllocStrings_ (TENTRY *OldEntry) #else void FreeAllocStrings (TENTRY *OldEntry) #endif // } { if (OldEntry->flags.IsMalloced) { free (OldEntry->TypeString); OldEntry->flags.IsMalloced = FALSE; } else if (OldEntry->flags.IsPool2) { Pool2Free (OldEntry->TypeString); OldEntry->flags.IsPool2 = FALSE; } else if (OldEntry->flags.IsPool) { PoolFree (OldEntry->TypeString); OldEntry->flags.IsPool = FALSE; } } /** BuildHash * * Build a global symbol hash table using the hash function * passed in lpfnHash * * The format of this table is as follows: * * Position Size Description * * 0 2 # of hash entries * 2 2 filler to preserve nat. alignment * 4 4*n Hash table, each entry is the offset from * the start of this table to the * chain associated with its index. * 4+4*n 2*n Count of entries in each hash bucket * chain associated with its index. * 4 + 6*n 4*m Chain table, each entry is a length prefixed * list of offsets to the symbols associated with * this index. * * NOTE: All offsets are ulongs * */ LOCAL void BuildHash ( LPFNHASH lpfnHash, ushort *pusHashId, ulong *pcbHash, VBuf *HashBuf, ulong cSym, GLOBALSYM **HT ) { ulong ulSymbolAddr = 0; ushort HashSize; PECT *rgpect; POVFL rgpecet [ cpecetMax ] = { NULL }; ushort cpecet = 0; ushort cect = 0; ushort iect = 0; ulong cbAlloc; ushort index; PECT *ppect; PECT pect; ushort ipecet; ushort iHash; ulong ulChain; POVFL pOvfl; POVFL *ppOvfl; ushort culSymbol; ushort ipect; GLOBALSYM *p; if (cSym == 0) { return; } // compute size of hash table and allow for initial zero length. // the hashsize is always rounded to an even number so that the // count array is aligned. The intent is to minimize the average // length of the bucket to about cBucketSize entries per chain. We // are also assuming that the number of entries per bucket is less // than 65k. HashSize = (ushort) min (cSym / cBucketSize, 0xFFFF); HashSize = max (HashSize, MINHASH); HashSize = (HashSize + 1) & ~1; // Set up the chain tables for each bucket. rgpect is an array that // contains pointers to portions of the array of hash entry structures. // The hash entry structures contain the count of symbols in this bucket, // the offsets of the first cBucketSize symbols in the bucket and a pointer // to the overflow chain. cect = HashSize / cectMax + 1; rgpect = Alloc (cect * sizeof (PECT)); for (iect = 0; iect < cect; iect++) { cbAlloc = (iect == cect-1) ? (((long)HashSize * sizeof (ECT)) % (cectMax * sizeof (ECT))) : cectMax * sizeof (ECT); DASSERT (cbAlloc <= UINT_MAX); *(rgpect + iect) = CAlloc ((size_t)cbAlloc); } // loop through all of the symbols generating hash information // for each symbol for (iHash = 0; iHash < HASH_SYM; iHash++) { for (p = HT[iHash]; p != NULL; p = p->Next) { // compute hash index, pointer to pointer to chain and // pointer to chain if ( ((SYMPTR) (&p->Sym))->rectyp == S_ALIGN ) { ulSymbolAddr += ((SYMPTR)(&p->Sym))->reclen + LNGTHSZ; continue; } index = (ushort) (p->sumName % HashSize); ppect = rgpect + (index / cectMax); pect = *ppect + (index % cectMax); if (pect->culSymbol < culEct) { // the bucket has not overflowed pect->rgsoh[pect->culSymbol].uoff = ulSymbolAddr; pect->rgsoh[pect->culSymbol].ulHash = p->sumName; } else { // the bucket has overflowed. Walk the chain of // overflow buffers to the final bucket and store // the symbol offset ppOvfl = &pect->pOvflNext; culSymbol = (pect->culSymbol - culEct) % OVFL_C; while (*ppOvfl != NULL && (culSymbol == 0 || (*ppOvfl)->pOvflNext != NULL)) { ppOvfl = &(*ppOvfl)->pOvflNext; } if (culSymbol == 0) { ipecet = cpecet / cecetMax; if (rgpecet [ ipecet ] == NULL) { rgpecet [ ipecet ] = CAlloc (cbMaxAlloc); } *ppOvfl = rgpecet [ ipecet ] + ( cpecet % cecetMax ); cpecet += 1; } (*ppOvfl)->rgsoh[ culSymbol ].uoff = ulSymbolAddr; (*ppOvfl)->rgsoh[ culSymbol ].ulHash = p->sumName; } pect->culSymbol += 1; ulSymbolAddr += ((SYMPTR)(&p->Sym))->reclen + LNGTHSZ; } } // Now put all of this information into the VBuf VBufInit (HashBuf, NameHashBlockSize); // Write out the table size preserving natural alignment VBufCpy (HashBuf, (uchar *) &HashSize, sizeof (HashSize)); VBufSet (HashBuf, 0, sizeof (ushort)); // Write out the actual hash table ulChain = 0; for (iHash = 0; iHash < HashSize; iHash++) { ppect = rgpect + (iHash / cectMax); pect = *ppect + (iHash % cectMax); VBufCpy (HashBuf, (uchar *)&ulChain, sizeof (ulChain)); ulChain += pect->culSymbol * 2 * sizeof (ulong); } // Write out the bucket counts for (iHash = 0; iHash < HashSize; iHash++) { ppect = rgpect + (iHash / cectMax); pect = *ppect + (iHash % cectMax); VBufCpy (HashBuf, (uchar *)&pect->culSymbol, sizeof (culSymbol)); VBufSet (HashBuf, 0, sizeof ( ushort ) ); } // Write out the chains for (iHash = 0; iHash < HashSize; iHash++) { ppect = rgpect + (iHash / cectMax); pect = *ppect + (iHash % cectMax); pOvfl = pect->pOvflNext; culSymbol = pect->culSymbol; VBufCpy ( HashBuf, (uchar *)pect->rgsoh, min (culEct, culSymbol) * sizeof (SOH) ); culSymbol -= min (culEct, culSymbol); while (culSymbol > 0) { VBufCpy ( HashBuf, (uchar *)pOvfl->rgsoh, min (OVFL_C, culSymbol) * sizeof (SOH) ); culSymbol -= min (OVFL_C, culSymbol); pOvfl = pOvfl->pOvflNext; } } *pusHashId = 10; *pcbHash = sizeof (HashSize) + sizeof (ushort) + sizeof (ulong) * HashSize * 2 + sizeof (SOH) * cSym; // Now free all of our internal structures for (ipect = 0; ipect < cect; ipect++) { free (*(rgpect + ipect)); } free (rgpect); for (ipecet = 0; ipecet < cpecetMax; ipecet++) { free (rgpecet [ipecet]); } } typedef struct _EST { GLOBALSYM *pglb; ulong ulsym; } EST; // Entry in Sort Table typedef EST *PEST; typedef struct _SGN { int csym; int isym; PEST rgest; } SGN; // SeGment Node typedef SGN *PSGN; LOCAL int __cdecl GlbAddrCmp ( const void *pv1, const void *pv2 ) { const EST *pest1 = pv1; const EST *pest2 = pv2; return (int) ( pest1->pglb->uoff - pest2->pglb->uoff ); } LOCAL void BuildSort ( ushort *pusHashId, ulong *pcbHash, VBuf *SortBuf, ulong cSym, GLOBALSYM **HT ) { ushort cseg = 0; int iseg; int isym; int iHash; ulong ulsrt; PSGN rgsgn = NULL; ulong ulsym = 0; GLOBALSYM *p = NULL; int csymBogus = 0; if ( cSym == 0 ) { return; } // Find the number of segments used by the publics for ( iHash = 0; iHash < HASH_SYM; iHash++ ) { for ( p = HT[iHash]; p != NULL; p = p->Next ) { if ( ((SYMPTR) (&p->Sym))->rectyp != S_ALIGN && p->seg > (ushort) cseg ) { cseg = p->seg; } } } // Allocate an array containing global information for each segment rgsgn = CAlloc ( sizeof ( SGN ) * cseg ); for ( iHash = 0; iHash < HASH_SYM; iHash++ ) { for ( p = HT[iHash]; p != NULL; p = p->Next ) { if ( ((SYMPTR) (&p->Sym))->rectyp == S_ALIGN ) { // Do nothing -- cSym doesn't include align symbols } else if ( p->seg == 0 ) { csymBogus += 1; } else { rgsgn [ p->seg - 1 ].csym += 1; } } } // Allocate memory for the list of symbols associated w/ each segment for ( iseg = 0; iseg < (int) cseg; iseg++ ) { if ( rgsgn [ iseg ].csym ) { rgsgn [ iseg ].rgest = CAlloc ( rgsgn [ iseg ].csym * sizeof (EST) ); } } // Associate a pointer to each symbol with the appropriate segment for ( iHash = 0; iHash < HASH_SYM; iHash++ ) { for ( p = HT[iHash]; p != NULL; p = p->Next ) { PEST pest = NULL; if ( ((SYMPTR) (&p->Sym))->rectyp != S_ALIGN ) { iseg = p->seg - 1; if ( iseg != -1 ) { pest = &rgsgn [ iseg ].rgest [ rgsgn [ iseg ].isym++ ]; pest->pglb = p; pest->ulsym = ulsym; } } ulsym += ((SYMPTR)(&p->Sym))->reclen + LNGTHSZ; } } // Now sort the symbols within each segment for ( iseg = 0; iseg < (int) cseg; iseg++ ) { PSGN psgn = &rgsgn [ iseg ]; qsort ((void *)psgn->rgest, (size_t) psgn->csym, sizeof (EST), GlbAddrCmp ); } // Write the sorted table out to the vbuf VBufInit (SortBuf, NameHashBlockSize); // Write out the number of segments preserving natural alignment VBufCpy (SortBuf, (uchar *) &cseg, sizeof (cseg) ); VBufSet (SortBuf, 0, sizeof (ushort)); // Write out the position of each segment's info ulsrt = 0; for ( iseg = 0; iseg < (int) cseg; iseg++ ) { VBufCpy (SortBuf, (uchar *) &ulsrt, sizeof ( ulong ) ); ulsrt += rgsgn [ iseg ].csym * ( 2 * sizeof ( ulong ) ); } // Write out the count of symbols in each segment for ( iseg = 0; iseg < (int) cseg; iseg++ ) { // Note that this should really be a long rather than a short // bufferd by a 0 word, but that would requires a more global // change to this function, which would be too high impact // for right now. VBufCpy (SortBuf, (uchar *) &(rgsgn [ iseg ].csym), sizeof ( ushort ) ); VBufSet (SortBuf, 0, sizeof ( ushort ) ); } // Write out the sorted list of publics associated w/ each segment for ( iseg = 0; iseg < (int) cseg; iseg++ ) { PSGN psgn = &rgsgn [ iseg ]; for ( isym = 0; isym < psgn->csym; isym++ ) { VBufCpy ( SortBuf, (uchar *) &(psgn->rgest [ isym ].ulsym), sizeof ( ulong ) ); VBufCpy ( SortBuf, (uchar *) &(psgn->rgest [ isym ].pglb->uoff), sizeof ( ulong ) ); } } *pusHashId = 12; *pcbHash = sizeof (cseg) + sizeof (ushort) + sizeof (ulong) * cseg * 2 + sizeof (ulong) * ( cSym - csymBogus ) * 2; // Free the temporary memory for ( iseg = 0; iseg < (int) cseg; iseg++ ) { if ( rgsgn [ iseg ].rgest ) { free ( rgsgn [ iseg ].rgest ); } } free ( rgsgn ); } #define FNH_SIZE 50 typedef struct _FNH { unsigned char *szFileName; ulong ulFileOffset; struct _FNH *pfnhOrder; struct _FNH *pfnhNext; } FNH; // File Name Hash typedef FNH *PFNH; PFNH rgpfnh [ FNH_SIZE ]; typedef struct _MFO { ushort imod; ushort cFiles; struct _MFO *pmfoNext; ulong rgulFileOffset [ ]; } MFO; // Module File Offsets typedef MFO *PMFO; PFNH AddFileName ( unsigned char *pch, PFNH pfnhPrev, ulong ulFileOffset ) { // Assumes that filename does not already exist // Returns the structure created PFNH pfnhT = Alloc ( sizeof ( FNH ) ); pfnhT->szFileName = pch; pfnhT->ulFileOffset = ulFileOffset; pfnhT->pfnhOrder = NULL; pfnhPrev->pfnhOrder = pfnhT; return pfnhT; } void BuildFileIndex ( void ) { PMOD pmod = NULL; ushort cfilerefs = 0; FNH fnhHead = {0}; PFNH pfnhPrev = &fnhHead; PFNH pfnh = NULL; PFNH pfnhNext = NULL; ulong ulFileOffset = 0; MFO mfoHead = { 0 }; PMFO pmfoPrev = &mfoHead; PMFO pmfo = NULL; PMFO pmfoNext = NULL; OMFFileIndex *pfit = NULL; ushort imod = 0; ushort iulNames = 0; ulong *pulNames = NULL; unsigned char *pch = NULL; // Set up an intermediate structure memset ( rgpfnh, 0, sizeof ( PFNH ) * FNH_SIZE ); for ( pmod = ModuleList; pmod != NULL; pmod = pmod->next ) { OMFSourceModule *psmi = (OMFSourceModule *) pmod->SrcLnAddr; if ( psmi != NULL ) { int isf = 0; PMFO pmfoT = Alloc ( sizeof ( MFO ) + sizeof ( ulong ) * psmi->cFile ); pmfoT->imod = pmod->ModuleIndex; pmfoT->pmfoNext = NULL; pmfoT->cFiles = psmi->cFile; pmfoPrev->pmfoNext = pmfoT; pmfoPrev = pmfoT; for ( isf = 0; isf < (int) psmi->cFile; isf++ ) { OMFSourceFile *psfi = (OMFSourceFile *) ( psmi->baseSrcFile[isf] + pmod->SrcLnAddr ); unsigned char *pch = ( (char *) psfi->baseSrcLn ) + psfi->cSeg * ( sizeof ( ulong ) * 3 ); ulong ulFOT = 0; pfnhPrev = AddFileName ( pch, pfnhPrev, ulFileOffset ); pmfoT->rgulFileOffset [ isf ] = ulFileOffset; ulFileOffset += *pch + 1; cfilerefs += 1; } } } // Re-format as byte stream to written to disk FileIndexSize = sizeof ( ushort ) * 2 + // Initial fields sizeof ( ushort ) * 2 * cMod + // Module list & cfiles sizeof ( ulong ) * cfilerefs + // String offsets pfnhPrev->ulFileOffset + // String table *( pfnhPrev->szFileName ) + 1; FileIndexSize = ( FileIndexSize + 3 ) & ~3L; pfit = Alloc ( FileIndexSize ); FileIndex = (_vmhnd_t) pfit; pfit->cmodules = cMod; pfit->cfilerefs = cfilerefs; // Handle modulelist, cfiles, & ulNames arrays imod = 1; iulNames = 0; pulNames = (ulong *) &pfit->modulelist [ cMod * 2 ]; for ( pmfo = mfoHead.pmfoNext; pmfo != NULL; pmfo = pmfo->pmfoNext ) { // Fill in modules w/o source lines while ( imod < pmfo->imod ) { pfit->modulelist [ imod - 1 ] = 0; pfit->modulelist [ cMod + imod - 1 ] = 0; imod += 1; } pfit->modulelist [ imod - 1 ] = iulNames; pfit->modulelist [ cMod + imod - 1 ] = pmfo->cFiles; iulNames += pmfo->cFiles; memcpy ( pulNames, pmfo->rgulFileOffset, sizeof ( ulong ) * pmfo->cFiles ); pulNames += pmfo->cFiles; imod += 1; } // Fill in trailing modules w/o source lines while ( imod < cMod + 1 ) { pfit->modulelist [ imod - 1 ] = 0; pfit->modulelist [ cMod + imod - 1 ] = 0; imod += 1; } // Handle Name strings pch = (char *) &pfit->modulelist [ cMod * 2 + cfilerefs * 2 ]; for ( pfnh = fnhHead.pfnhOrder; pfnh != NULL; pfnh = pfnh->pfnhOrder ) { memcpy ( pch, pfnh->szFileName, (size_t)*pfnh->szFileName + 1 ); pch += *pch + 1; } // Free the temporary structures for ( pmfo = mfoHead.pmfoNext; pmfo != NULL; pmfo = pmfoNext ) { pmfoNext = pmfo->pmfoNext; free ( pmfo ); } for ( pfnh = fnhHead.pfnhOrder; pfnh != NULL; pfnh = pfnhNext ) { pfnhNext = pfnh->pfnhOrder; free ( pfnh ); } } void AddSymToTable ( SYMPTR pSym, GLOBALSYM **HT, int imod, ulong ibSym, ushort rectyp ) { ushort hashName; ulong sumName; ushort indName; GLOBALSYM *pNew; uint cbReqd; ushort seg = 0; ulong uoff = 0; REFSYM *prs; hashName = HASHFUNC ( pSym, &sumName, &indName, &seg, &uoff, HASH_SYM ); cbReqd = sizeof (GLOBALSYM) + sizeof (REFSYM); pNew = AllocForHT ( cbReqd ); pNew->sumName = sumName; pNew->indName = indName; pNew->seg = seg; pNew->uoff = uoff; prs = (REFSYM *) (pNew->Sym); prs->reclen = sizeof ( REFSYM ) - LNGTHSZ; prs->rectyp = rectyp; prs->sumName = sumName; prs->imod = imod; prs->ibSym = ibSym; pNew->Next = HT[hashName]; HT[hashName] = pNew; } void BuildStatics ( SYMPTR psymStart, ulong cbSym, int imod ) { ulong ibSym = sizeof ( ulong ); SYMPTR psym = (SYMPTR) (( (uchar *) psymStart ) + sizeof ( ulong )); while ( ibSym < cbSym ) { switch ( psym->rectyp ) { case S_GPROC16: case S_GPROC32: case S_GPROCMIPS: AddSymToTable ( psym, HPDBym, imod, ibSym, S_PROCREF ); ibSym = ( (PROCPTR) psym )->pEnd; psym = (SYMPTR) ( ((uchar *) psymStart) + ibSym ); cbGlobalSym += sizeof ( REFSYM ); cGlobalSym++; break; case S_LPROC16: case S_LPROC32: case S_LPROCMIPS: AddSymToTable ( psym, HTLoc, imod, ibSym, S_PROCREF ); ibSym = ( (PROCPTR) psym )->pEnd; psym = (SYMPTR) ( ((uchar *) psymStart) + ibSym ); cbStaticSym += sizeof ( REFSYM ); cStaticSym++; break; case S_LDATA16: case S_GDATA16: case S_LDATA32: case S_GDATA32: case S_LTHREAD32: case S_GTHREAD32: AddSymToTable ( psym, HTLoc, imod, ibSym, S_DATAREF ); cbStaticSym += sizeof ( REFSYM ); cStaticSym++; break; default: break; } // For procs we are now pointing to the end symbol, all others // we are pointing to the symbol we just processed ibSym += psym->reclen + LNGTHSZ; psym = (SYMPTR) ( ((uchar *) psym) + psym->reclen + LNGTHSZ ); } } void WriteStaticSym (OMFDirEntry *Dir, long lfoStart) { OMFSymHash hash; GLOBALSYM *p; VBuf NameHashBuf; VBlock *NameHashBlock; VBuf AddrHashBuf; VBlock *AddrHashBlock; ushort iHash; int PadCount; ulong Zero = 0; memset ( &hash, 0, sizeof (hash) ); cbStaticSym += AlignTable ( HTLoc, 0 ); hash.cbSymbol = cbStaticSym; BuildHash ( &HASHFUNC, &hash.symhash, &hash.cbHSym, &NameHashBuf, cStaticSym, HTLoc ); BuildSort ( &hash.addrhash, &hash.cbHAddr, &AddrHashBuf, cStaticSym, HTLoc ); Dir->SubSection = sstStaticSym; Dir->iMod = 0xffff; Dir->lfo = lfoStart; Dir->cb = sizeof (OMFSymHash) + hash.cbSymbol + hash.cbHSym + hash.cbHAddr; // write out static symbols if (!BWrite ((char *)&hash, sizeof (hash))) { ErrorExit (ERR_NOSPACE, NULL, NULL); } for (iHash = 0; iHash < HASH_SYM; iHash++) { if (iHash == 0x205) { int i = 0; } for (p = HTLoc[iHash]; p != NULL; p = p->Next) { if (!BWrite (&p->Sym, ((SYMPTR)(&(p->Sym)))->reclen + LNGTHSZ)) { ErrorExit (ERR_NOSPACE, NULL, NULL); } } } // write out the hash table if ( hash.symhash != 0 ) { for ( NameHashBlock = VBufFirstBlock (&NameHashBuf); NameHashBlock != NULL; NameHashBlock = VBufNextBlock (NameHashBlock) ) { if (!BWrite (NameHashBlock->Address, NameHashBlock->Size)) { ErrorExit (ERR_NOSPACE, NULL, NULL); } } } if ( hash.addrhash != 0 ) { for ( AddrHashBlock = VBufFirstBlock (&AddrHashBuf); AddrHashBlock != NULL; AddrHashBlock = VBufNextBlock (AddrHashBlock) ) { if (!BWrite (AddrHashBlock->Address, AddrHashBlock->Size)) { ErrorExit (ERR_NOSPACE, NULL, NULL); } } } PadCount = (int)(sizeof (ulong) - (Dir->cb % sizeof (ulong))); if ((PadCount != 4) && (!BWrite (&Zero, PadCount))) { ErrorExit (ERR_NOSPACE, NULL, NULL); } } ulong AlignTable ( GLOBALSYM **HT, int cbMinFill ) { int ipgs = 0; ushort offSym = 0; ushort cbMinAlignSym = cbMinFill + sizeof ( ALIGNSYM ); ulong offExtra = 0; for ( ipgs = 0; ipgs < HASH_SYM ; ipgs++ ) { GLOBALSYM *pgs = HT [ ipgs ]; GLOBALSYM *pgsPrev = NULL; while ( pgs != NULL ) { if ( offSym + ( (SYMPTR) pgs->Sym )->reclen + LNGTHSZ + cbMinAlignSym > (ushort) cbAlign ) { // Insert an alignment symbol uint cbSym = cbAlign - offSym; GLOBALSYM *pgsT = AllocForHT ( (sizeof ( GLOBALSYM ) + cbSym) ); SYMPTR psym = (SYMPTR) pgsT->Sym; pgsT->sumName = 0xFFFF; pgsT->indName = 0xFFFF; pgsT->seg = 0; pgsT->uoff = 0; memset ( psym, 0, cbSym ); psym->reclen = cbSym - LNGTHSZ; psym->rectyp = S_ALIGN; pgsT->Next = pgs; if ( pgsPrev ) { pgsPrev->Next = pgsT; } else { HT [ ipgs ] = pgsT; } offExtra += cbSym; offSym = 0; } offSym += ( (SYMPTR) pgs->Sym )->reclen + LNGTHSZ; pgsPrev = pgs; pgs = pgs->Next; } if ( ipgs == HASH_SYM - 1 && cbMinFill >= sizeof ( ulong ) ) { // Insert an end symbol uint cbSym = 2 * sizeof ( ulong ); GLOBALSYM *pgsT = AllocForHT ( (sizeof ( GLOBALSYM ) + cbSym) ); SYMPTR psym = (SYMPTR) pgsT->Sym; pgsT->sumName = 0xFFFF; pgsT->indName = 0xFFFF; pgsT->seg = 0; pgsT->uoff = 0; memset ( psym, 0xFF, cbSym ); psym->reclen = cbSym - LNGTHSZ; psym->rectyp = S_ALIGN; pgsT->Next = pgs; if ( pgsPrev ) { pgsPrev->Next = pgsT; } else { HT [ ipgs ] = pgsT; } offExtra += cbSym; } } return offExtra; }