PATCH: Support mixing COMDAT and linkonce
H. J. Lu
hjl@lucon.org
Fri May 14 21:07:00 GMT 2004
When there are mixed COMDAT and linkonce inputs, linker doesn't handle
them gracefully:
http://sources.redhat.com/bugzilla/show_bug.cgi?id=161
This patch tries to fix it.
H.J.
-------------- next part --------------
2004-05-14 H.J. Lu <hongjiu.lu@intel.com>
* elflink.c (find_group_section): New function.
(elf_merge_comdat_linkonce): Likewise. Combine .gnu.linkonce
section with a comdat group.
(_bfd_elf_merge_symbol): Use it.
--- bfd/elflink.c.linkonce 2004-05-11 13:34:11.000000000 -0700
+++ bfd/elflink.c 2004-05-14 13:48:44.000000000 -0700
@@ -674,6 +674,106 @@ _bfd_elf_link_renumber_dynsyms (bfd *out
return elf_hash_table (info)->dynsymcount = dynsymcount;
}
+/* Rerurn TRUE if SEC is the group section which contains the section
+ INF. */
+
+static bfd_boolean
+find_group_section (bfd *abfd ATTRIBUTE_UNUSED, asection *sec,
+ void *inf)
+{
+ asection *elt;
+
+ if (elf_section_type (sec) != SHT_GROUP)
+ return FALSE;
+
+ elt = elf_next_in_group (sec);
+ while (elt != NULL)
+ {
+ if (elt == (asection *) inf)
+ return TRUE;
+ elt = elf_next_in_group (sec);
+ }
+
+ return FALSE;
+}
+
+/* Combine .gnu.linkonce section with a comdat group. */
+
+static void
+elf_merge_comdat_linkonce (bfd *newbfd, bfd *oldbfd,
+ asection *newsec, asection *oldsec,
+ bfd_boolean *skip)
+{
+ /* Skip symbols in discarded section. */
+ if (elf_discarded_section (newsec))
+ {
+ *skip = TRUE;
+ return;
+ }
+
+ /* Make sure that we have a perfect match. */
+ if ((newsec->flags & (SEC_LINK_ONCE | SEC_LINK_DUPLICATES_DISCARD))
+ != (oldsec->flags & (SEC_LINK_ONCE | SEC_LINK_DUPLICATES_DISCARD))
+ && (((newsec->flags & (SEC_LINK_ONCE | SEC_LINK_DUPLICATES_DISCARD))
+ && elf_next_in_group (oldsec) == oldsec)
+ || ((oldsec->flags
+ & (SEC_LINK_ONCE | SEC_LINK_DUPLICATES_DISCARD))
+ && elf_next_in_group (newsec) == newsec))
+ && newsec->_raw_size == oldsec->_raw_size
+ && elf_section_type (newsec) == elf_section_type (oldsec)
+ && ((elf_section_flags (newsec) & ~SHF_GROUP)
+ == (elf_section_flags (oldsec) & ~SHF_GROUP)))
+ {
+ bfd_byte *newcontents;
+ bfd_byte *oldcontents;
+ bfd_boolean comdat = elf_section_flags (newsec) & SHF_GROUP;
+ asection *group;
+
+ /* Find the group section. */
+ group = bfd_sections_find_if (comdat ? newbfd : oldbfd,
+ find_group_section,
+ (void *) (comdat ? newsec : oldsec));
+ if (!group)
+ {
+ (*_bfd_error_handler)
+ (_("%s: warning: group member `%s' [%d] doesn't belong to any group"),
+ bfd_archive_filename (comdat ? newbfd : oldbfd),
+ comdat ? newsec->name : oldsec->name,
+ (comdat ? newsec->index : oldsec->index) + 1);
+ return;
+ }
+
+ /* Check if it is a comdat group. */
+ if ((group->flags
+ & (SEC_LINK_ONCE | SEC_LINK_DUPLICATES_DISCARD))
+ != (SEC_LINK_ONCE | SEC_LINK_DUPLICATES_DISCARD))
+ return;
+
+ newcontents = bfd_malloc (newsec->_raw_size);
+ oldcontents = bfd_malloc (newsec->_raw_size);
+ if (newcontents
+ && oldcontents
+ && bfd_get_section_contents (newbfd, newsec, newcontents,
+ 0, newsec->_raw_size)
+ && bfd_get_section_contents (oldbfd, oldsec, oldcontents,
+ 0, newsec->_raw_size)
+ && memcmp (newcontents, oldcontents, newsec->_raw_size) == 0)
+ {
+ newsec->output_section = bfd_abs_section_ptr;
+ *skip = TRUE;
+
+ /* Discard the comdat group section if needed. */
+ if (comdat)
+ group->output_section = bfd_abs_section_ptr;
+ }
+
+ if (newcontents)
+ free (newcontents);
+ if (oldcontents)
+ free (oldcontents);
+ }
+}
+
/* This function is called when we want to define a new symbol. It
handles the various cases which arise when we find a definition in
a dynamic object, or when there is already a definition in a
@@ -1163,6 +1263,22 @@ _bfd_elf_merge_symbol (bfd *abfd,
h->verinfo.vertree = NULL;
}
+ /* Handle the special case of a new non-weak definition in a
+ relocatable file merging with an old non-weak definition from
+ another relocatable file where only one of them is in a
+ .gnu.linkonce section and the other is in a section group by
+ itself. In this case, we discard the new definition along with
+ its section if 2 sections are the same. */
+ if (ELF_ST_TYPE (sym->st_info) == h->type
+ && newdef
+ && !newdyn
+ && !newweak
+ && olddef
+ && !olddyn
+ && !oldweak)
+ elf_merge_comdat_linkonce (abfd, oldbfd, sec, h->root.u.def.section,
+ skip);
+
if (flip != NULL)
{
/* Handle the case where we had a versioned symbol in a dynamic
More information about the Binutils
mailing list