about summary refs log tree commit diff
path: root/elf/dl-open.c
diff options
context:
space:
mode:
Diffstat (limited to 'elf/dl-open.c')
-rw-r--r--elf/dl-open.c139
1 files changed, 37 insertions, 102 deletions
diff --git a/elf/dl-open.c b/elf/dl-open.c
index 32e7caac7f..c997521126 100644
--- a/elf/dl-open.c
+++ b/elf/dl-open.c
@@ -1,5 +1,5 @@
 /* Load a shared object at runtime, relocate it, and run its initializer.
-   Copyright (C) 1996-2004, 2005, 2006, 2007 Free Software Foundation, Inc.
+   Copyright (C) 1996-2004, 2005, 2006 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
@@ -32,7 +32,6 @@
 #include <bp-sym.h>
 #include <caller.h>
 #include <sysdep-cancel.h>
-#include <tls.h>
 
 #include <dl-dst.h>
 
@@ -98,17 +97,17 @@ add_to_global (struct link_map *new)
      in an realloc() call.  Therefore we allocate a completely new
      array the first time we have to add something to the locale scope.  */
 
-  struct link_namespaces *ns = &GL(dl_ns)[new->l_ns];
-  if (ns->_ns_global_scope_alloc == 0)
+  if (GL(dl_ns)[new->l_ns]._ns_global_scope_alloc == 0)
     {
       /* This is the first dynamic object given global scope.  */
-      ns->_ns_global_scope_alloc
-	= ns->_ns_main_searchlist->r_nlist + to_add + 8;
+      GL(dl_ns)[new->l_ns]._ns_global_scope_alloc
+	= GL(dl_ns)[new->l_ns]._ns_main_searchlist->r_nlist + to_add + 8;
       new_global = (struct link_map **)
-	malloc (ns->_ns_global_scope_alloc * sizeof (struct link_map *));
+	malloc (GL(dl_ns)[new->l_ns]._ns_global_scope_alloc
+		* sizeof (struct link_map *));
       if (new_global == NULL)
 	{
-	  ns->_ns_global_scope_alloc = 0;
+	  GL(dl_ns)[new->l_ns]._ns_global_scope_alloc = 0;
 	nomem:
 	  _dl_signal_error (ENOMEM, new->l_libname->name, NULL,
 			    N_("cannot extend global scope"));
@@ -116,39 +115,29 @@ add_to_global (struct link_map *new)
 	}
 
       /* Copy over the old entries.  */
-      ns->_ns_main_searchlist->r_list
-	= memcpy (new_global, ns->_ns_main_searchlist->r_list,
-		  (ns->_ns_main_searchlist->r_nlist
+      GL(dl_ns)[new->l_ns]._ns_main_searchlist->r_list
+	= memcpy (new_global,
+		  GL(dl_ns)[new->l_ns]._ns_main_searchlist->r_list,
+		  (GL(dl_ns)[new->l_ns]._ns_main_searchlist->r_nlist
 		   * sizeof (struct link_map *)));
     }
-  else if (ns->_ns_main_searchlist->r_nlist + to_add
-	   > ns->_ns_global_scope_alloc)
+  else if (GL(dl_ns)[new->l_ns]._ns_main_searchlist->r_nlist + to_add
+	   > GL(dl_ns)[new->l_ns]._ns_global_scope_alloc)
     {
       /* We have to extend the existing array of link maps in the
 	 main map.  */
-      struct link_map **old_global
-	= GL(dl_ns)[new->l_ns]._ns_main_searchlist->r_list;
-      size_t new_nalloc = ((ns->_ns_global_scope_alloc + to_add) * 2);
-
       new_global = (struct link_map **)
-	malloc (new_nalloc * sizeof (struct link_map *));
+	realloc (GL(dl_ns)[new->l_ns]._ns_main_searchlist->r_list,
+		 ((GL(dl_ns)[new->l_ns]._ns_global_scope_alloc + to_add + 8)
+		  * sizeof (struct link_map *)));
       if (new_global == NULL)
 	goto nomem;
 
-      memcpy (new_global, old_global,
-	      ns->_ns_global_scope_alloc * sizeof (struct link_map *));
-
-      ns->_ns_global_scope_alloc = new_nalloc;
-      ns->_ns_main_searchlist->r_list = new_global;
-
-      if (!RTLD_SINGLE_THREAD_P)
-	THREAD_GSCOPE_WAIT ();
-
-      free (old_global);
+      GL(dl_ns)[new->l_ns]._ns_global_scope_alloc += to_add + 8;
+      GL(dl_ns)[new->l_ns]._ns_main_searchlist->r_list = new_global;
     }
 
   /* Now add the new entries.  */
-  unsigned int new_nlist = ns->_ns_main_searchlist->r_nlist;
   for (cnt = 0; cnt < new->l_searchlist.r_nlist; ++cnt)
     {
       struct link_map *map = new->l_searchlist.r_list[cnt];
@@ -156,49 +145,15 @@ add_to_global (struct link_map *new)
       if (map->l_global == 0)
 	{
 	  map->l_global = 1;
-	  ns->_ns_main_searchlist->r_list[new_nlist++] = map;
+	  GL(dl_ns)[new->l_ns]._ns_main_searchlist->r_list[GL(dl_ns)[new->l_ns]._ns_main_searchlist->r_nlist]
+	    = map;
+	  ++GL(dl_ns)[new->l_ns]._ns_main_searchlist->r_nlist;
 	}
     }
-  atomic_write_barrier ();
-  ns->_ns_main_searchlist->r_nlist = new_nlist;
 
   return 0;
 }
 
-int
-_dl_scope_free (struct r_scope_elem **old)
-{
-  struct dl_scope_free_list *fsl;
-#define DL_SCOPE_FREE_LIST_SIZE (sizeof (fsl->list) / sizeof (fsl->list[0]))
-
-  if (RTLD_SINGLE_THREAD_P)
-    free (old);
-  else if ((fsl = GL(dl_scope_free_list)) == NULL)
-    {
-      GL(dl_scope_free_list) = fsl = malloc (sizeof (*fsl));
-      if (fsl == NULL)
-	{
-	  THREAD_GSCOPE_WAIT ();
-	  free (old);
-	  return 1;
-	}
-      else
-	{
-	  fsl->list[0] = old;
-	  fsl->count = 1;
-	}
-    }
-  else if (fsl->count < DL_SCOPE_FREE_LIST_SIZE)
-    fsl->list[fsl->count++] = old;
-  else
-    {
-      THREAD_GSCOPE_WAIT ();
-      while (fsl->count > 0)
-	free (fsl->list[--fsl->count]);
-      return 1;
-    }
-  return 0;
-}
 
 static void
 dl_open_worker (void *a)
@@ -206,12 +161,10 @@ dl_open_worker (void *a)
   struct dl_open_args *args = a;
   const char *file = args->file;
   int mode = args->mode;
-  struct link_map *new;
+  struct link_map *new, *l;
   int lazy;
   unsigned int i;
-#ifdef USE_TLS
   bool any_tls = false;
-#endif
   struct link_map *call_map = NULL;
 
   /* Check whether _dl_open() has been called from a valid DSO.  */
@@ -233,14 +186,13 @@ dl_open_worker (void *a)
 	 By default we assume this is the main application.  */
       call_map = GL(dl_ns)[LM_ID_BASE]._ns_loaded;
 
-      struct link_map *l;
       for (Lmid_t ns = 0; ns < DL_NNS; ++ns)
 	for (l = GL(dl_ns)[ns]._ns_loaded; l != NULL; l = l->l_next)
 	  if (caller_dlopen >= (const void *) l->l_map_start
-	      && caller_dlopen < (const void *) l->l_map_end
-	      && (l->l_contiguous
-		  || _dl_addr_inside_object (l, (ElfW(Addr)) caller_dlopen)))
+	      && caller_dlopen < (const void *) l->l_map_end)
 	    {
+	      /* There must be exactly one DSO for the range of the virtual
+		 memory.  Otherwise something is really broken.  */
 	      assert (ns == l->l_ns);
 	      call_map = l;
 	      goto found_caller;
@@ -373,7 +325,7 @@ dl_open_worker (void *a)
   /* Relocate the objects loaded.  We do this in reverse order so that copy
      relocs of earlier objects overwrite the data written by later objects.  */
 
-  struct link_map *l = new;
+  l = new;
   while (l->l_next)
     l = l->l_next;
   while (1)
@@ -465,10 +417,17 @@ dl_open_worker (void *a)
 	      memcpy (newp, imap->l_scope, cnt * sizeof (imap->l_scope[0]));
 	      struct r_scope_elem **old = imap->l_scope;
 
-	      imap->l_scope = newp;
+	      if (RTLD_SINGLE_THREAD_P)
+		imap->l_scope = newp;
+	      else
+		{
+		  __rtld_mrlock_change (imap->l_scope_lock);
+		  imap->l_scope = newp;
+		  __rtld_mrlock_done (imap->l_scope_lock);
+		}
 
 	      if (old != imap->l_scope_mem)
-		_dl_scope_free (old);
+		free (old);
 
 	      imap->l_scope_max = new_size;
 	    }
