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

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