+2014-11-25  H.J. Lu  <hongjiu.lu@intel.com>
+
+       * elf32-i386.c (elf_i386_got_plt_entry): New.
+       (elf_i386_pic_got_plt_entry): Likewise.
+       (elf_i386_link_hash_entry): Add plt_got.
+       (elf_i386_link_hash_table): Likewise.
+       (elf_i386_link_hash_newfunc): Initialize plt_got.offset to -1.
+       (elf_i386_get_local_sym_hash): Likewise.
+       (elf_i386_check_relocs): Create the GOT PLT if there are both
+       PLT and GOT references when the regular PLT is used.
+       (elf_i386_allocate_dynrelocs): Use the GOT PLT if there are
+       both PLT and GOT references unless pointer equality is needed.
+       (elf_i386_relocate_section): Also check the GOT PLT when
+       resolving R_386_PLT32.
+       (elf_i386_finish_dynamic_symbol): Use the GOT PLT if it is
+       available.
+
+       * elf64-x86-64.c (elf_x86_64_link_hash_entry): Add plt_got.
+       (elf_x86_64_link_hash_table): Likewise.
+       (elf_x86_64_link_hash_newfunc): Initialize plt_got.offset to -1.
+       (elf_x86_64_get_local_sym_hash): Likewise.
+       (elf_x86_64_check_relocs): Create the GOT PLT if there are both
+       PLT and GOT references when the regular PLT is used.
+       (elf_x86_64_allocate_dynrelocs): Use the GOT PLT if there are
+       both PLT and GOT references unless pointer equality is needed.
+       (elf_x86_64_relocate_section): Also check the GOT PLT when
+       resolving R_X86_64_PLT32.
+       (elf_x86_64_finish_dynamic_symbol): Use the GOT PLT if it is
+       available.
+
 2014-11-24  H.J. Lu  <hongjiu.lu@intel.com>
 
        * configure: Regenerated.
 
   0, 0, 0, 0   /* replaced with offset to start of .plt.  */
 };
 
+/* Entries in the GOT procedure linkage table look like this.  */
+
+static const bfd_byte elf_i386_got_plt_entry[8] =
+{
+  0xff, 0x25,  /* jmp indirect */
+  0, 0, 0, 0,  /* replaced with offset of this symbol in .got.  */
+  0x66, 0x90   /* xchg %ax,%ax  */
+};
+
+/* Entries in the PIC GOT procedure linkage table look like this.  */
+
+static const bfd_byte elf_i386_pic_got_plt_entry[8] =
+{
+  0xff, 0xa3,  /* jmp *offset(%ebx)  */
+  0, 0, 0, 0,  /* replaced with offset of this symbol in .got.  */
+  0x66, 0x90   /* xchg %ax,%ax  */
+};
+
 /* .eh_frame covering the .plt section.  */
 
 static const bfd_byte elf_i386_eh_frame_plt[] =
   (GOT_TLS_GD_P (type) || GOT_TLS_GDESC_P (type))
   unsigned char tls_type;
 
+  /* Information about the GOT PLT entry. Filled when there are both
+     GOT and PLT relocations against the same function.  */
+  union gotplt_union plt_got;
+
   /* Offset of the GOTPLT entry reserved for the TLS descriptor,
      starting at the end of the jump table.  */
   bfd_vma tlsdesc_got;
   asection *sdynbss;
   asection *srelbss;
   asection *plt_eh_frame;
+  asection *plt_got;
 
   union
   {
       eh = (struct elf_i386_link_hash_entry *) entry;
       eh->dyn_relocs = NULL;
       eh->tls_type = GOT_UNKNOWN;
+      eh->plt_got.offset = (bfd_vma) -1;
       eh->tlsdesc_got = (bfd_vma) -1;
     }
 
       ret->elf.indx = sec->id;
       ret->elf.dynstr_index = ELF32_R_SYM (rel->r_info);
       ret->elf.dynindx = -1;
+      ret->plt_got.offset = (bfd_vma) -1;
       *slot = ret;
     }
   return &ret->elf;
   const Elf_Internal_Rela *rel;
   const Elf_Internal_Rela *rel_end;
   asection *sreloc;
+  bfd_boolean use_plt_got;
 
   if (info->relocatable)
     return TRUE;
   if (htab == NULL)
     return FALSE;
 
