2004-05-14 H.J. Lu * 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