about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog17
-rw-r--r--elf/dl-libc.c3
-rw-r--r--elf/dl-lookup.c45
-rw-r--r--elf/dl-reloc.c6
-rw-r--r--elf/dl-runtime.c10
-rw-r--r--elf/dl-sym.c10
-rw-r--r--elf/do-lookup.h33
-rw-r--r--sysdeps/generic/ldsodefs.h13
-rw-r--r--sysdeps/mips/dl-machine.h3
9 files changed, 99 insertions, 41 deletions
diff --git a/ChangeLog b/ChangeLog
index 8d296f7239..539d1a4fe2 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,20 @@
+2002-04-13  Ulrich Drepper  <drepper@redhat.com>
+
+	* elf/do-lookup.h [!VERSIONED]: Add new parameter flags.  Use it to
+	check whether the caller prefers getting the most recent version of
+	a symbol of the earliest version.
+	* elf/dl-lookup.c: Adjust all callers of do_lookup.  Change
+	_dl_do_lookup to also take the new parameter and pass it on.
+	Change 'explicit' parameter of _dl_lookup_symbol and
+	_dl_lookup_versioned_symbol to flags.  Adjust tests.
+	* sysdeps/generic/ldsodefs.h: Adjust prototypes.
+	* elf/dl-libc.c: Adjust all callers of _dl_lookup_symbol and
+	_dl_lookup_versioned_symbol.
+	* elf/dl-reloc.c: Likewise.
+	* elf/dl-runtime.c: Likewise.
+	* elf/dl-sym.c: Likewise.
+	* sysdeps/mips/dl-machine.h: Likewise.
+
 2002-04-11  Jakub Jelinek  <jakub@redhat.com>
 
 	* sysdeps/unix/sysv/linux/sparc/sparc32/sysdep.h (LOC): Don't paste
diff --git a/elf/dl-libc.c b/elf/dl-libc.c
index bb32f697e1..938b5d707d 100644
--- a/elf/dl-libc.c
+++ b/elf/dl-libc.c
@@ -84,7 +84,8 @@ do_dlsym (void *ptr)
   struct do_dlsym_args *args = (struct do_dlsym_args *) ptr;
   args->ref = NULL;
   args->loadbase = _dl_lookup_symbol (args->name, args->map, &args->ref,
-				      args->map->l_local_scope, 0, 1);
+				      args->map->l_local_scope, 0,
+				      DL_LOOKUP_RETURN_NEWEST);
 }
 
 static void
diff --git a/elf/dl-lookup.c b/elf/dl-lookup.c
index f9a229d8ea..9d1e1f65af 100644
--- a/elf/dl-lookup.c
+++ b/elf/dl-lookup.c
@@ -190,7 +190,7 @@ static int
 internal_function
 _dl_do_lookup (const char *undef_name, unsigned long int hash,
 	       const ElfW(Sym) *ref, struct sym_val *result,
-	       struct r_scope_elem *scope, size_t i,
+	       struct r_scope_elem *scope, size_t i, int flags,
 	       struct link_map *skip, int type_class);
 static int
 internal_function