@@ -480,7 +439,6 @@ dl_open_worker (void *a)
 	  atomic_write_barrier ();
 	  imap->l_scope[cnt] = &new->l_searchlist;
 	}
-#if USE_TLS
       /* Only add TLS memory if this object is loaded now and
 	 therefore is not yet initialized.  */
       else if (! imap->l_init_called
@@ -495,11 +453,11 @@ dl_open_worker (void *a)
 	  if (imap->l_need_tls_init)
 	    {
 	      imap->l_need_tls_init = 0;
-# ifdef SHARED
+#ifdef SHARED
 	      /* Update the slot information data for at least the
 		 generation of the DSO we are allocating data for.  */
 	      _dl_update_slotinfo (imap->l_tls_modid);
-# endif
+#endif
 
 	      GL(dl_init_static_tls) (imap);
 	      assert (imap->l_need_tls_init == 0);
@@ -508,15 +466,12 @@ dl_open_worker (void *a)
 	  /* We have to bump the generation counter.  */
 	  any_tls = true;
 	}
-#endif
     }
 
-#if USE_TLS
   /* Bump the generation number if necessary.  */
   if (any_tls && __builtin_expect (++GL(dl_tls_generation) == 0, 0))
     _dl_fatal_printf (N_("\
 TLS generation counter wrapped!  Please report this."));
