]> sourceware.org Git - glibc.git/blame - elf/dl-lookup.c
Update.
[glibc.git] / elf / dl-lookup.c
CommitLineData
d66e34cd 1/* Look up a symbol in the loaded objects.
a42195db 2 Copyright (C) 1995,96,97,98,99,2000 Free Software Foundation, Inc.
afd4eb37 3 This file is part of the GNU C Library.
d66e34cd 4
afd4eb37
UD
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public License as
7 published by the Free Software Foundation; either version 2 of the
8 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
13 Library General Public License for more details.
d66e34cd 14
afd4eb37
UD
15 You should have received a copy of the GNU Library General Public
16 License along with the GNU C Library; see the file COPYING.LIB. If not,
17 write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA. */
d66e34cd 19
f671aeab 20#include <alloca.h>
cf197e41 21#include <stdlib.h>
8d6468d0 22#include <string.h>
3db52d94 23#include <unistd.h>
a42195db 24#include <ldsodefs.h>
bc9f6000
UD
25#include "dl-hash.h"
26#include <dl-machine.h>
cf197e41 27#include <bits/libc-lock.h>
c84142e8 28
a853022c
UD
29#include <assert.h>
30
c84142e8 31#define VERSTAG(tag) (DT_NUM + DT_PROCNUM + DT_VERSIONTAGIDX (tag))
266180eb 32
714a562f
UD
33/* We need this string more than once. */
34static const char undefined_msg[] = "undefined symbol: ";
35
36
84384f5b
UD
37struct sym_val
38 {
84384f5b 39 const ElfW(Sym) *s;
0c367d92 40 struct link_map *m;
84384f5b
UD
41 };
42
43
1fb05e3d
UD
44#define make_string(string, rest...) \
45 ({ \
46 const char *all[] = { string, ## rest }; \
47 size_t len, cnt; \
48 char *result, *cp; \
49 \
50 len = 1; \
51 for (cnt = 0; cnt < sizeof (all) / sizeof (all[0]); ++cnt) \
52 len += strlen (all[cnt]); \
53 \
54 cp = result = alloca (len); \
55 for (cnt = 0; cnt < sizeof (all) / sizeof (all[0]); ++cnt) \
da832465 56 cp = __stpcpy (cp, all[cnt]); \
1fb05e3d
UD
57 \
58 result; \
59 })
60
8352b484
UD
61/* Statistics function. */
62unsigned long int _dl_num_relocations;
63
cf197e41
UD
64/* During the program run we must not modify the global data of
65 loaded shared object simultanously in two threads. Therefore we
66 protect `_dl_open' and `_dl_close' in dl-close.c.
67
68 This must be a recursive lock since the initializer function of
69 the loaded object might as well require a call to this function.
70 At this time it is not anymore a problem to modify the tables. */
71__libc_lock_define (extern, _dl_load_lock)
72
1fb05e3d 73
a0e3f6f4
UD
74/* We have two different situations when looking up a simple: with or
75 without versioning. gcc is not able to optimize a single function
76 definition serving for both purposes so we define two functions. */
77#define VERSIONED 0
78#include "do-lookup.h"
84384f5b 79
a0e3f6f4
UD
80#define VERSIONED 1
81#include "do-lookup.h"
84384f5b 82
84384f5b 83
cf197e41
UD
84/* Add extra dependency on MAP to UNDEF_MAP. */
85static int
86add_dependency (struct link_map *undef_map, struct link_map *map)
87{
88 struct link_map **list;
89 unsigned act;
90 unsigned int i;
91 int result = 0;
92
93 /* Make sure nobody can unload the object while we are at it. */
94 __libc_lock_lock (_dl_load_lock);
95
96 /* Determine whether UNDEF_MAP already has a reference to MAP. First
97 look in the normal dependencies. */
98 list = undef_map->l_searchlist.r_list;
99 act = undef_map->l_searchlist.r_nlist;
100
101 for (i = 0; i < act; ++i)
102 if (list[i] == map)
103 break;
104
e3265f5b 105 if (__builtin_expect (i == act, 1))
cf197e41
UD
106 {
107 /* No normal dependency. See whether we already had to add it
108 to the special list of dynamic dependencies. */
109 list = undef_map->l_reldeps;
110 act = undef_map->l_reldepsact;
111
112 for (i = 0; i < act; ++i)
113 if (list[i] == map)
114 break;
115
116 if (i == act)
117 {
118 /* The object is not yet in the dependency list. Before we add
119 it make sure just one more time the object we are about to
120 reference is still available. There is a brief period in
121 which the object could have been removed since we found the
122 definition. */
123 struct link_map *runp = _dl_loaded;
124
125 while (runp != NULL && runp != map)
126 runp = runp->l_next;
127
128 if (runp != NULL)
129 {
130 /* The object is still available. Add the reference now. */
131 if (act >= undef_map->l_reldepsmax)
132 {
133 /* Allocate more memory for the dependency list. Since
134 this can never happen during the startup phase we can
135 use `realloc'. */
136 void *newp;
137
138 undef_map->l_reldepsmax += 5;
139 newp = realloc (undef_map->l_reldeps,
140 undef_map->l_reldepsmax);
141
142 if (__builtin_expect (newp != NULL, 1))
143 undef_map->l_reldeps = (struct link_map **) newp;
144 else
145 /* Correct the addition. */
146 undef_map->l_reldepsmax -= 5;
147 }
148
149 /* If we didn't manage to allocate memory for the list this
150 is no fatal mistake. We simply increment the use counter
151 of the referenced object and don't record the dependencies.
152 This means this increment can never be reverted and the
153 object will never be unloaded. This is semantically the
154 correct behaviour. */
155 if (act < undef_map->l_reldepsmax)
156 undef_map->l_reldeps[undef_map->l_reldepsact++] = map;
157
158 /* And increment the counter in the referenced object. */
159 ++map->l_opencount;
160
161 /* Display information if we are debugging. */
162 if (__builtin_expect (_dl_debug_files, 0))
163 _dl_debug_message (1, "\nfile=",
164 map->l_name[0] ? map->l_name : _dl_argv[0],
165 "; needed by ",
166 undef_map->l_name[0]
167 ? undef_map->l_name : _dl_argv[0],
168 " (relocation dependency)\n\n", NULL);
169 }
170 else
171 /* Whoa, that was bad luck. We have to search again. */
172 result = -1;
173 }
174 }
175
176 /* Release the lock. */
177 __libc_lock_unlock (_dl_load_lock);
178
179 return result;
180}
181
182
6c03c2cf 183/* Search loaded objects' symbol tables for a definition of the symbol
bc9f6000 184 UNDEF_NAME. */
d66e34cd 185
266180eb 186ElfW(Addr)
d0fc4041 187internal_function
06535ae9
UD
188_dl_lookup_symbol (const char *undef_name, struct link_map *undef_map,
189 const ElfW(Sym) **ref, struct r_scope_elem *symbol_scope[],
bc9f6000 190 int reloc_type)
d66e34cd 191{
06535ae9 192 const char *reference_name = undef_map ? undef_map->l_name : NULL;
266180eb 193 const unsigned long int hash = _dl_elf_hash (undef_name);
0c367d92 194 struct sym_val current_value = { NULL, NULL };
be935610 195 struct r_scope_elem **scope;
d66e34cd 196
48f6496e
UD
197 ++_dl_num_relocations;
198
d66e34cd 199 /* Search the relevant loaded objects for a definition. */
ba79d61b 200 for (scope = symbol_scope; *scope; ++scope)
06535ae9
UD
201 if (do_lookup (undef_name, undef_map, hash, *ref, &current_value,
202 *scope, 0, NULL, reloc_type))
cf197e41
UD
203 {
204 /* We have to check whether this would bind UNDEF_MAP to an object
205 in the global scope which was dynamically loaded. In this case
206 we have to prevent the latter from being unloaded unless the
207 UNDEF_MAP object is also unloaded. */
208 if (current_value.m->l_global
209 && (__builtin_expect (current_value.m->l_type, lt_library)
210 == lt_loaded)
211 && undef_map != current_value.m
212 /* Add UNDEF_MAP to the dependencies. */
213 && add_dependency (undef_map, current_value.m) < 0)
214 /* Something went wrong. Perhaps the object we tried to reference
215 was just removed. Try finding another definition. */
216 return _dl_lookup_symbol (undef_name, undef_map, ref, symbol_scope,
217 reloc_type);
218
219 break;
220 }
ba79d61b 221
0c367d92
UD
222 if (current_value.s == NULL)
223 {
224 if (*ref == NULL || ELFW(ST_BIND) ((*ref)->st_info) != STB_WEAK)
225 /* We could find no value for a strong reference. */
7730a3b9 226 _dl_signal_cerror (0, (reference_name && reference_name[0]
3f933dc2
UD
227 ? reference_name
228 : (_dl_argv[0] ?: "<main program>")),
229 make_string (undefined_msg, undef_name));
0c367d92
UD
230 *ref = NULL;
231 return 0;
232 }
233
cf197e41 234 if (__builtin_expect (_dl_debug_bindings, 0))
bc526b60
UD
235 _dl_debug_message (1, "binding file ",
236 (reference_name && reference_name[0]
237 ? reference_name
238 : (_dl_argv[0] ?: "<main program>")),
239 " to ", current_value.m->l_name[0]
0c367d92
UD
240 ? current_value.m->l_name : _dl_argv[0],
241 ": symbol `", undef_name, "'\n", NULL);
d66e34cd 242
84384f5b 243 *ref = current_value.s;
0c367d92 244 return current_value.m->l_addr;
84384f5b
UD
245}
246
247
248/* This function is nearly the same as `_dl_lookup_symbol' but it
249 skips in the first list all objects until SKIP_MAP is found. I.e.,
250 it only considers objects which were loaded after the described
251 object. If there are more search lists the object described by
252 SKIP_MAP is only skipped. */
253ElfW(Addr)
d0fc4041 254internal_function
06535ae9
UD
255_dl_lookup_symbol_skip (const char *undef_name,
256 struct link_map *undef_map, const ElfW(Sym) **ref,
be935610 257 struct r_scope_elem *symbol_scope[],
bc9f6000 258 struct link_map *skip_map)
84384f5b 259{
06535ae9 260 const char *reference_name = undef_map ? undef_map->l_name : NULL;
84384f5b 261 const unsigned long int hash = _dl_elf_hash (undef_name);
0c367d92 262 struct sym_val current_value = { NULL, NULL };
be935610 263 struct r_scope_elem **scope;
84384f5b
UD
264 size_t i;
265
48f6496e
UD
266 ++_dl_num_relocations;
267
84384f5b
UD
268 /* Search the relevant loaded objects for a definition. */
269 scope = symbol_scope;
be935610
UD
270 for (i = 0; (*scope)->r_duplist[i] != skip_map; ++i)
271 assert (i < (*scope)->r_nduplist);
84384f5b 272
cf197e41
UD
273 if (i < (*scope)->r_nlist
274 && do_lookup (undef_name, undef_map, hash, *ref, &current_value,
275 *scope, i, skip_map, 0))
276 {
277 /* We have to check whether this would bind UNDEF_MAP to an object
278 in the global scope which was dynamically loaded. In this case
279 we have to prevent the latter from being unloaded unless the
280 UNDEF_MAP object is also unloaded. */
281 if (current_value.m->l_global
282 && (__builtin_expect (current_value.m->l_type, lt_library)
283 == lt_loaded)
284 && undef_map != current_value.m
285 /* Add UNDEF_MAP to the dependencies. */
286 && add_dependency (undef_map, current_value.m) < 0)
287 /* Something went wrong. Perhaps the object we tried to reference
288 was just removed. Try finding another definition. */
289 return _dl_lookup_symbol_skip (undef_name, undef_map, ref,
290 symbol_scope, skip_map);
291 }
292 else
c84142e8 293 while (*++scope)
06535ae9
UD
294 if (do_lookup (undef_name, undef_map, hash, *ref, &current_value,
295 *scope, 0, skip_map, 0))
cf197e41
UD
296 {
297 /* We have to check whether this would bind UNDEF_MAP to an object
298 in the global scope which was dynamically loaded. In this case
299 we have to prevent the latter from being unloaded unless the
300 UNDEF_MAP object is also unloaded. */
301 if (current_value.m->l_global
302 && (__builtin_expect (current_value.m->l_type, lt_library)
303 == lt_loaded)
304 && undef_map != current_value.m
305 /* Add UNDEF_MAP to the dependencies. */
306 && add_dependency (undef_map, current_value.m) < 0)
307 /* Something went wrong. Perhaps the object we tried to reference
308 was just removed. Try finding another definition. */
309 return _dl_lookup_symbol_skip (undef_name, undef_map, ref,
310 symbol_scope, skip_map);
311
312 break;
313 }
c84142e8 314
0c367d92
UD
315 if (current_value.s == NULL)
316 {
317 *ref = NULL;
318 return 0;
319 }
320
cf197e41 321 if (__builtin_expect (_dl_debug_bindings, 0))
bc526b60
UD
322 _dl_debug_message (1, "binding file ",
323 (reference_name && reference_name[0]
324 ? reference_name
325 : (_dl_argv[0] ?: "<main program>")),
326 " to ", current_value.m->l_name[0]
0c367d92 327 ? current_value.m->l_name : _dl_argv[0],
bc526b60 328 ": symbol `", undef_name, "' (skip)\n", NULL);
0c367d92 329
c84142e8 330 *ref = current_value.s;
0c367d92 331 return current_value.m->l_addr;
c84142e8
UD
332}
333
334
335/* This function works like _dl_lookup_symbol but it takes an
336 additional arguement with the version number of the requested
337 symbol.
338
339 XXX We'll see whether we need this separate function. */
340ElfW(Addr)
d0fc4041 341internal_function
06535ae9
UD
342_dl_lookup_versioned_symbol (const char *undef_name,
343 struct link_map *undef_map, const ElfW(Sym) **ref,
be935610 344 struct r_scope_elem *symbol_scope[],
bc9f6000
UD
345 const struct r_found_version *version,
346 int reloc_type)
c84142e8 347{
06535ae9 348 const char *reference_name = undef_map ? undef_map->l_name : NULL;
c84142e8 349 const unsigned long int hash = _dl_elf_hash (undef_name);
0c367d92 350 struct sym_val current_value = { NULL, NULL };
be935610 351 struct r_scope_elem **scope;
c84142e8 352
48f6496e
UD
353 ++_dl_num_relocations;
354
c84142e8
UD
355 /* Search the relevant loaded objects for a definition. */
356 for (scope = symbol_scope; *scope; ++scope)
1fb05e3d 357 {
06535ae9
UD
358 int res = do_lookup_versioned (undef_name, undef_map, hash, *ref,
359 &current_value, *scope, 0, version, NULL,
a0e3f6f4 360 reloc_type);
1fb05e3d 361 if (res > 0)
cf197e41
UD
362 {
363 /* We have to check whether this would bind UNDEF_MAP to an object
364 in the global scope which was dynamically loaded. In this case
365 we have to prevent the latter from being unloaded unless the
366 UNDEF_MAP object is also unloaded. */
367 if (current_value.m->l_global
368 && (__builtin_expect (current_value.m->l_type, lt_library)
369 == lt_loaded)
370 && undef_map != current_value.m
371 /* Add UNDEF_MAP to the dependencies. */
372 && add_dependency (undef_map, current_value.m) < 0)
373 /* Something went wrong. Perhaps the object we tried to reference
374 was just removed. Try finding another definition. */
375 return _dl_lookup_versioned_symbol (undef_name, undef_map, ref,
376 symbol_scope, version,
377 reloc_type);
378
379 break;
380 }
1fb05e3d
UD
381
382 if (res < 0)
3f933dc2
UD
383 {
384 /* Oh, oh. The file named in the relocation entry does not
385 contain the needed symbol. */
386 _dl_signal_cerror (0, (reference_name && reference_name[0]
387 ? reference_name
388 : (_dl_argv[0] ?: "<main program>")),
389 make_string ("symbol ", undef_name, ", version ",
390 version->name,
391 " not defined in file ",
392 version->filename,
393 " with link time reference",
394 res == -2
395 ? " (no version symbols)" : ""));
396 *ref = NULL;
397 return 0;
398 }
1fb05e3d 399 }
c84142e8 400
0c367d92
UD
401 if (current_value.s == NULL)
402 {
403 if (*ref == NULL || ELFW(ST_BIND) ((*ref)->st_info) != STB_WEAK)
404 /* We could find no value for a strong reference. */
3f933dc2
UD
405 _dl_signal_cerror (0, (reference_name && reference_name[0]
406 ? reference_name
407 : (_dl_argv[0] ?: "<main program>")),
408 make_string (undefined_msg, undef_name,
409 ", version ", version->name ?: NULL));
0c367d92
UD
410 *ref = NULL;
411 return 0;
412 }
413
cf197e41 414 if (__builtin_expect (_dl_debug_bindings, 0))
bc526b60
UD
415 _dl_debug_message (1, "binding file ",
416 (reference_name && reference_name[0]
417 ? reference_name
418 : (_dl_argv[0] ?: "<main program>")),
419 " to ", current_value.m->l_name[0]
0c367d92 420 ? current_value.m->l_name : _dl_argv[0],
db0b91a9
UD
421 ": symbol `", undef_name, "' [", version->name,
422 "]\n", NULL);
c84142e8
UD
423
424 *ref = current_value.s;
0c367d92 425 return current_value.m->l_addr;
c84142e8
UD
426}
427
428
429/* Similar to _dl_lookup_symbol_skip but takes an additional argument
430 with the version we are looking for. */
431ElfW(Addr)
d0fc4041 432internal_function
c84142e8 433_dl_lookup_versioned_symbol_skip (const char *undef_name,
06535ae9 434 struct link_map *undef_map,
c84142e8 435 const ElfW(Sym) **ref,
be935610 436 struct r_scope_elem *symbol_scope[],
1fb05e3d 437 const struct r_found_version *version,
bc9f6000 438 struct link_map *skip_map)
c84142e8 439{
06535ae9 440 const char *reference_name = undef_map ? undef_map->l_name : NULL;
c84142e8 441 const unsigned long int hash = _dl_elf_hash (undef_name);
0c367d92 442 struct sym_val current_value = { NULL, NULL };
be935610 443 struct r_scope_elem **scope;
c84142e8
UD
444 size_t i;
445
48f6496e
UD
446 ++_dl_num_relocations;
447
c84142e8
UD
448 /* Search the relevant loaded objects for a definition. */
449 scope = symbol_scope;
be935610
UD
450 for (i = 0; (*scope)->r_duplist[i] != skip_map; ++i)
451 assert (i < (*scope)->r_nduplist);
c84142e8 452
cf197e41
UD
453 if (i < (*scope)->r_nlist
454 && do_lookup_versioned (undef_name, undef_map, hash, *ref,
455 &current_value, *scope, i, version, skip_map, 0))
456 {
457 /* We have to check whether this would bind UNDEF_MAP to an object
458 in the global scope which was dynamically loaded. In this case
459 we have to prevent the latter from being unloaded unless the
460 UNDEF_MAP object is also unloaded. */
461 if (current_value.m->l_global
462 && (__builtin_expect (current_value.m->l_type, lt_library)
463 == lt_loaded)
464 && undef_map != current_value.m
465 /* Add UNDEF_MAP to the dependencies. */
466 && add_dependency (undef_map, current_value.m) < 0)
467 /* Something went wrong. Perhaps the object we tried to reference
468 was just removed. Try finding another definition. */
469 return _dl_lookup_versioned_symbol_skip (undef_name, undef_map, ref,
470 symbol_scope, version,
471 skip_map);
472 }
473 else
84384f5b 474 while (*++scope)
06535ae9
UD
475 if (do_lookup_versioned (undef_name, undef_map, hash, *ref,
476 &current_value, *scope, 0, version, skip_map,
477 0))
cf197e41
UD
478 {
479 /* We have to check whether this would bind UNDEF_MAP to an object
480 in the global scope which was dynamically loaded. In this case
481 we have to prevent the latter from being unloaded unless the
482 UNDEF_MAP object is also unloaded. */
483 if (current_value.m->l_global
484 && (__builtin_expect (current_value.m->l_type, lt_library)
485 == lt_loaded)
486 && undef_map != current_value.m
487 /* Add UNDEF_MAP to the dependencies. */
488 && add_dependency (undef_map, current_value.m) < 0)
489 /* Something went wrong. Perhaps the object we tried to reference
490 was just removed. Try finding another definition. */
491 return _dl_lookup_versioned_symbol_skip (undef_name, undef_map,
492 ref, symbol_scope,
493 version, skip_map);
494 break;
495 }
84384f5b 496
0c367d92 497 if (current_value.s == NULL)
1f205a47 498 {
0c367d92
UD
499 if (*ref == NULL || ELFW(ST_BIND) ((*ref)->st_info) != STB_WEAK)
500 {
501 /* We could find no value for a strong reference. */
502 const size_t len = strlen (undef_name);
503 char buf[sizeof undefined_msg + len];
504 __mempcpy (__mempcpy (buf, undefined_msg, sizeof undefined_msg - 1),
505 undef_name, len + 1);
3f933dc2
UD
506 _dl_signal_cerror (0, (reference_name && reference_name[0]
507 ? reference_name
508 : (_dl_argv[0] ?: "<main program>")), buf);
0c367d92
UD
509 }
510 *ref = NULL;
511 return 0;
1f205a47
UD
512 }
513
cf197e41 514 if (__builtin_expect (_dl_debug_bindings, 0))
bc526b60
UD
515 _dl_debug_message (1, "binding file ",
516 (reference_name && reference_name[0]
517 ? reference_name
518 : (_dl_argv[0] ?: "<main program>")),
519 " to ",
0c367d92
UD
520 current_value.m->l_name[0]
521 ? current_value.m->l_name : _dl_argv[0],
db0b91a9 522 ": symbol `", undef_name, "' [", version->name,
bc526b60 523 "] (skip)\n", NULL);
0c367d92 524
84384f5b 525 *ref = current_value.s;
0c367d92 526 return current_value.m->l_addr;
d66e34cd
RM
527}
528
529
530/* Cache the location of MAP's hash table. */
531
532void
d0fc4041 533internal_function
d66e34cd
RM
534_dl_setup_hash (struct link_map *map)
535{
a1eca9f3
UD
536 Elf_Symndx *hash;
537 Elf_Symndx nchain;
f41c8091
UD
538
539 if (!map->l_info[DT_HASH])
540 return;
541 hash = (void *)(map->l_addr + map->l_info[DT_HASH]->d_un.d_ptr);
542
d66e34cd
RM
543 map->l_nbuckets = *hash++;
544 nchain = *hash++;
545 map->l_buckets = hash;
546 hash += map->l_nbuckets;
547 map->l_chain = hash;
548}
This page took 0.159602 seconds and 5 git commands to generate.