@@ -215,7 +215,7 @@ lookup_t
 internal_function
 _dl_lookup_symbol (const char *undef_name, struct link_map *undef_map,
 		   const ElfW(Sym) **ref, struct r_scope_elem *symbol_scope[],
-		   int type_class, int explicit)
+		   int type_class, int flags)
 {
   const unsigned long int hash = _dl_elf_hash (undef_name);
   struct sym_val current_value = { NULL, NULL };
@@ -226,8 +226,8 @@ _dl_lookup_symbol (const char *undef_name, struct link_map *undef_map,
 
   /* Search the relevant loaded objects for a definition.  */
   for (scope = symbol_scope; *scope; ++scope)
-    if (do_lookup (undef_name, hash, *ref, &current_value, *scope, 0, NULL,
-		   type_class))
+    if (do_lookup (undef_name, hash, *ref, &current_value, *scope, 0, flags,
+		   NULL, type_class))
       {
 	/* We have to check whether this would bind UNDEF_MAP to an object
 	   in the global scope which was dynamically loaded.  In this case
@@ -236,7 +236,7 @@ _dl_lookup_symbol (const char *undef_name, struct link_map *undef_map,
 	if (__builtin_expect (current_value.m->l_type == lt_loaded, 0)
 	    /* Don't do this for explicit lookups as opposed to implicit
 	       runtime lookups.  */
-	    && ! explicit
+	    && (flags & DL_LOOKUP_ADD_DEPENDENCY) != 0
 	    /* Add UNDEF_MAP to the dependencies.  */
 	    && add_dependency (undef_map, current_value.m) < 0)
 	  /* Something went wrong.  Perhaps the object we tried to reference
@@ -272,7 +272,7 @@ _dl_lookup_symbol (const char *undef_name, struct link_map *undef_map,
 
       for (scope = symbol_scope; *scope; ++scope)
 	if (_dl_do_lookup (undef_name, hash, *ref, &protected_value, *scope,
-			   0, NULL, ELF_RTYPE_CLASS_PLT))
+			   0, flags, NULL, ELF_RTYPE_CLASS_PLT))
 	  break;
 
       if (protected_value.s != NULL && protected_value.m != undef_map)
@@ -319,10 +319,10 @@ _dl_lookup_symbol_skip (const char *undef_name,
     assert (i < (*scope)->r_nlist);
 
   if (! _dl_do_lookup (undef_name, hash, *ref, &current_value, *scope, i,
-		       skip_map, 0))
+		       DL_LOOKUP_RETURN_NEWEST, skip_map, 0))
     while (*++scope)
       if (_dl_do_lookup (undef_name, hash, *ref, &current_value, *scope, 0,
-			 skip_map, 0))
+			 DL_LOOKUP_RETURN_NEWEST, skip_map, 0))
 	break;
 
   if (__builtin_expect (current_value.s == NULL, 0))
@@ -341,10 +341,12 @@ _dl_lookup_symbol_skip (const char *undef_name,
 
       if (i >= (*scope)->r_nlist
 	  || !_dl_do_lookup (undef_name, hash, *ref, &protected_value, *scope,
-			     i, skip_map, ELF_RTYPE_CLASS_PLT))
+			     i, DL_LOOKUP_RETURN_NEWEST, skip_map,
+			     ELF_RTYPE_CLASS_PLT))
 	while (*++scope)
 	  if (_dl_do_lookup (undef_name, hash, *ref, &protected_value, *scope,
-			     0, skip_map, ELF_RTYPE_CLASS_PLT))
+			     0, DL_LOOKUP_RETURN_NEWEST, skip_map,
+			     ELF_RTYPE_CLASS_PLT))
 	    break;
 
       if (protected_value.s != NULL && protected_value.m != undef_map)
@@ -375,7 +377,7 @@ _dl_lookup_versioned_symbol (const char *undef_name,
 			     struct link_map *undef_map, const ElfW(Sym) **ref,
 			     struct r_scope_elem *symbol_scope[],
 			     const struct r_found_version *version,
-			     int type_class, int explicit)
+			     int type_class, int flags)
 {
   const unsigned long int hash = _dl_elf_hash (undef_name);
   struct sym_val current_value = { NULL, NULL };
@@ -384,6 +386,9 @@ _dl_lookup_versioned_symbol (const char *undef_name,
 
   bump_num_relocations ();
 
+  /* No other flag than DL_LOOKUP_ADD_DEPENDENCY is allowed.  */
+  assert (flags == 0 || flags == DL_LOOKUP_ADD_DEPENDENCY);
+
   /* Search the relevant loaded objects for a definition.  */
   for (scope = symbol_scope; *scope; ++scope)
     {
@@ -398,14 +403,15 @@ _dl_lookup_versioned_symbol (const char *undef_name,
 	  if (__builtin_expect (current_value.m->l_type == lt_loaded, 0)
 	      /* Don't do this for explicit lookups as opposed to implicit
 		 runtime lookups.  */
-	      && ! explicit
+	      && flags != 0
 	      /* Add UNDEF_MAP to the dependencies.  */
 	      && add_dependency (undef_map, current_value.m) < 0)
 	    /* Something went wrong.  Perhaps the object we tried to reference
 	       was just removed.  Try finding another definition.  */
 	    return INTUSE(_dl_lookup_versioned_symbol) (undef_name, undef_map,
 							ref, symbol_scope,
-							version, type_class, 0);
+							version, type_class,
+							0);
 
 	  break;
 	}
@@ -590,12 +596,14 @@ _dl_setup_hash (struct link_map *map)
   map->l_chain = hash;
 }
 
+
 static void
 internal_function
 _dl_debug_bindings (const char *undef_name, struct link_map *undef_map,
 		    const ElfW(Sym) **ref, struct r_scope_elem *symbol_scope[],
-		    struct sym_val *value, const struct r_found_version *version,
-		    int type_class, int protected)
+		    struct sym_val *value,
+		    const struct r_found_version *version, int type_class,
+		    int protected)
 {
   const char *reference_name = undef_map->l_name;
 
@@ -628,7 +636,8 @@ _dl_debug_bindings (const char *undef_name, struct link_map *undef_map,
 
 	  if (version == 0)
 	    _dl_do_lookup (undef_name, hash, *ref, &val,
-			   undef_map->l_local_scope[0], 0, NULL, type_class);
+			   undef_map->l_local_scope[0], 0, 0, NULL,
+			   type_class);
 	  else
 	    _dl_do_lookup_versioned (undef_name, hash, *ref, &val,
 				     undef_map->l_local_scope[0], 0, version,
@@ -671,10 +680,10 @@ static int __attribute_noinline__
 internal_function
 _dl_do_lookup (const char *undef_name, unsigned long int hash,
 	       const ElfW(Sym) *ref, struct sym_val *result,
-	       struct r_scope_elem *scope, size_t i,
+	       struct r_scope_elem *scope, size_t i, int flags,
 	       struct link_map *skip, int type_class)
 {
-  return do_lookup (undef_name, hash, ref, result, scope, i, skip,
+  return do_lookup (undef_name, hash, ref, result, scope, i, flags, skip,
 		    type_class);
 }
 
diff --git a/elf/dl-reloc.c b/elf/dl-reloc.c
index 88bd3b681e..e5fbb440a5 100644
--- a/elf/dl-reloc.c
+++ b/elf/dl-reloc.c
@@ -131,7 +131,8 @@ _dl_relocate_object (struct link_map *l, struct r_scope_elem *scope[],
 							   l, (ref), scope,   \
 							   (version), _tc, 0) \
 		    : INTUSE(_dl_lookup_symbol) (strtab + (*ref)->st_name, l, \
-					         (ref), scope, _tc, 0));      \
+					         (ref), scope, _tc,	      \
+						 DL_LOOKUP_ADD_DEPENDENCY));  \
 	     l->l_lookup_cache.ret = (*ref);				      \
 	     l->l_lookup_cache.value = _lr; }))				      \
      : l)