-#endif
 
   /* Run the initializer functions of new objects.  */
   _dl_init (new, args->argc, args->argv, args->env);
@@ -613,7 +568,6 @@ no more namespaces available for dlmopen()"));
 	 state if relocation failed, for example.  */
       if (args.map)
 	{
-#ifdef USE_TLS
 	  /* Maybe some of the modules which were loaded use TLS.
 	     Since it will be removed in the following _dl_close call
 	     we have to mark the dtv array as having gaps to fill the
@@ -623,7 +577,6 @@ no more namespaces available for dlmopen()"));
 	     up.  */
 	  if ((mode & __RTLD_AUDIT) == 0)
 	    GL(dl_tls_dtv_gaps) = true;
-#endif
 
 	  _dl_close_worker (args.map);
 	}
@@ -697,21 +650,3 @@ show_scope (struct link_map *new)
     }
 }
 #endif
-
-#ifdef IS_IN_rtld
-/* Return non-zero if ADDR lies within one of L's segments.  */
-int
-internal_function
-_dl_addr_inside_object (struct link_map *l, const ElfW(Addr) addr)
-{
-  int n = l->l_phnum;
-  const ElfW(Addr) reladdr = addr - l->l_addr;
-
-  while (--n >= 0)
-    if (l->l_phdr[n].p_type == PT_LOAD
-	&& reladdr - l->l_phdr[n].p_vaddr >= 0
-	&& reladdr - l->l_phdr[n].p_vaddr < l->l_phdr[n].p_memsz)
-      return 1;
-  return 0;
-}
-#endif