Relax assertion in BFIN linker to allow for discard GOT relocs.
[binutils-gdb.git] / bfd / elf64-x86-64.c
index b10c0c14a8b527e017932e348e79b062aeea00d1..dc7738a35645e33a8b08700f68e4d424cc819f0a 100644 (file)
@@ -1,5 +1,5 @@
 /* X86-64 specific support for ELF
-   Copyright (C) 2000-2014 Free Software Foundation, Inc.
+   Copyright (C) 2000-2016 Free Software Foundation, Inc.
    Contributed by Jan Hubicka <jh@suse.cz>.
 
    This file is part of BFD, the Binary File Descriptor library.
@@ -31,6 +31,7 @@
 #include "dwarf2.h"
 #include "libiberty.h"
 
+#include "opcode/i386.h"
 #include "elf/x86-64.h"
 
 #ifdef CORE_HEADER
@@ -54,7 +55,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,
@@ -176,12 +177,18 @@ static reloc_howto_type x86_64_elf_howto_table[] =
   HOWTO(R_X86_64_PLT32_BND, 0, 2, 32, TRUE, 0, complain_overflow_signed,
        bfd_elf_generic_reloc, "R_X86_64_PLT32_BND", FALSE, 0xffffffff, 0xffffffff,
        TRUE),
+  HOWTO(R_X86_64_GOTPCRELX, 0, 2, 32, TRUE, 0, complain_overflow_signed,
+       bfd_elf_generic_reloc, "R_X86_64_GOTPCRELX", FALSE, 0xffffffff,
+       0xffffffff, TRUE),
+  HOWTO(R_X86_64_REX_GOTPCRELX, 0, 2, 32, TRUE, 0, complain_overflow_signed,
+       bfd_elf_generic_reloc, "R_X86_64_REX_GOTPCRELX", FALSE, 0xffffffff,
+       0xffffffff, TRUE),
 
   /* We have a gap in the reloc numbers here.
      R_X86_64_standard counts the number up to this point, and
      R_X86_64_vt_offset is the value to subtract from a reloc type of
      R_X86_64_GNU_VT* to form an index into this table.  */
-#define R_X86_64_standard (R_X86_64_PLT32_BND + 1)
+#define R_X86_64_standard (R_X86_64_REX_GOTPCRELX + 1)
 #define R_X86_64_vt_offset (R_X86_64_GNU_VTINHERIT - R_X86_64_standard)
 
 /* GNU extension to record C++ vtable hierarchy.  */
@@ -253,8 +260,10 @@ static const struct elf_reloc_map x86_64_reloc_map[] =
   { BFD_RELOC_X86_64_TLSDESC_CALL, R_X86_64_TLSDESC_CALL, },
   { BFD_RELOC_X86_64_TLSDESC,  R_X86_64_TLSDESC, },
   { BFD_RELOC_X86_64_IRELATIVE,        R_X86_64_IRELATIVE, },
-  { BFD_RELOC_X86_64_PC32_BND, R_X86_64_PC32_BND,},
-  { BFD_RELOC_X86_64_PLT32_BND,        R_X86_64_PLT32_BND,},
+  { BFD_RELOC_X86_64_PC32_BND, R_X86_64_PC32_BND, },
+  { BFD_RELOC_X86_64_PLT32_BND,        R_X86_64_PLT32_BND, },
+  { BFD_RELOC_X86_64_GOTPCRELX, R_X86_64_GOTPCRELX, },
+  { BFD_RELOC_X86_64_REX_GOTPCRELX, R_X86_64_REX_GOTPCRELX, },
   { BFD_RELOC_VTABLE_INHERIT,  R_X86_64_GNU_VTINHERIT, },
   { BFD_RELOC_VTABLE_ENTRY,    R_X86_64_GNU_VTENTRY, },
 };
@@ -302,7 +311,7 @@ elf_x86_64_reloc_type_lookup (bfd *abfd,
        return elf_x86_64_rtype_to_howto (abfd,
                                          x86_64_reloc_map[i].elf_reloc_val);
     }
-  return 0;
+  return NULL;
 }
 
 static reloc_howto_type *
@@ -733,6 +742,20 @@ static const struct elf_x86_64_backend_data elf_x86_64_bnd_arch_bed =
 
 #define        elf_backend_arch_data   &elf_x86_64_arch_bed
 
+/* Is a undefined weak symbol which is resolved to 0.  Reference to an
+   undefined weak symbol is resolved to 0 when building executable if
+   it isn't dynamic and
+   1. Has non-GOT/non-PLT relocations in text section.  Or
+   2. Has no GOT/PLT relocation.
+ */
+#define UNDEFINED_WEAK_RESOLVED_TO_ZERO(INFO, EH) \
+  ((EH)->elf.root.type == bfd_link_hash_undefweak              \
+   && bfd_link_executable (INFO)                               \
+   && (elf_x86_64_hash_table (INFO)->interp == NULL            \
+       || !(EH)->has_got_reloc                                 \
+       || (EH)->has_non_got_reloc                              \
+       || !(INFO)->dynamic_undefined_weak))
+
 /* x86-64 ELF linker hash entry.  */
 
 struct elf_x86_64_link_hash_entry
@@ -757,8 +780,25 @@ struct elf_x86_64_link_hash_entry
   (GOT_TLS_GD_P (type) || GOT_TLS_GDESC_P (type))
   unsigned char tls_type;
 
+  /* TRUE if a weak symbol with a real definition needs a copy reloc.
+     When there is a weak symbol with a real definition, the processor
+     independent code will have arranged for us to see the real
+     definition first.  We need to copy the needs_copy bit from the
+     real definition and check it when allowing copy reloc in PIE.  */
+  unsigned int needs_copy : 1;
+
   /* TRUE if symbol has at least one BND relocation.  */
-  bfd_boolean has_bnd_reloc;
+  unsigned int has_bnd_reloc : 1;
+
+  /* TRUE if symbol has GOT or PLT relocations.  */
+  unsigned int has_got_reloc : 1;
+
+  /* TRUE if symbol has non-GOT/non-PLT relocations in text sections.  */
+  unsigned int has_non_got_reloc : 1;
+
+  /* Reference count of C/C++ function pointer relocations in read-write
+     section which can be resolved at run-time.  */
+  bfd_signed_vma func_pointer_refcount;
 
   /* Information about the GOT PLT entry. Filled when there are both
      GOT and PLT relocations against the same function.  */
@@ -815,6 +855,7 @@ struct elf_x86_64_link_hash_table
   struct elf_link_hash_table elf;
 
   /* Short-cuts to get to dynamic linker sections.  */
+  asection *interp;
   asection *sdynbss;
   asection *srelbss;
   asection *plt_eh_frame;
@@ -897,7 +938,11 @@ elf_x86_64_link_hash_newfunc (struct bfd_hash_entry *entry,
       eh = (struct elf_x86_64_link_hash_entry *) entry;
       eh->dyn_relocs = NULL;
       eh->tls_type = GOT_UNKNOWN;
-      eh->has_bnd_reloc = FALSE;
+      eh->needs_copy = 0;
+      eh->has_bnd_reloc = 0;
+      eh->has_got_reloc = 0;
+      eh->has_non_got_reloc = 0;
+      eh->func_pointer_refcount = 0;
       eh->plt_bnd.offset = (bfd_vma) -1;
       eh->plt_got.offset = (bfd_vma) -1;
       eh->tlsdesc_got = (bfd_vma) -1;
@@ -968,6 +1013,7 @@ elf_x86_64_get_local_sym_hash (struct elf_x86_64_link_hash_table *htab,
       ret->elf.indx = sec->id;
       ret->elf.dynstr_index = htab->r_sym (rel->r_info);
       ret->elf.dynindx = -1;
+      ret->func_pointer_refcount = 0;
       ret->plt_got.offset = (bfd_vma) -1;
       *slot = ret;
     }
@@ -1060,13 +1106,28 @@ elf_x86_64_create_dynamic_sections (bfd *dynobj,
     return FALSE;
 
   htab->sdynbss = bfd_get_linker_section (dynobj, ".dynbss");
-  if (!info->shared)
-    htab->srelbss = bfd_get_linker_section (dynobj, ".rela.bss");
-
-  if (!htab->sdynbss
-      || (!info->shared && !htab->srelbss))
+  if (!htab->sdynbss)
     abort ();
 
+  if (bfd_link_executable (info))
+    {
+      /* Always allow copy relocs for building executables.  */
+      asection *s = bfd_get_linker_section (dynobj, ".rela.bss");
+      if (s == NULL)
+       {
+         const struct elf_backend_data *bed = get_elf_backend_data (dynobj);
+         s = bfd_make_section_anyway_with_flags (dynobj,
+                                                 ".rela.bss",
+                                                 (bed->dynamic_sec_flags
+                                                  | SEC_READONLY));
+         if (s == NULL
+             || ! bfd_set_section_alignment (dynobj, s,
+                                             bed->s->log_file_align))
+           return FALSE;
+       }
+      htab->srelbss = s;
+    }
+
   if (!info->no_ld_generated_unwind_info
       && htab->plt_eh_frame == NULL
       && htab->elf.splt != NULL)
@@ -1098,6 +1159,12 @@ elf_x86_64_copy_indirect_symbol (struct bfd_link_info *info,
   if (!edir->has_bnd_reloc)
     edir->has_bnd_reloc = eind->has_bnd_reloc;
 
+  if (!edir->has_got_reloc)
+    edir->has_got_reloc = eind->has_got_reloc;
+
+  if (!edir->has_non_got_reloc)
+    edir->has_non_got_reloc = eind->has_non_got_reloc;
+
   if (eind->dyn_relocs != NULL)
     {
       if (edir->dyn_relocs != NULL)
@@ -1150,7 +1217,15 @@ elf_x86_64_copy_indirect_symbol (struct bfd_link_info *info,
       dir->pointer_equality_needed |= ind->pointer_equality_needed;
     }
   else
-    _bfd_elf_link_hash_copy_indirect (info, dir, ind);
+    {
+      if (eind->func_pointer_refcount > 0)
+       {
+         edir->func_pointer_refcount += eind->func_pointer_refcount;
+         eind->func_pointer_refcount = 0;
+       }
+
+      _bfd_elf_link_hash_copy_indirect (info, dir, ind);
+    }
 }
 
 static bfd_boolean
@@ -1411,7 +1486,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;
@@ -1426,7 +1501,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)
@@ -1450,7 +1525,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;
 
@@ -1506,6 +1581,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_load 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.  */
@@ -1523,7 +1602,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));
@@ -1545,6 +1624,7 @@ elf_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info,
       unsigned int r_type;
       unsigned long r_symndx;
       struct elf_link_hash_entry *h;
