summaryrefslogtreecommitdiff
path: root/bfd
diff options
context:
space:
mode:
authorAlan Modra <amodra@bigpond.net.au>2011-08-17 00:39:37 +0000
committerAlan Modra <amodra@bigpond.net.au>2011-08-17 00:39:37 +0000
commit72441da6f2fe16629e17588548de3d03119a2046 (patch)
tree05742db0b022327ddf846eeb79393d044966a747 /bfd
parent2d810ba757592d1df19034a12b015b9861ce3368 (diff)
downloadgdb-72441da6f2fe16629e17588548de3d03119a2046.tar.gz
PR ld/12762
bfd/ * bfd-in.h (struct bfd_section_already_linked): Forward declare. (_bfd_handle_already_linked): Declare. * coff-alpha.c (_bfd_ecoff_section_already_linked): Define as _bfd_coff_section_already_linked. * coff-mips.c (_bfd_ecoff_section_already_linked): Likewise. * coffcode.h (coff_section_already_linked): Likewise. * cofflink.c (coff_link_add_symbols): Revert 2011-07-09 changes. * elf-bfd.h: Likewise. * libbfd-in.h: Likewise. * targets.c: Likewise. * linker.c (bfd_section_already_linked): Likewise. (bfd_section_already_linked_table_lookup): Likewise. (bfd_section_already_linked_table_insert): Likewise. (_bfd_generic_section_already_linked): Likewise. Call _bfd_handle_already_linked. (_bfd_handle_already_linked): New function, split out from.. * elflink.c (_bfd_elf_section_already_linked): ..here. Revert 2011-07-09 changes. Avoid unnecessary strcmp when matching already_linked_list entries. Match plugin linkonce section. (section_signature): Delete. * coffgen.c (_bfd_coff_section_already_linked): New function. * libcoff-in.h (_bfd_coff_section_already_linked): Declare. * libbfd.h: Regenerate. * libcoff.h: Regenerate. * bfd-in2.h: Regenerate. ld/ * ldlang.c (section_already_linked): Revert 2011-07-09 changes. * plugin.c: Likewise. (asymbol_from_plugin_symbol): Create linkonce section for syms with comdat_key.
Diffstat (limited to 'bfd')
-rw-r--r--bfd/ChangeLog29
-rw-r--r--bfd/bfd-in.h15
-rw-r--r--bfd/bfd-in2.h24
-rw-r--r--bfd/coff-alpha.c2
-rw-r--r--bfd/coff-mips.c2
-rw-r--r--bfd/coffcode.h2
-rw-r--r--bfd/coffgen.c67
-rw-r--r--bfd/cofflink.c6
-rw-r--r--bfd/elf-bfd.h3
-rw-r--r--bfd/elflink.c371
-rw-r--r--bfd/libbfd-in.h20
-rw-r--r--bfd/libbfd.h20
-rw-r--r--bfd/libcoff-in.h2
-rw-r--r--bfd/libcoff.h2
-rw-r--r--bfd/linker.c250
-rw-r--r--bfd/targets.c3
16 files changed, 357 insertions, 461 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index d3ec8300434..1cd864b692c 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -1,3 +1,32 @@
+2011-08-17 Alan Modra <amodra@gmail.com>
+
+ PR ld/12762
+ * bfd-in.h (struct bfd_section_already_linked): Forward declare.
+ (_bfd_handle_already_linked): Declare.
+ * coff-alpha.c (_bfd_ecoff_section_already_linked): Define as
+ _bfd_coff_section_already_linked.
+ * coff-mips.c (_bfd_ecoff_section_already_linked): Likewise.
+ * coffcode.h (coff_section_already_linked): Likewise.
+ * cofflink.c (coff_link_add_symbols): Revert 2011-07-09 changes.
+ * elf-bfd.h: Likewise.
+ * libbfd-in.h: Likewise.
+ * targets.c: Likewise.
+ * linker.c (bfd_section_already_linked): Likewise.
+ (bfd_section_already_linked_table_lookup): Likewise.
+ (bfd_section_already_linked_table_insert): Likewise.
+ (_bfd_generic_section_already_linked): Likewise. Call
+ _bfd_handle_already_linked.
+ (_bfd_handle_already_linked): New function, split out from..
+ * elflink.c (_bfd_elf_section_already_linked): ..here. Revert
+ 2011-07-09 changes. Avoid unnecessary strcmp when matching
+ already_linked_list entries. Match plugin linkonce section.
+ (section_signature): Delete.
+ * coffgen.c (_bfd_coff_section_already_linked): New function.
+ * libcoff-in.h (_bfd_coff_section_already_linked): Declare.
+ * libbfd.h: Regenerate.
+ * libcoff.h: Regenerate.
+ * bfd-in2.h: Regenerate.
+
2011-08-14 Alan Modra <amodra@gmail.com>
* elf32-ppc.c (ppc_elf_select_plt_layout): Force bss-plt when
diff --git a/bfd/bfd-in.h b/bfd/bfd-in.h
index f375d2f4880..718d72e51f3 100644
--- a/bfd/bfd-in.h
+++ b/bfd/bfd-in.h
@@ -552,11 +552,6 @@ void bfd_putl16 (bfd_vma, void *);
bfd_uint64_t bfd_get_bits (const void *, int, bfd_boolean);
void bfd_put_bits (bfd_uint64_t, void *, int, bfd_boolean);
-extern bfd_boolean bfd_section_already_linked_table_init (void);
-extern void bfd_section_already_linked_table_free (void);
-
-/* Externally visible ECOFF routines. */
-
#if defined(__STDC__) || defined(ALMOST_STDC)
struct ecoff_debug_info;
struct ecoff_debug_swap;
@@ -564,8 +559,18 @@ struct ecoff_extr;
struct bfd_symbol;
struct bfd_link_info;
struct bfd_link_hash_entry;
+struct bfd_section_already_linked;
struct bfd_elf_version_tree;
#endif
+
+extern bfd_boolean bfd_section_already_linked_table_init (void);
+extern void bfd_section_already_linked_table_free (void);
+extern bfd_boolean _bfd_handle_already_linked
+ (struct bfd_section *, struct bfd_section_already_linked *,
+ struct bfd_link_info *);
+
+/* Externally visible ECOFF routines. */
+
extern bfd_vma bfd_ecoff_get_gp_value
(bfd * abfd);
extern bfd_boolean bfd_ecoff_set_gp_value
diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h
index 63ffd95f534..7cf3b7e60bc 100644
--- a/bfd/bfd-in2.h
+++ b/bfd/bfd-in2.h
@@ -559,11 +559,6 @@ void bfd_putl16 (bfd_vma, void *);
bfd_uint64_t bfd_get_bits (const void *, int, bfd_boolean);
void bfd_put_bits (bfd_uint64_t, void *, int, bfd_boolean);
-extern bfd_boolean bfd_section_already_linked_table_init (void);
-extern void bfd_section_already_linked_table_free (void);
-
-/* Externally visible ECOFF routines. */
-
#if defined(__STDC__) || defined(ALMOST_STDC)
struct ecoff_debug_info;
struct ecoff_debug_swap;
@@ -571,8 +566,18 @@ struct ecoff_extr;
struct bfd_symbol;
struct bfd_link_info;
struct bfd_link_hash_entry;
+struct bfd_section_already_linked;
struct bfd_elf_version_tree;
#endif
+
+extern bfd_boolean bfd_section_already_linked_table_init (void);
+extern void bfd_section_already_linked_table_free (void);
+extern bfd_boolean _bfd_handle_already_linked
+ (struct bfd_section *, struct bfd_section_already_linked *,
+ struct bfd_link_info *);
+
+/* Externally visible ECOFF routines. */
+
extern bfd_vma bfd_ecoff_get_gp_value
(bfd * abfd);
extern bfd_boolean bfd_ecoff_set_gp_value
@@ -5773,7 +5778,6 @@ 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;
/* Forward declaration. */
typedef struct flag_info flag_info;
@@ -6107,7 +6111,7 @@ typedef struct bfd_target
/* Check if SEC has been already linked during a reloceatable or
final link. */
- bfd_boolean (*_section_already_linked) (bfd *, struct already_linked *,
+ bfd_boolean (*_section_already_linked) (bfd *, asection *,
struct bfd_link_info *);
/* Define a common symbol. */
@@ -6178,11 +6182,11 @@ bfd_boolean bfd_link_split_section (bfd *abfd, asection *sec);
BFD_SEND (abfd, _bfd_link_split_section, (abfd, sec))
bfd_boolean bfd_section_already_linked (bfd *abfd,
- struct already_linked *data,
+ asection *sec,
struct bfd_link_info *info);
-#define bfd_section_already_linked(abfd, data, info) \
- BFD_SEND (abfd, _section_already_linked, (abfd, data, info))
+#define bfd_section_already_linked(abfd, sec, info) \
+ BFD_SEND (abfd, _section_already_linked, (abfd, sec, info))
bfd_boolean bfd_generic_define_common_symbol
(bfd *output_bfd, struct bfd_link_info *info,
diff --git a/bfd/coff-alpha.c b/bfd/coff-alpha.c
index 2233a335cbf..4466e4d71a5 100644
--- a/bfd/coff-alpha.c
+++ b/bfd/coff-alpha.c
@@ -2403,7 +2403,7 @@ static const struct ecoff_backend_data alpha_ecoff_backend_data =
#define _bfd_ecoff_bfd_is_group_section bfd_generic_is_group_section
#define _bfd_ecoff_bfd_discard_group bfd_generic_discard_group
#define _bfd_ecoff_section_already_linked \
- _bfd_generic_section_already_linked
+ _bfd_coff_section_already_linked
#define _bfd_ecoff_bfd_define_common_symbol bfd_generic_define_common_symbol
const bfd_target ecoffalpha_little_vec =
diff --git a/bfd/coff-mips.c b/bfd/coff-mips.c
index 9f8b90dcef8..4048ca89dd1 100644
--- a/bfd/coff-mips.c
+++ b/bfd/coff-mips.c
@@ -1419,7 +1419,7 @@ static const struct ecoff_backend_data mips_ecoff_backend_data =
#define _bfd_ecoff_bfd_is_group_section bfd_generic_is_group_section
#define _bfd_ecoff_bfd_discard_group bfd_generic_discard_group
#define _bfd_ecoff_section_already_linked \
- _bfd_generic_section_already_linked
+ _bfd_coff_section_already_linked
#define _bfd_ecoff_bfd_define_common_symbol bfd_generic_define_common_symbol
extern const bfd_target ecoff_big_vec;
diff --git a/bfd/coffcode.h b/bfd/coffcode.h
index 2313dc50a2d..6f9685b4ee9 100644
--- a/bfd/coffcode.h
+++ b/bfd/coffcode.h
@@ -5670,7 +5670,7 @@ static bfd_coff_backend_data ticoff1_swap_table =
#ifndef coff_section_already_linked
#define coff_section_already_linked \
- _bfd_generic_section_already_linked
+ _bfd_coff_section_already_linked
#endif
#ifndef coff_bfd_define_common_symbol
diff --git a/bfd/coffgen.c b/bfd/coffgen.c
index b0c2c62f187..bbb0acc1c62 100644
--- a/bfd/coffgen.c
+++ b/bfd/coffgen.c
@@ -2399,3 +2399,70 @@ bfd_coff_get_comdat_section (bfd *abfd, struct bfd_section *sec)
else
return NULL;
}
+
+bfd_boolean
+_bfd_coff_section_already_linked (bfd *abfd,
+ asection *sec,
+ struct bfd_link_info *info)
+{
+ flagword flags;
+ const char *name, *key;
+ struct bfd_section_already_linked *l;
+ struct bfd_section_already_linked_hash_entry *already_linked_list;
+ struct coff_comdat_info *s_comdat;
+
+ flags = sec->flags;
+ if ((flags & SEC_LINK_ONCE) == 0)
+ return FALSE;
+
+ /* The COFF backend linker doesn't support group sections. */
+ if ((flags & SEC_GROUP) != 0)
+ return FALSE;
+
+ name = bfd_get_section_name (abfd, sec);
+ s_comdat = bfd_coff_get_comdat_section (abfd, sec);
+
+ if (s_comdat != NULL)
+ key = s_comdat->name;
+ else
+ {
+ if (CONST_STRNEQ (name, ".gnu.linkonce.")
+ && (key = strchr (name + sizeof (".gnu.linkonce.") - 1, '.')) != NULL)
+ key++;
+ else
+ /* FIXME: gcc as of 2011-09 emits sections like .text$<key>,
+ .xdata$<key> and .pdata$<key> only the first of which has a
+ comdat key. Should these all match the LTO IR key? */
+ key = name;
+ }
+
+ already_linked_list = bfd_section_already_linked_table_lookup (key);
+
+ for (l = already_linked_list->entry; l != NULL; l = l->next)
+ {
+ struct coff_comdat_info *l_comdat;
+
+ l_comdat = bfd_coff_get_comdat_section (l->sec->owner, l->sec);
+
+ /* The section names must match, and both sections must be
+ comdat and have the same comdat name, or both sections must
+ be non-comdat. LTO IR plugin sections are an exception. They
+ are always named .gnu.linkonce.t.<key> (<key> is some string)
+ and match any comdat section with comdat name of <key>, and
+ any linkonce section with the same suffix, ie.
+ .gnu.linkonce.*.<key>. */
+ if (((s_comdat != NULL) == (l_comdat != NULL)
+ && 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. */
+ return _bfd_handle_already_linked (sec, l, info);
+ }
+ }
+
+ /* This is the first section with this name. Record it. */
+ if (!bfd_section_already_linked_table_insert (already_linked_list, sec))
+ info->callbacks->einfo (_("%F%P: already_linked_table: %E\n"));
+ return FALSE;
+}
diff --git a/bfd/cofflink.c b/bfd/cofflink.c
index 27257baa9c4..bca136445de 100644
--- a/bfd/cofflink.c
+++ b/bfd/cofflink.c
@@ -392,11 +392,7 @@ coff_link_add_symbols (bfd *abfd,
section = coff_section_from_bfd_index (abfd, sym.n_scnum);
if (! obj_pe (abfd))
value -= section->vma;
- /* Treat a symbol from a discarded section as undefined. */
- if (bfd_is_abs_section (section)
- || !bfd_is_abs_section (section->output_section))
- break;
- /* Fall thru */
+ break;
case COFF_SYMBOL_UNDEFINED:
flags = 0;
diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h
index 2c80f67be77..d6e2ab29ce4 100644
--- a/bfd/elf-bfd.h
+++ b/bfd/elf-bfd.h
@@ -1801,9 +1801,8 @@ extern bfd_boolean _bfd_elf_match_sections_by_type
(bfd *, const asection *, bfd *, const asection *);
extern bfd_boolean bfd_elf_is_group_section
(bfd *, const struct bfd_section *);
-struct already_linked;
extern bfd_boolean _bfd_elf_section_already_linked
- (bfd *, struct already_linked *, struct bfd_link_info *);
+ (bfd *, asection *, 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/elflink.c b/bfd/elflink.c
index 53765b626df..528f705e8a8 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
diff --git a/bfd/libbfd-in.h b/bfd/libbfd-in.h
index db39f3cfc65..b6c90d1fb11 100644
--- a/bfd/libbfd-in.h
+++ b/bfd/libbfd-in.h
@@ -3,7 +3,7 @@
Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,
- 2010
+ 2010, 2011
Free Software Foundation, Inc.
Written by Cygnus Support.
@@ -481,7 +481,7 @@ 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 \
- ((bfd_boolean (*) (bfd *, struct already_linked*, \
+ ((bfd_boolean (*) (bfd *, asection *, \
struct bfd_link_info *)) bfd_false)
#define _bfd_nolink_bfd_define_common_symbol \
((bfd_boolean (*) (bfd *, struct bfd_link_info *, \
@@ -603,7 +603,7 @@ extern bfd_boolean _bfd_generic_link_split_section
(bfd *, struct bfd_section *);
extern bfd_boolean _bfd_generic_section_already_linked
- (bfd *, struct already_linked *, struct bfd_link_info *);
+ (bfd *, asection *, struct bfd_link_info *);
/* Generic reloc_link_order processing routine. */
extern bfd_boolean _bfd_generic_reloc_link_order
@@ -795,26 +795,16 @@ 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;
- struct already_linked linked;
+ asection *sec;
};
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 *, struct already_linked *);
+ (struct bfd_section_already_linked_hash_entry *, asection *);
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 71188dcc1e9..200a6fad319 100644
--- a/bfd/libbfd.h
+++ b/bfd/libbfd.h
@@ -8,7 +8,7 @@
Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,
- 2010
+ 2010, 2011
Free Software Foundation, Inc.
Written by Cygnus Support.
@@ -486,7 +486,7 @@ 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 \
- ((bfd_boolean (*) (bfd *, struct already_linked*, \
+ ((bfd_boolean (*) (bfd *, asection *, \
struct bfd_link_info *)) bfd_false)
#define _bfd_nolink_bfd_define_common_symbol \
((bfd_boolean (*) (bfd *, struct bfd_link_info *, \
@@ -608,7 +608,7 @@ extern bfd_boolean _bfd_generic_link_split_section
(bfd *, struct bfd_section *);
extern bfd_boolean _bfd_generic_section_already_linked
- (bfd *, struct already_linked *, struct bfd_link_info *);
+ (bfd *, asection *, struct bfd_link_info *);
/* Generic reloc_link_order processing routine. */
extern bfd_boolean _bfd_generic_reloc_link_order
@@ -800,26 +800,16 @@ 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;
- struct already_linked linked;
+ asection *sec;
};
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 *, struct already_linked *);
+ (struct bfd_section_already_linked_hash_entry *, asection *);
extern void bfd_section_already_linked_table_traverse
(bfd_boolean (*) (struct bfd_section_already_linked_hash_entry *,
void *), void *);
diff --git a/bfd/libcoff-in.h b/bfd/libcoff-in.h
index 1b651514760..00d9ab261b2 100644
--- a/bfd/libcoff-in.h
+++ b/bfd/libcoff-in.h
@@ -546,6 +546,8 @@ extern struct bfd_link_hash_table *_bfd_coff_link_hash_table_create
(bfd *);
extern const char *_bfd_coff_internal_syment_name
(bfd *, const struct internal_syment *, char *);
+extern bfd_boolean _bfd_coff_section_already_linked
+ (bfd *, asection *, struct bfd_link_info *);
extern bfd_boolean _bfd_coff_link_add_symbols
(bfd *, struct bfd_link_info *);
extern bfd_boolean _bfd_coff_final_link
diff --git a/bfd/libcoff.h b/bfd/libcoff.h
index 37b05d19701..bd58c82e479 100644
--- a/bfd/libcoff.h
+++ b/bfd/libcoff.h
@@ -550,6 +550,8 @@ extern struct bfd_link_hash_table *_bfd_coff_link_hash_table_create
(bfd *);
extern const char *_bfd_coff_internal_syment_name
(bfd *, const struct internal_syment *, char *);
+extern bfd_boolean _bfd_coff_section_already_linked
+ (bfd *, asection *, struct bfd_link_info *);
extern bfd_boolean _bfd_coff_link_add_symbols
(bfd *, struct bfd_link_info *);
extern bfd_boolean _bfd_coff_final_link
diff --git a/bfd/linker.c b/bfd/linker.c
index b3ccefd6e11..e44386232d3 100644
--- a/bfd/linker.c
+++ b/bfd/linker.c
@@ -2889,15 +2889,15 @@ FUNCTION
SYNOPSIS
bfd_boolean bfd_section_already_linked (bfd *abfd,
- struct already_linked *data,
+ asection *sec,
struct bfd_link_info *info);
DESCRIPTION
Check if @var{data} has been already linked during a reloceatable
or final link. Return TRUE if it has.
-.#define bfd_section_already_linked(abfd, data, info) \
-. BFD_SEND (abfd, _section_already_linked, (abfd, data, info))
+.#define bfd_section_already_linked(abfd, sec, info) \
+. BFD_SEND (abfd, _section_already_linked, (abfd, sec, info))
.
*/
@@ -2940,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,
- struct already_linked *data)
+ asection *sec)
{
struct bfd_section_already_linked *l;
@@ -2950,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->linked = *data;
+ l->sec = sec;
l->next = already_linked_list->entry;
already_linked_list->entry = l;
return TRUE;
@@ -2988,159 +2988,137 @@ bfd_section_already_linked_table_free (void)
bfd_hash_table_free (&_bfd_section_already_linked_table);
}
-/* This is used on non-ELF inputs. */
+/* Report warnings as appropriate for duplicate section SEC.
+ Return FALSE if we decide to keep SEC after all. */
bfd_boolean
-_bfd_generic_section_already_linked (bfd *abfd,
- struct already_linked *linked,
- struct bfd_link_info *info)
+_bfd_handle_already_linked (asection *sec,
+ struct bfd_section_already_linked *l,
+ 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;
-
- name = linked->comdat_key;
- if (name)
- {
- sec = NULL;
- flags = SEC_LINK_ONCE | SEC_LINK_DUPLICATES_DISCARD;
- s_comdat = NULL;
- }
- else
+ switch (sec->flags & SEC_LINK_DUPLICATES)
{
- sec = linked->u.sec;
- flags = sec->flags;
- if ((flags & SEC_LINK_ONCE) == 0)
- return FALSE;
+ default:
+ abort ();
- s_comdat = bfd_coff_get_comdat_section (abfd, sec);
+ 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->sec->owner->flags & BFD_PLUGIN) != 0)
+ {
+ l->sec = sec;
+ return FALSE;
+ }
+ break;
- /* 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.
+ case SEC_LINK_DUPLICATES_ONE_ONLY:
+ info->callbacks->einfo
+ (_("%B: ignoring duplicate section `%A'\n"),
+ sec->owner, sec);
+ break;
- 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. */
+ case SEC_LINK_DUPLICATES_SAME_SIZE:
+ if ((l->sec->owner->flags & BFD_PLUGIN) != 0)
+ ;
+ else if (sec->size != l->sec->size)
+ info->callbacks->einfo
+ (_("%B: duplicate section `%A' has different size\n"),
+ sec->owner, sec);
+ break;
- name = bfd_get_section_name (abfd, sec);
+ case SEC_LINK_DUPLICATES_SAME_CONTENTS:
+ if ((l->sec->owner->flags & BFD_PLUGIN) != 0)
+ ;
+ else if (sec->size != l->sec->size)
+ info->callbacks->einfo
+ (_("%B: duplicate section `%A' has different size\n"),
+ sec->owner, sec);
+ else if (sec->size != 0)
+ {
+ bfd_byte *sec_contents, *l_sec_contents = NULL;
+
+ if (!bfd_malloc_and_get_section (sec->owner, sec, &sec_contents))
+ info->callbacks->einfo
+ (_("%B: could not read contents of section `%A'\n"),
+ sec->owner, sec);
+ else if (!bfd_malloc_and_get_section (l->sec->owner, l->sec,
+ &l_sec_contents))
+ info->callbacks->einfo
+ (_("%B: could not read contents of section `%A'\n"),
+ l->sec->owner, l->sec);
+ else if (memcmp (sec_contents, l_sec_contents, sec->size) != 0)
+ info->callbacks->einfo
+ (_("%B: duplicate section `%A' has different contents\n"),
+ sec->owner, sec);
+
+ if (sec_contents)
+ free (sec_contents);
+ if (l_sec_contents)
+ free (l_sec_contents);
+ }
+ break;
}
- already_linked_list = bfd_section_already_linked_table_lookup (name);
+ /* 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 TRUE;
+}
- for (l = already_linked_list->entry; l != NULL; l = l->next)
- {
- bfd_boolean skip = FALSE;
- bfd *l_owner;
- flagword l_flags;
- struct coff_comdat_info *l_comdat;
- asection *l_sec;
+/* This is used on non-ELF inputs. */
- if (l->linked.comdat_key)
- {
- l_sec = NULL;
- l_owner = l->linked.u.abfd;
- l_comdat = NULL;
- l_flags = 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_comdat = bfd_coff_get_comdat_section (l_sec->owner, l_sec);
- }
+bfd_boolean
+_bfd_generic_section_already_linked (bfd *abfd ATTRIBUTE_UNUSED,
+ asection *sec,
+ struct bfd_link_info *info)
+{
+ const char *name;
+ struct bfd_section_already_linked *l;
+ struct bfd_section_already_linked_hash_entry *already_linked_list;
- /* We may have 3 different sections on the list: group section,
- comdat section and linkonce section. SEC may be a linkonce or
- comdat section. We always ignore group section. For non-COFF
- inputs, we also ignore comdat section.
+ if ((sec->flags & SEC_LINK_ONCE) == 0)
+ return FALSE;
- FIXME: Is that safe to match a linkonce section with a comdat
- section for COFF inputs? */
- if ((l_flags & SEC_GROUP) != 0)
- skip = TRUE;
- else if (bfd_get_flavour (abfd) == bfd_target_coff_flavour)
- {
- if (s_comdat != NULL
- && l_comdat != NULL
- && strcmp (s_comdat->name, l_comdat->name) != 0)
- skip = TRUE;
- }
- else if (l_comdat != NULL)
- skip = TRUE;
+ /* The generic linker doesn't handle section groups. */
+ if ((sec->flags & SEC_GROUP) != 0)
+ return FALSE;
- if (!skip)
- {
- /* 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;
+ /* 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.
- case SEC_LINK_DUPLICATES_ONE_ONLY:
- (*_bfd_error_handler)
- (_("%B: warning: ignoring duplicate section `%A'\n"),
- abfd, sec);
- break;
+ 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. */
- case SEC_LINK_DUPLICATES_SAME_CONTENTS:
- /* FIXME: We should really dig out the contents of both
- sections and memcmp them. The COFF/PE spec says that
- the Microsoft linker does not implement this
- correctly, so I'm not going to bother doing it
- either. */
- /* Fall through. */
- case SEC_LINK_DUPLICATES_SAME_SIZE:
- if (sec->size != l_sec->size)
- (*_bfd_error_handler)
- (_("%B: warning: duplicate section `%A' has different size\n"),
- abfd, sec);
- break;
- }
+ name = bfd_get_section_name (abfd, 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;
- }
+ already_linked_list = bfd_section_already_linked_table_lookup (name);
- return TRUE;
- }
+ l = already_linked_list->entry;
+ if (l != NULL)
+ {
+ /* The section has already been linked. See if we should
+ issue a warning. */
+ return _bfd_handle_already_linked (sec, l, info);
}
/* 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 FALSE;
}
diff --git a/bfd/targets.c b/bfd/targets.c
index 3dfa145b458..46c2c9442e3 100644
--- a/bfd/targets.c
+++ b/bfd/targets.c
@@ -176,7 +176,6 @@ DESCRIPTION
.
.{* Forward declaration. *}
.typedef struct bfd_link_info _bfd_link_info;
-.struct already_linked;
.
.{* Forward declaration. *}
.typedef struct flag_info flag_info;
@@ -512,7 +511,7 @@ BFD_JUMP_TABLE macros.
.
. {* Check if SEC has been already linked during a reloceatable or
. final link. *}
-. bfd_boolean (*_section_already_linked) (bfd *, struct already_linked *,
+. bfd_boolean (*_section_already_linked) (bfd *, asection *,
. struct bfd_link_info *);
.
. {* Define a common symbol. *}