]>
Commit | Line | Data |
---|---|---|
d66e34cd | 1 | /* Look up a symbol in the loaded objects. |
02125962 | 2 | Copyright (C) 1995-2005, 2006, 2007, 2009 Free Software Foundation, Inc. |
afd4eb37 | 3 | This file is part of the GNU C Library. |
d66e34cd | 4 | |
afd4eb37 | 5 | The GNU C Library is free software; you can redistribute it and/or |
41bdb6e2 AJ |
6 | modify it under the terms of the GNU Lesser General Public |
7 | License as published by the Free Software Foundation; either | |
8 | version 2.1 of the License, or (at your option) any later version. | |
d66e34cd | 9 | |
afd4eb37 UD |
10 | The GNU C Library is distributed in the hope that it will be useful, |
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
41bdb6e2 | 13 | Lesser General Public License for more details. |
d66e34cd | 14 | |
41bdb6e2 AJ |
15 | You should have received a copy of the GNU Lesser General Public |
16 | License along with the GNU C Library; if not, write to the Free | |
17 | Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA | |
18 | 02111-1307 USA. */ | |
d66e34cd | 19 | |
f671aeab | 20 | #include <alloca.h> |
407fe3bb | 21 | #include <libintl.h> |
cf197e41 | 22 | #include <stdlib.h> |
8d6468d0 | 23 | #include <string.h> |
3db52d94 | 24 | #include <unistd.h> |
a42195db | 25 | #include <ldsodefs.h> |
8f480b4b | 26 | #include <dl-hash.h> |
bc9f6000 | 27 | #include <dl-machine.h> |
4e35ef2c | 28 | #include <sysdep-cancel.h> |
cf197e41 | 29 | #include <bits/libc-lock.h> |
f1cc669a | 30 | #include <tls.h> |
c84142e8 | 31 | |
a853022c UD |
32 | #include <assert.h> |
33 | ||
b0982c4a | 34 | #define VERSTAG(tag) (DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGIDX (tag)) |
266180eb | 35 | |
714a562f UD |
36 | /* We need this string more than once. */ |
37 | static const char undefined_msg[] = "undefined symbol: "; | |
38 | ||
39 | ||
84384f5b UD |
40 | struct sym_val |
41 | { | |
84384f5b | 42 | const ElfW(Sym) *s; |
0c367d92 | 43 | struct link_map *m; |
84384f5b UD |
44 | }; |
45 | ||
46 | ||
1fb05e3d UD |
47 | #define make_string(string, rest...) \ |
48 | ({ \ | |
49 | const char *all[] = { string, ## rest }; \ | |
50 | size_t len, cnt; \ | |
51 | char *result, *cp; \ | |
52 | \ | |
53 | len = 1; \ | |
54 | for (cnt = 0; cnt < sizeof (all) / sizeof (all[0]); ++cnt) \ | |
55 | len += strlen (all[cnt]); \ | |
56 | \ | |
57 | cp = result = alloca (len); \ | |
58 | for (cnt = 0; cnt < sizeof (all) / sizeof (all[0]); ++cnt) \ | |
da832465 | 59 | cp = __stpcpy (cp, all[cnt]); \ |
1fb05e3d UD |
60 | \ |
61 | result; \ | |
62 | }) | |
63 | ||
8352b484 | 64 | /* Statistics function. */ |
d6b5d570 UD |
65 | #ifdef SHARED |
66 | # define bump_num_relocations() ++GL(dl_num_relocations) | |
be4b5a95 | 67 | #else |
d6b5d570 | 68 | # define bump_num_relocations() ((void) 0) |
be4b5a95 UD |
69 | #endif |
70 | ||
8352b484 | 71 | |
bdf4a4f1 | 72 | /* The actual lookup code. */ |
a0e3f6f4 | 73 | #include "do-lookup.h" |
84384f5b | 74 | |
84384f5b | 75 | |
871b9158 UD |
76 | static uint_fast32_t |
77 | dl_new_hash (const char *s) | |
78 | { | |
79 | uint_fast32_t h = 5381; | |
80 | for (unsigned char c = *s; c != '\0'; c = *++s) | |
81 | h = h * 33 + c; | |
82 | return h & 0xffffffff; | |
83 | } | |
84 | ||
85 | ||
cf197e41 UD |
86 | /* Add extra dependency on MAP to UNDEF_MAP. */ |
87 | static int | |
80d9c5f0 | 88 | internal_function |
b90395e6 | 89 | add_dependency (struct link_map *undef_map, struct link_map *map, int flags) |
cf197e41 | 90 | { |
c4bb124a | 91 | struct link_map *runp; |
cf197e41 UD |
92 | unsigned int i; |
93 | int result = 0; | |
94 | ||
aff4519d UD |
95 | /* Avoid self-references and references to objects which cannot be |
96 | unloaded anyway. */ | |
c4bb124a UD |
97 | if (undef_map == map) |
98 | return 0; | |
99 | ||
385b4cf4 UD |
100 | /* Avoid references to objects which cannot be unloaded anyway. */ |
101 | assert (map->l_type == lt_loaded); | |
102 | if ((map->l_flags_1 & DF_1_NODELETE) != 0) | |
103 | return 0; | |
104 | ||
105 | struct link_map_reldeps *l_reldeps | |
106 | = atomic_forced_read (undef_map->l_reldeps); | |
107 | ||
108 | /* Make sure l_reldeps is read before l_initfini. */ | |
109 | atomic_read_barrier (); | |
110 | ||
111 | /* Determine whether UNDEF_MAP already has a reference to MAP. First | |
112 | look in the normal dependencies. */ | |
113 | struct link_map **l_initfini = atomic_forced_read (undef_map->l_initfini); | |
114 | if (l_initfini != NULL) | |
115 | { | |
116 | for (i = 0; l_initfini[i] != NULL; ++i) | |
117 | if (l_initfini[i] == map) | |
118 | return 0; | |
119 | } | |
120 | ||
121 | /* No normal dependency. See whether we already had to add it | |
122 | to the special list of dynamic dependencies. */ | |
123 | unsigned int l_reldepsact = 0; | |
124 | if (l_reldeps != NULL) | |
125 | { | |
126 | struct link_map **list = &l_reldeps->list[0]; | |
127 | l_reldepsact = l_reldeps->act; | |
128 | for (i = 0; i < l_reldepsact; ++i) | |
129 | if (list[i] == map) | |
130 | return 0; | |
131 | } | |
132 | ||
b90395e6 | 133 | /* Save serial number of the target MAP. */ |
385b4cf4 | 134 | unsigned long long serial = map->l_serial; |
aff4519d | 135 | |
b90395e6 UD |
136 | /* Make sure nobody can unload the object while we are at it. */ |
137 | if (__builtin_expect (flags & DL_LOOKUP_GSCOPE_LOCK, 0)) | |
aff4519d | 138 | { |
b90395e6 UD |
139 | /* We can't just call __rtld_lock_lock_recursive (GL(dl_load_lock)) |
140 | here, that can result in ABBA deadlock. */ | |
141 | THREAD_GSCOPE_RESET_FLAG (); | |
142 | __rtld_lock_lock_recursive (GL(dl_load_lock)); | |
b90395e6 UD |
143 | /* While MAP value won't change, after THREAD_GSCOPE_RESET_FLAG () |
144 | it can e.g. point to unallocated memory. So avoid the optimizer | |
145 | treating the above read from MAP->l_serial as ensurance it | |
146 | can safely dereference it. */ | |
147 | map = atomic_forced_read (map); | |
b90395e6 | 148 | |
385b4cf4 UD |
149 | /* From this point on it is unsafe to dereference MAP, until it |
150 | has been found in one of the lists. */ | |
cf197e41 | 151 | |
385b4cf4 UD |
152 | /* Redo the l_initfini check in case undef_map's l_initfini |
153 | changed in the mean time. */ | |
154 | if (undef_map->l_initfini != l_initfini | |
155 | && undef_map->l_initfini != NULL) | |
156 | { | |
157 | l_initfini = undef_map->l_initfini; | |
158 | for (i = 0; l_initfini[i] != NULL; ++i) | |
159 | if (l_initfini[i] == map) | |
160 | goto out_check; | |
161 | } | |
cf197e41 | 162 | |
385b4cf4 UD |
163 | /* Redo the l_reldeps check if undef_map's l_reldeps changed in |
164 | the mean time. */ | |
165 | if (undef_map->l_reldeps != NULL) | |
166 | { | |
167 | if (undef_map->l_reldeps != l_reldeps) | |
168 | { | |
169 | struct link_map **list = &undef_map->l_reldeps->list[0]; | |
170 | l_reldepsact = undef_map->l_reldeps->act; | |
171 | for (i = 0; i < l_reldepsact; ++i) | |
172 | if (list[i] == map) | |
173 | goto out_check; | |
174 | } | |
175 | else if (undef_map->l_reldeps->act > l_reldepsact) | |
176 | { | |
177 | struct link_map **list | |
178 | = &undef_map->l_reldeps->list[0]; | |
179 | i = l_reldepsact; | |
180 | l_reldepsact = undef_map->l_reldeps->act; | |
181 | for (; i < l_reldepsact; ++i) | |
182 | if (list[i] == map) | |
183 | goto out_check; | |
184 | } | |
185 | } | |
c4bb124a | 186 | } |
385b4cf4 UD |
187 | else |
188 | __rtld_lock_lock_recursive (GL(dl_load_lock)); | |
c4bb124a UD |
189 | |
190 | /* The object is not yet in the dependency list. Before we add | |
191 | it make sure just one more time the object we are about to | |
192 | reference is still available. There is a brief period in | |
193 | which the object could have been removed since we found the | |
194 | definition. */ | |
c0f62c56 | 195 | runp = GL(dl_ns)[undef_map->l_ns]._ns_loaded; |
c4bb124a UD |
196 | while (runp != NULL && runp != map) |
197 | runp = runp->l_next; | |
198 | ||
199 | if (runp != NULL) | |
200 | { | |
b90395e6 UD |
201 | /* The object is still available. */ |
202 | ||
203 | /* MAP could have been dlclosed, freed and then some other dlopened | |
204 | library could have the same link_map pointer. */ | |
205 | if (map->l_serial != serial) | |
206 | goto out_check; | |
207 | ||
385b4cf4 UD |
208 | /* Redo the NODELETE check, as when dl_load_lock wasn't held |
209 | yet this could have changed. */ | |
715899d1 | 210 | if ((map->l_flags_1 & DF_1_NODELETE) != 0) |
b90395e6 UD |
211 | goto out; |
212 | ||
213 | /* If the object with the undefined reference cannot be removed ever | |
214 | just make sure the same is true for the object which contains the | |
215 | definition. */ | |
216 | if (undef_map->l_type != lt_loaded | |
217 | || (undef_map->l_flags_1 & DF_1_NODELETE) != 0) | |
218 | { | |
219 | map->l_flags_1 |= DF_1_NODELETE; | |
220 | goto out; | |
221 | } | |
222 | ||
223 | /* Add the reference now. */ | |
385b4cf4 | 224 | if (__builtin_expect (l_reldepsact >= undef_map->l_reldepsmax, 0)) |
cf197e41 | 225 | { |
c4bb124a UD |
226 | /* Allocate more memory for the dependency list. Since this |
227 | can never happen during the startup phase we can use | |
228 | `realloc'. */ | |
385b4cf4 UD |
229 | struct link_map_reldeps *newp; |
230 | unsigned int max | |
231 | = undef_map->l_reldepsmax ? undef_map->l_reldepsmax * 2 : 10; | |
232 | ||
233 | newp = malloc (sizeof (*newp) + max * sizeof (struct link_map *)); | |
234 | if (newp == NULL) | |
235 | { | |
236 | /* If we didn't manage to allocate memory for the list this is | |
237 | no fatal problem. We simply make sure the referenced object | |
238 | cannot be unloaded. This is semantically the correct | |
239 | behavior. */ | |
240 | map->l_flags_1 |= DF_1_NODELETE; | |
241 | goto out; | |
242 | } | |
cf197e41 | 243 | else |
385b4cf4 UD |
244 | { |
245 | if (l_reldepsact) | |
246 | memcpy (&newp->list[0], &undef_map->l_reldeps->list[0], | |
247 | l_reldepsact * sizeof (struct link_map *)); | |
248 | newp->list[l_reldepsact] = map; | |
249 | newp->act = l_reldepsact + 1; | |
250 | atomic_write_barrier (); | |
251 | void *old = undef_map->l_reldeps; | |
252 | undef_map->l_reldeps = newp; | |
253 | undef_map->l_reldepsmax = max; | |
254 | if (old) | |
255 | _dl_scope_free (old); | |
256 | } | |
cf197e41 | 257 | } |
715899d1 | 258 | else |
385b4cf4 UD |
259 | { |
260 | undef_map->l_reldeps->list[l_reldepsact] = map; | |
261 | atomic_write_barrier (); | |
262 | undef_map->l_reldeps->act = l_reldepsact + 1; | |
263 | } | |
c4bb124a | 264 | |
c4bb124a | 265 | /* Display information if we are debugging. */ |
afdca0f2 | 266 | if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_FILES, 0)) |
154d10bd | 267 | _dl_debug_printf ("\ |
c0f62c56 | 268 | \nfile=%s [%lu]; needed by %s [%lu] (relocation dependency)\n\n", |
154d10bd | 269 | map->l_name[0] ? map->l_name : rtld_progname, |
c0f62c56 | 270 | map->l_ns, |
154d10bd | 271 | undef_map->l_name[0] |
c0f62c56 UD |
272 | ? undef_map->l_name : rtld_progname, |
273 | undef_map->l_ns); | |
cf197e41 | 274 | } |
c4bb124a UD |
275 | else |
276 | /* Whoa, that was bad luck. We have to search again. */ | |
277 | result = -1; | |
cf197e41 | 278 | |
c4bb124a | 279 | out: |
cf197e41 | 280 | /* Release the lock. */ |
d3c9f895 | 281 | __rtld_lock_unlock_recursive (GL(dl_load_lock)); |
cf197e41 | 282 | |
385b4cf4 UD |
283 | if (__builtin_expect (flags & DL_LOOKUP_GSCOPE_LOCK, 0)) |
284 | THREAD_GSCOPE_SET_FLAG (); | |
285 | ||
cf197e41 | 286 | return result; |
b90395e6 UD |
287 | |
288 | out_check: | |
289 | if (map->l_serial != serial) | |
290 | result = -1; | |
291 | goto out; | |
cf197e41 UD |
292 | } |
293 | ||
32e6df36 UD |
294 | static void |
295 | internal_function | |
296 | _dl_debug_bindings (const char *undef_name, struct link_map *undef_map, | |
c0a777e8 | 297 | const ElfW(Sym) **ref, struct sym_val *value, |
7969407a UD |
298 | const struct r_found_version *version, int type_class, |
299 | int protected); | |
647eb037 | 300 | |
84384f5b | 301 | |
bdf4a4f1 | 302 | /* Search loaded objects' symbol tables for a definition of the symbol |
609cf614 UD |
303 | UNDEF_NAME, perhaps with a requested version for the symbol. |
304 | ||
305 | We must never have calls to the audit functions inside this function | |
306 | or in any function which gets called. If this would happen the audit | |
307 | code might create a thread which can throw off all the scope locking. */ | |
c0282c06 | 308 | lookup_t |
d0fc4041 | 309 | internal_function |
bdf4a4f1 UD |
310 | _dl_lookup_symbol_x (const char *undef_name, struct link_map *undef_map, |
311 | const ElfW(Sym) **ref, | |
312 | struct r_scope_elem *symbol_scope[], | |
313 | const struct r_found_version *version, | |
314 | int type_class, int flags, struct link_map *skip_map) | |
84384f5b | 315 | { |
871b9158 UD |
316 | const uint_fast32_t new_hash = dl_new_hash (undef_name); |
317 | unsigned long int old_hash = 0xffffffff; | |
0c367d92 | 318 | struct sym_val current_value = { NULL, NULL }; |
bdf4a4f1 | 319 | struct r_scope_elem **scope = symbol_scope; |
84384f5b | 320 | |
be4b5a95 | 321 | bump_num_relocations (); |
48f6496e | 322 | |
b90395e6 UD |
323 | /* No other flag than DL_LOOKUP_ADD_DEPENDENCY or DL_LOOKUP_GSCOPE_LOCK |
324 | is allowed if we look up a versioned symbol. */ | |
325 | assert (version == NULL | |
326 | || (flags & ~(DL_LOOKUP_ADD_DEPENDENCY | DL_LOOKUP_GSCOPE_LOCK)) | |
327 | == 0); | |
c84142e8 | 328 | |
bdf4a4f1 UD |
329 | size_t i = 0; |
330 | if (__builtin_expect (skip_map != NULL, 0)) | |
3c457089 UD |
331 | /* Search the relevant loaded objects for a definition. */ |
332 | while ((*scope)->r_list[i] != skip_map) | |
333 | ++i; | |
32e6df36 | 334 | |
c84142e8 | 335 | /* Search the relevant loaded objects for a definition. */ |
bdf4a4f1 | 336 | for (size_t start = i; *scope != NULL; start = 0, ++scope) |
1fb05e3d | 337 | { |
871b9158 UD |
338 | int res = do_lookup_x (undef_name, new_hash, &old_hash, *ref, |
339 | ¤t_value, *scope, start, version, flags, | |
415ac3df | 340 | skip_map, type_class, undef_map); |
1fb05e3d | 341 | if (res > 0) |
78575a84 | 342 | break; |
1fb05e3d | 343 | |
bdf4a4f1 | 344 | if (__builtin_expect (res, 0) < 0 && skip_map == NULL) |
3f933dc2 UD |
345 | { |
346 | /* Oh, oh. The file named in the relocation entry does not | |
bdf4a4f1 UD |
347 | contain the needed symbol. This code is never reached |
348 | for unversioned lookups. */ | |
349 | assert (version != NULL); | |
c90b5d28 UD |
350 | const char *reference_name = undef_map ? undef_map->l_name : NULL; |
351 | ||
8e17ea58 | 352 | /* XXX We cannot translate the message. */ |
32e6df36 | 353 | _dl_signal_cerror (0, (reference_name[0] |
3f933dc2 | 354 | ? reference_name |
e6caf4e1 | 355 | : (rtld_progname ?: "<main program>")), |
407fe3bb | 356 | N_("relocation error"), |
3f933dc2 UD |
357 | make_string ("symbol ", undef_name, ", version ", |
358 | version->name, | |
359 | " not defined in file ", | |
360 | version->filename, | |
361 | " with link time reference", | |
362 | res == -2 | |
363 | ? " (no version symbols)" : "")); | |
364 | *ref = NULL; | |
365 | return 0; | |
366 | } | |
1fb05e3d | 367 | } |
c84142e8 | 368 | |
466a0ec9 | 369 | if (__builtin_expect (current_value.s == NULL, 0)) |
0c367d92 | 370 | { |
bdf4a4f1 UD |
371 | if ((*ref == NULL || ELFW(ST_BIND) ((*ref)->st_info) != STB_WEAK) |
372 | && skip_map == NULL) | |
c90b5d28 UD |
373 | { |
374 | /* We could find no value for a strong reference. */ | |
9363dbb8 | 375 | const char *reference_name = undef_map ? undef_map->l_name : ""; |
bdf4a4f1 UD |
376 | const char *versionstr = version ? ", version " : ""; |
377 | const char *versionname = (version && version->name | |
378 | ? version->name : ""); | |
c90b5d28 UD |
379 | |
380 | /* XXX We cannot translate the message. */ | |
32e6df36 | 381 | _dl_signal_cerror (0, (reference_name[0] |
c90b5d28 | 382 | ? reference_name |
24a07b1f UD |
383 | : (rtld_progname ?: "<main program>")), |
384 | N_("symbol lookup error"), | |
c90b5d28 | 385 | make_string (undefined_msg, undef_name, |
bdf4a4f1 | 386 | versionstr, versionname)); |
c90b5d28 | 387 | } |
0c367d92 UD |
388 | *ref = NULL; |
389 | return 0; | |
390 | } | |
391 | ||
bdf4a4f1 UD |
392 | int protected = (*ref |
393 | && ELFW(ST_VISIBILITY) ((*ref)->st_other) == STV_PROTECTED); | |
32e6df36 | 394 | if (__builtin_expect (protected != 0, 0)) |
6aa29abe | 395 | { |
78575a84 UD |
396 | /* It is very tricky. We need to figure out what value to |
397 | return for the protected symbol. */ | |
697119d6 | 398 | if (type_class == ELF_RTYPE_CLASS_PLT) |
6aa29abe | 399 | { |
697119d6 UD |
400 | if (current_value.s != NULL && current_value.m != undef_map) |
401 | { | |
402 | current_value.s = *ref; | |
403 | current_value.m = undef_map; | |
404 | } | |
405 | } | |
406 | else | |
407 | { | |
408 | struct sym_val protected_value = { NULL, NULL }; | |
409 | ||
9363dbb8 | 410 | for (scope = symbol_scope; *scope != NULL; i = 0, ++scope) |
871b9158 UD |
411 | if (do_lookup_x (undef_name, new_hash, &old_hash, *ref, |
412 | &protected_value, *scope, i, version, flags, | |
415ac3df | 413 | skip_map, ELF_RTYPE_CLASS_PLT, NULL) != 0) |
697119d6 UD |
414 | break; |
415 | ||
9363dbb8 | 416 | if (protected_value.s != NULL && protected_value.m != undef_map) |
697119d6 UD |
417 | { |
418 | current_value.s = *ref; | |
419 | current_value.m = undef_map; | |
420 | } | |
6aa29abe | 421 | } |
6aa29abe | 422 | } |
32e6df36 | 423 | |
78575a84 UD |
424 | /* We have to check whether this would bind UNDEF_MAP to an object |
425 | in the global scope which was dynamically loaded. In this case | |
426 | we have to prevent the latter from being unloaded unless the | |
427 | UNDEF_MAP object is also unloaded. */ | |
428 | if (__builtin_expect (current_value.m->l_type == lt_loaded, 0) | |
429 | /* Don't do this for explicit lookups as opposed to implicit | |
430 | runtime lookups. */ | |
bdf4a4f1 | 431 | && (flags & DL_LOOKUP_ADD_DEPENDENCY) != 0 |
78575a84 | 432 | /* Add UNDEF_MAP to the dependencies. */ |
b90395e6 | 433 | && add_dependency (undef_map, current_value.m, flags) < 0) |
78575a84 UD |
434 | /* Something went wrong. Perhaps the object we tried to reference |
435 | was just removed. Try finding another definition. */ | |
b90395e6 UD |
436 | return _dl_lookup_symbol_x (undef_name, undef_map, ref, |
437 | (flags & DL_LOOKUP_GSCOPE_LOCK) | |
438 | ? undef_map->l_scope : symbol_scope, | |
e4eb675d | 439 | version, type_class, flags, skip_map); |
78575a84 | 440 | |
7a11603d UD |
441 | /* The object is used. */ |
442 | current_value.m->l_used = 1; | |
443 | ||
afdca0f2 | 444 | if (__builtin_expect (GLRO(dl_debug_mask) |
32e6df36 | 445 | & (DL_DEBUG_BINDINGS|DL_DEBUG_PRELINK), 0)) |
c0a777e8 | 446 | _dl_debug_bindings (undef_name, undef_map, ref, |
32e6df36 UD |
447 | ¤t_value, version, type_class, protected); |
448 | ||
449 | *ref = current_value.s; | |
450 | return LOOKUP_VALUE (current_value.m); | |
c84142e8 UD |
451 | } |
452 | ||
453 | ||
d66e34cd RM |
454 | /* Cache the location of MAP's hash table. */ |
455 | ||
456 | void | |
d0fc4041 | 457 | internal_function |
d66e34cd RM |
458 | _dl_setup_hash (struct link_map *map) |
459 | { | |
a1eca9f3 UD |
460 | Elf_Symndx *hash; |
461 | Elf_Symndx nchain; | |
f41c8091 | 462 | |
871b9158 UD |
463 | if (__builtin_expect (map->l_info[DT_ADDRTAGIDX (DT_GNU_HASH) + DT_NUM |
464 | + DT_THISPROCNUM + DT_VERSIONTAGNUM | |
465 | + DT_EXTRANUM + DT_VALNUM] != NULL, 1)) | |
466 | { | |
467 | Elf32_Word *hash32 | |
468 | = (void *) D_PTR (map, l_info[DT_ADDRTAGIDX (DT_GNU_HASH) + DT_NUM | |
469 | + DT_THISPROCNUM + DT_VERSIONTAGNUM | |
470 | + DT_EXTRANUM + DT_VALNUM]); | |
471 | map->l_nbuckets = *hash32++; | |
472 | Elf32_Word symbias = *hash32++; | |
473 | Elf32_Word bitmask_nwords = *hash32++; | |
474 | /* Must be a power of two. */ | |
475 | assert ((bitmask_nwords & (bitmask_nwords - 1)) == 0); | |
476 | map->l_gnu_bitmask_idxbits = bitmask_nwords - 1; | |
477 | map->l_gnu_shift = *hash32++; | |
478 | ||
479 | map->l_gnu_bitmask = (ElfW(Addr) *) hash32; | |
480 | hash32 += __ELF_NATIVE_CLASS / 32 * bitmask_nwords; | |
481 | ||
482 | map->l_gnu_buckets = hash32; | |
483 | hash32 += map->l_nbuckets; | |
484 | map->l_gnu_chain_zero = hash32 - symbias; | |
485 | return; | |
486 | } | |
487 | ||
f41c8091 UD |
488 | if (!map->l_info[DT_HASH]) |
489 | return; | |
9a88a2d7 | 490 | hash = (void *) D_PTR (map, l_info[DT_HASH]); |
f41c8091 | 491 | |
d66e34cd RM |
492 | map->l_nbuckets = *hash++; |
493 | nchain = *hash++; | |
494 | map->l_buckets = hash; | |
495 | hash += map->l_nbuckets; | |
496 | map->l_chain = hash; | |
497 | } | |
80d9c5f0 | 498 | |
f9f2a150 | 499 | |
32e6df36 UD |
500 | static void |
501 | internal_function | |
502 | _dl_debug_bindings (const char *undef_name, struct link_map *undef_map, | |
c0a777e8 | 503 | const ElfW(Sym) **ref, struct sym_val *value, |
f9f2a150 UD |
504 | const struct r_found_version *version, int type_class, |
505 | int protected) | |
32e6df36 UD |
506 | { |
507 | const char *reference_name = undef_map->l_name; | |
508 | ||
afdca0f2 | 509 | if (GLRO(dl_debug_mask) & DL_DEBUG_BINDINGS) |
32e6df36 | 510 | { |
21e2d3a4 | 511 | _dl_debug_printf ("binding file %s [%lu] to %s [%lu]: %s symbol `%s'", |
154d10bd UD |
512 | (reference_name[0] |
513 | ? reference_name | |
514 | : (rtld_progname ?: "<main program>")), | |
21e2d3a4 | 515 | undef_map->l_ns, |
154d10bd | 516 | value->m->l_name[0] ? value->m->l_name : rtld_progname, |
21e2d3a4 | 517 | value->m->l_ns, |
154d10bd | 518 | protected ? "protected" : "normal", undef_name); |
32e6df36 UD |
519 | if (version) |
520 | _dl_debug_printf_c (" [%s]\n", version->name); | |
521 | else | |
522 | _dl_debug_printf_c ("\n"); | |
523 | } | |
524 | #ifdef SHARED | |
afdca0f2 | 525 | if (GLRO(dl_debug_mask) & DL_DEBUG_PRELINK) |
32e6df36 UD |
526 | { |
527 | int conflict = 0; | |
528 | struct sym_val val = { NULL, NULL }; | |
529 | ||
afdca0f2 | 530 | if ((GLRO(dl_trace_prelink_map) == NULL |
c0f62c56 UD |
531 | || GLRO(dl_trace_prelink_map) == GL(dl_ns)[LM_ID_BASE]._ns_loaded) |
532 | && undef_map != GL(dl_ns)[LM_ID_BASE]._ns_loaded) | |
32e6df36 | 533 | { |
871b9158 UD |
534 | const uint_fast32_t new_hash = dl_new_hash (undef_name); |
535 | unsigned long int old_hash = 0xffffffff; | |
32e6df36 | 536 | |
871b9158 | 537 | do_lookup_x (undef_name, new_hash, &old_hash, *ref, &val, |
bdf4a4f1 | 538 | undef_map->l_local_scope[0], 0, version, 0, NULL, |
415ac3df | 539 | type_class, undef_map); |
32e6df36 UD |
540 | |
541 | if (val.s != value->s || val.m != value->m) | |
542 | conflict = 1; | |
543 | } | |
544 | ||
02125962 JJ |
545 | if (value->s) |
546 | { | |
547 | if (__builtin_expect (ELFW(ST_TYPE) (value->s->st_info) | |
548 | == STT_TLS, 0)) | |
549 | type_class = 4; | |
550 | else if (__builtin_expect (ELFW(ST_TYPE) (value->s->st_info) | |
551 | == STT_GNU_IFUNC, 0)) | |
552 | type_class |= 8; | |
553 | } | |
1d0ad773 | 554 | |
32e6df36 | 555 | if (conflict |
afdca0f2 UD |
556 | || GLRO(dl_trace_prelink_map) == undef_map |
557 | || GLRO(dl_trace_prelink_map) == NULL | |
02125962 | 558 | || type_class >= 4) |
32e6df36 UD |
559 | { |
560 | _dl_printf ("%s 0x%0*Zx 0x%0*Zx -> 0x%0*Zx 0x%0*Zx ", | |
561 | conflict ? "conflict" : "lookup", | |
32e6df36 | 562 | (int) sizeof (ElfW(Addr)) * 2, |
d347a4ab | 563 | (size_t) undef_map->l_map_start, |
32e6df36 | 564 | (int) sizeof (ElfW(Addr)) * 2, |
d347a4ab | 565 | (size_t) (((ElfW(Addr)) *ref) - undef_map->l_map_start), |
32e6df36 | 566 | (int) sizeof (ElfW(Addr)) * 2, |
d347a4ab UD |
567 | (size_t) (value->s ? value->m->l_map_start : 0), |
568 | (int) sizeof (ElfW(Addr)) * 2, | |
569 | (size_t) (value->s ? value->s->st_value : 0)); | |
32e6df36 UD |
570 | |
571 | if (conflict) | |
572 | _dl_printf ("x 0x%0*Zx 0x%0*Zx ", | |
573 | (int) sizeof (ElfW(Addr)) * 2, | |
d347a4ab | 574 | (size_t) (val.s ? val.m->l_map_start : 0), |
32e6df36 | 575 | (int) sizeof (ElfW(Addr)) * 2, |
d347a4ab | 576 | (size_t) (val.s ? val.s->st_value : 0)); |
32e6df36 UD |
577 | |
578 | _dl_printf ("/%x %s\n", type_class, undef_name); | |
579 | } | |
580 | } | |
581 | #endif | |
582 | } |