]>
Commit | Line | Data |
---|---|---|
d66e34cd | 1 | /* Look up a symbol in the loaded objects. |
aff4519d | 2 | Copyright (C) 1995-2002, 2003 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> |
bc9f6000 UD |
26 | #include "dl-hash.h" |
27 | #include <dl-machine.h> | |
cf197e41 | 28 | #include <bits/libc-lock.h> |
f1cc669a | 29 | #include <tls.h> |
c84142e8 | 30 | |
a853022c UD |
31 | #include <assert.h> |
32 | ||
b0982c4a | 33 | #define VERSTAG(tag) (DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGIDX (tag)) |
266180eb | 34 | |
714a562f UD |
35 | /* We need this string more than once. */ |
36 | static const char undefined_msg[] = "undefined symbol: "; | |
37 | ||
38 | ||
84384f5b UD |
39 | struct sym_val |
40 | { | |
84384f5b | 41 | const ElfW(Sym) *s; |
0c367d92 | 42 | struct link_map *m; |
84384f5b UD |
43 | }; |
44 | ||
45 | ||
1fb05e3d UD |
46 | #define make_string(string, rest...) \ |
47 | ({ \ | |
48 | const char *all[] = { string, ## rest }; \ | |
49 | size_t len, cnt; \ | |
50 | char *result, *cp; \ | |
51 | \ | |
52 | len = 1; \ | |
53 | for (cnt = 0; cnt < sizeof (all) / sizeof (all[0]); ++cnt) \ | |
54 | len += strlen (all[cnt]); \ | |
55 | \ | |
56 | cp = result = alloca (len); \ | |
57 | for (cnt = 0; cnt < sizeof (all) / sizeof (all[0]); ++cnt) \ | |
da832465 | 58 | cp = __stpcpy (cp, all[cnt]); \ |
1fb05e3d UD |
59 | \ |
60 | result; \ | |
61 | }) | |
62 | ||
8352b484 | 63 | /* Statistics function. */ |
d6b5d570 UD |
64 | #ifdef SHARED |
65 | # define bump_num_relocations() ++GL(dl_num_relocations) | |
be4b5a95 | 66 | #else |
d6b5d570 | 67 | # define bump_num_relocations() ((void) 0) |
be4b5a95 UD |
68 | #endif |
69 | ||
8352b484 | 70 | |
1fb05e3d | 71 | |
a0e3f6f4 UD |
72 | /* We have two different situations when looking up a simple: with or |
73 | without versioning. gcc is not able to optimize a single function | |
74 | definition serving for both purposes so we define two functions. */ | |
75 | #define VERSIONED 0 | |
76 | #include "do-lookup.h" | |
84384f5b | 77 | |
a0e3f6f4 UD |
78 | #define VERSIONED 1 |
79 | #include "do-lookup.h" | |
84384f5b | 80 | |
84384f5b | 81 | |
cf197e41 UD |
82 | /* Add extra dependency on MAP to UNDEF_MAP. */ |
83 | static int | |
80d9c5f0 | 84 | internal_function |
cf197e41 UD |
85 | add_dependency (struct link_map *undef_map, struct link_map *map) |
86 | { | |
87 | struct link_map **list; | |
c4bb124a | 88 | struct link_map *runp; |
c0282c06 | 89 | unsigned int act; |
cf197e41 UD |
90 | unsigned int i; |
91 | int result = 0; | |
92 | ||
aff4519d UD |
93 | /* Avoid self-references and references to objects which cannot be |
94 | unloaded anyway. */ | |
c4bb124a UD |
95 | if (undef_map == map) |
96 | return 0; | |
97 | ||
aff4519d UD |
98 | /* Make sure nobody can unload the object while we are at it. */ |
99 | __rtld_lock_lock_recursive (GL(dl_load_lock)); | |
100 | ||
6d78cd00 UD |
101 | /* Don't create cross-reference between modules which are |
102 | dynamically loaded by the same dlopen() call. */ | |
103 | if (undef_map->l_opencount == 0 && map->l_opencount == 0) | |
aff4519d UD |
104 | goto out; |
105 | ||
106 | /* Avoid references to objects which cannot be unloaded anyway. */ | |
107 | if (map->l_type != lt_loaded | |
108 | || (map->l_flags_1 & DF_1_NODELETE) != 0) | |
109 | goto out; | |
110 | ||
111 | /* If the object with the undefined reference cannot be removed ever | |
112 | just make sure the same is true for the object which contains the | |
113 | definition. */ | |
114 | if (undef_map->l_type != lt_loaded | |
115 | || (undef_map->l_flags_1 & DF_1_NODELETE) != 0) | |
116 | { | |
117 | ++map->l_opencount; | |
118 | map->l_flags |= DF_1_NODELETE; | |
119 | goto out; | |
120 | } | |
cf197e41 UD |
121 | |
122 | /* Determine whether UNDEF_MAP already has a reference to MAP. First | |
123 | look in the normal dependencies. */ | |
c4bb124a | 124 | if (undef_map->l_searchlist.r_list != NULL) |
cf197e41 | 125 | { |
c4bb124a | 126 | list = undef_map->l_initfini; |
cf197e41 | 127 | |
c4bb124a | 128 | for (i = 0; list[i] != NULL; ++i) |
cf197e41 | 129 | if (list[i] == map) |
c4bb124a UD |
130 | goto out; |
131 | } | |
132 | ||
133 | /* No normal dependency. See whether we already had to add it | |
134 | to the special list of dynamic dependencies. */ | |
135 | list = undef_map->l_reldeps; | |
136 | act = undef_map->l_reldepsact; | |
cf197e41 | 137 | |
c4bb124a UD |
138 | for (i = 0; i < act; ++i) |
139 | if (list[i] == map) | |
140 | goto out; | |
141 | ||
142 | /* The object is not yet in the dependency list. Before we add | |
143 | it make sure just one more time the object we are about to | |
144 | reference is still available. There is a brief period in | |
145 | which the object could have been removed since we found the | |
146 | definition. */ | |
d6b5d570 | 147 | runp = GL(dl_loaded); |
c4bb124a UD |
148 | while (runp != NULL && runp != map) |
149 | runp = runp->l_next; | |
150 | ||
151 | if (runp != NULL) | |
152 | { | |
153 | /* The object is still available. Add the reference now. */ | |
154 | if (__builtin_expect (act >= undef_map->l_reldepsmax, 0)) | |
cf197e41 | 155 | { |
c4bb124a UD |
156 | /* Allocate more memory for the dependency list. Since this |
157 | can never happen during the startup phase we can use | |
158 | `realloc'. */ | |
159 | void *newp; | |
160 | ||
161 | undef_map->l_reldepsmax += 5; | |
162 | newp = realloc (undef_map->l_reldeps, | |
163 | undef_map->l_reldepsmax | |
164 | * sizeof (struct link_map *)); | |
165 | ||
166 | if (__builtin_expect (newp != NULL, 1)) | |
167 | undef_map->l_reldeps = (struct link_map **) newp; | |
cf197e41 | 168 | else |
c4bb124a UD |
169 | /* Correct the addition. */ |
170 | undef_map->l_reldepsmax -= 5; | |
cf197e41 | 171 | } |
c4bb124a UD |
172 | |
173 | /* If we didn't manage to allocate memory for the list this is | |
174 | no fatal mistake. We simply increment the use counter of the | |
175 | referenced object and don't record the dependencies. This | |
176 | means this increment can never be reverted and the object | |
177 | will never be unloaded. This is semantically the correct | |
0b5045fe | 178 | behavior. */ |
c4bb124a UD |
179 | if (__builtin_expect (act < undef_map->l_reldepsmax, 1)) |
180 | undef_map->l_reldeps[undef_map->l_reldepsact++] = map; | |
181 | ||
84aafa91 UD |
182 | if (map->l_searchlist.r_list != NULL) |
183 | /* And increment the counter in the referenced object. */ | |
184 | ++map->l_opencount; | |
185 | else | |
186 | /* We have to bump the counts for all dependencies since so far | |
187 | this object was only a normal or transitive dependency. | |
188 | Now it might be closed with _dl_close() directly. */ | |
189 | for (list = map->l_initfini; *list != NULL; ++list) | |
190 | ++(*list)->l_opencount; | |
c4bb124a UD |
191 | |
192 | /* Display information if we are debugging. */ | |
d6b5d570 | 193 | if (__builtin_expect (GL(dl_debug_mask) & DL_DEBUG_FILES, 0)) |
64b6bd34 | 194 | INTUSE(_dl_debug_printf) ("\ |
c4bb124a | 195 | \nfile=%s; needed by %s (relocation dependency)\n\n", |
e6caf4e1 | 196 | map->l_name[0] ? map->l_name : rtld_progname, |
64b6bd34 | 197 | undef_map->l_name[0] |
e6caf4e1 | 198 | ? undef_map->l_name : rtld_progname); |
cf197e41 | 199 | } |
c4bb124a UD |
200 | else |
201 | /* Whoa, that was bad luck. We have to search again. */ | |
202 | result = -1; | |
cf197e41 | 203 | |
c4bb124a | 204 | out: |
cf197e41 | 205 | /* Release the lock. */ |
d3c9f895 | 206 | __rtld_lock_unlock_recursive (GL(dl_load_lock)); |
cf197e41 UD |
207 | |
208 | return result; | |
209 | } | |
210 | ||
80d9c5f0 UD |
211 | static int |
212 | internal_function | |
213 | _dl_do_lookup (const char *undef_name, unsigned long int hash, | |
214 | const ElfW(Sym) *ref, struct sym_val *result, | |
f9f2a150 | 215 | struct r_scope_elem *scope, size_t i, int flags, |
cf5a372e | 216 | struct link_map *skip, int type_class); |
80d9c5f0 UD |
217 | static int |
218 | internal_function | |
219 | _dl_do_lookup_versioned (const char *undef_name, unsigned long int hash, | |
220 | const ElfW(Sym) *ref, struct sym_val *result, | |
221 | struct r_scope_elem *scope, size_t i, | |
222 | const struct r_found_version *const version, | |
cf5a372e | 223 | struct link_map *skip, int type_class); |
cf197e41 | 224 | |
32e6df36 UD |
225 | static void |
226 | internal_function | |
227 | _dl_debug_bindings (const char *undef_name, struct link_map *undef_map, | |
228 | const ElfW(Sym) **ref, struct r_scope_elem *symbol_scope[], | |
7969407a UD |
229 | struct sym_val *value, |
230 | const struct r_found_version *version, int type_class, | |
231 | int protected); | |
647eb037 | 232 | |
6c03c2cf | 233 | /* Search loaded objects' symbol tables for a definition of the symbol |
bc9f6000 | 234 | UNDEF_NAME. */ |
d66e34cd | 235 | |
c0282c06 | 236 | lookup_t |
d0fc4041 | 237 | internal_function |
06535ae9 UD |
238 | _dl_lookup_symbol (const char *undef_name, struct link_map *undef_map, |
239 | const ElfW(Sym) **ref, struct r_scope_elem *symbol_scope[], | |
f9f2a150 | 240 | int type_class, int flags) |
d66e34cd | 241 | { |
32e6df36 | 242 | const unsigned long int hash = _dl_elf_hash (undef_name); |
680254fe | 243 | struct sym_val current_value = { NULL, NULL }; |
be935610 | 244 | struct r_scope_elem **scope; |
6aa29abe | 245 | int protected; |
d66e34cd | 246 | |
be4b5a95 | 247 | bump_num_relocations (); |
48f6496e | 248 | |
d66e34cd | 249 | /* Search the relevant loaded objects for a definition. */ |
ba79d61b | 250 | for (scope = symbol_scope; *scope; ++scope) |
f9f2a150 UD |
251 | if (do_lookup (undef_name, hash, *ref, ¤t_value, *scope, 0, flags, |
252 | NULL, type_class)) | |
78575a84 | 253 | break; |
ba79d61b | 254 | |
466a0ec9 | 255 | if (__builtin_expect (current_value.s == NULL, 0)) |
0c367d92 | 256 | { |
c90b5d28 UD |
257 | const char *reference_name = undef_map ? undef_map->l_name : NULL; |
258 | ||
0c367d92 UD |
259 | if (*ref == NULL || ELFW(ST_BIND) ((*ref)->st_info) != STB_WEAK) |
260 | /* We could find no value for a strong reference. */ | |
8e17ea58 | 261 | /* XXX We cannot translate the messages. */ |
32e6df36 | 262 | _dl_signal_cerror (0, (reference_name[0] |
3f933dc2 | 263 | ? reference_name |
e6caf4e1 | 264 | : (rtld_progname ?: "<main program>")), |
407fe3bb | 265 | N_("relocation error"), |
3f933dc2 | 266 | make_string (undefined_msg, undef_name)); |
0c367d92 UD |
267 | *ref = NULL; |
268 | return 0; | |
269 | } | |
270 | ||
6aa29abe | 271 | protected = *ref && ELFW(ST_VISIBILITY) ((*ref)->st_other) == STV_PROTECTED; |
32e6df36 | 272 | if (__builtin_expect (protected != 0, 0)) |
6aa29abe | 273 | { |
78575a84 UD |
274 | /* It is very tricky. We need to figure out what value to |
275 | return for the protected symbol. */ | |
6aa29abe UD |
276 | struct sym_val protected_value = { NULL, NULL }; |
277 | ||
278 | for (scope = symbol_scope; *scope; ++scope) | |
80d9c5f0 | 279 | if (_dl_do_lookup (undef_name, hash, *ref, &protected_value, *scope, |
f9f2a150 | 280 | 0, flags, NULL, ELF_RTYPE_CLASS_PLT)) |
6aa29abe UD |
281 | break; |
282 | ||
32e6df36 | 283 | if (protected_value.s != NULL && protected_value.m != undef_map) |
6aa29abe | 284 | { |
32e6df36 UD |
285 | current_value.s = *ref; |
286 | current_value.m = undef_map; | |
6aa29abe | 287 | } |
6aa29abe | 288 | } |
32e6df36 | 289 | |
78575a84 UD |
290 | /* We have to check whether this would bind UNDEF_MAP to an object |
291 | in the global scope which was dynamically loaded. In this case | |
292 | we have to prevent the latter from being unloaded unless the | |
293 | UNDEF_MAP object is also unloaded. */ | |
294 | if (__builtin_expect (current_value.m->l_type == lt_loaded, 0) | |
295 | /* Don't do this for explicit lookups as opposed to implicit | |
296 | runtime lookups. */ | |
297 | && (flags & DL_LOOKUP_ADD_DEPENDENCY) != 0 | |
298 | /* Add UNDEF_MAP to the dependencies. */ | |
299 | && add_dependency (undef_map, current_value.m) < 0) | |
300 | /* Something went wrong. Perhaps the object we tried to reference | |
301 | was just removed. Try finding another definition. */ | |
302 | return INTUSE(_dl_lookup_symbol) (undef_name, undef_map, ref, | |
303 | symbol_scope, type_class, flags); | |
304 | ||
d6b5d570 | 305 | if (__builtin_expect (GL(dl_debug_mask) |
32e6df36 UD |
306 | & (DL_DEBUG_BINDINGS|DL_DEBUG_PRELINK), 0)) |
307 | _dl_debug_bindings (undef_name, undef_map, ref, symbol_scope, | |
308 | ¤t_value, NULL, type_class, protected); | |
309 | ||
310 | *ref = current_value.s; | |
311 | return LOOKUP_VALUE (current_value.m); | |
84384f5b | 312 | } |
7969407a | 313 | INTDEF (_dl_lookup_symbol) |
84384f5b UD |
314 | |
315 | ||
316 | /* This function is nearly the same as `_dl_lookup_symbol' but it | |
317 | skips in the first list all objects until SKIP_MAP is found. I.e., | |
318 | it only considers objects which were loaded after the described | |
319 | object. If there are more search lists the object described by | |
320 | SKIP_MAP is only skipped. */ | |
c0282c06 | 321 | lookup_t |
d0fc4041 | 322 | internal_function |
06535ae9 UD |
323 | _dl_lookup_symbol_skip (const char *undef_name, |
324 | struct link_map *undef_map, const ElfW(Sym) **ref, | |
be935610 | 325 | struct r_scope_elem *symbol_scope[], |
bc9f6000 | 326 | struct link_map *skip_map) |
84384f5b | 327 | { |
84384f5b | 328 | const unsigned long int hash = _dl_elf_hash (undef_name); |
0c367d92 | 329 | struct sym_val current_value = { NULL, NULL }; |
be935610 | 330 | struct r_scope_elem **scope; |
84384f5b | 331 | size_t i; |
6aa29abe | 332 | int protected; |
84384f5b | 333 | |
be4b5a95 | 334 | bump_num_relocations (); |
48f6496e | 335 | |
84384f5b UD |
336 | /* Search the relevant loaded objects for a definition. */ |
337 | scope = symbol_scope; | |
80d9c5f0 UD |
338 | for (i = 0; (*scope)->r_list[i] != skip_map; ++i) |
339 | assert (i < (*scope)->r_nlist); | |
84384f5b | 340 | |
80d9c5f0 | 341 | if (! _dl_do_lookup (undef_name, hash, *ref, ¤t_value, *scope, i, |
f9f2a150 | 342 | DL_LOOKUP_RETURN_NEWEST, skip_map, 0)) |
c84142e8 | 343 | while (*++scope) |
80d9c5f0 | 344 | if (_dl_do_lookup (undef_name, hash, *ref, ¤t_value, *scope, 0, |
f9f2a150 | 345 | DL_LOOKUP_RETURN_NEWEST, skip_map, 0)) |
2b7238dd | 346 | break; |
c84142e8 | 347 | |
466a0ec9 | 348 | if (__builtin_expect (current_value.s == NULL, 0)) |
0c367d92 UD |
349 | { |
350 | *ref = NULL; | |
351 | return 0; | |
352 | } | |
353 | ||
6aa29abe UD |
354 | protected = *ref && ELFW(ST_VISIBILITY) ((*ref)->st_other) == STV_PROTECTED; |
355 | ||
32e6df36 | 356 | if (__builtin_expect (protected != 0, 0)) |
6aa29abe | 357 | { |
2b7238dd UD |
358 | /* It is very tricky. We need to figure out what value to |
359 | return for the protected symbol. */ | |
6aa29abe UD |
360 | struct sym_val protected_value = { NULL, NULL }; |
361 | ||
362 | if (i >= (*scope)->r_nlist | |
80d9c5f0 | 363 | || !_dl_do_lookup (undef_name, hash, *ref, &protected_value, *scope, |
f9f2a150 UD |
364 | i, DL_LOOKUP_RETURN_NEWEST, skip_map, |
365 | ELF_RTYPE_CLASS_PLT)) | |
6aa29abe | 366 | while (*++scope) |
80d9c5f0 | 367 | if (_dl_do_lookup (undef_name, hash, *ref, &protected_value, *scope, |
f9f2a150 UD |
368 | 0, DL_LOOKUP_RETURN_NEWEST, skip_map, |
369 | ELF_RTYPE_CLASS_PLT)) | |
6aa29abe UD |
370 | break; |
371 | ||
32e6df36 | 372 | if (protected_value.s != NULL && protected_value.m != undef_map) |
6aa29abe | 373 | { |
32e6df36 UD |
374 | current_value.s = *ref; |
375 | current_value.m = undef_map; | |
6aa29abe | 376 | } |
6aa29abe | 377 | } |
32e6df36 | 378 | |
d6b5d570 | 379 | if (__builtin_expect (GL(dl_debug_mask) |
32e6df36 UD |
380 | & (DL_DEBUG_BINDINGS|DL_DEBUG_PRELINK), 0)) |
381 | _dl_debug_bindings (undef_name, undef_map, ref, symbol_scope, | |
382 | ¤t_value, NULL, 0, protected); | |
383 | ||
384 | *ref = current_value.s; | |
385 | return LOOKUP_VALUE (current_value.m); | |
c84142e8 UD |
386 | } |
387 | ||
388 | ||
389 | /* This function works like _dl_lookup_symbol but it takes an | |
390 | additional arguement with the version number of the requested | |
391 | symbol. | |
392 | ||
393 | XXX We'll see whether we need this separate function. */ | |
c0282c06 | 394 | lookup_t |
d0fc4041 | 395 | internal_function |
06535ae9 UD |
396 | _dl_lookup_versioned_symbol (const char *undef_name, |
397 | struct link_map *undef_map, const ElfW(Sym) **ref, | |
be935610 | 398 | struct r_scope_elem *symbol_scope[], |
bc9f6000 | 399 | const struct r_found_version *version, |
f9f2a150 | 400 | int type_class, int flags) |
c84142e8 | 401 | { |
32e6df36 | 402 | const unsigned long int hash = _dl_elf_hash (undef_name); |
680254fe | 403 | struct sym_val current_value = { NULL, NULL }; |
be935610 | 404 | struct r_scope_elem **scope; |
6aa29abe | 405 | int protected; |
c84142e8 | 406 | |
be4b5a95 | 407 | bump_num_relocations (); |
48f6496e | 408 | |
f9f2a150 UD |
409 | /* No other flag than DL_LOOKUP_ADD_DEPENDENCY is allowed. */ |
410 | assert (flags == 0 || flags == DL_LOOKUP_ADD_DEPENDENCY); | |
411 | ||
c84142e8 UD |
412 | /* Search the relevant loaded objects for a definition. */ |
413 | for (scope = symbol_scope; *scope; ++scope) | |
1fb05e3d | 414 | { |
2b7238dd | 415 | int res = do_lookup_versioned (undef_name, hash, *ref, ¤t_value, |
cf5a372e | 416 | *scope, 0, version, NULL, type_class); |
1fb05e3d | 417 | if (res > 0) |
78575a84 | 418 | break; |
1fb05e3d | 419 | |
466a0ec9 | 420 | if (__builtin_expect (res, 0) < 0) |
3f933dc2 UD |
421 | { |
422 | /* Oh, oh. The file named in the relocation entry does not | |
423 | contain the needed symbol. */ | |
c90b5d28 UD |
424 | const char *reference_name = undef_map ? undef_map->l_name : NULL; |
425 | ||
8e17ea58 | 426 | /* XXX We cannot translate the message. */ |
32e6df36 | 427 | _dl_signal_cerror (0, (reference_name[0] |
3f933dc2 | 428 | ? reference_name |
e6caf4e1 | 429 | : (rtld_progname ?: "<main program>")), |
407fe3bb | 430 | N_("relocation error"), |
3f933dc2 UD |
431 | make_string ("symbol ", undef_name, ", version ", |
432 | version->name, | |
433 | " not defined in file ", | |
434 | version->filename, | |
435 | " with link time reference", | |
436 | res == -2 | |
437 | ? " (no version symbols)" : "")); | |
438 | *ref = NULL; | |
439 | return 0; | |
440 | } | |
1fb05e3d | 441 | } |
c84142e8 | 442 | |
466a0ec9 | 443 | if (__builtin_expect (current_value.s == NULL, 0)) |
0c367d92 UD |
444 | { |
445 | if (*ref == NULL || ELFW(ST_BIND) ((*ref)->st_info) != STB_WEAK) | |
c90b5d28 UD |
446 | { |
447 | /* We could find no value for a strong reference. */ | |
448 | const char *reference_name = undef_map ? undef_map->l_name : NULL; | |
449 | ||
450 | /* XXX We cannot translate the message. */ | |
32e6df36 | 451 | _dl_signal_cerror (0, (reference_name[0] |
c90b5d28 | 452 | ? reference_name |
e6caf4e1 | 453 | : (rtld_progname ?: "<main program>")), NULL, |
c90b5d28 UD |
454 | make_string (undefined_msg, undef_name, |
455 | ", version ", | |
456 | version->name ?: NULL)); | |
457 | } | |
0c367d92 UD |
458 | *ref = NULL; |
459 | return 0; | |
460 | } | |
461 | ||
6aa29abe UD |
462 | protected = *ref && ELFW(ST_VISIBILITY) ((*ref)->st_other) == STV_PROTECTED; |
463 | ||
32e6df36 | 464 | if (__builtin_expect (protected != 0, 0)) |
6aa29abe | 465 | { |
78575a84 UD |
466 | /* It is very tricky. We need to figure out what value to |
467 | return for the protected symbol. */ | |
6aa29abe UD |
468 | struct sym_val protected_value = { NULL, NULL }; |
469 | ||
470 | for (scope = symbol_scope; *scope; ++scope) | |
80d9c5f0 | 471 | if (_dl_do_lookup_versioned (undef_name, hash, *ref, &protected_value, |
cf5a372e UD |
472 | *scope, 0, version, NULL, |
473 | ELF_RTYPE_CLASS_PLT)) | |
6aa29abe UD |
474 | break; |
475 | ||
32e6df36 | 476 | if (protected_value.s != NULL && protected_value.m != undef_map) |
6aa29abe | 477 | { |
32e6df36 UD |
478 | current_value.s = *ref; |
479 | current_value.m = undef_map; | |
6aa29abe | 480 | } |
6aa29abe | 481 | } |
32e6df36 | 482 | |
78575a84 UD |
483 | /* We have to check whether this would bind UNDEF_MAP to an object |
484 | in the global scope which was dynamically loaded. In this case | |
485 | we have to prevent the latter from being unloaded unless the | |
486 | UNDEF_MAP object is also unloaded. */ | |
487 | if (__builtin_expect (current_value.m->l_type == lt_loaded, 0) | |
488 | /* Don't do this for explicit lookups as opposed to implicit | |
489 | runtime lookups. */ | |
490 | && flags != 0 | |
491 | /* Add UNDEF_MAP to the dependencies. */ | |
492 | && add_dependency (undef_map, current_value.m) < 0) | |
493 | /* Something went wrong. Perhaps the object we tried to reference | |
494 | was just removed. Try finding another definition. */ | |
495 | return INTUSE(_dl_lookup_versioned_symbol) (undef_name, undef_map, | |
496 | ref, symbol_scope, | |
497 | version, type_class, flags); | |
498 | ||
d6b5d570 | 499 | if (__builtin_expect (GL(dl_debug_mask) |
32e6df36 UD |
500 | & (DL_DEBUG_BINDINGS|DL_DEBUG_PRELINK), 0)) |
501 | _dl_debug_bindings (undef_name, undef_map, ref, symbol_scope, | |
502 | ¤t_value, version, type_class, protected); | |
503 | ||
504 | *ref = current_value.s; | |
505 | return LOOKUP_VALUE (current_value.m); | |
c84142e8 | 506 | } |
7969407a | 507 | INTDEF (_dl_lookup_versioned_symbol) |
c84142e8 UD |
508 | |
509 | ||
510 | /* Similar to _dl_lookup_symbol_skip but takes an additional argument | |
511 | with the version we are looking for. */ | |
c0282c06 | 512 | lookup_t |
d0fc4041 | 513 | internal_function |
c84142e8 | 514 | _dl_lookup_versioned_symbol_skip (const char *undef_name, |
06535ae9 | 515 | struct link_map *undef_map, |
c84142e8 | 516 | const ElfW(Sym) **ref, |
be935610 | 517 | struct r_scope_elem *symbol_scope[], |
1fb05e3d | 518 | const struct r_found_version *version, |
bc9f6000 | 519 | struct link_map *skip_map) |
c84142e8 | 520 | { |
32e6df36 | 521 | const char *reference_name = undef_map->l_name; |
c84142e8 | 522 | const unsigned long int hash = _dl_elf_hash (undef_name); |
0c367d92 | 523 | struct sym_val current_value = { NULL, NULL }; |
be935610 | 524 | struct r_scope_elem **scope; |
c84142e8 | 525 | size_t i; |
6aa29abe | 526 | int protected; |
c84142e8 | 527 | |
be4b5a95 | 528 | bump_num_relocations (); |
48f6496e | 529 | |
c84142e8 UD |
530 | /* Search the relevant loaded objects for a definition. */ |
531 | scope = symbol_scope; | |
80d9c5f0 UD |
532 | for (i = 0; (*scope)->r_list[i] != skip_map; ++i) |
533 | assert (i < (*scope)->r_nlist); | |
c84142e8 | 534 | |
80d9c5f0 | 535 | if (! _dl_do_lookup_versioned (undef_name, hash, *ref, ¤t_value, |
cf5a372e | 536 | *scope, i, version, skip_map, 0)) |
84384f5b | 537 | while (*++scope) |
80d9c5f0 | 538 | if (_dl_do_lookup_versioned (undef_name, hash, *ref, ¤t_value, |
cf5a372e | 539 | *scope, 0, version, skip_map, 0)) |
2b7238dd | 540 | break; |
84384f5b | 541 | |
466a0ec9 | 542 | if (__builtin_expect (current_value.s == NULL, 0)) |
1f205a47 | 543 | { |
0c367d92 UD |
544 | if (*ref == NULL || ELFW(ST_BIND) ((*ref)->st_info) != STB_WEAK) |
545 | { | |
546 | /* We could find no value for a strong reference. */ | |
547 | const size_t len = strlen (undef_name); | |
548 | char buf[sizeof undefined_msg + len]; | |
549 | __mempcpy (__mempcpy (buf, undefined_msg, sizeof undefined_msg - 1), | |
550 | undef_name, len + 1); | |
8e17ea58 | 551 | /* XXX We cannot translate the messages. */ |
32e6df36 | 552 | _dl_signal_cerror (0, (reference_name[0] |
3f933dc2 | 553 | ? reference_name |
e6caf4e1 | 554 | : (rtld_progname ?: "<main program>")), |
407fe3bb | 555 | NULL, buf); |
0c367d92 UD |
556 | } |
557 | *ref = NULL; | |
558 | return 0; | |
1f205a47 UD |
559 | } |
560 | ||
6aa29abe UD |
561 | protected = *ref && ELFW(ST_VISIBILITY) ((*ref)->st_other) == STV_PROTECTED; |
562 | ||
32e6df36 | 563 | if (__builtin_expect (protected != 0, 0)) |
6aa29abe | 564 | { |
78575a84 UD |
565 | /* It is very tricky. We need to figure out what value to |
566 | return for the protected symbol. */ | |
6aa29abe UD |
567 | struct sym_val protected_value = { NULL, NULL }; |
568 | ||
569 | if (i >= (*scope)->r_nlist | |
80d9c5f0 UD |
570 | || !_dl_do_lookup_versioned (undef_name, hash, *ref, |
571 | &protected_value, *scope, i, version, | |
cf5a372e | 572 | skip_map, ELF_RTYPE_CLASS_PLT)) |
6aa29abe | 573 | while (*++scope) |
80d9c5f0 UD |
574 | if (_dl_do_lookup_versioned (undef_name, hash, *ref, |
575 | &protected_value, *scope, 0, version, | |
cf5a372e | 576 | skip_map, ELF_RTYPE_CLASS_PLT)) |
6aa29abe UD |
577 | break; |
578 | ||
32e6df36 | 579 | if (protected_value.s != NULL && protected_value.m != undef_map) |
6aa29abe | 580 | { |
32e6df36 UD |
581 | current_value.s = *ref; |
582 | current_value.m = undef_map; | |
6aa29abe | 583 | } |
6aa29abe | 584 | } |
32e6df36 | 585 | |
d6b5d570 | 586 | if (__builtin_expect (GL(dl_debug_mask) |
32e6df36 UD |
587 | & (DL_DEBUG_BINDINGS|DL_DEBUG_PRELINK), 0)) |
588 | _dl_debug_bindings (undef_name, undef_map, ref, symbol_scope, | |
589 | ¤t_value, version, 0, protected); | |
590 | ||
591 | *ref = current_value.s; | |
592 | return LOOKUP_VALUE (current_value.m); | |
d66e34cd RM |
593 | } |
594 | ||
595 | ||
596 | /* Cache the location of MAP's hash table. */ | |
597 | ||
598 | void | |
d0fc4041 | 599 | internal_function |
d66e34cd RM |
600 | _dl_setup_hash (struct link_map *map) |
601 | { | |
a1eca9f3 UD |
602 | Elf_Symndx *hash; |
603 | Elf_Symndx nchain; | |
f41c8091 UD |
604 | |
605 | if (!map->l_info[DT_HASH]) | |
606 | return; | |
9a88a2d7 | 607 | hash = (void *) D_PTR (map, l_info[DT_HASH]); |
f41c8091 | 608 | |
d66e34cd RM |
609 | map->l_nbuckets = *hash++; |
610 | nchain = *hash++; | |
611 | map->l_buckets = hash; | |
612 | hash += map->l_nbuckets; | |
613 | map->l_chain = hash; | |
614 | } | |
80d9c5f0 | 615 | |
f9f2a150 | 616 | |
32e6df36 UD |
617 | static void |
618 | internal_function | |
619 | _dl_debug_bindings (const char *undef_name, struct link_map *undef_map, | |
620 | const ElfW(Sym) **ref, struct r_scope_elem *symbol_scope[], | |
f9f2a150 UD |
621 | struct sym_val *value, |
622 | const struct r_found_version *version, int type_class, | |
623 | int protected) | |
32e6df36 UD |
624 | { |
625 | const char *reference_name = undef_map->l_name; | |
626 | ||
d6b5d570 | 627 | if (GL(dl_debug_mask) & DL_DEBUG_BINDINGS) |
32e6df36 | 628 | { |
64b6bd34 AJ |
629 | INTUSE(_dl_debug_printf) ("binding file %s to %s: %s symbol `%s'", |
630 | (reference_name[0] | |
631 | ? reference_name | |
e6caf4e1 | 632 | : (rtld_progname ?: "<main program>")), |
64b6bd34 | 633 | value->m->l_name[0] |
e6caf4e1 | 634 | ? value->m->l_name : rtld_progname, |
64b6bd34 AJ |
635 | protected ? "protected" : "normal", |
636 | undef_name); | |
32e6df36 UD |
637 | if (version) |
638 | _dl_debug_printf_c (" [%s]\n", version->name); | |
639 | else | |
640 | _dl_debug_printf_c ("\n"); | |
641 | } | |
642 | #ifdef SHARED | |
d6b5d570 | 643 | if (GL(dl_debug_mask) & DL_DEBUG_PRELINK) |
32e6df36 UD |
644 | { |
645 | int conflict = 0; | |
646 | struct sym_val val = { NULL, NULL }; | |
647 | ||
d6b5d570 UD |
648 | if ((GL(dl_trace_prelink_map) == NULL |
649 | || GL(dl_trace_prelink_map) == GL(dl_loaded)) | |
650 | && undef_map != GL(dl_loaded)) | |
32e6df36 UD |
651 | { |
652 | const unsigned long int hash = _dl_elf_hash (undef_name); | |
653 | ||
654 | if (version == 0) | |
655 | _dl_do_lookup (undef_name, hash, *ref, &val, | |
f9f2a150 UD |
656 | undef_map->l_local_scope[0], 0, 0, NULL, |
657 | type_class); | |
32e6df36 UD |
658 | else |
659 | _dl_do_lookup_versioned (undef_name, hash, *ref, &val, | |
660 | undef_map->l_local_scope[0], 0, version, | |
661 | NULL, type_class); | |
662 | ||
663 | if (val.s != value->s || val.m != value->m) | |
664 | conflict = 1; | |
665 | } | |
666 | ||
1d0ad773 RM |
667 | #ifdef USE_TLS |
668 | if (value->s | |
669 | && (__builtin_expect (ELFW(ST_TYPE) (value->s->st_info) | |
670 | == STT_TLS, 0))) | |
671 | type_class = 4; | |
672 | #endif | |
673 | ||
32e6df36 | 674 | if (conflict |
d6b5d570 | 675 | || GL(dl_trace_prelink_map) == undef_map |
1d0ad773 RM |
676 | || GL(dl_trace_prelink_map) == NULL |
677 | || type_class == 4) | |
32e6df36 UD |
678 | { |
679 | _dl_printf ("%s 0x%0*Zx 0x%0*Zx -> 0x%0*Zx 0x%0*Zx ", | |
680 | conflict ? "conflict" : "lookup", | |
681 | (int) sizeof (ElfW(Addr)) * 2, undef_map->l_map_start, | |
682 | (int) sizeof (ElfW(Addr)) * 2, | |
683 | ((ElfW(Addr)) *ref) - undef_map->l_map_start, | |
684 | (int) sizeof (ElfW(Addr)) * 2, | |
685 | (ElfW(Addr)) (value->s ? value->m->l_map_start : 0), | |
686 | (int) sizeof (ElfW(Addr)) * 2, | |
687 | (ElfW(Addr)) (value->s ? value->s->st_value : 0)); | |
688 | ||
689 | if (conflict) | |
690 | _dl_printf ("x 0x%0*Zx 0x%0*Zx ", | |
691 | (int) sizeof (ElfW(Addr)) * 2, | |
692 | (ElfW(Addr)) (val.s ? val.m->l_map_start : 0), | |
693 | (int) sizeof (ElfW(Addr)) * 2, | |
694 | (ElfW(Addr)) (val.s ? val.s->st_value : 0)); | |
695 | ||
696 | _dl_printf ("/%x %s\n", type_class, undef_name); | |
697 | } | |
698 | } | |
699 | #endif | |
700 | } | |
701 | ||
80d9c5f0 UD |
702 | /* These are here so that we only inline do_lookup{,_versioned} in the common |
703 | case, not everywhere. */ | |
fb23eb25 | 704 | static int __attribute_noinline__ |
80d9c5f0 UD |
705 | internal_function |
706 | _dl_do_lookup (const char *undef_name, unsigned long int hash, | |
707 | const ElfW(Sym) *ref, struct sym_val *result, | |
f9f2a150 | 708 | struct r_scope_elem *scope, size_t i, int flags, |
cf5a372e | 709 | struct link_map *skip, int type_class) |
80d9c5f0 | 710 | { |
f9f2a150 | 711 | return do_lookup (undef_name, hash, ref, result, scope, i, flags, skip, |
cf5a372e | 712 | type_class); |
80d9c5f0 UD |
713 | } |
714 | ||
fb23eb25 | 715 | static int __attribute_noinline__ |
80d9c5f0 UD |
716 | internal_function |
717 | _dl_do_lookup_versioned (const char *undef_name, unsigned long int hash, | |
718 | const ElfW(Sym) *ref, struct sym_val *result, | |
719 | struct r_scope_elem *scope, size_t i, | |
720 | const struct r_found_version *const version, | |
cf5a372e | 721 | struct link_map *skip, int type_class) |
80d9c5f0 UD |
722 | { |
723 | return do_lookup_versioned (undef_name, hash, ref, result, scope, i, | |
cf5a372e | 724 | version, skip, type_class); |
80d9c5f0 | 725 | } |