PR ld/12942
bfd/ * elflink.c (elf_link_add_object_symbols): Use elf_discarded_section rather than kept_section to determine whether a symbol is from a discarded section. * cofflink.c (coff_link_add_symbols): Make symbols from discarded sections appear undefined. * elf-bfd.h (_bfd_elf_section_already_linked): Replace "asection *" with "struct already_linked *". * libbfd-in.h (_bfd_nolink_section_already_linked): Likewise. (_bfd_generic_section_already_linked): Likewise. (bfd_section_already_linked_table_insert): Likewise. (struct already_linked): New. (struct bfd_section_already_linked): Use it. * elflink.c (_bfd_elf_section_already_linked): Replace. "asection *" with "struct already_linked *". Replace the plugin dummy with the LTO output. * linker.c (_bfd_generic_section_already_linked): Likewise. * targets.c (struct already_linked): Add forward declaration. (bfd_target): Replace "struct bfd_section *" with "struct already_linked *" in _section_already_linked. * bfd-in2.h: Regenerate. * libbfd.h: Regenerate. include/ * bfdlink.h (bfd_link_info): Add loading_lto_outputs. ld/ * ldlang.c (section_already_linked): Pass "struct already_linked *" to bfd_section_already_linked. (lang_process): Set link_info.loading_lto_outputs before loading LTO outputs. * plugin.c: Include "libbfd.h". (add_symbols): Call bfd_section_already_linked with comdat_key.
This commit is contained in:
parent
beabb2c68f
commit
0c51100021
@ -1,3 +1,32 @@
|
||||
2011-07-09 Alan Modra <amodra@gmail.com>
|
||||
|
||||
PR ld/12942
|
||||
* elflink.c (elf_link_add_object_symbols): Use elf_discarded_section
|
||||
rather than kept_section to determine whether a symbol is from
|
||||
a discarded section.
|
||||
* cofflink.c (coff_link_add_symbols): Make symbols from discarded
|
||||
sections appear undefined.
|
||||
|
||||
2011-07-09 H.J. Lu <hongjiu.lu@intel.com>
|
||||
|
||||
PR ld/12942
|
||||
* elf-bfd.h (_bfd_elf_section_already_linked): Replace
|
||||
"asection *" with "struct already_linked *".
|
||||
* libbfd-in.h (_bfd_nolink_section_already_linked): Likewise.
|
||||
(_bfd_generic_section_already_linked): Likewise.
|
||||
(bfd_section_already_linked_table_insert): Likewise.
|
||||
(struct already_linked): New.
|
||||
(struct bfd_section_already_linked): Use it.
|
||||
* elflink.c (_bfd_elf_section_already_linked): Replace.
|
||||
"asection *" with "struct already_linked *". Replace the plugin
|
||||
dummy with the LTO output.
|
||||
* linker.c (_bfd_generic_section_already_linked): Likewise.
|
||||
* targets.c (struct already_linked): Add forward declaration.
|
||||
(bfd_target): Replace "struct bfd_section *" with
|
||||
"struct already_linked *" in _section_already_linked.
|
||||
* bfd-in2.h: Regenerate.
|
||||
* libbfd.h: Regenerate.
|
||||
|
||||
2011-07-06 Tristan Gingold <gingold@adacore.com>
|
||||
|
||||
* mach-o.h: Move loader related definitions to
|
||||
|
@ -5726,6 +5726,7 @@ enum bfd_endian { BFD_ENDIAN_BIG, BFD_ENDIAN_LITTLE, BFD_ENDIAN_UNKNOWN };
|
||||
|
||||
/* Forward declaration. */
|
||||
typedef struct bfd_link_info _bfd_link_info;
|
||||
struct already_linked;
|
||||
|
||||
typedef struct bfd_target
|
||||
{
|
||||
@ -6051,7 +6052,7 @@ typedef struct bfd_target
|
||||
|
||||
/* Check if SEC has been already linked during a reloceatable or
|
||||
final link. */
|
||||
void (*_section_already_linked) (bfd *, struct bfd_section *,
|
||||
void (*_section_already_linked) (bfd *, struct already_linked *,
|
||||
struct bfd_link_info *);
|
||||
|
||||
/* Define a common symbol. */
|
||||
@ -6121,11 +6122,12 @@ bfd_boolean bfd_link_split_section (bfd *abfd, asection *sec);
|
||||
#define bfd_link_split_section(abfd, sec) \
|
||||
BFD_SEND (abfd, _bfd_link_split_section, (abfd, sec))
|
||||
|
||||
void bfd_section_already_linked (bfd *abfd, asection *sec,
|
||||
void bfd_section_already_linked (bfd *abfd,
|
||||
struct already_linked *data,
|
||||
struct bfd_link_info *info);
|
||||
|
||||
#define bfd_section_already_linked(abfd, sec, info) \
|
||||
BFD_SEND (abfd, _section_already_linked, (abfd, sec, info))
|
||||
#define bfd_section_already_linked(abfd, data, info) \
|
||||
BFD_SEND (abfd, _section_already_linked, (abfd, data, info))
|
||||
|
||||
bfd_boolean bfd_generic_define_common_symbol
|
||||
(bfd *output_bfd, struct bfd_link_info *info,
|
||||
|
@ -392,7 +392,11 @@ coff_link_add_symbols (bfd *abfd,
|
||||
section = coff_section_from_bfd_index (abfd, sym.n_scnum);
|
||||
if (! obj_pe (abfd))
|
||||
value -= section->vma;
|
||||
break;
|
||||
/* 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 */
|
||||
|
||||
case COFF_SYMBOL_UNDEFINED:
|
||||
flags = 0;
|
||||
|
@ -1793,7 +1793,7 @@ extern bfd_boolean _bfd_elf_match_sections_by_type
|
||||
extern bfd_boolean bfd_elf_is_group_section
|
||||
(bfd *, const struct bfd_section *);
|
||||
extern void _bfd_elf_section_already_linked
|
||||
(bfd *, struct bfd_section *, struct bfd_link_info *);
|
||||
(bfd *, struct already_linked *, struct bfd_link_info *);
|
||||
extern void bfd_elf_set_group_contents
|
||||
(bfd *, asection *, void *);
|
||||
extern asection *_bfd_elf_check_kept_section
|
||||
|
333
bfd/elflink.c
333
bfd/elflink.c
@ -3900,7 +3900,7 @@ error_free_dyn:
|
||||
sec = bfd_section_from_elf_index (abfd, isym->st_shndx);
|
||||
if (sec == NULL)
|
||||
sec = bfd_abs_section_ptr;
|
||||
else if (sec->kept_section)
|
||||
else if (elf_discarded_section (sec))
|
||||
{
|
||||
/* Symbols from discarded section are undefined. We keep
|
||||
its visibility. */
|
||||
@ -12438,63 +12438,100 @@ section_signature (asection *sec)
|
||||
}
|
||||
|
||||
void
|
||||
_bfd_elf_section_already_linked (bfd *abfd, asection *sec,
|
||||
_bfd_elf_section_already_linked (bfd *abfd,
|
||||
struct already_linked *linked,
|
||||
struct bfd_link_info *info)
|
||||
{
|
||||
flagword flags;
|
||||
const char *name, *p;
|
||||
struct bfd_section_already_linked *l;
|
||||
struct bfd_section_already_linked_hash_entry *already_linked_list;
|
||||
asection *sec, *l_sec;
|
||||
|
||||
if (sec->output_section == bfd_abs_section_ptr)
|
||||
return;
|
||||
|
||||
flags = sec->flags;
|
||||
|
||||
/* Return if it isn't a linkonce section. A comdat group section
|
||||
also has SEC_LINK_ONCE set. */
|
||||
if ((flags & SEC_LINK_ONCE) == 0)
|
||||
return;
|
||||
|
||||
/* Don't put group member sections on our list of already linked
|
||||
sections. They are handled as a group via their group section. */
|
||||
if (elf_sec_group (sec) != NULL)
|
||||
return;
|
||||
|
||||
/* FIXME: When doing a relocatable link, we may have trouble
|
||||
copying relocations in other sections that refer to local symbols
|
||||
in the section being discarded. Those relocations will have to
|
||||
be converted somehow; as of this writing I'm not sure that any of
|
||||
the backends handle that correctly.
|
||||
|
||||
It is tempting to instead not discard link once sections when
|
||||
doing a relocatable link (technically, they should be discarded
|
||||
whenever we are building constructors). However, that fails,
|
||||
because the linker winds up combining all the link once sections
|
||||
into a single large link once section, which defeats the purpose
|
||||
of having link once sections in the first place.
|
||||
|
||||
Also, not merging link once sections in a relocatable link
|
||||
causes trouble for MIPS ELF, which relies on link once semantics
|
||||
to handle the .reginfo section correctly. */
|
||||
|
||||
name = section_signature (sec);
|
||||
|
||||
if (CONST_STRNEQ (name, ".gnu.linkonce.")
|
||||
&& (p = strchr (name + sizeof (".gnu.linkonce.") - 1, '.')) != NULL)
|
||||
p++;
|
||||
p = name = linked->comdat_key;
|
||||
if (name)
|
||||
{
|
||||
sec = NULL;
|
||||
flags = SEC_GROUP | SEC_LINK_ONCE | SEC_LINK_DUPLICATES_DISCARD;
|
||||
}
|
||||
else
|
||||
p = name;
|
||||
{
|
||||
sec = linked->u.sec;
|
||||
if (sec->output_section == bfd_abs_section_ptr)
|
||||
return;
|
||||
|
||||
flags = sec->flags;
|
||||
|
||||
/* Return if it isn't a linkonce section. A comdat group section
|
||||
also has SEC_LINK_ONCE set. */
|
||||
if ((flags & SEC_LINK_ONCE) == 0)
|
||||
return;
|
||||
|
||||
/* Don't put group member sections on our list of already linked
|
||||
sections. They are handled as a group via their group section.
|
||||
*/
|
||||
if (elf_sec_group (sec) != NULL)
|
||||
return;
|
||||
|
||||
/* FIXME: When doing a relocatable link, we may have trouble
|
||||
copying relocations in other sections that refer to local symbols
|
||||
in the section being discarded. Those relocations will have to
|
||||
be converted somehow; as of this writing I'm not sure that any of
|
||||
the backends handle that correctly.
|
||||
|
||||
It is tempting to instead not discard link once sections when
|
||||
doing a relocatable link (technically, they should be discarded
|
||||
whenever we are building constructors). However, that fails,
|
||||
because the linker winds up combining all the link once sections
|
||||
into a single large link once section, which defeats the purpose
|
||||
of having link once sections in the first place.
|
||||
|
||||
Also, not merging link once sections in a relocatable link
|
||||
causes trouble for MIPS ELF, which relies on link once semantics
|
||||
to handle the .reginfo section correctly. */
|
||||
|
||||
name = section_signature (sec);
|
||||
|
||||
if (CONST_STRNEQ (name, ".gnu.linkonce.")
|
||||
&& ((p = strchr (name + sizeof (".gnu.linkonce.") - 1, '.'))
|
||||
!= NULL))
|
||||
p++;
|
||||
else
|
||||
p = name;
|
||||
}
|
||||
|
||||
already_linked_list = bfd_section_already_linked_table_lookup (p);
|
||||
|
||||
for (l = already_linked_list->entry; l != NULL; l = l->next)
|
||||
{
|
||||
bfd_boolean l_coff_comdat_sec;
|
||||
flagword l_flags;
|
||||
bfd *l_owner;
|
||||
const char *l_name = l->linked.comdat_key;
|
||||
if (l_name)
|
||||
{
|
||||
l_sec = NULL;
|
||||
l_owner = l->linked.u.abfd;
|
||||
l_flags = (SEC_GROUP
|
||||
| SEC_LINK_ONCE
|
||||
| SEC_LINK_DUPLICATES_DISCARD);
|
||||
l_coff_comdat_sec = FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
l_sec = l->linked.u.sec;
|
||||
l_owner = l_sec->owner;
|
||||
l_flags = l_sec->flags;
|
||||
l_coff_comdat_sec
|
||||
= !!bfd_coff_get_comdat_section (l_sec->owner, l_sec);
|
||||
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->sec->flags & SEC_GROUP)
|
||||
&& strcmp (name, section_signature (l->sec)) == 0
|
||||
&& bfd_coff_get_comdat_section (l->sec->owner, l->sec) == NULL)
|
||||
if ((flags & SEC_GROUP) == (l_flags & SEC_GROUP)
|
||||
&& strcmp (name, l_name) == 0
|
||||
&& !l_coff_comdat_sec)
|
||||
{
|
||||
/* The section has already been linked. See if we should
|
||||
issue a warning. */
|
||||
@ -12504,6 +12541,18 @@ _bfd_elf_section_already_linked (bfd *abfd, asection *sec,
|
||||
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;
|
||||
}
|
||||
break;
|
||||
|
||||
case SEC_LINK_DUPLICATES_ONE_ONLY:
|
||||
@ -12513,14 +12562,20 @@ _bfd_elf_section_already_linked (bfd *abfd, asection *sec,
|
||||
break;
|
||||
|
||||
case SEC_LINK_DUPLICATES_SAME_SIZE:
|
||||
if (sec->size != l->sec->size)
|
||||
if (!sec || !l_sec)
|
||||
abort ();
|
||||
|
||||
if (sec->size != l_sec->size)
|
||||
(*_bfd_error_handler)
|
||||
(_("%B: duplicate section `%A' has different size"),
|
||||
abfd, sec);
|
||||
break;
|
||||
|
||||
case SEC_LINK_DUPLICATES_SAME_CONTENTS:
|
||||
if (sec->size != l->sec->size)
|
||||
if (!sec || !l_sec)
|
||||
abort ();
|
||||
|
||||
if (sec->size != l_sec->size)
|
||||
(*_bfd_error_handler)
|
||||
(_("%B: duplicate section `%A' has different size"),
|
||||
abfd, sec);
|
||||
@ -12532,11 +12587,11 @@ _bfd_elf_section_already_linked (bfd *abfd, asection *sec,
|
||||
(*_bfd_error_handler)
|
||||
(_("%B: warning: could not read contents of section `%A'"),
|
||||
abfd, sec);
|
||||
else if (!bfd_malloc_and_get_section (l->sec->owner, l->sec,
|
||||
else if (!bfd_malloc_and_get_section (l_sec->owner, l_sec,
|
||||
&l_sec_contents))
|
||||
(*_bfd_error_handler)
|
||||
(_("%B: warning: could not read contents of section `%A'"),
|
||||
l->sec->owner, l->sec);
|
||||
l_sec->owner, l_sec);
|
||||
else if (memcmp (sec_contents, l_sec_contents, sec->size) != 0)
|
||||
(*_bfd_error_handler)
|
||||
(_("%B: warning: duplicate section `%A' has different contents"),
|
||||
@ -12550,28 +12605,31 @@ _bfd_elf_section_already_linked (bfd *abfd, asection *sec,
|
||||
break;
|
||||
}
|
||||
|
||||
/* Set the output_section field so that lang_add_section
|
||||
does not create a lang_input_section structure for this
|
||||
section. Since there might be a symbol in the section
|
||||
being discarded, we must retain a pointer to the section
|
||||
which we are really going to use. */
|
||||
sec->output_section = bfd_abs_section_ptr;
|
||||
sec->kept_section = l->sec;
|
||||
|
||||
if (flags & SEC_GROUP)
|
||||
if (sec)
|
||||
{
|
||||
asection *first = elf_next_in_group (sec);
|
||||
asection *s = first;
|
||||
/* Set the output_section field so that lang_add_section
|
||||
does not create a lang_input_section structure for this
|
||||
section. Since there might be a symbol in the section
|
||||
being discarded, we must retain a pointer to the section
|
||||
which we are really going to use. */
|
||||
sec->output_section = bfd_abs_section_ptr;
|
||||
sec->kept_section = l_sec;
|
||||
|
||||
while (s != NULL)
|
||||
if (flags & SEC_GROUP)
|
||||
{
|
||||
s->output_section = bfd_abs_section_ptr;
|
||||
/* Record which group discards it. */
|
||||
s->kept_section = l->sec;
|
||||
s = elf_next_in_group (s);
|
||||
/* These lists are circular. */
|
||||
if (s == first)
|
||||
break;
|
||||
asection *first = elf_next_in_group (sec);
|
||||
asection *s = first;
|
||||
|
||||
while (s != NULL)
|
||||
{
|
||||
s->output_section = bfd_abs_section_ptr;
|
||||
/* Record which group discards it. */
|
||||
s->kept_section = l_sec;
|
||||
s = elf_next_in_group (s);
|
||||
/* These lists are circular. */
|
||||
if (s == first)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -12579,67 +12637,100 @@ _bfd_elf_section_already_linked (bfd *abfd, asection *sec,
|
||||
}
|
||||
}
|
||||
|
||||
/* A single member comdat group section may be discarded by a
|
||||
linkonce section and vice versa. */
|
||||
|
||||
if ((flags & SEC_GROUP) != 0)
|
||||
if (sec)
|
||||
{
|
||||
asection *first = elf_next_in_group (sec);
|
||||
/* A single member comdat group section may be discarded by a
|
||||
linkonce section and vice versa. */
|
||||
|
||||
if (first != NULL && elf_next_in_group (first) == first)
|
||||
/* Check this single member group against linkonce sections. */
|
||||
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;
|
||||
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) == 0
|
||||
&& bfd_coff_get_comdat_section (l->sec->owner, l->sec) == NULL
|
||||
&& bfd_elf_match_symbols_in_sections (l->sec, first, info))
|
||||
{
|
||||
first->output_section = bfd_abs_section_ptr;
|
||||
first->kept_section = l->sec;
|
||||
sec->output_section = bfd_abs_section_ptr;
|
||||
break;
|
||||
}
|
||||
{
|
||||
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;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Do not complain on unresolved relocations in `.gnu.linkonce.r.F'
|
||||
referencing its discarded `.gnu.linkonce.t.F' counterpart -
|
||||
g++-3.4 specific as g++-4.x is using COMDAT groups (without the
|
||||
`.gnu.linkonce' prefix) instead. `.gnu.linkonce.r.*' were the
|
||||
`.rodata' part of its matching `.gnu.linkonce.t.*'. If
|
||||
`.gnu.linkonce.r.F' is not discarded but its `.gnu.linkonce.t.F'
|
||||
is discarded means we chose one-only `.gnu.linkonce.t.F' section
|
||||
from a different bfd not requiring any `.gnu.linkonce.r.F'.
|
||||
Thus `.gnu.linkonce.r.F' should be discarded. The reverse order
|
||||
cannot happen as there is never a bfd with only the
|
||||
`.gnu.linkonce.r.F' section. The order of sections in a bfd
|
||||
does not matter as here were are looking only for cross-bfd
|
||||
sections. */
|
||||
|
||||
if ((flags & SEC_GROUP) == 0
|
||||
&& CONST_STRNEQ (name, ".gnu.linkonce.r."))
|
||||
for (l = already_linked_list->entry; l != NULL; l = l->next)
|
||||
{
|
||||
if (l->linked.comdat_key == NULL)
|
||||
{
|
||||
l_sec = l->linked.u.sec;
|
||||
|
||||
if ((l_sec->flags & SEC_GROUP) == 0
|
||||
&& CONST_STRNEQ (l_sec->name, ".gnu.linkonce.t."))
|
||||
{
|
||||
if (abfd != l_sec->owner)
|
||||
sec->output_section = bfd_abs_section_ptr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
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, sec))
|
||||
if (! bfd_section_already_linked_table_insert (already_linked_list,
|
||||
linked))
|
||||
info->callbacks->einfo (_("%F%P: already_linked_table: %E\n"));
|
||||
}
|
||||
|
||||
|
@ -478,7 +478,8 @@ extern bfd_boolean _bfd_generic_set_section_contents
|
||||
#define _bfd_nolink_bfd_link_split_section \
|
||||
((bfd_boolean (*) (bfd *, struct bfd_section *)) bfd_false)
|
||||
#define _bfd_nolink_section_already_linked \
|
||||
((void (*) (bfd *, struct bfd_section *, struct bfd_link_info *)) bfd_void)
|
||||
((void (*) (bfd *, struct already_linked*, \
|
||||
struct bfd_link_info *)) bfd_void)
|
||||
#define _bfd_nolink_bfd_define_common_symbol \
|
||||
((bfd_boolean (*) (bfd *, struct bfd_link_info *, \
|
||||
struct bfd_link_hash_entry *)) bfd_false)
|
||||
@ -599,7 +600,7 @@ extern bfd_boolean _bfd_generic_link_split_section
|
||||
(bfd *, struct bfd_section *);
|
||||
|
||||
extern void _bfd_generic_section_already_linked
|
||||
(bfd *, struct bfd_section *, struct bfd_link_info *);
|
||||
(bfd *, struct already_linked *, struct bfd_link_info *);
|
||||
|
||||
/* Generic reloc_link_order processing routine. */
|
||||
extern bfd_boolean _bfd_generic_reloc_link_order
|
||||
@ -791,16 +792,26 @@ struct bfd_section_already_linked_hash_entry
|
||||
struct bfd_section_already_linked *entry;
|
||||
};
|
||||
|
||||
struct already_linked
|
||||
{
|
||||
const char *comdat_key;
|
||||
union
|
||||
{
|
||||
asection *sec;
|
||||
bfd *abfd;
|
||||
} u;
|
||||
};
|
||||
|
||||
struct bfd_section_already_linked
|
||||
{
|
||||
struct bfd_section_already_linked *next;
|
||||
asection *sec;
|
||||
struct already_linked linked;
|
||||
};
|
||||
|
||||
extern struct bfd_section_already_linked_hash_entry *
|
||||
bfd_section_already_linked_table_lookup (const char *);
|
||||
extern bfd_boolean bfd_section_already_linked_table_insert
|
||||
(struct bfd_section_already_linked_hash_entry *, asection *);
|
||||
(struct bfd_section_already_linked_hash_entry *, struct already_linked *);
|
||||
extern void bfd_section_already_linked_table_traverse
|
||||
(bfd_boolean (*) (struct bfd_section_already_linked_hash_entry *,
|
||||
void *), void *);
|
||||
|
19
bfd/libbfd.h
19
bfd/libbfd.h
@ -483,7 +483,8 @@ extern bfd_boolean _bfd_generic_set_section_contents
|
||||
#define _bfd_nolink_bfd_link_split_section \
|
||||
((bfd_boolean (*) (bfd *, struct bfd_section *)) bfd_false)
|
||||
#define _bfd_nolink_section_already_linked \
|
||||
((void (*) (bfd *, struct bfd_section *, struct bfd_link_info *)) bfd_void)
|
||||
((void (*) (bfd *, struct already_linked*, \
|
||||
struct bfd_link_info *)) bfd_void)
|
||||
#define _bfd_nolink_bfd_define_common_symbol \
|
||||
((bfd_boolean (*) (bfd *, struct bfd_link_info *, \
|
||||
struct bfd_link_hash_entry *)) bfd_false)
|
||||
@ -604,7 +605,7 @@ extern bfd_boolean _bfd_generic_link_split_section
|
||||
(bfd *, struct bfd_section *);
|
||||
|
||||
extern void _bfd_generic_section_already_linked
|
||||
(bfd *, struct bfd_section *, struct bfd_link_info *);
|
||||
(bfd *, struct already_linked *, struct bfd_link_info *);
|
||||
|
||||
/* Generic reloc_link_order processing routine. */
|
||||
extern bfd_boolean _bfd_generic_reloc_link_order
|
||||
@ -796,16 +797,26 @@ struct bfd_section_already_linked_hash_entry
|
||||
struct bfd_section_already_linked *entry;
|
||||
};
|
||||
|
||||
struct already_linked
|
||||
{
|
||||
const char *comdat_key;
|
||||
union
|
||||
{
|
||||
asection *sec;
|
||||
bfd *abfd;
|
||||
} u;
|
||||
};
|
||||
|
||||
struct bfd_section_already_linked
|
||||
{
|
||||
struct bfd_section_already_linked *next;
|
||||
asection *sec;
|
||||
struct already_linked linked;
|
||||
};
|
||||
|
||||
extern struct bfd_section_already_linked_hash_entry *
|
||||
bfd_section_already_linked_table_lookup (const char *);
|
||||
extern bfd_boolean bfd_section_already_linked_table_insert
|
||||
(struct bfd_section_already_linked_hash_entry *, asection *);
|
||||
(struct bfd_section_already_linked_hash_entry *, struct already_linked *);
|
||||
extern void bfd_section_already_linked_table_traverse
|
||||
(bfd_boolean (*) (struct bfd_section_already_linked_hash_entry *,
|
||||
void *), void *);
|
||||
|
121
bfd/linker.c
121
bfd/linker.c
@ -2888,15 +2888,16 @@ FUNCTION
|
||||
bfd_section_already_linked
|
||||
|
||||
SYNOPSIS
|
||||
void bfd_section_already_linked (bfd *abfd, asection *sec,
|
||||
void bfd_section_already_linked (bfd *abfd,
|
||||
struct already_linked *data,
|
||||
struct bfd_link_info *info);
|
||||
|
||||
DESCRIPTION
|
||||
Check if @var{sec} has been already linked during a reloceatable
|
||||
Check if @var{data} has been already linked during a reloceatable
|
||||
or final link.
|
||||
|
||||
.#define bfd_section_already_linked(abfd, sec, info) \
|
||||
. BFD_SEND (abfd, _section_already_linked, (abfd, sec, info))
|
||||
.#define bfd_section_already_linked(abfd, data, info) \
|
||||
. BFD_SEND (abfd, _section_already_linked, (abfd, data, info))
|
||||
.
|
||||
|
||||
*/
|
||||
@ -2939,7 +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,
|
||||
asection *sec)
|
||||
struct already_linked *data)
|
||||
{
|
||||
struct bfd_section_already_linked *l;
|
||||
|
||||
@ -2949,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->sec = sec;
|
||||
l->linked = *data;
|
||||
l->next = already_linked_list->entry;
|
||||
already_linked_list->entry = l;
|
||||
return TRUE;
|
||||
@ -2990,42 +2991,74 @@ bfd_section_already_linked_table_free (void)
|
||||
/* This is used on non-ELF inputs. */
|
||||
|
||||
void
|
||||
_bfd_generic_section_already_linked (bfd *abfd, asection *sec,
|
||||
_bfd_generic_section_already_linked (bfd *abfd,
|
||||
struct already_linked *linked,
|
||||
struct bfd_link_info *info)
|
||||
{
|
||||
flagword flags;
|
||||
const char *name;
|
||||
struct bfd_section_already_linked *l;
|
||||
struct bfd_section_already_linked_hash_entry *already_linked_list;
|
||||
struct coff_comdat_info *s_comdat;
|
||||
asection *sec;
|
||||
|
||||
flags = sec->flags;
|
||||
if ((flags & SEC_LINK_ONCE) == 0)
|
||||
return;
|
||||
name = linked->comdat_key;
|
||||
if (name)
|
||||
{
|
||||
sec = NULL;
|
||||
flags = SEC_GROUP | SEC_LINK_ONCE | SEC_LINK_DUPLICATES_DISCARD;
|
||||
s_comdat = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
sec = linked->u.sec;
|
||||
flags = sec->flags;
|
||||
if ((flags & SEC_LINK_ONCE) == 0)
|
||||
return;
|
||||
|
||||
/* 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.
|
||||
s_comdat = bfd_coff_get_comdat_section (abfd, sec);
|
||||
|
||||
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. */
|
||||
/* 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.
|
||||
|
||||
name = bfd_get_section_name (abfd, sec);
|
||||
It is tempting to instead not discard link once sections when
|
||||
doing a relocatable link (technically, they should be discarded
|
||||
whenever we are building constructors). However, that fails,
|
||||
because the linker winds up combining all the link once sections
|
||||
into a single large link once section, which defeats the purpose
|
||||
of having link once sections in the first place. */
|
||||
|
||||
name = bfd_get_section_name (abfd, sec);
|
||||
}
|
||||
|
||||
already_linked_list = bfd_section_already_linked_table_lookup (name);
|
||||
|
||||
for (l = already_linked_list->entry; l != NULL; l = l->next)
|
||||
{
|
||||
bfd_boolean skip = FALSE;
|
||||
struct coff_comdat_info *s_comdat
|
||||
= bfd_coff_get_comdat_section (abfd, sec);
|
||||
struct coff_comdat_info *l_comdat
|
||||
= bfd_coff_get_comdat_section (l->sec->owner, l->sec);
|
||||
bfd *l_owner;
|
||||
flagword l_flags;
|
||||
struct coff_comdat_info *l_comdat;
|
||||
asection *l_sec;
|
||||
|
||||
if (l->linked.comdat_key)
|
||||
{
|
||||
l_sec = NULL;
|
||||
l_owner = l->linked.u.abfd;
|
||||
l_comdat = NULL;
|
||||
l_flags = (SEC_GROUP
|
||||
| SEC_LINK_ONCE
|
||||
| SEC_LINK_DUPLICATES_DISCARD);
|
||||
}
|
||||
else
|
||||
{
|
||||
l_sec = l->linked.u.sec;
|
||||
l_owner = l_sec->owner;
|
||||
l_comdat = bfd_coff_get_comdat_section (l_sec->owner, l_sec);
|
||||
}
|
||||
|
||||
/* We may have 3 different sections on the list: group section,
|
||||
comdat section and linkonce section. SEC may be a linkonce or
|
||||
@ -3034,7 +3067,7 @@ _bfd_generic_section_already_linked (bfd *abfd, asection *sec,
|
||||
|
||||
FIXME: Is that safe to match a linkonce section with a comdat
|
||||
section for COFF inputs? */
|
||||
if ((l->sec->flags & SEC_GROUP) != 0)
|
||||
if ((l_flags & SEC_GROUP) != 0)
|
||||
skip = TRUE;
|
||||
else if (bfd_get_flavour (abfd) == bfd_target_coff_flavour)
|
||||
{
|
||||
@ -3056,6 +3089,18 @@ _bfd_generic_section_already_linked (bfd *abfd, asection *sec,
|
||||
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;
|
||||
}
|
||||
break;
|
||||
|
||||
case SEC_LINK_DUPLICATES_ONE_ONLY:
|
||||
@ -3072,27 +3117,31 @@ _bfd_generic_section_already_linked (bfd *abfd, asection *sec,
|
||||
either. */
|
||||
/* Fall through. */
|
||||
case SEC_LINK_DUPLICATES_SAME_SIZE:
|
||||
if (sec->size != l->sec->size)
|
||||
if (sec->size != l_sec->size)
|
||||
(*_bfd_error_handler)
|
||||
(_("%B: warning: duplicate section `%A' has different size\n"),
|
||||
abfd, sec);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Set the output_section field so that lang_add_section
|
||||
does not create a lang_input_section structure for this
|
||||
section. Since there might be a symbol in the section
|
||||
being discarded, we must retain a pointer to the section
|
||||
which we are really going to use. */
|
||||
sec->output_section = bfd_abs_section_ptr;
|
||||
sec->kept_section = l->sec;
|
||||
if (sec)
|
||||
{
|
||||
/* Set the output_section field so that lang_add_section
|
||||
does not create a lang_input_section structure for this
|
||||
section. Since there might be a symbol in the section
|
||||
being discarded, we must retain a pointer to the section
|
||||
which we are really going to use. */
|
||||
sec->output_section = bfd_abs_section_ptr;
|
||||
sec->kept_section = l_sec;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* This is the first section with this name. Record it. */
|
||||
if (! bfd_section_already_linked_table_insert (already_linked_list, sec))
|
||||
if (! bfd_section_already_linked_table_insert (already_linked_list,
|
||||
linked))
|
||||
info->callbacks->einfo (_("%F%P: already_linked_table: %E\n"));
|
||||
}
|
||||
|
||||
|
@ -176,6 +176,7 @@ DESCRIPTION
|
||||
.
|
||||
.{* Forward declaration. *}
|
||||
.typedef struct bfd_link_info _bfd_link_info;
|
||||
.struct already_linked;
|
||||
.
|
||||
.typedef struct bfd_target
|
||||
.{
|
||||
@ -503,7 +504,7 @@ BFD_JUMP_TABLE macros.
|
||||
.
|
||||
. {* Check if SEC has been already linked during a reloceatable or
|
||||
. final link. *}
|
||||
. void (*_section_already_linked) (bfd *, struct bfd_section *,
|
||||
. void (*_section_already_linked) (bfd *, struct already_linked *,
|
||||
. struct bfd_link_info *);
|
||||
.
|
||||
. {* Define a common symbol. *}
|
||||
|
@ -1,3 +1,8 @@
|
||||
2011-07-09 H.J. Lu <hongjiu.lu@intel.com>
|
||||
|
||||
PR ld/12942
|
||||
* bfdlink.h (bfd_link_info): Add loading_lto_outputs.
|
||||
|
||||
2011-07-01 Joel Brobecker <brobecker@adacore.com>
|
||||
|
||||
* filenames.h (HAVE_CASE_INSENSITIVE_FILE_SYSTEM): Define
|
||||
|
@ -357,6 +357,9 @@ struct bfd_link_info
|
||||
linker created sections, TRUE if it should be omitted. */
|
||||
unsigned int no_ld_generated_unwind_info: 1;
|
||||
|
||||
/* TRUE if we are loading LTO outputs. */
|
||||
unsigned int loading_lto_outputs: 1;
|
||||
|
||||
/* Non-NULL if .note.gnu.build-id section should be created. */
|
||||
char *emit_note_gnu_build_id;
|
||||
|
||||
|
10
ld/ChangeLog
10
ld/ChangeLog
@ -1,3 +1,13 @@
|
||||
2011-07-09 H.J. Lu <hongjiu.lu@intel.com>
|
||||
|
||||
PR ld/12942
|
||||
* ldlang.c (section_already_linked): Pass "struct already_linked *"
|
||||
to bfd_section_already_linked.
|
||||
(lang_process): Set link_info.loading_lto_outputs before
|
||||
loading LTO outputs.
|
||||
* plugin.c: Include "libbfd.h".
|
||||
(add_symbols): Call bfd_section_already_linked with comdat_key.
|
||||
|
||||
2011-06-20 H.J. Lu <hongjiu.lu@intel.com>
|
||||
|
||||
* configure.tgt: Revert x32 change.
|
||||
|
@ -2237,7 +2237,12 @@ section_already_linked (bfd *abfd, asection *sec, void *data)
|
||||
}
|
||||
|
||||
if (!(abfd->flags & DYNAMIC))
|
||||
bfd_section_already_linked (abfd, sec, &link_info);
|
||||
{
|
||||
struct already_linked linked;
|
||||
linked.comdat_key = NULL;
|
||||
linked.u.sec = sec;
|
||||
bfd_section_already_linked (abfd, &linked, &link_info);
|
||||
}
|
||||
}
|
||||
|
||||
/* The wild routines.
|
||||
@ -6544,6 +6549,7 @@ lang_process (void)
|
||||
einfo (_("%P%F: %s: plugin reported error after all symbols read\n"),
|
||||
plugin_error_plugin ());
|
||||
/* Open any newly added files, updating the file chains. */
|
||||
link_info.loading_lto_outputs = TRUE;
|
||||
open_input_bfds (added.head, OPEN_BFD_NORMAL);
|
||||
/* Restore the global list pointer now they have all been added. */
|
||||
lang_list_remove_tail (stat_ptr, &added);
|
||||
|
12
ld/plugin.c
12
ld/plugin.c
@ -32,6 +32,7 @@
|
||||
#include "plugin.h"
|
||||
#include "plugin-api.h"
|
||||
#include "elf-bfd.h"
|
||||
#include "libbfd.h"
|
||||
#if !defined (HAVE_DLFCN_H) && defined (HAVE_WINDOWS_H)
|
||||
#include <windows.h>
|
||||
#endif
|
||||
@ -385,7 +386,16 @@ add_symbols (void *handle, int nsyms, const struct ld_plugin_symbol *syms)
|
||||
for (n = 0; n < nsyms; n++)
|
||||
{
|
||||
enum ld_plugin_status rv;
|
||||
asymbol *bfdsym = bfd_make_empty_symbol (abfd);
|
||||
asymbol *bfdsym;
|
||||
|
||||
if (syms[n].comdat_key)
|
||||
{
|
||||
struct already_linked linked;
|
||||
linked.comdat_key = xstrdup (syms[n].comdat_key);
|
||||
linked.u.abfd = abfd;
|
||||
bfd_section_already_linked (abfd, &linked, &link_info);
|
||||
}
|
||||
bfdsym = bfd_make_empty_symbol (abfd);
|
||||
symptrs[n] = bfdsym;
|
||||
rv = asymbol_from_plugin_symbol (abfd, bfdsym, syms + n);
|
||||
if (rv != LDPS_OK)
|
||||
|
Loading…
x
Reference in New Issue
Block a user