about summary refs log tree commit diff
path: root/elf
diff options
context:
space:
mode:
authorJakub Jelinek <jakub@redhat.com>2007-07-07 17:15:07 +0000
committerJakub Jelinek <jakub@redhat.com>2007-07-07 17:15:07 +0000
commit542ac2393c1ca0d070fa9cce57ca2b2e562f72cc (patch)
treed17a88450a5ec0811ab35c82f003bde8a3f4a329 /elf
parent9542710f1329c25f861435d7b96d08991e52bd6d (diff)
downloadglibc-542ac2393c1ca0d070fa9cce57ca2b2e562f72cc.tar.gz
glibc-542ac2393c1ca0d070fa9cce57ca2b2e562f72cc.tar.xz
glibc-542ac2393c1ca0d070fa9cce57ca2b2e562f72cc.zip
2007-06-09 Ulrich Drepper <drepper@redhat.com>
	* elf/do-lookup.h (do_lookup_x): Read r_nlist before r_list and
	make sure gcc doesn't mess around with this.

2007-06-08  Ulrich Drepper  <drepper@redhat.com>

	* elf/dl-lookup.c (_dl_lookup_symbol_x): Remove use of r_nlist.

2007-06-08  Jakub Jelinek  <jakub@redhat.com>

	* elf/dl-close.c (_dl_close_worker): Remove all to be removed
	libraries from the global scope at once and call THREAD_GSCOPE_WAIT

2007-05-18  Ulrich Drepper  <drepper@redhat.com>

	* elf/dl-close.c (_dl_close_worker): When removing object from
	global scope, wait for all lookups to finish afterwards.
	* elf/dl-open.c (add_to_global): When global scope array must
	grow, allocate a new one and free old array only after all
	lookups finish.
	* elf/dl-runtime.c (_dl_fixup): Protect using global scope.
	(_dl_lookup_symbol_x): Likewise.
	* elf/dl-support.c: Define _dl_wait_lookup_done.
	* sysdeps/generic/ldsodefs.h (struct rtld_global): Add
	_dl_wait_lookup_done.

nptl/
2007-05-28  Jakub Jelinek  <jakub@redhat.com>

	* sysdeps/i386/tls.h (THREAD_GSCOPE_RESET_FLAG): Use explicit
	insn suffix.
	(THREAD_GSCOPE_GET_FLAG): Remove.
	* sysdeps/x86_64/tls.h (THREAD_GSCOPE_GET_FLAG): Remove.
	* allocatestack.c (__wait_lookup_done): Revert 2007-05-24
	changes.
	* sysdeps/powerpc/tls.h (tcbhead_t): Remove gscope_flag.
	(THREAD_GSCOPE_GET_FLAG): Remove.
	(THREAD_GSCOPE_RESET_FLAG): Use THREAD_SELF->header.gscope_flag
	instead of THREAD_GSCOPE_GET_FLAG.
	(THREAD_GSCOPE_SET_FLAG): Likewise.  Add atomic_write_barrier after
	it.
	* sysdeps/s390/tls.h (THREAD_GSCOPE_FLAG_UNUSED,
	THREAD_GSCOPE_FLAG_USED, THREAD_GSCOPE_FLAG_WAIT,
	THREAD_GSCOPE_RESET_FLAG, THREAD_GSCOPE_SET_FLAG,
	THREAD_GSCOPE_WAIT): Define.
	* sysdeps/sparc/tls.h (THREAD_GSCOPE_FLAG_UNUSED,
	THREAD_GSCOPE_FLAG_USED, THREAD_GSCOPE_FLAG_WAIT,
	THREAD_GSCOPE_RESET_FLAG, THREAD_GSCOPE_SET_FLAG,
	THREAD_GSCOPE_WAIT): Define.
	* sysdeps/sh/tls.h (THREAD_GSCOPE_FLAG_UNUSED,
	THREAD_GSCOPE_FLAG_USED, THREAD_GSCOPE_FLAG_WAIT,
	THREAD_GSCOPE_RESET_FLAG, THREAD_GSCOPE_SET_FLAG,
	THREAD_GSCOPE_WAIT): Define.
	* sysdeps/ia64/tls.h (THREAD_GSCOPE_FLAG_UNUSED,
	THREAD_GSCOPE_FLAG_USED, THREAD_GSCOPE_FLAG_WAIT,
	THREAD_GSCOPE_RESET_FLAG, THREAD_GSCOPE_SET_FLAG,
	THREAD_GSCOPE_WAIT): Define.

