diff -r 22486c9c7b15 -r 378360dbbdba bintools/petools/pefile/pe_tran.cpp --- /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 +#include +#include +#include "e32image.h" +#include +#include +#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; iNumberOfFunctions; 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>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); + } +