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.
434 lines
13 KiB
434 lines
13 KiB
/***********************************************************************
|
|
* Microsoft (R) 32-Bit Incremental Linker
|
|
*
|
|
* Copyright (C) Microsoft Corp 1992-1996. All rights reserved.
|
|
*
|
|
* File: i386.cpp
|
|
*
|
|
* File Comments:
|
|
*
|
|
* This module contains all i386 specific code.
|
|
*
|
|
***********************************************************************/
|
|
|
|
#include "link.h"
|
|
|
|
|
|
|
|
VOID
|
|
ApplyI386Fixups(
|
|
PCON pcon,
|
|
PIMAGE_RELOCATION prel,
|
|
DWORD creloc,
|
|
BYTE *pbRawData,
|
|
PIMAGE_SYMBOL rgsym,
|
|
PIMAGE pimage,
|
|
PSYMBOL_INFO rgsymInfo)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Applys all I386 fixups to raw data.
|
|
|
|
Arguments:
|
|
|
|
pcon - contribution
|
|
|
|
pbRawData - raw data to apply fixups to
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
BOOL fVxD;
|
|
BOOL fFixed;
|
|
BOOL fDebugFixup;
|
|
DWORD rvaSec;
|
|
DWORD iReloc;
|
|
|
|
fVxD = pimage->imaget == imagetVXD;
|
|
|
|
fFixed = pimage->Switch.Link.fFixed;
|
|
|
|
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;
|
|
|
|
rvaCur = rvaSec + prel->VirtualAddress - RvaSrcPCON(pcon);
|
|
|
|
pb = pbRawData + prel->VirtualAddress - RvaSrcPCON(pcon);
|
|
isym = prel->SymbolTableIndex;
|
|
|
|
isecTarget = rgsym[isym].SectionNumber;
|
|
rvaTarget = rgsym[isym].Value;
|
|
|
|
if (fINCR && !fDebugFixup && rgsymInfo[isym].fJmpTbl &&
|
|
(rgsym[isym].StorageClass == IMAGE_SYM_CLASS_EXTERNAL ||
|
|
rgsym[isym].StorageClass == IMAGE_SYM_CLASS_WEAK_EXTERNAL ||
|
|
rgsym[isym].StorageClass == IMAGE_SYM_CLASS_FAR_EXTERNAL)) {
|
|
|
|
if (*(DWORD UNALIGNED *) pb) {
|
|
// Don't go thru the jump table for fixups to functions on non-zero offset
|
|
|
|
MarkExtern_FuncFixup(&rgsym[isym], pimage, pcon);
|
|
} else {
|
|
// -1 since offset is to the addr
|
|
|
|
rvaTarget = pconJmpTbl->rva + rgsymInfo[isym].Offset - 1;
|
|
}
|
|
}
|
|
|
|
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) {
|
|
SaveDebugFixup(prel->Type, 0, rvaCur, rvaTarget);
|
|
}
|
|
|
|
switch (prel->Type) {
|
|
DWORD ibCur;
|
|
DWORD ib;
|
|
DWORD baseRelocVA;
|
|
DWORD baseRelocValue;
|
|
PSEC psec;
|
|
|
|
case IMAGE_REL_I386_REL32:
|
|
if (pimage->Switch.Link.fMap) {
|
|
SaveFixupForMapFile(rvaCur);
|
|
}
|
|
|
|
if (fVxD) {
|
|
// Calculate the source and destination addresses for VxDs
|
|
|
|
ibCur = rvaCur - PsecPCON(pcon)->rva;
|
|
|
|
psec = PsecFindIsec(isecTarget, &pimage->secs);
|
|
assert(psec != NULL);
|
|
assert(psec->isec);
|
|
ib = rvaTarget - psec->rva;
|
|
|
|
if (PsecPCON(pcon) != psec) {
|
|
// Only store base reloc for inter-section references
|
|
|
|
baseRelocVA = VXD_PACK_VA(PsecPCON(pcon), ibCur);
|
|
baseRelocValue = VXD_PACK_VA(psec, ib);
|
|
|
|
// Check to see if we are losing info when we squish offset into 24 bits
|
|
|
|
struct _OFF { signed long off:24; } OFF;
|
|
DWORD ibTemp = OFF.off = VXD_UNPACK_OFFSET(baseRelocValue);
|
|
if (ibTemp != ib) {
|
|
FatalPcon(pcon, VXDFIXUPOVERFLOW, SzNameFixupSym(pimage, rgsym + isym));
|
|
}
|
|
|
|
StoreBaseRelocation(IMAGE_REL_BASED_VXD_RELATIVE,
|
|
baseRelocVA,
|
|
isecTarget,
|
|
baseRelocValue,
|
|
fFixed);
|
|
|
|
break;
|
|
}
|
|
|
|
// Compute the RVA to add in to the fixup destination ... it
|
|
// is the section-relative offset of the target minus the
|
|
// section-relative offset of the next instruction.
|
|
|
|
rvaTarget = ib - (ibCur + sizeof(DWORD));
|
|
} else {
|
|
// The displacement is the RVA of the target
|
|
// minus the RVA of the next instruction.
|
|
|
|
rvaTarget -= rvaCur + sizeof(DWORD);
|
|
|
|
if (!fAbsolute && pimage->Switch.Link.fNewRelocs) {
|
|
if (isecTarget != PsecPCON(pcon)->isec) {
|
|
StoreBaseRelocation(IMAGE_REL_BASED_REL32,
|
|
rvaCur,
|
|
isecTarget,
|
|
0,
|
|
fFixed);
|
|
}
|
|
}
|
|
}
|
|
|
|
*(DWORD UNALIGNED *) pb += rvaTarget;
|
|
break;
|
|
|
|
case IMAGE_REL_I386_DIR32:
|
|
if (fDebugFixup) {
|
|
// When a DIR32 fixup is found in a debug section, it is
|
|
// treated as a SECREL fixup followed by a SECTION fixup.
|
|
|
|
if (fAbsolute) {
|
|
// Max section # + 1 is the sstSegMap entry for absolute
|
|
// symbols.
|
|
|
|
*(WORD UNALIGNED *) (pb + sizeof(DWORD)) += (WORD) (pimage->ImgFileHdr.NumberOfSections + 1);
|
|
} else {
|
|
psec = PsecFindIsec(isecTarget, &pimage->secs);
|
|
|
|
if (psec != NULL) {
|
|
rvaTarget -= psec->rva;
|
|
|
|
*(WORD UNALIGNED *) (pb + sizeof(DWORD)) += psec->isec;
|
|
} 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;
|
|
}
|
|
|
|
if (fVxD && !fAbsolute) {
|
|
ibCur = rvaCur - PsecPCON(pcon)->rva;
|
|
|
|
psec = PsecFindIsec(isecTarget, &pimage->secs);
|
|
assert(psec != NULL);
|
|
assert(psec->isec);
|
|
|
|
ib = rvaTarget - psec->rva;
|
|
|
|
// VXD relocations are not additive. Add in
|
|
// the displacement present in the object file.
|
|
|
|
ib += *(DWORD UNALIGNED *) pb;
|
|
|
|
baseRelocVA = VXD_PACK_VA(PsecPCON(pcon), ibCur);
|
|
baseRelocValue = VXD_PACK_VA(psec, ib);
|
|
|
|
// Check to see if we are losing info when we squish offset into 24 bits
|
|
|
|
struct _OFF { signed long off:24; } OFF;
|
|
DWORD ibTemp = OFF.off = VXD_UNPACK_OFFSET(baseRelocValue);
|
|
if (ibTemp != ib) {
|
|
FatalPcon(pcon, VXDFIXUPOVERFLOW, SzNameFixupSym(pimage, rgsym + isym));
|
|
}
|
|
|
|
StoreBaseRelocation(IMAGE_REL_BASED_HIGHLOW,
|
|
baseRelocVA,
|
|
isecTarget,
|
|
baseRelocValue,
|
|
fFixed);
|
|
|
|
break;
|
|
}
|
|
|
|
*(DWORD UNALIGNED *) pb += vaTarget;
|
|
|
|
if (!fAbsolute) {
|
|
StoreBaseRelocation(IMAGE_REL_BASED_HIGHLOW,
|
|
rvaCur,
|
|
isecTarget,
|
|
0,
|
|
fFixed);
|
|
}
|
|
break;
|
|
|
|
case IMAGE_REL_I386_DIR32NB:
|
|
*(DWORD UNALIGNED *) pb += rvaTarget;
|
|
break;
|
|
|
|
case IMAGE_REL_I386_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_I386_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_I386_ABSOLUTE:
|
|
// Ignore (fixup not required).
|
|
break;
|
|
|
|
case IMAGE_REL_I386_SEG12:
|
|
WarningPcon(pcon, UNKNOWN_SEG12_FIXUP, prel->VirtualAddress);
|
|
break;
|
|
|
|
case IMAGE_REL_I386_DIR16:
|
|
if (fVxD) {
|
|
psec = PsecFindIsec(isecTarget, &pimage->secs);
|
|
|
|
if (psec != NULL) {
|
|
rvaTarget -= psec->rva;
|
|
} else {
|
|
// UNDONE: Is this possible for VxDs?
|
|
|
|
// This occurs when a discarded comdat is the target of
|
|
// a relocation in the .debug section.
|
|
|
|
assert(rvaTarget == 0);
|
|
}
|
|
|
|
*(SHORT UNALIGNED *) pb += (SHORT) rvaTarget;
|
|
break;
|
|
}
|
|
|
|
// Fall through for non-VxDs
|
|
|
|
case IMAGE_REL_I386_REL16:
|
|
if (fVxD) {
|
|
// The source and target must be in the same section
|
|
|
|
if (PsecPCON(pcon)->isec != isecTarget) {
|
|
// UNDONE: This should be an error
|
|
|
|
assert(FALSE);
|
|
}
|
|
|
|
rvaTarget -= rvaCur + sizeof(WORD);
|
|
|
|
*(SHORT UNALIGNED *) pb += (SHORT) rvaTarget;
|
|
break;
|
|
}
|
|
|
|
// Fall through for non-VxDs
|
|
|
|
default:
|
|
ErrorPcon(pcon, UNKNOWNFIXUP, prel->Type, SzNameFixupSym(pimage, rgsym + isym));
|
|
CountFixupError(pimage);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
VOID I386LinkerInit(PIMAGE pimage, BOOL *pfIlinkSupported)
|
|
{
|
|
// If section alignment switch not used, set the default.
|
|
|
|
if (!FUsedOpt(pimage->SwitchInfo, OP_ALIGN) && pimage->imaget != imagetVXD) {
|
|
pimage->ImgOptHdr.SectionAlignment = _4K;
|
|
}
|
|
|
|
if (FUsedOpt(pimage->SwitchInfo, OP_GPSIZE)) {
|
|
Warning(NULL, SWITCH_INCOMPATIBLE_WITH_MACHINE, "GPSIZE", "IX86");
|
|
|
|
pimage->Switch.Link.GpSize = 0;
|
|
}
|
|
|
|
*pfIlinkSupported = TRUE;
|
|
ApplyFixups = ApplyI386Fixups;
|
|
|
|
// 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;
|
|
}
|
|
}
|
|
|
|
|
|
const char *SzI386RelocationType(WORD wType, WORD *pcb, BOOL *pfSymValid)
|
|
{
|
|
const char *szName;
|
|
WORD cb;
|
|
|
|
switch (wType) {
|
|
case IMAGE_REL_I386_ABSOLUTE:
|
|
szName = "ABS";
|
|
cb = 0;
|
|
break;
|
|
|
|
case IMAGE_REL_I386_DIR16:
|
|
szName = "DIR16";
|
|
cb = sizeof(WORD);
|
|
break;
|
|
|
|
case IMAGE_REL_I386_REL16:
|
|
szName = "REL16";
|
|
cb = sizeof(WORD);
|
|
break;
|
|
|
|
case IMAGE_REL_I386_DIR32:
|
|
szName = "DIR32";
|
|
cb = sizeof(DWORD);
|
|
break;
|
|
|
|
case IMAGE_REL_I386_DIR32NB:
|
|
szName = "DIR32NB";
|
|
cb = sizeof(DWORD);
|
|
break;
|
|
|
|
case IMAGE_REL_I386_SEG12:
|
|
szName = "SEG12";
|
|
cb = sizeof(WORD);
|
|
break;
|
|
|
|
case IMAGE_REL_I386_REL32:
|
|
szName = "REL32";
|
|
cb = sizeof(DWORD);
|
|
break;
|
|
|
|
case IMAGE_REL_I386_SECTION:
|
|
szName = "SECTION";
|
|
cb = sizeof(WORD);
|
|
break;
|
|
|
|
case IMAGE_REL_I386_SECREL:
|
|
szName = "SECREL";
|
|
cb = sizeof(DWORD);
|
|
break;
|
|
|
|
default:
|
|
szName = NULL;
|
|
cb = 0;
|
|
break;
|
|
}
|
|
|
|
*pcb = cb;
|
|
*pfSymValid = (cb != 0);
|
|
|
|
return(szName);
|
|
}
|