]> 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.
da832465 2 Copyright (C) 1995, 1996, 1997, 1998 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>
d66e34cd 21#include <link.h>
a1a9d215 22#include <assert.h>
8d6468d0 23#include <string.h>
3db52d94 24#include <unistd.h>
d66e34cd 25
bc9f6000
UD
26#include "dl-hash.h"
27#include <dl-machine.h>
c84142e8
UD
28
29#define VERSTAG(tag) (DT_NUM + DT_PROCNUM + DT_VERSIONTAGIDX (tag))
266180eb 30
714a562f
UD
31/* We need this string more than once. */
32static const char undefined_msg[] = "undefined symbol: ";
33
34
84384f5b
UD
35struct sym_val
36 {
84384f5b 37 const ElfW(Sym) *s;
0c367d92 38 struct link_map *m;
84384f5b
UD
39 };
40
41
1fb05e3d
UD
42#define make_string(string, rest...) \
43 ({ \
44 const char *all[] = { string, ## rest }; \
45 size_t len, cnt; \
46 char *result, *cp; \
47 \
48 len = 1; \
49 for (cnt = 0; cnt < sizeof (all) / sizeof (all[0]); ++cnt) \
50 len += strlen (all[cnt]); \
51 \
52 cp = result = alloca (len); \
53 for (cnt = 0; cnt < sizeof (all) / sizeof (all[0]); ++cnt) \
da832465 54 cp = __stpcpy (cp, all[cnt]); \
1fb05e3d
UD
55 \
56 result; \
57 })
58
59
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. */
63static inline int
84384f5b 64do_lookup (const char *undef_name, unsigned long int hash,
bc9f6000 65 const ElfW(Sym) *ref, struct sym_val *result,
de100ca7
UD
66 struct link_map *scope, size_t i, const char *reference_name,
67 const struct r_found_version *version, struct link_map *skip,
68 int reloc_type)
84384f5b 69{
de100ca7
UD
70 struct link_map **list = scope->l_searchlist;
71 size_t n = scope->l_nsearchlist;
84384f5b
UD
72 struct link_map *map;
73
74 for (; i < n; ++i)
75 {
76 const ElfW(Sym) *symtab;
77 const char *strtab;
c84142e8 78 const ElfW(Half) *verstab;
84384f5b
UD
79 ElfW(Symndx) symidx;
80
81 map = list[i];
82
83 /* Here come the extra test needed for `_dl_lookup_symbol_skip'. */
84 if (skip != NULL && map == skip)
85 continue;
86
5107cf1d
UD
87 /* Skip objects that could not be opened, which can occur in trace
88 mode. */
89 if (map->l_opencount == 0)
90 continue;
91
84384f5b 92 /* Don't search the executable when resolving a copy reloc. */
0c367d92
UD
93 if (elf_machine_lookup_noexec_p (reloc_type)
94 && map->l_type == lt_executable)
84384f5b
UD
95 continue;
96
f41c8091
UD
97 /* Skip objects without symbol tables. */
98 if (map->l_info[DT_SYMTAB] == NULL)
99 continue;
100
de100ca7
UD
101 /* Print some debugging info if wanted. */
102 if (_dl_debug_symbols)
8193034b 103 _dl_debug_message (1, "symbol=", undef_name, "; lookup in file=",
de100ca7
UD
104 map->l_name[0] ? map->l_name : _dl_argv[0],
105 "\n", NULL);
106
84384f5b
UD
107 symtab = ((void *) map->l_addr + map->l_info[DT_SYMTAB]->d_un.d_ptr);
108 strtab = ((void *) map->l_addr + map->l_info[DT_STRTAB]->d_un.d_ptr);
0c367d92 109 verstab = map->l_versyms;
84384f5b
UD
110
111 /* Search the appropriate hash bucket in this object's symbol table
112 for a definition for the same symbol name. */
113 for (symidx = map->l_buckets[hash % map->l_nbuckets];
114 symidx != STN_UNDEF;
115 symidx = map->l_chain[symidx])
116 {
117 const ElfW(Sym) *sym = &symtab[symidx];
118
119 if (sym->st_value == 0 || /* No value. */
bc9f6000 120 (elf_machine_lookup_noplt_p (reloc_type) /* Reject PLT entry. */
84384f5b
UD
121 && sym->st_shndx == SHN_UNDEF))
122 continue;
123
714a562f
UD
124 if (ELFW(ST_TYPE) (sym->st_info) > STT_FUNC)
125 /* Ignore all but STT_NOTYPE, STT_OBJECT and STT_FUNC entries
126 since these are no code/data definitions. */
127 continue;
84384f5b 128
bc9f6000 129 if (sym != ref && strcmp (strtab + sym->st_name, undef_name))
84384f5b
UD
130 /* Not the symbol we are looking for. */
131 continue;
132
1fb05e3d 133 if (version == NULL)
c84142e8 134 {
1fb05e3d
UD
135 /* No specific version is selected. When the object
136 file also does not define a version we have a match.
137 Otherwise we only accept the default version, i.e.,
138 the version which name is "". */
139 if (verstab != NULL)
140 {
141 ElfW(Half) ndx = verstab[symidx] & 0x7fff;
714a562f 142 if (ndx > 2) /* map->l_versions[ndx].hash != 0) */
1fb05e3d
UD
143 continue;
144 }
145 }
146 else
147 {
148 if (verstab == NULL)
149 {
150 /* We need a versioned system but haven't found any.
151 If this is the object which is referenced in the
152 verneed entry it is a bug in the library since a
153 symbol must not simply disappear. */
154 if (version->filename != NULL
155 && _dl_name_match_p (version->filename, map))
714a562f 156 return -2;
1fb05e3d
UD
157 /* Otherwise we accept the symbol. */
158 }
159 else
160 {
f9a73ae1 161 /* We can match the version information or use the
6973fc01 162 default one if it is not hidden. */
1fb05e3d 163 ElfW(Half) ndx = verstab[symidx] & 0x7fff;
f9a73ae1
UD
164 if ((map->l_versions[ndx].hash != version->hash
165 || strcmp (map->l_versions[ndx].name, version->name))
6973fc01
UD
166 && (version->hidden || map->l_versions[ndx].hash
167 || (verstab[symidx] & 0x8000)))
1fb05e3d
UD
168 /* It's not the version we want. */
169 continue;
170 }
c84142e8
UD
171 }
172
84384f5b
UD
173 switch (ELFW(ST_BIND) (sym->st_info))
174 {
175 case STB_GLOBAL:
176 /* Global definition. Just what we need. */
177 result->s = sym;
0c367d92 178 result->m = map;
84384f5b
UD
179 return 1;
180 case STB_WEAK:
181 /* Weak definition. Use this value if we don't find
182 another. */
183 if (! result->s)
184 {
185 result->s = sym;
0c367d92 186 result->m = map;
84384f5b
UD
187 }
188 break;
189 default:
190 /* Local symbols are ignored. */
191 break;
192 }
714a562f
UD
193
194 /* There cannot be another entry for this symbol so stop here. */
195 break;
84384f5b 196 }
1fb05e3d 197
714a562f
UD
198 /* If this current map is the one mentioned in the verneed entry
199 and we have not found a weak entry, it is a bug. */
200 if (symidx == STN_UNDEF && version != NULL && version->filename != NULL
1fb05e3d
UD
201 && _dl_name_match_p (version->filename, map))
202 return -1;
84384f5b
UD
203 }
204
205 /* We have not found anything until now. */
206 return 0;
207}
208
6c03c2cf 209/* Search loaded objects' symbol tables for a definition of the symbol
bc9f6000 210 UNDEF_NAME. */
d66e34cd 211
266180eb
RM
212ElfW(Addr)
213_dl_lookup_symbol (const char *undef_name, const ElfW(Sym) **ref,
ba79d61b 214 struct link_map *symbol_scope[],
f2b0f935 215 const char *reference_name,
bc9f6000 216 int reloc_type)
d66e34cd 217{
266180eb 218 const unsigned long int hash = _dl_elf_hash (undef_name);
0c367d92 219 struct sym_val current_value = { NULL, NULL };
84384f5b 220 struct link_map **scope;
d66e34cd
RM
221
222 /* Search the relevant loaded objects for a definition. */
ba79d61b 223 for (scope = symbol_scope; *scope; ++scope)
bc9f6000 224 if (do_lookup (undef_name, hash, *ref, &current_value,
de100ca7 225 *scope, 0, reference_name, NULL, NULL, reloc_type))
84384f5b 226 break;
ba79d61b 227
0c367d92
UD
228 if (current_value.s == NULL)
229 {
230 if (*ref == NULL || ELFW(ST_BIND) ((*ref)->st_info) != STB_WEAK)
231 /* We could find no value for a strong reference. */
232 _dl_signal_error (0, reference_name,
233 make_string (undefined_msg, undef_name));
234 *ref = NULL;
235 return 0;
236 }
237
238 if (_dl_debug_bindings)
8193034b 239 _dl_debug_message (1, "binding file ", reference_name, " to ",
0c367d92
UD
240 current_value.m->l_name[0]
241 ? current_value.m->l_name : _dl_argv[0],
242 ": symbol `", undef_name, "'\n", NULL);
d66e34cd 243
84384f5b 244 *ref = current_value.s;
0c367d92 245 return current_value.m->l_addr;
84384f5b
UD
246}
247
248
249/* This function is nearly the same as `_dl_lookup_symbol' but it
250 skips in the first list all objects until SKIP_MAP is found. I.e.,
251 it only considers objects which were loaded after the described
252 object. If there are more search lists the object described by
253 SKIP_MAP is only skipped. */
254ElfW(Addr)
255_dl_lookup_symbol_skip (const char *undef_name, const ElfW(Sym) **ref,
256 struct link_map *symbol_scope[],
257 const char *reference_name,
bc9f6000 258 struct link_map *skip_map)
84384f5b 259{
84384f5b 260 const unsigned long int hash = _dl_elf_hash (undef_name);
0c367d92 261 struct sym_val current_value = { NULL, NULL };
84384f5b
UD
262 struct link_map **scope;
263 size_t i;
264
265 /* Search the relevant loaded objects for a definition. */
266 scope = symbol_scope;
267 for (i = 0; (*scope)->l_dupsearchlist[i] != skip_map; ++i)
268 assert (i < (*scope)->l_ndupsearchlist);
269
bc9f6000 270 if (! do_lookup (undef_name, hash, *ref, &current_value,
de100ca7 271 *scope, i, reference_name, NULL, skip_map, 0))
c84142e8 272 while (*++scope)
bc9f6000 273 if (do_lookup (undef_name, hash, *ref, &current_value,
de100ca7 274 *scope, 0, reference_name, NULL, skip_map, 0))
c84142e8
UD
275 break;
276
0c367d92
UD
277 if (current_value.s == NULL)
278 {
279 *ref = NULL;
280 return 0;
281 }
282
283 if (_dl_debug_bindings)
8193034b 284 _dl_debug_message (1, "binding file ", reference_name, " to ",
0c367d92
UD
285 current_value.m->l_name[0]
286 ? current_value.m->l_name : _dl_argv[0],
287 ": symbol `", undef_name, "'\n", NULL);
288
c84142e8 289 *ref = current_value.s;
0c367d92 290 return current_value.m->l_addr;
c84142e8
UD
291}
292
293
294/* This function works like _dl_lookup_symbol but it takes an
295 additional arguement with the version number of the requested
296 symbol.
297
298 XXX We'll see whether we need this separate function. */
299ElfW(Addr)
300_dl_lookup_versioned_symbol (const char *undef_name, const ElfW(Sym) **ref,
301 struct link_map *symbol_scope[],
302 const char *reference_name,
bc9f6000
UD
303 const struct r_found_version *version,
304 int reloc_type)
c84142e8
UD
305{
306 const unsigned long int hash = _dl_elf_hash (undef_name);
0c367d92 307 struct sym_val current_value = { NULL, NULL };
c84142e8
UD
308 struct link_map **scope;
309
310 /* Search the relevant loaded objects for a definition. */
311 for (scope = symbol_scope; *scope; ++scope)
1fb05e3d 312 {
bc9f6000 313 int res = do_lookup (undef_name, hash, *ref, &current_value,
de100ca7 314 *scope, 0, reference_name, version, NULL, reloc_type);
1fb05e3d
UD
315 if (res > 0)
316 break;
317
318 if (res < 0)
319 /* Oh, oh. The file named in the relocation entry does not
320 contain the needed symbol. */
1618c590
UD
321 _dl_signal_error (0, (*reference_name
322 ? reference_name
323 : (_dl_argv[0] ?: "<main program>")),
1fb05e3d
UD
324 make_string ("symbol ", undef_name, ", version ",
325 version->name,
326 " not defined in file ",
327 version->filename,
714a562f
UD
328 " with link time reference",
329 res == -2
330 ? " (no version symbols)" : ""));
1fb05e3d 331 }
c84142e8 332
0c367d92
UD
333 if (current_value.s == NULL)
334 {
335 if (*ref == NULL || ELFW(ST_BIND) ((*ref)->st_info) != STB_WEAK)
336 /* We could find no value for a strong reference. */
337 _dl_signal_error (0, reference_name,
338 make_string (undefined_msg, undef_name,
339 ", version ", version->name ?: NULL));
340 *ref = NULL;
341 return 0;
342 }
343
344 if (_dl_debug_bindings)
8193034b 345 _dl_debug_message (1, "binding file ", reference_name, " to ",
0c367d92
UD
346 current_value.m->l_name[0]
347 ? current_value.m->l_name : _dl_argv[0],
db0b91a9
UD
348 ": symbol `", undef_name, "' [", version->name,
349 "]\n", NULL);
c84142e8
UD
350
351 *ref = current_value.s;
0c367d92 352 return current_value.m->l_addr;
c84142e8
UD
353}
354
355
356/* Similar to _dl_lookup_symbol_skip but takes an additional argument
357 with the version we are looking for. */
358ElfW(Addr)
359_dl_lookup_versioned_symbol_skip (const char *undef_name,
360 const ElfW(Sym) **ref,
361 struct link_map *symbol_scope[],
362 const char *reference_name,
1fb05e3d 363 const struct r_found_version *version,
bc9f6000 364 struct link_map *skip_map)
c84142e8
UD
365{
366 const unsigned long int hash = _dl_elf_hash (undef_name);
0c367d92 367 struct sym_val current_value = { NULL, NULL };
c84142e8 368 struct link_map **scope;
c84142e8
UD
369 size_t i;
370
c84142e8
UD
371 /* Search the relevant loaded objects for a definition. */
372 scope = symbol_scope;
373 for (i = 0; (*scope)->l_dupsearchlist[i] != skip_map; ++i)
374 assert (i < (*scope)->l_ndupsearchlist);
375
bc9f6000 376 if (! do_lookup (undef_name, hash, *ref, &current_value,
de100ca7 377 *scope, i, reference_name, version, skip_map, 0))
84384f5b 378 while (*++scope)
bc9f6000 379 if (do_lookup (undef_name, hash, *ref, &current_value,
de100ca7 380 *scope, 0, reference_name, version, skip_map, 0))
84384f5b
UD
381 break;
382
0c367d92 383 if (current_value.s == NULL)
1f205a47 384 {
0c367d92
UD
385 if (*ref == NULL || ELFW(ST_BIND) ((*ref)->st_info) != STB_WEAK)
386 {
387 /* We could find no value for a strong reference. */
388 const size_t len = strlen (undef_name);
389 char buf[sizeof undefined_msg + len];
390 __mempcpy (__mempcpy (buf, undefined_msg, sizeof undefined_msg - 1),
391 undef_name, len + 1);
392 _dl_signal_error (0, reference_name, buf);
393 }
394 *ref = NULL;
395 return 0;
1f205a47
UD
396 }
397
0c367d92 398 if (_dl_debug_bindings)
8193034b 399 _dl_debug_message (1, "binding file ", reference_name, " to ",
0c367d92
UD
400 current_value.m->l_name[0]
401 ? current_value.m->l_name : _dl_argv[0],
db0b91a9
UD
402 ": symbol `", undef_name, "' [", version->name,
403 "]\n", NULL);
0c367d92 404
84384f5b 405 *ref = current_value.s;
0c367d92 406 return current_value.m->l_addr;
d66e34cd
RM
407}
408
409
410/* Cache the location of MAP's hash table. */
411
412void
413_dl_setup_hash (struct link_map *map)
414{
f41c8091 415 ElfW(Symndx) *hash;
8d6468d0 416 ElfW(Symndx) nchain;
f41c8091
UD
417
418 if (!map->l_info[DT_HASH])
419 return;
420 hash = (void *)(map->l_addr + map->l_info[DT_HASH]->d_un.d_ptr);
421
d66e34cd
RM
422 map->l_nbuckets = *hash++;
423 nchain = *hash++;
424 map->l_buckets = hash;
425 hash += map->l_nbuckets;
426 map->l_chain = hash;
427}
This page took 0.094897 seconds and 5 git commands to generate.