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.
1165 lines
31 KiB
1165 lines
31 KiB
/***********************************************************************
|
|
* Microsoft (R) 32-Bit Incremental Linker
|
|
*
|
|
* Copyright (C) Microsoft Corp 1992-1996. All rights reserved.
|
|
*
|
|
* File: ppc.cpp
|
|
*
|
|
* File Comments:
|
|
*
|
|
* Code specific to Windows PPC images
|
|
*
|
|
***********************************************************************/
|
|
|
|
#include "link.h"
|
|
|
|
|
|
STATIC BOOL fNeedToc;
|
|
STATIC DWORD cdwToc;
|
|
STATIC DWORD *rgdwToc;
|
|
STATIC PGRP pgrpToc;
|
|
STATIC PGRP pgrpTocIAT;
|
|
STATIC PGRP pgrpTocdLast;
|
|
STATIC PGRP pgrpTocLast;
|
|
|
|
|
|
BOOL
|
|
FPpcTocSym(
|
|
PIMAGE pimage,
|
|
PIMAGE_SYMBOL psym
|
|
)
|
|
{
|
|
switch (psym->StorageClass) {
|
|
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.
|
|
|
|
break;
|
|
|
|
default :
|
|
// The TOC symbol is external. This isn't it.
|
|
|
|
return(FALSE);
|
|
}
|
|
|
|
return(strcmp(SzNameSymPst(*psym, pimage->pst), ".toc") == 0);
|
|
}
|
|
|
|
|
|
void
|
|
DiagnoseTocTrouble (
|
|
PIMAGE pimage,
|
|
PCON pcon,
|
|
PIMAGE_SYMBOL psym,
|
|
DWORD rva
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Write a meaningful diagnostic for a failed TOCREL relocation.
|
|
|
|
Arguments:
|
|
|
|
pcon - A pointer to a contribution in the section data.
|
|
prel - Relocation being performed.
|
|
rva - Desired symbol value.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
|
|
{
|
|
if ((rva < pgrpToc->rva) || (rva > pgrpTocLast->rva + pgrpTocLast->cb)) {
|
|
// RVA occurs outside the TOC. It's up to the user (or linker)
|
|
// to place the symbol in either .tocd (or .idata$5).
|
|
|
|
ErrorPcon(pcon, TOCFIXUPNOTTOC, SzNameFixupSym(pimage, psym));
|
|
return;
|
|
}
|
|
|
|
// Something's not quite right--lie.
|
|
|
|
ErrorPcon(pcon, TOCFIXUPTOOFAR);
|
|
}
|
|
|
|
|
|
LONG
|
|
AssignTocSlot (
|
|
PIMAGE pimage,
|
|
PMOD pmod,
|
|
IN PIMAGE_RELOCATION prel,
|
|
DWORD isym,
|
|
SHORT isec,
|
|
DWORD rva
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Determine the TOC relative value for a TOCREL relocation.
|
|
|
|
Arguments:
|
|
|
|
pmod - Subject MOD (object file).
|
|
prel - Relocation being performed.
|
|
isym - Symbol table index (same as prel->SymbolTableIndex).
|
|
rva - Desired symbol value.
|
|
|
|
Return Value:
|
|
|
|
TOC relative value.
|
|
|
|
--*/
|
|
|
|
|
|
{
|
|
static DWORD slot;
|
|
LONG ibToc;
|
|
|
|
if (prel->Type & IMAGE_REL_PPC_TOCDEFN) {
|
|
return(rva - pconTocTable->rva - TOC_BIAS);
|
|
}
|
|
|
|
if (bv_readBit(pmod->tocBitVector, isym)) {
|
|
PEXTERNAL pext = pmod->rgpext[isym];
|
|
|
|
if (!READ_BIT(pext, fAssignedToc)) {
|
|
SET_BIT(pext, fAssignedToc);
|
|
|
|
DWORD rvaCur = pconTocTable->rva + (slot * sizeof(DWORD));
|
|
|
|
SaveDebugFixup(IMAGE_REL_PPC_ADDR32, 0, rvaCur, rva);
|
|
|
|
rgdwToc[slot] = pimage->ImgOptHdr.ImageBase + rva;
|
|
|
|
ibToc = (slot * sizeof(DWORD)) - TOC_BIAS;
|
|
|
|
StoreBaseRelocation(IMAGE_REL_BASED_HIGHLOW,
|
|
rvaCur,
|
|
isec,
|
|
0,
|
|
pimage->Switch.Link.fFixed);
|
|
|
|
slot++;
|
|
|
|
pext->ibToc = (SHORT) ibToc;
|
|
|
|
if (pimage->Switch.Link.fMap) {
|
|
SaveTocForMapFile(pext);
|
|
}
|
|
}
|
|
|
|
return(pext->ibToc);
|
|
}
|
|
|
|
if (!bv_setAndReadBit(pmod->writeBitVector, isym)) {
|
|
DWORD rvaCur = pconTocTable->rva + (slot * sizeof(DWORD));
|
|
|
|
SaveDebugFixup(IMAGE_REL_PPC_ADDR32, 0, rvaCur, rva);
|
|
|
|
rgdwToc[slot] = pimage->ImgOptHdr.ImageBase + rva;
|
|
|
|
ibToc = (slot * sizeof(DWORD)) - TOC_BIAS;
|
|
|
|
StoreBaseRelocation(IMAGE_REL_BASED_HIGHLOW,
|
|
rvaCur,
|
|
isec,
|
|
0,
|
|
pimage->Switch.Link.fFixed);
|
|
|
|
slot++;
|
|
|
|
pmod->rgpext[isym] = (PEXTERNAL) ibToc;
|
|
}
|
|
|
|
return((LONG) pmod->rgpext[isym]);
|
|
}
|
|
|
|
|
|
VOID
|
|
ApplyPpcFixups(
|
|
PCON pcon,
|
|
PIMAGE_RELOCATION prel,
|
|
DWORD creloc,
|
|
BYTE *pbRawData,
|
|
PIMAGE_SYMBOL rgsym,
|
|
PIMAGE pimage,
|
|
PSYMBOL_INFO /* rgsymInfo */
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Applys all ppc fixups to raw data.
|
|
|
|
Arguments:
|
|
|
|
pcon - A pointer to a contribution in the section data.
|
|
Raw - A pointer to the raw data.
|
|
rgsymAll - A pointer to the symbol table.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
|
|
{
|
|
BOOL fFixed;
|
|
BOOL fIfGlue;
|
|
BOOL fDebugFixup;
|
|
DWORD rvaSec;
|
|
DWORD iReloc;
|
|
|
|
fFixed = pimage->Switch.Link.fFixed;
|
|
|
|
fIfGlue = PmodPCON(pcon)->fIfGlue;
|
|
|
|
fDebugFixup = (PsecPCON(pcon) == psecDebug);
|
|
|
|
BOOL fSaveDebugFixup = (pimage->Switch.Link.DebugType & FixupDebug) && !fDebugFixup;
|
|
|
|
rvaSec = pcon->rva;
|
|
|
|
for (iReloc = creloc; iReloc; iReloc--, prel++) {
|
|
DWORD rvaCur;
|
|
BYTE *pb;
|
|
DWORD isym;
|
|
SHORT isecTarget;
|
|
DWORD rvaTarget;
|
|
DWORD vaTarget;
|
|
BOOL fAbsolute;
|
|
BOOL fNeg;
|
|
PEXTERNAL pext;
|
|
|
|
rvaCur = rvaSec + prel->VirtualAddress - RvaSrcPCON(pcon);
|
|
|
|
pb = pbRawData + prel->VirtualAddress - RvaSrcPCON(pcon);
|
|
isym = prel->SymbolTableIndex;
|
|
|
|
isecTarget = rgsym[isym].SectionNumber;
|
|
rvaTarget = rgsym[isym].Value;
|
|
|
|
if (isecTarget == IMAGE_SYM_ABSOLUTE) {
|
|
fAbsolute = TRUE;
|
|
vaTarget = rvaTarget;
|
|
} else {
|
|
fAbsolute = FALSE;
|
|
vaTarget = pimage->ImgOptHdr.ImageBase + rvaTarget;
|
|
|
|
// UNDONE: Check for rvaTarget == 0. Possible fixup to discarded code?
|
|
}
|
|
|
|
if (fSaveDebugFixup && !fAbsolute) {
|
|
WORD wExtra = 0;
|
|
|
|
// UNDONE: Special handling for IMGLUE relocation
|
|
|
|
if (rvaTarget == pextToc->FinalValue) {
|
|
// The target is either the TOC or the actual symbol at
|
|
// that location. Lets check further.
|
|
|
|
if (FPpcTocSym(pimage, rgsym + isym)) {
|
|
// Indicate this the target symbol is the toc symbol
|
|
|
|
// UNDONE: Use mnemonic constant instead of 1
|
|
|
|
wExtra = 1;
|
|
}
|
|
}
|
|
|
|
SaveDebugFixup(prel->Type, wExtra, rvaCur, rvaTarget);
|
|
}
|
|
|
|
// UNDONE: Negative fixups can't work because the NT loader doesn't
|
|
// UNDONE: support negative base fixups. Also, some of the cases
|
|
// UNDONE: below are nonsense (e.g. IMAGE_REL_PPC_ADDR24).
|
|
|
|
fNeg = ((prel->Type & IMAGE_REL_PPC_NEG) != 0);
|
|
|
|
if (fNeg && !fAbsolute && !fFixed) {
|
|
ErrorPcon(pcon, RELOCATABLETARGET, SzNameFixupSym(pimage, rgsym + isym));
|
|
CountFixupError(pimage);
|
|
continue;
|
|
}
|
|
|
|
switch (prel->Type & IMAGE_REL_PPC_TYPEMASK) {
|
|
DWORD dw;
|
|
LONG lT;
|
|
LONG ibToc;
|
|
WORD w;
|
|
PSEC psec;
|
|
|
|
case IMAGE_REL_PPC_ABSOLUTE :
|
|
break;
|
|
|
|
case IMAGE_REL_PPC_ADDR32 :
|
|
if (fNeg) {
|
|
*(DWORD UNALIGNED *) pb -= vaTarget;
|
|
} else {
|
|
*(DWORD UNALIGNED *) pb += vaTarget;
|
|
}
|
|
|
|
if (!fAbsolute) {
|
|
StoreBaseRelocation(IMAGE_REL_BASED_HIGHLOW,
|
|
rvaCur,
|
|
isecTarget,
|
|
0,
|
|
fFixed);
|
|
}
|
|
break;
|
|
|
|
case IMAGE_REL_PPC_ADDR24 :
|
|
if (!fAbsolute && !fFixed) {
|
|
// Absolute address fixups are only allowed for absolute
|
|
// targets or when -FIXED is specified
|
|
|
|
ErrorPcon(pcon, RELOCATABLETARGET, SzNameFixupSym(pimage, rgsym + isym));
|
|
CountFixupError(pimage);
|
|
break;
|
|
}
|
|
|
|
// UNDONE: The fNeg case is nonsense.
|
|
|
|
if ((vaTarget & 3) != 0) {
|
|
ErrorPcon(pcon, UNALIGNEDFIXUP, SzNameFixupSym(pimage, rgsym + isym));
|
|
CountFixupError(pimage);
|
|
|
|
vaTarget &= ~3;
|
|
}
|
|
|
|
dw = *(DWORD UNALIGNED *) pb;
|
|
|
|
lT = (LONG) (dw & 0x03FFFFFC);
|
|
|
|
if ((lT & 0x2000000) != 0) {
|
|
lT |= 0xFC000000; // Sign extend
|
|
}
|
|
|
|
if (fNeg) {
|
|
lT -= vaTarget;
|
|
} else {
|
|
lT += vaTarget;
|
|
}
|
|
|
|
if (((lT & 0xFE000000) != 0) &&
|
|
((lT & 0xFE000000) != 0xFE000000)) {
|
|
ErrorPcon(pcon, TOOFAR, SzNameFixupSym(pimage, rgsym + isym));
|
|
CountFixupError(pimage);
|
|
}
|
|
|
|
*(DWORD UNALIGNED *) pb = (dw & 0xFC000003) | (lT & 0x03FFFFFC);
|
|
break;
|
|
|
|
case IMAGE_REL_PPC_ADDR16 :
|
|
if (fNeg) {
|
|
*(SHORT UNALIGNED *) pb -= (SHORT) vaTarget;
|
|
} else {
|
|
*(SHORT UNALIGNED *) pb += (SHORT) vaTarget;
|
|
}
|
|
|
|
if (!fAbsolute) {
|
|
StoreBaseRelocation(IMAGE_REL_BASED_LOW,
|
|
rvaCur,
|
|
isecTarget,
|
|
0,
|
|
fFixed);
|
|
}
|
|
break;
|
|
|
|
case IMAGE_REL_PPC_ADDR14 :
|
|
if (!fAbsolute && !fFixed) {
|
|
// Absolute address fixups are only allowed for absolute
|
|
// targets or when -FIXED is specified
|
|
|
|
ErrorPcon(pcon, RELOCATABLETARGET, SzNameFixupSym(pimage, rgsym + isym));
|
|
CountFixupError(pimage);
|
|
break;
|
|
}
|
|
|
|
// UNDONE: The fNeg case is nonsense.
|
|
|
|
if ((vaTarget & 3) != 0) {
|
|
ErrorPcon(pcon, UNALIGNEDFIXUP, SzNameFixupSym(pimage, rgsym + isym));
|
|
CountFixupError(pimage);
|
|
|
|
vaTarget &= ~3;
|
|
}
|
|
|
|
dw = *(DWORD UNALIGNED *) pb;
|
|
|
|
lT = (LONG) (dw & 0x0000FFFC);
|
|
|
|
if ((lT & 0x8000) != 0) {
|
|
lT |= 0xFFFF0000; // Sign extend
|
|
}
|
|
|
|
if (fNeg) {
|
|
lT -= vaTarget;
|
|
} else {
|
|
lT += vaTarget;
|
|
}
|
|
|
|
if ((lT > 32767) || (lT < -32768)) {
|
|
ErrorPcon(pcon, TOOFAR, SzNameFixupSym(pimage, rgsym + isym));
|
|
CountFixupError(pimage);
|
|
}
|
|
|
|
if (prel->Type & IMAGE_REL_PPC_BRTAKEN) {
|
|
if (lT >= 0) {
|
|
dw |= 0x00200000;
|
|
} else {
|
|
dw &= 0xFFDFFFFF;
|
|
}
|
|
} else if (prel->Type & IMAGE_REL_PPC_BRNTAKEN) {
|
|
if (lT < 0) {
|
|
dw |= 0x00200000;
|
|
} else {
|
|
dw &= 0xFFDFFFFF;
|
|
}
|
|
}
|
|
|
|
*(DWORD UNALIGNED *) pb = (dw & 0xFFFF0003) | (lT & 0x0000FFFC);
|
|
break;
|
|
|
|
case IMAGE_REL_PPC_REL24 :
|
|
if ((rvaTarget & 3) != 0) {
|
|
ErrorPcon(pcon, UNALIGNEDFIXUP, SzNameFixupSym(pimage, rgsym + isym));
|
|
CountFixupError(pimage);
|
|
|
|
rvaTarget &= ~3;
|
|
}
|
|
|
|
// Relocation relative to start of this CON
|
|
|
|
rvaTarget -= rvaSec;
|
|
|
|
dw = *(DWORD UNALIGNED *) pb;
|
|
|
|
if (!fIfGlue && ((dw & 1) != 0)) {
|
|
// This is a BL instruction in a module with no IFGLUE
|
|
// relocations. Check if the target is "glue" code.
|
|
|
|
pext = PmodPCON(pcon)->rgpext[isym];
|
|
|
|
if ((pext != NULL) && (READ_BIT(pext, fImGlue) != 0) &&
|
|
strcmp("..setjmp", SzNameFixupSym(pimage, rgsym + isym))) { // no ZNOPs for ..setjmp
|
|
// Target is "glue" code
|
|
|
|
WarningPcon(pcon, NOIFGLUE, SzNameFixupSym(pimage, rgsym + isym));
|
|
}
|
|
}
|
|
|
|
lT = (LONG) (dw & 0x03FFFFFC);
|
|
|
|
if ((lT & 0x2000000) != 0) {
|
|
lT |= 0xFC000000; // Sign extend
|
|
}
|
|
|
|
if (fNeg) {
|
|
lT -= rvaTarget;
|
|
} else {
|
|
lT += rvaTarget;
|
|
}
|
|
|
|
if (((lT & 0xFE000000) != 0) &&
|
|
((lT & 0xFE000000) != 0xFE000000)) {
|
|
ErrorPcon(pcon, TOOFAR, SzNameFixupSym(pimage, rgsym + isym));
|
|
CountFixupError(pimage);
|
|
}
|
|
|
|
*(DWORD UNALIGNED *) pb = (dw & 0xFC000003) | (lT & 0x03FFFFFC);
|
|
break;
|
|
|
|
case IMAGE_REL_PPC_REL14 :
|
|
if ((rvaTarget & 3) != 0) {
|
|
ErrorPcon(pcon, UNALIGNEDFIXUP, SzNameFixupSym(pimage, rgsym + isym));
|
|
CountFixupError(pimage);
|
|
|
|
rvaTarget &= ~3;
|
|
}
|
|
|
|
// Relocation relative to start of this CON
|
|
|
|
rvaTarget -= rvaSec;
|
|
|
|
dw = *(DWORD UNALIGNED *) pb;
|
|
|
|
lT = (LONG) (dw & 0x0000FFFC);
|
|
|
|
if ((lT & 0x8000) != 0) {
|
|
lT |= 0xFFFF0000; // Sign extend
|
|
}
|
|
|
|
if (fNeg) {
|
|
lT -= rvaTarget;
|
|
} else {
|
|
lT += rvaTarget;
|
|
}
|
|
|
|
if ((lT > 32767) || (lT < -32768)) {
|
|
ErrorPcon(pcon, TOOFAR, SzNameFixupSym(pimage, rgsym + isym));
|
|
CountFixupError(pimage);
|
|
}
|
|
|
|
if (prel->Type & IMAGE_REL_PPC_BRTAKEN) {
|
|
if (lT >= 0) {
|
|
dw |= 0x00200000;
|
|
} else {
|
|
dw &= 0xFFDFFFFF;
|
|
}
|
|
} else if (prel->Type & IMAGE_REL_PPC_BRNTAKEN) {
|
|
if (lT < 0) {
|
|
dw |= 0x00200000;
|
|
} else {
|
|
dw &= 0xFFDFFFFF;
|
|
}
|
|
}
|
|
|
|
*(DWORD UNALIGNED *) pb = (dw & 0xFFFF0003) | (lT & 0x0000FFFC);
|
|
break;
|
|
|
|
case IMAGE_REL_PPC_TOCREL16 :
|
|
ibToc = AssignTocSlot(pimage, PmodPCON(pcon), prel, isym, isecTarget, rvaTarget);
|
|
|
|
lT = *(SHORT UNALIGNED *) pb;
|
|
|
|
if ((lT & 0x8000) != 0) {
|
|
lT |= 0xFFFF0000; // Sign extend
|
|
}
|
|
|
|
if (fNeg) {
|
|
lT -= ibToc;
|
|
} else {
|
|
lT += ibToc;
|
|
}
|
|
|
|
if ((lT > 32767) || (lT < -32768)) {
|
|
DiagnoseTocTrouble(pimage, pcon, rgsym + isym, rvaTarget);
|
|
CountFixupError(pimage);
|
|
break;
|
|
}
|
|
|
|
*(SHORT UNALIGNED *) pb = (SHORT) lT;
|
|
break;
|
|
|
|
case IMAGE_REL_PPC_TOCREL14 :
|
|
ibToc = AssignTocSlot(pimage, PmodPCON(pcon), prel, isym, isecTarget, rvaTarget);
|
|
|
|
w = *(WORD UNALIGNED *) pb;
|
|
|
|
lT = (SHORT) (w & 0xFFFC);
|
|
|
|
if ((lT & 0x8000) != 0) {
|
|
lT |= 0xFFFF0000; // Sign extend
|
|
}
|
|
|
|
if (fNeg) {
|
|
lT -= ibToc;
|
|
} else {
|
|
lT += ibToc;
|
|
}
|
|
|
|
if ((lT > 32767) || (lT < -32768)) {
|
|
DiagnoseTocTrouble(pimage, pcon, rgsym + isym, rvaTarget);
|
|
CountFixupError(pimage);
|
|
break;
|
|
}
|
|
|
|
*(WORD UNALIGNED *) pb = (WORD) ((w & 0x0003) | (lT & 0xFFFC));
|
|
break;
|
|
|
|
case IMAGE_REL_PPC_ADDR32NB :
|
|
if (fNeg) {
|
|
*(DWORD UNALIGNED *) pb -= rvaTarget;
|
|
} else {
|
|
*(DWORD UNALIGNED *) pb += rvaTarget;
|
|
}
|
|
break;
|
|
|
|
case IMAGE_REL_PPC_SECREL :
|
|
if (!fAbsolute) {
|
|
psec = PsecFindIsec(isecTarget, &pimage->secs);
|
|
|
|
if (psec != NULL) {
|
|
rvaTarget -= psec->rva;
|
|
} else {
|
|
// This occurs when a discarded comdat is the target of
|
|
// a relocation in the .debug section.
|
|
|
|
assert(rvaTarget == 0);
|
|
}
|
|
}
|
|
|
|
*(DWORD UNALIGNED *) pb += rvaTarget;
|
|
break;
|
|
|
|
case IMAGE_REL_PPC_SECTION :
|
|
if (isecTarget > 0) {
|
|
*(WORD UNALIGNED *) pb += (WORD) isecTarget;
|
|
} else if (fAbsolute) {
|
|
// Max section # + 1 is the sstSegMap entry for absolute
|
|
// symbols.
|
|
|
|
*(WORD UNALIGNED *) pb += (WORD) (pimage->ImgFileHdr.NumberOfSections + 1);
|
|
} else {
|
|
*(WORD UNALIGNED *) pb += 0;
|
|
}
|
|
break;
|
|
|
|
case IMAGE_REL_PPC_IFGLUE :
|
|
pext = PmodPCON(pcon)->rgpext[isym];
|
|
|
|
if ((pext != NULL) && (READ_BIT(pext, fImGlue) != 0)) {
|
|
#if 0
|
|
if (pimage->Switch.Link.fZConvert) {
|
|
printf("IFGLUE relocation fixed up on call to glue code \"%s\"\n",
|
|
SzNameFixupSym(pimage, rgsym + isym));
|
|
}
|
|
ZnopsConverted++;
|
|
#endif
|
|
*(DWORD UNALIGNED *) pb = pext->dwRestoreToc;
|
|
} else {
|
|
#if 0
|
|
if (pimage->Switch.Link.fZExtra) {
|
|
printf("IFGLUE relocation ignored on call to local routine \"%s\"\n",
|
|
SzNameFixupSym(pimage, rgsym + isym));
|
|
|
|
}
|
|
ZnopsStillNops++;
|
|
#endif
|
|
}
|
|
break;
|
|
|
|
case IMAGE_REL_PPC_IMGLUE :
|
|
break;
|
|
|
|
case IMAGE_REL_PPC_SECREL16 :
|
|
if (!fAbsolute) {
|
|
psec = PsecFindIsec(isecTarget, &pimage->secs);
|
|
|
|
if (psec != NULL) {
|
|
rvaTarget -= psec->rva;
|
|
} else {
|
|
// This occurs when a discarded comdat is the target of
|
|
// a relocation in the .debug section.
|
|
|
|
assert(rvaTarget == 0);
|
|
}
|
|
}
|
|
|
|
// UNDONE: Fixup overflow?
|
|
|
|
*(SHORT UNALIGNED *) pb += (SHORT) rvaTarget;
|
|
break;
|
|
|
|
case IMAGE_REL_PPC_REFHI:
|
|
// A REFHI has to be followed by a PAIR
|
|
|
|
if ((iReloc == 0) || (prel[1].Type != IMAGE_REL_PPC_PAIR)) {
|
|
// UNDONE: This should be an error
|
|
|
|
WarningPcon(pcon, UNMATCHEDPAIR, "REFHI");
|
|
break;
|
|
}
|
|
|
|
assert(!fNeg); // UNDONE: This should be an error
|
|
|
|
iReloc--;
|
|
prel++;
|
|
|
|
if (fSaveDebugFixup && !fAbsolute) {
|
|
DWORD rvaFixup = rvaSec + prel->VirtualAddress - RvaSrcPCON(pcon);
|
|
|
|
SaveDebugFixup(prel->Type, 0, rvaFixup, prel->SymbolTableIndex);
|
|
}
|
|
|
|
lT = *(SHORT UNALIGNED *) pb; // fetch the hi word
|
|
lT <<= 16; // Shift to high half.
|
|
|
|
// Sign extend the low.
|
|
|
|
lT += (LONG) (SHORT) prel->SymbolTableIndex;
|
|
lT += rvaTarget;
|
|
|
|
if (!fAbsolute) {
|
|
StoreBaseRelocation(IMAGE_REL_BASED_HIGHADJ,
|
|
rvaCur,
|
|
isecTarget,
|
|
lT,
|
|
fFixed);
|
|
|
|
lT += pimage->ImgOptHdr.ImageBase;
|
|
}
|
|
|
|
// By adding the 0x8000 to the low word, if the 16th bit
|
|
// is set, the addition will cause the high word to get
|
|
// incremented. Because the chip sign extends the low word,
|
|
// this will effectively cancel the increment at runtime.
|
|
|
|
lT += 0x8000;
|
|
|
|
*(SHORT UNALIGNED *) pb = (SHORT) (lT >> 16);
|
|
break;
|
|
|
|
case IMAGE_REL_PPC_REFLO:
|
|
assert(!fNeg); // UNDONE: This should be an error
|
|
|
|
*(SHORT UNALIGNED *) pb += (SHORT) vaTarget;
|
|
|
|
if (!fAbsolute) {
|
|
StoreBaseRelocation(IMAGE_REL_BASED_LOW,
|
|
rvaCur,
|
|
isecTarget,
|
|
0,
|
|
fFixed);
|
|
}
|
|
break;
|
|
|
|
case IMAGE_REL_PPC_PAIR:
|
|
// UNDONE: This should be an error
|
|
|
|
WarningPcon(pcon, UNMATCHEDPAIR, "PAIR");
|
|
break;
|
|
|
|
default:
|
|
ErrorPcon(pcon, UNKNOWNFIXUP, prel->Type, SzNameFixupSym(pimage, rgsym + isym));
|
|
CountFixupError(pimage);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
PpcLinkerInit(
|
|
PIMAGE pimage,
|
|
BOOL *pfIlinkSupported
|
|
)
|
|
{
|
|
fPowerPC = TRUE;
|
|
|
|
// If section alignment switch not used, set the default.
|
|
|
|
if (!FUsedOpt(pimage->SwitchInfo, OP_ALIGN)) {
|
|
pimage->ImgOptHdr.SectionAlignment = _4K;
|
|
}
|
|
|
|
if (FUsedOpt(pimage->SwitchInfo, OP_GPSIZE)) {
|
|
Warning(NULL, SWITCH_INCOMPATIBLE_WITH_MACHINE, "GPSIZE", "PPC");
|
|
|
|
pimage->Switch.Link.GpSize = 0;
|
|
}
|
|
|
|
*pfIlinkSupported = FALSE;
|
|
ApplyFixups = ApplyPpcFixups;
|
|
|
|
// If the section alignment is < _4K then make the file alignment the
|
|
// same as the section alignment. This ensures that the image will
|
|
// be the same in memory as in the image file, since the alignment is less
|
|
// than the maximum alignment of memory-mapped files.
|
|
|
|
if (pimage->ImgOptHdr.SectionAlignment < _4K) {
|
|
fImageMappedAsFile = TRUE;
|
|
pimage->ImgOptHdr.FileAlignment = pimage->ImgOptHdr.SectionAlignment;
|
|
}
|
|
}
|
|
|
|
|
|
void ProcessTocSymbol (
|
|
PIMAGE pimage,
|
|
PMOD pmod,
|
|
PEXTERNAL pext,
|
|
DWORD isym,
|
|
BYTE bToc
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Keep track of how many linker created TOC slots are needed (and their
|
|
corresponding base relocations). Record back pointers to external
|
|
symbols from the MOD for later use by AssignTocSlot
|
|
|
|
Arguments:
|
|
|
|
pmod - Subject MOD (object file).
|
|
pext - External symbol or NULL if the symbol is static.
|
|
isym - Symbol table index.
|
|
bToc - Aggregate set of TOC related relocations applied to the
|
|
symbol.
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
|
|
{
|
|
BOOL fNewSlot;
|
|
|
|
fNeedToc = TRUE;
|
|
|
|
// For external symbols, the rgpext array contains a pointer to the
|
|
// EXTERNAL structure which contains the flags for whether a TOC slot
|
|
// was allocated. For static symbols, the rgpext array contains the
|
|
// flags directly.
|
|
|
|
if (pext != NULL) {
|
|
fNewSlot = ((bToc & fReferenceToc) && !READ_BIT(pext, fReferenceToc));
|
|
} else {
|
|
BYTE bState = (BYTE) (DWORD) pmod->rgpext[isym];
|
|
|
|
fNewSlot = ((bToc & fReferenceToc) && (bState & fReferenceToc) == 0);
|
|
|
|
bState |= bToc;
|
|
|
|
pmod->rgpext[isym] = (PEXTERNAL) (DWORD) bState;
|
|
}
|
|
|
|
// Account for the first TOCREL relocation.
|
|
|
|
if (fNewSlot) {
|
|
cdwToc++;
|
|
|
|
if (cdwToc > (TOC_SIZE / sizeof(DWORD))) {
|
|
Fatal(NULL, TOCTOOLARGE);
|
|
}
|
|
|
|
crelocTotal++;
|
|
|
|
if (!pimage->Switch.Link.fFixed) {
|
|
// A base relocation is needed for the TOC entry
|
|
|
|
pimage->ImgOptHdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size++;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void CreatePconToc(PIMAGE pimage)
|
|
{
|
|
DWORD cbToc;
|
|
const char *szToc;
|
|
DWORD Characteristics;
|
|
|
|
cbToc = cdwToc * sizeof(DWORD);
|
|
|
|
// If we need a TOC, but there are no linker generated entries,
|
|
// add one so that pconTocTable->rva points to the right place.
|
|
|
|
if (cbToc == 0) {
|
|
if (!fNeedToc) {
|
|
pconTocTable = NULL;
|
|
pextToc->ImageSymbol.SectionNumber = IMAGE_SYM_ABSOLUTE;
|
|
|
|
return;
|
|
}
|
|
|
|
cbToc = 4;
|
|
}
|
|
|
|
// This is checked in ProcessTocSymbol.
|
|
assert(cbToc <= TOC_SIZE);
|
|
|
|
rgdwToc = (DWORD *) PvAllocZ(cbToc);
|
|
|
|
if (psecImportDescriptor->pgrpNext != NULL) {
|
|
// If the .idata section exists, place the toc between .idata$4
|
|
// and .idata$5. The import address table is in .idata$5 and becomes
|
|
// part of the toc.
|
|
|
|
szToc = ".idata$4toc";
|
|
Characteristics = ReservedSection.ImportDescriptor.Characteristics;
|
|
} else {
|
|
szToc = ".data$toc";
|
|
Characteristics = ReservedSection.Data.Characteristics;
|
|
}
|
|
|
|
pconTocTable = PconNew(szToc,
|
|
cbToc,
|
|
IMAGE_SCN_CNT_INITIALIZED_DATA |
|
|
IMAGE_SCN_MEM_READ |
|
|
IMAGE_SCN_ALIGN_4BYTES,
|
|
Characteristics,
|
|
pmodLinkerDefined,
|
|
&pimage->secs, pimage);
|
|
|
|
if (pimage->Switch.Link.fTCE) {
|
|
InitNodPcon(pconTocTable, NULL, TRUE);
|
|
}
|
|
|
|
UpdateExternalSymbol(pextToc,
|
|
pconTocTable,
|
|
TOC_BIAS,
|
|
IMAGE_SYM_DEBUG,
|
|
IMAGE_SYM_TYPE_NULL,
|
|
0,
|
|
pmodLinkerDefined,
|
|
pimage->pst);
|
|
|
|
pgrpToc = pconTocTable->pgrpBack;
|
|
}
|
|
|
|
|
|
void MergeTocData(PIMAGE pimage)
|
|
{
|
|
PSEC psecTocd;
|
|
|
|
// When the .idata section exists, the layout is
|
|
//
|
|
// .idata$4
|
|
// .idata$4toc <- The TOC starts with this GRP
|
|
// .tocd <- This set of GRPs is optional
|
|
// .tocd$ ???
|
|
// .idata$5 <- The TOC ends with this GRP
|
|
// .idata$6
|
|
|
|
// When the .idata section does not exist, the layout of .data is
|
|
//
|
|
// .data
|
|
// .data$ ???
|
|
// .data$toc <- The TOC starts with this GRP
|
|
// .tocd <- This set of GRPs is optional
|
|
// .tocd$...
|
|
|
|
psecTocd = PsecFindNoFlags(".tocd", &pimage->secs);
|
|
|
|
pgrpTocIAT = PgrpFind(psecIdata5, ".idata$5");
|
|
|
|
#if DBG
|
|
if (pgrpTocIAT != NULL) {
|
|
// Make sure .idata$4toc precedes .idata$5
|
|
assert(pgrpToc->pgrpNext == pgrpTocIAT);
|
|
}
|
|
#endif
|
|
|
|
if (psecTocd != NULL) {
|
|
PSEC psecTocTable;
|
|
PGRP pgrp;
|
|
|
|
// Transfer all GRP's from psecTocd to just after pgrpTocTable.
|
|
|
|
psecTocTable = pgrpToc->psecBack;
|
|
|
|
for (pgrp = psecTocd->pgrpNext; pgrp != NULL; pgrp = pgrp->pgrpNext) {
|
|
pgrp->psecBack = psecTocTable;
|
|
pgrpTocdLast = pgrp;
|
|
}
|
|
|
|
pgrpTocdLast->pgrpNext = pgrpToc->pgrpNext;
|
|
pgrpToc->pgrpNext = psecTocd->pgrpNext;
|
|
|
|
psecTocd->pgrpNext = NULL;
|
|
|
|
psecTocd->psecMerge = psecTocTable;
|
|
}
|
|
|
|
// Now set the bounds for the toc.
|
|
|
|
if (pgrpTocIAT != NULL) {
|
|
pgrpTocLast = pgrpTocIAT;
|
|
} else if (pgrpTocdLast != NULL) {
|
|
pgrpTocLast = pgrpTocdLast;
|
|
} else {
|
|
pgrpTocLast = pgrpToc;
|
|
}
|
|
}
|
|
|
|
|
|
BOOL IsPPCTocRW(PIMAGE pimage)
|
|
{
|
|
// UNDONE: Need to walk .tocd* looking for r/w.
|
|
return(FALSE);
|
|
}
|
|
|
|
|
|
void ValidateToc(PIMAGE /* pimage */)
|
|
{
|
|
DWORD cbToc;
|
|
|
|
if (pconTocTable == NULL) {
|
|
// There is no TOC
|
|
|
|
return;
|
|
}
|
|
|
|
cbToc = pgrpTocLast->rva + pgrpTocLast->cb - pgrpToc->rva;
|
|
|
|
if (cbToc > TOC_SIZE) {
|
|
Fatal(NULL, TOCTOOLARGE);
|
|
}
|
|
}
|
|
|
|
|
|
void WriteToc(void)
|
|
{
|
|
if (pconTocTable == NULL) {
|
|
// There is no TOC
|
|
|
|
return;
|
|
}
|
|
|
|
FileSeek(FileWriteHandle, pconTocTable->foRawDataDest, SEEK_SET);
|
|
FileWrite(FileWriteHandle, rgdwToc, cdwToc * sizeof(DWORD));
|
|
|
|
FreePv(rgdwToc);
|
|
}
|
|
|
|
|
|
const char *SzPpcRelocationType(WORD wType, WORD *pcb, BOOL *pfSymValid)
|
|
{
|
|
const char *szName;
|
|
WORD cb;
|
|
BOOL fSymValid = TRUE;
|
|
static char szTemp[50];
|
|
|
|
switch (wType & IMAGE_REL_PPC_TYPEMASK) {
|
|
case IMAGE_REL_PPC_ABSOLUTE :
|
|
szName = "ABS";
|
|
cb = 0;
|
|
fSymValid = FALSE;
|
|
break;
|
|
|
|
case IMAGE_REL_PPC_ADDR64 :
|
|
szName = "ADDR64";
|
|
cb = 2 * sizeof(DWORD);
|
|
break;
|
|
|
|
case IMAGE_REL_PPC_ADDR32 :
|
|
szName = "ADDR32";
|
|
cb = sizeof(DWORD);
|
|
break;
|
|
|
|
case IMAGE_REL_PPC_ADDR24 :
|
|
szName = "ADDR24";
|
|
cb = sizeof(DWORD);
|
|
break;
|
|
|
|
case IMAGE_REL_PPC_ADDR16 :
|
|
szName = "ADDR16";
|
|
cb = sizeof(WORD);
|
|
break;
|
|
|
|
case IMAGE_REL_PPC_ADDR14 :
|
|
szName = "ADDR14";
|
|
cb = sizeof(WORD);
|
|
break;
|
|
|
|
case IMAGE_REL_PPC_REL24 :
|
|
szName = "REL24";
|
|
cb = sizeof(DWORD);
|
|
break;
|
|
|
|
case IMAGE_REL_PPC_REL14 :
|
|
szName = "REL14";
|
|
cb = sizeof(WORD);
|
|
break;
|
|
|
|
case IMAGE_REL_PPC_TOCREL16 :
|
|
szName = "TOCREL16";
|
|
cb = sizeof(WORD);
|
|
break;
|
|
|
|
case IMAGE_REL_PPC_TOCREL14 :
|
|
szName = "TOCREL14";
|
|
cb = sizeof(WORD);
|
|
break;
|
|
|
|
case IMAGE_REL_PPC_ADDR32NB :
|
|
szName = "ADDR32NB";
|
|
cb = sizeof(DWORD);
|
|
break;
|
|
|
|
case IMAGE_REL_PPC_SECREL :
|
|
szName = "SECREL";
|
|
cb = sizeof(DWORD);
|
|
break;
|
|
|
|
case IMAGE_REL_PPC_SECTION :
|
|
szName = "SECTION";
|
|
cb = sizeof(SHORT);
|
|
break;
|
|
|
|
case IMAGE_REL_PPC_IFGLUE :
|
|
szName = "IFGLUE";
|
|
cb = sizeof(DWORD);
|
|
break;
|
|
|
|
case IMAGE_REL_PPC_IMGLUE :
|
|
szName = "IMGLUE";
|
|
cb = 0;
|
|
break;
|
|
|
|
case IMAGE_REL_PPC_SECREL16 :
|
|
szName = "SECREL16";
|
|
cb = sizeof(SHORT);
|
|
break;
|
|
|
|
case IMAGE_REL_PPC_REFHI :
|
|
szName = "REFHI";
|
|
cb = sizeof(SHORT);
|
|
break;
|
|
|
|
case IMAGE_REL_PPC_REFLO :
|
|
szName = "REFLO";
|
|
cb = sizeof(SHORT);
|
|
break;
|
|
|
|
case IMAGE_REL_PPC_PAIR :
|
|
szName = "PAIR";
|
|
cb = 0;
|
|
fSymValid = FALSE;
|
|
break;
|
|
|
|
default:
|
|
*pcb = 0;
|
|
*pfSymValid = FALSE;
|
|
return(NULL);
|
|
}
|
|
|
|
*pcb = cb;
|
|
*pfSymValid = fSymValid;
|
|
|
|
wType &= ~IMAGE_REL_PPC_TYPEMASK;
|
|
|
|
if (wType != 0) {
|
|
szName = strcpy(szTemp, szName);
|
|
|
|
if (wType & IMAGE_REL_PPC_NEG) {
|
|
strcat(szTemp, ",NEG");
|
|
|
|
wType &= ~IMAGE_REL_PPC_NEG;
|
|
}
|
|
|
|
if (wType & IMAGE_REL_PPC_BRTAKEN) {
|
|
strcat(szTemp, ",BRTAKEN");
|
|
|
|
wType &= ~IMAGE_REL_PPC_BRTAKEN;
|
|
}
|
|
|
|
if (wType & IMAGE_REL_PPC_BRNTAKEN) {
|
|
strcat(szTemp, ",BRNTAKEN");
|
|
|
|
wType &= ~IMAGE_REL_PPC_BRNTAKEN;
|
|
}
|
|
|
|
if (wType & IMAGE_REL_PPC_TOCDEFN) {
|
|
strcat(szTemp, ",TOCDEFN");
|
|
|
|
wType &= ~IMAGE_REL_PPC_TOCDEFN;
|
|
}
|
|
|
|
if (wType != 0) {
|
|
sprintf(szTemp + strlen(szTemp), ",0x%04X", wType);
|
|
}
|
|
}
|
|
|
|
return(szName);
|
|
}
|