+  use_plt_got = (!get_elf_i386_backend_data (abfd)->is_vxworks
+                && (get_elf_i386_backend_data (abfd)
+                    == &elf_i386_arch_bed));
+
   symtab_hdr = &elf_symtab_hdr (abfd);
   sym_hashes = elf_sym_hashes (abfd);
 
        default:
          break;
        }
+
+      if (use_plt_got
+         && h != NULL
+         && h->plt.refcount > 0
+         && h->got.refcount > 0
+         && htab->plt_got == NULL)
+       {
+         /* Create the GOT procedure linkage table.  */
+         unsigned int plt_got_align;
+         const struct elf_backend_data *bed;
+
+         bed = get_elf_backend_data (info->output_bfd);
+         BFD_ASSERT (sizeof (elf_i386_got_plt_entry) == 8
+                     && (sizeof (elf_i386_got_plt_entry)
+                         == sizeof (elf_i386_pic_got_plt_entry)));
+         plt_got_align = 3;
+
+         if (htab->elf.dynobj == NULL)
+           htab->elf.dynobj = abfd;
+         htab->plt_got
+           = bfd_make_section_anyway_with_flags (htab->elf.dynobj,
+                                                 ".plt.got",
+                                                 (bed->dynamic_sec_flags
+                                                  | SEC_ALLOC
+                                                  | SEC_CODE
+                                                  | SEC_LOAD
+                                                  | SEC_READONLY));
+         if (htab->plt_got == NULL
+             || !bfd_set_section_alignment (htab->elf.dynobj,
+                                            htab->plt_got,
+                                            plt_got_align))
+           return FALSE;
+       }
     }
 
   return TRUE;
 
   plt_entry_size = GET_PLT_ENTRY_SIZE (info->output_bfd);
 
+  /* 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
+     loop at run-time.  */
+  if (htab->plt_got != NULL
+      && h->type != STT_GNU_IFUNC
+      && !h->pointer_equality_needed
+      && h->plt.refcount > 0
+      && h->got.refcount > 0)
+    {
+      /* Don't use the regular PLT if there are both GOT and GOTPLT
+         reloctions.  */
+      h->plt.offset = (bfd_vma) -1;
+
+      /* Use the GOT PLT.  */
+      eh->plt_got.refcount = 1;
+    }
+
   /* 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
                                                plt_entry_size,
                                               plt_entry_size, 4);
   else if (htab->elf.dynamic_sections_created
-          && h->plt.refcount > 0)
+          && (h->plt.refcount > 0 || eh->plt_got.refcount > 0))
     {
+      bfd_boolean 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
          || WILL_CALL_FINISH_DYNAMIC_SYMBOL (1, 0, h))
        {
          asection *s = htab->elf.splt;
+         asection *got_s = htab->plt_got;
 
          /* If this is the first .plt entry, make room for the special
             first entry.  */
          if (s->size == 0)
            s->size = plt_entry_size;
 
-         h->plt.offset = s->size;
+         if (use_plt_got)
+           eh->plt_got.offset = got_s->size;
+         else
+           h->plt.offset = s->size;
 
          /* If this symbol is not defined in a regular file, and we are
             not generating a shared library, then set the symbol to this
          if (! info->shared
              && !h->def_regular)
            {
-             h->root.u.def.section = s;
-             h->root.u.def.value = h->plt.offset;
+             if (use_plt_got)
+               {
+                 /* We need to make a call to the entry of the GOT PLT
+                    instead of regular PLT entry.  */
+                 h->root.u.def.section = got_s;
+                 h->root.u.def.value = eh->plt_got.offset;
+               }
+             else
+               {
+                 h->root.u.def.section = s;
+                 h->root.u.def.value = h->plt.offset;
+               }
            }
 
          /* Make room for this entry.  */
