bintools/elftools/elftran/elf_file.cpp
changeset 0 044383f39525
child 590 360bd6b35136
--- /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);
+}
+