about summary refs log tree commit diff
path: root/elf/dl-lookup.c
diff options
context:
space:
mode:
Diffstat (limited to 'elf/dl-lookup.c')
-rw-r--r--elf/dl-lookup.c304
1 files changed, 159 insertions, 145 deletions
diff --git a/elf/dl-lookup.c b/elf/dl-lookup.c
index be6f76faa8..896e1d2771 100644
--- a/elf/dl-lookup.c
+++ b/elf/dl-lookup.c
@@ -186,6 +186,162 @@ check_match (const char *const undef_name,
   return sym;
 }
 
+/* Utility function for do_lookup_x. Lookup an STB_GNU_UNIQUE symbol
+   in the unique symbol table, creating a new entry if necessary.
+   Return the matching symbol in RESULT.  */
+static void
+do_lookup_unique (const char *undef_name, uint_fast32_t new_hash,
+		  const struct link_map *map, struct sym_val *result,
+		  int type_class, const ElfW(Sym) *sym, const char *strtab,
+		  const ElfW(Sym) *ref, const struct link_map *undef_map)
+{
+  /* We have to determine whether we already found a
+     symbol with this name before.  If not then we have to
+     add it to the search table.  If we already found a
+     definition we have to use it.  */
+  void enter (struct unique_sym *table, size_t size,
+	      unsigned int hash, const char *name,
+	      const ElfW(Sym) *sym, const struct link_map *map)
+  {
+    size_t idx = hash % size;
+    size_t hash2 = 1 + hash % (size - 2);
+    while (table[idx].name != NULL)
+      {
+	idx += hash2;
+	if (idx >= size)
+	  idx -= size;
+      }
+
+    table[idx].hashval = hash;
+    table[idx].name = name;
+    table[idx].sym = sym;
+    table[idx].map = map;
+  }
+
+  struct unique_sym_table *tab
+    = &GL(dl_ns)[map->l_ns]._ns_unique_sym_table;
+
+  __rtld_lock_lock_recursive (tab->lock);
+
+  struct unique_sym *entries = tab->entries;
+  size_t size = tab->size;
+  if (entries != NULL)
+    {
+      size_t idx = new_hash % size;
+      size_t hash2 = 1 + new_hash % (size - 2);
+      while (1)
+	{
+	  if (entries[idx].hashval == new_hash
+	      && strcmp (entries[idx].name, undef_name) == 0)
+	    {
+	      if ((type_class & ELF_RTYPE_CLASS_COPY) != 0)
+		{
+		  /* We possibly have to initialize the central
+		     copy from the copy addressed through the
+		     relocation.  */
+		  result->s = sym;
+		  result->m = (struct link_map *) map;
+		}
+	      else
+		{
+		  result->s = entries[idx].sym;
+		  result->m = (struct link_map *) entries[idx].map;
+		}
+	      __rtld_lock_unlock_recursive (tab->lock);
+	      return;
+	    }
+
+	  if (entries[idx].name == NULL)
+	    break;
+
+	  idx += hash2;
+	  if (idx >= size)
+	    idx -= size;
+	}
+
+      if (size * 3 <= tab->n_elements * 4)
+	{
+	  /* Expand the table.  */
+#ifdef RTLD_CHECK_FOREIGN_CALL
+	  /* This must not happen during runtime relocations.  */
+	  assert (!RTLD_CHECK_FOREIGN_CALL);
+#endif
+	  size_t newsize = _dl_higher_prime_number (size + 1);
+	  struct unique_sym *newentries
+	    = calloc (sizeof (struct unique_sym), newsize);
+	  if (newentries == NULL)
+	    {
+	    nomem:
+	      __rtld_lock_unlock_recursive (tab->lock);
+	      _dl_fatal_printf ("out of memory\n");
+	    }
+
+	  for (idx = 0; idx < size; ++idx)
+	    if (entries[idx].name != NULL)
+	      enter (newentries, newsize, entries[idx].hashval,
+		     entries[idx].name, entries[idx].sym,
+		     entries[idx].map);
+
+	  tab->free (entries);
+	  tab->size = newsize;
+	  size = newsize;
+	  entries = tab->entries = newentries;
+	  tab->free = free;
+	}
+    }
+  else
+    {
+#ifdef RTLD_CHECK_FOREIGN_CALL
+      /* This must not happen during runtime relocations.  */
+      assert (!RTLD_CHECK_FOREIGN_CALL);
+#endif
+
+#ifdef SHARED
+      /* If tab->entries is NULL, but tab->size is not, it means
+	 this is the second, conflict finding, lookup for
+	 LD_TRACE_PRELINKING in _dl_debug_bindings.  Don't
+	 allocate anything and don't enter anything into the
+	 hash table.  */
+      if (__glibc_unlikely (tab->size))
+	{
+	  assert (GLRO(dl_debug_mask) & DL_DEBUG_PRELINK);
+	  goto success;
+	}
+#endif
+
+#define INITIAL_NUNIQUE_SYM_TABLE 31
+      size = INITIAL_NUNIQUE_SYM_TABLE;
+      entries = calloc (sizeof (struct unique_sym), size);
+      if (entries == NULL)
+	goto nomem;
+
+      tab->entries = entries;
+      tab->size = size;
+      tab->free = free;
+    }
+
+  if ((type_class & ELF_RTYPE_CLASS_COPY) != 0)
+    enter (entries, size, new_hash, strtab + sym->st_name, ref,
+	   undef_map);
+  else
+    {
+      enter (entries, size, new_hash, strtab + sym->st_name, sym, map);
+
+      if (map->l_type == lt_loaded)
+	/* Make sure we don't unload this object by
+	   setting the appropriate flag.  */
+	((struct link_map *) map)->l_flags_1 |= DF_1_NODELETE;
+    }
+  ++tab->n_elements;
+
+#ifdef SHARED
+ success:
+#endif
+  __rtld_lock_unlock_recursive (tab->lock);
+
+  result->s = sym;
+  result->m = (struct link_map *) map;
+}
 
 /* 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
@@ -323,157 +479,15 @@ do_lookup_x (const char *undef_name, uint_fast32_t new_hash,
 		}
 	      /* FALLTHROUGH */
 	    case STB_GLOBAL:
