--- /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);
+ }
+