|
|
/***********************************************************************
* Microsoft (R) 32-Bit Incremental Linker * * Copyright (C) Microsoft Corp 1992-1996. All rights reserved. * * File: pdata.cpp * * File Comments: * * This module handles the re-ordering of the pdata section. * ***********************************************************************/
#include "link.h"
struct TFIXUP { DWORD rva; WORD ftype; WORD wAdj; };
void LoadPdata( PIMAGE pimage, INT FileHandle, IMAGE_SECTION_HEADER *pshPdata, IMAGE_SECTION_HEADER *pshReloc, PIMAGE_RUNTIME_FUNCTION_ENTRY *prgrfe, DWORD *pcrfe, TFIXUP **prgtfixup, DWORD *pctfixup ) { *pshPdata = NullSectionHdr; *pshReloc = NullSectionHdr;
DWORD rvaPdata = pimage->ImgOptHdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION].VirtualAddress; DWORD rvaReloc = pimage->ImgOptHdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress;
DWORD fo = CoffHeaderSeek + sizeof(IMAGE_FILE_HEADER) + pimage->ImgFileHdr.SizeOfOptionalHeader; FileSeek(FileHandle, fo, SEEK_SET);
for (DWORD i = 0; i < pimage->ImgFileHdr.NumberOfSections; i++) { IMAGE_SECTION_HEADER sh;
FileRead(FileHandle, &sh, sizeof(sh));
if ((rvaPdata >= sh.VirtualAddress) && (rvaPdata < sh.VirtualAddress+sh.SizeOfRawData)) { *pshPdata = sh; continue; }
if ((rvaReloc >= sh.VirtualAddress) && (rvaReloc < sh.VirtualAddress+sh.SizeOfRawData)) { *pshReloc = sh; continue; } }
DWORD cbRfe = pimage->ImgOptHdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION].Size;
DWORD crfe = cbRfe / sizeof(IMAGE_RUNTIME_FUNCTION_ENTRY);
PIMAGE_RUNTIME_FUNCTION_ENTRY rgrfe = (PIMAGE_RUNTIME_FUNCTION_ENTRY) PvAlloc(cbRfe);
FileSeek(FileHandle, pshPdata->PointerToRawData, SEEK_SET); FileRead(FileHandle, rgrfe, cbRfe);
DWORD foReloc = rvaReloc - pshReloc->VirtualAddress + pshReloc->PointerToRawData;
FileSeek(FileHandle, foReloc, SEEK_SET);
DWORD cbReloc = pimage->ImgOptHdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size; DWORD cbTfixup = (cbReloc ? (cbReloc / sizeof(WORD)) : 1) * sizeof(TFIXUP);
TFIXUP *rgtfixup = (TFIXUP *) PvAlloc(cbTfixup);
DWORD ctfixup = 0;
if (cbReloc != 0) { WORD *rgwReloc = (WORD *) PvAlloc(0xffff);
while (cbReloc > 0) { IMAGE_BASE_RELOCATION bre;
FileRead(FileHandle, &bre, IMAGE_SIZEOF_BASE_RELOCATION);
if (bre.SizeOfBlock == 0) { break; }
DWORD cbBlock = bre.SizeOfBlock - IMAGE_SIZEOF_BASE_RELOCATION; FileRead(FileHandle, rgwReloc, cbBlock);
DWORD cw = cbBlock / sizeof(WORD);
for (DWORD iw = 0; iw < cw; iw++) { if (rgwReloc[iw] == 0) { // indicates a pad
continue; }
DWORD ib = rgwReloc[iw] & 0xfff; rgtfixup[ctfixup].rva = bre.VirtualAddress + ib; rgtfixup[ctfixup].ftype = rgwReloc[iw] >> 12;
if (rgtfixup[ctfixup].ftype == IMAGE_REL_BASED_HIGHADJ) { rgtfixup[ctfixup].wAdj = rgwReloc[++iw]; }
ctfixup++; }
cbReloc -= bre.SizeOfBlock; }
FreePv(rgwReloc); }
*prgrfe = rgrfe; *pcrfe = crfe;
*prgtfixup = rgtfixup; *pctfixup = ctfixup; }
int __cdecl cmpPprfePprfeBeginAddress(void const *pprfe1, void const *pprfe2) { DWORD addr1 = (*(PIMAGE_RUNTIME_FUNCTION_ENTRY *) pprfe1)->BeginAddress; DWORD addr2 = (*(PIMAGE_RUNTIME_FUNCTION_ENTRY *) pprfe2)->BeginAddress;
if (addr1 == 0) { return(1); }
if (addr2 == 0) { return(-1); }
if (addr1 < addr2) { return(-1); }
if (addr1 > addr2) { return(1); }
return(0); }
int __cdecl cmpPtfixupPtfixupRva(void const *ptfixup1, void const *ptfixup2) { DWORD rva1 = ((TFIXUP *) ptfixup1)->rva; DWORD rva2 = ((TFIXUP *) ptfixup2)->rva;
if (rva1 < rva2) { return(-1); }
if (rva1 > rva2) { return(1); }
return(0); }
void SortFunctionTable( PIMAGE pimage )
/*++
Routine Description:
Re-Order the pdata section according to the beginning address and also simultaneously adjust the relocations.
Arguments:
none.
Return Value:
none
--*/ { if (psecException->cbVirtualSize == 0) { // Nothing to do
return; }
assert(psecException->rva != 0);
// Read in the section headers for .pdata and .reloc
IMAGE_SECTION_HEADER shPdata; IMAGE_SECTION_HEADER shReloc; PIMAGE_RUNTIME_FUNCTION_ENTRY rgrfe; DWORD crfe; TFIXUP *rgtfixup; DWORD ctfixup;
LoadPdata(pimage, FileWriteHandle, &shPdata, &shReloc, &rgrfe, &crfe, &rgtfixup, &ctfixup);
PIMAGE_RUNTIME_FUNCTION_ENTRY *rgprfe = (PIMAGE_RUNTIME_FUNCTION_ENTRY *) PvAlloc(crfe * sizeof(PIMAGE_RUNTIME_FUNCTION_ENTRY));
for (DWORD irfe = 0; irfe < crfe; irfe++) { rgprfe[irfe] = rgrfe + irfe; }
// Sort the runtime function entries by address
qsort(rgprfe, crfe, sizeof(PIMAGE_RUNTIME_FUNCTION_ENTRY), cmpPprfePprfeBeginAddress);
// Write out the now sorted entries
FileSeek(FileWriteHandle, shPdata.PointerToRawData, SEEK_SET);
for (irfe = 0; irfe < crfe; irfe++) { FileWrite(FileWriteHandle, rgprfe[irfe], sizeof(IMAGE_RUNTIME_FUNCTION_ENTRY)); }
// Build a map from old RFE index to new RFE index
DWORD *mpirfeOldirfeNew = (DWORD *) PvAlloc(crfe * sizeof(DWORD));
for (irfe = 0; irfe < crfe; irfe++) { DWORD irfeOld = rgprfe[irfe] - rgrfe;
mpirfeOldirfeNew[irfeOld] = irfe; }
DWORD rvaMin = psecException->rva; DWORD rvaMax = rvaMin + psecException->cbVirtualSize;
// Update the temp fixups with the new RVA where each is applied
TFIXUP *ptfixup = rgtfixup;
for (DWORD itfixup = 0; itfixup < ctfixup; itfixup++, ptfixup++) { if ((ptfixup->rva < rvaMin) || (ptfixup->rva >= rvaMax)) { continue; }
DWORD irfeOld = (ptfixup->rva - rvaMin) / sizeof(IMAGE_RUNTIME_FUNCTION_ENTRY); DWORD irfeNew = mpirfeOldirfeNew[irfeOld];
DWORD ib = (irfeNew - irfeOld) * sizeof(IMAGE_RUNTIME_FUNCTION_ENTRY);
ptfixup->rva += ib; }
if (pimage->Switch.Link.DebugType & FixupDebug) { // Update debug FIXUPs (SaveDebugFixup) with the new RVAs
FileSeek(FileWriteHandle, pconFixupDebug->foRawDataDest, SEEK_SET);
DWORD cxfixup = pconFixupDebug->cbRawData / sizeof(XFIXUP);
for (DWORD ixfixup = 0; ixfixup < cxfixup; ixfixup++) { XFIXUP xfixup;
FileRead(FileWriteHandle, &xfixup, sizeof(XFIXUP));
if ((xfixup.rva < rvaMin) || (xfixup.rva >= rvaMax)) { continue; }
DWORD irfeOld = (xfixup.rva - rvaMin) / sizeof(IMAGE_RUNTIME_FUNCTION_ENTRY); DWORD irfeNew = mpirfeOldirfeNew[irfeOld];
DWORD ib = (irfeNew - irfeOld) * sizeof(IMAGE_RUNTIME_FUNCTION_ENTRY);
if (ib != 0) { xfixup.rva += ib;
FileSeek(FileWriteHandle, -(long) sizeof(XFIXUP), SEEK_CUR); FileWrite(FileWriteHandle, &xfixup, sizeof(XFIXUP)); } } }
// We are done with these now
FreePv(mpirfeOldirfeNew); FreePv(rgprfe); FreePv(rgrfe);
if (ctfixup != 0) { // Sort the temp fixups by RVA
qsort(rgtfixup, ctfixup, sizeof(TFIXUP), cmpPtfixupPtfixupRva);
// Write out the now sorted entries
WORD *fixups = (WORD *) PvAlloc(0xffff);
DWORD rvaReloc = psecBaseReloc->rva; DWORD foReloc = rvaReloc - shReloc.VirtualAddress + shReloc.PointerToRawData;
FileSeek(FileWriteHandle, foReloc, SEEK_SET);
DWORD i = 0; DWORD cb = 0; while (i < ctfixup) { DWORD rva = rgtfixup[i].rva & 0xfffff000;
IMAGE_BASE_RELOCATION bre;
bre.VirtualAddress = rva;
DWORD j = 0;
for (;;) { DWORD ib = rgtfixup[i].rva & 0xfff; fixups[j] = (WORD) ((rgtfixup[i].ftype << 12) | ib);
if (rgtfixup[i].ftype == IMAGE_REL_BASED_HIGHADJ) { fixups[++j] = rgtfixup[i].wAdj; }
i++; j++;
if ((rgtfixup[i].rva & 0xfffff000) != rva) { break; }
if (i == ctfixup) { break; } }
bre.SizeOfBlock = IMAGE_SIZEOF_BASE_RELOCATION + (j * sizeof(WORD));
if (bre.SizeOfBlock & 0x2) { bre.SizeOfBlock += 2; fixups[j] = 0; }
cb += bre.SizeOfBlock;
FileWrite(FileWriteHandle, &bre, IMAGE_SIZEOF_BASE_RELOCATION); FileWrite(FileWriteHandle, fixups, bre.SizeOfBlock-IMAGE_SIZEOF_BASE_RELOCATION); }
pimage->ImgOptHdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size = cb;
FreePv(fixups); }
FreePv(rgtfixup); }
void DumpDbgFunctionTable( DWORD foTable, DWORD cbTable ) { DWORD cfe; DWORD ife = 0;
cfe = cbTable / sizeof(IMAGE_FUNCTION_ENTRY);
fprintf(InfoStream, "\nFunction Table (%lu)\n\n", cfe); fprintf(InfoStream, " Begin End PrologEnd\n\n");
FileSeek(FileReadHandle, foTable, SEEK_SET);
while (cfe--) { IMAGE_FUNCTION_ENTRY fe;
FileRead(FileReadHandle, &fe, sizeof(IMAGE_FUNCTION_ENTRY));
fprintf(InfoStream, "%08lX %08lX %08lX %08lX\n", ife * sizeof(IMAGE_FUNCTION_ENTRY), fe.StartingAddress, fe.EndingAddress, fe.EndOfPrologue); ife++; } }
void DumpFunctionTable( PIMAGE pimage, PIMAGE_SYMBOL rgsym, const char *StringTable ) { IMAGE_SECTION_HEADER shPdata; IMAGE_SECTION_HEADER shReloc; PIMAGE_RUNTIME_FUNCTION_ENTRY rgrfe; DWORD crfe; TFIXUP *rgtfixup; DWORD ctfixup;
LoadPdata(pimage, FileReadHandle, &shPdata, &shReloc, &rgrfe, &crfe, &rgtfixup, &ctfixup);
fprintf(InfoStream, "\nFunction Table (%lu)\n\n", crfe); fprintf(InfoStream, " Begin End Excptn ExcpDat Prolog Fixups Function Name\n\n");
DWORD rvaRfe = shPdata.VirtualAddress;
PIMAGE_RUNTIME_FUNCTION_ENTRY prfe = rgrfe;
DWORD itfixup = 0;
while ((itfixup < ctfixup) && (rgtfixup[itfixup].rva < rvaRfe)) { itfixup++; }
for (DWORD irfe = 0; irfe < crfe; irfe++, prfe++) { DWORD ib = irfe * sizeof(IMAGE_RUNTIME_FUNCTION_ENTRY);
fprintf(InfoStream, "%08lX %08lX %08lX %08lX %08lX %08lX ", ib, prfe->BeginAddress, prfe->EndAddress, (DWORD) prfe->ExceptionHandler, (DWORD) prfe->HandlerData, prfe->PrologEndAddress);
DWORD i;
for (i = 0; i < 5; i++) { if ((itfixup < ctfixup) && (rgtfixup[itfixup].rva == rvaRfe)) { fputc('Y', InfoStream);
itfixup++; } else { fputc('N', InfoStream); }
rvaRfe += sizeof(DWORD); }
if (rgsym != NULL) { DWORD rva = prfe->BeginAddress - pimage->ImgOptHdr.ImageBase;
PIMAGE_SYMBOL psymNext = rgsym;
for (i = 0; i < pimage->ImgFileHdr.NumberOfSymbols; i++) { PIMAGE_SYMBOL psym;
psym = FetchNextSymbol(&psymNext);
if ((psym->Value == rva) && (psym->NumberOfAuxSymbols == 0)) { fprintf(InfoStream, " %s", SzNameSymPb(*psym, StringTable)); break; } } }
fputc('\n', InfoStream); }
FreePv(rgrfe); FreePv(rgtfixup); }
void DumpObjFunctionTable( PIMAGE_SECTION_HEADER sh, SHORT SectionNumber ) { DWORD crfe; DWORD irfe = 0;
crfe = sh->SizeOfRawData / sizeof(IMAGE_RUNTIME_FUNCTION_ENTRY);
fprintf(InfoStream, "\nFUNCTION TABLE #%d (%lu)\n\n", SectionNumber, crfe); fprintf(InfoStream, " Begin End Excptn ExcpDat PrologEnd\n\n");
while (crfe--) { IMAGE_RUNTIME_FUNCTION_ENTRY rfe;
FileRead(FileReadHandle, &rfe, sizeof(IMAGE_RUNTIME_FUNCTION_ENTRY));
fprintf(InfoStream, "%08lX %08lX %08lX %08lX %08lX %08lX\n", irfe * sizeof(IMAGE_RUNTIME_FUNCTION_ENTRY), rfe.BeginAddress, rfe.EndAddress, (DWORD) rfe.ExceptionHandler, (DWORD) rfe.HandlerData, rfe.PrologEndAddress); irfe++; } }
void DumpPexFunctionTable( PIMAGE_RUNTIME_FUNCTION_ENTRY rgrfe, DWORD crfe ) { fprintf(InfoStream, "\nFUNCTION TABLE (%lu)\n\n", crfe); fprintf(InfoStream, " Begin End Excptn ExcpDat PrologEnd\n\n");
PIMAGE_RUNTIME_FUNCTION_ENTRY prfe = rgrfe;
for (DWORD irfe = 0; irfe < crfe; irfe++, prfe++) { fprintf(InfoStream, "%08lX %08lX %08lX %08lX %08lX %08lX\n", irfe * sizeof(IMAGE_RUNTIME_FUNCTION_ENTRY), DwSwap(prfe->BeginAddress), DwSwap(prfe->EndAddress), DwSwap((DWORD) prfe->ExceptionHandler), DwSwap((DWORD) prfe->HandlerData), DwSwap(prfe->PrologEndAddress)); } }
|