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.
524 lines
14 KiB
524 lines
14 KiB
/***********************************************************************
|
|
* 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));
|
|
}
|
|
}
|