@@ -152,7 +153,8 @@ _dl_relocate_object (struct link_map *l, struct r_scope_elem *scope[],
 							   l, (ref), scope,   \
 							   (version), _tc, 0) \
 		    : INTUSE(_dl_lookup_symbol) (strtab + (*ref)->st_name, l, \
-					      	 (ref), scope, _tc, 0));      \
+					      	 (ref), scope, _tc,	      \
+						 DL_LOOKUP_ADD_DEPENDENCY));  \
 	     l->l_lookup_cache.ret = (*ref);				      \
 	     l->l_lookup_cache.value = _lr; }))				      \
      : l->l_addr)
diff --git a/elf/dl-runtime.c b/elf/dl-runtime.c
index 3cc832512f..ed1c337367 100644
--- a/elf/dl-runtime.c
+++ b/elf/dl-runtime.c
@@ -98,7 +98,8 @@ fixup (
 	  }
 	case 0:
 	  result = INTUSE(_dl_lookup_symbol) (strtab + sym->st_name, l, &sym,
-					      l->l_scope, ELF_RTYPE_CLASS_PLT, 0);
+					      l->l_scope, ELF_RTYPE_CLASS_PLT,
+					      DL_LOOKUP_ADD_DEPENDENCY);
 	}
 
       /* Currently result contains the base load address (or link map)
@@ -192,9 +193,10 @@ profile_fixup (
 		  }
 	      }
 	    case 0:
-	      result = INTUSE(_dl_lookup_symbol) (strtab + sym->st_name, l, &sym,
-						  l->l_scope, ELF_RTYPE_CLASS_PLT,
-						  0);
+	      result = INTUSE(_dl_lookup_symbol) (strtab + sym->st_name, l,
+						  &sym, l->l_scope,
+						  ELF_RTYPE_CLASS_PLT,
+						  DL_LOOKUP_ADD_DEPENDENCY);
 	    }
 
 	  /* Currently result contains the base load address (or link map)
diff --git a/elf/dl-sym.c b/elf/dl-sym.c
index 8cb5d2f411..3bf8104a4a 100644
--- a/elf/dl-sym.c
+++ b/elf/dl-sym.c
@@ -51,7 +51,9 @@ _dl_sym (void *handle, const char *name, void *who)
 
   if (handle == RTLD_DEFAULT)
     /* Search the global scope as seen in the caller object.  */