-         s->size += plt_entry_size;
+         if (use_plt_got)
+           got_s->size += sizeof (elf_i386_got_plt_entry);
+         else
+           {
+             s->size += plt_entry_size;
 
-         /* We also need to make an entry in the .got.plt section, which
-            will be placed in the .got section by the linker script.  */
-         htab->elf.sgotplt->size += 4;
+             /* We also need to make an entry in the .got.plt section,
+                which will be placed in the .got section by the linker
+                script.  */
+             htab->elf.sgotplt->size += 4;
 
-         /* We also need to make an entry in the .rel.plt section.  */
-         htab->elf.srelplt->size += sizeof (Elf32_External_Rel);
-         htab->elf.srelplt->reloc_count++;
+             /* We also need to make an entry in the .rel.plt section.  */
+             htab->elf.srelplt->size += sizeof (Elf32_External_Rel);
+             htab->elf.srelplt->reloc_count++;
+           }
 
          if (get_elf_i386_backend_data (info->output_bfd)->is_vxworks
               && !info->shared)
       else if (s == htab->elf.sgotplt
               || s == htab->elf.iplt
               || s == htab->elf.igotplt
+              || s == htab->plt_got
               || s == htab->plt_eh_frame
               || s == htab->sdynbss)
        {
       reloc_howto_type *howto;
       unsigned long r_symndx;
       struct elf_link_hash_entry *h;
+      struct elf_i386_link_hash_entry *eh;
       Elf_Internal_Sym *sym;
       asection *sec;
-      bfd_vma off, offplt;
+      bfd_vma off, offplt, plt_offset;
       bfd_vma relocation;
       bfd_boolean unresolved_reloc;
       bfd_reloc_status_type r;
       unsigned int indx;
       int tls_type;
       bfd_vma st_size;
+      asection *resolved_plt;
 
       r_type = ELF32_R_TYPE (rel->r_info);
       if (r_type == R_386_GNU_VTINHERIT
          if (h == NULL)
            break;
 
-         if (h->plt.offset == (bfd_vma) -1
+         eh = (struct elf_i386_link_hash_entry *) h;
+         if ((h->plt.offset == (bfd_vma) -1
+              && eh->plt_got.offset == (bfd_vma) -1)
              || htab->elf.splt == NULL)
            {
              /* We didn't make a PLT entry for this symbol.  This
              break;
            }
 
-         relocation = (htab->elf.splt->output_section->vma
-                       + htab->elf.splt->output_offset
-                       + h->plt.offset);
+         if (h->plt.offset != (bfd_vma) -1)
+           {
+             resolved_plt = htab->elf.splt;
+             plt_offset = h->plt.offset;
+           }
+         else
+           {
+             resolved_plt = htab->plt_got;
+             plt_offset = eh->plt_got.offset;
+           }
+
+         relocation = (resolved_plt->output_section->vma
+                       + resolved_plt->output_offset
+                       + plt_offset);
          unresolved_reloc = FALSE;
          break;
 
   struct elf_i386_link_hash_table *htab;
   unsigned plt_entry_size;
   const struct elf_i386_backend_data *abed;
+  struct elf_i386_link_hash_entry *eh;
 
   htab = elf_i386_hash_table (info);
   if (htab == NULL)
   abed = get_elf_i386_backend_data (output_bfd);
   plt_entry_size = GET_PLT_ENTRY_SIZE (output_bfd);
 
+  eh = (struct elf_i386_link_hash_entry *) h;
+
   if (h->plt.offset != (bfd_vma) -1)
     {
       bfd_vma plt_index;
                      plt->contents + h->plt.offset
                       + abed->plt->plt_plt_offset);
        }
+    }
+  else if (eh->plt_got.offset != (bfd_vma) -1)
+    {
+      bfd_vma got_offset, plt_offset;
+      asection *plt, *got, *gotplt;
+      const bfd_byte *got_plt_entry;
+
+      /* Offset of displacement of the indirect jump.  */
+      bfd_vma plt_got_offset = 2;
 
-      if (!h->def_regular)
+      /* Set the entry in the GOT procedure linkage table.  */
+      plt = htab->plt_got;
+      got = htab->elf.sgot;
+      gotplt = htab->elf.sgotplt;
+      got_offset = h->got.offset;
+
+      if (got_offset == (bfd_vma) -1
+         || plt == NULL
+         || got == NULL
+         || gotplt == NULL)
+       abort ();
+
+      /* Fill in the entry in the GOT procedure linkage table.  */
+      if (! info->shared)
        {
-         /* Mark the symbol as undefined, rather than as defined in
-            the .plt section.  Leave the value if there were any
-            relocations where pointer equality matters (this is a clue
-            for the dynamic linker, to make function pointer
-            comparisons work between an application and shared
-            library), otherwise set it to zero.  If a function is only
-            called from a binary, there is no need to slow down
-            shared libraries because of that.  */
-         sym->st_shndx = SHN_UNDEF;
-         if (!h->pointer_equality_needed)
-           sym->st_value = 0;
+         got_plt_entry = elf_i386_got_plt_entry;
+         got_offset += got->output_section->vma + got->output_offset;
        }
+      else
+       {
+         got_plt_entry = elf_i386_pic_got_plt_entry;
+         got_offset += (got->output_section->vma
+                        + got->output_offset
+                        - gotplt->output_section->vma
+                        - gotplt->output_offset);
+       }
+
+      plt_offset = eh->plt_got.offset;
+      memcpy (plt->contents + plt_offset, got_plt_entry,
+             sizeof (elf_i386_got_plt_entry));
+      bfd_put_32 (output_bfd, got_offset,
+                 plt->contents + plt_offset + plt_got_offset);
+    }
+
+  if (!h->def_regular
+      && (h->plt.offset != (bfd_vma) -1
+         || eh->plt_got.offset != (bfd_vma) -1))
+    {
+      /* Mark the symbol as undefined, rather than as defined in
+        the .plt section.  Leave the value if there were any
+        relocations where pointer equality matters (this is a clue
+        for the dynamic linker, to make function pointer
+        comparisons work between an application and shared
+        library), otherwise set it to zero.  If a function is only
+        called from a binary, there is no need to slow down
+        shared libraries because of that.  */
+      sym->st_shndx = SHN_UNDEF;
+      if (!h->pointer_equality_needed)
+       sym->st_value = 0;
     }
 
   if (h->got.offset != (bfd_vma) -1
 
   /* TRUE if symbol has at least one BND relocation.  */
   bfd_boolean has_bnd_reloc;
 
+  /* Information about the GOT PLT entry. Filled when there are both
+     GOT and PLT relocations against the same function.  */
+  union gotplt_union plt_got;
+
   /* Information about the second PLT entry. Filled when has_bnd_reloc is
      set.  */
   union gotplt_union plt_bnd;
   asection *srelbss;
   asection *plt_eh_frame;
   asection *plt_bnd;
+  asection *plt_got;
 
   union
   {
       eh->tls_type = GOT_UNKNOWN;
       eh->has_bnd_reloc = FALSE;
       eh->plt_bnd.offset = (bfd_vma) -1;
+      eh->plt_got.offset = (bfd_vma) -1;
       eh->tlsdesc_got = (bfd_vma) -1;
     }
 
       ret->elf.indx = sec->id;
       ret->elf.dynstr_index = htab->r_sym (rel->r_info);
       ret->elf.dynindx = -1;
+      ret->plt_got.offset = (bfd_vma) -1;
       *slot = ret;
     }
   return &ret->elf;
   const Elf_Internal_Rela *rel;
   const Elf_Internal_Rela *rel_end;
   asection *sreloc;
+  bfd_boolean use_plt_got;
 
   if (info->relocatable)
     return TRUE;
   if (htab == NULL)
     return FALSE;
 
+  use_plt_got = get_elf_x86_64_backend_data (abfd) == &elf_x86_64_arch_bed;
+
   symtab_hdr = &elf_symtab_hdr (abfd);
   sym_hashes = elf_sym_hashes (abfd);
 
        default:
          break;
        }
+
+      if (use_plt_got
+         && h != NULL
+         && h->plt.refcount > 0
+         && h->got.refcount > 0
+         && htab->plt_got == NULL)
+       {
+         /* Create the GOT procedure linkage table.  */
+         unsigned int plt_got_align;
+         const struct elf_backend_data *bed;
+
+         bed = get_elf_backend_data (info->output_bfd);
+         BFD_ASSERT (sizeof (elf_x86_64_legacy_plt2_entry) == 8
+                     && (sizeof (elf_x86_64_bnd_plt2_entry)
+                         == sizeof (elf_x86_64_legacy_plt2_entry)));
+         plt_got_align = 3;
+
+         if (htab->elf.dynobj == NULL)
+           htab->elf.dynobj = abfd;
+         htab->plt_got
+           = bfd_make_section_anyway_with_flags (htab->elf.dynobj,
+                                                 ".plt.got",
+                                                 (bed->dynamic_sec_flags
+                                                  | SEC_ALLOC
+                                                  | SEC_CODE
+                                                  | SEC_LOAD
+                                                  | SEC_READONLY));
+         if (htab->plt_got == NULL
+             || !bfd_set_section_alignment (htab->elf.dynobj,
+                                            htab->plt_got,
+                                            plt_got_align))
+           return FALSE;
+       }
     }
 
   return TRUE;
   bed = get_elf_backend_data (info->output_bfd);
   plt_entry_size = GET_PLT_ENTRY_SIZE (info->output_bfd);
 
+  /* 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
+     loop at run-time.  */
+  if (htab->plt_got != NULL
+      && h->type != STT_GNU_IFUNC
+      && !h->pointer_equality_needed
+      && h->plt.refcount > 0
+      && h->got.refcount > 0)
+    {
+      /* Don't use the regular PLT if there are both GOT and GOTPLT
+         reloctions.  */
+      h->plt.offset = (bfd_vma) -1;
+
+      /* Use the GOT PLT.  */
+      eh->plt_got.refcount = 1;
+    }
+
   /* 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
        return FALSE;
     }
   else if (htab->elf.dynamic_sections_created
-          && h->plt.refcount > 0)
+          && (h->plt.refcount > 0 || eh->plt_got.refcount > 0))
     {
+      bfd_boolean 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
        {
          asection *s = htab->elf.splt;
          asection *bnd_s = htab->plt_bnd;
+         asection *got_s = htab->plt_got;
 
          /* If this is the first .plt entry, make room for the special
             first entry.  */
          if (s->size == 0)
            s->size = plt_entry_size;
 
-         h->plt.offset = s->size;
-         if (bnd_s)
-           eh->plt_bnd.offset = bnd_s->size;
+         if (use_plt_got)
+           eh->plt_got.offset = got_s->size;
+         else
+           {
+             h->plt.offset = s->size;
+             if (bnd_s)
+               eh->plt_bnd.offset = bnd_s->size;
+           }
 
          /* If this symbol is not defined in a regular file, and we are
             not generating a shared library, then set the symbol to this
          if (! info->shared
              && !h->def_regular)
            {
-             if (bnd_s)
+             if (use_plt_got)
                {
-                 /* We need to make a call to the entry of the second
-                    PLT instead of regular PLT entry.  */
-                 h->root.u.def.section = bnd_s;
-                 h->root.u.def.value = eh->plt_bnd.offset;
+                 /* We need to make a call to the entry of the GOT PLT
+                    instead of regular PLT entry.  */
+                 h->root.u.def.section = got_s;
+                 h->root.u.def.value = eh->plt_got.offset;
                }
              else
                {
-                 h->root.u.def.section = s;
-                 h->root.u.def.value = h->plt.offset;
+                 if (bnd_s)
+                   {
+                     /* We need to make a call to the entry of the second
+                        PLT instead of regular PLT entry.  */
+                     h->root.u.def.section = bnd_s;
+                     h->root.u.def.value = eh->plt_bnd.offset;
+                   }
+                 else
+                   {
+                     h->root.u.def.section = s;
+                     h->root.u.def.value = h->plt.offset;
+                   }
                }
            }
 
          /* Make room for this entry.  */
