This is the mail archive of the binutils@sourceware.org mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

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


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]