PR ld/12942
authorAlan Modra <amodra@gmail.com>
Sat, 9 Jul 2011 06:20:52 +0000 (06:20 +0000)
committerAlan Modra <amodra@gmail.com>
Sat, 9 Jul 2011 06:20:52 +0000 (06:20 +0000)
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.

14 files changed:
bfd/ChangeLog
bfd/bfd-in2.h
bfd/cofflink.c
bfd/elf-bfd.h
bfd/elflink.c
bfd/libbfd-in.h
bfd/libbfd.h
bfd/linker.c
bfd/targets.c
include/ChangeLog
include/bfdlink.h
ld/ChangeLog
ld/ldlang.c
ld/plugin.c

index 9a3dafb5d91625d636dc4619dc2a4f29dfb08cdc..a1b91973d459d0261edf3ff480d65b97caa4d0de 100644 (file)
@@ -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
index 672c293e0be5fe0e7bf7007eaadda8bb94f9a3b5..da4688c48fdf26418e93f1e30836a1f3bc50acab 100644 (file)
@@ -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,
index bca136445de141eef3bb77cac9b734139810dad7..27257baa9c48490aee28857e0bb927b56f8e69d0 100644 (file)
@@ -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;
index 64a9dc0e40e6f4e7fe81bd113538943c92dcfff8..b2075a5677b71ad6efba049dd0360e5a2ad35971 100644 (file)
@@ -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
index b518da8ad09c75ab9ed0edc71f36b849eee73a85..238a4aab1a7a769068e8e64de7352d88dc2a6145 100644 (file)
@@ -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.  */
-       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;
-           }
-    }
-  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)
+      if ((flags & SEC_GROUP) != 0)
        {
-         asection *first = elf_next_in_group (l->sec);
+         asection *first = elf_next_in_group (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;
-           }
+         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->linked.comdat_key == NULL)
+             {
+               l_sec = l->linked.u.sec;
 
-  /* 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;
-       }
+               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;
+                 }
+             }
+         }
+    }
 
   /* 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"));
 }
 
index ad45ba3e4279d597b8fc61913a15c3c67807a577..a80687e2f634fb643ac0247d332269d0d38b8044 100644 (file)
@@ -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 *);
index dd4cc944408b05c48747ccb5b43f96e78419673f..c72ff16442f445cb7734162880c80457c915e613 100644 (file)
@@ -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 *);
index e472317b791ccc066f7f9d1994bb5c3d025a938e..492e77404d1b9b3112249009263e307cc008075e 100644 (file)
@@ -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;
-
-  /* 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);
+  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;
+
+      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;
-      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"));
 }
 
index 52dcd6b4d3f5ab2e57d608612766f181c97ddfb5..ac978a14fbdc98d95e9d9a9a095953b92d60ad42 100644 (file)
@@ -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.  *}
index c80aeb8a58fa17941f3882b47b34fa9a38febce4..bf2c020fdaefafae562f1ebb8ea2444e33a0909d 100644 (file)
@@ -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
index b1c751a84051b591b87fa3601454bb35916ce987..193b855113004eb4a281262a4217c919a9c1fc6b 100644 (file)
@@ -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;
 
index 407cc2dd1ab72a78e0487734eb8d13e5317469bb..7ce5d7abd6a321f86e4b7163c7399174ac6697a1 100644 (file)
@@ -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.
index 7e06613b5100699d23747d9c13e0538e0e3eb1da..860ce27b3005f9ed943b8cb3b9ad33fa034d3878 100644 (file)
@@ -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);
+    }
 }
 \f
 /* 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);
index 60eb1028a83825a2f894db1c534033bf33c59daf..0a0ee0c0d386bd594aaafac4817d29eda7e70d3a 100644 (file)
@@ -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)