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. */
23 #include <elf/ldsodefs.h>
25 #include <dl-machine.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: ";
42 #define make_string(string, rest...) \
44 const char *all[] = { string, ## rest }; \
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]); \
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. */
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
,
70 struct link_map
**list
= scope
->r_list
;
71 size_t n
= scope
->r_nlist
;
76 const ElfW(Sym
) *symtab
;
78 const ElfW(Half
) *verstab
;
82 const ElfW(Sym
) *versioned_sym
;
86 /* Here come the extra test needed for `_dl_lookup_symbol_skip'. */
87 if (skip
!= NULL
&& map
== skip
)
90 /* Skip objects that could not be opened, which can occur in trace
92 if (map
->l_opencount
== 0)
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
)
100 /* Skip objects without symbol tables. */
101 if (map
->l_info
[DT_SYMTAB
] == NULL
)
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],
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
];
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
))
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. */
132 if (sym
!= ref
&& strcmp (strtab
+ sym
->st_name
, undef_name
))
133 /* Not the symbol we are looking for. */
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. */
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. */
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
))
167 /* Otherwise we accept the symbol. */
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. */
183 /* There cannot be another entry for this symbol so stop here. */
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
;
196 switch (ELFW(ST_BIND
) (sym
->st_info
))
199 /* Global definition. Just what we need. */
204 /* Weak definition. Use this value if we don't find another. */
212 /* Local symbols are ignored. */
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
))
224 /* We have not found anything until now. */
228 /* Search loaded objects' symbol tables for a definition of the symbol
233 _dl_lookup_symbol (const char *undef_name
, const ElfW(Sym
) **ref
,
234 struct r_scope_elem
*symbol_scope
[],
235 const char *reference_name
,
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
, ¤t_value
,
245 *scope
, 0, reference_name
, NULL
, NULL
, reloc_type
))
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]
254 : (_dl_argv
[0] ?: "<main program>")),
255 make_string (undefined_msg
, undef_name
));
260 if (_dl_debug_bindings
)
261 _dl_debug_message (1, "binding file ",
262 (reference_name
&& reference_name
[0]
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. */
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
;
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
, ¤t_value
,
297 *scope
, i
, reference_name
, NULL
, skip_map
, 0))
299 if (do_lookup (undef_name
, hash
, *ref
, ¤t_value
,
300 *scope
, 0, reference_name
, NULL
, skip_map
, 0))
303 if (current_value
.s
== NULL
)
309 if (_dl_debug_bindings
)
310 _dl_debug_message (1, "binding file ",
311 (reference_name
&& reference_name
[0]
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
327 XXX We'll see whether we need this separate 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
,
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
, ¤t_value
,
344 *scope
, 0, reference_name
, version
, NULL
, reloc_type
);
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]
353 : (_dl_argv
[0] ?: "<main program>")),
354 make_string ("symbol ", undef_name
, ", version ",
356 " not defined in file ",
358 " with link time reference",
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]
369 : (_dl_argv
[0] ?: "<main program>")),
370 make_string (undefined_msg
, undef_name
,
371 ", version ", version
->name
?: NULL
));
376 if (_dl_debug_bindings
)
377 _dl_debug_message (1, "binding file ",
378 (reference_name
&& reference_name
[0]
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
,
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. */
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
;
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
, ¤t_value
,
413 *scope
, i
, reference_name
, version
, skip_map
, 0))
415 if (do_lookup (undef_name
, hash
, *ref
, ¤t_value
,
416 *scope
, 0, reference_name
, version
, skip_map
, 0))
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]
430 : (_dl_argv
[0] ?: "<main program>")), buf
);
436 if (_dl_debug_bindings
)
437 _dl_debug_message (1, "binding file ",
438 (reference_name
&& reference_name
[0]
440 : (_dl_argv
[0] ?: "<main program>")),
442 current_value
.m
->l_name
[0]
443 ? current_value
.m
->l_name
: _dl_argv
[0],
444 ": symbol `", undef_name
, "' [", version
->name
,
447 *ref
= current_value
.s
;
448 return current_value
.m
->l_addr
;
452 /* Cache the location of MAP's hash table. */
456 _dl_setup_hash (struct link_map
*map
)
461 if (!map
->l_info
[DT_HASH
])
463 hash
= (void *)(map
->l_addr
+ map
->l_info
[DT_HASH
]->d_un
.d_ptr
);
465 map
->l_nbuckets
= *hash
++;
467 map
->l_buckets
= hash
;
468 hash
+= map
->l_nbuckets
;