-         s->size += plt_entry_size;
-         if (bnd_s)
-           bnd_s->size += sizeof (elf_x86_64_legacy_plt2_entry);
+         if (use_plt_got)
+           got_s->size += sizeof (elf_x86_64_legacy_plt2_entry);
+         else
+           {
+             s->size += plt_entry_size;
+             if (bnd_s)
+               bnd_s->size += sizeof (elf_x86_64_legacy_plt2_entry);
 
-         /* We also need to make an entry in the .got.plt section, which
-            will be placed in the .got section by the linker script.  */
-         htab->elf.sgotplt->size += GOT_ENTRY_SIZE;
+             /* We also need to make an entry in the .got.plt section,
+                which will be placed in the .got section by the linker
+                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++;
+             /* 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
        {
          || s == htab->elf.iplt
          || s == htab->elf.igotplt
          || s == htab->plt_bnd
+         || s == htab->plt_got
          || s == htab->plt_eh_frame
          || s == htab->sdynbss)
        {
          if (h == NULL)
            break;
 
-         if (h->plt.offset == (bfd_vma) -1
+         if ((h->plt.offset == (bfd_vma) -1
+              && eh->plt_got.offset == (bfd_vma) -1)
              || htab->elf.splt == NULL)
            {
              /* We didn't make a PLT entry for this symbol.  This
              break;
            }
 
-         if (htab->plt_bnd != NULL)
+         if (h->plt.offset != (bfd_vma) -1)
            {
-             resolved_plt = htab->plt_bnd;
-             plt_offset = eh->plt_bnd.offset;
+             if (htab->plt_bnd != NULL)
+               {
+                 resolved_plt = htab->plt_bnd;
+                 plt_offset = eh->plt_bnd.offset;
+               }
+             else
+               {
+                 resolved_plt = htab->elf.splt;
+                 plt_offset = h->plt.offset;
+               }
            }
          else
            {
-             resolved_plt = htab->elf.splt;
-             plt_offset = h->plt.offset;
+             /* Use the GOT PLT.  */
+             resolved_plt = htab->plt_got;
+             plt_offset = eh->plt_got.offset;
            }
 
          relocation = (resolved_plt->output_section->vma
   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;
 
   htab = elf_x86_64_hash_table (info);
   if (htab == NULL)
          ? &elf_x86_64_bnd_arch_bed
          : get_elf_x86_64_backend_data (output_bfd));
 
