⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 loader.cxx

📁 eCos/RedBoot for勤研ARM AnywhereII(4510) 含全部源代码
💻 CXX
📖 第 1 页 / 共 2 页
字号:
//==========================================================================
//
//      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 + -