/* 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 <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 (const char *name)
+find_needed (const char *name, struct link_map *map)
{
+ struct link_map *tmap;
unsigned int n;
- for (n = 0; n < _dl_loaded->l_nsearchlist; ++n)
- if (_dl_name_match_p (name, _dl_loaded->l_searchlist[n]))
- return _dl_loaded->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);
+ const char *strtab = (const void *) map->l_info[DT_STRTAB]->d_un.d_ptr;
ElfW(Addr) def_offset;
ElfW(Verdef) *def;
- if (map->l_info[VERSTAG (DT_VERDEF)] == NULL)
+ /* 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_offset = map->l_info[VERSTAG (DT_VERDEF)]->d_un.d_ptr;
+ 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);
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 (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. */
/* 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;
int
+internal_function
_dl_check_all_versions (struct link_map *map, int verbose)
{
struct link_map *l;