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

📄 loader.cxx

📁 eCos/RedBoot for勤研ARM AnywhereII(4510) 含全部源代码
💻 CXX
📖 第 1 页 / 共 2 页
字号:
        case DT_REL:                    /* address of rel. tbl. w addends */
            rel = (Elf32_Rel *)(dynamic->d_un.d_ptr + base);
            break;
        case DT_RELSZ:                  /* size of DT_REL relocation table */
            relsize = dynamic->d_un.d_val;
            break;
        case DT_RELENT:                 /* size of DT_REL relocation entry */
            relent = dynamic->d_un.d_val;
            break;
        case DT_PLTREL:                 /* PLT referenced relocation entry */
            pltrel = dynamic->d_un.d_val;
            break;
        case DT_DEBUG:                  /* Debug data */
            break;                      /* ignore for now */
        case DT_TEXTREL:                /* Allow rel. mod. to unwritable seg */
            flags |= DF_TEXTREL;
            break;
        case DT_JMPREL:                 /* add. of PLT's relocation entries */
            jmprel = dynamic->d_un.d_ptr + base;
            break;
        case DT_BIND_NOW:               /* Bind now regardless of env setting */
            flags |= DF_BIND_NOW;
            break;
        case DT_INIT_ARRAY:             /* init array address */
            init_array = (Elf32_Addr *)(dynamic->d_un.d_ptr + base);
            break;
        case DT_FINI_ARRAY:             /* fini array address */
            fini_array = (Elf32_Addr *)(dynamic->d_un.d_ptr + base);
            break;
        case DT_INIT_ARRAYSZ:           /* init array size */
            init_array_sz = dynamic->d_un.d_val;
            break;
        case DT_FINI_ARRAYSZ:           /* fini array size */
            fini_array_sz = dynamic->d_un.d_val;
            break;
        case DT_FLAGS:                  /* flags */
            flags |= dynamic->d_un.d_val;
            break;
        case DT_PREINIT_ARRAY:          /* preinit array address */
            pre_init_array = (Elf32_Addr *)(dynamic->d_un.d_ptr + base);
            break;
        case DT_PREINIT_ARRAYSZ:        /* preinit array size */
            pre_init_array_sz = dynamic->d_un.d_val;
            break;
            
        default:
            // handle format-specific entries
            break;
        }
    }
    
    CYG_REPORT_RETURN();
}

// -------------------------------------------------------------------------
// Get the symbol name from the current object's symbol table, look it
// up in the hash tables of the loaded objects, and return its address.

CYG_ADDRESS Cyg_LoadObject_Base::get_sym_addr_from_ix( Elf32_Word ix )
{
    Elf32_Sym *sym = get_sym( ix );

    if( sym == NULL ) return 0;

    const char *name = get_name( sym->st_name );

    // If the symbol has local binding, we must look for
    // it in this object only.
    if( ELF32_ST_BIND(sym->st_info) == STB_LOCAL )
         return hash_lookup_addr( name );

    // Otherwise search the loaded objects in load order
    return Cyg_Loader::loader->hash_lookup_addr( name );

}

// -------------------------------------------------------------------------
// Lookup the name in our hash table and return the symbol table entry

Elf32_Sym *Cyg_LoadObject_Base::hash_lookup( const char *name )
{
    Elf32_Sym *ret = NULL;

    if( hash == NULL )
    {
        error = CYG_LOADERR_NO_HASHTABLE;
        return NULL;
    }

    error = CYG_LOADERR_NO_SYMBOL;
    
    Elf32_Word ix = elf_hash( (const unsigned char *)name );

    ix %= hash->nbucket;

    // get head of chain
    Elf32_Word iy = bucket[ ix ]; 
    
    while( iy != STN_UNDEF )
    {
        Elf32_Sym *sym = get_sym( iy );
        const char *sname = get_name( sym->st_name );

        if( streq( name, sname ) )
        {
            ret = sym;
            error = CYG_LOADERR_NOERROR;
            break;
        }

        iy = chain[ iy ];
    }

    return ret;
}

// -------------------------------------------------------------------------
// Lookup the given name in our symbol table and return it's value
// relocated to our load address.

CYG_ADDRESS Cyg_LoadObject_Base::hash_lookup_addr( const char *name )
{
    Elf32_Sym *sym = hash_lookup( name );

    if( sym == NULL )
        return CYG_LOADER_NULLSYMADDR;

    // Check that this symbol is for a defined object, if its type is
    // NOTYPE then it is undefined, here, and we cannot take its address.
    // Hopefully it is defined in some other object.
    
    if( ELF32_ST_TYPE(sym->st_info) == STT_NOTYPE )
    {
        error = CYG_LOADERR_NO_SYMBOL;
        return CYG_LOADER_NULLSYMADDR;
    }
    
    return sym->st_value + base;
}

// -------------------------------------------------------------------------
// ELF hash function
// This is the standard hash function used for indexing the bucket
// array in the hash table.

