diff options
Diffstat (limited to 'bfd/linker.c')
-rw-r--r-- | bfd/linker.c | 127 |
1 files changed, 88 insertions, 39 deletions
diff --git a/bfd/linker.c b/bfd/linker.c index e472317..492e774 100644 --- a/bfd/linker.c +++ b/bfd/linker.c @@ -2888,15 +2888,16 @@ FUNCTION bfd_section_already_linked SYNOPSIS - void bfd_section_already_linked (bfd *abfd, asection *sec, + void bfd_section_already_linked (bfd *abfd, + struct already_linked *data, struct bfd_link_info *info); DESCRIPTION - Check if @var{sec} has been already linked during a reloceatable + Check if @var{data} has been already linked during a reloceatable or final link. -.#define bfd_section_already_linked(abfd, sec, info) \ -. BFD_SEND (abfd, _section_already_linked, (abfd, sec, info)) +.#define bfd_section_already_linked(abfd, data, info) \ +. BFD_SEND (abfd, _section_already_linked, (abfd, data, info)) . */ @@ -2939,7 +2940,7 @@ bfd_section_already_linked_table_lookup (const char *name) bfd_boolean bfd_section_already_linked_table_insert (struct bfd_section_already_linked_hash_entry *already_linked_list, - asection *sec) + struct already_linked *data) { struct bfd_section_already_linked *l; @@ -2949,7 +2950,7 @@ bfd_section_already_linked_table_insert bfd_hash_allocate (&_bfd_section_already_linked_table, sizeof *l); if (l == NULL) return FALSE; - l->sec = sec; + l->linked = *data; l->next = already_linked_list->entry; already_linked_list->entry = l; return TRUE; @@ -2990,42 +2991,74 @@ bfd_section_already_linked_table_free (void) /* This is used on non-ELF inputs. */ void -_bfd_generic_section_already_linked (bfd *abfd, asection *sec, +_bfd_generic_section_already_linked (bfd *abfd, + struct already_linked *linked, struct bfd_link_info *info) { flagword flags; const char *name; struct bfd_section_already_linked *l; struct bfd_section_already_linked_hash_entry *already_linked_list; + struct coff_comdat_info *s_comdat; + asection *sec; - flags = sec->flags; - if ((flags & SEC_LINK_ONCE) == 0) - return; - - /* 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. - - 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. */ - - name = bfd_get_section_name (abfd, sec); + name = linked->comdat_key; + if (name) + { + sec = NULL; + flags = SEC_GROUP | SEC_LINK_ONCE | SEC_LINK_DUPLICATES_DISCARD; + s_comdat = NULL; + } + else + { + sec = linked->u.sec; + flags = sec->flags; + if ((flags & SEC_LINK_ONCE) == 0) + return; + + s_comdat = bfd_coff_get_comdat_section (abfd, sec); + + /* 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. + + 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. */ + + name = bfd_get_section_name (abfd, sec); + } already_linked_list = bfd_section_already_linked_table_lookup (name); for (l = already_linked_list->entry; l != NULL; l = l->next) { bfd_boolean skip = FALSE; - struct coff_comdat_info *s_comdat - = bfd_coff_get_comdat_section (abfd, sec); - struct coff_comdat_info *l_comdat - = bfd_coff_get_comdat_section (l->sec->owner, l->sec); + bfd *l_owner; + flagword l_flags; + struct coff_comdat_info *l_comdat; + asection *l_sec; + + if (l->linked.comdat_key) + { + l_sec = NULL; + l_owner = l->linked.u.abfd; + l_comdat = NULL; + l_flags = (SEC_GROUP + | SEC_LINK_ONCE + | SEC_LINK_DUPLICATES_DISCARD); + } + else + { + l_sec = l->linked.u.sec; + l_owner = l_sec->owner; + l_comdat = bfd_coff_get_comdat_section (l_sec->owner, l_sec); + } /* We may have 3 different sections on the list: group section, comdat section and linkonce section. SEC may be a linkonce or @@ -3034,7 +3067,7 @@ _bfd_generic_section_already_linked (bfd *abfd, asection *sec, FIXME: Is that safe to match a linkonce section with a comdat section for COFF inputs? */ - if ((l->sec->flags & SEC_GROUP) != 0) + if ((l_flags & SEC_GROUP) != 0) skip = TRUE; else if (bfd_get_flavour (abfd) == bfd_target_coff_flavour) { @@ -3056,6 +3089,18 @@ _bfd_generic_section_already_linked (bfd *abfd, asection *sec, 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; + } break; case SEC_LINK_DUPLICATES_ONE_ONLY: @@ -3072,27 +3117,31 @@ _bfd_generic_section_already_linked (bfd *abfd, asection *sec, either. */ /* Fall through. */ case SEC_LINK_DUPLICATES_SAME_SIZE: - if (sec->size != l->sec->size) + if (sec->size != l_sec->size) (*_bfd_error_handler) (_("%B: warning: duplicate section `%A' has different size\n"), abfd, sec); break; } - /* 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; + if (sec) + { + /* 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; + } return; } } /* This is the first section with this name. Record it. */ - if (! bfd_section_already_linked_table_insert (already_linked_list, sec)) + if (! bfd_section_already_linked_table_insert (already_linked_list, + linked)) info->callbacks->einfo (_("%F%P: already_linked_table: %E\n")); } |