Update.
[glibc.git] / elf / dl-lookup.c
blobbfe942cbb78d4db937ec3ffa8ce829882e206940
1 /* Look up a symbol in the loaded objects.
2 Copyright (C) 1995, 1996, 1997, 1998, 1999 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. */
20 #include <alloca.h>
21 #include <string.h>
22 #include <unistd.h>
23 #include <elf/ldsodefs.h>
24 #include "dl-hash.h"
25 #include <dl-machine.h>
27 #include <assert.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: ";
35 struct sym_val
37 const ElfW(Sym) *s;
38 struct link_map *m;
42 #define make_string(string, rest...) \
43 ({ \
44 const char *all[] = { string, ## rest }; \
45 size_t len, cnt; \
46 char *result, *cp; \
48 len = 1; \
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]); \
56 result; \
59 /* Statistics function. */
60 unsigned long int _dl_num_relocations;
63 /* We have two different situations when looking up a simple: with or
64 without versioning. gcc is not able to optimize a single function
65 definition serving for both purposes so we define two functions. */
66 #define VERSIONED 0
67 #include "do-lookup.h"
69 #define VERSIONED 1
70 #include "do-lookup.h"
73 /* Search loaded objects' symbol tables for a definition of the symbol
74 UNDEF_NAME. */
76 ElfW(Addr)
77 internal_function
78 _dl_lookup_symbol (const char *undef_name, struct link_map *undef_map,
79 const ElfW(Sym) **ref, struct r_scope_elem *symbol_scope[],
80 int reloc_type)
82 const char *reference_name = undef_map ? undef_map->l_name : NULL;
83 const unsigned long int hash = _dl_elf_hash (undef_name);
84 struct sym_val current_value = { NULL, NULL };
85 struct r_scope_elem **scope;
87 ++_dl_num_relocations;
89 /* Search the relevant loaded objects for a definition. */
90 for (scope = symbol_scope; *scope; ++scope)
91 if (do_lookup (undef_name, undef_map, hash, *ref, &current_value,
92 *scope, 0, NULL, reloc_type))
93 break;
95 if (current_value.s == NULL)
97 if (*ref == NULL || ELFW(ST_BIND) ((*ref)->st_info) != STB_WEAK)
98 /* We could find no value for a strong reference. */
99 _dl_signal_cerror (0, (reference_name && reference_name[0]
100 ? reference_name
101 : (_dl_argv[0] ?: "<main program>")),
102 make_string (undefined_msg, undef_name));
103 *ref = NULL;
104 return 0;
107 if (_dl_debug_bindings)
108 _dl_debug_message (1, "binding file ",
109 (reference_name && reference_name[0]
110 ? reference_name
111 : (_dl_argv[0] ?: "<main program>")),
112 " to ", current_value.m->l_name[0]
113 ? current_value.m->l_name : _dl_argv[0],
114 ": symbol `", undef_name, "'\n", NULL);
116 *ref = current_value.s;
117 return current_value.m->l_addr;
121 /* This function is nearly the same as `_dl_lookup_symbol' but it
122 skips in the first list all objects until SKIP_MAP is found. I.e.,
123 it only considers objects which were loaded after the described
124 object. If there are more search lists the object described by
125 SKIP_MAP is only skipped. */
126 ElfW(Addr)
127 internal_function
128 _dl_lookup_symbol_skip (const char *undef_name,
129 struct link_map *undef_map, const ElfW(Sym) **ref,
130 struct r_scope_elem *symbol_scope[],
131 struct link_map *skip_map)
133 const char *reference_name = undef_map ? undef_map->l_name : NULL;
134 const unsigned long int hash = _dl_elf_hash (undef_name);
135 struct sym_val current_value = { NULL, NULL };
136 struct r_scope_elem **scope;
137 size_t i;
139 ++_dl_num_relocations;
141 /* Search the relevant loaded objects for a definition. */
142 scope = symbol_scope;
143 for (i = 0; (*scope)->r_duplist[i] != skip_map; ++i)
144 assert (i < (*scope)->r_nduplist);
146 if (i >= (*scope)->r_nlist
147 || ! do_lookup (undef_name, undef_map, hash, *ref, &current_value,
148 *scope, i, skip_map, 0))
149 while (*++scope)
150 if (do_lookup (undef_name, undef_map, hash, *ref, &current_value,
151 *scope, 0, skip_map, 0))
152 break;
154 if (current_value.s == NULL)
156 *ref = NULL;
157 return 0;
160 if (_dl_debug_bindings)
161 _dl_debug_message (1, "binding file ",
162 (reference_name && reference_name[0]
163 ? reference_name
164 : (_dl_argv[0] ?: "<main program>")),
165 " to ", current_value.m->l_name[0]
166 ? current_value.m->l_name : _dl_argv[0],
167 ": symbol `", undef_name, "' (skip)\n", NULL);
169 *ref = current_value.s;
170 return current_value.m->l_addr;
174 /* This function works like _dl_lookup_symbol but it takes an
175 additional arguement with the version number of the requested
176 symbol.
178 XXX We'll see whether we need this separate function. */
179 ElfW(Addr)
180 internal_function
181 _dl_lookup_versioned_symbol (const char *undef_name,
182 struct link_map *undef_map, const ElfW(Sym) **ref,
183 struct r_scope_elem *symbol_scope[],
184 const struct r_found_version *version,
185 int reloc_type)
187 const char *reference_name = undef_map ? undef_map->l_name : NULL;
188 const unsigned long int hash = _dl_elf_hash (undef_name);
189 struct sym_val current_value = { NULL, NULL };
190 struct r_scope_elem **scope;
192 ++_dl_num_relocations;
194 /* Search the relevant loaded objects for a definition. */
195 for (scope = symbol_scope; *scope; ++scope)
197 int res = do_lookup_versioned (undef_name, undef_map, hash, *ref,
198 &current_value, *scope, 0, version, NULL,
199 reloc_type);
200 if (res > 0)
201 break;
203 if (res < 0)
205 /* Oh, oh. The file named in the relocation entry does not
206 contain the needed symbol. */
207 _dl_signal_cerror (0, (reference_name && reference_name[0]
208 ? reference_name
209 : (_dl_argv[0] ?: "<main program>")),
210 make_string ("symbol ", undef_name, ", version ",
211 version->name,
212 " not defined in file ",
213 version->filename,
214 " with link time reference",
215 res == -2
216 ? " (no version symbols)" : ""));
217 *ref = NULL;
218 return 0;
222 if (current_value.s == NULL)
224 if (*ref == NULL || ELFW(ST_BIND) ((*ref)->st_info) != STB_WEAK)
225 /* We could find no value for a strong reference. */
226 _dl_signal_cerror (0, (reference_name && reference_name[0]
227 ? reference_name
228 : (_dl_argv[0] ?: "<main program>")),
229 make_string (undefined_msg, undef_name,
230 ", version ", version->name ?: NULL));
231 *ref = NULL;
232 return 0;
235 if (_dl_debug_bindings)
236 _dl_debug_message (1, "binding file ",
237 (reference_name && reference_name[0]
238 ? reference_name
239 : (_dl_argv[0] ?: "<main program>")),
240 " to ", current_value.m->l_name[0]
241 ? current_value.m->l_name : _dl_argv[0],
242 ": symbol `", undef_name, "' [", version->name,
243 "]\n", NULL);
245 *ref = current_value.s;
246 return current_value.m->l_addr;
250 /* Similar to _dl_lookup_symbol_skip but takes an additional argument
251 with the version we are looking for. */
252 ElfW(Addr)
253 internal_function
254 _dl_lookup_versioned_symbol_skip (const char *undef_name,
255 struct link_map *undef_map,
256 const ElfW(Sym) **ref,
257 struct r_scope_elem *symbol_scope[],
258 const struct r_found_version *version,
259 struct link_map *skip_map)
261 const char *reference_name = undef_map ? undef_map->l_name : NULL;
262 const unsigned long int hash = _dl_elf_hash (undef_name);
263 struct sym_val current_value = { NULL, NULL };
264 struct r_scope_elem **scope;
265 size_t i;
267 ++_dl_num_relocations;
269 /* Search the relevant loaded objects for a definition. */
270 scope = symbol_scope;
271 for (i = 0; (*scope)->r_duplist[i] != skip_map; ++i)
272 assert (i < (*scope)->r_nduplist);
274 if (i >= (*scope)->r_nlist
275 || ! do_lookup_versioned (undef_name, undef_map, hash, *ref,
276 &current_value, *scope, i, version, skip_map,
278 while (*++scope)
279 if (do_lookup_versioned (undef_name, undef_map, hash, *ref,
280 &current_value, *scope, 0, version, skip_map,
282 break;
284 if (current_value.s == NULL)
286 if (*ref == NULL || ELFW(ST_BIND) ((*ref)->st_info) != STB_WEAK)
288 /* We could find no value for a strong reference. */
289 const size_t len = strlen (undef_name);
290 char buf[sizeof undefined_msg + len];
291 __mempcpy (__mempcpy (buf, undefined_msg, sizeof undefined_msg - 1),
292 undef_name, len + 1);
293 _dl_signal_cerror (0, (reference_name && reference_name[0]
294 ? reference_name
295 : (_dl_argv[0] ?: "<main program>")), buf);
297 *ref = NULL;
298 return 0;
301 if (_dl_debug_bindings)
302 _dl_debug_message (1, "binding file ",
303 (reference_name && reference_name[0]
304 ? reference_name
305 : (_dl_argv[0] ?: "<main program>")),
306 " to ",
307 current_value.m->l_name[0]
308 ? current_value.m->l_name : _dl_argv[0],
309 ": symbol `", undef_name, "' [", version->name,
310 "] (skip)\n", NULL);
312 *ref = current_value.s;
313 return current_value.m->l_addr;
317 /* Cache the location of MAP's hash table. */
319 void
320 internal_function
321 _dl_setup_hash (struct link_map *map)
323 Elf_Symndx *hash;
324 Elf_Symndx nchain;
326 if (!map->l_info[DT_HASH])
327 return;
328 hash = (void *)(map->l_addr + map->l_info[DT_HASH]->d_un.d_ptr);
330 map->l_nbuckets = *hash++;
331 nchain = *hash++;
332 map->l_buckets = hash;
333 hash += map->l_nbuckets;
334 map->l_chain = hash;