about summary refs log tree commit diff
path: root/elf/do-lookup.h
diff options
context:
space:
mode:
Diffstat (limited to 'elf/do-lookup.h')
-rw-r--r--elf/do-lookup.h280
1 files changed, 113 insertions, 167 deletions
diff --git a/elf/do-lookup.h b/elf/do-lookup.h
index ab9a510ba1..e57d9df26d 100644
--- a/elf/do-lookup.h
+++ b/elf/do-lookup.h
@@ -1,5 +1,5 @@
 /* Look up a symbol in the loaded objects.
-   Copyright (C) 1995-2004, 2005, 2006, 2007 Free Software Foundation, Inc.
+   Copyright (C) 1995-2002, 2003, 2004 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -17,208 +17,150 @@
    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
    02111-1307 USA.  */
 
-
 /* Inner part of the lookup functions.  We return a value > 0 if we
    found the symbol, the value 0 if nothing is found and < 0 if
    something bad happened.  */
 static int
 __attribute_noinline__
-do_lookup_x (const char *undef_name, uint_fast32_t new_hash,
-	     unsigned long int *old_hash, const ElfW(Sym) *ref,
-	     struct sym_val *result, struct r_scope_elem *scope, size_t i,
+do_lookup_x (const char *undef_name, unsigned long int hash,
+	     const ElfW(Sym) *ref, struct sym_val *result,
+	     struct r_scope_elem *scope, size_t i,
 	     const struct r_found_version *const version, int flags,
 	     struct link_map *skip, int type_class)
 {
-  size_t n = scope->r_nlist;
-  /* Make sure we read the value before proceeding.  Otherwise we
-     might use r_list pointing to the initial scope and r_nlist being
-     the value after a resize.  That is the only path in dl-open.c not
-     protected by GSCOPE.  A read barrier here might be to expensive.  */
-  __asm volatile ("" : "+r" (n), "+m" (scope->r_list));
   struct link_map **list = scope->r_list;
+  size_t n = scope->r_nlist;
+  struct link_map *map;
 
   do
     {
-      /* These variables are used in the nested function.  */
+      const ElfW(Sym) *symtab;
+      const char *strtab;
+      const ElfW(Half) *verstab;
       Elf_Symndx symidx;
+      const ElfW(Sym) *sym;
       int num_versions = 0;
       const ElfW(Sym) *versioned_sym = NULL;
 
-      const struct link_map *map = list[i]->l_real;
+      map = list[i]->l_real;
 
       /* Here come the extra test needed for `_dl_lookup_symbol_skip'.  */
-      if (map == skip)
+      if (skip != NULL && map == skip)
 	continue;
 
       /* Don't search the executable when resolving a copy reloc.  */
       if ((type_class & ELF_RTYPE_CLASS_COPY) && map->l_type == lt_executable)
 	continue;
 
-      /* Do not look into objects which are going to be removed.  */
-      if (map->l_removed)
-	continue;
-
       /* Print some debugging info if wanted.  */
       if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_SYMBOLS, 0))
-	_dl_debug_printf ("symbol=%s;  lookup in file=%s [%lu]\n",
+	_dl_debug_printf ("symbol=%s;  lookup in file=%s\n",
 			  undef_name,
-			  map->l_name[0] ? map->l_name : rtld_progname,
-			  map->l_ns);
-
-      /* If the hash table is empty there is nothing to do here.  */
-      if (map->l_nbuckets == 0)
-	continue;
-
-      /* The tables for this map.  */
-      const ElfW(Sym) *symtab = (const void *) D_PTR (map, l_info[DT_SYMTAB]);
-      const char *strtab = (const void *) D_PTR (map, l_info[DT_STRTAB]);
-
-
-      /* Nested routine to check whether the symbol matches.  */
-      const ElfW(Sym) *
-      __attribute_noinline__
-      check_match (const ElfW(Sym) *sym)
-      {
-	assert (ELF_RTYPE_CLASS_PLT == 1);
-	if (__builtin_expect ((sym->st_value == 0 /* No value.  */
-			       && ELFW(ST_TYPE) (sym->st_info) != STT_TLS)
-			      || (type_class & (sym->st_shndx == SHN_UNDEF)),
-			      0))
-	  return NULL;
-
-	if (__builtin_expect (ELFW(ST_TYPE) (sym->st_info) > STT_FUNC
-			      && ELFW(ST_TYPE) (sym->st_info) != STT_TLS, 0))
-	  /* Ignore all but STT_NOTYPE, STT_OBJECT and STT_FUNC
-	     entries (and STT_TLS if TLS is supported) since these
-	     are no code/data definitions.  */
-	  return NULL;
-
-	if (sym != ref && strcmp (strtab + sym->st_name, undef_name))
-	  /* Not the symbol we are looking for.  */
-	  return NULL;
-
-	const ElfW(Half) *verstab = map->l_versyms;
-	if (version != NULL)
-	  {
-	    if (__builtin_expect (verstab == NULL, 0))
-	      {
-		/* We need a versioned symbol but haven't found any.  If
-		   this is the object which is referenced in the verneed
-		   entry it is a bug in the library since a symbol must
-		   not simply disappear.
-
-		   It would also be a bug in the object since it means that
-		   the list of required versions is incomplete and so the
-		   tests in dl-version.c haven't found a problem.*/
-		assert (version->filename == NULL
-			|| ! _dl_name_match_p (version->filename, map));
-
-		/* Otherwise we accept the symbol.  */
-	      }
-	    else
-	      {
-		/* We can match the version information or use the
-		   default one if it is not hidden.  */
-		ElfW(Half) ndx = verstab[symidx] & 0x7fff;
-		if ((map->l_versions[ndx].hash != version->hash
-		     || strcmp (map->l_versions[ndx].name, version->name))
-		    && (version->hidden || map->l_versions[ndx].hash
-			|| (verstab[symidx] & 0x8000)))
-		  /* It's not the version we want.  */
-		  return NULL;
-	      }
-	  }
-	else
-	  {
-	    /* 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.
+			  map->l_name[0] ? map->l_name : rtld_progname);
 
-	       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)
-	      {
-		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;
+      symtab = (const void *) D_PTR (map, l_info[DT_SYMTAB]);
+      strtab = (const void *) D_PTR (map, l_info[DT_STRTAB]);
+      verstab = map->l_versyms;
 
-		    return NULL;
-		  }
-	      }
-	  }
+      /* Search the appropriate hash bucket in this object's symbol table
+	 for a definition for the same symbol name.  */
+      for (symidx = map->l_buckets[hash % map->l_nbuckets];
+	   symidx != STN_UNDEF;
+	   symidx = map->l_chain[symidx])
+	{
+	  sym = &symtab[symidx];
+
+	  assert (ELF_RTYPE_CLASS_PLT == 1);
+	  if ((sym->st_value == 0 /* No value.  */
+#ifdef USE_TLS
+	       && ELFW(ST_TYPE) (sym->st_info) != STT_TLS
+#endif
+	       )
+	      || (type_class & (sym->st_shndx == SHN_UNDEF)))
+	    continue;
+
+	  if (ELFW(ST_TYPE) (sym->st_info) > STT_FUNC
+#ifdef USE_TLS
+	      && ELFW(ST_TYPE) (sym->st_info) != STT_TLS
+#endif
+	      )
+	    /* Ignore all but STT_NOTYPE, STT_OBJECT and STT_FUNC
+	       entries (and STT_TLS if TLS is supported) since these
+	       are no code/data definitions.  */
+	    continue;
+
+	  if (sym != ref && strcmp (strtab + sym->st_name, undef_name))
+	    /* Not the symbol we are looking for.  */
+	    continue;
+
+	  if (version != NULL)
+	    {
+	      if (__builtin_expect (verstab == NULL, 0))
+		{
+		  /* We need a versioned symbol but haven't found any.  If
+		     this is the object which is referenced in the verneed
+		     entry it is a bug in the library since a symbol must
+		     not simply disappear.
+
+		     It would also be a bug in the object since it means that
+		     the list of required versions is incomplete and so the
+		     tests in dl-version.c haven't found a problem.*/
+		  assert (version->filename == NULL
+			  || ! _dl_name_match_p (version->filename, map));
+
+		  /* Otherwise we accept the symbol.  */
+		}
+	      else
+		{
+		  /* We can match the version information or use the
+		     default one if it is not hidden.  */
+		  ElfW(Half) ndx = verstab[symidx] & 0x7fff;
+		  if ((map->l_versions[ndx].hash != version->hash
+		       || strcmp (map->l_versions[ndx].name, version->name))
+		      && (version->hidden || map->l_versions[ndx].hash
+			  || (verstab[symidx] & 0x8000)))
+		    /* It's not the version we want.  */
+		    continue;
+		}
+	    }
+	  else
+	    {
+	      /* No specific version is selected.  There are two ways we
+		 can got here:
 
-	/* There cannot be another entry for this symbol so stop here.  */
-	return sym;
-      }
+		 - a binary which does not include versioning information
+		   is loaded
 
-      const ElfW(Sym) *sym;
-      const ElfW(Addr) *bitmask = map->l_gnu_bitmask;
-      if (__builtin_expect (bitmask != NULL, 1))
-	{
-	  ElfW(Addr) bitmask_word
-	    = bitmask[(new_hash / __ELF_NATIVE_CLASS)
-		      & map->l_gnu_bitmask_idxbits];
+		 - dlsym() instead of dlvsym() is used to get a symbol which
+		   might exist in more than one form
 
-	  unsigned int hashbit1 = new_hash & (__ELF_NATIVE_CLASS - 1);
-	  unsigned int hashbit2 = ((new_hash >> map->l_gnu_shift)
-				   & (__ELF_NATIVE_CLASS - 1));
+		 If the library does not provide symbol version
+		 information there is no problem at at: we simply use the
+		 symbol if it is defined.
 
-	  if (__builtin_expect ((bitmask_word >> hashbit1)
-				& (bitmask_word >> hashbit2) & 1, 0))
-	    {
-	      Elf32_Word bucket = map->l_gnu_buckets[new_hash
-						     % map->l_nbuckets];
-	      if (bucket != 0)
+		 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)
 		{
-		  const Elf32_Word *hasharr = &map->l_gnu_chain_zero[bucket];
+		  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;
 
-		  do
-		    if ((*hasharr & ~1u) == (new_hash & ~1u))
-		      {
-			symidx = hasharr - map->l_gnu_chain_zero;
-			sym = check_match (&symtab[symidx]);
-			if (sym != NULL)
-			  goto found_it;
-		      }
-		  while ((*hasharr++ & 1u) == 0);
+		      continue;
+		    }
 		}
 	    }
-	  /* No symbol found.  */
-	  symidx = SHN_UNDEF;
-	}
-      else
-	{
-	  if (*old_hash == 0xffffffff)
-	    *old_hash = _dl_elf_hash (undef_name);
 
-	  /* Use the old SysV-style hash table.  Search the appropriate
-	     hash bucket in this object's symbol table for a definition
-	     for the same symbol name.  */
-	  for (symidx = map->l_buckets[*old_hash % map->l_nbuckets];
-	       symidx != STN_UNDEF;
-	       symidx = map->l_chain[symidx])
-	    {
-	      sym = check_match (&symtab[symidx]);
-	      if (sym != NULL)
-		goto found_it;
-	    }
+	  /* There cannot be another entry for this symbol so stop here.  */
+	  goto found_it;
 	}
 
       /* If we have seen exactly one versioned symbol while we are
@@ -239,7 +181,7 @@ do_lookup_x (const char *undef_name, uint_fast32_t new_hash,
 		  if (! result->s)
 		    {
 		      result->s = sym;
-		      result->m = (struct link_map *) map;
+		      result->m = map;
 		    }
 		  break;
 		}
@@ -247,7 +189,7 @@ do_lookup_x (const char *undef_name, uint_fast32_t new_hash,
 	    case STB_GLOBAL:
 	      /* Global definition.  Just what we need.  */
 	      result->s = sym;
-	      result->m = (struct link_map *) map;
+	      result->m = map;
 	      return 1;
 	    default:
 	      /* Local symbols are ignored.  */
@@ -266,3 +208,7 @@ do_lookup_x (const char *undef_name, uint_fast32_t new_hash,
   /* We have not found anything until now.  */
   return 0;
 }
+
+#undef FCT
+#undef ARG
+#undef VERSIONED