diff options
Diffstat (limited to 'bfd/elflink.c')
-rw-r--r-- | bfd/elflink.c | 371 |
1 files changed, 103 insertions, 268 deletions
diff --git a/bfd/elflink.c b/bfd/elflink.c index 53765b6..528f705 100644 --- a/bfd/elflink.c +++ b/bfd/elflink.c @@ -12502,208 +12502,84 @@ bfd_elf_discard_info (bfd *output_bfd, struct bfd_link_info *info) return ret; } -/* For a SHT_GROUP section, return the group signature. For other - sections, return the normal section name. */ - -static const char * -section_signature (asection *sec) -{ - if ((sec->flags & SEC_GROUP) != 0 - && elf_next_in_group (sec) != NULL - && elf_group_name (elf_next_in_group (sec)) != NULL) - return elf_group_name (elf_next_in_group (sec)); - return sec->name; -} - bfd_boolean _bfd_elf_section_already_linked (bfd *abfd, - struct already_linked *linked, + asection *sec, struct bfd_link_info *info) { flagword flags; - const char *name, *p; + const char *name, *key; struct bfd_section_already_linked *l; struct bfd_section_already_linked_hash_entry *already_linked_list; - asection *sec, *l_sec; - bfd_boolean matched; - - p = name = linked->comdat_key; - if (name) - { - sec = NULL; - flags = SEC_GROUP | SEC_LINK_ONCE | SEC_LINK_DUPLICATES_DISCARD; - } - else - { - sec = linked->u.sec; - if (sec->output_section == bfd_abs_section_ptr) - return FALSE; - flags = sec->flags; - - /* Return if it isn't a linkonce section. A comdat group section - also has SEC_LINK_ONCE set. */ - if ((flags & SEC_LINK_ONCE) == 0) - return FALSE; - - /* Don't put group member sections on our list of already linked - sections. They are handled as a group via their group section. - */ - if (elf_sec_group (sec) != NULL) - return FALSE; - - /* FIXME: When doing a relocatable link, we may have trouble - copying relocations in other sections that refer to local symbols - in the section being discarded. Those relocations will have to - be converted somehow; as of this writing I'm not sure that any of - the backends handle that correctly. + if (sec->output_section == bfd_abs_section_ptr) + return FALSE; - It is tempting to instead not discard link once sections when - doing a relocatable link (technically, they should be discarded - whenever we are building constructors). However, that fails, - because the linker winds up combining all the link once sections - into a single large link once section, which defeats the purpose - of having link once sections in the first place. + flags = sec->flags; - Also, not merging link once sections in a relocatable link - causes trouble for MIPS ELF, which relies on link once semantics - to handle the .reginfo section correctly. */ + /* Return if it isn't a linkonce section. A comdat group section + also has SEC_LINK_ONCE set. */ + if ((flags & SEC_LINK_ONCE) == 0) + return FALSE; - name = section_signature (sec); + /* Don't put group member sections on our list of already linked + sections. They are handled as a group via their group section. */ + if (elf_sec_group (sec) != NULL) + return FALSE; + /* For a SHT_GROUP section, use the group signature as the key. */ + name = sec->name; + if ((flags & SEC_GROUP) != 0 + && elf_next_in_group (sec) != NULL + && elf_group_name (elf_next_in_group (sec)) != NULL) + key = elf_group_name (elf_next_in_group (sec)); + else + { + /* Otherwise we should have a .gnu.linkonce.<type>.<key> section. */ if (CONST_STRNEQ (name, ".gnu.linkonce.") - && ((p = strchr (name + sizeof (".gnu.linkonce.") - 1, '.')) - != NULL)) - p++; + && (key = strchr (name + sizeof (".gnu.linkonce.") - 1, '.')) != NULL) + key++; else - p = name; + /* Must be a user linkonce section that doesn't follow gcc's + naming convention. In this case we won't be matching + single member groups. */ + key = name; } - already_linked_list = bfd_section_already_linked_table_lookup (p); + already_linked_list = bfd_section_already_linked_table_lookup (key); for (l = already_linked_list->entry; l != NULL; l = l->next) { - flagword l_flags; - bfd *l_owner; - const char *l_name = l->linked.comdat_key; - if (l_name) - { - l_sec = NULL; - l_owner = l->linked.u.abfd; - l_flags = (SEC_GROUP - | SEC_LINK_ONCE - | SEC_LINK_DUPLICATES_DISCARD); - } - else - { - l_sec = l->linked.u.sec; - l_owner = l_sec->owner; - l_flags = l_sec->flags; - l_name = section_signature (l_sec); - } - /* We may have 2 different types of sections on the list: group - sections and linkonce sections. Match like sections. */ - if ((flags & SEC_GROUP) == (l_flags & SEC_GROUP) - && strcmp (name, l_name) == 0) + sections with a signature of <key> (<key> is some string), + and linkonce sections named .gnu.linkonce.<type>.<key>. + Match like sections. LTO plugin sections are an exception. + They are always named .gnu.linkonce.t.<key> and match either + type of section. */ + if (((flags & SEC_GROUP) == (l->sec->flags & SEC_GROUP) + && ((flags & SEC_GROUP) != 0 + || strcmp (name, l->sec->name) == 0)) + || (l->sec->owner->flags & BFD_PLUGIN) != 0) { /* The section has already been linked. See if we should issue a warning. */ - switch (flags & SEC_LINK_DUPLICATES) - { - default: - abort (); - - case SEC_LINK_DUPLICATES_DISCARD: - /* If we found an LTO IR match for this comdat group on - the first pass, replace it with the LTO output on the - second pass. We can't simply choose real object - files over IR because the first pass may contain a - mix of LTO and normal objects and we must keep the - first match, be it IR or real. */ - if (info->loading_lto_outputs - && (l_owner->flags & BFD_PLUGIN) != 0) - { - l->linked = *linked; - return FALSE; - } - break; - - case SEC_LINK_DUPLICATES_ONE_ONLY: - (*_bfd_error_handler) - (_("%B: ignoring duplicate section `%A'"), - abfd, sec); - break; - - case SEC_LINK_DUPLICATES_SAME_SIZE: - if (!sec || !l_sec) - abort (); - - if (sec->size != l_sec->size) - (*_bfd_error_handler) - (_("%B: duplicate section `%A' has different size"), - abfd, sec); - break; - - case SEC_LINK_DUPLICATES_SAME_CONTENTS: - if (!sec || !l_sec) - abort (); - - if (sec->size != l_sec->size) - (*_bfd_error_handler) - (_("%B: duplicate section `%A' has different size"), - abfd, sec); - else if (sec->size != 0) - { - bfd_byte *sec_contents, *l_sec_contents; - - if (!bfd_malloc_and_get_section (abfd, sec, &sec_contents)) - (*_bfd_error_handler) - (_("%B: warning: could not read contents of section `%A'"), - abfd, sec); - else if (!bfd_malloc_and_get_section (l_sec->owner, l_sec, - &l_sec_contents)) - (*_bfd_error_handler) - (_("%B: warning: could not read contents of section `%A'"), - l_sec->owner, l_sec); - else if (memcmp (sec_contents, l_sec_contents, sec->size) != 0) - (*_bfd_error_handler) - (_("%B: warning: duplicate section `%A' has different contents"), - abfd, sec); - - if (sec_contents) - free (sec_contents); - if (l_sec_contents) - free (l_sec_contents); - } - break; - } + if (!_bfd_handle_already_linked (sec, l, info)) + return FALSE; - if (sec) + if (flags & SEC_GROUP) { - /* Set the output_section field so that lang_add_section - does not create a lang_input_section structure for this - section. Since there might be a symbol in the section - being discarded, we must retain a pointer to the section - which we are really going to use. */ - sec->output_section = bfd_abs_section_ptr; - sec->kept_section = l_sec; + asection *first = elf_next_in_group (sec); + asection *s = first; - if (flags & SEC_GROUP) + while (s != NULL) { - asection *first = elf_next_in_group (sec); - asection *s = first; - - while (s != NULL) - { - s->output_section = bfd_abs_section_ptr; - /* Record which group discards it. */ - s->kept_section = l_sec; - s = elf_next_in_group (s); - /* These lists are circular. */ - if (s == first) - break; - } + s->output_section = bfd_abs_section_ptr; + /* Record which group discards it. */ + s->kept_section = l->sec; + s = elf_next_in_group (s); + /* These lists are circular. */ + if (s == first) + break; } } @@ -12711,108 +12587,67 @@ _bfd_elf_section_already_linked (bfd *abfd, } } - matched = FALSE; - if (sec) + /* A single member comdat group section may be discarded by a + linkonce section and vice versa. */ + if ((flags & SEC_GROUP) != 0) { - /* A single member comdat group section may be discarded by a - linkonce section and vice versa. */ + asection *first = elf_next_in_group (sec); - if ((flags & SEC_GROUP) != 0) + if (first != NULL && elf_next_in_group (first) == first) + /* Check this single member group against linkonce sections. */ + for (l = already_linked_list->entry; l != NULL; l = l->next) + if ((l->sec->flags & SEC_GROUP) == 0 + && bfd_elf_match_symbols_in_sections (l->sec, first, info)) + { + first->output_section = bfd_abs_section_ptr; + first->kept_section = l->sec; + sec->output_section = bfd_abs_section_ptr; + break; + } + } + else + /* Check this linkonce section against single member groups. */ + for (l = already_linked_list->entry; l != NULL; l = l->next) + if (l->sec->flags & SEC_GROUP) { - asection *first = elf_next_in_group (sec); + asection *first = elf_next_in_group (l->sec); - if (first != NULL && elf_next_in_group (first) == first) - /* Check this single member group against linkonce sections. */ - for (l = already_linked_list->entry; l != NULL; l = l->next) - { - if (l->linked.comdat_key == NULL) - { - l_sec = l->linked.u.sec; - - if ((l_sec->flags & SEC_GROUP) == 0 - && bfd_coff_get_comdat_section (l_sec->owner, - l_sec) == NULL - && bfd_elf_match_symbols_in_sections (l_sec, - first, - info)) - { - first->output_section = bfd_abs_section_ptr; - first->kept_section = l_sec; - sec->output_section = bfd_abs_section_ptr; - matched = TRUE; - break; - } - } - } + if (first != NULL + && elf_next_in_group (first) == first + && bfd_elf_match_symbols_in_sections (first, sec, info)) + { + sec->output_section = bfd_abs_section_ptr; + sec->kept_section = first; + break; + } } - else - /* Check this linkonce section against single member groups. */ - for (l = already_linked_list->entry; l != NULL; l = l->next) - { - if (l->linked.comdat_key == NULL) - { - l_sec = l->linked.u.sec; - - if (l_sec->flags & SEC_GROUP) - { - asection *first = elf_next_in_group (l_sec); - - if (first != NULL - && elf_next_in_group (first) == first - && bfd_elf_match_symbols_in_sections (first, - sec, - info)) - { - sec->output_section = bfd_abs_section_ptr; - sec->kept_section = first; - matched = TRUE; - break; - } - } - } - } - /* Do not complain on unresolved relocations in `.gnu.linkonce.r.F' - referencing its discarded `.gnu.linkonce.t.F' counterpart - - g++-3.4 specific as g++-4.x is using COMDAT groups (without the - `.gnu.linkonce' prefix) instead. `.gnu.linkonce.r.*' were the - `.rodata' part of its matching `.gnu.linkonce.t.*'. If - `.gnu.linkonce.r.F' is not discarded but its `.gnu.linkonce.t.F' - is discarded means we chose one-only `.gnu.linkonce.t.F' section - from a different bfd not requiring any `.gnu.linkonce.r.F'. - Thus `.gnu.linkonce.r.F' should be discarded. The reverse order - cannot happen as there is never a bfd with only the - `.gnu.linkonce.r.F' section. The order of sections in a bfd - does not matter as here were are looking only for cross-bfd - sections. */ - - if ((flags & SEC_GROUP) == 0 - && CONST_STRNEQ (name, ".gnu.linkonce.r.")) - for (l = already_linked_list->entry; l != NULL; l = l->next) - { - if (l->linked.comdat_key == NULL) - { - l_sec = l->linked.u.sec; - - if ((l_sec->flags & SEC_GROUP) == 0 - && CONST_STRNEQ (l_sec->name, ".gnu.linkonce.t.")) - { - if (abfd != l_sec->owner) - { - sec->output_section = bfd_abs_section_ptr; - matched = TRUE; - } - break; - } - } - } - } + /* Do not complain on unresolved relocations in `.gnu.linkonce.r.F' + referencing its discarded `.gnu.linkonce.t.F' counterpart - g++-3.4 + specific as g++-4.x is using COMDAT groups (without the `.gnu.linkonce' + prefix) instead. `.gnu.linkonce.r.*' were the `.rodata' part of its + matching `.gnu.linkonce.t.*'. If `.gnu.linkonce.r.F' is not discarded + but its `.gnu.linkonce.t.F' is discarded means we chose one-only + `.gnu.linkonce.t.F' section from a different bfd not requiring any + `.gnu.linkonce.r.F'. Thus `.gnu.linkonce.r.F' should be discarded. + The reverse order cannot happen as there is never a bfd with only the + `.gnu.linkonce.r.F' section. The order of sections in a bfd does not + matter as here were are looking only for cross-bfd sections. */ + + if ((flags & SEC_GROUP) == 0 && CONST_STRNEQ (name, ".gnu.linkonce.r.")) + for (l = already_linked_list->entry; l != NULL; l = l->next) + if ((l->sec->flags & SEC_GROUP) == 0 + && CONST_STRNEQ (l->sec->name, ".gnu.linkonce.t.")) + { + if (abfd != l->sec->owner) + sec->output_section = bfd_abs_section_ptr; + break; + } /* This is the first section with this name. Record it. */ - if (! bfd_section_already_linked_table_insert (already_linked_list, - linked)) + if (!bfd_section_already_linked_table_insert (already_linked_list, sec)) info->callbacks->einfo (_("%F%P: already_linked_table: %E\n")); - return matched; + return sec->output_section == bfd_abs_section_ptr; } bfd_boolean |