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.
This commit is contained in:
Alan Modra 2011-08-17 00:39:41 +00:00
parent 142a8c5dcf
commit c77ec72614
19 changed files with 395 additions and 484 deletions

View File

@ -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

View File

@ -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

View File

@ -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,

View File

@ -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 =

View File

@ -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;

View File

@ -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

View File

@ -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;
}

View File

@ -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;

View File

@ -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

View File

@ -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;
}
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;
/* 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
{
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.
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);
/* 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)
if (!_bfd_handle_already_linked (sec, l, info))
return FALSE;
if (flags & SEC_GROUP)
{
default:
abort ();
asection *first = elf_next_in_group (sec);
asection *s = first;
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)
while (s != NULL)
{
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 (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;
if (flags & SEC_GROUP)
{
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)
{
asection *first = elf_next_in_group (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;
}
}
}
}
else
/* Check this linkonce section against single member groups. */
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)
{
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;
}
}
}
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 (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->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

View File

@ -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 *);

View File

@ -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 *);

View File

@ -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

View File

@ -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

View File

@ -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);
}
/* Report warnings as appropriate for duplicate section SEC.
Return FALSE if we decide to keep SEC after all. */
bfd_boolean
_bfd_handle_already_linked (asection *sec,
struct bfd_section_already_linked *l,
struct bfd_link_info *info)
{
switch (sec->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->sec->owner->flags & BFD_PLUGIN) != 0)
{
l->sec = sec;
return FALSE;
}
break;
case SEC_LINK_DUPLICATES_ONE_ONLY:
info->callbacks->einfo
(_("%B: ignoring duplicate section `%A'\n"),
sec->owner, sec);
break;
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;
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;
}
/* 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;
}
/* This is used on non-ELF inputs. */
bfd_boolean
_bfd_generic_section_already_linked (bfd *abfd,
struct already_linked *linked,
_bfd_generic_section_already_linked (bfd *abfd ATTRIBUTE_UNUSED,
asection *sec,
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
{
sec = linked->u.sec;
flags = sec->flags;
if ((flags & SEC_LINK_ONCE) == 0)
return FALSE;
if ((sec->flags & SEC_LINK_ONCE) == 0)
return FALSE;
s_comdat = bfd_coff_get_comdat_section (abfd, sec);
/* The generic linker doesn't handle section groups. */
if ((sec->flags & SEC_GROUP) != 0)
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.
/* 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. */
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 = 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)
l = already_linked_list->entry;
if (l != NULL)
{
bfd_boolean skip = FALSE;
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_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);
}
/* 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.
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;
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;
case SEC_LINK_DUPLICATES_ONE_ONLY:
(*_bfd_error_handler)
(_("%B: warning: ignoring duplicate section `%A'\n"),
abfd, sec);
break;
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;
}
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 TRUE;
}
/* 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;
}

View File

@ -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. *}

View File

@ -1,3 +1,11 @@
2011-08-17 Alan Modra <amodra@gmail.com>
PR ld/12762
* 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.
2011-08-09 Matthew Gretton-Dann <matthew.gretton-dann@arm.com>
* emultempl/armelf.em (fix_arm1176): New variable.

View File

@ -2240,12 +2240,7 @@ section_already_linked (bfd *abfd, asection *sec, void *data)
}
if (!(abfd->flags & DYNAMIC))
{
struct already_linked linked;
linked.comdat_key = NULL;
linked.u.sec = sec;
bfd_section_already_linked (abfd, &linked, &link_info);
}
bfd_section_already_linked (abfd, sec, &link_info);
}
/* The wild routines.

View File

@ -32,7 +32,6 @@
#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
@ -240,7 +239,7 @@ plugin_get_ir_dummy_bfd (const char *name, bfd *srctemplate)
{
flagword flags;
/* Create sections to own the symbols. */
/* Create section to own the symbols. */
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))
@ -285,7 +284,27 @@ 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)
{
char *name = concat (".gnu.linkonce.t.", ldsym->comdat_key,
(const char *) NULL);
section = bfd_get_section_by_name (abfd, name);
if (section != NULL)
free (name);
else
{
flagword sflags;
sflags = (SEC_CODE | SEC_HAS_CONTENTS | SEC_READONLY
| SEC_ALLOC | SEC_LOAD | SEC_KEEP | SEC_EXCLUDE
| SEC_LINK_ONCE | SEC_LINK_DUPLICATES_DISCARD);
section = bfd_make_section_anyway_with_flags (abfd, name, sflags);
if (section == NULL)
return LDPS_ERR;
}
}
else
section = bfd_get_section_by_name (abfd, ".text");
break;
case LDPK_WEAKUNDEF:
@ -389,13 +408,6 @@ add_symbols (void *handle, int nsyms, const struct ld_plugin_symbol *syms)
enum ld_plugin_status rv;
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);