/* Handle symbol and library versioning.
- Copyright (C) 1997 Free Software Foundation, Inc.
+ Copyright (C) 1997, 1998, 1999 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
#include <elf.h>
#include <errno.h>
-#include <link.h>
#include <stdlib.h>
#include <string.h>
-#include <assert.h>
-
-#include "../stdio-common/_itoa.h"
+#include <elf/ldsodefs.h>
+#include <stdio-common/_itoa.h>
+#include <assert.h>
-/* Set in rtld.c at startup. */
-extern char **_dl_argv;
-#define VERSTAG(tag) (DT_NUM + DT_PROCNUM + DT_VERSIONTAGIDX (tag))
+#ifndef VERSYMIDX
+# define VERSYMIDX(tag) (DT_NUM + DT_PROCNUM + DT_VERSIONTAGIDX (tag))
+#endif
#define make_string(string, rest...) \
\
cp = result = alloca (len); \
for (cnt = 0; cnt < sizeof (all) / sizeof (all[0]); ++cnt) \
- cp = stpcpy (cp, all[cnt]); \
+ cp = __stpcpy (cp, all[cnt]); \
\
result; \
})
static inline struct link_map *
-find_needed (struct link_map *map, const char *name)
+find_needed (const char *name, struct link_map *map)
{
+ struct link_map *tmap;
unsigned int n;
- for (n = 0; n < map->l_nsearchlist; ++n)
- if (_dl_does_name_match_p (name, map->l_searchlist[n]))
- return map->l_searchlist[n];
+ for (tmap = _dl_loaded; tmap != NULL; tmap = tmap->l_next)
+ if (_dl_name_match_p (name, tmap))
+ return tmap;
+
+ /* The required object is not in the global scope, look to see if it is
+ a dependency of the current object. */
+ for (n = 0; n < map->l_searchlist.r_nlist; n++)
+ if (_dl_name_match_p (name, map->l_searchlist.r_list[n]))
+ return map->l_searchlist.r_list[n];
/* Should never happen. */
return NULL;
static int
+internal_function
match_symbol (const char *name, ElfW(Word) hash, const char *string,
struct link_map *map, int verbose, int weak)
{
- const char *strtab = (const char *) (map->l_addr
- + map->l_info[DT_STRTAB]->d_un.d_ptr);
- ElfW(Addr) def_offset = map->l_info[VERSTAG (DT_VERDEF)]->d_un.d_ptr;
+ const char *strtab = (const void *) map->l_info[DT_STRTAB]->d_un.d_ptr;
+ ElfW(Addr) def_offset;
ElfW(Verdef) *def;
- if (def_offset == 0)
+ /* Display information about what we are doing while debugging. */
+ if (_dl_debug_versions)
+ _dl_debug_message (1, "checking for version `", string, "' in file ",
+ map->l_name[0] ? map->l_name : _dl_argv[0],
+ " required by file ", name, "\n", NULL);
+
+ if (map->l_info[VERSYMIDX (DT_VERDEF)] == NULL)
{
/* The file has no symbol versioning. I.e., the dependent
object was linked against another version of this file. We
only print a message if verbose output is requested. */
if (verbose)
- _dl_signal_error (0, map->l_name, make_string ("\
+ _dl_signal_cerror (0, map->l_name,
+ make_string ("\
no version information available (required by ",
- name, ")"));
+ name, ")"));
return 0;
}
- def = (ElfW(Verdef) *) (map->l_addr + def_offset);
+ def_offset = map->l_info[VERSYMIDX (DT_VERDEF)]->d_un.d_ptr;
+ assert (def_offset != 0);
+
+ def = (ElfW(Verdef) *) ((char *) map->l_addr + def_offset);
while (1)
{
/* Currently the version number of the definition entry is 1.
if (weak)
{
if (verbose)
- _dl_signal_error (0, map->l_name,
- make_string ("weak version `", string,
- "' not found (required by ", name,
- ")"));
+ _dl_signal_cerror (0, map->l_name,
+ make_string ("weak version `", string,
+ "' not found (required by ", name,
+ ")"));
return 0;
}
- _dl_signal_error (0, map->l_name,
- make_string ("version `", string,
- "' not found (required by ", name, ")"));
+ _dl_signal_cerror (0, map->l_name,
+ make_string ("version `", string,
+ "' not found (required by ", name, ")"));
return 1;
}
int
+internal_function
_dl_check_map_versions (struct link_map *map, int verbose)
{
int result = 0;
- const char *strtab = (const char *) (map->l_addr
- + map->l_info[DT_STRTAB]->d_un.d_ptr);
+ const char *strtab;
/* Pointer to section with needed versions. */
- ElfW(Dyn) *dyn = map->l_info[VERSTAG (DT_VERNEED)];
+ ElfW(Dyn) *dyn;
/* Pointer to dynamic section with definitions. */
- ElfW(Dyn) *def = map->l_info[VERSTAG (DT_VERDEF)];
+ ElfW(Dyn) *def;
/* We need to find out which is the highest version index used
in a dependecy. */
unsigned int ndx_high = 0;
+ /* If we don't have a string table, we must be ok. */
+ if (map->l_info[DT_STRTAB] == NULL)
+ return 0;
+ strtab = (const void *) map->l_info[DT_STRTAB]->d_un.d_ptr;
+
+ dyn = map->l_info[VERSYMIDX (DT_VERNEED)];
+ def = map->l_info[VERSYMIDX (DT_VERDEF)];
+
if (dyn != NULL)
{
/* This file requires special versions from its dependencies. */
while (1)
{
ElfW(Vernaux) *aux;
- struct link_map *needed = find_needed (map, strtab + ent->vn_file);
+ struct link_map *needed = find_needed (strtab + ent->vn_file, map);
/* If NEEDED is NULL this means a dependency was not found
and no stub entry was created. This should never happen. */
aux->vna_flags & VER_FLG_WEAK);
/* Compare the version index. */
- if ((aux->vna_other & 0x7fff) > ndx_high)
+ if ((unsigned int) (aux->vna_other & 0x7fff) > ndx_high)
ndx_high = aux->vna_other & 0x7fff;
if (aux->vna_next == 0)
if (def != NULL)
{
ElfW(Verdef) *ent;
- ent = (ElfW(Verdef) *) (map->l_addr + def->d_un.d_ptr);
+ ent = (ElfW(Verdef) *) (map->l_addr + def->d_un.d_ptr);
while (1)
{
- if ((ent->vd_ndx & 0x7fff) > ndx_high)
+ if ((unsigned int) (ent->vd_ndx & 0x7fff) > ndx_high)
ndx_high = ent->vd_ndx & 0x7fff;
if (ent->vd_next == 0)
/* Now we are ready to build the array with the version names
which can be indexed by the version index in the VERSYM
section. */
- map->l_versions = (hash_name_pair*) malloc ((ndx_high + 1)
- * sizeof (hash_name_pair));
- memset (map->l_versions, '\0', (ndx_high + 1) * sizeof (hash_name_pair));
+ map->l_versions = (struct r_found_version *)
+ calloc (ndx_high + 1, sizeof (*map->l_versions));
if (map->l_versions == NULL)
{
_dl_signal_error (ENOMEM, (*map->l_name ? map->l_name : _dl_argv[0]),
- "cannot allocate version name table");
+ "cannot allocate version reference table");
result = 1;
}
else
/* Store the number of available symbols. */
map->l_nversions = ndx_high + 1;
+ /* Compute the pointer to the version symbols. */
+ map->l_versyms =
+ (void *) map->l_info[VERSYMIDX (DT_VERSYM)]->d_un.d_ptr;
+
if (dyn != NULL)
{
ElfW(Verneed) *ent;
{
ElfW(Half) ndx = aux->vna_other & 0x7fff;
map->l_versions[ndx].hash = aux->vna_hash;
+ map->l_versions[ndx].hidden = aux->vna_other & 0x8000;
map->l_versions[ndx].name = &strtab[aux->vna_name];
+ map->l_versions[ndx].filename = &strtab[ent->vn_file];
if (aux->vna_next == 0)
/* No more symbols. */
ElfW(Half) ndx = ent->vd_ndx & 0x7fff;
map->l_versions[ndx].hash = ent->vd_hash;
map->l_versions[ndx].name = &strtab[aux->vda_name];
+ map->l_versions[ndx].filename = NULL;
}
if (ent->vd_next == 0)
int
+internal_function
_dl_check_all_versions (struct link_map *map, int verbose)
{
struct link_map *l;
int result = 0;
for (l = map; l != NULL; l = l->l_next)
- result |= _dl_check_map_versions (l, verbose);
+ result |= l->l_opencount != 0 && _dl_check_map_versions (l, verbose);
return result;
}