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.
490 lines
12 KiB
490 lines
12 KiB
/***********************************************************************
|
|
* Microsoft (R) 32-Bit Incremental Linker
|
|
*
|
|
* Copyright (C) Microsoft Corp 1992-95. All rights reserved.
|
|
*
|
|
* File: irelocs.cpp
|
|
*
|
|
* File Comments:
|
|
*
|
|
* Incremental handling of base relocs.
|
|
*
|
|
***********************************************************************/
|
|
|
|
#include "link.h"
|
|
|
|
void
|
|
InitPbri (
|
|
PBASEREL_INFO pbri,
|
|
DWORD cpage,
|
|
DWORD rvaBase,
|
|
DWORD cbPad
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Initializes the base reloc info array.
|
|
|
|
Arguments:
|
|
|
|
pbri - ptr to base reloc info.
|
|
|
|
cpage - count of pages for which we may have base relocs.
|
|
|
|
rvaBase - rva of first page.
|
|
|
|
cbPad - pad space for relocs.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
assert(cpage);
|
|
pbri->rgfoBlk = (DWORD *) Calloc(cpage, sizeof(DWORD));
|
|
pbri->cblk = cpage;
|
|
pbri->rvaBase = rvaBase & 0xfffff000; // save page rva
|
|
pbri->crelFree = cbPad / sizeof(WORD);
|
|
}
|
|
|
|
VOID
|
|
MPPCInitPbri (
|
|
PBASEREL_INFO pbri,
|
|
DWORD relocationHeaderOffset,
|
|
DWORD relocInstrTableOffset,
|
|
DWORD cbTotal
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Initializes the base reloc info array.
|
|
|
|
Arguments:
|
|
|
|
pbri - ptr to base reloc info which is NULL for PowerMac.
|
|
|
|
relocationHeaderOffset - Relocation header offset within the pcon.
|
|
|
|
relocInstrTableOffset - Relocation Instruction Tabel Offset within pcon.
|
|
|
|
cbPad - pad space for relocs.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
pbri->rgfoBlk = NULL;
|
|
pbri->cblk = relocationHeaderOffset;
|
|
pbri->rvaBase = relocInstrTableOffset;
|
|
pbri->crelFree = cbTotal; // This is the total RelocTable size
|
|
}
|
|
|
|
void
|
|
DeleteBaseRelocs (
|
|
PBASEREL_INFO pbri,
|
|
DWORD rva,
|
|
DWORD cb
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Delete any base relocs in the address range specified by the
|
|
CON's rva and size.
|
|
|
|
Arguments:
|
|
|
|
pbri - ptr to base reloc info.
|
|
|
|
rva - rva of the CON in the previous link.
|
|
|
|
cb - size of the CON.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD pagerva = rva & 0xfffff000;
|
|
DWORD index;
|
|
|
|
// compute the index (in the offset array) representing the rva
|
|
index = (DWORD)((pagerva - pbri->rvaBase) / _4K);
|
|
|
|
// get file offset to first reloc page block that exists
|
|
while (index < pbri->cblk && !pbri->rgfoBlk[index]) {
|
|
index++;
|
|
}
|
|
|
|
// no relocs in the rva range
|
|
if (index >= pbri->cblk) {
|
|
return;
|
|
}
|
|
|
|
// seek to start of base reloc page blocks for the rva
|
|
FileSeek(FileWriteHandle, pbri->rgfoBlk[index], SEEK_SET);
|
|
|
|
// read in a page block at a time
|
|
while (FileTell(FileWriteHandle) < psecBaseReloc->foPad) {
|
|
IMAGE_BASE_RELOCATION block;
|
|
BOOL fDirtyBlk = FALSE;
|
|
BOOL fDone = FALSE;
|
|
WORD *rgReloc;
|
|
LONG cbReloc;
|
|
WORD creloc;
|
|
WORD i;
|
|
|
|
// read in block header
|
|
FileRead(FileWriteHandle, &block, sizeof(IMAGE_BASE_RELOCATION));
|
|
if (block.VirtualAddress > (rva + cb)) {
|
|
return; // past the addr range
|
|
}
|
|
|
|
// read in <type, offset> pairs
|
|
cbReloc = block.SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION);
|
|
rgReloc = (WORD *)PvAlloc(cbReloc);
|
|
FileRead(FileWriteHandle, rgReloc, cbReloc);
|
|
|
|
// look at each reloc in this page block
|
|
creloc = (WORD) (cbReloc / sizeof(WORD));
|
|
for (i = 0; i < creloc; i++) {
|
|
DWORD relAddr = (rgReloc[i] & 0x0fff) + block.VirtualAddress;
|
|
|
|
assert(relAddr >= pagerva);
|
|
// zero out the reloc (absolute fixup) if within the addr range
|
|
BOOL fHighAdj = (((rgReloc[i] & 0xf000) >> 12) == IMAGE_REL_BASED_HIGHADJ);
|
|
if (fHighAdj) {
|
|
++i;
|
|
}
|
|
if (relAddr >= rva && relAddr < (rva + cb)) {
|
|
|
|
pbri->crelFree++;
|
|
rgReloc[i] = 0;
|
|
fDirtyBlk = TRUE;
|
|
|
|
if (fHighAdj) {
|
|
rgReloc[i-1] = 0;
|
|
pbri->crelFree++;
|
|
}
|
|
} else if (relAddr > (rva + cb)) {
|
|
fDone = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// if the block is dirty write it out
|
|
if (fDirtyBlk) {
|
|
FileSeek(FileWriteHandle, -cbReloc, SEEK_CUR);
|
|
FileWrite(FileWriteHandle, rgReloc, cbReloc);
|
|
}
|
|
|
|
FreePv(rgReloc);
|
|
|
|
if (fDone) {
|
|
return;
|
|
} // end if
|
|
}
|
|
}
|
|
|
|
|
|
// Enumeration of all base relocs in the image file
|
|
//
|
|
// Assumes that all globals used have been properly initialized
|
|
//
|
|
// CAVEAT: NO SEEKs in the image file when enumerating!!!
|
|
//
|
|
INIT_ENM(BaseReloc, BASE_RELOC, (ENM_BASE_RELOC *penm)) {
|
|
FileSeek(FileWriteHandle, psecBaseReloc->foRawData, SEEK_SET);
|
|
penm->block.VirtualAddress = 0;
|
|
penm->rgRelocs = NULL;
|
|
}
|
|
NEXT_ENM(BaseReloc, BASE_RELOC) {
|
|
|
|
if (!penm->block.VirtualAddress) {
|
|
if (FileTell(FileWriteHandle) >= psecBaseReloc->foPad || !fIncrDbFile) {
|
|
return FALSE;
|
|
}
|
|
|
|
FileRead(FileWriteHandle, &penm->block, sizeof (IMAGE_BASE_RELOCATION));
|
|
penm->creloc = (WORD)((penm->block.SizeOfBlock - sizeof (IMAGE_BASE_RELOCATION)) / sizeof (WORD));
|
|
penm->rgRelocs = (WORD *)PvAlloc(penm->creloc * sizeof (WORD));
|
|
penm->ireloc = 0;
|
|
FileRead(FileWriteHandle, penm->rgRelocs, penm->creloc * sizeof (WORD));
|
|
}
|
|
|
|
penm->reloc.rva = penm->block.VirtualAddress + (penm->rgRelocs[penm->ireloc] & 0xfff);
|
|
penm->reloc.Type = (WORD) ((penm->rgRelocs[penm->ireloc++] & 0xf000) >> 12);
|
|
if (penm->reloc.Type == IMAGE_REL_BASED_HIGHADJ) {
|
|
penm->reloc.Value = penm->rgRelocs[penm->ireloc++];
|
|
}
|
|
|
|
if (penm->ireloc == penm->creloc) {
|
|
FreePv(penm->rgRelocs);
|
|
penm->rgRelocs = NULL;
|
|
penm->block.VirtualAddress = 0;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
END_ENM(BaseReloc, BASE_RELOC) {
|
|
if (penm->rgRelocs) {
|
|
FreePv(penm->rgRelocs);
|
|
penm->rgRelocs = NULL;
|
|
}
|
|
}
|
|
DONE_ENM
|
|
|
|
BASE_RELOC *NextEnmNonAbsBaseReloc(
|
|
ENM_BASE_RELOC *penm
|
|
)
|
|
{
|
|
for (;;) {
|
|
if (FNextEnmBaseReloc(penm)) {
|
|
if (!penm->reloc.Type) {
|
|
// Skip absolute relocs
|
|
|
|
continue;
|
|
}
|
|
|
|
return(&penm->reloc);
|
|
}
|
|
|
|
return(NULL);
|
|
}
|
|
}
|
|
|
|
DWORD
|
|
UpdateBaseRelocs (
|
|
PBASEREL_INFO pbri
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Rewrite the base relocs by merging the existing relocs & the new ones.
|
|
|
|
Algorithm: Walks down the two sets of base relocs merging the two and
|
|
putting out base reloc page blocks using the same algorithm as in
|
|
WriteBaseRelocations().
|
|
|
|
Arguments:
|
|
|
|
pbri - ptr to base reloc info.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PVOID pvBaseReloc;
|
|
DWORD i;
|
|
BASE_RELOC *relNew;
|
|
BASE_RELOC *relOld;
|
|
void *pvBlock;
|
|
void *pvCur;
|
|
BASE_RELOC *reloc;
|
|
ENM_BASE_RELOC enm;
|
|
IMAGE_BASE_RELOCATION block;
|
|
DWORD cbTotal;
|
|
#if DBG
|
|
DWORD cbasereloc;
|
|
#endif
|
|
|
|
// alloc space for writing out the reloc page blocks
|
|
pvBaseReloc = PvAllocZ(psecBaseReloc->cbRawData);
|
|
|
|
// reset all file offsets to zero
|
|
for (i = 0; i < pbri->cblk; i++) {
|
|
pbri->rgfoBlk[i] = 0;
|
|
}
|
|
|
|
// init enumeration of existing base relocs
|
|
InitEnmBaseReloc(&enm);
|
|
|
|
// initialize ptrs to the old & new relocs
|
|
relOld = NextEnmNonAbsBaseReloc(&enm);
|
|
relNew = rgbr; // assumes no absolute fixups
|
|
|
|
// set up initial values
|
|
block.VirtualAddress = 0;
|
|
if (relOld) {
|
|
block.VirtualAddress = relOld->rva & 0xfffff000;
|
|
}
|
|
|
|
if (relNew != pbrCur && relNew->rva < relOld->rva) {
|
|
block.VirtualAddress = relNew->rva & 0xfffff000;
|
|
}
|
|
|
|
pvCur = pvBlock = pvBaseReloc;
|
|
pvCur = (BYTE *) pvCur + sizeof(IMAGE_BASE_RELOCATION);
|
|
|
|
for (;;) {
|
|
DWORD rva;
|
|
WORD wReloc;
|
|
|
|
// check if we are done
|
|
if (relNew == pbrCur && relOld == NULL) {
|
|
break;
|
|
}
|
|
|
|
// select the next reloc to write out
|
|
if (relNew == pbrCur) {
|
|
reloc = relOld;
|
|
} else if (relOld == NULL) {
|
|
reloc = relNew;
|
|
} else if (relOld->rva < relNew->rva) {
|
|
reloc = relOld;
|
|
} else if (relOld->rva > relNew->rva) {
|
|
reloc = relNew;
|
|
} else {
|
|
assert(relOld->Type == relNew->Type);
|
|
reloc = relOld;
|
|
relNew++; // reloc at same addr - obj pulled in for pass2
|
|
}
|
|
|
|
// no absolute fixups
|
|
assert(reloc->Type != IMAGE_REL_BASED_ABSOLUTE);
|
|
|
|
// process the reloc
|
|
rva = reloc->rva & 0xfffff000;
|
|
if (rva != block.VirtualAddress) {
|
|
block.SizeOfBlock = (BYTE *) pvCur - (BYTE *) pvBlock;
|
|
|
|
#if DBG
|
|
cbasereloc = (block.SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(WORD);
|
|
#endif
|
|
if (block.SizeOfBlock & 0x2) {
|
|
block.SizeOfBlock += 2;
|
|
pvCur = (BYTE *) pvCur + 2;
|
|
}
|
|
memcpy(pvBlock, &block, sizeof(IMAGE_BASE_RELOCATION));
|
|
|
|
DBEXEC(DB_BASERELINFO, DBPRINT("RVA: %08lx,", block.VirtualAddress));
|
|
DBEXEC(DB_BASERELINFO, DBPRINT(" Size: %08lx,", block.SizeOfBlock));
|
|
DBEXEC(DB_BASERELINFO, DBPRINT(" Number Of Relocs: %6lu\n", cbasereloc));
|
|
RecordRelocInfo(pbri,
|
|
psecBaseReloc->foRawData + (BYTE *) pvBlock - (BYTE *) pvBaseReloc,
|
|
block.VirtualAddress);
|
|
|
|
pvBlock = pvCur;
|
|
block.VirtualAddress = rva;
|
|
|
|
pvCur = (BYTE *) pvCur + sizeof(IMAGE_BASE_RELOCATION);
|
|
assert((BYTE *) pvCur < (BYTE *) pvBaseReloc + psecBaseReloc->cbRawData);
|
|
}
|
|
wReloc = (WORD) ((reloc->Type << 12) | (reloc->rva & 0xfff));
|
|
|
|
memcpy(pvCur, &wReloc, sizeof(WORD));
|
|
pvCur = (BYTE *) pvCur + sizeof (WORD);
|
|
|
|
if (reloc->Type == IMAGE_REL_BASED_HIGHADJ) {
|
|
memcpy(pvCur, &reloc->Value, sizeof(WORD));
|
|
pvCur = (BYTE *) pvCur + sizeof(WORD);
|
|
}
|
|
|
|
// update reloc
|
|
if (reloc == relOld) {
|
|
relOld = NextEnmNonAbsBaseReloc(&enm);
|
|
} else {
|
|
relNew++;
|
|
pbri->crelFree--;
|
|
}
|
|
}
|
|
|
|
// Do the last block
|
|
|
|
block.SizeOfBlock = (BYTE *) pvCur - (BYTE *) pvBlock;
|
|
|
|
#if DBG
|
|
cbasereloc = (block.SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(WORD);
|
|
#endif
|
|
|
|
if (block.SizeOfBlock & 0x2) {
|
|
block.SizeOfBlock += 2;
|
|
pvCur = (BYTE *) pvCur + 2;
|
|
}
|
|
memcpy(pvBlock, &block, sizeof(IMAGE_BASE_RELOCATION));
|
|
|
|
DBEXEC(DB_BASERELINFO, DBPRINT("RVA: %08lx,", block.VirtualAddress));
|
|
DBEXEC(DB_BASERELINFO, DBPRINT(" Size: %08lx,", block.SizeOfBlock));
|
|
DBEXEC(DB_BASERELINFO, DBPRINT(" Number Of Relocs: %6lu\n", cbasereloc));
|
|
if (block.SizeOfBlock != sizeof(IMAGE_BASE_RELOCATION)) {
|
|
RecordRelocInfo(pbri,
|
|
psecBaseReloc->foRawData + (BYTE *) pvBlock - (BYTE *) pvBaseReloc,
|
|
block.VirtualAddress);
|
|
}
|
|
|
|
// compute size of relocs
|
|
cbTotal = (BYTE *) pvCur - (BYTE *) pvBaseReloc;
|
|
|
|
// update .reloc section
|
|
psecBaseReloc->foPad = psecBaseReloc->foRawData + cbTotal;
|
|
|
|
// write out the new .reloc section
|
|
FileSeek(FileWriteHandle, psecBaseReloc->foRawData, SEEK_SET);
|
|
FileWrite(FileWriteHandle, pvBaseReloc, psecBaseReloc->cbRawData);
|
|
|
|
// Cleanup
|
|
|
|
FreePv(pvBaseReloc);
|
|
FreePv((void *) rgbr);
|
|
EndEnmBaseReloc(&enm);
|
|
|
|
return cbTotal;
|
|
}
|
|
|
|
#if DBG
|
|
|
|
VOID
|
|
DumpPbri (
|
|
PBASEREL_INFO pbri
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Dumps the base reloc info.
|
|
|
|
Arguments:
|
|
|
|
pbri - ptr to base reloc info.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD i;
|
|
|
|
DBPRINT("\nDump of Base Reloc Info\n\n");
|
|
|
|
DBPRINT("rva=%.8lx ", pbri->rvaBase);
|
|
DBPRINT("cblk=%.8lx ", pbri->cblk);
|
|
DBPRINT("crelFree=%.8lx\n", pbri->crelFree);
|
|
|
|
for (i = 0; i < pbri->cblk; i++) {
|
|
DBPRINT("foBlock=%.8lx\n", pbri->rgfoBlk[i]);
|
|
}
|
|
|
|
DBPRINT("\nEnd of Dump of Base Reloc Info\n");
|
|
}
|
|
|
|
#endif // DBG
|