+      struct elf_x86_64_link_hash_entry *eh;
       Elf_Internal_Sym *isym;
       const char *name;
       bfd_boolean size_reloc;
@@ -1650,7 +1730,7 @@ elf_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info,
                      && (get_elf_x86_64_backend_data (abfd)
                          == &elf_x86_64_arch_bed))
                {
-                 elf_x86_64_hash_entry (h)->has_bnd_reloc = TRUE;
+                 elf_x86_64_hash_entry (h)->has_bnd_reloc = 1;
 
                  /* Create the second PLT for Intel MPX support.  */
                  if (htab->plt_bnd == NULL)
@@ -1685,6 +1765,8 @@ elf_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info,
            case R_X86_64_32S:
            case R_X86_64_PC64:
            case R_X86_64_GOTPCREL:
+           case R_X86_64_GOTPCRELX:
+           case R_X86_64_REX_GOTPCRELX:
            case R_X86_64_GOTPCREL64:
              if (htab->elf.dynobj == NULL)
                htab->elf.dynobj = abfd;
@@ -1696,6 +1778,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,
@@ -1704,6 +1790,7 @@ elf_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info,
                                       rel, rel_end, h, r_symndx))
        return FALSE;
 
+      eh = (struct elf_x86_64_link_hash_entry *) h;
       switch (r_type)
        {
        case R_X86_64_TLSLD:
@@ -1711,7 +1798,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;
@@ -1725,15 +1812,19 @@ elf_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info,
              bfd_set_error (bfd_error_bad_value);
              return FALSE;
            }
+         if (eh != NULL)
+           eh->has_got_reloc = 1;
          break;
 
        case R_X86_64_GOTTPOFF:
-         if (!info->executable)
+         if (!bfd_link_executable (info))
            info->flags |= DF_STATIC_TLS;
          /* Fall through */
 
        case R_X86_64_GOT32:
        case R_X86_64_GOTPCREL:
+       case R_X86_64_GOTPCRELX:
+       case R_X86_64_REX_GOTPCRELX:
        case R_X86_64_TLSGD:
        case R_X86_64_GOT64:
        case R_X86_64_GOTPCREL64:
@@ -1757,7 +1848,7 @@ elf_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info,
            if (h != NULL)
              {
                h->got.refcount += 1;
-               old_tls_type = elf_x86_64_hash_entry (h)->tls_type;
+               old_tls_type = eh->tls_type;
              }
            else
              {
@@ -1815,8 +1906,8 @@ elf_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info,
 
            if (old_tls_type != tls_type)
              {
-               if (h != NULL)
-                 elf_x86_64_hash_entry (h)->tls_type = tls_type;
+               if (eh != NULL)
+                 eh->tls_type = tls_type;
                else
                  elf_x86_64_local_got_tls_type (abfd) [r_symndx] = tls_type;
              }
@@ -1827,6 +1918,8 @@ elf_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info,
        case R_X86_64_GOTPC32:
        case R_X86_64_GOTPC64:
        create_got:
+         if (eh != NULL)
+           eh->has_got_reloc = 1;
          if (htab->elf.sgot == NULL)
            {
              if (htab->elf.dynobj == NULL)
@@ -1851,6 +1944,7 @@ elf_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info,
          if (h == NULL)
            continue;
 
+         eh->has_got_reloc = 1;
          h->needs_plt = 1;
          h->plt.refcount += 1;
          break;
@@ -1879,8 +1973,10 @@ elf_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info,
          /* Let's help debug shared library creation.  These relocs
             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
+            non-constant sections, or when relocation overflow check
+            is disabled.  */
+         if (!info->no_reloc_overflow_check
+             && bfd_link_pic (info)
              && (sec->flags & SEC_ALLOC) != 0
              && (sec->flags & SEC_READONLY) != 0)
            {
@@ -1903,7 +1999,17 @@ 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 (eh != NULL && (sec->flags & SEC_CODE) != 0)
+           eh->has_non_got_reloc = 1;
+         /* STT_GNU_IFUNC symbol must go through PLT even if it is
+            locally defined and undefined symbol may turn out to be
+            a STT_GNU_IFUNC symbol later.  */
+         if (h != NULL
+             && (bfd_link_executable (info)
+                 || ((h->type == STT_GNU_IFUNC
+                      || h->root.type == bfd_link_hash_undefweak
+                      || h->root.type == bfd_link_hash_undefined)
+                     && SYMBOLIC_BIND (info, h))))
            {
              /* If this reloc is in a read-only section, we might
                 need a copy reloc.  We can't check reliably at this
@@ -1916,10 +2022,28 @@ pointer:
              /* We may need a .plt entry if the function this reloc
                 refers to is in a shared lib.  */
              h->plt.refcount += 1;
-             if (r_type != R_X86_64_PC32
-                 && r_type != R_X86_64_PC32_BND
-                 && r_type != R_X86_64_PC64)
-               h->pointer_equality_needed = 1;
+             if (r_type == R_X86_64_PC32)
+               {
+                 /* Since something like ".long foo - ." may be used
+                    as pointer, make sure that PLT is used if foo is
+                    a function defined in a shared library.  */
+                 if ((sec->flags & SEC_CODE) == 0)
+                   h->pointer_equality_needed = 1;
+               }
+             else if (r_type != R_X86_64_PC32_BND
+                      && r_type != R_X86_64_PC64)
+               {
+                 h->pointer_equality_needed = 1;
+                 /* At run-time, R_X86_64_64 can be resolved for both
+                    x86-64 and x32. But R_X86_64_32 and R_X86_64_32S
+                    can only be resolved for x32.  */
+                 if ((sec->flags & SEC_READONLY) == 0
+                     && (r_type == R_X86_64_64
+                         || (!ABI_64_P (abfd)
+                             && (r_type == R_X86_64_32
+                                 || r_type == R_X86_64_32S))))
+                   eh->func_pointer_refcount += 1;
+               }
            }
 
          size_reloc = FALSE;
@@ -1945,15 +2069,16 @@ 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
-                      && (! SYMBOLIC_BIND (info, h)
+                      && (! (bfd_link_pie (info)
+                             || SYMBOLIC_BIND (info, h))
                           || 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
@@ -1981,9 +2106,7 @@ do_size:
              /* If this is a global symbol, we count the number of
                 relocations we need for this symbol.  */
              if (h != NULL)
-               {
-                 head = &((struct elf_x86_64_link_hash_entry *) h)->dyn_relocs;
-               }
+               head = &eh->dyn_relocs;
              else
                {
                  /* Track dynamic relocs needed for local syms too.
@@ -2053,7 +2176,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.  */
@@ -2082,6 +2206,12 @@ do_size:
                                             plt_got_align))
            return FALSE;
        }
+
+      if ((r_type == R_X86_64_GOTPCREL
+          || r_type == R_X86_64_GOTPCRELX
+          || r_type == R_X86_64_REX_GOTPCRELX)
+         && (h == NULL || h->type != STT_GNU_IFUNC))
+       sec->need_convert_load = 1;
     }
 
   return TRUE;
@@ -2121,7 +2251,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);
@@ -2141,6 +2271,7 @@ elf_x86_64_gc_sweep_hook (bfd *abfd, struct bfd_link_info *info,
       unsigned long r_symndx;
       unsigned int r_type;
       struct elf_link_hash_entry *h = NULL;
+      bfd_boolean pointer_reloc;
 
       r_symndx = htab->r_sym (rel->r_info);
       if (r_symndx >= symtab_hdr->sh_info)
@@ -2192,6 +2323,7 @@ elf_x86_64_gc_sweep_hook (bfd *abfd, struct bfd_link_info *info,
                                       rel, relend, h, r_symndx))
        return FALSE;
 
+      pointer_reloc = FALSE;
       switch (r_type)
        {
        case R_X86_64_TLSLD:
@@ -2205,6 +2337,8 @@ elf_x86_64_gc_sweep_hook (bfd *abfd, struct bfd_link_info *info,
        case R_X86_64_GOTTPOFF:
        case R_X86_64_GOT32:
        case R_X86_64_GOTPCREL:
+       case R_X86_64_GOTPCRELX:
+       case R_X86_64_REX_GOTPCRELX:
        case R_X86_64_GOT64:
        case R_X86_64_GOTPCREL64:
        case R_X86_64_GOTPLT64:
@@ -2225,11 +2359,15 @@ elf_x86_64_gc_sweep_hook (bfd *abfd, struct bfd_link_info *info,
            }
          break;
 
-       case R_X86_64_8:
-       case R_X86_64_16:
        case R_X86_64_32:
-       case R_X86_64_64:
        case R_X86_64_32S:
+         pointer_reloc = !ABI_64_P (abfd);
+         goto pointer;
+
+       case R_X86_64_64:
+         pointer_reloc = TRUE;
+       case R_X86_64_8:
+       case R_X86_64_16:
        case R_X86_64_PC8:
        case R_X86_64_PC16:
        case R_X86_64_PC32:
@@ -2237,7 +2375,8 @@ 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
+pointer:
+         if (bfd_link_pic (info)
              && (h == NULL || h->type != STT_GNU_IFUNC))
            break;
          /* Fall thru */
@@ -2249,6 +2388,13 @@ elf_x86_64_gc_sweep_hook (bfd *abfd, struct bfd_link_info *info,
            {
              if (h->plt.refcount > 0)
                h->plt.refcount -= 1;
+             if (pointer_reloc && (sec->flags & SEC_READONLY) == 0)
+               {
+                 struct elf_x86_64_link_hash_entry *eh
+                   = (struct elf_x86_64_link_hash_entry *) h;
+                 if (eh->func_pointer_refcount > 0)
+                   eh->func_pointer_refcount -= 1;
+               }
            }
          break;
 
@@ -2260,6 +2406,24 @@ elf_x86_64_gc_sweep_hook (bfd *abfd, struct bfd_link_info *info,
   return TRUE;
 }
 
+/* Remove undefined weak symbol from the dynamic symbol table if it
+   is resolved to 0.   */
+
+static bfd_boolean
+elf_x86_64_fixup_symbol (struct bfd_link_info *info,
+                      struct elf_link_hash_entry *h)
+{
+  if (h->dynindx != -1
+      && UNDEFINED_WEAK_RESOLVED_TO_ZERO (info,
+                                         elf_x86_64_hash_entry (h)))
+    {
+      h->dynindx = -1;
+      _bfd_elf_strtab_delref (elf_hash_table (info)->dynstr,
+                             h->dynstr_index);
+    }
+  return TRUE;
+}
+
 /* Adjust a symbol defined by a dynamic object and referenced by a
    regular object.  The current definition is in some section of the
    dynamic object, but we're not including those sections.  We have to
@@ -2358,7 +2522,11 @@ elf_x86_64_adjust_dynamic_symbol (struct bfd_link_info *info,
       h->root.u.def.section = h->u.weakdef->root.u.def.section;
       h->root.u.def.value = h->u.weakdef->root.u.def.value;
       if (ELIMINATE_COPY_RELOCS || info->nocopyreloc)
-       h->non_got_ref = h->u.weakdef->non_got_ref;
+       {
+         eh = (struct elf_x86_64_link_hash_entry *) h;
+         h->non_got_ref = h->u.weakdef->non_got_ref;
+         eh->needs_copy = h->u.weakdef->needs_copy;
+       }
       return TRUE;
     }
 
@@ -2369,7 +2537,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->shared)
+  if (!bfd_link_executable (info))
     return TRUE;
 
   /* If there are no references to this symbol that do not use the
@@ -2430,7 +2598,7 @@ elf_x86_64_adjust_dynamic_symbol (struct bfd_link_info *info,
 
   s = htab->sdynbss;
 
-  return _bfd_elf_adjust_dynamic_copy (h, s);
+  return _bfd_elf_adjust_dynamic_copy (info, h, s);
 }
 
 /* Allocate space in .plt, .got and associated reloc sections for
@@ -2445,6 +2613,7 @@ elf_x86_64_allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf)
   struct elf_dyn_relocs *p;
   const struct elf_backend_data *bed;
   unsigned int plt_entry_size;
+  bfd_boolean resolved_to_zero;
 
   if (h->root.type == bfd_link_hash_indirect)
     return TRUE;
@@ -2458,6 +2627,8 @@ elf_x86_64_allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf)
   bed = get_elf_backend_data (info->output_bfd);
   plt_entry_size = GET_PLT_ENTRY_SIZE (info->output_bfd);
 
+  resolved_to_zero = UNDEFINED_WEAK_RESOLVED_TO_ZERO (info, eh);
+
   /* We can't use the GOT PLT if pointer equality is needed since
      finish_dynamic_symbol won't clear symbol value and the dynamic
      linker won't update the GOT slot.  We will get into an infinite
@@ -2476,6 +2647,11 @@ elf_x86_64_allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf)
       eh->plt_got.refcount = 1;
     }
 
+  /* Clear the reference count of function pointer relocations if
+     symbol isn't a normal function.  */
+  if (h->type != STT_FUNC)
+    eh->func_pointer_refcount = 0;
+
   /* Since STT_GNU_IFUNC symbol must go through PLT, we handle it
      here if it is defined and referenced in a non-shared object.  */
   if (h->type == STT_GNU_IFUNC
@@ -2502,21 +2678,41 @@ elf_x86_64_allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf)
       else
        return FALSE;
     }
+  /* Don't create the PLT entry if there are only function pointer
+     relocations which can be resolved at run-time.  */
   else if (htab->elf.dynamic_sections_created
-          && (h->plt.refcount > 0 || eh->plt_got.refcount > 0))
+          && (h->plt.refcount > eh->func_pointer_refcount
+              || eh->plt_got.refcount > 0))
     {
-      bfd_boolean use_plt_got = eh->plt_got.refcount > 0;
+      bfd_boolean use_plt_got;
+
+      /* Clear the reference count of function pointer relocations
+        if PLT is used.  */
+      eh->func_pointer_refcount = 0;
+
+      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.  */
       if (h->dynindx == -1
-         && !h->forced_local)
+         && !h->forced_local
+         && !resolved_to_zero)
        {
          if (! bfd_elf_link_record_dynamic_symbol (info, h))
            return FALSE;
        }
 
-      if (info->shared
+      if (bfd_link_pic (info)
          || WILL_CALL_FINISH_DYNAMIC_SYMBOL (1, 0, h))
        {
          asection *s = htab->elf.splt;
@@ -2524,7 +2720,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;
 
@@ -2542,7 +2739,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)
@@ -2583,20 +2780,27 @@ elf_x86_64_allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf)
                 script.  */
              htab->elf.sgotplt->size += GOT_ENTRY_SIZE;
 
-             /* We also need to make an entry in the .rela.plt
-                section.  */
-             htab->elf.srelplt->size += bed->s->sizeof_rela;
-             htab->elf.srelplt->reloc_count++;
+             /* There should be no PLT relocation against resolved
+                undefined weak symbol in executable.  */
+             if (!resolved_to_zero)
+               {
+                 /* We also need to make an entry in the .rela.plt
+                    section.  */
+                 htab->elf.srelplt->size += bed->s->sizeof_rela;
+                 htab->elf.srelplt->reloc_count++;
+               }
            }
        }
       else
        {
+         eh->plt_got.offset = (bfd_vma) -1;
          h->plt.offset = (bfd_vma) -1;
          h->needs_plt = 0;
        }
     }
   else
     {
+      eh->plt_got.offset = (bfd_vma) -1;
       h->plt.offset = (bfd_vma) -1;
       h->needs_plt = 0;
     }
