]> git.ipfire.org Git - thirdparty/glibc.git/blame - elf/dl-version.c
(CFLAGS-tst-align.c): Add -mpreferred-stack-boundary=4.
[thirdparty/glibc.git] / elf / dl-version.c
CommitLineData
c84142e8 1/* Handle symbol and library versioning.
a334319f 2 Copyright (C) 1997-2002, 2003, 2004 Free Software Foundation, Inc.
c84142e8
UD
3 This file is part of the GNU C Library.
4 Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
5
6 The GNU C Library is free software; you can redistribute it and/or
41bdb6e2
AJ
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
c84142e8
UD
10
11 The GNU C Library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
41bdb6e2 14 Lesser General Public License for more details.
c84142e8 15
41bdb6e2
AJ
16 You should have received a copy of the GNU Lesser General Public
17 License along with the GNU C Library; if not, write to the Free
18 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19 02111-1307 USA. */
c84142e8
UD
20
21#include <elf.h>
22#include <errno.h>
8e17ea58 23#include <libintl.h>
c84142e8
UD
24#include <stdlib.h>
25#include <string.h>
a42195db 26#include <ldsodefs.h>
714a562f 27#include <stdio-common/_itoa.h>
c84142e8 28
a853022c
UD
29#include <assert.h>
30
c84142e8 31
f420344c 32#ifndef VERSYMIDX
b0982c4a 33# define VERSYMIDX(tag) (DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGIDX (tag))
f420344c 34#endif
c84142e8
UD
35
36
37#define make_string(string, rest...) \
38 ({ \
39 const char *all[] = { string, ## rest }; \
40 size_t len, cnt; \
41 char *result, *cp; \
42 \
43 len = 1; \
44 for (cnt = 0; cnt < sizeof (all) / sizeof (all[0]); ++cnt) \
45 len += strlen (all[cnt]); \
46 \
47 cp = result = alloca (len); \
48 for (cnt = 0; cnt < sizeof (all) / sizeof (all[0]); ++cnt) \
26b4d766 49 cp = __stpcpy (cp, all[cnt]); \
c84142e8
UD
50 \
51 result; \
52 })
53
54
55static inline struct link_map *
dd9423a6 56__attribute ((always_inline))
762a2918 57find_needed (const char *name, struct link_map *map)
c84142e8 58{
26b4d766 59 struct link_map *tmap;
c84142e8
UD
60 unsigned int n;
61
c0f62c56
UD
62 for (tmap = GL(dl_ns)[map->l_ns]._ns_loaded; tmap != NULL;
63 tmap = tmap->l_next)
26b4d766
UD
64 if (_dl_name_match_p (name, tmap))
65 return tmap;
c84142e8 66
762a2918
UD
67 /* The required object is not in the global scope, look to see if it is
68 a dependency of the current object. */
be935610
UD
69 for (n = 0; n < map->l_searchlist.r_nlist; n++)
70 if (_dl_name_match_p (name, map->l_searchlist.r_list[n]))
71 return map->l_searchlist.r_list[n];
762a2918 72
c84142e8
UD
73 /* Should never happen. */
74 return NULL;
75}
76
77
78static int
d0fc4041 79internal_function
a334319f 80match_symbol (const char *name, ElfW(Word) hash, const char *string,
c84142e8
UD
81 struct link_map *map, int verbose, int weak)
82{
a42195db 83 const char *strtab = (const void *) D_PTR (map, l_info[DT_STRTAB]);
714a562f 84 ElfW(Addr) def_offset;
c84142e8 85 ElfW(Verdef) *def;
6ed623f8
UD
86 /* Initialize to make the compiler happy. */
87 const char *errstring = NULL;
88 int result = 0;
c84142e8 89
8193034b 90 /* Display information about what we are doing while debugging. */
afdca0f2 91 if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_VERSIONS, 0))
154d10bd 92 _dl_debug_printf ("\
a334319f 93checking for version `%s' in file %s required by file %s\n",
154d10bd 94 string, map->l_name[0] ? map->l_name : rtld_progname,
a334319f 95 name);
8193034b 96
7b228b68 97 if (__builtin_expect (map->l_info[VERSYMIDX (DT_VERDEF)] == NULL, 0))
c84142e8
UD
98 {
99 /* The file has no symbol versioning. I.e., the dependent
100 object was linked against another version of this file. We
101 only print a message if verbose output is requested. */
102 if (verbose)
6ed623f8
UD
103 {
104 /* XXX We cannot translate the messages. */
105 errstring = make_string ("\
106no version information available (required by ", name, ")");
107 goto call_cerror;
108 }
c84142e8
UD
109 return 0;
110 }
111
f420344c 112 def_offset = map->l_info[VERSYMIDX (DT_VERDEF)]->d_un.d_ptr;
714a562f
UD
113 assert (def_offset != 0);
114
115 def = (ElfW(Verdef) *) ((char *) map->l_addr + def_offset);
c84142e8
UD
116 while (1)
117 {
118 /* Currently the version number of the definition entry is 1.
119 Make sure all we see is this version. */
7b228b68 120 if (__builtin_expect (def->vd_version, 1) != 1)
c84142e8
UD
121 {
122 char buf[20];
123 buf[sizeof (buf) - 1] = '\0';
8e17ea58 124 /* XXX We cannot translate the message. */
6ed623f8 125 errstring = make_string ("unsupported version ",
9710f75d
UD
126 _itoa (def->vd_version,
127 &buf[sizeof (buf) - 1], 10, 0),
6ed623f8
UD
128 " of Verdef record");
129 result = 1;
130 goto call_cerror;
c84142e8
UD
131 }
132
133 /* Compare the hash values. */
134 if (hash == def->vd_hash)
135 {
136 ElfW(Verdaux) *aux = (ElfW(Verdaux) *) ((char *) def + def->vd_aux);
137
138 /* To be safe, compare the string as well. */
7b228b68
UD
139 if (__builtin_expect (strcmp (string, strtab + aux->vda_name), 0)
140 == 0)
c84142e8
UD
141 /* Bingo! */
142 return 0;
143 }
144
145 /* If no more definitions we failed to find what we want. */
146 if (def->vd_next == 0)
147 break;
148
149 /* Next definition. */
150 def = (ElfW(Verdef) *) ((char *) def + def->vd_next);
151 }
152
153 /* Symbol not found. If it was a weak reference it is not fatal. */
7b228b68 154 if (__builtin_expect (weak, 1))
c84142e8
UD
155 {
156 if (verbose)
6ed623f8
UD
157 {
158 /* XXX We cannot translate the message. */
159 errstring = make_string ("weak version `", string,
160 "' not found (required by ", name, ")");
161 goto call_cerror;
162 }
c84142e8
UD
163 return 0;
164 }
165
8e17ea58 166 /* XXX We cannot translate the message. */
6ed623f8
UD
167 errstring = make_string ("version `", string, "' not found (required by ",
168 name, ")");
169 result = 1;
170 call_cerror:
e6caf4e1 171 _dl_signal_cerror (0, map->l_name[0] ? map->l_name : rtld_progname,
d6b5d570 172 NULL, errstring);
6ed623f8 173 return result;
c84142e8
UD
174}
175
176
177int
d0fc4041 178internal_function
145b8413 179_dl_check_map_versions (struct link_map *map, int verbose, int trace_mode)
c84142e8
UD
180{
181 int result = 0;
f41c8091 182 const char *strtab;
c84142e8 183 /* Pointer to section with needed versions. */
f41c8091 184 ElfW(Dyn) *dyn;
c84142e8 185 /* Pointer to dynamic section with definitions. */
f41c8091 186 ElfW(Dyn) *def;
c84142e8
UD
187 /* We need to find out which is the highest version index used
188 in a dependecy. */
189 unsigned int ndx_high = 0;
6ed623f8
UD
190 /* Initialize to make the compiler happy. */
191 const char *errstring = NULL;
192 int errval = 0;
c84142e8 193
f41c8091
UD
194 /* If we don't have a string table, we must be ok. */
195 if (map->l_info[DT_STRTAB] == NULL)
196 return 0;
a42195db 197 strtab = (const void *) D_PTR (map, l_info[DT_STRTAB]);
f41c8091 198
f420344c
UD
199 dyn = map->l_info[VERSYMIDX (DT_VERNEED)];
200 def = map->l_info[VERSYMIDX (DT_VERDEF)];
f41c8091 201
c84142e8
UD
202 if (dyn != NULL)
203 {
204 /* This file requires special versions from its dependencies. */
205 ElfW(Verneed) *ent = (ElfW(Verneed) *) (map->l_addr + dyn->d_un.d_ptr);
206
207 /* Currently the version number of the needed entry is 1.
208 Make sure all we see is this version. */
7b228b68 209 if (__builtin_expect (ent->vn_version, 1) != 1)
c84142e8
UD
210 {
211 char buf[20];
212 buf[sizeof (buf) - 1] = '\0';
8e17ea58 213 /* XXX We cannot translate the message. */
6ed623f8 214 errstring = make_string ("unsupported version ",
9710f75d
UD
215 _itoa (ent->vn_version,
216 &buf[sizeof (buf) - 1], 10, 0),
6ed623f8
UD
217 " of Verneed record\n");
218 call_error:
154d10bd
UD
219 _dl_signal_error (errval, *map->l_name ? map->l_name : rtld_progname,
220 NULL, errstring);
c84142e8
UD
221 }
222
223 while (1)
224 {
225 ElfW(Vernaux) *aux;
762a2918 226 struct link_map *needed = find_needed (strtab + ent->vn_file, map);
c84142e8
UD
227
228 /* If NEEDED is NULL this means a dependency was not found
229 and no stub entry was created. This should never happen. */
230 assert (needed != NULL);
231
145b8413
UD
232 /* Make sure this is no stub we created because of a missing
233 dependency. */
7b228b68 234 if (__builtin_expect (! trace_mode, 1)
a881e0a0 235 || ! __builtin_expect (needed->l_faked, 0))
c84142e8 236 {
145b8413
UD
237 /* NEEDED is the map for the file we need. Now look for the
238 dependency symbols. */
239 aux = (ElfW(Vernaux) *) ((char *) ent + ent->vn_aux);
240 while (1)
241 {
242 /* Match the symbol. */
243 result |= match_symbol ((*map->l_name
e6caf4e1 244 ? map->l_name : rtld_progname),
a334319f 245 aux->vna_hash,
145b8413 246 strtab + aux->vna_name,
c0f62c56 247 needed->l_real, verbose,
145b8413
UD
248 aux->vna_flags & VER_FLG_WEAK);
249
250 /* Compare the version index. */
251 if ((unsigned int) (aux->vna_other & 0x7fff) > ndx_high)
252 ndx_high = aux->vna_other & 0x7fff;
253
254 if (aux->vna_next == 0)
255 /* No more symbols. */
256 break;
257
258 /* Next symbol. */
259 aux = (ElfW(Vernaux) *) ((char *) aux + aux->vna_next);
260 }
c84142e8
UD
261 }
262
263 if (ent->vn_next == 0)
264 /* No more dependencies. */
265 break;
266
267 /* Next dependency. */
268 ent = (ElfW(Verneed) *) ((char *) ent + ent->vn_next);
269 }
270 }
271
272 /* We also must store the names of the defined versions. Determine
273 the maximum index here as well.
274
275 XXX We could avoid the loop by just taking the number of definitions
276 as an upper bound of new indeces. */
277 if (def != NULL)
278 {
279 ElfW(Verdef) *ent;
714a562f 280 ent = (ElfW(Verdef) *) (map->l_addr + def->d_un.d_ptr);
c84142e8
UD
281 while (1)
282 {
c131718c 283 if ((unsigned int) (ent->vd_ndx & 0x7fff) > ndx_high)
c84142e8
UD
284 ndx_high = ent->vd_ndx & 0x7fff;
285
286 if (ent->vd_next == 0)
287 /* No more definitions. */
288 break;
289
290 ent = (ElfW(Verdef) *) ((char *) ent + ent->vd_next);
291 }
292 }
293
294 if (ndx_high > 0)
295 {
296 /* Now we are ready to build the array with the version names
297 which can be indexed by the version index in the VERSYM
298 section. */
1fb05e3d 299 map->l_versions = (struct r_found_version *)
c131718c 300 calloc (ndx_high + 1, sizeof (*map->l_versions));
7b228b68 301 if (__builtin_expect (map->l_versions == NULL, 0))
c84142e8 302 {
6ed623f8
UD
303 errstring = N_("cannot allocate version reference table");
304 errval = ENOMEM;
305 goto call_error;
c84142e8 306 }
c84142e8 307
6ed623f8
UD
308 /* Store the number of available symbols. */
309 map->l_nversions = ndx_high + 1;
310
311 /* Compute the pointer to the version symbols. */
312 map->l_versyms = (void *) D_PTR (map, l_info[VERSYMIDX (DT_VERSYM)]);
0c367d92 313
6ed623f8
UD
314 if (dyn != NULL)
315 {
316 ElfW(Verneed) *ent;
317 ent = (ElfW(Verneed) *) (map->l_addr + dyn->d_un.d_ptr);
318 while (1)
c84142e8 319 {
6ed623f8
UD
320 ElfW(Vernaux) *aux;
321 aux = (ElfW(Vernaux) *) ((char *) ent + ent->vn_aux);
c84142e8
UD
322 while (1)
323 {
6ed623f8
UD
324 ElfW(Half) ndx = aux->vna_other & 0x7fff;
325 map->l_versions[ndx].hash = aux->vna_hash;
326 map->l_versions[ndx].hidden = aux->vna_other & 0x8000;
327 map->l_versions[ndx].name = &strtab[aux->vna_name];
328 map->l_versions[ndx].filename = &strtab[ent->vn_file];
329
330 if (aux->vna_next == 0)
331 /* No more symbols. */
c84142e8
UD
332 break;
333
6ed623f8
UD
334 /* Advance to next symbol. */
335 aux = (ElfW(Vernaux) *) ((char *) aux + aux->vna_next);
c84142e8 336 }
6ed623f8
UD
337
338 if (ent->vn_next == 0)
339 /* No more dependencies. */
340 break;
341
342 /* Advance to next dependency. */
343 ent = (ElfW(Verneed) *) ((char *) ent + ent->vn_next);
c84142e8 344 }
6ed623f8 345 }
c84142e8 346
6ed623f8
UD
347 /* And insert the defined versions. */
348 if (def != NULL)
349 {
350 ElfW(Verdef) *ent;
351 ent = (ElfW(Verdef) *) (map->l_addr + def->d_un.d_ptr);
352 while (1)
c84142e8 353 {
6ed623f8
UD
354 ElfW(Verdaux) *aux;
355 aux = (ElfW(Verdaux) *) ((char *) ent + ent->vd_aux);
c84142e8 356
6ed623f8
UD
357 if ((ent->vd_flags & VER_FLG_BASE) == 0)
358 {
359 /* The name of the base version should not be
360 available for matching a versioned symbol. */
361 ElfW(Half) ndx = ent->vd_ndx & 0x7fff;
362 map->l_versions[ndx].hash = ent->vd_hash;
363 map->l_versions[ndx].name = &strtab[aux->vda_name];
364 map->l_versions[ndx].filename = NULL;
c84142e8 365 }
6ed623f8
UD
366
367 if (ent->vd_next == 0)
368 /* No more definitions. */
369 break;
370
371 ent = (ElfW(Verdef) *) ((char *) ent + ent->vd_next);
c84142e8
UD
372 }
373 }
374 }
375
376 return result;
377}
378
379
380int
d0fc4041 381internal_function
145b8413 382_dl_check_all_versions (struct link_map *map, int verbose, int trace_mode)
c84142e8
UD
383{
384 struct link_map *l;
385 int result = 0;
386
387 for (l = map; l != NULL; l = l->l_next)
7969407a 388 result |= (! l->l_faked
154d10bd 389 && _dl_check_map_versions (l, verbose, trace_mode));
c84142e8
UD
390
391 return result;
392}