bintools/petools/pefile/pe_reloc.cpp
changeset 600 6d08f4a05d93
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bintools/petools/pefile/pe_reloc.cpp	Fri Jun 25 18:11:34 2010 +0800
@@ -0,0 +1,374 @@
+// Copyright (c) 1996-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+//
+
+#include <stdlib.h>
+#include <string.h>
+#include <e32std.h>
+#include <e32std_private.h>
+#include "pe_file.h"
+#include "h_utl.h"
+#include <stdio.h>
+
+extern char* gX86imp;
+extern int gX86num_imp_dlls;
+extern int gX86imp_size;
+extern int gX86num_imports;
+extern int* gX86imp_relocs;
+
+TInt sizeOfCodeRelocs(TUint *relocs, TUint *relocsection, TInt nrelocs)
+	{
+
+	TInt bytecount=0;
+	TInt page=-1;
+	TInt i;
+	for (i=0; i<nrelocs; i++)
+		{
+		if ((TInt)relocsection[i]==KTextSection || (TInt)relocsection[i]==KConstSection || (TInt)relocsection[i]==KCrtSection)
+			{
+			TInt p=relocs[i]&0xfffff000;
+			if (page!=p)
+				{
+				if (bytecount%4!=0)
+					bytecount+=2;
+				bytecount+=8; // page, block size
+				page=p;
+				}
+			bytecount+=2;
+			}
+		}
+	if (bytecount%4!=0)
+		bytecount+=2;
+	return bytecount;
+	}
+
+TInt sizeOfDataRelocs(TUint *relocs, TUint *relocsection, TInt nrelocs)
+	{
+
+	TInt bytecount=0;
+	TInt page=-1;
+	TInt i;
+	for (i=0; i<nrelocs; i++)
+		{
+		if ((TInt)relocsection[i]==KDataSection)
+			{
+			TInt p=relocs[i]&0xfffff000;
+			if (page!=p)
+				{
+				if (bytecount%4!=0)
+					bytecount+=2;
+				bytecount+=8; // page, block size
+				page=p;
+				}
+			bytecount+=2;
+			}
+		}
+	if (bytecount%4!=0)
+		bytecount+=2;
+	return bytecount;
+	}
+
+void reorderRelocs(TUint aReloc[], TUint aRelocSection[], TInt aNumberOfRelocs)
+//
+// sort the relocations in section order
+//
+	{
+	TUint *temp=new TUint [aNumberOfRelocs];
+	TUint *tempsection=new TUint [aNumberOfRelocs];
+	TInt idx=0;
+	TUint section=0;
+	while (idx<aNumberOfRelocs)
+		{
+		for (TInt i=0; i<aNumberOfRelocs; i++)
+			{
+			if (aRelocSection[i]==section)
+				{
+				temp[idx]=aReloc[i];
+				tempsection[idx]=aRelocSection[i];
+				idx++;
+				}
+			}
+		section++;
+		}
+	memcpy((char *)aReloc, (char *)temp, aNumberOfRelocs*sizeof(TUint));
+	memcpy((char *)aRelocSection, (char *)tempsection, aNumberOfRelocs*sizeof(TUint));
+	delete [] temp;
+	delete [] tempsection;
+	}
+
+char *E32ImageFile_PE::CreateCodeRelocs(TUint *relocs, TUint *relocsection, TInt nrelocs, TInt &aSize)
+	{
+
+	TInt bytecount=sizeOfCodeRelocs(relocs, relocsection, nrelocs);
+	aSize=0;
+	if (bytecount==0)
+		return NULL;
+	aSize=bytecount+sizeof(E32RelocSection);
+
+	char *section=new char [bytecount+sizeof(E32RelocSection)];
+	char *data=section+sizeof(E32RelocSection);
+	char *startofblock=data;
+
+	TInt ncoderelocs=0;
+	TInt page=-1;
+	TInt pagesize=8;
+	TInt i;
+	for (i=0; i<nrelocs; i++)
+		{
+		if ((TInt)relocsection[i]==KTextSection || (TInt)relocsection[i]==KConstSection || (TInt)relocsection[i]==KCrtSection)
+			{
+			TInt p=relocs[i]&0xfffff000;
+			if (page!=p)
+				{
+				if (pagesize%4!=0)
+					{
+					*(TUint16 *)data=0;
+					data+=2;
+					pagesize+=2;
+					}
+				*(TUint *)startofblock=page;
+				*(TUint *)(startofblock+4)=pagesize;
+				pagesize=8;
+				page=p;
+				startofblock=data;
+				data+=8;
+				}
+			*(TUint16 *)data=(TUint16)((relocs[i]&0xfff)|0x3000);
+			data+=2;
+			pagesize+=2;
+			ncoderelocs++;
+			}
+		}
+	if (pagesize%4!=0)
+		{
+		*(TUint16 *)data=0;
+		data+=2;
+		pagesize+=2;
+		}
+	*(TUint *)startofblock=page;
+	*(TUint *)(startofblock+4)=pagesize;
+	((E32RelocSection *)section)->iNumberOfRelocs=ncoderelocs;
+	((E32RelocSection *)section)->iSize=bytecount;
+	return section;
+	}
+
+char *E32ImageFile_PE::CreateDataRelocs(TUint *relocs, TUint *relocsection, TInt nrelocs, TInt &aSize)
+	{
+
+	TInt bytecount=sizeOfDataRelocs(relocs, relocsection, nrelocs);
+	aSize=0;
+	if (bytecount==0)
+		return NULL;
+	aSize=bytecount+sizeof(E32RelocSection);
+
+	char *section=new char [bytecount+sizeof(E32RelocSection)];
+	char *data=section+sizeof(E32RelocSection);
+	char *startofblock=data;
+
+	TInt ndatarelocs=0;
+	TInt page=-1;
+	TInt pagesize=8;
+	TInt i;
+	for (i=0; i<nrelocs; i++)
+		{
+		if ((TInt)relocsection[i]==KDataSection)
+			{
+			TInt p=relocs[i]&0xfffff000;
+			if (page!=p)
+				{
+				if (pagesize%4!=0)
+					{
+					*(TUint16 *)data=0;
+					data+=2;
+					pagesize+=2;
+					}
+				*(TUint *)startofblock=page;
+				*(TUint *)(startofblock+4)=pagesize;
+				pagesize=8;
+				page=p;
+				startofblock=data;
+				data+=8;
+				}
+			*(TUint16 *)data=(TUint16)((relocs[i]&0xfff)|0x3000);
+			data+=2;
+			pagesize+=2;
+			ndatarelocs++;
+			}
+		}
+	if (pagesize%4!=0)
+		{
+		*(TUint16 *)data=0;
+		data+=2;
+		pagesize+=2;
+		}
+	*(TUint *)startofblock=page;
+	*(TUint *)(startofblock+4)=pagesize;
+
+	((E32RelocSection *)section)->iNumberOfRelocs=ndatarelocs;
+	((E32RelocSection *)section)->iSize=bytecount;
+	return section;
+	}
+
+void checkreloc(PEFile &aPeFile, TUint va, TUint reloc)
+	{
+
+	// Allow the section find routine to use heuristics to resolve addresses
+	// which have been offset by the compiler
+	TInt s = aPeFile.FindSectionByVa(va, 1);
+	switch(s)
+		{
+		case KTextSection:
+		case KConstSection:
+		case KDataSection:
+		case KCrtSection:
+		case KBssSection:
+		case KImportSection:
+			return;
+		default:
+			break;
+		}
+	Print(EAlways, "bad relocation:  [%08x] = %08x\n", reloc, va);
+	}
+
+void E32ImageFile_PE::FixRelocs(PEFile &aPeFile, TUint *relocation, TUint *relocsection, TInt aNumberOfRelocs)
+	{
+
+	TUint *data;
+	TInt i;
+#if 0
+	Print(EAlways, "Linked base %08x\n", aPeFile.iLinkedBase);
+	for (i=0; i<KNumberOfSections; i++)
+		{
+		if (!aPeFile.iSectionHeader[i])
+			continue;
+		TUint start = aPeFile.iSectionHeader[i]->VirtualAddress;
+		TUint finish = start + aPeFile.iSectionHeader[i]->Misc.VirtualSize;
+		Print(EAlways, "Section %d %08x-%08x\n", i, start, finish);
+		}
+#endif
+	for (i=0; i<aNumberOfRelocs; i++)
+		{
+		switch (relocsection[i])
+			{
+		case KTextSection:
+			relocation[i]-=aPeFile.iSectionHeader[KTextSection]->VirtualAddress;
+			data=(TUint *)(aPeFile.iSectionData[KTextSection]+relocation[i]);
+			if (!gLittleEndian) ByteSwap(*data);
+			checkreloc(aPeFile, *data, relocation[i]+aPeFile.iSectionHeader[KTextSection]->VirtualAddress);
+			*data=FixAddress(aPeFile, *data);
+			if (!gLittleEndian) ByteSwap(*data);
+			break;
+		case KConstSection:
+			relocation[i]-=aPeFile.iSectionHeader[KConstSection]->VirtualAddress;
+			data=(TUint *)(aPeFile.iSectionData[KConstSection]+relocation[i]);
+			if (!gLittleEndian) ByteSwap(*data);
+			checkreloc(aPeFile, *data, relocation[i]+aPeFile.iSectionHeader[KConstSection]->VirtualAddress);
+			relocation[i]+=ConstOffset();
+			*data=FixAddress(aPeFile, *data);
+			if (!gLittleEndian) ByteSwap(*data);
+			break;
+		case KCrtSection:
+			relocation[i]-=aPeFile.iSectionHeader[KCrtSection]->VirtualAddress;
+			data=(TUint *)(aPeFile.iSectionData[KCrtSection]+relocation[i]);
+			if (!gLittleEndian) ByteSwap(*data);
+			checkreloc(aPeFile, *data, relocation[i]+aPeFile.iSectionHeader[KCrtSection]->VirtualAddress);
+			relocation[i]+=iCrtOffset;
+			*data=FixAddress(aPeFile, *data);
+			if (!gLittleEndian) ByteSwap(*data);
+			break;
+		case KDataSection:
+			relocation[i]-=aPeFile.iSectionHeader[KDataSection]->VirtualAddress;
+			data=(TUint *)(aPeFile.iSectionData[KDataSection]+relocation[i]);
+			if (!gLittleEndian) ByteSwap(*data);
+			checkreloc(aPeFile, *data, relocation[i]+aPeFile.iSectionHeader[KDataSection]->VirtualAddress);
+			*data=FixAddress(aPeFile, *data);
+			if (!gLittleEndian) ByteSwap(*data);
+			break;
+		default:
+			Print(EWarning, "Relocation in invalid section.\n");
+			break;
+			}
+		}
+	reorderRelocs(relocation, relocsection, aNumberOfRelocs);
+	}
+
+TUint E32ImageFile_PE::FixAddress(PEFile &aPeFile, TUint va)
+//
+// Fix the given virtual address for the new headers
+//
+	{
+
+	// Allow the section find routine to use heuristics to resolve addresses
+	// which have been offset by the compiler
+	TInt section=aPeFile.FindSectionByVa(va, 1);
+	switch(section)
+		{
+		case KTextSection:
+			va-=aPeFile.iLinkedBase;
+			va-=aPeFile.iSectionHeader[KTextSection]->VirtualAddress;
+			va+=iHdr->iCodeBase;
+			break;
+		case KConstSection:
+			va-=aPeFile.iLinkedBase;
+			va-=aPeFile.iSectionHeader[KConstSection]->VirtualAddress;
+			if (gX86imp)
+				{
+				TUint old_iat_size=(gX86num_imports+gX86num_imp_dlls)<<2;
+				if (va<old_iat_size)
+					{
+					TInt offset=iHdr->iTextSize;
+//					fprintf(stderr,"IAT OFF %x ",va);
+					va=gX86imp_relocs[va>>2]+iHdr->iCodeBase+offset;
+//					fprintf(stderr,"-> %x\n",va);
+					break;
+					}
+				}
+			va+=iHdr->iCodeBase+ConstOffset();
+//			fprintf(stderr,"const reloc -> %x\n",va);
+			break;
+		case KDataSection:
+			va-=aPeFile.iLinkedBase;
+			va-=aPeFile.iSectionHeader[KDataSection]->VirtualAddress;
+			va+=iHdr->iDataBase; //DataOffset();
+			break;
+		case KCrtSection:
+			va-=aPeFile.iLinkedBase;
+			va-=aPeFile.iSectionHeader[KCrtSection]->VirtualAddress;
+			va+=iHdr->iCodeBase+iCrtOffset;
+			break;
+		case KBssSection:
+			va-=aPeFile.iLinkedBase;
+			va-=aPeFile.iSectionHeader[KBssSection]->VirtualAddress;
+			va+=iHdr->iDataBase+iHdr->iDataSize;
+			break;
+		case KImportSection:
+			va-=aPeFile.iLinkedBase;
+			va=FixImportThunk(aPeFile, va-aPeFile.iSectionHeader[KImportSection]->VirtualAddress);
+			va+=iHdr->iCodeBase;
+			break;
+		default:
+			if (va < 0x10000u)
+				{
+				// assume it's a relocation relative to an omitted section
+				break;
+				}
+			Print(EWarning, "Address to relocate cannot be resolved to .text, .rdata, .idata or data sections\n");
+			Print(EWarning, "Problem address = %08x (section %d)\n", va, section);
+			break;
+		}
+	// va is now an offset from the start of the text
+	return va;
+	}
+
+