This is the mail archive of the
binutils@sources.redhat.com
mailing list for the binutils project.
Fix an --as-needed linker problem
- From: Alan Modra <amodra at bigpond dot net dot au>
- To: binutils at sources dot redhat dot com
- Date: Wed, 22 Dec 2004 14:25:42 +1030
- Subject: 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