-	    success:
 	      /* Global definition.  Just what we need.  */
 	      result->s = sym;
 	      result->m = (struct link_map *) map;
 	      return 1;
 
 	    case STB_GNU_UNIQUE:;
-	      /* We have to determine whether we already found a
-		 symbol with this name before.  If not then we have to
-		 add it to the search table.  If we already found a
-		 definition we have to use it.  */
-	      void enter (struct unique_sym *table, size_t size,
-			  unsigned int hash, const char *name,
-			  const ElfW(Sym) *sym, const struct link_map *map)
-	      {
-		size_t idx = hash % size;
-		size_t hash2 = 1 + hash % (size - 2);
-		while (table[idx].name != NULL)
-		  {
-		    idx += hash2;
-		    if (idx >= size)
-		      idx -= size;
-		  }
-
-		table[idx].hashval = hash;
-		table[idx].name = name;
-		table[idx].sym = sym;
-		table[idx].map = map;
-	      }
-
-	      struct unique_sym_table *tab
-		= &GL(dl_ns)[map->l_ns]._ns_unique_sym_table;
-
-	      __rtld_lock_lock_recursive (tab->lock);
-
-	      struct unique_sym *entries = tab->entries;
-	      size_t size = tab->size;
-	      if (entries != NULL)
-		{
-		  size_t idx = new_hash % size;
-		  size_t hash2 = 1 + new_hash % (size - 2);
-		  while (1)
-		    {
-		      if (entries[idx].hashval == new_hash
-			  && strcmp (entries[idx].name, undef_name) == 0)
-			{
-			  if ((type_class & ELF_RTYPE_CLASS_COPY) != 0)
-			    {
-			      /* We possibly have to initialize the central
-				 copy from the copy addressed through the
-				 relocation.  */
-			      result->s = sym;
-			      result->m = (struct link_map *) map;
-			    }
-			  else
-			    {
-			      result->s = entries[idx].sym;
-			      result->m = (struct link_map *) entries[idx].map;
-			    }
-			  __rtld_lock_unlock_recursive (tab->lock);
-			  return 1;
-			}
-
-		      if (entries[idx].name == NULL)
-			break;
-
-		      idx += hash2;
-		      if (idx >= size)
-			idx -= size;
-		    }
-
-		  if (size * 3 <= tab->n_elements * 4)
-		    {
-		      /* Expand the table.  */
-#ifdef RTLD_CHECK_FOREIGN_CALL
-		      /* This must not happen during runtime relocations.  */
-		      assert (!RTLD_CHECK_FOREIGN_CALL);
-#endif
-		      size_t newsize = _dl_higher_prime_number (size + 1);
-		      struct unique_sym *newentries
-			= calloc (sizeof (struct unique_sym), newsize);
-		      if (newentries == NULL)
-			{
-			nomem:
-			  __rtld_lock_unlock_recursive (tab->lock);
-			  _dl_fatal_printf ("out of memory\n");
-			}
-
-		      for (idx = 0; idx < size; ++idx)
-			if (entries[idx].name != NULL)
-			  enter (newentries, newsize, entries[idx].hashval,
-				 entries[idx].name, entries[idx].sym,
-				 entries[idx].map);
-
-		      tab->free (entries);
-		      tab->size = newsize;
-		      size = newsize;
-		      entries = tab->entries = newentries;
-		      tab->free = free;
-		    }
-		}
-	      else
-		{
-#ifdef RTLD_CHECK_FOREIGN_CALL
-		  /* This must not happen during runtime relocations.  */
-		  assert (!RTLD_CHECK_FOREIGN_CALL);
-#endif
-
-#ifdef SHARED
-		  /* If tab->entries is NULL, but tab->size is not, it means
-		     this is the second, conflict finding, lookup for
-		     LD_TRACE_PRELINKING in _dl_debug_bindings.  Don't
-		     allocate anything and don't enter anything into the
-		     hash table.  */
-		  if (__glibc_unlikely (tab->size))
-		    {
-		      assert (GLRO(dl_debug_mask) & DL_DEBUG_PRELINK);
-		      __rtld_lock_unlock_recursive (tab->lock);
-		      goto success;
-		    }
-#endif
-
-#define INITIAL_NUNIQUE_SYM_TABLE 31
-		  size = INITIAL_NUNIQUE_SYM_TABLE;
-		  entries = calloc (sizeof (struct unique_sym), size);
-		  if (entries == NULL)
-		    goto nomem;
-
-		  tab->entries = entries;
-		  tab->size = size;
-		  tab->free = free;
-		}
-
-	      if ((type_class & ELF_RTYPE_CLASS_COPY) != 0)
-		enter (entries, size, new_hash, strtab + sym->st_name, ref,
-		       undef_map);
-	      else
-		{
-		  enter (entries, size, new_hash, strtab + sym->st_name, sym,
-			 map);
-
-		  if (map->l_type == lt_loaded)
-		    /* Make sure we don't unload this object by
-		       setting the appropriate flag.  */
-		    ((struct link_map *) map)->l_flags_1 |= DF_1_NODELETE;
-		}
-	      ++tab->n_elements;
-
-	      __rtld_lock_unlock_recursive (tab->lock);
-
-	      goto success;
+	      do_lookup_unique (undef_name, new_hash, map, result, type_class,
+				sym, strtab, ref, undef_map);
+	      return 1;
 
 	    default:
 	      /* Local symbols are ignored.  */