Add ability to change linker warning messages into errors when reporting executable...
[binutils-gdb.git] / bfd / elflink.c
index f8d6313168003ba58a08b46bc645e5bfd50f22a4..49ea222ec77e3fe4305a5ff08344987050f5d9ab 100644 (file)
@@ -1,5 +1,5 @@
 /* ELF linking support for BFD.
-   Copyright (C) 1995-2021 Free Software Foundation, Inc.
+   Copyright (C) 1995-2023 Free Software Foundation, Inc.
 
    This file is part of BFD, the Binary File Descriptor library.
 
@@ -32,9 +32,7 @@
 #include "plugin.h"
 #endif
 
-#ifdef HAVE_LIMITS_H
 #include <limits.h>
-#endif
 #ifndef CHAR_BIT
 #define CHAR_BIT 8
 #endif
@@ -361,6 +359,17 @@ _bfd_elf_link_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info)
        elf_section_data (s)->this_hdr.sh_entsize = 4;
     }
 
+  if (info->enable_dt_relr)
+    {
+      s = bfd_make_section_anyway_with_flags (abfd, ".relr.dyn",
+                                             (bed->dynamic_sec_flags
+                                              | SEC_READONLY));
+      if (s == NULL
+         || !bfd_set_section_alignment (s, bed->s->log_file_align))
+       return false;
+      elf_hash_table (info)->srelrdyn = s;
+    }
+
   /* 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.  */
