From ae5fe7e6bca2874c5f1ef077204bb63124fb3db3 Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Sun, 26 Oct 2014 18:09:41 -0700 Subject: cpukit: Add libdl with the Runtime Loader (RTL) code. This is a merge of the RTL project. --- cpukit/libdl/rtl-sym.c | 245 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 245 insertions(+) create mode 100644 cpukit/libdl/rtl-sym.c (limited to 'cpukit/libdl/rtl-sym.c') diff --git a/cpukit/libdl/rtl-sym.c b/cpukit/libdl/rtl-sym.c new file mode 100644 index 0000000000..f8063948bd --- /dev/null +++ b/cpukit/libdl/rtl-sym.c @@ -0,0 +1,245 @@ +/* + * COPYRIGHT (c) 2012 Chris Johns + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + */ +/** + * @file + * + * @ingroup rtems_rtl + * + * @brief RTEMS Run-Time Linker Object File Symbol Table. + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include + +#include +#include "rtl-error.h" +#include "rtl-sym.h" +#include "rtl-trace.h" + +/** + * The single symbol forced into the global symbol table that is used to load a + * symbol table from an object file. + */ +static rtems_rtl_obj_sym_t global_sym_add = +{ + .name = "rtems_rtl_base_sym_global_add", + .value = (void*) rtems_rtl_base_sym_global_add +}; + +static uint_fast32_t +rtems_rtl_symbol_hash (const char *s) +{ + uint_fast32_t h = 5381; + unsigned char c; + for (c = *s; c != '\0'; c = *++s) + h = h * 33 + c; + return h & 0xffffffff; +} + +static void +rtems_rtl_symbol_global_insert (rtems_rtl_symbols_t* symbols, + rtems_rtl_obj_sym_t* symbol) +{ + uint_fast32_t hash = rtems_rtl_symbol_hash (symbol->name); + rtems_chain_append (&symbols->buckets[hash % symbols->nbuckets], + &symbol->node); +} + +bool +rtems_rtl_symbol_table_open (rtems_rtl_symbols_t* symbols, + size_t buckets) +{ + symbols->buckets = rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_SYMBOL, + buckets * sizeof (rtems_chain_control), + true); + if (!symbols->buckets) + { + rtems_rtl_set_error (ENOMEM, "no memory for global symbol table"); + return false; + } + symbols->nbuckets = buckets; + for (buckets = 0; buckets < symbols->nbuckets; ++buckets) + rtems_chain_initialize_empty (&symbols->buckets[buckets]); + rtems_rtl_symbol_global_insert (symbols, &global_sym_add); + return true; +} + +void +rtems_rtl_symbol_table_close (rtems_rtl_symbols_t* symbols) +{ + rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_SYMBOL, symbols->buckets); +} + +bool +rtems_rtl_symbol_global_add (rtems_rtl_obj_t* obj, + const unsigned char* esyms, + unsigned int size) +{ + rtems_rtl_symbols_t* symbols; + rtems_rtl_obj_sym_t* sym; + size_t count; + size_t s; + uint32_t marker; + + count = 0; + s = 0; + while ((s < size) && (esyms[s] != 0)) + { + int l = strlen ((char*) &esyms[s]); + if ((esyms[s + l] != '\0') || ((s + l) > size)) + { + rtems_rtl_set_error (EINVAL, "invalid exported symbol table"); + return false; + } + ++count; + s += l + sizeof (unsigned long) + 1; + } + + /* + * Check this is the correct end of the table. + */ + marker = esyms[s + 1]; + marker <<= 8; + marker |= esyms[s + 2]; + marker <<= 8; + marker |= esyms[s + 3]; + marker <<= 8; + marker |= esyms[s + 4]; + + if (marker != 0xdeadbeefUL) + { + rtems_rtl_set_error (ENOMEM, "invalid export symbol table"); + return false; + } + + if (rtems_rtl_trace (RTEMS_RTL_TRACE_GLOBAL_SYM)) + printf ("rtl: global symbol add: %zi\n", count); + + obj->global_size = count * sizeof (rtems_rtl_obj_sym_t); + obj->global_table = rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_SYMBOL, + obj->global_size, true); + if (!obj->global_table) + { + obj->global_size = 0; + rtems_rtl_set_error (ENOMEM, "no memory for global symbols"); + return false; + } + + symbols = rtems_rtl_global_symbols (); + + s = 0; + sym = obj->global_table; + + while ((s < size) && (esyms[s] != 0)) + { + /* + * Copy the void* using a union and memcpy to avoid any strict aliasing or + * alignment issues. The variable length of the label and the packed nature + * of the table means casting is not suitable. + */ + union { + uint8_t data[sizeof (void*)]; + void* value; + } copy_voidp; + int b; + + sym->name = (const char*) &esyms[s]; + s += strlen (sym->name) + 1; + for (b = 0; b < sizeof (void*); ++b, ++s) + copy_voidp.data[b] = esyms[s]; + sym->value = copy_voidp.value; + if (rtems_rtl_trace (RTEMS_RTL_TRACE_GLOBAL_SYM)) + printf ("rtl: esyms: %s -> %8p\n", sym->name, sym->value); + if (rtems_rtl_symbol_global_find (sym->name) == NULL) + rtems_rtl_symbol_global_insert (symbols, sym); + ++sym; + } + + obj->global_syms = count; + + return true; +} + +rtems_rtl_obj_sym_t* +rtems_rtl_symbol_global_find (const char* name) +{ + rtems_rtl_symbols_t* symbols; + uint_fast32_t hash; + rtems_chain_control* bucket; + rtems_chain_node* node; + + symbols = rtems_rtl_global_symbols (); + + hash = rtems_rtl_symbol_hash (name); + bucket = &symbols->buckets[hash % symbols->nbuckets]; + node = rtems_chain_first (bucket); + + while (!rtems_chain_is_tail (bucket, node)) + { + rtems_rtl_obj_sym_t* sym = (rtems_rtl_obj_sym_t*) node; + /* + * Use the hash. I could add this to the symbol but it uses more memory. + */ + if (strcmp (name, sym->name) == 0) + return sym; + node = rtems_chain_next (node); + } + + return NULL; +} + +rtems_rtl_obj_sym_t* +rtems_rtl_symbol_obj_find (rtems_rtl_obj_t* obj, const char* name) +{ + rtems_rtl_obj_sym_t* sym; + size_t s; + /* + * 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; + return rtems_rtl_symbol_global_find (name); +} + +void +rtems_rtl_symbol_obj_add (rtems_rtl_obj_t* obj) +{ + rtems_rtl_symbols_t* symbols; + rtems_rtl_obj_sym_t* sym; + size_t s; + + symbols = rtems_rtl_global_symbols (); + + for (s = 0, sym = obj->global_table; s < obj->global_syms; ++s, ++sym) + rtems_rtl_symbol_global_insert (symbols, sym); +} + +void +rtems_rtl_symbol_obj_erase (rtems_rtl_obj_t* obj) +{ + if (obj->global_table) + { + rtems_rtl_obj_sym_t* sym; + size_t s; + for (s = 0, sym = obj->global_table; s < obj->global_syms; ++s, ++sym) + if (!rtems_chain_is_node_off_chain (&sym->node)) + rtems_chain_extract (&sym->node); + rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_SYMBOL, obj->global_table); + obj->global_table = NULL; + obj->global_size = 0; + obj->global_syms = 0; + } +} -- cgit v1.2.3