forked from Imagelibrary/binutils-gdb
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:
381
bfd/elflink.c
381
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;
|
||||
}
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user