unsigned long Cyg_LoadObject_Base::elf_hash( const unsigned char *name )
{
    unsigned long h = 0, g;

    while( *name )
    {
        h = ( h << 4 ) + *name++;
        if( (g = h & 0xf0000000) != 0 )
            h ^= g >> 24;
        h &= ~g;
    }
    return h;
}

// -------------------------------------------------------------------------
//

Elf32_Sym *Cyg_LoadObject_Base::get_sym( Elf32_Word ix )
{
    if( symtab == NULL )
        return NULL;
    
    return &symtab[ix];
}

char *Cyg_LoadObject_Base::get_name( Elf32_Word offset )
{
    if( strtab == NULL || offset > strsize )
        return NULL;
    
    return (char *)(&strtab[offset]);
}

// -------------------------------------------------------------------------
// Destructor

// -------------------------------------------------------------------------
// Cyg_LoadObject_Base destructor

Cyg_LoadObject_Base::~Cyg_LoadObject_Base()
{
    CYG_REPORT_FUNCTION();
    // empty out segments list
    while( !segs.empty() )
    {
        Cyg_LoaderMemBlock *block = segs.rem_head();

        block->free();
    }
    CYG_REPORT_RETURN();
}

// -------------------------------------------------------------------------
// Translate a symbol into its address.

void *Cyg_LoadObject_Base::symbol( const char *name )
{
    CYG_REPORT_FUNCTION();

    Elf32_Addr addr = hash_lookup_addr( name );

    if( addr == CYG_LOADER_NULLSYMADDR )
        addr = 0;
    
    CYG_REPORT_RETVAL( addr );

    return (void *)addr;
}

// -------------------------------------------------------------------------
// Start the given executable object running

cyg_code Cyg_LoadObject_Base::exec(int argc, char **argv, char **envv)
{
    CYG_REPORT_FUNCTION();
    CYG_REPORT_FUNCARG3XV( argc, argv, envv );

    cyg_code error = 0;
    
    CYG_REPORT_RETVAL(error);

    return error;
}

// =========================================================================
// Cyg_LoadObject members

// -------------------------------------------------------------------------
// Apply relocations

void Cyg_LoadObject::relocate()
{
    CYG_REPORT_FUNCTION();

    if( rel != NULL )
    {
        Elf32_Rel *r = rel;
        for( int i = relsize; i > 0 && error == 0; i -= relent, r++ )
            error = apply_rel( ELF32_R_TYPE(r->r_info),
                               ELF32_R_SYM(r->r_info),
                               r->r_offset);
    }
        

    if( error == 0 && rela != NULL )
    {
        Elf32_Rela *r = rela;
        for( int i = relasize; i > 0 && error == 0; i -= relaent, r++ )
            error = apply_rela( ELF32_R_TYPE(r->r_info),
                                ELF32_R_SYM(r->r_info),
                                r->r_offset,
                                r->r_addend);
    }
    
    CYG_REPORT_RETURN();
}

// -------------------------------------------------------------------------
// Apply JMPREL relocations for the PLT

void Cyg_LoadObject::relocate_plt()
{
    CYG_REPORT_FUNCTION();

    if( pltrel == DT_REL )
    {
        Elf32_Rel *r = (Elf32_Rel *)jmprel;
        for( int i = pltrelsz; i > 0 && error == 0; i -= sizeof(Elf32_Rel), r++ )
            error = apply_rel( ELF32_R_TYPE(r->r_info),
                               ELF32_R_SYM(r->r_info),
                               r->r_offset);
    }
        

    if( error == 0 && pltrel == DT_RELA )
    {
        Elf32_Rela *r = (Elf32_Rela *)jmprel;
        for( int i = pltrelsz; i > 0 && error == 0; i -= sizeof(Elf32_Rela), r++ )
            error = apply_rela( ELF32_R_TYPE(r->r_info),
                                ELF32_R_SYM(r->r_info),
                                r->r_offset,
                                r->r_addend);
    }
    
    CYG_REPORT_RETURN();
}

// =========================================================================
// Loader memory allocator default class methods.
// The default behaviour of this class is to use malloc/realloc/free
// to handle memory.

// -------------------------------------------------------------------------

Cyg_LoaderMemAlloc::Cyg_LoaderMemAlloc()
{
    // no initialization needed
}

// -------------------------------------------------------------------------

Cyg_LoaderMemAlloc::~Cyg_LoaderMemAlloc()
{
    // No destruction needed
}

// -------------------------------------------------------------------------
// Allocate memory of the supplied size and alignment.
// size      - size in bytes
// alignment - alignment expressed as a power of 2

Cyg_LoaderMemBlock *Cyg_LoaderMemAlloc::alloc( cyg_int32 size,
                                               cyg_int32 alignment)
{
#if CYGINT_ISO_MALLOC    
    Cyg_LoaderMemBlock *block;
    cyg_uint8 *mem;
    cyg_uint32 acsize = sizeof(Cyg_LoaderMemBlock) + size + alignment;

    mem = (cyg_uint8 *)::malloc( acsize );

    if( mem == NULL )
        return NULL;

    block = (Cyg_LoaderMemBlock *)mem;

    // set up aligned block address
    block->address      = (void *)((((CYG_ADDRWORD)mem+sizeof(Cyg_LoaderMemBlock))+alignment) & ~(alignment-1));
    block->size         = size;
    block->alignment    = alignment;
    block->mem          = this;
    block->actual_address = (CYG_ADDRESS) mem;
    block->actual_size    = acsize;

    return block;

#else

    return 0;

#endif
    
}

