|
|
/***********************************************************************
* Microsoft (R) 32-Bit Incremental Linker * * Copyright (C) Microsoft Corp 1992-95. All rights reserved. * * File: contrib.cpp * * File Comments: * * Manipulators for contributors. * ***********************************************************************/
#include "link.h"
WORD csec;
extern VOID ProcessSectionFlags(DWORD *, const char *, PIMAGE_OPTIONAL_HEADER);
void ContribInit( PPMOD ppmodLinkerDefined)
/*++
Routine Description:
Initialize the contributor manager.
Arguments:
*ppmodLinkerDefined - linker defined module
Return Value:
None.
--*/
{ PMOD pmod;
pmod = (PMOD) Calloc(1, sizeof(MOD));
pmod->plibBack = (PLIB) Calloc(1, sizeof(LIB)); pmod->szFileOrig = Strdup(SZ_LNK_DEF_MOD); pmod->plibBack->szName = Strdup(SZ_LNK_DEF_LIB);
*ppmodLinkerDefined = pmod; }
char * SzComNamePMOD( PMOD pmod, char *szBuf)
/*++
Routine Description:
Combines a module name and a library name into a buffer.
Arguments:
pmod - module node in driver map
Return Value:
Combined name.
--*/
{ assert(pmod); assert(szBuf);
szBuf[0] = '\0';
if (pmod) { char szFname[_MAX_FNAME]; char szExt[_MAX_EXT];
if (FIsLibPMOD(pmod)) { _splitpath(SzFilePMOD(pmod), NULL, NULL, szFname, szExt); strcat(szBuf, szFname); strcat(szBuf, szExt); strcat(szBuf, "("); }
_splitpath(SzOrigFilePMOD(pmod), NULL, NULL, szFname, szExt); strcat(szBuf, szFname); strcat(szBuf, szExt);
if (FIsLibPMOD(pmod)) { strcat(szBuf, ")"); } }
return(szBuf); }
char *SzComNamePCON(PCON pcon, char *szBuf) { PMOD pmod = PmodPCON(pcon);
if (pmod == pmodLinkerDefined) { return(NULL); }
return(SzComNamePMOD(pmod, szBuf)); }
void ParseSecName( const char *szName, const char **pszSec)
/*++
Routine Description:
Parse a COFF section name into a section name.
Arguments:
szName - COFF section name
*pszSec - section name
Return Value:
None. --*/
{ char *pb; static char szSec[33];
strncpy(szSec, szName, 32);
*pszSec = szSec;
// Check for group section
pb = strchr(szSec, '$');
if (pb != NULL) { *pb = '\0'; } }
PSEC PsecApplyMergePsec(PSEC psec) { PSEC psecOut;
if (psec == NULL) { return(psec); }
psecOut = psec;
while (psecOut->psecMerge != NULL) { psecOut = psecOut->psecMerge;
if (psecOut == psec) { Fatal(NULL, CIRCULAR_MERGE, psec->szName); } }
return(psecOut); }
PGRP PgrpFind( PSEC psec, const char *szName)
/*++
Routine Description:
Find a group.
Arguments:
psec - section to look in
szName - section name
Return Value:
group if found, NULL otherwise
--*/
{ ENM_GRP enm_grp; PGRP pgrp = NULL;
psec = PsecApplyMergePsec(psec);
InitEnmGrp(&enm_grp, psec); while (FNextEnmGrp(&enm_grp)) { if (strcmp(enm_grp.pgrp->szName, szName) == 0) { pgrp = enm_grp.pgrp; break; } } EndEnmGrp(&enm_grp);
return(pgrp); }
PGRP PgrpNew( const char *szName, PSEC psec)
/*++
Routine Description:
If the group doesn't exist create it, otherwise return existing one.
Arguments:
szName - group name
psec - parent section
Return Value:
pointer to library
--*/
{ PGRP pgrp; PGRP pgrpCur; PPGRP ppgrpLast;
assert(psec);
pgrp = PgrpFind(psec, szName);
if (pgrp != NULL) { return(pgrp); }
// group not found
// allocate a new group
pgrp = (PGRP) Calloc(1, sizeof(GRP));
pgrp->szName = Strdup(szName); pgrp->psecBack = psec; pgrp->cbAlign = 1; // default
// Link group into section in lexical order by name
pgrpCur = psec->pgrpNext; ppgrpLast = &(psec->pgrpNext);
while (pgrpCur && strcmp(pgrp->szName, pgrpCur->szName) >= 0) { ppgrpLast = &(pgrpCur->pgrpNext); pgrpCur = pgrpCur->pgrpNext; }
*ppgrpLast = pgrp; pgrp->pgrpNext = pgrpCur;
DBEXEC(DB_CONLOG, DBPRINT("new pgrp = %s\n", pgrp->szName));
return(pgrp); }
void ReallyMergePsec( PSEC psecOld, PSEC psecNew ) { // Move all the cons from this section into the new section. Pick
// the first group since it really doesn't matter.
PGRP pgrpFrom, pgrpTo; PCON pconFrom, pconTmp;
// Transfer all cons from all groups in psecOld to psecNew
if (psecOld->pgrpNext == NULL) { return; }
if (psecNew->pgrpNext == NULL) { psecNew->pgrpNext = PgrpNew(psecNew->szName, psecNew); }
pgrpFrom = psecOld->pgrpNext; pgrpTo = psecNew->pgrpNext;
while (pgrpFrom != NULL) { pconFrom = pgrpFrom->pconNext; while (pgrpFrom->ccon != 0) { pconTmp = pconFrom->pconNext; pconFrom->pgrpBack = pgrpTo; pconFrom->pconNext = pgrpTo->pconNext; pgrpTo->pconNext = pconFrom; pconFrom = pconTmp; pgrpFrom->ccon--; pgrpTo->ccon++; } pgrpFrom = pgrpFrom->pgrpNext; psecOld->pgrpNext = pgrpFrom; } }
void MovePgrp( const char *szName, PSEC psecOld, PSEC psecNew ) { PGRP pgrp; PGRP pgrpCur; PPGRP ppgrpLast;
assert(psecOld); assert(psecNew);
if (!(pgrp = PgrpFind(psecOld, szName))) { // If the group doesn't exist in the old section, nothing to do.
return; }
// Remove this node from the old section
pgrpCur = psecOld->pgrpNext; ppgrpLast = &(psecOld->pgrpNext);
while ((pgrpCur != pgrp) && pgrpCur) { ppgrpLast = &(pgrpCur->pgrpNext); pgrpCur = pgrpCur->pgrpNext; }
assert(pgrpCur);
*ppgrpLast = pgrp->pgrpNext;
// Add it to the new section (while maintaining lexical order).
psecNew = PsecApplyMergePsec(psecNew);
pgrpCur = psecNew->pgrpNext; ppgrpLast = &(psecNew->pgrpNext);
while (pgrpCur && strcmp(pgrp->szName, pgrpCur->szName) >= 0) { ppgrpLast = &(pgrpCur->pgrpNext); pgrpCur = pgrpCur->pgrpNext; }
*ppgrpLast = pgrp; pgrp->pgrpNext = pgrpCur;
// And update the psec to the new section.
pgrp->psecBack = psecNew;
DBEXEC(DB_CONLOG, DBPRINT("pgrp: %s moved from psec: %s to psec: %s\n", pgrp->szName, psecOld->szName, psecNew->szName)); }
PCON PconNew( const char *szName, DWORD cbRawData, DWORD flagsPCON, DWORD flagsPSEC, PMOD pmod, PSECS psecs, PIMAGE pimage)
/*++
Routine Description:
Create a new contributor.
Arguments:
szName - COFF section name
cbRawData - size of raw data
flagsPCON - characteristics from the section in the object
flagsPSEC - characteristics for image destination section
pmod - module contribution came from
Return Value:
pointer to new contribution
--*/
{ PCON pcon; PGRP pgrp; PSEC psec; const char *szSec;
ParseSecName(szName, &szSec);
psec = NULL; if (pimage->imaget == imagetVXD) { // For a VxD we relax the flags restrictions and merge everything with the same section
// name into one SEC, since the .def file will probably set the flags anyway.
psec = PsecFindNoFlags(szSec, psecs); }
if (psec == NULL) { // Find or create a section with the desired flags.
psec = PsecNew(pmod, szSec, flagsPSEC, psecs, &pimage->ImgOptHdr); }
pgrp = PgrpNew(szName, psec);
assert(pgrp);
assert(pmod);
if (pmod->icon < pmod->ccon) { // The initial allocation of CONs hasn't been used up.
// Grab the next available CON from the initial set.
pcon = RgconPMOD(pmod) + pmod->icon; } else { size_t cb;
if (fIncrDbFile) { assert(pmod == pmodLinkerDefined); }
cb = sizeof(CON);
if (pimage->Switch.Link.fTCE) { cb += sizeof(NOD); }
pcon = (PCON) Calloc(1, cb); }
pmod->icon++; pgrp->ccon++;
DBEXEC(DB_CONLOG, DBPRINT("new pcon (%p) in group %s\n", pcon, szName));
pcon->cbRawData = cbRawData; pcon->pgrpBack = pgrp; pcon->flags = flagsPCON; pcon->pmodBack = pmod;
if (fIncrDbFile) { return(pcon); }
// Add to group
if (pgrp->pconLast) { assert(pgrp->pconLast->pconNext == NULL); pgrp->pconLast->pconNext = pcon; } else { assert(pgrp->pconNext == NULL); pgrp->pconNext = pcon; }
pgrp->pconLast = pcon;
return(pcon); }
void DupConInfo ( PCON pconSrc, PCON pconDst)
/*++
Routine Description:
Duplicates info of a CON. !!!Used by m68k ONLY!!!
Arguments:
pconSrc -
pconDst -
Return Value:
None.
--*/
{ PMOD pmodSrc = PmodPCON(pconSrc); PMOD pmodDst = PmodPCON(pconDst);
assert(pmodSrc->rgci); assert(pmodSrc->ccon > (DWORD) IsecPCON(pconSrc)); assert(pmodDst->rgci); assert(pmodDst->ccon > (DWORD) IsecPCON(pconDst));
pmodDst->rgci[IsecPCON(pconDst)].cReloc = CRelocSrcPCON(pconSrc); pmodDst->rgci[IsecPCON(pconDst)].cLinenum = CLinenumSrcPCON(pconSrc); pmodDst->rgci[IsecPCON(pconDst)].foRelocSrc = FoRelocSrcPCON(pconSrc); pmodDst->rgci[IsecPCON(pconDst)].foLinenumSrc = FoLinenumSrcPCON(pconSrc); pmodDst->rgci[IsecPCON(pconDst)].foRawDataSrc = FoRawDataSrcPCON(pconSrc); pmodDst->rgci[IsecPCON(pconDst)].rvaSrc = RvaSrcPCON(pconSrc); }
PMOD PmodNew( const char *szNameMod, const char *szFileOrig, DWORD foMember, DWORD foSymbolTable, DWORD csymbols, WORD cbOptHdr, WORD flags, WORD ccon, PLIB plibBack, BOOL *pfNew)
/*++
Routine Description:
If the module has not been created, create one.
Arguments:
szNameMod - module name, NULL if an archive member
szFileOrig - original module name
foMember - offset of module in archive, only valid if !szName
foSymbolTable - offset to COFF symbol table
csymbols - number of symbols
cbObtHdr - size of optional header
flags - module flags (see ntimage.h for values)
ccon - number of contributions for module
plibBack - pointer to library, dummy library of module is an object file
Return Value:
pointer to new module
--*/
{ PMOD pmod;
assert(szFileOrig); assert(plibBack);
pmod = PmodFind(plibBack, szFileOrig, foMember);
if (pfNew) { *pfNew = (pmod == NULL); }
// if we didn't find it
if (!pmod) { pmod = (PMOD) Calloc(1, sizeof(MOD) + (ccon * sizeof(CON)));
pmod->rgci = (CONINFO *)PvAllocZ(ccon * sizeof(CONINFO));
if (szNameMod) { pmod->szNameMod = Strdup(szNameMod); } else { pmod->foMember = foMember; }
if (szFileOrig) { pmod->szFileOrig = Strdup(szFileOrig); }
pmod->imod = (fINCR && !fIncrDbFile) ? NewIModIdx() : 0; if (pmod->imod >= IMODIDXMAC && (fINCR || fPdb)) { Fatal(NULL, PDBLIMIT, NULL); }
pmod->foSymbolTable = foSymbolTable; pmod->csymbols = csymbols; pmod->cbOptHdr = cbOptHdr; pmod->flags = flags; pmod->ccon = ccon; pmod->plibBack = plibBack; pmod->pmodNext = plibBack->pmodNext;
if (fINCR) { pmod->plpextRef = (PLPEXT)Calloc(1, sizeof (LPEXT)); pmod->plpextRef->cpextMax = CPEXT_REFS; }
if (fPowerMac || fPowerPC) { DWORD cdwBitVector;
// Allocate bit vectors according to the number of symbols.
cdwBitVector = (csymbols / 32) + 1; pmod->tocBitVector = fINCR ? Calloc (cdwBitVector, sizeof(DWORD)) : PvAllocZ(cdwBitVector * sizeof(DWORD)); pmod->writeBitVector = fINCR ? Calloc (cdwBitVector, sizeof(DWORD)) : PvAllocZ(cdwBitVector * sizeof(DWORD)); pmod->rgpext = fINCR ? (PEXTERNAL *) Calloc (csymbols, sizeof(PEXTERNAL)) : (PEXTERNAL *) PvAllocZ(csymbols * sizeof(PEXTERNAL)); }
plibBack->pmodNext = pmod;
DBEXEC(DB_CONLOG, { char szBuf[256]; DBPRINT("new pmod = %s\n", SzComNamePMOD(pmod, szBuf)); }); }
return(pmod); }
PLIB PlibNew( const char *szName, DWORD foIntMemSymTab, LIBS *plibs)
/*++
Routine Description:
If the library doesn't exist create it, otherwise return existing one.
Arguments:
szName - library name
foIntMemSymTab - file offset to library interface member symbol table
Return Value:
pointer to library
--*/
{ PLIB plib;
plib = PlibFind(szName, plibs->plibHead, FALSE);
// if we didn't find it
if (!plib) { // allocate a new library
plib = (PLIB) Calloc(1, sizeof(LIB));
// fill in library node
if (!szName) { plib->szName = NULL; } else { plib->szName = Strdup(szName); }
plib->foIntMemSymTab = foIntMemSymTab; plib->pmodNext = NULL; plib->plibNext = NULL;
*plibs->pplibTail = plib; plibs->pplibTail = &plib->plibNext;
DBEXEC(DB_CONLOG, DBPRINT("new plib = %s\n", plib->szName)); }
return(plib); }
void FreePLIB( LIBS *plibs)
/*++
Routine Description:
Free a library nodes in the driver map.
Arguments:
None.
Return Value:
None.
--*/
{ ENM_LIB enm_lib; PLIB plibLast = NULL; PLIB plib;
InitEnmLib(&enm_lib, plibs->plibHead); while (FNextEnmLib(&enm_lib)) { plib = enm_lib.plib;
// UNDONE: It's not safe to call free() for plib because this are
// UNDONE: allocated with Calloc() and not calloc().
free(plibLast);
FreePv(plib->rgulSymMemOff); FreePv(plib->rgusOffIndex); FreePv(plib->rgbST); FreePv(plib->rgszSym); FreePv(plib->rgbLongFileNames);
plibLast = plib; }
// UNDONE: It's not safe to call free() for plib because this are
// UNDONE: allocated with Calloc() and not calloc().
free(plibLast);
InitLibs(plibs); }
PSEC PsecNew( PMOD pmod, const char *szName, DWORD flags, PSECS psecs, PIMAGE_OPTIONAL_HEADER pImgOptHdr)
/*++
Routine Description:
If the section doesn't exist create it, otherwise return existing one.
Arguments:
szName - section name
flags - section flags
Return Value:
pointer to section
--*/
{ PSEC psec;
assert(szName);
// Check if section exists
psec = PsecFind(pmod, szName, flags, psecs, pImgOptHdr);
if (psec != NULL) { return(psec); }
ProcessSectionFlags(&flags, szName, pImgOptHdr);
// allocate a new library
psec = (PSEC) Calloc(1, sizeof(SEC));
// fill in section node
psec->szName = Strdup(szName); psec->flags = flags; psec->flagsOrig = flags; psec->pgrpNext = NULL; psec->psecMerge = NULL; if (fM68K && (flags & IMAGE_SCN_CNT_CODE)) { AssignTMAC(psec);
// Init the ResType of this section to whatever the user specified.
// If the user didn't specify anything, default is CODE.
psec->ResTypeMac = sbeCODE;
ApplyM68KSectionResInfo(psec, FALSE);
if (psec->ResTypeMac == sbeCODE) { fSACodeOnly = FALSE; } }
// link library into global list
*psecs->ppsecTail = psec; psecs->ppsecTail = &psec->psecNext;
DBEXEC(DB_CONLOG, DBPRINT("new psec = %s\n", psec->szName));
csec++; return(psec); }
#if DBG
PSEC PsecFindSectionOfRVA( DWORD rva, PSECS psecs )
/*++
Routine Description:
Determines in which section an RVA lies.
Arguments:
rva - Relative Virtual Address
psecs - Pointer to head of section list
Return Value:
Pointer to SEC, or NULL if RVA could not be mapped to any section.
--*/
{ ENM_SEC enm_sec;
InitEnmSec(&enm_sec, psecs); while (FNextEnmSec(&enm_sec)) { PSEC psec = enm_sec.psec;
if ((rva >= psec->rva) && (rva < (psec->rva + psec->cbVirtualSize))) { break; } } EndEnmSec(&enm_sec);
return(enm_sec.psec); }
#endif // DBG
PSEC PsecFindIsec( SHORT isec, PSECS psecs )
/*++
Routine Description:
Determines a section corresponding to the isec.
Arguments:
isec - section number
psecs - Pointer to head of sections list
Return Value:
Pointer to SEC, or NULL if RVA could not be mapped to any section.
--*/
{ static PSEC psec; ENM_SEC enm_sec;
if (isec <= 0) { return(NULL); }
if (psec != NULL) { // Do a quick test to see if rva is within the last found section
if (psec->isec == isec) { return(psec); } }
InitEnmSec(&enm_sec, psecs); while (FNextEnmSec(&enm_sec)) { if (enm_sec.psec->isec == isec) { break; } } EndEnmSec(&enm_sec);
psec = enm_sec.psec;
return(psec); }
PSEC PsecFindNoFlags( const char *szName, PSECS psecs)
/*++
Routine Description:
Find a section based on its name.
Arguments:
szName - section name
Return Value:
section if found, NULL otherwise
--*/
{ ENM_SEC enm_sec;
InitEnmSec(&enm_sec, psecs); while (FNextEnmSec(&enm_sec)) { if (!strcmp(enm_sec.psec->szName, szName)) { break; } } EndEnmSec(&enm_sec);
return(PsecApplyMergePsec(enm_sec.psec)); }
PSEC PsecFind( PMOD pmod, const char *szName, DWORD Characteristics, PSECS psecs, PIMAGE_OPTIONAL_HEADER pImgOptHdr)
/*++
Routine Description:
Find a section.
Arguments:
szName - section name
Return Value:
section if found, NULL otherwise
--*/
{ DWORD flags; BOOL fMatchedName; ENM_SEC enm_sec;
flags = Characteristics; ProcessSectionFlags(&flags, szName, pImgOptHdr);
fMatchedName = FALSE;
InitEnmSec(&enm_sec, psecs); while (FNextEnmSec(&enm_sec)) { if (!strcmp(enm_sec.psec->szName, szName)) { if (flags == enm_sec.psec->flagsOrig) { break; }
fMatchedName = TRUE; } } EndEnmSec(&enm_sec);
if (fMatchedName && (enm_sec.psec == NULL)) { const char *sz; char szBuf[512 + 1];
if (pmod == NULL) { sz = NULL; } else { sz = SzComNamePMOD(pmod, szBuf); }
Warning(sz, DIFSECATTRIB, szName, Characteristics); }
return(PsecApplyMergePsec(enm_sec.psec)); }
PSEC PsecFindGrp( PMOD pmod, const char *szName, DWORD Characteristics, PSECS psecs, PIMAGE_OPTIONAL_HEADER pImgOptHdr)
/*++
Routine Description:
Find a section corresponding to a section in a module. This could be a group. For example, .debug$S.
Arguments:
szName - module section name
Return Value:
section if found, NULL otherwise
--*/
{ const char *szSec; PSEC psec;
ParseSecName(szName, &szSec);
psec = PsecFind(pmod, szSec, Characteristics, psecs, pImgOptHdr);
if (psec != NULL) { // Make sure this group actually exists in this section.
if (PgrpFind(psec, szName) != NULL) { return(psec); } }
// We have a group name, but a simple truncation at the '$' didn't produce
// the correct section. Search every section.
ENM_SEC enm_sec;
InitEnmSec(&enm_sec, psecs); while (FNextEnmSec(&enm_sec)) { if (PgrpFind(enm_sec.psec, szName) != NULL) { break; } } EndEnmSec(&enm_sec);
return(enm_sec.psec); }
void MergePsec(PSEC psecFrom, PSEC psecInto) { PGRP pgrpA; PGRP pgrpB; PGRP *ppgrpTail;
// Transfer all GRP's from psecFrom to psecInto.
if (PsecApplyMergePsec(psecFrom) == psecInto) { // Already merged
return; }
psecInto = PsecApplyMergePsec(psecInto);
// Merge the GRPs from both sections into a single sorted list
pgrpA = psecFrom->pgrpNext; pgrpB = psecInto->pgrpNext;
ppgrpTail = &psecInto->pgrpNext;
for (;;) { int i; PGRP pgrp;
// Set i < 0: Pick A, i > 0: Pick B
if (pgrpA == NULL) { if (pgrpB == NULL) { break; }
i = 1; } else if (pgrpB == NULL) { i = -1;
} else { i = strcmp(pgrpA->szName, pgrpB->szName); }
if (i < 0) { pgrpA->psecBack = psecInto;
pgrp = pgrpA; pgrpA = pgrpA->pgrpNext; } else { pgrp = pgrpB; pgrpB = pgrpB->pgrpNext; }
*ppgrpTail = pgrp;
ppgrpTail = &pgrp->pgrpNext; }
*ppgrpTail = NULL;
psecFrom->pgrpNext = NULL;
// Remember to merge all new GRPs from psecFrom to psecInto
psecFrom->psecMerge = psecInto; }
void AppendPsec(PSEC psecFrom, PSEC psecTo) { PGRP *ppgrp;
// Transfer all GRP's from psecFrom to psecTo.
if (PsecApplyMergePsec(psecFrom) == psecTo) { // Already merged
return; }
psecTo = PsecApplyMergePsec(psecTo);
// Find last GRP in psecTo
ppgrp = &psecTo->pgrpNext; while (*ppgrp != NULL) { ppgrp = &(*ppgrp)->pgrpNext; }
// Attach psecFrom's GRPs to psecTo
*ppgrp = psecFrom->pgrpNext;
// Update backpointer in moved GRPs to point to psecTo
for (; *ppgrp != NULL; ppgrp = &(*ppgrp)->pgrpNext) { (*ppgrp)->psecBack = psecTo; }
psecFrom->pgrpNext = NULL;
// Remember to merge all new GRPs from psecFrom to psecTo
psecFrom->psecMerge = psecTo; }
void OrderPsecs(PSECS psecs, DWORD dwMask, DWORD dwMatch) { PSEC *rgpsec; WORD isec; ENM_SEC enmSec;
rgpsec = (PSEC *) PvAlloc(csec * sizeof(PSEC));
for (InitEnmSec(&enmSec, psecs), isec = 0; FNextEnmSec(&enmSec); isec++) { rgpsec[isec] = enmSec.psec; } assert(isec == csec);
psecs->ppsecTail = &psecs->psecHead;
for (isec = 0; isec < csec; isec++) { if ((rgpsec[isec]->flags & dwMask) != dwMatch) { continue; }
*psecs->ppsecTail = rgpsec[isec]; psecs->ppsecTail = &(*psecs->ppsecTail)->psecNext; }
for (isec = 0; isec < csec; isec++) { if ((rgpsec[isec]->flags & dwMask) == dwMatch) { continue; }
*psecs->ppsecTail = rgpsec[isec]; psecs->ppsecTail = &(*psecs->ppsecTail)->psecNext; }
*psecs->ppsecTail = NULL;
FreePv(rgpsec); }
void SortSectionList(PSECS psecs, int (__cdecl *pfn)(const void *, const void *)) { PSEC *rgpsec; WORD isec; ENM_SEC enmSec;
rgpsec = (PSEC *) PvAlloc(csec * sizeof(PSEC));
for (InitEnmSec(&enmSec, psecs), isec = 0; FNextEnmSec(&enmSec); isec++) { rgpsec[isec] = enmSec.psec; } assert(isec == csec);
qsort(rgpsec, csec, sizeof(PSEC), pfn);
psecs->ppsecTail = &psecs->psecHead;
for (isec = 0; isec < csec; isec++) { *psecs->ppsecTail = rgpsec[isec]; psecs->ppsecTail = &(*psecs->ppsecTail)->psecNext; }
*psecs->ppsecTail = NULL;
FreePv(rgpsec); }
int __cdecl ComparePsecPsecName(const void *ppsec1, const void *ppsec2) { PSEC psec1 = *(PSEC *) ppsec1; PSEC psec2 = *(PSEC *) ppsec2;
return(strcmp(psec1->szName, psec2->szName)); }
void SortSectionListByName(PSECS psecs) { SortSectionList(psecs, ComparePsecPsecName); }
BOOL FValidSecName ( const char *szSec ) { // Name must not include '$' or blank
return((_tcschr(szSec, '$') == NULL) && (_tcschr(szSec, ' ') == NULL)); }
PLIB PlibFind( const char *szName, PLIB plibHead, BOOL fIgnoreDir) // Looks for a library by name.
// If fIgnoreDir, then szName has no directory specified, and we ignore
// the directory when matching it with an existing .lib.
{ ENM_LIB enm_lib; PLIB plib = NULL;
InitEnmLib(&enm_lib, plibHead); while (FNextEnmLib(&enm_lib)) { const char *szLibName; char szPath[_MAX_PATH];
if (fIgnoreDir && (enm_lib.plib->szName != NULL)) { char szFname[_MAX_FNAME]; char szExt[_MAX_EXT];
_splitpath(enm_lib.plib->szName, NULL, NULL, szFname, szExt); strcpy(szPath, szFname); strcat(szPath, szExt);
szLibName = szPath; } else { szLibName = enm_lib.plib->szName; }
if (szName == NULL && enm_lib.plib->szName == NULL || enm_lib.plib->szName && szName && !_ftcsicmp(szLibName, szName)) { plib = enm_lib.plib; EndEnmLib(&enm_lib); break; } }
return (plib); }
PMOD PmodFind( PLIB plib, const char *szName, DWORD foMember)
/*++
Routine Description:
Find a module.
Arguments:
plib - library to look in
szName - module name
foMember - file offset to member - 0 if object file
Return Value:
module if found, NULL otherwise
--*/
{ ENM_MOD enm_mod; PMOD pmod = NULL;
InitEnmMod(&enm_mod, plib); while (FNextEnmMod(&enm_mod)) { assert(enm_mod.pmod); if (foMember) { if (foMember == enm_mod.pmod->foMember) { pmod = enm_mod.pmod; EndEnmMod(&enm_mod); break; } } else { int i;
// Need to do a strcmp() for 68K because of the DUPCON mods
if (fM68K) { i = strcmp(SzOrigFilePMOD(enm_mod.pmod), szName); } else { i = _tcsicmp(SzOrigFilePMOD(enm_mod.pmod), szName); }
if (!i) { pmod = enm_mod.pmod; EndEnmMod(&enm_mod); break; } } }
return (pmod); }
STATIC int __cdecl ComparePCON( const void *pv1, const void *pv2)
/*++
Routine Description:
Compare routine for sorting contibutions by module.
Arguments:
pv1 - element 1
pv2 - element 2
Return Value:
< 0 if element 1 < element 2 > 0 if element 1 > element 2 = 0 if element 1 = element 2
--*/
{ assert(pv1); assert(pv2); assert(PmodPCON(*(PPCON) pv1)); assert(PmodPCON(*(PPCON) pv2));
return(strcmp(SzObjNamePCON(*(PPCON) pv1), SzObjNamePCON(*(PPCON) pv2))); }
void SortPGRPByPMOD( PGRP pgrp)
/*++
Routine Description:
Sort a group by its module name. This routine is used to handle idata$* groups. All idata group contributions must be contiguous if they have similar module names.
Arguments:
pgrp - group to sort
Return Value:
None.
--*/
{ ENM_DST enm_dst; PPCON rgpcon; DWORD ipcon; PCON pcon;
rgpcon = (PPCON) PvAlloc(pgrp->ccon * sizeof(PCON));
ipcon = 0; InitEnmDst(&enm_dst, pgrp); while (FNextEnmDst(&enm_dst)) { pcon = enm_dst.pcon;
rgpcon[ipcon] = pcon; ipcon++; }
assert(ipcon == pgrp->ccon); qsort((void *) rgpcon, (size_t) pgrp->ccon, sizeof(PCON), ComparePCON);
for (ipcon = 0; ipcon < (pgrp->ccon - 1); ipcon++) { assert(rgpcon[ipcon]); assert(rgpcon[ipcon + 1]); rgpcon[ipcon]->pconNext = rgpcon[ipcon + 1]; } pgrp->pconNext = rgpcon[0]; rgpcon[pgrp->ccon - 1]->pconNext = NULL;
FreePv(rgpcon); }
BOOL MoveToEndOfPMODsPCON( IN PCON pcon)
/*++
Routine Description:
Move a contribution to the end of a particular contiguous block of unique module contributions.
Arguments:
pcon - image/driver map contribution
Return Value:
None.
--*/
{ PPCON ppconB; PCON pconC; PCON pconL;
assert(pcon); assert(pcon->pgrpBack);
// find element before pcon
ppconB = &(pcon->pgrpBack->pconNext); pconC = pcon->pgrpBack->pconNext;
while (*ppconB != pcon) { ppconB = &(pconC->pconNext); pconC = pconC->pconNext; }
// find last element with same module name
pconL = pcon; pconC = pcon;
while (pconC != NULL && !strcmp(SzObjNamePCON(pconL), SzObjNamePCON(pconC))) { pconL = pconC; pconC = pconC->pconNext; }
// if it is already the last contrib - just ret :azk:
if (pconL == pcon) { return FALSE; }
// swap pcon with pconL
assert(*ppconB); assert(pconL); *ppconB = pcon->pconNext; pcon->pconNext = pconL->pconNext; pconL->pconNext = pcon; return TRUE; }
void MoveToBeginningOfPGRPsPCON( IN PCON pcon)
/*++
Routine Description:
Move a contribution to the beginning of its group
Arguments:
pcon - image/driver map contribution
Return Value:
None.
--*/
{ PCON pconBack; // One contribution before
PGRP pgrp;
assert(pcon); pgrp = pcon->pgrpBack; assert(pgrp);
pconBack = pgrp->pconNext;
// If the pcon is already first in the list, then return. It also
// takes care of the case where this is the only con in the group
if (pconBack == pcon) { return; }
// find element before pcon
while (pconBack->pconNext != pcon) { pconBack = pconBack->pconNext; }
pconBack->pconNext = pcon->pconNext; pcon->pconNext = pgrp->pconNext; pgrp->pconNext = pcon; }
void MoveToBeginningOfPSECsPGRP( IN PGRP pgrp)
/*++
Routine Description:
Move a group to the beginning of its section
Arguments:
pgrp - image/driver map grp
Return Value:
None.
--*/
{ PGRP pgrpBack; // One group before
PSEC psec;
assert(pgrp); psec = pgrp->psecBack; assert(psec);
pgrpBack = psec->pgrpNext;
// If the pgrp is already first in the list, then return. It also
// takes care of the case where this is the only grp in the section
if (pgrpBack == pgrp) { return; }
// find element before pgrp
while (pgrpBack->pgrpNext != pgrp) { pgrpBack = pgrpBack->pgrpNext; }
pgrpBack->pgrpNext = pgrp->pgrpNext; pgrp->pgrpNext = psec->pgrpNext; psec->pgrpNext = pgrp; }
void MoveToEndPSEC( IN PSEC psec, IN PSECS psecs)
/*++
Routine Description:
Move a section to the end of the section list.
Arguments:
psec - section node in image/driver map to move to the end
Return Value:
None.
--*/
{ PPSEC ppsec;
if (psecs->ppsecTail == &psec->psecNext) { assert(psec->psecNext == NULL); return; // already last
}
// find link to psec
for (ppsec = &psecs->psecHead; *ppsec != psec; ppsec = &(*ppsec)->psecNext) { assert(*ppsec != NULL); // must find psec
} *ppsec = psec->psecNext; // unhook from list
*psecs->ppsecTail = psec; // add at end
psecs->ppsecTail = &psec->psecNext; psec->psecNext = NULL; // terminate list
}
void MoveToBegOfLibPMOD ( IN PMOD pmod )
/*++
Routine Description:
Moves a PMOD to be the first pmod in the list (PLIB).
Arguments:
pmod - pointer to mod that needs to be moved.
Return Value:
None.
--*/
{ PPMOD ppmodB; PMOD pmodC;
// if it is already the first - return
if (pmod->plibBack->pmodNext == pmod) { return; }
// find pmod before this pmod
ppmodB = &(pmod->plibBack->pmodNext); pmodC = pmod->plibBack->pmodNext;
while (*ppmodB != pmod) { ppmodB = &(pmodC->pmodNext); pmodC = pmodC->pmodNext; }
// move pmod to head of list
assert(*ppmodB); *ppmodB = pmod->pmodNext; pmod->pmodNext = pmod->plibBack->pmodNext; pmod->plibBack->pmodNext = pmod; }
void FreePLMODList ( IN PLMOD *pplmod )
/*++
Routine Description:
Frees the list of pmods.
Arguments:
pplmod - pointer to list of pmods
Return Value:
None.
--*/
{ PLMOD plmod, plmodNext;
plmod = *pplmod; while (plmod) { plmodNext = plmod->plmodNext; FreePv(plmod); plmod = plmodNext; } (*pplmod) = NULL; }
void AddToPLMODList ( IN PLMOD *pplmod, IN PMOD pmod )
/*++
Routine Description:
Adds this pmod to list of pmods.
Arguments:
pplmod - pointer to list of pmods
pmod - pmod
Return Value:
None.
--*/
{ PLMOD plmod;
// See if already on list
if (*pplmod) { plmod = *pplmod; while (plmod) { if (plmod->pmod == pmod) { return; } plmod = plmod->plmodNext; } }
// allocate a LMOD
plmod = (PLMOD) PvAllocZ(sizeof(LMOD));
// fill in field
plmod->pmod = pmod;
// attach it
if (*pplmod) { plmod->plmodNext = *pplmod; }
// update head of list
(*pplmod) = plmod; }
/*++
Routine Description:
Library enumerator definition.
Arguments:
None.
Return Value:
None.
--*/
INIT_ENM(Lib, LIB, (ENM_LIB *penm, PLIB plibHead)) { penm->plib = NULL; penm->plibHead = plibHead; } NEXT_ENM(Lib, LIB) { if (!penm->plib) { penm->plib = penm->plibHead; } else { penm->plib = penm->plib->plibNext; }
return (penm->plib != NULL); } END_ENM(Lib, LIB) { } DONE_ENM
/*++
Routine Description:
Module enumerator definition.
Arguments:
None.
Return Value:
None.
--*/
INIT_ENM(Mod, MOD, (ENM_MOD *penm, PLIB plib)) { penm->pmod = NULL; penm->plib = plib; } NEXT_ENM(Mod, MOD) { if (penm->plib) { if (!penm->pmod) { penm->pmod = penm->plib->pmodNext; } else { penm->pmod = penm->pmod->pmodNext; } }
return (penm->pmod != NULL); } END_ENM(Mod, MOD) { } DONE_ENM
/*++
Routine Description:
Section enumerator definition.
Arguments:
None.
Return Value:
None.
--*/
INIT_ENM(Sec, SEC, (ENM_SEC *penm, PSECS psecs)) { penm->psec = NULL; penm->psecHead = psecs->psecHead; } NEXT_ENM(Sec, SEC) { if (!penm->psec) { penm->psec = penm->psecHead; } else { penm->psec = penm->psec->psecNext; }
return (penm->psec != NULL); } END_ENM(Sec, SEC) { } DONE_ENM
/*++
Routine Description:
Group enumerator definition.
Arguments:
None.
Return Value:
None.
--*/
INIT_ENM(Grp, GRP, (ENM_GRP *penm, PSEC psec)) { penm->pgrp = NULL; penm->psec = psec; } NEXT_ENM(Grp, GRP) { if (!penm->pgrp) { penm->pgrp = penm->psec->pgrpNext; } else { penm->pgrp = penm->pgrp->pgrpNext; }
return (penm->pgrp != NULL); } END_ENM(Grp, GRP) { } DONE_ENM
/*++
Routine Description:
Source contribution enumerator definition.
Arguments:
None.
Return Value:
None.
--*/
INIT_ENM(Src, SRC, (ENM_SRC *penm, PMOD pmod)) { penm->pcon = NULL; penm->pmod = pmod; penm->icon = 0; } NEXT_ENM(Src, SRC) { if (penm->icon < penm->pmod->ccon) { penm->pcon = RgconPMOD(penm->pmod) + penm->icon; penm->icon++;
return(TRUE); }
penm->pcon = NULL; return(FALSE); } END_ENM(Src, SRC) { } DONE_ENM
/*++
Routine Description:
Destination contribution enumerator definition.
Arguments:
None.
Return Value:
None.
--*/
INIT_ENM(Dst, DST, (ENM_DST *penm, PGRP pgrp)) { penm->pcon = NULL; penm->pgrp = pgrp; } NEXT_ENM(Dst, DST) { if (!penm->pcon) { penm->pcon = penm->pgrp->pconNext; } else { penm->pcon = penm->pcon->pconNext; }
return (penm->pcon != NULL); } END_ENM(Dst, DST) { } DONE_ENM
#if DBG
void DumpImageMap( PSECS psecs)
/*++
Routine Description:
Dump the image map.
Arguments:
None.
Return Value:
None.
--*/
{ ENM_SEC enm_sec; ENM_GRP enm_grp; ENM_DST enm_dst;
DBPRINT("Linker Image Map\n"); DBPRINT("----------------\n\n");
InitEnmSec(&enm_sec, psecs); while (FNextEnmSec(&enm_sec)) { DumpPSEC(enm_sec.psec); InitEnmGrp(&enm_grp, enm_sec.psec); while (FNextEnmGrp(&enm_grp)) { DumpPGRP(enm_grp.pgrp); InitEnmDst(&enm_dst, enm_grp.pgrp); while (FNextEnmDst(&enm_dst)) { DumpPCON(enm_dst.pcon); } } }
DBPRINT("\n"); }
void DumpDriverMap( PLIB plibHead)
/*++
Routine Description:
Dump the driver map.
Arguments:
None.
Return Value:
None.
--*/
{ ENM_LIB enm_lib; ENM_MOD enm_mod; ENM_SRC enm_src;
DBPRINT("Linker Driver Map\n"); DBPRINT("-----------------\n\n");
InitEnmLib(&enm_lib, plibHead); while (FNextEnmLib(&enm_lib)) { DumpPLIB(enm_lib.plib); InitEnmMod(&enm_mod, enm_lib.plib); while (FNextEnmMod(&enm_mod)) { DumpPMOD(enm_mod.pmod); InitEnmSrc(&enm_src, enm_mod.pmod); while (FNextEnmSrc(&enm_src)) { DumpPCON(enm_src.pcon); } } }
DBPRINT("\n"); }
void DumpPSEC( PSEC psec)
/*++
Routine Description:
Dump an image section.
Arguments:
psec - section to dump.
Return Value:
None.
--*/
{ assert(psec);
DBPRINT("\n==========\n"); DBPRINT("section=%.8s, isec=%04X\n", psec->szName, psec->isec); DBPRINT("rva= %08lX ", psec->rva); DBPRINT("foPad= %08lX ", psec->foPad); DBPRINT("cbRawData= %08lX ", psec->cbRawData); DBPRINT("foRawData= %08lX\n", psec->foRawData); DBPRINT("foLinenum= %08lX ", psec->foLinenum); DBPRINT("flags= %08lX ", psec->flags); DBPRINT("cLinenum= %04X\n", psec->cLinenum); fflush(stdout); }
void DumpPGRP( PGRP pgrp)
/*++
Routine Description:
Dump an image group.
Arguments:
pgrp - group to dump.
Return Value:
None.
--*/
{ DBPRINT("\n----------\n"); DBPRINT("\n group=%s\n", pgrp->szName); fflush(stdout); }
void DumpPLIB( PLIB plib)
/*++
Routine Description:
Dump a library.
Arguments:
plib - library to dump.
Return Value:
None.
--*/
{ DBPRINT("\n==========\n"); DBPRINT("library=%s\n", plib->szName); DBPRINT("foIntMemST=%08lX ", plib->foIntMemSymTab); DBPRINT("csymIntMem=%08lX ", plib->csymIntMem); DBPRINT("flags= %08lX\n", plib->flags); DBPRINT("TimeStamp= %s", ctime((time_t *) &plib->TimeStamp)); fflush(stdout); }
void DumpPMOD( PMOD pmod)
/*++
Routine Description:
Dump a module.
Arguments:
pmod - module to dump.
Return Value:
None.
--*/
{ DBPRINT("\n----------\n"); DBPRINT(" module=%s, ", SzOrigFilePMOD(pmod));
if (FIsLibPMOD(pmod)) { DBPRINT("foMember=%08lX\n", pmod->foMember); } else { DBPRINT("szNameMod=%s\n", pmod->szNameMod); }
DBPRINT("foSymTable=%08lX ", pmod->foSymbolTable); DBPRINT("csymbols= %08lX ", pmod->csymbols); DBPRINT("cbOptHdr= %08lX\n", pmod->cbOptHdr); DBPRINT("flags= %08lX ", pmod->flags); DBPRINT("ccon= %08lX ", pmod->ccon); DBPRINT("icon= %08lX ", pmod->icon); DBPRINT("TimeStamp= %s", ctime((time_t *) &pmod->TimeStamp)); fflush(stdout); }
void DumpPCON( PCON pcon)
/*++
Routine Description:
Dump a contribution.
Arguments:
pcon - contribution to dump.
Return Value:
None.
--*/
{ DBPRINT("\n contributor: flags=%08lX, rva=%08lX, module=%s\n", pcon->flags, pcon->rva, SzObjNamePCON(pcon)); DBPRINT("cbRawData= %08lX ", pcon->cbRawData); DBPRINT("foRawDataD=%08lX ", pcon->foRawDataDest); DBPRINT("chksum =%08lX ", pcon->chksumComdat); DBPRINT("selComdat= %04X\n", pcon->selComdat); DBPRINT("cbPad = %04X\n", pcon->cbPad); fflush(stdout); }
#endif // DBG
|