(_dl_num_relocations): New variable. (do_lookup): Increment _dl_num_relocations for...
[glibc.git] / elf / dl-lookup.c
blob01d71678b403d6d633988b24b90e8695c2fb285d
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; \
59 /* Statistics function. */
60 unsigned long int _dl_num_relocations;
63 /* Inner part of the lookup functions. We return a value > 0 if we
64 found the symbol, the value 0 if nothing is found and < 0 if
65 something bad happened. */
66 static inline int
67 do_lookup (const char *undef_name, unsigned long int hash,
68 const ElfW(Sym) *ref, struct sym_val *result,
69 struct r_scope_elem *scope, size_t i, const char *reference_name,
70 const struct r_found_version *version, struct link_map *skip,
71 int reloc_type)
73 struct link_map **list = scope->r_list;
74 size_t n = scope->r_nlist;
75 struct link_map *map;
77 ++_dl_num_relocations;
79 for (; i < n; ++i)
81 const ElfW(Sym) *symtab;
82 const char *strtab;
83 const ElfW(Half) *verstab;
84 ElfW(Symndx) symidx;
85 int num_versions = 0;
86 const ElfW(Sym) *sym;
87 const ElfW(Sym) *versioned_sym = NULL;
89 map = list[i];
91 /* Here come the extra test needed for `_dl_lookup_symbol_skip'. */
92 if (skip != NULL && map == skip)
93 continue;
95 /* Skip objects that could not be opened, which can occur in trace
96 mode. */
97 if (map->l_opencount == 0)
98 continue;
100 /* Don't search the executable when resolving a copy reloc. */
101 if (elf_machine_lookup_noexec_p (reloc_type)
102 && map->l_type == lt_executable)
103 continue;
105 /* Skip objects without symbol tables. */
106 if (map->l_info[DT_SYMTAB] == NULL)
107 continue;
109 /* Print some debugging info if wanted. */
110 if (_dl_debug_symbols)
111 _dl_debug_message (1, "symbol=", undef_name, "; lookup in file=",
112 map->l_name[0] ? map->l_name : _dl_argv[0],
113 "\n", NULL);
115 symtab = ((void *) map->l_addr + map->l_info[DT_SYMTAB]->d_un.d_ptr);
116 strtab = ((void *) map->l_addr + map->l_info[DT_STRTAB]->d_un.d_ptr);
117 verstab = map->l_versyms;
119 /* Search the appropriate hash bucket in this object's symbol table
120 for a definition for the same symbol name. */
121 for (symidx = map->l_buckets[hash % map->l_nbuckets];
122 symidx != STN_UNDEF;
123 symidx = map->l_chain[symidx])
125 sym = &symtab[symidx];
127 if (sym->st_value == 0 || /* No value. */
128 (elf_machine_lookup_noplt_p (reloc_type) /* Reject PLT entry. */
129 && sym->st_shndx == SHN_UNDEF))
130 continue;
132 if (ELFW(ST_TYPE) (sym->st_info) > STT_FUNC)
133 /* Ignore all but STT_NOTYPE, STT_OBJECT and STT_FUNC entries
134 since these are no code/data definitions. */
135 continue;
137 if (sym != ref && strcmp (strtab + sym->st_name, undef_name))
138 /* Not the symbol we are looking for. */
139 continue;
141 if (version == NULL)
143 /* No specific version is selected. When the object
144 file also does not define a version we have a match.
145 Otherwise we accept the default version, or in case
146 there is only one version defined, this one version. */
147 if (verstab != NULL)
149 ElfW(Half) ndx = verstab[symidx] & 0x7fff;
150 if (ndx > 2) /* map->l_versions[ndx].hash != 0) */
152 /* Don't accept hidden symbols. */
153 if ((verstab[symidx] & 0x8000) == 0
154 && num_versions++ == 0)
155 /* No version so far. */
156 versioned_sym = sym;
157 continue;
161 else
163 if (verstab == NULL)
165 /* We need a versioned system but haven't found any.
166 If this is the object which is referenced in the
167 verneed entry it is a bug in the library since a
168 symbol must not simply disappear. */
169 if (version->filename != NULL
170 && _dl_name_match_p (version->filename, map))
171 return -2;
172 /* Otherwise we accept the symbol. */
174 else
176 /* We can match the version information or use the
177 default one if it is not hidden. */
178 ElfW(Half) ndx = verstab[symidx] & 0x7fff;
179 if ((map->l_versions[ndx].hash != version->hash
180 || strcmp (map->l_versions[ndx].name, version->name))
181 && (version->hidden || map->l_versions[ndx].hash
182 || (verstab[symidx] & 0x8000)))
183 /* It's not the version we want. */
184 continue;
188 /* There cannot be another entry for this symbol so stop here. */
189 goto found_it;
192 /* If we have seem exactly one versioned symbol while we are
193 looking for an unversioned symbol and the version is not the
194 default version we still accept this symbol since there are
195 no possible ambiguities. */
196 sym = num_versions == 1 ? versioned_sym : NULL;
198 if (sym != NULL)
200 found_it:
201 switch (ELFW(ST_BIND) (sym->st_info))
203 case STB_GLOBAL:
204 /* Global definition. Just what we need. */
205 result->s = sym;
206 result->m = map;
207 return 1;
208 case STB_WEAK:
209 /* Weak definition. Use this value if we don't find another. */
210 if (! result->s)
212 result->s = sym;
213 result->m = map;
215 break;
216 default:
217 /* Local symbols are ignored. */
218 break;
222 /* If this current map is the one mentioned in the verneed entry
223 and we have not found a weak entry, it is a bug. */
224 if (symidx == STN_UNDEF && version != NULL && version->filename != NULL
225 && _dl_name_match_p (version->filename, map))
226 return -1;
229 /* We have not found anything until now. */
230 return 0;
233 /* Search loaded objects' symbol tables for a definition of the symbol
234 UNDEF_NAME. */
236 ElfW(Addr)
237 internal_function
238 _dl_lookup_symbol (const char *undef_name, const ElfW(Sym) **ref,
239 struct r_scope_elem *symbol_scope[],
240 const char *reference_name,
241 int reloc_type)
243 const unsigned long int hash = _dl_elf_hash (undef_name);
244 struct sym_val current_value = { NULL, NULL };
245 struct r_scope_elem **scope;
247 /* Search the relevant loaded objects for a definition. */
248 for (scope = symbol_scope; *scope; ++scope)
249 if (do_lookup (undef_name, hash, *ref, &current_value,
250 *scope, 0, reference_name, NULL, NULL, reloc_type))
251 break;
253 if (current_value.s == NULL)
255 if (*ref == NULL || ELFW(ST_BIND) ((*ref)->st_info) != STB_WEAK)
256 /* We could find no value for a strong reference. */
257 _dl_signal_error (0, (reference_name && reference_name[0]
258 ? reference_name
259 : (_dl_argv[0] ?: "<main program>")),
260 make_string (undefined_msg, undef_name));
261 *ref = NULL;
262 return 0;
265 if (_dl_debug_bindings)
266 _dl_debug_message (1, "binding file ",
267 (reference_name && reference_name[0]
268 ? reference_name
269 : (_dl_argv[0] ?: "<main program>")),
270 " to ", current_value.m->l_name[0]
271 ? current_value.m->l_name : _dl_argv[0],
272 ": symbol `", undef_name, "'\n", NULL);
274 *ref = current_value.s;
275 return current_value.m->l_addr;
279 /* This function is nearly the same as `_dl_lookup_symbol' but it
280 skips in the first list all objects until SKIP_MAP is found. I.e.,
281 it only considers objects which were loaded after the described
282 object. If there are more search lists the object described by
283 SKIP_MAP is only skipped. */
284 ElfW(Addr)
285 internal_function
286 _dl_lookup_symbol_skip (const char *undef_name, const ElfW(Sym) **ref,
287 struct r_scope_elem *symbol_scope[],
288 const char *reference_name,
289 struct link_map *skip_map)
291 const unsigned long int hash = _dl_elf_hash (undef_name);
292 struct sym_val current_value = { NULL, NULL };
293 struct r_scope_elem **scope;
294 size_t i;
296 /* Search the relevant loaded objects for a definition. */
297 scope = symbol_scope;
298 for (i = 0; (*scope)->r_duplist[i] != skip_map; ++i)
299 assert (i < (*scope)->r_nduplist);
301 if (! do_lookup (undef_name, hash, *ref, &current_value,
302 *scope, i, reference_name, NULL, skip_map, 0))
303 while (*++scope)
304 if (do_lookup (undef_name, hash, *ref, &current_value,
305 *scope, 0, reference_name, NULL, skip_map, 0))
306 break;
308 if (current_value.s == NULL)
310 *ref = NULL;
311 return 0;
314 if (_dl_debug_bindings)
315 _dl_debug_message (1, "binding file ",
316 (reference_name && reference_name[0]
317 ? reference_name
318 : (_dl_argv[0] ?: "<main program>")),
319 " to ", current_value.m->l_name[0]
320 ? current_value.m->l_name : _dl_argv[0],
321 ": symbol `", undef_name, "' (skip)\n", NULL);
323 *ref = current_value.s;
324 return current_value.m->l_addr;
328 /* This function works like _dl_lookup_symbol but it takes an
329 additional arguement with the version number of the requested
330 symbol.
332 XXX We'll see whether we need this separate function. */
333 ElfW(Addr)
334 internal_function
335 _dl_lookup_versioned_symbol (const char *undef_name, const ElfW(Sym) **ref,
336 struct r_scope_elem *symbol_scope[],
337 const char *reference_name,
338 const struct r_found_version *version,
339 int reloc_type)
341 const unsigned long int hash = _dl_elf_hash (undef_name);
342 struct sym_val current_value = { NULL, NULL };
343 struct r_scope_elem **scope;
345 /* Search the relevant loaded objects for a definition. */
346 for (scope = symbol_scope; *scope; ++scope)
348 int res = do_lookup (undef_name, hash, *ref, &current_value,
349 *scope, 0, reference_name, version, NULL, reloc_type);
350 if (res > 0)
351 break;
353 if (res < 0)
354 /* Oh, oh. The file named in the relocation entry does not
355 contain the needed symbol. */
356 _dl_signal_error (0, (reference_name && reference_name[0]
357 ? reference_name
358 : (_dl_argv[0] ?: "<main program>")),
359 make_string ("symbol ", undef_name, ", version ",
360 version->name,
361 " not defined in file ",
362 version->filename,
363 " with link time reference",
364 res == -2
365 ? " (no version symbols)" : ""));
368 if (current_value.s == NULL)
370 if (*ref == NULL || ELFW(ST_BIND) ((*ref)->st_info) != STB_WEAK)
371 /* We could find no value for a strong reference. */
372 _dl_signal_error (0, (reference_name && reference_name[0]
373 ? reference_name
374 : (_dl_argv[0] ?: "<main program>")),
375 make_string (undefined_msg, undef_name,
376 ", version ", version->name ?: NULL));
377 *ref = NULL;
378 return 0;
381 if (_dl_debug_bindings)
382 _dl_debug_message (1, "binding file ",
383 (reference_name && reference_name[0]
384 ? reference_name
385 : (_dl_argv[0] ?: "<main program>")),
386 " to ", current_value.m->l_name[0]
387 ? current_value.m->l_name : _dl_argv[0],
388 ": symbol `", undef_name, "' [", version->name,
389 "]\n", NULL);
391 *ref = current_value.s;
392 return current_value.m->l_addr;
396 /* Similar to _dl_lookup_symbol_skip but takes an additional argument
397 with the version we are looking for. */
398 ElfW(Addr)
399 internal_function
400 _dl_lookup_versioned_symbol_skip (const char *undef_name,
401 const ElfW(Sym) **ref,
402 struct r_scope_elem *symbol_scope[],
403 const char *reference_name,
404 const struct r_found_version *version,
405 struct link_map *skip_map)
407 const unsigned long int hash = _dl_elf_hash (undef_name);
408 struct sym_val current_value = { NULL, NULL };
409 struct r_scope_elem **scope;
410 size_t i;
412 /* Search the relevant loaded objects for a definition. */
413 scope = symbol_scope;
414 for (i = 0; (*scope)->r_duplist[i] != skip_map; ++i)
415 assert (i < (*scope)->r_nduplist);
417 if (! do_lookup (undef_name, hash, *ref, &current_value,
418 *scope, i, reference_name, version, skip_map, 0))
419 while (*++scope)
420 if (do_lookup (undef_name, hash, *ref, &current_value,
421 *scope, 0, reference_name, version, skip_map, 0))
422 break;
424 if (current_value.s == NULL)
426 if (*ref == NULL || ELFW(ST_BIND) ((*ref)->st_info) != STB_WEAK)
428 /* We could find no value for a strong reference. */
429 const size_t len = strlen (undef_name);
430 char buf[sizeof undefined_msg + len];
431 __mempcpy (__mempcpy (buf, undefined_msg, sizeof undefined_msg - 1),
432 undef_name, len + 1);
433 _dl_signal_error (0, (reference_name && reference_name[0]
434 ? reference_name
435 : (_dl_argv[0] ?: "<main program>")), buf);
437 *ref = NULL;
438 return 0;
441 if (_dl_debug_bindings)
442 _dl_debug_message (1, "binding file ",
443 (reference_name && reference_name[0]
444 ? reference_name
445 : (_dl_argv[0] ?: "<main program>")),
446 " to ",
447 current_value.m->l_name[0]
448 ? current_value.m->l_name : _dl_argv[0],
449 ": symbol `", undef_name, "' [", version->name,
450 "] (skip)\n", NULL);
452 *ref = current_value.s;
453 return current_value.m->l_addr;
457 /* Cache the location of MAP's hash table. */
459 void
460 internal_function
461 _dl_setup_hash (struct link_map *map)
463 ElfW(Symndx) *hash;
464 ElfW(Symndx) nchain;
466 if (!map->l_info[DT_HASH])
467 return;
468 hash = (void *)(map->l_addr + map->l_info[DT_HASH]->d_un.d_ptr);
470 map->l_nbuckets = *hash++;
471 nchain = *hash++;
472 map->l_buckets = hash;
473 hash += map->l_nbuckets;
474 map->l_chain = hash;