@@ -2606,7 +2810,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)
     {
@@ -2621,7 +2825,8 @@ elf_x86_64_allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf)
       /* Make sure this symbol is output as a dynamic symbol.
         Undefined weak syms won't yet be marked as dynamic.  */
       if (h->dynindx == -1
-         && !h->forced_local)
+         && !h->forced_local
+         && !resolved_to_zero)
        {
          if (! bfd_elf_link_record_dynamic_symbol (info, h))
            return FALSE;
@@ -2645,17 +2850,19 @@ elf_x86_64_allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf)
        }
       dyn = htab->elf.dynamic_sections_created;
       /* R_X86_64_TLSGD needs one dynamic relocation if local symbol
-        and two if global.
-        R_X86_64_GOTTPOFF needs one dynamic relocation.  */
+        and two if global.  R_X86_64_GOTTPOFF needs one dynamic
+        relocation.  No dynamic relocation against resolved undefined
+        weak symbol in executable.  */
       if ((GOT_TLS_GD_P (tls_type) && h->dynindx == -1)
          || tls_type == GOT_TLS_IE)
        htab->elf.srelgot->size += bed->s->sizeof_rela;
       else if (GOT_TLS_GD_P (tls_type))
        htab->elf.srelgot->size += 2 * bed->s->sizeof_rela;
       else if (! GOT_TLS_GDESC_P (tls_type)
-              && (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
+              && ((ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
+                   && !resolved_to_zero)
                   || 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))
@@ -2676,7 +2883,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.
@@ -2700,29 +2907,51 @@ elf_x86_64_allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf)
        }
 
       /* Also discard relocs on undefined weak syms with non-default
-        visibility.  */
-      if (eh->dyn_relocs != NULL
-         && h->root.type == bfd_link_hash_undefweak)
+        visibility or in PIE.  */
+      if (eh->dyn_relocs != NULL)
        {
-         if (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT)
-           eh->dyn_relocs = NULL;
-
-         /* Make sure undefined weak symbols are output as a dynamic
-            symbol in PIEs.  */
-         else if (h->dynindx == -1
-                  && ! h->forced_local
-                  && ! bfd_elf_link_record_dynamic_symbol (info, h))
-           return FALSE;
-       }
+         if (h->root.type == bfd_link_hash_undefweak)
+           {
+             /* Undefined weak symbol is never bound locally in shared
+                library.  */
+             if (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT
+                 || resolved_to_zero)
+               eh->dyn_relocs = NULL;
+             else if (h->dynindx == -1
+                      && ! h->forced_local
+                      && ! bfd_elf_link_record_dynamic_symbol (info, h))
+               return FALSE;
+           }
+         /* 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)
+           {
+             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)
     {
       /* For the non-shared case, discard space for relocs against
         symbols which turn out to need copy relocs or are not
-        dynamic.  */
+        dynamic.  Keep dynamic relocations for run-time function
+        pointer initialization.  */
 
-      if (!h->non_got_ref
+      if ((!h->non_got_ref
+          || eh->func_pointer_refcount > 0
+          || (h->root.type == bfd_link_hash_undefweak
+              && !resolved_to_zero))
          && ((h->def_dynamic
               && !h->def_regular)
              || (htab->elf.dynamic_sections_created
@@ -2733,6 +2962,7 @@ elf_x86_64_allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf)
             Undefined weak syms won't yet be marked as dynamic.  */
          if (h->dynindx == -1
              && ! h->forced_local
+             && ! resolved_to_zero
              && ! bfd_elf_link_record_dynamic_symbol (info, h))
            return FALSE;
 
@@ -2743,6 +2973,7 @@ elf_x86_64_allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf)
        }
 
       eh->dyn_relocs = NULL;
+      eh->func_pointer_refcount = 0;
 
     keep: ;
     }
@@ -2805,8 +3036,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);
 
@@ -2817,15 +3049,28 @@ elf_x86_64_readonly_dynrelocs (struct elf_link_hash_entry *h,
   return TRUE;
 }
 
-/* Convert
+/* With the local symbol, foo, we convert
    mov foo@GOTPCREL(%rip), %reg
    to
    lea foo(%rip), %reg
-   with the local symbol, foo.  */
+   and convert
+   call/jmp *foo@GOTPCREL(%rip)
+   to
+   nop call foo/jmp foo nop
+   When PIC is false, convert
+   test %reg, foo@GOTPCREL(%rip)
+   to
+   test $foo, %reg
+   and convert
+   binop foo@GOTPCREL(%rip), %reg
+   to
+   binop $foo, %reg
+   where binop is one of adc, add, and, cmp, or, sbb, sub, xor
+   instructions.  */
 
 static bfd_boolean
