source: trunk/libs/newlib/src/newlib/libc/sys/linux/dl/dl-version.c

Last change on this file was 444, checked in by satin@…, 6 years ago

add newlib,libalmos-mkh, restructure shared_syscalls.h and mini-libc

File size: 11.0 KB
Line 
1/* Handle symbol and library versioning.
2   Copyright (C) 1997, 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
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
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.
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
14   Lesser General Public License for more details.
15
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.  */
20
21#include <elf.h>
22#include <errno.h>
23#include <libintl.h>
24#include <stdlib.h>
25#include <string.h>
26#include <ldsodefs.h>
27
28#include <assert.h>
29
30
31#ifndef VERSYMIDX
32# define VERSYMIDX(tag) (DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGIDX (tag))
33#endif
34
35
36#define make_string(string, rest...) \
37  ({                                                                          \
38    const char *all[] = { string, ## rest };                                  \
39    size_t len, cnt;                                                          \
40    char *result, *cp;                                                        \
41                                                                              \
42    len = 1;                                                                  \
43    for (cnt = 0; cnt < sizeof (all) / sizeof (all[0]); ++cnt)                \
44      len += strlen (all[cnt]);                                               \
45                                                                              \
46    cp = result = alloca (len);                                               \
47    for (cnt = 0; cnt < sizeof (all) / sizeof (all[0]); ++cnt)                \
48    {                                                                         \
49      cp = strcpy (cp, all[cnt]);                                             \
50      cp += strlen (all[cnt]);                                                \
51    }                                                                         \
52                                                                              \
53    result;                                                                   \
54  })
55
56
57static inline struct link_map *
58find_needed (const char *name, struct link_map *map)
59{
60  struct link_map *tmap;
61  unsigned int n;
62
63  for (tmap = _dl_loaded; tmap != NULL; tmap = tmap->l_next)
64    if (_dl_name_match_p (name, tmap))
65      return tmap;
66
67  /* The required object is not in the global scope, look to see if it is
68     a dependency of the current object.  */
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];
72
73  /* Should never happen.  */
74  return NULL;
75}
76
77
78static int
79internal_function
80match_symbol (const char *name, ElfW(Word) hash, const char *string,
81              struct link_map *map, int verbose, int weak)
82{
83  const char *strtab = (const void *) D_PTR (map, l_info[DT_STRTAB]);
84  ElfW(Addr) def_offset;
85  ElfW(Verdef) *def;
86  /* Initialize to make the compiler happy.  */
87  const char *errstring = NULL;
88  int result = 0;
89
90  /* Display information about what we are doing while debugging.  */
91  if (__builtin_expect (_dl_debug_mask & DL_DEBUG_VERSIONS, 0))
92    _dl_debug_printf ("\
93checking for version `%s' in file %s required by file %s\n",
94                      string, map->l_name[0] ? map->l_name : _dl_argv[0],
95                      name);
96
97  if (__builtin_expect (map->l_info[VERSYMIDX (DT_VERDEF)] == NULL, 0))
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)
103        {
104          /* XXX We cannot translate the messages.  */
105          errstring = make_string ("\
106no version information available (required by ", name, ")");
107          goto call_cerror;
108        }
109      return 0;
110    }
111
112  def_offset = map->l_info[VERSYMIDX (DT_VERDEF)]->d_un.d_ptr;
113  assert (def_offset != 0);
114
115  def = (ElfW(Verdef) *) ((char *) map->l_addr + def_offset);
116  while (1)
117    {
118      /* Currently the version number of the definition entry is 1.
119         Make sure all we see is this version.  */
120      if (__builtin_expect (def->vd_version, 1) != 1)
121        {
122          char buf[20];
123          buf[sizeof (buf) - 1] = '\0';
124          /* XXX We cannot translate the message.  */
125          errstring = make_string ("unsupported version of Verdef record");
126          result = 1;
127          goto call_cerror;
128        }
129
130      /* Compare the hash values.  */
131      if (hash == def->vd_hash)
132        {
133          ElfW(Verdaux) *aux = (ElfW(Verdaux) *) ((char *) def + def->vd_aux);
134
135          /* To be safe, compare the string as well.  */
136          if (__builtin_expect (strcmp (string, strtab + aux->vda_name), 0)
137              == 0)
138            /* Bingo!  */
139            return 0;
140        }
141
142      /* If no more definitions we failed to find what we want.  */
143      if (def->vd_next == 0)
144        break;
145
146      /* Next definition.  */
147      def = (ElfW(Verdef) *) ((char *) def + def->vd_next);
148    }
149
150  /* Symbol not found.  If it was a weak reference it is not fatal.  */
151  if (__builtin_expect (weak, 1))
152    {
153      if (verbose)
154        {
155          /* XXX We cannot translate the message.  */
156          errstring = make_string ("weak version `", string,
157                                   "' not found (required by ", name, ")");
158          goto call_cerror;
159        }
160      return 0;
161    }
162
163  /* XXX We cannot translate the message.  */
164  errstring = make_string ("version `", string, "' not found (required by ",
165                           name, ")");
166  result = 1;
167 call_cerror:
168  _dl_signal_cerror (0, map->l_name[0] ? map->l_name : _dl_argv[0], NULL,
169                     errstring);
170  return result;
171}
172
173
174int
175internal_function
176_dl_check_map_versions (struct link_map *map, int verbose, int trace_mode)
177{
178  int result = 0;
179  const char *strtab;
180  /* Pointer to section with needed versions.  */
181  ElfW(Dyn) *dyn;
182  /* Pointer to dynamic section with definitions.  */
183  ElfW(Dyn) *def;
184  /* We need to find out which is the highest version index used
185    in a dependecy.  */
186  unsigned int ndx_high = 0;
187  /* Initialize to make the compiler happy.  */
188  const char *errstring = NULL;
189  int errval = 0;
190
191  /* If we don't have a string table, we must be ok.  */
192  if (map->l_info[DT_STRTAB] == NULL)
193    return 0;
194  strtab = (const void *) D_PTR (map, l_info[DT_STRTAB]);
195
196  dyn = map->l_info[VERSYMIDX (DT_VERNEED)];
197  def = map->l_info[VERSYMIDX (DT_VERDEF)];
198
199  if (dyn != NULL)
200    {
201      /* This file requires special versions from its dependencies.  */
202      ElfW(Verneed) *ent = (ElfW(Verneed) *) (map->l_addr + dyn->d_un.d_ptr);
203
204      /* Currently the version number of the needed entry is 1.
205         Make sure all we see is this version.  */
206      if (__builtin_expect (ent->vn_version, 1) != 1)
207        {
208          char buf[20];
209          buf[sizeof (buf) - 1] = '\0';
210          /* XXX We cannot translate the message.  */
211          errstring = make_string ("unsupported version of Verneed record\n");
212        call_error:
213          _dl_signal_error (errval, (*map->l_name ? map->l_name : _dl_argv[0]),
214                            NULL, errstring);
215        }
216
217      while (1)
218        {
219          ElfW(Vernaux) *aux;
220          struct link_map *needed = find_needed (strtab + ent->vn_file, map);
221
222          /* If NEEDED is NULL this means a dependency was not found
223             and no stub entry was created.  This should never happen.  */
224          assert (needed != NULL);
225
226          /* Make sure this is no stub we created because of a missing
227             dependency.  */
228          if (__builtin_expect (! trace_mode, 1)
229              || ! __builtin_expect (needed->l_faked, 0))
230            {
231              /* NEEDED is the map for the file we need.  Now look for the
232                 dependency symbols.  */
233              aux = (ElfW(Vernaux) *) ((char *) ent + ent->vn_aux);
234              while (1)
235                {
236                  /* Match the symbol.  */
237                  result |= match_symbol ((*map->l_name
238                                           ? map->l_name : _dl_argv[0]),
239                                          aux->vna_hash,
240                                          strtab + aux->vna_name,
241                                          needed, verbose,
242                                          aux->vna_flags & VER_FLG_WEAK);
243
244                  /* Compare the version index.  */
245                  if ((unsigned int) (aux->vna_other & 0x7fff) > ndx_high)
246                    ndx_high = aux->vna_other & 0x7fff;
247
248                  if (aux->vna_next == 0)
249                    /* No more symbols.  */
250                    break;
251
252                  /* Next symbol.  */
253                  aux = (ElfW(Vernaux) *) ((char *) aux + aux->vna_next);
254                }
255            }
256
257          if (ent->vn_next == 0)
258            /* No more dependencies.  */
259            break;
260
261          /* Next dependency.  */
262          ent = (ElfW(Verneed) *) ((char *) ent + ent->vn_next);
263        }
264    }
265
266  /* We also must store the names of the defined versions.  Determine
267     the maximum index here as well.
268
269     XXX We could avoid the loop by just taking the number of definitions
270     as an upper bound of new indeces.  */
271  if (def != NULL)
272    {
273      ElfW(Verdef) *ent;
274      ent = (ElfW(Verdef) *) (map->l_addr + def->d_un.d_ptr);
275      while (1)
276        {
277          if ((unsigned int) (ent->vd_ndx & 0x7fff) > ndx_high)
278            ndx_high = ent->vd_ndx & 0x7fff;
279
280          if (ent->vd_next == 0)
281            /* No more definitions.  */
282            break;
283
284          ent = (ElfW(Verdef) *) ((char *) ent + ent->vd_next);
285        }
286    }
287
288  if (ndx_high > 0)
289    {
290      /* Now we are ready to build the array with the version names
291         which can be indexed by the version index in the VERSYM
292         section.  */
293      map->l_versions = (struct r_found_version *)
294        calloc (ndx_high + 1, sizeof (*map->l_versions));
295      if (__builtin_expect (map->l_versions == NULL, 0))
296        {
297          errstring = N_("cannot allocate version reference table");
298          errval = ENOMEM;
299          goto call_error;
300        }
301
302      /* Store the number of available symbols.  */
303      map->l_nversions = ndx_high + 1;
304
305      /* Compute the pointer to the version symbols.  */
306      map->l_versyms = (void *) D_PTR (map, l_info[VERSYMIDX (DT_VERSYM)]);
307
308      if (dyn != NULL)
309        {
310          ElfW(Verneed) *ent;
311          ent = (ElfW(Verneed) *) (map->l_addr + dyn->d_un.d_ptr);
312          while (1)
313            {
314              ElfW(Vernaux) *aux;
315              aux = (ElfW(Vernaux) *) ((char *) ent + ent->vn_aux);
316              while (1)
317                {
318                  ElfW(Half) ndx = aux->vna_other & 0x7fff;
319                  map->l_versions[ndx].hash = aux->vna_hash;
320                  map->l_versions[ndx].hidden = aux->vna_other & 0x8000;
321                  map->l_versions[ndx].name = &strtab[aux->vna_name];
322                  map->l_versions[ndx].filename = &strtab[ent->vn_file];
323
324                  if (aux->vna_next == 0)
325                    /* No more symbols.  */
326                    break;
327
328                  /* Advance to next symbol.  */
329                  aux = (ElfW(Vernaux) *) ((char *) aux + aux->vna_next);
330                }
331
332              if (ent->vn_next == 0)
333                /* No more dependencies.  */
334                break;
335
336              /* Advance to next dependency.  */
337              ent = (ElfW(Verneed) *) ((char *) ent + ent->vn_next);
338            }
339        }
340
341      /* And insert the defined versions.  */
342      if (def != NULL)
343        {
344          ElfW(Verdef) *ent;
345          ent = (ElfW(Verdef)  *) (map->l_addr + def->d_un.d_ptr);
346          while (1)
347            {
348              ElfW(Verdaux) *aux;
349              aux = (ElfW(Verdaux) *) ((char *) ent + ent->vd_aux);
350
351              if ((ent->vd_flags & VER_FLG_BASE) == 0)
352                {
353                  /* The name of the base version should not be
354                     available for matching a versioned symbol.  */
355                  ElfW(Half) ndx = ent->vd_ndx & 0x7fff;
356                  map->l_versions[ndx].hash = ent->vd_hash;
357                  map->l_versions[ndx].name = &strtab[aux->vda_name];
358                  map->l_versions[ndx].filename = NULL;
359                }
360
361              if (ent->vd_next == 0)
362                /* No more definitions.  */
363                break;
364
365              ent = (ElfW(Verdef) *) ((char *) ent + ent->vd_next);
366            }
367        }
368    }
369
370  return result;
371}
372
373
374int
375internal_function
376_dl_check_all_versions (struct link_map *map, int verbose, int trace_mode)
377{
378  struct link_map *l;
379  int result = 0;
380
381  for (l = map; l != NULL; l = l->l_next)
382    result |= ! l->l_faked && _dl_check_map_versions (l, verbose, trace_mode);
383
384  return result;
385}
Note: See TracBrowser for help on using the repository browser.