📄 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)#elsestatic 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 allocatorstatic Cyg_LoaderMemAlloc memalloc;// Loader objectstatic Cyg_Loader loader(&memalloc);Cyg_Loader *Cyg_Loader::loader = &::loader;// =========================================================================// Main loader class members// -------------------------------------------------------------------------// ConstructorCyg_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();}// -------------------------------------------------------------------------// DestructorCyg_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 memorycyg_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 loadlistCYG_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 membersCyg_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 + -