-    result = _dl_lookup_symbol (name, match, &ref, match->l_scope, 0, 0);
+    result = _dl_lookup_symbol (name, match, &ref, match->l_scope, 0,
+				DL_LOOKUP_RETURN_NEWEST
+				| DL_LOOKUP_ADD_DEPENDENCY);
   else
     {
       if (handle != RTLD_NEXT)
@@ -60,7 +62,7 @@ _dl_sym (void *handle, const char *name, void *who)
 	  struct link_map *map = handle;
 
 	  result = _dl_lookup_symbol (name, match, &ref, map->l_local_scope,
-				      0, 1);
+				      0, DL_LOOKUP_RETURN_NEWEST);
 	}
       else
 	{
@@ -132,7 +134,7 @@ _dl_vsym (void *handle, const char *name, const char *version, void *who)
   if (handle == RTLD_DEFAULT)
     /* Search the global scope.  */
     result = _dl_lookup_versioned_symbol (name, match, &ref, match->l_scope,
-					  &vers, 0, 0);
+					  &vers, 0, DL_LOOKUP_ADD_DEPENDENCY);
   else if (handle == RTLD_NEXT)
     {
       if (__builtin_expect (match == GL(dl_loaded), 0))
@@ -157,7 +159,7 @@ RTLD_NEXT used in code not dynamically loaded"));
       /* Search the scope of the given object.  */
       struct link_map *map = handle;
       result = _dl_lookup_versioned_symbol (name, map, &ref,
-					    map->l_local_scope, &vers, 0, 1);
+					    map->l_local_scope, &vers, 0, 0);
     }
 
   if (ref != NULL)
diff --git a/elf/do-lookup.h b/elf/do-lookup.h
index bebdb0c09f..be75fb7b00 100644
--- a/elf/do-lookup.h
+++ b/elf/do-lookup.h
@@ -19,10 +19,10 @@
 
 #if VERSIONED
 # define FCT do_lookup_versioned
-# define ARG const struct r_found_version *const version,
+# define ARG const struct r_found_version *const version
 #else
 # define FCT do_lookup
