diff -r c7c26511138f -r 360bd6b35136 bintools/elftools/elftran/elf_dlld.cpp --- a/bintools/elftools/elftran/elf_dlld.cpp Wed Jun 16 16:51:40 2010 +0300 +++ b/bintools/elftools/elftran/elf_dlld.cpp Wed Jun 23 16:56:47 2010 +0800 @@ -1,954 +1,928 @@ -/* -* 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 -#include -#include -#include -#include "elfdll.h" -#include "elffile.h" -#include -#include - -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]; - } -} - +/* +* 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 +#include +#include +#include "elfdefs.h" +#include "elfdll.h" +#include "elffile.h" +#include "h_utl.h" +#include + +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()) + { + // If _E32Startup is defined then this is not a DLL + iImageIsDll = !iElfFile->SymbolPresent("_E32Startup"); + } + 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(const char* s) + { + TUint h = elf_hash((const unsigned char*)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), 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)); + if ((iExportTableSymIdx = FindSymbolIndex(EXPORTTABLENAME)) != (Elf32_Word)-1) + { + iExportTableSizeSymIdx = FindSymbolIndex(EXPORTTABLESIZENAME); + //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"); + Print(EPeError, "Dll: %s\n", sym->iDll); + Print(EPeError, "Ordinal: %d\n", sym->iOrd); + Print(EPeError, "DLL name: %s\n", dll->iName); + 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"); + Print(EPeError, "Dll: %s\n", sym->iDll); + Print(EPeError, "Ordinal: %d\n", sym->iOrd); + Print(EPeError, "DLL name: %s\n", dll->iName); + } + if (importOrdinal > 0xFFFF) { + Print(EPeError, "Import ordinal exceeds E32Image limit of 64K.\n"); + Print(EPeError, "Dll: %s\n", sym->iDll); + Print(EPeError, "Ordinal: %d\n", sym->iOrd); + Print(EPeError, "DLL name: %s\n", dll->iName); + } + *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 idx = 0; + TInt cidx = 0; + TInt didx = 0; + + for (idx = 0, cidx = 0, didx = 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( iExportTableSymIdx == (Elf32_Word)-1 || iExportTableSizeSymIdx == (Elf32_Word)-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]; + } +} +