public inbox for libc-hacker@sourceware.org
 help / color / mirror / Atom feed
* [PATCH] Fix handling of STB_GNU_UNIQUE in LD_TRACE_PRELINKING
@ 2010-03-23 10:34 Jakub Jelinek
  2010-03-24 17:16 ` Ulrich Drepper
  0 siblings, 1 reply; 2+ messages in thread
From: Jakub Jelinek @ 2010-03-23 10:34 UTC (permalink / raw)
  To: Ulrich Drepper; +Cc: Glibc hackers, Michael Matz

[-- Attachment #1: Type: text/plain, Size: 1556 bytes --]

Hi!

The STB_GNU_UNIQUE hash table breaks computation of conflicts
during LD_TRACE_PRELINKING, thus prelink doesn't add relocations into
.gnu.conflict section and programs might misbehave at runtime when
prelinked.

The problem is that to detect a conflict, _dl_debug_bindings in addition
to the normal lookup does also a lookup in undef_map->l_local_scope[0],
and if the lookup has different result, reports a conflict, otherwise
just non-conflicting lookup.  But, as STB_GNU_UNIQUE hash table for
such symbols always gives the first lookup that entered the hash table,
conflicts are never reported for STB_GNU_UNIQUE lookups.

Attached are two possible patches.  The second, shorter one, is all that is
needed currently (I believe).  The difference between the patches is in
handling libraries with DT_SYMBOLIC and STB_GNU_UNIQUE symbols.  Apparently
current GNU ld if there is a relocation against STB_GNU_UNIQUE symbol
defined in the library itself, doesn't emit any relocation and resolves at
link time (possibly through a relative relocation).  Is that what we want
though?  Then the STB_GNU_UNIQUE symbols aren't really unique...

If we want to change ld(1) behavior to always emit dynamic relocations
against STB_GNU_UNIQUE symbols defined in the library even
for -Wl,-Bsymbolic, then I'm afraid we need something like the former patch.
It can be pessimizing, reporting a conflict even when there is really none,
but I don't see how else to do this cheaply.  And, -Wl,-Bsymbolic is very
rare I believe, so I don't care about that too much.

	Jakub

[-- Attachment #2: S --]
[-- Type: text/plain, Size: 5469 bytes --]

2010-03-23  Jakub Jelinek  <jakub@redhat.com>

	* elf/dl-lookup.c (do_lookup_x): If tab->entries is NULL,
	but tab->size != 0, just unlock and goto success, without
	allocating anything or entering anything into the hash table.
	(_dl_debug_bindings): Temporarily set tab->entries to NULL
	around do_lookup_x in undef_map->l_local_scope[0].  If
	undef_map->l_symbolic_in_local_scope, lookup also in
	symbolic_searchlist of following libraries in l_local_scope
	that have DT_SYMBOLIC set.
	* elf/dl-deps.c (_dl_map_object_deps): Compute
	l_symbolic_in_local_scope.
	* include/link.h (struct link_map): Add l_symbolic_in_local_scope
	bitfield.

--- libc/elf/dl-deps.c.jj	2009-05-16 19:23:29.000000000 +0200
+++ libc/elf/dl-deps.c	2010-03-23 09:24:57.000000000 +0100
@@ -1,5 +1,5 @@
 /* Load the dependencies of a mapped object.
-   Copyright (C) 1996-2003, 2004, 2005, 2006, 2007
+   Copyright (C) 1996-2003, 2004, 2005, 2006, 2007, 2010
    Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
@@ -554,7 +554,12 @@ Filters not supported with LD_TRACE_PREL
 	  cnt = _dl_build_local_scope (l_initfini, l);
 	  assert (cnt <= nlist);
 	  for (j = 0; j < cnt; j++)
-	    l_initfini[j]->l_reserved = 0;
+	    {
+	      l_initfini[j]->l_reserved = 0;
+	      if (j && __builtin_expect (l_initfini[j]->l_info[DT_SYMBOLIC]
+					 != NULL, 0))
+		l->l_symbolic_in_local_scope = true;
+	    }
 
 	  l->l_local_scope[0] =
 	    (struct r_scope_elem *) malloc (sizeof (struct r_scope_elem)
--- libc/elf/dl-lookup.c.jj	2009-12-16 00:10:37.000000000 +0100
+++ libc/elf/dl-lookup.c	2010-03-23 10:00:35.000000000 +0100
@@ -1,5 +1,6 @@
 /* Look up a symbol in the loaded objects.
-   Copyright (C) 1995-2005, 2006, 2007, 2009 Free Software Foundation, Inc.
+   Copyright (C) 1995-2005, 2006, 2007, 2009, 2010
+   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
@@ -414,6 +415,20 @@ do_lookup_x (const char *undef_name, uin
 		  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 (__builtin_expect (tab->size, 0))
+		    {
+		      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);
@@ -917,13 +932,48 @@ _dl_debug_bindings (const char *undef_na
 	{
 	  const uint_fast32_t new_hash = dl_new_hash (undef_name);
 	  unsigned long int old_hash = 0xffffffff;
+	  struct unique_sym *saved_entries
+	    = GL(dl_ns)[LM_ID_BASE]._ns_unique_sym_table.entries;
 
+	  GL(dl_ns)[LM_ID_BASE]._ns_unique_sym_table.entries = NULL;
 	  do_lookup_x (undef_name, new_hash, &old_hash, *ref, &val,
 		       undef_map->l_local_scope[0], 0, version, 0, NULL,
 		       type_class, undef_map);
-
 	  if (val.s != value->s || val.m != value->m)
 	    conflict = 1;
+	  else if (__builtin_expect (undef_map->l_symbolic_in_local_scope, 0)
+		   && val.s
+		   && __builtin_expect (ELFW(ST_BIND) (val.s->st_info),
+					STB_GLOBAL) == STB_GNU_UNIQUE)
+	    {
+	      /* If it is STB_GNU_UNIQUE and undef_map's l_local_scope
+		 contains any DT_SYMBOLIC libraries, unfortunately there
+		 can be conflicts even if the above is equal.  As symbol
+		 resolution goes from the last library to the first and
+		 if a STB_GNU_UNIQUE symbol is found in some late DT_SYMBOLIC
+		 library, it would be the one that is looked up.  */
+	      struct sym_val val2 = { NULL, NULL };
+	      size_t n;
+	      struct r_scope_elem *scope = undef_map->l_local_scope[0];
+
+	      for (n = 0; n < scope->r_nlist; n++)
+		if (scope->r_list[n] == val.m)
+		  break;
+
+	      for (n++; n < scope->r_nlist; n++)
+		if (scope->r_list[n]->l_info[DT_SYMBOLIC] != NULL
+		    && do_lookup_x (undef_name, new_hash, &old_hash, *ref,
+				    &val2,
+				    &scope->r_list[n]->l_symbolic_searchlist,
+				    0, version, 0, NULL, type_class,
+				    undef_map) > 0)
+		  {
+		    conflict = 1;
+		    val = val2;
+		    break;
+		  }
+	    }
+	  GL(dl_ns)[LM_ID_BASE]._ns_unique_sym_table.entries = saved_entries;
 	}
 
       if (value->s)
--- libc/include/link.h.jj	2009-12-16 00:10:37.000000000 +0100
+++ libc/include/link.h	2010-03-23 09:27:18.000000000 +0100
@@ -1,6 +1,6 @@
 /* Data structure for communication from the run-time dynamic linker for
    loaded ELF shared objects.
-   Copyright (C) 1995-2006, 2007, 2009 Free Software Foundation, Inc.
+   Copyright (C) 1995-2006, 2007, 2009, 2010 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
@@ -188,6 +188,10 @@ struct link_map
     unsigned int l_contiguous:1; /* Nonzero if inter-segment holes are
 				    mprotected or if no holes are present at
 				    all.  */
+    unsigned int l_symbolic_in_local_scope:1; /* Nonzero if l_local_scope
+						 during LD_TRACE_PRELINKING=1
+						 contains any DT_SYMBOLIC
+						 libraries.  */
 
     /* Collected information about own RPATH directories.  */
     struct r_search_path_struct l_rpath_dirs;

[-- Attachment #3: S2 --]
[-- Type: text/plain, Size: 2194 bytes --]

2010-03-23  Jakub Jelinek  <jakub@redhat.com>

	* elf/dl-lookup.c (do_lookup_x): If tab->entries is NULL,
	but tab->size != 0, just unlock and goto success, without
	allocating anything or entering anything into the hash table.
	(_dl_debug_bindings): Temporarily set tab->entries to NULL
	around do_lookup_x in undef_map->l_local_scope[0].

--- libc/elf/dl-lookup.c.jj	2009-12-16 00:10:37.000000000 +0100
+++ libc/elf/dl-lookup.c	2010-03-23 11:03:45.850560036 +0100
@@ -1,5 +1,6 @@
 /* Look up a symbol in the loaded objects.
-   Copyright (C) 1995-2005, 2006, 2007, 2009 Free Software Foundation, Inc.
+   Copyright (C) 1995-2005, 2006, 2007, 2009, 2010
+   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
@@ -414,6 +415,20 @@ do_lookup_x (const char *undef_name, uin
 		  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 (__builtin_expect (tab->size, 0))
+		    {
+		      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);
@@ -917,13 +932,17 @@ _dl_debug_bindings (const char *undef_na
 	{
 	  const uint_fast32_t new_hash = dl_new_hash (undef_name);
 	  unsigned long int old_hash = 0xffffffff;
+	  struct unique_sym *saved_entries
+	    = GL(dl_ns)[LM_ID_BASE]._ns_unique_sym_table.entries;
 
+	  GL(dl_ns)[LM_ID_BASE]._ns_unique_sym_table.entries = NULL;
 	  do_lookup_x (undef_name, new_hash, &old_hash, *ref, &val,
 		       undef_map->l_local_scope[0], 0, version, 0, NULL,
 		       type_class, undef_map);
 
 	  if (val.s != value->s || val.m != value->m)
 	    conflict = 1;
+	  GL(dl_ns)[LM_ID_BASE]._ns_unique_sym_table.entries = saved_entries;
 	}
 
       if (value->s)

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2010-03-24 17:16 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-03-23 10:34 [PATCH] Fix handling of STB_GNU_UNIQUE in LD_TRACE_PRELINKING Jakub Jelinek
2010-03-24 17:16 ` Ulrich Drepper

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).