// -------------------------------------------------------------------------
// Reallocate block

Cyg_LoaderMemBlock *Cyg_LoaderMemAlloc::realloc( Cyg_LoaderMemBlock *oblock,
                                                 cyg_int32 size,
                                                 cyg_int32 alignment)
{
#if CYGINT_ISO_MALLOC
    
    Cyg_LoaderMemBlock *block;
    cyg_uint8 *mem;

    if( alignment == -1 )
        alignment = oblock->alignment;
    
    cyg_uint32 acsize = sizeof(Cyg_LoaderMemBlock) + size + alignment;

    mem = (cyg_uint8 *)::realloc( (void *)(oblock->actual_address), acsize );

    if( mem == NULL )
        return NULL;

    block = (Cyg_LoaderMemBlock *)mem;

    // set up aligned block address
    block->address      = (void *)((((CYG_ADDRWORD)mem+sizeof(Cyg_LoaderMemBlock))+alignment) & (alignment-1));
    block->size         = size;
    block->alignment    = alignment;
    block->mem          = this;
    block->actual_address = (CYG_ADDRESS) mem;
    block->actual_size    = acsize;

    return block;

#else

    return NULL;

#endif
}
    
// -------------------------------------------------------------------------
// Free a previously allocated memory segment.

void Cyg_LoaderMemAlloc::free( Cyg_LoaderMemBlock *block )
{
#if CYGINT_ISO_MALLOC        
    ::free( (void *)block->actual_address );
#endif    
}

// =========================================================================
// Loader stream functions

Cyg_LoaderStream::Cyg_LoaderStream()
{
}

Cyg_LoaderStream::~Cyg_LoaderStream()
{
}

cyg_code Cyg_LoaderStream::get_byte(CYG_BYTE *val)
{
    return CYG_LOADERR_EOF;
}

cyg_code Cyg_LoaderStream::get_data(CYG_BYTE *addr, CYG_ADDRWORD size)
{
    return CYG_LOADERR_EOF;
}

cyg_code Cyg_LoaderStream::seek(CYG_ADDRWORD pos)
{
    return CYG_LOADERR_SEEK;    
}

// =========================================================================
// Memory based loader stream

Cyg_LoaderStream_Mem::Cyg_LoaderStream_Mem( const void *addr, cyg_int32 size )
{
    base = pos = (CYG_ADDRESS)addr;
    end = base + size;
}

Cyg_LoaderStream_Mem::~Cyg_LoaderStream_Mem()
{
    // nothing to do
}
    
cyg_code Cyg_LoaderStream_Mem::get_byte(CYG_BYTE *val)
{
    if( pos == end )
        return CYG_LOADERR_EOF;

    *val = *(CYG_BYTE *)pos;
    pos++;
    
    return CYG_LOADERR_NOERROR;
}

cyg_code Cyg_LoaderStream_Mem::get_data(CYG_BYTE *addr, CYG_ADDRWORD size)
{
    if( pos == end || (pos+size) > end )
        return CYG_LOADERR_EOF;

    memcpy( (void *)addr, (void *)pos, size );

    pos += size;
    
    return CYG_LOADERR_NOERROR;
}

cyg_code Cyg_LoaderStream_Mem::seek(CYG_ADDRWORD apos)
{
    CYG_ADDRWORD npos = base+apos;
    
    if( npos > end || npos < base )
        return CYG_LOADERR_SEEK;

    pos = npos;

    return CYG_LOADERR_NOERROR;
}

// =========================================================================
// file based loader stream

#ifdef CYGPKG_IO_FILEIO

#include <unistd.h>

Cyg_LoaderStream_File::Cyg_LoaderStream_File( int afd )
{
    fd = afd;
}

Cyg_LoaderStream_File::~Cyg_LoaderStream_File()
{
    // nothing to do
    fd = 0;
}
    
cyg_code Cyg_LoaderStream_File::get_byte(CYG_BYTE *val)
{
    ssize_t got = read( fd, (void *)val, 1 );
    
    if( got == 0 )
        return CYG_LOADERR_EOF;

    return CYG_LOADERR_NOERROR;
}

cyg_code Cyg_LoaderStream_File::get_data(CYG_BYTE *addr, CYG_ADDRWORD size)
{
    ssize_t got = read( fd, (void *)addr, size );
    
    if( got != (ssize_t)size )
        return CYG_LOADERR_EOF;

    return CYG_LOADERR_NOERROR;
}

cyg_code Cyg_LoaderStream_File::seek(CYG_ADDRWORD apos)
{
    off_t npos = lseek( fd, apos, SEEK_SET );
    
    if( npos != apos )
        return CYG_LOADERR_SEEK;

    return CYG_LOADERR_NOERROR;
}

#endif

// =========================================================================
// EOF loader.cxx

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -