This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
Re: Fix PR12762 using linkonce sections in plugin bfd
Revised patch. This one gives the plugin comdat_key symbols sections
named .gnu.linkonce.t.<comdat_key>, so that SEC_LINK_ONCE gets set for
the sections when recreating them during bfd_make_readable().
I've also given the COFF backend its own bfd_section_already_linked
and tidied the existing bfd_section_already_linked functions. I'd
appreciate someone familiar with our COFF support reviewing
_bfd_coff_section_already_linked in case I've made some glaring
mistakes.. The old code basically matched on section name, but if
both sections had a comdat symbol then the symbols had to match too.
That meant a comdat section could match a non-comdat section with the
same name, something the new code specifically disallows, and anyway
is a side-effect of hashing on the comdat key. COFF also gets the
benefit of the ELF code for SEC_LINK_DUPLICATES_SAME_CONTENTS, so
section contents are actually checked now.
bfd/
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.
ld/
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.
Index: bfd/bfd-in.h
===================================================================
RCS file: /cvs/src/src/bfd/bfd-in.h,v
retrieving revision 1.156
diff -u -p -r1.156 bfd-in.h
--- bfd/bfd-in.h 9 Aug 2011 13:10:43 -0000 1.156
+++ bfd/bfd-in.h 12 Aug 2011 23:56:06 -0000
@@ -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
Index: bfd/coff-alpha.c
===================================================================
RCS file: /cvs/src/src/bfd/coff-alpha.c,v
retrieving revision 1.47
diff -u -p -r1.47 coff-alpha.c
--- bfd/coff-alpha.c 11 Jul 2011 15:03:04 -0000 1.47
+++ bfd/coff-alpha.c 12 Aug 2011 23:56:09 -0000
@@ -2403,7 +2403,7 @@ static const struct ecoff_backend_data a
#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 =
Index: bfd/coff-mips.c
===================================================================
RCS file: /cvs/src/src/bfd/coff-mips.c,v
retrieving revision 1.40
diff -u -p -r1.40 coff-mips.c
--- bfd/coff-mips.c 11 Jul 2011 15:03:04 -0000 1.40
+++ bfd/coff-mips.c 12 Aug 2011 23:56:09 -0000
@@ -1419,7 +1419,7 @@ static const struct ecoff_backend_data m
#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;
Index: bfd/coffcode.h
===================================================================
RCS file: /cvs/src/src/bfd/coffcode.h,v
retrieving revision 1.180
diff -u -p -r1.180 coffcode.h
--- bfd/coffcode.h 11 Jul 2011 15:03:04 -0000 1.180
+++ bfd/coffcode.h 12 Aug 2011 23:56:11 -0000
@@ -5670,7 +5670,7 @@ static bfd_coff_backend_data ticoff1_swa
#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
Index: bfd/cofflink.c
===================================================================
RCS file: /cvs/src/src/bfd/cofflink.c,v
retrieving revision 1.78
diff -u -p -r1.78 cofflink.c
--- bfd/cofflink.c 9 Jul 2011 06:20:50 -0000 1.78
+++ bfd/cofflink.c 12 Aug 2011 23:56:13 -0000
@@ -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;
Index: bfd/elf-bfd.h
===================================================================
RCS file: /cvs/src/src/bfd/elf-bfd.h,v
retrieving revision 1.328
diff -u -p -r1.328 elf-bfd.h
--- bfd/elf-bfd.h 5 Aug 2011 03:17:11 -0000 1.328
+++ bfd/elf-bfd.h 12 Aug 2011 23:56:14 -0000
@@ -1801,9 +1801,8 @@ extern bfd_boolean _bfd_elf_match_sectio
(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
Index: bfd/libbfd-in.h
===================================================================
RCS file: /cvs/src/src/bfd/libbfd-in.h,v
retrieving revision 1.91
diff -u -p -r1.91 libbfd-in.h
--- bfd/libbfd-in.h 5 Aug 2011 03:17:11 -0000 1.91
+++ bfd/libbfd-in.h 12 Aug 2011 23:56:25 -0000
@@ -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_sect
#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_spl
(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_e
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 *);
Index: bfd/libcoff-in.h
===================================================================
RCS file: /cvs/src/src/bfd/libcoff-in.h,v
retrieving revision 1.43
diff -u -p -r1.43 libcoff-in.h
--- bfd/libcoff-in.h 13 Jun 2011 00:59:15 -0000 1.43
+++ bfd/libcoff-in.h 12 Aug 2011 23:56:25 -0000
@@ -546,6 +546,8 @@ extern struct bfd_link_hash_table *_bfd_
(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
Index: bfd/linker.c
===================================================================
RCS file: /cvs/src/src/bfd/linker.c,v
retrieving revision 1.88
diff -c -p -r1.88 linker.c
*** bfd/linker.c 5 Aug 2011 03:17:11 -0000 1.88
--- bfd/linker.c 13 Aug 2011 06:21:45 -0000
*************** FUNCTION
*** 2889,2903 ****
SYNOPSIS
bfd_boolean bfd_section_already_linked (bfd *abfd,
! struct already_linked *data,
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))
.
*/
--- 2889,2903 ----
SYNOPSIS
bfd_boolean bfd_section_already_linked (bfd *abfd,
! 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, sec, info) \
! . BFD_SEND (abfd, _section_already_linked, (abfd, sec, info))
.
*/
*************** bfd_section_already_linked_table_lookup
*** 2940,2946 ****
bfd_boolean
bfd_section_already_linked_table_insert
(struct bfd_section_already_linked_hash_entry *already_linked_list,
! struct already_linked *data)
{
struct bfd_section_already_linked *l;
--- 2940,2946 ----
bfd_boolean
bfd_section_already_linked_table_insert
(struct bfd_section_already_linked_hash_entry *already_linked_list,
! asection *sec)
{
struct bfd_section_already_linked *l;
*************** bfd_section_already_linked_table_insert
*** 2950,2956 ****
bfd_hash_allocate (&_bfd_section_already_linked_table, sizeof *l);
if (l == NULL)
return FALSE;
! l->linked = *data;
l->next = already_linked_list->entry;
already_linked_list->entry = l;
return TRUE;
--- 2950,2956 ----
bfd_hash_allocate (&_bfd_section_already_linked_table, sizeof *l);
if (l == NULL)
return FALSE;
! l->sec = sec;
l->next = already_linked_list->entry;
already_linked_list->entry = l;
return TRUE;
*************** bfd_section_already_linked_table_free (v
*** 2988,3146 ****
bfd_hash_table_free (&_bfd_section_already_linked_table);
}
! /* This is used on non-ELF inputs. */
bfd_boolean
! _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;
!
! 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;
!
! s_comdat = bfd_coff_get_comdat_section (abfd, sec);
!
! /* 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. */
!
! 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;
! 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;
! }
}
/* This is the first section with this name. Record it. */
! if (! bfd_section_already_linked_table_insert (already_linked_list,
! linked))
info->callbacks->einfo (_("%F%P: already_linked_table: %E\n"));
return FALSE;
}
--- 2988,3124 ----
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 ATTRIBUTE_UNUSED,
! asection *sec,
! struct bfd_link_info *info)
! {
! const char *name;
! struct bfd_section_already_linked *l;
! struct bfd_section_already_linked_hash_entry *already_linked_list;
! if ((sec->flags & SEC_LINK_ONCE) == 0)
! return FALSE;
! /* 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.
!
! 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);
!
! l = already_linked_list->entry;
! if (l != NULL)
! {
! /* The section has already been linked. See if we should
! issue a warning. */
! return _bfd_handle_already_linked (sec, l, info);
}
/* This is the first section with this name. Record it. */
! if (!bfd_section_already_linked_table_insert (already_linked_list, sec))
info->callbacks->einfo (_("%F%P: already_linked_table: %E\n"));
return FALSE;
}
Index: bfd/elflink.c
===================================================================
RCS file: /cvs/src/src/bfd/elflink.c,v
retrieving revision 1.417
diff -c -p -r1.417 elflink.c
*** bfd/elflink.c 5 Aug 2011 03:17:11 -0000 1.417
--- bfd/elflink.c 13 Aug 2011 06:21:48 -0000
*************** bfd_elf_discard_info (bfd *output_bfd, s
*** 12502,12709 ****
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,
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;
- bfd_boolean matched;
! p = name = linked->comdat_key;
! if (name)
! {
! sec = NULL;
! flags = SEC_GROUP | SEC_LINK_ONCE | SEC_LINK_DUPLICATES_DISCARD;
! }
! else
! {
! sec = linked->u.sec;
! if (sec->output_section == bfd_abs_section_ptr)
! return FALSE;
!
! flags = sec->flags;
!
! /* Return if it isn't a linkonce section. A comdat group section
! also has SEC_LINK_ONCE set. */
! if ((flags & SEC_LINK_ONCE) == 0)
! return FALSE;
!
! /* Don't put group member sections on our list of already linked
! sections. They are handled as a group via their group section.
! */
! if (elf_sec_group (sec) != NULL)
! return FALSE;
!
! /* FIXME: When doing a relocatable link, we may have trouble
! copying relocations in other sections that refer to local symbols
! in the section being discarded. Those relocations will have to
! be converted somehow; as of this writing I'm not sure that any of
! the backends handle that correctly.
!
! 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)
{
- 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)
{
/* The section has already been linked. See if we should
issue a warning. */
! switch (flags & SEC_LINK_DUPLICATES)
! {
! default:
! abort ();
!
! case SEC_LINK_DUPLICATES_DISCARD:
! /* If we found an LTO IR match for this comdat group on
! the first pass, replace it with the LTO output on the
! second pass. We can't simply choose real object
! files over IR because the first pass may contain a
! mix of LTO and normal objects and we must keep the
! first match, be it IR or real. */
! if (info->loading_lto_outputs
! && (l_owner->flags & BFD_PLUGIN) != 0)
! {
! l->linked = *linked;
! return FALSE;
! }
! break;
!
! case SEC_LINK_DUPLICATES_ONE_ONLY:
! (*_bfd_error_handler)
! (_("%B: ignoring duplicate section `%A'"),
! abfd, sec);
! break;
! case SEC_LINK_DUPLICATES_SAME_SIZE:
! if (!sec || !l_sec)
! abort ();
!
! if (sec->size != l_sec->size)
! (*_bfd_error_handler)
! (_("%B: duplicate section `%A' has different size"),
! abfd, sec);
! break;
!
! case SEC_LINK_DUPLICATES_SAME_CONTENTS:
! if (!sec || !l_sec)
! abort ();
!
! if (sec->size != l_sec->size)
! (*_bfd_error_handler)
! (_("%B: duplicate section `%A' has different size"),
! abfd, sec);
! else if (sec->size != 0)
! {
! bfd_byte *sec_contents, *l_sec_contents;
!
! if (!bfd_malloc_and_get_section (abfd, sec, &sec_contents))
! (*_bfd_error_handler)
! (_("%B: warning: could not read contents of section `%A'"),
! abfd, sec);
! else if (!bfd_malloc_and_get_section (l_sec->owner, l_sec,
! &l_sec_contents))
! (*_bfd_error_handler)
! (_("%B: warning: could not read contents of section `%A'"),
! l_sec->owner, l_sec);
! else if (memcmp (sec_contents, l_sec_contents, sec->size) != 0)
! (*_bfd_error_handler)
! (_("%B: warning: duplicate section `%A' has different contents"),
! abfd, sec);
!
! if (sec_contents)
! free (sec_contents);
! if (l_sec_contents)
! free (l_sec_contents);
! }
! break;
! }
!
! if (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;
! }
}
}
--- 12502,12585 ----
return ret;
}
bfd_boolean
_bfd_elf_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;
! 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
+ {
+ /* Otherwise we should have a .gnu.linkonce.<type>.<key> section. */
if (CONST_STRNEQ (name, ".gnu.linkonce.")
! && (key = strchr (name + sizeof (".gnu.linkonce.") - 1, '.')) != NULL)
! key++;
else
! {
! BFD_ASSERT (0);
! key = name;
! }
}
! already_linked_list = bfd_section_already_linked_table_lookup (key);
for (l = already_linked_list->entry; l != NULL; l = l->next)
{
/* We may have 2 different types of sections on the list: group
! 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. */
! if (!_bfd_handle_already_linked (sec, l, info))
! return FALSE;
! 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;
}
}
*************** _bfd_elf_section_already_linked (bfd *ab
*** 12711,12818 ****
}
}
! 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)
{
! 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. */
- 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;
! }
! }
! }
! }
/* This is the first section with this name. Record it. */
! if (! bfd_section_already_linked_table_insert (already_linked_list,
! linked))
info->callbacks->einfo (_("%F%P: already_linked_table: %E\n"));
! return matched;
}
bfd_boolean
--- 12587,12653 ----
}
}
! /* A single member comdat group section may be discarded by a
! linkonce section and vice versa. */
! 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->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, sec))
info->callbacks->einfo (_("%F%P: already_linked_table: %E\n"));
! return sec->output_section == bfd_abs_section_ptr;
}
bfd_boolean
Index: bfd/coffgen.c
===================================================================
RCS file: /cvs/src/src/bfd/coffgen.c,v
retrieving revision 1.79
diff -c -p -r1.79 coffgen.c
*** bfd/coffgen.c 7 May 2011 14:26:56 -0000 1.79
--- bfd/coffgen.c 13 Aug 2011 06:21:49 -0000
*************** bfd_coff_get_comdat_section (bfd *abfd,
*** 2399,2401 ****
--- 2399,2468 ----
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;
+ }
Index: bfd/targets.c
===================================================================
RCS file: /cvs/src/src/bfd/targets.c,v
retrieving revision 1.207
diff -u -p -r1.207 targets.c
--- bfd/targets.c 5 Aug 2011 03:17:11 -0000 1.207
+++ bfd/targets.c 12 Aug 2011 23:56:27 -0000
@@ -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. *}
Index: ld/ldlang.c
===================================================================
RCS file: /cvs/src/src/ld/ldlang.c,v
retrieving revision 1.375
diff -u -p -r1.375 ldlang.c
--- ld/ldlang.c 16 Jul 2011 07:58:40 -0000 1.375
+++ ld/ldlang.c 12 Aug 2011 23:56:57 -0000
@@ -2240,12 +2240,7 @@ section_already_linked (bfd *abfd, asect
}
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.
Index: ld/plugin.c
===================================================================
RCS file: /cvs/src/src/ld/plugin.c,v
retrieving revision 1.38
diff -u -p -r1.38 plugin.c
--- ld/plugin.c 9 Aug 2011 09:27:34 -0000 1.38
+++ ld/plugin.c 12 Aug 2011 23:56:57 -0000
@@ -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 *nam
{
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, a
/* 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, co
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);
--
Alan Modra
Australia Development Lab, IBM