From a2e1e30d9862b0f926f694d146ab0e7450aa759b Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Tue, 4 Nov 2014 12:12:25 +1100 Subject: libdl: Add a local symbol table to the object module. Adding a local symbol lets the relocator find local symbols referenced in relocation records. The local symbol table is erased once the object module has been loaded. --- cpukit/libdl/rtl-elf.c | 235 +++++++++++++++++++++++++++++++---------------- cpukit/libdl/rtl-obj.h | 3 + cpukit/libdl/rtl-sym.c | 30 +++++- cpukit/libdl/rtl-sym.h | 9 +- cpukit/libdl/rtl-trace.h | 3 +- 5 files changed, 193 insertions(+), 87 deletions(-) (limited to 'cpukit/libdl') diff --git a/cpukit/libdl/rtl-elf.c b/cpukit/libdl/rtl-elf.c index e4f1ffc007..46f5613014 100644 --- a/cpukit/libdl/rtl-elf.c +++ b/cpukit/libdl/rtl-elf.c @@ -1,5 +1,5 @@ /* - * COPYRIGHT (c) 2012 Chris Johns + * COPYRIGHT (c) 2012-2014 Chris Johns * * The license and distribution terms for this file may be * found in the file LICENSE in this distribution or at @@ -73,7 +73,10 @@ rtems_rtl_elf_find_symbol (rtems_rtl_obj_t* obj, if (ELF_ST_TYPE(sym->st_info) == STT_NOTYPE) { - rtems_rtl_obj_sym_t* symbol = rtems_rtl_symbol_global_find (symname); + /* + * Search the object file then the global table for the symbol. + */ + rtems_rtl_obj_sym_t* symbol = rtems_rtl_symbol_obj_find (obj, symname); if (!symbol) { rtems_rtl_set_error (EINVAL, "global symbol not found: %s", symname); @@ -337,9 +340,14 @@ rtems_rtl_elf_symbols (rtems_rtl_obj_t* obj, rtems_rtl_obj_cache_t* symbols; rtems_rtl_obj_cache_t* strings; rtems_rtl_obj_sect_t* strtab; + int locals; + int local_string_space; + rtems_rtl_obj_sym_t* lsym; + char* lstring; int globals; - int string_space; - char* string; + int global_string_space; + rtems_rtl_obj_sym_t* gsym; + char* gstring; int sym; strtab = rtems_rtl_obj_find_section (obj, ".strtab"); @@ -359,8 +367,10 @@ rtems_rtl_elf_symbols (rtems_rtl_obj_t* obj, * needed. Also check for duplicate symbols. */ - globals = 0; - string_space = 0; + globals = 0; + global_string_space = 0; + locals = 0; + local_string_space = 0; for (sym = 0; sym < (sect->size / sizeof (Elf_Sym)); ++sym) { @@ -382,121 +392,181 @@ rtems_rtl_elf_symbols (rtems_rtl_obj_t* obj, return false; /* - * Only keep the functions and global or weak symbols. + * Only keep the functions and global or weak symbols so place them in a + * separate table to local symbols. Local symbols are not needed after the + * object file has been loaded. Undefined symbols are NOTYPE so for locals + * we need to make sure there is a valid seciton. */ - if ((ELF_ST_TYPE (symbol.st_info) == STT_OBJECT) || - (ELF_ST_TYPE (symbol.st_info) == STT_FUNC)) + if ((symbol.st_shndx != 0) && + ((ELF_ST_TYPE (symbol.st_info) == STT_OBJECT) || + (ELF_ST_TYPE (symbol.st_info) == STT_FUNC) || + (ELF_ST_TYPE (symbol.st_info) == STT_NOTYPE))) { - if ((ELF_ST_BIND (symbol.st_info) == STB_GLOBAL) || - (ELF_ST_BIND (symbol.st_info) == STB_WEAK)) + rtems_rtl_obj_sect_t* symsect; + + symsect = rtems_rtl_obj_find_section_by_index (obj, symbol.st_shndx); + if (symsect) { - /* - * If there is a globally exported symbol already present and this - * symbol is not weak raise an error. If the symbol is weak and present - * globally ignore this symbol and use the global one and if it is not - * present take this symbol global or weak. We accept the first weak - * symbol we find and make it globally exported. - */ - if (rtems_rtl_symbol_global_find (name) && - (ELF_ST_BIND (symbol.st_info) != STB_WEAK)) + if ((ELF_ST_BIND (symbol.st_info) == STB_GLOBAL) || + (ELF_ST_BIND (symbol.st_info) == STB_WEAK)) { - rtems_rtl_set_error (ENOMEM, "duplicate global symbol: %s", name); - return false; + /* + * If there is a globally exported symbol already present and this + * symbol is not weak raise an error. If the symbol is weak and + * present globally ignore this symbol and use the global one and if + * it is not present take this symbol global or weak. We accept the + * first weak symbol we find and make it globally exported. + */ + if (rtems_rtl_symbol_global_find (name) && + (ELF_ST_BIND (symbol.st_info) != STB_WEAK)) + { + rtems_rtl_set_error (ENOMEM, "duplicate global symbol: %s", name); + return false; + } + else + { + ++globals; + global_string_space += strlen (name) + 1; + } } - else + else if (ELF_ST_BIND (symbol.st_info) == STB_LOCAL) { - ++globals; - string_space += strlen (name) + 1; + ++locals; + local_string_space += strlen (name) + 1; } } } } - if (globals) + if (locals) { - rtems_rtl_obj_sym_t* gsym; + obj->local_size = locals * sizeof (rtems_rtl_obj_sym_t) + local_string_space; + obj->local_table = rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_SYMBOL, + obj->local_size, true); + if (!obj->local_table) + { + obj->local_size = 0; + rtems_rtl_set_error (ENOMEM, "no memory for obj local syms"); + return false; + } + + obj->local_syms = locals; + } - obj->global_size = globals * sizeof (rtems_rtl_obj_sym_t) + string_space; + if (globals) + { + obj->global_size = globals * sizeof (rtems_rtl_obj_sym_t) + global_string_space; obj->global_table = rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_SYMBOL, obj->global_size, true); if (!obj->global_table) { + if (locals) + { + rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_SYMBOL, obj->local_table); + obj->local_size = 0; + obj->local_syms = 0; + } obj->global_size = 0; rtems_rtl_set_error (ENOMEM, "no memory for obj global syms"); return false; } obj->global_syms = globals; + } - for (sym = 0, - gsym = obj->global_table, - string = (((char*) obj->global_table) + - (globals * sizeof (rtems_rtl_obj_sym_t))); - sym < (sect->size / sizeof (Elf_Sym)); - ++sym) - { - Elf_Sym symbol; - off_t off; - const char* name; - size_t len; + lsym = obj->local_table; + lstring = + (((char*) obj->local_table) + (locals * sizeof (rtems_rtl_obj_sym_t))); + gsym = obj->global_table; + gstring = + (((char*) obj->global_table) + (globals * sizeof (rtems_rtl_obj_sym_t))); + + for (sym = 0; sym < (sect->size / sizeof (Elf_Sym)); ++sym) + { + Elf_Sym symbol; + off_t off; + const char* name; + size_t len; - off = obj->ooffset + sect->offset + (sym * sizeof (symbol)); + off = obj->ooffset + sect->offset + (sym * sizeof (symbol)); - if (!rtems_rtl_obj_cache_read_byval (symbols, fd, off, - &symbol, sizeof (symbol))) + if (!rtems_rtl_obj_cache_read_byval (symbols, fd, off, + &symbol, sizeof (symbol))) + { + if (locals) { - free (obj->global_table); + 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) + { + rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_SYMBOL, obj->global_table); obj->global_table = NULL; obj->global_syms = 0; obj->global_size = 0; - return false; } + return false; + } - off = obj->ooffset + strtab->offset + symbol.st_name; - len = RTEMS_RTL_ELF_STRING_MAX; + 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 (!rtems_rtl_obj_cache_read (strings, fd, off, (void**) &name, &len)) + return false; - if (((ELF_ST_TYPE (symbol.st_info) == STT_OBJECT) || - (ELF_ST_TYPE (symbol.st_info) == STT_FUNC)) && - ((ELF_ST_BIND (symbol.st_info) == STB_GLOBAL) || - (ELF_ST_BIND (symbol.st_info) == STB_WEAK))) + if ((symbol.st_shndx != 0) && + ((ELF_ST_TYPE (symbol.st_info) == STT_OBJECT) || + (ELF_ST_TYPE (symbol.st_info) == STT_FUNC) || + (ELF_ST_TYPE (symbol.st_info) == STT_NOTYPE)) && + ((ELF_ST_BIND (symbol.st_info) == STB_GLOBAL) || + (ELF_ST_BIND (symbol.st_info) == STB_WEAK) || + (ELF_ST_BIND (symbol.st_info) == STB_LOCAL))) { rtems_rtl_obj_sect_t* symsect; + rtems_rtl_obj_sym_t* osym; + char* string; + symsect = rtems_rtl_obj_find_section_by_index (obj, symbol.st_shndx); - if (!symsect) + if (symsect) { - free (obj->global_table); - obj->global_table = NULL; - obj->global_syms = 0; - obj->global_size = 0; - rtems_rtl_set_error (EINVAL, "sym section not found"); - return false; + 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; + } + + rtems_chain_set_off_chain (&osym->node); + memcpy (string, name, strlen (name) + 1); + osym->name = string; + osym->value = symbol.st_value + (uint8_t*) symsect->base; + osym->data = symbol.st_info; + + 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); } - - rtems_chain_set_off_chain (&gsym->node); - - memcpy (string, name, strlen (name) + 1); - gsym->name = string; - string += strlen (name) + 1; - gsym->value = symbol.st_value + (uint8_t*) symsect->base; - gsym->data = symbol.st_info; - - 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, gsym->name, - (int) ELF_ST_BIND (symbol.st_info), - (int) ELF_ST_TYPE (symbol.st_info), - gsym->value, symbol.st_shndx, - (int) symbol.st_size); - - ++gsym; } - } + } + if (globals) rtems_rtl_symbol_obj_add (obj); - } return true; } @@ -631,8 +701,9 @@ rtems_rtl_elf_parse_sections (rtems_rtl_obj_t* obj, int fd, Elf_Ehdr* ehdr) break; default: - printf ("rtl: unsupported section: %2d: type=%02d flags=%02x\n", - section, (int) shdr.sh_type, (int) shdr.sh_flags); + if (rtems_rtl_trace (RTEMS_RTL_TRACE_WARNING)) + printf ("rtl: unsupported section: %2d: type=%02d flags=%02x\n", + section, (int) shdr.sh_type, (int) shdr.sh_flags); break; } @@ -867,6 +938,8 @@ rtems_rtl_elf_file_load (rtems_rtl_obj_t* obj, int fd) if (!rtems_rtl_obj_relocate (obj, fd, rtems_rtl_elf_relocator, &ehdr)) return false; + rtems_rtl_symbol_obj_erase_local (obj); + if (!rtems_rtl_elf_load_details (obj)) { return false; diff --git a/cpukit/libdl/rtl-obj.h b/cpukit/libdl/rtl-obj.h index 05507232ca..96c76808ab 100644 --- a/cpukit/libdl/rtl-obj.h +++ b/cpukit/libdl/rtl-obj.h @@ -145,6 +145,9 @@ struct rtems_rtl_obj_s size_t fsize; /**< Size of the object file. */ rtems_chain_control sections; /**< The sections of interest in the * object file. */ + rtems_rtl_obj_sym_t* local_table; /**< Local symbol table. */ + size_t local_syms; /**< Local symbol count. */ + size_t local_size; /**< Local symbol memory usage. */ rtems_rtl_obj_sym_t* global_table; /**< Global symbol table. */ size_t global_syms; /**< Global symbol count. */ size_t global_size; /**< Global symbol memory usage. */ diff --git a/cpukit/libdl/rtl-sym.c b/cpukit/libdl/rtl-sym.c index f8063948bd..ebd68412c0 100644 --- a/cpukit/libdl/rtl-sym.c +++ b/cpukit/libdl/rtl-sym.c @@ -1,5 +1,5 @@ /* - * COPYRIGHT (c) 2012 Chris Johns + * COPYRIGHT (c) 2012-2014 Chris Johns * * The license and distribution terms for this file may be * found in the file LICENSE in this distribution or at @@ -208,9 +208,18 @@ rtems_rtl_symbol_obj_find (rtems_rtl_obj_t* obj, const char* name) * Check the object file's symbols first. If not found search the * global symbol table. */ - for (s = 0, sym = obj->global_table; s < obj->global_syms; ++s, ++sym) - if (strcmp (name, sym->name) == 0) - return sym; + if (obj->local_syms) + { + for (s = 0, sym = obj->local_table; s < obj->local_syms; ++s, ++sym) + if (strcmp (name, sym->name) == 0) + return sym; + } + if (obj->global_syms) + { + for (s = 0, sym = obj->global_table; s < obj->global_syms; ++s, ++sym) + if (strcmp (name, sym->name) == 0) + return sym; + } return rtems_rtl_symbol_global_find (name); } @@ -227,9 +236,22 @@ rtems_rtl_symbol_obj_add (rtems_rtl_obj_t* obj) rtems_rtl_symbol_global_insert (symbols, sym); } +void +rtems_rtl_symbol_obj_erase_local (rtems_rtl_obj_t* obj) +{ + if (obj->local_table) + { + rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_SYMBOL, obj->local_table); + obj->local_table = NULL; + obj->local_size = 0; + obj->local_syms = 0; + } +} + void rtems_rtl_symbol_obj_erase (rtems_rtl_obj_t* obj) { + rtems_rtl_symbol_obj_erase_local (obj); if (obj->global_table) { rtems_rtl_obj_sym_t* sym; diff --git a/cpukit/libdl/rtl-sym.h b/cpukit/libdl/rtl-sym.h index b793a547dc..9bd40ec241 100644 --- a/cpukit/libdl/rtl-sym.h +++ b/cpukit/libdl/rtl-sym.h @@ -1,5 +1,5 @@ /* - * COPYRIGHT (c) 2012 Chris Johns + * COPYRIGHT (c) 2012-2014 Chris Johns * * The license and distribution terms for this file may be * found in the file LICENSE in this distribution or at @@ -114,6 +114,13 @@ rtems_rtl_obj_sym_t* rtems_rtl_symbol_obj_find (rtems_rtl_obj_t* obj, */ void rtems_rtl_symbol_obj_add (rtems_rtl_obj_t* obj); +/** + * Erase the object file's local symbols. + * + * @param obj The object file the local symbols are to be erased from. + */ +void rtems_rtl_symbol_obj_erase_local (rtems_rtl_obj_t* obj); + /** * Erase the object file's symbols. * diff --git a/cpukit/libdl/rtl-trace.h b/cpukit/libdl/rtl-trace.h index 1a5ee973a5..141b3769a5 100644 --- a/cpukit/libdl/rtl-trace.h +++ b/cpukit/libdl/rtl-trace.h @@ -1,5 +1,5 @@ /* - * COPYRIGHT (c) 2012 Chris Johns + * COPYRIGHT (c) 2012-2014 Chris Johns * * The license and distribution terms for this file may be * found in the file LICENSE in this distribution or at @@ -47,6 +47,7 @@ typedef uint32_t rtems_rtl_trace_mask; #define RTEMS_RTL_TRACE_ALLOCATOR (1UL << 7) #define RTEMS_RTL_TRACE_UNRESOLVED (1UL << 8) #define RTEMS_RTL_TRACE_DETAIL (1UL << 9) +#define RTEMS_RTL_TRACE_WARNING (1UL << 10) /** * Call to check if this part is bring traced. If RTEMS_RTL_TRACE is defined to -- cgit v1.2.3