-elf_x86_64_convert_mov_to_lea (bfd *abfd, asection *sec,
-                              struct bfd_link_info *link_info)
+elf_x86_64_convert_load (bfd *abfd, asection *sec,
+                        struct bfd_link_info *link_info)
 {
   Elf_Internal_Shdr *symtab_hdr;
   Elf_Internal_Rela *internal_relocs;
@@ -2835,14 +3080,17 @@ 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;
+  bfd_boolean is_pic;
+  bfd_boolean require_reloc_pc32;
 
   /* 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_load == 0
       || bfd_is_abs_section (sec->output_section))
     return TRUE;
 
@@ -2859,6 +3107,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)
@@ -2869,6 +3118,13 @@ elf_x86_64_convert_mov_to_lea (bfd *abfd, asection *sec,
        goto error_return;
     }
 
+  is_pic = bfd_link_pic (link_info);
+
+  /* TRUE if we can convert only to R_X86_64_PC32.  Enable it for
+     --no-relax.  */
+  require_reloc_pc32
+    = link_info->disable_target_specific_optimizations > 1;
+
   irelend = internal_relocs + sec->reloc_count;
   for (irel = internal_relocs; irel < irelend; irel++)
     {
@@ -2876,10 +3132,52 @@ 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;
+      bfd_signed_vma raddend;
+      unsigned int opcode;
+      unsigned int modrm;
+      bfd_boolean relocx;
+      bfd_boolean to_reloc_pc32;
+
+      relocx = (r_type == R_X86_64_GOTPCRELX
+               || r_type == R_X86_64_REX_GOTPCRELX);
+      if (!relocx && r_type != R_X86_64_GOTPCREL)
+       continue;
+
+      roff = irel->r_offset;
+      if (roff < (r_type == R_X86_64_REX_GOTPCRELX ? 3 : 2))
+       continue;
 
-      if (r_type != R_X86_64_GOTPCREL)
+      raddend = irel->r_addend;
+      /* Addend for 32-bit PC-relative relocation must be -4.  */
+      if (raddend != -4)
        continue;
 
+      opcode = bfd_get_8 (abfd, contents + roff - 2);
+
+      /* Convert mov to lea since it has been done for a while.  */
+      if (opcode != 0x8b)
+       {
+         /* Only convert R_X86_64_GOTPCRELX and R_X86_64_REX_GOTPCRELX
+            for call, jmp or one of adc, add, and, cmp, or, sbb, sub,
+            test, xor instructions.  */
+         if (!relocx)
+           continue;
+       }
+
+      /* We convert only to R_X86_64_PC32:
+        1. Branch.
+        2. R_X86_64_GOTPCREL since we can't modify REX byte.
+        3. require_reloc_pc32 is true.
+        4. PIC.
+       */
+      to_reloc_pc32 = (opcode == 0xff
+                      || !relocx
+                      || require_reloc_pc32
+                      || is_pic);
+
       /* Get the symbol referred to by the reloc.  */
       if (r_symndx < symtab_hdr->sh_info)
        {
@@ -2888,50 +3186,326 @@ elf_x86_64_convert_mov_to_lea (bfd *abfd, asection *sec,
          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 GOTPCREL relocations and skip
+            relocation against undefined symbols.  */
+         if (symtype == STT_GNU_IFUNC || isym->st_shndx == SHN_UNDEF)
+           continue;
+
+         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);
+
+         h = NULL;
+         toff = isym->st_value;
+       }
+      else
+       {
+         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;
+
+         /* STT_GNU_IFUNC must keep GOTPCREL relocations.  We also
+            avoid optimizing GOTPCREL relocations againt _DYNAMIC
+            since ld.so may use its link-time address.  */
+         if (h->type == STT_GNU_IFUNC)
+           continue;
+
+         /* Undefined weak symbol is only bound locally in executable
+            and its reference is resolved as 0 without relocation
+            overflow.  We can only perform this optimization for
+            GOTPCRELX relocations since we need to modify REX byte.
+            It is OK convert mov with R_X86_64_GOTPCREL to
+            R_X86_64_PC32.  */
+         if ((relocx || opcode == 0x8b)
+             && UNDEFINED_WEAK_RESOLVED_TO_ZERO (link_info,
+                                                 elf_x86_64_hash_entry (h)))
            {
-             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 (opcode == 0xff)
+               {
+                 /* Skip for branch instructions since R_X86_64_PC32
+                    may overflow.  */
+                 if (require_reloc_pc32)
+                   continue;
+               }
+             else if (relocx)
+               {
+                 /* For non-branch instructions, we can convert to
+                    R_X86_64_32/R_X86_64_32S since we know if there
+                    is a REX byte.  */
+                 to_reloc_pc32 = FALSE;
+               }
+
+             /* Since we don't know the current PC when PIC is true,
+                we can't convert to R_X86_64_PC32.  */
+             if (to_reloc_pc32 && is_pic)
+               continue;
+
+             goto convert;
            }
-         continue;
+         else if ((h->def_regular
+                   || h->root.type == bfd_link_hash_defined
+                   || h->root.type == bfd_link_hash_defweak)
+                  && h != htab->elf.hdynamic
+                  && SYMBOL_REFERENCES_LOCAL (link_info, h))
+           {
+             /* bfd_link_hash_new or bfd_link_hash_undefined is
+                set by an assignment in a linker script in
+                bfd_elf_record_link_assignment.   */
+             if (h->def_regular
+                 && (h->root.type == bfd_link_hash_new
+                     || h->root.type == bfd_link_hash_undefined))
+               {
+                 /* Skip since R_X86_64_32/R_X86_64_32S may overflow.  */
+                 if (require_reloc_pc32)
+                   continue;
+                 goto convert;
+               }
+             tsec = h->root.u.def.section;
+             toff = h->root.u.def.value;
+             symtype = h->type;
+           }
+         else
+           continue;
        }
 
-      indx = r_symndx - symtab_hdr->sh_info;
-      h = elf_sym_hashes (abfd)[indx];
-      BFD_ASSERT (h != NULL);
+      /* We can only estimate relocation overflow for R_X86_64_PC32.  */
+      if (!to_reloc_pc32)
+       goto convert;
 
-      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;
+      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 += raddend;
+
+          toff = _bfd_merged_section_offset (abfd, &tsec,
+                                             elf_section_data (tsec)->sec_info,
+                                             toff);
+
+          if (symtype != STT_SECTION)
+            toff += raddend;
+       }
+      else
+       toff += raddend;
 
-      /* 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)
+      /* Don't convert if R_X86_64_PC32 relocation overflows.  */
+      if (tsec->output_section == sec->output_section)
+       {
+         if ((toff - roff + 0x80000000) > 0xffffffff)
+           continue;
+       }
+      else
+       {
+         bfd_signed_vma distance;
+
+         /* At this point, we don't know the load addresses of TSEC
+            section nor SEC section.  We estimate the distrance between
+            SEC and TSEC.  We store the estimated distances in the
+            compressed_size field of the output section, which is only
+            used to decompress the compressed input section.  */
+         if (sec->output_section->compressed_size == 0)
+           {
+             asection *asect;
+             bfd_size_type size = 0;
+             for (asect = link_info->output_bfd->sections;
+                  asect != NULL;
+                  asect = asect->next)
+               {
+                 asection *i;
+                 for (i = asect->map_head.s;
+                      i != NULL;
+                      i = i->map_head.s)
+                   {
+                     size = align_power (size, i->alignment_power);
+                     size += i->size;
+                   }
+                 asect->compressed_size = size;
+               }
+           }
+
+         /* Don't convert GOTPCREL relocations if TSEC isn't placed
+            after SEC.  */
+         distance = (tsec->output_section->compressed_size
+                     - sec->output_section->compressed_size);
+         if (distance < 0)
+           continue;
+
+         /* Take PT_GNU_RELRO segment into account by adding
+            maxpagesize.  */
+         if ((toff + distance + maxpagesize - roff + 0x80000000)
+             > 0xffffffff)
+           continue;
+       }
+
+convert:
+      if (opcode == 0xff)
+       {
+         /* We have "call/jmp *foo@GOTPCREL(%rip)".  */
+         unsigned int nop;
+         unsigned int disp;
+         bfd_vma nop_offset;
+
+         /* Convert R_X86_64_GOTPCRELX and R_X86_64_REX_GOTPCRELX to
+            R_X86_64_PC32.  */
+         modrm = bfd_get_8 (abfd, contents + roff - 1);
+         if (modrm == 0x25)
+           {
+             /* Convert to "jmp foo nop".  */
+             modrm = 0xe9;
+             nop = NOP_OPCODE;
+             nop_offset = irel->r_offset + 3;
+             disp = bfd_get_32 (abfd, contents + irel->r_offset);
+             irel->r_offset -= 1;
+             bfd_put_32 (abfd, disp, contents + irel->r_offset);
+           }
+         else
+           {
+             /* Convert to "nop call foo".  ADDR_PREFIX_OPCODE
+                is a nop prefix.  */
+             modrm = 0xe8;
+             nop = link_info->call_nop_byte;
+             if (link_info->call_nop_as_suffix)
+               {
+                 nop_offset = irel->r_offset + 3;
+                 disp = bfd_get_32 (abfd, contents + irel->r_offset);
+                 irel->r_offset -= 1;
+                 bfd_put_32 (abfd, disp, contents + irel->r_offset);
+               }
+             else
+               nop_offset = irel->r_offset - 2;
+           }
+         bfd_put_8 (abfd, nop, contents + nop_offset);
+         bfd_put_8 (abfd, modrm, contents + irel->r_offset - 1);
+         r_type = R_X86_64_PC32;
+       }
+      else
+       {
+         unsigned int rex;
+         unsigned int rex_mask = REX_R;
+
+         if (r_type == R_X86_64_REX_GOTPCRELX)
+           rex = bfd_get_8 (abfd, contents + roff - 3);
+         else
+           rex = 0;
+
+         if (opcode == 0x8b)
+           {
+             if (to_reloc_pc32)
+               {
+                 /* Convert "mov foo@GOTPCREL(%rip), %reg" to
+                    "lea foo(%rip), %reg".  */
+                 opcode = 0x8d;
+                 r_type = R_X86_64_PC32;
+               }
+             else
+               {
+                 /* Convert "mov foo@GOTPCREL(%rip), %reg" to
+                    "mov $foo, %reg".  */
+                 opcode = 0xc7;
+                 modrm = bfd_get_8 (abfd, contents + roff - 1);
+                 modrm = 0xc0 | (modrm & 0x38) >> 3;
+                 if ((rex & REX_W) != 0
+                     && ABI_64_P (link_info->output_bfd))
+                   {
+                     /* Keep the REX_W bit in REX byte for LP64.  */
+                     r_type = R_X86_64_32S;
+                     goto rewrite_modrm_rex;
+                   }
+                 else
+                   {
+                     /* If the REX_W bit in REX byte isn't needed,
+                        use R_X86_64_32 and clear the W bit to avoid
+                        sign-extend imm32 to imm64.  */
+                     r_type = R_X86_64_32;
+                     /* Clear the W bit in REX byte.  */
+                     rex_mask |= REX_W;
+                     goto rewrite_modrm_rex;
+                   }
+               }
+           }
+         else
+           {
+             /* R_X86_64_PC32 isn't supported.  */
+             if (to_reloc_pc32)
+               continue;
+
+             modrm = bfd_get_8 (abfd, contents + roff - 1);
+             if (opcode == 0x85)
+               {
+                 /* Convert "test %reg, foo@GOTPCREL(%rip)" to
+                    "test $foo, %reg".  */
+                 modrm = 0xc0 | (modrm & 0x38) >> 3;
+                 opcode = 0xf7;
+               }
+             else
+               {
+                 /* Convert "binop foo@GOTPCREL(%rip), %reg" to
+                    "binop $foo, %reg".  */
+                 modrm = 0xc0 | (modrm & 0x38) >> 3 | (opcode & 0x3c);
+                 opcode = 0x81;
+               }
+
+             /* Use R_X86_64_32 with 32-bit operand to avoid relocation
+                overflow when sign-extending imm32 to imm64.  */
+             r_type = (rex & REX_W) != 0 ? R_X86_64_32S : R_X86_64_32;
+
+rewrite_modrm_rex:
+             bfd_put_8 (abfd, modrm, contents + roff - 1);
+
+             if (rex)
+               {
+                 /* Move the R bit to the B bit in REX byte.  */
+                 rex = (rex & ~rex_mask) | (rex & REX_R) >> 2;
+                 bfd_put_8 (abfd, rex, contents + roff - 3);
+               }
+
+             /* No addend for R_X86_64_32/R_X86_64_32S relocations.  */
+             irel->r_addend = 0;
+           }
+
+         bfd_put_8 (abfd, opcode, contents + roff - 2);
+       }
+
+      irel->r_info = htab->r_info (r_symndx, r_type);
+      changed_contents = TRUE;
+      changed_relocs = TRUE;
+
+      if (h)
        {
-         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;
+       }
+      else
+       {
+         if (local_got_refcounts != NULL
+             && local_got_refcounts[r_symndx] > 0)
+           local_got_refcounts[r_symndx] -= 1;
        }
     }
 
