This is the mail archive of the binutils@sourceware.org mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: PATCH: PR ld/15146: Reference from dummy plugin symbol isn't removed


The LTO 9 failure is due to _bfd_elf_strtab_emit finding refcount
non-zero for some libstdc++ symbols:
"... assertion fail /src/binutils-virgin/bfd/elf-strtab.c:251".

What's happening is that libstdc++.so is being added more than once.
The first time around a number of symbols are made dynamic, occupying
space in dynstr strtab.  libstdc++ is found not needed, so the symbol
table is restored and the dynstr strtab refcounts set to zero, but the
symbols are not removed from strtab->array.  A number of shared libs
later dynstr strtab has grown, and libstdc++.so loaded again on ld's
second pass through input objects for lto.  This time the same symbols
are made dynamic, but their strtab array entry is already present, so
they get an index below the current size of the strtab.
_bfd_elf_strtab_clear_refs() therefore doesn't clear the entries.  The
problem is that the symbols also become indirect, with dynindx and
dynstr_index on the versioned symbol.  The versioned symbol is new, so
the loops over the old hash table doesn't see it.  Leaving the strtab
refcount unadjusted.  Fixed by ensuring that new symbols will always
make the strtab grow.

The really annoying thing about this bug is that I wrote
http://sourceware.org/ml/binutils/2013-01/msg00165.html this way
first, then for some reason thought it was safe to keep the strtab
array entries around.

	PR ld/12549
	* elf-bfd.h (_bfd_elf_strtab_clear_refs): Delete.
	(_bfd_elf_strtab_clear_all_refs): Declare.
	(_bfd_elf_strtab_resize): Declare.
	* elf-strtab.c (_bfd_elf_strtab_clear_refs): Delete.
	(_bfd_elf_strtab_clear_all_refs): New function.
	(_bfd_elf_strtab_resize): Likewise.
	* elflink.c (elf_link_add_object_symbols): Use _bfd_elf_strtab_resize.

Index: bfd/elf-bfd.h
===================================================================
RCS file: /cvs/src/src/bfd/elf-bfd.h,v
retrieving revision 1.360
diff -u -p -r1.360 elf-bfd.h
--- bfd/elf-bfd.h	18 Feb 2013 02:56:58 -0000	1.360
+++ bfd/elf-bfd.h	18 Feb 2013 09:41:51 -0000
@@ -1927,10 +1944,10 @@ extern void _bfd_elf_strtab_delref
   (struct elf_strtab_hash *, bfd_size_type);
 extern unsigned int _bfd_elf_strtab_refcount
   (struct elf_strtab_hash *, bfd_size_type);
-extern void _bfd_elf_strtab_clear_refs
+extern void _bfd_elf_strtab_clear_all_refs
+  (struct elf_strtab_hash *tab);
+extern void _bfd_elf_strtab_restore_size
   (struct elf_strtab_hash *, bfd_size_type);
-#define _bfd_elf_strtab_clear_all_refs(tab) \
-  do { _bfd_elf_strtab_clear_refs (tab, 1); } while (0)
 extern bfd_size_type _bfd_elf_strtab_size
   (struct elf_strtab_hash *);
 extern bfd_size_type _bfd_elf_strtab_offset
Index: bfd/elf-strtab.c
===================================================================
RCS file: /cvs/src/src/bfd/elf-strtab.c,v
retrieving revision 1.18
diff -u -p -r1.18 elf-strtab.c
--- bfd/elf-strtab.c	11 Jan 2013 14:09:58 -0000	1.18
+++ bfd/elf-strtab.c	18 Feb 2013 09:41:51 -0000
@@ -208,10 +208,32 @@ _bfd_elf_strtab_refcount (struct elf_str
 }
 
 void
-_bfd_elf_strtab_clear_refs (struct elf_strtab_hash *tab, bfd_size_type idx)
+_bfd_elf_strtab_clear_all_refs (struct elf_strtab_hash *tab)
 {
-  while (idx < tab->size)
-    tab->array[idx++]->refcount = 0;
+  bfd_size_type idx;
+
+  for (idx = 1; idx < tab->size; idx++)
+    tab->array[idx]->refcount = 0;
+}
+
+/* Downsizes strtab.  Entries from IDX up to the current size are
+   removed from the array.  */
+void
+_bfd_elf_strtab_restore_size (struct elf_strtab_hash *tab, bfd_size_type idx)
+{
+  bfd_size_type curr_size = tab->size;
+
+  BFD_ASSERT (tab->sec_size == 0);
+  BFD_ASSERT (idx <= curr_size);
+  tab->size = idx;
+  for (; idx < curr_size; ++idx)
+    {
+      /* We don't remove entries from the hash table, just set their
+	 REFCOUNT to zero.  Setting LEN zero will result in the size
+	 growing if the entry is added again.  See _bfd_elf_strtab_add.  */
+      tab->array[idx]->refcount = 0;
+      tab->array[idx]->len = 0;
+    }
 }
 
 bfd_size_type
Index: bfd/elflink.c
===================================================================
RCS file: /cvs/src/src/bfd/elflink.c,v
retrieving revision 1.469
diff -u -p -r1.469 elflink.c
--- bfd/elflink.c	16 Feb 2013 17:54:37 -0000	1.469
+++ bfd/elflink.c	18 Feb 2013 09:41:53 -0000
@@ -4554,7 +4554,7 @@ error_free_dyn:
       memcpy (sym_hash, old_hash, hashsize);
       htab->root.undefs = old_undefs;
       htab->root.undefs_tail = old_undefs_tail;
-      _bfd_elf_strtab_clear_refs (htab->dynstr, old_dynstr_size);
+      _bfd_elf_strtab_restore_size (htab->dynstr, old_dynstr_size);
       for (i = 0; i < htab->root.table.size; i++)
 	{
 	  struct bfd_hash_entry *p;

-- 
Alan Modra
Australia Development Lab, IBM


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]