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

4.115
Last change on this file since a2e1e30d was a2e1e30d, checked in by Chris Johns <chrisj@…>, on 11/04/14 at 01:12:25

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.

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