@@ -2992,13 +3566,14 @@ 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) && !info->nointerp)
        {
          s = bfd_get_linker_section (dynobj, ".interp");
          if (s == NULL)
            abort ();
          s->size = htab->dynamic_interpreter_size;
          s->contents = (unsigned char *) htab->dynamic_interpreter;
+         htab->interp = s;
        }
     }
 
@@ -3021,7 +3596,7 @@ elf_x86_64_size_dynamic_sections (bfd *output_bfd,
        {
          struct elf_dyn_relocs *p;
 
-         if (!elf_x86_64_convert_mov_to_lea (ibfd, s, info))
+         if (!elf_x86_64_convert_load (ibfd, s, info))
            return FALSE;
 
          for (p = (struct elf_dyn_relocs *)
@@ -3045,8 +3620,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);
                    }
                }
@@ -3085,7 +3661,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)
                {
@@ -3280,7 +3856,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;
@@ -3288,12 +3864,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)))
@@ -3316,6 +3899,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;
            }
@@ -3362,6 +3954,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);
        }
     }
@@ -3380,7 +3973,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);
@@ -3444,6 +4037,42 @@ is_32bit_relative_branch (bfd_byte *contents, bfd_vma offset)
              && (contents [offset - 1] & 0xf0) == 0x80));
 }
 
+static bfd_boolean
+elf_x86_64_need_pic (bfd *input_bfd, struct elf_link_hash_entry *h,
+                    reloc_howto_type *howto)
+{
+  const char *fmt;
+  const char *v;
+  const char *pic = "";
+
+  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");
+      pic = _("; recompile with -fPIC");
+      break;
+    }
+
+  if (h->def_regular)
+    fmt = _("%B: relocation %s against %s `%s' can not be used when making a shared object%s");
+  else
+    fmt = _("%B: relocation %s against undefined %s `%s' can not be used when making a shared object%s");
+
+  (*_bfd_error_handler) (fmt, input_bfd, howto->name,
+                        v,  h->root.root.string, pic);
+  bfd_set_error (bfd_error_bad_value);
+  return FALSE;
+}
+
 /* Relocate an x86_64 ELF section.  */
 
 static bfd_boolean
