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.
 
 
 
 
 
 

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);
}