1 /* Look up a symbol in the loaded objects.
2 Copyright (C) 1995, 1996, 1997 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>
28 #include <stdio-common/_itoa.h>
30 #define VERSTAG(tag) (DT_NUM + DT_PROCNUM + DT_VERSIONTAGIDX (tag))
32 /* We need this string more than once. */
33 static const char undefined_msg
[] = "undefined symbol: ";
43 #define make_string(string, rest...) \
45 const char *all[] = { string, ## rest }; \
50 for (cnt = 0; cnt < sizeof (all) / sizeof (all[0]); ++cnt) \
51 len += strlen (all[cnt]); \
53 cp = result = alloca (len); \
54 for (cnt = 0; cnt < sizeof (all) / sizeof (all[0]); ++cnt) \
55 cp = stpcpy (cp, all[cnt]); \
61 /* Inner part of the lookup functions. We return a value > 0 if we
62 found the symbol, the value 0 if nothing is found and < 0 if
63 something bad happened. */
65 do_lookup (const char *undef_name
, unsigned long int hash
,
66 const ElfW(Sym
) *ref
, struct sym_val
*result
,
67 struct link_map
*list
[], size_t i
, size_t n
,
68 const char *reference_name
, const struct r_found_version
*version
,
69 struct link_map
*skip
, int reloc_type
)
75 const ElfW(Sym
) *symtab
;
77 const ElfW(Half
) *verstab
;
82 /* Here come the extra test needed for `_dl_lookup_symbol_skip'. */
83 if (skip
!= NULL
&& map
== skip
)
86 /* Skip objects that could not be opened, which can occur in trace
88 if (map
->l_opencount
== 0)
91 /* Don't search the executable when resolving a copy reloc. */
92 if (elf_machine_lookup_noexec_p (reloc_type
) &&
93 map
->l_type
== lt_executable
)
96 symtab
= ((void *) map
->l_addr
+ map
->l_info
[DT_SYMTAB
]->d_un
.d_ptr
);
97 strtab
= ((void *) map
->l_addr
+ map
->l_info
[DT_STRTAB
]->d_un
.d_ptr
);
98 if (map
->l_nversions
> 0 && map
->l_info
[VERSTAG (DT_VERSYM
)] != NULL
)
99 verstab
= ((void *) map
->l_addr
100 + map
->l_info
[VERSTAG (DT_VERSYM
)]->d_un
.d_ptr
);
104 /* Search the appropriate hash bucket in this object's symbol table
105 for a definition for the same symbol name. */
106 for (symidx
= map
->l_buckets
[hash
% map
->l_nbuckets
];
108 symidx
= map
->l_chain
[symidx
])
110 const ElfW(Sym
) *sym
= &symtab
[symidx
];
112 if (sym
->st_value
== 0 || /* No value. */
113 (elf_machine_lookup_noplt_p (reloc_type
) /* Reject PLT entry. */
114 && sym
->st_shndx
== SHN_UNDEF
))
117 if (ELFW(ST_TYPE
) (sym
->st_info
) > STT_FUNC
)
118 /* Ignore all but STT_NOTYPE, STT_OBJECT and STT_FUNC entries
119 since these are no code/data definitions. */
122 if (sym
!= ref
&& strcmp (strtab
+ sym
->st_name
, undef_name
))
123 /* Not the symbol we are looking for. */
128 /* No specific version is selected. When the object
129 file also does not define a version we have a match.
130 Otherwise we only accept the default version, i.e.,
131 the version which name is "". */
134 ElfW(Half
) ndx
= verstab
[symidx
] & 0x7fff;
135 if (ndx
> 2) /* map->l_versions[ndx].hash != 0) */
143 /* We need a versioned system but haven't found any.
144 If this is the object which is referenced in the
145 verneed entry it is a bug in the library since a
146 symbol must not simply disappear. */
147 if (version
->filename
!= NULL
148 && _dl_name_match_p (version
->filename
, map
))
150 /* Otherwise we accept the symbol. */
154 /* We can match the version information or use the
156 ElfW(Half
) ndx
= verstab
[symidx
] & 0x7fff;
157 if ((map
->l_versions
[ndx
].hash
!= version
->hash
158 || strcmp (map
->l_versions
[ndx
].name
, version
->name
))
159 && (version
->hidden
|| map
->l_versions
[ndx
].hash
))
160 /* It's not the version we want. */
165 switch (ELFW(ST_BIND
) (sym
->st_info
))
168 /* Global definition. Just what we need. */
170 result
->a
= map
->l_addr
;
173 /* Weak definition. Use this value if we don't find
178 result
->a
= map
->l_addr
;
182 /* Local symbols are ignored. */
186 /* There cannot be another entry for this symbol so stop here. */
190 /* If this current map is the one mentioned in the verneed entry
191 and we have not found a weak entry, it is a bug. */
192 if (symidx
== STN_UNDEF
&& version
!= NULL
&& version
->filename
!= NULL
193 && _dl_name_match_p (version
->filename
, map
))
197 /* We have not found anything until now. */
201 /* Search loaded objects' symbol tables for a definition of the symbol
205 _dl_lookup_symbol (const char *undef_name
, const ElfW(Sym
) **ref
,
206 struct link_map
*symbol_scope
[],
207 const char *reference_name
,
210 const unsigned long int hash
= _dl_elf_hash (undef_name
);
211 struct sym_val current_value
= { 0, NULL
};
212 struct link_map
**scope
;
214 /* Search the relevant loaded objects for a definition. */
215 for (scope
= symbol_scope
; *scope
; ++scope
)
216 if (do_lookup (undef_name
, hash
, *ref
, ¤t_value
,
217 (*scope
)->l_searchlist
, 0, (*scope
)->l_nsearchlist
,
218 reference_name
, NULL
, NULL
, reloc_type
))
221 if (current_value
.s
== NULL
&&
222 (*ref
== NULL
|| ELFW(ST_BIND
) ((*ref
)->st_info
) != STB_WEAK
))
223 /* We could find no value for a strong reference. */
224 _dl_signal_error (0, reference_name
,
225 make_string (undefined_msg
, undef_name
));
227 *ref
= current_value
.s
;
228 return current_value
.a
;
232 /* This function is nearly the same as `_dl_lookup_symbol' but it
233 skips in the first list all objects until SKIP_MAP is found. I.e.,
234 it only considers objects which were loaded after the described
235 object. If there are more search lists the object described by
236 SKIP_MAP is only skipped. */
238 _dl_lookup_symbol_skip (const char *undef_name
, const ElfW(Sym
) **ref
,
239 struct link_map
*symbol_scope
[],
240 const char *reference_name
,
241 struct link_map
*skip_map
)
243 const unsigned long int hash
= _dl_elf_hash (undef_name
);
244 struct sym_val current_value
= { 0, NULL
};
245 struct link_map
**scope
;
248 /* Search the relevant loaded objects for a definition. */
249 scope
= symbol_scope
;
250 for (i
= 0; (*scope
)->l_dupsearchlist
[i
] != skip_map
; ++i
)
251 assert (i
< (*scope
)->l_ndupsearchlist
);
253 if (! do_lookup (undef_name
, hash
, *ref
, ¤t_value
,
254 (*scope
)->l_dupsearchlist
, i
, (*scope
)->l_ndupsearchlist
,
255 reference_name
, NULL
, skip_map
, 0))
257 if (do_lookup (undef_name
, hash
, *ref
, ¤t_value
,
258 (*scope
)->l_dupsearchlist
, 0, (*scope
)->l_ndupsearchlist
,
259 reference_name
, NULL
, skip_map
, 0))
262 *ref
= current_value
.s
;
263 return current_value
.a
;
267 /* This function works like _dl_lookup_symbol but it takes an
268 additional arguement with the version number of the requested
271 XXX We'll see whether we need this separate function. */
273 _dl_lookup_versioned_symbol (const char *undef_name
, const ElfW(Sym
) **ref
,
274 struct link_map
*symbol_scope
[],
275 const char *reference_name
,
276 const struct r_found_version
*version
,
279 const unsigned long int hash
= _dl_elf_hash (undef_name
);
280 struct sym_val current_value
= { 0, NULL
};
281 struct link_map
**scope
;
283 /* Search the relevant loaded objects for a definition. */
284 for (scope
= symbol_scope
; *scope
; ++scope
)
286 int res
= do_lookup (undef_name
, hash
, *ref
, ¤t_value
,
287 (*scope
)->l_searchlist
, 0, (*scope
)->l_nsearchlist
,
288 reference_name
, version
, NULL
, reloc_type
);
293 /* Oh, oh. The file named in the relocation entry does not
294 contain the needed symbol. */
295 _dl_signal_error (0, reference_name
,
296 make_string ("symbol ", undef_name
, ", version ",
298 " not defined in file ",
300 " with link time reference",
302 ? " (no version symbols)" : ""));
305 if (current_value
.s
== NULL
&&
306 (*ref
== NULL
|| ELFW(ST_BIND
) ((*ref
)->st_info
) != STB_WEAK
))
307 /* We could find no value for a strong reference. */
308 _dl_signal_error (0, reference_name
,
309 make_string (undefined_msg
, undef_name
,
310 ", version ", version
->name
?: NULL
));
312 *ref
= current_value
.s
;
313 return current_value
.a
;
317 /* Similar to _dl_lookup_symbol_skip but takes an additional argument
318 with the version we are looking for. */
320 _dl_lookup_versioned_symbol_skip (const char *undef_name
,
321 const ElfW(Sym
) **ref
,
322 struct link_map
*symbol_scope
[],
323 const char *reference_name
,
324 const struct r_found_version
*version
,
325 struct link_map
*skip_map
)
327 const unsigned long int hash
= _dl_elf_hash (undef_name
);
328 struct sym_val current_value
= { 0, NULL
};
329 struct link_map
**scope
;
332 /* Search the relevant loaded objects for a definition. */
333 scope
= symbol_scope
;
334 for (i
= 0; (*scope
)->l_dupsearchlist
[i
] != skip_map
; ++i
)
335 assert (i
< (*scope
)->l_ndupsearchlist
);
337 if (! do_lookup (undef_name
, hash
, *ref
, ¤t_value
,
338 (*scope
)->l_dupsearchlist
, i
, (*scope
)->l_ndupsearchlist
,
339 reference_name
, version
, skip_map
, 0))
341 if (do_lookup (undef_name
, hash
, *ref
, ¤t_value
,
342 (*scope
)->l_dupsearchlist
, 0, (*scope
)->l_ndupsearchlist
,
343 reference_name
, version
, skip_map
, 0))
346 if (current_value
.s
== NULL
&&
347 (*ref
== NULL
|| ELFW(ST_BIND
) ((*ref
)->st_info
) != STB_WEAK
))
349 /* We could find no value for a strong reference. */
350 const size_t len
= strlen (undef_name
);
351 char buf
[sizeof undefined_msg
+ len
];
352 memcpy (buf
, undefined_msg
, sizeof undefined_msg
- 1);
353 memcpy (&buf
[sizeof undefined_msg
- 1], undef_name
, len
+ 1);
354 _dl_signal_error (0, reference_name
, buf
);
357 *ref
= current_value
.s
;
358 return current_value
.a
;
362 /* Cache the location of MAP's hash table. */
365 _dl_setup_hash (struct link_map
*map
)
367 ElfW(Symndx
) *hash
= (void *)(map
->l_addr
+ map
->l_info
[DT_HASH
]->d_un
.d_ptr
);
369 map
->l_nbuckets
= *hash
++;
371 map
->l_buckets
= hash
;
372 hash
+= map
->l_nbuckets
;