source: rtems/cpukit/libdl/rtl-sym.c @ 4408603

5
Last change on this file since 4408603 was f59d435d, checked in by Chris Johns <chrisj@…>, on 04/12/18 at 07:46:49

libdl: Remove _t from all structures as this is reserved for the standards

  • Property mode set to 100644
File size: 6.7 KB
Line 
1/*
2 *  COPYRIGHT (c) 2012-2014, 2018 Chris Johns <chrisj@rtems.org>
3 *
4 *  The license and distribution terms for this file may be
5 *  found in the file LICENSE in this distribution or at
6 *  http://www.rtems.org/license/LICENSE.
7 */
8/**
9 * @file
10 *
11 * @ingroup rtems_rtl
12 *
13 * @brief RTEMS Run-Time Linker Object File Symbol Table.
14 */
15
16#if HAVE_CONFIG_H
17#include "config.h"
18#endif
19
20#include <errno.h>
21#include <inttypes.h>
22#include <stdlib.h>
23#include <stdio.h>
24#include <string.h>
25
26#include <rtems/rtl/rtl.h>
27#include "rtl-error.h"
28#include <rtems/rtl/rtl-sym.h>
29#include <rtems/rtl/rtl-trace.h>
30
31/**
32 * The single symbol forced into the global symbol table that is used to load a
33 * symbol table from an object file.
34 */
35static rtems_rtl_obj_sym global_sym_add =
36{
37  .name  = "rtems_rtl_base_sym_global_add",
38  .value = (void*) rtems_rtl_base_sym_global_add
39};
40
41static uint_fast32_t
42rtems_rtl_symbol_hash (const char *s)
43{
44  uint_fast32_t h = 5381;
45  unsigned char c;
46  for (c = *s; c != '\0'; c = *++s)
47    h = h * 33 + c;
48  return h & 0xffffffff;
49}
50
51static void
52rtems_rtl_symbol_global_insert (rtems_rtl_symbols* symbols,
53                                rtems_rtl_obj_sym* symbol)
54{
55  uint_fast32_t hash = rtems_rtl_symbol_hash (symbol->name);
56  rtems_chain_append (&symbols->buckets[hash % symbols->nbuckets],
57                      &symbol->node);
58}
59
60bool
61rtems_rtl_symbol_table_open (rtems_rtl_symbols* symbols,
62                             size_t             buckets)
63{
64  symbols->buckets = rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_SYMBOL,
65                                          buckets * sizeof (rtems_chain_control),
66                                          true);
67  if (!symbols->buckets)
68  {
69    rtems_rtl_set_error (ENOMEM, "no memory for global symbol table");
70    return false;
71  }
72  symbols->nbuckets = buckets;
73  for (buckets = 0; buckets < symbols->nbuckets; ++buckets)
74    rtems_chain_initialize_empty (&symbols->buckets[buckets]);
75  rtems_rtl_symbol_global_insert (symbols, &global_sym_add);
76  return true;
77}
78
79void
80rtems_rtl_symbol_table_close (rtems_rtl_symbols* symbols)
81{
82  rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_SYMBOL, symbols->buckets);
83}
84
85bool
86rtems_rtl_symbol_global_add (rtems_rtl_obj*       obj,
87                             const unsigned char* esyms,
88                             unsigned int         size)
89{
90  rtems_rtl_symbols* symbols;
91  rtems_rtl_obj_sym* sym;
92  size_t             count;
93  size_t             s;
94  uint32_t           marker;
95
96  count = 0;
97  s = 0;
98  while ((s < size) && (esyms[s] != 0))
99  {
100    int l = strlen ((char*) &esyms[s]);
101    if ((esyms[s + l] != '\0') || ((s + l) > size))
102    {
103      rtems_rtl_set_error (EINVAL, "invalid exported symbol table");
104      return false;
105    }
106    ++count;
107    s += l + sizeof (unsigned long) + 1;
108  }
109
110  /*
111   * Check this is the correct end of the table.
112   */
113  marker = esyms[s + 1];
114  marker <<= 8;
115  marker |= esyms[s + 2];
116  marker <<= 8;
117  marker |= esyms[s + 3];
118  marker <<= 8;
119  marker |= esyms[s + 4];
120
121  if (marker != 0xdeadbeefUL)
122  {
123    rtems_rtl_set_error (ENOMEM, "invalid export symbol table");
124    return false;
125  }
126
127  if (rtems_rtl_trace (RTEMS_RTL_TRACE_GLOBAL_SYM))
128    printf ("rtl: global symbol add: %zi\n", count);
129
130  obj->global_size = count * sizeof (rtems_rtl_obj_sym);
131  obj->global_table = rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_SYMBOL,
132                                           obj->global_size, true);
133  if (!obj->global_table)
134  {
135    obj->global_size = 0;
136    rtems_rtl_set_error (ENOMEM, "no memory for global symbols");
137    return false;
138  }
139
140  symbols = rtems_rtl_global_symbols ();
141
142  s = 0;
143  sym = obj->global_table;
144
145  while ((s < size) && (esyms[s] != 0))
146  {
147    /*
148     * Copy the void* using a union and memcpy to avoid any strict aliasing or
149     * alignment issues. The variable length of the label and the packed nature
150     * of the table means casting is not suitable.
151     */
152    union {
153      uint8_t data[sizeof (void*)];
154      void*   value;
155    } copy_voidp;
156    int b;
157
158    sym->name = (const char*) &esyms[s];
159    s += strlen (sym->name) + 1;
160    for (b = 0; b < sizeof (void*); ++b, ++s)
161      copy_voidp.data[b] = esyms[s];
162    sym->value = copy_voidp.value;
163    if (rtems_rtl_trace (RTEMS_RTL_TRACE_GLOBAL_SYM))
164      printf ("rtl: esyms: %s -> %8p\n", sym->name, sym->value);
165    if (rtems_rtl_symbol_global_find (sym->name) == NULL)
166      rtems_rtl_symbol_global_insert (symbols, sym);
167    ++sym;
168  }
169
170  obj->global_syms = count;
171
172  return true;
173}
174
175rtems_rtl_obj_sym*
176rtems_rtl_symbol_global_find (const char* name)
177{
178  rtems_rtl_symbols*   symbols;
179  uint_fast32_t        hash;
180  rtems_chain_control* bucket;
181  rtems_chain_node*    node;
182
183  symbols = rtems_rtl_global_symbols ();
184
185  hash = rtems_rtl_symbol_hash (name);
186  bucket = &symbols->buckets[hash % symbols->nbuckets];
187  node = rtems_chain_first (bucket);
188
189  while (!rtems_chain_is_tail (bucket, node))
190  {
191    rtems_rtl_obj_sym* sym = (rtems_rtl_obj_sym*) node;
192    /*
193     * Use the hash. I could add this to the symbol but it uses more memory.
194     */
195    if (strcmp (name, sym->name) == 0)
196      return sym;
197    node = rtems_chain_next (node);
198  }
199
200  return NULL;
201}
202
203rtems_rtl_obj_sym*
204rtems_rtl_symbol_obj_find (rtems_rtl_obj* obj, const char* name)
205{
206  rtems_rtl_obj_sym* sym;
207  size_t             s;
208  /*
209   * Check the object file's symbols first. If not found search the
210   * global symbol table.
211   */
212  if (obj->local_syms)
213  {
214    for (s = 0, sym = obj->local_table; s < obj->local_syms; ++s, ++sym)
215      if (strcmp (name, sym->name) == 0)
216        return sym;
217  }
218  if (obj->global_syms)
219  {
220    for (s = 0, sym = obj->global_table; s < obj->global_syms; ++s, ++sym)
221      if (strcmp (name, sym->name) == 0)
222        return sym;
223  }
224  return rtems_rtl_symbol_global_find (name);
225}
226
227void
228rtems_rtl_symbol_obj_add (rtems_rtl_obj* obj)
229{
230  rtems_rtl_symbols* symbols;
231  rtems_rtl_obj_sym* sym;
232  size_t             s;
233
234  symbols = rtems_rtl_global_symbols ();
235
236  for (s = 0, sym = obj->global_table; s < obj->global_syms; ++s, ++sym)
237    rtems_rtl_symbol_global_insert (symbols, sym);
238}
239
240void
241rtems_rtl_symbol_obj_erase_local (rtems_rtl_obj* obj)
242{
243  if (obj->local_table)
244  {
245    rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_SYMBOL, obj->local_table);
246    obj->local_table = NULL;
247    obj->local_size = 0;
248    obj->local_syms = 0;
249  }
250}
251
252void
253rtems_rtl_symbol_obj_erase (rtems_rtl_obj* obj)
254{
255  rtems_rtl_symbol_obj_erase_local (obj);
256  if (obj->global_table)
257  {
258    rtems_rtl_obj_sym* sym;
259    size_t             s;
260    for (s = 0, sym = obj->global_table; s < obj->global_syms; ++s, ++sym)
261        if (!rtems_chain_is_node_off_chain (&sym->node))
262          rtems_chain_extract (&sym->node);
263    rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_SYMBOL, obj->global_table);
264    obj->global_table = NULL;
265    obj->global_size = 0;
266    obj->global_syms = 0;
267  }
268}
Note: See TracBrowser for help on using the repository browser.