@@ -3462,6 +4091,7 @@ elf_x86_64_relocate_section (bfd *output_bfd,
   bfd_vma *local_got_offsets;
   bfd_vma *local_tlsdesc_gotents;
   Elf_Internal_Rela *rel;
+  Elf_Internal_Rela *wrel;
   Elf_Internal_Rela *relend;
   const unsigned int plt_entry_size = GET_PLT_ENTRY_SIZE (info->output_bfd);
 
@@ -3477,9 +4107,9 @@ elf_x86_64_relocate_section (bfd *output_bfd,
 
   elf_x86_64_set_tls_module_base (info);
 
-  rel = relocs;
+  rel = wrel = relocs;
   relend = relocs + input_section->reloc_count;
-  for (; rel < relend; rel++)
+  for (; rel < relend; wrel++, rel++)
     {
       unsigned int r_type;
       reloc_howto_type *howto;
@@ -3495,11 +4125,16 @@ elf_x86_64_relocate_section (bfd *output_bfd,
       int tls_type;
       asection *base_got, *resolved_plt;
       bfd_vma st_size;
+      bfd_boolean resolved_to_zero;
 
       r_type = ELF32_R_TYPE (rel->r_info);
       if (r_type == (int) R_X86_64_GNU_VTINHERIT
          || r_type == (int) R_X86_64_GNU_VTENTRY)
-       continue;
+       {
+         if (wrel != rel)
+           *wrel = *rel;
+         continue;
+       }
 
       if (r_type >= (int) R_X86_64_standard)
        {
@@ -3531,7 +4166,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,
@@ -3557,11 +4192,29 @@ elf_x86_64_relocate_section (bfd *output_bfd,
        }
 
       if (sec != NULL && discarded_section (sec))
-       RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section,
-                                        rel, 1, relend, howto, 0, contents);
+       {
+         _bfd_clear_contents (howto, input_bfd, input_section,
+                              contents + rel->r_offset);
+         wrel->r_offset = rel->r_offset;
+         wrel->r_info = 0;
+         wrel->r_addend = 0;
+
+         /* For ld -r, remove relocations in debug sections against
+            sections defined in discarded sections.  Not done for
+            eh_frame editing code expects to be present.  */
+          if (bfd_link_relocatable (info)
+              && (input_section->flags & SEC_DEBUGGING))
+            wrel--;
 
-      if (info->relocatable)
-       continue;
+         continue;
+       }
+
+      if (bfd_link_relocatable (info))
+       {
+         if (wrel != rel)
+           *wrel = *rel;
+         continue;
+       }
 
       if (rel->r_addend == 0 && !ABI_64_P (output_bfd))
        {
@@ -3592,8 +4245,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.  */
@@ -3630,13 +4291,12 @@ elf_x86_64_relocate_section (bfd *output_bfd,
              (*_bfd_error_handler)
                (_("%B: relocation %s against STT_GNU_IFUNC "
                   "symbol `%s' isn't handled by %s"), input_bfd,
-                x86_64_elf_howto_table[r_type].name,
-                name, __FUNCTION__);
+                howto->name, name, __FUNCTION__);
              bfd_set_error (bfd_error_bad_value);
              return FALSE;
 
            case R_X86_64_32S:
-             if (info->shared)
+             if (bfd_link_pic (info))
                abort ();
              goto do_relocation;
 
@@ -3655,15 +4315,14 @@ elf_x86_64_relocate_section (bfd *output_bfd,
                  (*_bfd_error_handler)
                    (_("%B: relocation %s against STT_GNU_IFUNC "
                       "symbol `%s' has non-zero addend: %d"),
-                    input_bfd, x86_64_elf_howto_table[r_type].name,
-                    name, rel->r_addend);
+                    input_bfd, howto->name, name, rel->r_addend);
                  bfd_set_error (bfd_error_bad_value);
                  return FALSE;
                }
 
              /* 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;
@@ -3683,7 +4342,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);
@@ -3716,6 +4375,8 @@ elf_x86_64_relocate_section (bfd *output_bfd,
              goto do_relocation;
 
            case R_X86_64_GOTPCREL:
+           case R_X86_64_GOTPCRELX:
+           case R_X86_64_REX_GOTPCRELX:
            case R_X86_64_GOTPCREL64:
              base_got = htab->elf.sgot;
              off = h->got.offset;
@@ -3775,6 +4436,9 @@ elf_x86_64_relocate_section (bfd *output_bfd,
            }
        }
 
+      resolved_to_zero = (eh != NULL
+                         && UNDEFINED_WEAK_RESOLVED_TO_ZERO (info, eh));
+
       /* When generating a shared object, the relocations handled here are
         copied into the output file to be resolved at run time.  */
       switch (r_type)
@@ -3784,6 +4448,8 @@ elf_x86_64_relocate_section (bfd *output_bfd,
          /* Relocation is to the entry for this symbol in the global
             offset table.  */
        case R_X86_64_GOTPCREL:
+       case R_X86_64_GOTPCRELX:
+       case R_X86_64_REX_GOTPCRELX:
        case R_X86_64_GOTPCREL64:
          /* Use global offset table entry as symbol value.  */
        case R_X86_64_GOTPLT64:
@@ -3813,8 +4479,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))
@@ -3861,7 +4527,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;
@@ -3889,7 +4555,10 @@ elf_x86_64_relocate_section (bfd *output_bfd,
 
          relocation = base_got->output_section->vma
                       + base_got->output_offset + off;
-         if (r_type != R_X86_64_GOTPCREL && r_type != R_X86_64_GOTPCREL64)
+         if (r_type != R_X86_64_GOTPCREL
+             && r_type != R_X86_64_GOTPCRELX
+             && r_type != R_X86_64_REX_GOTPCRELX
+             && r_type != R_X86_64_GOTPCREL64)
            relocation -= htab->elf.sgotplt->output_section->vma
                          - htab->elf.sgotplt->output_offset;
 
@@ -3899,21 +4568,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
@@ -4018,10 +4718,17 @@ 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
-             && (input_section->flags & SEC_ALLOC) != 0
+         /* Don't complain about -fPIC if the symbol is undefined when
+            building executable unless it is unresolved weak symbol.  */
+          if ((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_undefweak
+                 && !resolved_to_zero)
+                 || (bfd_link_pic (info)
+                     && !(bfd_link_pie (info)
+                          && h->root.type == bfd_link_hash_undefined))))
            {
              bfd_boolean fail = FALSE;
              bfd_boolean branch
@@ -4035,48 +4742,18 @@ elf_x86_64_relocate_section (bfd *output_bfd,
                     defined locally or for a branch.  */
                  fail = !h->def_regular && !branch;
                }
-             else
+             else if (!(bfd_link_pie (info)
+                        && (h->needs_copy || eh->needs_copy)))
                {
-                 /* Symbol isn't referenced locally.  We only allow
-                    branch to symbol with non-default visibility. */
+                 /* Symbol doesn't need copy reloc and isn't referenced
+                    locally.  We only allow branch to symbol with
+                    non-default visibility. */
                  fail = (!branch
                          || ELF_ST_VISIBILITY (h->other) == STV_DEFAULT);
                }
 
              if (fail)
-               {
-                 const char *fmt;
-                 const char *v;
-                 const char *pic = "";
-
-                 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");
-                     pic = _("; recompile with -fPIC");
-                     break;
-                   }
-
-                 if (h->def_regular)
-                   fmt = _("%B: relocation %s against %s `%s' can not be used when making a shared object%s");
-                 else
-                   fmt = _("%B: relocation %s against undefined %s `%s' can not be used when making a shared object%s");
-
-                 (*_bfd_error_handler) (fmt, input_bfd,
-                                        x86_64_elf_howto_table[r_type].name,
-                                        v,  h->root.root.string, pic);
-                 bfd_set_error (bfd_error_bad_value);
-                 return FALSE;
-               }
+               return elf_x86_64_need_pic (input_bfd, h, howto);
            }
          /* Fall through.  */
 
@@ -4092,22 +4769,37 @@ direct:
          if ((input_section->flags & SEC_ALLOC) == 0)
            break;
 
-         if ((info->shared
+          /* Don't copy a pc-relative relocation into the output file
+             if the symbol needs copy reloc or the symbol is undefined
+             when building executable.  Copy dynamic function pointer
+             relocations.  Don't generate dynamic relocations against
+             resolved undefined weak symbols in PIE.  */
+         if ((bfd_link_pic (info)
+              && !(bfd_link_pie (info)
+                   && h != NULL
+                   && (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
-                  || h->root.type != bfd_link_hash_undefweak)
+                  || ((ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
+                       && !resolved_to_zero)
+                      || h->root.type != bfd_link_hash_undefweak))
               && ((! IS_X86_64_PCREL_TYPE (r_type)
                      && r_type != R_X86_64_SIZE32
                      && 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
-                 && ((h->def_dynamic
-                      && !h->def_regular)
-                     || h->root.type == bfd_link_hash_undefweak
+                 && (!h->non_got_ref
+                     || eh->func_pointer_refcount > 0
+                     || (h->root.type == bfd_link_hash_undefweak
+                         && !resolved_to_zero))
+                 && ((h->def_dynamic && !h->def_regular)
+                     /* Undefined weak symbol is bound locally when
+                        PIC is false.  */
                      || h->root.type == bfd_link_hash_undefined)))
            {
              Elf_Internal_Rela outrel;
@@ -4139,17 +4831,26 @@ direct:
              else if (h != NULL
                       && h->dynindx != -1
                       && (IS_X86_64_PCREL_TYPE (r_type)
-                          || ! info->shared
-                          || ! SYMBOLIC_BIND (info, h)
+                          || !(bfd_link_executable (info)
+                               || SYMBOLIC_BIND (info, h))
                           || ! h->def_regular))
                {
+                 if ((r_type != R_X86_64_PC64 && r_type != R_X86_64_64)
+                     && bfd_link_executable (info)
+                     && h->root.type == bfd_link_hash_undefweak
+                     && !resolved_to_zero)
+                   return elf_x86_64_need_pic (input_bfd, h, howto);
                  outrel.r_info = htab->r_info (h->dynindx, r_type);
                  outrel.r_addend = rel->r_addend;
                }
              else
                {
-                 /* This symbol is local, or marked to become local.  */
-                 if (r_type == htab->pointer_r_type)
+                 /* This symbol is local, or marked to become local.
+                    When relocation overflow check is disabled, we
+                    convert R_X86_64_32 to dynamic R_X86_64_RELATIVE.  */
+                 if (r_type == htab->pointer_r_type
+                     || (r_type == R_X86_64_32
+                         && info->no_reloc_overflow_check))
                    {
                      relocate = TRUE;
                      outrel.r_info = htab->r_info (0, R_X86_64_RELATIVE);
@@ -4179,16 +4880,16 @@ direct:
                                 "symbol `%s' at 0x%lx in section `%A' is "
                                 "out of range"),
                               input_bfd, input_section, addend,
-                              x86_64_elf_howto_table[r_type].name,
-                              name, (unsigned long) rel->r_offset);
+                              howto->name, name,
+                              (unsigned long) rel->r_offset);
                          else
                            (*_bfd_error_handler)
                              (_("%B: addend 0x%x in relocation %s against "
                                 "symbol `%s' at 0x%lx in section `%A' is "
                                 "out of range"),
                               input_bfd, input_section, addend,
-                              x86_64_elf_howto_table[r_type].name,
-                              name, (unsigned long) rel->r_offset);
+                              howto->name, name,
+                              (unsigned long) rel->r_offset);
                          bfd_set_error (bfd_error_bad_value);
                          return FALSE;
                        }
@@ -4316,6 +5017,7 @@ direct:
                              contents + roff + 8 + largepic);
                  /* Skip R_X86_64_PC32/R_X86_64_PLT32/R_X86_64_PLTOFF64.  */
                  rel++;
+                 wrel++;
                  continue;
                }
              else if (ELF32_R_TYPE (rel->r_info) == R_X86_64_GOTPC32_TLSDESC)
@@ -4598,6 +5300,7 @@ direct:
                              contents + roff + 8 + largepic);
                  /* Skip R_X86_64_PLT32/R_X86_64_PLTOFF64.  */
                  rel++;
+                 wrel++;
                  continue;
                }
              else if (ELF32_R_TYPE (rel->r_info) == R_X86_64_GOTPC32_TLSDESC)
@@ -4682,6 +5385,7 @@ direct:
                        "\x0f\x1f\x40\x00\x64\x8b\x04\x25\0\0\0", 12);
              /* Skip R_X86_64_PC32/R_X86_64_PLT32/R_X86_64_PLTOFF64.  */
              rel++;
+             wrel++;
              continue;
            }
 
@@ -4717,7 +5421,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);
@@ -4725,7 +5430,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;
 
@@ -4797,6 +5502,29 @@ check_relocation_error:
              return FALSE;
            }
        }
+
+      if (wrel != rel)
+       *wrel = *rel;
+    }
+
+  if (wrel != rel)
+    {
+      Elf_Internal_Shdr *rel_hdr;
+      size_t deleted = rel - wrel;
+
+      rel_hdr = _bfd_elf_single_rel_hdr (input_section->output_section);
+      rel_hdr->sh_size -= rel_hdr->sh_entsize * deleted;
+      if (rel_hdr->sh_size == 0)
+       {
+         /* It is too late to remove an empty reloc section.  Leave
+            one NONE reloc.
+            ??? What is wrong with an empty section???  */
+         rel_hdr->sh_size = rel_hdr->sh_entsize;
+         deleted -= 1;
+       }
+      rel_hdr = _bfd_elf_single_rel_hdr (input_section);
+      rel_hdr->sh_size -= rel_hdr->sh_entsize * deleted;
+      input_section->reloc_count -= deleted;
     }
 
   return TRUE;
