]> git.ipfire.org Git - thirdparty/glibc.git/blame - elf/dl-lookup.c
[BZ #3369]
[thirdparty/glibc.git] / elf / dl-lookup.c
CommitLineData
d66e34cd 1/* Look up a symbol in the loaded objects.
871b9158 2 Copyright (C) 1995-2005, 2006 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>
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. */
36static const char undefined_msg[] = "undefined symbol: ";
37
38
84384f5b
UD
39struct 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
bdf4a4f1 71/* The actual lookup code. */
a0e3f6f4 72#include "do-lookup.h"
84384f5b 73
84384f5b 74
871b9158
UD
75static uint_fast32_t
76dl_new_hash (const char *s)
77{
78 uint_fast32_t h = 5381;
79 for (unsigned char c = *s; c != '\0'; c = *++s)
80 h = h * 33 + c;
81 return h & 0xffffffff;
82}
83
84
cf197e41
UD
85/* Add extra dependency on MAP to UNDEF_MAP. */
86static int
80d9c5f0 87internal_function
cf197e41
UD
88add_dependency (struct link_map *undef_map, struct link_map *map)
89{
90 struct link_map **list;
c4bb124a 91 struct link_map *runp;
c0282c06 92 unsigned int act;
cf197e41
UD
93 unsigned int i;
94 int result = 0;
95
aff4519d
UD
96 /* Avoid self-references and references to objects which cannot be
97 unloaded anyway. */
c4bb124a
UD
98 if (undef_map == map)
99 return 0;
100
aff4519d
UD
101 /* Make sure nobody can unload the object while we are at it. */
102 __rtld_lock_lock_recursive (GL(dl_load_lock));
103
aff4519d
UD
104 /* Avoid references to objects which cannot be unloaded anyway. */
105 if (map->l_type != lt_loaded
106 || (map->l_flags_1 & DF_1_NODELETE) != 0)
107 goto out;
108
109 /* If the object with the undefined reference cannot be removed ever
110 just make sure the same is true for the object which contains the
111 definition. */
112 if (undef_map->l_type != lt_loaded
113 || (undef_map->l_flags_1 & DF_1_NODELETE) != 0)
114 {
a752d0cc 115 map->l_flags_1 |= DF_1_NODELETE;
aff4519d
UD
116 goto out;
117 }
cf197e41
UD
118
119 /* Determine whether UNDEF_MAP already has a reference to MAP. First
120 look in the normal dependencies. */
f7e39466 121 if (undef_map->l_initfini != NULL)
cf197e41 122 {
c4bb124a 123 list = undef_map->l_initfini;
cf197e41 124
c4bb124a 125 for (i = 0; list[i] != NULL; ++i)
cf197e41 126 if (list[i] == map)
c4bb124a
UD
127 goto out;
128 }
129
130 /* No normal dependency. See whether we already had to add it
131 to the special list of dynamic dependencies. */
132 list = undef_map->l_reldeps;
133 act = undef_map->l_reldepsact;
cf197e41 134
c4bb124a
UD
135 for (i = 0; i < act; ++i)
136 if (list[i] == map)
137 goto out;
138
139 /* The object is not yet in the dependency list. Before we add
140 it make sure just one more time the object we are about to
141 reference is still available. There is a brief period in
142 which the object could have been removed since we found the
143 definition. */
c0f62c56 144 runp = GL(dl_ns)[undef_map->l_ns]._ns_loaded;
c4bb124a
UD
145 while (runp != NULL && runp != map)
146 runp = runp->l_next;
147
148 if (runp != NULL)
149 {
150 /* The object is still available. Add the reference now. */
151 if (__builtin_expect (act >= undef_map->l_reldepsmax, 0))
cf197e41 152 {
c4bb124a
UD
153 /* Allocate more memory for the dependency list. Since this
154 can never happen during the startup phase we can use
155 `realloc'. */
156 void *newp;
157
158 undef_map->l_reldepsmax += 5;
159 newp = realloc (undef_map->l_reldeps,
160 undef_map->l_reldepsmax
161 * sizeof (struct link_map *));
162
163 if (__builtin_expect (newp != NULL, 1))
164 undef_map->l_reldeps = (struct link_map **) newp;
cf197e41 165 else
c4bb124a
UD
166 /* Correct the addition. */
167 undef_map->l_reldepsmax -= 5;
cf197e41 168 }
c4bb124a
UD
169
170 /* If we didn't manage to allocate memory for the list this is
171 no fatal mistake. We simply increment the use counter of the
172 referenced object and don't record the dependencies. This
173 means this increment can never be reverted and the object
174 will never be unloaded. This is semantically the correct
0b5045fe 175 behavior. */
c4bb124a
UD
176 if (__builtin_expect (act < undef_map->l_reldepsmax, 1))
177 undef_map->l_reldeps[undef_map->l_reldepsact++] = map;
178
c4bb124a 179 /* Display information if we are debugging. */
afdca0f2 180 if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_FILES, 0))
154d10bd 181 _dl_debug_printf ("\
c0f62c56 182\nfile=%s [%lu]; needed by %s [%lu] (relocation dependency)\n\n",
154d10bd 183 map->l_name[0] ? map->l_name : rtld_progname,
c0f62c56 184 map->l_ns,
154d10bd 185 undef_map->l_name[0]
c0f62c56
UD
186 ? undef_map->l_name : rtld_progname,
187 undef_map->l_ns);
cf197e41 188 }
c4bb124a
UD
189 else
190 /* Whoa, that was bad luck. We have to search again. */
191 result = -1;
cf197e41 192
c4bb124a 193 out:
cf197e41 194 /* Release the lock. */
d3c9f895 195 __rtld_lock_unlock_recursive (GL(dl_load_lock));
cf197e41
UD
196
197 return result;
198}
199
32e6df36
UD
200static void
201internal_function
202_dl_debug_bindings (const char *undef_name, struct link_map *undef_map,
a334319f
UD
203 const ElfW(Sym) **ref, struct r_scope_elem *symbol_scope[],
204 struct sym_val *value,
7969407a
UD
205 const struct r_found_version *version, int type_class,
206 int protected);
647eb037 207
84384f5b 208
bdf4a4f1 209/* Search loaded objects' symbol tables for a definition of the symbol
a334319f 210 UNDEF_NAME, perhaps with a requested version for the symbol. */
c0282c06 211lookup_t
d0fc4041 212internal_function
bdf4a4f1
UD
213_dl_lookup_symbol_x (const char *undef_name, struct link_map *undef_map,
214 const ElfW(Sym) **ref,
215 struct r_scope_elem *symbol_scope[],
216 const struct r_found_version *version,
217 int type_class, int flags, struct link_map *skip_map)
84384f5b 218{
871b9158
UD
219 const uint_fast32_t new_hash = dl_new_hash (undef_name);
220 unsigned long int old_hash = 0xffffffff;
0c367d92 221 struct sym_val current_value = { NULL, NULL };
bdf4a4f1 222 struct r_scope_elem **scope = symbol_scope;
84384f5b 223
be4b5a95 224 bump_num_relocations ();
48f6496e 225
bdf4a4f1
UD
226 /* No other flag than DL_LOOKUP_ADD_DEPENDENCY is allowed if we look
227 up a versioned symbol. */
a334319f 228 assert (version == NULL || flags == 0 || flags == DL_LOOKUP_ADD_DEPENDENCY);
c84142e8 229
bdf4a4f1
UD
230 size_t i = 0;
231 if (__builtin_expect (skip_map != NULL, 0))
a334319f
UD
232 {
233 /* Search the relevant loaded objects for a definition. */
234 while ((*scope)->r_list[i] != skip_map)
235 ++i;
236
237 assert (i < (*scope)->r_nlist);
238 }
32e6df36 239
c84142e8 240 /* Search the relevant loaded objects for a definition. */
bdf4a4f1 241 for (size_t start = i; *scope != NULL; start = 0, ++scope)
1fb05e3d 242 {
871b9158
UD
243 int res = do_lookup_x (undef_name, new_hash, &old_hash, *ref,
244 &current_value, *scope, start, version, flags,
245 skip_map, type_class);
1fb05e3d 246 if (res > 0)
78575a84 247 break;
1fb05e3d 248
bdf4a4f1 249 if (__builtin_expect (res, 0) < 0 && skip_map == NULL)
3f933dc2
UD
250 {
251 /* Oh, oh. The file named in the relocation entry does not
bdf4a4f1
UD
252 contain the needed symbol. This code is never reached
253 for unversioned lookups. */
254 assert (version != NULL);
c90b5d28
UD
255 const char *reference_name = undef_map ? undef_map->l_name : NULL;
256
8e17ea58 257 /* XXX We cannot translate the message. */
32e6df36 258 _dl_signal_cerror (0, (reference_name[0]
3f933dc2 259 ? reference_name
e6caf4e1 260 : (rtld_progname ?: "<main program>")),
407fe3bb 261 N_("relocation error"),
3f933dc2
UD
262 make_string ("symbol ", undef_name, ", version ",
263 version->name,
264 " not defined in file ",
265 version->filename,
266 " with link time reference",
267 res == -2
268 ? " (no version symbols)" : ""));
269 *ref = NULL;
270 return 0;
271 }
1fb05e3d 272 }
c84142e8 273
466a0ec9 274 if (__builtin_expect (current_value.s == NULL, 0))
0c367d92 275 {
bdf4a4f1
UD
276 if ((*ref == NULL || ELFW(ST_BIND) ((*ref)->st_info) != STB_WEAK)
277 && skip_map == NULL)
c90b5d28
UD
278 {
279 /* We could find no value for a strong reference. */
9363dbb8 280 const char *reference_name = undef_map ? undef_map->l_name : "";
bdf4a4f1
UD
281 const char *versionstr = version ? ", version " : "";
282 const char *versionname = (version && version->name
283 ? version->name : "");
c90b5d28
UD
284
285 /* XXX We cannot translate the message. */
32e6df36 286 _dl_signal_cerror (0, (reference_name[0]
c90b5d28 287 ? reference_name
24a07b1f
UD
288 : (rtld_progname ?: "<main program>")),
289 N_("symbol lookup error"),
c90b5d28 290 make_string (undefined_msg, undef_name,
bdf4a4f1 291 versionstr, versionname));
c90b5d28 292 }
0c367d92
UD
293 *ref = NULL;
294 return 0;
295 }
296
bdf4a4f1
UD
297 int protected = (*ref
298 && ELFW(ST_VISIBILITY) ((*ref)->st_other) == STV_PROTECTED);
32e6df36 299 if (__builtin_expect (protected != 0, 0))
6aa29abe 300 {
78575a84
UD
301 /* It is very tricky. We need to figure out what value to
302 return for the protected symbol. */
697119d6 303 if (type_class == ELF_RTYPE_CLASS_PLT)
6aa29abe 304 {
697119d6
UD
305 if (current_value.s != NULL && current_value.m != undef_map)
306 {
307 current_value.s = *ref;
308 current_value.m = undef_map;
309 }
310 }
311 else
312 {
313 struct sym_val protected_value = { NULL, NULL };
314
9363dbb8 315 for (scope = symbol_scope; *scope != NULL; i = 0, ++scope)
871b9158
UD
316 if (do_lookup_x (undef_name, new_hash, &old_hash, *ref,
317 &protected_value, *scope, i, version, flags,
318 skip_map, ELF_RTYPE_CLASS_PLT) != 0)
697119d6
UD
319 break;
320
9363dbb8 321 if (protected_value.s != NULL && protected_value.m != undef_map)
697119d6
UD
322 {
323 current_value.s = *ref;
324 current_value.m = undef_map;
325 }
6aa29abe 326 }
6aa29abe 327 }
32e6df36 328
78575a84
UD
329 /* We have to check whether this would bind UNDEF_MAP to an object
330 in the global scope which was dynamically loaded. In this case
331 we have to prevent the latter from being unloaded unless the
332 UNDEF_MAP object is also unloaded. */
333 if (__builtin_expect (current_value.m->l_type == lt_loaded, 0)
334 /* Don't do this for explicit lookups as opposed to implicit
335 runtime lookups. */
bdf4a4f1 336 && (flags & DL_LOOKUP_ADD_DEPENDENCY) != 0
78575a84
UD
337 /* Add UNDEF_MAP to the dependencies. */
338 && add_dependency (undef_map, current_value.m) < 0)
339 /* Something went wrong. Perhaps the object we tried to reference
340 was just removed. Try finding another definition. */
a334319f
UD
341 return _dl_lookup_symbol_x (undef_name, undef_map, ref,
342 symbol_scope, version, type_class,
343 flags, skip_map);
78575a84 344
7a11603d
UD
345 /* The object is used. */
346 current_value.m->l_used = 1;
347
afdca0f2 348 if (__builtin_expect (GLRO(dl_debug_mask)
32e6df36 349 & (DL_DEBUG_BINDINGS|DL_DEBUG_PRELINK), 0))
a334319f 350 _dl_debug_bindings (undef_name, undef_map, ref, symbol_scope,
32e6df36
UD
351 &current_value, version, type_class, protected);
352
353 *ref = current_value.s;
354 return LOOKUP_VALUE (current_value.m);
c84142e8
UD
355}
356
357
d66e34cd
RM
358/* Cache the location of MAP's hash table. */
359
360void
d0fc4041 361internal_function
d66e34cd
RM
362_dl_setup_hash (struct link_map *map)
363{
a1eca9f3
UD
364 Elf_Symndx *hash;
365 Elf_Symndx nchain;
f41c8091 366
871b9158
UD
367 if (__builtin_expect (map->l_info[DT_ADDRTAGIDX (DT_GNU_HASH) + DT_NUM
368 + DT_THISPROCNUM + DT_VERSIONTAGNUM
369 + DT_EXTRANUM + DT_VALNUM] != NULL, 1))
370 {
371 Elf32_Word *hash32
372 = (void *) D_PTR (map, l_info[DT_ADDRTAGIDX (DT_GNU_HASH) + DT_NUM
373 + DT_THISPROCNUM + DT_VERSIONTAGNUM
374 + DT_EXTRANUM + DT_VALNUM]);
375 map->l_nbuckets = *hash32++;
376 Elf32_Word symbias = *hash32++;
377 Elf32_Word bitmask_nwords = *hash32++;
378 /* Must be a power of two. */
379 assert ((bitmask_nwords & (bitmask_nwords - 1)) == 0);
380 map->l_gnu_bitmask_idxbits = bitmask_nwords - 1;
381 map->l_gnu_shift = *hash32++;
382
383 map->l_gnu_bitmask = (ElfW(Addr) *) hash32;
384 hash32 += __ELF_NATIVE_CLASS / 32 * bitmask_nwords;
385
386 map->l_gnu_buckets = hash32;
387 hash32 += map->l_nbuckets;
388 map->l_gnu_chain_zero = hash32 - symbias;
389 return;
390 }
391
f41c8091
UD
392 if (!map->l_info[DT_HASH])
393 return;
9a88a2d7 394 hash = (void *) D_PTR (map, l_info[DT_HASH]);
f41c8091 395
d66e34cd
RM
396 map->l_nbuckets = *hash++;
397 nchain = *hash++;
398 map->l_buckets = hash;
399 hash += map->l_nbuckets;
400 map->l_chain = hash;
401}
80d9c5f0 402
f9f2a150 403
32e6df36
UD
404static void
405internal_function
406_dl_debug_bindings (const char *undef_name, struct link_map *undef_map,
a334319f
UD
407 const ElfW(Sym) **ref, struct r_scope_elem *symbol_scope[],
408 struct sym_val *value,
f9f2a150
UD
409 const struct r_found_version *version, int type_class,
410 int protected)
32e6df36
UD
411{
412 const char *reference_name = undef_map->l_name;
413
afdca0f2 414 if (GLRO(dl_debug_mask) & DL_DEBUG_BINDINGS)
32e6df36 415 {
21e2d3a4 416 _dl_debug_printf ("binding file %s [%lu] to %s [%lu]: %s symbol `%s'",
154d10bd
UD
417 (reference_name[0]
418 ? reference_name
419 : (rtld_progname ?: "<main program>")),
21e2d3a4 420 undef_map->l_ns,
154d10bd 421 value->m->l_name[0] ? value->m->l_name : rtld_progname,
21e2d3a4 422 value->m->l_ns,
154d10bd 423 protected ? "protected" : "normal", undef_name);
32e6df36
UD
424 if (version)
425 _dl_debug_printf_c (" [%s]\n", version->name);
426 else
427 _dl_debug_printf_c ("\n");
428 }
429#ifdef SHARED
afdca0f2 430 if (GLRO(dl_debug_mask) & DL_DEBUG_PRELINK)
32e6df36
UD
431 {
432 int conflict = 0;
433 struct sym_val val = { NULL, NULL };
434
afdca0f2 435 if ((GLRO(dl_trace_prelink_map) == NULL
c0f62c56
UD
436 || GLRO(dl_trace_prelink_map) == GL(dl_ns)[LM_ID_BASE]._ns_loaded)
437 && undef_map != GL(dl_ns)[LM_ID_BASE]._ns_loaded)
32e6df36 438 {
871b9158
UD
439 const uint_fast32_t new_hash = dl_new_hash (undef_name);
440 unsigned long int old_hash = 0xffffffff;
32e6df36 441
871b9158 442 do_lookup_x (undef_name, new_hash, &old_hash, *ref, &val,
bdf4a4f1
UD
443 undef_map->l_local_scope[0], 0, version, 0, NULL,
444 type_class);
32e6df36
UD
445
446 if (val.s != value->s || val.m != value->m)
447 conflict = 1;
448 }
449
c0f62c56 450# ifdef USE_TLS
1d0ad773
RM
451 if (value->s
452 && (__builtin_expect (ELFW(ST_TYPE) (value->s->st_info)
453 == STT_TLS, 0)))
454 type_class = 4;
c0f62c56 455# endif
1d0ad773 456
32e6df36 457 if (conflict
afdca0f2
UD
458 || GLRO(dl_trace_prelink_map) == undef_map
459 || GLRO(dl_trace_prelink_map) == NULL
1d0ad773 460 || type_class == 4)
32e6df36
UD
461 {
462 _dl_printf ("%s 0x%0*Zx 0x%0*Zx -> 0x%0*Zx 0x%0*Zx ",
463 conflict ? "conflict" : "lookup",
32e6df36 464 (int) sizeof (ElfW(Addr)) * 2,
d347a4ab 465 (size_t) undef_map->l_map_start,
32e6df36 466 (int) sizeof (ElfW(Addr)) * 2,
d347a4ab 467 (size_t) (((ElfW(Addr)) *ref) - undef_map->l_map_start),
32e6df36 468 (int) sizeof (ElfW(Addr)) * 2,
d347a4ab
UD
469 (size_t) (value->s ? value->m->l_map_start : 0),
470 (int) sizeof (ElfW(Addr)) * 2,
471 (size_t) (value->s ? value->s->st_value : 0));
32e6df36
UD
472
473 if (conflict)
474 _dl_printf ("x 0x%0*Zx 0x%0*Zx ",
475 (int) sizeof (ElfW(Addr)) * 2,
d347a4ab 476 (size_t) (val.s ? val.m->l_map_start : 0),
32e6df36 477 (int) sizeof (ElfW(Addr)) * 2,
d347a4ab 478 (size_t) (val.s ? val.s->st_value : 0));
32e6df36
UD
479
480 _dl_printf ("/%x %s\n", type_class, undef_name);
481 }
482 }
483#endif
484}