@@ -1081,6 +1090,7 @@ _bfd_elf_merge_symbol (bfd *abfd,
   const struct elf_backend_data *bed;
   char *new_version;
   bool default_sym = *matched;
+  struct elf_link_hash_table *htab;
 
   *skip = false;
   *override = NULL;
@@ -1211,6 +1221,8 @@ _bfd_elf_merge_symbol (bfd *abfd,
      symbols.  */
   bfd_elf_link_mark_dynamic_symbol (info, h, sym);
 
+  htab = elf_hash_table (info);
+
   /* NEWDYN and OLDDYN indicate whether the new or old symbol,
      respectively, is from a dynamic object.  */
 
@@ -1274,14 +1286,26 @@ _bfd_elf_merge_symbol (bfd *abfd,
       olddyn = (oldsec->symbol->flags & BSF_DYNAMIC) != 0;
     }
 
-  /* Handle a case where plugin_notice won't be called and thus won't
-     set the non_ir_ref flags on the first pass over symbols.  */
-  if (oldbfd != NULL
-      && (oldbfd->flags & BFD_PLUGIN) != (abfd->flags & BFD_PLUGIN)
-      && newdyn != olddyn)
+  /* Set non_ir_ref_dynamic only when not handling DT_NEEDED entries.  */
+  if (!htab->handling_dt_needed
+      && oldbfd != NULL
+      && (oldbfd->flags & BFD_PLUGIN) != (abfd->flags & BFD_PLUGIN))
     {
-      h->root.non_ir_ref_dynamic = true;
-      hi->root.non_ir_ref_dynamic = true;
+      if (newdyn != olddyn)
+       {
+         /* Handle a case where plugin_notice won't be called and thus
+            won't set the non_ir_ref flags on the first pass over
+            symbols.  */
+         h->root.non_ir_ref_dynamic = true;
+         hi->root.non_ir_ref_dynamic = true;
+       }
+      else if ((oldbfd->flags & BFD_PLUGIN) != 0
+              && hi->root.type == bfd_link_hash_indirect)
+       {
+         /* Change indirect symbol from IR to undefined.  */
+         hi->root.type = bfd_link_hash_undefined;
+         hi->root.u.undef.abfd = oldbfd;
+       }
     }
 
   /* NEWDEF and OLDDEF indicate whether the new or old symbol,
@@ -2193,6 +2217,85 @@ _bfd_elf_export_symbol (struct elf_link_hash_entry *h, void *data)
   return true;
 }
 \f
+/* Return true if GLIBC_ABI_DT_RELR is added to the list of version
+   dependencies successfully.  GLIBC_ABI_DT_RELR will be put into the
+   .gnu.version_r section.  */
+
+static bool
+elf_link_add_dt_relr_dependency (struct elf_find_verdep_info *rinfo)
+{
+  bfd *glibc_bfd = NULL;
+  Elf_Internal_Verneed *t;
+  Elf_Internal_Vernaux *a;
+  size_t amt;
+  const char *relr = "GLIBC_ABI_DT_RELR";
+
+  /* See if we already know about GLIBC_PRIVATE_DT_RELR.  */
+  for (t = elf_tdata (rinfo->info->output_bfd)->verref;
+       t != NULL;
+       t = t->vn_nextref)
+    {
+      const char *soname = bfd_elf_get_dt_soname (t->vn_bfd);
+      /* Skip the shared library if it isn't libc.so.  */
+      if (!soname || !startswith (soname, "libc.so."))
+       continue;
+
+      for (a = t->vn_auxptr; a != NULL; a = a->vna_nextptr)
+       {
+         /* Return if GLIBC_PRIVATE_DT_RELR dependency has been
+            added.  */
+         if (a->vna_nodename == relr
+             || strcmp (a->vna_nodename, relr) == 0)
+           return true;
+
+         /* Check if libc.so provides GLIBC_2.XX version.  */
+         if (!glibc_bfd && startswith (a->vna_nodename, "GLIBC_2."))
+           glibc_bfd = t->vn_bfd;
+       }
+
+      break;
+    }
+
+  /* Skip if it isn't linked against glibc.  */
+  if (glibc_bfd == NULL)
+    return true;
+
+  /* This is a new version.  Add it to tree we are building.  */
+  if (t == NULL)
+    {
+      amt = sizeof *t;
+      t = (Elf_Internal_Verneed *) bfd_zalloc (rinfo->info->output_bfd,
+                                              amt);
+      if (t == NULL)
+       {
+         rinfo->failed = true;
+         return false;
+       }
+
+      t->vn_bfd = glibc_bfd;
+      t->vn_nextref = elf_tdata (rinfo->info->output_bfd)->verref;
+      elf_tdata (rinfo->info->output_bfd)->verref = t;
+    }
+
+  amt = sizeof *a;
+  a = (Elf_Internal_Vernaux *) bfd_zalloc (rinfo->info->output_bfd, amt);
+  if (a == NULL)
+    {
+      rinfo->failed = true;
+      return false;
+    }
+
+  a->vna_nodename = relr;
+  a->vna_flags = 0;
+  a->vna_nextptr = t->vn_auxptr;
+  a->vna_other = rinfo->vers + 1;
+  ++rinfo->vers;
+
+  t->vn_auxptr = a;
+
+  return true;
+}
+
 /* Look through the symbols which are defined in other shared
    libraries and referenced here.  Update the list of version
    dependencies.  This will be put into the .gnu.version_r section.
@@ -2548,7 +2651,7 @@ elf_link_read_relocs_from_section (bfd *abfd,
     return false;
 
   /* Read the relocations.  */
-  if (bfd_bread (external_relocs, shdr->sh_size, abfd) != shdr->sh_size)
+  if (bfd_read (external_relocs, shdr->sh_size, abfd) != shdr->sh_size)
     return false;
 
   symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
@@ -2621,14 +2724,16 @@ elf_link_read_relocs_from_section (bfd *abfd,
    according to the KEEP_MEMORY argument.  If O has two relocation
    sections (both REL and RELA relocations), then the REL_HDR
    relocations will appear first in INTERNAL_RELOCS, followed by the
-   RELA_HDR relocations.  */
+   RELA_HDR relocations.  If INFO isn't NULL and KEEP_MEMORY is true,
+   update cache_size.  */
 
 Elf_Internal_Rela *
-_bfd_elf_link_read_relocs (bfd *abfd,
-                          asection *o,
-                          void *external_relocs,
-                          Elf_Internal_Rela *internal_relocs,
-                          bool keep_memory)
+_bfd_elf_link_info_read_relocs (bfd *abfd,
+                               struct bfd_link_info *info,
+                               asection *o,
+                               void *external_relocs,
+                               Elf_Internal_Rela *internal_relocs,
+                               bool keep_memory)
 {
   void *alloc1 = NULL;
   Elf_Internal_Rela *alloc2 = NULL;
@@ -2648,7 +2753,11 @@ _bfd_elf_link_read_relocs (bfd *abfd,
 
       size = (bfd_size_type) o->reloc_count * sizeof (Elf_Internal_Rela);
       if (keep_memory)
-       internal_relocs = alloc2 = (Elf_Internal_Rela *) bfd_alloc (abfd, size);
+       {
+         internal_relocs = alloc2 = (Elf_Internal_Rela *) bfd_alloc (abfd, size);
+         if (info)
+           info->cache_size += size;
+       }
       else
        internal_relocs = alloc2 = (Elf_Internal_Rela *) bfd_malloc (size);
       if (internal_relocs == NULL)
@@ -2712,6 +2821,22 @@ _bfd_elf_link_read_relocs (bfd *abfd,
   return NULL;
 }
 
+/* This is similar to _bfd_elf_link_info_read_relocs, except for that
+   NULL is passed to _bfd_elf_link_info_read_relocs for pointer to
+   struct bfd_link_info.  */
+
+Elf_Internal_Rela *
+_bfd_elf_link_read_relocs (bfd *abfd,
+                          asection *o,
+                          void *external_relocs,
+                          Elf_Internal_Rela *internal_relocs,
+                          bool keep_memory)
+{
+  return _bfd_elf_link_info_read_relocs (abfd, NULL, o, external_relocs,
+                                        internal_relocs, keep_memory);
+
+}
+
 /* Compute the size of, and allocate space for, REL_HDR which is the
    section header for a section containing relocations for O.  */
 
@@ -3246,7 +3371,7 @@ _bfd_elf_dynamic_symbol_p (struct elf_link_hash_entry *h,
 
     case STV_PROTECTED:
       hash_table = elf_hash_table (info);
-      if (!is_elf_hash_table (hash_table))
+      if (!is_elf_hash_table (&hash_table->root))
        return false;
 
       bed = get_elf_backend_data (hash_table->dynobj);
@@ -3330,7 +3455,11 @@ _bfd_elf_symbol_refs_local_p (struct elf_link_hash_entry *h,
     return false;
 
   hash_table = elf_hash_table (info);
-  if (!is_elf_hash_table (hash_table))
+  if (!is_elf_hash_table (&hash_table->root))
+    return true;
+
+  /* STV_PROTECTED symbols with indirect external access are local. */
+  if (info->indirect_extern_access > 0)
     return true;
 
   bed = get_elf_backend_data (hash_table->dynobj);
@@ -3435,7 +3564,7 @@ elf_link_is_defined_archive_symbol (bfd * abfd, carsym * symdef)
   Elf_Internal_Sym *isymend;
   bool result;
 
-  abfd = _bfd_get_elt_at_filepos (abfd, symdef->file_offset);
+  abfd = _bfd_get_elt_at_filepos (abfd, symdef->file_offset, NULL);
   if (abfd == NULL)
     return false;
 
@@ -3457,10 +3586,19 @@ elf_link_is_defined_archive_symbol (bfd * abfd, carsym * symdef)
       abfd = abfd->plugin_dummy_bfd;
       hdr = &elf_tdata (abfd)->symtab_hdr;
     }
-  else if ((abfd->flags & DYNAMIC) == 0 || elf_dynsymtab (abfd) == 0)
-    hdr = &elf_tdata (abfd)->symtab_hdr;
   else
-    hdr = &elf_tdata (abfd)->dynsymtab_hdr;
+    {
+      if (elf_use_dt_symtab_p (abfd))
+       {
+         bfd_set_error (bfd_error_wrong_format);
+         return false;
+       }
+
+      if ((abfd->flags & DYNAMIC) == 0 || elf_dynsymtab (abfd) == 0)
+       hdr = &elf_tdata (abfd)->symtab_hdr;
+      else
+       hdr = &elf_tdata (abfd)->dynsymtab_hdr;
+    }
 
   symcount = hdr->sh_size / get_elf_backend_data (abfd)->s->sizeof_sym;
 
@@ -3524,7 +3662,7 @@ _bfd_elf_add_dynamic_entry (struct bfd_link_info *info,
   Elf_Internal_Dyn dyn;
 
   hash_table = elf_hash_table (info);
-  if (! is_elf_hash_table (hash_table))
+  if (! is_elf_hash_table (&hash_table->root))
     return false;
 
   if (tag == DT_RELA || tag == DT_REL)
@@ -3568,7 +3706,7 @@ _bfd_elf_strip_zero_sized_dynamic_sections (struct bfd_link_info *info)
     return true;
 
   hash_table = elf_hash_table (info);
-  if (!is_elf_hash_table (hash_table))
+  if (!is_elf_hash_table (&hash_table->root))
     return false;
 
   if (!hash_table->dynobj)
@@ -3614,7 +3752,7 @@ _bfd_elf_strip_zero_sized_dynamic_sections (struct bfd_link_info *info)
     else
       pp = &s->next;
 
-  if (strip_zero_sized_plt)
+  if (strip_zero_sized_plt && sdynamic->size != 0)
     for (extdyn = sdynamic->contents;
         extdyn < sdynamic->contents + sdynamic->size;
         extdyn = next)
@@ -3641,7 +3779,8 @@ _bfd_elf_strip_zero_sized_dynamic_sections (struct bfd_link_info *info)
     {
       /* Regenerate program headers.  */
       elf_seg_map (info->output_bfd) = NULL;
-      return _bfd_elf_map_sections_to_segments (info->output_bfd, info);
+      return _bfd_elf_map_sections_to_segments (info->output_bfd, info,
+                                               NULL);
     }
 
   return true;
@@ -3674,7 +3813,7 @@ bfd_elf_add_dt_needed_tag (bfd *abfd, struct bfd_link_info *info)
 
       bed = get_elf_backend_data (hash_table->dynobj);
       sdyn = bfd_get_linker_section (hash_table->dynobj, ".dynamic");
-      if (sdyn != NULL)
+      if (sdyn != NULL && sdyn->size != 0)
        for (extdyn = sdyn->contents;
             extdyn < sdyn->contents + sdyn->size;
             extdyn += bed->s->sizeof_dyn)
@@ -3823,7 +3962,7 @@ elf_finalize_dynstr (bfd *output_bfd, struct bfd_link_info *info)
 
   /* Update all .dynamic entries referencing .dynstr strings.  */
   for (extdyn = sdyn->contents;
-       extdyn < sdyn->contents + sdyn->size;
+       extdyn < PTR_ADD (sdyn->contents, sdyn->size);
        extdyn += bed->s->sizeof_dyn)
     {
       Elf_Internal_Dyn dyn;
@@ -3973,10 +4112,13 @@ _bfd_elf_notice_as_needed (bfd *ibfd,
   return (*info->callbacks->notice) (info, NULL, NULL, ibfd, NULL, act, 0);
 }
 
-/* Check relocations an ELF object file.  */
+/* Call ACTION on each relocation in an ELF object file.  */
 
 bool
-_bfd_elf_link_check_relocs (bfd *abfd, struct bfd_link_info *info)
+_bfd_elf_link_iterate_on_relocs
+  (bfd *abfd, struct bfd_link_info *info,
+   bool (*action) (bfd *, struct bfd_link_info *, asection *,
+                  const Elf_Internal_Rela *))
 {
   const struct elf_backend_data *bed = get_elf_backend_data (abfd);
   struct elf_link_hash_table *htab = elf_hash_table (info);
@@ -3999,8 +4141,7 @@ _bfd_elf_link_check_relocs (bfd *abfd, struct bfd_link_info *info)
      I have no idea how to handle linking PIC code into a file of a
      different format.  It probably can't be done.  */
   if ((abfd->flags & DYNAMIC) == 0
-      && is_elf_hash_table (htab)
-      && bed->check_relocs != NULL
+      && is_elf_hash_table (&htab->root)
       && elf_object_id (abfd) == elf_hash_table_id (htab)
       && (*bed->relocs_compatible) (abfd->xvec, info->output_bfd->xvec))
     {
@@ -4028,12 +4169,14 @@ _bfd_elf_link_check_relocs (bfd *abfd, struct bfd_link_info *info)
              || bfd_is_abs_section (o->output_section))
            continue;
 
-         internal_relocs = _bfd_elf_link_read_relocs (abfd, o, NULL, NULL,
-                                                      info->keep_memory);
+         internal_relocs = _bfd_elf_link_info_read_relocs (abfd, info,
+                                                           o, NULL,
+                                                           NULL,
+                                                           _bfd_link_keep_memory (info));
          if (internal_relocs == NULL)
            return false;
 
-         ok = (*bed->check_relocs) (abfd, info, o, internal_relocs);
+         ok = action (abfd, info, o, internal_relocs);
 
          if (elf_section_data (o)->relocs != internal_relocs)
            free (internal_relocs);
@@ -4046,6 +4189,19 @@ _bfd_elf_link_check_relocs (bfd *abfd, struct bfd_link_info *info)
   return true;
 }
 
+/* Check relocations in an ELF object file.  This is called after
+   all input files have been opened.  */
+
+bool
+_bfd_elf_link_check_relocs (bfd *abfd, struct bfd_link_info *info)
+{
+  const struct elf_backend_data *bed = get_elf_backend_data (abfd);
+  if (bed->check_relocs != NULL)
+    return _bfd_elf_link_iterate_on_relocs (abfd, info,
+                                           bed->check_relocs);
+  return true;
+}
+
 /* Add symbols from an ELF object file to the linker hash table.  */
 
 static bool
@@ -4086,6 +4242,12 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info)
   htab = elf_hash_table (info);
   bed = get_elf_backend_data (abfd);
 
+  if (elf_use_dt_symtab_p (abfd))
+    {
+      bfd_set_error (bfd_error_wrong_format);
+      return false;
+    }
+
   if ((abfd->flags & DYNAMIC) == 0)
     dynamic = false;
   else
@@ -4096,7 +4258,7 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info)
         hope of using a dynamic object which does not exactly match
         the format of the output file.  */
       if (bfd_link_relocatable (info)
-         || !is_elf_hash_table (htab)
+         || !is_elf_hash_table (&htab->root)
          || info->output_bfd->xvec != abfd->xvec)
        {
          if (bfd_link_relocatable (info))
@@ -4204,7 +4366,7 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info)
              || (!bfd_link_relocatable (info)
                  && info->nointerp
                  && (info->export_dynamic || info->dynamic)))
-         && is_elf_hash_table (htab)
+         && is_elf_hash_table (&htab->root)
          && info->output_bfd->xvec == abfd->xvec
          && !htab->dynamic_sections_created)
        {
@@ -4212,7 +4374,7 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info)
            goto error_return;
        }
     }
-  else if (!is_elf_hash_table (htab))
+  else if (!is_elf_hash_table (&htab->root))
     goto error_return;
   else
     {
@@ -4239,7 +4401,7 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info)
                       | DYN_NO_NEEDED)) == 0;
 
       s = bfd_get_section_by_name (abfd, ".dynamic");
