[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) 2004-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:
// Implementation of the Class ElfProducer for the elf2e32 tool
// @internalComponent
// @released
//
//
#include "pl_elfproducer.h"
#include "pl_dllsymbol.h"
#include <stdio.h>
#include <string>
#include "errorhandler.h"
/**
* Following array is indexed on the SECTION_INDEX enum
*/
char* SECTION_NAME[] = {
"",
"ER_RO",
".dynamic",
".hash",
".version_d",
".version",
".strtab",
".dynsym",
".shstrtab"
};
/**
Constructor for class ElfProducer
@param aParameterListInterface - instance of class ParameterListInterface
@internalComponent
@released
*/
ElfProducer::ElfProducer(ParameterListInterface *aParameterListInterface): ElfExecutable(aParameterListInterface) , \
iDSONameOffset(0),\
iLinkAsOffset(0),\
iSymbolsList(NULL),
iDSODaux(NULL), \
iDSOBuckets(NULL), \
iDSOChains(NULL),\
iCodeSectionData(NULL),\
iElfFileOffset(0)
{
}
/**
Destructor for class ElfProducer to release allocated memory
@internalComponent
@released
*/
ElfProducer::~ElfProducer(){
Cleanup();
}
/**
This function sets the export Symbol list
@internalComponent
@released
@param aSymbolList The export Symbol list.
*/
void ElfProducer::SetSymbolList(SymbolList& aSymbolList){
iSymbolsList = &aSymbolList;
if (iSymbolsList)
{
SymbolList::iterator aPos, aEnd;
aPos = iSymbolsList->begin();
aEnd = iSymbolsList->end();
char *aAbsentSymbol = "_._.absent_export_";
int length = strlen(aAbsentSymbol);
while(aPos != aEnd)
{
/* If a symbol is marked as Absent in the DEF file, replace the
* symbol name with "_._.absent_export_<Ordinal Number>"
*/
if((*aPos)->Absent())
{
int aOrdinalNo = (*aPos)->OrdNum();
// Ordinal Number can be upto 0xffff which is 6 digits
char * aSymName = new char[length+7];
sprintf(aSymName, "_._.absent_export_%d", aOrdinalNo);
(*aPos)->SetSymbolName(aSymName);
delete[] aSymName;
}
aPos++;
}
}
iNSymbols = iSymbolsList->size() + 1;
}
/**
This function takes the file names and generates the proxy dso library.
@internalComponent
@released
@param aDsoFullName The full path and proxy-dso file name
@param aDsoFileName The proxy-dso file name
@param aLinkAs The DLL that defines the export Symbols
*/
void ElfProducer::WriteElfFile(char* aDsoFullName, char* aDsoFileName , char* aLinkAs){
//This includes the full path followed by the file name
iDsoFullName = aDsoFullName;
iDSOName = aDsoFileName;
iLinkAs = aLinkAs;
InitElfContents();
WriteElfContents();
}
/**
This function initializes the Elf members
@internalComponent
@released
*/
void ElfProducer::InitElfContents() {
iElfHeader = new Elf32_Ehdr;
iSections = new Elf32_Shdr[MAX_SECTIONS+1];
iElfDynSym = new Elf32_Sym[iNSymbols];
iVersionTbl = new Elf32_Half[iNSymbols];
iVersionDef = new Elf32_Verdef[2];
iDSODaux = new Elf32_Verdaux[2];
iProgHeader = new Elf32_Phdr[2];
iCodeSectionData = new PLUINT32[iNSymbols];
iHashTbl = new Elf32_HashTable;
//premeditated
iHashTbl->nBuckets = (iNSymbols /3) + (iNSymbols % 0x3);
iHashTbl->nChains = iNSymbols;
iDSOBuckets = new Elf32_Sword[iHashTbl->nBuckets];
iDSOChains = new Elf32_Sword[iHashTbl->nChains];
Elf32_Sword aNullPtr = 0;
memset(iDSOBuckets, aNullPtr, sizeof(Elf32_Sword)*iHashTbl->nBuckets);
memset(iDSOChains, aNullPtr, sizeof(Elf32_Sword)*iHashTbl->nChains);
memset(iCodeSectionData, 0, sizeof(PLUINT32)*iNSymbols);
CreateElfHeader();
SymbolList::iterator aItr = iSymbolsList->begin();
SymbolList::iterator aEnd = iSymbolsList->end();
Symbol *aSym;
PLUINT32 aIdx = 1;
memset( &iElfDynSym[0], 0, sizeof(Elf32_Sym));
iDSOSymNameStrTbl.insert(iDSOSymNameStrTbl.end(), 0);
while(aItr != aEnd) {
String aSymName("");
aSym = *aItr;
aSymName = aSym->SymbolName();
//set symbol info..
iElfDynSym[aIdx].st_name = iDSOSymNameStrTbl.size();
iDSOSymNameStrTbl.insert(iDSOSymNameStrTbl.end(), aSymName.begin(), aSymName.end() );
iDSOSymNameStrTbl.insert(iDSOSymNameStrTbl.end(), 0);
SetSymolFields( aSym, &iElfDynSym[aIdx], aIdx);
//set version table info...
iVersionTbl[aIdx] = DEFAULT_VERSION;
AddToHashTable(aSym->SymbolName(), aIdx);
aItr++;aIdx++;
}
CreateVersionTable();
//Fill section headers...
CreateSections();
//Copy dyn entries..
CreateDynamicEntries();
//create code section data - this has the ordinal numbers...
CreateProgHeader();
}
/**
This function creates the version definition table
@internalComponent
@released
*/
void ElfProducer::CreateVersionTable()
{
//Fill verdef table...
iVersionDef[0].vd_ndx = 1;
iVersionDef[0].vd_cnt = 1;
iVersionDef[0].vd_flags = 1;
iVersionDef[0].vd_hash = Util::elf_hash((const PLUCHAR*) iDSOName.c_str());
iVersionDef[0].vd_version = 1;
iVersionDef[0].vd_aux = sizeof(Elf32_Verdef);
iVersionDef[0].vd_next = sizeof(Elf32_Verdef) + sizeof(Elf32_Verdaux);
iDSONameOffset = iDSOSymNameStrTbl.size();
iDSOSymNameStrTbl.insert(iDSOSymNameStrTbl.end(),iDSOName.begin(), iDSOName.end());
iDSOSymNameStrTbl.insert(iDSOSymNameStrTbl.end(), 0);
iDSODaux[0].vda_name = iDSONameOffset;
iDSODaux[0].vda_next = 0;
iVersionDef[1].vd_ndx = DEFAULT_VERSION;
iVersionDef[1].vd_cnt = 1;
iVersionDef[1].vd_flags = 0;
iVersionDef[1].vd_hash = Util::elf_hash((const PLUCHAR*)iLinkAs.c_str());
iVersionDef[1].vd_version = 1;
iVersionDef[1].vd_aux = sizeof(Elf32_Verdef);
iVersionDef[1].vd_next = 0;
iLinkAsOffset = iDSOSymNameStrTbl.size();
iDSOSymNameStrTbl.insert(iDSOSymNameStrTbl.end(),iLinkAs.begin(), iLinkAs.end());
iDSOSymNameStrTbl.insert(iDSOSymNameStrTbl.end(), 0);
iDSODaux[1].vda_name = iLinkAsOffset;
iDSODaux[1].vda_next = 0;
}
/**
This function sets the Elf Symbol fields
@internalComponent
@released
@param aSym The Symbol representation
@param aElfSym The Elf Symbol
@param aCodeIndex The index at which this Symbol refers to in the code section where, we have the ordinal number
*/
void ElfProducer::SetSymolFields(Symbol *aSym, Elf32_Sym* aElfSym, PLUINT32 aCodeIndex) {
aElfSym->st_other = STV_DEFAULT;
aElfSym->st_info = (PLUCHAR) (ELF32_ST_INFO(STB_GLOBAL, aSym->CodeDataType()));
aElfSym->st_value = (aCodeIndex - 1)*sizeof(Elf32_Word);
if(aSym->CodeDataType() == SymbolTypeCode){
aElfSym->st_size = sizeof(Elf32_Word);
}else{
aElfSym->st_size = aSym->SymbolSize();
}
aElfSym->st_shndx = CODE_SECTION;
}
/**
This function adds an entry into the hash table based on the symbol name.
@internalComponent
@released
@param aSymName The Symbol name
@param aIndex The Symbol index in the Symbol table
*/
void ElfProducer::AddToHashTable(const char* aSymName, PLUINT32 aIndex)
{
Elf32_Sword aNullPtr = 0;
PLULONG aHash = Util::elf_hash((PLUCHAR*)aSymName);
PLUINT32 aBIdx = aHash % iHashTbl->nBuckets;
if(iDSOBuckets[aBIdx] == aNullPtr)
{
iDSOBuckets[aBIdx] = aIndex;
}
else
{
PLUINT32 aCIdx = iDSOBuckets[aBIdx];
while(iDSOChains[aCIdx] != aNullPtr){
/* If the entry is already added into the hash table*/
if((PLUINT32)iDSOChains[aCIdx] == aIndex) {
return;
}
aCIdx = iDSOChains[aCIdx];
}
iDSOChains[aCIdx] = aIndex;
}
}
/**
This function creates the different sections of the Elf file
@internalComponent
@released
*/
void ElfProducer::CreateSections() {
PLUINT32 aIdx = 0;
//clear the first section...
memset(&iSections[0], 0, sizeof(Elf32_Shdr));
iDSOSectionNames.insert(iDSOSectionNames.begin(), 0);
// Set the ELF file offset.
// This indicates the start of sections.
iElfFileOffset = sizeof(Elf32_Ehdr);
iElfFileOffset += (sizeof(Elf32_Shdr) * iElfHeader->e_shnum);
//Check if the string table is 4-byte aligned..
AlignString(iDSOSymNameStrTbl);
for(aIdx = 1; aIdx <= MAX_SECTIONS; aIdx++) {
switch(aIdx)
{
case SYMBOL_SECTION:
SetSectionFields(aIdx, SECTION_NAME[aIdx], SHT_DYNSYM, \
sizeof(Elf32_Sym), (iNSymbols * sizeof(Elf32_Sym)),\
STRING_SECTION, CODE_SECTION, 4, 0, 0);
break;
case STRING_SECTION:
SetSectionFields(aIdx, SECTION_NAME[aIdx], SHT_STRTAB, \
1, iDSOSymNameStrTbl.size(), 0, \
0, 0, 0,0);
break;
case VERSION_SECTION:
SetSectionFields(aIdx, SECTION_NAME[aIdx], 0x6fffffff, \
sizeof(Elf32_Half), (iNSymbols * sizeof(Elf32_Half)), SYMBOL_SECTION, \
0, 2, 0, 0);
break;
case VER_DEF_SECTION:
SetSectionFields(aIdx, SECTION_NAME[aIdx],0x6ffffffd, \
sizeof(Elf32_Verdaux), (2*(sizeof(Elf32_Verdef) + sizeof(Elf32_Verdaux))),\
STRING_SECTION, DYNAMIC_SECTION, 4, 0, 0);
break;
case HASH_TBL_SECTION:
{
PLUINT32 aSize = sizeof(Elf32_HashTable) + \
(sizeof(Elf32_Sword) * (iHashTbl->nBuckets + iHashTbl->nChains));
SetSectionFields(aIdx, SECTION_NAME[aIdx], SHT_HASH, \
0, aSize, SYMBOL_SECTION, 0, 4, 0, 0);
}
break;
case DYNAMIC_SECTION:
SetSectionFields(aIdx, SECTION_NAME[aIdx], SHT_DYNAMIC, \
sizeof(Elf32_Dyn), ((MAX_DYN_ENTS + 1) *sizeof(Elf32_Dyn)),\
STRING_SECTION, 0, 4, 0,0);
break;
case CODE_SECTION:
SetSectionFields(aIdx, SECTION_NAME[aIdx], SHT_PROGBITS, \
0, (iNSymbols *sizeof(PLUINT32)),\
0, 0, 4, (SHF_ALLOC | SHF_EXECINSTR),0);
break;
case SH_STR_SECTION:
{
PLUINT32 aSize = iDSOSectionNames.size() + strlen(SECTION_NAME[aIdx]);
SetSectionFields(aIdx, SECTION_NAME[aIdx], SHT_STRTAB, \
1, aSize, 0, \
0, 0, 0, 0);
//Check if the string table is 4-byte aligned..
AlignString(iDSOSectionNames);
iSections[aIdx].sh_size = iDSOSectionNames.size();
}
break;
default:
break;
}
iSections[aIdx].sh_offset = iElfFileOffset;
iElfFileOffset += iSections[aIdx].sh_size;
if(iElfFileOffset %4) {
iElfFileOffset += (4 - (iElfFileOffset %4));
}
}
}
/**
This function sets the section header fields.
@internalComponent
@released
@return Error status
@param aSectionIndex The index of the section
@param aSectionName The name of the section
@param aType The type of the section
@param aEntSz The size of each entry of the section
@param aSectionSize The size of the section
@param aLink The section this section is linked to
@param aInfo Extra information. Depends on the section type of this section.
@param aAddrAlign The address alignment of this section.
@param aFlags Section flags
@param aAddr The address of this section in memory(Here it remains 0)
*/
void ElfProducer::SetSectionFields(PLUINT32 aSectionIndex, char* aSectionName, PLUINT32 aType, \
PLUINT32 aEntSz, PLUINT32 aSectionSize, PLUINT32 aLink, \
PLUINT32 aInfo, PLUINT32 aAddrAlign, PLUINT32 aFlags, \
PLUINT32 aAddr)
{
String aSecName = aSectionName;
iSections[aSectionIndex].sh_name = iDSOSectionNames.size();
iDSOSectionNames.insert(iDSOSectionNames.end(), aSecName.begin(), aSecName.end());
iDSOSectionNames.insert(iDSOSectionNames.end(), 0);
iSections[aSectionIndex].sh_type = aType;
iSections[aSectionIndex].sh_entsize = aEntSz;
iSections[aSectionIndex].sh_size = aSectionSize;
iSections[aSectionIndex].sh_link = aLink;
iSections[aSectionIndex].sh_flags = aFlags;
iSections[aSectionIndex].sh_addralign = aAddrAlign;
iSections[aSectionIndex].sh_info = aInfo;
iSections[aSectionIndex].sh_addr = aAddr;
}
/**
This function cleans up the memory allocated to the Elf fields.
@internalComponent
@released
*/
void ElfProducer::Cleanup()
{
DELETE_PTR(iElfHeader);
DELETE_PTR_ARRAY(iSections);
DELETE_PTR_ARRAY(iElfDynSym);
DELETE_PTR_ARRAY(iVersionTbl);
DELETE_PTR_ARRAY(iVersionDef);
DELETE_PTR_ARRAY(iDSODaux);
DELETE_PTR_ARRAY(iProgHeader);
DELETE_PTR_ARRAY(iCodeSectionData);
DELETE_PTR_ARRAY(iHashTbl);
DELETE_PTR_ARRAY(iDSOBuckets);
DELETE_PTR_ARRAY(iDSOChains);
}
/**
This function creates the dynamic sections.
@internalComponent
@released
*/
void ElfProducer::CreateDynamicEntries()
{
for(PLUINT32 aIdx = 0; aIdx <= MAX_DYN_ENTS; aIdx++ ) {
switch(aIdx) {
case DSO_DT_DSONAME:
iDSODynTbl[aIdx].d_tag = DT_SONAME;
iDSODynTbl[aIdx].d_val = iDSONameOffset;
break;
case DSO_DT_SYMTAB:
iDSODynTbl[aIdx].d_tag = DT_SYMTAB;
iDSODynTbl[aIdx].d_val = iSections[SYMBOL_SECTION].sh_offset;
break;
case DSO_DT_SYMENT:
iDSODynTbl[aIdx].d_tag = DT_SYMENT;
iDSODynTbl[aIdx].d_val = iSections[SYMBOL_SECTION].sh_entsize;
break;
case DSO_DT_STRTAB:
iDSODynTbl[aIdx].d_tag = DT_STRTAB;
iDSODynTbl[aIdx].d_val = iSections[STRING_SECTION].sh_offset;
break;
case DSO_DT_STRSZ:
iDSODynTbl[aIdx].d_tag = DT_STRSZ;
iDSODynTbl[aIdx].d_val = iDSOSymNameStrTbl.size();
break;
case DSO_DT_VERSYM:
iDSODynTbl[aIdx].d_tag = DT_VERSYM;
iDSODynTbl[aIdx].d_val = iSections[VERSION_SECTION].sh_offset;
break;
case DSO_DT_VERDEF:
iDSODynTbl[aIdx].d_tag = DT_VERDEF;
iDSODynTbl[aIdx].d_val = iSections[VER_DEF_SECTION].sh_offset;
break;
case DSO_DT_VERDEFNUM:
iDSODynTbl[aIdx].d_tag = DT_VERDEFNUM;
iDSODynTbl[aIdx].d_val = 2;
break;
case DSO_DT_HASH:
iDSODynTbl[aIdx].d_tag = DT_HASH;
iDSODynTbl[aIdx].d_val = iSections[HASH_TBL_SECTION].sh_offset;
break;
case DSO_DT_NULL:
iDSODynTbl[aIdx].d_tag = DT_NULL;
iDSODynTbl[aIdx].d_val = 0;
break;
default:
break;
}
}
}
/**
This function creates the Elf header.
@internalComponent
@released
*/
void ElfProducer::CreateElfHeader()
{
//create ELF header
unsigned char c[EI_NIDENT] = {0x7f, 'E', 'L', 'F', \
ELFCLASS32, ELFDATA2LSB, 1, 0, \
0, 0, 0, 0, \
0, 0, 0, 0}; // e_ident
for (PLUINT32 i=0; i <EI_NIDENT;i++)
iElfHeader->e_ident[i] = c[i];
iElfHeader->e_type = ET_DYN;
iElfHeader->e_machine = EM_ARM;
iElfHeader->e_version = EV_CURRENT;
iElfHeader->e_entry = 0;
iElfHeader->e_shoff = sizeof(Elf32_Ehdr);
iElfHeader->e_flags = EF_ARM_BPABI_VERSION | EF_ARM_SYMSARESORTED;
iElfHeader->e_ehsize = sizeof(Elf32_Ehdr);
iElfHeader->e_phentsize = sizeof(Elf32_Phdr);
iElfHeader->e_shentsize = sizeof(Elf32_Shdr);
iElfHeader->e_shnum = MAX_SECTIONS + 1;
iElfHeader->e_shstrndx = SH_STR_SECTION;
iElfHeader->e_phnum = 2;
}
/**
This function creates the program header
@internalComponent
@released
*/
void ElfProducer::CreateProgHeader()
{
//Update the program header offset..
iElfHeader->e_phoff = iElfFileOffset;
// Update code section data..
SymbolList::iterator aItr = iSymbolsList->begin();
SymbolList::iterator end = iSymbolsList->end();
Symbol *aSym;
PLUINT32 aPos = 0;
while(aItr != end) {
aSym = *aItr;
iCodeSectionData[aPos] = aSym->OrdNum();
aItr++;aPos++;
}
//Create program header
iProgHeader[0].p_align = 4;
iProgHeader[0].p_offset = iSections[CODE_SECTION].sh_offset;
iProgHeader[0].p_type = PT_LOAD;
iProgHeader[0].p_flags = (PF_X | PF_ARM_ENTRY);
iProgHeader[0].p_filesz = iSections[CODE_SECTION].sh_size;
iProgHeader[0].p_paddr = 0;
iProgHeader[0].p_vaddr = 0;
iProgHeader[0].p_memsz = iSections[CODE_SECTION].sh_size;
iProgHeader[1].p_align = 4;
iProgHeader[1].p_offset = iSections[DYNAMIC_SECTION].sh_offset;
iProgHeader[1].p_type = PT_DYNAMIC;
iProgHeader[1].p_flags = (PF_R );
iProgHeader[1].p_filesz = iSections[DYNAMIC_SECTION].sh_size;
iProgHeader[1].p_paddr = 0;
iProgHeader[1].p_vaddr = 0;
iProgHeader[1].p_memsz = 0;
}
/**
This function aligns the string table to a 4-byte boundary
@internalComponent
@released
@return Error status
@param aStr - string to be aligned
*/
void ElfProducer::AlignString(String& aStr) {
if( aStr.size() %4 ){
PLUCHAR aPad = (PLUCHAR)(4 - (aStr.size() %4));
while(aPad--) {
aStr.insert(aStr.end(), 0);
}
}
}
/**
This function writes the Elf file contents.
@internalComponent
@released
*/
void ElfProducer::WriteElfContents()
{
FILE *aElfFd;
PLUINT32 aIndex;
if((aElfFd = fopen(iDsoFullName.c_str(), "wb")) == NULL ) {
throw FileError(FILEOPENERROR, (char*)iDsoFullName.c_str());
}
// The ELF header..
fwrite(iElfHeader, 1, sizeof(Elf32_Ehdr), aElfFd);
//Section headers
for(aIndex = 0; aIndex <= MAX_SECTIONS; aIndex++) {
fwrite(&iSections[aIndex], 1, sizeof(Elf32_Shdr), aElfFd);
}
//Each section..
//code
for(aIndex = 0; aIndex < iNSymbols; aIndex++) {
fwrite(&iCodeSectionData[aIndex], 1, sizeof(PLUINT32), aElfFd );
}
//dyn table
for(aIndex = 0; aIndex <= MAX_DYN_ENTS; aIndex++) {
fwrite(&iDSODynTbl[aIndex], 1, sizeof(Elf32_Dyn), aElfFd);
}
//hash table
fwrite(&iHashTbl->nBuckets, 1, sizeof(Elf32_Word), aElfFd);
fwrite(&iHashTbl->nChains, 1, sizeof(Elf32_Word), aElfFd);
for(aIndex=0; aIndex < iHashTbl->nBuckets; aIndex++) {
fwrite(&iDSOBuckets[aIndex], 1, sizeof(Elf32_Sword), aElfFd);
}
for(aIndex=0; aIndex < iHashTbl->nChains; aIndex++) {
fwrite(&iDSOChains[aIndex], 1, sizeof(Elf32_Sword), aElfFd);
}
//version def table
for(aIndex = 0; aIndex < 2; aIndex++) {
fwrite(&iVersionDef[aIndex], 1, sizeof(Elf32_Verdef), aElfFd);
fwrite(&iDSODaux[aIndex], 1, sizeof(Elf32_Verdaux), aElfFd);
}
//version table
for(aIndex = 0; aIndex < iNSymbols; aIndex++) {
fwrite(&iVersionTbl[aIndex], 1, sizeof(Elf32_Half), aElfFd );
}
if( iSections[VERSION_SECTION].sh_size %4 ) {
PLUINT32 aNPads = 4 - (iSections[VERSION_SECTION].sh_size %4);
PLUCHAR aPad = '\0';
while(aNPads--) {
fwrite(&aPad, 1, 1, aElfFd);
}
}
//string table
PLUINT32 aSz = iDSOSymNameStrTbl.size();
char *aData = new char[aSz];
memcpy(aData, iDSOSymNameStrTbl.data(), aSz);
fwrite(aData, 1, aSz, aElfFd);
DELETE_PTR_ARRAY(aData);
//Sym table
for(aIndex = 0; aIndex < iNSymbols; aIndex ++) {
fwrite(&iElfDynSym[aIndex], 1, sizeof(Elf32_Sym), aElfFd);
}
//section header name table
aSz = iDSOSectionNames.size();
char *aData1 = new char[ aSz];
memcpy(aData1, iDSOSectionNames.data(), aSz);
fwrite(aData1, 1, aSz, aElfFd);
DELETE_PTR_ARRAY(aData1);
//program header
for(aIndex = 0; aIndex < 2; aIndex++) {
fwrite(&iProgHeader[aIndex], 1, sizeof(Elf32_Phdr), aElfFd );
}
fclose(aElfFd);
}