@@ -4809,12 +5537,13 @@ static bfd_boolean
 elf_x86_64_finish_dynamic_symbol (bfd *output_bfd,
                                  struct bfd_link_info *info,
                                  struct elf_link_hash_entry *h,
-                                 Elf_Internal_Sym *sym ATTRIBUTE_UNUSED)
+                                 Elf_Internal_Sym *sym)
 {
   struct elf_x86_64_link_hash_table *htab;
   const struct elf_x86_64_backend_data *abed;
   bfd_boolean use_plt_bnd;
   struct elf_x86_64_link_hash_entry *eh;
+  bfd_boolean local_undefweak;
 
   htab = elf_x86_64_hash_table (info);
   if (htab == NULL)
@@ -4829,6 +5558,11 @@ elf_x86_64_finish_dynamic_symbol (bfd *output_bfd,
 
   eh = (struct elf_x86_64_link_hash_entry *) h;
 
+  /* We keep PLT/GOT entries without dynamic PLT/GOT relocations for
+     resolved undefined weak symbols in executable so that their
+     references have value 0 at run-time.  */
+  local_undefweak = UNDEFINED_WEAK_RESOLVED_TO_ZERO (info, eh);
+
   if (h->plt.offset != (bfd_vma) -1)
     {
       bfd_vma plt_index;
@@ -4858,7 +5592,8 @@ 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)
+          && !local_undefweak
+          && !((h->forced_local || bfd_link_executable (info))
                && h->def_regular
                && h->type == STT_GNU_IFUNC))
          || plt == NULL
@@ -4958,60 +5693,67 @@ elf_x86_64_finish_dynamic_symbol (bfd *output_bfd,
                  resolved_plt->contents + plt_offset + plt_got_offset);
 
       /* Fill in the entry in the global offset table, initially this
-        points to the second part of the PLT entry.  */
-      bfd_put_64 (output_bfd, (plt->output_section->vma
-                              + plt->output_offset
-                              + h->plt.offset + abed->plt_lazy_offset),
-                 gotplt->contents + got_offset);
-
-      /* Fill in the entry in the .rela.plt section.  */
-      rela.r_offset = (gotplt->output_section->vma
-                      + gotplt->output_offset
-                      + got_offset);
-      if (h->dynindx == -1
-         || ((info->executable
-              || ELF_ST_VISIBILITY (h->other) != STV_DEFAULT)
-             && h->def_regular
-             && h->type == STT_GNU_IFUNC))
-       {
-         /* If an STT_GNU_IFUNC symbol is locally defined, generate
-            R_X86_64_IRELATIVE instead of R_X86_64_JUMP_SLOT.  */
-         rela.r_info = htab->r_info (0, R_X86_64_IRELATIVE);
-         rela.r_addend = (h->root.u.def.value
-                          + h->root.u.def.section->output_section->vma
-                          + h->root.u.def.section->output_offset);
-         /* R_X86_64_IRELATIVE comes last.  */
-         plt_index = htab->next_irelative_index--;
-       }
-      else
+        points to the second part of the PLT entry.  Leave the entry
+        as zero for undefined weak symbol in PIE.  No PLT relocation
+        against undefined weak symbol in PIE.  */
+      if (!local_undefweak)
        {
-         rela.r_info = htab->r_info (h->dynindx, R_X86_64_JUMP_SLOT);
-         rela.r_addend = 0;
-         plt_index = htab->next_jump_slot_index++;
-       }
+         bfd_put_64 (output_bfd, (plt->output_section->vma
+                                  + plt->output_offset
+                                  + h->plt.offset
+                                  + abed->plt_lazy_offset),
+                     gotplt->contents + got_offset);
+
+         /* Fill in the entry in the .rela.plt section.  */
+         rela.r_offset = (gotplt->output_section->vma
+                          + gotplt->output_offset
+                          + got_offset);
+         if (h->dynindx == -1
+             || ((bfd_link_executable (info)
+                  || ELF_ST_VISIBILITY (h->other) != STV_DEFAULT)
+                 && h->def_regular
+                 && h->type == STT_GNU_IFUNC))
+           {
+             /* If an STT_GNU_IFUNC symbol is locally defined, generate
+                R_X86_64_IRELATIVE instead of R_X86_64_JUMP_SLOT.  */
+             rela.r_info = htab->r_info (0, R_X86_64_IRELATIVE);
+             rela.r_addend = (h->root.u.def.value
+                              + h->root.u.def.section->output_section->vma
+                              + h->root.u.def.section->output_offset);
+             /* R_X86_64_IRELATIVE comes last.  */
+             plt_index = htab->next_irelative_index--;
+           }
+         else
+           {
+             rela.r_info = htab->r_info (h->dynindx, R_X86_64_JUMP_SLOT);
+             rela.r_addend = 0;
+             plt_index = htab->next_jump_slot_index++;
+           }
 
-      /* Don't fill PLT entry for static executables.  */
-      if (plt == htab->elf.splt)
-       {
-         bfd_vma plt0_offset = h->plt.offset + plt_plt_insn_end;
-
-         /* Put relocation index.  */
-         bfd_put_32 (output_bfd, plt_index,
-                     plt->contents + h->plt.offset + abed->plt_reloc_offset);
-
-         /* Put offset for jmp .PLT0 and check for overflow.  We don't
-            check relocation index for overflow since branch displacement
-            will overflow first.  */
-         if (plt0_offset > 0x80000000)
-           info->callbacks->einfo (_("%F%B: branch displacement overflow in PLT entry for `%s'\n"),
-                                   output_bfd, h->root.root.string);
-         bfd_put_32 (output_bfd, - plt0_offset,
-                     plt->contents + h->plt.offset + plt_plt_offset);
-       }
+         /* Don't fill PLT entry for static executables.  */
+         if (plt == htab->elf.splt)
+           {
+             bfd_vma plt0_offset = h->plt.offset + plt_plt_insn_end;
+
+             /* Put relocation index.  */
+             bfd_put_32 (output_bfd, plt_index,
+                         (plt->contents + h->plt.offset
+                          + abed->plt_reloc_offset));
+
+             /* Put offset for jmp .PLT0 and check for overflow.  We don't
+                check relocation index for overflow since branch displacement
+                will overflow first.  */
+             if (plt0_offset > 0x80000000)
+               info->callbacks->einfo (_("%F%B: branch displacement overflow in PLT entry for `%s'\n"),
+                                       output_bfd, h->root.root.string);
+             bfd_put_32 (output_bfd, - plt0_offset,
+                         plt->contents + h->plt.offset + plt_plt_offset);
+           }
 
-      bed = get_elf_backend_data (output_bfd);
-      loc = relplt->contents + plt_index * bed->s->sizeof_rela;
-      bed->s->swap_reloca_out (output_bfd, &rela, loc);
+         bed = get_elf_backend_data (output_bfd);
+         loc = relplt->contents + plt_index * bed->s->sizeof_rela;
+         bed->s->swap_reloca_out (output_bfd, &rela, loc);
+       }
     }
   else if (eh->plt_got.offset != (bfd_vma) -1)
     {
@@ -5073,7 +5815,8 @@ elf_x86_64_finish_dynamic_symbol (bfd *output_bfd,
                  plt->contents + plt_offset + plt_got_offset);
     }
 
-  if (!h->def_regular
+  if (!local_undefweak
+      && !h->def_regular
       && (h->plt.offset != (bfd_vma) -1
          || eh->plt_got.offset != (bfd_vma) -1))
     {
@@ -5090,9 +5833,12 @@ elf_x86_64_finish_dynamic_symbol (bfd *output_bfd,
        sym->st_value = 0;
     }
 
+  /* Don't generate dynamic GOT relocation against undefined weak
+     symbol in executable.  */
   if (h->got.offset != (bfd_vma) -1
       && ! GOT_TLS_GD_ANY_P (elf_x86_64_hash_entry (h)->tls_type)
-      && elf_x86_64_hash_entry (h)->tls_type != GOT_TLS_IE)
+      && elf_x86_64_hash_entry (h)->tls_type != GOT_TLS_IE
+      && !local_undefweak)
     {
       Elf_Internal_Rela rela;
 
@@ -5113,7 +5859,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;
@@ -5136,7 +5882,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)
@@ -5198,14 +5944,54 @@ elf_x86_64_finish_local_dynamic_symbol (void **slot, void *inf)
                                             info, h, NULL);
 }
 
+/* Finish up undefined weak symbol handling in PIE.  Fill its PLT entry
+   here since undefined weak symbol may not be dynamic and may not be
+   called for elf_x86_64_finish_dynamic_symbol.  */
+
+static bfd_boolean
+elf_x86_64_pie_finish_undefweak_symbol (struct bfd_hash_entry *bh,
+                                       void *inf)
+{
+  struct elf_link_hash_entry *h = (struct elf_link_hash_entry *) bh;
+  struct bfd_link_info *info = (struct bfd_link_info *) inf;
+
+  if (h->root.type != bfd_link_hash_undefweak
+      || h->dynindx != -1)
+    return TRUE;
+
+  return elf_x86_64_finish_dynamic_symbol (info->output_bfd,
+                                            info, h, NULL);
+}
+
 /* Used to decide how to sort relocs in an optimal manner for the
    dynamic linker, before writing them out.  */
 
 static enum elf_reloc_type_class