-      if (s != NULL)
+      if (s != NULL && s->size != 0 && (s->flags & SEC_HAS_CONTENTS) != 0)
        {
          bfd_byte *dynbuf;
          bfd_byte *extdyn;
@@ -4259,7 +4421,7 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info)
          shlink = elf_elfsections (abfd)[elfsec]->sh_link;
 
          for (extdyn = dynbuf;
-              extdyn <= dynbuf + s->size - bed->s->sizeof_dyn;
+              (size_t) (dynbuf + s->size - extdyn) >= bed->s->sizeof_dyn;
               extdyn += bed->s->sizeof_dyn)
            {
              Elf_Internal_Dyn dyn;
@@ -4351,6 +4513,8 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info)
                  unsigned int tagv = dyn.d_un.d_val;
                  audit = bfd_elf_string_from_elf_section (abfd, shlink, tagv);
                }
+             if (dyn.d_tag == DT_FLAGS_1)
+               elf_tdata (abfd)->is_pie = (dyn.d_un.d_val & DF_1_PIE) != 0;
            }
 
          free (dynbuf);
@@ -4611,7 +4775,7 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info)
        (_("%pB: plugin needed to handle lto object"), abfd);
     }
 
-  for (isym = isymbuf, isymend = isymbuf + extsymcount;
+  for (isym = isymbuf, isymend = PTR_ADD (isymbuf, extsymcount);
        isym < isymend;
        isym++, sym_hash++, ever = (ever != NULL ? ever + 1 : NULL))
     {
@@ -4796,7 +4960,7 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info)
       old_bfd = NULL;
       new_sec = sec;
 
-      if (is_elf_hash_table (htab))
+      if (is_elf_hash_table (&htab->root))
        {
          Elf_Internal_Versym iver;
          unsigned int vernum = 0;
@@ -4948,7 +5112,8 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info)
                 || h->root.type == bfd_link_hash_warning)
            h = (struct elf_link_hash_entry *) h->root.u.i.link;
 
-         if (elf_tdata (abfd)->verdef != NULL
+         if (h->versioned != unversioned
+             && elf_tdata (abfd)->verdef != NULL
              && vernum > 1
              && definition)
            h->verinfo.verdef = &elf_tdata (abfd)->verdef[vernum - 1];
@@ -4972,7 +5137,7 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info)
 
       /* Setting the index to -3 tells elf_link_output_extsym that
         this symbol is defined in a discarded section.  */
-      if (discarded && is_elf_hash_table (htab))
+      if (discarded && is_elf_hash_table (&htab->root))
        h->indx = -3;
 
       new_weak = (flags & BSF_WEAK) != 0;
@@ -4980,7 +5145,7 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info)
          && definition
          && new_weak
          && !bed->is_function_type (ELF_ST_TYPE (isym->st_info))
-         && is_elf_hash_table (htab)
+         && is_elf_hash_table (&htab->root)
          && h->u.alias == NULL)
        {
          /* Keep a list of all weak defined non function symbols from
@@ -5019,7 +5184,7 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info)
            h->root.u.c.p->alignment_power = old_alignment;
        }
 
-      if (is_elf_hash_table (htab))
+      if (is_elf_hash_table (&htab->root))
        {
          /* Set a flag in the hash table entry indicating the type of
             reference or definition we just found.  A dynamic symbol
@@ -5152,10 +5317,14 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info)
                  else
                    _bfd_error_handler
                      /* xgettext:c-format */
-                     (_("warning: alignment %u of symbol `%s' in %pB"
-                        " is smaller than %u in %pB"),
+                     (_("warning: alignment %u of normal symbol `%s' in %pB"
+                        " is smaller than %u used by the common definition in %pB"),
                       1 << normal_align, name, normal_bfd,
                       1 << common_align, common_bfd);
+
+                 /* PR 30499: make sure that users understand that this warning is serious.  */
+                 _bfd_error_handler
+                   (_("warning: NOTE: alignment discrepancies can cause real problems.  Investigation is advised."));
                }
            }
 
@@ -5167,12 +5336,18 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info)
              if (h->size != 0
                  && h->size != isym->st_size
                  && ! size_change_ok)
-               _bfd_error_handler
-                 /* xgettext:c-format */
-                 (_("warning: size of symbol `%s' changed"
-                    " from %" PRIu64 " in %pB to %" PRIu64 " in %pB"),
-                  name, (uint64_t) h->size, old_bfd,
-                  (uint64_t) isym->st_size, abfd);
+               {
+                 _bfd_error_handler
+                   /* xgettext:c-format */
+                   (_("warning: size of symbol `%s' changed"
+                      " from %" PRIu64 " in %pB to %" PRIu64 " in %pB"),
+                    name, (uint64_t) h->size, old_bfd,
+                    (uint64_t) isym->st_size, abfd);
+
+                 /* PR 30499: make sure that users understand that this warning is serious.  */
+                 _bfd_error_handler
+                   (_("warning: NOTE: size discrepancies can cause real problems.  Investigation is advised."));
+               }
 
              h->size = isym->st_size;
            }
@@ -5232,7 +5407,14 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info)
              h->unique_global = (flags & BSF_GNU_UNIQUE) != 0;
            }
 
-         if (definition && !dynamic)
+         /* Don't add indirect symbols for .symver x, x@FOO aliases
+            in IR.  Since all data or text symbols in IR have the
+            same type, value and section, we can't tell if a symbol
+            is an alias of another symbol by their types, values and
+            sections.  */
+         if (definition
+             && !dynamic
+             && (abfd->flags & BFD_PLUGIN) == 0)
            {
              char *p = strchr (name, ELF_VER_CHR);
              if (p != NULL && p[1] != ELF_VER_CHR)
@@ -5356,9 +5538,10 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info)
                  && (s->flags & SEC_DEBUGGING) != 0))
            continue;
 
-         internal_relocs = _bfd_elf_link_read_relocs (abfd, s, NULL,
-                                                      NULL,
-                                                      info->keep_memory);
+         internal_relocs = _bfd_elf_link_info_read_relocs (abfd, info,
+                                                           s, NULL,
+                                                           NULL,
+                                                           _bfd_link_keep_memory (info));
          if (internal_relocs == NULL)
            goto error_free_vers;
 
@@ -5681,7 +5864,7 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info)
      of the .stab/.stabstr sections.  */
   if (! dynamic
       && ! info->traditional_format
-      && is_elf_hash_table (htab)
+      && is_elf_hash_table (&htab->root)
       && (info->strip != strip_all && info->strip != strip_debugger))
     {
       asection *stabstr;
@@ -5744,16 +5927,16 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info)
 /* Return the linker hash table entry of a symbol that might be
    satisfied by an archive symbol.  Return -1 on error.  */
 