2007-05-24  Richard Henderson  <rth@redhat.com>

	* descr.h (struct pthread): Add header.gscope_flag.
	* sysdeps/alpha/tls.h (THREAD_GSCOPE_FLAG_UNUSED,
	THREAD_GSCOPE_FLAG_USED, THREAD_GSCOPE_FLAG_WAIT,
	THREAD_GSCOPE_RESET_FLAG, THREAD_GSCOPE_SET_FLAG,
	THREAD_GSCOPE_WAIT): Define.

2007-05-26  Ulrich Drepper  <drepper@redhat.com>

	* allocatestack.c: Revert last change.
	* init.c: Likewise.
	* sysdeps/i386/tls.h: Likewise.
	* sysdeps/x86_64/tls.h: Likewise.

2007-05-24  Jakub Jelinek  <jakub@redhat.com>

	* sysdeps/powerpc/tls.h (tcbhead_t): Add gscope_flag.
	(THREAD_GSCOPE_FLAG_UNUSED, THREAD_GSCOPE_FLAG_USED,
	THREAD_GSCOPE_FLAG_WAIT): Define.
	(THREAD_GSCOPE_GET_FLAG, THREAD_GSCOPE_SET_FLAG,
	THREAD_GSCOPE_RESET_FLAG, THREAD_GSCOPE_WAIT): Define.
	* sysdeps/i386/tls.h (THREAD_GSCOPE_WAIT): Don't use
	PTR_DEMANGLE.
	(THREAD_GSCOPE_GET_FLAG): Define.
	* sysdeps/x86_64/tls.h (THREAD_GSCOPE_GET_FLAG): Define.
	* allocatestack.c (__wait_lookup_done): Use THREAD_GSCOPE_GET_FLAG
	instead of ->header.gscope_flag directly.

2007-05-21  Ulrich Drepper  <drepper@redhat.com>

	* sysdeps/pthread/pthread-functions.h (struct pthread_functions):
	Remove ptr_wait_lookup_done again.
	* init.c (pthread_functions): Don't add .ptr_wait_lookup_done here.
	(__pthread_initialize_minimal_internal): Initialize
	_dl_wait_lookup_done pointer in _rtld_global directly.
	* sysdeps/unix/sysv/linux/libc_pthread_init.c (__libc_pthread_init):
	Remove code to code _dl_wait_lookup_done.
	* sysdeps/x86_64/tls.h (THREAD_GSCOPE_WAIT): The pointer is not
	encrypted for now.

2007-05-19  Ulrich Drepper  <drepper@redhat.com>

	* allocatestack.c (__wait_lookup_done): New function.
	* sysdeps/pthread/pthread-functions.h (struct pthread_functions):
	Add ptr_wait_lookup_done.
	* init.c (pthread_functions): Initialize .ptr_wait_lookup_done.
	* pthreadP.h: Declare __wait_lookup_done.
	* sysdeps/i386/tls.h (tcbhead_t): Add gscope_flag.
	Define macros to implement reference handling of global scope.
	* sysdeps/x86_64/tls.h: Likewise.
	* sysdeps/unix/sysv/linux/libc_pthread_init.c (__libc_pthread_init):
	Initialize GL(dl_wait_lookup_done).
Diffstat (limited to 'elf')
-rw-r--r--elf/dl-close.c49
-rw-r--r--elf/dl-lookup.c10
-rw-r--r--elf/dl-open.c23
-rw-r--r--elf/dl-runtime.c32
-rw-r--r--elf/dl-support.c5
-rw-r--r--elf/do-lookup.h9
6 files changed, 88 insertions, 40 deletions
diff --git a/elf/dl-close.c b/elf/dl-close.c
index e0fe26ad02..2c2b3b6163 100644
--- a/elf/dl-close.c
+++ b/elf/dl-close.c
@@ -31,6 +31,7 @@
 #include <sys/types.h>
 #include <sys/mman.h>
 #include <sysdep-cancel.h>
+#include <tls.h>
 
 
 /* Type of the constructor functions.  */
@@ -228,6 +229,7 @@ _dl_close_worker (struct link_map *map)
   bool do_audit = GLRO(dl_naudit) > 0 && !ns->_ns_loaded->l_auditing;
 #endif
   bool unload_any = false;
