1 | /* SPDX-License-Identifier: BSD-2-Clause */ |
---|
2 | |
---|
3 | /** |
---|
4 | * @file |
---|
5 | * |
---|
6 | * @ingroup rtems_rtl |
---|
7 | * |
---|
8 | * @brief RTEMS Run-Time Linker Object File Symbol Table. |
---|
9 | */ |
---|
10 | |
---|
11 | /* |
---|
12 | * COPYRIGHT (c) 2012-2014, 2018 Chris Johns <chrisj@rtems.org> |
---|
13 | * |
---|
14 | * Redistribution and use in source and binary forms, with or without |
---|
15 | * modification, are permitted provided that the following conditions |
---|
16 | * are met: |
---|
17 | * 1. Redistributions of source code must retain the above copyright |
---|
18 | * notice, this list of conditions and the following disclaimer. |
---|
19 | * 2. Redistributions in binary form must reproduce the above copyright |
---|
20 | * notice, this list of conditions and the following disclaimer in the |
---|
21 | * documentation and/or other materials provided with the distribution. |
---|
22 | * |
---|
23 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
---|
24 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
---|
25 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
---|
26 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE |
---|
27 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
---|
28 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
---|
29 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
---|
30 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
---|
31 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
---|
32 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
---|
33 | * POSSIBILITY OF SUCH DAMAGE. |
---|
34 | */ |
---|
35 | |
---|
36 | #ifdef HAVE_CONFIG_H |
---|
37 | #include "config.h" |
---|
38 | #endif |
---|
39 | |
---|
40 | #include <errno.h> |
---|
41 | #include <inttypes.h> |
---|
42 | #include <stdlib.h> |
---|
43 | #include <stdio.h> |
---|
44 | #include <string.h> |
---|
45 | |
---|
46 | #include <rtems/rtl/rtl.h> |
---|
47 | #include "rtl-error.h" |
---|
48 | #include <rtems/rtl/rtl-sym.h> |
---|
49 | #include <rtems/rtl/rtl-trace.h> |
---|
50 | |
---|
51 | /** |
---|
52 | * The single symbol forced into the global symbol table that is used to load a |
---|
53 | * symbol table from an object file. |
---|
54 | */ |
---|
55 | static rtems_rtl_obj_sym global_sym_add = |
---|
56 | { |
---|
57 | .name = "rtems_rtl_base_sym_global_add", |
---|
58 | .value = (void*) rtems_rtl_base_sym_global_add |
---|
59 | }; |
---|
60 | |
---|
61 | static uint_fast32_t |
---|
62 | rtems_rtl_symbol_hash (const char *s) |
---|
63 | { |
---|
64 | uint_fast32_t h = 5381; |
---|
65 | unsigned char c; |
---|
66 | for (c = *s; c != '\0'; c = *++s) |
---|
67 | h = h * 33 + c; |
---|
68 | return h & 0xffffffff; |
---|
69 | } |
---|
70 | |
---|
71 | static void |
---|
72 | rtems_rtl_symbol_global_insert (rtems_rtl_symbols* symbols, |
---|
73 | rtems_rtl_obj_sym* symbol) |
---|
74 | { |
---|
75 | uint_fast32_t hash = rtems_rtl_symbol_hash (symbol->name); |
---|
76 | rtems_chain_append (&symbols->buckets[hash % symbols->nbuckets], |
---|
77 | &symbol->node); |
---|
78 | } |
---|
79 | |
---|
80 | bool |
---|
81 | rtems_rtl_symbol_table_open (rtems_rtl_symbols* symbols, |
---|
82 | size_t buckets) |
---|
83 | { |
---|
84 | symbols->buckets = rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_SYMBOL, |
---|
85 | buckets * sizeof (rtems_chain_control), |
---|
86 | true); |
---|
87 | if (!symbols->buckets) |
---|
88 | { |
---|
89 | rtems_rtl_set_error (ENOMEM, "no memory for global symbol table"); |
---|
90 | return false; |
---|
91 | } |
---|
92 | symbols->nbuckets = buckets; |
---|
93 | for (buckets = 0; buckets < symbols->nbuckets; ++buckets) |
---|
94 | rtems_chain_initialize_empty (&symbols->buckets[buckets]); |
---|
95 | rtems_rtl_symbol_global_insert (symbols, &global_sym_add); |
---|
96 | return true; |
---|
97 | } |
---|
98 | |
---|
99 | void |
---|
100 | rtems_rtl_symbol_table_close (rtems_rtl_symbols* symbols) |
---|
101 | { |
---|
102 | rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_SYMBOL, symbols->buckets); |
---|
103 | } |
---|
104 | |
---|
105 | bool |
---|
106 | rtems_rtl_symbol_global_add (rtems_rtl_obj* obj, |
---|
107 | const unsigned char* esyms, |
---|
108 | unsigned int size) |
---|
109 | { |
---|
110 | rtems_rtl_symbols* symbols; |
---|
111 | rtems_rtl_obj_sym* sym; |
---|
112 | size_t count; |
---|
113 | size_t s; |
---|
114 | uint32_t marker; |
---|
115 | |
---|
116 | count = 0; |
---|
117 | s = 0; |
---|
118 | while ((s < size) && (esyms[s] != 0)) |
---|
119 | { |
---|
120 | int l = strlen ((char*) &esyms[s]); |
---|
121 | if ((esyms[s + l] != '\0') || ((s + l) > size)) |
---|
122 | { |
---|
123 | rtems_rtl_set_error (EINVAL, "invalid exported symbol table"); |
---|
124 | return false; |
---|
125 | } |
---|
126 | ++count; |
---|
127 | s += l + sizeof (void *) + 1; |
---|
128 | } |
---|
129 | |
---|
130 | /* |
---|
131 | * Check this is the correct end of the table. |
---|
132 | */ |
---|
133 | marker = esyms[s + 1]; |
---|
134 | marker <<= 8; |
---|
135 | marker |= esyms[s + 2]; |
---|
136 | marker <<= 8; |
---|
137 | marker |= esyms[s + 3]; |
---|
138 | marker <<= 8; |
---|
139 | marker |= esyms[s + 4]; |
---|
140 | |
---|
141 | if (marker != 0xdeadbeefUL) |
---|
142 | { |
---|
143 | rtems_rtl_set_error (ENOMEM, "invalid export symbol table"); |
---|
144 | return false; |
---|
145 | } |
---|
146 | |
---|
147 | if (rtems_rtl_trace (RTEMS_RTL_TRACE_GLOBAL_SYM)) |
---|
148 | printf ("rtl: global symbol add: %zi\n", count); |
---|
149 | |
---|
150 | obj->global_size = count * sizeof (rtems_rtl_obj_sym); |
---|
151 | obj->global_table = rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_SYMBOL, |
---|
152 | obj->global_size, true); |
---|
153 | if (!obj->global_table) |
---|
154 | { |
---|
155 | obj->global_size = 0; |
---|
156 | rtems_rtl_set_error (ENOMEM, "no memory for global symbols"); |
---|
157 | return false; |
---|
158 | } |
---|
159 | |
---|
160 | symbols = rtems_rtl_global_symbols (); |
---|
161 | |
---|
162 | s = 0; |
---|
163 | sym = obj->global_table; |
---|
164 | |
---|
165 | while ((s < size) && (esyms[s] != 0)) |
---|
166 | { |
---|
167 | /* |
---|
168 | * Copy the void* using a union and memcpy to avoid any strict aliasing or |
---|
169 | * alignment issues. The variable length of the label and the packed nature |
---|
170 | * of the table means casting is not suitable. |
---|
171 | */ |
---|
172 | union { |
---|
173 | uint8_t data[sizeof (void*)]; |
---|
174 | void* value; |
---|
175 | } copy_voidp; |
---|
176 | int b; |
---|
177 | |
---|
178 | sym->name = (const char*) &esyms[s]; |
---|
179 | s += strlen (sym->name) + 1; |
---|
180 | for (b = 0; b < sizeof (void*); ++b, ++s) |
---|
181 | copy_voidp.data[b] = esyms[s]; |
---|
182 | sym->value = copy_voidp.value; |
---|
183 | if (rtems_rtl_trace (RTEMS_RTL_TRACE_GLOBAL_SYM)) |
---|
184 | printf ("rtl: esyms: %s -> %8p\n", sym->name, sym->value); |
---|
185 | if (rtems_rtl_symbol_global_find (sym->name) == NULL) |
---|
186 | rtems_rtl_symbol_global_insert (symbols, sym); |
---|
187 | ++sym; |
---|
188 | } |
---|
189 | |
---|
190 | obj->global_syms = count; |
---|
191 | |
---|
192 | return true; |
---|
193 | } |
---|
194 | |
---|
195 | rtems_rtl_obj_sym* |
---|
196 | rtems_rtl_symbol_global_find (const char* name) |
---|
197 | { |
---|
198 | rtems_rtl_symbols* symbols; |
---|
199 | uint_fast32_t hash; |
---|
200 | rtems_chain_control* bucket; |
---|
201 | rtems_chain_node* node; |
---|
202 | |
---|
203 | symbols = rtems_rtl_global_symbols (); |
---|
204 | |
---|
205 | hash = rtems_rtl_symbol_hash (name); |
---|
206 | bucket = &symbols->buckets[hash % symbols->nbuckets]; |
---|
207 | node = rtems_chain_first (bucket); |
---|
208 | |
---|
209 | while (!rtems_chain_is_tail (bucket, node)) |
---|
210 | { |
---|
211 | rtems_rtl_obj_sym* sym = (rtems_rtl_obj_sym*) node; |
---|
212 | /* |
---|
213 | * Use the hash. I could add this to the symbol but it uses more memory. |
---|
214 | */ |
---|
215 | if (strcmp (name, sym->name) == 0) |
---|
216 | return sym; |
---|
217 | node = rtems_chain_next (node); |
---|
218 | } |
---|
219 | |
---|
220 | return NULL; |
---|
221 | } |
---|
222 | |
---|
223 | static int |
---|
224 | rtems_rtl_symbol_obj_compare (const void* a, const void* b) |
---|
225 | { |
---|
226 | const rtems_rtl_obj_sym* sa; |
---|
227 | const rtems_rtl_obj_sym* sb; |
---|
228 | sa = (const rtems_rtl_obj_sym*) a; |
---|
229 | sb = (const rtems_rtl_obj_sym*) b; |
---|
230 | return strcmp (sa->name, sb->name); |
---|
231 | } |
---|
232 | |
---|
233 | void |
---|
234 | rtems_rtl_symbol_obj_sort (rtems_rtl_obj* obj) |
---|
235 | { |
---|
236 | qsort (obj->local_table, |
---|
237 | obj->local_syms, |
---|
238 | sizeof (rtems_rtl_obj_sym), |
---|
239 | rtems_rtl_symbol_obj_compare); |
---|
240 | qsort (obj->global_table, |
---|
241 | obj->global_syms, |
---|
242 | sizeof (rtems_rtl_obj_sym), |
---|
243 | rtems_rtl_symbol_obj_compare); |
---|
244 | } |
---|
245 | |
---|
246 | rtems_rtl_obj_sym* |
---|
247 | rtems_rtl_symbol_obj_find (rtems_rtl_obj* obj, const char* name) |
---|
248 | { |
---|
249 | /* |
---|
250 | * Check the object file's symbols first. If not found search the |
---|
251 | * global symbol table. |
---|
252 | */ |
---|
253 | if (obj->local_syms) |
---|
254 | { |
---|
255 | rtems_rtl_obj_sym* match; |
---|
256 | rtems_rtl_obj_sym key = { 0 }; |
---|
257 | key.name = name; |
---|
258 | match = bsearch (&key, obj->local_table, |
---|
259 | obj->local_syms, |
---|
260 | sizeof (rtems_rtl_obj_sym), |
---|
261 | rtems_rtl_symbol_obj_compare); |
---|
262 | if (match != NULL) |
---|
263 | return match; |
---|
264 | } |
---|
265 | if (obj->global_syms) |
---|
266 | { |
---|
267 | rtems_rtl_obj_sym* match; |
---|
268 | rtems_rtl_obj_sym key = { 0 }; |
---|
269 | key.name = name; |
---|
270 | match = bsearch (&key, obj->global_table, |
---|
271 | obj->global_syms, |
---|
272 | sizeof (rtems_rtl_obj_sym), |
---|
273 | rtems_rtl_symbol_obj_compare); |
---|
274 | if (match != NULL) |
---|
275 | return match; |
---|
276 | } |
---|
277 | return rtems_rtl_symbol_global_find (name); |
---|
278 | } |
---|
279 | |
---|
280 | void |
---|
281 | rtems_rtl_symbol_obj_add (rtems_rtl_obj* obj) |
---|
282 | { |
---|
283 | rtems_rtl_symbols* symbols; |
---|
284 | rtems_rtl_obj_sym* sym; |
---|
285 | size_t s; |
---|
286 | |
---|
287 | symbols = rtems_rtl_global_symbols (); |
---|
288 | |
---|
289 | for (s = 0, sym = obj->global_table; s < obj->global_syms; ++s, ++sym) |
---|
290 | rtems_rtl_symbol_global_insert (symbols, sym); |
---|
291 | } |
---|
292 | |
---|
293 | void |
---|
294 | rtems_rtl_symbol_obj_erase_local (rtems_rtl_obj* obj) |
---|
295 | { |
---|
296 | if (obj->local_table) |
---|
297 | { |
---|
298 | rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_SYMBOL, obj->local_table); |
---|
299 | obj->local_table = NULL; |
---|
300 | obj->local_size = 0; |
---|
301 | obj->local_syms = 0; |
---|
302 | } |
---|
303 | } |
---|
304 | |
---|
305 | void |
---|
306 | rtems_rtl_symbol_obj_erase (rtems_rtl_obj* obj) |
---|
307 | { |
---|
308 | rtems_rtl_symbol_obj_erase_local (obj); |
---|
309 | if (obj->global_table) |
---|
310 | { |
---|
311 | rtems_rtl_obj_sym* sym; |
---|
312 | size_t s; |
---|
313 | for (s = 0, sym = obj->global_table; s < obj->global_syms; ++s, ++sym) |
---|
314 | if (!rtems_chain_is_node_off_chain (&sym->node)) |
---|
315 | rtems_chain_extract (&sym->node); |
---|
316 | rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_SYMBOL, obj->global_table); |
---|
317 | obj->global_table = NULL; |
---|
318 | obj->global_size = 0; |
---|
319 | obj->global_syms = 0; |
---|
320 | } |
---|
321 | } |
---|