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
, struct link_map
*undef_map
,
79 const ElfW(Sym
) **ref
, struct r_scope_elem
*symbol_scope
[],
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
, ¤t_value
,
92 *scope
, 0, 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
,
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
;
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
, ¤t_value
,
148 *scope
, i
, skip_map
, 0))
150 if (do_lookup (undef_name
, undef_map
, hash
, *ref
, ¤t_value
,
151 *scope
, 0, skip_map
, 0))
154 if (current_value
.s
== NULL
)
160 if (_dl_debug_bindings
)
161 _dl_debug_message (1, "binding file ",
162 (reference_name
&& reference_name
[0]
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
178 XXX We'll see whether we need this separate 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
,
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 ¤t_value
, *scope
, 0, version
, NULL
,
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]
209 : (_dl_argv
[0] ?: "<main program>")),
210 make_string ("symbol ", undef_name
, ", version ",
212 " not defined in file ",
214 " with link time reference",
216 ? " (no version symbols)" : ""));
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]
228 : (_dl_argv
[0] ?: "<main program>")),
229 make_string (undefined_msg
, undef_name
,
230 ", version ", version
->name
?: NULL
));
235 if (_dl_debug_bindings
)
236 _dl_debug_message (1, "binding file ",
237 (reference_name
&& reference_name
[0]
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
,
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. */
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
;
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 ¤t_value
, *scope
, i
, version
, skip_map
,
279 if (do_lookup_versioned (undef_name
, undef_map
, hash
, *ref
,
280 ¤t_value
, *scope
, 0, version
, skip_map
,
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]
295 : (_dl_argv
[0] ?: "<main program>")), buf
);
301 if (_dl_debug_bindings
)
302 _dl_debug_message (1, "binding file ",
303 (reference_name
&& reference_name
[0]
305 : (_dl_argv
[0] ?: "<main program>")),
307 current_value
.m
->l_name
[0]
308 ? current_value
.m
->l_name
: _dl_argv
[0],
309 ": symbol `", undef_name
, "' [", version
->name
,
312 *ref
= current_value
.s
;
313 return current_value
.m
->l_addr
;
317 /* Cache the location of MAP's hash table. */
321 _dl_setup_hash (struct link_map
*map
)
326 if (!map
->l_info
[DT_HASH
])
328 hash
= (void *)(map
->l_addr
+ map
->l_info
[DT_HASH
]->d_un
.d_ptr
);
330 map
->l_nbuckets
= *hash
++;
332 map
->l_buckets
= hash
;
333 hash
+= map
->l_nbuckets
;