Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1564 lines
34 KiB

/***********************************************************************
* Microsoft (R) 32-Bit Incremental Linker
*
* Copyright (C) Microsoft Corp 1992-95. All rights reserved.
*
* File: symbol.cpp
*
* File Comments:
*
* External symbol table for the linker/librarian/dumper.
*
***********************************************************************/
#include "link.h"
static const char *SzFromExternal(void *, void *);
static PPEXTERNAL RgpexternalSort(PST, int (__cdecl *)(const void *, const void *));
static int __cdecl CompareExternalName(const void *, const void *);
static int __cdecl CompareExternalAddr(const void *, const void *);
static int __cdecl CompareExternalMacAddr(const void *, const void *);
static BLK blkStringTable; // used for callback function during a sort
PEXTERNAL
LookupExternName (
PST pst,
SHORT TypeName,
const char *Name,
PBOOL pfNewSymbol)
/*++
Routine Description:
Looks up a symbol name in the external table. If not found, adds
the symbol to the external table. This routine sits on a lower level
generic hash table data structure, which intern sits on a dynamic array
data structure.
Arguments:
pst - symbol table to lookup symbol in
TypeName - Indicates if Name is a short name, or a long name.
Name - Pointer to symbol name.
pfNewSymbol - set to !0 if new symbol, otherwise not touched
Return Value:
A pointer to the EXTERNAL symbol for the named symbol.
--*/
{
PELEMENT pelement;
BOOL fNewSymbolDefined;
PHT pht;
assert(pst);
assert(Name);
pht = pst->pht;
assert(pht);
// Adds "Name" to Extern Table if not found.
if (TypeName == SHORTNAME) {
Name = strncpy(ShortName, Name, IMAGE_SIZEOF_SHORT_NAME);
}
// lookup the hashtable element
fNewSymbolDefined = 0;
pelement = PelementLookup_HT(Name, pst->pht, 1, (PVOID)&pst->blkStringTable, &fNewSymbolDefined);
// if the element wasn't found, a new element was allocated,
// blast in a new external into this element
if (fNewSymbolDefined) {
DWORD nm;
// NOTE: cbExteranl is less than sizeof(EXTERNAL) for x86, mips ilink.
pelement->pv = (EXTERNAL *) Calloc(1, cbExternal);
// let the caller know we have a new symbol
if (pfNewSymbol != NULL) {
*pfNewSymbol = TRUE;
}
((EXTERNAL *)(pelement->pv))->ImageSymbol = NullSymbol;
((EXTERNAL *)(pelement->pv))->ImageSymbol.StorageClass =
IMAGE_SYM_CLASS_EXTERNAL;
if (TypeName == LONGNAME) {
// on an ilink simply append the name to string table (COFF not supported on ilink)
if (fINCR) {
nm = AppendLongName(pst, Name);
} else {
nm = LookupLongName(pst, Name);
}
((EXTERNAL *)(pelement->pv))->ImageSymbol.n_offset = nm;
} else {
strncpy((char *)((EXTERNAL *)(pelement->pv))->ImageSymbol.n_name,
Name, IMAGE_SIZEOF_SHORT_NAME);
}
((EXTERNAL *)(pelement->pv))->pcon = NULL;
// Fake a state transition from defined to undefined. This adds it
// to the linked list of undefined things.
((PEXTERNAL)pelement->pv)->Flags |= EXTERN_DEFINED;
SetDefinedExt((PEXTERNAL) pelement->pv, FALSE, pst);
#if 0
// Following code isn't necessary because of calloc, but
// leave the code so we can determine where things happen.
((EXTERNAL *)(pelement->pv))->PtrSection = 0;
((EXTERNAL *)(pelement->pv))->Flags = 0; // !DEFINED !COMMON !EMITTED
((EXTERNAL *)(pelement->pv))->FinalValue = 0;
((EXTERNAL *)(pelement->pv))->ComDatCheckSum = 0;
((EXTERNAL *)(pelement->pv))->ComDatSelection = 0;
((EXTERNAL *)(pelement->pv))->WeakExternSearchType = 0;
((EXTERNAL *)(pelement->pv))->ArchiveMemberIndex = 0;
((EXTERNAL *)(pelement->pv))->pextWeakDefault = NULL;
#endif
}
return((EXTERNAL *) (pelement->pv));
}
PEXTERNAL
LookupExternSz (
PST pst,
const char *Name,
PBOOL pfNewSymbol)
{
SHORT TypeName;
PEXTERNAL pext;
TypeName = (SHORT) ((strlen(Name) <= IMAGE_SIZEOF_SHORT_NAME) ? SHORTNAME : LONGNAME);
pext = LookupExternName(pst, TypeName, Name, pfNewSymbol);
return(pext);
}
PEXTERNAL
SearchExternSz (
PST pst,
const char *Name)
/*++
Routine Description:
Search for a symbol name in the external table. If not found, return NULL.
This routine sits on a lower level generic hash table data structure,
which intern sits on a dynamic array data structure.
Arguments:
pst - symbol table to lookup symbol in
TypeName - Indicates if Name is a short name, or a long name.
Name - Pointer to symbol name.
Return Value:
A pointer to the EXTERNAL symbol for the named symbol.
--*/
{
PELEMENT pelement;
BOOL fNewSymbol;
// lookup the hashtable element
pelement = PelementLookup_HT(Name, pst->pht, 0, (PVOID)&pst->blkStringTable, &fNewSymbol);
if (pelement) {
return (PEXTERNAL) pelement->pv;
} else {
return NULL;
}
}
void
SetDefinedExt(PEXTERNAL pext, BOOL fNowDefined, PST pst)
{
if (!!(pext->Flags & EXTERN_DEFINED) == !!fNowDefined) {
return; // already in desired state
}
if (fNowDefined) {
if (!fINCR && pext->Flags & EXTERN_MULT_REFS) {
// Free the list of modules which referenced this symbol (on a non-ilink)
while (pext->pmodsFirst != NULL) {
PMODS pmods = pext->pmodsFirst;
pext->pmodsFirst = pmods->pmodsNext;
FreePv(pmods);
}
pext->Flags &= ~EXTERN_MULT_REFS;
}
pext->Flags |= EXTERN_DEFINED;
if (pext->pextNextUndefined != NULL) {
pext->pextNextUndefined->ppextPrevUndefined =
pext->ppextPrevUndefined;
}
*pext->ppextPrevUndefined = pext->pextNextUndefined;
if (pst->ppextLastUndefined == &pext->pextNextUndefined) {
pst->ppextLastUndefined = pext->ppextPrevUndefined;
}
// bug trap -- not strictly necessary
pext->ppextPrevUndefined = NULL;
pext->pextNextUndefined = NULL;
} else {
PEXTERNAL *ppextLoc;
pext->Flags &= ~EXTERN_DEFINED;
// Add the symbol to a link list of external symbols. The list is
// doubly linked to support deletion.
ppextLoc = pst->ppextLastUndefined;
assert(*ppextLoc == NULL ||
(*ppextLoc)->ppextPrevUndefined == ppextLoc);
pext->pextNextUndefined = *ppextLoc;
pext->ppextPrevUndefined = ppextLoc;
*ppextLoc = pext;
if (pext->pextNextUndefined != NULL) {
pext->pextNextUndefined->ppextPrevUndefined =
&pext->pextNextUndefined;
}
if (pst->ppextLastUndefined == ppextLoc) {
pst->ppextLastUndefined = &pext->pextNextUndefined;
}
// on an ilink we want to keep the list of references
if (!fINCR) {
pext->pmodOnly = NULL; // no references to this external
}
}
}
// Enumerator for all undefined symbols in an ST.
//
// You can change the current symbol's state to DEFINED without screwing
// up the enumeration.
//
// WARNING: there is some code in SearchLib() which knows about the internals
// of this enumerator.
//
INIT_ENM(UndefExt, UNDEF_EXT, (ENM_UNDEF_EXT *penm, PST pst)) {
penm->pextNext = pst->pextFirstUndefined;
}
NEXT_ENM(UndefExt, UNDEF_EXT) {
if ((penm->pext = penm->pextNext) == NULL) {
return FALSE;
}
assert(!(penm->pext->Flags & EXTERN_DEFINED));
penm->pextNext = penm->pext->pextNextUndefined;
return TRUE;
}
END_ENM(UndefExt, UNDEF_EXT) {
}
DONE_ENM
// AddReferenceExt
//
// Remembers (for error messages) that pmod references pext.
// pext must be undefined.
void
AddReferenceExt(PEXTERNAL pext, PMOD pmod)
{
PMODS pmods;
PMOD *rgpmod;
DWORD ipmod;
if (!fINCR && (pext->Flags & EXTERN_DEFINED)) {
return;
}
if (!(pext->Flags & EXTERN_MULT_REFS)) {
if (pext->pmodOnly == NULL) {
pext->pmodOnly = pmod;
return;
}
pmods = (PMODS) Calloc(1, sizeof(MODS) + CPMODS * sizeof(PMOD));
rgpmod = RgpmodPMODS(pmods);
rgpmod[0] = pext->pmodOnly;
rgpmod[1] = pmod;
pmods->pmodsNext = NULL;
pext->pmodsFirst = pmods;
pext->Flags |= EXTERN_MULT_REFS;
return;
}
rgpmod = RgpmodPMODS(pext->pmodsFirst);
for (ipmod = 1; ipmod < CPMODS; ipmod++) {
if (!rgpmod[ipmod]) {
rgpmod[ipmod] = pmod;
return;
}
}
pmods = (PMODS) Calloc(1, sizeof(MODS) + CPMODS * sizeof(PMOD));
rgpmod = RgpmodPMODS(pmods);
rgpmod[0] = pmod;
pmods->pmodsNext = pext->pmodsFirst;
pext->pmodsFirst = pmods;
}
// Enumerator for all the modules which reference an undefined external.
INIT_ENM(ModExt, MOD_EXT, (ENM_MOD_EXT *penm, PEXTERNAL pext)) {
if (!fINCR) {
assert(!(pext->Flags & EXTERN_DEFINED));
}
penm->pext = pext;
if (penm->pext->Flags & EXTERN_MULT_REFS) {
penm->pmods = penm->pext->pmodsFirst;
penm->ipmod = 0;
}
}
NEXT_ENM(ModExt, MOD_EXT) {
if (penm->pext == NULL) {
return FALSE;
}
if (!(penm->pext->Flags & EXTERN_MULT_REFS)) {
penm->pmod = penm->pext->pmodOnly;
penm->pext = NULL;
return penm->pmod != NULL;
}
for (;;) {
PMOD *rgpmod;
if (penm->pmods == NULL) {
return(FALSE);
}
rgpmod = RgpmodPMODS(penm->pmods);
// find a non-null pmod - a chunk may not be full & ilink can leave holes
while (penm->ipmod < CPMODS && !rgpmod[penm->ipmod]) {
penm->ipmod++;
}
if (penm->ipmod == CPMODS) {
penm->pmods = penm->pmods->pmodsNext;
penm->ipmod = 0;
} else {
penm->pmod = rgpmod[penm->ipmod];
penm->ipmod++;
return (TRUE);
}
}
}
END_ENM(ModExt, MOD_EXT) {
}
DONE_ENM
BOOL
FPextRef(
PEXTERNAL pext)
{
ENM_MOD_EXT enmModExt;
InitEnmModExt(&enmModExt, pext);
while (FNextEnmModExt(&enmModExt)) {
assert(enmModExt.pmod);
EndEnmModExt(&enmModExt);
return(TRUE);
}
EndEnmModExt(&enmModExt);
return(FALSE);
}
void
InitExternalSymbolTable(
PPST ppst,
DWORD celementInChunk,
DWORD cchunkInDir)
/*++
Routine Description:
Initialize the external symbol table. The external symbol table sits
on top of an underlying dynamic hash table.
Arguments:
ppst - external structure to initialize
celementInChunk - no. of elements
celementInDir - no. of dir entries
Return Value:
None.
--*/
{
*ppst = (PST) Calloc(1, sizeof(ST));
Init_HT(
&((*ppst)->pht), // hash table pointer to be filled in
celementInChunk, // number of elements in dynamic array chunk
cchunkInDir, // number of chunks in dynamic array
SzFromExternal, // routine to extract element name from external
0); // initial status flags of hash table
(*ppst)->pextFirstUndefined = NULL;
(*ppst)->ppextLastUndefined = &(*ppst)->pextFirstUndefined;
}
// in the incr case reset values of fields
void
IncrInitExternalSymbolTable(
PPST ppst)
{
assert(ppst);
assert(*ppst);
assert((*ppst)->pht);
(*ppst)->pht->SzFromPv = SzFromExternal;
(*ppst)->pextFirstUndefined = NULL;
(*ppst)->ppextLastUndefined = &(*ppst)->pextFirstUndefined;
}
void
FreeExternalSymbolTable(
PPST ppst)
/*++
Routine Description:
Free's up the external symbol table.
Arguments:
ppst - external structure to initialize
Return Value:
None.
--*/
{
assert(ppst);
assert(*ppst);
// free underlying hash table
Free_HT(&((*ppst)->pht));
// free string table
FreeBlk(&((*ppst)->blkStringTable));
// UNDONE: It is not safe to free this. It is allocated with Calloc()
// free the symbol table structure
free(*ppst);
// done
*ppst = NULL;
}
void
InitEnumerateExternals(
PST pst)
/*++
Routine Description:
initialize the enumeration of the external symbol table
Argument:
pst - external structure to enumerate
Return Value:
None.
--*/
{
InitEnumeration_HT(pst->pht);
}
PEXTERNAL
PexternalEnumerateNext(
PST pst)
/*++
Routine Description:
Get the next element in the enumeration of a hash table.
Arguments:
pst - external structure to enumerate
Return Value:
None.
--*/
{
ELEMENT *pelement;
pelement = PelementEnumerateNext_HT(pst->pht);
if (pelement) {
return ((PEXTERNAL) pelement->pv);
} else {
return (NULL);
}
}
void
TerminateEnumerateExternals(
PST pst)
/*++
Routine Description:
Pop an enumeration state from hash table state stack.
Arguments:
pst - external sturcture to enumerate
Return Value:
None.
--*/
{
TerminateEnumerate_HT(pst->pht);
}
static const char *
SzFromExternal(
void *pvExt,
void *pvblk
)
/*++
Routine Description:
Get a symbol name from an EXTERNAL data structure. If the result of this
is being compared with another symbol, ensure that the other symbol name
is not extracted with this routine, as there is only one buffer for short
names.
Arguments:
pexternal - pointer to an EXTERNAL
Return Value:
Return a symbol name.
--*/
{
PEXTERNAL pexternal = (PEXTERNAL) pvExt;
PBLK pblk = (PBLK) pvblk;
static CHAR szBuf[IMAGE_SIZEOF_SHORT_NAME+1];
assert(pexternal);
if (IsLongName(pexternal->ImageSymbol)) {
return ((char *)&pblk->pb[pexternal->ImageSymbol.n_offset]);
}
return(strncpy(szBuf, (char *) pexternal->ImageSymbol.n_name, IMAGE_SIZEOF_SHORT_NAME));
}
DWORD
Cexternal(
PST pst)
/*++
Routine Description:
Return the number of EXTERNALs in an external symbol table.
Arguments:
pst - pointer to external symbol table
Return Value:
return number of elements in symbol table
--*/
{
return (Celement_HT(pst->pht));
}
static INT __cdecl
CompareExternalAddr(
const void * pv1,
const void * pv2)
/*++
Routine Description:
compare two externals by address
Arguments:
pv1 - first external to compare
pv2 - second external to compare
Return Value:
< 0 if pv1 < pv2
= 0 if pv1 == pv2
> 0 if pv1 > pv2
--*/
{
PEXTERNAL pext1 = *((PPEXTERNAL) pv1);
PEXTERNAL pext2 = *((PPEXTERNAL) pv2);
return ((pext1->FinalValue - pext2->FinalValue));
}
static INT __cdecl
CompareExternalMacAddr(
const void * pv1,
const void * pv2)
/*++
Routine Description:
compare two externals by mac address
Arguments:
pv1 - first external to compare
pv2 - second external to compare
Return Value:
< 0 if pv1 < pv2
= 0 if pv1 == pv2
> 0 if pv1 > pv2
--*/
{
PEXTERNAL pext1 = *((PPEXTERNAL) pv1);
PEXTERNAL pext2 = *((PPEXTERNAL) pv2);
WORD isec1;
WORD isec2;
// "Some sort of exception case -- ignore it." - quote from EmitMap().
// Basically means ignore symbols created by the linker, like "end"
// Sort these wierd symbols to be at the end of the list. Also ignore
// undefined symbols which can result if -force is used.
if (!(pext1->Flags & EXTERN_DEFINED) || pext1->pcon == NULL) {
return 1;
}
if (!(pext2->Flags & EXTERN_DEFINED) || pext2->pcon == NULL) {
return -1;
}
isec1 = PsecPCON(pext1->pcon)->isec;
isec2 = PsecPCON(pext2->pcon)->isec;
if (isec1 != isec2) {
return(isec1 - isec2);
}
return(pext1->FinalValue - pext2->FinalValue);
}
static INT __cdecl
CompareExternalModName(
const void * pv1,
const void * pv2)
/*++
Routine Description:
compare two externals by name
Arguments:
pv1 - first external to compare
pv2 - second external to compare
Return Value:
< 0 if pv1 < pv2
= 0 if pv1 == pv2
> 0 if pv1 > pv2
--*/
{
PEXTERNAL pext1;
PEXTERNAL pext2;
WORD ArchiveMemberIndex1;
WORD ArchiveMemberIndex2;
char szB1[IMAGE_SIZEOF_SHORT_NAME+1];
char szB2[IMAGE_SIZEOF_SHORT_NAME+1];
char *sz1;
char *sz2;
pext1 = *((PPEXTERNAL) pv1);
pext2 = *((PPEXTERNAL) pv2);
ArchiveMemberIndex1 = pext1->ArchiveMemberIndex;
ArchiveMemberIndex2 = pext1->ArchiveMemberIndex;
if (ArchiveMemberIndex1 < ArchiveMemberIndex2) {
return(-1);
}
if (ArchiveMemberIndex1 > ArchiveMemberIndex2) {
return(1);
}
if (IsLongName(pext1->ImageSymbol)) {
sz1 = (char *)(&blkStringTable.pb[pext1->ImageSymbol.n_offset]);
} else {
sz1 = strncpy(szB1, (char *) (pext1->ImageSymbol.n_name), IMAGE_SIZEOF_SHORT_NAME);
sz1[IMAGE_SIZEOF_SHORT_NAME] = '\0';
}
if (IsLongName(pext2->ImageSymbol)) {
sz2 = (char *)(&blkStringTable.pb[pext2->ImageSymbol.n_offset]);
} else {
sz2 = strncpy(szB2, (char *)(pext2->ImageSymbol.n_name), IMAGE_SIZEOF_SHORT_NAME);
sz2[IMAGE_SIZEOF_SHORT_NAME] = '\0';
}
return(strcmp(sz1, sz2));
}
static INT __cdecl
CompareExternalName(
const void * pv1,
const void * pv2)
/*++
Routine Description:
compare two externals by name
Arguments:
pv1 - first external to compare
pv2 - second external to compare
Return Value:
< 0 if pv1 < pv2
= 0 if pv1 == pv2
> 0 if pv1 > pv2
--*/
{
PEXTERNAL pext1;
PEXTERNAL pext2;
char szB1[IMAGE_SIZEOF_SHORT_NAME+1];
char szB2[IMAGE_SIZEOF_SHORT_NAME+1];
char *sz1;
char *sz2;
pext1 = *((PPEXTERNAL) pv1);
pext2 = *((PPEXTERNAL) pv2);
if (IsLongName(pext1->ImageSymbol)) {
sz1 = (char *)(&blkStringTable.pb[pext1->ImageSymbol.n_offset]);
} else {
sz1 = strncpy(szB1, (char *) (pext1->ImageSymbol.n_name), IMAGE_SIZEOF_SHORT_NAME);
sz1[IMAGE_SIZEOF_SHORT_NAME] = '\0';
}
if (IsLongName(pext2->ImageSymbol)) {
sz2 = (char *)(&blkStringTable.pb[pext2->ImageSymbol.n_offset]);
} else {
sz2 = strncpy(szB2, (char *)(pext2->ImageSymbol.n_name), IMAGE_SIZEOF_SHORT_NAME);
sz2[IMAGE_SIZEOF_SHORT_NAME] = '\0';
}
return(strcmp(sz1, sz2));
}
static PPEXTERNAL
RgpexternalSort(
PST pst,
INT (__cdecl *pfnCompare)(const void *, const void *))
/*++
Routine Description:
sort the external table
Arguments:
pst - pointer to external structure to sort in address order
Compare - routine to compare two PEXTERNALs
Return Value:
pointer to a table pst->celement large containing sorted externals
--*/
{
PEXTERNAL *rgpexternal;
DWORD ipexternal;
DWORD cpexternal;
// set status to inserts not allowed
SetStatus_HT(pst->pht, HT_InsertsNotAllowed);
// get the number of externals
cpexternal = Cexternal(pst);
// allocate space for the externals
rgpexternal = (PPEXTERNAL) PvAllocZ(cpexternal * sizeof(PEXTERNAL));
// enumerate the external structure filling in the table
InitEnumerateExternals(pst);
for(ipexternal = 0; ipexternal < cpexternal; ipexternal++) {
rgpexternal[ipexternal] = PexternalEnumerateNext(pst);
}
TerminateEnumerateExternals(pst);
// sort the table by address
qsort((PVOID) rgpexternal, (size_t) cpexternal, sizeof(PEXTERNAL),
pfnCompare);
// return the sorted table
return (rgpexternal);
}
PPEXTERNAL
RgpexternalByAddr(
PST pst)
/*++
Routine Description:
return a pointer to a Cexternal(pst) element table sorted by address
Arguments:
pst - pointer to external structure
Return Value:
pointer to table of externals
--*/
{
if (!pst->rgpexternalByAddr) {
pst->rgpexternalByAddr = RgpexternalSort(pst, CompareExternalAddr);
}
return pst->rgpexternalByAddr;
}
PPEXTERNAL
RgpexternalByMacAddr(
PST pst)
/*++
Routine Description:
return a pointer to a Cexternal(pst) element table sorted by Macintosh
address (i.e. sort first by isec, and then by offset)
Arguments:
pst - pointer to external structure
Return Value:
pointer to table of externals
--*/
{
if (!pst->rgpexternalByMacAddr) {
pst->rgpexternalByMacAddr = RgpexternalSort(pst, CompareExternalMacAddr);
}
return pst->rgpexternalByMacAddr;
}
PPEXTERNAL
RgpexternalByModName(
PST pst)
/*++
Routine Description:
return a pointer to a Cexternal(pst) element table sorted by archive member index, name
Arguments:
pst - pointer to external structure
Return Value:
pointer to table of externals
--*/
{
if (!pst->rgpexternalByModName) {
blkStringTable = pst->blkStringTable; // hack
pst->rgpexternalByModName = RgpexternalSort(pst, CompareExternalModName);
}
return pst->rgpexternalByModName;
}
PPEXTERNAL
RgpexternalByName(
PST pst)
/*++
Routine Description:
return a pointer to a Cexternal(pst) element table sorted by name
Arguments:
pst - pointer to external structure
Return Value:
pointer to table of externals
--*/
{
if (!pst->rgpexternalByName) {
blkStringTable = pst->blkStringTable; // hack
pst->rgpexternalByName = RgpexternalSort(pst, CompareExternalName);
}
return pst->rgpexternalByName;
}
VOID
AllowInserts (
PST pst
)
/*++
Routine Description:
Allow for inserts again.
Arguments:
pst - pointer to external structure
Return Value:
pointer to table of externals
--*/
{
WORD status;
status = GetStatus_HT(pst->pht);
if (status & HT_InsertsNotAllowed) {
// set new status of inserts allowed
status &= ~(HT_InsertsNotAllowed);
SetStatus_HT(pst->pht, status);
// free up the sorted tables
assert(pst->rgpexternalByAddr || pst->rgpexternalByName);
if (pst->rgpexternalByAddr) {
FreePv(pst->rgpexternalByAddr);
pst->rgpexternalByAddr = NULL;
}
if (pst->rgpexternalByMacAddr) {
FreePv(pst->rgpexternalByMacAddr);
pst->rgpexternalByMacAddr = NULL;
}
if (pst->rgpexternalByModName) {
FreePv(pst->rgpexternalByModName);
pst->rgpexternalByModName = NULL;
}
if (pst->rgpexternalByName) {
FreePv(pst->rgpexternalByName);
pst->rgpexternalByName = NULL;
}
}
}
VOID
SearchForDuplicate (
PST pst,
const char *Name,
WORD *Count,
char **Match,
char **MatchFilename,
BOOL SkipUnderscore
)
/*++
Routine Description:
Searches for duplicate names while performing a fuzzy lookup.
Arguments:
Name - Name to look for.
pst - Pointer to external structure.
Return Value:
None.
--*/
{
PBLK pblk;
PPEXTERNAL rgpexternal;
DWORD cpexternal;
DWORD ipexternal;
pblk = &pst->blkStringTable;
rgpexternal = RgpexternalByName(pst);
cpexternal = Cexternal(pst);
for (ipexternal = 0; ipexternal < cpexternal; ipexternal++) {
PEXTERNAL pexternal;
pexternal = rgpexternal[ipexternal];
if ((pexternal->Flags & EXTERN_DEFINED) &&
!(pexternal->Flags & EXTERN_FUZZYMATCH)) {
const char *szNameObj;
size_t cchName;
WORD skipChar;
szNameObj = SzNameSym(pexternal->ImageSymbol, *pblk);
if ((szNameObj[0] == '?') ||
(szNameObj[0] == '@') ||
(SkipUnderscore && (szNameObj[0] == '_'))) {
skipChar = 1;
} else {
skipChar = 0;
}
cchName = strlen(Name);
if (!strncmp(Name, szNameObj+skipChar, cchName)) {
if ((szNameObj[cchName+skipChar] == '\0') ||
(szNameObj[cchName+skipChar] == '@')) {
if (*Count && !strcmp(Match[0], szNameObj)) {
// if the symbol matches the first symbol, ignore it.
continue;
}
// UNDONE: There is no protection against overflowing
// UNDONE: the Match and MatchFilename arrays.
Match[*Count] = SzDup(szNameObj);
if (pexternal->pcon == NULL) {
MatchFilename[*Count] = "(common)";
} else {
MatchFilename[*Count] = SzObjNamePCON(pexternal->pcon);
}
(*Count)++;
}
}
}
}
}
VOID
FuzzyLookupPext (
PEXTERNAL pexternal,
PST pstDef,
PST pstObj,
PLIB plibHeadObj,
BOOL SkipUnderscore)
/*++
Routine Description:
Compares ??? for each external symbol.
Arguments:
pstDef - Pointer to def file externals.
pstObj - Pointer to externals found in objs & libs.
bLibLookup - if TRUE do a lookup of the libs as well.
Return Value:
None.
--*/
{
PBLK pblk;
static char shortName[IMAGE_SIZEOF_SHORT_NAME+1];
const char *szDefSymbolName;
WORD found;
char *matches[60];
char *matchesFilenames[60];
size_t cch;
char *szMatch;
PEXTERNAL pextNew;
pblk = &pstDef->blkStringTable;
if (pexternal->szOtherName) {
if (pexternal->Flags & EXTERN_FORWARDER) {
szDefSymbolName = strchr(pexternal->szOtherName, '.') + 1;
if (szDefSymbolName[0] == '#') {
if (IsLongName(pexternal->ImageSymbol)) {
szDefSymbolName = (char *)(&pblk->pb[pexternal->ImageSymbol.n_offset]);
} else {
szDefSymbolName = strncpy(shortName,
(char *)(pexternal->ImageSymbol.n_name), IMAGE_SIZEOF_SHORT_NAME);
}
}
} else {
szDefSymbolName = pexternal->szOtherName;
}
} else {
if (IsLongName(pexternal->ImageSymbol)) {
szDefSymbolName = (char *)(&pblk->pb[pexternal->ImageSymbol.n_offset]);
} else {
szDefSymbolName = strncpy(shortName,
(char *)(pexternal->ImageSymbol.n_name), IMAGE_SIZEOF_SHORT_NAME);
}
}
if (strchr(szDefSymbolName, '@') != 0) {
// Skip the symbol if it is already decorated
return;
}
found = 0;
SearchForDuplicate(pstObj, szDefSymbolName, &found, matches, matchesFilenames, SkipUnderscore);
if (plibHeadObj != NULL) {
BOOL fSameLanguageMatch;
WORD iszT;
fSameLanguageMatch = FALSE;
for (iszT = 0; iszT < found; iszT++) {
if (matches[iszT][0] != '?') {
fSameLanguageMatch = TRUE;
break;
}
}
if ((found == 0) || !fSameLanguageMatch) {
ENM_LIB enm_lib;
// Not found in the objects, so search the libs.
cch = strlen(szDefSymbolName);
InitEnmLib(&enm_lib, plibHeadObj);
while (FNextEnmLib(&enm_lib)) {
PLIB plib;
DWORD i;
plib = enm_lib.plib;
for (i = 0; i < plib->csymIntMem; i++) {
char *szObjSymbolName;
WORD skipChar;
szObjSymbolName = plib->rgszSym[i];
if ((szObjSymbolName[0] == '?') ||
(szObjSymbolName[0] == '@') ||
(SkipUnderscore && (szObjSymbolName[0] == '_'))) {
skipChar = 1;
} else {
skipChar = 0;
}
if (!strncmp(szDefSymbolName, szObjSymbolName+skipChar, cch)) {
if ((szObjSymbolName[skipChar+cch] == '\0') ||
(szObjSymbolName[skipChar+cch] == '@')) {
if (found) {
// If the symbol matches the first symbol
// we found, then we can ignore it.
if (!strcmp(matches[0], szObjSymbolName)) {
continue;
}
}
if (found < 60) {
matches[found] = SzDup(szObjSymbolName);
matchesFilenames[found++] = plib->szName;
}
}
}
}
}
}
}
if (found == 0) {
SetDefinedExt(pexternal, FALSE, pstDef);
if (pexternal->pcon != NULL) {
AddReferenceExt(pexternal, PmodPCON(pexternal->pcon));
}
return;
}
if (found == 1) {
szMatch = matches[0];
} else {
WORD cszNonDname;
WORD isz;
WORD iszNonDname;
WORD iszT;
// Found more than one match. Look for an exact match,
cszNonDname = 0;
for (isz = 0; isz < found; isz++) {
szMatch = matches[isz];
if (strcmp(szMatch, szDefSymbolName) == 0) {
break;
}
if (szMatch[0] != '?') {
cszNonDname++;
iszNonDname = isz;
}
}
if (isz == found) {
// Did not find an exact match
if (cszNonDname == 1) {
// If only one name isn't decorated, select it as a match
isz = iszNonDname;
szMatch = matches[isz];
} else {
// UNDONE: This code could be executed by a call to
// UNDONE: FuzzyLookup for the entry point and should
// UNDONE: not use DefFilename.
BadFuzzyMatch = TRUE;
Warning(DefFilename, MULTIPLEFUZZYMATCH, szDefSymbolName);
for (isz = 0; isz < found; isz++) {
char *szOutput = SzOutputSymbolName(matches[isz], TRUE);
Warning(DefFilename, FUZZYMATCHINFO, szOutput,
matchesFilenames[isz]);
if (szOutput != matches[isz]) {
FreePv(szOutput);
}
}
return;
}
}
for (iszT = 0; iszT < found; iszT++) {
if (iszT != isz) {
FreePv(matches[iszT]);
}
}
}
// If an internal name was specified, the decoration of the
// internal name needs to be applied to the external name.
if (pexternal->szOtherName) {
char *szDecoratedName;
BOOL fPrefix = FALSE;
const char *szDecoration;
szDecoratedName = szMatch;
if ((pexternal->Flags & EXTERN_FORWARDER) == 0) {
// Replace internal name with decorated name.
FreePv(pexternal->szOtherName);
pexternal->szOtherName = szDecoratedName;
}
szDefSymbolName = SzNameSym(pexternal->ImageSymbol, *pblk);
cch = strlen(szDefSymbolName);
if ((szDecoratedName[0] == '?') ||
(szDecoratedName[0] == '@') ||
(SkipUnderscore && (szDecoratedName[0] == '_'))) {
cch++;
fPrefix = TRUE;
}
szDecoration = strchr(szDecoratedName, '@');
if (szDecoration) {
cch += strlen(szDecoration);
}
szMatch = (char *) PvAllocZ(cch+1);
if (fPrefix) {
szMatch[0] = szDecoratedName[0];
}
strcat(szMatch, szDefSymbolName);
if (szDecoration) {
strcat(szMatch, szDecoration);
}
if (szDecoratedName != pexternal->szOtherName) {
free(szDecoratedName);
}
}
// Add the decorated name to the symbol table.
pextNew = LookupExternSz(pstDef, szMatch, NULL);
if (pextNew != pexternal) {
pextNew->pcon = pexternal->pcon;
pextNew->szOtherName = pexternal->szOtherName;
SetDefinedExt(pextNew, TRUE, pstDef);
assert(pexternal->Flags & EXTERN_DEFINED);
pextNew->Flags = pexternal->Flags | EXTERN_FUZZYMATCH;
pextNew->FinalValue = pexternal->FinalValue;
pextNew->ArchiveMemberIndex = pexternal->ArchiveMemberIndex;
pextNew->ImageSymbol.Value = pexternal->ImageSymbol.Value;
// Ignore the old name (not used).
SetDefinedExt(pexternal, FALSE, pstDef);
if (pexternal->pcon != NULL) {
AddReferenceExt(pexternal, PmodPCON(pexternal->pcon));
}
pexternal->Flags |= EXTERN_IGNORE;
}
FreePv(szMatch);
}
VOID
FuzzyLookup (
PST pstDef,
PST pstObj,
PLIB plibHeadObj,
BOOL SkipUnderscore)
/*++
Routine Description:
Compares ??? for each external symbol.
Arguments:
pstDef - Pointer to def file externals.
pstObj - Pointer to externals found in objs & libs.
bLibLookup - if TRUE do a lookup of the libs as well.
Return Value:
None.
--*/
{
PBLK pblk;
PEXTERNAL *rgpexternalT;
DWORD cexternal;
PEXTERNAL *rgpexternalByName;
DWORD iexternal;
pblk = &pstDef->blkStringTable;
// Get an alphabetically sorted array of the current contents of pstDef,
// then set up pstDef to allow inserts again.
rgpexternalT = RgpexternalByName(pstDef);
cexternal = Cexternal(pstDef);
rgpexternalByName = (PEXTERNAL *) PvAlloc(cexternal * sizeof(PEXTERNAL));
memcpy(rgpexternalByName, rgpexternalT, cexternal * sizeof(PEXTERNAL));
AllowInserts(pstDef);
for (iexternal = 0; iexternal < cexternal; iexternal++) {
PEXTERNAL pexternal;
pexternal = rgpexternalByName[iexternal];
if ((pexternal->Flags & EXTERN_DEFINED) == 0) {
continue;
}
if ((pexternal->Flags & EXTERN_FUZZYMATCH) != 0) {
continue;
}
FuzzyLookupPext(pexternal, pstDef, pstObj, plibHeadObj, SkipUnderscore);
}
FreePv(rgpexternalByName);
}
#if DBG
VOID
DumpPst(PST pst)
{
PEXTERNAL pext;
DWORD cext;
printf("--- SYMBOL TABLE DUMP (%d. symbols) ---\n", cext = Cexternal(pst));
InitEnumerateExternals(pst);
while ((pext = PexternalEnumerateNext(pst)) != NULL) {
cext--;
printf((pext->Flags & EXTERN_DEFINED) ? "d" : " ");
printf(": %s\n", SzNamePext(pext, pst));
}
TerminateEnumerateExternals(pst);
printf("--- END OF SYMBOL TABLE DUMP ---\n");
assert(cext == 0);
}
#endif // DBG