This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
RFC: PATCH: ld/12942: Plugin not handling correctly resolution of COMDATs.
- From: "H.J. Lu" <hongjiu dot lu at intel dot com>
- To: binutils at sourceware dot org
- Date: Mon, 4 Jul 2011 15:53:28 -0700
- Subject: RFC: PATCH: ld/12942: Plugin not handling correctly resolution of COMDATs.
- Reply-to: "H.J. Lu" <hjl dot tools at gmail dot com>
Hi,
This adds SEC_LTO_COMDAT and GNU_LTO_COMAT_SECTION_NAME. They are
used to support LTO COMDAT symbols. Any comments?
Thanks.
H.J.
---
diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h
index 69851be..5b1a233 100644
--- a/bfd/bfd-in2.h
+++ b/bfd/bfd-in2.h
@@ -1350,6 +1350,9 @@ typedef struct bfd_section
when memory read flag isn't set. */
#define SEC_COFF_NOREAD 0x40000000
+ /* Indicate that this is a special LTO COMDAT section. */
+#define SEC_LTO_COMDAT 0x80000000
+
/* End of section flags. */
/* Some internal packed boolean fields. */
@@ -1549,6 +1552,9 @@ struct relax_table {
#define BFD_COM_SECTION_NAME "*COM*"
#define BFD_IND_SECTION_NAME "*IND*"
+/* GNU LTO COMDAT section name. */
+#define GNU_LTO_COMAT_SECTION_NAME ".text.gnu.lto_comdat"
+
/* GNU object-only section name. */
#define GNU_OBJECT_ONLY_SECTION_NAME ".gnu_object_only"
@@ -5745,6 +5751,7 @@ enum bfd_endian { BFD_ENDIAN_BIG, BFD_ENDIAN_LITTLE, BFD_ENDIAN_UNKNOWN };
/* Forward declaration. */
typedef struct bfd_link_info _bfd_link_info;
+struct already_linked;
typedef struct bfd_target
{
@@ -6070,7 +6077,7 @@ typedef struct bfd_target
/* Check if SEC has been already linked during a reloceatable or
final link. */
- void (*_section_already_linked) (bfd *, struct bfd_section *,
+ void (*_section_already_linked) (bfd *, struct already_linked *,
struct bfd_link_info *);
/* Define a common symbol. */
@@ -6140,11 +6147,13 @@ bfd_boolean bfd_link_split_section (bfd *abfd, asection *sec);
#define bfd_link_split_section(abfd, sec) \
BFD_SEND (abfd, _bfd_link_split_section, (abfd, sec))
-void bfd_section_already_linked (bfd *abfd, asection *sec,
+struct already_linked;
+void bfd_section_already_linked (bfd *abfd,
+ struct already_linked *data,
struct bfd_link_info *info);
-#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))
bfd_boolean bfd_generic_define_common_symbol
(bfd *output_bfd, struct bfd_link_info *info,
diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h
index 64a9dc0..b2075a5 100644
--- a/bfd/elf-bfd.h
+++ b/bfd/elf-bfd.h
@@ -1793,7 +1793,7 @@ extern bfd_boolean _bfd_elf_match_sections_by_type
extern bfd_boolean bfd_elf_is_group_section
(bfd *, const struct bfd_section *);
extern void _bfd_elf_section_already_linked
- (bfd *, struct bfd_section *, struct bfd_link_info *);
+ (bfd *, struct already_linked *, struct bfd_link_info *);
extern void bfd_elf_set_group_contents
(bfd *, asection *, void *);
extern asection *_bfd_elf_check_kept_section
diff --git a/bfd/elf.c b/bfd/elf.c
index 98a1463..7884cec 100644
--- a/bfd/elf.c
+++ b/bfd/elf.c
@@ -933,6 +933,10 @@ _bfd_elf_make_section_from_shdr (bfd *abfd,
&& elf_next_in_group (newsect) == NULL)
flags |= SEC_LINK_ONCE | SEC_LINK_DUPLICATES_DISCARD;
+ /* Check the LTO COMDAT section. */
+ if (CONST_STRNEQ (name, GNU_LTO_COMAT_SECTION_NAME))
+ flags |= SEC_LTO_COMDAT;
+
bed = get_elf_backend_data (abfd);
if (bed->elf_backend_section_flags)
if (! bed->elf_backend_section_flags (&flags, hdr))
diff --git a/bfd/elflink.c b/bfd/elflink.c
index 12fa714..42186db 100644
--- a/bfd/elflink.c
+++ b/bfd/elflink.c
@@ -12441,63 +12441,100 @@ section_signature (asection *sec)
}
void
-_bfd_elf_section_already_linked (bfd *abfd, asection *sec,
+_bfd_elf_section_already_linked (bfd *abfd,
+ struct already_linked *linked,
struct bfd_link_info *info)
{
flagword flags;
const char *name, *p;
struct bfd_section_already_linked *l;
struct bfd_section_already_linked_hash_entry *already_linked_list;
+ asection *sec, *l_sec;
- if (sec->output_section == bfd_abs_section_ptr)
- return;
-
- 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;
-
- /* 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;
-
- /* 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.
-
- 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. */
-
- name = section_signature (sec);
-
- if (CONST_STRNEQ (name, ".gnu.linkonce.")
- && (p = strchr (name + sizeof (".gnu.linkonce.") - 1, '.')) != NULL)
- p++;
+ p = name = linked->comdat_key;
+ if (name)
+ {
+ sec = NULL;
+ flags = SEC_GROUP | SEC_LINK_ONCE | SEC_LINK_DUPLICATES_DISCARD;
+ }
else
- p = name;
+ {
+ sec = linked->u.sec;
+ if (sec->output_section == bfd_abs_section_ptr)
+ return;
+
+ 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;
+
+ /* 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;
+
+ /* 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.
+
+ 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. */
+
+ name = section_signature (sec);
+
+ if (CONST_STRNEQ (name, ".gnu.linkonce.")
+ && ((p = strchr (name + sizeof (".gnu.linkonce.") - 1, '.'))
+ != NULL))
+ p++;
+ else
+ p = name;
+ }
already_linked_list = bfd_section_already_linked_table_lookup (p);
for (l = already_linked_list->entry; l != NULL; l = l->next)
{
+ bfd_boolean l_coff_comdat_sec;
+ flagword l_flags;
+ bfd *l_owner;
+ const char *l_name = l->linked.comdat_key;
+ if (l_name)
+ {
+ l_owner = l->linked.u.abfd;
+ l_sec = NULL;
+ l_flags = (SEC_GROUP
+ | SEC_LINK_ONCE
+ | SEC_LINK_DUPLICATES_DISCARD);
+ l_coff_comdat_sec = FALSE;
+ }
+ else
+ {
+ l_sec = l->linked.u.sec;
+ l_owner = l_sec->owner;
+ l_name = section_signature (l_sec);
+ l_flags = l_sec->flags;
+ l_coff_comdat_sec
+ = !!bfd_coff_get_comdat_section (l_sec->owner, 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->sec->flags & SEC_GROUP)
- && strcmp (name, section_signature (l->sec)) == 0
- && bfd_coff_get_comdat_section (l->sec->owner, l->sec) == NULL)
+ if ((flags & SEC_GROUP) == (l_flags & SEC_GROUP)
+ && strcmp (name, l_name) == 0
+ && !l_coff_comdat_sec)
{
/* The section has already been linked. See if we should
issue a warning. */
@@ -12507,6 +12544,13 @@ _bfd_elf_section_already_linked (bfd *abfd, asection *sec,
abort ();
case SEC_LINK_DUPLICATES_DISCARD:
+ if (info->loading_lto_outputs
+ && (l_owner->flags & BFD_PLUGIN) != 0)
+ {
+ /* Replace the plugin dummy with the LTO output. */
+ l->linked = *linked;
+ return;
+ }
break;
case SEC_LINK_DUPLICATES_ONE_ONLY:
@@ -12516,14 +12560,20 @@ _bfd_elf_section_already_linked (bfd *abfd, asection *sec,
break;
case SEC_LINK_DUPLICATES_SAME_SIZE:
- if (sec->size != l->sec->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->size != l->sec->size)
+ if (!sec || !l_sec)
+ abort ();
+
+ if (sec->size != l_sec->size)
(*_bfd_error_handler)
(_("%B: duplicate section `%A' has different size"),
abfd, sec);
@@ -12535,11 +12585,11 @@ _bfd_elf_section_already_linked (bfd *abfd, asection *sec,
(*_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,
+ 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);
+ 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"),
@@ -12553,28 +12603,31 @@ _bfd_elf_section_already_linked (bfd *abfd, asection *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 (flags & SEC_GROUP)
+ if (sec)
{
- asection *first = elf_next_in_group (sec);
- asection *s = first;
+ /* 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;
- while (s != NULL)
+ if (flags & SEC_GROUP)
{
- 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;
+ 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;
+ }
}
}
@@ -12582,67 +12635,100 @@ _bfd_elf_section_already_linked (bfd *abfd, asection *sec,
}
}
- /* A single member comdat group section may be discarded by a
- linkonce section and vice versa. */
-
- if ((flags & SEC_GROUP) != 0)
+ if (sec)
{
- asection *first = elf_next_in_group (sec);
+ /* A single member comdat group section may be discarded by a
+ linkonce section and vice versa. */
- 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_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;
- 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)
+ if ((flags & SEC_GROUP) != 0)
{
- asection *first = elf_next_in_group (l->sec);
+ asection *first = elf_next_in_group (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;
- break;
- }
+ 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;
+ 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;
- /* 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;
- }
+ 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;
+ 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;
+ break;
+ }
+ }
+ }
+ }
/* 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"));
}
diff --git a/bfd/libbfd-in.h b/bfd/libbfd-in.h
index ad45ba3..a80687e 100644
--- a/bfd/libbfd-in.h
+++ b/bfd/libbfd-in.h
@@ -478,7 +478,8 @@ extern bfd_boolean _bfd_generic_set_section_contents
#define _bfd_nolink_bfd_link_split_section \
((bfd_boolean (*) (bfd *, struct bfd_section *)) bfd_false)
#define _bfd_nolink_section_already_linked \
- ((void (*) (bfd *, struct bfd_section *, struct bfd_link_info *)) bfd_void)
+ ((void (*) (bfd *, struct already_linked*, \
+ struct bfd_link_info *)) bfd_void)
#define _bfd_nolink_bfd_define_common_symbol \
((bfd_boolean (*) (bfd *, struct bfd_link_info *, \
struct bfd_link_hash_entry *)) bfd_false)
@@ -599,7 +600,7 @@ extern bfd_boolean _bfd_generic_link_split_section
(bfd *, struct bfd_section *);
extern void _bfd_generic_section_already_linked
- (bfd *, struct bfd_section *, struct bfd_link_info *);
+ (bfd *, struct already_linked *, struct bfd_link_info *);
/* Generic reloc_link_order processing routine. */
extern bfd_boolean _bfd_generic_reloc_link_order
@@ -791,16 +792,26 @@ struct bfd_section_already_linked_hash_entry
struct bfd_section_already_linked *entry;
};
+struct already_linked
+{
+ const char *comdat_key;
+ union
+ {
+ asection *sec;
+ bfd *abfd;
+ } u;
+};
+
struct bfd_section_already_linked
{
struct bfd_section_already_linked *next;
- asection *sec;
+ struct already_linked linked;
};
extern struct bfd_section_already_linked_hash_entry *
bfd_section_already_linked_table_lookup (const char *);
extern bfd_boolean bfd_section_already_linked_table_insert
- (struct bfd_section_already_linked_hash_entry *, asection *);
+ (struct bfd_section_already_linked_hash_entry *, struct already_linked *);
extern void bfd_section_already_linked_table_traverse
(bfd_boolean (*) (struct bfd_section_already_linked_hash_entry *,
void *), void *);
diff --git a/bfd/libbfd.h b/bfd/libbfd.h
index dd4cc94..d778f89 100644
--- a/bfd/libbfd.h
+++ b/bfd/libbfd.h
@@ -483,7 +483,8 @@ extern bfd_boolean _bfd_generic_set_section_contents
#define _bfd_nolink_bfd_link_split_section \
((bfd_boolean (*) (bfd *, struct bfd_section *)) bfd_false)
#define _bfd_nolink_section_already_linked \
- ((void (*) (bfd *, struct bfd_section *, struct bfd_link_info *)) bfd_void)
+ ((void (*) (bfd *, struct already_linked*, \
+ struct bfd_link_info *)) bfd_void)
#define _bfd_nolink_bfd_define_common_symbol \
((bfd_boolean (*) (bfd *, struct bfd_link_info *, \
struct bfd_link_hash_entry *)) bfd_false)
@@ -604,7 +605,7 @@ extern bfd_boolean _bfd_generic_link_split_section
(bfd *, struct bfd_section *);
extern void _bfd_generic_section_already_linked
- (bfd *, struct bfd_section *, struct bfd_link_info *);
+ (bfd *, struct already_linked *, struct bfd_link_info *);
/* Generic reloc_link_order processing routine. */
extern bfd_boolean _bfd_generic_reloc_link_order
@@ -796,16 +797,26 @@ struct bfd_section_already_linked_hash_entry
struct bfd_section_already_linked *entry;
};
+struct already_linked
+{
+ const char *comdat_key;
+ union
+ {
+ asection *sec;
+ bfd *abfd;
+ } u;
+};
+
struct bfd_section_already_linked
{
struct bfd_section_already_linked *next;
- asection *sec;
+ struct already_linked linked;
};
extern struct bfd_section_already_linked_hash_entry *
bfd_section_already_linked_table_lookup (const char *);
extern bfd_boolean bfd_section_already_linked_table_insert
- (struct bfd_section_already_linked_hash_entry *, asection *);
+ (struct bfd_section_already_linked_hash_entry *, struct already_linked *);
extern void bfd_section_already_linked_table_traverse
(bfd_boolean (*) (struct bfd_section_already_linked_hash_entry *,
void *), void *);
diff --git a/bfd/linker.c b/bfd/linker.c
index e472317..b9db8e2 100644
--- a/bfd/linker.c
+++ b/bfd/linker.c
@@ -2888,15 +2888,17 @@ FUNCTION
bfd_section_already_linked
SYNOPSIS
- void bfd_section_already_linked (bfd *abfd, asection *sec,
+ struct already_linked;
+ 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 +2941,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 +2951,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 +2992,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_owner = l->linked.u.abfd;
+ l_flags = (SEC_GROUP
+ | SEC_LINK_ONCE
+ | SEC_LINK_DUPLICATES_DISCARD);
+ l_sec = NULL;
+ l_comdat = NULL;
+ }
+ else
+ {
+ l_owner = l_sec->owner;
+ l_sec = l->linked.u.sec;
+ 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 +3068,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 +3090,13 @@ _bfd_generic_section_already_linked (bfd *abfd, asection *sec,
abort ();
case SEC_LINK_DUPLICATES_DISCARD:
+ if (info->loading_lto_outputs
+ && (l_owner->flags & BFD_PLUGIN) != 0)
+ {
+ /* Replace the plugin dummy with the LTO output. */
+ l->linked = *linked;
+ return;
+ }
break;
case SEC_LINK_DUPLICATES_ONE_ONLY:
@@ -3072,27 +3113,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"));
}
diff --git a/bfd/section.c b/bfd/section.c
index 3a124d8..5565a2c 100644
--- a/bfd/section.c
+++ b/bfd/section.c
@@ -352,6 +352,9 @@ CODE_FRAGMENT
. when memory read flag isn't set. *}
.#define SEC_COFF_NOREAD 0x40000000
.
+. {* Indicate that this is a special LTO COMDAT section. *}
+.#define SEC_LTO_COMDAT 0x80000000
+.
. {* End of section flags. *}
.
. {* Some internal packed boolean fields. *}
@@ -551,6 +554,9 @@ CODE_FRAGMENT
.#define BFD_COM_SECTION_NAME "*COM*"
.#define BFD_IND_SECTION_NAME "*IND*"
.
+.{* GNU LTO COMDAT section name. *}
+.#define GNU_LTO_COMAT_SECTION_NAME ".text.gnu.lto_comdat"
+.
.{* GNU object-only section name. *}
.#define GNU_OBJECT_ONLY_SECTION_NAME ".gnu_object_only"
.
diff --git a/bfd/targets.c b/bfd/targets.c
index 52dcd6b..ac978a1 100644
--- a/bfd/targets.c
+++ b/bfd/targets.c
@@ -176,6 +176,7 @@ DESCRIPTION
.
.{* Forward declaration. *}
.typedef struct bfd_link_info _bfd_link_info;
+.struct already_linked;
.
.typedef struct bfd_target
.{
@@ -503,7 +504,7 @@ BFD_JUMP_TABLE macros.
.
. {* Check if SEC has been already linked during a reloceatable or
. final link. *}
-. void (*_section_already_linked) (bfd *, struct bfd_section *,
+. void (*_section_already_linked) (bfd *, struct already_linked *,
. struct bfd_link_info *);
.
. {* Define a common symbol. *}
diff --git a/include/bfdlink.h b/include/bfdlink.h
index 51d65d8..89deaee 100644
--- a/include/bfdlink.h
+++ b/include/bfdlink.h
@@ -357,6 +357,9 @@ struct bfd_link_info
linker created sections, TRUE if it should be omitted. */
unsigned int no_ld_generated_unwind_info: 1;
+ /* TRUE if we are loading LTO outputs. */
+ unsigned int loading_lto_outputs: 1;
+
/* TRUE if .gnu_object_only section should be created. */
unsigned int emit_gnu_object_only: 1;
diff --git a/ld/ldlang.c b/ld/ldlang.c
index 3f45c37..50eccf3 100644
--- a/ld/ldlang.c
+++ b/ld/ldlang.c
@@ -2252,7 +2252,12 @@ section_already_linked (bfd *abfd, asection *sec, void *data)
}
if (!(abfd->flags & DYNAMIC))
- bfd_section_already_linked (abfd, sec, &link_info);
+ {
+ struct already_linked linked;
+ linked.comdat_key = NULL;
+ linked.u.sec = sec;
+ bfd_section_already_linked (abfd, &linked, &link_info);
+ }
}
/* The wild routines.
@@ -6565,6 +6570,7 @@ lang_process (void)
einfo (_("%P%F: %s: plugin reported error after all symbols read\n"),
plugin_error_plugin ());
/* Open any newly added files, updating the file chains. */
+ link_info.loading_lto_outputs = TRUE;
open_input_bfds (added.head, OPEN_BFD_NORMAL);
/* Restore the global list pointer now they have all been added. */
lang_list_remove_tail (stat_ptr, &added);
diff --git a/ld/plugin.c b/ld/plugin.c
index a9c2a95..91f2d5c 100644
--- a/ld/plugin.c
+++ b/ld/plugin.c
@@ -32,6 +32,7 @@
#include "plugin.h"
#include "plugin-api.h"
#include "elf-bfd.h"
+#include "libbfd.h"
#if !defined (HAVE_DLFCN_H) && defined (HAVE_WINDOWS_H)
#include <windows.h>
#endif
@@ -257,7 +258,13 @@ plugin_get_ir_dummy_bfd (const char *name, bfd *srctemplate)
flags = (SEC_CODE | SEC_HAS_CONTENTS | SEC_READONLY
| SEC_ALLOC | SEC_LOAD | SEC_KEEP | SEC_EXCLUDE);
if (bfd_make_section_anyway_with_flags (abfd, ".text", flags))
- return abfd;
+ {
+ flags |= SEC_LTO_COMDAT;
+ if (bfd_make_section_anyway_with_flags (abfd,
+ GNU_LTO_COMAT_SECTION_NAME,
+ flags))
+ return abfd;
+ }
}
}
einfo (_("could not create dummy IR bfd: %F%E\n"));
@@ -298,7 +305,11 @@ asymbol_from_plugin_symbol (bfd *abfd, asymbol *asym,
/* FALLTHRU */
case LDPK_DEF:
flags |= BSF_GLOBAL;
- section = bfd_get_section_by_name (abfd, ".text");
+ if (ldsym->comdat_key)
+ section = bfd_get_section_by_name (abfd,
+ GNU_LTO_COMAT_SECTION_NAME);
+ else
+ section = bfd_get_section_by_name (abfd, ".text");
break;
case LDPK_WEAKUNDEF:
@@ -399,7 +410,15 @@ add_symbols (void *handle, int nsyms, const struct ld_plugin_symbol *syms)
for (n = 0; n < nsyms; n++)
{
enum ld_plugin_status rv;
- asymbol *bfdsym = bfd_make_empty_symbol (abfd);
+ asymbol *bfdsym;
+ if (syms[n].comdat_key)
+ {
+ struct already_linked linked;
+ linked.comdat_key = xstrdup (syms[n].comdat_key);
+ linked.u.abfd = abfd;
+ bfd_section_already_linked (abfd, &linked, &link_info);
+ }
+ bfdsym = bfd_make_empty_symbol (abfd);
symptrs[n] = bfdsym;
rv = asymbol_from_plugin_symbol (abfd, bfdsym, syms + n);
if (rv != LDPS_OK)
@@ -934,8 +953,6 @@ plugin_notice (struct bfd_link_info *info,
{
if (h != NULL)
{
- bfd *sym_bfd;
-
/* No further processing if this def/ref is from an IR dummy BFD. */
if (is_ir_dummy_bfd (abfd))
return TRUE;
@@ -975,14 +992,26 @@ plugin_notice (struct bfd_link_info *info,
definition, and strong symbols will normally cause multiple
definition errors. Avoid this by making the symbol appear
to be undefined. */
- else if (((h->type == bfd_link_hash_defweak
+ else if ((h->type == bfd_link_hash_defweak
|| h->type == bfd_link_hash_defined)
- && is_ir_dummy_bfd (sym_bfd = h->u.def.section->owner))
- || (h->type == bfd_link_hash_common
- && is_ir_dummy_bfd (sym_bfd = h->u.c.p->section->owner)))
+ && is_ir_dummy_bfd (h->u.def.section->owner))
+ {
+ /* A symbol with comdat key in IR dummy BFD may override
+ the comdat symbol in a real BFD. */
+ if (link_info.loading_lto_outputs
+ || (h->u.def.section->flags & SEC_LTO_COMDAT) == 0)
+ {
+ h->type = bfd_link_hash_undefweak;
+ h->u.undef.abfd = h->u.def.section->owner;
+ }
+ else
+ h->non_ir_ref = TRUE;
+ }
+ else if (h->type == bfd_link_hash_common
+ && is_ir_dummy_bfd (h->u.c.p->section->owner))
{
h->type = bfd_link_hash_undefweak;
- h->u.undef.abfd = sym_bfd;
+ h->u.undef.abfd = h->u.c.p->section->owner;
}
}