[GCCE] We need a way for the HAL config extension to parameterise the HAL config file (.hcf) that will be used, depending upon
the toolchain we are building with. E.g. if we are building BeagleBoard with RVCT we can configure hardware floating point
because we have ARM's vfp math libraries; if we are building it with GCC, we lack this library support.
// 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==NULL)
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 TText * 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, NULL, EFalse, EFalse);
}