bintools/elftools/elftran/elf_file.cpp
changeset 2 39c28ec933dd
equal deleted inserted replaced
1:820b22e13ff1 2:39c28ec933dd
       
     1 /*
       
     2 * Copyright (c) 2001-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of the License "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description: 
       
    15 *
       
    16 */
       
    17 
       
    18 
       
    19 
       
    20 #include <e32def.h>
       
    21 #include <e32std.h>
       
    22 #include "elftran.h"
       
    23 #include <elfdefs.h>
       
    24 #include "elffile.h"
       
    25 #include "elfdll.h"
       
    26 #include <h_utl.h>
       
    27 #include <string.h>
       
    28 #include <stdlib.h>
       
    29 
       
    30 TBool hadText, hadReloc = EFalse;
       
    31 
       
    32 ELFFile::ELFFile() 
       
    33     :
       
    34     iHeapCommittedSize(0x1000),
       
    35     iHeapReservedSize(0x100000),
       
    36     iStackCommittedSize(0),
       
    37 
       
    38     iFileName(0),
       
    39     iFileHandle(-1),
       
    40     iElfFile(0),
       
    41 
       
    42     iDynamicSegmentHdr(0),
       
    43     iDynamicSegmentIdx(0),
       
    44 
       
    45     iCodeSegmentHdr(0),
       
    46     iCodeSegmentIdx(0),
       
    47 
       
    48     iDataSegmentHdr(0),
       
    49     iDataSegmentIdx(0),
       
    50 
       
    51     iDllData(0),
       
    52     iCpu(ECpuUnknown)
       
    53     {}
       
    54 
       
    55 
       
    56 
       
    57 
       
    58 ELFFile::~ELFFile()
       
    59 	{
       
    60 	delete [] iFileName;
       
    61 	delete iElfFile;
       
    62 	delete iDllData;
       
    63 	}
       
    64 
       
    65 
       
    66 TBool ELFFile::Init(const TText * const aFileName)
       
    67 //
       
    68 // Read the ELF file into memory
       
    69 //
       
    70  	{
       
    71 
       
    72  	delete [] iFileName;	
       
    73 	iFileName = new TText[strlen((const char *)aFileName)+1];
       
    74 	strcpy ((char *)iFileName, (const char *)aFileName);
       
    75 
       
    76 	TInt error = HFile::Open(iFileName, &iFileHandle);
       
    77 	if (error!=0)
       
    78 		return EFalse;
       
    79 
       
    80 	TInt flength = HFile::GetLength(iFileHandle);
       
    81 
       
    82 	iElfFile = (Elf32_Ehdr *)HMem::Alloc(0,flength);
       
    83 	if (!iElfFile)
       
    84 		{
       
    85 		Print(EPeError,"Failed to allocate memory to read in file.\n");
       
    86 		Close();
       
    87 		return EFalse;
       
    88 		}
       
    89 
       
    90 	if (!HFile::Read(iFileHandle,iElfFile,flength))
       
    91 		{
       
    92 		Print(EPeError,"Unable to read file %s.\n",iFileName);
       
    93 		Close();
       
    94 		return EFalse;
       
    95 		}
       
    96 
       
    97         Close();
       
    98 
       
    99 	if (!IsValidFileHeader(iElfFile))
       
   100 		{
       
   101 		Print(EPeError,"Invalid file header.\n");
       
   102 		return EFalse;
       
   103 		}
       
   104 	// we only support this....for the moment
       
   105 	iCpu = ECpuArmV4;
       
   106 
       
   107 	if (!InitHeaders()) return EFalse;
       
   108 	
       
   109 	if (!InitDllData()) return EFalse;
       
   110 
       
   111 	iEntryPoint = iElfFile->e_entry;
       
   112 
       
   113 	iCodeSize = GetCodeSize();
       
   114 	iDataSize = GetDataSize();
       
   115 	iBssSize = GetBssSize();
       
   116 
       
   117 	iStackReservedSize = 0x2000;
       
   118 	iStackCommittedSize = 0x2000;
       
   119 
       
   120  	iLinkedBase = iCodeSegmentHdr->p_vaddr;
       
   121 	
       
   122 	iImageIsDll = iDllData->ImageIsDll();
       
   123 
       
   124 	return ETrue;
       
   125 	}
       
   126 
       
   127 char * ELFFile::CreateImportSection(TInt &aSize)
       
   128 //
       
   129 // get ELFDLLData to do it
       
   130 //
       
   131 	{
       
   132 	TInt size;
       
   133 	char * newSection = iDllData->CreateImportSection(size);
       
   134 	aSize = size;
       
   135 	return newSection;
       
   136 	}
       
   137 
       
   138 TUint ELFFile::GetExportTableOffset(void)
       
   139         {
       
   140 	return iDllData->GetExportTableOffset();
       
   141 	}
       
   142 
       
   143 TBool ELFFile::InitHeaders(void)
       
   144         {
       
   145 	TInt nphdrs = iElfFile->e_phnum;
       
   146 	if (nphdrs)
       
   147 	       {
       
   148 	       // Find the dynamic segment
       
   149 	       Elf32_Phdr * aPhdr = ELFADDR(Elf32_Phdr, iElfFile, iElfFile->e_phoff);
       
   150 	       iPhdr = aPhdr;
       
   151 	       for (TInt idx = 0; idx < nphdrs; idx++)
       
   152 					{
       
   153 					Elf32_Word ptype = aPhdr[idx].p_type;
       
   154 					if (ptype == PT_DYNAMIC)
       
   155 							{
       
   156 							iDynamicSegmentHdr = &aPhdr[idx];
       
   157 							iDynamicSegmentIdx = idx;
       
   158 							}
       
   159       				else if (ptype == PT_LOAD && 
       
   160 							 (aPhdr[idx].p_flags & (PF_X + PF_ARM_ENTRY)))
       
   161 							{
       
   162 							iCodeSegmentHdr = &aPhdr[idx];
       
   163 							iCodeSegmentIdx = idx;
       
   164 							}
       
   165       				else if (ptype == PT_LOAD && 
       
   166 							 (aPhdr[idx].p_flags & (PF_W + PF_R)))
       
   167 							{
       
   168 							iDataSegmentHdr = &aPhdr[idx];
       
   169 							iDataSegmentIdx = idx;
       
   170 							}
       
   171 					}
       
   172 	       }
       
   173 	
       
   174 	// cache pointer to symbol table
       
   175 
       
   176 	// Get section header table
       
   177 	Elf32_Shdr * s = ELFADDR(Elf32_Shdr, iElfFile, iElfFile->e_shoff);
       
   178 	// Index of section header for section header string table
       
   179 	TInt stIdx = iElfFile->e_shstrndx;
       
   180 	TInt symIdx = -1;
       
   181 	// Section name string table
       
   182 	char * stringtable = ELFADDR(char, iElfFile, s[stIdx].sh_offset);
       
   183 	// the index at which we find '.symtab' is the index of the symtab section
       
   184 	for (TInt idx = 0; idx < iElfFile->e_shnum; idx++)
       
   185 	    {
       
   186 		if (idx != stIdx)
       
   187 		       {
       
   188 		       if (!strcmp(&stringtable[s[idx].sh_name], ".symtab"))
       
   189 			      {
       
   190 			      symIdx = idx;
       
   191 			      break;
       
   192 			      }
       
   193 		       }
       
   194 		}
       
   195 	if (symIdx == -1) return EFalse;
       
   196 
       
   197 	// save section header table
       
   198 	iSectionHeaderTable = s;
       
   199 	// save the index
       
   200 	iSymIdx = symIdx;	
       
   201 	// here's the symbol table
       
   202 	iSymTab = ELFADDR(Elf32_Sym, iElfFile, s[symIdx].sh_offset);
       
   203 	return ETrue;
       
   204 	}
       
   205 
       
   206 TBool ELFFile::InitDllData(void)
       
   207 	{
       
   208 	if (!iDynamicSegmentHdr)
       
   209 	       {
       
   210 #if defined(_DEBUG)
       
   211 	       Print(EWarning, "Image '%s' has no import/export data.\n", iFileName);
       
   212 #endif
       
   213 	       return ETrue;
       
   214 	       }
       
   215 	iDllData = new ELFDllData(this);
       
   216 	if (!iDllData)
       
   217 	       {
       
   218 	       Print(EPeError, "Out of memory allocating DLL data\n");
       
   219 	       return EFalse;
       
   220 	       }
       
   221 
       
   222 	Elf32_Dyn * dyn = ELFADDR(Elf32_Dyn, iElfFile, iDynamicSegmentHdr->p_offset);
       
   223 	TInt idx = 0;
       
   224 	TInt soNameOffset = 0;
       
   225 	while(dyn[idx].d_tag != DT_NULL) // best to make it explicit
       
   226 	       {
       
   227 	       switch (dyn[idx].d_tag)
       
   228 		      {
       
   229 		      case DT_HASH:
       
   230 			   iDllData->iHashTable = ELFADDR(Elf32_HashTable, dyn, dyn[idx].d_val);
       
   231 			   break;
       
   232 		      case DT_STRTAB:
       
   233 			   iDllData->iDynStrTab = ELFADDR(char, dyn, dyn[idx].d_val);
       
   234 			   break;
       
   235 		      case DT_SYMTAB:
       
   236 			   iDllData->iDynSymTab = ELFADDR(Elf32_Sym, dyn, dyn[idx].d_val);
       
   237 			   break;
       
   238 		      case DT_RELA:
       
   239 			   iDllData->iRela = ELFADDR(Elf32_Rela, dyn, dyn[idx].d_val);
       
   240 			   break;
       
   241 		      case DT_RELASZ:
       
   242 			   iDllData->iRelaSz = dyn[idx].d_val;
       
   243 			   break;
       
   244 		      case DT_RELAENT:
       
   245 			   iDllData->iRelaSz = dyn[idx].d_val;
       
   246 			   break;
       
   247 		      case DT_STRSZ:
       
   248 			   iDllData->iDynStrTabSize = dyn[idx].d_val;
       
   249 			   break;
       
   250 		      case DT_ARM_SYMTABSZ_21: //For RVCT2.1
       
   251 			   //iDllData->iDynSymTabSize = dyn[idx].d_val;
       
   252 		      case DT_ARM_SYMTABSZ:
       
   253 			  /* This is same as DT_ARM_SYMTABSZ_21, but for RVCT 2.2
       
   254 			   * The tag value has been changed for RVC2.2 from RVCT2.1.
       
   255 			   * We just ignore this. i.e., we get the symbol table size
       
   256 			   * from the nchain field of the hash table as noted in section
       
   257 			   * 3.2.2.2 of the BPABI.
       
   258 			   */
       
   259 			   break;
       
   260 		      case DT_SYMENT:
       
   261 			   iDllData->iSymSize = dyn[idx].d_val;
       
   262 			   break;
       
   263 		      case DT_SONAME:
       
   264 			   soNameOffset = dyn[idx].d_val;
       
   265 			   break;
       
   266 		      case DT_REL:
       
   267 			   iDllData->iRel = ELFADDR(Elf32_Rel, dyn, dyn[idx].d_val);
       
   268 			   break;
       
   269 		      case DT_RELSZ:
       
   270 			   iDllData->iRelSz = dyn[idx].d_val;
       
   271 			   break;
       
   272 		      case DT_RELENT:
       
   273 			   iDllData->iRelEnt = dyn[idx].d_val;
       
   274 			   break;
       
   275 		      case DT_NEEDED:
       
   276 			   iDllData->AddToDependency(dyn[idx].d_val);
       
   277 			   break;
       
   278 		      case DT_PLTRELSZ:
       
   279 		      case DT_PLTGOT:
       
   280 		      case DT_INIT:
       
   281 		      case DT_FINI:
       
   282 		      case DT_RPATH:
       
   283 		      case DT_SYMBOLIC:
       
   284 		      case DT_PLTREL:
       
   285 		      case DT_DEBUG:
       
   286 		      case DT_TEXTREL:
       
   287 		      case DT_JMPREL:
       
   288 		      case DT_BIND_NOW:
       
   289 			   break;
       
   290 		      default:
       
   291 		           Print(EPeError,"Unrecognized Dyn Array tag in image '%s'.\n", iFileName);
       
   292 			   return EFalse;
       
   293 		      }
       
   294 		      idx++;
       
   295 	       }
       
   296 	return iDllData->Init();
       
   297 	}
       
   298 
       
   299 
       
   300 void ELFFile::Close()
       
   301 //
       
   302 // close the ELF file
       
   303 //
       
   304 	{
       
   305 	HFile::Close(iFileHandle);
       
   306 	}
       
   307 
       
   308 
       
   309 
       
   310 TInt ELFFile::NumberOfImports() const
       
   311 //
       
   312 // Count the total number of imports for this image
       
   313 //
       
   314 	{
       
   315 	return iDllData->NumberOfImports();
       
   316 	}
       
   317 
       
   318 TInt ELFFile::NumberOfImportDlls() const
       
   319 //
       
   320 // Count the number of referenced Dlls
       
   321 //
       
   322 	{
       
   323 	return iDllData->NumberOfImportDlls();
       
   324 	}
       
   325 
       
   326 TInt ELFFile::NumberOfExports() const
       
   327 //
       
   328 // Count the number of exported symbols
       
   329 //
       
   330 	{
       
   331 	return iDllData->NumberOfExports();
       
   332 	}
       
   333 
       
   334 TInt ELFFile::NumberOfCodeRelocs() 
       
   335 	{ 
       
   336 	return iDllData->NumberOfCodeRelocs(); 
       
   337 	}
       
   338 
       
   339 TInt ELFFile::NumberOfDataRelocs() 
       
   340 	{ 
       
   341 	return iDllData->NumberOfDataRelocs(); 
       
   342 	}
       
   343 
       
   344 Elf32_Phdr * ELFFile::GetSegmentFromAddr(Elf32_Addr addr)
       
   345 	{
       
   346 	TInt nphdrs = iElfFile->e_phnum;
       
   347 	for (TInt idx = 0; idx < nphdrs; idx++)
       
   348 	        {
       
   349 		// take advantage of unsignedness 
       
   350 		if ((addr - iPhdr[idx].p_vaddr) < iPhdr[idx].p_memsz) return &iPhdr[idx];
       
   351 		}
       
   352 	return NULL;
       
   353 	}
       
   354 
       
   355 
       
   356 TInt ELFFile::NumberOfRelocs()
       
   357 	{
       
   358 	return iDllData->NumberOfRelocs();
       
   359 	}
       
   360 
       
   361 TUint16 ELFFile::GetRelocType(Elf32_Rel *aReloc)
       
   362     {
       
   363 	// We work out the type by figuring out the segment of the reloc
       
   364 	TInt segmentIdx = ELF32_R_SYM(aReloc->r_info);
       
   365 	
       
   366 	// check to see if its a reserved or special index.
       
   367 	if ((!segmentIdx) || ((segmentIdx >= SHN_LORESERVE) && (segmentIdx <= SHN_HIRESERVE)))
       
   368 		// up until now these have been treated as KInferredRelocType, so lets continue...
       
   369 		return KInferredRelocType;
       
   370 			
       
   371 	// need to see if this section is executable or writable
       
   372 	if (iPhdr[segmentIdx-1].p_flags & PF_X) 
       
   373 		return KTextRelocType;
       
   374 	if (iPhdr[segmentIdx-1].p_flags & PF_W) 
       
   375 		return KDataRelocType;
       
   376 	// perhaps we should error here.
       
   377 	return KInferredRelocType;
       
   378 	}
       
   379 
       
   380 TBool ELFFile::GetRelocs(Elf32_Rel **aCodeRelocs, Elf32_Rel **aDataRelocs)
       
   381         {
       
   382 	return iDllData->GetRelocs(aCodeRelocs, aDataRelocs);
       
   383 	}
       
   384 
       
   385 TUint ELFFile::GetCodeSize()
       
   386     {
       
   387 	return iCodeSegmentHdr->p_filesz;
       
   388 	}
       
   389 
       
   390 TBool ELFFile::HasInitialisedData()
       
   391 	{
       
   392 	return iDataSegmentHdr != NULL && iDataSegmentHdr->p_filesz != 0;
       
   393 	}
       
   394 
       
   395 TUint ELFFile::GetDataSize()
       
   396     {
       
   397 	return iDataSegmentHdr != NULL ? iDataSegmentHdr->p_filesz : 0;
       
   398 	}
       
   399 
       
   400 TBool ELFFile::HasBssData()
       
   401 	{
       
   402 	return iDataSegmentHdr != NULL && (iDataSegmentHdr->p_memsz - iDataSegmentHdr->p_filesz) != 0;
       
   403 	}
       
   404 
       
   405 TUint ELFFile::GetBssSize()
       
   406     {
       
   407 	return iDataSegmentHdr != NULL ? iDataSegmentHdr->p_memsz - iDataSegmentHdr->p_filesz: 0;
       
   408 	}
       
   409 
       
   410 
       
   411 
       
   412 
       
   413 
       
   414 
       
   415 TBool ELFFile::IsValidFileHeader(Elf32_Ehdr * iElfFile)
       
   416  	{
       
   417         if (!(iElfFile->e_ident[EI_MAG0] == ELFMAG0 &&
       
   418 	      iElfFile->e_ident[EI_MAG1] == ELFMAG1 &&
       
   419 	      iElfFile->e_ident[EI_MAG2] == ELFMAG2 &&
       
   420 	      iElfFile->e_ident[EI_MAG3] == ELFMAG3))
       
   421 		{
       
   422                 Print(EPeError,"Invalid ELF magic.\n");
       
   423 		return EFalse;
       
   424 		}
       
   425 
       
   426         if (iElfFile->e_ident[EI_CLASS] != ELFCLASS32)
       
   427 		{
       
   428                 Print(EPeError,"File is not a 32 bit object file.\n");
       
   429 		return EFalse;
       
   430 		}
       
   431         if (iElfFile->e_ident[EI_DATA] != ELFDATA2LSB)
       
   432 		{
       
   433                 Print(EPeError,"File data encoding is not Little Endian.\n");
       
   434 		return EFalse;
       
   435 		}
       
   436 
       
   437   	if (iElfFile->e_machine != EM_ARM)
       
   438 		{
       
   439 		Print(EPeError,"File does not target ARM/THUMB processors.\n");
       
   440 		return EFalse;
       
   441 		}
       
   442 
       
   443   	if (!(iElfFile->e_type == ET_EXEC || iElfFile->e_type == ET_DYN))
       
   444 		{
       
   445 		Print(EPeError,"File is neither an executable nor a shared object\n");
       
   446 		return EFalse;
       
   447 		}
       
   448 
       
   449 	return ETrue;
       
   450 	}
       
   451 
       
   452 
       
   453 // Get details of the next import to fix-up in the current file. Fill in the name of the dll 
       
   454 //it is imported from, the ordinal number and the address to write back to.
       
   455 #define ORDINAL_DONE 0x40000000
       
   456 
       
   457 
       
   458 // The following static functions are passed an array of PE files to operate on
       
   459 
       
   460 Elf32_Sym * ELFFile::FindSymbol(const TText *aName)
       
   461     {
       
   462 	Elf32_Shdr * s = ELFADDR(Elf32_Shdr, iElfFile, iElfFile->e_shoff);	
       
   463 	TInt symIdx = iSymIdx;
       
   464 	Elf32_Sym * sym = iSymTab;
       
   465 	TInt nSyms = s[symIdx].sh_size / s[symIdx].sh_entsize;
       
   466 	char * symStringtable = ELFADDR(char, iElfFile, s[s[symIdx].sh_link].sh_offset);
       
   467 	for (TInt jdx = 0; jdx < nSyms; jdx++)
       
   468 	    {
       
   469 		if (!strcmp(&symStringtable[sym[jdx].st_name], (char *)aName)) 
       
   470 			return &sym[jdx];
       
   471 		}
       
   472 	return (Elf32_Sym *)0;
       
   473     }
       
   474 
       
   475 TBool ELFFile::SymbolPresent(TText *aName)
       
   476     {
       
   477 	return (FindSymbol(aName) != 0);
       
   478     }
       
   479 
       
   480 TBool ELFFile::GetExceptionIndexInfo(TUint32 &aOffset)
       
   481     {
       
   482     const TText * aBase = (TText *)".ARM.exidx$$Base";
       
   483     const TText * aLimit = (TText *)".ARM.exidx$$Limit";
       
   484 	Elf32_Sym * exidxBase = FindSymbol(aBase);
       
   485 	Elf32_Sym * exidxLimit = FindSymbol(aLimit);
       
   486 	if (exidxBase && exidxLimit && (exidxLimit->st_value - exidxBase->st_value)) 
       
   487 	    {
       
   488 		const TText * aExceptionDescriptor = (TText *)"Symbian$$CPP$$Exception$$Descriptor";
       
   489 		Elf32_Sym * aED = FindSymbol(aExceptionDescriptor);
       
   490 		if (aED) 
       
   491 			{
       
   492 			// Set bottom bit so 0 in header slot means an old binary.
       
   493 			// The decriptor is always aligned on a 4 byte boundary.
       
   494 			aOffset = (aED->st_value - iLinkedBase) | 0x00000001;
       
   495 			return ETrue;
       
   496 			}
       
   497 		else
       
   498 			{
       
   499 			Print(EPeError,"Executable has exception table but no exception descriptor\n");
       
   500 			exit(666);
       
   501 			}
       
   502 		}
       
   503 	return EFalse;
       
   504     }
       
   505 
       
   506 TBool ELFFile::SetUpLookupTable()
       
   507 {
       
   508 	if(!iDllData->CreateSymLookupTable() ) {
       
   509 		Print(EPeError,"Failed to create named symbol lookup information\n");
       
   510 		return FALSE;
       
   511 	}
       
   512 	if(!iDllData->CreateDependency()){
       
   513 		Print(EPeError,"Failed to create dependency ordering for named symbol lookup\n");
       
   514 		return FALSE;
       
   515 	}
       
   516 
       
   517 	iDllData->SetExportSymInfo();
       
   518 	return TRUE;
       
   519 }
       
   520 
       
   521 void ELFFile::GetExportSymInfoHeader(E32EpocExpSymInfoHdr& aSymInfoHdr)
       
   522 {
       
   523 	iDllData->GetExportSymInfoHeader(aSymInfoHdr);
       
   524 }
       
   525 
       
   526 void ELFFile::SetLookupTblBase(TInt aBaseOffset)
       
   527 {
       
   528 	iDllData->SetLookupTblBase(aBaseOffset);
       
   529 }
       
   530 
       
   531 TInt ELFFile::GetLookupTblSize()
       
   532 {
       
   533 	return iDllData->GetLookupTblSize();
       
   534 }
       
   535 
       
   536 TUint ELFFile::GetSymLookupSection(char* aBuff)
       
   537 {
       
   538 	return iDllData->GetSymLookupSection(aBuff);
       
   539 }
       
   540