bintools/elftools/elftran/elf_dlld.cpp
author raptorbot <raptorbot@systemstesthead.symbian.intra>
Fri, 18 Dec 2009 19:57:42 +0000
branchwip
changeset 117 ecf683438dc6
parent 0 044383f39525
child 590 360bd6b35136
permissions -rw-r--r--
Don't mess around with EPOCROOT until actually entering raptor so we know what the original was Put the original epocroot back on the front of the whatcomp output. This allows what output to be either relative or absolute depending on what your epocroot is.

/*
* 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];
	}
}