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.
 
 
 
 
 
 

2043 lines
50 KiB

/***********************************************************************
* Microsoft (R) 32-Bit Incremental Linker
*
* Copyright (C) Microsoft Corp 1992-1996. All rights reserved.
*
* File: lnkp2.cpp
*
* File Comments:
*
* Pass 2 of the COFF Linker.
*
***********************************************************************/
#include "link.h"
#include "pdb.h"
BOOL fPDBNotFound;
#if DBG
void
DumpPSYM(
PIMAGE_SYMBOL psym)
/*++
Routine Description:
Dump an image symbol to standard out.
Arguments:
psym - image symbol
Return Value:
None.
--*/
{
char szShort[IMAGE_SIZEOF_SHORT_NAME + 1];
DWORD ibSym;
if (psym->N.Name.Short) {
memset(szShort, '\0', IMAGE_SIZEOF_SHORT_NAME + 1);
strncpy(szShort, (char *) psym->n_name, 8);
printf("%s\n", szShort);
} else {
ibSym = psym->N.Name.Long;
printf("%s\n", &(StringTable[ibSym]));
}
printf("value=%.8lx, isec=%.4x, type=%.4x, sc=%.2x, caux=%.2x\n",
psym->Value, psym->SectionNumber, psym->Type,
psym->StorageClass, psym->NumberOfAuxSymbols);
fflush(stdout);
}
#endif // DBG
void
Pass2PSYM_file(
PIMAGE pimage,
PIMAGE_SYMBOL psym,
DWORD cSym,
DWORD *pcSymLink
)
/*++
Routine Description:
Process a file symbol.
Arguments:
psym - symbol
Return Value:
None.
--*/
{
static DWORD FileClassSeek = 0;
static DWORD FileClassFirst = 0;
IMAGE_SYMBOL sym;
DWORD li;
// A couple of points here. First, we need to maintain the
// .file thread through the output symbol table. To do so,
// we check for previous .file output and patch the value to
// point to us. Second, FeedLinenums expects pmod->isymFirstFile
// to point to the first .file record in an object *and* it will
// walk the original symbol table where it expects the .file thread
// to be intact.
// The problem is the link from the end to the beginning. For the input
// file, the last link almost always has a value field of zero (all
// compilers emit a .file record as the first record in the symbol table).
// However, the symbol table in the output image may not be the same.
// For instance, if the first two objects are foo.exp and foo.res, we'll
// get two static section records and the first .file record will be at
// symbol table offset 2 (not offset 0).
// Maintain the .file symbol entries linked list.
if (IsDebugSymbol(IMAGE_SYM_CLASS_FILE, &pimage->Switch)) {
if ((li = FileClassSeek) != 0) {
FileClassSeek = FileTell(FileWriteHandle);
FileSeek(FileWriteHandle, li, SEEK_SET);
ReadSymbolTableEntry(FileWriteHandle, &sym);
sym.Value = csymDebug;
FileSeek(FileWriteHandle, li, SEEK_SET);
WriteSymbolTableEntry(FileWriteHandle, &sym);
// Put the file pointer back were it was.
FileSeek(FileWriteHandle, FileClassSeek, SEEK_SET);
} else {
FileClassSeek = FileTell(FileWriteHandle);
FileClassFirst = csymDebug;
}
// Link the current .file to the first one, in case it's the last
// one. Save the current value so we can restore it after writing
// the record.
*pcSymLink = psym->Value;
psym->Value = FileClassFirst;
}
if ((CvInfo != NULL) &&
(CvInfo[NextCvObject].pmod->isymFirstFile == ISYMFIRSTFILEDEF))
{
// This is the first file for this object
CvInfo[NextCvObject].pmod->isymFirstFile = cSym;
}
}
void
Pass2PSYM_static_label(
PIMAGE pimage,
PIMAGE_SYMBOL psym,
PMOD pmod)
/*++
Routine Description:
Process a defined or undefined static or label symbol.
Arguments:
pst - image external symbol table
psym - symbol
pmod - pointer to module node
Return Value:
None.
--*/
{
SHORT isec;
BOOL fMapFile;
const char *szSymName;
isec = psym->SectionNumber;
fMapFile = pimage->Switch.Link.fMap &&
(isec > 0) &&
(psym->StorageClass == IMAGE_SYM_CLASS_STATIC) &&
ISFCN(psym->Type);
if (fMapFile) {
szSymName = SzNameSymPb(*psym, StringTable); // about to trash offset
}
if (IsLongName(*psym) && IsDebugSymbol(psym->StorageClass, &pimage->Switch)) {
// Change pointer to symbol name to be an
// offset within the long string table.
psym->n_offset = LookupLongName(pimage->pst, &StringTable[psym->n_offset]);
}
if (isec > 0) {
PCON pcon;
// Assign the real virtual address to the symbol.
pcon = PconPMOD(pmod, isec);
psym->SectionNumber = PsecPCON(pcon)->isec;
if (fMapFile && pcon->cbRawData != 0) {
SaveStaticForMapFile(szSymName, pcon, psym->Value, TRUE);
}
if (fM68K) {
DWORD Characteristics = pcon->flags;
// REVIEW - this isn't a very good check for .debug section
if (Characteristics & (IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_CNT_UNINITIALIZED_DATA)) {
psym->Value += pcon->rva - MacDataBase - cbMacData;
if (strncmp((char*)psym->N.ShortName, ".debug", 6) &&
strncmp((char*)psym->N.ShortName, ".rdata", 6)) {
assert((LONG)psym->Value <= 0);
}
} else { // MAC - symbol is in code.
psym->Value += pcon->rva - PsecPCON(pcon)->rva;
}
} else {
psym->Value += pcon->rva;
}
} else {
// UNDONE: This appears to be wrong for static absolute symbols
psym->Value = 0;
}
}
PEXTERNAL
PextPass2PSYM_external(
PIMAGE pimage,
PIMAGE_SYMBOL psym,
PSYMBOL_INFO psymInfo
)
/*++
Routine Description:
Process an external symbol.
Arguments:
psym - symbol
Return Value:
external symbol
--*/
{
PEXTERNAL pext;
PCON pcon;
DWORD rvaBase;
// CONSIDER: The call to LookupExternName should be unnecessary if the
// CONSIDER: symbol is defined in a non-COMDAT section in this module.
// CONSIDER: Check isec > 0 and PconPMOD(pmod, isec)->flags & IMAGE_SCN_LNK_COMDAT
if (IsLongName(*psym)) {
pext = LookupExternName(pimage->pst, LONGNAME, &StringTable[psym->n_offset],
NULL);
psym->N.Name = pext->ImageSymbol.N.Name;
} else {
pext = LookupExternName(pimage->pst, SHORTNAME, (char *) psym->n_name, NULL);
}
// setup values in symbol info
if (fINCR) {
assert(psymInfo);
assert(pext);
if (pext->Offset) {
psymInfo->fJmpTbl = 1;
psymInfo->Offset = pext->Offset;
}
}
pcon = pext->pcon;
if ((pext->Flags & EXTERN_DEFINED) == 0) {
// This symbol is undefined. Mark it as undefined.
psym->SectionNumber = IMAGE_SYM_UNDEFINED;
rvaBase = 0;
} else if (pcon == NULL) {
// This symbol is either debug or absolute
// Use the section number from the defining object file
psym->SectionNumber = pext->ImageSymbol.SectionNumber;
rvaBase = 0;
} else if ((pcon->flags & IMAGE_SCN_LNK_REMOVE) ||
(pimage->Switch.Link.fTCE && FDiscardPCON_TCE(pcon))) {
// This CON has been discarded
psym->SectionNumber = IMAGE_SYM_UNDEFINED;
rvaBase = 0;
} else {
// Use the section number from the generated image
psym->SectionNumber = PsecPCON(pcon)->isec;
if (fM68K) {
if (pcon->flags & IMAGE_SCN_CNT_CODE) {
rvaBase = pcon->rva - PsecPCON(pcon)->rva;
} else {
rvaBase = pcon->rva - MacDataBase - cbMacData;
}
} else {
rvaBase = pcon->rva;
}
}
// Set the symbol value to be the final value of the extern.
// This is used later when resolving fixups.
psym->Value = rvaBase + pext->ImageSymbol.Value;
pext->FinalValue = psym->Value;
pext->ImageSymbol.SectionNumber = psym->SectionNumber;
if (fM68K && (pcon != NULL) && !(pcon->flags & IMAGE_SCN_CNT_CODE)
&& !(pimage->Switch.Link.Force & ftUnresolved)) {
assert((LONG)psym->Value < 0);
}
return(pext);
}
void
Pass2PSYM_section(
PIMAGE pimage,
PIMAGE_SYMBOL psym,
PMOD pmod)
/*++
Routine Description:
Process a section symbol.
Arguments:
psym - symbol
Return Value:
None.
--*/
{
const char *szSec;
PSEC psec;
szSec = SzNameSymPst(*psym, pimage->pst);
// Look for matching section.
// The symbol value contains the section characteristics.
psec = PsecFindGrp(pmod, szSec, psym->Value, &pimage->secs, &pimage->ImgOptHdr);
if (psec == NULL) {
char szComFileName[_MAX_PATH * 2];
// UNDONE: Better error
Fatal(SzComNamePMOD(pmod, szComFileName), UNDEFINED, szSec);
}
// looking up an .idata group is a special case ... we want the beginning of this module's
// contribution to the .idata group, not the beginning of the whole thing. (This is the
// long-required "stupid linker trick" for linking import tables correctly.) We compare
// with szSec rather than psec->szName, so it still works even if the .idata stuff has
// been -merge'd into some other SEC.
if (strncmp(szSec, ".idata$", 7) == 0) {
PGRP pgrp;
ENM_DST enm_dst;
// This assigns the value of the section symbol to be the RVA of the
// first contribution to this group for the imported DLL.
psym->Value = 0;
// Enumerate the CONs in the group names in the symbol
pgrp = PgrpFind(psec, szSec);
InitEnmDst(&enm_dst, pgrp);
while (FNextEnmDst(&enm_dst)) {
if (enm_dst.pcon->flags & IMAGE_SCN_LNK_REMOVE) {
continue;
}
if (pimage->Switch.Link.fTCE) {
if (FDiscardPCON_TCE(enm_dst.pcon)) {
continue;
}
}
if (!strcmp(SzObjNamePCON(enm_dst.pcon), SzOrigFilePMOD(pmod))) {
psym->Value = enm_dst.pcon->rva;
break;
}
}
EndEnmDst(&enm_dst);
assert(psym->Value != 0);
} else {
psym->Value = psec->rva;
}
psym->SectionNumber = psec->isec;
}
void
Pass2PSYM_default(
PIMAGE pimage,
PIMAGE_SYMBOL psym)
/*++
Routine Description:
Process all other symbols.
Arguments:
pst - image external symbol table
psym - symbol
Return Value:
None.
--*/
{
if (IsLongName(*psym) && IsDebugSymbol(psym->StorageClass, &pimage->Switch)) {
// Change pointer to symbol name to be an
// offset within the long string table.
if (psym->n_offset) {
psym->n_offset =
LookupLongName(pimage->pst, &StringTable[psym->n_offset]);
}
}
}
void
Pass2PSYM_AUX_function(
PIMAGE_SYMBOL psym,
DWORD *pfoPrevDefToBF,
DWORD *pfoPrevBF,
DWORD iasym)
/*++
Routine Description:
Process an function symbol's auxiliary symbol(s).
Arguments:
psym - image symbol
pasym - image aux symbol
*pfoPrevDefToBf - previous offset to def corresponding to BF
*pfoPrevDef - previous offset to def
*pfoPrevBF - previous offset to BF
iasym - current aux symbol for psym
Return Value:
!0 if a user symbols, 0 otherwise.
--*/
{
#define foPrevDefToBF (*pfoPrevDefToBF)
#define foPrevBF (*pfoPrevBF)
IMAGE_AUX_SYMBOL asym;
DWORD foCurPos;
// Check for ".bf" record
if (psym->n_name[1] != 'b' ||
psym->NumberOfAuxSymbols != (BYTE) iasym) {
return; // not a .bf
}
// Update the previous .bf pointer and previous .def to .bf pointer
foCurPos = FileTell(FileWriteHandle);
// Previouse BF forward pointer
if (foPrevBF) {
FileSeek(FileWriteHandle, foPrevBF, SEEK_SET);
ReadSymbolTableEntry(FileWriteHandle, (PIMAGE_SYMBOL) &asym);
asym.Sym.FcnAry.Function.PointerToNextFunction = csymDebug - 1;
FileSeek(FileWriteHandle, foPrevBF, SEEK_SET);
WriteAuxSymbolTableEntry(FileWriteHandle, &asym);
}
if (foPrevDefToBF) {
FileSeek(FileWriteHandle, foPrevDefToBF, SEEK_SET);
ReadSymbolTableEntry(FileWriteHandle, (PIMAGE_SYMBOL) &asym);
asym.Sym.TagIndex = csymDebug - 1;
FileSeek(FileWriteHandle, foPrevDefToBF, SEEK_SET);
WriteAuxSymbolTableEntry(FileWriteHandle, &asym);
}
if (foPrevBF || foPrevDefToBF) {
FileSeek(FileWriteHandle, foCurPos, SEEK_SET);
}
// update the file pointers
foPrevBF = foCurPos;
foPrevDefToBF = 0;
#undef foPrevDefToBF
#undef foPrevBF
}
void
Pass2PSYM_AUX(
PIMAGE_SYMBOL psym,
PIMAGE_SYMBOL *ppsymNext,
BOOL fEmit,
DWORD *pcsymbol)
/*++
Routine Description:
Process auxiliary symbols.
Arguments:
psym - image symbol
*ppsymNext - next image symbol
fEmit - !0 if we should emit symbol, 0 otherwise
*pcsymbol - number of symbols read so far
Return Value:
None.
--*/
{
static DWORD foPrevDefToBF = 0;
static DWORD foPrevBF = 0;
DWORD iasym;
for (iasym = psym->NumberOfAuxSymbols; iasym; iasym--) {
PIMAGE_AUX_SYMBOL pasym;
pasym = (PIMAGE_AUX_SYMBOL) FetchNextSymbol(ppsymNext);
(*pcsymbol)++;
if (fEmit) {
// If the symbol was defined, and we're writting debug
// information, then write the auxiliary symbol table
// entry to the image file.
if (psym->StorageClass == IMAGE_SYM_CLASS_FUNCTION) {
Pass2PSYM_AUX_function(psym,
&foPrevDefToBF,
&foPrevBF,
iasym);
}
WriteAuxSymbolTableEntry(FileWriteHandle, pasym);
csymDebug++;
}
}
}
void
AddPublicMod(
PIMAGE pimage,
const char *szName,
WORD isecAbsolute,
PEXTERNAL pext
)
/*++
Routine Description:
Passes on a public to PDB. Review: absolutes?
Arguments:
szName - name of public.
isec - section number.
pext - ptr to external
Return Value:
None.
--*/
{
PCON pcon;
// Emit symbols once.
if (pext->Flags & EXTERN_EMITTED) {
return;
}
pext->Flags |= EXTERN_EMITTED;
if ((pext->Flags & EXTERN_DEFINED) == 0) {
return;
}
pcon = pext->pcon;
if (pcon != NULL) {
PMOD pmod;
PSEC psec;
if (pcon->flags & IMAGE_SCN_LNK_REMOVE) {
return;
}
if (pimage->Switch.Link.fTCE) {
if (FDiscardPCON_TCE(pcon)) {
// Ignore symbols of discarded comdats
return;
}
}
psec = PsecPCON(pcon);
pmod = PmodPCON(pcon);
// Check for a common; pmod is NULL for these symbols
if (pext->Flags & EXTERN_COMMON) {
if (fPDBNotFound) {
DBG_AddPublicDBI(szName, psec->isec, pext->FinalValue - psec->rva);
} else {
DBG_AddPublicMod(szName, psec->isec, pext->FinalValue - psec->rva);
}
return;
}
if (pmod == NULL) {
// Ignore internal symbols
return;
}
// Emit a public
if (fPDBNotFound) {
DBG_AddPublicDBI(szName, psec->isec, pext->FinalValue - (fM68K ? 0 : psec->rva));
} else {
DBG_AddPublicMod(szName, psec->isec, pext->FinalValue - (fM68K ? 0 : psec->rva));
}
} else if (pext->ImageSymbol.SectionNumber == IMAGE_SYM_ABSOLUTE) {
// Absolute: pcon == NULL, isec = IMAGE_SYM_ABSOLUTE
if (fPDBNotFound) {
DBG_AddPublicDBI(szName, isecAbsolute, pext->FinalValue);
} else {
DBG_AddPublicMod(szName, isecAbsolute, pext->FinalValue);
}
}
}
void
Pass2PSYM(
PIMAGE pimage,
PMOD pmod,
PIMAGE_SYMBOL psym,
PIMAGE_SYMBOL *ppsymNext,
DWORD *pcsymbol,
PSYMBOL_INFO psymInfo,
BOOL fDoDbg
)
/*++
Routine Description:
Reads and sorts relocation entries. Process each symbol entry. If the
symbol is a definition, the symbol is written to the image file. Reads
raw data from object, applys fixups, and writes raw data to image file.
Arguments:
pst - external symbol table
psym - current symbol
*ppsymNext - next image symbol
*pcsymbol - number of symbols read so far
fNoDbg - no debug info required
Return Value:
None.
--*/
{
SHORT isec;
BOOL fDiscarded;
PCON pcon;
PEXTERNAL pext = NULL;
BOOL fEmit;
DWORD dwSymLink = ISYMFIRSTFILEDEF;
assert(*ppsymNext);
assert(pcsymbol);
isec = psym->SectionNumber;
fDiscarded = FALSE;
if (isec > 0) {
pcon = PconPMOD(pmod, isec);
// Filter out all symbols in sections which aren't linked.
if (pcon->flags & IMAGE_SCN_LNK_REMOVE) {
fDiscarded = TRUE;
} else if (pimage->Switch.Link.fTCE) {
if (FDiscardPCON_TCE(pcon)) {
fDiscarded = TRUE;
}
}
}
switch (psym->StorageClass) {
case IMAGE_SYM_CLASS_FILE :
Pass2PSYM_file(pimage, psym, *pcsymbol, &dwSymLink);
break;
case IMAGE_SYM_CLASS_STATIC :
case IMAGE_SYM_CLASS_UNDEFINED_STATIC :
case IMAGE_SYM_CLASS_LABEL :
case IMAGE_SYM_CLASS_UNDEFINED_LABEL :
Pass2PSYM_static_label(pimage, psym, pmod);
break;
case IMAGE_SYM_CLASS_EXTERNAL :
case IMAGE_SYM_CLASS_FAR_EXTERNAL :
case IMAGE_SYM_CLASS_WEAK_EXTERNAL :
pext = PextPass2PSYM_external(pimage, psym, psymInfo);
if (fDoDbg && fPdb) {
// UNDONE: Why not do this in or around EmitExternals for non-INCREMENTAL
// UNDONE: case. This avoids repeated calls to AddPublicMod for each
// UNDONE: reference to an external symbol.
AddPublicMod(pimage,
SzNameSymPst(*psym, pimage->pst),
(WORD) (pimage->ImgFileHdr.NumberOfSections + 1),
pext);
}
if (fM68K) {
rgpExternObj[*pcsymbol] = pext;
}
break;
case IMAGE_SYM_CLASS_SECTION :
Pass2PSYM_section(pimage, psym, pmod);
break;
default :
Pass2PSYM_default(pimage, psym);
break;
}
// If the symbol is being defined, and we're writting debug
// information, then write the updated symbol table entry
// to the image file. If the symbol is external, then dump
// only those that have an auxiliary entry (must be a
// function definition). All other externals will be written
// to the end of the symbol table.
fEmit = FALSE;
if ((isec != 0) &&
!fDiscarded &&
IsDebugSymbol(psym->StorageClass, &pimage->Switch)) {
// Use for loop to allow easy exit via break.
for (;;) {
if (pext != NULL) {
// External symbols are emitted in EmitExternals
break;
}
if ((psym->StorageClass == IMAGE_SYM_CLASS_STATIC) &&
((isec > 0) && (CLinenumSrcPCON(pcon) == 0))) {
// This is a static symbol in a section w/o line numbers
if (psym->NumberOfAuxSymbols > 0) {
// Don't write symbols with aux records. These are
// most likely section symbols.
break;
}
}
if ((isec > 0) &&
(PsecPCON(pcon) == psecDebug) &&
!IncludeDebugSection) {
// Don't emit symbols in .debug if .debug isn't mapped
break;
}
if (fM68K && (isec > 0)) {
psym->Value += PsecPCON(pcon)->rva;
}
WriteSymbolTableEntry(FileWriteHandle, psym);
csymDebug++;
if (dwSymLink != ISYMFIRSTFILEDEF) {
psym->Value = dwSymLink;
}
if (fM68K && (isec > 0)) {
psym->Value -= PsecPCON(pcon)->rva;
}
fEmit = TRUE;
break;
}
}
if (psym->NumberOfAuxSymbols != 0) {
Pass2PSYM_AUX(psym,
ppsymNext,
fEmit,
pcsymbol);
}
}
const char *
SzNameFixupSym(
PIMAGE pimage,
PIMAGE_SYMBOL psym
)
{
switch (psym->StorageClass) {
// Minimal, Partial or Full debug
case IMAGE_SYM_CLASS_STATIC:
if ((pimage->Switch.Link.DebugType & CoffDebug) == 0) {
break;
}
// Fall through
case IMAGE_SYM_CLASS_FAR_EXTERNAL:
case IMAGE_SYM_CLASS_EXTERNAL:
case IMAGE_SYM_CLASS_WEAK_EXTERNAL:
// Pass2PSYM updated sym to use the image's string table.
return(SzNameSymPst(*psym, pimage->pst));
}
return(SzNameSymPb(*psym, StringTable));
}
void
CountFixupError(
PIMAGE pimage
)
{
cFixupError++;
if ((cFixupError >= 100) && !(pimage->Switch.Link.Force & ftUnresolved)) {
Fatal(NULL, FIXUPERRORS);
}
}
void
Pass2InitUninitDataPcon(PCON pcon)
{
PSEC psec;
DWORD cbInit;
DWORD ib;
DWORD cbZero;
void *pvRawData;
psec = PsecPCON(pcon);
cbInit = psec->cbInitData;
ib = pcon->rva - psec->rva;
if (ib >= cbInit) {
// This CON is beyond the initialized region for this section
return;
}
// This is uninitialized data in the initialized region of a section. This needs to be
// initialized to zero. With buffered I/O or mapped I/O under Windows 95, the memory
// is not guaranteed to be zero so it must be zeroed explicitly.
cbZero = __min(pcon->cbRawData, cbInit - ib);
assert(pcon->foRawDataDest != 0);
pvRawData = PbMappedRegion(FileWriteHandle, pcon->foRawDataDest, cbZero);
if (pvRawData) {
// If we're mapped, just zap in place.
memset(pvRawData, 0, cbZero);
} else {
// Otherwise, do it the slow way.
#define cbZeroLoop 16
static const BYTE rgbZero[cbZeroLoop] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
FileSeek(FileWriteHandle, pcon->foRawDataDest, SEEK_SET);
while (cbZero > cbZeroLoop) {
FileWrite(FileWriteHandle, rgbZero, cbZeroLoop);
cbZero -= cbZeroLoop;
}
#undef cbZeroLoop
FileWrite(FileWriteHandle, rgbZero, cbZero);
}
}
void
Pass2InitCommonPmod(PMOD pmod, PIMAGE pimage)
{
LEXT *plext;
for (plext = pmod->plextCommon; plext != NULL; plext = plext->plextNext) {
PEXTERNAL pext = plext->pext;
if ((pext->Flags & EXTERN_COMMON) == 0) {
// Symbol was really defined after seeing a COMMON definition
return;
}
if (pimage->Switch.Link.fTCE) {
if (FDiscardPCON_TCE(pext->pcon)) {
continue;
}
}
Pass2InitUninitDataPcon(pext->pcon);
}
}
void
Pass2ReadWriteRawDataPCON(
PIMAGE pimage,
PCON pcon,
PIMAGE_SYMBOL rgsymAll,
PSYMBOL_INFO rgsymInfo
)
/*++
Routine Description:
Reads and writes raw data during pass 2.
Arguments:
pst - external symbol table
pcon - contribution node in driver map
Return Value:
None.
--*/
{
#define CvNext (CvInfo[NextCvObject])
PVOID pvRawData;
BOOL fMappedOut;
if (pcon->flags & IMAGE_SCN_LNK_REMOVE) {
return;
}
if (pcon->cbRawData == 0) {
return;
}
if (FetchContent(pcon->flags) == IMAGE_SCN_CNT_UNINITIALIZED_DATA) {
Pass2InitUninitDataPcon(pcon);
return;
}
if (fM68K && (pcon->flags & IMAGE_SCN_CNT_CODE) &&
pcon->rva == PsecPCON(pcon)->pgrpNext->rva) {
WriteResourceHeader(pcon, (BOOL)fDLL(pimage));
}
// Generate NB05 only when pdb:none, otherwise NB10
if (!fPdb && (pimage->Switch.Link.DebugType & CvDebug)) {
// Save required CodeView info.
if (pcon->pgrpBack == pgrpCvSymbols) {
if (!CvNext.Locals.PointerToSubsection) {
assert(pcon->foRawDataDest >= CvSeeks.Base);
CvNext.Locals.PointerToSubsection = pcon->foRawDataDest;
} else {
pcon->foRawDataDest = CvNext.Locals.PointerToSubsection +
CvNext.Locals.SizeOfSubsection;
}
CvNext.Locals.SizeOfSubsection += (pcon->cbRawData - pcon->cbPad);
} else if (pcon->pgrpBack == pgrpCvTypes) {
if (!CvNext.Types.PointerToSubsection) {
assert(pcon->foRawDataDest >= CvSeeks.Base);
CvNext.Types.PointerToSubsection = pcon->foRawDataDest;
CvNext.Types.Precompiled = FALSE;
} else {
pcon->foRawDataDest = CvNext.Types.PointerToSubsection +
CvNext.Types.SizeOfSubsection;
}
CvNext.Types.SizeOfSubsection += (pcon->cbRawData - pcon->cbPad);
} else if (pcon->pgrpBack == pgrpCvPTypes) {
if (!CvNext.Types.PointerToSubsection) {
assert(pcon->foRawDataDest >= CvSeeks.Base);
CvNext.Types.PointerToSubsection = pcon->foRawDataDest;
CvNext.Types.Precompiled = TRUE;
} else {
pcon->foRawDataDest = CvNext.Types.PointerToSubsection +
CvNext.Types.SizeOfSubsection;
}
CvNext.Types.SizeOfSubsection += (pcon->cbRawData - pcon->cbPad);
}
}
// Read the raw data, apply fixups, write it to the image
if ((fPdb && (PsecPCON(pcon) == psecDebug)) ||
(fINCR && (fPowerMac ? PgrpPCON(pcon) == pgrpPdata : PsecPCON(pcon) == psecException))) {
// Don't do mapping for NB10 debug info (goes to PDB).
// When incremental, don't map .pdata
pvRawData = NULL;
fMappedOut = FALSE;
} else {
assert(pcon->foRawDataDest != 0);
pvRawData = PbMappedRegion(FileWriteHandle,
pcon->foRawDataDest,
pcon->cbRawData);
fMappedOut = (pvRawData != NULL);
}
if (!fMappedOut) {
pvRawData = PvAlloc(pcon->cbRawData);
}
assert(pcon->cbRawData >= pcon->cbPad);
FileSeek(FileReadHandle, FoRawDataSrcPCON(pcon), SEEK_SET);
FileRead(FileReadHandle, pvRawData, pcon->cbRawData - pcon->cbPad);
if (FHasRelocSrcPCON(pcon)) {
PIMAGE_RELOCATION rgrel;
DWORD creloc;
BASE_RELOC *pbrSave = pbrCur;
rgrel = ReadRgrelPCON(pcon, &creloc);
ApplyFixups(pcon, rgrel, creloc, (BYTE *) pvRawData, rgsymAll, pimage, rgsymInfo);
FreeRgrel(rgrel);
PsecPCON(pcon)->fHasBaseRelocs |= (pbrSave != pbrCur);
}
if (fPdb && (PsecPCON(pcon) == psecDebug)) {
// Write debug information to the PDB
if ((pcon->pgrpBack == pgrpCvTypes) ||
(pcon->pgrpBack == pgrpCvPTypes)) {
ERROR_TYPES eTypes = DBG_AddTypesMod(pcon,
pvRawData,
pcon->cbRawData - pcon->cbPad,
!fIncrDbFile);
switch (eTypes) {
case eNone :
break;
case ePCT :
if (!fIncrDbFile) {
// Full link failure - fatal
FatalPcon(pcon, INTERNAL_ERR);
}
errInc = errTypes;
break;
case ePDBNotFound :
fPDBNotFound = TRUE;
break;
default :
FatalPcon(pcon, INTERNAL_ERR);
}
} else if (pcon->pgrpBack == pgrpCvSymbols) {
DBG_AddSymbolsMod(pvRawData, pcon->cbRawData - pcon->cbPad);
} else if (pcon->pgrpBack == pgrpFpoData) {
if (!FPOAddFpo(PmodPCON(pcon)->imod, (FPO_DATA *) pvRawData,
(pcon->cbRawData - pcon->cbPad)/sizeof(FPO_DATA))) {
if (!fIncrDbFile) {
FatalPcon(pcon, INTERNAL_ERR);
}
#ifdef INSTRUMENT
LogNoteEvent(Log, SZILINK, SZPASS2, letypeEvent, "fpo pad exhausted");
#endif // INSTRUMENT
errInc = errFpo;
}
} else {
goto NotPdbData;
}
assert(!fMappedOut);
FreePv(pvRawData);
return;
NotPdbData: ;
}
if (fINCR && (fPowerMac ? PgrpPCON(pcon) == pgrpPdata : PsecPCON(pcon) == psecException)) {
if (!PDATAAddPdataPcon(pcon, (PIMAGE_RUNTIME_FUNCTION_ENTRY) pvRawData)) {
if (!fIncrDbFile) {
FatalPcon(pcon, INTERNAL_ERR);
}
#ifdef INSTRUMENT
LogNoteEvent(Log, SZILINK, SZPASS2, letypeEvent, "pdata pad exhausted");
#endif // INSTRUMENT
errInc = errPdata;
}
assert(!fMappedOut);
FreePv(pvRawData);
return;
}
if (pcon->cbPad) {
void *pvPad;
int iPad;
pvPad = ((PBYTE) pvRawData) + pcon->cbRawData - pcon->cbPad;
if ((FetchContent(pcon->flags) == IMAGE_SCN_CNT_CODE) &&
(pimage->ImgFileHdr.Machine == IMAGE_FILE_MACHINE_I386)) {
// Pad with int3
iPad = X86_INT3;
} else {
iPad = 0;
}
memset(pvPad, iPad, pcon->cbPad);
}
if (!fMappedOut) {
assert(pcon->foRawDataDest != 0);
FileSeek(FileWriteHandle, pcon->foRawDataDest, SEEK_SET);
// Write out the data and the padding that follows
FileWrite(FileWriteHandle, pvRawData, pcon->cbRawData);
FreePv(pvRawData);
}
#undef CvNext
}
void
Pass2ReadWriteLineNumbersPCON(
PIMAGE pimage,
PCON pcon)
/*++
Routine Description:
Reads and writes line numbers during pass 2.
Arguments:
pst - external symbol table
pcon - contribution node in driver map
Return Value:
None.
--*/
{
DWORD cLinenum;
DWORD cbLinenum;
PIMAGE_LINENUMBER rgLinenum;
cLinenum = CLinenumSrcPCON(pcon);
if (cLinenum == 0) {
return;
}
if ((pimage->Switch.Link.DebugInfo == None ||
pimage->Switch.Link.DebugInfo == Minimal) &&
!pimage->Switch.Link.fMapLines) {
return;
}
cbLinenum = cLinenum * sizeof(IMAGE_LINENUMBER);
rgLinenum = (PIMAGE_LINENUMBER) PvAlloc(cbLinenum);
FileSeek(FileReadHandle, FoLinenumSrcPCON(pcon), SEEK_SET);
FileRead(FileReadHandle, (void *) rgLinenum, cbLinenum);
if (((pimage->Switch.Link.DebugType & CvDebug) != 0) ||
pimage->Switch.Link.fMapLines) {
PMOD pmod = PmodPCON(pcon);
assert(pmod->rgSymObj);
FeedLinenums(rgLinenum,
cLinenum,
pcon,
pmod->rgSymObj,
pmod->csymbols,
pmod->isymFirstFile,
((pimage->Switch.Link.DebugType & CvDebug) != 0),
pimage->Switch.Link.fMapLines);
}
if (pimage->Switch.Link.DebugType & CoffDebug) {
WORD lineFuncStart = 0; // Normally set (by 0-valued linenum) before use
PIMAGE_LINENUMBER pLinenum;
DWORD li;
for (pLinenum = rgLinenum, li = cLinenum; li; li--, pLinenum++) {
if (pLinenum->Linenumber != 0) {
pLinenum->Type.VirtualAddress -= RvaSrcPCON(pcon); // the virtual address is now relative to the virtual address of the source
pLinenum->Type.VirtualAddress += pcon->rva;
if (pLinenum->Linenumber == 0x7fff) {
// This is how the compiler says that the COFF relative linenum was 0,
// without confusing the linker for which 0 has a special meaning.
pLinenum->Linenumber = 0;
}
// Make line number absolute
pLinenum->Linenumber += lineFuncStart;
} else {
PMOD pmod = PmodPCON(pcon);
DWORD isymDefObj, isymBfObj;
PIMAGE_SYMBOL psymDefObj;
assert(pmod != NULL);
if (pLinenum->Type.SymbolTableIndex >
PmodPCON(pcon)->csymbols) {
FatalPcon(pcon, CORRUPTOBJECT);
}
// Find the starting line # in the function (lineFuncStart). This is
// added to the subsequent linenumbers, to convert them from relative
// to absolute.
assert(pmod->rgSymObj);
isymDefObj = pLinenum->Type.SymbolTableIndex;
if (isymDefObj + 1 >= pmod->csymbols ||
(psymDefObj = &pmod->rgSymObj[isymDefObj])->NumberOfAuxSymbols < 1 ||
(isymBfObj = ((PIMAGE_AUX_SYMBOL)(psymDefObj + 1))->Sym.TagIndex)
+ 1 >= pmod->csymbols ||
pmod->rgSymObj[isymBfObj].NumberOfAuxSymbols < 1)
{
// linenums do not point to a valid .def, or .def's aux record doesn't
// contain a valid pointer to a .bf, or .bf isn't a valid .bf.
FatalPcon(pcon, CORRUPTOBJECT);
}
lineFuncStart = ((PIMAGE_AUX_SYMBOL)&pmod->rgSymObj[isymBfObj + 1])
->Sym.Misc.LnSz.Linenumber;
// Update the current linenumber record so it is just a regular one like all
// the others, instead of being a special 0-valued one.
pLinenum->Linenumber = lineFuncStart;
pLinenum->Type.VirtualAddress = psymDefObj->Value;
}
}
FileSeek(FileWriteHandle, PsecPCON(pcon)->foLinenum, SEEK_SET);
FileWrite(FileWriteHandle, (void *) rgLinenum, cbLinenum);
PsecPCON(pcon)->foLinenum += cbLinenum;
}
FreePv((void *) rgLinenum);
}
void
AddSecContribs (
PIMAGE pimage,
PMOD pmod
)
/*++
Routine Description:
Adds mod's contributions to the code section.
Arguments:
pimage - pointer to image struct
pmod - module node in driver map
Return Value:
None.
--*/
{
ENM_SRC enmSrc;
for (InitEnmSrc(&enmSrc, pmod); FNextEnmSrc(&enmSrc); ) {
if (enmSrc.pcon->flags & IMAGE_SCN_LNK_REMOVE) {
continue;
}
if (enmSrc.pcon->cbRawData == 0) {
continue;
}
if (PsecPCON(enmSrc.pcon) == psecDebug) {
continue;
}
if (pimage->Switch.Link.fTCE) {
if (FDiscardPCON_TCE(enmSrc.pcon)) {
// Discarded comdat
continue;
}
}
DBG_AddSecContribMod(PsecPCON(enmSrc.pcon)->isec,
enmSrc.pcon->rva - PsecPCON(enmSrc.pcon)->rva,
(enmSrc.pcon->cbRawData - enmSrc.pcon->cbPad),
enmSrc.pcon->flags);
}
}
void
Pass2PMOD(
PIMAGE pimage,
PMOD pmod,
BOOL fDoDbg)
/*++
Routine Description:
Reads and sorts relocation entries. Process each symbol entry. If the
symbol is a definition, the symbol is written to the image file. Reads
raw data from object, applys fixups, and writes raw data to image file.
Arguments:
pst - external symbol table
pmod - module node in driver map
fDoDbg - TRUE if debug info needs to be done (only for NB10)
Return Value:
None.
--*/
{
#define CvNext (CvInfo[NextCvObject])
PIMAGE_SYMBOL rgsymAll;
PIMAGE_SYMBOL psymNext;
PIMAGE_SYMBOL psym;
PSYMBOL_INFO rgsymInfo = NULL;
ENM_SRC enm_src;
DWORD csymbol;
DWORD cbST;
PST pst = pimage->pst;
VERBOSE(printf(" %s\n", InternalError.CombinedFilenames));
// Read in image section headers if necessary
if (pmod->rgci == NULL) {
ReadImageSecHdrInfoPMOD(pmod, NULL);
}
// Read and store object string table.
StringTable = ReadStringTablePMOD(pmod, &cbST);
if (pmod->csymbols > 0) {
rgsymAll = ReadSymbolTablePMOD(pmod, TRUE);
} else {
rgsymAll = NULL; /* .exp libs consisting only of directives will have no symbols */
}
pmod->rgSymObj = rgsymAll;
if (fM68K) {
rgpExternObj = (PEXTERNAL *)PvAllocZ(pmod->csymbols * sizeof(PEXTERNAL));
}
// seek to current offset in image symbol table
FileSeek(FileWriteHandle,
foCoffSyms + csymDebug * sizeof(IMAGE_SYMBOL), SEEK_SET);
// seek to beginning of symbol table in module
FileSeek(FileReadHandle, FoSymbolTablePMOD(pmod), SEEK_SET);
// allocate space for a parallel sym info array
if (fINCR) {
rgsymInfo = (PSYMBOL_INFO) PvAllocZ(pmod->csymbols * sizeof(SYMBOL_INFO));
}
if (CvInfo != NULL) {
CvNext.pmod = pmod; // initialize
pmod->isymFirstFile = ISYMFIRSTFILEDEF;
}
// First pass: Do all the types first
fPDBNotFound = FALSE;
if (fDoDbg) {
if (CvInfo != NULL) {
CvNext.ObjectFilename = SzOrigFilePMOD(pmod);
}
InitEnmSrc(&enm_src, pmod);
while (FNextEnmSrc(&enm_src)) {
if ((enm_src.pcon->pgrpBack != pgrpCvTypes) &&
(enm_src.pcon->pgrpBack != pgrpCvPTypes)) {
continue;
}
// do not expect any relocs for a types section
assert(!FHasRelocSrcPCON(enm_src.pcon));
Pass2ReadWriteRawDataPCON(pimage, enm_src.pcon, rgsymAll, rgsymInfo);
if (errInc != errNone) {
return;
}
}
}
// Process all objects symbols. Do this after doing the types
// so that if a PDB isn't found we add the publics to DBI
// instead of to the Mod.
csymbol = 0;
psymNext = rgsymAll;
while (csymbol != pmod->csymbols) {
psym = psymNext++;
DBEXEC(DB_PASS2PSYM, DumpPSYM(psym));
Pass2PSYM(pimage, pmod, psym, &psymNext, &csymbol,
fINCR ? &rgsymInfo[csymbol] : NULL, fDoDbg);
csymbol++;
}
if (fPDBNotFound) {
// Now that we have added types & publics check to see if
// we should continue to pass on debug info to PDB
fDoDbg = FALSE;
}
InitEnmSrc(&enm_src, pmod);
while (FNextEnmSrc(&enm_src)) {
PEXTNODE pextDupConNode;
DBEXEC(DB_PASS2PCON, DumpPCON(enm_src.pcon));
pextDupConNode = fM68K ? IsDupCon(enm_src.pcon) : NULL;
if ((enm_src.pcon->flags & IMAGE_SCN_LNK_REMOVE) && pextDupConNode == NULL) {
continue;
}
if (pimage->Switch.Link.fTCE) {
if (FDiscardPCON_TCE(enm_src.pcon)) {
continue;
}
}
// Ignore debug contribs if required (unchanged mods)
if (!fDoDbg && (PsecPCON(enm_src.pcon) == psecDebug)) {
continue;
}
// Second pass: Types have already been done
if ((enm_src.pcon->pgrpBack == pgrpCvTypes)) {
continue;
}
if ((enm_src.pcon->pgrpBack == pgrpCvPTypes)) {
continue;
}
if (enm_src.pcon->pgrpBack->pconNext == enm_src.pcon) {
PGRP pgrp;
DWORD cbPad;
// This is the first CON in this GRP
pgrp = enm_src.pcon->pgrpBack;
cbPad = pgrp->cbPad;
if (cbPad != 0) {
BYTE bPad = 0;
// This GRP requires padding at it's start
FileSeek(FileWriteHandle, pgrp->foRawData, SEEK_SET);
while (cbPad-- > 0) {
FileWrite(FileWriteHandle, &bPad, 1);
}
}
}
if (pextDupConNode != NULL) {
PMOD pmodT;
WORD sn;
PPSECREFDUPCON ptmp;
assert(fM68K);
// If this con is a dupcon, do all the other ones now
pmodT = PmodFind(pLibDupCon,
SzNamePext(pextDupConNode->pext, pimage->pst), 0);
// add dupcon only to the sections in the list
ptmp = pextDupConNode->ppsecrefdupcon;
while (ptmp) {
sn = ptmp->psec->isec;
if (sn == 0 ) {// is this enough? need ptmp->psec->cbRawData == 0 ?
ptmp = ptmp->psecNext;
continue;
}
Pass2ReadWriteRawDataPCON(pimage, PconPMOD(pmodT, sn), rgsymAll, rgsymInfo);
ptmp = ptmp->psecNext;
}
} else {
Pass2ReadWriteRawDataPCON(pimage, enm_src.pcon, rgsymAll, rgsymInfo);
}
if (fDoDbg && (enm_src.pcon->cbRawData != 0)) {
Pass2ReadWriteLineNumbersPCON(pimage, enm_src.pcon);
}
}
if (fDoDbg) {
// do this if we are not doing debug info - so we skip only on ilinks
Pass2InitCommonPmod(pmod, pimage);
}
FreeStringTable(StringTable);
StringTable = NULL;
if ((pimage->Switch.Link.DebugType & CvDebug) != 0) {
if (!fPdb) {
DWORD cb;
cb = ModQueryCbSstSrcModule(pmod->pModDebugInfoApi);
if (cb != 0) {
pmod->pSstSrcModInfo = PvAlloc(cb);
ModQuerySstSrcModule(pmod->pModDebugInfoApi, (BYTE *) pmod->pSstSrcModInfo, cb);
}
pmod->cbSstSrcModInfo = cb;
FreeLineNumInfo(pmod->pModDebugInfoApi);
} else if (fDoDbg) {
AddSecContribs(pimage, pmod);
}
}
if (rgsymAll != NULL) {
FreeSymbolTable(rgsymAll);
}
if (fM68K) {
FreePv(rgpExternObj);
if (fDLL(pimage) && fDLL16Reloc) {
fDLL16Reloc = FALSE;
Warning(InternalError.CombinedFilenames, MACDLLA5RELC);
}
}
if (fINCR) {
FreePv(rgsymInfo);
}
NextCvObject++;
#undef CvNext
}
void
AddSectionsToDBI (
PIMAGE pimage
)
/*++
Routine Description:
Reports the various section info through the DBI API.
Arguments:
pimage - pointer to image struct
Return Value:
None.
--*/
{
ENM_SEC enm_sec;
PSEC psec;
WORD i, flags, temp;
for (i = 1; i <= pimage->ImgFileHdr.NumberOfSections; i++) {
InitEnmSec(&enm_sec, &pimage->secs);
while (FNextEnmSec(&enm_sec)) {
psec = enm_sec.psec;
assert(psec);
if (psec->isec == i) {
EndEnmSec(&enm_sec);
break;
}
}
flags = 0x0108;
if (psec->flags & IMAGE_SCN_MEM_READ) {
flags |= 0x1;
}
if (psec->flags & IMAGE_SCN_MEM_WRITE) {
flags |= 0x2;
}
if (psec->flags & IMAGE_SCN_MEM_EXECUTE) {
flags |= 0x4;
}
// In the case of M68K pass the MacResource number
// instead of the actual section number.
temp = fM68K ? (WORD) (psec->iResMac) : i;
DBG_AddSecDBI(temp, flags, fM68K ? psec->dwM68KDataOffset : 0,
psec->cbRawData);
}
// Add an entry for absolutes
DBG_AddSecDBI(0, 0x0208, 0, (DWORD)-1);
}
BOOL
FCacheFilesInPlib (
PLIB plib
)
/*++
Routine Description:
Builds the list of mods in the lib with the count of times they are
repeated in the lib if required.
Arguments:
pst - external symbol table
Return Value:
TRUE if a list was needed.
--*/
{
BOOL fMultiple;
PMOD pmod;
if (plib->flags & LIB_LinkerDefined) {
return(FALSE);
}
fMultiple = FALSE;
for (pmod = plib->pmodNext; pmod != NULL; pmod = pmod->pmodNext) {
if (fIncrDbFile && !FDoDebugPMOD(pmod)) {
continue;
}
PMI pmi = LookupCachedMods(SzOrigFilePMOD(pmod), NULL);
pmi->cmods++;
fMultiple |= (pmi->cmods > 1);
}
if (!fMultiple) {
// This library does not require special treatment
// for multiple module contributions with same name
FreeMi();
return(FALSE);
}
return(TRUE);
}
BOOL FIsPCTMod(PMOD pmod)
{
for (PLMOD plmod = PCTMods; plmod != NULL; plmod = plmod->plmodNext) {
if (plmod->pmod == pmod) {
return(TRUE);
}
}
return(FALSE);
}
void Pass2Worker(PIMAGE pimage, PMOD pmod, BOOL fCache)
{
if (fIncrDbFile && !FDoPass2PMOD(pmod)) {
return;
}
FileReadHandle = FileOpen(SzFilePMOD(pmod), O_RDONLY | O_BINARY, 0);
MemberSeekBase = FoMemberPMOD(pmod);
SzComNamePMOD(pmod, InternalError.CombinedFilenames);
BOOL fDoDebug = fIncrDbFile ? FDoDebugPMOD(pmod) : TRUE;
// Don't even open MOD if we aren't doing debug info
if (fPdb && fDoDebug) {
DBG_OpenMod(SzOrigFilePMOD(pmod),
FIsLibPMOD(pmod) ? SzFilePMOD(pmod) : SzOrigFilePMOD(pmod),
fCache);
}
if (fIncrDbFile) {
// Delete MOD's fpo/pdata records
FPODeleteImod(pmod->imod);
PDATADeleteImod(pmod->imod);
}
Pass2PMOD(pimage, pmod, fDoDebug);
FileClose(FileReadHandle, !FIsLibPMOD(pmod));
// Bail out on error on an ilink
if (fIncrDbFile && (errInc != errNone)) {
return;
}
if (fPdb && fDoDebug) {
DBG_CloseMod(pmod, FIsLibPMOD(pmod) ? SzOrigFilePMOD(pmod) : pmod->szNameMod, fCache);
}
if (fIncrDbFile) {
pmod->LnkFlags &= ~(MOD_DoPass2 | MOD_DoDebug | MOD_NoPass1 | MOD_DidPass1);
}
}
void Pass2(PIMAGE pimage)
{
DWORD *rgThunkMap = NULL;
DWORD cThunkMap;
VERBOSE(Message(STRTPASS2));
if (fINCR) {
// Fixup/write out the jump table in the case of an incr build
if (fIncrDbFile) {
UpdateJumpTable(pimage, &rgThunkMap, &cThunkMap);
} else {
WriteJumpTable(pimage, pconJmpTbl, &rgThunkMap, &cThunkMap);
}
}
if (fPdb) {
// NB10 if /PDB specified
DBG_OpenPDB(PdbFilename);
nb10i.sig = DBG_QuerySignaturePDB();
nb10i.age = DBG_QueryAgePDB();
if (fIncrDbFile) {
// Check the signature & age of pdb
if ((nb10i.sig != pimage->pdbSig) ||
(nb10i.age < pimage->pdbAge)) {
Fatal(NULL, MISMATCHINPDB, PdbFilename);
}
pimage->pdbAge = nb10i.age;
DBG_OpenDBI(OutFilename);
if (errInc != errNone) {
DBG_ClosePDB();
return;
}
} else {
nb10i.off = 0;
pimage->pdbSig = nb10i.sig;
pimage->pdbAge = nb10i.age;
DBG_CreateDBI(OutFilename);
// Add linker defined public symbols to PDB
if (pimage->ImgFileHdr.Machine == IMAGE_FILE_MACHINE_POWERPC) {
if (pextToc->pcon != NULL) {
DBG_AddPublicDBI(".toc", PsecPCON(pextToc->pcon)->isec, pextToc->FinalValue - PsecPCON(pextToc->pcon)->rva);
}
}
if (fPowerMac) {
DBG_AddPublicDBI("__TocTb", PsecPCON(pextToc->pcon)->isec, pextToc->FinalValue - PsecPCON(pextToc->pcon)->rva);
DBG_AddPublicDBI("__FTInfo", PsecPCON(pextFTInfo->pcon)->isec, pextFTInfo->FinalValue - PsecPCON(pextFTInfo->pcon)->rva);
}
}
}
if (fPowerMac && !fINCR) {
MppcPass2Descriptors(pimage);
}
// First process all MODs containing precompiled types
for (PLMOD plmod = PCTMods; plmod != NULL; plmod = plmod->plmodNext) {
PMOD pmod = plmod->pmod;
PLIB plib = pmod->plibBack;
BOOL fCache;
if (fPdb) {
// Terrible hack so that dbi api openmod() doesn't see
// the same MOD names as is possible in import libs.
fCache = FCacheFilesInPlib(plib);
}
Pass2Worker(pimage, pmod, fCache);
if (fIncrDbFile && (errInc != errNone)) {
DBG_CloseDBI();
DBG_ClosePDB();
return;
}
}
// Now process all other MODs
ENM_LIB enm_lib;
InitEnmLib(&enm_lib, pimage->libs.plibHead);
while (FNextEnmLib(&enm_lib)) {
PLIB plib = enm_lib.plib;
BOOL fCache;
if (fPdb) {
// Terrible hack so that dbi api openmod() doesn't see
// the same MOD names as is possible in import libs.
fCache = FCacheFilesInPlib(plib);
}
ENM_MOD enm_mod;
InitEnmMod(&enm_mod, plib);
while (FNextEnmMod(&enm_mod)) {
PMOD pmod = enm_mod.pmod;
if (!fIncrDbFile && FIsPCTMod(pmod)) {
// Skip PCT MODs processed above. The call is unnecessary
// for fIncrDbFile because Pass2Worker clears MOD_DoPass2.
continue;
}
Pass2Worker(pimage, pmod, fCache);
if (fIncrDbFile && (errInc != errNone)) {
DBG_CloseDBI();
DBG_ClosePDB();
return;
}
}
}
if (!fIncrDbFile) {
Pass2InitCommonPmod(pmodLinkerDefined, pimage);
}
InternalError.CombinedFilenames[0] = '\0';
if ((cFixupError != 0) && !(pimage->Switch.Link.Force & ftUnresolved)) {
Fatal(NULL, FIXUPERRORS);
}
if (fPdb) {
if (fINCR && pconJmpTbl) {
// For PowerMac, the first entry in the iLink Thunk Table is null
DBG_AddThunkMapDBI(rgThunkMap, cThunkMap, CbJumpEntry(),
PsecPCON(pconJmpTbl)->isec,
PsecPCON(pconJmpTbl)->foRawData-pconJmpTbl->foRawDataDest +
(fPowerMac ? CbJumpEntry() : 0),
&pimage->secs,
pimage->ImgFileHdr.NumberOfSections);
FreePv(rgThunkMap);
}
AddSectionsToDBI(pimage);
DBG_CloseDBI();
DBG_CommitPDB();
DBG_ClosePDB();
}
VERBOSE(Message(ENDPASS2));
}