* configure.ac (ia64*-*-*vms*): Add support for ld.
[deliverable/binutils-gdb.git] / bfd / elflink.c
index 4675aab82ad354ae692a6c6334005a324d37f3e6..0ed52081999d43d5237185dd36e229ffe43ae9ff 100644 (file)
@@ -36,7 +36,6 @@
 struct elf_info_failed
 {
   struct bfd_link_info *info;
-  struct bfd_elf_version_tree *verdefs;
   bfd_boolean failed;
 };
 
@@ -111,17 +110,17 @@ _bfd_elf_create_got_section (bfd *abfd, struct bfd_link_info *info)
 
   flags = bed->dynamic_sec_flags;
 
-  s = bfd_make_section_with_flags (abfd,
-                                  (bed->rela_plts_and_copies_p
-                                   ? ".rela.got" : ".rel.got"),
-                                  (bed->dynamic_sec_flags
-                                   | SEC_READONLY));
+  s = bfd_make_section_anyway_with_flags (abfd,
+                                         (bed->rela_plts_and_copies_p
+                                          ? ".rela.got" : ".rel.got"),
+                                         (bed->dynamic_sec_flags
+                                          | SEC_READONLY));
   if (s == NULL
       || ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align))
     return FALSE;
   htab->srelgot = s;
 
-  s = bfd_make_section_with_flags (abfd, ".got", flags);
+  s = bfd_make_section_anyway_with_flags (abfd, ".got", flags);
   if (s == NULL
       || !bfd_set_section_alignment (abfd, s, bed->s->log_file_align))
     return FALSE;
@@ -129,7 +128,7 @@ _bfd_elf_create_got_section (bfd *abfd, struct bfd_link_info *info)
 
   if (bed->want_got_plt)
     {
-      s = bfd_make_section_with_flags (abfd, ".got.plt", flags);
+      s = bfd_make_section_anyway_with_flags (abfd, ".got.plt", flags);
       if (s == NULL
          || !bfd_set_section_alignment (abfd, s,
                                         bed->s->log_file_align))
@@ -207,44 +206,44 @@ _bfd_elf_link_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info)
      shared library does not.  */
   if (info->executable)
     {
-      s = bfd_make_section_with_flags (abfd, ".interp",
-                                      flags | SEC_READONLY);
+      s = bfd_make_section_anyway_with_flags (abfd, ".interp",
+                                             flags | SEC_READONLY);
       if (s == NULL)
        return FALSE;
     }
 
   /* Create sections to hold version informations.  These are removed
      if they are not needed.  */
-  s = bfd_make_section_with_flags (abfd, ".gnu.version_d",
-                                  flags | SEC_READONLY);
+  s = bfd_make_section_anyway_with_flags (abfd, ".gnu.version_d",
+                                         flags | SEC_READONLY);
   if (s == NULL
       || ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align))
     return FALSE;
 
-  s = bfd_make_section_with_flags (abfd, ".gnu.version",
-                                  flags | SEC_READONLY);
+  s = bfd_make_section_anyway_with_flags (abfd, ".gnu.version",
+                                         flags | SEC_READONLY);
   if (s == NULL
       || ! bfd_set_section_alignment (abfd, s, 1))
     return FALSE;
 
-  s = bfd_make_section_with_flags (abfd, ".gnu.version_r",
-                                  flags | SEC_READONLY);
+  s = bfd_make_section_anyway_with_flags (abfd, ".gnu.version_r",
+                                         flags | SEC_READONLY);
   if (s == NULL
       || ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align))
     return FALSE;
 
-  s = bfd_make_section_with_flags (abfd, ".dynsym",
-                                  flags | SEC_READONLY);
+  s = bfd_make_section_anyway_with_flags (abfd, ".dynsym",
+                                         flags | SEC_READONLY);
   if (s == NULL
       || ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align))
     return FALSE;
 
-  s = bfd_make_section_with_flags (abfd, ".dynstr",
-                                  flags | SEC_READONLY);
+  s = bfd_make_section_anyway_with_flags (abfd, ".dynstr",
+                                         flags | SEC_READONLY);
   if (s == NULL)
     return FALSE;
 
-  s = bfd_make_section_with_flags (abfd, ".dynamic", flags);
+  s = bfd_make_section_anyway_with_flags (abfd, ".dynamic", flags);
   if (s == NULL
       || ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align))
     return FALSE;
@@ -260,7 +259,8 @@ _bfd_elf_link_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info)
 
   if (info->emit_hash)
     {
-      s = bfd_make_section_with_flags (abfd, ".hash", flags | SEC_READONLY);
+      s = bfd_make_section_anyway_with_flags (abfd, ".hash",
+                                             flags | SEC_READONLY);
       if (s == NULL
          || ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align))
        return FALSE;
@@ -269,8 +269,8 @@ _bfd_elf_link_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info)
 
   if (info->emit_gnu_hash)
     {
-      s = bfd_make_section_with_flags (abfd, ".gnu.hash",
-                                      flags | SEC_READONLY);
+      s = bfd_make_section_anyway_with_flags (abfd, ".gnu.hash",
+                                             flags | SEC_READONLY);
       if (s == NULL
          || ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align))
        return FALSE;
@@ -286,7 +286,8 @@ _bfd_elf_link_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info)
   /* Let the backend create the rest of the sections.  This lets the
      backend set the right flags.  The backend will normally create
      the .got and .plt sections.  */
-  if (! (*bed->elf_backend_create_dynamic_sections) (abfd, info))
+  if (bed->elf_backend_create_dynamic_sections == NULL
+      || ! (*bed->elf_backend_create_dynamic_sections) (abfd, info))
     return FALSE;
 
   elf_hash_table (info)->dynamic_sections_created = TRUE;
@@ -320,7 +321,7 @@ _bfd_elf_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info)
   if (bed->plt_readonly)
     pltflags |= SEC_READONLY;
 
-  s = bfd_make_section_with_flags (abfd, ".plt", pltflags);
+  s = bfd_make_section_anyway_with_flags (abfd, ".plt", pltflags);
   if (s == NULL
       || ! bfd_set_section_alignment (abfd, s, bed->plt_alignment))
     return FALSE;
@@ -337,10 +338,10 @@ _bfd_elf_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info)
        return FALSE;
     }
 
-  s = bfd_make_section_with_flags (abfd,
-                                  (bed->rela_plts_and_copies_p
-                                   ? ".rela.plt" : ".rel.plt"),
-                                  flags | SEC_READONLY);
+  s = bfd_make_section_anyway_with_flags (abfd,
+                                         (bed->rela_plts_and_copies_p
+                                          ? ".rela.plt" : ".rel.plt"),
+                                         flags | SEC_READONLY);
   if (s == NULL
       || ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align))
     return FALSE;
