This is the mail archive of the binutils@sources.redhat.com 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]

Fix an --as-needed linker problem


This is a fix for http://gcc.gnu.org/bugzilla/show_bug.cgi?id=17608
Quoting from the PR:

When linking we use:
-lgcc --as-needed -lgcc_s --no-as-needed -lc_p -lgcc --as-needed -lgcc_s
--no-as-needed.

During the first scan of libgcc_s.so, the linker finds no reason to mark
libgcc_s.so as needed, because no symbols in libgcc_s.so are referenced
at that point.  After linking libc_p.a, the second scan of libgcc_s.so
does find referenced symbols.  However, the linker sees that these
symbols have already been defined, thus the "new" definitions found in
the second scan of libgcc_s.so aren't used.  (If a symbol is defined in
two shared libs, the one from the lib first encountered by the linker is
used.  As far as the linker is concerned the first libgcc_s.so is a
different shared lib from the second libgcc_s.so).  Thus the linker
decides that the second libgcc_s.so isn't needed, and so doesn't emit a
DT_NEEDED tag for libgcc_s.so.

With older glibc ld.so, this resulted in segfaults.  Current ld.so
complains with 
 Inconsistency detected by ld.so: dl-version.c: 230: _dl_check_map_versions:
Assertion `needed != ((void *)0)' failed!

	* elflink.c (_bfd_elf_merge_symbol): Treat old definitions from
	as-needed dynamic libs as undefined.
	(elf_link_add_object_symbols): Remove DYN_AS_NEEDED from as-needed
	libs when finding they are needed.

Index: bfd/elflink.c
===================================================================
RCS file: /cvs/src/src/bfd/elflink.c,v
retrieving revision 1.121
diff -u -p -r1.121 elflink.c
--- bfd/elflink.c	10 Dec 2004 14:04:58 -0000	1.121
+++ bfd/elflink.c	22 Dec 2004 03:42:50 -0000
@@ -719,7 +719,7 @@ _bfd_elf_merge_symbol (bfd *abfd,
   int bind;
   bfd *oldbfd;
   bfd_boolean newdyn, olddyn, olddef, newdef, newdyncommon, olddyncommon;
-  bfd_boolean newweak, oldweak;
+  bfd_boolean newweak, oldweak, old_asneeded;
 
   *skip = FALSE;
   *override = FALSE;
@@ -849,6 +849,14 @@ _bfd_elf_merge_symbol (bfd *abfd,
   else
     olddef = TRUE;
 
+  /* If the old definition came from an as-needed dynamic library which
+     wasn't found to be needed, treat the sym as undefined.  */
+  old_asneeded = FALSE;
+  if (newdyn
+      && olddyn
+      && (elf_dyn_lib_class (oldbfd) & DYN_AS_NEEDED) != 0)
+    old_asneeded = TRUE;
+
   /* Check TLS symbol.  */
   if ((ELF_ST_TYPE (sym->st_info) == STT_TLS || h->type == STT_TLS)
       && ELF_ST_TYPE (sym->st_info) != h->type)
@@ -1051,6 +1059,7 @@ _bfd_elf_merge_symbol (bfd *abfd,
 
   if (olddyn
       && olddef
+      && !old_asneeded
       && h->root.type == bfd_link_hash_defined
       && h->def_dynamic
       && (h->root.u.def.section->flags & SEC_ALLOC) != 0
@@ -1102,7 +1111,7 @@ _bfd_elf_merge_symbol (bfd *abfd,
 
   if (newdyn
       && newdef
-      && (olddef
+      && ((olddef && !old_asneeded)
 	  || (h->root.type == bfd_link_hash_common
 	      && (newweak
 		  || ELF_ST_TYPE (sym->st_info) == STT_FUNC))))
@@ -1152,7 +1161,7 @@ _bfd_elf_merge_symbol (bfd *abfd,
      symbol is a function or is weak.  */
 
   flip = NULL;
-  if (! newdyn
+  if ((!newdyn || old_asneeded)
       && (newdef
 	  || (bfd_is_com_section (sec)
 	      && (oldweak
@@ -3937,6 +3946,8 @@ elf_link_add_object_symbols (bfd *abfd, 
 		  goto error_free_vers;
 		}
 
+	      elf_dyn_lib_class (abfd) &= ~DYN_AS_NEEDED;
+
 	      add_needed = TRUE;
 	      ret = elf_add_dt_needed_tag (info, soname, add_needed);
 	      if (ret < 0)

-- 
Alan Modra
IBM OzLabs - Linux Technology Centre


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