Mercurial > ecos-v3_0-branch
diff packages/services/objloader/current/src/objelf.c @ 2011:662e1b34b811
Added OBJLOADER package.
| author | nickg |
|---|---|
| date | Thu, 07 Jul 2005 10:55:12 +0000 |
| parents | |
| children | 8bf90d16b837 |
line wrap: on
line diff
new file mode 100644 --- /dev/null +++ b/packages/services/objloader/current/src/objelf.c @@ -0,0 +1,397 @@ +/* ================================================================= + * + * objelf.c + * + * Relocation routine for eCos loader. + * + * ================================================================= + * ####ECOSGPLCOPYRIGHTBEGIN#### + * ------------------------------------------- + * This file is part of eCos, the Embedded Configurable Operating + * System. + * Copyright (C) 2005 eCosCentric Ltd. + * + * 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. + * + * ------------------------------------------- + * ####ECOSGPLCOPYRIGHTEND#### + * ================================================================= + * #####DESCRIPTIONBEGIN#### + * + * Author(s): atonizzo@lycos.com + * Contributors: nickg@ecoscentric.com + * Date: 2005-05-13 + * Purpose: + * Description: + * + * ####DESCRIPTIONEND#### + * + * ================================================================= + */ + +#include <cyg/infra/diag.h> // For diagnostic printing. +#include <pkgconf/io_fileio.h> +#include <cyg/hal/hal_tables.h> +#include <stdio.h> + +#include <pkgconf/objloader.h> +#include <cyg/objloader/elf.h> +#include <cyg/objloader/objelf.h> + +CYG_HAL_TABLE_BEGIN( cyg_ldr_table, ldr_table ); +CYG_HAL_TABLE_END( cyg_ldr_table_end, ldr_table ); + +__externC cyg_ldr_table_entry cyg_ldr_table[]; +__externC cyg_ldr_table_entry cyg_ldr_table_end[]; + +#if CYGPKG_SERVICES_OBJLOADER_DEBUG_LEVEL > 0 +void +cyg_ldr_print_section_data( PELF_OBJECT p ) +{ + cyg_int32 i; + cyg_uint8 strname[32]; + cyg_uint8 *p_strtab = (cyg_uint8*)p->sections[p->p_elfhdr->e_shstrndx]; + + diag_printf( "\n\nSection Headers:\n" ); + diag_printf( "[Nr] Name Addr Offset Size Info\n" ); + for ( i = 0; i < p->p_elfhdr->e_shnum; i++ ) + { + sprintf( strname, "%s", p_strtab + p->p_sechdr[i].sh_name ); + while ( strlen( strname ) < 20 ) + strcat( strname, " " ); + diag_printf( "[%02d] %s %08X %08X %08X %08X\n", + i, + strname, + p->p_sechdr[i].sh_addr, + p->p_sechdr[i].sh_offset, + p->p_sechdr[i].sh_size, + p->p_sechdr[i].sh_info ); + } + diag_printf( "\n" ); +} + +void +cyg_ldr_print_symbol_names( PELF_OBJECT p ) +{ + cyg_int32 i, symtab_entries; + Elf32_Sym *p_symtab = (Elf32_Sym*)p->sections[p->hdrndx_symtab]; + cyg_uint8 *p_strtab = (cyg_uint8*)p->sections[p->hdrndx_strtab]; + cyg_uint8 strname[32]; + + // Total number of entries in the symbol table. + symtab_entries = p->p_sechdr[p->hdrndx_symtab].sh_size / + p->p_sechdr[p->hdrndx_symtab].sh_entsize; + diag_printf( "Num Value Size Ndx Name\n" ); + for ( i = 1; i < symtab_entries; i++ ) + { + sprintf( strname, "%d", i ); + while ( strlen( strname ) < 5 ) + strcat( strname, " " ); + diag_printf( strname ); + + sprintf( strname, + "%08X %d", + p_symtab[i].st_value, + p_symtab[i].st_size ); + while ( strlen( strname ) < 15 ) + strcat( strname, " " ); + diag_printf( strname ); + + sprintf( strname, "%d", p_symtab[i].st_shndx ); + while ( strlen( strname ) < 6 ) + strcat( strname, " " ); + diag_printf( strname ); + + strncpy( strname, + p_strtab + p_symtab[i].st_name, + sizeof( strname ) - 1 ); + strname[strlen( p_strtab + p_symtab[i].st_name )] = '\0'; + diag_printf( strname ); + diag_printf( "\n" ); + } +} + +void +cyg_ldr_print_rel_names( PELF_OBJECT p ) +{ + cyg_int32 i, j, r_entries, sym_index; + Elf32_Sym *p_symtab = (Elf32_Sym*)p->sections[p->hdrndx_symtab]; + cyg_uint8 *p_strtab = (cyg_uint8*)p->sections[p->hdrndx_strtab]; + cyg_uint8 *p_shstrtab = (cyg_uint8*)p->sections[p->p_elfhdr->e_shstrndx]; +#if ELF_ARCH_RELTYPE == Elf_Rela + Elf32_Rela* p_rela; +#else + Elf32_Rel* p_rel; +#endif + cyg_uint8 strname[32]; + + for ( i = 1; i < p->p_elfhdr->e_shnum; i++ ) + { + if ( ( p->p_sechdr[i].sh_type == SHT_REL ) || + ( p->p_sechdr[i].sh_type == SHT_RELA ) ) + { + // Calculate the total number of entries in the .rela section. + r_entries = p->p_sechdr[i].sh_size / p->p_sechdr[i].sh_entsize; + + diag_printf( "\n\nSymbols at: %s\n\n", + p_shstrtab + p->p_sechdr[i].sh_name ); +#if ELF_ARCH_RELTYPE == Elf_Rela + p_rela = (Elf32_Rela*)cyg_ldr_load_elf_section( p, i ); + printf( "Offset Info Name [+ Addend]\n" ); +#else + p_rel = (Elf32_Rel*)cyg_ldr_load_elf_section( p, i ); + printf( "Offset Info Name\n" ); +#endif + + for ( j = 0; j < r_entries; j++ ) + { + sprintf( strname, + "%08X %08X ", + p_rela[j].r_offset, + p_rela[j].r_info ); + + diag_printf( strname ); + + cyg_uint8 sym_type = ELF32_R_SYM( p_rela[j].r_info ); + if ( strlen ( p_strtab + p_symtab[sym_type].st_name ) > 0 ) + diag_printf( p_strtab + p_symtab[sym_type].st_name ); + else + { + // If the symbol name is not available, then print + // the name of the section. + sym_index = p_symtab[sym_type].st_shndx; + diag_printf( p_shstrtab + p->p_sechdr[sym_index].sh_name ); + } +#if ELF_ARCH_RELTYPE == Elf_Rela + if ( p_rela[j].r_addend != 0 ) + diag_printf( " + %08X", p_rela[j].r_addend ); +#endif + diag_printf( "\n" ); + } + // After all the printing is done, the relocation table can + // be dumped. + cyg_ldr_delete_elf_section( p, i ); + } + } +} +#endif // DEBUG_PRINT + +static void +*cyg_ldr_local_address( PELF_OBJECT p, cyg_uint32 sym_index ) +{ + cyg_uint32 data_sec, addr; + Elf32_Sym *p_symtab; + + p_symtab = (Elf32_Sym*)cyg_ldr_section_address( p, p->hdrndx_symtab ); + + // Find out the section number in which the data for this symbol is + // located. + data_sec = p_symtab[sym_index].st_shndx; + + // From the section number we get the start of the memory area in + // memory. + addr = (cyg_uint32)cyg_ldr_section_address( p, data_sec ); + + // And now return the address of the data. + return (void*)( addr + p_symtab[sym_index].st_value); +} + +static void +*cyg_ldr_external_address( PELF_OBJECT p, cyg_uint32 sym_index ) +{ + cyg_uint8* tmp2; + Elf32_Sym *p_symtab; + cyg_uint8 *p_strtab; + cyg_ldr_table_entry *entry = cyg_ldr_table; + + + p_symtab = (Elf32_Sym*)cyg_ldr_section_address( p, p->hdrndx_symtab ); + p_strtab = (cyg_uint8*)cyg_ldr_section_address( p, p->hdrndx_strtab ); + + // This is the name of the external reference to search. + tmp2 = p_strtab + p_symtab[sym_index].st_name; + while ( entry != cyg_ldr_table_end ) + { + if ( !strcmp( (const char*)tmp2, entry->symbol_name ) ) + return entry->handler; + entry++; + } + + // Symbol not found. + return 0; +} + +// input: +// p : Pointer to the elf file object +// sym_index : Index of the symbol to be searched (in the SYMTAB) +// +// out: +// 0 : Symbol not found +// Other : Address of the symbol in absolute memory. +void +*cyg_ldr_symbol_address( PELF_OBJECT p, cyg_uint32 sym_index ) +{ + cyg_uint32 addr; + cyg_uint8 sym_info; + Elf32_Sym *p_symtab; + + p_symtab = (Elf32_Sym*)cyg_ldr_section_address( p, p->hdrndx_symtab ); + sym_info = p_symtab[sym_index].st_info; + + switch ( ELF32_ST_TYPE( sym_info ) ) + { + case STT_NOTYPE: + case STT_FUNC: + case STT_OBJECT: + switch ( ELF32_ST_BIND( sym_info ) ) + { + case STB_LOCAL: + case STB_GLOBAL: + if ( p_symtab[sym_index].st_shndx == SHN_UNDEF ) + return cyg_ldr_external_address( p, sym_index ); + else + return cyg_ldr_local_address( p, sym_index ); + case STB_WEAK: + addr = (cyg_uint32)cyg_ldr_external_address( p, sym_index ); + if ( addr != 0 ) + return (void*)addr; + else + return cyg_ldr_local_address( p, sym_index ); + default: + return 0; + } + break; + case STT_SECTION: + // Return the starting address of a section, given its index. + return (void*)cyg_ldr_section_address( p, + p_symtab[sym_index].st_shndx ); + default: + return 0; + } +} + +// Loads the relocation information, relocates, and dumps the relocation +// information once the process is complete. +cyg_int32 +cyg_ldr_relocate_section( PELF_OBJECT p, cyg_uint32 r_shndx ) +{ + cyg_int32 i, rc; + cyg_uint32 r_entries, r_target_shndx, r_target_addr; + cyg_uint32 sym_value, sym_index; + Elf32_Addr r_offset; + Elf32_Word r_type; + Elf32_Sword r_addend; +#if ELF_ARCH_RELTYPE == Elf_Rela + Elf32_Rela* p_rela = (Elf32_Rela*)cyg_ldr_load_elf_section( p, r_shndx ); +#else + Elf32_Rel* p_rel = (Elf32_Rel*)cyg_ldr_load_elf_section( p, r_shndx ); +#endif + +#if CYGPKG_SERVICES_OBJLOADER_DEBUG_LEVEL > 0 + Elf32_Sym *p_symtab = (Elf32_Sym*)cyg_ldr_section_address( p, + p->hdrndx_symtab ); + cyg_uint8 *p_strtab = (cyg_uint8*)cyg_ldr_section_address( p, + p->hdrndx_strtab ); + cyg_uint8 *p_shstrtab = (cyg_uint8*)cyg_ldr_section_address( p, + p->p_elfhdr->e_shstrndx ); +#endif + + // Now we can get the address of the contents of the section to modify. + r_target_shndx = p->p_sechdr[r_shndx].sh_info; + r_target_addr = (cyg_uint32)cyg_ldr_section_address( p, r_target_shndx ); + +#if CYGPKG_SERVICES_OBJLOADER_DEBUG_LEVEL > 0 + diag_printf( "Relocating section \"%s\"\n", + p_shstrtab + p->p_sechdr[r_target_shndx].sh_name ); +#if CYGPKG_SERVICES_OBJLOADER_DEBUG_LEVEL > 1 + diag_printf( "Ndx Type Offset Name\"\n" ); +#endif +#endif + + // Perform relocatation for each of the members of this table. + r_entries = p->p_sechdr[r_shndx].sh_size / p->p_sechdr[r_shndx].sh_entsize; + for ( i = 0; i < r_entries; i++ ) + { +#if ELF_ARCH_RELTYPE == Elf_Rela + r_offset = p_rela[i].r_offset; + r_type = ELF32_R_TYPE( p_rela[i].r_info ); + sym_index = ELF32_R_SYM( p_rela[i].r_info ); + r_addend = p_rela[i].r_addend; +#else + r_offset = p_rel[i].r_offset; + r_type = ELF32_R_TYPE( p_rel[i].r_info ); + sym_index = ELF32_R_SYM( p_rel[i].r_info ); + r_addend = 0; +#endif + + sym_value = (cyg_uint32)cyg_ldr_symbol_address( p, sym_index ); + if ( sym_value == 0 ) + { +#if CYGPKG_SERVICES_OBJLOADER_DEBUG_LEVEL > 0 + diag_printf( "Unknown symbol value: %s Index: %d\n", + p_strtab + p_symtab[sym_index].st_name, + sym_index ); +#endif + return -1; + } + + // This is architecture dependent, and deals with whether we have + // '.rel' or '.rela' sections. +#if CYGPKG_SERVICES_OBJLOADER_DEBUG_LEVEL > 1 + diag_printf( "%04X %04X %08X ", + sym_index, + r_type, + r_offset ); + if ( strlen ( p_strtab + p_symtab[sym_index].st_name ) > 0 ) + diag_printf( p_strtab + p_symtab[sym_index].st_name ); + else + { + // If the symbol name is not available, then print + // the name of the section. + cyg_uint32 sec_ndx = p_symtab[sym_index].st_shndx; + diag_printf( p_shstrtab + p->p_sechdr[sec_ndx].sh_name ); + } + diag_printf( "\n" ); +#endif + rc = cyg_ldr_relocate( r_type, + r_target_addr + r_offset, + sym_value + r_addend ); + if ( rc != 0 ) + { +#if CYGPKG_SERVICES_OBJLOADER_DEBUG_LEVEL > 0 + diag_printf( "Relocation error: Cannot find symbol: %s\n", + p_strtab + p_symtab[sym_index].st_name ); +#endif + return -1; + } + } + + // After the relocation is done, the relocation table can be dumped. + cyg_ldr_delete_elf_section( p, r_shndx ); + return 0; +} +
