📄 loader.cxx
字号:
//==========================================================================
//
// loader.cxx
//
// Loader class implementation
//
//==========================================================================
//####ECOSGPLCOPYRIGHTBEGIN####
// -------------------------------------------
// This file is part of eCos, the Embedded Configurable Operating System.
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
//
// eCos is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 2 or (at your option) any later version.
//
// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
//
// You should have received a copy of the GNU General Public License along
// with eCos; if not, write to the Free Software Foundation, Inc.,
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
//
// As a special exception, if other files instantiate templates or use macros
// or inline functions from this file, or you compile this file and link it
// with other works to produce a work based on this file, this file does not
// by itself cause the resulting work to be covered by the GNU General Public
// License. However the source code for this file must still be made available
// in accordance with section (3) of the GNU General Public License.
//
// This exception does not invalidate any other reasons why a work based on
// this file might be covered by the GNU General Public License.
//
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
// at http://sources.redhat.com/ecos/ecos-license/
// -------------------------------------------
//####ECOSGPLCOPYRIGHTEND####
//==========================================================================
//#####DESCRIPTIONBEGIN####
//
// Author(s): nickg
// Contributors: nickg
// Date: 2000-11-03
// Purpose: Loader class implementation
// Description: This file contains the implementation of the ELF loader
// classes.
//
//
//
//####DESCRIPTIONEND####
//
//==========================================================================
#include <pkgconf/hal.h>
#include <pkgconf/kernel.h>
#include <pkgconf/isoinfra.h>
#include <cyg/kernel/ktypes.h> // base kernel types
#include <cyg/infra/cyg_trac.h> // tracing macros
#include <cyg/infra/cyg_ass.h> // assertion macros
#include <string.h>
#include <cyg/loader/loader.hxx> // our header
#if CYGINT_ISO_MALLOC
#include <stdlib.h> // for malloc() etc
#endif
// ----------------------------------------------------------------------------
#ifdef CYGPKG_LIBC_STRING
#define streq( a, b ) (strcmp(a,b) == 0)
#else
static int streq( const char *s1, const char *s2 )
{
while( *s1 == *s2 && *s1 && *s2 ) s1++,s2++;
return !(*s2-*s1);
}
#endif
// ----------------------------------------------------------------------------
// new operator to allow us to invoke constructors on previously allocated
// memory.
inline void *operator new(size_t size, void *ptr) { return ptr; };
// =========================================================================
// Static objects
// Default memory allocator
static Cyg_LoaderMemAlloc memalloc;
// Loader object
static Cyg_Loader loader(&memalloc);
Cyg_Loader *Cyg_Loader::loader = &::loader;
// =========================================================================
// Main loader class members
// -------------------------------------------------------------------------
// Constructor
Cyg_Loader::Cyg_Loader( Cyg_LoaderMemAlloc *memalloc )
{
CYG_REPORT_FUNCTION();
error = 0;
mem_default = memalloc;
// build an object for the main program
Cyg_LoaderMemBlock *obj = mem_default->alloc( sizeof(Cyg_LoadObject));
main = new(obj->address) Cyg_LoadObject( );
// Add to load list
loadlist.add_head(main);
error = main->get_error();
CYG_REPORT_RETURN();
}
// -------------------------------------------------------------------------
// Destructor
Cyg_Loader::~Cyg_Loader()
{
CYG_REPORT_FUNCTION();
CYG_REPORT_RETURN();
}
// -------------------------------------------------------------------------
// Load an object and all its dependencies.
cyg_code Cyg_Loader::load( Cyg_LoaderStream& stream,
cyg_uint32 mode,
Cyg_LoadObject **object)
{
CYG_REPORT_FUNCTION();
CYG_REPORT_FUNCARG3XV( &stream, mode, object );
cyg_code error = 0;
Cyg_LoaderMemBlock *obj = mem_default->alloc( sizeof(Cyg_LoadObject));
Cyg_LoadObject *pobj = NULL;
pobj = new(obj->address) Cyg_LoadObject( stream, mode, mem_default, obj );
error = pobj->get_error();
if( error != 0 )
goto finish;
// Add this object to list before we do any relocations to make
// the symbol lookups work.
loadlist.add_tail(pobj);
// The object is now loaded. We must now do any relocations.
pobj->relocate();
error = pobj->get_error();
if( error != 0 )
goto finish;
// Handle PLT relocations if we are told to do so
// We always do this for now..
// if( mode & RTLD_NOW )
pobj->relocate_plt();
error = pobj->get_error();
finish:
if( error != 0 )
{
// remove object from list.
loadlist.remove( pobj );
pobj->~Cyg_LoadObject();
mem_default->free( obj );
}
else
{
// return it from this function.
*object = pobj;
}
CYG_REPORT_RETVAL(error);
return error;
}
// -------------------------------------------------------------------------
// Close object and remove it from memory
cyg_code Cyg_Loader::close( Cyg_LoadObject *object )
{
CYG_REPORT_FUNCTION();
cyg_code error = 0;
Cyg_LoaderMemBlock *block = object->get_block();
object->~Cyg_LoadObject();
if( block )
block->free();
CYG_REPORT_RETVAL(error);
return error;
}
// -------------------------------------------------------------------------
// Translate current error code into a string.
const char *Cyg_Loader::error_string( )
{
CYG_REPORT_FUNCTION();
char *ret = "";
CYG_REPORT_RETVAL(ret);
return ret;
}
// -------------------------------------------------------------------------
// Look up a named symbol in loadlist
CYG_ADDRESS Cyg_Loader::hash_lookup_addr( const char *name )
{
CYG_ADDRESS addr = 0;
Cyg_LoadObject *object = loadlist.get_head();
do
{
addr = object->hash_lookup_addr( name );
if( addr != CYG_LOADER_NULLSYMADDR )
break;
object = object->get_next();
} while( object != loadlist.get_head() );
if( addr == CYG_LOADER_NULLSYMADDR )
error = CYG_LOADERR_NO_SYMBOL;
return addr;
}
// =========================================================================
// Loader Object class members
Cyg_LoadObject_Base::Cyg_LoadObject_Base()
{
e_type = ET_EXEC;
e_entry = 0;
base = 0;
dynamic = _DYNAMIC;
parse_dynamic( dynamic );
}
// -------------------------------------------------------------------------
// Constructor - reads and allocates the executable.
Cyg_LoadObject_Base::Cyg_LoadObject_Base( Cyg_LoaderStream& stream,
cyg_uint32 amode,
Cyg_LoaderMemAlloc *mem )
{
CYG_REPORT_FUNCTION();
CYG_REPORT_FUNCARG3XV( &stream, mode, mem );
Cyg_LoaderMemBlock *phblock = NULL;
Cyg_LoaderMemBlock *block = NULL;
Elf32_Phdr *phdr;
Elf32_Phdr *dynhdr = NULL;
cyg_uint32 memsize = 0;
cyg_uint32 maxalign = 0;
CYG_BYTE *memaddr;
Elf32_Addr vaddr_low = 0x7FFFFFFF;
Elf32_Addr vaddr_hi = 0;
mode = amode;
memalloc = mem;
error = CYG_LOADERR_NOERROR;
// OK, let's start by getting the ELF header...
Elf32_Ehdr elf_hdr;
error = stream.get_data( (CYG_BYTE *)&elf_hdr, sizeof( elf_hdr ) );
if( error != 0 )
goto finish;
// Check that this is a valid ELF file and that the various header
// fields match what we expect for our current architecture and
// platform.
if( !IS_ELF( elf_hdr ) )
error = CYG_LOADERR_NOT_ELF;
else if( elf_hdr.e_ident[EI_CLASS] != ELFCLASS32 )
error = CYG_LOADERR_INVALID_CLASS;
#if CYG_BYTEORDER == CYG_LSBFIRST
else if( elf_hdr.e_ident[EI_DATA] != ELFDATA2LSB )
#else
else if( elf_hdr.e_ident[EI_DATA] != ELFDATA2MSB )
#endif
error = CYG_LOADERR_INVALID_BYTEORDER;
else if( elf_hdr.e_ident[EI_VERSION] != EV_CURRENT )
error = CYG_LOADERR_INVALID_VERSION;
else if( elf_hdr.e_machine != CYG_ELF_MACHINE )
error = CYG_LOADERR_INVALID_MACHINE;
else if( elf_hdr.e_version != EV_CURRENT )
error = CYG_LOADERR_INVALID_VERSION;
else if( elf_hdr.e_phentsize != sizeof(Elf32_Phdr) )
error = CYG_LOADERR_INVALID_VERSION;
if( error != 0 )
goto finish;
// OK that all seems in order, save some fields away for later.
e_type = elf_hdr.e_type;
e_entry = elf_hdr.e_entry;
// Now we must read the program header and prepare to read the
// object file into memory.
error = stream.seek( elf_hdr.e_phoff );
if( error != 0 )
goto finish;
// Allocate space for the header
phblock = memalloc->alloc( elf_hdr.e_phentsize * elf_hdr.e_phnum );
if( phblock == NULL )
{
error = CYG_LOADERR_NO_MEMORY;
goto finish;
}
error = stream.get_data( (CYG_BYTE *)phblock->address, sizeof(Elf32_Phdr)*elf_hdr.e_phnum );
if( error != 0 )
goto finish;
phdr = (Elf32_Phdr *)phblock->address;
// Loop over the program headers, totalling the sizes of the the
// PT_LOAD entries and saving a pointer to the PT_DYNAMIC entry
// when we find it.
// Since the segments must retain the same relationship to
// eachother in memory that their virtual addresses do in the
// headers, we determine the amount of memory needed by finding
// the extent of the virtual addresses covered by the executable.
for( int i = 0; i < elf_hdr.e_phnum; i++,phdr++ )
{
if( phdr->p_type == PT_DYNAMIC )
{
dynhdr = phdr;
continue;
}
if( phdr->p_type != PT_LOAD )
continue;
if( phdr->p_vaddr < vaddr_low )
vaddr_low = phdr->p_vaddr;
if( (phdr->p_vaddr+phdr->p_memsz) > vaddr_hi )
vaddr_hi = phdr->p_vaddr+phdr->p_memsz;
if( phdr->p_align > maxalign )
maxalign = phdr->p_align;
}
// Calculate how much memory we need and allocate it
memsize = vaddr_hi - vaddr_low;
block = memalloc->alloc( memsize, maxalign );
if( block == NULL )
{
error = CYG_LOADERR_NO_MEMORY;
goto finish;
}
// Attach to segments list
segs.add_tail( block );
// Calculate the base address for this executable. This is the
// difference between the actual address the executable is loaded
// at and its lowest virtual address. This value must be added to
// all addresses derived from the executable to relocate them into
// the real memory space.
base = (CYG_ADDRESS)block->address - vaddr_low;
// Loop over the program headers again, this time loading them
// into the memory segment we have allocated and clearing any
// unused areas to zero.
phdr = (Elf32_Phdr *)phblock->address;
memaddr = (CYG_BYTE *)block->address;
for( int i = 0; i < elf_hdr.e_phnum; i++,phdr++ )
{
if( phdr->p_type != PT_LOAD )
continue;
error = stream.seek( phdr->p_offset );
if( error != 0 ) break;
// Calculate the actual load address for this segment.
CYG_BYTE *loadaddr = (CYG_BYTE *)(phdr->p_vaddr + base);
error = stream.get_data( loadaddr, phdr->p_filesz );
if( error != 0 ) break;
// If the memory size is more than we got from the file, zero the remainder.
if( phdr->p_filesz < phdr->p_memsz )
memset( loadaddr+phdr->p_filesz,
0,
phdr->p_memsz-phdr->p_filesz );
}
dynamic = (Elf32_Dyn *)(dynhdr->p_vaddr + base);
parse_dynamic( dynamic );
finish:
if( phblock != NULL )
memalloc->free( phblock );
CYG_REPORT_RETURN();
}
// -------------------------------------------------------------------------
// Parse the dynamic segment
void Cyg_LoadObject_Base::parse_dynamic( Elf32_Dyn *dynamic )
{
CYG_REPORT_FUNCTION();
flags = 0;
for(;; dynamic++)
{
switch( dynamic->d_tag )
{
case DT_NULL: /* marks end of _DYNAMIC array */
return;
case DT_NEEDED: /* string table offset of needed lib */
break; // ignore for now
case DT_PLTRELSZ: /* size of relocation entries in PLT */
pltrelsz = dynamic->d_un.d_val;
break;
case DT_PLTGOT: /* address PLT/GOT */
pltgot = dynamic->d_un.d_ptr + base;
break;
case DT_HASH: /* address of symbol hash table */
hash = (Elf_Hash *)(dynamic->d_un.d_ptr + base);
bucket = (Elf32_Word *)(hash+1);
chain = bucket+hash->nbucket;
break;
case DT_STRTAB: /* address of string table */
strtab = (unsigned char *)(dynamic->d_un.d_ptr + base);
break;
case DT_SYMTAB: /* address of symbol table */
symtab = (Elf32_Sym *)(dynamic->d_un.d_ptr + base);
break;
case DT_RELA: /* address of relocation table */
rela = (Elf32_Rela *)(dynamic->d_un.d_ptr + base);
break;
case DT_RELASZ: /* size of relocation table */
relasize = dynamic->d_un.d_val;
break;
case DT_RELAENT: /* size of relocation entry */
relaent = dynamic->d_un.d_val;
break;
case DT_STRSZ: /* size of string table */
strsize = dynamic->d_un.d_val;
break;
case DT_SYMENT: /* size of symbol table entry */
syment = dynamic->d_un.d_val;
break;
case DT_INIT: /* address of initialization func. */
init = dynamic->d_un.d_ptr + base;
break;
case DT_FINI: /* address of termination function */
fini = dynamic->d_un.d_ptr + base;
break;
case DT_SONAME: /* string table offset of shared obj */
soname = dynamic->d_un.d_val;
break;
case DT_SYMBOLIC: /* start sym search in shared obj. */
flags |= DF_SYMBOLIC;
break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -