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 /* Don't search the executable when resolving a copy reloc. */
87 if (elf_machine_lookup_noexec_p (reloc_type
) &&
88 map
->l_type
== lt_executable
)
91 symtab
= ((void *) map
->l_addr
+ map
->l_info
[DT_SYMTAB
]->d_un
.d_ptr
);
92 strtab
= ((void *) map
->l_addr
+ map
->l_info
[DT_STRTAB
]->d_un
.d_ptr
);
93 if (map
->l_nversions
> 0 && map
->l_info
[VERSTAG (DT_VERSYM
)] != NULL
)
94 verstab
= ((void *) map
->l_addr
95 + map
->l_info
[VERSTAG (DT_VERSYM
)]->d_un
.d_ptr
);
99 /* Search the appropriate hash bucket in this object's symbol table
100 for a definition for the same symbol name. */
101 for (symidx
= map
->l_buckets
[hash
% map
->l_nbuckets
];
103 symidx
= map
->l_chain
[symidx
])
105 const ElfW(Sym
) *sym
= &symtab
[symidx
];
107 if (sym
->st_value
== 0 || /* No value. */
108 (elf_machine_lookup_noplt_p (reloc_type
) /* Reject PLT entry. */
109 && sym
->st_shndx
== SHN_UNDEF
))
112 if (ELFW(ST_TYPE
) (sym
->st_info
) > STT_FUNC
)
113 /* Ignore all but STT_NOTYPE, STT_OBJECT and STT_FUNC entries
114 since these are no code/data definitions. */
117 if (sym
!= ref
&& strcmp (strtab
+ sym
->st_name
, undef_name
))
118 /* Not the symbol we are looking for. */
123 /* No specific version is selected. When the object
124 file also does not define a version we have a match.
125 Otherwise we only accept the default version, i.e.,
126 the version which name is "". */
129 ElfW(Half
) ndx
= verstab
[symidx
] & 0x7fff;
130 if (ndx
> 2) /* map->l_versions[ndx].hash != 0) */
138 /* We need a versioned system but haven't found any.
139 If this is the object which is referenced in the
140 verneed entry it is a bug in the library since a
141 symbol must not simply disappear. */
142 if (version
->filename
!= NULL
143 && _dl_name_match_p (version
->filename
, map
))
145 /* Otherwise we accept the symbol. */
149 /* We can match the version information. */
150 ElfW(Half
) ndx
= verstab
[symidx
] & 0x7fff;
151 if (map
->l_versions
[ndx
].hash
!= version
->hash
152 || strcmp (map
->l_versions
[ndx
].name
, version
->name
))
153 /* It's not the version we want. */
158 switch (ELFW(ST_BIND
) (sym
->st_info
))
161 /* Global definition. Just what we need. */
163 result
->a
= map
->l_addr
;
166 /* Weak definition. Use this value if we don't find
171 result
->a
= map
->l_addr
;
175 /* Local symbols are ignored. */
179 /* There cannot be another entry for this symbol so stop here. */
183 /* If this current map is the one mentioned in the verneed entry
184 and we have not found a weak entry, it is a bug. */
185 if (symidx
== STN_UNDEF
&& version
!= NULL
&& version
->filename
!= NULL
186 && _dl_name_match_p (version
->filename
, map
))
190 /* We have not found anything until now. */
194 /* Search loaded objects' symbol tables for a definition of the symbol
198 _dl_lookup_symbol (const char *undef_name
, const ElfW(Sym
) **ref
,
199 struct link_map
*symbol_scope
[],
200 const char *reference_name
,
203 const unsigned long int hash
= _dl_elf_hash (undef_name
);
204 struct sym_val current_value
= { 0, NULL
};
205 struct link_map
**scope
;
207 /* Search the relevant loaded objects for a definition. */
208 for (scope
= symbol_scope
; *scope
; ++scope
)
209 if (do_lookup (undef_name
, hash
, *ref
, ¤t_value
,
210 (*scope
)->l_searchlist
, 0, (*scope
)->l_nsearchlist
,
211 reference_name
, NULL
, NULL
, reloc_type
))
214 if (current_value
.s
== NULL
&&
215 (*ref
== NULL
|| ELFW(ST_BIND
) ((*ref
)->st_info
) != STB_WEAK
))
216 /* We could find no value for a strong reference. */
217 _dl_signal_error (0, reference_name
,
218 make_string (undefined_msg
, undef_name
));
220 *ref
= current_value
.s
;
221 return current_value
.a
;
225 /* This function is nearly the same as `_dl_lookup_symbol' but it
226 skips in the first list all objects until SKIP_MAP is found. I.e.,
227 it only considers objects which were loaded after the described
228 object. If there are more search lists the object described by
229 SKIP_MAP is only skipped. */
231 _dl_lookup_symbol_skip (const char *undef_name
, const ElfW(Sym
) **ref
,
232 struct link_map
*symbol_scope
[],
233 const char *reference_name
,
234 struct link_map
*skip_map
)
236 const unsigned long int hash
= _dl_elf_hash (undef_name
);
237 struct sym_val current_value
= { 0, NULL
};
238 struct link_map
**scope
;
241 /* Search the relevant loaded objects for a definition. */
242 scope
= symbol_scope
;
243 for (i
= 0; (*scope
)->l_dupsearchlist
[i
] != skip_map
; ++i
)
244 assert (i
< (*scope
)->l_ndupsearchlist
);
246 if (! do_lookup (undef_name
, hash
, *ref
, ¤t_value
,
247 (*scope
)->l_dupsearchlist
, i
, (*scope
)->l_ndupsearchlist
,
248 reference_name
, NULL
, skip_map
, 0))
250 if (do_lookup (undef_name
, hash
, *ref
, ¤t_value
,
251 (*scope
)->l_dupsearchlist
, 0, (*scope
)->l_ndupsearchlist
,
252 reference_name
, NULL
, skip_map
, 0))
255 *ref
= current_value
.s
;
256 return current_value
.a
;
260 /* This function works like _dl_lookup_symbol but it takes an
261 additional arguement with the version number of the requested
264 XXX We'll see whether we need this separate function. */
266 _dl_lookup_versioned_symbol (const char *undef_name
, const ElfW(Sym
) **ref
,
267 struct link_map
*symbol_scope
[],
268 const char *reference_name
,
269 const struct r_found_version
*version
,
272 const unsigned long int hash
= _dl_elf_hash (undef_name
);
273 struct sym_val current_value
= { 0, NULL
};
274 struct link_map
**scope
;
276 /* Search the relevant loaded objects for a definition. */
277 for (scope
= symbol_scope
; *scope
; ++scope
)
279 int res
= do_lookup (undef_name
, hash
, *ref
, ¤t_value
,
280 (*scope
)->l_searchlist
, 0, (*scope
)->l_nsearchlist
,
281 reference_name
, version
, NULL
, reloc_type
);
286 /* Oh, oh. The file named in the relocation entry does not
287 contain the needed symbol. */
288 _dl_signal_error (0, *reference_name
? reference_name
: NULL
,
289 make_string ("symbol ", undef_name
, ", version ",
291 " not defined in file ",
293 " with link time reference",
295 ? " (no version symbols)" : ""));
298 if (current_value
.s
== NULL
&&
299 (*ref
== NULL
|| ELFW(ST_BIND
) ((*ref
)->st_info
) != STB_WEAK
))
300 /* We could find no value for a strong reference. */
301 _dl_signal_error (0, reference_name
,
302 make_string (undefined_msg
, undef_name
,
303 ", version ", version
->name
?: NULL
));
305 *ref
= current_value
.s
;
306 return current_value
.a
;
310 /* Similar to _dl_lookup_symbol_skip but takes an additional argument
311 with the version we are looking for. */
313 _dl_lookup_versioned_symbol_skip (const char *undef_name
,
314 const ElfW(Sym
) **ref
,
315 struct link_map
*symbol_scope
[],
316 const char *reference_name
,
317 const struct r_found_version
*version
,
318 struct link_map
*skip_map
)
320 const unsigned long int hash
= _dl_elf_hash (undef_name
);
321 struct sym_val current_value
= { 0, NULL
};
322 struct link_map
**scope
;
325 /* Search the relevant loaded objects for a definition. */
326 scope
= symbol_scope
;
327 for (i
= 0; (*scope
)->l_dupsearchlist
[i
] != skip_map
; ++i
)
328 assert (i
< (*scope
)->l_ndupsearchlist
);
330 if (! do_lookup (undef_name
, hash
, *ref
, ¤t_value
,
331 (*scope
)->l_dupsearchlist
, i
, (*scope
)->l_ndupsearchlist
,
332 reference_name
, version
, skip_map
, 0))
334 if (do_lookup (undef_name
, hash
, *ref
, ¤t_value
,
335 (*scope
)->l_dupsearchlist
, 0, (*scope
)->l_ndupsearchlist
,
336 reference_name
, version
, skip_map
, 0))
339 if (current_value
.s
== NULL
&&
340 (*ref
== NULL
|| ELFW(ST_BIND
) ((*ref
)->st_info
) != STB_WEAK
))
342 /* We could find no value for a strong reference. */
343 const size_t len
= strlen (undef_name
);
344 char buf
[sizeof undefined_msg
+ len
];
345 memcpy (buf
, undefined_msg
, sizeof undefined_msg
- 1);
346 memcpy (&buf
[sizeof undefined_msg
- 1], undef_name
, len
+ 1);
347 _dl_signal_error (0, reference_name
, buf
);
350 *ref
= current_value
.s
;
351 return current_value
.a
;
355 /* Cache the location of MAP's hash table. */
358 _dl_setup_hash (struct link_map
*map
)
360 ElfW(Symndx
) *hash
= (void *)(map
->l_addr
+ map
->l_info
[DT_HASH
]->d_un
.d_ptr
);
362 map
->l_nbuckets
= *hash
++;
364 map
->l_buckets
= hash
;
365 hash
+= map
->l_nbuckets
;