+  eh = (struct elf_x86_64_link_hash_entry *) h;
+
   if (h->plt.offset != (bfd_vma) -1)
     {
       bfd_vma plt_index;
        {
          /* Use the second PLT with BND relocations.  */
          const bfd_byte *plt_entry, *plt2_entry;
-         struct elf_x86_64_link_hash_entry *eh
-           = (struct elf_x86_64_link_hash_entry *) h;
 
          if (eh->has_bnd_reloc)
            {
       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)
+    {
+      bfd_vma got_offset, plt_offset, plt_got_offset, plt_got_insn_size;
+      asection *plt, *got;
+      bfd_boolean got_after_plt;
+      int32_t got_pcrel_offset;
+      const bfd_byte *got_plt_entry;
+
+      /* Set the entry in the GOT procedure linkage table.  */
+      plt = htab->plt_got;
+      got = htab->elf.sgot;
+      got_offset = h->got.offset;
+
+      if (got_offset == (bfd_vma) -1
+         || h->type == STT_GNU_IFUNC
+         || plt == NULL
+         || got == NULL)
+       abort ();
 
-      if (!h->def_regular)
+      /* Use the second PLT entry template for the GOT PLT since they
+        are the identical.  */
+      plt_got_insn_size = elf_x86_64_bnd_arch_bed.plt_got_insn_size;
+      plt_got_offset = elf_x86_64_bnd_arch_bed.plt_got_offset;
+      if (eh->has_bnd_reloc)
+       got_plt_entry = elf_x86_64_bnd_plt2_entry;
+      else
        {
-         /* Mark the symbol as undefined, rather than as defined in
-            the .plt section.  Leave the value if there were any
-            relocations where pointer equality matters (this is a clue
-            for the dynamic linker, to make function pointer
-            comparisons work between an application and shared
-            library), otherwise set it to zero.  If a function is only
-            called from a binary, there is no need to slow down
-            shared libraries because of that.  */
-         sym->st_shndx = SHN_UNDEF;
-         if (!h->pointer_equality_needed)
-           sym->st_value = 0;
+         got_plt_entry = elf_x86_64_legacy_plt2_entry;
+
+         /* Subtract 1 since there is no BND prefix.  */
+         plt_got_insn_size -= 1;
+         plt_got_offset -= 1;
        }
+
+      /* Fill in the entry in the GOT procedure linkage table.  */
+      plt_offset = eh->plt_got.offset;
+      memcpy (plt->contents + plt_offset,
+             got_plt_entry, sizeof (elf_x86_64_legacy_plt2_entry));
+
+      /* Put offset the PC-relative instruction referring to the GOT
+        entry, subtracting the size of that instruction.  */
+      got_pcrel_offset = (got->output_section->vma
+                         + got->output_offset
+                         + got_offset
+                         - plt->output_section->vma
+                         - plt->output_offset
+                         - plt_offset
+                         - plt_got_insn_size);
+
+      /* Check PC-relative offset overflow in GOT PLT entry.  */
+      got_after_plt = got->output_section->vma > plt->output_section->vma;
+      if ((got_after_plt && got_pcrel_offset < 0)
+         || (!got_after_plt && got_pcrel_offset > 0))
+       info->callbacks->einfo (_("%F%B: PC-relative offset overflow in GOT PLT entry for `%s'\n"),
+                               output_bfd, h->root.root.string);
+
+      bfd_put_32 (output_bfd, got_pcrel_offset,
+                 plt->contents + plt_offset + plt_got_offset);
+    }
+
+  if (!h->def_regular
+      && (h->plt.offset != (bfd_vma) -1
+         || eh->plt_got.offset != (bfd_vma) -1))
+    {
+      /* Mark the symbol as undefined, rather than as defined in
+        the .plt section.  Leave the value if there were any
+        relocations where pointer equality matters (this is a clue
+        for the dynamic linker, to make function pointer
+        comparisons work between an application and shared
+        library), otherwise set it to zero.  If a function is only
+        called from a binary, there is no need to slow down
+        shared libraries because of that.  */
+      sym->st_shndx = SHN_UNDEF;
+      if (!h->pointer_equality_needed)
+       sym->st_value = 0;
     }
 
   if (h->got.offset != (bfd_vma) -1
 
+2014-11-25  H.J. Lu  <hongjiu.lu@intel.com>
+
+       * emulparams/elf_i386.sh (TINY_READONLY_SECTION): New.
+       * emulparams/elf_x86_64.sh (TINY_READONLY_SECTION): Add .plt.got.
+
 2014-11-24  H.J. Lu  <hongjiu.lu@intel.com>
 
        * configure: Regenerated.
 
 NO_SMALL_DATA=yes
 SEPARATE_GOTPLT="SIZEOF (.got.plt) >= 12 ? 12 : 0"
 IREL_IN_PLT=
+# Reuse TINY_READONLY_SECTION which is placed right after .plt section.
+TINY_READONLY_SECTION="
+.plt.got      ${RELOCATING-0} : { *(.plt.got) }
+"
 
 # Linux modify the default library search path to first include
 # a 32-bit specific directory.
 
 SEPARATE_GOTPLT="SIZEOF (.got.plt) >= 24 ? 24 : 0"
 IREL_IN_PLT=
 # Reuse TINY_READONLY_SECTION which is placed right after .plt section.
-TINY_READONLY_SECTION=".plt.bnd      ${RELOCATING-0} : { *(.plt.bnd) }"
+TINY_READONLY_SECTION="
+.plt.got      ${RELOCATING-0} : { *(.plt.got) }
+.plt.bnd      ${RELOCATING-0} : { *(.plt.bnd) }
+"
 
 if [ "x${host}" = "x${target}" ]; then
   case " $EMULATION_LIBPATH " in
 
+2014-11-25  H.J. Lu  <hongjiu.lu@intel.com>
+
+       * ld-i386/i386.exp: Add run-time relocation tests for plt-main.
+       * ld-i386/plt-main.rd: New file.
+       * ld-x86-64/plt-main-bnd.dd: Likewise.
+       * ld-x86-64/plt-main.rd: Likewise.
+       * ld-x86-64/x86-64.exp: Add run-time relocation tests for
+       plt-main.
+
 2014-11-21  H.J. Lu  <hongjiu.lu@intel.com>
 
        * ld-i386/plt-lib.c: New file.
 
            {{readelf {-Wr} plt-main4.rd}} \
            "libplt-main4.a" \
        ] \
+       [list \
+           "Build plt-main" \
+           "tmpdir/plt-main1.o tmpdir/plt-main2.o tmpdir/plt-main3.o \
+            tmpdir/plt-main4.o tmpdir/libplt-lib.so" \
+           "" \
+           { plt-main5.c } \
+           {{readelf {-Wr} plt-main.rd}} \
+           "plt-main" \
+       ] \
+       [list \
+           "Build plt-main with PIE" \
+           "tmpdir/plt-main1.o tmpdir/plt-main2.o tmpdir/plt-main3.o \
+            tmpdir/plt-main4.o tmpdir/libplt-lib.so -pie" \
+           "-fPIC" \
+           { plt-main5.c } \
+           {{readelf {-Wr} plt-main.rd}} \
+           "plt-main" \
+       ] \
     ]
 
     run_ld_link_exec_tests [] [list \
 
--- /dev/null
+#failif
+#...
+[0-9a-f ]+R_386_JUMP_SLOT +0+ +bar
+#...
 
--- /dev/null
+#...
+Disassembly of section .plt.got:
+
+[a-f0-9]+ <.plt.got>:
+[      ]*[a-f0-9]+:    f2 ff 25 .. .. 20 00    bnd jmpq \*0x20....\(%rip\)        # ...... <_DYNAMIC\+0x...>
+[      ]*[a-f0-9]+:    90                      nop
+#pass
 
--- /dev/null
+#failif
+#...
+[0-9a-f ]+R_X86_64_JUMP_SLOT +0+ +bar \+ 0
+#...
 
            {{readelf {-Wr} plt-main4.rd}} \
            "libplt-main4.a" \
        ] \
+       [list \
+           "Build plt-main" \
+           "tmpdir/plt-main1.o tmpdir/plt-main2.o tmpdir/plt-main3.o \
+            tmpdir/plt-main4.o tmpdir/libplt-lib.so" \
+           "" \
+           { plt-main5.c } \
+           {{readelf {-Wr} plt-main.rd}} \
+           "plt-main" \
+       ] \
+       [list \
+           "Build plt-main with PIE" \
+           "tmpdir/plt-main1.o tmpdir/plt-main2.o tmpdir/plt-main3.o \
+            tmpdir/plt-main4.o tmpdir/libplt-lib.so -pie" \
+           "-fPIC" \
+           { plt-main5.c } \
+           {{readelf {-Wr} plt-main.rd}} \
+           "plt-main" \
+       ] \
     ]
 
     run_ld_link_exec_tests [] [list \
            "-fPIC" \
        ] \
     ]
