aboutsummaryrefslogtreecommitdiff
path: root/bfd/linker.c
diff options
context:
space:
mode:
Diffstat (limited to 'bfd/linker.c')
-rw-r--r--bfd/linker.c127
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"));
}