+  unsigned int unload_global = 0;
   unsigned int first_loaded = ~0;
   for (unsigned int i = 0; i < nloaded; ++i)
     {
@@ -292,6 +294,9 @@ _dl_close_worker (struct link_map *map)
 	  /* We indeed have an object to remove.  */
 	  unload_any = true;
 
+	  if (imap->l_global)
+	    ++unload_global;
+
 	  /* Remember where the first dynamically loaded object is.  */
 	  if (i < first_loaded)
 	    first_loaded = i;
@@ -457,6 +462,34 @@ _dl_close_worker (struct link_map *map)
   r->r_state = RT_DELETE;
   _dl_debug_state ();
 
+  if (unload_global)
+    {
+      /* Some objects are in the global scope list.  Remove them.  */
+      struct r_scope_elem *ns_msl = ns->_ns_main_searchlist;
+      unsigned int i;
+      unsigned int j = 0;
+      unsigned int cnt = ns_msl->r_nlist;
+
+      while (cnt > 0 && ns_msl->r_list[cnt - 1]->l_removed)
+	--cnt;
+
+      if (cnt + unload_global == ns_msl->r_nlist)
+	/* Speed up removing most recently added objects.  */
+	j = cnt;
+      else
+ 	for (i = 0; i < cnt; i++)
+	  if (ns_msl->r_list[i]->l_removed == 0)
+	    {
+	      if (i != j)
+		ns_msl->r_list[j] = ns_msl->r_list[i];
+	      j++;
+	    }
+      ns_msl->r_nlist = j;
+
+      if (!RTLD_SINGLE_THREAD_P)
+	THREAD_GSCOPE_WAIT ();
+    }
+
   size_t tls_free_start;
   size_t tls_free_end;
   tls_free_start = tls_free_end = NO_TLS_OFFSET;
@@ -472,22 +505,6 @@ _dl_close_worker (struct link_map *map)
 
 	  /* That was the last reference, and this was a dlopen-loaded
 	     object.  We can unmap it.  */
-	  if (__builtin_expect (imap->l_global, 0))
-	    {
-	      /* This object is in the global scope list.  Remove it.  */
-	      struct r_scope_elem *ns_msl = ns->_ns_main_searchlist;
-	      unsigned int cnt = ns_msl->r_nlist;
-
-	      do
-		--cnt;
-	      while (ns_msl->r_list[cnt] != imap);
-
-	      /* The object was already correctly registered.  */
-	      while (++cnt < ns_msl->r_nlist)
-		ns_msl->r_list[cnt - 1] = ns_msl->r_list[cnt];
-
-	      --ns_msl->r_nlist;
-	    }
 
 	  /* Remove the object from the dtv slotinfo array if it uses TLS.  */
 	  if (__builtin_expect (imap->l_tls_blocksize > 0, 0))
diff --git a/elf/dl-lookup.c b/elf/dl-lookup.c
index a6a958419f..dc1b865bc7 100644
--- a/elf/dl-lookup.c
+++ b/elf/dl-lookup.c
@@ -244,13 +244,9 @@ _dl_lookup_symbol_x (const char *undef_name, struct link_map *undef_map,
 
   size_t i = 0;
   if (__builtin_expect (skip_map != NULL, 0))
-    {
-      /* Search the relevant loaded objects for a definition.  */
-      while ((*scope)->r_list[i] != skip_map)
-	++i;
-
-      assert (i < (*scope)->r_nlist);
-    }
+    /* Search the relevant loaded objects for a definition.  */
+    while ((*scope)->r_list[i] != skip_map)
+      ++i;
 
   /* Search the relevant loaded objects for a definition.  */
   for (size_t start = i; *scope != NULL; start = 0, ++scope)
diff --git a/elf/dl-open.c b/elf/dl-open.c
index 0afe94b5bf..a043cf61b6 100644
--- a/elf/dl-open.c
+++ b/elf/dl-open.c
@@ -32,6 +32,7 @@
 #include <bp-sym.h>
 #include <caller.h>
 #include <sysdep-cancel.h>
+#include <tls.h>
 
 #include <dl-dst.h>
 
@@ -125,19 +126,25 @@ add_to_global (struct link_map *new)
     {
       /* We have to extend the existing array of link maps in the
 	 main map.  */
-      size_t new_size = ns->_ns_global_scope_alloc;
-      if (new_size >= 256 && new_size > to_add + 8)
-	new_size *= 2;
-      else
-	new_size += to_add + 8;
+      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 **)
-	realloc (ns->_ns_main_searchlist->r_list,
-		 new_size * sizeof (struct link_map *));
+	malloc (new_nalloc * sizeof (struct link_map *));
       if (new_global == NULL)
 	goto nomem;
 
-      ns->_ns_global_scope_alloc = new_size;
+      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);
     }
 
   /* Now add the new entries.  */
diff --git a/elf/dl-runtime.c b/elf/dl-runtime.c
index 9ecf62b436..6add5e4fff 100644
--- a/elf/dl-runtime.c
+++ b/elf/dl-runtime.c
@@ -26,6 +26,8 @@
 #include <ldsodefs.h>
 #include <sysdep-cancel.h>
 #include "dynamic-link.h"