-elf_x86_64_reloc_type_class (const struct bfd_link_info *info ATTRIBUTE_UNUSED,
+elf_x86_64_reloc_type_class (const struct bfd_link_info *info,
                             const asection *rel_sec ATTRIBUTE_UNUSED,
                             const Elf_Internal_Rela *rela)
 {
+  bfd *abfd = info->output_bfd;
+  const struct elf_backend_data *bed = get_elf_backend_data (abfd);
+  struct elf_x86_64_link_hash_table *htab = elf_x86_64_hash_table (info);
+
+  if (htab->elf.dynsym != NULL
+      && htab->elf.dynsym->contents != NULL)
+    {
+      /* Check relocation against STT_GNU_IFUNC symbol if there are
+         dynamic symbols.  */
+      unsigned long r_symndx = htab->r_sym (rela->r_info);
+      Elf_Internal_Sym sym;
+      if (!bed->s->swap_symbol_in (abfd,
+                                  (htab->elf.dynsym->contents
+                                   + r_symndx * bed->s->sizeof_sym),
+                                  0, &sym))
+       abort ();
+
+      if (ELF_ST_TYPE (sym.st_info) == STT_GNU_IFUNC)
+       return reloc_class_ifunc;
+    }
+
   switch ((int) ELF32_R_TYPE (rela->r_info))
     {
     case R_X86_64_RELATIVE:
@@ -5450,88 +6236,113 @@ elf_x86_64_finish_dynamic_sections (bfd *output_bfd,
                 elf_x86_64_finish_local_dynamic_symbol,
                 info);
 
+  /* Fill PLT entries for undefined weak symbols in PIE.  */
+  if (bfd_link_pie (info))
+    bfd_hash_traverse (&info->hash->table,
+                      elf_x86_64_pie_finish_undefweak_symbol,
+                      info);
+
   return TRUE;
 }
 
-/* Return address in section PLT for the Ith GOTPLT relocation, for
-   relocation REL or (bfd_vma) -1 if it should not be included.  */
+/* Return an array of PLT entry symbol values.  */
 
-static bfd_vma
-elf_x86_64_plt_sym_val (bfd_vma i, const asection *plt,
-                       const arelent *rel)
+static bfd_vma *
+elf_x86_64_get_plt_sym_val (bfd *abfd, asymbol **dynsyms, asection *plt,
+                           asection *relplt)
 {
-  bfd *abfd;
-  const struct elf_x86_64_backend_data *bed;
+  bfd_boolean (*slurp_relocs) (bfd *, asection *, asymbol **, bfd_boolean);
+  arelent *p;
+  long count, i;
+  bfd_vma *plt_sym_val;
   bfd_vma plt_offset;
+  bfd_byte *plt_contents;
+  const struct elf_x86_64_backend_data *bed;
+  Elf_Internal_Shdr *hdr;
+  asection *plt_bnd;
 
-  /* Only match R_X86_64_JUMP_SLOT and R_X86_64_IRELATIVE.  */
-  if (rel->howto->type != R_X86_64_JUMP_SLOT
-      && rel->howto->type != R_X86_64_IRELATIVE)
-    return (bfd_vma) -1;
-
-  abfd = plt->owner;
-  bed = get_elf_x86_64_backend_data (abfd);
-  plt_offset = bed->plt_entry_size;
-
-  if (elf_elfheader (abfd)->e_ident[EI_OSABI] != ELFOSABI_GNU)
-    return plt->vma + (i + 1) * plt_offset;
+  /* Get the .plt section contents.  PLT passed down may point to the
+     .plt.bnd section.  Make sure that PLT always points to the .plt
+     section.  */
+  plt_bnd = bfd_get_section_by_name (abfd, ".plt.bnd");
+  if (plt_bnd)
+    {
+      if (plt != plt_bnd)
+       abort ();
+      plt = bfd_get_section_by_name (abfd, ".plt");
+      if (plt == NULL)
+       abort ();
+      bed = &elf_x86_64_bnd_arch_bed;
+    }
+  else
+    bed = get_elf_x86_64_backend_data (abfd);
 
-  while (plt_offset < plt->size)
+  plt_contents = (bfd_byte *) bfd_malloc (plt->size);
+  if (plt_contents == NULL)
+    return NULL;
+  if (!bfd_get_section_contents (abfd, (asection *) plt,
+                                plt_contents, 0, plt->size))
     {
-      bfd_vma reloc_index;
-      bfd_byte reloc_index_raw[4];
-
-      if (!bfd_get_section_contents (abfd, (asection *) plt,
-                                    reloc_index_raw,
-                                    plt_offset + bed->plt_reloc_offset,
-                                    sizeof (reloc_index_raw)))
-       return (bfd_vma) -1;
-
-      reloc_index = H_GET_32 (abfd, reloc_index_raw);
-      if (reloc_index == i)
-       return plt->vma + plt_offset;
-      plt_offset += bed->plt_entry_size;
+bad_return:
+      free (plt_contents);
+      return NULL;
     }
 
-  abort ();
-}
+  slurp_relocs = get_elf_backend_data (abfd)->s->slurp_reloc_table;
+  if (! (*slurp_relocs) (abfd, relplt, dynsyms, TRUE))
+    goto bad_return;
 
-/* Return offset in .plt.bnd section for the Ith GOTPLT relocation with
-   PLT section, or (bfd_vma) -1 if it should not be included.  */
+  hdr = &elf_section_data (relplt)->this_hdr;
+  count = relplt->size / hdr->sh_entsize;
 
-static bfd_vma
-elf_x86_64_plt_sym_val_offset_plt_bnd (bfd_vma i, const asection *plt)
-{
-  const struct elf_x86_64_backend_data *bed = &elf_x86_64_bnd_arch_bed;
-  bfd *abfd = plt->owner;
-  bfd_vma plt_offset = bed->plt_entry_size;
+  plt_sym_val = (bfd_vma *) bfd_malloc (sizeof (bfd_vma) * count);
+  if (plt_sym_val == NULL)
+    goto bad_return;
 
-  if (elf_elfheader (abfd)->e_ident[EI_OSABI] != ELFOSABI_GNU)
-    return i * sizeof (elf_x86_64_legacy_plt2_entry);
+  for (i = 0; i < count; i++)
+    plt_sym_val[i] = -1;
 
-  while (plt_offset < plt->size)
+  plt_offset = bed->plt_entry_size;
+  p = relplt->relocation;
+  for (i = 0; i < count; i++, p++)
     {
-      bfd_vma reloc_index;
-      bfd_byte reloc_index_raw[4];
+      long reloc_index;
 
-      if (!bfd_get_section_contents (abfd, (asection *) plt,
-                                    reloc_index_raw,
-                                    plt_offset + bed->plt_reloc_offset,
-                                    sizeof (reloc_index_raw)))
-       return (bfd_vma) -1;
+      /* Skip unknown relocation.  */
+      if (p->howto == NULL)
+       continue;
 
-      reloc_index = H_GET_32 (abfd, reloc_index_raw);
-      if (reloc_index == i)
+      if (p->howto->type != R_X86_64_JUMP_SLOT
+         && p->howto->type != R_X86_64_IRELATIVE)
+       continue;
+
+      reloc_index = H_GET_32 (abfd, (plt_contents + plt_offset
+                                    + bed->plt_reloc_offset));
+      if (reloc_index < count)
        {
-         /* This is the index in .plt section.  */
-         long plt_index = plt_offset / bed->plt_entry_size;
-         /* Return the offset in .plt.bnd section.  */
-         return (plt_index - 1) * sizeof (elf_x86_64_legacy_plt2_entry);
+         if (plt_bnd)
+           {
+             /* This is the index in .plt section.  */
+             long plt_index = plt_offset / bed->plt_entry_size;
+             /* Store VMA + the offset in .plt.bnd section.  */
+             plt_sym_val[reloc_index] =
+               (plt_bnd->vma
+                + (plt_index - 1) * sizeof (elf_x86_64_legacy_plt2_entry));
+           }
+         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;
     }
 
-  abort ();
+  free (plt_contents);
+
+  return plt_sym_val;
 }
 
 /* Similar to _bfd_elf_get_synthetic_symtab, with .plt.bnd section
@@ -5545,108 +6356,15 @@ elf_x86_64_get_synthetic_symtab (bfd *abfd,
                                 asymbol **dynsyms,
                                 asymbol **ret)
 {
-  const struct elf_backend_data *bed = get_elf_backend_data (abfd);
-  asection *relplt;
-  asymbol *s;
-  bfd_boolean (*slurp_relocs) (bfd *, asection *, asymbol **, bfd_boolean);
-  arelent *p;
-  long count, i, n;
-  size_t size;
-  Elf_Internal_Shdr *hdr;
-  char *names;
-  asection *plt, *plt_push;
-
-  plt_push = bfd_get_section_by_name (abfd, ".plt");
-  if (plt_push == NULL)
-    return 0;
-
-  plt = bfd_get_section_by_name (abfd, ".plt.bnd");
-  /* Use the generic ELF version if there is no .plt.bnd section.  */
+  /* Pass the .plt.bnd section to _bfd_elf_ifunc_get_synthetic_symtab
+     as PLT if it exists.  */
+  asection *plt = bfd_get_section_by_name (abfd, ".plt.bnd");
   if (plt == NULL)
-    return _bfd_elf_get_synthetic_symtab (abfd, symcount, syms,
-                                         dynsymcount, dynsyms, ret);
-
-  *ret = NULL;
-
-  if ((abfd->flags & (DYNAMIC | EXEC_P)) == 0)
-    return 0;
-
-  if (dynsymcount <= 0)
-    return 0;
-
-  relplt = bfd_get_section_by_name (abfd, ".rela.plt");
-  if (relplt == NULL)
-    return 0;
-
-  hdr = &elf_section_data (relplt)->this_hdr;
-  if (hdr->sh_link != elf_dynsymtab (abfd)
-      || (hdr->sh_type != SHT_REL && hdr->sh_type != SHT_RELA))
-    return 0;
-
-  slurp_relocs = get_elf_backend_data (abfd)->s->slurp_reloc_table;
-  if (! (*slurp_relocs) (abfd, relplt, dynsyms, TRUE))
-    return -1;
-
-  count = relplt->size / hdr->sh_entsize;
-  size = count * sizeof (asymbol);
-  p = relplt->relocation;
-  for (i = 0; i < count; i++, p += bed->s->int_rels_per_ext_rel)
-    {
-      size += strlen ((*p->sym_ptr_ptr)->name) + sizeof ("@plt");
-      if (p->addend != 0)
-       size += sizeof ("+0x") - 1 + 8 + 8;
-    }
-
-  s = *ret = (asymbol *) bfd_malloc (size);
-  if (s == NULL)
-    return -1;
-
-  names = (char *) (s + count);
-  p = relplt->relocation;
-  n = 0;
-  for (i = 0; i < count; i++, p++)
-    {
-      bfd_vma offset;
-      size_t len;
-
-      if (p->howto->type != R_X86_64_JUMP_SLOT
-         && p->howto->type != R_X86_64_IRELATIVE)
-       continue;
-
-      offset = elf_x86_64_plt_sym_val_offset_plt_bnd (i, plt_push);
-
-      *s = **p->sym_ptr_ptr;
-      /* Undefined syms won't have BSF_LOCAL or BSF_GLOBAL set.  Since
-        we are defining a symbol, ensure one of them is set.  */
-      if ((s->flags & BSF_LOCAL) == 0)
-       s->flags |= BSF_GLOBAL;
-      s->flags |= BSF_SYNTHETIC;
-      s->section = plt;
-      s->value = offset;
-      s->name = names;
-      s->udata.p = NULL;
-      len = strlen ((*p->sym_ptr_ptr)->name);
-      memcpy (names, (*p->sym_ptr_ptr)->name, len);
-      names += len;
-      if (p->addend != 0)
-       {
-         char buf[30], *a;
-
-         memcpy (names, "+0x", sizeof ("+0x") - 1);
-         names += sizeof ("+0x") - 1;
-         bfd_sprintf_vma (abfd, buf, p->addend);
-         for (a = buf; *a == '0'; ++a)
-           ;
-         len = strlen (a);
-         memcpy (names, a, len);
-         names += len;
-       }
-      memcpy (names, "@plt", sizeof ("@plt"));
-      names += sizeof ("@plt");
-      ++s, ++n;
-    }
-
-  return n;
+    plt = bfd_get_section_by_name (abfd, ".plt");
+  return _bfd_elf_ifunc_get_synthetic_symtab (abfd, symcount, syms,
+                                             dynsymcount, dynsyms, ret,
+                                             plt,
+                                             elf_x86_64_get_plt_sym_val);
 }
 
 /* Handle an x86-64 specific section when reading an object file.  This
@@ -5700,11 +6418,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;
 }
@@ -5877,6 +6595,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
 
@@ -5905,7 +6624,6 @@ static const struct bfd_elf_special_section
 #define elf_backend_size_dynamic_sections   elf_x86_64_size_dynamic_sections
 #define elf_backend_always_size_sections    elf_x86_64_always_size_sections
 #define elf_backend_init_index_section     _bfd_elf_init_1_index_section
-#define elf_backend_plt_sym_val                    elf_x86_64_plt_sym_val
 #define elf_backend_object_p               elf64_x86_64_elf_object_p
 #define bfd_elf64_mkobject                 elf_x86_64_mkobject
 #define bfd_elf64_get_synthetic_symtab     elf_x86_64_get_synthetic_symtab
@@ -5933,6 +6651,25 @@ static const struct bfd_elf_special_section
   elf_x86_64_additional_program_headers
 #define elf_backend_hash_symbol \
   elf_x86_64_hash_symbol
+#define elf_backend_omit_section_dynsym \
+  ((bfd_boolean (*) (bfd *, struct bfd_link_info *, asection *)) bfd_true)
+#define elf_backend_fixup_symbol \
+  elf_x86_64_fixup_symbol
+
+#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"
 
@@ -5979,8 +6716,6 @@ static const struct bfd_elf_special_section
 
 #include "elf64-target.h"
 
-#undef bfd_elf64_get_synthetic_symtab
-
 /* Native Client support.  */
 
 static bfd_boolean
@@ -6159,6 +6894,8 @@ elf32_x86_64_nacl_elf_object_p (bfd *abfd)
   elf_x86_64_reloc_name_lookup
 #define bfd_elf32_mkobject \
   elf_x86_64_mkobject
+#define bfd_elf32_get_synthetic_symtab \
+  elf_x86_64_get_synthetic_symtab
 
 #undef elf_backend_object_p
 #define elf_backend_object_p \