--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/bintools/elftools/elftran/elf_file.cpp Tue Oct 27 16:36:35 2009 +0000
@@ -0,0 +1,540 @@
+/*
+* 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 <e32def.h>
+#include <e32std.h>
+#include "elftran.h"
+#include <elfdefs.h>
+#include "elffile.h"
+#include "elfdll.h"
+#include <h_utl.h>
+#include <string.h>
+#include <stdlib.h>
+
+TBool hadText, hadReloc = EFalse;
+
+ELFFile::ELFFile()
+ :
+ iHeapCommittedSize(0x1000),
+ iHeapReservedSize(0x100000),
+ iStackCommittedSize(0),
+
+ iFileName(0),
+ iFileHandle(-1),
+ iElfFile(0),
+
+ iDynamicSegmentHdr(0),
+ iDynamicSegmentIdx(0),
+
+ iCodeSegmentHdr(0),
+ iCodeSegmentIdx(0),
+
+ iDataSegmentHdr(0),
+ iDataSegmentIdx(0),
+
+ iDllData(0),
+ iCpu(ECpuUnknown)
+ {}
+
+
+
+
+ELFFile::~ELFFile()
+ {
+ delete [] iFileName;
+ delete iElfFile;
+ delete iDllData;
+ }
+
+
+TBool ELFFile::Init(const TText * const aFileName)
+//
+// Read the ELF file into memory
+//
+ {
+
+ delete [] iFileName;
+ iFileName = new TText[strlen((const char *)aFileName)+1];
+ strcpy ((char *)iFileName, (const char *)aFileName);
+
+ TInt error = HFile::Open(iFileName, &iFileHandle);
+ if (error!=0)
+ return EFalse;
+
+ TInt flength = HFile::GetLength(iFileHandle);
+
+ iElfFile = (Elf32_Ehdr *)HMem::Alloc(0,flength);
+ if (!iElfFile)
+ {
+ Print(EPeError,"Failed to allocate memory to read in file.\n");
+ Close();
+ return EFalse;
+ }
+
+ if (!HFile::Read(iFileHandle,iElfFile,flength))
+ {
+ Print(EPeError,"Unable to read file %s.\n",iFileName);
+ Close();
+ return EFalse;
+ }
+
+ Close();
+
+ if (!IsValidFileHeader(iElfFile))
+ {
+ Print(EPeError,"Invalid file header.\n");
+ return EFalse;
+ }
+ // we only support this....for the moment
+ iCpu = ECpuArmV4;
+
+ if (!InitHeaders()) return EFalse;
+
+ if (!InitDllData()) return EFalse;
+
+ iEntryPoint = iElfFile->e_entry;
+
+ iCodeSize = GetCodeSize();
+ iDataSize = GetDataSize();
+ iBssSize = GetBssSize();
+
+ iStackReservedSize = 0x2000;
+ iStackCommittedSize = 0x2000;
+
+ iLinkedBase = iCodeSegmentHdr->p_vaddr;
+
+ iImageIsDll = iDllData->ImageIsDll();
+
+ return ETrue;
+ }
+
+char * ELFFile::CreateImportSection(TInt &aSize)
+//
+// get ELFDLLData to do it
+//
+ {
+ TInt size;
+ char * newSection = iDllData->CreateImportSection(size);
+ aSize = size;
+ return newSection;
+ }
+
+TUint ELFFile::GetExportTableOffset(void)
+ {
+ return iDllData->GetExportTableOffset();
+ }
+
+TBool ELFFile::InitHeaders(void)
+ {
+ TInt nphdrs = iElfFile->e_phnum;
+ if (nphdrs)
+ {
+ // Find the dynamic segment
+ Elf32_Phdr * aPhdr = ELFADDR(Elf32_Phdr, iElfFile, iElfFile->e_phoff);
+ iPhdr = aPhdr;
+ for (TInt idx = 0; idx < nphdrs; idx++)
+ {
+ Elf32_Word ptype = aPhdr[idx].p_type;
+ if (ptype == PT_DYNAMIC)
+ {
+ iDynamicSegmentHdr = &aPhdr[idx];
+ iDynamicSegmentIdx = idx;
+ }
+ else if (ptype == PT_LOAD &&
+ (aPhdr[idx].p_flags & (PF_X + PF_ARM_ENTRY)))
+ {
+ iCodeSegmentHdr = &aPhdr[idx];
+ iCodeSegmentIdx = idx;
+ }
+ else if (ptype == PT_LOAD &&
+ (aPhdr[idx].p_flags & (PF_W + PF_R)))
+ {
+ iDataSegmentHdr = &aPhdr[idx];
+ iDataSegmentIdx = idx;
+ }
+ }
+ }
+
+ // cache pointer to symbol table
+
+ // Get section header table
+ Elf32_Shdr * s = ELFADDR(Elf32_Shdr, iElfFile, iElfFile->e_shoff);
+ // Index of section header for section header string table
+ TInt stIdx = iElfFile->e_shstrndx;
+ TInt symIdx = -1;
+ // Section name string table
+ char * stringtable = ELFADDR(char, iElfFile, s[stIdx].sh_offset);
+ // the index at which we find '.symtab' is the index of the symtab section
+ for (TInt idx = 0; idx < iElfFile->e_shnum; idx++)
+ {
+ if (idx != stIdx)
+ {
+ if (!strcmp(&stringtable[s[idx].sh_name], ".symtab"))
+ {
+ symIdx = idx;
+ break;
+ }
+ }
+ }
+ if (symIdx == -1) return EFalse;
+
+ // save section header table
+ iSectionHeaderTable = s;
+ // save the index
+ iSymIdx = symIdx;
+ // here's the symbol table
+ iSymTab = ELFADDR(Elf32_Sym, iElfFile, s[symIdx].sh_offset);
+ return ETrue;
+ }
+
+TBool ELFFile::InitDllData(void)
+ {
+ if (!iDynamicSegmentHdr)
+ {
+#if defined(_DEBUG)
+ Print(EWarning, "Image '%s' has no import/export data.\n", iFileName);
+#endif
+ return ETrue;
+ }
+ iDllData = new ELFDllData(this);
+ if (!iDllData)
+ {
+ Print(EPeError, "Out of memory allocating DLL data\n");
+ return EFalse;
+ }
+
+ Elf32_Dyn * dyn = ELFADDR(Elf32_Dyn, iElfFile, iDynamicSegmentHdr->p_offset);
+ TInt idx = 0;
+ TInt soNameOffset = 0;
+ while(dyn[idx].d_tag != DT_NULL) // best to make it explicit
+ {
+ switch (dyn[idx].d_tag)
+ {
+ case DT_HASH:
+ iDllData->iHashTable = ELFADDR(Elf32_HashTable, dyn, dyn[idx].d_val);
+ break;
+ case DT_STRTAB:
+ iDllData->iDynStrTab = ELFADDR(char, dyn, dyn[idx].d_val);
+ break;
+ case DT_SYMTAB:
+ iDllData->iDynSymTab = ELFADDR(Elf32_Sym, dyn, dyn[idx].d_val);
+ break;
+ case DT_RELA:
+ iDllData->iRela = ELFADDR(Elf32_Rela, dyn, dyn[idx].d_val);
+ break;
+ case DT_RELASZ:
+ iDllData->iRelaSz = dyn[idx].d_val;
+ break;
+ case DT_RELAENT:
+ iDllData->iRelaSz = dyn[idx].d_val;
+ break;
+ case DT_STRSZ:
+ iDllData->iDynStrTabSize = dyn[idx].d_val;
+ break;
+ case DT_ARM_SYMTABSZ_21: //For RVCT2.1
+ //iDllData->iDynSymTabSize = dyn[idx].d_val;
+ case DT_ARM_SYMTABSZ:
+ /* This is same as DT_ARM_SYMTABSZ_21, but for RVCT 2.2
+ * The tag value has been changed for RVC2.2 from RVCT2.1.
+ * We just ignore this. i.e., we get the symbol table size
+ * from the nchain field of the hash table as noted in section
+ * 3.2.2.2 of the BPABI.
+ */
+ break;
+ case DT_SYMENT:
+ iDllData->iSymSize = dyn[idx].d_val;
+ break;
+ case DT_SONAME:
+ soNameOffset = dyn[idx].d_val;
+ break;
+ case DT_REL:
+ iDllData->iRel = ELFADDR(Elf32_Rel, dyn, dyn[idx].d_val);
+ break;
+ case DT_RELSZ:
+ iDllData->iRelSz = dyn[idx].d_val;
+ break;
+ case DT_RELENT:
+ iDllData->iRelEnt = dyn[idx].d_val;
+ break;
+ case DT_NEEDED:
+ iDllData->AddToDependency(dyn[idx].d_val);
+ break;
+ case DT_PLTRELSZ:
+ case DT_PLTGOT:
+ case DT_INIT:
+ case DT_FINI:
+ case DT_RPATH:
+ case DT_SYMBOLIC:
+ case DT_PLTREL:
+ case DT_DEBUG:
+ case DT_TEXTREL:
+ case DT_JMPREL:
+ case DT_BIND_NOW:
+ break;
+ default:
+ Print(EPeError,"Unrecognized Dyn Array tag in image '%s'.\n", iFileName);
+ return EFalse;
+ }
+ idx++;
+ }
+ return iDllData->Init();
+ }
+
+
+void ELFFile::Close()
+//
+// close the ELF file
+//
+ {
+ HFile::Close(iFileHandle);
+ }
+
+
+
+TInt ELFFile::NumberOfImports() const
+//
+// Count the total number of imports for this image
+//
+ {
+ return iDllData->NumberOfImports();
+ }
+
+TInt ELFFile::NumberOfImportDlls() const
+//
+// Count the number of referenced Dlls
+//
+ {
+ return iDllData->NumberOfImportDlls();
+ }
+
+TInt ELFFile::NumberOfExports() const
+//
+// Count the number of exported symbols
+//
+ {
+ return iDllData->NumberOfExports();
+ }
+
+TInt ELFFile::NumberOfCodeRelocs()
+ {
+ return iDllData->NumberOfCodeRelocs();
+ }
+
+TInt ELFFile::NumberOfDataRelocs()
+ {
+ return iDllData->NumberOfDataRelocs();
+ }
+
+Elf32_Phdr * ELFFile::GetSegmentFromAddr(Elf32_Addr addr)
+ {
+ TInt nphdrs = iElfFile->e_phnum;
+ for (TInt idx = 0; idx < nphdrs; idx++)
+ {
+ // take advantage of unsignedness
+ if ((addr - iPhdr[idx].p_vaddr) < iPhdr[idx].p_memsz) return &iPhdr[idx];
+ }
+ return NULL;
+ }
+
+
+TInt ELFFile::NumberOfRelocs()
+ {
+ return iDllData->NumberOfRelocs();
+ }
+
+TUint16 ELFFile::GetRelocType(Elf32_Rel *aReloc)
+ {
+ // We work out the type by figuring out the segment of the reloc
+ TInt segmentIdx = ELF32_R_SYM(aReloc->r_info);
+
+ // check to see if its a reserved or special index.
+ if ((!segmentIdx) || ((segmentIdx >= SHN_LORESERVE) && (segmentIdx <= SHN_HIRESERVE)))
+ // up until now these have been treated as KInferredRelocType, so lets continue...
+ return KInferredRelocType;
+
+ // need to see if this section is executable or writable
+ if (iPhdr[segmentIdx-1].p_flags & PF_X)
+ return KTextRelocType;
+ if (iPhdr[segmentIdx-1].p_flags & PF_W)
+ return KDataRelocType;
+ // perhaps we should error here.
+ return KInferredRelocType;
+ }
+
+TBool ELFFile::GetRelocs(Elf32_Rel **aCodeRelocs, Elf32_Rel **aDataRelocs)
+ {
+ return iDllData->GetRelocs(aCodeRelocs, aDataRelocs);
+ }
+
+TUint ELFFile::GetCodeSize()
+ {
+ return iCodeSegmentHdr->p_filesz;
+ }
+
+TBool ELFFile::HasInitialisedData()
+ {
+ return iDataSegmentHdr != NULL && iDataSegmentHdr->p_filesz != 0;
+ }
+
+TUint ELFFile::GetDataSize()
+ {
+ return iDataSegmentHdr != NULL ? iDataSegmentHdr->p_filesz : 0;
+ }
+
+TBool ELFFile::HasBssData()
+ {
+ return iDataSegmentHdr != NULL && (iDataSegmentHdr->p_memsz - iDataSegmentHdr->p_filesz) != 0;
+ }
+
+TUint ELFFile::GetBssSize()
+ {
+ return iDataSegmentHdr != NULL ? iDataSegmentHdr->p_memsz - iDataSegmentHdr->p_filesz: 0;
+ }
+
+
+
+
+
+
+TBool ELFFile::IsValidFileHeader(Elf32_Ehdr * iElfFile)
+ {
+ if (!(iElfFile->e_ident[EI_MAG0] == ELFMAG0 &&
+ iElfFile->e_ident[EI_MAG1] == ELFMAG1 &&
+ iElfFile->e_ident[EI_MAG2] == ELFMAG2 &&
+ iElfFile->e_ident[EI_MAG3] == ELFMAG3))
+ {
+ Print(EPeError,"Invalid ELF magic.\n");
+ return EFalse;
+ }
+
+ if (iElfFile->e_ident[EI_CLASS] != ELFCLASS32)
+ {
+ Print(EPeError,"File is not a 32 bit object file.\n");
+ return EFalse;
+ }
+ if (iElfFile->e_ident[EI_DATA] != ELFDATA2LSB)
+ {
+ Print(EPeError,"File data encoding is not Little Endian.\n");
+ return EFalse;
+ }
+
+ if (iElfFile->e_machine != EM_ARM)
+ {
+ Print(EPeError,"File does not target ARM/THUMB processors.\n");
+ return EFalse;
+ }
+
+ if (!(iElfFile->e_type == ET_EXEC || iElfFile->e_type == ET_DYN))
+ {
+ Print(EPeError,"File is neither an executable nor a shared object\n");
+ return EFalse;
+ }
+
+ return ETrue;
+ }
+
+
+// Get details of the next import to fix-up in the current file. Fill in the name of the dll
+//it is imported from, the ordinal number and the address to write back to.
+#define ORDINAL_DONE 0x40000000
+
+
+// The following static functions are passed an array of PE files to operate on
+
+Elf32_Sym * ELFFile::FindSymbol(const TText *aName)
+ {
+ Elf32_Shdr * s = ELFADDR(Elf32_Shdr, iElfFile, iElfFile->e_shoff);
+ TInt symIdx = iSymIdx;
+ Elf32_Sym * sym = iSymTab;
+ TInt nSyms = s[symIdx].sh_size / s[symIdx].sh_entsize;
+ char * symStringtable = ELFADDR(char, iElfFile, s[s[symIdx].sh_link].sh_offset);
+ for (TInt jdx = 0; jdx < nSyms; jdx++)
+ {
+ if (!strcmp(&symStringtable[sym[jdx].st_name], (char *)aName))
+ return &sym[jdx];
+ }
+ return (Elf32_Sym *)0;
+ }
+
+TBool ELFFile::SymbolPresent(TText *aName)
+ {
+ return (FindSymbol(aName) != 0);
+ }
+
+TBool ELFFile::GetExceptionIndexInfo(TUint32 &aOffset)
+ {
+ const TText * aBase = (TText *)".ARM.exidx$$Base";
+ const TText * aLimit = (TText *)".ARM.exidx$$Limit";
+ Elf32_Sym * exidxBase = FindSymbol(aBase);
+ Elf32_Sym * exidxLimit = FindSymbol(aLimit);
+ if (exidxBase && exidxLimit && (exidxLimit->st_value - exidxBase->st_value))
+ {
+ const TText * aExceptionDescriptor = (TText *)"Symbian$$CPP$$Exception$$Descriptor";
+ Elf32_Sym * aED = FindSymbol(aExceptionDescriptor);
+ if (aED)
+ {
+ // Set bottom bit so 0 in header slot means an old binary.
+ // The decriptor is always aligned on a 4 byte boundary.
+ aOffset = (aED->st_value - iLinkedBase) | 0x00000001;
+ return ETrue;
+ }
+ else
+ {
+ Print(EPeError,"Executable has exception table but no exception descriptor\n");
+ exit(666);
+ }
+ }
+ return EFalse;
+ }
+
+TBool ELFFile::SetUpLookupTable()
+{
+ if(!iDllData->CreateSymLookupTable() ) {
+ Print(EPeError,"Failed to create named symbol lookup information\n");
+ return FALSE;
+ }
+ if(!iDllData->CreateDependency()){
+ Print(EPeError,"Failed to create dependency ordering for named symbol lookup\n");
+ return FALSE;
+ }
+
+ iDllData->SetExportSymInfo();
+ return TRUE;
+}
+
+void ELFFile::GetExportSymInfoHeader(E32EpocExpSymInfoHdr& aSymInfoHdr)
+{
+ iDllData->GetExportSymInfoHeader(aSymInfoHdr);
+}
+
+void ELFFile::SetLookupTblBase(TInt aBaseOffset)
+{
+ iDllData->SetLookupTblBase(aBaseOffset);
+}
+
+TInt ELFFile::GetLookupTblSize()
+{
+ return iDllData->GetLookupTblSize();
+}
+
+TUint ELFFile::GetSymLookupSection(char* aBuff)
+{
+ return iDllData->GetSymLookupSection(aBuff);
+}
+