mirror of https://github.com/lianthony/NT4.0
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
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));
|
|
}
|