+#include <tls.h>
+
 
 #if (!defined ELF_MACHINE_NO_RELA && !defined ELF_MACHINE_PLT_REL) \
     || ELF_MACHINE_NO_REL
@@ -97,10 +99,15 @@ _dl_fixup (
 	 not necessary for objects which cannot be unloaded or when
 	 we are not using any threads (yet).  */
       int flags = DL_LOOKUP_ADD_DEPENDENCY;
-      if (l->l_type == lt_loaded && !RTLD_SINGLE_THREAD_P)
+      if (!RTLD_SINGLE_THREAD_P)
 	{
-	  __rtld_mrlock_lock (l->l_scope_lock);
-	  flags |= DL_LOOKUP_SCOPE_LOCK;
+	  THREAD_GSCOPE_SET_FLAG ();
+
+	  if (l->l_type == lt_loaded)
+	    {
+	      __rtld_mrlock_lock (l->l_scope_lock);
+	      flags |= DL_LOOKUP_SCOPE_LOCK;
+	    }
 	}
 
       result = _dl_lookup_symbol_x (strtab + sym->st_name, l, &sym, l->l_scope,
@@ -109,6 +116,10 @@ _dl_fixup (
       if ((flags & DL_LOOKUP_SCOPE_LOCK) != 0)
 	__rtld_mrlock_unlock (l->l_scope_lock);
 
+      /* We are done with the global scope.  */
+      if (!RTLD_SINGLE_THREAD_P)
+	THREAD_GSCOPE_RESET_FLAG ();
+
       /* Currently result contains the base load address (or link map)
 	 of the object that defines sym.  Now add in the symbol
 	 offset.  */
@@ -191,10 +202,15 @@ _dl_profile_fixup (
 	     not necessary for objects which cannot be unloaded or when
 	     we are not using any threads (yet).  */
 	  int flags = DL_LOOKUP_ADD_DEPENDENCY;
-	  if (l->l_type == lt_loaded && !RTLD_SINGLE_THREAD_P)
+	  if (!RTLD_SINGLE_THREAD_P)
 	    {
-	      __rtld_mrlock_lock (l->l_scope_lock);
-	      flags |= DL_LOOKUP_SCOPE_LOCK;
+	      THREAD_GSCOPE_SET_FLAG ();
+
+	      if (l->l_type == lt_loaded)
+		{
+		  __rtld_mrlock_lock (l->l_scope_lock);
+		  flags |= DL_LOOKUP_SCOPE_LOCK;
+		}
 	    }
 
 	  result = _dl_lookup_symbol_x (strtab + refsym->st_name, l,
@@ -204,6 +220,10 @@ _dl_profile_fixup (
 	  if ((flags & DL_LOOKUP_SCOPE_LOCK) != 0)
 	    __rtld_mrlock_unlock (l->l_scope_lock);
 
+	  /* We are done with the global scope.  */
+	  if (!RTLD_SINGLE_THREAD_P)
+	    THREAD_GSCOPE_RESET_FLAG ();
+
 	  /* Currently result contains the base load address (or link map)
 	     of the object that defines sym.  Now add in the symbol
 	     offset.  */
diff --git a/elf/dl-support.c b/elf/dl-support.c
index c7479dc639..cecb603ae6 100644
--- a/elf/dl-support.c
+++ b/elf/dl-support.c
@@ -1,5 +1,5 @@
 /* Support for dynamic linking code in static libc.
-   Copyright (C) 1996-2005, 2006 Free Software Foundation, Inc.
+   Copyright (C) 1996-2005, 2006, 2007 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
@@ -132,6 +132,9 @@ int (*_dl_make_stack_executable_hook) (void **) internal_function
   = _dl_make_stack_executable;
 
 
+/* Function in libpthread to wait for termination of lookups.  */
+void (*_dl_wait_lookup_done) (void);
+
 #ifdef NEED_DL_SYSINFO
 /* Needed for improved syscall handling on at least x86/Linux.  */
 uintptr_t _dl_sysinfo = DL_SYSINFO_DEFAULT;
diff --git a/elf/do-lookup.h b/elf/do-lookup.h
index 2585d83005..ab9a510ba1 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 Free Software Foundation, Inc.
+   Copyright (C) 1995-2004, 2005, 2006, 2007 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
@@ -29,8 +29,13 @@ do_lookup_x (const char *undef_name, uint_fast32_t new_hash,
 	     const struct r_found_version *const version, int flags,
 	     struct link_map *skip, int type_class)
 {
-  struct link_map **list = scope->r_list;
   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;
 
   do
     {