Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:24:16

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /**
0004  * @file
0005  *
0006  * @ingroup rtems_rtl
0007  *
0008  * @brief RTEMS Run-Time Linker Object File Symbol Table.
0009  */
0010 
0011 /*
0012  *  COPYRIGHT (c) 2012-2014, 2018 Chris Johns <chrisj@rtems.org>
0013  *
0014  * Redistribution and use in source and binary forms, with or without
0015  * modification, are permitted provided that the following conditions
0016  * are met:
0017  * 1. Redistributions of source code must retain the above copyright
0018  *    notice, this list of conditions and the following disclaimer.
0019  * 2. Redistributions in binary form must reproduce the above copyright
0020  *    notice, this list of conditions and the following disclaimer in the
0021  *    documentation and/or other materials provided with the distribution.
0022  *
0023  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0024  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0025  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0026  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0027  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0028  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0029  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0030  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0031  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0032  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0033  * POSSIBILITY OF SUCH DAMAGE.
0034  */
0035 
0036 #ifdef HAVE_CONFIG_H
0037 #include "config.h"
0038 #endif
0039 
0040 #include <errno.h>
0041 #include <inttypes.h>
0042 #include <stdlib.h>
0043 #include <stdio.h>
0044 #include <string.h>
0045 
0046 #include <rtems/rtl/rtl.h>
0047 #include "rtl-error.h"
0048 #include <rtems/rtl/rtl-sym.h>
0049 #include <rtems/rtl/rtl-trace.h>
0050 
0051 /**
0052  * The single symbol forced into the global symbol table that is used to load a
0053  * symbol table from an object file.
0054  */
0055 static rtems_rtl_obj_sym global_sym_add =
0056 {
0057   .name  = "rtems_rtl_base_sym_global_add",
0058   .value = (void*) rtems_rtl_base_sym_global_add
0059 };
0060 
0061 static uint_fast32_t
0062 rtems_rtl_symbol_hash (const char *s)
0063 {
0064   uint_fast32_t h = 5381;
0065   unsigned char c;
0066   for (c = *s; c != '\0'; c = *++s)
0067     h = h * 33 + c;
0068   return h & 0xffffffff;
0069 }
0070 
0071 static void
0072 rtems_rtl_symbol_global_insert (rtems_rtl_symbols* symbols,
0073                                 rtems_rtl_obj_sym* symbol)
0074 {
0075   uint_fast32_t hash = rtems_rtl_symbol_hash (symbol->name);
0076   rtems_chain_append (&symbols->buckets[hash % symbols->nbuckets],
0077                       &symbol->node);
0078 }
0079 
0080 static const rtems_rtl_tls_offset*
0081 rtems_rtl_symbol_find_tls_offset (size_t                      index,
0082                                   const rtems_rtl_tls_offset* tls_offsets,
0083                                   size_t                      tls_size)
0084 {
0085   size_t entry;
0086   for (entry = 0; entry < tls_size; ++entry)
0087   {
0088     if (tls_offsets[entry].index == index)
0089     {
0090       return &tls_offsets[entry];
0091     }
0092   }
0093   return NULL;
0094 }
0095 
0096 bool
0097 rtems_rtl_symbol_table_open (rtems_rtl_symbols* symbols,
0098                              size_t             buckets)
0099 {
0100   symbols->buckets = rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_SYMBOL,
0101                                           buckets * sizeof (rtems_chain_control),
0102                                           true);
0103   if (!symbols->buckets)
0104   {
0105     rtems_rtl_set_error (ENOMEM, "no memory for global symbol table");
0106     return false;
0107   }
0108   symbols->nbuckets = buckets;
0109   for (buckets = 0; buckets < symbols->nbuckets; ++buckets)
0110     rtems_chain_initialize_empty (&symbols->buckets[buckets]);
0111   rtems_rtl_symbol_global_insert (symbols, &global_sym_add);
0112   return true;
0113 }
0114 
0115 void
0116 rtems_rtl_symbol_table_close (rtems_rtl_symbols* symbols)
0117 {
0118   rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_SYMBOL, symbols->buckets);
0119 }
0120 
0121 bool
0122 rtems_rtl_symbol_global_add (rtems_rtl_obj*              obj,
0123                              const unsigned char*        esyms,
0124                              unsigned int                size,
0125                              const rtems_rtl_tls_offset* tls_offsets,
0126                              unsigned int                tls_size)
0127 {
0128   rtems_rtl_symbols* symbols;
0129   rtems_rtl_obj_sym* sym;
0130   size_t             count;
0131   size_t             s;
0132   uint32_t           marker;
0133 
0134   count = 0;
0135   s = 0;
0136   while ((s < size) && (esyms[s] != 0))
0137   {
0138     int l = strlen ((char*) &esyms[s]);
0139     if ((esyms[s + l] != '\0') || ((s + l) > size))
0140     {
0141       rtems_rtl_set_error (EINVAL, "invalid exported symbol table");
0142       return false;
0143     }
0144     ++count;
0145     s += l + sizeof (void *) + 1;
0146   }
0147 
0148   /*
0149    * Check this is the correct end of the table.
0150    */
0151   marker = esyms[s + 1];
0152   marker <<= 8;
0153   marker |= esyms[s + 2];
0154   marker <<= 8;
0155   marker |= esyms[s + 3];
0156   marker <<= 8;
0157   marker |= esyms[s + 4];
0158 
0159   if (marker != 0xdeadbeefUL)
0160   {
0161     rtems_rtl_set_error (ENOMEM, "invalid export symbol table");
0162     return false;
0163   }
0164 
0165   if (rtems_rtl_trace (RTEMS_RTL_TRACE_GLOBAL_SYM))
0166     printf ("rtl: global symbol add: %zi\n", count);
0167 
0168   obj->global_size = count * sizeof (rtems_rtl_obj_sym);
0169   obj->global_table = rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_SYMBOL,
0170                                            obj->global_size, true);
0171   if (!obj->global_table)
0172   {
0173     obj->global_size = 0;
0174     rtems_rtl_set_error (ENOMEM, "no memory for global symbols");
0175     return false;
0176   }
0177 
0178   symbols = rtems_rtl_global_symbols ();
0179 
0180   obj->global_syms = count;
0181 
0182   count = 0;
0183   s = 0;
0184   sym = obj->global_table;
0185 
0186   while ((s < size) && (esyms[s] != 0))
0187   {
0188     /*
0189      * Copy the void* using a union and memcpy to avoid any strict aliasing or
0190      * alignment issues. The variable length of the label and the packed nature
0191      * of the table means casting is not suitable.
0192      */
0193     union {
0194       uint8_t data[sizeof (void*)];
0195       void*   voidp;
0196     } copy_voidp;
0197     const rtems_rtl_tls_offset* tls_off;
0198     int b;
0199 
0200     sym->name = (const char*) &esyms[s];
0201     s += strlen (sym->name) + 1;
0202     for (b = 0; b < sizeof (void*); ++b, ++s)
0203       copy_voidp.data[b] = esyms[s];
0204     tls_off = rtems_rtl_symbol_find_tls_offset (count, tls_offsets, tls_size);
0205     if (tls_off == NULL) {
0206       sym->value = copy_voidp.voidp;
0207     } else {
0208       sym->value = (void*) tls_off->offset();
0209     }
0210     if (rtems_rtl_trace (RTEMS_RTL_TRACE_GLOBAL_SYM))
0211       printf ("rtl: esyms: %s -> %8p\n", sym->name, sym->value);
0212     if (rtems_rtl_symbol_global_find (sym->name) == NULL)
0213       rtems_rtl_symbol_global_insert (symbols, sym);
0214     ++count;
0215     ++sym;
0216   }
0217 
0218   return true;
0219 }
0220 
0221 rtems_rtl_obj_sym*
0222 rtems_rtl_symbol_global_find (const char* name)
0223 {
0224   rtems_rtl_symbols*   symbols;
0225   uint_fast32_t        hash;
0226   rtems_chain_control* bucket;
0227   rtems_chain_node*    node;
0228 
0229   symbols = rtems_rtl_global_symbols ();
0230 
0231   hash = rtems_rtl_symbol_hash (name);
0232   bucket = &symbols->buckets[hash % symbols->nbuckets];
0233   node = rtems_chain_first (bucket);
0234 
0235   while (!rtems_chain_is_tail (bucket, node))
0236   {
0237     rtems_rtl_obj_sym* sym = (rtems_rtl_obj_sym*) node;
0238     /*
0239      * Use the hash. I could add this to the symbol but it uses more memory.
0240      */
0241     if (strcmp (name, sym->name) == 0)
0242       return sym;
0243     node = rtems_chain_next (node);
0244   }
0245 
0246   return NULL;
0247 }
0248 
0249 static int
0250 rtems_rtl_symbol_obj_compare (const void* a, const void* b)
0251 {
0252   const rtems_rtl_obj_sym* sa;
0253   const rtems_rtl_obj_sym* sb;
0254   sa = (const rtems_rtl_obj_sym*) a;
0255   sb = (const rtems_rtl_obj_sym*) b;
0256   return strcmp (sa->name, sb->name);
0257 }
0258 
0259 void
0260 rtems_rtl_symbol_obj_sort (rtems_rtl_obj* obj)
0261 {
0262   qsort (obj->local_table,
0263          obj->local_syms,
0264          sizeof (rtems_rtl_obj_sym),
0265          rtems_rtl_symbol_obj_compare);
0266   qsort (obj->global_table,
0267          obj->global_syms,
0268          sizeof (rtems_rtl_obj_sym),
0269          rtems_rtl_symbol_obj_compare);
0270 }
0271 
0272 rtems_rtl_obj_sym*
0273 rtems_rtl_symbol_obj_find (rtems_rtl_obj* obj, const char* name)
0274 {
0275   /*
0276    * Check the object file's symbols first. If not found search the
0277    * global symbol table.
0278    */
0279   if (obj->local_syms)
0280   {
0281     rtems_rtl_obj_sym* match;
0282     rtems_rtl_obj_sym  key = { 0 };
0283     key.name = name;
0284     match = bsearch (&key, obj->local_table,
0285                      obj->local_syms,
0286                      sizeof (rtems_rtl_obj_sym),
0287                      rtems_rtl_symbol_obj_compare);
0288     if (match != NULL)
0289       return match;
0290   }
0291   if (obj->global_syms)
0292   {
0293     rtems_rtl_obj_sym* match;
0294     rtems_rtl_obj_sym  key = { 0 };
0295     key.name = name;
0296     match = bsearch (&key, obj->global_table,
0297                      obj->global_syms,
0298                      sizeof (rtems_rtl_obj_sym),
0299                      rtems_rtl_symbol_obj_compare);
0300     if (match != NULL)
0301       return match;
0302   }
0303   return rtems_rtl_symbol_global_find (name);
0304 }
0305 
0306 void
0307 rtems_rtl_symbol_obj_add (rtems_rtl_obj* obj)
0308 {
0309   rtems_rtl_symbols* symbols;
0310   rtems_rtl_obj_sym* sym;
0311   size_t             s;
0312 
0313   symbols = rtems_rtl_global_symbols ();
0314 
0315   for (s = 0, sym = obj->global_table; s < obj->global_syms; ++s, ++sym)
0316     rtems_rtl_symbol_global_insert (symbols, sym);
0317 }
0318 
0319 void
0320 rtems_rtl_symbol_obj_erase_local (rtems_rtl_obj* obj)
0321 {
0322   if (obj->local_table)
0323   {
0324     rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_SYMBOL, obj->local_table);
0325     obj->local_table = NULL;
0326     obj->local_size = 0;
0327     obj->local_syms = 0;
0328   }
0329 }
0330 
0331 void
0332 rtems_rtl_symbol_obj_erase (rtems_rtl_obj* obj)
0333 {
0334   rtems_rtl_symbol_obj_erase_local (obj);
0335   if (obj->global_table)
0336   {
0337     rtems_rtl_obj_sym* sym;
0338     size_t             s;
0339     for (s = 0, sym = obj->global_table; s < obj->global_syms; ++s, ++sym)
0340         if (!rtems_chain_is_node_off_chain (&sym->node))
0341           rtems_chain_extract (&sym->node);
0342     rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_SYMBOL, obj->global_table);
0343     obj->global_table = NULL;
0344     obj->global_size = 0;
0345     obj->global_syms = 0;
0346   }
0347 }