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. */
27 #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 link_map
*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
->l_searchlist
;
71 size_t n
= scope
->l_nsearchlist
;
76 const ElfW(Sym
) *symtab
;
78 const ElfW(Half
) *verstab
;
83 /* Here come the extra test needed for `_dl_lookup_symbol_skip'. */
84 if (skip
!= NULL
&& map
== skip
)
87 /* Skip objects that could not be opened, which can occur in trace
89 if (map
->l_opencount
== 0)
92 /* Don't search the executable when resolving a copy reloc. */
93 if (elf_machine_lookup_noexec_p (reloc_type
)
94 && map
->l_type
== lt_executable
)
97 /* Skip objects without symbol tables. */
98 if (map
->l_info
[DT_SYMTAB
] == NULL
)
101 /* Print some debugging info if wanted. */
102 if (_dl_debug_symbols
)
103 _dl_debug_message (1, "symbol=", undef_name
, "; lookup in file=",
104 map
->l_name
[0] ? map
->l_name
: _dl_argv
[0],
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
);
109 verstab
= map
->l_versyms
;
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
];
115 symidx
= map
->l_chain
[symidx
])
117 const ElfW(Sym
) *sym
= &symtab
[symidx
];
119 if (sym
->st_value
== 0 || /* No value. */
120 (elf_machine_lookup_noplt_p (reloc_type
) /* Reject PLT entry. */
121 && sym
->st_shndx
== SHN_UNDEF
))
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. */
129 if (sym
!= ref
&& strcmp (strtab
+ sym
->st_name
, undef_name
))
130 /* Not the symbol we are looking for. */
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 "". */
141 ElfW(Half
) ndx
= verstab
[symidx
] & 0x7fff;
142 if (ndx
> 2) /* map->l_versions[ndx].hash != 0) */
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
))
157 /* Otherwise we accept the symbol. */
161 /* We can match the version information or use the
162 default one if it is not hidden. */
163 ElfW(Half
) ndx
= verstab
[symidx
] & 0x7fff;
164 if ((map
->l_versions
[ndx
].hash
!= version
->hash
165 || strcmp (map
->l_versions
[ndx
].name
, version
->name
))
166 && (version
->hidden
|| map
->l_versions
[ndx
].hash
167 || (verstab
[symidx
] & 0x8000)))
168 /* It's not the version we want. */
173 switch (ELFW(ST_BIND
) (sym
->st_info
))
176 /* Global definition. Just what we need. */
181 /* Weak definition. Use this value if we don't find
190 /* Local symbols are ignored. */
194 /* There cannot be another entry for this symbol so stop here. */
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
201 && _dl_name_match_p (version
->filename
, map
))
205 /* We have not found anything until now. */
209 /* Search loaded objects' symbol tables for a definition of the symbol
213 _dl_lookup_symbol (const char *undef_name
, const ElfW(Sym
) **ref
,
214 struct link_map
*symbol_scope
[],
215 const char *reference_name
,
218 const unsigned long int hash
= _dl_elf_hash (undef_name
);
219 struct sym_val current_value
= { NULL
, NULL
};
220 struct link_map
**scope
;
222 /* Search the relevant loaded objects for a definition. */
223 for (scope
= symbol_scope
; *scope
; ++scope
)
224 if (do_lookup (undef_name
, hash
, *ref
, ¤t_value
,
225 *scope
, 0, reference_name
, NULL
, NULL
, reloc_type
))
228 if (current_value
.s
== NULL
)
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
&& reference_name
[0]
234 : (_dl_argv
[0] ?: "<main program>")),
235 make_string (undefined_msg
, undef_name
));
240 if (_dl_debug_bindings
)
241 _dl_debug_message (1, "binding file ",
242 (reference_name
&& reference_name
[0]
244 : (_dl_argv
[0] ?: "<main program>")),
245 " to ", current_value
.m
->l_name
[0]
246 ? current_value
.m
->l_name
: _dl_argv
[0],
247 ": symbol `", undef_name
, "'\n", NULL
);
249 *ref
= current_value
.s
;
250 return current_value
.m
->l_addr
;
254 /* This function is nearly the same as `_dl_lookup_symbol' but it
255 skips in the first list all objects until SKIP_MAP is found. I.e.,
256 it only considers objects which were loaded after the described
257 object. If there are more search lists the object described by
258 SKIP_MAP is only skipped. */
260 _dl_lookup_symbol_skip (const char *undef_name
, const ElfW(Sym
) **ref
,
261 struct link_map
*symbol_scope
[],
262 const char *reference_name
,
263 struct link_map
*skip_map
)
265 const unsigned long int hash
= _dl_elf_hash (undef_name
);
266 struct sym_val current_value
= { NULL
, NULL
};
267 struct link_map
**scope
;
270 /* Search the relevant loaded objects for a definition. */
271 scope
= symbol_scope
;
272 for (i
= 0; (*scope
)->l_dupsearchlist
[i
] != skip_map
; ++i
)
273 assert (i
< (*scope
)->l_ndupsearchlist
);
275 if (! do_lookup (undef_name
, hash
, *ref
, ¤t_value
,
276 *scope
, i
, reference_name
, NULL
, skip_map
, 0))
278 if (do_lookup (undef_name
, hash
, *ref
, ¤t_value
,
279 *scope
, 0, reference_name
, NULL
, skip_map
, 0))
282 if (current_value
.s
== NULL
)
288 if (_dl_debug_bindings
)
289 _dl_debug_message (1, "binding file ",
290 (reference_name
&& reference_name
[0]
292 : (_dl_argv
[0] ?: "<main program>")),
293 " to ", current_value
.m
->l_name
[0]
294 ? current_value
.m
->l_name
: _dl_argv
[0],
295 ": symbol `", undef_name
, "' (skip)\n", NULL
);
297 *ref
= current_value
.s
;
298 return current_value
.m
->l_addr
;
302 /* This function works like _dl_lookup_symbol but it takes an
303 additional arguement with the version number of the requested
306 XXX We'll see whether we need this separate function. */
308 _dl_lookup_versioned_symbol (const char *undef_name
, const ElfW(Sym
) **ref
,
309 struct link_map
*symbol_scope
[],
310 const char *reference_name
,
311 const struct r_found_version
*version
,
314 const unsigned long int hash
= _dl_elf_hash (undef_name
);
315 struct sym_val current_value
= { NULL
, NULL
};
316 struct link_map
**scope
;
318 /* Search the relevant loaded objects for a definition. */
319 for (scope
= symbol_scope
; *scope
; ++scope
)
321 int res
= do_lookup (undef_name
, hash
, *ref
, ¤t_value
,
322 *scope
, 0, reference_name
, version
, NULL
, reloc_type
);
327 /* Oh, oh. The file named in the relocation entry does not
328 contain the needed symbol. */
329 _dl_signal_error (0, (reference_name
&& reference_name
[0]
331 : (_dl_argv
[0] ?: "<main program>")),
332 make_string ("symbol ", undef_name
, ", version ",
334 " not defined in file ",
336 " with link time reference",
338 ? " (no version symbols)" : ""));
341 if (current_value
.s
== NULL
)
343 if (*ref
== NULL
|| ELFW(ST_BIND
) ((*ref
)->st_info
) != STB_WEAK
)
344 /* We could find no value for a strong reference. */
345 _dl_signal_error (0, (reference_name
&& reference_name
[0]
347 : (_dl_argv
[0] ?: "<main program>")),
348 make_string (undefined_msg
, undef_name
,
349 ", version ", version
->name
?: NULL
));
354 if (_dl_debug_bindings
)
355 _dl_debug_message (1, "binding file ",
356 (reference_name
&& reference_name
[0]
358 : (_dl_argv
[0] ?: "<main program>")),
359 " to ", current_value
.m
->l_name
[0]
360 ? current_value
.m
->l_name
: _dl_argv
[0],
361 ": symbol `", undef_name
, "' [", version
->name
,
364 *ref
= current_value
.s
;
365 return current_value
.m
->l_addr
;
369 /* Similar to _dl_lookup_symbol_skip but takes an additional argument
370 with the version we are looking for. */
372 _dl_lookup_versioned_symbol_skip (const char *undef_name
,
373 const ElfW(Sym
) **ref
,
374 struct link_map
*symbol_scope
[],
375 const char *reference_name
,
376 const struct r_found_version
*version
,
377 struct link_map
*skip_map
)
379 const unsigned long int hash
= _dl_elf_hash (undef_name
);
380 struct sym_val current_value
= { NULL
, NULL
};
381 struct link_map
**scope
;
384 /* Search the relevant loaded objects for a definition. */
385 scope
= symbol_scope
;
386 for (i
= 0; (*scope
)->l_dupsearchlist
[i
] != skip_map
; ++i
)
387 assert (i
< (*scope
)->l_ndupsearchlist
);
389 if (! do_lookup (undef_name
, hash
, *ref
, ¤t_value
,
390 *scope
, i
, reference_name
, version
, skip_map
, 0))
392 if (do_lookup (undef_name
, hash
, *ref
, ¤t_value
,
393 *scope
, 0, reference_name
, version
, skip_map
, 0))
396 if (current_value
.s
== NULL
)
398 if (*ref
== NULL
|| ELFW(ST_BIND
) ((*ref
)->st_info
) != STB_WEAK
)
400 /* We could find no value for a strong reference. */
401 const size_t len
= strlen (undef_name
);
402 char buf
[sizeof undefined_msg
+ len
];
403 __mempcpy (__mempcpy (buf
, undefined_msg
, sizeof undefined_msg
- 1),
404 undef_name
, len
+ 1);
405 _dl_signal_error (0, (reference_name
&& reference_name
[0]
407 : (_dl_argv
[0] ?: "<main program>")), buf
);
413 if (_dl_debug_bindings
)
414 _dl_debug_message (1, "binding file ",
415 (reference_name
&& reference_name
[0]
417 : (_dl_argv
[0] ?: "<main program>")),
419 current_value
.m
->l_name
[0]
420 ? current_value
.m
->l_name
: _dl_argv
[0],
421 ": symbol `", undef_name
, "' [", version
->name
,
424 *ref
= current_value
.s
;
425 return current_value
.m
->l_addr
;
429 /* Cache the location of MAP's hash table. */
432 _dl_setup_hash (struct link_map
*map
)
437 if (!map
->l_info
[DT_HASH
])
439 hash
= (void *)(map
->l_addr
+ map
->l_info
[DT_HASH
]->d_un
.d_ptr
);
441 map
->l_nbuckets
= *hash
++;
443 map
->l_buckets
= hash
;
444 hash
+= map
->l_nbuckets
;