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.
 
 
 
 
 
 

2283 lines
39 KiB

/***********************************************************************
* 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