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.
 
 
 
 
 
 

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