bintools/petools/pefile/pe_tran.cpp
changeset 607 378360dbbdba
parent 600 6d08f4a05d93
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bintools/petools/pefile/pe_tran.cpp	Wed Jun 30 11:35:58 2010 +0800
@@ -0,0 +1,453 @@
+// 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 <time.h>
+#include <malloc.h>
+#include <string.h>
+#include "e32image.h"
+#include <e32std.h>
+#include <e32std_private.h>
+#include "pe_defs.h"
+#include "pe_file.h"
+#include "h_ver.h"
+#include "h_utl.h"
+
+int gAlignConstSection=FALSE;
+TUint gConstSectionAddressMask=0;
+static TUint gRequiredConstPadding;
+
+extern char* gX86imp;
+extern int gX86num_imp_dlls;
+extern int gX86imp_size;
+extern int gX86num_imports;
+
+E32ImageFile* E32ImageFile::New()
+	{
+	return new E32ImageFile_PE;
+	}
+
+E32ImageFile_PE::E32ImageFile_PE()
+	{
+	}
+
+E32ImageFile_PE::~E32ImageFile_PE()
+	{
+	}
+
+TUint E32ImageFile_PE::ImportAddressTableOffset()
+//
+// Return the offset of the iat
+//
+	{
+	return iHdr->iTextSize;
+	}
+
+TUint E32ImageFile_PE::ConstOffset()
+//
+// return the offset of the const data
+//
+	{
+	return iConstOffset;
+	}
+
+void E32ImageFile_PE::CreateExportDirectory(char *aPtr, PEFile &aPeFile)
+//
+// create a new format export directory
+//
+	{
+	
+	if (iHdr->iExportDirCount==0)
+		return;
+	TUint *src=(TUint *)aPeFile.iSectionData[KExportSection];
+	TUint *dst=(TUint *)aPtr;
+	PIMAGE_EXPORT_DIRECTORY dir=(PIMAGE_EXPORT_DIRECTORY)src;
+	src+=(((TInt)dir->AddressOfFunctions)-((TInt)aPeFile.iSectionHeader[KExportSection]->VirtualAddress))/4;
+	TUint i;
+	for (i=0; i<dir->NumberOfFunctions; i++)
+		{
+		TUint va=*src++;
+		dst[i]=va;
+		}
+	FixExportDirectory(dst, aPeFile);
+	}
+
+void E32ImageFile_PE::FixExportDirectory(TUint *aExportDir, PEFile &aPeFile)
+//
+// Fix the export directory
+//
+	{
+
+	TUint lb = aPeFile.iLinkedBase;
+	TUint *exportdir=aExportDir;
+	TInt n;
+	for (n=0; n<(TInt)iHdr->iExportDirCount; n++)
+		{
+		TUint va=*exportdir;
+		if (!gLittleEndian) ByteSwap(va);
+
+		// va is the address of an exported item, so assume it can't have been offset
+		TInt i=aPeFile.FindSectionByVa(va+lb);
+		if (i==KTextSection)
+			va=va-aPeFile.iSectionHeader[i]->VirtualAddress;
+		else if (i==KConstSection)
+			va=va-aPeFile.iSectionHeader[i]->VirtualAddress+ConstOffset();
+		else if (i==KDataSection)
+			va=va-aPeFile.iSectionHeader[i]->VirtualAddress+DataOffset();
+		else if (i==KBssSection)
+			va=va-aPeFile.iSectionHeader[i]->VirtualAddress+BssOffset();
+		else
+			{
+			if (va == 0)
+				Print(EWarning, "No export specified for ordinal %d\n", n+1, va);
+			else
+				Print(EError, "Export %d (address %08x) is not from .text, .rdata, or data sections\n", n+1, va);
+			}
+		if (!gLittleEndian) ByteSwap(va);
+		*exportdir++=va;
+		}
+	}
+
+TInt E32ImageFile_PE::DoCodeHeader(PEFile &aPeFile)
+//
+// Calculate the code parts of the pefile
+//
+	{
+
+	// .text
+	TInt size=ALIGN4(aPeFile.iSectionHeader[KTextSection]->Misc.VirtualSize);
+
+	// .rdata
+	iConstOffset=0;
+	if (gAlignConstSection)
+		{
+	    // Compute the amount of padding to put before the
+	    // const section to align it correctly
+	    TUint   oldAddressBits = aPeFile.iSectionHeader[KConstSection]->VirtualAddress & gConstSectionAddressMask;
+	    TUint   oldConstAddress = size;
+	    TUint   newConstAddress = oldConstAddress;
+	    // slow but sure
+	    while ((newConstAddress & gConstSectionAddressMask) != oldAddressBits)
+	    	{
+			newConstAddress++;
+			}
+	    gRequiredConstPadding = newConstAddress - oldConstAddress;
+	    size += gRequiredConstPadding;
+		}
+	if (aPeFile.iSectionHeader[KConstSection])
+		{
+		iConstOffset = size;
+		size += ALIGN4(aPeFile.iSectionHeader[KConstSection]->Misc.VirtualSize);
+		}
+
+	// .crt
+	iCrtOffset=0;
+	if (aPeFile.iSectionHeader[KCrtSection])
+		{
+		iCrtOffset = size;
+		size += ALIGN4(aPeFile.iSectionHeader[KCrtSection]->Misc.VirtualSize);
+		}
+
+	iHdr->iTextSize=size; // The "text" part of the E32 code section combines PE's .text + .rdata + .crt.
+						  // The remainder of the E32 code section is the IAT + export directory.
+
+	// Import Address Table (IAT)
+	TInt nimports=gX86imp?gX86num_imports:aPeFile.NumberOfImports();
+	if (nimports!=0)
+		size+=nimports*4+4; // null terminated
+	
+	// Export Dir
+	if (iHdr->iExportDirCount)
+		{
+		iHdr->iExportDirOffset = iHdr->iCodeOffset + size;
+		size += ALIGN4(iHdr->iExportDirCount*4);
+		}
+	iHdr->iCodeSize=size;
+	return size;
+	}
+
+TInt E32ImageFile_PE::DoDataHeader(PEFile &aPeFile, TUint aDataBase)
+//
+//
+//
+	{
+
+	if (aDataBase == (TUint)0)
+		aDataBase=iHdr->iCodeBase+iHdr->iCodeSize;
+	TInt size=0;
+	if (PEFile::HasInitialisedData(aPeFile.iSectionHeader[KDataSection]))
+		{
+		size=ALIGN4(aPeFile.iSectionHeader[KDataSection]->Misc.VirtualSize);
+		iHdr->iDataBase=aDataBase;
+		iHdr->iDataOffset = iHdr->iCodeOffset + iHdr->iCodeSize;
+		TInt bsssize=aPeFile.iSectionHeader[KDataSection]->Misc.VirtualSize-aPeFile.iSectionHeader[KDataSection]->SizeOfRawData;
+		// drop any uninitialised data
+		if (bsssize>0)
+			{
+			iHdr->iBssSize+=bsssize;
+			size=ALIGN4(aPeFile.iSectionHeader[KDataSection]->SizeOfRawData);
+			}
+		iHdr->iDataSize=size;
+		}
+	else if (aPeFile.iSectionHeader[KDataSection])
+		{ // just .bss
+		iHdr->iDataBase=aDataBase;
+		TInt bsssize=aPeFile.iSectionHeader[KDataSection]->Misc.VirtualSize;
+		iHdr->iBssSize+=bsssize;
+		}
+	if (aPeFile.iSectionHeader[KBssSection])
+		{
+		iHdr->iBssSize+=ALIGN4(aPeFile.iSectionHeader[KBssSection]->Misc.VirtualSize);
+		if (iHdr->iDataBase==0) // .bss but no .data
+			iHdr->iDataBase=aDataBase;
+		}
+	return size;
+	}
+
+TInt E32ImageFile_PE::CopyCode(char *p, PEFile &aPeFile)
+//
+// Copies the files code sections to p
+// returns the number of bytes copied or KErrGeneral
+//
+	{
+
+	// text
+	TInt size=aPeFile.iSectionHeader[KTextSection]->Misc.VirtualSize;
+	memcpy(p, aPeFile.iSectionData[KTextSection], size);
+	TInt text_offset=ALIGN4(size);
+	p+=text_offset;
+
+	// rdata
+	if (aPeFile.iSectionData[KConstSection])
+		{
+		if (gAlignConstSection)
+			{
+			// add padding ahead of const section
+			p += gRequiredConstPadding;
+			}
+		TInt size=ALIGN4(aPeFile.iSectionHeader[KConstSection]->Misc.VirtualSize);
+		memcpy(p, aPeFile.iSectionData[KConstSection], size);
+		p+=size;
+		}
+	if (aPeFile.iSectionData[KCrtSection])
+		{
+		TInt size=ALIGN4(aPeFile.iSectionHeader[KCrtSection]->Misc.VirtualSize);
+		memcpy(p, aPeFile.iSectionData[KCrtSection], size);
+		p+=size;
+		}
+
+	// iat
+	TInt nimports=gX86imp?gX86num_imports:aPeFile.NumberOfImports();
+//	TInt nimports=aPeFile.NumberOfImports();
+	if (nimports)
+		{
+		if (gX86imp)
+			{
+			TUint *rdata=(TUint*)aPeFile.iSectionData[KConstSection];
+			int i;
+			int* s=(int*)gX86imp;
+			s++;
+			for (i=0; i<gX86num_imp_dlls; ++i)
+				{
+				++s;
+				int n=*s++;
+				while (n--)
+					{
+					*(int*)p=rdata[(*s)>>2]&0x7fffffffu;	// rdata offset to ordinal
+					++s;
+					p+=4;
+					}
+				}
+			*(int*)p=0;
+			p+=4;
+			}
+		else
+			{
+			TInt r=CopyImportAddrTable(p, aPeFile);
+			p+=ALIGN4(nimports*4+4);
+			if (r!=KErrNone)
+				return Print(EError, "%s is importing symbols by name.\n", iFileName);
+			}
+		}
+	// export dir
+	CreateExportDirectory(p, aPeFile);
+	p+=iHdr->iExportDirCount*4;
+	return iHdr->iCodeSize;
+	}
+
+TInt E32ImageFile_PE::CopyData(char *p, PEFile &aPeFile)
+	{
+	
+	if (iHdr->iDataSize)
+		memcpy(p, aPeFile.iSectionData[KDataSection], iHdr->iDataSize);
+	return iHdr->iDataSize;
+	}
+
+TInt E32ImageFile_PE::Translate(const char* aFileName, TUint aDataBase, TBool aAllowDllData, TBool /*aSymLkupEnabled*/)
+//
+// Translate a PE format file to a E32Image file
+//
+	{
+	iSource = EPeFile;
+	PEFile pefile;
+	if (!pefile.Init((const char * const)aFileName))
+		return KErrGeneral;
+	TInt r=pefile.ReadSectionHeaders();
+	if (r!=KErrNone) return r;
+	r=pefile.ReadData();
+	if (r!=KErrNone) return r;
+	pefile.Close();
+	r=pefile.Normalise();
+	if (r!=KErrNone) return r;
+	iFileName = strdup(aFileName);
+
+	Adjust(ALIGN4(sizeof(E32ImageHeaderV)));	// fixed for now because holes not supported
+	SetDefaultHeader();
+	if (gX86imp)
+		iHdr->iDllRefTableCount=gX86num_imp_dlls;
+	else
+		iHdr->iDllRefTableCount=pefile.NumberOfImportDlls();
+	iHdr->iExportDirCount=pefile.NumberOfExports();
+	iHdr->iCodeBase=pefile.iLinkedBase;
+	TInt nimports=gX86imp?gX86num_imports:pefile.NumberOfImports();
+
+	TInt importSectionSize;
+	char *newImportSection=CreateImportSection(pefile, importSectionSize);
+
+	TInt size = ALIGN4(sizeof(E32ImageHeaderV));	// fixed for now because holes not supported
+	iHdr->iCodeOffset = size;
+	TInt pos = size;
+	size+=DoCodeHeader(pefile);
+	TInt t=DoDataHeader(pefile, aDataBase);
+	if (t>0)
+		{
+		iHdr->iDataOffset = size;
+		size += t;
+		}
+	if (importSectionSize!=0)
+		{
+		iHdr->iImportOffset = size;
+		size += importSectionSize;
+		}
+
+	char *newCodeRelocs=NULL;
+	char *newDataRelocs=NULL;
+	TInt codeRelocSize=0, dataRelocSize=0;
+	TInt nrelocs=pefile.NumberOfRelocs();
+	if (nrelocs)
+		{
+		TUint *relocs=new TUint [nrelocs];
+		TUint *relocsection=new TUint [nrelocs];
+		pefile.GetRelocs(relocs, relocsection, nrelocs);
+		FixRelocs(pefile, relocs, relocsection, nrelocs);
+		newCodeRelocs=CreateCodeRelocs(relocs, relocsection, nrelocs, codeRelocSize);
+		newDataRelocs=CreateDataRelocs(relocs, relocsection, nrelocs, dataRelocSize);
+		if (codeRelocSize)
+			{
+			iHdr->iCodeRelocOffset = size;
+			size += codeRelocSize;
+			}
+		if (dataRelocSize)
+			{
+			iHdr->iDataRelocOffset = size;
+			size += dataRelocSize;
+			}
+		delete [] relocs;
+		delete [] relocsection;
+		}
+
+	Adjust(size);
+	t=CopyCode(iData + pos, pefile);
+	if (t<0)
+		return KErrGeneral;
+	pos += t;
+	pos += CopyData(iData + pos, pefile);
+	if (nimports)
+		{
+		memcpy(iData + pos, newImportSection, importSectionSize);
+		pos += importSectionSize;
+		}
+	if (codeRelocSize)
+		{
+		memcpy(iData + pos, newCodeRelocs, codeRelocSize);
+		pos += codeRelocSize;
+		}
+	if (dataRelocSize)
+		{
+		memcpy(iData + pos, newDataRelocs, dataRelocSize);
+		pos += dataRelocSize;
+		}
+
+	// locate the entry point
+	// entry point must be in the text section
+	TInt entryPointSectionIndex=pefile.FindSectionByVa(pefile.iEntryPoint+pefile.iLinkedBase);
+	TUint entryPointOffset=pefile.iEntryPoint-pefile.iSectionHeader[entryPointSectionIndex]->VirtualAddress;
+	if (entryPointSectionIndex!=KTextSection)
+		return Print(EError, "Entry Point not in code section\n");
+
+	// Arrange a header for this E32 Image
+	switch (pefile.iCpu)
+		{
+	case IMAGE_FILE_MACHINE_I386:
+		iHdr->iCpuIdentifier = (TUint16)ECpuX86;
+		break;
+	case 0x0a00:
+		iHdr->iCpuIdentifier = (TUint16)ECpuArmV4;
+		break;
+	case 0x0b00:
+		iHdr->iCpuIdentifier = (TUint16)ECpuMCore;
+		break;
+	default:
+		iHdr->iCpuIdentifier = (TUint16)ECpuUnknown;
+		break;
+		}
+
+	// Import format is PE-derived without redundant ordinal lists
+	// ABI is GCC98r2 ABI (on ARM)
+	iHdr->iFlags |= KImageImpFmt_PE2;
+
+	if (pefile.iImageIsDll)
+		{
+		iHdr->iFlags|=KImageDll;
+		if (iHdr->iDataSize && !aAllowDllData)
+			return Print(EError, "Dll '%s' has initialised data.\n", iFileName);
+		if (iHdr->iBssSize  && !aAllowDllData)
+			return Print(EError, "Dll '%s' has uninitialised data.\n", iFileName);
+		}
+	iHdr->iHeapSizeMin=pefile.iHeapCommittedSize;
+	iHdr->iHeapSizeMax=pefile.iHeapReservedSize;
+	iHdr->iStackSize=pefile.iStackCommittedSize;
+	iHdr->iEntryPoint=entryPointOffset;
+	r = DetermineEntryPointType();
+	if (r == KErrCorrupt)
+		return Print(EError, "File '%s': Bad Entry Point.\n", iFileName);
+	else if (r == KErrNotSupported)
+		return Print(EError, "File '%s': Bad Entry Point Type.\n", iFileName);
+
+	delete [] newImportSection;
+	delete [] newCodeRelocs;
+	delete [] newDataRelocs;
+
+	return KErrNone;
+	}
+
+TBool E32ImageFile_PE::Translate(PEFile &aPeFile)
+//
+//
+//
+	{
+
+	return Translate((const char*)aPeFile.iFileName, (TUint)0, EFalse, EFalse);
+	}
+