Add support for --asm option when using elf2e32 in the "expgen" recipe - see bug 2979 and bug 1405
/*
* Copyright (c) 2001-2009 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of the License "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 <string.h>
#include <stdlib.h>
#include <e32std.h>
#include <elfdefs.h>
#include "elfdll.h"
#include "elffile.h"
#include <h_utl.h>
#include <e32ldr.h>
ELFFile::ELFDllData::ELFDllData(ELFFile * f)
:
iElfFile(f),
iDynStrTab(0),
iDynStrTabSize(0),
iDynSymTab(0),
iSymSize(0),
iRela(0),
iRelaSz(0),
iRelaEnt(0),
iRel(0),
iRelSz(0),
iRelEnt(0),
iHashTable(0),
iNamedExportSymbolHead(0),
iNamedExportCount(0),
iSymStringTableSize(0),
iStringNameOffset(0),
iDepRecords(0),
iDepRecordsTail(0),
iNeededDllNames(0),
iNeededDllNamesTail(0),
iOrdZeroRec(0),
iNamedLookupEnabled(0),
iDllHead(0),
iDllTail(0),
iNumberOfImports(0),
iNumberOfExports(0),
iNumberOfImportDlls(0),
iStringTableSize(0),
iNumberOfRelocs(0),
iNumberOfCodeRelocs(0),
iNumberOfDataRelocs(0)
{
}
ELFFile::ELFDllData::~ELFDllData()
{
delete iOrdZeroRec;
delete iDepRecords;
delete iNeededDllNames;
}
TBool ELFFile::ELFDllData::Init()
{
// process imported symbols
// There will be at least one relocation (assumed to be Elf32_Rel) for each such symbol.
// S iterate over relocations looking for DLL symbols and add them to the record of
// of import info.
TInt nrelocs = iRelSz/iRelEnt;
TInt SrcSegIdx = -1;
TInt errors = 0;
for (TInt idx = 0; idx < nrelocs; idx++)
{
Elf32_Rel * rel = &iRel[idx];
TUint relType = ELF32_R_TYPE(rel->r_info);
if (relType == R_ARM_ABS32)
{
TInt symIdx = ELF32_R_SYM(rel->r_info);
Elf32_Sym * sym = &iDynSymTab[symIdx];
DllSymbol * dllSym = DllSymbolP(sym);
if (dllSym)
{
dllSym->iRel = rel;
dllSym->iSegment = iElfFile->GetSegment(SrcSegIdx);
if (!AddSymbol(dllSym)) return EFalse;
}
else errors++;
}
else if (relType == R_ARM_RABS32)
{
iNumberOfRelocs++;
if (iElfFile->CodeSegmentP(SrcSegIdx)) iNumberOfCodeRelocs++;
else iNumberOfDataRelocs++;
}
else if (relType == R_ARM_RBASE)
{
SrcSegIdx = ELF32_R_SYM(rel->r_info);
if (SrcSegIdx) SrcSegIdx--;
}
else
{
// Gives error with all other Relocation types..
TInt symIdx = ELF32_R_SYM(rel->r_info);
Elf32_Sym * s = &iDynSymTab[symIdx];
char * symName = ELFADDR(char,iDynStrTab,s->st_name);
Print(EPeError, "Unresolved symbol: %s\n", symName);
errors++;
}
}
// Set up export info
if (InitExportInfo())
{
TText * sym = (TText *)"_E32Startup";
// If _E32Startup is defined then this is not a DLL
iImageIsDll = !iElfFile->SymbolPresent(sym);
}
if (errors > 0) return EFalse;
return ETrue;
}
TBool ELFFile::ELFDllData::ParseDllSymbol(Elf32_Sym * s, char *& dll, TUint& len, TInt& ord)
{
char * sym = ELFADDR(char,iDynStrTab,s->st_name);
if (!strncmp(sym, DLLSYMPREFIX, strlen(DLLSYMPREFIX)))
{
dll = sym + strlen(DLLSYMPREFIX);
TUint lim = strlen(dll);
TUint index = strcspn(dll, DLLSYMPREFIX0);
if ((index + strlen(DLLSYMSUFFIX)) < lim)
{
len = index;
char * dllSuffix = dll+index;
char * match = DLLSYMSUFFIX;
int suflen = strlen(DLLSYMSUFFIX);
if (!strncmp(dllSuffix, match, suflen))
{
char * ordString = dll+index+suflen;
char * final;
TUint X = strtoul(ordString, &final, ORDBASE);
if (ordString != final)
{
ord = (TInt)X;
return ETrue;
}
}
}
}
dll = 0;
len = 0;
ord = -1;
return EFalse;
}
ELFFile::ELFDllData::DllSymbol * ELFFile::ELFDllData::DllSymbolP(Elf32_Sym * s)
{
char * dllName;
TUint nameLen;
TInt symOrd;
if (ParseDllSymbol(s, dllName, nameLen, symOrd))
{
DllSymbol * ds = new DllSymbol(dllName, nameLen, symOrd);
if (ds) return ds;
Print(EPeError, "Out of memory.\n");
return NULL;
}
// If we get here its not a valid 'dll symbol' and so it is an unresolved symbol
char * sym = ELFADDR(char,iDynStrTab,s->st_name);
Print(EPeError, "Unresolved symbol: %s\n", sym);
return NULL;
}
TBool ELFFile::ELFDllData::AddSymbol(ELFFile::ELFDllData::DllSymbol * s)
{
DllRec * aDll = NULL;
for (DllRec * r = iDllHead; r != NULL; r = r->iNext)
{
if (!strncmp(s->iDll, r->iName, s->iLen))
{
aDll = r;
break;
}
}
if (aDll)
{
iNumberOfImports++;
aDll->AddSymbol(s);
return ETrue;
}
else
{
aDll = new DllRec(s->iDll, s->iLen, s);
if (aDll)
{
if (!iDllHead)
{
iDllHead = iDllTail = aDll;
}
else
{
iDllTail->iNext = aDll;
iDllTail = aDll;
}
iStringTableSize += (s->iLen + 1);
iNumberOfImportDlls++;
iNumberOfImports++;
return ETrue;
}
else
{
Print(EPeError, "Out of memory.\n");
return EFalse;
}
}
}
void ELFFile::ELFDllData::DllRec::AddSymbol(ELFFile::ELFDllData::DllSymbol * s)
{
nImports++;
iTail->iNext = s;
iTail = s;
}
static unsigned long elf_hash(const unsigned char *name)
{
unsigned long h, g;
for (h = 0; *name != 0; ++name)
{
h = (h << 4) + *name;
g = h & 0xf0000000;
if (g != 0) h ^= g >> 24;
h &= ~g;
}
return h;
}
Elf32_Word ELFFile::ELFDllData::FindSymbolIndex(TText * s)
{
TUint h = elf_hash(s);
TUint nb = iHashTable[0].nBuckets;
TUint probe = h%nb;
Elf32_Sword * bucket = ELFADDR(Elf32_Sword, iHashTable, sizeof(Elf32_HashTable));
Elf32_Sword * chain = ELFADDR(Elf32_Sword, bucket, nb * sizeof(Elf32_Sword));
Elf32_Sword idx = bucket[probe];
do
{
if (!strcmp(ELFADDR(char, iDynStrTab, iDynSymTab[idx].st_name), (char *)s)) return idx;
idx = chain[idx];
} while (idx > 0);
if (idx == 0) idx = -1;
return idx;
}
TBool ELFFile::ELFDllData::InitExportInfo()
{
memset(&iSymInfoHdr, 0, sizeof(iSymInfoHdr));
TText * exp = (TText *)EXPORTTABLENAME;
if ( int(iExportTableSymIdx = FindSymbolIndex(exp)) != -1 )
{
TText * exps = (TText *)EXPORTTABLESIZENAME;
iExportTableSizeSymIdx = FindSymbolIndex(exps);
//TUint offset = iDynSymTab[iExportTableSizeSymIdx].st_value - (TUint)code;
Elf32_Word * pNumberOfExports = iElfFile->CodePtrFromAddr(iDynSymTab[iExportTableSizeSymIdx].st_value);
iNumberOfExports = * pNumberOfExports;
iImageIsDll = ETrue;
return ETrue;
}
else iImageIsDll = EFalse;
return EFalse;
}
TInt ELFFile::ELFDllData::NumberOfImports(void)
{
return iNumberOfImports;
}
TInt ELFFile::ELFDllData::NumberOfExports(void)
{
return iNumberOfExports;
}
TInt ELFFile::ELFDllData::NumberOfImportDlls(void)
{
return iNumberOfImportDlls;
}
TInt ELFFile::ELFDllData::NumberOfRelocs()
{
return iNumberOfRelocs;
}
char * ELFFile::ELFDllData::CreateImportSection(TInt &aSize)
{
if (!iNumberOfImports)
{
aSize = 0;
return 0;
}
TInt byteSize = sizeof(E32ImportSection) +
(sizeof(E32ImportBlock) * iNumberOfImportDlls) +
(sizeof(TUint) * iNumberOfImports) +
iStringTableSize;
if(iNamedLookupEnabled)
{
// 0th ordinal of each DLL imported from.
byteSize += (sizeof(TUint) * iNumberOfImportDlls);
}
char * newSection = new char[byteSize];
if (!newSection)
{
Print(EPeError, "Failed to allocate new import section.\n");
aSize = 0;
return 0;
}
((E32ImportSection *)newSection)->iSize = byteSize;
// used to point to current ImportBlock
E32ImportBlock * bp = ELFADDR(E32ImportBlock, newSection, sizeof(E32ImportSection));
// used to point to current import relocation entry
TUint * rp;
// used to point to current location in string table
char * sp = ELFADDR(char, newSection, (byteSize - iStringTableSize));
OrdZeroRecord *aDep = iDepRecords;
for (DllRec * dll = iDllHead; dll != NULL ; dll = dll->iNext, bp = (E32ImportBlock *)rp )
{
// set up the offset from E32ImportBlock.iOffsetOfDllName to the
// corresponding string table location
bp->iOffsetOfDllName = (sp - (char *)newSection);
bp->iNumberOfImports = dll->nImports;
if(iNamedLookupEnabled)
{
bp->iNumberOfImports++;
}
// copy the DLL name to the string table
memcpy(sp , dll->iName, dll->iLen);
sp[dll->iLen] = 0;
sp = sp + dll->iLen + 1;
// sort out the import 'relocs'
rp = ELFADDR(TUint, bp, sizeof(E32ImportBlock));
for (DllSymbol * sym = dll->iHead; sym != NULL; sym = sym->iNext, rp++)
{
Elf32_Phdr * segment = sym->iSegment;
Elf32_Addr segBase = segment->p_vaddr;
// sanity check: segment should be the code segment
if (!iElfFile->CodeSegmentP(segment))
{
Print(EPeError, "Import relocation does not refer to code segment.\n");
aSize = 0;
return 0;
}
// This field is misnamed because it is actually given as a virtual address in
// dynamic relocations
Elf32_Addr dynOffset = sym->iRel->r_offset;
//So this is the 'real' offset of the reloc in the segment in which it occurs
Elf32_Addr segOffset = dynOffset - segBase;
TUint * relocAddr = ELFADDR(TUint, iElfFile->ELFFileBase(), (segment->p_offset + segOffset));
// The only non-zero reloc vals we expect are for vtables.
// We store there reloc offset in the top 16 bits of the 'reloc info'.
// NB the ELF reloc values should only ever be multiples of 4. So we could optimize here,
// but we won't.
TUint relocVal = *relocAddr;
TUint importOrdinal = sym->iOrd;
if (relocVal > 0xFFFF)
Print(EPeError, "ELF relocation exceeds E32Image limit of 64K.\n");
if (importOrdinal > 0xFFFF)
Print(EPeError, "Import ordinal exceeds E32Image limit of 64K.\n");
*rp = segOffset;
// eek !! surgery on the code segment....
*relocAddr = (relocVal<<16) | importOrdinal;
}
if(iNamedLookupEnabled)
{
aDep = FindDependency(dll->iName, dll->iLen);
if( aDep )
{
*rp = aDep->iOffset;
rp++;
}
}
}
aSize = byteSize;
return newSection;
}
TUint ELFFile::ELFDllData::GetExportTableOffset(void)
{
Elf32_Sym * et = &iDynSymTab[iExportTableSymIdx];
Elf32_Phdr * segment = iElfFile->GetSegment(et->st_shndx - 1);
return et->st_value - segment->p_vaddr;
}
TBool ELFFile::ELFDllData::GetRelocs(Elf32_Rel **aCodeRelocs, Elf32_Rel **aDataRelocs)
//
// load the relocs from the reloc section into relocation and relocsection arrays
//
{
TInt nrelocs = iRelSz/iRelEnt;
TInt SrcSegIdx = -1;
TInt cidx = 0;
TInt didx = 0;
for (TInt idx = 0; idx < nrelocs; idx++)
{
Elf32_Rel * rel = &iRel[idx];
if (ELF32_R_TYPE(rel->r_info) == R_ARM_RABS32)
{
if (iElfFile->CodeSegmentP(SrcSegIdx))
aCodeRelocs[cidx++]=rel;
else if (iElfFile->DataSegmentP(SrcSegIdx))
aDataRelocs[didx++]=rel;
}
else if (ELF32_R_TYPE(rel->r_info) == R_ARM_RBASE)
{
SrcSegIdx = ELF32_R_SYM(rel->r_info);
if (!(iElfFile->CodeSegmentP(SrcSegIdx-1) || iElfFile->DataSegmentP(SrcSegIdx-1)))
{
Print(EPeError, "Source segment for relocations is neither Code or Data.\n");
return EFalse;
}
SrcSegIdx--;
}
}
if(!iNamedLookupEnabled)
return ETrue;
// Add the 0th ordinal of this binary - The relocation info is already setup.
aCodeRelocs[cidx++] = &iOrdZeroRec->iReloc;
// add relocation entries for each of the symbols
NamedExportSymbol *aSym = iNamedExportSymbolHead;
while(aSym)
{
// The symbol name info is part of the code section hence all relocations
// are collected as part of Code relocations.
aCodeRelocs[cidx++] = &aSym->iReloc;
aSym = aSym->Next();
}
// Since we have added a few relocations, lets make sure
// they are still sorted on addresses they refer to.
//Sorting the code relocs
TInt aIdx1, aIdx2;
Elf32_Rel *aTmp;
for (aIdx1 = 0; aIdx1 < cidx; aIdx1++) {
for (aIdx2 = aIdx1; aIdx2 < cidx; aIdx2++) {
if(aCodeRelocs[aIdx1]->r_offset > aCodeRelocs[aIdx2]->r_offset) {
aTmp = aCodeRelocs[aIdx2];
aCodeRelocs[aIdx2] = aCodeRelocs[aIdx1];
aCodeRelocs[aIdx1] = aTmp;
}
}
}
//Sorting the data relocs
for (aIdx1 = 0; aIdx1 < didx; aIdx1++) {
for (aIdx2 = aIdx1; aIdx2 < didx; aIdx2++) {
if(aDataRelocs[aIdx1]->r_offset > aDataRelocs[aIdx2]->r_offset) {
aTmp = aDataRelocs[aIdx2];
aDataRelocs[aIdx2] = aDataRelocs[aIdx1];
aDataRelocs[aIdx1] = aTmp;
}
}
}
return ETrue;
}
NamedExportSymbol::NamedExportSymbol(char* aName, Elf32_Addr aValue) : \
iSymbolName(aName), iValue(aValue), iNext(NULL)
{
}
TBool ELFFile::ELFDllData::CreateSymLookupTable()
{
if( !SetupSymbolValues() )
return FALSE;
if( !SetupSymbolNames() )
return FALSE;
return TRUE;
}
TBool ELFFile::ELFDllData::SetupSymbolValues()
{
NamedExportSymbol *aSym, *aPrevSym;
if( int(iExportTableSymIdx) == -1 || int(iExportTableSizeSymIdx) == -1)
return FALSE;
// Fetch the 'export table' symbol from the dynamic symbol table.
Elf32_Sym *aElfExpTbl = &iDynSymTab[iExportTableSymIdx];
// Fetch the 'export table size' symbol from the dynamic symbol table.
Elf32_Sym *aElfExpTblSz = &iDynSymTab[iExportTableSizeSymIdx];
if((aElfExpTbl->st_value - aElfExpTblSz->st_value) != 4)
{
// Check that the word prior to the export table is not the export table size
// This is to make sure that there is space for the 0th ordinal and
// we dont overwrite the 'export table size' entry.
iNamedLookupEnabled = 1;
}
else
return FALSE;
// Fetch the export table contents
Elf32_Word * aExpEntries = iElfFile->CodePtrFromAddr(aElfExpTbl->st_value);
if(!aExpEntries)
return FALSE;
aSym = aPrevSym = NULL;
TInt idx;
// Create symbols corresponding to export table entries.
for(idx = 0; idx < iNumberOfExports; idx++)
{
//Symbols marked Absent are ignored.
if( aExpEntries[idx] == iElfFile->iEntryPoint)
continue;
aSym = new NamedExportSymbol(0, aExpEntries[idx]);
iNamedExportCount++;
if(aPrevSym)
{
aPrevSym->Next(aSym);
}
else
{
iNamedExportSymbolHead = aSym;
}
aPrevSym = aSym;
}
return TRUE;
}
TBool ELFFile::ELFDllData::SetupSymbolNames()
{
char *aSymName = NULL;
NamedExportSymbol *aSym;
TUint aDynSymbolTblCount = iHashTable->nChains;
TInt aCount = 0;
TInt aCodeSegIdx = iElfFile->CodeSegmentIndex() + 1;
TInt aDataSegIdx = iElfFile->DataSegmentIndex() + 1;
// Traverse the dynamic symbol table
for(TUint idx = 0; idx < aDynSymbolTblCount; idx++)
{
//Consider only the the defined symbols
if( ELF32_ST_TYPE(iDynSymTab[idx].st_info) == STT_OBJECT ||
ELF32_ST_TYPE(iDynSymTab[idx].st_info) == STT_FUNC )
{
aSym = iNamedExportSymbolHead;
while(aSym)
{
// Name already set
if(aSym->Name())
{
aSym = aSym->Next();
continue;
}
Elf32_Addr aAddr = aSym->Value();
// If the exported symbol and the dynamic symbol table entry have the
// same values, setup the name
if(iDynSymTab[idx].st_value == aAddr)
{
aSymName = ELFADDR(char, iDynStrTab, iDynSymTab[idx].st_name);
aSym->Name(aSymName);
if(iElfFile->CodeSegmentP (iElfFile->GetSegmentFromAddr(aAddr)) ) {
aSym->iReloc.r_info = aCodeSegIdx << 8 | R_ARM_RABS32;
aSym->iSymRelocType = KTextRelocType;
}
else {
aSym->iReloc.r_info = aDataSegIdx << 8 | R_ARM_RABS32;
aSym->iSymRelocType = KDataRelocType;
}
iNumberOfCodeRelocs++;
iNumberOfRelocs++;
// The offset to the name is always 4 byte aligned.
iStringNameOffset = iSymStringTableSize >> 2;
aSym->NameOffset( iSymStringTableSize );
// These are NULL-terminated strings
iSymStringTableSize += (strlen(aSymName) + 1);
iSymStringTableSize = ALIGN4(iSymStringTableSize);
aCount++;
break;
}
aSym = aSym->Next();
}
}
}
if(aCount != iNamedExportCount)
return FALSE;
// Sort symbols on their names...
if(iNamedExportCount > 1)
{
NamedExportSymbol **aTmpStart = &iNamedExportSymbolHead;
Sort(aTmpStart, iNamedExportSymbolHead);
}
return TRUE;
}
void ELFFile::ELFDllData::SetLookupTblBase(TInt aBaseOffset)
{
Elf32_Addr aBaseAddr = iElfFile->iLinkedBase + iElfFile->GetCodeSize();
Elf32_Addr aAddr;
// setup relocations of each of the exported symbols.
aAddr = aBaseAddr + iSymInfoHdr.iSymbolTblOffset;
NamedExportSymbol *aSym = iNamedExportSymbolHead;
while(aSym)
{
aSym->iReloc.r_offset = aAddr;
aAddr += sizeof(Elf32_Addr);
aSym = aSym->Next();
}
// setup relocations for the 0th ordinal of this binary.
iOrdZeroRec = new OrdZeroRecord(0);
Elf32_Sym * et = &iDynSymTab[iExportTableSymIdx];
iOrdZeroRec->iReloc.r_offset = et->st_value - 4; // The word prior ro the first entry
// of the export table is the 0th ordinal entry.
//At the 0th ordinal, write the address of the start of symbol info
TUint32 aZeroOrdOff = et->st_value - 4 - iElfFile->iLinkedBase;
aZeroOrdOff += (iElfFile->GetSegment(et->st_shndx - 1))->p_offset;
TUint32 *aZeroOrdLocation = ELFADDR(TUint32, iElfFile->ELFFileBase(), aZeroOrdOff);
*aZeroOrdLocation = aBaseAddr;
iOrdZeroRec->iReloc.r_info = ELF32_R_INFO(et->st_shndx, R_ARM_RABS32);
iNumberOfCodeRelocs++;
iNumberOfRelocs++;
TInt aOffset = aBaseOffset + iSymInfoHdr.iDepDllZeroOrdTableOffset;
OrdZeroRecord *aDepRecord = iDepRecords;
while( aDepRecord )
{
// Setup the offset - This offset (relative code segment) is filled in the
// import table to point to this dependency record.
aDepRecord->iOffset = aOffset;
aOffset += 4;
aDepRecord = aDepRecord->iNext;
}
}
TBool ELFFile::ELFDllData::AddToDependency(TUint aOff)
{
// Add the name found in DT_NEEDED into a list.
// The dynamic string table might not have been found in dynamic table yet.
// So store the offset (wrt base of dynamic string table) for now.
NeededDLLsList *aNeeded = new NeededDLLsList(aOff);
if(!aNeeded)
return FALSE;
if ( iNeededDllNames ) {
iNeededDllNamesTail->iNext= aNeeded;
iNeededDllNamesTail = aNeeded;
}
else {
iNeededDllNames = iNeededDllNamesTail = aNeeded;
}
return TRUE;
}
TBool ELFFile::ELFDllData::CreateDependency()
{
OrdZeroRecord *aDep;
NeededDLLsList *aNeeded = iNeededDllNames;
char *aDllName = NULL;
DllRec *aRec;
TInt aNeededFound;
for(aNeededFound = 0; (aNeededFound < iNumberOfImportDlls) && aNeeded;)
{
aRec = 0;
while(aNeeded) {
aDllName = iDynStrTab + aNeeded->iOffset;
// aNeeded is just a guess that this binary might be dependent on aDllName
// Search through the import table to find if the guess was correct.
aRec = SearchImports(aDllName);
if(aRec && FindDependency(aRec->iName, aRec->iLen) == NULL) {
// Check if aDllName is listed in import table and it
// not added already in the depedency records.
aNeededFound++;
break;
}
// Bad guess...go to the next aNeeded
aNeeded = aNeeded->iNext;
}
if( !aRec )
return FALSE;
aDep = new OrdZeroRecord(aDllName);
if(!iDepRecords)
{
iDepRecords = iDepRecordsTail = aDep;
}
else
{
iDepRecordsTail->iNext = aDep;
iDepRecordsTail = aDep;
}
aNeeded = aNeeded->iNext;
}
return (aNeededFound == iNumberOfImportDlls);
}
ELFFile::ELFDllData::DllRec* ELFFile::ELFDllData::SearchImports(char *aName)
{
DllRec *aRec = iDllHead;
while (aRec)
{
if(strncmp(aRec->iName, aName, aRec->iLen) == 0)
return aRec;
aRec = aRec->iNext;
}
return NULL;
}
OrdZeroRecord* ELFFile::ELFDllData::FindDependency(char* aName, TUint aLen)
{
OrdZeroRecord* aDep = iDepRecords;
while(aDep)
{
if(strncmp(aName, aDep->iName, aLen) == 0)
return aDep;
aDep = aDep->iNext;
}
return NULL;
}
void ELFFile::ELFDllData::GetExportSymInfoHeader(E32EpocExpSymInfoHdr& aSymInfoHdr)
{
memcpy(&aSymInfoHdr, &iSymInfoHdr, sizeof(E32EpocExpSymInfoHdr));
}
void ELFFile::ELFDllData::SetExportSymInfo()
{
iSymInfoHdr.iSymCount = (TUint16)iNamedExportCount;
iSymInfoHdr.iSymbolTblOffset = sizeof(E32EpocExpSymInfoHdr);
iSymInfoHdr.iStringTableSz = iSymStringTableSize;
TInt aSymTabSz;
if( iStringNameOffset > 0xffff){
iSymInfoHdr.iFlags = KNameLookupOffsetFlag32; // Flag indicating 32 bit offsets
// for symbol names
aSymTabSz = iNamedExportCount* sizeof(TUint32);// symbol addresses
aSymTabSz += iNamedExportCount* sizeof(TUint32);// symbol name 32-bit offsets
}
else
{
iSymInfoHdr.iFlags &= ~KNameLookupOffsetFlag32;// Flag indicating 16-bit offsets
// for symbol names
aSymTabSz = iNamedExportCount* sizeof(TUint32); // symbol addresses
aSymTabSz += iNamedExportCount* sizeof(TUint16);// symbol name 16-bit offsets
aSymTabSz = ALIGN4(aSymTabSz);
}
iSymInfoHdr.iStringTableOffset = iSymInfoHdr.iSymbolTblOffset + aSymTabSz;
iSymInfoHdr.iDllCount = iNumberOfImportDlls;
iSymInfoHdr.iDepDllZeroOrdTableOffset = iSymInfoHdr.iStringTableOffset + \
iSymInfoHdr.iStringTableSz;
iSymInfoHdr.iSize = iSymInfoHdr.iDepDllZeroOrdTableOffset + \
iSymInfoHdr.iDllCount * sizeof(Elf32_Addr);
}
TUint ELFFile::ELFDllData::GetSymLookupSection(char* aBuff)
{
if( !iNamedLookupEnabled)
return 0;
memcpy(aBuff, &iSymInfoHdr, sizeof(iSymInfoHdr));
// Name offsets start after the end of symbol addresses.
TUint32 aNameOffsetStart = iSymInfoHdr.iSymbolTblOffset + \
iNamedExportCount* sizeof(TUint32);
TUint32 *aAddrPtr = (TUint32*)(aBuff + iSymInfoHdr.iSymbolTblOffset);
TUint32 aStringTabOff = 0;
char *aStringTab = aBuff + iSymInfoHdr.iStringTableOffset;//Start of the string table.
NamedExportSymbol *aSym = iNamedExportSymbolHead;
while(aSym)
{
*aAddrPtr = aSym->Value();
aStringTabOff = aSym->NameOffset(); // Get the offset of symbol name (which is wrt
// string table base).
if( iSymInfoHdr.iFlags & KNameLookupOffsetFlag32 )
{
TUint32 *aNameOffPtr = (TUint32*)(aBuff + aNameOffsetStart);
*aNameOffPtr = (aStringTabOff >> 2);//write the offset of the name
strcpy(aStringTab + aStringTabOff, aSym->Name());//write the symbol name
aNameOffsetStart +=4;
}
else
{
TUint16 *aNameOffPtr = (TUint16*)(aBuff + aNameOffsetStart);
*aNameOffPtr = (TUint16)(aStringTabOff >> 2);//write the offset of the name
strcpy(aStringTab + aStringTabOff, aSym->Name());//write the symbol name
aNameOffsetStart +=2;
}
aAddrPtr++;
aSym = aSym->Next();
}
OrdZeroRecord *aRec = iDepRecords;
TUint32* aDepsTable = (TUint32*)(aBuff + iSymInfoHdr.iDepDllZeroOrdTableOffset);
while(aRec)
{
*aDepsTable++ = 0;
aRec = aRec->iNext;
}
return iSymInfoHdr.iSize;
}
void ELFFile::ELFDllData::Sort(NamedExportSymbol** aDstList, NamedExportSymbol* aSrcList)
{
NamedExportSymbol *aSym = aSrcList;
NamedExportSymbol **aSymbols = new NamedExportSymbol*[iNamedExportCount];
TInt pos;
for (pos = 0; pos < iNamedExportCount; pos++) {
aSymbols[pos] = aSym;
aSym = aSym->Next();
}
NamedExportSymbol **aResult = new NamedExportSymbol*[iNamedExportCount];
MergeSort(aResult, aSymbols);
iNamedExportSymbolHead = aResult[0];
for (pos = 0; pos < iNamedExportCount; pos++) {
aSym = aResult[pos];
if( pos == iNamedExportCount-1)
aSym->Next(NULL);
else
aSym->Next(aResult[pos+1]);
}
*aDstList = aResult[0];
delete [] aResult;
delete [] aSymbols;
}
void ELFFile::ELFDllData::MergeSort(NamedExportSymbol** aDstList, NamedExportSymbol** aSrcList)
{
MergeSort(aDstList, aSrcList, 0, iNamedExportCount);
}
void ELFFile::ELFDllData::MergeSort(NamedExportSymbol** aDstList, NamedExportSymbol** aSrcList, \
TUint aLeft, TUint aRight)
{
if( (aRight - aLeft) <= 1)
return;
TUint aSize = aRight - aLeft;
TUint aCenter = aLeft + aSize/2;
MergeSort(aDstList, aSrcList, aLeft, aCenter);
MergeSort(aDstList, aSrcList, aCenter, aRight);
TUint aLPos, aRPos, aCnt;
aLPos = aLeft;
aRPos = aCenter;
for(aCnt = 0; aCnt < aSize; aCnt++)
{
if( (aLPos < aCenter) &&
(aRPos == aRight || (strcmp(aSrcList[aLPos]->Name(), aSrcList[aRPos]->Name()) < 0) )
)
{
// Compare the left half with the right and add the lesser one.
// The comparision is done on the topmost element on each half.
// if aRPos is past the last element of the right half, the left element has
// nothing to compare with. Just add it to the result list.
aDstList[aCnt] = aSrcList[aLPos];
aLPos++;
}
else
{
// Add the greater one into the list.
// if aLPos is past the element at the center, it anyway belongs to the
// right half. Add it to the result list.
aDstList[aCnt] = aSrcList[aRPos];
aRPos++;
}
}
// Once the sublist is sorted, put it back to the source list
// so that the parent has its left and right sublists are sorted.
for(aCnt = 0; aCnt < aSize; aCnt++)
{
aSrcList[aLeft+aCnt] = aDstList[aCnt];
}
}