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. */
26 #include <dl-machine.h>
27 #include "../stdio-common/_itoa.h"
29 #define VERSTAG(tag) (DT_NUM + DT_PROCNUM + DT_VERSIONTAGIDX (tag))
38 #define make_string(string, rest...) \
40 const char *all[] = { string, ## rest }; \
45 for (cnt = 0; cnt < sizeof (all) / sizeof (all[0]); ++cnt) \
46 len += strlen (all[cnt]); \
48 cp = result = alloca (len); \
49 for (cnt = 0; cnt < sizeof (all) / sizeof (all[0]); ++cnt) \
50 cp = stpcpy (cp, all[cnt]); \
56 /* Inner part of the lookup functions. We return a value > 0 if we
57 found the symbol, the value 0 if nothing is found and < 0 if
58 something bad happened. */
60 do_lookup (const char *undef_name
, unsigned long int hash
,
61 const ElfW(Sym
) *ref
, struct sym_val
*result
,
62 struct link_map
*list
[], size_t i
, size_t n
,
63 const char *reference_name
, const struct r_found_version
*version
,
64 struct link_map
*skip
, int reloc_type
)
70 const ElfW(Sym
) *symtab
;
72 const ElfW(Half
) *verstab
;
77 /* Here come the extra test needed for `_dl_lookup_symbol_skip'. */
78 if (skip
!= NULL
&& map
== skip
)
81 /* Don't search the executable when resolving a copy reloc. */
82 if (elf_machine_lookup_noexec_p (reloc_type
) &&
83 map
->l_type
== lt_executable
)
86 symtab
= ((void *) map
->l_addr
+ map
->l_info
[DT_SYMTAB
]->d_un
.d_ptr
);
87 strtab
= ((void *) map
->l_addr
+ map
->l_info
[DT_STRTAB
]->d_un
.d_ptr
);
88 if (map
->l_nversions
> 0 && map
->l_info
[VERSTAG (DT_VERSYM
)] != NULL
)
89 verstab
= ((void *) map
->l_addr
90 + map
->l_info
[VERSTAG (DT_VERSYM
)]->d_un
.d_ptr
);
94 /* Search the appropriate hash bucket in this object's symbol table
95 for a definition for the same symbol name. */
96 for (symidx
= map
->l_buckets
[hash
% map
->l_nbuckets
];
98 symidx
= map
->l_chain
[symidx
])
100 const ElfW(Sym
) *sym
= &symtab
[symidx
];
102 if (sym
->st_value
== 0 || /* No value. */
103 (elf_machine_lookup_noplt_p (reloc_type
) /* Reject PLT entry. */
104 && sym
->st_shndx
== SHN_UNDEF
))
107 switch (ELFW(ST_TYPE
) (sym
->st_info
))
114 /* Not a code/data definition. */
118 if (sym
!= ref
&& strcmp (strtab
+ sym
->st_name
, undef_name
))
119 /* Not the symbol we are looking for. */
124 /* No specific version is selected. When the object
125 file also does not define a version we have a match.
126 Otherwise we only accept the default version, i.e.,
127 the version which name is "". */
130 ElfW(Half
) ndx
= verstab
[symidx
] & 0x7fff;
131 if (map
->l_versions
[ndx
].hash
!= 0)
139 /* We need a versioned system but haven't found any.
140 If this is the object which is referenced in the
141 verneed entry it is a bug in the library since a
142 symbol must not simply disappear. */
143 if (version
->filename
!= NULL
144 && _dl_name_match_p (version
->filename
, map
))
146 /* Otherwise we accept the symbol. */
150 /* We can match the version information. */
151 ElfW(Half
) ndx
= verstab
[symidx
] & 0x7fff;
152 if (map
->l_versions
[ndx
].hash
!= version
->hash
153 || strcmp (map
->l_versions
[ndx
].name
, version
->name
))
154 /* It's not the version we want. */
159 switch (ELFW(ST_BIND
) (sym
->st_info
))
162 /* Global definition. Just what we need. */
164 result
->a
= map
->l_addr
;
167 /* Weak definition. Use this value if we don't find
172 result
->a
= map
->l_addr
;
176 /* Local symbols are ignored. */
181 /* If this current is the one mentioned in the verneed entry it
183 if (version
!= NULL
&& version
->filename
!= NULL
184 && _dl_name_match_p (version
->filename
, map
))
188 /* We have not found anything until now. */
192 /* Search loaded objects' symbol tables for a definition of the symbol
196 _dl_lookup_symbol (const char *undef_name
, const ElfW(Sym
) **ref
,
197 struct link_map
*symbol_scope
[],
198 const char *reference_name
,
201 const unsigned long int hash
= _dl_elf_hash (undef_name
);
202 struct sym_val current_value
= { 0, NULL
};
203 struct link_map
**scope
;
205 /* Search the relevant loaded objects for a definition. */
206 for (scope
= symbol_scope
; *scope
; ++scope
)
207 if (do_lookup (undef_name
, hash
, *ref
, ¤t_value
,
208 (*scope
)->l_searchlist
, 0, (*scope
)->l_nsearchlist
,
209 reference_name
, NULL
, NULL
, reloc_type
))
212 if (current_value
.s
== NULL
&&
213 (*ref
== NULL
|| ELFW(ST_BIND
) ((*ref
)->st_info
) != STB_WEAK
))
214 /* We could find no value for a strong reference. */
215 _dl_signal_error (0, reference_name
,
216 make_string ("undefined symbol: ", undef_name
));
218 *ref
= current_value
.s
;
219 return current_value
.a
;
223 /* This function is nearly the same as `_dl_lookup_symbol' but it
224 skips in the first list all objects until SKIP_MAP is found. I.e.,
225 it only considers objects which were loaded after the described
226 object. If there are more search lists the object described by
227 SKIP_MAP is only skipped. */
229 _dl_lookup_symbol_skip (const char *undef_name
, const ElfW(Sym
) **ref
,
230 struct link_map
*symbol_scope
[],
231 const char *reference_name
,
232 struct link_map
*skip_map
)
234 const unsigned long int hash
= _dl_elf_hash (undef_name
);
235 struct sym_val current_value
= { 0, NULL
};
236 struct link_map
**scope
;
239 /* Search the relevant loaded objects for a definition. */
240 scope
= symbol_scope
;
241 for (i
= 0; (*scope
)->l_dupsearchlist
[i
] != skip_map
; ++i
)
242 assert (i
< (*scope
)->l_ndupsearchlist
);
244 if (! do_lookup (undef_name
, hash
, *ref
, ¤t_value
,
245 (*scope
)->l_dupsearchlist
, i
, (*scope
)->l_ndupsearchlist
,
246 reference_name
, NULL
, skip_map
, 0))
248 if (do_lookup (undef_name
, hash
, *ref
, ¤t_value
,
249 (*scope
)->l_dupsearchlist
, 0, (*scope
)->l_ndupsearchlist
,
250 reference_name
, NULL
, skip_map
, 0))
253 *ref
= current_value
.s
;
254 return current_value
.a
;
258 /* This function works like _dl_lookup_symbol but it takes an
259 additional arguement with the version number of the requested
262 XXX We'll see whether we need this separate function. */
264 _dl_lookup_versioned_symbol (const char *undef_name
, const ElfW(Sym
) **ref
,
265 struct link_map
*symbol_scope
[],
266 const char *reference_name
,
267 const struct r_found_version
*version
,
270 const unsigned long int hash
= _dl_elf_hash (undef_name
);
271 struct sym_val current_value
= { 0, NULL
};
272 struct link_map
**scope
;
274 /* Search the relevant loaded objects for a definition. */
275 for (scope
= symbol_scope
; *scope
; ++scope
)
277 int res
= do_lookup (undef_name
, hash
, *ref
, ¤t_value
,
278 (*scope
)->l_searchlist
, 0, (*scope
)->l_nsearchlist
,
279 reference_name
, version
, NULL
, reloc_type
);
284 /* Oh, oh. The file named in the relocation entry does not
285 contain the needed symbol. */
286 _dl_signal_error (0, *reference_name
? reference_name
: NULL
,
287 make_string ("symbol ", undef_name
, ", version ",
289 " not defined in file ",
291 " with link time reference"));
294 if (current_value
.s
== NULL
&&
295 (*ref
== NULL
|| ELFW(ST_BIND
) ((*ref
)->st_info
) != STB_WEAK
))
296 /* We could find no value for a strong reference. */
297 _dl_signal_error (0, reference_name
,
298 make_string ("undefined symbol: ", undef_name
,
299 ", version ", version
->name
?: NULL
));
301 *ref
= current_value
.s
;
302 return current_value
.a
;
306 /* Similar to _dl_lookup_symbol_skip but takes an additional argument
307 with the version we are looking for. */
309 _dl_lookup_versioned_symbol_skip (const char *undef_name
,
310 const ElfW(Sym
) **ref
,
311 struct link_map
*symbol_scope
[],
312 const char *reference_name
,
313 const struct r_found_version
*version
,
314 struct link_map
*skip_map
)
316 const unsigned long int hash
= _dl_elf_hash (undef_name
);
317 struct sym_val current_value
= { 0, NULL
};
318 struct link_map
**scope
;
321 /* Search the relevant loaded objects for a definition. */
322 scope
= symbol_scope
;
323 for (i
= 0; (*scope
)->l_dupsearchlist
[i
] != skip_map
; ++i
)
324 assert (i
< (*scope
)->l_ndupsearchlist
);
326 if (! do_lookup (undef_name
, hash
, *ref
, ¤t_value
,
327 (*scope
)->l_dupsearchlist
, i
, (*scope
)->l_ndupsearchlist
,
328 reference_name
, version
, skip_map
, 0))
330 if (do_lookup (undef_name
, hash
, *ref
, ¤t_value
,
331 (*scope
)->l_dupsearchlist
, 0, (*scope
)->l_ndupsearchlist
,
332 reference_name
, version
, skip_map
, 0))
335 *ref
= current_value
.s
;
336 return current_value
.a
;
340 /* Cache the location of MAP's hash table. */
343 _dl_setup_hash (struct link_map
*map
)
345 ElfW(Symndx
) *hash
= (void *)(map
->l_addr
+ map
->l_info
[DT_HASH
]->d_un
.d_ptr
);
347 map
->l_nbuckets
= *hash
++;
349 map
->l_buckets
= hash
;
350 hash
+= map
->l_nbuckets
;