+
+    if { [istarget "x86_64-*-linux*"] \
+        && ![istarget "x86_64-*-linux*-gnux32"]} {
+
+       run_cc_link_tests [list \
+           [list \
+               "Build plt-main with -z bndplt" \
+               "tmpdir/plt-main1.o tmpdir/plt-main2.o tmpdir/plt-main3.o \
+                tmpdir/plt-main4.o tmpdir/libplt-lib.so -z bndplt" \
+               "" \
+               { plt-main5.c } \
+               {{objdump {-drw} plt-main-bnd.dd}} \
+               "plt-main-bnd" \
+           ] \
+           [list \
+               "Build plt-main with PIE and -z bndplt" \
+               "tmpdir/plt-main1.o tmpdir/plt-main2.o tmpdir/plt-main3.o \
+                tmpdir/plt-main4.o tmpdir/libplt-lib.so -z bndplt -pie" \
+               "-fPIC" \
+               { plt-main5.c } \
+               {{objdump {-drw} plt-main-bnd.dd}} \
+               "plt-main-pie-bnd" \
+           ] \
+       ]
+
+       run_ld_link_exec_tests [] [list \
+           [list \
+               "Run plt-main with -z bndplt" \
+               "tmpdir/plt-main1.o tmpdir/plt-main2.o tmpdir/plt-main3.o \
+                tmpdir/plt-main4.o tmpdir/libplt-lib.so -z bndplt" \
+               "" \
+               { plt-main5.c } \
+               "plt-main-bnd" \
+               "plt-main.out" \
+           ] \
+           [list \
+               "Run plt-main with PIE and -z bndplt" \
+               "tmpdir/plt-main1.o tmpdir/plt-main2.o tmpdir/plt-main3.o \
+                tmpdir/plt-main4.o tmpdir/libplt-lib.so -z bndplt -pie" \
+               "" \
+               { plt-main5.c } \
+               "plt-main-pie-bnd" \
+               "plt-main.out" \
+               "-fPIC" \
+           ] \
+       ]
+    }
 }
 
 if { ![istarget "x86_64-*-linux*"]} {