From b36c52097f52012f9a52dff6fc8393d63805158b Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Fri, 3 May 2019 10:15:20 +1000 Subject: libdl: Do not access the ELF file while the allocator is locked. - Load symbols before allocation. - Parse reloc records and place any reloc recs in a cache to use while the allocator is locked. - Relocate symbols after section allocation. - Split section loading into allocation/locating and loading. - Update all arch back-ends with a new reloc interface to control tramp handling. - Add `-a` and `-t` to the object list shell command. Closes #3741 --- cpukit/libdl/rtl-allocator.c | 2 +- cpukit/libdl/rtl-elf.c | 484 +++++++++++++++++++++++++------------ cpukit/libdl/rtl-elf.h | 73 +++--- cpukit/libdl/rtl-mdreloc-arm.c | 122 ++++++---- cpukit/libdl/rtl-mdreloc-bfin.c | 22 +- cpukit/libdl/rtl-mdreloc-h8300.c | 22 +- cpukit/libdl/rtl-mdreloc-i386.c | 18 +- cpukit/libdl/rtl-mdreloc-lm32.c | 21 +- cpukit/libdl/rtl-mdreloc-m68k.c | 174 ++++++------- cpukit/libdl/rtl-mdreloc-mips.c | 24 +- cpukit/libdl/rtl-mdreloc-moxie.c | 20 +- cpukit/libdl/rtl-mdreloc-powerpc.c | 69 ++++-- cpukit/libdl/rtl-mdreloc-sparc.c | 26 +- cpukit/libdl/rtl-mdreloc-v850.c | 20 +- cpukit/libdl/rtl-obj.c | 138 ++++++++--- cpukit/libdl/rtl-shell.c | 59 ++++- cpukit/libdl/rtl-trampoline.h | 94 +++++++ cpukit/libdl/rtl-unresolved.c | 137 ++++++++--- cpukit/libdl/rtl.c | 31 +-- 19 files changed, 1042 insertions(+), 514 deletions(-) create mode 100644 cpukit/libdl/rtl-trampoline.h (limited to 'cpukit/libdl') diff --git a/cpukit/libdl/rtl-allocator.c b/cpukit/libdl/rtl-allocator.c index 0dca6b2f9a..647c0c89a4 100644 --- a/cpukit/libdl/rtl-allocator.c +++ b/cpukit/libdl/rtl-allocator.c @@ -147,7 +147,7 @@ rtems_rtl_alloc_wr_disable (rtems_rtl_alloc_tag tag, void* address) rtems_rtl_data* rtl = rtems_rtl_lock (); if (rtems_rtl_trace (RTEMS_RTL_TRACE_ALLOCATOR)) - printf ("rtl: alloc: wr-enable: addr=%p\n", address); + printf ("rtl: alloc: wr-disable: addr=%p\n", address); if (rtl != NULL && address != NULL) rtl->allocator.allocator (RTEMS_RTL_ALLOC_WR_DISABLE, diff --git a/cpukit/libdl/rtl-elf.c b/cpukit/libdl/rtl-elf.c index 963cb4b2f4..0fa639f36f 100644 --- a/cpukit/libdl/rtl-elf.c +++ b/cpukit/libdl/rtl-elf.c @@ -1,5 +1,5 @@ /* - * COPYRIGHT (c) 2012-2018 Chris Johns + * COPYRIGHT (c) 2012-2019 Chris Johns * * The license and distribution terms for this file may be * found in the file LICENSE in this distribution or at @@ -31,11 +31,12 @@ #include "rtl-elf.h" #include "rtl-error.h" #include +#include "rtl-trampoline.h" #include "rtl-unwind.h" #include /** - * The offsets in the unresolved array. + * The offsets in the reloc words. */ #define REL_R_OFFSET (0) #define REL_R_INFO (1) @@ -166,66 +167,77 @@ rtems_rtl_elf_reloc_parser (rtems_rtl_obj* obj, void* data) { rtems_rtl_elf_reloc_data* rd = (rtems_rtl_elf_reloc_data*) data; + rtems_rtl_word rel_words[3]; + rtems_rtl_elf_rel_status rs; /* - * The symbol has to have been resolved to parse the reloc record. Unresolved - * symbols are handled in the relocator but we need to count them here so a - * trampoline is accounted for. We have to assume the unresolved may be out of - * of range. + * Check the reloc record to see if a trampoline is needed. */ - if (!resolved) + if (is_rela) { - ++rd->unresolved; + const Elf_Rela* rela = (const Elf_Rela*) relbuf; + if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) + printf ("rtl: rela tramp: sym: %c:%s(%d)=%08jx type:%d off:%08jx addend:%d\n", + ELF_ST_BIND (sym->st_info) == STB_GLOBAL || + ELF_ST_BIND (sym->st_info) == STB_WEAK ? 'G' : 'L', + symname, (int) ELF_R_SYM (rela->r_info), + (uintmax_t) symvalue, (int) ELF_R_TYPE (rela->r_info), + (uintmax_t) rela->r_offset, (int) rela->r_addend); + rs = rtems_rtl_elf_relocate_rela_tramp (obj, rela, targetsect, + symname, sym->st_info, symvalue); + rel_words[REL_R_OFFSET] = rela->r_offset; + rel_words[REL_R_INFO] = rela->r_info; + rel_words[REL_R_ADDEND] = rela->r_addend; } else + { + const Elf_Rel* rel = (const Elf_Rel*) relbuf; + if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) + printf ("rtl: rel tramp: sym: %c:%s(%d)=%08jx type:%d off:%08jx\n", + ELF_ST_BIND (sym->st_info) == STB_GLOBAL || + ELF_ST_BIND (sym->st_info) == STB_WEAK ? 'G' : 'L', + symname, (int) ELF_R_SYM (rel->r_info), + (uintmax_t) symvalue, (int) ELF_R_TYPE (rel->r_info), + (uintmax_t) rel->r_offset); + rs = rtems_rtl_elf_relocate_rel_tramp (obj, rel, targetsect, + symname, sym->st_info, symvalue); + rel_words[REL_R_OFFSET] = rel->r_offset; + rel_words[REL_R_INFO] = rel->r_info; + rel_words[REL_R_ADDEND] = 0; + } + + if (rs == rtems_rtl_elf_rel_failure) + return false; + + if (rs == rtems_rtl_elf_rel_tramp_cache || rs == rtems_rtl_elf_rel_tramp_add) + { + uint32_t flags = (is_rela ? 1 : 0) | (resolved ? 0 : 1 << 1) | (sym->st_info << 8); + if (!rtems_rtl_trampoline_add (obj, flags, + targetsect->section, symvalue, rel_words)) + return false; + } + + /* + * Handle any dependencies if there is a valid symbol. + */ + if (symname != NULL) { /* - * Check the reloc record to see if a trampoline is needed. + * Find the symbol's object file. It cannot be NULL so ignore that result + * if returned, it means something is corrupted. We are in an iterator. */ - if (is_rela) - { - const Elf_Rela* rela = (const Elf_Rela*) relbuf; - if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) - printf ("rtl: rela tramp: sym:%s(%d)=%08jx type:%d off:%08jx addend:%d\n", - symname, (int) ELF_R_SYM (rela->r_info), - (uintmax_t) symvalue, (int) ELF_R_TYPE (rela->r_info), - (uintmax_t) rela->r_offset, (int) rela->r_addend); - if (!rtems_rtl_elf_relocate_rela_tramp (obj, rela, targetsect, - symname, sym->st_info, symvalue)) - return false; - } - else - { - const Elf_Rel* rel = (const Elf_Rel*) relbuf; - if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) - printf ("rtl: rel tramp: sym:%s(%d)=%08jx type:%d off:%08jx\n", - symname, (int) ELF_R_SYM (rel->r_info), - (uintmax_t) symvalue, (int) ELF_R_TYPE (rel->r_info), - (uintmax_t) rel->r_offset); - if (!rtems_rtl_elf_relocate_rel_tramp (obj, rel, targetsect, - symname, sym->st_info, symvalue)) - return false; - } - - if (symname != NULL) + rtems_rtl_obj* sobj = rtems_rtl_find_obj_with_symbol (symbol); + if (sobj != NULL) { /* - * Find the symbol's object file. It cannot be NULL so ignore that result - * if returned, it means something is corrupted. We are in an iterator. + * A dependency is not the base kernel image or itself. Tag the object as + * having been visited so we count it only once. */ - rtems_rtl_obj* sobj = rtems_rtl_find_obj_with_symbol (symbol); - if (sobj != NULL) + if (sobj != rtems_rtl_baseimage () && obj != sobj && + (sobj->flags & RTEMS_RTL_OBJ_RELOC_TAG) == 0) { - /* - * A dependency is not the base kernel image or itself. Tag the object as - * having been visited so we count it only once. - */ - if (sobj != rtems_rtl_baseimage () && obj != sobj && - (sobj->flags & RTEMS_RTL_OBJ_RELOC_TAG) == 0) - { - sobj->flags |= RTEMS_RTL_OBJ_RELOC_TAG; - ++rd->dependents; - } + sobj->flags |= RTEMS_RTL_OBJ_RELOC_TAG; + ++rd->dependents; } } } @@ -278,7 +290,8 @@ rtems_rtl_elf_reloc_relocator (rtems_rtl_obj* obj, } else { - rtems_rtl_obj* sobj; + rtems_rtl_obj* sobj; + rtems_rtl_elf_rel_status rs; if (is_rela) { @@ -287,8 +300,9 @@ rtems_rtl_elf_reloc_relocator (rtems_rtl_obj* obj, symname, (int) ELF_R_SYM (rela->r_info), (uintmax_t) symvalue, (int) ELF_R_TYPE (rela->r_info), (uintmax_t) rela->r_offset, (int) rela->r_addend); - if (!rtems_rtl_elf_relocate_rela (obj, rela, targetsect, - symname, sym->st_info, symvalue)) + rs = rtems_rtl_elf_relocate_rela (obj, rela, targetsect, + symname, sym->st_info, symvalue); + if (rs != rtems_rtl_elf_rel_no_error) return false; } else @@ -298,8 +312,9 @@ rtems_rtl_elf_reloc_relocator (rtems_rtl_obj* obj, symname, (int) ELF_R_SYM (rel->r_info), (uintmax_t) symvalue, (int) ELF_R_TYPE (rel->r_info), (uintmax_t) rel->r_offset); - if (!rtems_rtl_elf_relocate_rel (obj, rel, targetsect, - symname, sym->st_info, symvalue)) + rs = rtems_rtl_elf_relocate_rel (obj, rel, targetsect, + symname, sym->st_info, symvalue); + if (rs != rtems_rtl_elf_rel_no_error) return false; } @@ -419,7 +434,10 @@ rtems_rtl_elf_relocate_worker (rtems_rtl_obj* obj, /* * Only need the name of the symbol if global or a common symbol. */ - if (ELF_ST_TYPE (sym.st_info) == STT_NOTYPE || + if (ELF_ST_TYPE (sym.st_info) == STT_OBJECT || + ELF_ST_TYPE (sym.st_info) == STT_COMMON || + ELF_ST_TYPE (sym.st_info) == STT_FUNC || + ELF_ST_TYPE (sym.st_info) == STT_NOTYPE || ELF_ST_TYPE (sym.st_info) == STT_TLS || sym.st_shndx == SHN_COMMON) { @@ -491,10 +509,11 @@ bool rtems_rtl_obj_relocate_unresolved (rtems_rtl_unresolv_reloc* reloc, rtems_rtl_obj_sym* sym) { - rtems_rtl_obj_sect* sect; - bool is_rela; - Elf_Word symvalue; - rtems_rtl_obj* sobj; + rtems_rtl_obj_sect* sect; + bool is_rela; + Elf_Word symvalue; + rtems_rtl_obj* sobj; + rtems_rtl_elf_rel_status rs; is_rela = reloc->flags & 1; @@ -516,8 +535,9 @@ rtems_rtl_obj_relocate_unresolved (rtems_rtl_unresolv_reloc* reloc, printf ("rtl: rela: sym:%d type:%d off:%08jx addend:%d\n", (int) ELF_R_SYM (rela.r_info), (int) ELF_R_TYPE (rela.r_info), (uintmax_t) rela.r_offset, (int) rela.r_addend); - if (!rtems_rtl_elf_relocate_rela (reloc->obj, &rela, sect, - sym->name, sym->data, symvalue)) + rs = rtems_rtl_elf_relocate_rela (reloc->obj, &rela, sect, + sym->name, sym->data, symvalue); + if (rs != rtems_rtl_elf_rel_no_error) return false; } else @@ -529,8 +549,9 @@ rtems_rtl_obj_relocate_unresolved (rtems_rtl_unresolv_reloc* reloc, printf ("rtl: rel: sym:%d type:%d off:%08jx\n", (int) ELF_R_SYM (rel.r_info), (int) ELF_R_TYPE (rel.r_info), (uintmax_t) rel.r_offset); - if (!rtems_rtl_elf_relocate_rel (reloc->obj, &rel, sect, - sym->name, sym->data, symvalue)) + rs = rtems_rtl_elf_relocate_rel (reloc->obj, &rel, sect, + sym->name, sym->data, symvalue); + if (rs != rtems_rtl_elf_rel_no_error) return false; } @@ -621,16 +642,117 @@ rtems_rtl_elf_common (rtems_rtl_obj* obj, return true; } +/** + * Struct to handle trampoline reloc recs in the unresolved table. + */ +typedef struct rtems_rtl_tramp_data +{ + bool failure; + rtems_rtl_obj* obj; + size_t count; + size_t total; +} rtems_rtl_tramp_data; + +static bool +rtems_rtl_elf_tramp_resolve_reloc (rtems_rtl_unresolv_rec* rec, + void* data) +{ + rtems_rtl_tramp_data* td = (rtems_rtl_tramp_data*) data; + if (rec->type == rtems_rtl_trampoline_reloc) + { + const rtems_rtl_tramp_reloc* tramp = &rec->rec.tramp; + + ++td->total; + + if (tramp->obj == td->obj) + { + const rtems_rtl_obj_sect* targetsect; + Elf_Byte st_info; + Elf_Word symvalue; + rtems_rtl_elf_rel_status rs; + bool* failure = (bool*) data; + const bool is_rela = (tramp->flags & 1) == 1; + const bool unresolved = (tramp->flags & (1 << 1)) != 0; + + ++td->count; + + targetsect = rtems_rtl_obj_find_section_by_index (tramp->obj, tramp->sect); + st_info = tramp->flags >> 8; + symvalue = tramp->symvalue; + + if (is_rela) + { + Elf_Rela rela = { + .r_offset = tramp->rel[REL_R_OFFSET], + .r_info = tramp->rel[REL_R_INFO], + .r_addend = tramp->rel[REL_R_ADDEND] + }; + if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) + printf ("rtl: rela tramp: check: %c(%d)=%08jx type:%d off:%08jx addend:%d\n", + ELF_ST_BIND (st_info) == STB_GLOBAL || + ELF_ST_BIND (st_info) == STB_WEAK ? 'G' : 'L', + (int) ELF_R_SYM (rela.r_info), + (uintmax_t) symvalue, (int) ELF_R_TYPE (rela.r_info), + (uintmax_t) rela.r_offset, (int) rela.r_addend); + rs = rtems_rtl_elf_relocate_rela_tramp (tramp->obj, &rela, targetsect, + NULL, st_info, symvalue); + } + else + { + Elf_Rel rel = { + .r_offset = tramp->rel[REL_R_OFFSET], + .r_info = tramp->rel[REL_R_INFO], + }; + if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) + printf ("rtl: rel tramp: check: %c(%d)=%08jx type:%d off:%08jx\n", + ELF_ST_BIND (st_info) == STB_GLOBAL || + ELF_ST_BIND (st_info) == STB_WEAK ? 'G' : 'L', + (int) ELF_R_SYM (rel.r_info), + (uintmax_t) symvalue, (int) ELF_R_TYPE (rel.r_info), + (uintmax_t) rel.r_offset); + rs = rtems_rtl_elf_relocate_rel_tramp (tramp->obj, &rel, targetsect, + NULL, st_info, symvalue); + } + + if (unresolved || rs == rtems_rtl_elf_rel_tramp_add) + tramp->obj->tramps_size += tramp->obj->tramp_size; + if (rs == rtems_rtl_elf_rel_failure) + { + *failure = true; + return true; + } + } + } + + return false; +} + static bool rtems_rtl_elf_alloc_trampoline (rtems_rtl_obj* obj, size_t unresolved) { + rtems_rtl_tramp_data td = { 0 }; + td.obj = obj; + /* + * See which relocs are out of range and need a trampoline. + */ + rtems_rtl_unresolved_iterate (rtems_rtl_elf_tramp_resolve_reloc, &td); + if (td.failure) + return false; + rtems_rtl_trampoline_remove (obj); + obj->tramp_relocs = obj->tramp_size == 0 ? 0 : obj->tramps_size / obj->tramp_size; + if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) + printf ("rtl: tramp:elf: tramps: %zu count:%zu total:%zu\n", + obj->tramp_relocs, td.count, td.total); /* * Add on enough space to handle the unresolved externals that need to be * resolved at some point in time. They could all require fixups and * trampolines. */ - obj->tramp_size += - rtems_rtl_elf_relocate_tramp_max_size () * unresolved; + obj->tramps_size += obj->tramp_size * unresolved; + if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) + printf ("rtl: tramp:elf: slots: %zu (%zu)\n", + obj->tramp_size == 0 ? 0 : obj->tramps_size / obj->tramp_size, + obj->tramps_size); return rtems_rtl_obj_alloc_trampoline (obj); } @@ -653,10 +775,10 @@ rtems_rtl_elf_dependents (rtems_rtl_obj* obj, rtems_rtl_elf_reloc_data* reloc) } static bool -rtems_rtl_elf_symbols (rtems_rtl_obj* obj, - int fd, - rtems_rtl_obj_sect* sect, - void* data) +rtems_rtl_elf_symbols_load (rtems_rtl_obj* obj, + int fd, + rtems_rtl_obj_sect* sect, + void* data) { rtems_rtl_obj_cache* symbols; rtems_rtl_obj_cache* strings; @@ -720,19 +842,20 @@ rtems_rtl_elf_symbols (rtems_rtl_obj* obj, * we need to make sure there is a valid seciton. */ if (rtems_rtl_trace (RTEMS_RTL_TRACE_SYMBOL)) - printf ("rtl: sym:elf:%-2d name:%-2d:%-20s bind:%-2d " \ - "type:%-2d sect:%d size:%d\n", + printf ("rtl: sym:elf:%-4d name:%-4d: %-20s: bind:%-2d " \ + "type:%-2d sect:%-5d size:%-5d value:%d\n", sym, (int) symbol.st_name, name, (int) ELF_ST_BIND (symbol.st_info), (int) ELF_ST_TYPE (symbol.st_info), symbol.st_shndx, - (int) symbol.st_size); + (int) symbol.st_size, + (int) symbol.st_value); - /* - * If a duplicate forget it. - */ - if (rtems_rtl_symbol_global_find (name)) - continue; + /* + * If a duplicate forget it. + */ + if (rtems_rtl_symbol_global_find (name)) + continue; if ((symbol.st_shndx != 0) && ((ELF_ST_TYPE (symbol.st_info) == STT_OBJECT) || @@ -775,7 +898,7 @@ rtems_rtl_elf_symbols (rtems_rtl_obj* obj, else { if (rtems_rtl_trace (RTEMS_RTL_TRACE_SYMBOL)) - printf ("rtl: sym:elf:%-2d name:%-2d:%-20s: global\n", + printf ("rtl: sym:elf:%-4d name:%-4d: %-20s: global\n", sym, (int) symbol.st_name, name); ++globals; global_string_space += strlen (name) + 1; @@ -784,7 +907,7 @@ rtems_rtl_elf_symbols (rtems_rtl_obj* obj, else if (ELF_ST_BIND (symbol.st_info) == STB_LOCAL) { if (rtems_rtl_trace (RTEMS_RTL_TRACE_SYMBOL)) - printf ("rtl: sym:elf:%-2d name:%-2d:%-20s: local\n", + printf ("rtl: sym:elf:%-4d name:%-4d: %-20s: local\n", sym, (int) symbol.st_name, name); ++locals; local_string_space += strlen (name) + 1; @@ -849,14 +972,14 @@ rtems_rtl_elf_symbols (rtems_rtl_obj* obj, if (!rtems_rtl_obj_cache_read_byval (symbols, fd, off, &symbol, sizeof (symbol))) { - if (locals) + if (obj->local_syms) { rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_SYMBOL, obj->local_table); obj->local_table = NULL; obj->local_size = 0; obj->local_syms = 0; } - if (globals) + if (obj->global_syms) { rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_SYMBOL, obj->global_table); obj->global_table = NULL; @@ -875,78 +998,113 @@ rtems_rtl_elf_symbols (rtems_rtl_obj* obj, (ELF_ST_BIND (symbol.st_info) == STB_WEAK) || (ELF_ST_BIND (symbol.st_info) == STB_LOCAL))) { - rtems_rtl_obj_sect* symsect; - rtems_rtl_obj_sym* osym; - char* string; - Elf_Word value; + rtems_rtl_obj_sym* osym; + char* string; + Elf_Word value; + const char* name; - symsect = rtems_rtl_obj_find_section_by_index (obj, symbol.st_shndx); - if (symsect) + off = obj->ooffset + strtab->offset + symbol.st_name; + len = RTEMS_RTL_ELF_STRING_MAX; + + if (!rtems_rtl_obj_cache_read (strings, fd, off, (void**) &name, &len)) + return false; + + /* + * If a duplicate forget it. + */ + if (rtems_rtl_symbol_global_find (name)) + continue; + + if ((ELF_ST_BIND (symbol.st_info) == STB_GLOBAL) || + (ELF_ST_BIND (symbol.st_info) == STB_WEAK)) + { + osym = gsym; + string = gstring; + gstring += strlen (name) + 1; + ++gsym; + } + else { - const char* name; + osym = lsym; + string = lstring; + lstring += strlen (name) + 1; + ++lsym; + } - off = obj->ooffset + strtab->offset + symbol.st_name; - len = RTEMS_RTL_ELF_STRING_MAX; + /* + * Allocate any common symbols in the common section. + */ + if (symbol.st_shndx == SHN_COMMON) + { + size_t value_off = rtems_rtl_obj_align (common_offset, + symbol.st_value); + common_offset = value_off + symbol.st_size; + value = value_off; + } + else + { + value = symbol.st_value; + } - if (!rtems_rtl_obj_cache_read (strings, fd, off, (void**) &name, &len)) - return false; + rtems_chain_set_off_chain (&osym->node); + memcpy (string, name, strlen (name) + 1); + osym->name = string; + osym->value = (uint8_t*) value; + osym->data = symbol.st_shndx; - /* - * If a duplicate forget it. - */ - if (rtems_rtl_symbol_global_find (name)) - continue; + if (rtems_rtl_trace (RTEMS_RTL_TRACE_SYMBOL)) + printf ("rtl: sym:add:%-4d name:%-4d: %-20s: bind:%-2d " \ + "type:%-2d val:%-8p sect:%-3d size:%d\n", + sym, (int) symbol.st_name, osym->name, + (int) ELF_ST_BIND (symbol.st_info), + (int) ELF_ST_TYPE (symbol.st_info), + osym->value, symbol.st_shndx, + (int) symbol.st_size); + } + } - if ((ELF_ST_BIND (symbol.st_info) == STB_GLOBAL) || - (ELF_ST_BIND (symbol.st_info) == STB_WEAK)) - { - osym = gsym; - string = gstring; - gstring += strlen (name) + 1; - ++gsym; - } - else - { - osym = lsym; - string = lstring; - lstring += strlen (name) + 1; - ++lsym; - } + return true; +} - /* - * Allocate any common symbols in the common section. - */ - if (symbol.st_shndx == SHN_COMMON) - { - size_t value_off = rtems_rtl_obj_align (common_offset, - symbol.st_value); - common_offset = value_off + symbol.st_size; - value = value_off; - } - else - { - value = symbol.st_value; - } +static bool +rtems_rtl_elf_symbols_locate (rtems_rtl_obj* obj, + int fd, + rtems_rtl_obj_sect* sect, + void* data) +{ + int sym; - rtems_chain_set_off_chain (&osym->node); - memcpy (string, name, strlen (name) + 1); - osym->name = string; - osym->value = value + (uint8_t*) symsect->base; - osym->data = symbol.st_info; + for (sym = 0; sym < obj->local_syms; ++sym) + { + rtems_rtl_obj_sym* osym = &obj->local_table[sym]; + rtems_rtl_obj_sect* symsect; + symsect = rtems_rtl_obj_find_section_by_index (obj, osym->data); + if (symsect) + { + osym->value += (intptr_t) symsect->base; + if (rtems_rtl_trace (RTEMS_RTL_TRACE_SYMBOL)) + printf ("rtl: sym:locate:local :%-4d name: %-20s val:%-8p sect:%-3d (%s, %p)\n", + sym, osym->name, osym->value, osym->data, + symsect->name, symsect->base); + } + } + for (sym = 0; sym < obj->global_syms; ++sym) + { + rtems_rtl_obj_sym* osym = &obj->global_table[sym]; + rtems_rtl_obj_sect* symsect; + symsect = rtems_rtl_obj_find_section_by_index (obj, osym->data); + if (symsect) + { + osym->value += (intptr_t) symsect->base; if (rtems_rtl_trace (RTEMS_RTL_TRACE_SYMBOL)) - printf ("rtl: sym:add:%-2d name:%-2d:%-20s bind:%-2d " \ - "type:%-2d val:%8p sect:%d size:%d\n", - sym, (int) symbol.st_name, osym->name, - (int) ELF_ST_BIND (symbol.st_info), - (int) ELF_ST_TYPE (symbol.st_info), - osym->value, symbol.st_shndx, - (int) symbol.st_size); + printf ("rtl: sym:locate:global:%-4d name: %-20s val:%-8p sect:%-3d (%s, %p)\n", + sym, osym->name, osym->value, osym->data, + symsect->name, symsect->base); } - } } - if (globals) + if (obj->global_size) rtems_rtl_symbol_obj_add (obj); return true; @@ -1434,6 +1592,11 @@ rtems_rtl_elf_file_load (rtems_rtl_obj* obj, int fd) return false; } + /* + * Set the format's architecture's maximum tramp size. + */ + obj->tramp_size = rtems_rtl_elf_relocate_tramp_max_size (); + /* * Parse the section information first so we have the memory map of the object * file and the memory allocated. Any further allocations we make to complete @@ -1443,18 +1606,31 @@ rtems_rtl_elf_file_load (rtems_rtl_obj* obj, int fd) return false; /* - * See if there are any common variables and if there are add a common - * section. + * Set the entry point if there is one. + */ + obj->entry = (void*)(uintptr_t) ehdr.e_entry; + + /* + * Load the symbol table. + * + * 1. See if there are any common variables and if there are add a + * common section. + * 2. Add up the common. + * 3. */ if (!rtems_rtl_obj_load_symbols (obj, fd, rtems_rtl_elf_common, &common)) return false; if (!rtems_rtl_elf_add_common (obj, common.size, common.alignment)) return false; + if (!rtems_rtl_obj_load_symbols (obj, fd, rtems_rtl_elf_symbols_load, &ehdr)) + return false; /* - * Set the entry point if there is one. + * Parse the relocation records. It lets us know how many dependents + * and fixup trampolines there are. */ - obj->entry = (void*)(uintptr_t) ehdr.e_entry; + if (!rtems_rtl_obj_relocate (obj, fd, rtems_rtl_elf_relocs_parser, &relocs)) + return false; /* * Lock the allocator so the section memory and the trampoline memory are as @@ -1468,17 +1644,7 @@ rtems_rtl_elf_file_load (rtems_rtl_obj* obj, int fd) if (!rtems_rtl_obj_alloc_sections (obj, fd, rtems_rtl_elf_arch_alloc, &ehdr)) return false; - /* - * Load the sections and symbols and then relocation to the base address. - */ - if (!rtems_rtl_obj_load_sections (obj, fd, rtems_rtl_elf_loader, &ehdr)) - return false; - - /* - * Parse the relocation records. It lets us know how many dependents - * and fixup trampolines there are. - */ - if (!rtems_rtl_obj_relocate (obj, fd, rtems_rtl_elf_relocs_parser, &relocs)) + if (!rtems_rtl_obj_load_symbols (obj, fd, rtems_rtl_elf_symbols_locate, &ehdr)) return false; if (!rtems_rtl_elf_dependents (obj, &relocs)) @@ -1492,9 +1658,15 @@ rtems_rtl_elf_file_load (rtems_rtl_obj* obj, int fd) */ rtems_rtl_alloc_unlock (); - if (!rtems_rtl_obj_load_symbols (obj, fd, rtems_rtl_elf_symbols, &ehdr)) + /* + * Load the sections and symbols and then relocation to the base address. + */ + if (!rtems_rtl_obj_load_sections (obj, fd, rtems_rtl_elf_loader, &ehdr)) return false; + /* + * Fix up the relocations. + */ if (!rtems_rtl_obj_relocate (obj, fd, rtems_rtl_elf_relocs_locator, &ehdr)) return false; diff --git a/cpukit/libdl/rtl-elf.h b/cpukit/libdl/rtl-elf.h index 73d1e01bb1..660b0c47b4 100644 --- a/cpukit/libdl/rtl-elf.h +++ b/cpukit/libdl/rtl-elf.h @@ -51,6 +51,17 @@ extern "C" { ** Imported NetBSD ELF Specifics End. **/ +/** + * ELF Relocation status codes. + */ +typedef enum rtems_rtl_elf_rel_status +{ + rtems_rtl_elf_rel_no_error, /**< There is no error processing the record. */ + rtems_rtl_elf_rel_failure, /**< There was a failure processing the record. */ + rtems_rtl_elf_rel_tramp_cache, /**< The reloc record may need a trampoliine. */ + rtems_rtl_elf_rel_tramp_add /**< Add a trampoliine. */ +} rtems_rtl_elf_rel_status; + /** * Relocation trampoline relocation data. */ @@ -143,20 +154,19 @@ size_t rtems_rtl_elf_relocate_tramp_max_size (void); * relocation record requires a trampoline. * * @param obj The object file being relocated. - * @param rel The ELF relocation record. + * @param rela The ELF relocation record. * @param sect The section of the object file the relocation is for. * @param symname The symbol's name. * @param syminfo The ELF symbol info field. * @param symvalue If a symbol is referenced, this is the symbols value. - * @retval bool The relocation is valid. - * @retval bool The relocation is not valid. + * @retval rtems_rtl_elf_rel_status The result of the trampoline parsing. */ -bool rtems_rtl_elf_relocate_rel_tramp (rtems_rtl_obj* obj, - const Elf_Rel* rel, - const rtems_rtl_obj_sect* sect, - const char* symname, - const Elf_Byte syminfo, - const Elf_Word symvalue); +rtems_rtl_elf_rel_status rtems_rtl_elf_relocate_rel_tramp (rtems_rtl_obj* obj, + const Elf_Rel* rel, + const rtems_rtl_obj_sect* sect, + const char* symname, + const Elf_Byte syminfo, + const Elf_Word symvalue); /** * Architecture specific relocation handler compiled in for a specific @@ -169,15 +179,14 @@ bool rtems_rtl_elf_relocate_rel_tramp (rtems_rtl_obj* obj, * @param symname The symbol's name. * @param syminfo The ELF symbol info field. * @param symvalue If a symbol is referenced, this is the symbols value. - * @retval bool The relocation is valid. - * @retval bool The relocation is not valid. + * @retval rtems_rtl_elf_rel_status The result of the trampoline parsing. */ -bool rtems_rtl_elf_relocate_rela_tramp (rtems_rtl_obj* obj, - const Elf_Rela* rela, - const rtems_rtl_obj_sect* sect, - const char* symname, - const Elf_Byte syminfo, - const Elf_Word symvalue); +rtems_rtl_elf_rel_status rtems_rtl_elf_relocate_rela_tramp (rtems_rtl_obj* obj, + const Elf_Rela* rela, + const rtems_rtl_obj_sect* sect, + const char* symname, + const Elf_Byte syminfo, + const Elf_Word symvalue); /** * Architecture specific relocation handler compiled in for a specific @@ -190,15 +199,14 @@ bool rtems_rtl_elf_relocate_rela_tramp (rtems_rtl_obj* obj, * @param symname The symbol's name. * @param syminfo The ELF symbol info field. * @param symvalue If a symbol is referenced, this is the symbols value. - * @retval bool The relocation has been applied. - * @retval bool The relocation could not be applied. + * @retval rtems_rtl_elf_rel_status The result of the trampoline parsing. */ -bool rtems_rtl_elf_relocate_rel (rtems_rtl_obj* obj, - const Elf_Rel* rel, - const rtems_rtl_obj_sect* sect, - const char* symname, - const Elf_Byte syminfo, - const Elf_Word symvalue); +rtems_rtl_elf_rel_status rtems_rtl_elf_relocate_rel (rtems_rtl_obj* obj, + const Elf_Rel* rel, + const rtems_rtl_obj_sect* sect, + const char* symname, + const Elf_Byte syminfo, + const Elf_Word symvalue); /** * Architecture specific relocation handler compiled in for a specific @@ -211,15 +219,14 @@ bool rtems_rtl_elf_relocate_rel (rtems_rtl_obj* obj, * @param symname The symbol's name. * @param syminfo The ELF symbol info field. * @param symvalue If a symbol is referenced, this is the symbols value. - * @retval bool The relocation has been applied. - * @retval bool The relocation could not be applied. + * @retval rtems_rtl_elf_rel_status The result of the trampoline parsing. */ -bool rtems_rtl_elf_relocate_rela (rtems_rtl_obj* obj, - const Elf_Rela* rela, - const rtems_rtl_obj_sect* sect, - const char* symname, - const Elf_Byte syminfo, - const Elf_Word symvalue); +rtems_rtl_elf_rel_status rtems_rtl_elf_relocate_rela (rtems_rtl_obj* obj, + const Elf_Rela* rela, + const rtems_rtl_obj_sect* sect, + const char* symname, + const Elf_Byte syminfo, + const Elf_Word symvalue); /** * The ELF format check handler. diff --git a/cpukit/libdl/rtl-mdreloc-arm.c b/cpukit/libdl/rtl-mdreloc-arm.c index b0c55c257a..4d5a2456a7 100644 --- a/cpukit/libdl/rtl-mdreloc-arm.c +++ b/cpukit/libdl/rtl-mdreloc-arm.c @@ -147,7 +147,7 @@ rtems_rtl_elf_rel_resolve_sym (Elf_Word type) return true; } -bool +rtems_rtl_elf_rel_status rtems_rtl_elf_relocate_rela_tramp (rtems_rtl_obj* obj, const Elf_Rela* rela, const rtems_rtl_obj_sect* sect, @@ -162,10 +162,10 @@ rtems_rtl_elf_relocate_rela_tramp (rtems_rtl_obj* obj, (void) syminfo; (void) symvalue; rtems_rtl_set_error (EINVAL, "rela type record not supported"); - return false; + return rtems_rtl_elf_rel_failure; } -bool +rtems_rtl_elf_rel_status rtems_rtl_elf_relocate_rela (rtems_rtl_obj* obj, const Elf_Rela* rela, const rtems_rtl_obj_sect* sect, @@ -180,10 +180,10 @@ rtems_rtl_elf_relocate_rela (rtems_rtl_obj* obj, (void) syminfo; (void) symvalue; rtems_rtl_set_error (EINVAL, "rela type record not supported"); - return false; + return rtems_rtl_elf_rel_failure; } -static bool +static rtems_rtl_elf_rel_status rtems_rtl_elf_reloc_rel (rtems_rtl_obj* obj, const Elf_Rel* rel, const rtems_rtl_obj_sect* sect, @@ -209,24 +209,37 @@ rtems_rtl_elf_reloc_rel (rtems_rtl_obj* obj, case R_TYPE(CALL): /* BL/BLX */ case R_TYPE(JUMP24): /* B/BL */ - insn = *where; - - if (insn & 0x00800000) - addend = insn | 0xff000000; - else addend = insn & 0x00ffffff; - - if (isThumb(symvalue)) { - if ((insn & 0xfe000000) == 0xfa000000); /* Already blx */ - else { - if ((insn & 0xff000000) == 0xeb000000) { /* BL