From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 26023 invoked by alias); 23 Mar 2010 10:34:13 -0000 Received: (qmail 26004 invoked by uid 22791); 23 Mar 2010 10:34:13 -0000 X-SWARE-Spam-Status: No, hits=-1.6 required=5.0 tests=AWL,BAYES_00,KAM_STOCKGEN X-Spam-Check-By: sourceware.org Received: from sunsite.ms.mff.cuni.cz (HELO sunsite.mff.cuni.cz) (195.113.15.26) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Tue, 23 Mar 2010 10:34:08 +0000 Received: from sunsite.mff.cuni.cz (localhost [127.0.0.1]) by sunsite.mff.cuni.cz (8.14.3/8.14.3) with ESMTP id o2NAXng6021619; Tue, 23 Mar 2010 11:33:49 +0100 Received: (from jj@localhost) by sunsite.mff.cuni.cz (8.14.3/8.14.3/Submit) id o2NAXmcr021618; Tue, 23 Mar 2010 11:33:48 +0100 Date: Tue, 23 Mar 2010 10:34:00 -0000 From: Jakub Jelinek To: Ulrich Drepper Cc: Glibc hackers , Michael Matz Subject: [PATCH] Fix handling of STB_GNU_UNIQUE in LD_TRACE_PRELINKING Message-ID: <20100323103348.GE3601@sunsite.ms.mff.cuni.cz> Reply-To: Jakub Jelinek MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="XsQoSWH+UP9D9v3l" Content-Disposition: inline User-Agent: Mutt/1.5.19 (2009-01-05) Mailing-List: contact libc-hacker-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: libc-hacker-owner@sourceware.org X-SW-Source: 2010-03/txt/msg00010.txt.bz2 --XsQoSWH+UP9D9v3l Content-Type: text/plain; charset=us-ascii Content-Disposition: inline Content-length: 1556 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 --XsQoSWH+UP9D9v3l Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename=S Content-length: 5469 2010-03-23 Jakub Jelinek * 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; --XsQoSWH+UP9D9v3l Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename=S2 Content-length: 2194 2010-03-23 Jakub Jelinek * 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) --XsQoSWH+UP9D9v3l--