]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blobdiff - bfd/elf64-x86-64.c
Add output_type to bfd_link_info
[thirdparty/binutils-gdb.git] / bfd / elf64-x86-64.c
index 581ee171773f243ccf952037e91cebf81f275ea1..987ce0e5b776c4eb30b67641c1993ebfc9d56318 100644 (file)
@@ -54,7 +54,7 @@
    special_function, name, partial_inplace, src_mask, dst_mask, pcrel_offset.  */
 static reloc_howto_type x86_64_elf_howto_table[] =
 {
-  HOWTO(R_X86_64_NONE, 0, 0, 0, FALSE, 0, complain_overflow_dont,
+  HOWTO(R_X86_64_NONE, 0, 3, 0, FALSE, 0, complain_overflow_dont,
        bfd_elf_generic_reloc, "R_X86_64_NONE", FALSE, 0x00000000, 0x00000000,
        FALSE),
   HOWTO(R_X86_64_64, 0, 4, 64, FALSE, 0, complain_overflow_bitfield,
@@ -1071,7 +1071,7 @@ elf_x86_64_create_dynamic_sections (bfd *dynobj,
   if (!htab->sdynbss)
     abort ();
 
-  if (info->executable)
+  if (bfd_link_executable (info))
     {
       /* Always allow copy relocs for building executables.  */
       asection *s = bfd_get_linker_section (dynobj, ".rela.bss");
@@ -1434,7 +1434,7 @@ elf_x86_64_tls_transition (struct bfd_link_info *info, bfd *abfd,
     case R_X86_64_GOTPC32_TLSDESC:
     case R_X86_64_TLSDESC_CALL:
     case R_X86_64_GOTTPOFF:
-      if (info->executable)
+      if (bfd_link_executable (info))
        {
          if (h == NULL)
            to_type = R_X86_64_TPOFF32;
@@ -1449,7 +1449,7 @@ elf_x86_64_tls_transition (struct bfd_link_info *info, bfd *abfd,
        {
          unsigned int new_to_type = to_type;
 
-         if (info->executable
+         if (bfd_link_executable (info)
              && h != NULL
              && h->dynindx == -1
              && tls_type == GOT_TLS_IE)
@@ -1473,7 +1473,7 @@ elf_x86_64_tls_transition (struct bfd_link_info *info, bfd *abfd,
       break;
 
     case R_X86_64_TLSLD:
-      if (info->executable)
+      if (bfd_link_executable (info))
        to_type = R_X86_64_TPOFF32;
       break;
 
@@ -1529,6 +1529,10 @@ elf_x86_64_tls_transition (struct bfd_link_info *info, bfd *abfd,
   return TRUE;
 }
 
+/* Rename some of the generic section flags to better document how they
+   are used here.  */
+#define need_convert_mov_to_lea sec_flg0
+
 /* Look through the relocs for a section during the first phase, and
    calculate needed space in the global offset table, procedure
    linkage table, and dynamic reloc sections.  */
@@ -1546,7 +1550,7 @@ elf_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info,
   asection *sreloc;
   bfd_boolean use_plt_got;
 
-  if (info->relocatable)
+  if (bfd_link_relocatable (info))
     return TRUE;
 
   BFD_ASSERT (is_x86_64_elf (abfd));
@@ -1719,6 +1723,10 @@ elf_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info,
          /* It is referenced by a non-shared object. */
          h->ref_regular = 1;
          h->root.non_ir_ref = 1;
+
+         if (h->type == STT_GNU_IFUNC)
+           elf_tdata (info->output_bfd)->has_gnu_symbols
+             |= elf_gnu_symbol_ifunc;
        }
 
       if (! elf_x86_64_tls_transition (info, abfd, sec, NULL,
@@ -1734,7 +1742,7 @@ elf_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info,
          goto create_got;
 
        case R_X86_64_TPOFF32:
-         if (!info->executable && ABI_64_P (abfd))
+         if (!bfd_link_executable (info) && ABI_64_P (abfd))
            {
              if (h)
                name = h->root.root.string;
@@ -1751,7 +1759,7 @@ elf_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info,
          break;
 
        case R_X86_64_GOTTPOFF:
-         if (!info->executable)
+         if (!bfd_link_executable (info))
            info->flags |= DF_STATIC_TLS;
          /* Fall through */
 
@@ -1903,7 +1911,7 @@ elf_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info,
             cannot be used in shared libs.  Don't error out for
             sections we don't care about, such as debug sections or
             non-constant sections.  */
-         if (info->shared
+         if (bfd_link_pic (info)
              && (sec->flags & SEC_ALLOC) != 0
              && (sec->flags & SEC_READONLY) != 0)
            {
@@ -1926,7 +1934,7 @@ elf_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info,
        case R_X86_64_PC64:
        case R_X86_64_64:
 pointer:
-         if (h != NULL && info->executable)
+         if (h != NULL && bfd_link_executable (info))
            {
              /* If this reloc is in a read-only section, we might
                 need a copy reloc.  We can't check reliably at this
@@ -1968,7 +1976,7 @@ do_size:
             may need to keep relocations for symbols satisfied by a
             dynamic library if we manage to avoid copy relocs for the
             symbol.  */
-         if ((info->shared
+         if ((bfd_link_pic (info)
               && (sec->flags & SEC_ALLOC) != 0
               && (! IS_X86_64_PCREL_TYPE (r_type)
                   || (h != NULL
@@ -1976,7 +1984,7 @@ do_size:
                           || h->root.type == bfd_link_hash_defweak
                           || !h->def_regular))))
              || (ELIMINATE_COPY_RELOCS
-                 && !info->shared
+                 && !bfd_link_pic (info)
                  && (sec->flags & SEC_ALLOC) != 0
                  && h != NULL
                  && (h->root.type == bfd_link_hash_defweak
@@ -2076,7 +2084,8 @@ do_size:
       if (use_plt_got
          && h != NULL
          && h->plt.refcount > 0
-         && h->got.refcount > 0
+         && (((info->flags & DF_BIND_NOW) && !h->pointer_equality_needed)
+             || h->got.refcount > 0)
          && htab->plt_got == NULL)
        {
          /* Create the GOT procedure linkage table.  */
@@ -2105,6 +2114,10 @@ do_size:
                                             plt_got_align))
            return FALSE;
        }
+
+      if (r_type == R_X86_64_GOTPCREL
+         && (h == NULL || h->type != STT_GNU_IFUNC))
+       sec->need_convert_mov_to_lea = 1;
     }
 
   return TRUE;
@@ -2144,7 +2157,7 @@ elf_x86_64_gc_sweep_hook (bfd *abfd, struct bfd_link_info *info,
   bfd_signed_vma *local_got_refcounts;
   const Elf_Internal_Rela *rel, *relend;
 
-  if (info->relocatable)
+  if (bfd_link_relocatable (info))
     return TRUE;
 
   htab = elf_x86_64_hash_table (info);
@@ -2260,7 +2273,7 @@ elf_x86_64_gc_sweep_hook (bfd *abfd, struct bfd_link_info *info,
        case R_X86_64_PC64:
        case R_X86_64_SIZE32:
        case R_X86_64_SIZE64:
-         if (info->shared
+         if (bfd_link_pic (info)
              && (h == NULL || h->type != STT_GNU_IFUNC))
            break;
          /* Fall thru */
@@ -2396,7 +2409,7 @@ elf_x86_64_adjust_dynamic_symbol (struct bfd_link_info *info,
      only references to the symbol are via the global offset table.
      For such cases we need not do anything here; the relocations will
      be handled correctly by relocate_section. */
-  if (!info->executable)
+  if (!bfd_link_executable (info))
     return TRUE;
 
   /* If there are no references to this symbol that do not use the
@@ -2532,7 +2545,19 @@ elf_x86_64_allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf)
   else if (htab->elf.dynamic_sections_created
           && (h->plt.refcount > 0 || eh->plt_got.refcount > 0))
     {
-      bfd_boolean use_plt_got = eh->plt_got.refcount > 0;
+      bfd_boolean use_plt_got;
+
+      if ((info->flags & DF_BIND_NOW) && !h->pointer_equality_needed)
+       {
+         /* Don't use the regular PLT for DF_BIND_NOW. */
+         h->plt.offset = (bfd_vma) -1;
+
+         /* Use the GOT PLT.  */
+         h->got.refcount = 1;
+         eh->plt_got.refcount = 1;
+       }
+
+      use_plt_got = eh->plt_got.refcount > 0;
 
       /* Make sure this symbol is output as a dynamic symbol.
         Undefined weak syms won't yet be marked as dynamic.  */
@@ -2543,7 +2568,7 @@ elf_x86_64_allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf)
            return FALSE;
        }
 
-      if (info->shared
+      if (bfd_link_pic (info)
          || WILL_CALL_FINISH_DYNAMIC_SYMBOL (1, 0, h))
        {
          asection *s = htab->elf.splt;
@@ -2551,7 +2576,8 @@ elf_x86_64_allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf)
          asection *got_s = htab->plt_got;
 
          /* If this is the first .plt entry, make room for the special
-            first entry.  */
+            first entry.  The .plt section is used by prelink to undo
+            prelinking for dynamic relocations.  */
          if (s->size == 0)
            s->size = plt_entry_size;
 
@@ -2569,7 +2595,7 @@ elf_x86_64_allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf)
             location in the .plt.  This is required to make function
             pointers compare as equal between the normal executable and
             the shared library.  */
-         if (! info->shared
+         if (! bfd_link_pic (info)
              && !h->def_regular)
            {
              if (use_plt_got)
@@ -2633,7 +2659,7 @@ elf_x86_64_allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf)
   /* If R_X86_64_GOTTPOFF symbol is now local to the binary,
      make it a R_X86_64_TPOFF32 requiring no GOT entry.  */
   if (h->got.refcount > 0
-      && info->executable
+      && bfd_link_executable (info)
       && h->dynindx == -1
       && elf_x86_64_hash_entry (h)->tls_type == GOT_TLS_IE)
     {
@@ -2682,7 +2708,7 @@ elf_x86_64_allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf)
       else if (! GOT_TLS_GDESC_P (tls_type)
               && (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
                   || h->root.type != bfd_link_hash_undefweak)
-              && (info->shared
+              && (bfd_link_pic (info)
                   || WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, 0, h)))
        htab->elf.srelgot->size += bed->s->sizeof_rela;
       if (GOT_TLS_GDESC_P (tls_type))
@@ -2703,7 +2729,7 @@ elf_x86_64_allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf)
      space for pc-relative relocs that have become local due to symbol
      visibility changes.  */
 
-  if (info->shared)
+  if (bfd_link_pic (info))
     {
       /* Relocs that use pc_count are those that appear on a call
         insn, or certain REL relocs that can generated via assembly.
@@ -2742,13 +2768,23 @@ elf_x86_64_allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf)
                       && ! bfd_elf_link_record_dynamic_symbol (info, h))
                return FALSE;
            }
-         /* For PIE, discard space for relocs against symbols which
-            turn out to need copy relocs.  */
-         else if (info->executable
+         /* For PIE, discard space for pc-relative relocs against
+            symbols which turn out to need copy relocs.  */
+         else if (bfd_link_executable (info)
                   && (h->needs_copy || eh->needs_copy)
                   && h->def_dynamic
                   && !h->def_regular)
-           eh->dyn_relocs = NULL;
+           {
+             struct elf_dyn_relocs **pp;
+
+             for (pp = &eh->dyn_relocs; (p = *pp) != NULL; )
+               {
+                 if (p->pc_count != 0)
+                   *pp = p->next;
+                 else
+                   pp = &p->next;
+               }
+           }
        }
     }
   else if (ELIMINATE_COPY_RELOCS)
@@ -2840,8 +2876,9 @@ elf_x86_64_readonly_dynrelocs (struct elf_link_hash_entry *h,
 
          info->flags |= DF_TEXTREL;
 
-         if (info->warn_shared_textrel && info->shared)
-           info->callbacks->einfo (_("%P: %B: warning: relocation against `%s' in readonly section `%A'.\n"),
+         if ((info->warn_shared_textrel && bfd_link_pic (info))
+             || info->error_textrel)
+           info->callbacks->einfo (_("%P: %B: warning: relocation against `%s' in readonly section `%A'\n"),
                                    p->sec->owner, h->root.root.string,
                                    p->sec);
 
@@ -2870,14 +2907,15 @@ elf_x86_64_convert_mov_to_lea (bfd *abfd, asection *sec,
   bfd_boolean changed_contents;
   bfd_boolean changed_relocs;
   bfd_signed_vma *local_got_refcounts;
+  bfd_vma maxpagesize;
 
   /* Don't even try to convert non-ELF outputs.  */
   if (!is_elf_hash_table (link_info->hash))
     return FALSE;
 
-  /* Nothing to do if there are no codes, no relocations or no output.  */
+  /* Nothing to do if there is no need or no output.  */
   if ((sec->flags & (SEC_CODE | SEC_RELOC)) != (SEC_CODE | SEC_RELOC)
-      || sec->reloc_count == 0
+      || sec->need_convert_mov_to_lea == 0
       || bfd_is_abs_section (sec->output_section))
     return TRUE;
 
@@ -2894,6 +2932,7 @@ elf_x86_64_convert_mov_to_lea (bfd *abfd, asection *sec,
   changed_contents = FALSE;
   changed_relocs = FALSE;
   local_got_refcounts = elf_local_got_refcounts (abfd);
+  maxpagesize = get_elf_backend_data (abfd)->maxpagesize;
 
   /* Get the section contents.  */
   if (elf_section_data (sec)->this_hdr.contents != NULL)
@@ -2911,62 +2950,177 @@ elf_x86_64_convert_mov_to_lea (bfd *abfd, asection *sec,
       unsigned int r_symndx = htab->r_sym (irel->r_info);
       unsigned int indx;
       struct elf_link_hash_entry *h;
+      asection *tsec;
+      char symtype;
+      bfd_vma toff, roff;
+      enum {
+       none, local, global
+      } convert_mov_to_lea;
+      unsigned int opcode;
 
       if (r_type != R_X86_64_GOTPCREL)
        continue;
 
+      roff = irel->r_offset;
+
+      if (roff < 2)
+       continue;
+
+      opcode = bfd_get_8 (abfd, contents + roff - 2);
+
+      /* PR ld/18591: Don't convert R_X86_64_GOTPCREL relocation if it
+         isn't for mov instruction.  */
+      if (opcode != 0x8b)
+       continue;
+
+      tsec = NULL;
+      convert_mov_to_lea = none;
+
       /* Get the symbol referred to by the reloc.  */
       if (r_symndx < symtab_hdr->sh_info)
        {
          Elf_Internal_Sym *isym;
 
+         /* Silence older GCC warning.  */
+         h = NULL;
+
          isym = bfd_sym_from_r_symndx (&htab->sym_cache,
                                        abfd, r_symndx);
 
-         /* STT_GNU_IFUNC must keep R_X86_64_GOTPCREL relocation.  */
-         if (ELF_ST_TYPE (isym->st_info) != STT_GNU_IFUNC
-             && irel->r_offset >= 2
-             && bfd_get_8 (input_bfd,
-                           contents + irel->r_offset - 2) == 0x8b)
+         symtype = ELF_ST_TYPE (isym->st_info);
+
+         /* STT_GNU_IFUNC must keep R_X86_64_GOTPCREL relocation and
+            skip relocation against undefined symbols.  */
+         if (symtype != STT_GNU_IFUNC && isym->st_shndx != SHN_UNDEF)
            {
-             bfd_put_8 (output_bfd, 0x8d,
-                        contents + irel->r_offset - 2);
-             irel->r_info = htab->r_info (r_symndx, R_X86_64_PC32);
-             if (local_got_refcounts != NULL
-                 && local_got_refcounts[r_symndx] > 0)
-               local_got_refcounts[r_symndx] -= 1;
-             changed_contents = TRUE;
-             changed_relocs = TRUE;
+             if (isym->st_shndx == SHN_ABS)
+               tsec = bfd_abs_section_ptr;
+             else if (isym->st_shndx == SHN_COMMON)
+               tsec = bfd_com_section_ptr;
+             else if (isym->st_shndx == SHN_X86_64_LCOMMON)
+               tsec = &_bfd_elf_large_com_section;
+             else
+               tsec = bfd_section_from_elf_index (abfd, isym->st_shndx);
+
+             toff = isym->st_value;
+             convert_mov_to_lea = local;
            }
-         continue;
        }
+      else
+       {
+         indx = r_symndx - symtab_hdr->sh_info;
+         h = elf_sym_hashes (abfd)[indx];
+         BFD_ASSERT (h != NULL);
 
-      indx = r_symndx - symtab_hdr->sh_info;
-      h = elf_sym_hashes (abfd)[indx];
-      BFD_ASSERT (h != NULL);
+         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;
 
-      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;
+         /* STT_GNU_IFUNC must keep R_X86_64_GOTPCREL relocation.  We also
+            avoid optimizing _DYNAMIC since ld.so may use its link-time
+            address.  */
+         if (h->def_regular
+             && h->type != STT_GNU_IFUNC
+             && h != htab->elf.hdynamic
+             && SYMBOL_REFERENCES_LOCAL (link_info, h))
+           {
+             tsec = h->root.u.def.section;
+             toff = h->root.u.def.value;
+             symtype = h->type;
+             convert_mov_to_lea = global;
+           }
+       }
 
-      /* STT_GNU_IFUNC must keep R_X86_64_GOTPCREL relocation.  We also
-        avoid optimizing _DYNAMIC since ld.so may use its link-time
-        address.  */
-      if (h->def_regular
-         && h->type != STT_GNU_IFUNC
-         && h != htab->elf.hdynamic
-         && SYMBOL_REFERENCES_LOCAL (link_info, h)
-         && irel->r_offset >= 2
-         && bfd_get_8 (input_bfd,
-                       contents + irel->r_offset - 2) == 0x8b)
+      if (convert_mov_to_lea == none)
+       continue;
+
+      if (tsec->sec_info_type == SEC_INFO_TYPE_MERGE)
+       {
+         /* At this stage in linking, no SEC_MERGE symbol has been
+            adjusted, so all references to such symbols need to be
+            passed through _bfd_merged_section_offset.  (Later, in
+            relocate_section, all SEC_MERGE symbols *except* for
+            section symbols have been adjusted.)
+
+            gas may reduce relocations against symbols in SEC_MERGE
+            sections to a relocation against the section symbol when
+            the original addend was zero.  When the reloc is against
+            a section symbol we should include the addend in the
+            offset passed to _bfd_merged_section_offset, since the
+            location of interest is the original symbol.  On the
+            other hand, an access to "sym+addend" where "sym" is not
+            a section symbol should not include the addend;  Such an
+            access is presumed to be an offset from "sym";  The
+            location of interest is just "sym".  */
+          if (symtype == STT_SECTION)
+            toff += irel->r_addend;
+
+          toff = _bfd_merged_section_offset (abfd, &tsec,
+                                             elf_section_data (tsec)->sec_info,
+                                             toff);
+
+          if (symtype != STT_SECTION)
+            toff += irel->r_addend;
+       }
+      else
+       toff += irel->r_addend;
+
+      /* Don't convert if R_X86_64_PC32 relocation overflows.  */
+      if (tsec->output_section == sec->output_section)
+       {
+         if ((toff - roff + 0x80000000) > 0xffffffff)
+           continue;
+       }
+      else
+       {
+         asection *asect;
+         bfd_size_type size;
+
+         /* At this point, we don't know the load addresses of TSEC
+            section nor SEC section.  We estimate the distrance between
+            SEC and TSEC.  */
+         size = 0;
+         for (asect = sec->output_section;
+              asect != NULL && asect != tsec->output_section;
+              asect = asect->next)
+           {
+             asection *i;
+             for (i = asect->output_section->map_head.s;
+                  i != NULL;
+                  i = i->map_head.s)
+               {
+                 size = align_power (size, i->alignment_power);
+                 size += i->size;
+               }
+           }
+
+         /* Don't convert R_X86_64_GOTPCREL if TSEC isn't placed after
+            SEC.  */
+         if (asect == NULL)
+           continue;
+
+         /* Take PT_GNU_RELRO segment into account by adding
+            maxpagesize.  */
+         if ((toff + size + maxpagesize - roff + 0x80000000)
+             > 0xffffffff)
+           continue;
+       }
+
+      bfd_put_8 (abfd, 0x8d, contents + roff - 2);
+      irel->r_info = htab->r_info (r_symndx, R_X86_64_PC32);
+      changed_contents = TRUE;
+      changed_relocs = TRUE;
+
+      if (convert_mov_to_lea == local)
+       {
+         if (local_got_refcounts != NULL
+             && local_got_refcounts[r_symndx] > 0)
+           local_got_refcounts[r_symndx] -= 1;
+       }
+      else
        {
-         bfd_put_8 (output_bfd, 0x8d,
-                    contents + irel->r_offset - 2);
-         irel->r_info = htab->r_info (r_symndx, R_X86_64_PC32);
          if (h->got.refcount > 0)
            h->got.refcount -= 1;
-         changed_contents = TRUE;
-         changed_relocs = TRUE;
        }
     }
 
@@ -3027,7 +3181,7 @@ elf_x86_64_size_dynamic_sections (bfd *output_bfd,
   if (htab->elf.dynamic_sections_created)
     {
       /* Set the contents of the .interp section to the interpreter.  */
-      if (info->executable)
+      if (bfd_link_executable (info))
        {
          s = bfd_get_linker_section (dynobj, ".interp");
          if (s == NULL)
@@ -3080,8 +3234,9 @@ elf_x86_64_size_dynamic_sections (bfd *output_bfd,
                      && (info->flags & DF_TEXTREL) == 0)
                    {
                      info->flags |= DF_TEXTREL;
-                     if (info->warn_shared_textrel && info->shared)
-                       info->callbacks->einfo (_("%P: %B: warning: relocation in readonly section `%A'.\n"),
+                     if ((info->warn_shared_textrel && bfd_link_pic (info))
+                         || info->error_textrel)
+                       info->callbacks->einfo (_("%P: %B: warning: relocation in readonly section `%A'\n"),
                                                p->sec->owner, p->sec);
                    }
                }
@@ -3120,7 +3275,7 @@ elf_x86_64_size_dynamic_sections (bfd *output_bfd,
                  if (GOT_TLS_GD_P (*local_tls_type))
                    s->size += GOT_ENTRY_SIZE;
                }
-             if (info->shared
+             if (bfd_link_pic (info)
                  || GOT_TLS_GD_ANY_P (*local_tls_type)
                  || *local_tls_type == GOT_TLS_IE)
                {
@@ -3315,7 +3470,7 @@ elf_x86_64_size_dynamic_sections (bfd *output_bfd,
 #define add_dynamic_entry(TAG, VAL) \
   _bfd_elf_add_dynamic_entry (info, TAG, VAL)
 
-      if (info->executable)
+      if (bfd_link_executable (info))
        {
          if (!add_dynamic_entry (DT_DEBUG, 0))
            return FALSE;
@@ -3323,12 +3478,19 @@ elf_x86_64_size_dynamic_sections (bfd *output_bfd,
 
       if (htab->elf.splt->size != 0)
        {
-         if (!add_dynamic_entry (DT_PLTGOT, 0)
-             || !add_dynamic_entry (DT_PLTRELSZ, 0)
-             || !add_dynamic_entry (DT_PLTREL, DT_RELA)
-             || !add_dynamic_entry (DT_JMPREL, 0))
+         /* DT_PLTGOT is used by prelink even if there is no PLT
+            relocation.  */
+         if (!add_dynamic_entry (DT_PLTGOT, 0))
            return FALSE;
 
+         if (htab->elf.srelplt->size != 0)
+           {
+             if (!add_dynamic_entry (DT_PLTRELSZ, 0)
+                 || !add_dynamic_entry (DT_PLTREL, DT_RELA)
+                 || !add_dynamic_entry (DT_JMPREL, 0))
+               return FALSE;
+           }
+
          if (htab->tlsdesc_plt
              && (!add_dynamic_entry (DT_TLSDESC_PLT, 0)
                  || !add_dynamic_entry (DT_TLSDESC_GOT, 0)))
@@ -3351,6 +3513,15 @@ elf_x86_64_size_dynamic_sections (bfd *output_bfd,
 
          if ((info->flags & DF_TEXTREL) != 0)
            {
+             if ((elf_tdata (output_bfd)->has_gnu_symbols
+                  & elf_gnu_symbol_ifunc) == elf_gnu_symbol_ifunc)
+               {
+                 info->callbacks->einfo
+                   (_("%P%X: read-only segment has dynamic IFUNC relocations; recompile with -fPIC\n"));
+                 bfd_set_error (bfd_error_bad_value);
+                 return FALSE;
+               }
+
              if (!add_dynamic_entry (DT_TEXTREL, 0))
                return FALSE;
            }
@@ -3397,6 +3568,7 @@ elf_x86_64_always_size_sections (bfd *output_bfd,
          tlsbase = (struct elf_link_hash_entry *)bh;
          tlsbase->def_regular = 1;
          tlsbase->other = STV_HIDDEN;
+         tlsbase->root.linker_def = 1;
          (*bed->elf_backend_hide_symbol) (info, tlsbase, TRUE);
        }
     }
@@ -3415,7 +3587,7 @@ elf_x86_64_set_tls_module_base (struct bfd_link_info *info)
   struct elf_x86_64_link_hash_table *htab;
   struct bfd_link_hash_entry *base;
 
-  if (!info->executable)
+  if (!bfd_link_executable (info))
     return;
 
   htab = elf_x86_64_hash_table (info);
@@ -3566,7 +3738,7 @@ elf_x86_64_relocate_section (bfd *output_bfd,
          st_size = sym->st_size;
 
          /* Relocate against local STT_GNU_IFUNC symbol.  */
-         if (!info->relocatable
+         if (!bfd_link_relocatable (info)
              && ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC)
            {
              h = elf_x86_64_get_local_sym_hash (htab, input_bfd,
@@ -3595,7 +3767,7 @@ elf_x86_64_relocate_section (bfd *output_bfd,
        RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section,
                                         rel, 1, relend, howto, 0, contents);
 
-      if (info->relocatable)
+      if (bfd_link_relocatable (info))
        continue;
 
       if (rel->r_addend == 0 && !ABI_64_P (output_bfd))
@@ -3627,8 +3799,16 @@ elf_x86_64_relocate_section (bfd *output_bfd,
          bfd_vma plt_index;
          const char *name;
 
-         if ((input_section->flags & SEC_ALLOC) == 0
-             || h->plt.offset == (bfd_vma) -1)
+         if ((input_section->flags & SEC_ALLOC) == 0)
+           {
+             /* Dynamic relocs are not propagated for SEC_DEBUGGING
+                sections because such sections are not SEC_ALLOC and
+                thus ld.so will not process them.  */
+             if ((input_section->flags & SEC_DEBUGGING) != 0)
+               continue;
+             abort ();
+           }
+         else if (h->plt.offset == (bfd_vma) -1)
            abort ();
 
          /* STT_GNU_IFUNC symbol must go through PLT.  */
@@ -3671,7 +3851,7 @@ elf_x86_64_relocate_section (bfd *output_bfd,
              return FALSE;
 
            case R_X86_64_32S:
-             if (info->shared)
+             if (bfd_link_pic (info))
                abort ();
              goto do_relocation;
 
@@ -3698,7 +3878,7 @@ elf_x86_64_relocate_section (bfd *output_bfd,
 
              /* Generate dynamic relcoation only when there is a
                 non-GOT reference in a shared object.  */
-             if (info->shared && h->non_got_ref)
+             if (bfd_link_pic (info) && h->non_got_ref)
                {
                  Elf_Internal_Rela outrel;
                  asection *sreloc;
@@ -3718,7 +3898,7 @@ elf_x86_64_relocate_section (bfd *output_bfd,
 
                  if (h->dynindx == -1
                      || h->forced_local
-                     || info->executable)
+                     || bfd_link_executable (info))
                    {
                      /* This symbol is resolved locally.  */
                      outrel.r_info = htab->r_info (0, R_X86_64_IRELATIVE);
@@ -3848,8 +4028,8 @@ elf_x86_64_relocate_section (bfd *output_bfd,
 
              dyn = htab->elf.dynamic_sections_created;
 
-             if (! WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, info->shared, h)
-                 || (info->shared
+             if (! WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, bfd_link_pic (info), h)
+                 || (bfd_link_pic (info)
                      && SYMBOL_REFERENCES_LOCAL (info, h))
                  || (ELF_ST_VISIBILITY (h->other)
                      && h->root.type == bfd_link_hash_undefweak))
@@ -3896,7 +4076,7 @@ elf_x86_64_relocate_section (bfd *output_bfd,
                  bfd_put_64 (output_bfd, relocation,
                              base_got->contents + off);
 
-                 if (info->shared)
+                 if (bfd_link_pic (info))
                    {
                      asection *s;
                      Elf_Internal_Rela outrel;
@@ -3934,21 +4114,52 @@ elf_x86_64_relocate_section (bfd *output_bfd,
          /* Relocation is relative to the start of the global offset
             table.  */
 
-         /* Check to make sure it isn't a protected function symbol
-            for shared library since it may not be local when used
-            as function address.  */
-         if (!info->executable
-             && h
-             && !SYMBOLIC_BIND (info, h)
-             && h->def_regular
-             && h->type == STT_FUNC
-             && ELF_ST_VISIBILITY (h->other) == STV_PROTECTED)
+         /* Check to make sure it isn't a protected function or data
+            symbol for shared library since it may not be local when
+            used as function address or with copy relocation.  We also
+            need to make sure that a symbol is referenced locally.  */
+         if (bfd_link_pic (info) && h)
            {
-             (*_bfd_error_handler)
-               (_("%B: relocation R_X86_64_GOTOFF64 against protected function `%s' can not be used when making a shared object"),
-                input_bfd, h->root.root.string);
-             bfd_set_error (bfd_error_bad_value);
+             if (!h->def_regular)
+               {
+                 const char *v;
+
+                 switch (ELF_ST_VISIBILITY (h->other))
+                   {
+                   case STV_HIDDEN:
+                     v = _("hidden symbol");
+                     break;
+                   case STV_INTERNAL:
+                     v = _("internal symbol");
+                     break;
+                   case STV_PROTECTED:
+                     v = _("protected symbol");
+                     break;
+                   default:
+                     v = _("symbol");
+                     break;
+                   }
+
+                 (*_bfd_error_handler)
+                   (_("%B: relocation R_X86_64_GOTOFF64 against undefined %s `%s' can not be used when making a shared object"),
+                    input_bfd, v, h->root.root.string);
+                 bfd_set_error (bfd_error_bad_value);
+                 return FALSE;
+               }
+             else if (!bfd_link_executable (info)
+                      && !SYMBOL_REFERENCES_LOCAL (info, h)
+                      && (h->type == STT_FUNC
+                          || h->type == STT_OBJECT)
+                      && ELF_ST_VISIBILITY (h->other) == STV_PROTECTED)
+               {
+                 (*_bfd_error_handler)
+                   (_("%B: relocation R_X86_64_GOTOFF64 against protected %s `%s' can not be used when making a shared object"),
+                    input_bfd,
+                    h->type == STT_FUNC ? "function" : "data",
+                    h->root.root.string);
+                 bfd_set_error (bfd_error_bad_value);
              return FALSE;
+               }
            }
 
          /* Note that sgot is not involved in this
@@ -4053,10 +4264,14 @@ elf_x86_64_relocate_section (bfd *output_bfd,
        case R_X86_64_PC16:
        case R_X86_64_PC32:
        case R_X86_64_PC32_BND:
-         if (info->shared
+         /* Don't complain about -fPIC if the symbol is undefined when
+            building executable.  */
+         if (bfd_link_pic (info)
              && (input_section->flags & SEC_ALLOC) != 0
              && (input_section->flags & SEC_READONLY) != 0
-             && h != NULL)
+             && h != NULL
+             && !(bfd_link_executable (info)
+                  && h->root.type == bfd_link_hash_undefined))
            {
              bfd_boolean fail = FALSE;
              bfd_boolean branch
@@ -4070,7 +4285,7 @@ elf_x86_64_relocate_section (bfd *output_bfd,
                     defined locally or for a branch.  */
                  fail = !h->def_regular && !branch;
                }
-             else if (!(info->executable
+             else if (!(bfd_link_executable (info)
                         && (h->needs_copy || eh->needs_copy)))
                {
                  /* Symbol doesn't need copy reloc and isn't referenced
@@ -4130,11 +4345,14 @@ direct:
            break;
 
           /* Don't copy a pc-relative relocation into the output file
-             if the symbol needs copy reloc.  */
-         if ((info->shared
-              && !(info->executable
+             if the symbol needs copy reloc or the symbol is undefined
+             when building executable.  */
+         if ((bfd_link_pic (info)
+              && !(bfd_link_executable (info)
                    && h != NULL
-                   && (h->needs_copy || eh->needs_copy)
+                   && (h->needs_copy
+                       || eh->needs_copy
+                       || h->root.type == bfd_link_hash_undefined)
                    && IS_X86_64_PCREL_TYPE (r_type))
               && (h == NULL
                   || ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
@@ -4144,7 +4362,7 @@ direct:
                      && r_type != R_X86_64_SIZE64)
                   || ! SYMBOL_CALLS_LOCAL (info, h)))
              || (ELIMINATE_COPY_RELOCS
-                 && !info->shared
+                 && !bfd_link_pic (info)
                  && h != NULL
                  && h->dynindx != -1
                  && !h->non_got_ref
@@ -4182,7 +4400,7 @@ direct:
              else if (h != NULL
                       && h->dynindx != -1
                       && (IS_X86_64_PCREL_TYPE (r_type)
-                          || ! info->shared
+                          || ! bfd_link_pic (info)
                           || ! SYMBOLIC_BIND (info, h)
                           || ! h->def_regular))
                {
@@ -4760,7 +4978,8 @@ direct:
          break;
 
        case R_X86_64_DTPOFF32:
-         if (!info->executable|| (input_section->flags & SEC_CODE) == 0)
+         if (!bfd_link_executable (info)
+             || (input_section->flags & SEC_CODE) == 0)
            relocation -= elf_x86_64_dtpoff_base (info);
          else
            relocation = elf_x86_64_tpoff (info, relocation);
@@ -4768,7 +4987,7 @@ direct:
 
        case R_X86_64_TPOFF32:
        case R_X86_64_TPOFF64:
-         BFD_ASSERT (info->executable);
+         BFD_ASSERT (bfd_link_executable (info));
          relocation = elf_x86_64_tpoff (info, relocation);
          break;
 
@@ -4901,7 +5120,7 @@ elf_x86_64_finish_dynamic_symbol (bfd *output_bfd,
       /* This symbol has an entry in the procedure linkage table.  Set
         it up.  */
       if ((h->dynindx == -1
-          && !((h->forced_local || info->executable)
+          && !((h->forced_local || bfd_link_executable (info))
                && h->def_regular
                && h->type == STT_GNU_IFUNC))
          || plt == NULL
@@ -5012,7 +5231,7 @@ elf_x86_64_finish_dynamic_symbol (bfd *output_bfd,
                       + gotplt->output_offset
                       + got_offset);
       if (h->dynindx == -1
-         || ((info->executable
+         || ((bfd_link_executable (info)
               || ELF_ST_VISIBILITY (h->other) != STV_DEFAULT)
              && h->def_regular
              && h->type == STT_GNU_IFUNC))
@@ -5156,7 +5375,7 @@ elf_x86_64_finish_dynamic_symbol (bfd *output_bfd,
       if (h->def_regular
          && h->type == STT_GNU_IFUNC)
        {
-         if (info->shared)
+         if (bfd_link_pic (info))
            {
              /* Generate R_X86_64_GLOB_DAT.  */
              goto do_glob_dat;
@@ -5179,7 +5398,7 @@ elf_x86_64_finish_dynamic_symbol (bfd *output_bfd,
              return TRUE;
            }
        }
-      else if (info->shared
+      else if (bfd_link_pic (info)
               && SYMBOL_REFERENCES_LOCAL (info, h))
        {
          if (!h->def_regular)
@@ -5550,7 +5769,7 @@ bad_return:
   if (plt_sym_val == NULL)
     goto bad_return;
 
-  for (i = 0; i < count; i++, p++)
+  for (i = 0; i < count; i++)
     plt_sym_val[i] = -1;
 
   plt_offset = bed->plt_entry_size;
@@ -5583,6 +5802,11 @@ bad_return:
       else
        plt_sym_val[reloc_index] = plt->vma + plt_offset;
       plt_offset += bed->plt_entry_size;
+
+      /* PR binutils/18437: Skip extra relocations in the .rela.plt
+        section.  */
+      if (plt_offset >= plt->size)
+       break;
     }
 
   free (plt_contents);
@@ -5663,11 +5887,11 @@ elf_x86_64_add_symbol_hook (bfd *abfd,
       return TRUE;
     }
 
-  if ((ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC
-       || ELF_ST_BIND (sym->st_info) == STB_GNU_UNIQUE)
+  if (ELF_ST_BIND (sym->st_info) == STB_GNU_UNIQUE
       && (abfd->flags & DYNAMIC) == 0
       && bfd_get_flavour (info->output_bfd) == bfd_target_elf_flavour)
-    elf_tdata (info->output_bfd)->has_gnu_symbols = TRUE;
+    elf_tdata (info->output_bfd)->has_gnu_symbols
+      |= elf_gnu_symbol_unique;
 
   return TRUE;
 }
@@ -5840,6 +6064,7 @@ static const struct bfd_elf_special_section
 #define elf_backend_got_header_size        (GOT_ENTRY_SIZE*3)
 #define elf_backend_rela_normal                    1
 #define elf_backend_plt_alignment           4
+#define elf_backend_extern_protected_data   1
 
 #define elf_info_to_howto                  elf_x86_64_info_to_howto
 
@@ -5898,6 +6123,21 @@ static const struct bfd_elf_special_section
 
 #include "elf64-target.h"
 
+/* CloudABI support.  */
+
+#undef  TARGET_LITTLE_SYM
+#define TARGET_LITTLE_SYM                  x86_64_elf64_cloudabi_vec
+#undef  TARGET_LITTLE_NAME
+#define TARGET_LITTLE_NAME                 "elf64-x86-64-cloudabi"
+
+#undef ELF_OSABI
+#define        ELF_OSABI                           ELFOSABI_CLOUDABI
+
+#undef  elf64_bed
+#define elf64_bed elf64_x86_64_cloudabi_bed
+
+#include "elf64-target.h"
+
 /* FreeBSD support.  */
 
 #undef  TARGET_LITTLE_SYM