📄 loader.cxx
字号:
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 + -