-# define ARG
+# define ARG int flags
 #endif
 
 /* Inner part of the lookup functions.  We return a value > 0 if we
@@ -30,7 +30,7 @@
    something bad happened.  */
 static inline int
 FCT (const char *undef_name, unsigned long int hash, const ElfW(Sym) *ref,
-     struct sym_val *result, struct r_scope_elem *scope, size_t i, ARG
+     struct sym_val *result, struct r_scope_elem *scope, size_t i, ARG,
      struct link_map *skip, int type_class)
 {
   struct link_map **list = scope->r_list;
@@ -129,19 +129,34 @@ FCT (const char *undef_name, unsigned long int hash, const ElfW(Sym) *ref,
 		continue;
 	    }
 #else
-	  /* No specific version is selected.  When the object file
-	     also does not define a version we have a match.
-	     Otherwise we accept the default version, or in case there
-	     is only one version defined, this one version.  */
+	  /* No specific version is selected.  There are two ways we
+	     can got here:
+
+	     - a binary which does not include versioning information
+	       is loaded
+
+	     - dlsym() instead of dlvsym() is used to get a symbol which
+	       might exist in more than one form
+
+	     If the library does not provide symbol version
+	     information there is no problem at at: we simply use the
+	     symbol if it is defined.
+
+	     These two lookups need to be handled differently if the
+	     library defines versions.  In the case of the old
+	     unversioned application the oldest (default) version
+	     should be used.  In case of a dlsym() call the latest and
+	     public interface should be returned.  */
 	  if (verstab != NULL)
 	    {
-	      ElfW(Half) ndx = verstab[symidx] & 0x7fff;
-	      if (ndx >= 2) /* map->l_versions[ndx].hash != 0) */
+	      if ((verstab[symidx] & 0x7fff)
+		  >= ((flags & DL_LOOKUP_RETURN_NEWEST) ? 2 : 3))
 		{
 		  /* Don't accept hidden symbols.  */
 		  if ((verstab[symidx] & 0x8000) == 0 && num_versions++ == 0)
 		    /* No version so far.  */
 		    versioned_sym = sym;
+
 		  continue;
 		}
 	    }
diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h
index 011391865f..5f586f2e3c 100644
--- a/sysdeps/generic/ldsodefs.h
+++ b/sysdeps/generic/ldsodefs.h
@@ -532,15 +532,24 @@ extern lookup_t _dl_lookup_symbol (const char *undef,
 				   struct link_map *undef_map,
 				   const ElfW(Sym) **sym,
 				   struct r_scope_elem *symbol_scope[],
-				   int type_class, int explicit)
+				   int type_class, int flags)
      internal_function;
 extern lookup_t _dl_lookup_symbol_internal (const char *undef,
 					    struct link_map *undef_map,
 					    const ElfW(Sym) **sym,
 					    struct r_scope_elem *symbol_scope[],
-					    int type_class, int explicit)
+					    int type_class, int flags)
      internal_function;
 
+enum
+  {
+    /* If necessary add dependency between user and provider object.  */
+    DL_LOOKUP_ADD_DEPENDENCY = 1,
+    /* Return most recent version instead of default version for
+       unversioned lookup.  */
+    DL_LOOKUP_RETURN_NEWEST = 2
+  };
+
 /* Lookup versioned symbol.  */
 extern lookup_t _dl_lookup_versioned_symbol (const char *undef,
 					     struct link_map *undef_map,
diff --git a/sysdeps/mips/dl-machine.h b/sysdeps/mips/dl-machine.h
index fcf37f6569..bc5e84fd86 100644
--- a/sysdeps/mips/dl-machine.h
+++ b/sysdeps/mips/dl-machine.h
@@ -307,7 +307,8 @@ __dl_runtime_resolve (ElfW(Word) sym_index,				      \
 	  }								      \
 	case 0:								      \
 	  value = _dl_lookup_symbol (strtab + sym->st_name, l, &sym,	      \
-				     l->l_scope, ELF_RTYPE_CLASS_PLT, 0);     \
+				     l->l_scope, ELF_RTYPE_CLASS_PLT,	      \
+				     DL_LOOKUP_ADD_DEPENDENCY);		      \
 	}								      \
 									      \
       /* Currently value contains the base load address of the object	      \