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