@@ -357,9 +358,8 @@ _bfd_elf_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info)
         image and use a R_*_COPY reloc to tell the dynamic linker to
         initialize them at run time.  The linker script puts the .dynbss
         section into the .bss section of the final image.  */
-      s = bfd_make_section_with_flags (abfd, ".dynbss",
-                                      (SEC_ALLOC
-                                       | SEC_LINKER_CREATED));
+      s = bfd_make_section_anyway_with_flags (abfd, ".dynbss",
+                                             (SEC_ALLOC | SEC_LINKER_CREATED));
       if (s == NULL)
        return FALSE;
 
@@ -376,10 +376,10 @@ _bfd_elf_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info)
         copy relocs.  */
       if (! info->shared)
        {
-         s = bfd_make_section_with_flags (abfd,
-                                          (bed->rela_plts_and_copies_p
-                                           ? ".rela.bss" : ".rel.bss"),
-                                          flags | SEC_READONLY);
+         s = bfd_make_section_anyway_with_flags (abfd,
+                                                 (bed->rela_plts_and_copies_p
+                                                  ? ".rela.bss" : ".rel.bss"),
+                                                 flags | SEC_READONLY);
          if (s == NULL
              || ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align))
            return FALSE;
@@ -721,9 +721,6 @@ elf_link_renumber_hash_table_dynsyms (struct elf_link_hash_entry *h,
 {
   size_t *count = (size_t *) data;
 
-  if (h->root.type == bfd_link_hash_warning)
-    h = (struct elf_link_hash_entry *) h->root.u.i.link;
-
   if (h->forced_local)
     return TRUE;
 
@@ -743,9 +740,6 @@ elf_link_renumber_local_hash_table_dynsyms (struct elf_link_hash_entry *h,
 {
   size_t *count = (size_t *) data;
 
-  if (h->root.type == bfd_link_hash_warning)
-    h = (struct elf_link_hash_entry *) h->root.u.i.link;
-
   if (!h->forced_local)
     return TRUE;
 
@@ -1085,11 +1079,15 @@ _bfd_elf_merge_symbol (bfd *abfd,
       return TRUE;
     }
 
+  /* Plugin symbol type isn't currently set.  Stop bogus errors.  */
+  if (oldbfd != NULL && (oldbfd->flags & BFD_PLUGIN) != 0)
+    *type_change_ok = TRUE;
+
   /* Check TLS symbol.  We don't check undefined symbol introduced by
      "ld -u".  */
-  if ((ELF_ST_TYPE (sym->st_info) == STT_TLS || h->type == STT_TLS)
-      && ELF_ST_TYPE (sym->st_info) != h->type
-      && oldbfd != NULL)
+  else if (oldbfd != NULL
+          && ELF_ST_TYPE (sym->st_info) != h->type
+          && (ELF_ST_TYPE (sym->st_info) == STT_TLS || h->type == STT_TLS))
     {
       bfd *ntbfd, *tbfd;
       bfd_boolean ntdef, tdef;
@@ -1240,7 +1238,6 @@ _bfd_elf_merge_symbol (bfd *abfd,
        {
          h->def_dynamic = 0;
          h->ref_dynamic = 1;
-         h->dynamic_def = 1;
        }
       /* FIXME: Should we check type and size for protected symbol?  */
       h->size = 0;
@@ -1428,7 +1425,8 @@ _bfd_elf_merge_symbol (bfd *abfd,
   if (newdef && olddef && newweak)
     {
       /* Don't skip new non-IR weak syms.  */
-      if (!((oldbfd->flags & BFD_PLUGIN) != 0
+      if (!(oldbfd != NULL
+           && (oldbfd->flags & BFD_PLUGIN) != 0
            && (abfd->flags & BFD_PLUGIN) == 0))
        *skip = TRUE;
 
@@ -1811,32 +1809,23 @@ _bfd_elf_export_symbol (struct elf_link_hash_entry *h, void *data)
 {
   struct elf_info_failed *eif = (struct elf_info_failed *) data;
 
-  /* Ignore this if we won't export it.  */
-  if (!eif->info->export_dynamic && !h->dynamic)
-    return TRUE;
-
   /* Ignore indirect symbols.  These are added by the versioning code.  */
   if (h->root.type == bfd_link_hash_indirect)
     return TRUE;
 
-  if (h->root.type == bfd_link_hash_warning)
-    h = (struct elf_link_hash_entry *) h->root.u.i.link;
+  /* Ignore this if we won't export it.  */
+  if (!eif->info->export_dynamic && !h->dynamic)
+    return TRUE;
 
   if (h->dynindx == -1
-      && (h->def_regular
-         || h->ref_regular))
+      && (h->def_regular || h->ref_regular)
+      && ! bfd_hide_sym_by_version (eif->info->version_info,
+                                   h->root.root.string))
     {
-      bfd_boolean hide;
-
-      if (eif->verdefs == NULL
-         || (bfd_find_version_for_sym (eif->verdefs, h->root.root.string, &hide)
-             && !hide))
+      if (! bfd_elf_link_record_dynamic_symbol (eif->info, h))
        {
-         if (! bfd_elf_link_record_dynamic_symbol (eif->info, h))
-           {
-             eif->failed = TRUE;
-             return FALSE;
-           }
+         eif->failed = TRUE;
+         return FALSE;
        }
     }
 
@@ -1857,9 +1846,6 @@ _bfd_elf_link_find_version_dependencies (struct elf_link_hash_entry *h,
   Elf_Internal_Vernaux *a;
   bfd_size_type amt;
 
-  if (h->root.type == bfd_link_hash_warning)
-    h = (struct elf_link_hash_entry *) h->root.u.i.link;
-
   /* We only care about symbols defined in shared objects with version
      information.  */
   if (!h->def_dynamic
@@ -1945,9 +1931,6 @@ _bfd_elf_link_assign_sym_version (struct elf_link_hash_entry *h, void *data)
   sinfo = (struct elf_info_failed *) data;
   info = sinfo->info;
 
-  if (h->root.type == bfd_link_hash_warning)
-    h = (struct elf_link_hash_entry *) h->root.u.i.link;
-
   /* Fix the symbol flags.  */
   eif.failed = FALSE;
   eif.info = info;
@@ -1990,7 +1973,7 @@ _bfd_elf_link_assign_sym_version (struct elf_link_hash_entry *h, void *data)
        }
 
       /* Look for the version.  If we find it, it is no longer weak.  */
-      for (t = sinfo->verdefs; t != NULL; t = t->next)
+      for (t = sinfo->info->version_info; t != NULL; t = t->next)
        {
          if (strcmp (t->name, p) == 0)
            {
@@ -2059,9 +2042,12 @@ _bfd_elf_link_assign_sym_version (struct elf_link_hash_entry *h, void *data)
 
          version_index = 1;
          /* Don't count anonymous version tag.  */
-         if (sinfo->verdefs != NULL && sinfo->verdefs->vernum == 0)
+         if (sinfo->info->version_info != NULL
+             && sinfo->info->version_info->vernum == 0)
            version_index = 0;
-         for (pp = &sinfo->verdefs; *pp != NULL; pp = &(*pp)->next)
+         for (pp = &sinfo->info->version_info;
+              *pp != NULL;
+              pp = &(*pp)->next)
            ++version_index;
          t->vernum = version_index;
 
@@ -2087,12 +2073,13 @@ _bfd_elf_link_assign_sym_version (struct elf_link_hash_entry *h, void *data)
 
   /* If we don't have a version for this symbol, see if we can find
      something.  */
-  if (h->verinfo.vertree == NULL && sinfo->verdefs != NULL)
+  if (h->verinfo.vertree == NULL && sinfo->info->version_info != NULL)
     {
       bfd_boolean hide;
 
-      h->verinfo.vertree = bfd_find_version_for_sym (sinfo->verdefs,
-                                                h->root.root.string, &hide);
+      h->verinfo.vertree
+       = bfd_find_version_for_sym (sinfo->info->version_info,
+                                   h->root.root.string, &hide);
       if (h->verinfo.vertree != NULL && hide)
        (*bed->elf_backend_hide_symbol) (info, h, TRUE);
     }
@@ -2523,23 +2510,21 @@ _bfd_elf_fix_symbol_flags (struct elf_link_hash_entry *h,
      over to the real definition.  */
   if (h->u.weakdef != NULL)
     {
-      struct elf_link_hash_entry *weakdef;
-
-      weakdef = h->u.weakdef;
-      if (h->root.type == bfd_link_hash_indirect)
-       h = (struct elf_link_hash_entry *) h->root.u.i.link;
-
-      BFD_ASSERT (h->root.type == bfd_link_hash_defined
-                 || h->root.type == bfd_link_hash_defweak);
-      BFD_ASSERT (weakdef->def_dynamic);
-
       /* If the real definition is defined by a regular object file,
         don't do anything special.  See the longer description in
         _bfd_elf_adjust_dynamic_symbol, below.  */
-      if (weakdef->def_regular)
+      if (h->u.weakdef->def_regular)
        h->u.weakdef = NULL;
       else
        {
+         struct elf_link_hash_entry *weakdef = h->u.weakdef;
+
+         while (h->root.type == bfd_link_hash_indirect)
+           h = (struct elf_link_hash_entry *) h->root.u.i.link;
+
+         BFD_ASSERT (h->root.type == bfd_link_hash_defined
+                     || h->root.type == bfd_link_hash_defweak);
+         BFD_ASSERT (weakdef->def_dynamic);
          BFD_ASSERT (weakdef->root.type == bfd_link_hash_defined
                      || weakdef->root.type == bfd_link_hash_defweak);
          (*bed->elf_backend_copy_indirect_symbol) (eif->info, weakdef, h);
@@ -2563,17 +2548,6 @@ _bfd_elf_adjust_dynamic_symbol (struct elf_link_hash_entry *h, void *data)
   if (! is_elf_hash_table (eif->info->hash))
     return FALSE;
 
-  if (h->root.type == bfd_link_hash_warning)
-    {
-      h->got = elf_hash_table (eif->info)->init_got_offset;
-      h->plt = elf_hash_table (eif->info)->init_plt_offset;
-
-      /* When warning symbols are created, they **replace** the "real"
-        entry in the hash table, thus we never get to see the real
-        symbol in a hash traversal.  So look at it now.  */
-      h = (struct elf_link_hash_entry *) h->root.u.i.link;
-    }
-
   /* Ignore indirect symbols.  These are added by the versioning code.  */
   if (h->root.type == bfd_link_hash_indirect)
     return TRUE;
@@ -2641,12 +2615,12 @@ _bfd_elf_adjust_dynamic_symbol (struct elf_link_hash_entry *h, void *data)
 
   if (h->u.weakdef != NULL)
     {
-      /* If we get to this point, we know there is an implicit
-        reference by a regular object file via the weak symbol H.
-        FIXME: Is this really true?  What if the traversal finds
-        H->U.WEAKDEF before it finds H?  */
+      /* If we get to this point, there is an implicit reference to
+        H->U.WEAKDEF by a regular object file via the weak symbol H.  */
       h->u.weakdef->ref_regular = 1;
 
+      /* Ensure that the backend adjust_dynamic_symbol function sees
+        H->U.WEAKDEF before H by recursively calling ourselves.  */
       if (! _bfd_elf_adjust_dynamic_symbol (h->u.weakdef, eif))
        return FALSE;
     }
@@ -2729,9 +2703,6 @@ _bfd_elf_link_sec_merge_syms (struct elf_link_hash_entry *h, void *data)
 {
   asection *sec;
 
-  if (h->root.type == bfd_link_hash_warning)
-    h = (struct elf_link_hash_entry *) h->root.u.i.link;
-
   if ((h->root.type == bfd_link_hash_defined
        || h->root.type == bfd_link_hash_defweak)
       && ((sec = h->root.u.def.section)->flags & SEC_MERGE)
@@ -2881,8 +2852,10 @@ _bfd_elf_symbol_refs_local_p (struct elf_link_hash_entry *h,
     return TRUE;
 
   /* Function pointer equality tests may require that STV_PROTECTED
-     symbols be treated as dynamic symbols, even when we know that the
-     dynamic linker will resolve them locally.  */
+     symbols be treated as dynamic symbols.  If the address of a
+     function not defined in an executable is set to that function's
+     plt entry in the executable, then the address of the function in
+     a shared library must also be the plt entry in the executable.  */
   return local_protected;
 }
 
@@ -3177,9 +3150,6 @@ elf_adjust_dynstr_offsets (struct elf_link_hash_entry *h, void *data)
 {
   struct elf_strtab_hash *dynstr = (struct elf_strtab_hash *) data;
 
-  if (h->root.type == bfd_link_hash_warning)
-    h = (struct elf_link_hash_entry *) h->root.u.i.link;
-
   if (h->dynindx != -1)
     h->dynstr_index = _bfd_elf_strtab_offset (dynstr, h->dynstr_index);
   return TRUE;
@@ -3924,7 +3894,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.  */
@@ -4380,7 +4350,6 @@ error_free_dyn:
                    {
                      h->def_dynamic = 0;
                      h->ref_dynamic = 1;
-                     h->dynamic_def = 1;
                    }
                }
              if (! info->executable
@@ -4393,7 +4362,10 @@ error_free_dyn:
              if (! definition)
                h->ref_dynamic = 1;
              else
-               h->def_dynamic = 1;
+               {
+                 h->def_dynamic = 1;
+                 h->dynamic_def = 1;
+               }
              if (h->def_regular
                  || h->ref_regular
                  || (h->u.weakdef != NULL
@@ -4402,11 +4374,13 @@ error_free_dyn:
                dynsym = TRUE;
            }
 
+         /* We don't want to make debug symbol dynamic.  */
          if (definition && (sec->flags & SEC_DEBUGGING) && !info->relocatable)
-           {
-             /* We don't want to make debug symbol dynamic.  */
-             dynsym = FALSE;
-           }
+           dynsym = FALSE;
+
+         /* Nor should we make plugin symbols dynamic.  */
+         if ((abfd->flags & BFD_PLUGIN) != 0)
+           dynsym = FALSE;
 
          if (definition)
            h->target_internal = isym->st_target_internal;
@@ -4539,6 +4513,8 @@ error_free_dyn:
        {
          struct bfd_hash_entry *p;
          struct elf_link_hash_entry *h;
+         bfd_size_type size;
+         unsigned int alignment_power;
 
          for (p = htab->root.table.table[i]; p != NULL; p = p->next)
            {
@@ -4548,6 +4524,20 @@ error_free_dyn:
              if (h->dynindx >= old_dynsymcount)
                _bfd_elf_strtab_delref (htab->dynstr, h->dynstr_index);
 
+             /* Preserve the maximum alignment and size for common
+                symbols even if this dynamic lib isn't on DT_NEEDED
+                since it can still be loaded at the run-time by another
+                dynamic lib.  */
+             if (h->root.type == bfd_link_hash_common)
+               {
+                 size = h->root.u.c.size;
+                 alignment_power = h->root.u.c.p->alignment_power;
+               }
+             else
+               {
+                 size = 0;
+                 alignment_power = 0;
+               }
              memcpy (p, old_ent, htab->root.table.entsize);
              old_ent = (char *) old_ent + htab->root.table.entsize;
              h = (struct elf_link_hash_entry *) p;
@@ -4556,6 +4546,13 @@ error_free_dyn:
                  memcpy (h->root.u.i.link, old_ent, htab->root.table.entsize);
                  old_ent = (char *) old_ent + htab->root.table.entsize;
                }
+             else if (h->root.type == bfd_link_hash_common)
+               {
+                 if (size > h->root.u.c.size)
+                   h->root.u.c.size = size;
+                 if (alignment_power > h->root.u.c.p->alignment_power)
+                   h->root.u.c.p->alignment_power = alignment_power;
+               }
            }
        }
 
@@ -4909,7 +4906,7 @@ _bfd_elf_archive_symbol_lookup (bfd *abfd,
   char *p, *copy;
   size_t len, first;
 
-  h = elf_link_hash_lookup (elf_hash_table (info), name, FALSE, FALSE, FALSE);
+  h = elf_link_hash_lookup (elf_hash_table (info), name, FALSE, FALSE, TRUE);
   if (h != NULL)
     return h;
 
@@ -4932,14 +4929,14 @@ _bfd_elf_archive_symbol_lookup (bfd *abfd,
   memcpy (copy, name, first);
   memcpy (copy + first, name + first + 1, len - first);
 
-  h = elf_link_hash_lookup (elf_hash_table (info), copy, FALSE, FALSE, FALSE);
+  h = elf_link_hash_lookup (elf_hash_table (info), copy, FALSE, FALSE, TRUE);
   if (h == NULL)
     {
       /* We also need to check references to the symbol without the
         version.  */
       copy[first - 1] = '\0';
       h = elf_link_hash_lookup (elf_hash_table (info), copy,
-                               FALSE, FALSE, FALSE);
+                               FALSE, FALSE, TRUE);
     }
 
   bfd_release (abfd, copy);
@@ -5172,9 +5169,6 @@ elf_collect_hash_codes (struct elf_link_hash_entry *h, void *data)
   unsigned long ha;
   char *alc = NULL;
 
-  if (h->root.type == bfd_link_hash_warning)
-    h = (struct elf_link_hash_entry *) h->root.u.i.link;
-
   /* Ignore indirect symbols.  These are added by the versioning code.  */
   if (h->dynindx == -1)
     return TRUE;
@@ -5243,9 +5237,6 @@ elf_collect_gnu_hash_codes (struct elf_link_hash_entry *h, void *data)
   unsigned long ha;
   char *alc = NULL;
 
-  if (h->root.type == bfd_link_hash_warning)
-    h = (struct elf_link_hash_entry *) h->root.u.i.link;
-
   /* Ignore indirect symbols.  These are added by the versioning code.  */
   if (h->dynindx == -1)
     return TRUE;
@@ -5296,9 +5287,6 @@ elf_renumber_gnu_hash_syms (struct elf_link_hash_entry *h, void *data)
   unsigned long int bucket;
   unsigned long int val;
 
-  if (h->root.type == bfd_link_hash_warning)
-    h = (struct elf_link_hash_entry *) h->root.u.i.link;
-
   /* Ignore indirect symbols.  */
   if (h->dynindx == -1)
     return TRUE;
@@ -5526,8 +5514,7 @@ bfd_elf_size_dynamic_sections (bfd *output_bfd,
                               const char *depaudit,
                               const char * const *auxiliary_filters,
                               struct bfd_link_info *info,
-                              asection **sinterpptr,
-                              struct bfd_elf_version_tree *verdefs)
+                              asection **sinterpptr)
 {
   bfd_size_type soname_indx;
   bfd *dynobj;
@@ -5558,7 +5545,8 @@ bfd_elf_size_dynamic_sections (bfd *output_bfd,
        {
          asection *s;
 
-         if (inputobj->flags & (DYNAMIC | EXEC_P | BFD_LINKER_CREATED))
+         if (inputobj->flags
+             & (DYNAMIC | EXEC_P | BFD_PLUGIN | BFD_LINKER_CREATED))
            continue;
          s = bfd_get_section_by_name (inputobj, ".note.GNU-stack");
          if (s)
@@ -5703,7 +5691,6 @@ bfd_elf_size_dynamic_sections (bfd *output_bfd,
        }
 
       eif.info = info;
-      eif.verdefs = verdefs;
       eif.failed = FALSE;
 
       /* If we are supposed to export all symbols into the dynamic symbol
@@ -5719,7 +5706,7 @@ bfd_elf_size_dynamic_sections (bfd *output_bfd,
        }
 
       /* Make all global versions with definition.  */
-      for (t = verdefs; t != NULL; t = t->next)
+      for (t = info->version_info; t != NULL; t = t->next)
        for (d = t->globals.list; d != NULL; d = d->next)
          if (!d->symver && d->literal)
            {
@@ -5772,7 +5759,6 @@ bfd_elf_size_dynamic_sections (bfd *output_bfd,
 
       /* Attach all the symbols to their version information.  */
       asvinfo.info = info;
-      asvinfo.verdefs = verdefs;
       asvinfo.failed = FALSE;
 
       elf_link_hash_traverse (elf_hash_table (info),
@@ -5785,7 +5771,7 @@ bfd_elf_size_dynamic_sections (bfd *output_bfd,
        {
          /* Check if all global versions have a definition.  */
          all_defined = TRUE;
-         for (t = verdefs; t != NULL; t = t->next)
+         for (t = info->version_info; t != NULL; t = t->next)
            for (d = t->globals.list; d != NULL; d = d->next)
              if (d->literal && !d->symver && !d->script)
                {
@@ -5918,6 +5904,7 @@ bfd_elf_size_dynamic_sections (bfd *output_bfd,
   if (elf_hash_table (info)->dynamic_sections_created)
     {
       unsigned long section_sym_count;
+      struct bfd_elf_version_tree *verdefs;
       asection *s;
 
       /* Set up the version definition section.  */
@@ -5926,7 +5913,7 @@ bfd_elf_size_dynamic_sections (bfd *output_bfd,
 
       /* We may have created additional version definitions if we are
         just linking a regular application.  */
-      verdefs = asvinfo.verdefs;
+      verdefs = info->version_info;
 
       /* Skip anonymous version tag.  */
       if (verdefs != NULL && verdefs->vernum == 0)
@@ -8602,8 +8589,9 @@ elf_link_check_versioned_symbol (struct bfd_link_info *info,
    global symbols.  */
 
 static bfd_boolean
-elf_link_output_extsym (struct elf_link_hash_entry *h, void *data)
+elf_link_output_extsym (struct bfd_hash_entry *bh, void *data)
 {
+  struct elf_link_hash_entry *h = (struct elf_link_hash_entry *) bh;
   struct elf_outext_info *eoinfo = (struct elf_outext_info *) data;
   struct elf_final_link_info *finfo = eoinfo->finfo;
   bfd_boolean strip;
@@ -8669,10 +8657,11 @@ elf_link_output_extsym (struct elf_link_hash_entry *h, void *data)
 
   /* We should also warn if a forced local symbol is referenced from
      shared libraries.  */
-  if (! finfo->info->relocatable
-      && (! finfo->info->shared)
+  if (!finfo->info->relocatable
+      && finfo->info->executable
       && h->forced_local
       && h->ref_dynamic
+      && h->def_regular
       && !h->dynamic_def
       && !h->dynamic_weak
       && ! elf_link_check_versioned_symbol (finfo->info, bed, h))
@@ -8714,10 +8703,12 @@ elf_link_output_extsym (struct elf_link_hash_entry *h, void *data)
           && bfd_hash_lookup (finfo->info->keep_hash,
                               h->root.root.string, FALSE, FALSE) == NULL)
     strip = TRUE;
-  else if (finfo->info->strip_discarded
-          && (h->root.type == bfd_link_hash_defined
-              || h->root.type == bfd_link_hash_defweak)
-          && elf_discarded_section (h->root.u.def.section))
+  else if ((h->root.type == bfd_link_hash_defined
+           || h->root.type == bfd_link_hash_defweak)
+          && ((finfo->info->strip_discarded
+               && elf_discarded_section (h->root.u.def.section))
+              || (h->root.u.def.section->owner != NULL
+                  && (h->root.u.def.section->owner->flags & BFD_PLUGIN) != 0)))
     strip = TRUE;
   else if ((h->root.type == bfd_link_hash_undefined
            || h->root.type == bfd_link_hash_undefweak)
@@ -8917,7 +8908,8 @@ elf_link_output_extsym (struct elf_link_hash_entry *h, void *data)
   /* If this symbol should be put in the .dynsym section, then put it
      there now.  We already know the symbol index.  We also fill in
      the entry in the .hash section.  */
-  if (h->dynindx != -1
+  if (finfo->dynsym_sec != NULL
+      && h->dynindx != -1
       && elf_hash_table (finfo->info)->dynamic_sections_created)
     {
       bfd_byte *esym;
@@ -9756,23 +9748,12 @@ elf_link_input_bfd (struct elf_final_link_info *finfo, bfd *input_bfd)
                              r_symndx = osec->target_index;
                              if (r_symndx == STN_UNDEF)
                                {
-                                 struct elf_link_hash_table *htab;
-                                 asection *oi;
-
-                                 htab = elf_hash_table (finfo->info);
-                                 oi = htab->text_index_section;
-                                 if ((osec->flags & SEC_READONLY) == 0
-                                     && htab->data_index_section != NULL)
-                                   oi = htab->data_index_section;
-
-                                 if (oi != NULL)
-                                   {
-                                     irela->r_addend += osec->vma - oi->vma;
-                                     r_symndx = oi->target_index;
-                                   }
+                                 irela->r_addend += osec->vma;
+                                 osec = _bfd_nearby_section (output_bfd, osec,
+                                                             osec->vma);
+                                 irela->r_addend -= osec->vma;
+                                 r_symndx = osec->target_index;
                                }
-
-                             BFD_ASSERT (r_symndx != STN_UNDEF);
                            }
                        }
 
@@ -10325,7 +10306,7 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
     {
       finfo.dynsym_sec = bfd_get_section_by_name (dynobj, ".dynsym");
       finfo.hash_sec = bfd_get_section_by_name (dynobj, ".hash");
-      BFD_ASSERT (finfo.dynsym_sec != NULL);
+      /* Note that dynsym_sec can be NULL (on VMS).  */
       finfo.symver_sec = bfd_get_section_by_name (dynobj, ".gnu.version");
       /* Note that it is OK if symver_sec is NULL.  */
     }
@@ -10819,8 +10800,7 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
   eoinfo.failed = FALSE;
   eoinfo.finfo = &finfo;
   eoinfo.localsyms = TRUE;
-  elf_link_hash_traverse (elf_hash_table (info), elf_link_output_extsym,
-                         &eoinfo);
+  bfd_hash_traverse (&info->hash->table, elf_link_output_extsym, &eoinfo);
   if (eoinfo.failed)
     return FALSE;
 
@@ -10846,6 +10826,7 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
   symtab_hdr->sh_info = bfd_get_symcount (abfd);
 
   if (dynamic
+      && finfo.dynsym_sec != NULL
       && finfo.dynsym_sec->output_section != bfd_abs_section_ptr)
     {
       Elf_Internal_Sym sym;
@@ -10929,8 +10910,7 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
   eoinfo.failed = FALSE;
   eoinfo.localsyms = FALSE;
   eoinfo.finfo = &finfo;
-  elf_link_hash_traverse (elf_hash_table (info), elf_link_output_extsym,
-                         &eoinfo);
+  bfd_hash_traverse (&info->hash->table, elf_link_output_extsym, &eoinfo);
   if (eoinfo.failed)
     return FALSE;
 
@@ -11146,6 +11126,13 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
                    (_("%B: could not find output section %s"), abfd, name);
                  goto error_return;
                }
+             if (elf_section_data (o->output_section)->this_hdr.sh_type == SHT_NOTE)
+               {
+                 (*_bfd_error_handler)
+                   (_("warning: section '%s' is being made into a note"), name);
+                 bfd_set_error (bfd_error_nonrepresentable_section);
+                 goto error_return;
+               }
              dyn.d_un.d_ptr = o->vma;
              break;
 
@@ -11190,14 +11177,12 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
        goto error_return;
 
       /* Check for DT_TEXTREL (late, in case the backend removes it).  */
-      if (info->warn_shared_textrel && info->shared)
+      if (((info->warn_shared_textrel && info->shared)
+          || info->error_textrel)
+         && (o = bfd_get_section_by_name (dynobj, ".dynamic")) != NULL)
        {
          bfd_byte *dyncon, *dynconend;
 
-         /* Fix up .dynamic entries.  */
-         o = bfd_get_section_by_name (dynobj, ".dynamic");
-         BFD_ASSERT (o != NULL);
-
          dyncon = o->contents;
          dynconend = o->contents + o->size;
          for (; dyncon < dynconend; dyncon += bed->s->sizeof_dyn)
@@ -11208,8 +11193,12 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
 
              if (dyn.d_tag == DT_TEXTREL)
                {
-                info->callbacks->einfo
-                   (_("%P: warning: creating a DT_TEXTREL in a shared object.\n"));
+                 if (info->error_textrel)
+                   info->callbacks->einfo
+                     (_("%P%X: read-only segment has dynamic relocations.\n"));
+                 else
+                   info->callbacks->einfo
+                     (_("%P: warning: creating a DT_TEXTREL in a shared object.\n"));
                  break;
                }
            }
@@ -11233,7 +11222,7 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
            continue;
          if ((elf_section_data (o->output_section)->this_hdr.sh_type
               != SHT_STRTAB)
-             || strcmp (bfd_get_section_name (abfd, o), ".dynstr") != 0)
+             && (strcmp (bfd_get_section_name (abfd, o), ".dynstr") != 0))
            {
              /* FIXME: octets_per_byte.  */
              if (! bfd_set_section_contents (abfd, o->output_section,
@@ -11574,6 +11563,13 @@ _bfd_elf_gc_mark_rsec (struct bfd_link_info *info, asection *sec,
       while (h->root.type == bfd_link_hash_indirect
             || h->root.type == bfd_link_hash_warning)
        h = (struct elf_link_hash_entry *) h->root.u.i.link;
+      h->mark = 1;
+      /* If this symbol is weak and there is a non-weak definition, we
+        keep the non-weak definition because many backends put
+        dynamic reloc info on the non-weak definition for code
+        handling copy relocs.  */
+      if (h->u.weakdef != NULL)
+       h->u.weakdef->mark = 1;
       return (*gc_mark_hook) (sec, info, cookie->rel, h, NULL);
     }
 
@@ -11596,7 +11592,8 @@ _bfd_elf_gc_mark_reloc (struct bfd_link_info *info,
   rsec = _bfd_elf_gc_mark_rsec (info, sec, gc_mark_hook, cookie);
   if (rsec && !rsec->gc_mark)
     {
-      if (bfd_get_flavour (rsec->owner) != bfd_target_elf_flavour)
+      if (bfd_get_flavour (rsec->owner) != bfd_target_elf_flavour
+         || (rsec->owner->flags & DYNAMIC) != 0)
        rsec->gc_mark = 1;
       else if (!_bfd_elf_gc_mark (info, rsec, gc_mark_hook))
        return FALSE;
@@ -11665,6 +11662,50 @@ _bfd_elf_gc_mark (struct bfd_link_info *info,
   return ret;
 }
 
+/* Keep debug and special sections.  */
+
+bfd_boolean
+_bfd_elf_gc_mark_extra_sections (struct bfd_link_info *info,
+                                elf_gc_mark_hook_fn mark_hook ATTRIBUTE_UNUSED)
+{
+  bfd *ibfd;
+
+  for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
+    {
+      asection *isec;
+      bfd_boolean some_kept;
+
+      if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour)
+       continue;
+
+      /* Ensure all linker created sections are kept, and see whether
+        any other section is already marked.  */
+      some_kept = FALSE;
+      for (isec = ibfd->sections; isec != NULL; isec = isec->next)
+       {
+         if ((isec->flags & SEC_LINKER_CREATED) != 0)
+           isec->gc_mark = 1;
+         else if (isec->gc_mark)
+           some_kept = TRUE;
+       }
+
+      /* If no section in this file will be kept, then we can
+        toss out debug sections.  */
+      if (!some_kept)
+       continue;
+
+      /* Keep debug and special sections like .comment when they are
+        not part of a group, or when we have single-member groups.  */
+      for (isec = ibfd->sections; isec != NULL; isec = isec->next)
+       if ((elf_next_in_group (isec) == NULL
+            || elf_next_in_group (isec) == isec)
+           && ((isec->flags & SEC_DEBUGGING) != 0
+               || (isec->flags & (SEC_ALLOC | SEC_LOAD | SEC_RELOC)) == 0))
+         isec->gc_mark = 1;
+    }
+  return TRUE;
+}
+
 /* Sweep symbols in swept sections.  Called via elf_link_hash_traverse.  */
 
 struct elf_gc_sweep_symbol_info
@@ -11677,17 +11718,21 @@ struct elf_gc_sweep_symbol_info
 static bfd_boolean
 elf_gc_sweep_symbol (struct elf_link_hash_entry *h, void *data)
 {
-  if (h->root.type == bfd_link_hash_warning)
-    h = (struct elf_link_hash_entry *) h->root.u.i.link;
-
-  if ((h->root.type == bfd_link_hash_defined
-       || h->root.type == bfd_link_hash_defweak)
-      && !h->root.u.def.section->gc_mark
-      && !(h->root.u.def.section->owner->flags & DYNAMIC))
+  if (!h->mark
+      && (((h->root.type == bfd_link_hash_defined
+           || h->root.type == bfd_link_hash_defweak)
+          && !(h->def_regular
+               && h->root.u.def.section->gc_mark))
+         || h->root.type == bfd_link_hash_undefined
+         || h->root.type == bfd_link_hash_undefweak))
     {
-      struct elf_gc_sweep_symbol_info *inf =
-          (struct elf_gc_sweep_symbol_info *) data;
+      struct elf_gc_sweep_symbol_info *inf;
+
+      inf = (struct elf_gc_sweep_symbol_info *) data;
       (*inf->hide_symbol) (inf->info, h, TRUE);
+      h->def_regular = 0;
+      h->ref_regular = 0;
+      h->ref_regular_nonweak = 0;
     }
 
   return TRUE;
@@ -11725,13 +11770,6 @@ elf_gc_sweep (bfd *abfd, struct bfd_link_info *info)
              asection *first = elf_next_in_group (o);
              o->gc_mark = first->gc_mark;
            }
-         else if ((o->flags & (SEC_DEBUGGING | SEC_LINKER_CREATED)) != 0
-                  || (o->flags & (SEC_ALLOC | SEC_LOAD | SEC_RELOC)) == 0
-                  || elf_section_data (o)->this_hdr.sh_type == SHT_NOTE)
-           {
-             /* Keep debug, special and SHT_NOTE sections.  */
-             o->gc_mark = 1;
-           }
 
          if (o->gc_mark)
            continue;
@@ -11792,9 +11830,6 @@ elf_gc_sweep (bfd *abfd, struct bfd_link_info *info)
 static bfd_boolean
 elf_gc_propagate_vtable_entries_used (struct elf_link_hash_entry *h, void *okp)
 {
-  if (h->root.type == bfd_link_hash_warning)
-    h = (struct elf_link_hash_entry *) h->root.u.i.link;
-
   /* Those that are not vtables.  */
   if (h->vtable == NULL || h->vtable->parent == NULL)
     return TRUE;
@@ -11856,9 +11891,6 @@ elf_gc_smash_unused_vtentry_relocs (struct elf_link_hash_entry *h, void *okp)
   const struct elf_backend_data *bed;
   unsigned int log_file_align;
 
-  if (h->root.type == bfd_link_hash_warning)
-    h = (struct elf_link_hash_entry *) h->root.u.i.link;
-
   /* Take care of both those symbols that do not describe vtables as
      well as those that are not loaded.  */
   if (h->vtable == NULL || h->vtable->parent == NULL)
@@ -11906,16 +11938,16 @@ bfd_elf_gc_mark_dynamic_ref_symbol (struct elf_link_hash_entry *h, void *inf)
 {
   struct bfd_link_info *info = (struct bfd_link_info *) inf;
 
-  if (h->root.type == bfd_link_hash_warning)
-    h = (struct elf_link_hash_entry *) h->root.u.i.link;
-
   if ((h->root.type == bfd_link_hash_defined
        || h->root.type == bfd_link_hash_defweak)
       && (h->ref_dynamic
-         || (!info->executable
+         || ((!info->executable || info->export_dynamic)
              && h->def_regular
              && ELF_ST_VISIBILITY (h->other) != STV_INTERNAL
-             && ELF_ST_VISIBILITY (h->other) != STV_HIDDEN)))
+             && ELF_ST_VISIBILITY (h->other) != STV_HIDDEN
+             && (strchr (h->root.root.string, ELF_VER_CHR) != NULL
+                 || !bfd_hide_sym_by_version (info->version_info,
+                                              h->root.root.string)))))
     h->root.u.def.section->flags |= SEC_KEEP;
 
   return TRUE;
@@ -12011,15 +12043,23 @@ bfd_elf_gc_sections (bfd *abfd, struct bfd_link_info *info)
       if (bfd_get_flavour (sub) != bfd_target_elf_flavour)
        continue;
 
+      /* Start at sections marked with SEC_KEEP (ref _bfd_elf_gc_keep).
+        Also treat note sections as a root, if the section is not part
+        of a group.  */
       for (o = sub->sections; o != NULL; o = o->next)
-       if ((o->flags & (SEC_EXCLUDE | SEC_KEEP)) == SEC_KEEP && !o->gc_mark)
-         if (!_bfd_elf_gc_mark (info, o, gc_mark_hook))
-           return FALSE;
+       if (!o->gc_mark
+           && (o->flags & SEC_EXCLUDE) == 0
+           && ((o->flags & SEC_KEEP) != 0
+               || (elf_section_data (o)->this_hdr.sh_type == SHT_NOTE
+                   && elf_next_in_group (o) == NULL )))
+         {
+           if (!_bfd_elf_gc_mark (info, o, gc_mark_hook))
+             return FALSE;
+         }
     }
 
   /* Allow the backend to mark additional target specific sections.  */
-  if (bed->gc_mark_extra_sections)
-    bed->gc_mark_extra_sections (info, gc_mark_hook);
+  bed->gc_mark_extra_sections (info, gc_mark_hook);
 
   /* ... and mark SEC_EXCLUDE for those that go.  */
   return elf_gc_sweep (abfd, info);
@@ -12162,6 +12202,83 @@ bfd_elf_gc_record_vtentry (bfd *abfd ATTRIBUTE_UNUSED,
   return TRUE;
 }
 
+/* Map an ELF section header flag to its corresponding string.  */
+typedef struct
+{
+  char *flag_name;
+  flagword flag_value;
+} elf_flags_to_name_table;
+
+static elf_flags_to_name_table elf_flags_to_names [] =
+{
+  { "SHF_WRITE", SHF_WRITE },
+  { "SHF_ALLOC", SHF_ALLOC },
+  { "SHF_EXECINSTR", SHF_EXECINSTR },
+  { "SHF_MERGE", SHF_MERGE },
+  { "SHF_STRINGS", SHF_STRINGS },
+  { "SHF_INFO_LINK", SHF_INFO_LINK},
+  { "SHF_LINK_ORDER", SHF_LINK_ORDER},
+  { "SHF_OS_NONCONFORMING", SHF_OS_NONCONFORMING},
+  { "SHF_GROUP", SHF_GROUP },
+  { "SHF_TLS", SHF_TLS },
+  { "SHF_MASKOS", SHF_MASKOS },
+  { "SHF_EXCLUDE", SHF_EXCLUDE },
+};
+
+void
+bfd_elf_lookup_section_flags (struct bfd_link_info *info,
+                             struct flag_info *finfo)
+{
+  bfd *output_bfd = info->output_bfd;
+  const struct elf_backend_data *bed = get_elf_backend_data (output_bfd);
+  struct flag_info_list *tf = finfo->flag_list;
+  int with_hex = 0;
+  int without_hex = 0;
+
+  for (tf = finfo->flag_list; tf != NULL; tf = tf->next)
+    {
+      int i;
+      if (bed->elf_backend_lookup_section_flags_hook)
+       {
+         flagword hexval =
+            (*bed->elf_backend_lookup_section_flags_hook) ((char *) tf->name);
+
+         if (hexval != 0)
+           {
+             if (tf->with == with_flags)
+               with_hex |= hexval;
+             else if (tf->with == without_flags)
+               without_hex |= hexval;
+             tf->valid = TRUE;
+             continue;
+           }
+       }
+      for (i = 0; i < 12; i++)
+       {
+         if (!strcmp (tf->name, elf_flags_to_names[i].flag_name))
+           {
+             if (tf->with == with_flags)
+               with_hex |= elf_flags_to_names[i].flag_value;
+             else if (tf->with == without_flags)
+               without_hex |= elf_flags_to_names[i].flag_value;
+             tf->valid = TRUE;
+             continue;
+           }
+       }
+      if (tf->valid == FALSE)
+       {
+         info->callbacks->einfo 
+               (_("Unrecognized INPUT_SECTION_FLAG %s\n"), tf->name);
+         return;
+       }
+    }
+ finfo->flags_initialized = TRUE;
+ finfo->only_with_flags |= with_hex;
+ finfo->not_with_flags |= without_hex;
+
+ return;
+}
+
 struct alloc_got_off_arg {
   bfd_vma gotoff;
   struct bfd_link_info *info;
@@ -12177,9 +12294,6 @@ elf_gc_allocate_got_offsets (struct elf_link_hash_entry *h, void *arg)
   bfd *obfd = gofarg->info->output_bfd;
   const struct elf_backend_data *bed = get_elf_backend_data (obfd);
 
-  if (h->root.type == bfd_link_hash_warning)
-    h = (struct elf_link_hash_entry *) h->root.u.i.link;
-
   if (h->got.refcount > 0)
     {
       h->got.offset = gofarg->gotoff;
@@ -12422,139 +12536,69 @@ bfd_elf_discard_info (bfd *output_bfd, struct bfd_link_info *info)
   return ret;
 }
 
-/* For a SHT_GROUP section, return the group signature.  For other
-   sections, return the normal section name.  */
-
-static const char *
-section_signature (asection *sec)
-{
-  if ((sec->flags & SEC_GROUP) != 0
-      && elf_next_in_group (sec) != NULL
-      && elf_group_name (elf_next_in_group (sec)) != NULL)
-    return elf_group_name (elf_next_in_group (sec));
-  return sec->name;
-}
-
-void
-_bfd_elf_section_already_linked (bfd *abfd, asection *sec,
+bfd_boolean
+_bfd_elf_section_already_linked (bfd *abfd,
+                                asection *sec,
                                 struct bfd_link_info *info)
 {
   flagword flags;
-  const char *name, *p;
+  const char *name, *key;
   struct bfd_section_already_linked *l;
   struct bfd_section_already_linked_hash_entry *already_linked_list;
 
   if (sec->output_section == bfd_abs_section_ptr)
-    return;
+    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;
+    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;
-
-  /* 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);
+    return FALSE;
 
-  if (CONST_STRNEQ (name, ".gnu.linkonce.")
-      && (p = strchr (name + sizeof (".gnu.linkonce.") - 1, '.')) != NULL)
-    p++;
+  /* 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
-    p = name;
+    {
+      /* 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
+       /* Must be a user linkonce section that doesn't follow gcc's
+          naming convention.  In this case we won't be matching
+          single member groups.  */
+       key = name;
+    }
 
-  already_linked_list = bfd_section_already_linked_table_lookup (p);
+  already_linked_list = bfd_section_already_linked_table_lookup (key);
 
   for (l = already_linked_list->entry; l != NULL; l = l->next)
     {
       /* 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)
+        sections with a signature of <key> (<key> is some string),
+        and linkonce sections named .gnu.linkonce.<type>.<key>.
+        Match like sections.  LTO plugin sections are an exception.
+        They are always named .gnu.linkonce.t.<key> and match either
+        type of section.  */
+      if (((flags & SEC_GROUP) == (l->sec->flags & SEC_GROUP)
+          && ((flags & SEC_GROUP) != 0
+              || strcmp (name, l->sec->name) == 0))
+         || (l->sec->owner->flags & BFD_PLUGIN) != 0)
        {
          /* The section has already been linked.  See if we should
             issue a warning.  */
-         switch (flags & SEC_LINK_DUPLICATES)
-           {
-           default:
-             abort ();
-
-           case SEC_LINK_DUPLICATES_DISCARD:
-             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->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)
-               (*_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;
-           }
-
-         /* 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 (!_bfd_handle_already_linked (sec, l, info))
+           return FALSE;
 
          if (flags & SEC_GROUP)
            {
@@ -12573,13 +12617,12 @@ _bfd_elf_section_already_linked (bfd *abfd, asection *sec,
                }
            }
 
-         return;
+         return TRUE;
        }
     }
 
   /* 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);
@@ -12588,7 +12631,6 @@ _bfd_elf_section_already_linked (bfd *abfd, asection *sec,
        /* 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;
@@ -12637,8 +12679,9 @@ _bfd_elf_section_already_linked (bfd *abfd, asection *sec,
        }
 
   /* 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, sec))
     info->callbacks->einfo (_("%F%P: already_linked_table: %E\n"));
+  return sec->output_section == bfd_abs_section_ptr;
 }
 
 bfd_boolean
This page took 0.042989 seconds and 4 git commands to generate.