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 | */ |
---|
35 | static 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 | |
---|
41 | static uint_fast32_t |
---|
42 | rtems_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 | |
---|
51 | static void |
---|
52 | rtems_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 | |
---|
60 | bool |
---|
61 | rtems_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 | |
---|
79 | void |
---|
80 | rtems_rtl_symbol_table_close (rtems_rtl_symbols* symbols) |
---|
81 | { |
---|
82 | rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_SYMBOL, symbols->buckets); |
---|
83 | } |
---|
84 | |
---|
85 | bool |
---|
86 | rtems_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 | |
---|
175 | rtems_rtl_obj_sym* |
---|
176 | rtems_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 | |
---|
203 | rtems_rtl_obj_sym* |
---|
204 | rtems_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 | |
---|
227 | void |
---|
228 | rtems_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 | |
---|
240 | void |
---|
241 | rtems_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 | |
---|
252 | void |
---|
253 | rtems_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 | } |
---|