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. */
23 #include <elf/ldsodefs.h>
25 #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]); \
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. */
67 #include "do-lookup.h"
70 #include "do-lookup.h"
73 /* Search loaded objects' symbol tables for a definition of the symbol
78 _dl_lookup_symbol (const char *undef_name
, const ElfW(Sym
) **ref
,
79 struct r_scope_elem
*symbol_scope
[],
80 const char *reference_name
,
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
, hash
, *ref
, ¤t_value
,
92 *scope
, 0, reference_name
, NULL
, reloc_type
))
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]
101 : (_dl_argv
[0] ?: "<main program>")),
102 make_string (undefined_msg
, undef_name
));
107 if (_dl_debug_bindings
)
108 _dl_debug_message (1, "binding file ",
109 (reference_name
&& reference_name
[0]
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. */
128 _dl_lookup_symbol_skip (const char *undef_name
, const ElfW(Sym
) **ref
,
129 struct r_scope_elem
*symbol_scope
[],
130 const char *reference_name
,
131 struct link_map
*skip_map
)
133 const unsigned long int hash
= _dl_elf_hash (undef_name
);
134 struct sym_val current_value
= { NULL
, NULL
};
135 struct r_scope_elem
**scope
;
138 ++_dl_num_relocations
;
140 /* Search the relevant loaded objects for a definition. */
141 scope
= symbol_scope
;
142 for (i
= 0; (*scope
)->r_duplist
[i
] != skip_map
; ++i
)
143 assert (i
< (*scope
)->r_nduplist
);
145 if (i
>= (*scope
)->r_nlist
146 || ! do_lookup (undef_name
, hash
, *ref
, ¤t_value
,
147 *scope
, i
, reference_name
, skip_map
, 0))
149 if (do_lookup (undef_name
, hash
, *ref
, ¤t_value
,
150 *scope
, 0, reference_name
, skip_map
, 0))
153 if (current_value
.s
== NULL
)
159 if (_dl_debug_bindings
)
160 _dl_debug_message (1, "binding file ",
161 (reference_name
&& reference_name
[0]
163 : (_dl_argv
[0] ?: "<main program>")),
164 " to ", current_value
.m
->l_name
[0]
165 ? current_value
.m
->l_name
: _dl_argv
[0],
166 ": symbol `", undef_name
, "' (skip)\n", NULL
);
168 *ref
= current_value
.s
;
169 return current_value
.m
->l_addr
;
173 /* This function works like _dl_lookup_symbol but it takes an
174 additional arguement with the version number of the requested
177 XXX We'll see whether we need this separate function. */
180 _dl_lookup_versioned_symbol (const char *undef_name
, const ElfW(Sym
) **ref
,
181 struct r_scope_elem
*symbol_scope
[],
182 const char *reference_name
,
183 const struct r_found_version
*version
,
186 const unsigned long int hash
= _dl_elf_hash (undef_name
);
187 struct sym_val current_value
= { NULL
, NULL
};
188 struct r_scope_elem
**scope
;
190 ++_dl_num_relocations
;
192 /* Search the relevant loaded objects for a definition. */
193 for (scope
= symbol_scope
; *scope
; ++scope
)
195 int res
= do_lookup_versioned (undef_name
, hash
, *ref
, ¤t_value
,
196 *scope
, 0, reference_name
, version
, NULL
,
203 /* Oh, oh. The file named in the relocation entry does not
204 contain the needed symbol. */
205 _dl_signal_cerror (0, (reference_name
&& reference_name
[0]
207 : (_dl_argv
[0] ?: "<main program>")),
208 make_string ("symbol ", undef_name
, ", version ",
210 " not defined in file ",
212 " with link time reference",
214 ? " (no version symbols)" : ""));
220 if (current_value
.s
== NULL
)
222 if (*ref
== NULL
|| ELFW(ST_BIND
) ((*ref
)->st_info
) != STB_WEAK
)
223 /* We could find no value for a strong reference. */
224 _dl_signal_cerror (0, (reference_name
&& reference_name
[0]
226 : (_dl_argv
[0] ?: "<main program>")),
227 make_string (undefined_msg
, undef_name
,
228 ", version ", version
->name
?: NULL
));
233 if (_dl_debug_bindings
)
234 _dl_debug_message (1, "binding file ",
235 (reference_name
&& reference_name
[0]
237 : (_dl_argv
[0] ?: "<main program>")),
238 " to ", current_value
.m
->l_name
[0]
239 ? current_value
.m
->l_name
: _dl_argv
[0],
240 ": symbol `", undef_name
, "' [", version
->name
,
243 *ref
= current_value
.s
;
244 return current_value
.m
->l_addr
;
248 /* Similar to _dl_lookup_symbol_skip but takes an additional argument
249 with the version we are looking for. */
252 _dl_lookup_versioned_symbol_skip (const char *undef_name
,
253 const ElfW(Sym
) **ref
,
254 struct r_scope_elem
*symbol_scope
[],
255 const char *reference_name
,
256 const struct r_found_version
*version
,
257 struct link_map
*skip_map
)
259 const unsigned long int hash
= _dl_elf_hash (undef_name
);
260 struct sym_val current_value
= { NULL
, NULL
};
261 struct r_scope_elem
**scope
;
264 ++_dl_num_relocations
;
266 /* Search the relevant loaded objects for a definition. */
267 scope
= symbol_scope
;
268 for (i
= 0; (*scope
)->r_duplist
[i
] != skip_map
; ++i
)
269 assert (i
< (*scope
)->r_nduplist
);
271 if (i
>= (*scope
)->r_nlist
272 || ! do_lookup_versioned (undef_name
, hash
, *ref
, ¤t_value
, *scope
,
273 i
, reference_name
, version
, skip_map
, 0))
275 if (do_lookup_versioned (undef_name
, hash
, *ref
, ¤t_value
, *scope
,
276 0, reference_name
, version
, skip_map
, 0))
279 if (current_value
.s
== NULL
)
281 if (*ref
== NULL
|| ELFW(ST_BIND
) ((*ref
)->st_info
) != STB_WEAK
)
283 /* We could find no value for a strong reference. */
284 const size_t len
= strlen (undef_name
);
285 char buf
[sizeof undefined_msg
+ len
];
286 __mempcpy (__mempcpy (buf
, undefined_msg
, sizeof undefined_msg
- 1),
287 undef_name
, len
+ 1);
288 _dl_signal_cerror (0, (reference_name
&& reference_name
[0]
290 : (_dl_argv
[0] ?: "<main program>")), buf
);
296 if (_dl_debug_bindings
)
297 _dl_debug_message (1, "binding file ",
298 (reference_name
&& reference_name
[0]
300 : (_dl_argv
[0] ?: "<main program>")),
302 current_value
.m
->l_name
[0]
303 ? current_value
.m
->l_name
: _dl_argv
[0],
304 ": symbol `", undef_name
, "' [", version
->name
,
307 *ref
= current_value
.s
;
308 return current_value
.m
->l_addr
;
312 /* Cache the location of MAP's hash table. */
316 _dl_setup_hash (struct link_map
*map
)
321 if (!map
->l_info
[DT_HASH
])
323 hash
= (void *)(map
->l_addr
+ map
->l_info
[DT_HASH
]->d_un
.d_ptr
);
325 map
->l_nbuckets
= *hash
++;
327 map
->l_buckets
= hash
;
328 hash
+= map
->l_nbuckets
;