Update.
[glibc.git] / elf / dl-lookup.c
blob8c99f499fd3e44c288a20590183daa11a21074ee
1 /* Look up a symbol in the loaded objects.
2 Copyright (C) 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
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.
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.
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. */
20 #include <alloca.h>
21 #include <string.h>
22 #include <unistd.h>
23 #include <elf/ldsodefs.h>
24 #include "dl-hash.h"
25 #include <dl-machine.h>
27 #include <assert.h>
29 #define VERSTAG(tag) (DT_NUM + DT_PROCNUM + DT_VERSIONTAGIDX (tag))
31 /* We need this string more than once. */
32 static const char undefined_msg[] = "undefined symbol: ";
35 struct sym_val
37 const ElfW(Sym) *s;
38 struct link_map *m;
42 #define make_string(string, rest...) \
43 ({ \
44 const char *all[] = { string, ## rest }; \
45 size_t len, cnt; \
46 char *result, *cp; \
48 len = 1; \
49 for (cnt = 0; cnt < sizeof (all) / sizeof (all[0]); ++cnt) \
50 len += strlen (all[cnt]); \
52 cp = result = alloca (len); \
53 for (cnt = 0; cnt < sizeof (all) / sizeof (all[0]); ++cnt) \
54 cp = __stpcpy (cp, all[cnt]); \
56 result; \
60 /* Inner part of the lookup functions. We return a value > 0 if we
61 found the symbol, the value 0 if nothing is found and < 0 if
62 something bad happened. */
63 static inline int
64 do_lookup (const char *undef_name, unsigned long int hash,
65 const ElfW(Sym) *ref, struct sym_val *result,
66 struct r_scope_elem *scope, size_t i, const char *reference_name,
67 const struct r_found_version *version, struct link_map *skip,
68 int reloc_type)
70 struct link_map **list = scope->r_list;
71 size_t n = scope->r_nlist;
72 struct link_map *map;
74 for (; i < n; ++i)
76 const ElfW(Sym) *symtab;
77 const char *strtab;
78 const ElfW(Half) *verstab;
79 ElfW(Symndx) symidx;
80 int num_versions = 0;
81 const ElfW(Sym) *sym;
82 const ElfW(Sym) *versioned_sym;
84 map = list[i];
86 /* Here come the extra test needed for `_dl_lookup_symbol_skip'. */
87 if (skip != NULL && map == skip)
88 continue;
90 /* Skip objects that could not be opened, which can occur in trace
91 mode. */
92 if (map->l_opencount == 0)
93 continue;
95 /* Don't search the executable when resolving a copy reloc. */
96 if (elf_machine_lookup_noexec_p (reloc_type)
97 && map->l_type == lt_executable)
98 continue;
100 /* Skip objects without symbol tables. */
101 if (map->l_info[DT_SYMTAB] == NULL)
102 continue;
104 /* Print some debugging info if wanted. */
105 if (_dl_debug_symbols)
106 _dl_debug_message (1, "symbol=", undef_name, "; lookup in file=",
107 map->l_name[0] ? map->l_name : _dl_argv[0],
108 "\n", NULL);
110 symtab = ((void *) map->l_addr + map->l_info[DT_SYMTAB]->d_un.d_ptr);
111 strtab = ((void *) map->l_addr + map->l_info[DT_STRTAB]->d_un.d_ptr);
112 verstab = map->l_versyms;
114 /* Search the appropriate hash bucket in this object's symbol table
115 for a definition for the same symbol name. */
116 for (symidx = map->l_buckets[hash % map->l_nbuckets];
117 symidx != STN_UNDEF;
118 symidx = map->l_chain[symidx])
120 sym = &symtab[symidx];
122 if (sym->st_value == 0 || /* No value. */
123 (elf_machine_lookup_noplt_p (reloc_type) /* Reject PLT entry. */
124 && sym->st_shndx == SHN_UNDEF))
125 continue;
127 if (ELFW(ST_TYPE) (sym->st_info) > STT_FUNC)
128 /* Ignore all but STT_NOTYPE, STT_OBJECT and STT_FUNC entries
129 since these are no code/data definitions. */
130 continue;
132 if (sym != ref && strcmp (strtab + sym->st_name, undef_name))
133 /* Not the symbol we are looking for. */
134 continue;
136 if (version == NULL)
138 /* No specific version is selected. When the object
139 file also does not define a version we have a match.
140 Otherwise we accept the default version, or in case
141 there is only one version defined, this one version. */
142 if (verstab != NULL)
144 ElfW(Half) ndx = verstab[symidx] & 0x7fff;
145 if (ndx > 2) /* map->l_versions[ndx].hash != 0) */
147 /* Don't accept hidden symbols. */
148 if ((verstab[symidx] & 0x8000) == 0
149 && num_versions++ == 0)
150 /* No version so far. */
151 versioned_sym = sym;
152 continue;
156 else
158 if (verstab == NULL)
160 /* We need a versioned system but haven't found any.
161 If this is the object which is referenced in the
162 verneed entry it is a bug in the library since a
163 symbol must not simply disappear. */
164 if (version->filename != NULL
165 && _dl_name_match_p (version->filename, map))
166 return -2;
167 /* Otherwise we accept the symbol. */
169 else
171 /* We can match the version information or use the
172 default one if it is not hidden. */
173 ElfW(Half) ndx = verstab[symidx] & 0x7fff;
174 if ((map->l_versions[ndx].hash != version->hash
175 || strcmp (map->l_versions[ndx].name, version->name))
176 && (version->hidden || map->l_versions[ndx].hash
177 || (verstab[symidx] & 0x8000)))
178 /* It's not the version we want. */
179 continue;
183 /* There cannot be another entry for this symbol so stop here. */
184 goto found_it;
187 /* If we have seem exactly one versioned symbol while we are
188 looking for an unversioned symbol and the version is not the
189 default version we still accept this symbol since there are
190 no possible ambiguities. */
191 sym = num_versions == 1 ? versioned_sym : NULL;
193 if (sym != NULL)
195 found_it:
196 switch (ELFW(ST_BIND) (sym->st_info))
198 case STB_GLOBAL:
199 /* Global definition. Just what we need. */
200 result->s = sym;
201 result->m = map;
202 return 1;
203 case STB_WEAK:
204 /* Weak definition. Use this value if we don't find another. */
205 if (! result->s)
207 result->s = sym;
208 result->m = map;
210 break;
211 default:
212 /* Local symbols are ignored. */
213 break;
217 /* If this current map is the one mentioned in the verneed entry
218 and we have not found a weak entry, it is a bug. */
219 if (symidx == STN_UNDEF && version != NULL && version->filename != NULL
220 && _dl_name_match_p (version->filename, map))
221 return -1;
224 /* We have not found anything until now. */
225 return 0;
228 /* Search loaded objects' symbol tables for a definition of the symbol
229 UNDEF_NAME. */
231 ElfW(Addr)
232 internal_function
233 _dl_lookup_symbol (const char *undef_name, const ElfW(Sym) **ref,
234 struct r_scope_elem *symbol_scope[],
235 const char *reference_name,
236 int reloc_type)
238 const unsigned long int hash = _dl_elf_hash (undef_name);
239 struct sym_val current_value = { NULL, NULL };
240 struct r_scope_elem **scope;
242 /* Search the relevant loaded objects for a definition. */
243 for (scope = symbol_scope; *scope; ++scope)
244 if (do_lookup (undef_name, hash, *ref, &current_value,
245 *scope, 0, reference_name, NULL, NULL, reloc_type))
246 break;
248 if (current_value.s == NULL)
250 if (*ref == NULL || ELFW(ST_BIND) ((*ref)->st_info) != STB_WEAK)
251 /* We could find no value for a strong reference. */
252 _dl_signal_error (0, (reference_name && reference_name[0]
253 ? reference_name
254 : (_dl_argv[0] ?: "<main program>")),
255 make_string (undefined_msg, undef_name));
256 *ref = NULL;
257 return 0;
260 if (_dl_debug_bindings)
261 _dl_debug_message (1, "binding file ",
262 (reference_name && reference_name[0]
263 ? reference_name
264 : (_dl_argv[0] ?: "<main program>")),
265 " to ", current_value.m->l_name[0]
266 ? current_value.m->l_name : _dl_argv[0],
267 ": symbol `", undef_name, "'\n", NULL);
269 *ref = current_value.s;
270 return current_value.m->l_addr;
274 /* This function is nearly the same as `_dl_lookup_symbol' but it
275 skips in the first list all objects until SKIP_MAP is found. I.e.,
276 it only considers objects which were loaded after the described
277 object. If there are more search lists the object described by
278 SKIP_MAP is only skipped. */
279 ElfW(Addr)
280 internal_function
281 _dl_lookup_symbol_skip (const char *undef_name, const ElfW(Sym) **ref,
282 struct r_scope_elem *symbol_scope[],
283 const char *reference_name,
284 struct link_map *skip_map)
286 const unsigned long int hash = _dl_elf_hash (undef_name);
287 struct sym_val current_value = { NULL, NULL };
288 struct r_scope_elem **scope;
289 size_t i;
291 /* Search the relevant loaded objects for a definition. */
292 scope = symbol_scope;
293 for (i = 0; (*scope)->r_duplist[i] != skip_map; ++i)
294 assert (i < (*scope)->r_nduplist);
296 if (! do_lookup (undef_name, hash, *ref, &current_value,
297 *scope, i, reference_name, NULL, skip_map, 0))
298 while (*++scope)
299 if (do_lookup (undef_name, hash, *ref, &current_value,
300 *scope, 0, reference_name, NULL, skip_map, 0))
301 break;
303 if (current_value.s == NULL)
305 *ref = NULL;
306 return 0;
309 if (_dl_debug_bindings)
310 _dl_debug_message (1, "binding file ",
311 (reference_name && reference_name[0]
312 ? reference_name
313 : (_dl_argv[0] ?: "<main program>")),
314 " to ", current_value.m->l_name[0]
315 ? current_value.m->l_name : _dl_argv[0],
316 ": symbol `", undef_name, "' (skip)\n", NULL);
318 *ref = current_value.s;
319 return current_value.m->l_addr;
323 /* This function works like _dl_lookup_symbol but it takes an
324 additional arguement with the version number of the requested
325 symbol.
327 XXX We'll see whether we need this separate function. */
328 ElfW(Addr)
329 internal_function
330 _dl_lookup_versioned_symbol (const char *undef_name, const ElfW(Sym) **ref,
331 struct r_scope_elem *symbol_scope[],
332 const char *reference_name,
333 const struct r_found_version *version,
334 int reloc_type)
336 const unsigned long int hash = _dl_elf_hash (undef_name);
337 struct sym_val current_value = { NULL, NULL };
338 struct r_scope_elem **scope;
340 /* Search the relevant loaded objects for a definition. */
341 for (scope = symbol_scope; *scope; ++scope)
343 int res = do_lookup (undef_name, hash, *ref, &current_value,
344 *scope, 0, reference_name, version, NULL, reloc_type);
345 if (res > 0)
346 break;
348 if (res < 0)
349 /* Oh, oh. The file named in the relocation entry does not
350 contain the needed symbol. */
351 _dl_signal_error (0, (reference_name && reference_name[0]
352 ? reference_name
353 : (_dl_argv[0] ?: "<main program>")),
354 make_string ("symbol ", undef_name, ", version ",
355 version->name,
356 " not defined in file ",
357 version->filename,
358 " with link time reference",
359 res == -2
360 ? " (no version symbols)" : ""));
363 if (current_value.s == NULL)
365 if (*ref == NULL || ELFW(ST_BIND) ((*ref)->st_info) != STB_WEAK)
366 /* We could find no value for a strong reference. */
367 _dl_signal_error (0, (reference_name && reference_name[0]
368 ? reference_name
369 : (_dl_argv[0] ?: "<main program>")),
370 make_string (undefined_msg, undef_name,
371 ", version ", version->name ?: NULL));
372 *ref = NULL;
373 return 0;
376 if (_dl_debug_bindings)
377 _dl_debug_message (1, "binding file ",
378 (reference_name && reference_name[0]
379 ? reference_name
380 : (_dl_argv[0] ?: "<main program>")),
381 " to ", current_value.m->l_name[0]
382 ? current_value.m->l_name : _dl_argv[0],
383 ": symbol `", undef_name, "' [", version->name,
384 "]\n", NULL);
386 *ref = current_value.s;
387 return current_value.m->l_addr;
391 /* Similar to _dl_lookup_symbol_skip but takes an additional argument
392 with the version we are looking for. */
393 ElfW(Addr)
394 internal_function
395 _dl_lookup_versioned_symbol_skip (const char *undef_name,
396 const ElfW(Sym) **ref,
397 struct r_scope_elem *symbol_scope[],
398 const char *reference_name,
399 const struct r_found_version *version,
400 struct link_map *skip_map)
402 const unsigned long int hash = _dl_elf_hash (undef_name);
403 struct sym_val current_value = { NULL, NULL };
404 struct r_scope_elem **scope;
405 size_t i;
407 /* Search the relevant loaded objects for a definition. */
408 scope = symbol_scope;
409 for (i = 0; (*scope)->r_duplist[i] != skip_map; ++i)
410 assert (i < (*scope)->r_nduplist);
412 if (! do_lookup (undef_name, hash, *ref, &current_value,
413 *scope, i, reference_name, version, skip_map, 0))
414 while (*++scope)
415 if (do_lookup (undef_name, hash, *ref, &current_value,
416 *scope, 0, reference_name, version, skip_map, 0))
417 break;
419 if (current_value.s == NULL)
421 if (*ref == NULL || ELFW(ST_BIND) ((*ref)->st_info) != STB_WEAK)
423 /* We could find no value for a strong reference. */
424 const size_t len = strlen (undef_name);
425 char buf[sizeof undefined_msg + len];
426 __mempcpy (__mempcpy (buf, undefined_msg, sizeof undefined_msg - 1),
427 undef_name, len + 1);
428 _dl_signal_error (0, (reference_name && reference_name[0]
429 ? reference_name
430 : (_dl_argv[0] ?: "<main program>")), buf);
432 *ref = NULL;
433 return 0;
436 if (_dl_debug_bindings)
437 _dl_debug_message (1, "binding file ",
438 (reference_name && reference_name[0]
439 ? reference_name
440 : (_dl_argv[0] ?: "<main program>")),
441 " to ",
442 current_value.m->l_name[0]
443 ? current_value.m->l_name : _dl_argv[0],
444 ": symbol `", undef_name, "' [", version->name,
445 "] (skip)\n", NULL);
447 *ref = current_value.s;
448 return current_value.m->l_addr;
452 /* Cache the location of MAP's hash table. */
454 void
455 internal_function
456 _dl_setup_hash (struct link_map *map)
458 ElfW(Symndx) *hash;
459 ElfW(Symndx) nchain;
461 if (!map->l_info[DT_HASH])
462 return;
463 hash = (void *)(map->l_addr + map->l_info[DT_HASH]->d_un.d_ptr);
465 map->l_nbuckets = *hash++;
466 nchain = *hash++;
467 map->l_buckets = hash;
468 hash += map->l_nbuckets;
469 map->l_chain = hash;