-struct elf_link_hash_entry *
+struct bfd_link_hash_entry *
 _bfd_elf_archive_symbol_lookup (bfd *abfd,
                                struct bfd_link_info *info,
                                const char *name)
 {
-  struct elf_link_hash_entry *h;
+  struct bfd_link_hash_entry *h;
   char *p, *copy;
   size_t len, first;
 
-  h = elf_link_hash_lookup (elf_hash_table (info), name, false, false, true);
+  h = bfd_link_hash_lookup (info->hash, name, false, false, true);
   if (h != NULL)
     return h;
 
@@ -5770,20 +5953,19 @@ _bfd_elf_archive_symbol_lookup (bfd *abfd,
   len = strlen (name);
   copy = (char *) bfd_alloc (abfd, len);
   if (copy == NULL)
-    return (struct elf_link_hash_entry *) -1;
+    return (struct bfd_link_hash_entry *) -1;
 
   first = p - name + 1;
   memcpy (copy, name, first);
   memcpy (copy + first, name + first + 1, len - first);
 
-  h = elf_link_hash_lookup (elf_hash_table (info), copy, false, false, true);
+  h = bfd_link_hash_lookup (info->hash, 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, true);
+      h = bfd_link_hash_lookup (info->hash, copy, false, false, true);
     }
 
   bfd_release (abfd, copy);
@@ -5812,7 +5994,7 @@ elf_link_add_archive_symbols (bfd *abfd, struct bfd_link_info *info)
   bool loop;
   size_t amt;
   const struct elf_backend_data *bed;
-  struct elf_link_hash_entry * (*archive_symbol_lookup)
+  struct bfd_link_hash_entry * (*archive_symbol_lookup)
     (bfd *, struct bfd_link_info *, const char *);
 
   if (! bfd_has_map (abfd))
@@ -5853,7 +6035,7 @@ elf_link_add_archive_symbols (bfd *abfd, struct bfd_link_info *info)
       symdefend = symdef + c;
       for (i = 0; symdef < symdefend; symdef++, i++)
        {
-         struct elf_link_hash_entry *h;
+         struct bfd_link_hash_entry *h;
          bfd *element;
          struct bfd_link_hash_entry *undefs_tail;
          symindex mark;
@@ -5867,21 +6049,22 @@ elf_link_add_archive_symbols (bfd *abfd, struct bfd_link_info *info)
            }
 
          h = archive_symbol_lookup (abfd, info, symdef->name);
-         if (h == (struct elf_link_hash_entry *) -1)
+         if (h == (struct bfd_link_hash_entry *) -1)
            goto error_return;
 
          if (h == NULL)
            continue;
 
-         if (h->root.type == bfd_link_hash_undefined)
+         if (h->type == bfd_link_hash_undefined)
            {
              /* If the archive element has already been loaded then one
                 of the symbols defined by that element might have been
                 made undefined due to being in a discarded section.  */
-             if (h->indx == -3)
+             if (is_elf_hash_table (info->hash)
+                 && ((struct elf_link_hash_entry *) h)->indx == -3)
                continue;
            }
-         else if (h->root.type == bfd_link_hash_common)
+         else if (h->type == bfd_link_hash_common)
            {
              /* We currently have a common symbol.  The archive map contains
                 a reference to this symbol, so we may want to include it.  We
@@ -5900,14 +6083,15 @@ elf_link_add_archive_symbols (bfd *abfd, struct bfd_link_info *info)
            }
          else
            {
-             if (h->root.type != bfd_link_hash_undefweak)
+             if (h->type != bfd_link_hash_undefweak)
                /* Symbol must be defined.  Don't check it again.  */
                included[i] = true;
              continue;
            }
 
          /* We need to include this archive member.  */
-         element = _bfd_get_elt_at_filepos (abfd, symdef->file_offset);
+         element = _bfd_get_elt_at_filepos (abfd, symdef->file_offset,
+                                            info);
          if (element == NULL)
            goto error_return;
 
@@ -6202,15 +6386,11 @@ compute_bucket_count (struct bfd_link_info *info ATTRIBUTE_UNUSED,
   size_t best_size = 0;
   unsigned long int i;
 
-  /* We have a problem here.  The following code to optimize the table
-     size requires an integer type with more the 32 bits.  If
-     BFD_HOST_U_64_BIT is set we know about such a type.  */
-#ifdef BFD_HOST_U_64_BIT
   if (info->optimize)
     {
       size_t minsize;
       size_t maxsize;
-      BFD_HOST_U_64_BIT best_chlen = ~((BFD_HOST_U_64_BIT) 0);
+      uint64_t best_chlen = ~((uint64_t) 0);
       bfd *dynobj = elf_hash_table (info)->dynobj;
       size_t dynsymcount = elf_hash_table (info)->dynsymcount;
       const struct elf_backend_data *bed = get_elf_backend_data (dynobj);
@@ -6247,7 +6427,7 @@ compute_bucket_count (struct bfd_link_info *info ATTRIBUTE_UNUSED,
       for (i = minsize; i < maxsize; ++i)
        {
          /* Walk through the array of hashcodes and count the collisions.  */
-         BFD_HOST_U_64_BIT max;
+         uint64_t max;
          unsigned long int j;
          unsigned long int fact;
 
@@ -6312,11 +6492,7 @@ compute_bucket_count (struct bfd_link_info *info ATTRIBUTE_UNUSED,
       free (counts);
     }
   else
-#endif /* defined (BFD_HOST_U_64_BIT) */
     {
-      /* This is the fallback solution if no 64bit type is available or if we
-        are not supposed to spend much time on optimizations.  We select the
-        bucket count using a fixed set of numbers.  */
       for (i = 0; elf_buckets[i] != 0; i++)
        {
          best_size = elf_buckets[i];
@@ -6464,6 +6640,21 @@ bfd_elf_size_dynamic_sections (bfd *output_bfd,
   if (!is_elf_hash_table (info->hash))
     return true;
 
+  /* Any syms created from now on start with -1 in
+     got.refcount/offset and plt.refcount/offset.  */
+  elf_hash_table (info)->init_got_refcount
+    = elf_hash_table (info)->init_got_offset;
+  elf_hash_table (info)->init_plt_refcount
+    = elf_hash_table (info)->init_plt_offset;
+
+  bed = get_elf_backend_data (output_bfd);
+
+  /* The backend may have to create some sections regardless of whether
+     we're dynamic or not.  */
+  if (bed->elf_backend_always_size_sections
+      && ! (*bed->elf_backend_always_size_sections) (output_bfd, info))
+    return false;
+
   dynobj = elf_hash_table (info)->dynobj;
 
   if (dynobj != NULL && elf_hash_table (info)->dynamic_sections_created)
@@ -6822,8 +7013,6 @@ bfd_elf_size_dynamic_sections (bfd *output_bfd,
        }
     }
 
-  bed = get_elf_backend_data (output_bfd);
-
   if (info->gc_sections && bed->can_gc_sections)
     {
       struct elf_gc_sweep_symbol_info sweep_info;
@@ -6858,6 +7047,13 @@ bfd_elf_size_dynamic_sections (bfd *output_bfd,
       if (sinfo.failed)
        return false;
 
+      if (info->enable_dt_relr)
+       {
+         elf_link_add_dt_relr_dependency (&sinfo);
+         if (sinfo.failed)
+           return false;
+       }
+
       if (elf_tdata (output_bfd)->verref == NULL)
        s->flags |= SEC_EXCLUDE;
       else
@@ -6945,33 +7141,41 @@ bfd_elf_size_dynamic_sections (bfd *output_bfd,
        }
     }
 
-  /* Any syms created from now on start with -1 in
-     got.refcount/offset and plt.refcount/offset.  */
-  elf_hash_table (info)->init_got_refcount
-    = elf_hash_table (info)->init_got_offset;
-  elf_hash_table (info)->init_plt_refcount
-    = elf_hash_table (info)->init_plt_offset;
-
   if (bfd_link_relocatable (info)
       && !_bfd_elf_size_group_sections (info))
     return false;
 
-  /* The backend may have to create some sections regardless of whether
-     we're dynamic or not.  */
-  if (bed->elf_backend_always_size_sections
-      && ! (*bed->elf_backend_always_size_sections) (output_bfd, info))
-    return false;
-
   /* Determine any GNU_STACK segment requirements, after the backend
      has had a chance to set a default segment size.  */
   if (info->execstack)
-    elf_stack_flags (output_bfd) = PF_R | PF_W | PF_X;
+    {
+      /* If the user has explicitly requested warnings, then generate one even
+        though the choice is the result of another command line option.  */
+      if (info->warn_execstack == 1)
+       {
+         if (info->error_execstack)
+           {
+             _bfd_error_handler
+               (_("\
+error: creating an executable stack because of -z execstack command line option"));
+             return false;
+           }
+
+         _bfd_error_handler
+           (_("\
+warning: enabling an executable stack because of -z execstack command line option"));
+       }
+
+      elf_stack_flags (output_bfd) = PF_R | PF_W | PF_X;
+    }
   else if (info->noexecstack)
     elf_stack_flags (output_bfd) = PF_R | PF_W;
   else
     {
       bfd *inputobj;
       asection *notesec = NULL;
+      bfd *noteobj = NULL;
+      bfd *emptyobj = NULL;
       int exec = 0;
 
       for (inputobj = info->input_bfds;
@@ -6990,15 +7194,67 @@ bfd_elf_size_dynamic_sections (bfd *output_bfd,
          s = bfd_get_section_by_name (inputobj, ".note.GNU-stack");
          if (s)
            {
-             if (s->flags & SEC_CODE)
-               exec = PF_X;
              notesec = s;
+             if (s->flags & SEC_CODE)
+               {
+                 noteobj = inputobj;
+                 exec = PF_X;
+                 /* There is no point in scanning the remaining bfds.  */
+                 break;
+               }
+           }
+         else if (bed->default_execstack && info->default_execstack)
+           {
+             exec = PF_X;
+             emptyobj = inputobj;
            }
-         else if (bed->default_execstack)
-           exec = PF_X;
        }
+
       if (notesec || info->stacksize > 0)
-       elf_stack_flags (output_bfd) = PF_R | PF_W | exec;
+       {
+         if (exec)
+           {
+             if (info->warn_execstack != 0)
+               {
+                 /* PR 29072: Because an executable stack is a serious
+                    security risk, make sure that the user knows that it is
+                    being enabled despite the fact that it was not requested
+                    on the command line.  */
+                 if (noteobj)
+                   {
+                     if (info->error_execstack)
+                       {
+                         _bfd_error_handler (_("\
+error: %s: is triggering the generation of an executable stack (because it has an executable .note.GNU-stack section)"),
+                                             bfd_get_filename (noteobj));
+                         return false;
+                       }
+
+                     _bfd_error_handler (_("\
+warning: %s: requires executable stack (because the .note.GNU-stack section is executable)"),
+                      bfd_get_filename (noteobj));
+                   }
+                 else if (emptyobj)
+                   {
+                     if (info->error_execstack)
+                       {
+                         _bfd_error_handler (_("\
+error: %s: is triggering the generation of an executable stack because it does not have a .note.GNU-stack section"),
+                                             bfd_get_filename (emptyobj));
+                         return false;
+                       }
+
+                     _bfd_error_handler (_("\
+warning: %s: missing .note.GNU-stack section implies executable stack"),
+                                         bfd_get_filename (emptyobj));
+                     _bfd_error_handler (_("\
+NOTE: This behaviour is deprecated and will be removed in a future version of the linker"));
+                   }
+               }
+           }
+         elf_stack_flags (output_bfd) = PF_R | PF_W | exec;
+       }
+
       if (notesec && exec && bfd_link_relocatable (info)
          && notesec->output_section != bfd_abs_section_ptr)
        notesec->output_section->flags |= SEC_CODE;
@@ -8009,7 +8265,7 @@ bfd_elf_get_bfd_needed_list (bfd *abfd,
     return true;
 
   s = bfd_get_section_by_name (abfd, ".dynamic");
-  if (s == NULL || s->size == 0)
+  if (s == NULL || s->size == 0 || (s->flags & SEC_HAS_CONTENTS) == 0)
     return true;
 
   if (!bfd_malloc_and_get_section (abfd, s, &dynbuf))
@@ -8024,9 +8280,9 @@ bfd_elf_get_bfd_needed_list (bfd *abfd,
   extdynsize = get_elf_backend_data (abfd)->s->sizeof_dyn;
   swap_dyn_in = get_elf_backend_data (abfd)->s->swap_dyn_in;
 
-  extdyn = dynbuf;
-  extdynend = extdyn + s->size;
-  for (; extdyn < extdynend; extdyn += extdynsize)
+  for (extdyn = dynbuf, extdynend = dynbuf + s->size;
+       (size_t) (extdynend - extdyn) >= extdynsize;
+       extdyn += extdynsize)
     {
       Elf_Internal_Dyn dyn;
 
@@ -8177,8 +8433,7 @@ elf_create_symbuf (size_t symcount, Elf_Internal_Sym *isymbuf)
       ssymhead->count++;
     }
   BFD_ASSERT ((size_t) (ssymhead - ssymbuf) == shndx_count
-             && (((bfd_hostptr_t) ssym - (bfd_hostptr_t) ssymbuf)
-                 == total_size));
+             && (uintptr_t) ssym - (uintptr_t) ssymbuf == total_size);
 
   free (indbuf);
   return ssymbuf;
@@ -9151,7 +9406,6 @@ ext32b_r_offset (const void *p)
   return aval;
 }
 
-#ifdef BFD_HOST_64_BIT
 static bfd_vma
 ext64l_r_offset (const void *p)
 {
@@ -9195,7 +9449,6 @@ ext64b_r_offset (const void *p)
                   | (uint64_t) a->c[7]);
   return aval;
 }
-#endif
 
 /* When performing a relocatable link, the input relocations are
    preserved.  But, if they reference global symbols, the indices
@@ -9299,13 +9552,11 @@ elf_link_adjust_relocs (bfd *abfd,
        }
       else
        {
-#ifdef BFD_HOST_64_BIT
          if (abfd->xvec->header_byteorder == BFD_ENDIAN_LITTLE)
            ext_r_off = ext64l_r_offset;
          else if (abfd->xvec->header_byteorder == BFD_ENDIAN_BIG)
            ext_r_off = ext64b_r_offset;
          else
-#endif
            abort ();
        }
 
@@ -9358,12 +9609,20 @@ elf_link_adjust_relocs (bfd *abfd,
              size_t sortlen = p - loc;
              bfd_vma r_off2 = (*ext_r_off) (loc);
              size_t runlen = elt_size;
+             bfd_vma r_off_runend = r_off;
+             bfd_vma r_off_runend_next;
              size_t buf_size = 96 * 1024;
              while (p + runlen < end
                     && (sortlen <= buf_size
                         || runlen + elt_size <= buf_size)
-                    && r_off2 > (*ext_r_off) (p + runlen))
-               runlen += elt_size;
+                    /* run must not break the ordering of base..loc+1 */
+                    && r_off2 > (r_off_runend_next = (*ext_r_off) (p + runlen))
+                    /* run must be already sorted */
+                    && r_off_runend_next >= r_off_runend)
+               {
+                 runlen += elt_size;
+                 r_off_runend = r_off_runend_next;
+               }
              if (buf == NULL)
                {
                  buf = bfd_malloc (buf_size);
@@ -9797,9 +10056,7 @@ elf_link_output_symstrtab (void *finf,
   if (ELF_ST_BIND (elfsym->st_info) == STB_GNU_UNIQUE)
     elf_tdata (flinfo->output_bfd)->has_gnu_osabi |= elf_gnu_osabi_unique;
 
-  if (name == NULL
-      || *name == '\0'
-      || (input_sec->flags & SEC_EXCLUDE))
+  if (name == NULL || *name == '\0')
     elfsym->st_name = (unsigned long) -1;
   else
     {
@@ -9832,6 +10089,9 @@ elf_link_output_symstrtab (void *finf,
               && ELF_ST_BIND (elfsym->st_info) == STB_LOCAL)
        {
          struct local_hash_entry *lh;
+         size_t count_len;
+         size_t base_len;
+         char buf[30];
          switch (ELF_ST_TYPE (elfsym->st_info))
            {
            case STT_FILE:
@@ -9842,28 +10102,24 @@ elf_link_output_symstrtab (void *finf,
                     (&flinfo->local_hash_table, name, true, false);
              if (lh == NULL)
                return 0;
-             if (lh->count)
+             /* Always append ".COUNT" to local symbols to avoid
+                potential conflicts with local symbol "XXX.COUNT".  */
+             sprintf (buf, "%lx", lh->count);
+             base_len = lh->size;
+             if (!base_len)
                {
-                 /* Append ".COUNT" to duplicated local symbols.  */
-                 size_t count_len;
-                 size_t base_len = lh->size;
-                 char buf[30];
-                 sprintf (buf, "%lx", lh->count);
-                 if (!base_len)
-                   {
-                     base_len = strlen (name);
-                     lh->size = base_len;
-                   }
-                 count_len = strlen (buf);
-                 versioned_name = bfd_alloc (flinfo->output_bfd,
-                                             base_len + count_len + 2);
-                 if (versioned_name == NULL)
-                   return 0;
-                 memcpy (versioned_name, name, base_len);
-                 versioned_name[base_len] = '.';
-                 memcpy (versioned_name + base_len + 1, buf,
-                         count_len + 1);
+                 base_len = strlen (name);
+                 lh->size = base_len;
                }
+             count_len = strlen (buf);
+             versioned_name = bfd_alloc (flinfo->output_bfd,
+                                         base_len + count_len + 2);
+             if (versioned_name == NULL)
+               return 0;
+             memcpy (versioned_name, name, base_len);
+             versioned_name[base_len] = '.';
+             memcpy (versioned_name + base_len + 1, buf,
+                     count_len + 1);
              lh->count++;
              break;
            }
@@ -9877,7 +10133,7 @@ elf_link_output_symstrtab (void *finf,
 
   hash_table = elf_hash_table (flinfo->info);
   strtabsize = hash_table->strtabsize;
-  if (strtabsize <= hash_table->strtabcount)
+  if (strtabsize <= flinfo->output_bfd->symcount)
     {
       strtabsize += strtabsize;
       hash_table->strtabsize = strtabsize;
@@ -9888,14 +10144,10 @@ elf_link_output_symstrtab (void *finf,
       if (hash_table->strtab == NULL)
        return 0;
     }
-  hash_table->strtab[hash_table->strtabcount].sym = *elfsym;
-  hash_table->strtab[hash_table->strtabcount].dest_index
-    = hash_table->strtabcount;
-  hash_table->strtab[hash_table->strtabcount].destshndx_index
-    = flinfo->symshndxbuf ? bfd_get_symcount (flinfo->output_bfd) : 0;
-
+  hash_table->strtab[flinfo->output_bfd->symcount].sym = *elfsym;
+  hash_table->strtab[flinfo->output_bfd->symcount].dest_index
+    = flinfo->output_bfd->symcount;
   flinfo->output_bfd->symcount += 1;
-  hash_table->strtabcount += 1;
 
   return 1;
 }
@@ -9915,14 +10167,14 @@ elf_link_swap_symbols_out (struct elf_final_link_info *flinfo)
   file_ptr pos;
   bool ret;
 
-  if (!hash_table->strtabcount)
+  if (flinfo->output_bfd->symcount == 0)
     return true;
 
   BFD_ASSERT (elf_onesymtab (flinfo->output_bfd));
 
   bed = get_elf_backend_data (flinfo->output_bfd);
 
-  amt = bed->s->sizeof_sym * hash_table->strtabcount;
+  amt = bed->s->sizeof_sym * flinfo->output_bfd->symcount;
   symbuf = (bfd_byte *) bfd_malloc (amt);
   if (symbuf == NULL)
     return false;
@@ -9940,7 +10192,7 @@ elf_link_swap_symbols_out (struct elf_final_link_info *flinfo)
     }
 
   /* Now swap out the symbols.  */
-  for (i = 0; i < hash_table->strtabcount; i++)
+  for (i = 0; i < flinfo->output_bfd->symcount; i++)
     {
       struct elf_sym_strtab *elfsym = &hash_table->strtab[i];
       if (elfsym->sym.st_name == (unsigned long) -1)
@@ -9960,15 +10212,15 @@ elf_link_swap_symbols_out (struct elf_final_link_info *flinfo)
                               ((bfd_byte *) symbuf
                                + (elfsym->dest_index
                                   * bed->s->sizeof_sym)),
-                              (flinfo->symshndxbuf
-                               + elfsym->destshndx_index));
+                              NPTR_ADD (flinfo->symshndxbuf,
+                                        elfsym->dest_index));
     }
 
   hdr = &elf_tdata (flinfo->output_bfd)->symtab_hdr;
   pos = hdr->sh_offset + hdr->sh_size;
-  amt = hash_table->strtabcount * bed->s->sizeof_sym;
+  amt = bed->s->sizeof_sym * flinfo->output_bfd->symcount;
   if (bfd_seek (flinfo->output_bfd, pos, SEEK_SET) == 0
-      && bfd_bwrite (symbuf, amt, flinfo->output_bfd) == amt)
+      && bfd_write (symbuf, amt, flinfo->output_bfd) == amt)
     {
       hdr->sh_size += amt;
       ret = true;
@@ -10706,6 +10958,7 @@ elf_section_ignore_discarded_relocs (asection *sec)
     case SEC_INFO_TYPE_STABS:
     case SEC_INFO_TYPE_EH_FRAME:
     case SEC_INFO_TYPE_EH_FRAME_ENTRY:
+    case SEC_INFO_TYPE_SFRAME:
       return true;
     default:
       break;
@@ -10731,12 +10984,22 @@ elf_section_ignore_discarded_relocs (asection *sec)
 unsigned int
 _bfd_elf_default_action_discarded (asection *sec)
 {
+  const struct elf_backend_data *bed;
+  bed = get_elf_backend_data (sec->owner);
+
   if (sec->flags & SEC_DEBUGGING)
     return PRETEND;
 
   if (strcmp (".eh_frame", sec->name) == 0)
     return 0;
 
+  if (bed->elf_backend_can_make_multiple_eh_frame
+      && strncmp (sec->name, ".eh_frame.", 10) == 0)
+    return 0;
+
+  if (strcmp (".sframe", sec->name) == 0)
+    return 0;
+
   if (strcmp (".gcc_except_table", sec->name) == 0)
     return 0;
 
@@ -10874,7 +11137,7 @@ elf_link_input_bfd (struct elf_final_link_info *flinfo, bfd *input_bfd)
   /* Find local symbol sections and adjust values of symbols in
      SEC_MERGE sections.  Write out those local symbols we know are
      going into the output file.  */
-  isymend = isymbuf + locsymcount;
+  isymend = PTR_ADD (isymbuf, locsymcount);
   for (isym = isymbuf, pindex = flinfo->indices, ppsection = flinfo->sections;
        isym < isymend;
        isym++, pindex++, ppsection++)
@@ -10949,22 +11212,10 @@ elf_link_input_bfd (struct elf_final_link_info *flinfo, bfd *input_bfd)
 
       /* If this symbol is defined in a section which we are
         discarding, we don't need to keep it.  */
-      if (isym->st_shndx != SHN_UNDEF
-         && isym->st_shndx < SHN_LORESERVE
-         && isec->output_section == NULL
-         && flinfo->info->non_contiguous_regions
-         && flinfo->info->non_contiguous_regions_warnings)
-       {
-         _bfd_error_handler (_("warning: --enable-non-contiguous-regions "
-                               "discards section `%s' from '%s'\n"),
-                             isec->name, bfd_get_filename (isec->owner));
-         continue;
-       }
-
-      if (isym->st_shndx != SHN_UNDEF
-         && isym->st_shndx < SHN_LORESERVE
-         && bfd_section_removed_from_list (output_bfd,
-                                           isec->output_section))
+      if (isym->st_shndx < SHN_LORESERVE
+         && (isec->output_section == NULL
+             || bfd_section_removed_from_list (output_bfd,
+                                               isec->output_section)))
        continue;
 
       /* Get the name of the symbol.  */
@@ -11171,6 +11422,13 @@ elf_link_input_bfd (struct elf_final_link_info *flinfo, bfd *input_bfd)
              contents = flinfo->contents;
            }
        }
+      else if (!(o->flags & SEC_RELOC)
+              && !bed->elf_backend_write_section
+              && o->sec_info_type == SEC_INFO_TYPE_MERGE)
+       /* A MERGE section that has no relocations doesn't need the
+          contents anymore, they have been recorded earlier.  Except
+          if the backend has special provisions for writing sections.  */
+       contents = NULL;
       else
        {
          contents = flinfo->contents;
@@ -11187,37 +11445,14 @@ elf_link_input_bfd (struct elf_final_link_info *flinfo, bfd *input_bfd)
 
          /* Get the swapped relocs.  */
          internal_relocs
-           = _bfd_elf_link_read_relocs (input_bfd, o, flinfo->external_relocs,
-                                        flinfo->internal_relocs, false);
+           = _bfd_elf_link_info_read_relocs (input_bfd, flinfo->info, o,
+                                             flinfo->external_relocs,
+                                             flinfo->internal_relocs,
+                                             false);
          if (internal_relocs == NULL
              && o->reloc_count > 0)
            return false;
 
-         /* We need to reverse-copy input .ctors/.dtors sections if
-            they are placed in .init_array/.finit_array for output.  */
-         if (o->size > address_size
-             && ((startswith (o->name, ".ctors")
-                  && strcmp (o->output_section->name,
-                             ".init_array") == 0)
-                 || (startswith (o->name, ".dtors")
-                     && strcmp (o->output_section->name,
-                                ".fini_array") == 0))
-             && (o->name[6] == 0 || o->name[6] == '.'))
-           {
-             if (o->size * bed->s->int_rels_per_ext_rel
-                 != o->reloc_count * address_size)
-               {
-                 _bfd_error_handler
-                   /* xgettext:c-format */
-                   (_("error: %pB: size of section %pA is not "
-                      "multiple of address size"),
-                    input_bfd, o);
-                 bfd_set_error (bfd_error_bad_value);
-                 return false;
-               }
-             o->flags |= SEC_ELF_REVERSE_COPY;
-           }
-
          action_discarded = -1;
          if (!elf_section_ignore_discarded_relocs (o))
            action_discarded = (*bed->action_discarded) (o);
@@ -11416,7 +11651,7 @@ elf_link_input_bfd (struct elf_final_link_info *flinfo, bfd *input_bfd)
 
              irela = internal_relocs;
              irelaend = irela + o->reloc_count;
-             rel_hash = esdo->rel.hashes + esdo->rel.count;
+             rel_hash = PTR_ADD (esdo->rel.hashes, esdo->rel.count);
              /* We start processing the REL relocs, if any.  When we reach
                 IRELAMID in the loop, we switch to the RELA relocs.  */
              irelamid = irela;
@@ -11442,7 +11677,7 @@ elf_link_input_bfd (struct elf_final_link_info *flinfo, bfd *input_bfd)
 
                  if (irela == irelamid)
                    {
-                     rel_hash = esdo->rela.hashes + esdo->rela.count;
+                     rel_hash = PTR_ADD (esdo->rela.hashes, esdo->rela.count);
                      rela_hash_list = rel_hash;
                      rela_normal = bed->rela_normal;
                    }
@@ -11693,6 +11928,16 @@ elf_link_input_bfd (struct elf_final_link_info *flinfo, bfd *input_bfd)
              return false;
          }
          break;
+       case SEC_INFO_TYPE_SFRAME:
+           {
+             /* Merge .sframe sections into the ctf frame encoder
+                context of the output_bfd's section.  The final .sframe
+                output section will be written out later.  */
+             if (!_bfd_elf_merge_section_sframe (output_bfd, flinfo->info,
+                                                 o, contents))
+               return false;
+           }
+           break;
        default:
          {
            if (! (o->flags & SEC_EXCLUDE))
@@ -11702,9 +11947,25 @@ elf_link_input_bfd (struct elf_final_link_info *flinfo, bfd *input_bfd)
 
                offset *= bfd_octets_per_byte (output_bfd, o);
 
-               if ((o->flags & SEC_ELF_REVERSE_COPY))
+               if ((o->flags & SEC_ELF_REVERSE_COPY)
+                   && o->size > address_size)
                  {
                    /* Reverse-copy input section to output.  */
+
+                   if ((o->size & (address_size - 1)) != 0
+                       || (o->reloc_count != 0
+                           && (o->size * bed->s->int_rels_per_ext_rel
+                               != o->reloc_count * address_size)))
+                     {
+                       _bfd_error_handler
+                         /* xgettext:c-format */
+                         (_("error: %pB: size of section %pA is not "
+                            "multiple of address size"),
+                          input_bfd, o);
+                       bfd_set_error (bfd_error_bad_value);
+                       return false;
+                     }
+
                    do
                      {
                        todo -= address_size;
@@ -12066,7 +12327,8 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
   const struct elf_backend_data *bed = get_elf_backend_data (abfd);
   struct elf_outext_info eoinfo;
   bool merged;
-  size_t relativecount = 0;
+  size_t relativecount;
+  size_t relr_entsize;
   asection *reldyn = 0;
   bfd_size_type amt;
   asection *attr_section = NULL;
@@ -12076,7 +12338,7 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
   bool sections_removed;
   bool ret;
 
-  if (!is_elf_hash_table (htab))
+  if (!is_elf_hash_table (&htab->root))
     return false;
 
   if (bfd_link_pic (info))
@@ -12226,8 +12488,10 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
                      && elf_symtab_shndx_list (sec->owner) != NULL)
                    max_sym_shndx_count = sym_count;
 
-                 if (esdo->this_hdr.sh_type == SHT_REL
-                     || esdo->this_hdr.sh_type == SHT_RELA)
+                 esdi = elf_section_data (sec);
+
+                 if (esdi->this_hdr.sh_type == SHT_REL
+                     || esdi->this_hdr.sh_type == SHT_RELA)
                    /* Some backends use reloc_count in relocation sections
                       to count particular types of relocs.  Of course,
                       reloc sections themselves can't have relocations.  */
@@ -12245,8 +12509,6 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
                  else if (bed->elf_backend_count_relocs)
                    reloc_count = (*bed->elf_backend_count_relocs) (info, sec);
 
-                 esdi = elf_section_data (sec);
-
                  if ((sec->flags & SEC_RELOC) != 0)
                    {
                      size_t ext_size = 0;
@@ -12353,7 +12615,7 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
             later.  Use bfd_malloc since it will be freed by
             bfd_compress_section_contents.  */
          unsigned char *contents = esdo->this_hdr.contents;
-         if ((o->flags & SEC_ELF_COMPRESS) == 0 || contents != NULL)
+         if (contents != NULL)
            abort ();
          contents
            = (unsigned char *) bfd_malloc (esdo->this_hdr.sh_size);
@@ -12543,6 +12805,14 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
   if (!_bfd_elf_fixup_eh_frame_hdr (info))
     return false;
 
+  /* Finish relative relocations here after regular symbol processing
+     is finished if DT_RELR is enabled.  */
+  if (info->enable_dt_relr
+      && bed->finish_relative_relocs
+      && !bed->finish_relative_relocs (info))
+    info->callbacks->einfo
+      (_("%F%P: %pB: failed to finish relative relocations\n"), abfd);
+
   /* Since ELF permits relocations to be against local symbols, we
      must have the local symbols available when we do the relocations.
      Since we would rather only read the local symbols once, and we
@@ -12660,8 +12930,7 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
 
   /* If backend needs to output some local symbols not present in the hash
      table, do it now.  */
-  if (bed->elf_backend_output_arch_local_syms
-      && (info->strip != strip_all || emit_relocs))
+  if (bed->elf_backend_output_arch_local_syms)
     {
       if (! ((*bed->elf_backend_output_arch_local_syms)
             (abfd, info, &flinfo, elf_link_output_symstrtab)))
@@ -12834,7 +13103,7 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
                                                               off, true);
 
              if (bfd_seek (abfd, symtab_shndx_hdr->sh_offset, SEEK_SET) != 0
-                 || (bfd_bwrite (flinfo.symshndxbuf, amt, abfd) != amt))
+                 || (bfd_write (flinfo.symshndxbuf, amt, abfd) != amt))
                {
                  ret = false;
                  goto return_local_hash_table;
@@ -12902,9 +13171,24 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
       o->reloc_count = 0;
     }
 
+  relativecount = 0;
   if (dynamic && info->combreloc && dynobj != NULL)
     relativecount = elf_link_sort_relocs (abfd, info, &reldyn);
 
+  relr_entsize = 0;
+  if (htab->srelrdyn != NULL
+      && htab->srelrdyn->output_section != NULL
+      && htab->srelrdyn->size != 0)
+    {
+      asection *s = htab->srelrdyn->output_section;
+      relr_entsize = elf_section_data (s)->this_hdr.sh_entsize;
+      if (relr_entsize == 0)
+       {
+         relr_entsize = bed->s->arch_size / 8;
+         elf_section_data (s)->this_hdr.sh_entsize = relr_entsize;
+       }
+    }
+
   /* If we are linking against a dynamic object, or generating a
      shared library, finish up the dynamic linking information.  */
   if (dynamic)
@@ -12916,7 +13200,7 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
       BFD_ASSERT (o != NULL);
 
       dyncon = o->contents;
-      dynconend = o->contents + o->size;
+      dynconend = PTR_ADD (o->contents, o->size);
       for (; dyncon < dynconend; dyncon += bed->s->sizeof_dyn)
        {
          Elf_Internal_Dyn dyn;
@@ -12932,17 +13216,44 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
            default:
              continue;
            case DT_NULL:
-             if (relativecount > 0 && dyncon + bed->s->sizeof_dyn < dynconend)
+             if (relativecount != 0)
                {
                  switch (elf_section_data (reldyn)->this_hdr.sh_type)
                    {
                    case SHT_REL: dyn.d_tag = DT_RELCOUNT; break;
                    case SHT_RELA: dyn.d_tag = DT_RELACOUNT; break;
-                   default: continue;
                    }
-                 dyn.d_un.d_val = relativecount;
+                 if (dyn.d_tag != DT_NULL
+                     && dynconend - dyncon >= bed->s->sizeof_dyn)
+                   {
+                     dyn.d_un.d_val = relativecount;
+                     relativecount = 0;
+                     break;
+                   }
                  relativecount = 0;
-                 break;
+               }
+             if (relr_entsize != 0)
+               {
+                 if (dynconend - dyncon >= 3 * bed->s->sizeof_dyn)
+                   {
+                     asection *s = htab->srelrdyn;
+                     dyn.d_tag = DT_RELR;
+                     dyn.d_un.d_ptr
+                       = s->output_section->vma + s->output_offset;
+                     bed->s->swap_dyn_out (dynobj, &dyn, dyncon);
+                     dyncon += bed->s->sizeof_dyn;
+
+                     dyn.d_tag = DT_RELRSZ;
+                     dyn.d_un.d_val = s->size;
+                     bed->s->swap_dyn_out (dynobj, &dyn, dyncon);
+                     dyncon += bed->s->sizeof_dyn;
+
+                     dyn.d_tag = DT_RELRENT;
+                     dyn.d_un.d_val = relr_entsize;
+                     relr_entsize = 0;
+                     break;
+                   }
+                 relr_entsize = 0;
                }
              continue;
 
@@ -13119,7 +13430,8 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
 
       /* Check for DT_TEXTREL (late, in case the backend removes it).  */
       if (bfd_link_textrel_check (info)
-         && (o = bfd_get_linker_section (dynobj, ".dynamic")) != NULL)
+         && (o = bfd_get_linker_section (dynobj, ".dynamic")) != NULL
+         && o->size != 0)
        {
          bfd_byte *dyncon, *dynconend;
 
@@ -13139,6 +13451,9 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
                  else if (bfd_link_dll (info))
                    info->callbacks->einfo
                      (_("%P: warning: creating DT_TEXTREL in a shared object\n"));
+                 else if (bfd_link_pde (info))
+                   info->callbacks->einfo
+                     (_("%P: warning: creating DT_TEXTREL in a PDE\n"));
                  else
                    info->callbacks->einfo
                      (_("%P: warning: creating DT_TEXTREL in a PIE\n"));
@@ -13205,6 +13520,9 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
   if (! _bfd_elf_write_section_eh_frame_hdr (abfd, info))
     goto error_return;
 
+  if (! _bfd_elf_write_section_sframe (abfd, info))
+    goto error_return;
+
   if (info->callbacks->emit_ctf)
       info->callbacks->emit_ctf ();
 
@@ -13277,8 +13595,12 @@ init_reloc_cookie (struct elf_reloc_cookie *cookie,
          info->callbacks->einfo (_("%P%X: can not read symbols: %E\n"));
          return false;
        }
-      if (info->keep_memory)
-       symtab_hdr->contents = (bfd_byte *) cookie->locsyms;
+      if (_bfd_link_keep_memory (info) )
+       {
+         symtab_hdr->contents = (bfd_byte *) cookie->locsyms;
+         info->cache_size += (cookie->locsymcount
+                              * sizeof (Elf_External_Sym_Shndx));
+       }
     }
   return true;
 }
@@ -13310,8 +13632,9 @@ init_reloc_cookie_rels (struct elf_reloc_cookie *cookie,
     }
   else
     {
-      cookie->rels = _bfd_elf_link_read_relocs (abfd, sec, NULL, NULL,
-                                               info->keep_memory);
+      cookie->rels = _bfd_elf_link_info_read_relocs (abfd, info, sec,
+                                                    NULL, NULL,
+                                                    _bfd_link_keep_memory (info));
       if (cookie->rels == NULL)
        return false;
       cookie->rel = cookie->rels;
@@ -13416,7 +13739,7 @@ elf_gc_mark_debug_section (asection *sec ATTRIBUTE_UNUSED,
       /* Return the local debug definition section.  */
       asection *isec = bfd_section_from_elf_index (sec->owner,
                                                   sym->st_shndx);
-      if ((isec->flags & SEC_DEBUGGING) != 0)
+      if (isec != NULL && (isec->flags & SEC_DEBUGGING) != 0)
        return isec;
     }
 
@@ -13879,14 +14202,22 @@ elf_gc_propagate_vtable_entries_used (struct elf_link_hash_entry *h, void *okp)
   return true;
 }
 
+struct link_info_ok
+{
+  struct bfd_link_info *info;
+  bool ok;
+};
+
 static bool
-elf_gc_smash_unused_vtentry_relocs (struct elf_link_hash_entry *h, void *okp)
+elf_gc_smash_unused_vtentry_relocs (struct elf_link_hash_entry *h,
+                                   void *ptr)
 {
   asection *sec;
   bfd_vma hstart, hend;
   Elf_Internal_Rela *relstart, *relend, *rel;
   const struct elf_backend_data *bed;
   unsigned int log_file_align;
+  struct link_info_ok *info = (struct link_info_ok *) ptr;
 
   /* Take care of both those symbols that do not describe vtables as
      well as those that are not loaded.  */
@@ -13902,9 +14233,10 @@ elf_gc_smash_unused_vtentry_relocs (struct elf_link_hash_entry *h, void *okp)
   hstart = h->root.u.def.value;
   hend = hstart + h->size;
 
-  relstart = _bfd_elf_link_read_relocs (sec->owner, sec, NULL, NULL, true);
+  relstart = _bfd_elf_link_info_read_relocs (sec->owner, info->info,
+                                            sec, NULL, NULL, true);
   if (!relstart)
-    return *(bool *) okp = false;
+    return info->ok = false;
   bed = get_elf_backend_data (sec->owner);
   log_file_align = bed->s->log_file_align;
 
@@ -14027,6 +14359,7 @@ bfd_elf_gc_sections (bfd *abfd, struct bfd_link_info *info)
   elf_gc_mark_hook_fn gc_mark_hook;
   const struct elf_backend_data *bed = get_elf_backend_data (abfd);
   struct elf_link_hash_table *htab;
+  struct link_info_ok info_ok;
 
   if (!bed->can_gc_sections
       || !is_elf_hash_table (info->hash))
@@ -14068,8 +14401,10 @@ bfd_elf_gc_sections (bfd *abfd, struct bfd_link_info *info)
     return false;
 
   /* Kill the vtable relocations that were not used.  */
-  elf_link_hash_traverse (htab, elf_gc_smash_unused_vtentry_relocs, &ok);
-  if (!ok)
+  info_ok.info = info;
+  info_ok.ok = true;
+  elf_link_hash_traverse (htab, elf_gc_smash_unused_vtentry_relocs, &info_ok);
+  if (!info_ok.ok)
     return false;
 
   /* Mark dynamically referenced symbols.  */
@@ -14145,7 +14480,7 @@ bfd_elf_gc_record_vtinherit (bfd *abfd,
     extsymcount -= elf_tdata (abfd)->symtab_hdr.sh_info;
 
   sym_hashes = elf_sym_hashes (abfd);
-  sym_hashes_end = sym_hashes + extsymcount;
+  sym_hashes_end = PTR_ADD (sym_hashes, extsymcount);
 
   /* Hunt down the child symbol, which is in this section at the same
      offset as the relocation.  */
@@ -14643,6 +14978,41 @@ bfd_elf_discard_info (bfd *output_bfd, struct bfd_link_info *info)
                                _bfd_elf_adjust_eh_frame_global_symbol, NULL);
     }
 
+  o = bfd_get_section_by_name (output_bfd, ".sframe");
+  if (o != NULL)
+    {
+      asection *i;
+
+      for (i = o->map_head.s; i != NULL; i = i->map_head.s)
+       {
+         if (i->size == 0)
+           continue;
+
+         abfd = i->owner;
+         if (bfd_get_flavour (abfd) != bfd_target_elf_flavour)
+           continue;
+
+         if (!init_reloc_cookie_for_section (&cookie, info, i))
+           return -1;
+
+         if (_bfd_elf_parse_sframe (abfd, info, i, &cookie))
+           {
+             if (_bfd_elf_discard_section_sframe (i,
+                                                  bfd_elf_reloc_symbol_deleted_p,
+                                                  &cookie))
+               {
+                 if (i->size != i->rawsize)
+                   changed = 1;
+               }
+           }
+         fini_reloc_cookie_for_section (&cookie, i);
+       }
+      /* Update the reference to the output .sframe section.  Used to
+        determine later if PT_GNU_SFRAME segment is to be generated.  */
+      if (!_bfd_elf_set_section_sframe (output_bfd, info))
+       return -1;
+    }
+
   for (abfd = info->input_bfds; abfd != NULL; abfd = abfd->link.next)
     {
       const struct elf_backend_data *bed;
@@ -14673,7 +15043,7 @@ bfd_elf_discard_info (bfd *output_bfd, struct bfd_link_info *info)
 
   if (info->eh_frame_hdr_type
       && !bfd_link_relocatable (info)
-      && _bfd_elf_discard_section_eh_frame_hdr (output_bfd, info))
+      && _bfd_elf_discard_section_eh_frame_hdr (info))
     changed = 1;
 
   return changed;