gdb: add target_ops::supports_displaced_step
[deliverable/binutils-gdb.git] / bfd / elf32-i386.c
index ebba75c3f7b65b4aab3f3f46b59ac3aa488630a3..544b9315521ef9ea46f72d2388cea0df68b7c0b7 100644 (file)
@@ -1,5 +1,5 @@
 /* Intel 80386/80486-specific support for 32-bit ELF
-   Copyright (C) 1993-2017 Free Software Foundation, Inc.
+   Copyright (C) 1993-2020 Free Software Foundation, Inc.
 
    This file is part of BFD, the Binary File Descriptor library.
 
@@ -182,6 +182,10 @@ static reloc_howto_type elf_howto_table[]=
 
 };
 
+#define X86_PCREL_TYPE_P(TYPE) ((TYPE) == R_386_PC32)
+
+#define X86_SIZE_TYPE_P(TYPE) ((TYPE) == R_386_SIZE32)
+
 #ifdef DEBUG_GEN_RELOC
 #define TRACE(str) \
   fprintf (stderr, "i386 bfd reloc lookup %d (%s)\n", code, str)
@@ -190,7 +194,7 @@ static reloc_howto_type elf_howto_table[]=
 #endif
 
 static reloc_howto_type *
-elf_i386_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
+elf_i386_reloc_type_lookup (bfd *abfd,
                            bfd_reloc_code_real_type code)
 {
   switch (code)
@@ -342,11 +346,13 @@ elf_i386_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
       return &elf_howto_table[R_386_GNU_VTENTRY - R_386_vt_offset];
 
     default:
-      break;
+      TRACE ("Unknown");
+      /* xgettext:c-format */
+      _bfd_error_handler (_("%pB: unsupported relocation type: %#x"),
+                         abfd, (int) code);
+      bfd_set_error (bfd_error_bad_value);
+      return NULL;
     }
-
-  TRACE ("Unknown");
-  return 0;
 }
 
 static reloc_howto_type *
@@ -364,7 +370,7 @@ elf_i386_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
 }
 
 static reloc_howto_type *
-elf_i386_rtype_to_howto (bfd *abfd, unsigned r_type)
+elf_i386_rtype_to_howto (unsigned r_type)
 {
   unsigned int indx;
 
@@ -375,25 +381,30 @@ elf_i386_rtype_to_howto (bfd *abfd, unsigned r_type)
          >= R_386_ext2 - R_386_ext)
       && ((indx = r_type - R_386_vt_offset) - R_386_ext2
          >= R_386_vt - R_386_ext2))
-    {
-      /* xgettext:c-format */
-      _bfd_error_handler (_("%B: invalid relocation type %d"),
-                         abfd, (int) r_type);
-      indx = R_386_NONE;
-    }
+      return NULL;
   /* PR 17512: file: 0f67f69d.  */
   if (elf_howto_table [indx].type != r_type)
     return NULL;
   return &elf_howto_table[indx];
 }
 
-static void
-elf_i386_info_to_howto_rel (bfd *abfd ATTRIBUTE_UNUSED,
+static bfd_boolean
+elf_i386_info_to_howto_rel (bfd *abfd,
                            arelent *cache_ptr,
                            Elf_Internal_Rela *dst)
 {
   unsigned int r_type = ELF32_R_TYPE (dst->r_info);
-  cache_ptr->howto = elf_i386_rtype_to_howto (abfd, r_type);
+
+  if ((cache_ptr->howto = elf_i386_rtype_to_howto (r_type)) == NULL)
+    {
+      /* xgettext:c-format */
+      _bfd_error_handler (_("%pB: unsupported relocation type %#x"),
+                         abfd, r_type);
+      bfd_set_error (bfd_error_bad_value);
+      return FALSE;
+    }
+
+  return TRUE;
 }
 
 /* Return whether a symbol name implies a local label.  The UnixWare
@@ -424,7 +435,7 @@ elf_i386_grok_prstatus (bfd *abfd, Elf_Internal_Note *note)
       int pr_version = bfd_get_32 (abfd, note->descdata);
 
       if (pr_version != 1)
-       return FALSE;
+       return FALSE;
 
       /* pr_cursig */
       elf_tdata (abfd)->core->signal = bfd_get_32 (abfd, note->descdata + 20);
@@ -522,12 +533,6 @@ elf_i386_grok_psinfo (bfd *abfd, Elf_Internal_Note *note)
    early in the link process, elf_i386_finish_dynamic_sections is
    one of the last functions.  */
 
-
-/* The name of the dynamic interpreter.  This is put in the .interp
-   section.  */
-
-#define ELF_DYNAMIC_INTERPRETER "/usr/lib/libc.so.1"
-
 /* The size in bytes of an entry in the lazy procedure linkage table.  */
 
 #define LAZY_PLT_ENTRY_SIZE 16
@@ -609,9 +614,9 @@ static const bfd_byte elf_i386_pic_non_lazy_plt_entry[NON_LAZY_PLT_ENTRY_SIZE] =
 
 static const bfd_byte elf_i386_lazy_ibt_plt0_entry[LAZY_PLT_ENTRY_SIZE] =
 {
-  0xff, 0x35, 0, 0, 0, 0,      /* pushl GOT[1]       */
-  0xff, 0x25, 0, 0, 0, 0,      /* jmp *GOT[2]        */
-  0x0f, 0x1f, 0x40, 0x00       /* nopl 0(%rax)       */
+  0xff, 0x35, 0, 0, 0, 0,      /* pushl GOT[1]       */
+  0xff, 0x25, 0, 0, 0, 0,      /* jmp *GOT[2]        */
+  0x0f, 0x1f, 0x40, 0x00       /* nopl 0(%rax)       */
 };
 
 /* Subsequent entries for an absolute IBT-enabled lazy procedure linkage
@@ -620,10 +625,10 @@ static const bfd_byte elf_i386_lazy_ibt_plt0_entry[LAZY_PLT_ENTRY_SIZE] =
 
 static const bfd_byte elf_i386_lazy_ibt_plt_entry[LAZY_PLT_ENTRY_SIZE] =
 {
-  0xf3, 0x0f, 0x1e, 0xfb,       /* endbr32                    */
-  0x68, 0, 0, 0, 0,             /* pushl immediate            */
-  0xe9, 0, 0, 0, 0,             /* jmp relative               */
-  0x66, 0x90                   /* xchg %ax,%ax               */
+  0xf3, 0x0f, 0x1e, 0xfb,      /* endbr32                    */
+  0x68, 0, 0, 0, 0,            /* pushl immediate            */
+  0xe9, 0, 0, 0, 0,            /* jmp relative               */
+  0x66, 0x90                   /* xchg %ax,%ax               */
 };
 
 /* The first entry in a PIC IBT-enabled lazy procedure linkage table
@@ -632,8 +637,8 @@ static const bfd_byte elf_i386_lazy_ibt_plt_entry[LAZY_PLT_ENTRY_SIZE] =
 static const bfd_byte elf_i386_pic_lazy_ibt_plt0_entry[LAZY_PLT_ENTRY_SIZE] =
 {
   0xff, 0xb3, 4, 0, 0, 0,      /* pushl 4(%ebx)      */
-  0xff, 0xa3, 8, 0, 0, 0,      /* jmp *8(%ebx)       */
-  0x0f, 0x1f, 0x40, 0x00       /* nopl 0(%rax)       */
+  0xff, 0xa3, 8, 0, 0, 0,      /* jmp *8(%ebx)       */
+  0x0f, 0x1f, 0x40, 0x00       /* nopl 0(%rax)       */
 };
 
 /* Entries for branches with IBT-enabled in the absolute non-lazey
@@ -642,7 +647,7 @@ static const bfd_byte elf_i386_pic_lazy_ibt_plt0_entry[LAZY_PLT_ENTRY_SIZE] =
 
 static const bfd_byte elf_i386_non_lazy_ibt_plt_entry[LAZY_PLT_ENTRY_SIZE] =
 {
-  0xf3, 0x0f, 0x1e, 0xfb,            /* endbr32               */
+  0xf3, 0x0f, 0x1e, 0xfb,           /* endbr32               */
   0xff, 0x25, 0, 0, 0, 0,           /* jmp *name@GOT         */
   0x66, 0x0f, 0x1f, 0x44, 0x00, 0x00 /* nopw 0x0(%rax,%rax,1) */
 };
@@ -653,7 +658,7 @@ static const bfd_byte elf_i386_non_lazy_ibt_plt_entry[LAZY_PLT_ENTRY_SIZE] =
 
 static const bfd_byte elf_i386_pic_non_lazy_ibt_plt_entry[LAZY_PLT_ENTRY_SIZE] =
 {
-  0xf3, 0x0f, 0x1e, 0xfb,            /* endbr32               */
+  0xf3, 0x0f, 0x1e, 0xfb,           /* endbr32               */
   0xff, 0xa3, 0, 0, 0, 0,           /* jmp *name@GOT(%ebx)   */
   0x66, 0x0f, 0x1f, 0x44, 0x00, 0x00 /* nopw 0x0(%rax,%rax,1) */
 };
@@ -662,10 +667,6 @@ static const bfd_byte elf_i386_pic_non_lazy_ibt_plt_entry[LAZY_PLT_ENTRY_SIZE] =
 
 static const bfd_byte elf_i386_eh_frame_lazy_plt[] =
 {
-#define PLT_CIE_LENGTH         20
-#define PLT_FDE_LENGTH         36
-#define PLT_FDE_START_OFFSET   4 + PLT_CIE_LENGTH + 8
-#define PLT_FDE_LEN_OFFSET     4 + PLT_CIE_LENGTH + 12
   PLT_CIE_LENGTH, 0, 0, 0,     /* CIE length */
   0, 0, 0, 0,                  /* CIE ID */
   1,                           /* CIE version */
@@ -758,136 +759,80 @@ static const bfd_byte elf_i386_eh_frame_non_lazy_plt[] =
   DW_CFA_nop, DW_CFA_nop, DW_CFA_nop
 };
 
-struct elf_i386_lazy_plt_layout
-{
-  /* The first entry in an absolute lazy procedure linkage table looks
-     like this.  */
-  const bfd_byte *plt0_entry;
-  unsigned int plt0_entry_size;
-
-  /* Offsets into plt0_entry that are to be replaced with GOT[1] and
-     GOT[2].  */
-  unsigned int plt0_got1_offset;
-  unsigned int plt0_got2_offset;
-
-  /* Later entries in an absolute lazy procedure linkage table look
-     like this.  */
-  const bfd_byte *plt_entry;
-  unsigned int plt_entry_size;
-
-  /* Offsets into plt_entry that are to be replaced with...  */
-  unsigned int plt_got_offset;    /* ... address of this symbol in .got. */
-  unsigned int plt_reloc_offset;  /* ... offset into relocation table. */
-  unsigned int plt_plt_offset;    /* ... offset to start of .plt. */
-
-  /* Offset into plt_entry where the initial value of the GOT entry
-     points.  */
-  unsigned int plt_lazy_offset;
-
-  /* The first entry in a PIC lazy procedure linkage table looks like
-     this.  */
-  const bfd_byte *pic_plt0_entry;
-
-  /* Subsequent entries in a PIC lazy procedure linkage table look
-     like this.  */
-  const bfd_byte *pic_plt_entry;
-
-  /* .eh_frame covering the lazy .plt section.  */
-  const bfd_byte *eh_frame_plt;
-  unsigned int eh_frame_plt_size;
-};
-
-struct elf_i386_non_lazy_plt_layout
-{
-  /* Entries in an absolute non-lazy procedure linkage table look like
-     this.  */
-  const bfd_byte *plt_entry;
-  /* Entries in a PIC non-lazy procedure linkage table look like this.  */
-  const bfd_byte *pic_plt_entry;
-
-  unsigned int plt_entry_size;
-
-  /* Offsets into plt_entry that are to be replaced with...  */
-  unsigned int plt_got_offset;    /* ... address of this symbol in .got. */
-
-  /* .eh_frame covering the non-lazy .plt section.  */
-  const bfd_byte *eh_frame_plt;
-  unsigned int eh_frame_plt_size;
-};
-
-struct elf_i386_plt_layout
-{
-  /* The first entry in a lazy procedure linkage table looks like this.  */
-  const bfd_byte *plt0_entry;
-  /* Entries in a procedure linkage table look like this.  */
-  const bfd_byte *plt_entry;
-  unsigned int plt_entry_size;
-
-  /* 1 has PLT0.  */
-  unsigned int has_plt0;
-
-  /* Offsets into plt_entry that are to be replaced with...  */
-  unsigned int plt_got_offset;    /* ... address of this symbol in .got. */
-
-  /* .eh_frame covering the .plt section.  */
-  const bfd_byte *eh_frame_plt;
-  unsigned int eh_frame_plt_size;
-};
-
 /* These are the standard parameters.  */
-static const struct elf_i386_lazy_plt_layout elf_i386_lazy_plt =
+static const struct elf_x86_lazy_plt_layout elf_i386_lazy_plt =
   {
-    elf_i386_lazy_plt0_entry,           /* plt0_entry */
-    sizeof (elf_i386_lazy_plt0_entry),  /* plt0_entry_size */
-    2,                                  /* plt0_got1_offset */
-    8,                                  /* plt0_got2_offset */
-    elf_i386_lazy_plt_entry,            /* plt_entry */
-    LAZY_PLT_ENTRY_SIZE,                /* plt_entry_size */
-    2,                                  /* plt_got_offset */
-    7,                                  /* plt_reloc_offset */
-    12,                                 /* plt_plt_offset */
-    6,                                  /* plt_lazy_offset */
-    elf_i386_pic_lazy_plt0_entry,       /* pic_plt0_entry */
-    elf_i386_pic_lazy_plt_entry,        /* pic_plt_entry */
-    elf_i386_eh_frame_lazy_plt,         /* eh_frame_plt */
+    elf_i386_lazy_plt0_entry,          /* plt0_entry */
+    sizeof (elf_i386_lazy_plt0_entry), /* plt0_entry_size */
+    elf_i386_lazy_plt_entry,           /* plt_entry */
+    LAZY_PLT_ENTRY_SIZE,               /* plt_entry_size */
+    NULL,                              /* plt_tlsdesc_entry */
+    0,                                 /* plt_tlsdesc_entry_size*/
+    0,                                 /* plt_tlsdesc_got1_offset */
+    0,                                 /* plt_tlsdesc_got2_offset */
+    0,                                 /* plt_tlsdesc_got1_insn_end */
+    0,                                 /* plt_tlsdesc_got2_insn_end */
+    2,                                 /* plt0_got1_offset */
+    8,                                 /* plt0_got2_offset */
+    0,                                 /* plt0_got2_insn_end */
+    2,                                 /* plt_got_offset */
+    7,                                 /* plt_reloc_offset */
+    12,                                        /* plt_plt_offset */
+    0,                                 /* plt_got_insn_size */
+    0,                                 /* plt_plt_insn_end */
+    6,                                 /* plt_lazy_offset */
+    elf_i386_pic_lazy_plt0_entry,      /* pic_plt0_entry */
+    elf_i386_pic_lazy_plt_entry,       /* pic_plt_entry */
+    elf_i386_eh_frame_lazy_plt,                /* eh_frame_plt */
     sizeof (elf_i386_eh_frame_lazy_plt) /* eh_frame_plt_size */
   };
 
-static const struct elf_i386_non_lazy_plt_layout elf_i386_non_lazy_plt =
+static const struct elf_x86_non_lazy_plt_layout elf_i386_non_lazy_plt =
   {
-    elf_i386_non_lazy_plt_entry,        /* plt_entry */
-    elf_i386_pic_non_lazy_plt_entry,    /* pic_plt_entry */
-    NON_LAZY_PLT_ENTRY_SIZE,            /* plt_entry_size */
-    2,                                  /* plt_got_offset */
-    elf_i386_eh_frame_non_lazy_plt,     /* eh_frame_plt */
+    elf_i386_non_lazy_plt_entry,       /* plt_entry */
+    elf_i386_pic_non_lazy_plt_entry,   /* pic_plt_entry */
+    NON_LAZY_PLT_ENTRY_SIZE,           /* plt_entry_size */
+    2,                                 /* plt_got_offset */
+    0,                                 /* plt_got_insn_size */
+    elf_i386_eh_frame_non_lazy_plt,    /* eh_frame_plt */
     sizeof (elf_i386_eh_frame_non_lazy_plt) /* eh_frame_plt_size */
   };
 
-static const struct elf_i386_lazy_plt_layout elf_i386_lazy_ibt_plt =
+static const struct elf_x86_lazy_plt_layout elf_i386_lazy_ibt_plt =
   {
-    elf_i386_lazy_ibt_plt0_entry,       /* plt0_entry */
+    elf_i386_lazy_ibt_plt0_entry,      /* plt0_entry */
     sizeof (elf_i386_lazy_ibt_plt0_entry), /* plt0_entry_size */
-    2,                                  /* plt0_got1_offset */
-    8,                                  /* plt0_got2_offset */
-    elf_i386_lazy_ibt_plt_entry,        /* plt_entry */
-    LAZY_PLT_ENTRY_SIZE,                /* plt_entry_size */
-    4+2,                                /* plt_got_offset */
-    4+1,                                /* plt_reloc_offset */
-    4+6,                                /* plt_plt_offset */
-    0,                                  /* plt_lazy_offset */
-    elf_i386_pic_lazy_ibt_plt0_entry,   /* pic_plt0_entry */
-    elf_i386_lazy_ibt_plt_entry,        /* pic_plt_entry */
-    elf_i386_eh_frame_lazy_ibt_plt,     /* eh_frame_plt */
+    elf_i386_lazy_ibt_plt_entry,       /* plt_entry */
+    LAZY_PLT_ENTRY_SIZE,               /* plt_entry_size */
+    NULL,                              /* plt_tlsdesc_entry */
+    0,                                 /* plt_tlsdesc_entry_size*/
+    0,                                 /* plt_tlsdesc_got1_offset */
+    0,                                 /* plt_tlsdesc_got2_offset */
+    0,                                 /* plt_tlsdesc_got1_insn_end */
+    0,                                 /* plt_tlsdesc_got2_insn_end */
+    2,                                 /* plt0_got1_offset */
+    8,                                 /* plt0_got2_offset */
+    0,                                 /* plt0_got2_insn_end */
+    4+2,                               /* plt_got_offset */
+    4+1,                               /* plt_reloc_offset */
+    4+6,                               /* plt_plt_offset */
+    0,                                 /* plt_got_insn_size */
+    0,                                 /* plt_plt_insn_end */
+    0,                                 /* plt_lazy_offset */
+    elf_i386_pic_lazy_ibt_plt0_entry,  /* pic_plt0_entry */
+    elf_i386_lazy_ibt_plt_entry,       /* pic_plt_entry */
+    elf_i386_eh_frame_lazy_ibt_plt,    /* eh_frame_plt */
     sizeof (elf_i386_eh_frame_lazy_ibt_plt) /* eh_frame_plt_size */
   };
 
-static const struct elf_i386_non_lazy_plt_layout elf_i386_non_lazy_ibt_plt =
+static const struct elf_x86_non_lazy_plt_layout elf_i386_non_lazy_ibt_plt =
   {
-    elf_i386_non_lazy_ibt_plt_entry,    /* plt_entry */
+    elf_i386_non_lazy_ibt_plt_entry,   /* plt_entry */
     elf_i386_pic_non_lazy_ibt_plt_entry,/* pic_plt_entry */
-    LAZY_PLT_ENTRY_SIZE,                /* plt_entry_size */
-    4+2,                                /* plt_got_offset */
-    elf_i386_eh_frame_non_lazy_plt,     /* eh_frame_plt */
+    LAZY_PLT_ENTRY_SIZE,               /* plt_entry_size */
+    4+2,                               /* plt_got_offset */
+    0,                                 /* plt_got_insn_size */
+    elf_i386_eh_frame_non_lazy_plt,    /* eh_frame_plt */
     sizeof (elf_i386_eh_frame_non_lazy_plt) /* eh_frame_plt_size */
   };
 \f
@@ -898,145 +843,14 @@ static const struct elf_i386_non_lazy_plt_layout elf_i386_non_lazy_ibt_plt =
 #define PLTRESOLVE_RELOCS 2
 #define PLT_NON_JUMP_SLOT_RELOCS 2
 
-/* Architecture-specific backend data for i386.  */
-
-struct elf_i386_backend_data
-{
-  /* Value used to fill the unused bytes of the first PLT entry.  */
-  bfd_byte plt0_pad_byte;
-
-  /* Target system.  */
-  enum
-    {
-      is_normal,
-      is_vxworks,
-      is_nacl
-    } os;
-};
-
-#define get_elf_i386_backend_data(abfd) \
-  ((const struct elf_i386_backend_data *) \
-   get_elf_backend_data (abfd)->arch_data)
-
 /* These are the standard parameters.  */
-static const struct elf_i386_backend_data elf_i386_arch_bed =
+static const struct elf_x86_backend_data elf_i386_arch_bed =
   {
-    0,                                  /* plt0_pad_byte */
-    is_normal                           /* os */
+    is_normal                          /* os */
   };
 
 #define        elf_backend_arch_data   &elf_i386_arch_bed
 
-/* Values in tls_type of x86 ELF linker hash entry.  */
-#define GOT_TLS_IE     4
-#define GOT_TLS_IE_POS 5
-#define GOT_TLS_IE_NEG 6
-#define GOT_TLS_IE_BOTH 7
-#define GOT_TLS_GDESC  8
-#define GOT_TLS_GD_BOTH_P(type)                                                \
-  ((type) == (GOT_TLS_GD | GOT_TLS_GDESC))
-#define GOT_TLS_GD_P(type)                                             \
-  ((type) == GOT_TLS_GD || GOT_TLS_GD_BOTH_P (type))
-#define GOT_TLS_GDESC_P(type)                                          \
-  ((type) == GOT_TLS_GDESC || GOT_TLS_GD_BOTH_P (type))
-#define GOT_TLS_GD_ANY_P(type)                                         \
-  (GOT_TLS_GD_P (type) || GOT_TLS_GDESC_P (type))
-
-#define is_i386_elf(bfd)                               \
-  (bfd_get_flavour (bfd) == bfd_target_elf_flavour     \
-   && elf_tdata (bfd) != NULL                          \
-   && elf_object_id (bfd) == I386_ELF_DATA)
-
-static bfd_boolean
-elf_i386_mkobject (bfd *abfd)
-{
-  return bfd_elf_allocate_object (abfd,
-                                 sizeof (struct elf_x86_obj_tdata),
-                                 I386_ELF_DATA);
-}
-
-/* i386 ELF linker hash table.  */
-
-struct elf_i386_link_hash_table
-{
-  struct elf_x86_link_hash_table x86;
-
-  /* Parameters describing PLT generation, lazy or non-lazy.  */
-  struct elf_i386_plt_layout plt;
-
-  /* Parameters describing lazy PLT generation.  */
-  const struct elf_i386_lazy_plt_layout *lazy_plt;
-
-  /* Parameters describing non-lazy PLT generation.  */
-  const struct elf_i386_non_lazy_plt_layout *non_lazy_plt;
-
-  /* The (unloaded but important) .rel.plt.unloaded section on VxWorks.  */
-  asection *srelplt2;
-
-  /* The index of the next unused R_386_TLS_DESC slot in .rel.plt.  */
-  bfd_vma next_tls_desc_index;
-};
-
-#define elf_i386_next_tls_desc_index(htab) \
-  ((struct elf_i386_link_hash_table *) (htab))->next_tls_desc_index
-
-#define elf_i386_srelplt2(htab) \
-  ((struct elf_i386_link_hash_table *) (htab))->srelplt2
-
-#define elf_i386_plt(htab) \
-  ((struct elf_i386_link_hash_table *) (htab))->plt
-
-#define elf_i386_lazy_plt(htab) \
-  ((struct elf_i386_link_hash_table *) (htab))->lazy_plt
-
-#define elf_i386_non_lazy_plt(htab) \
-  ((struct elf_i386_link_hash_table *) (htab))->non_lazy_plt
-
-#define elf_i386_compute_jump_table_size(htab) \
-  ((htab)->elf.srelplt->reloc_count * 4)
-
-/* Create an i386 ELF linker hash table.  */
-
-static struct bfd_link_hash_table *
-elf_i386_link_hash_table_create (bfd *abfd)
-{
-  struct elf_x86_link_hash_table *ret;
-  bfd_size_type amt = sizeof (struct elf_i386_link_hash_table);
-
-  ret = (struct elf_x86_link_hash_table *) bfd_zmalloc (amt);
-  if (ret == NULL)
-    return NULL;
-
-  if (!_bfd_elf_link_hash_table_init (&ret->elf, abfd,
-                                     _bfd_x86_elf_link_hash_newfunc,
-                                     sizeof (struct elf_x86_link_hash_entry),
-                                     I386_ELF_DATA))
-    {
-      free (ret);
-      return NULL;
-    }
-
-  ret->r_info = elf32_r_info;
-  ret->r_sym = elf32_r_sym;
-  ret->pointer_r_type = R_386_32;
-  ret->dynamic_interpreter_size = sizeof ELF_DYNAMIC_INTERPRETER;
-  ret->dynamic_interpreter = ELF_DYNAMIC_INTERPRETER;
-  ret->tls_get_addr = "___tls_get_addr";
-  ret->loc_hash_table = htab_try_create (1024,
-                                        _bfd_x86_elf_local_htab_hash,
-                                        _bfd_x86_elf_local_htab_eq,
-                                        NULL);
-  ret->loc_hash_memory = objalloc_create ();
-  if (!ret->loc_hash_table || !ret->loc_hash_memory)
-    {
-      _bfd_x86_elf_link_hash_table_free (abfd);
-      return NULL;
-    }
-  ret->elf.root.hash_table_free = _bfd_x86_elf_link_hash_table_free;
-
-  return &ret->elf.root;
-}
-
 /* Return TRUE if the TLS access code sequence support transition
    from R_TYPE.  */
 
@@ -1293,10 +1107,7 @@ elf_i386_tls_transition (struct bfd_link_info *info, bfd *abfd,
        {
          unsigned int new_to_type = to_type;
 
-         if (bfd_link_executable (info)
-             && h != NULL
-             && h->dynindx == -1
-             && (tls_type & GOT_TLS_IE))
+         if (TLS_TRANSITION_IE_TO_LE_P (info, h, tls_type))
            new_to_type = R_386_TLS_LE_32;
 
          if (to_type == R_386_TLS_GD
@@ -1340,8 +1151,8 @@ elf_i386_tls_transition (struct bfd_link_info *info, bfd *abfd,
       reloc_howto_type *from, *to;
       const char *name;
 
-      from = elf_i386_rtype_to_howto (abfd, from_type);
-      to = elf_i386_rtype_to_howto (abfd, to_type);
+      from = elf_i386_rtype_to_howto (from_type);
+      to = elf_i386_rtype_to_howto (to_type);
 
       if (h)
        name = h->root.root.string;
@@ -1364,10 +1175,10 @@ elf_i386_tls_transition (struct bfd_link_info *info, bfd *abfd,
 
       _bfd_error_handler
        /* xgettext:c-format */
-       (_("%B: TLS transition from %s to %s against `%s' at %#Lx "
-          "in section `%A' failed"),
+       (_("%pB: TLS transition from %s to %s against `%s'"
+          " at %#" PRIx64 " in section `%pA' failed"),
         abfd, from->name, to->name, name,
-        rel->r_offset, sec);
+        (uint64_t) rel->r_offset, sec);
       bfd_set_error (bfd_error_bad_value);
       return FALSE;
     }
@@ -1399,6 +1210,7 @@ static
 bfd_boolean
 elf_i386_convert_load_reloc (bfd *abfd, Elf_Internal_Shdr *symtab_hdr,
                             bfd_byte *contents,
+                            unsigned int *r_type_p,
                             Elf_Internal_Rela *irel,
                             struct elf_link_hash_entry *h,
                             bfd_boolean *converted,
@@ -1414,9 +1226,12 @@ elf_i386_convert_load_reloc (bfd *abfd, Elf_Internal_Shdr *symtab_hdr,
   bfd_vma nop_offset;
   bfd_boolean is_pic;
   bfd_boolean to_reloc_32;
+  bfd_boolean abs_symbol;
   unsigned int r_type;
   unsigned int r_symndx;
   bfd_vma roff = irel->r_offset;
+  bfd_boolean local_ref;
+  struct elf_x86_link_hash_entry *eh;
 
   if (roff < 2)
     return TRUE;
@@ -1429,12 +1244,27 @@ elf_i386_convert_load_reloc (bfd *abfd, Elf_Internal_Shdr *symtab_hdr,
   htab = elf_x86_hash_table (link_info, I386_ELF_DATA);
   is_pic = bfd_link_pic (link_info);
 
-  r_type = ELF32_R_TYPE (irel->r_info);
+  r_type = *r_type_p;
   r_symndx = ELF32_R_SYM (irel->r_info);
 
   modrm = bfd_get_8 (abfd, contents + roff - 1);
   baseless = (modrm & 0xc7) == 0x5;
 
+  if (h)
+    {
+      /* NB: Also set linker_def via SYMBOL_REFERENCES_LOCAL_P.  */
+      local_ref = SYMBOL_REFERENCES_LOCAL_P (link_info, h);
+      isym = NULL;
+      abs_symbol = ABS_SYMBOL_P (h);
+    }
+  else
+    {
+      local_ref = TRUE;
+      isym = bfd_sym_from_r_symndx (&htab->sym_cache, abfd,
+                                   r_symndx);
+      abs_symbol = isym->st_shndx == SHN_ABS;
+    }
+
   if (baseless && is_pic)
     {
       /* For PIC, disallow R_386_GOT32X without a base register
@@ -1442,17 +1272,13 @@ elf_i386_convert_load_reloc (bfd *abfd, Elf_Internal_Shdr *symtab_hdr,
       const char *name;
 
       if (h == NULL)
-       {
-         isym = bfd_sym_from_r_symndx (&htab->sym_cache, abfd,
-                                       r_symndx);
-         name = bfd_elf_sym_name (abfd, symtab_hdr, isym, NULL);
-       }
+       name = bfd_elf_sym_name (abfd, symtab_hdr, isym, NULL);
       else
        name = h->root.root.string;
 
       _bfd_error_handler
        /* xgettext:c-format */
-       (_("%B: direct GOT relocation R_386_GOT32X against `%s' without base"
+       (_("%pB: direct GOT relocation R_386_GOT32X against `%s' without base"
           " register can not be used when making a shared object"),
         abfd, name);
       return FALSE;
@@ -1464,6 +1290,8 @@ elf_i386_convert_load_reloc (bfd *abfd, Elf_Internal_Shdr *symtab_hdr,
      register.  */
   to_reloc_32 = !is_pic || baseless;
 
+  eh = elf_x86_hash_entry (h);
+
   /* Try to convert R_386_GOT32X.  Get the symbol referred to by the
      reloc.  */
   if (h == NULL)
@@ -1480,8 +1308,9 @@ elf_i386_convert_load_reloc (bfd *abfd, Elf_Internal_Shdr *symtab_hdr,
 
   /* Undefined weak symbol is only bound locally in executable
      and its reference is resolved as 0.  */
-  if (UNDEFINED_WEAK_RESOLVED_TO_ZERO (link_info, I386_ELF_DATA, TRUE,
-                                      elf_x86_hash_entry (h)))
+  if (h->root.type == bfd_link_hash_undefweak
+      && !eh->linker_def
+      && local_ref)
     {
       if (opcode == 0xff)
        {
@@ -1504,16 +1333,13 @@ elf_i386_convert_load_reloc (bfd *abfd, Elf_Internal_Shdr *symtab_hdr,
       /* We have "call/jmp *foo@GOT[(%reg)]".  */
       if ((h->root.type == bfd_link_hash_defined
           || h->root.type == bfd_link_hash_defweak)
-         && SYMBOL_REFERENCES_LOCAL (link_info, h))
+         && local_ref)
        {
          /* The function is locally defined.   */
-convert_branch:
+       convert_branch:
          /* Convert R_386_GOT32X to R_386_PC32.  */
          if (modrm == 0x15 || (modrm & 0xf8) == 0x90)
            {
-             struct elf_x86_link_hash_entry *eh
-               = (struct elf_x86_link_hash_entry *) h;
-
              /* Convert to "nop call foo".  ADDR_PREFIX_OPCODE
                 is a nop prefix.  */
              modrm = 0xe8;
@@ -1526,8 +1352,8 @@ convert_branch:
                }
              else
                {
-                 nop = link_info->call_nop_byte;
-                 if (link_info->call_nop_as_suffix)
+                 nop = htab->params->call_nop_byte;
+                 if (htab->params->call_nop_as_suffix)
                    {
                      nop_offset = roff + 3;
                      irel->r_offset -= 1;
@@ -1551,7 +1377,7 @@ convert_branch:
             need to adjust addend by -4.  */
          bfd_put_32 (abfd, -4, contents + irel->r_offset);
          irel->r_info = ELF32_R_INFO (r_symndx, R_386_PC32);
-
+         *r_type_p = R_386_PC32;
          *converted = TRUE;
        }
     }
@@ -1570,14 +1396,18 @@ convert_branch:
         bfd_elf_record_link_assignment.  start_stop is set on
         __start_SECNAME/__stop_SECNAME which mark section SECNAME.  */
       if (h->start_stop
+         || eh->linker_def
          || ((h->def_regular
               || h->root.type == bfd_link_hash_defined
               || h->root.type == bfd_link_hash_defweak)
-             && SYMBOL_REFERENCES_LOCAL (link_info, h)))
+             && local_ref))
        {
-convert_load:
+       convert_load:
          if (opcode == 0x8b)
            {
+             if (abs_symbol && local_ref)
+               to_reloc_32 = TRUE;
+
              if (to_reloc_32)
                {
                  /* Convert "mov foo@GOT[(%reg1)], %reg2" to
@@ -1623,7 +1453,7 @@ convert_load:
 
          bfd_put_8 (abfd, opcode, contents + roff - 2);
          irel->r_info = ELF32_R_INFO (r_symndx, r_type);
-
+         *r_type_p = r_type;
          *converted = TRUE;
        }
     }
@@ -1633,8 +1463,7 @@ convert_load:
 
 /* Rename some of the generic section flags to better document how they
    are used here.  */
-#define need_convert_load      sec_flg0
-#define check_relocs_failed    sec_flg1
+#define check_relocs_failed    sec_flg0
 
 /* Look through the relocs for a section during the first phase, and
    calculate needed space in the global offset table, procedure linkage
@@ -1653,6 +1482,7 @@ elf_i386_check_relocs (bfd *abfd,
   const Elf_Internal_Rela *rel_end;
   asection *sreloc;
   bfd_byte *contents;
+  bfd_boolean converted;
 
   if (bfd_link_relocatable (info))
     return TRUE;
@@ -1666,8 +1496,6 @@ elf_i386_check_relocs (bfd *abfd,
   if ((sec->flags & SEC_ALLOC) == 0)
     return TRUE;
 
-  BFD_ASSERT (is_i386_elf (abfd));
-
   htab = elf_x86_hash_table (info, I386_ELF_DATA);
   if (htab == NULL)
     {
@@ -1675,6 +1503,8 @@ elf_i386_check_relocs (bfd *abfd,
       return FALSE;
     }
 
+  BFD_ASSERT (is_x86_elf (abfd, htab));
+
   /* Get the section contents.  */
   if (elf_section_data (sec)->this_hdr.contents != NULL)
     contents = elf_section_data (sec)->this_hdr.contents;
@@ -1687,6 +1517,8 @@ elf_i386_check_relocs (bfd *abfd,
   symtab_hdr = &elf_symtab_hdr (abfd);
   sym_hashes = elf_sym_hashes (abfd);
 
+  converted = FALSE;
+
   sreloc = NULL;
 
   rel_end = relocs + sec->reloc_count;
@@ -1699,6 +1531,7 @@ elf_i386_check_relocs (bfd *abfd,
       Elf_Internal_Sym *isym;
       const char *name;
       bfd_boolean size_reloc;
+      bfd_boolean no_dynreloc;
 
       r_symndx = ELF32_R_SYM (rel->r_info);
       r_type = ELF32_R_TYPE (rel->r_info);
@@ -1706,7 +1539,7 @@ elf_i386_check_relocs (bfd *abfd,
       if (r_symndx >= NUM_SHDR_ENTRIES (symtab_hdr))
        {
          /* xgettext:c-format */
-         _bfd_error_handler (_("%B: bad symbol index: %d"),
+         _bfd_error_handler (_("%pB: bad symbol index: %d"),
                              abfd, r_symndx);
          goto error_return;
        }
@@ -1755,23 +1588,36 @@ elf_i386_check_relocs (bfd *abfd,
 
          /* It is referenced by a non-shared object. */
          h->ref_regular = 1;
-         h->root.non_ir_ref_regular = 1;
+       }
 
-         if (h->type == STT_GNU_IFUNC)
-           elf_tdata (info->output_bfd)->has_gnu_symbols
-             |= elf_gnu_symbol_ifunc;
+      if (r_type == R_386_GOT32X
+         && (h == NULL || h->type != STT_GNU_IFUNC))
+       {
+         Elf_Internal_Rela *irel = (Elf_Internal_Rela *) rel;
+         if (!elf_i386_convert_load_reloc (abfd, symtab_hdr, contents,
+                                           &r_type, irel, h,
+                                           &converted, info))
+           goto error_return;
        }
 
+      if (!_bfd_elf_x86_valid_reloc_p (sec, info, htab, rel, h, isym,
+                                      symtab_hdr, &no_dynreloc))
+       return FALSE;
+
       if (! elf_i386_tls_transition (info, abfd, sec, contents,
                                     symtab_hdr, sym_hashes,
                                     &r_type, GOT_UNKNOWN,
                                     rel, rel_end, h, r_symndx, FALSE))
        goto error_return;
 
+      /* Check if _GLOBAL_OFFSET_TABLE_ is referenced.  */
+      if (h == htab->elf.hgot)
+       htab->got_referenced = TRUE;
+
       switch (r_type)
        {
        case R_386_TLS_LDM:
-         htab->tls_ld_or_ldm_got.refcount += 1;
+         htab->tls_ld_or_ldm_got.refcount = 1;
          goto create_got;
 
        case R_386_PLT32:
@@ -1787,9 +1633,9 @@ elf_i386_check_relocs (bfd *abfd,
          if (h == NULL)
            continue;
 
-         eh->has_got_reloc = 1;
+         eh->zero_undefweak &= 0x2;
          h->needs_plt = 1;
-         h->plt.refcount += 1;
+         h->plt.refcount = 1;
          break;
 
        case R_386_SIZE32:
@@ -1838,7 +1684,7 @@ elf_i386_check_relocs (bfd *abfd,
 
            if (h != NULL)
              {
-               h->got.refcount += 1;
+               h->got.refcount = 1;
                old_tls_type = elf_x86_hash_entry (h)->tls_type;
              }
            else
@@ -1855,7 +1701,7 @@ elf_i386_check_relocs (bfd *abfd,
                    size *= (sizeof (bfd_signed_vma)
                             + sizeof (bfd_vma) + sizeof(char));
                    local_got_refcounts = (bfd_signed_vma *)
-                        bfd_zalloc (abfd, size);
+                       bfd_zalloc (abfd, size);
                    if (local_got_refcounts == NULL)
                      goto error_return;
                    elf_local_got_refcounts (abfd) = local_got_refcounts;
@@ -1864,7 +1710,7 @@ elf_i386_check_relocs (bfd *abfd,
                    elf_x86_local_got_tls_type (abfd)
                      = (char *) (local_got_refcounts + 2 * symtab_hdr->sh_info);
                  }
-               local_got_refcounts[r_symndx] += 1;
+               local_got_refcounts[r_symndx] = 1;
                old_tls_type = elf_x86_local_got_tls_type (abfd) [r_symndx];
              }
 
@@ -1890,7 +1736,7 @@ elf_i386_check_relocs (bfd *abfd,
                                             NULL);
                    _bfd_error_handler
                      /* xgettext:c-format */
-                     (_("%B: `%s' accessed both as normal and "
+                     (_("%pB: `%s' accessed both as normal and "
                         "thread local symbol"),
                       abfd, name);
                    bfd_set_error (bfd_error_bad_value);
@@ -1914,7 +1760,15 @@ elf_i386_check_relocs (bfd *abfd,
          if (r_type != R_386_TLS_IE)
            {
              if (eh != NULL)
-               eh->has_got_reloc = 1;
+               {
+                 eh->zero_undefweak &= 0x2;
+
+                 /* Need GOT to resolve undefined weak symbol to 0.  */
+                 if (r_type == R_386_GOTOFF
+                     && h->root.type == bfd_link_hash_undefweak
+                     && bfd_link_executable (info))
+                   htab->got_referenced = TRUE;
+               }
              break;
            }
          /* Fall through */
@@ -1922,7 +1776,7 @@ elf_i386_check_relocs (bfd *abfd,
        case R_386_TLS_LE_32:
        case R_386_TLS_LE:
          if (eh != NULL)
-           eh->has_got_reloc = 1;
+           eh->zero_undefweak &= 0x2;
          if (bfd_link_executable (info))
            break;
          info->flags |= DF_STATIC_TLS;
@@ -1931,8 +1785,8 @@ elf_i386_check_relocs (bfd *abfd,
        case R_386_32:
        case R_386_PC32:
          if (eh != NULL && (sec->flags & SEC_CODE) != 0)
-           eh->has_non_got_reloc = 1;
-do_relocation:
+           eh->zero_undefweak |= 0x2;
+       do_relocation:
          /* We are called after all symbols have been resolved.  Only
             relocation against STT_GNU_IFUNC symbol must go through
             PLT.  */
@@ -1940,20 +1794,7 @@ do_relocation:
              && (bfd_link_executable (info)
                  || h->type == STT_GNU_IFUNC))
            {
-             /* If this reloc is in a read-only section, we might
-                need a copy reloc.  We can't check reliably at this
-                stage whether the section is read-only, as input
-                sections have not yet been mapped to output sections.
-                Tentatively set the flag for now, and correct in
-                adjust_dynamic_symbol.  */
-             h->non_got_ref = 1;
-
-             /* We may need a .plt entry if the symbol is a function
-                defined in a shared lib or is a STT_GNU_IFUNC function
-                referenced from the code or read-only section.  */
-             if (!h->def_regular
-                 || (sec->flags & (SEC_CODE | SEC_READONLY)) != 0)
-               h->plt.refcount += 1;
+             bfd_boolean func_pointer_ref = FALSE;
 
              if (r_type == R_386_PC32)
                {
@@ -1967,7 +1808,7 @@ do_relocation:
                    {
                      _bfd_error_handler
                        /* xgettext:c-format */
-                       (_("%B: unsupported non-PIC call to IFUNC `%s'"),
+                       (_("%pB: unsupported non-PIC call to IFUNC `%s'"),
                         abfd, h->root.root.string);
                      bfd_set_error (bfd_error_bad_value);
                      goto error_return;
@@ -1979,52 +1820,33 @@ do_relocation:
                  /* R_386_32 can be resolved at run-time.  */
                  if (r_type == R_386_32
                      && (sec->flags & SEC_READONLY) == 0)
-                   eh->func_pointer_refcount += 1;
+                   func_pointer_ref = TRUE;
+               }
+
+             if (!func_pointer_ref)
+               {
+                 /* If this reloc is in a read-only section, we might
+                    need a copy reloc.  We can't check reliably at this
+                    stage whether the section is read-only, as input
+                    sections have not yet been mapped to output sections.
+                    Tentatively set the flag for now, and correct in
+                    adjust_dynamic_symbol.  */
+                 h->non_got_ref = 1;
+
+                 /* We may need a .plt entry if the symbol is a function
+                    defined in a shared lib or is a function referenced
+                    from the code or read-only section.  */
+                 if (!h->def_regular
+                     || (sec->flags & (SEC_CODE | SEC_READONLY)) != 0)
+                   h->plt.refcount = 1;
                }
            }
 
          size_reloc = FALSE;
-do_size:
-         /* If we are creating a shared library, and this is a reloc
-            against a global symbol, or a non PC relative reloc
-            against a local symbol, then we need to copy the reloc
-            into the shared library.  However, if we are linking with
-            -Bsymbolic, we do not need to copy a reloc against a
-            global symbol which is defined in an object we are
-            including in the link (i.e., DEF_REGULAR is set).  At
-            this point we have not seen all the input files, so it is
-            possible that DEF_REGULAR is not set now but will be set
-            later (it is never cleared).  In case of a weak definition,
-            DEF_REGULAR may be cleared later by a strong definition in
-            a shared library.  We account for that possibility below by
-            storing information in the relocs_copied field of the hash
-            table entry.  A similar situation occurs when creating
-            shared libraries and symbol visibility changes render the
-            symbol local.
-
-            If on the other hand, we are creating an executable, we
-            may need to keep relocations for symbols satisfied by a
-            dynamic library if we manage to avoid copy relocs for the
-            symbol.
-
-            Generate dynamic pointer relocation against STT_GNU_IFUNC
-            symbol in the non-code section.  */
-         if ((bfd_link_pic (info)
-              && (r_type != R_386_PC32
-                  || (h != NULL
-                      && (! (bfd_link_pie (info)
-                             || SYMBOLIC_BIND (info, h))
-                          || h->root.type == bfd_link_hash_defweak
-                          || !h->def_regular))))
-             || (h != NULL
-                 && h->type == STT_GNU_IFUNC
-                 && r_type == R_386_32
-                 && (sec->flags & SEC_CODE) == 0)
-             || (ELIMINATE_COPY_RELOCS
-                 && !bfd_link_pic (info)
-                 && h != NULL
-                 && (h->root.type == bfd_link_hash_defweak
-                     || !h->def_regular)))
+       do_size:
+         if (!no_dynreloc
+             && NEED_DYNAMIC_RELOCATION_P (info, FALSE, h, sec, r_type,
+                                           R_386_32))
            {
              struct elf_dyn_relocs *p;
              struct elf_dyn_relocs **head;
@@ -2045,7 +1867,7 @@ do_size:
                 relocations we need for this symbol.  */
              if (h != NULL)
                {
-                 head = &eh->dyn_relocs;
+                 head = &h->dyn_relocs;
                }
              else
                {
@@ -2071,9 +1893,9 @@ do_size:
              p = *head;
              if (p == NULL || p->sec != sec)
                {
-                 bfd_size_type amt = sizeof *p;
+                 size_t amt = sizeof *p;
                  p = (struct elf_dyn_relocs *) bfd_alloc (htab->elf.dynobj,
-                                                           amt);
+                                                          amt);
                  if (p == NULL)
                    goto error_return;
                  p->next = *head;
@@ -2100,1344 +1922,150 @@ do_size:
          /* This relocation describes which C++ vtable entries are actually
             used.  Record for later use during GC.  */
        case R_386_GNU_VTENTRY:
-         BFD_ASSERT (h != NULL);
-         if (h != NULL
-             && !bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_offset))
+         if (!bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_offset))
            goto error_return;
          break;
 
        default:
          break;
        }
-
-      if (r_type == R_386_GOT32X
-         && (h == NULL || h->type != STT_GNU_IFUNC))
-       sec->need_convert_load = 1;
     }
 
   if (elf_section_data (sec)->this_hdr.contents != contents)
     {
-      if (!info->keep_memory)
+      if (!converted && !info->keep_memory)
        free (contents);
       else
        {
-         /* Cache the section contents for elf_link_input_bfd.  */
+         /* Cache the section contents for elf_link_input_bfd if any
+            load is converted or --no-keep-memory isn't used.  */
          elf_section_data (sec)->this_hdr.contents = contents;
        }
     }
 
+  /* Cache relocations if any load is converted.  */
+  if (elf_section_data (sec)->relocs != relocs && converted)
+    elf_section_data (sec)->relocs = (Elf_Internal_Rela *) relocs;
+
   return TRUE;
 
-error_return:
+ error_return:
   if (elf_section_data (sec)->this_hdr.contents != contents)
     free (contents);
   sec->check_relocs_failed = 1;
   return FALSE;
 }
 
-/* Return the section that should be marked against GC for a given
-   relocation.  */
-
-static asection *
-elf_i386_gc_mark_hook (asection *sec,
-                      struct bfd_link_info *info,
-                      Elf_Internal_Rela *rel,
-                      struct elf_link_hash_entry *h,
-                      Elf_Internal_Sym *sym)
-{
-  if (h != NULL)
-    switch (ELF32_R_TYPE (rel->r_info))
-      {
-      case R_386_GNU_VTINHERIT:
-      case R_386_GNU_VTENTRY:
-       return NULL;
-      }
-
-  return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym);
-}
-
-/* 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
-   change the definition to something the rest of the link can
-   understand.  */
+/* Set the correct type for an x86 ELF section.  We do this by the
+   section name, which is a hack, but ought to work.  */
 
 static bfd_boolean
-elf_i386_adjust_dynamic_symbol (struct bfd_link_info *info,
-                               struct elf_link_hash_entry *h)
+elf_i386_fake_sections (bfd *abfd ATTRIBUTE_UNUSED,
+                       Elf_Internal_Shdr *hdr,
+                       asection *sec)
 {
-  struct elf_x86_link_hash_table *htab;
-  asection *s, *srel;
-  struct elf_x86_link_hash_entry *eh;
-  struct elf_dyn_relocs *p;
-
-  /* STT_GNU_IFUNC symbol must go through PLT. */
-  if (h->type == STT_GNU_IFUNC)
-    {
-      /* All local STT_GNU_IFUNC references must be treate as local
-        calls via local PLT.  */
-      if (h->ref_regular
-         && SYMBOL_CALLS_LOCAL (info, h))
-       {
-         bfd_size_type pc_count = 0, count = 0;
-         struct elf_dyn_relocs **pp;
-
-         eh = (struct elf_x86_link_hash_entry *) h;
-         for (pp = &eh->dyn_relocs; (p = *pp) != NULL; )
-           {
-             pc_count += p->pc_count;
-             p->count -= p->pc_count;
-             p->pc_count = 0;
-             count += p->count;
-             if (p->count == 0)
-               *pp = p->next;
-             else
-               pp = &p->next;
-           }
-
-         if (pc_count || count)
-           {
-             h->non_got_ref = 1;
-             if (pc_count)
-               {
-                 /* Increment PLT reference count only for PC-relative
-                    references.  */
-                 h->needs_plt = 1;
-                 if (h->plt.refcount <= 0)
-                   h->plt.refcount = 1;
-                 else
-                   h->plt.refcount += 1;
-               }
-           }
-       }
-
-      if (h->plt.refcount <= 0)
-       {
-         h->plt.offset = (bfd_vma) -1;
-         h->needs_plt = 0;
-       }
-      return TRUE;
-    }
-
-  /* If this is a function, put it in the procedure linkage table.  We
-     will fill in the contents of the procedure linkage table later,
-     when we know the address of the .got section.  */
-  if (h->type == STT_FUNC
-      || h->needs_plt)
-    {
-      if (h->plt.refcount <= 0
-         || SYMBOL_CALLS_LOCAL (info, h)
-         || (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT
-             && h->root.type == bfd_link_hash_undefweak))
-       {
-         /* This case can occur if we saw a PLT32 reloc in an input
-            file, but the symbol was never referred to by a dynamic
-            object, or if all references were garbage collected.  In
-            such a case, we don't actually need to build a procedure
-            linkage table, and we can just do a PC32 reloc instead.  */
-         h->plt.offset = (bfd_vma) -1;
-         h->needs_plt = 0;
-       }
-
-      return TRUE;
-    }
-  else
-    /* It's possible that we incorrectly decided a .plt reloc was
-       needed for an R_386_PC32 reloc to a non-function sym in
-       check_relocs.  We can't decide accurately between function and
-       non-function syms in check-relocs;  Objects loaded later in
-       the link may change h->type.  So fix it now.  */
-    h->plt.offset = (bfd_vma) -1;
-
-  eh = (struct elf_x86_link_hash_entry *) h;
-
-  /* If this is a weak symbol, and there is a real definition, the
-     processor independent code will have arranged for us to see the
-     real definition first, and we can just use the same value.  */
-  if (h->u.weakdef != NULL)
-    {
-      BFD_ASSERT (h->u.weakdef->root.type == bfd_link_hash_defined
-                 || h->u.weakdef->root.type == bfd_link_hash_defweak);
-      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
-         || SYMBOL_NO_COPYRELOC (info, eh))
-       h->non_got_ref = h->u.weakdef->non_got_ref;
-      return TRUE;
-    }
-
-  /* This is a reference to a symbol defined by a dynamic object which
-     is not a function.  */
-
-  /* If we are creating a shared library, we must presume that the
-     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 (!bfd_link_executable (info))
-    return TRUE;
+  const char *name;
 
-  /* If there are no references to this symbol that do not use the
-     GOT nor R_386_GOTOFF relocation, we don't need to generate a copy
-     reloc.  */
-  if (!h->non_got_ref && !eh->gotoff_ref)
-    return TRUE;
+  name = bfd_section_name (sec);
 
-  /* If -z nocopyreloc was given, we won't generate them either.  */
-  if (info->nocopyreloc || SYMBOL_NO_COPYRELOC (info, eh))
-    {
-      h->non_got_ref = 0;
-      return TRUE;
-    }
+  /* This is an ugly, but unfortunately necessary hack that is
+     needed when producing EFI binaries on x86. It tells
+     elf.c:elf_fake_sections() not to consider ".reloc" as a section
+     containing ELF relocation info.  We need this hack in order to
+     be able to generate ELF binaries that can be translated into
+     EFI applications (which are essentially COFF objects).  Those
+     files contain a COFF ".reloc" section inside an ELFNN object,
+     which would normally cause BFD to segfault because it would
+     attempt to interpret this section as containing relocation
+     entries for section "oc".  With this hack enabled, ".reloc"
+     will be treated as a normal data section, which will avoid the
+     segfault.  However, you won't be able to create an ELFNN binary
+     with a section named "oc" that needs relocations, but that's
+     the kind of ugly side-effects you get when detecting section
+     types based on their names...  In practice, this limitation is
+     unlikely to bite.  */
+  if (strcmp (name, ".reloc") == 0)
+    hdr->sh_type = SHT_PROGBITS;
 
-  htab = elf_x86_hash_table (info, I386_ELF_DATA);
-  if (htab == NULL)
-    return FALSE;
+  return TRUE;
+}
 
-  /* If there aren't any dynamic relocs in read-only sections nor
-     R_386_GOTOFF relocation, then we can keep the dynamic relocs and
-     avoid the copy reloc.  This doesn't work on VxWorks, where we can
-     not have dynamic relocations (other than copy and jump slot
-     relocations) in an executable.  */
-  if (ELIMINATE_COPY_RELOCS
-      && !eh->gotoff_ref
-      && get_elf_i386_backend_data (info->output_bfd)->os != is_vxworks)
-    {
-      for (p = eh->dyn_relocs; p != NULL; p = p->next)
-       {
-         s = p->sec->output_section;
-         if (s != NULL && (s->flags & SEC_READONLY) != 0)
-           break;
-       }
+/* Return the relocation value for @tpoff relocation
+   if STT_TLS virtual address is ADDRESS.  */
 
-      if (p == NULL)
-       {
-         h->non_got_ref = 0;
-         return TRUE;
-       }
-    }
+static bfd_vma
+elf_i386_tpoff (struct bfd_link_info *info, bfd_vma address)
+{
+  struct elf_link_hash_table *htab = elf_hash_table (info);
+  const struct elf_backend_data *bed = get_elf_backend_data (info->output_bfd);
+  bfd_vma static_tls_size;
 
-  /* We must allocate the symbol in our .dynbss section, which will
-     become part of the .bss section of the executable.  There will be
-     an entry for this symbol in the .dynsym section.  The dynamic
-     object will contain position independent code, so all references
-     from the dynamic object to this symbol will go through the global
-     offset table.  The dynamic linker will use the .dynsym entry to
-     determine the address it must put in the global offset table, so
-     both the dynamic object and the regular object will refer to the
-     same memory location for the variable.  */
-
-  /* We must generate a R_386_COPY reloc to tell the dynamic linker to
-     copy the initial value out of the dynamic object and into the
-     runtime process image.  */
-  if ((h->root.u.def.section->flags & SEC_READONLY) != 0)
-    {
-      s = htab->elf.sdynrelro;
-      srel = htab->elf.sreldynrelro;
-    }
-  else
-    {
-      s = htab->elf.sdynbss;
-      srel = htab->elf.srelbss;
-    }
-  if ((h->root.u.def.section->flags & SEC_ALLOC) != 0 && h->size != 0)
-    {
-      srel->size += sizeof (Elf32_External_Rel);
-      h->needs_copy = 1;
-    }
+  /* If tls_sec is NULL, we should have signalled an error already.  */
+  if (htab->tls_sec == NULL)
+    return 0;
 
-  return _bfd_elf_adjust_dynamic_copy (info, h, s);
+  /* Consider special static TLS alignment requirements.  */
+  static_tls_size = BFD_ALIGN (htab->tls_size, bed->static_tls_alignment);
+  return static_tls_size + htab->tls_sec->vma - address;
 }
 
-/* Allocate space in .plt, .got and associated reloc sections for
-   dynamic relocs.  */
+/* Relocate an i386 ELF section.  */
 
 static bfd_boolean
-elf_i386_allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
+elf_i386_relocate_section (bfd *output_bfd,
+                          struct bfd_link_info *info,
+                          bfd *input_bfd,
+                          asection *input_section,
+                          bfd_byte *contents,
+                          Elf_Internal_Rela *relocs,
+                          Elf_Internal_Sym *local_syms,
+                          asection **local_sections)
 {
-  struct bfd_link_info *info;
   struct elf_x86_link_hash_table *htab;
-  struct elf_x86_link_hash_entry *eh;
-  struct elf_dyn_relocs *p;
+  Elf_Internal_Shdr *symtab_hdr;
+  struct elf_link_hash_entry **sym_hashes;
+  bfd_vma *local_got_offsets;
+  bfd_vma *local_tlsdesc_gotents;
+  Elf_Internal_Rela *rel;
+  Elf_Internal_Rela *wrel;
+  Elf_Internal_Rela *relend;
+  bfd_boolean is_vxworks_tls;
   unsigned plt_entry_size;
-  bfd_boolean resolved_to_zero;
-  const struct elf_i386_backend_data *bed;
-  const struct elf_i386_plt_layout *plt_layout;
-  const struct elf_i386_non_lazy_plt_layout *non_lazy_plt_layout;
-
-  if (h->root.type == bfd_link_hash_indirect)
-    return TRUE;
 
-  eh = (struct elf_x86_link_hash_entry *) h;
+  /* Skip if check_relocs failed.  */
+  if (input_section->check_relocs_failed)
+    return FALSE;
 
-  info = (struct bfd_link_info *) inf;
   htab = elf_x86_hash_table (info, I386_ELF_DATA);
   if (htab == NULL)
     return FALSE;
 
-  bed = get_elf_i386_backend_data (info->output_bfd);
-
-  plt_layout = &elf_i386_plt (htab);
-  non_lazy_plt_layout = elf_i386_non_lazy_plt (htab);
-  plt_entry_size = plt_layout->plt_entry_size;
-
-  resolved_to_zero = UNDEFINED_WEAK_RESOLVED_TO_ZERO (info,
-                                                     I386_ELF_DATA,
-                                                     eh->has_got_reloc,
-                                                     eh);
-
-  /* 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;
-
-  /* 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)
+  if (!is_x86_elf (input_bfd, htab))
     {
-      /* 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
-      && h->def_regular)
-    {
-      if (_bfd_elf_allocate_ifunc_dyn_relocs (info, h, &eh->dyn_relocs,
-                                             &htab->readonly_dynrelocs_against_ifunc,
-                                             plt_entry_size,
-                                             (plt_layout->has_plt0
-                                              * plt_entry_size),
-                                              4, TRUE))
-       {
-         asection *s = htab->plt_second;
-         if (h->plt.offset != (bfd_vma) -1 && s != NULL)
-           {
-             /* Use the second PLT section if it is created.  */
-             eh->plt_second.offset = s->size;
-
-             /* Make room for this entry in the second PLT section.  */
-             s->size += non_lazy_plt_layout->plt_entry_size;
-           }
-
-         return TRUE;
-       }
-      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 > eh->func_pointer_refcount
-              || eh->plt_got.refcount > 0))
-    {
-      bfd_boolean use_plt_got = eh->plt_got.refcount > 0;
-
-      /* Clear the reference count of function pointer relocations
-        if PLT is used.  */
-      eh->func_pointer_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
-         && !resolved_to_zero
-         && h->root.type == bfd_link_hash_undefweak)
-       {
-         if (! bfd_elf_link_record_dynamic_symbol (info, h))
-           return FALSE;
-       }
-
-      if (bfd_link_pic (info)
-         || WILL_CALL_FINISH_DYNAMIC_SYMBOL (1, 0, h))
-       {
-         asection *s = htab->elf.splt;
-         asection *second_s = htab->plt_second;
-         asection *got_s = htab->plt_got;
-
-         /* If this is the first .plt entry, make room for the special
-            first entry.  The .plt section is used by prelink to undo
-            prelinking for dynamic relocations.  */
-         if (s->size == 0)
-           s->size = plt_layout->has_plt0 * plt_entry_size;
-
-         if (use_plt_got)
-           eh->plt_got.offset = got_s->size;
-         else
-           {
-             h->plt.offset = s->size;
-             if (second_s)
-               eh->plt_second.offset = second_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
-            location in the .plt.  This is required to make function
-            pointers compare as equal between the normal executable and
-            the shared library.  */
-         if (! bfd_link_pic (info)
-             && !h->def_regular)
-           {
-             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
-               {
-                 if (second_s)
-                   {
-                     /* We need to make a call to the entry of the
-                        second PLT instead of regular PLT entry.  */
-                     h->root.u.def.section = second_s;
-                     h->root.u.def.value = eh->plt_second.offset;
-                   }
-                 else
-                   {
-                     h->root.u.def.section = s;
-                     h->root.u.def.value = h->plt.offset;
-                   }
-               }
-           }
-
-         /* Make room for this entry.  */
-         if (use_plt_got)
-           got_s->size += non_lazy_plt_layout->plt_entry_size;
-         else
-           {
-             s->size += plt_entry_size;
-             if (second_s)
-               second_s->size += non_lazy_plt_layout->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;
-
-             /* 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 .rel.plt
-                    section.  */
-                 htab->elf.srelplt->size += sizeof (Elf32_External_Rel);
-                 htab->elf.srelplt->reloc_count++;
-               }
-           }
-
-         if (bed->os == is_vxworks && !bfd_link_pic (info))
-           {
-             /* VxWorks has a second set of relocations for each PLT entry
-                in executables.  They go in a separate relocation section,
-                which is processed by the kernel loader.  */
-
-             /* There are two relocations for the initial PLT entry: an
-                R_386_32 relocation for _GLOBAL_OFFSET_TABLE_ + 4 and an
-                R_386_32 relocation for _GLOBAL_OFFSET_TABLE_ + 8.  */
-
-             asection *srelplt2 = elf_i386_srelplt2 (htab);
-             if (h->plt.offset == plt_entry_size)
-               srelplt2->size += (sizeof (Elf32_External_Rel) * 2);
-
-             /* There are two extra relocations for each subsequent PLT entry:
-                an R_386_32 relocation for the GOT entry, and an R_386_32
-                relocation for the PLT entry.  */
-
-             srelplt2->size += (sizeof (Elf32_External_Rel) * 2);
-           }
-       }
-      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;
-    }
-
-  eh->tlsdesc_got = (bfd_vma) -1;
-
-  /* If R_386_TLS_{IE_32,IE,GOTIE} symbol is now local to the binary,
-     make it a R_386_TLS_LE_32 requiring no TLS entry.  */
-  if (h->got.refcount > 0
-      && bfd_link_executable (info)
-      && h->dynindx == -1
-      && (elf_x86_hash_entry (h)->tls_type & GOT_TLS_IE))
-    h->got.offset = (bfd_vma) -1;
-  else if (h->got.refcount > 0)
-    {
-      asection *s;
-      bfd_boolean dyn;
-      int tls_type = elf_x86_hash_entry (h)->tls_type;
-
-      /* 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
-         && !resolved_to_zero
-         && h->root.type == bfd_link_hash_undefweak)
-       {
-         if (! bfd_elf_link_record_dynamic_symbol (info, h))
-           return FALSE;
-       }
-
-      s = htab->elf.sgot;
-      if (GOT_TLS_GDESC_P (tls_type))
-       {
-         eh->tlsdesc_got = htab->elf.sgotplt->size
-           - elf_i386_compute_jump_table_size (htab);
-         htab->elf.sgotplt->size += 8;
-         h->got.offset = (bfd_vma) -2;
-       }
-      if (! GOT_TLS_GDESC_P (tls_type)
-         || GOT_TLS_GD_P (tls_type))
-       {
-         h->got.offset = s->size;
-         s->size += 4;
-         /* R_386_TLS_GD needs 2 consecutive GOT slots.  */
-         if (GOT_TLS_GD_P (tls_type) || tls_type == GOT_TLS_IE_BOTH)
-           s->size += 4;
-       }
-      dyn = htab->elf.dynamic_sections_created;
-      /* R_386_TLS_IE_32 needs one dynamic relocation,
-        R_386_TLS_IE resp. R_386_TLS_GOTIE needs one dynamic relocation,
-        (but if both R_386_TLS_IE_32 and R_386_TLS_IE is present, we
-        need two), R_386_TLS_GD needs one if local symbol and two if
-        global.  No dynamic relocation against resolved undefined weak
-        symbol in executable.  */
-      if (tls_type == GOT_TLS_IE_BOTH)
-       htab->elf.srelgot->size += 2 * sizeof (Elf32_External_Rel);
-      else if ((GOT_TLS_GD_P (tls_type) && h->dynindx == -1)
-              || (tls_type & GOT_TLS_IE))
-       htab->elf.srelgot->size += sizeof (Elf32_External_Rel);
-      else if (GOT_TLS_GD_P (tls_type))
-       htab->elf.srelgot->size += 2 * sizeof (Elf32_External_Rel);
-      else if (! GOT_TLS_GDESC_P (tls_type)
-              && ((ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
-                   && !resolved_to_zero)
-                  || h->root.type != bfd_link_hash_undefweak)
-              && (bfd_link_pic (info)
-                  || WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, 0, h)))
-       htab->elf.srelgot->size += sizeof (Elf32_External_Rel);
-      if (GOT_TLS_GDESC_P (tls_type))
-       htab->elf.srelplt->size += sizeof (Elf32_External_Rel);
-    }
-  else
-    h->got.offset = (bfd_vma) -1;
-
-  if (eh->dyn_relocs == NULL)
-    return TRUE;
-
-  /* In the shared -Bsymbolic case, discard space allocated for
-     dynamic pc-relative relocs against symbols which turn out to be
-     defined in regular objects.  For the normal shared case, discard
-     space for pc-relative relocs that have become local due to symbol
-     visibility changes.  */
-
-  if (bfd_link_pic (info))
-    {
-      /* The only reloc that uses pc_count is R_386_PC32, which will
-        appear on a call or on something like ".long foo - .".  We
-        want calls to protected symbols to resolve directly to the
-        function rather than going via the plt.  If people want
-        function pointer comparisons to work as expected then they
-        should avoid writing assembly like ".long foo - .".  */
-      if (SYMBOL_CALLS_LOCAL (info, h))
-       {
-         struct elf_dyn_relocs **pp;
-
-         for (pp = &eh->dyn_relocs; (p = *pp) != NULL; )
-           {
-             p->count -= p->pc_count;
-             p->pc_count = 0;
-             if (p->count == 0)
-               *pp = p->next;
-             else
-               pp = &p->next;
-           }
-       }
-
-      if (bed->os == is_vxworks)
-       {
-         struct elf_dyn_relocs **pp;
-         for (pp = &eh->dyn_relocs; (p = *pp) != NULL; )
-           {
-             if (strcmp (p->sec->output_section->name, ".tls_vars") == 0)
-               *pp = p->next;
-             else
-               pp = &p->next;
-           }
-       }
-
-      /* Also discard relocs on undefined weak syms with non-default
-        visibility or in PIE.  */
-      if (eh->dyn_relocs != NULL
-         && 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)
-           {
-             if (h->non_got_ref)
-               {
-                 /* Keep dynamic non-GOT/non-PLT relocation so that we
-                    can branch to 0 without PLT.  */
-                 struct elf_dyn_relocs **pp;
-
-                 for (pp = &eh->dyn_relocs; (p = *pp) != NULL; )
-                   if (p->pc_count == 0)
-                     *pp = p->next;
-                   else
-                     {
-                       /* Remove non-R_386_PC32 relocation.  */
-                       p->count = p->pc_count;
-                       pp = &p->next;
-                     }
-
-                 if (eh->dyn_relocs != NULL)
-                   {
-                     /* Make sure undefined weak symbols are output
-                        as dynamic symbols in PIEs for dynamic non-GOT
-                        non-PLT reloations.  */
-                     if (! bfd_elf_link_record_dynamic_symbol (info, h))
-                       return FALSE;
-                   }
-               }
-             else
-               eh->dyn_relocs = NULL;
-           }
-         else if (h->dynindx == -1
-                  && !h->forced_local)
-           {
-             if (! bfd_elf_link_record_dynamic_symbol (info, h))
-               return FALSE;
-           }
-       }
-    }
-  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.  Keep dynamic relocations for run-time function
-        pointer initialization.  */
-
-      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
-                 && (h->root.type == bfd_link_hash_undefweak
-                     || h->root.type == bfd_link_hash_undefined))))
-       {
-         /* 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
-             && !resolved_to_zero
-             && h->root.type == bfd_link_hash_undefweak)
-           {
-             if (! bfd_elf_link_record_dynamic_symbol (info, h))
-               return FALSE;
-           }
-
-         /* If that succeeded, we know we'll be keeping all the
-            relocs.  */
-         if (h->dynindx != -1)
-           goto keep;
-       }
-
-      eh->dyn_relocs = NULL;
-      eh->func_pointer_refcount = 0;
-
-    keep: ;
-    }
-
-  /* Finally, allocate space.  */
-  for (p = eh->dyn_relocs; p != NULL; p = p->next)
-    {
-      asection *sreloc;
-
-      sreloc = elf_section_data (p->sec)->sreloc;
-
-      BFD_ASSERT (sreloc != NULL);
-      sreloc->size += p->count * sizeof (Elf32_External_Rel);
-    }
-
-  return TRUE;
-}
-
-/* Allocate space in .plt, .got and associated reloc sections for
-   local dynamic relocs.  */
-
-static bfd_boolean
-elf_i386_allocate_local_dynrelocs (void **slot, void *inf)
-{
-  struct elf_link_hash_entry *h
-    = (struct elf_link_hash_entry *) *slot;
-
-  if (h->type != STT_GNU_IFUNC
-      || !h->def_regular
-      || !h->ref_regular
-      || !h->forced_local
-      || h->root.type != bfd_link_hash_defined)
-    abort ();
-
-  return elf_i386_allocate_dynrelocs (h, inf);
-}
-
-/* Convert load via the GOT slot to load immediate.  */
-
-static bfd_boolean
-elf_i386_convert_load (bfd *abfd, asection *sec,
-                      struct bfd_link_info *link_info)
-{
-  struct elf_x86_link_hash_table *htab;
-  Elf_Internal_Shdr *symtab_hdr;
-  Elf_Internal_Rela *internal_relocs;
-  Elf_Internal_Rela *irel, *irelend;
-  bfd_byte *contents;
-  bfd_boolean changed;
-  bfd_signed_vma *local_got_refcounts;
-
-  /* Don't even try to convert non-ELF outputs.  */
-  if (!is_elf_hash_table (link_info->hash))
-    return FALSE;
-
-  /* Nothing to do if there is no need or no output.  */
-  if ((sec->flags & (SEC_CODE | SEC_RELOC)) != (SEC_CODE | SEC_RELOC)
-      || sec->need_convert_load == 0
-      || bfd_is_abs_section (sec->output_section))
-    return TRUE;
-
-  symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
-
-  /* Load the relocations for this section.  */
-  internal_relocs = (_bfd_elf_link_read_relocs
-                    (abfd, sec, NULL, (Elf_Internal_Rela *) NULL,
-                     link_info->keep_memory));
-  if (internal_relocs == NULL)
-    return FALSE;
-
-  changed = FALSE;
-  htab = elf_x86_hash_table (link_info, I386_ELF_DATA);
-  local_got_refcounts = elf_local_got_refcounts (abfd);
-
-  /* Get the section contents.  */
-  if (elf_section_data (sec)->this_hdr.contents != NULL)
-    contents = elf_section_data (sec)->this_hdr.contents;
-  else
-    {
-      if (!bfd_malloc_and_get_section (abfd, sec, &contents))
-       goto error_return;
-    }
-
-  irelend = internal_relocs + sec->reloc_count;
-  for (irel = internal_relocs; irel < irelend; irel++)
-    {
-      unsigned int r_type = ELF32_R_TYPE (irel->r_info);
-      unsigned int r_symndx;
-      struct elf_link_hash_entry *h;
-      bfd_boolean converted;
-
-      /* Don't convert R_386_GOT32 since we can't tell if it is applied
-        to "mov $foo@GOT, %reg" which isn't a load via GOT.  */
-      if (r_type != R_386_GOT32X)
-       continue;
-
-      r_symndx = ELF32_R_SYM (irel->r_info);
-      if (r_symndx < symtab_hdr->sh_info)
-       h = _bfd_elf_x86_get_local_sym_hash (htab, sec->owner,
-                                            (const Elf_Internal_Rela *) irel,
-                                            FALSE);
-      else
-       {
-         h = elf_sym_hashes (abfd)[r_symndx - symtab_hdr->sh_info];
-          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 GOT32 relocations.  */
-      if (h != NULL && h->type == STT_GNU_IFUNC)
-       continue;
-
-      converted = FALSE;
-      if (!elf_i386_convert_load_reloc (abfd, symtab_hdr, contents,
-                                       irel, h, &converted, link_info))
-       goto error_return;
-
-      if (converted)
-       {
-         changed = converted;
-         if (h)
-           {
-             if (h->got.refcount > 0)
-               h->got.refcount -= 1;
-           }
-         else
-           {
-             if (local_got_refcounts != NULL
-                 && local_got_refcounts[r_symndx] > 0)
-               local_got_refcounts[r_symndx] -= 1;
-           }
-       }
-    }
-
-  if (contents != NULL
-      && elf_section_data (sec)->this_hdr.contents != contents)
-    {
-      if (!changed && !link_info->keep_memory)
-       free (contents);
-      else
-       {
-         /* Cache the section contents for elf_link_input_bfd.  */
-         elf_section_data (sec)->this_hdr.contents = contents;
-       }
-    }
-
-  if (elf_section_data (sec)->relocs != internal_relocs)
-    {
-      if (!changed)
-       free (internal_relocs);
-      else
-       elf_section_data (sec)->relocs = internal_relocs;
-    }
-
-  return TRUE;
-
- error_return:
-  if (contents != NULL
-      && elf_section_data (sec)->this_hdr.contents != contents)
-    free (contents);
-  if (internal_relocs != NULL
-      && elf_section_data (sec)->relocs != internal_relocs)
-    free (internal_relocs);
-  return FALSE;
-}
-
-/* Set the sizes of the dynamic sections.  */
-
-static bfd_boolean
-elf_i386_size_dynamic_sections (bfd *output_bfd, struct bfd_link_info *info)
-{
-  struct elf_x86_link_hash_table *htab;
-  bfd *dynobj;
-  asection *s;
-  bfd_boolean relocs;
-  bfd *ibfd;
-
-  htab = elf_x86_hash_table (info, I386_ELF_DATA);
-  if (htab == NULL)
-    return FALSE;
-  dynobj = htab->elf.dynobj;
-  if (dynobj == NULL)
-    abort ();
-
-  /* Set up .got offsets for local syms, and space for local dynamic
-     relocs.  */
-  for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next)
-    {
-      bfd_signed_vma *local_got;
-      bfd_signed_vma *end_local_got;
-      char *local_tls_type;
-      bfd_vma *local_tlsdesc_gotent;
-      bfd_size_type locsymcount;
-      Elf_Internal_Shdr *symtab_hdr;
-      asection *srel;
-
-      if (! is_i386_elf (ibfd))
-       continue;
-
-      for (s = ibfd->sections; s != NULL; s = s->next)
-       {
-         struct elf_dyn_relocs *p;
-
-         if (!elf_i386_convert_load (ibfd, s, info))
-           return FALSE;
-
-         for (p = ((struct elf_dyn_relocs *)
-                    elf_section_data (s)->local_dynrel);
-              p != NULL;
-              p = p->next)
-           {
-             if (!bfd_is_abs_section (p->sec)
-                 && bfd_is_abs_section (p->sec->output_section))
-               {
-                 /* Input section has been discarded, either because
-                    it is a copy of a linkonce section or due to
-                    linker script /DISCARD/, so we'll be discarding
-                    the relocs too.  */
-               }
-             else if ((get_elf_i386_backend_data (output_bfd)->os
-                       == is_vxworks)
-                      && strcmp (p->sec->output_section->name,
-                                 ".tls_vars") == 0)
-               {
-                 /* Relocations in vxworks .tls_vars sections are
-                    handled specially by the loader.  */
-               }
-             else if (p->count != 0)
-               {
-                 srel = elf_section_data (p->sec)->sreloc;
-                 srel->size += p->count * sizeof (Elf32_External_Rel);
-                 if ((p->sec->output_section->flags & SEC_READONLY) != 0
-                     && (info->flags & DF_TEXTREL) == 0)
-                   {
-                     info->flags |= DF_TEXTREL;
-                     if ((info->warn_shared_textrel && bfd_link_pic (info))
-                         || info->error_textrel)
-                       /* xgettext:c-format */
-                       info->callbacks->einfo (_("%P: %B: warning: relocation in readonly section `%A'\n"),
-                                               p->sec->owner, p->sec);
-                   }
-               }
-           }
-       }
-
-      local_got = elf_local_got_refcounts (ibfd);
-      if (!local_got)
-       continue;
-
-      symtab_hdr = &elf_symtab_hdr (ibfd);
-      locsymcount = symtab_hdr->sh_info;
-      end_local_got = local_got + locsymcount;
-      local_tls_type = elf_x86_local_got_tls_type (ibfd);
-      local_tlsdesc_gotent = elf_x86_local_tlsdesc_gotent (ibfd);
-      s = htab->elf.sgot;
-      srel = htab->elf.srelgot;
-      for (; local_got < end_local_got;
-          ++local_got, ++local_tls_type, ++local_tlsdesc_gotent)
-       {
-         *local_tlsdesc_gotent = (bfd_vma) -1;
-         if (*local_got > 0)
-           {
-             if (GOT_TLS_GDESC_P (*local_tls_type))
-               {
-                 *local_tlsdesc_gotent = htab->elf.sgotplt->size
-                   - elf_i386_compute_jump_table_size (htab);
-                 htab->elf.sgotplt->size += 8;
-                 *local_got = (bfd_vma) -2;
-               }
-             if (! GOT_TLS_GDESC_P (*local_tls_type)
-                 || GOT_TLS_GD_P (*local_tls_type))
-               {
-                 *local_got = s->size;
-                 s->size += 4;
-                 if (GOT_TLS_GD_P (*local_tls_type)
-                     || *local_tls_type == GOT_TLS_IE_BOTH)
-                   s->size += 4;
-               }
-             if (bfd_link_pic (info)
-                 || GOT_TLS_GD_ANY_P (*local_tls_type)
-                 || (*local_tls_type & GOT_TLS_IE))
-               {
-                 if (*local_tls_type == GOT_TLS_IE_BOTH)
-                   srel->size += 2 * sizeof (Elf32_External_Rel);
-                 else if (GOT_TLS_GD_P (*local_tls_type)
-                          || ! GOT_TLS_GDESC_P (*local_tls_type))
-                   srel->size += sizeof (Elf32_External_Rel);
-                 if (GOT_TLS_GDESC_P (*local_tls_type))
-                   htab->elf.srelplt->size += sizeof (Elf32_External_Rel);
-               }
-           }
-         else
-           *local_got = (bfd_vma) -1;
-       }
-    }
-
-  if (htab->tls_ld_or_ldm_got.refcount > 0)
-    {
-      /* Allocate 2 got entries and 1 dynamic reloc for R_386_TLS_LDM
-        relocs.  */
-      htab->tls_ld_or_ldm_got.offset = htab->elf.sgot->size;
-      htab->elf.sgot->size += 8;
-      htab->elf.srelgot->size += sizeof (Elf32_External_Rel);
-    }
-  else
-    htab->tls_ld_or_ldm_got.offset = -1;
-
-  /* Allocate global sym .plt and .got entries, and space for global
-     sym dynamic relocs.  */
-  elf_link_hash_traverse (&htab->elf, elf_i386_allocate_dynrelocs, info);
-
-  /* Allocate .plt and .got entries, and space for local symbols.  */
-  htab_traverse (htab->loc_hash_table,
-                elf_i386_allocate_local_dynrelocs,
-                info);
-
-  /* For every jump slot reserved in the sgotplt, reloc_count is
-     incremented.  However, when we reserve space for TLS descriptors,
-     it's not incremented, so in order to compute the space reserved
-     for them, it suffices to multiply the reloc count by the jump
-     slot size.
-
-     PR ld/13302: We start next_irelative_index at the end of .rela.plt
-     so that R_386_IRELATIVE entries come last.  */
-  if (htab->elf.srelplt)
-    {
-      elf_i386_next_tls_desc_index(htab)
-       = htab->elf.srelplt->reloc_count;
-      htab->sgotplt_jump_table_size
-       = elf_i386_next_tls_desc_index(htab) * 4;
-      htab->next_irelative_index = htab->elf.srelplt->reloc_count - 1;
-    }
-  else if (htab->elf.irelplt)
-    htab->next_irelative_index = htab->elf.irelplt->reloc_count - 1;
-
-
-  if (htab->elf.sgotplt)
-    {
-      /* Don't allocate .got.plt section if there are no GOT nor PLT
-         entries and there is no reference to _GLOBAL_OFFSET_TABLE_.  */
-      if ((htab->elf.hgot == NULL
-          || !htab->elf.hgot->ref_regular_nonweak)
-         && (htab->elf.sgotplt->size
-             == get_elf_backend_data (output_bfd)->got_header_size)
-         && (htab->elf.splt == NULL
-             || htab->elf.splt->size == 0)
-         && (htab->elf.sgot == NULL
-             || htab->elf.sgot->size == 0)
-         && (htab->elf.iplt == NULL
-             || htab->elf.iplt->size == 0)
-         && (htab->elf.igotplt == NULL
-             || htab->elf.igotplt->size == 0))
-       htab->elf.sgotplt->size = 0;
-    }
-
-  if (_bfd_elf_eh_frame_present (info))
-    {
-      if (htab->plt_eh_frame != NULL
-         && htab->elf.splt != NULL
-         && htab->elf.splt->size != 0
-         && !bfd_is_abs_section (htab->elf.splt->output_section))
-       htab->plt_eh_frame->size = elf_i386_plt (htab).eh_frame_plt_size;
-
-      if (htab->plt_got_eh_frame != NULL
-         && htab->plt_got != NULL
-         && htab->plt_got->size != 0
-         && !bfd_is_abs_section (htab->plt_got->output_section))
-       htab->plt_got_eh_frame->size
-         = elf_i386_non_lazy_plt (htab)->eh_frame_plt_size;
-
-      /* Unwind info for the second PLT and .plt.got sections are
-        identical.  */
-      if (htab->plt_second_eh_frame != NULL
-         && htab->plt_second != NULL
-         && htab->plt_second->size != 0
-         && !bfd_is_abs_section (htab->plt_second->output_section))
-       htab->plt_second_eh_frame->size
-         = elf_i386_non_lazy_plt (htab)->eh_frame_plt_size;
-    }
-
-  /* We now have determined the sizes of the various dynamic sections.
-     Allocate memory for them.  */
-  relocs = FALSE;
-  for (s = dynobj->sections; s != NULL; s = s->next)
-    {
-      bfd_boolean strip_section = TRUE;
-
-      if ((s->flags & SEC_LINKER_CREATED) == 0)
-       continue;
-
-      if (s == htab->elf.splt
-         || s == htab->elf.sgot)
-       {
-         /* Strip this section if we don't need it; see the
-            comment below.  */
-         /* We'd like to strip these sections if they aren't needed, but if
-            we've exported dynamic symbols from them we must leave them.
-            It's too late to tell BFD to get rid of the symbols.  */
-
-         if (htab->elf.hplt != NULL)
-           strip_section = FALSE;
-       }
-      else if (s == htab->elf.sgotplt
-              || s == htab->elf.iplt
-              || s == htab->elf.igotplt
-              || s == htab->plt_second
-              || s == htab->plt_got
-              || s == htab->plt_eh_frame
-              || s == htab->plt_got_eh_frame
-              || s == htab->plt_second_eh_frame
-              || s == htab->elf.sdynbss
-              || s == htab->elf.sdynrelro)
-       {
-         /* Strip these too.  */
-       }
-      else if (CONST_STRNEQ (bfd_get_section_name (dynobj, s), ".rel"))
-       {
-         if (s->size != 0
-             && s != htab->elf.srelplt
-             && s != elf_i386_srelplt2 (htab))
-           relocs = TRUE;
-
-         /* We use the reloc_count field as a counter if we need
-            to copy relocs into the output file.  */
-         s->reloc_count = 0;
-       }
-      else
-       {
-         /* It's not one of our sections, so don't allocate space.  */
-         continue;
-       }
-
-      if (s->size == 0)
-       {
-         /* If we don't need this section, strip it from the
-            output file.  This is mostly to handle .rel.bss and
-            .rel.plt.  We must create both sections in
-            create_dynamic_sections, because they must be created
-            before the linker maps input sections to output
-            sections.  The linker does that before
-            adjust_dynamic_symbol is called, and it is that
-            function which decides whether anything needs to go
-            into these sections.  */
-         if (strip_section)
-           s->flags |= SEC_EXCLUDE;
-         continue;
-       }
-
-      if ((s->flags & SEC_HAS_CONTENTS) == 0)
-       continue;
-
-      /* Allocate memory for the section contents.  We use bfd_zalloc
-        here in case unused entries are not reclaimed before the
-        section's contents are written out.  This should not happen,
-        but this way if it does, we get a R_386_NONE reloc instead
-        of garbage.  */
-      s->contents = (unsigned char *) bfd_zalloc (dynobj, s->size);
-      if (s->contents == NULL)
-       return FALSE;
-    }
-
-  if (htab->plt_eh_frame != NULL
-      && htab->plt_eh_frame->contents != NULL)
-    {
-      memcpy (htab->plt_eh_frame->contents,
-             elf_i386_plt (htab).eh_frame_plt,
-             htab->plt_eh_frame->size);
-      bfd_put_32 (dynobj, htab->elf.splt->size,
-                 htab->plt_eh_frame->contents + PLT_FDE_LEN_OFFSET);
-    }
-
-  if (htab->plt_got_eh_frame != NULL
-      && htab->plt_got_eh_frame->contents != NULL)
-    {
-      memcpy (htab->plt_got_eh_frame->contents,
-             elf_i386_non_lazy_plt (htab)->eh_frame_plt,
-             htab->plt_got_eh_frame->size);
-      bfd_put_32 (dynobj, htab->plt_got->size,
-                 (htab->plt_got_eh_frame->contents
-                  + PLT_FDE_LEN_OFFSET));
-    }
-
-  if (htab->plt_second_eh_frame != NULL
-      && htab->plt_second_eh_frame->contents != NULL)
-    {
-      memcpy (htab->plt_second_eh_frame->contents,
-             elf_i386_non_lazy_plt (htab)->eh_frame_plt,
-             htab->plt_second_eh_frame->size);
-      bfd_put_32 (dynobj, htab->plt_second->size,
-                 (htab->plt_second_eh_frame->contents
-                  + PLT_FDE_LEN_OFFSET));
-    }
-
-  if (htab->elf.dynamic_sections_created)
-    {
-      /* Add some entries to the .dynamic section.  We fill in the
-        values later, in elf_i386_finish_dynamic_sections, but we
-        must add the entries now so that we get the correct size for
-        the .dynamic section.  The DT_DEBUG entry is filled in by the
-        dynamic linker and used by the debugger.  */
-#define add_dynamic_entry(TAG, VAL) \
-  _bfd_elf_add_dynamic_entry (info, TAG, VAL)
-
-      if (bfd_link_executable (info))
-       {
-         if (!add_dynamic_entry (DT_DEBUG, 0))
-           return FALSE;
-       }
-
-      if (htab->elf.splt->size != 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_REL)
-             || !add_dynamic_entry (DT_JMPREL, 0))
-           return FALSE;
-       }
-
-      if (relocs)
-       {
-         if (!add_dynamic_entry (DT_REL, 0)
-             || !add_dynamic_entry (DT_RELSZ, 0)
-             || !add_dynamic_entry (DT_RELENT, sizeof (Elf32_External_Rel)))
-           return FALSE;
-
-         /* If any dynamic relocs apply to a read-only section,
-            then we need a DT_TEXTREL entry.  */
-         if ((info->flags & DF_TEXTREL) == 0)
-           elf_link_hash_traverse (&htab->elf,
-                                   _bfd_x86_elf_readonly_dynrelocs,
-                                   info);
-
-         if ((info->flags & DF_TEXTREL) != 0)
-           {
-             if (htab->readonly_dynrelocs_against_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;
-           }
-       }
-      if (get_elf_i386_backend_data (output_bfd)->os == is_vxworks
-         && !elf_vxworks_add_dynamic_entries (output_bfd, info))
-       return FALSE;
+      bfd_set_error (bfd_error_wrong_format);
+      return FALSE;
     }
-#undef add_dynamic_entry
-
-  return TRUE;
-}
-
-/* Set the correct type for an x86 ELF section.  We do this by the
-   section name, which is a hack, but ought to work.  */
-
-static bfd_boolean
-elf_i386_fake_sections (bfd *abfd ATTRIBUTE_UNUSED,
-                       Elf_Internal_Shdr *hdr,
-                       asection *sec)
-{
-  const char *name;
-
-  name = bfd_get_section_name (abfd, sec);
 
-  /* This is an ugly, but unfortunately necessary hack that is
-     needed when producing EFI binaries on x86. It tells
-     elf.c:elf_fake_sections() not to consider ".reloc" as a section
-     containing ELF relocation info.  We need this hack in order to
-     be able to generate ELF binaries that can be translated into
-     EFI applications (which are essentially COFF objects).  Those
-     files contain a COFF ".reloc" section inside an ELFNN object,
-     which would normally cause BFD to segfault because it would
-     attempt to interpret this section as containing relocation
-     entries for section "oc".  With this hack enabled, ".reloc"
-     will be treated as a normal data section, which will avoid the
-     segfault.  However, you won't be able to create an ELFNN binary
-     with a section named "oc" that needs relocations, but that's
-     the kind of ugly side-effects you get when detecting section
-     types based on their names...  In practice, this limitation is
-     unlikely to bite.  */
-  if (strcmp (name, ".reloc") == 0)
-    hdr->sh_type = SHT_PROGBITS;
-
-  return TRUE;
-}
-
-/* Return the relocation value for @tpoff relocation
-   if STT_TLS virtual address is ADDRESS.  */
-
-static bfd_vma
-elf_i386_tpoff (struct bfd_link_info *info, bfd_vma address)
-{
-  struct elf_link_hash_table *htab = elf_hash_table (info);
-  const struct elf_backend_data *bed = get_elf_backend_data (info->output_bfd);
-  bfd_vma static_tls_size;
-
-  /* If tls_sec is NULL, we should have signalled an error already.  */
-  if (htab->tls_sec == NULL)
-    return 0;
-
-  /* Consider special static TLS alignment requirements.  */
-  static_tls_size = BFD_ALIGN (htab->tls_size, bed->static_tls_alignment);
-  return static_tls_size + htab->tls_sec->vma - address;
-}
-
-/* Relocate an i386 ELF section.  */
-
-static bfd_boolean
-elf_i386_relocate_section (bfd *output_bfd,
-                          struct bfd_link_info *info,
-                          bfd *input_bfd,
-                          asection *input_section,
-                          bfd_byte *contents,
-                          Elf_Internal_Rela *relocs,
-                          Elf_Internal_Sym *local_syms,
-                          asection **local_sections)
-{
-  struct elf_x86_link_hash_table *htab;
-  Elf_Internal_Shdr *symtab_hdr;
-  struct elf_link_hash_entry **sym_hashes;
-  bfd_vma *local_got_offsets;
-  bfd_vma *local_tlsdesc_gotents;
-  Elf_Internal_Rela *rel;
-  Elf_Internal_Rela *wrel;
-  Elf_Internal_Rela *relend;
-  bfd_boolean is_vxworks_tls;
-  unsigned plt_entry_size;
-
-  BFD_ASSERT (is_i386_elf (input_bfd));
-
-  /* Skip if check_relocs failed.  */
-  if (input_section->check_relocs_failed)
-    return FALSE;
-
-  htab = elf_x86_hash_table (info, I386_ELF_DATA);
-  if (htab == NULL)
-    return FALSE;
   symtab_hdr = &elf_symtab_hdr (input_bfd);
   sym_hashes = elf_sym_hashes (input_bfd);
   local_got_offsets = elf_local_got_offsets (input_bfd);
   local_tlsdesc_gotents = elf_x86_local_tlsdesc_gotent (input_bfd);
   /* We have to handle relocations in vxworks .tls_vars sections
      specially, because the dynamic loader is 'weird'.  */
-  is_vxworks_tls = ((get_elf_i386_backend_data (output_bfd)->os
-                    == is_vxworks)
-                    && bfd_link_pic (info)
+  is_vxworks_tls = (htab->target_os == is_vxworks
+                   && bfd_link_pic (info)
                    && !strcmp (input_section->output_section->name,
                                ".tls_vars"));
 
   _bfd_x86_elf_set_tls_module_base (info);
 
-  plt_entry_size = elf_i386_plt (htab).plt_entry_size;
+  plt_entry_size = htab->plt.plt_entry_size;
 
   rel = wrel = relocs;
   relend = relocs + input_section->reloc_count;
   for (; rel < relend; wrel++, rel++)
     {
-      unsigned int r_type;
+      unsigned int r_type, r_type_tls;
       reloc_howto_type *howto;
       unsigned long r_symndx;
       struct elf_link_hash_entry *h;
@@ -3464,15 +2092,10 @@ elf_i386_relocate_section (bfd *output_bfd,
          continue;
        }
 
-      if ((indx = r_type) >= R_386_standard
-         && ((indx = r_type - R_386_ext_offset) - R_386_standard
-             >= R_386_ext - R_386_standard)
-         && ((indx = r_type - R_386_tls_offset) - R_386_ext
-             >= R_386_ext2 - R_386_ext))
+      howto = elf_i386_rtype_to_howto (r_type);
+      if (howto == NULL)
        return _bfd_unrecognized_reloc (input_bfd, input_section, r_type);
 
-      howto = elf_howto_table + indx;
-
       r_symndx = ELF32_R_SYM (rel->r_info);
       h = NULL;
       sym = NULL;
@@ -3585,7 +2208,7 @@ elf_i386_relocate_section (bfd *output_bfd,
       if (sec != NULL && discarded_section (sec))
        {
          _bfd_clear_contents (howto, input_bfd, input_section,
-                              contents + rel->r_offset);
+                              contents, rel->r_offset);
          wrel->r_offset = rel->r_offset;
          wrel->r_info = 0;
          wrel->r_addend = 0;
@@ -3621,6 +2244,10 @@ elf_i386_relocate_section (bfd *output_bfd,
 
          if ((input_section->flags & SEC_ALLOC) == 0)
            {
+             /* If this is a SHT_NOTE section without SHF_ALLOC, treat
+                STT_GNU_IFUNC symbol as STT_FUNC.  */
+             if (elf_section_type (input_section) == SHT_NOTE)
+               goto skip_ifunc;
              /* Dynamic relocs are not propagated for SEC_DEBUGGING
                 sections because such sections are not SEC_ALLOC and
                 thus ld.so will not process them.  */
@@ -3676,7 +2303,7 @@ elf_i386_relocate_section (bfd *output_bfd,
                  if (htab->elf.splt != NULL)
                    {
                      plt_index = (h->plt.offset / plt_entry_size
-                                  - elf_i386_plt (htab).has_plt0);
+                                  - htab->plt.has_plt0);
                      off = (plt_index + 3) * 4;
                      base_got = htab->elf.sgotplt;
                    }
@@ -3753,7 +2380,7 @@ elf_i386_relocate_section (bfd *output_bfd,
          switch (r_type)
            {
            default:
-bad_ifunc_reloc:
+           bad_ifunc_reloc:
              if (h->root.root.string)
                name = h->root.root.string;
              else
@@ -3761,7 +2388,7 @@ bad_ifunc_reloc:
                                         NULL);
              _bfd_error_handler
                /* xgettext:c-format */
-               (_("%B: relocation %s against STT_GNU_IFUNC "
+               (_("%pB: relocation %s against STT_GNU_IFUNC "
                   "symbol `%s' isn't supported"), input_bfd,
                 howto->name, name);
              bfd_set_error (bfd_error_bad_value);
@@ -3777,7 +2404,7 @@ bad_ifunc_reloc:
                  asection *sreloc;
                  bfd_vma offset;
 
-do_ifunc_pointer:
+               do_ifunc_pointer:
                  /* Need a dynamic relocation to get the real function
                     adddress.  */
                  offset = _bfd_elf_section_offset (output_bfd,
@@ -3792,11 +2419,9 @@ do_ifunc_pointer:
                                     + input_section->output_offset
                                     + offset);
 
-                 if (h->dynindx == -1
-                     || h->forced_local
-                     || bfd_link_executable (info))
+                 if (POINTER_LOCAL_IFUNC_P (info, h))
                    {
-                     info->callbacks->minfo (_("Local IFUNC function `%s' in %B\n"),
+                     info->callbacks->minfo (_("Local IFUNC function `%s' in %pB\n"),
                                              h->root.root.string,
                                              h->root.u.def.section->owner);
 
@@ -3838,79 +2463,18 @@ do_ifunc_pointer:
            case R_386_GOTOFF:
              relocation -= (gotplt->output_section->vma
                             + gotplt->output_offset);
-             goto do_relocation;
-           }
-       }
-
-      resolved_to_zero = (eh != NULL
-                         && UNDEFINED_WEAK_RESOLVED_TO_ZERO (info,
-                                                             I386_ELF_DATA,
-                                                             eh->has_got_reloc,
-                                                             eh));
-
-      switch (r_type)
-       {
-       case R_386_GOT32X:
-         /* Avoid optimizing _DYNAMIC since ld.so may use its
-            link-time address.  */
-         if (h == htab->elf.hdynamic)
-           goto r_386_got32;
-
-         if (bfd_link_pic (info))
-           {
-             /* It is OK to convert mov to lea and convert indirect
-                branch to direct branch.  It is OK to convert adc,
-                add, and, cmp, or, sbb, sub, test, xor only when PIC
-                is false.   */
-             unsigned int opcode, addend;
-             addend = bfd_get_32 (input_bfd, contents + rel->r_offset);
-             if (addend != 0)
-               goto r_386_got32;
-             opcode = bfd_get_8 (input_bfd, contents + rel->r_offset - 2);
-             if (opcode != 0x8b && opcode != 0xff)
-               goto r_386_got32;
-           }
-
-         /* Resolve "mov GOT[(%reg)], %reg",
-            "call/jmp *GOT[(%reg)]", "test %reg, foo@GOT[(%reg)]"
-            and "binop foo@GOT[(%reg)], %reg".  */
-         if (h == NULL
-             || (h->plt.offset == (bfd_vma) -1
-                 && h->got.offset == (bfd_vma) -1)
-             || htab->elf.sgotplt == NULL)
-           abort ();
-
-         offplt = (htab->elf.sgotplt->output_section->vma
-                   + htab->elf.sgotplt->output_offset);
-
-         /* It is relative to .got.plt section.  */
-         if (h->got.offset != (bfd_vma) -1)
-           /* Use GOT entry.  Mask off the least significant bit in
-              GOT offset which may be set by R_386_GOT32 processing
-              below.  */
-           relocation = (htab->elf.sgot->output_section->vma
-                         + htab->elf.sgot->output_offset
-                         + (h->got.offset & ~1) - offplt);
-         else
-           /* Use GOTPLT entry.  */
-           relocation = (h->plt.offset / plt_entry_size
-                         - elf_i386_plt (htab).has_plt0 + 3) * 4;
-
-         if (!bfd_link_pic (info))
-           {
-             /* If not PIC, add the .got.plt section address for
-                baseless addressing.  */
-             unsigned int modrm;
-             modrm = bfd_get_8 (input_bfd, contents + rel->r_offset - 1);
-             if ((modrm & 0xc7) == 0x5)
-               relocation += offplt;
+             goto do_relocation;
            }
+       }
 
-         unresolved_reloc = FALSE;
-         break;
+    skip_ifunc:
+      resolved_to_zero = (eh != NULL
+                         && UNDEFINED_WEAK_RESOLVED_TO_ZERO (info, eh));
 
+      switch (r_type)
+       {
+       case R_386_GOT32X:
        case R_386_GOT32:
-r_386_got32:
          /* Relocation is to the entry for this symbol in the global
             offset table.  */
          if (htab->elf.sgot == NULL)
@@ -3919,26 +2483,13 @@ r_386_got32:
          relative_reloc = FALSE;
          if (h != NULL)
            {
-             bfd_boolean dyn;
-
              off = h->got.offset;
-             dyn = htab->elf.dynamic_sections_created;
-             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))
+             if (RESOLVED_LOCALLY_P (info, h, htab))
                {
-                 /* This is actually a static link, or it is a
-                    -Bsymbolic link and the symbol is defined
-                    locally, or the symbol was forced to be local
-                    because of a version file.  We must initialize
-                    this entry in the global offset table.  Since the
-                    offset must always be a multiple of 4, we use the
-                    least significant bit to record whether we have
-                    initialized it already.
+                 /* We must initialize this entry in the global offset
+                    table.  Since the offset must always be a multiple
+                    of 4, we use the least significant bit to record
+                    whether we have initialized it already.
 
                     When doing a dynamic link, we create a .rel.got
                     relocation entry to initialize the value.  This
@@ -3951,10 +2502,7 @@ r_386_got32:
                                  htab->elf.sgot->contents + off);
                      h->got.offset |= 1;
 
-                     if (h->dynindx == -1
-                         && !h->forced_local
-                         && h->root.type != bfd_link_hash_undefweak
-                         && bfd_link_pic (info))
+                     if (GENERATE_RELATIVE_RELOC_P (info, h))
                        {
                          /* PR ld/21402: If this symbol isn't dynamic
                             in PIC, generate R_386_RELATIVE here.  */
@@ -4021,7 +2569,7 @@ r_386_got32:
                     we don't know what the GOT base is.  */
                  const char *name;
 
-disallow_got32:
+               disallow_got32:
                  if (h == NULL || h->root.root.string == NULL)
                    name = bfd_elf_sym_name (input_bfd, symtab_hdr, sym,
                                             NULL);
@@ -4030,7 +2578,7 @@ disallow_got32:
 
                  _bfd_error_handler
                    /* xgettext:c-format */
-                   (_("%B: direct GOT relocation %s against `%s'"
+                   (_("%pB: direct GOT relocation %s against `%s'"
                       " without base register can not be used"
                       " when making a shared object"),
                     input_bfd, howto->name, name);
@@ -4080,20 +2628,20 @@ disallow_got32:
 
                  _bfd_error_handler
                    /* xgettext:c-format */
-                   (_("%B: relocation R_386_GOTOFF against undefined %s"
+                   (_("%pB: relocation R_386_GOTOFF 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 (!SYMBOL_REFERENCES_LOCAL (info, h)
+             else if (!SYMBOL_REFERENCES_LOCAL_P (info, h)
                       && (h->type == STT_FUNC
                           || h->type == STT_OBJECT)
                       && ELF_ST_VISIBILITY (h->other) == STV_PROTECTED)
                {
                  _bfd_error_handler
                    /* xgettext:c-format */
-                   (_("%B: relocation R_386_GOTOFF against protected %s"
+                   (_("%pB: relocation R_386_GOTOFF against protected %s"
                       " `%s' can not be used when making a shared object"),
                     input_bfd,
                     h->type == STT_FUNC ? "function" : "data",
@@ -4174,29 +2722,9 @@ disallow_got32:
              || is_vxworks_tls)
            break;
 
-         /* Copy dynamic function pointer relocations.  Don't generate
-            dynamic relocations against resolved undefined weak symbols
-            in PIE, except for R_386_PC32.  */
-         if ((bfd_link_pic (info)
-              && (h == NULL
-                  || ((ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
-                       && (!resolved_to_zero
-                           || r_type == R_386_PC32))
-                      || h->root.type != bfd_link_hash_undefweak))
-              && ((r_type != R_386_PC32 && r_type != R_386_SIZE32)
-                  || !SYMBOL_CALLS_LOCAL (info, h)))
-             || (ELIMINATE_COPY_RELOCS
-                 && !bfd_link_pic (info)
-                 && h != NULL
-                 && h->dynindx != -1
-                 && (!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_undefweak)))
+         if (GENERATE_DYNAMIC_RELOCATION_P (info, eh, r_type, sec,
+                                            FALSE, resolved_to_zero,
+                                            (r_type == R_386_PC32)))
            {
              Elf_Internal_Rela outrel;
              bfd_boolean skip, relocate;
@@ -4221,12 +2749,7 @@ disallow_got32:
 
              if (skip)
                memset (&outrel, 0, sizeof outrel);
-             else if (h != NULL
-                      && h->dynindx != -1
-                      && (r_type == R_386_PC32
-                          || !(bfd_link_executable (info)
-                               || SYMBOLIC_BIND (info, h))
-                          || !h->def_regular))
+             else if (COPY_INPUT_RELOC_P (info, h, r_type))
                outrel.r_info = ELF32_R_INFO (h->dynindx, r_type);
              else
                {
@@ -4284,17 +2807,18 @@ disallow_got32:
          if (tls_type == GOT_TLS_IE)
            tls_type = GOT_TLS_IE_NEG;
 
+          r_type_tls = r_type;
          if (! elf_i386_tls_transition (info, input_bfd,
                                         input_section, contents,
                                         symtab_hdr, sym_hashes,
-                                        &r_type, tls_type, rel,
+                                        &r_type_tls, tls_type, rel,
                                         relend, h, r_symndx, TRUE))
            return FALSE;
 
-         if (r_type == R_386_TLS_LE_32)
+         if (r_type_tls == R_386_TLS_LE_32)
            {
              BFD_ASSERT (! unresolved_reloc);
-             if (ELF32_R_TYPE (rel->r_info) == R_386_TLS_GD)
+             if (r_type == R_386_TLS_GD)
                {
                  unsigned int type;
                  bfd_vma roff;
@@ -4337,7 +2861,7 @@ disallow_got32:
                  wrel++;
                  continue;
                }
-             else if (ELF32_R_TYPE (rel->r_info) == R_386_TLS_GOTDESC)
+             else if (r_type == R_386_TLS_GOTDESC)
                {
                  /* GDesc -> LE transition.
                     It's originally something like:
@@ -4362,7 +2886,7 @@ disallow_got32:
                              contents + roff);
                  continue;
                }
-             else if (ELF32_R_TYPE (rel->r_info) == R_386_TLS_DESC_CALL)
+             else if (r_type == R_386_TLS_DESC_CALL)
                {
                  /* GDesc -> LE transition.
                     It's originally:
@@ -4377,7 +2901,7 @@ disallow_got32:
                  bfd_put_8 (output_bfd, 0x90, contents + roff + 1);
                  continue;
                }
-             else if (ELF32_R_TYPE (rel->r_info) == R_386_TLS_IE)
+             else if (r_type == R_386_TLS_IE)
                {
                  unsigned int val;
 
@@ -4471,7 +2995,7 @@ disallow_got32:
                    }
                  else
                    BFD_FAIL ();
-                 if (ELF32_R_TYPE (rel->r_info) == R_386_TLS_GOTIE)
+                 if (r_type == R_386_TLS_GOTIE)
                    bfd_put_32 (output_bfd, -elf_i386_tpoff (info, relocation),
                                contents + rel->r_offset);
                  else
@@ -4523,7 +3047,7 @@ disallow_got32:
                                     + htab->sgotplt_jump_table_size);
                  sreloc = htab->elf.srelplt;
                  loc = sreloc->contents;
-                 loc += (elf_i386_next_tls_desc_index (htab)++
+                 loc += (htab->next_tls_desc_index++
                          * sizeof (Elf32_External_Rel));
                  BFD_ASSERT (loc + sizeof (Elf32_External_Rel)
                              <= sreloc->contents + sreloc->size);
@@ -4577,7 +3101,7 @@ disallow_got32:
                {
                  if (indx == 0)
                    {
-                     BFD_ASSERT (! unresolved_reloc);
+                     BFD_ASSERT (! unresolved_reloc);
                      bfd_put_32 (output_bfd,
                                  relocation - _bfd_x86_elf_dtpoff_base (info),
                                  htab->elf.sgot->contents + off + 4);
@@ -4614,13 +3138,13 @@ disallow_got32:
          if (off >= (bfd_vma) -2
              && ! GOT_TLS_GDESC_P (tls_type))
            abort ();
-         if (r_type == R_386_TLS_GOTDESC
-             || r_type == R_386_TLS_DESC_CALL)
+         if (r_type_tls == R_386_TLS_GOTDESC
+             || r_type_tls == R_386_TLS_DESC_CALL)
            {
              relocation = htab->sgotplt_jump_table_size + offplt;
              unresolved_reloc = FALSE;
            }
-         else if (r_type == ELF32_R_TYPE (rel->r_info))
+         else if (r_type_tls == r_type)
            {
              bfd_vma g_o_t = htab->elf.sgotplt->output_section->vma
                              + htab->elf.sgotplt->output_offset;
@@ -4633,7 +3157,7 @@ disallow_got32:
                relocation += g_o_t;
              unresolved_reloc = FALSE;
            }
-         else if (ELF32_R_TYPE (rel->r_info) == R_386_TLS_GD)
+         else if (r_type == R_386_TLS_GD)
            {
              unsigned int val, type;
              bfd_vma roff;
@@ -4689,7 +3213,7 @@ disallow_got32:
              wrel++;
              continue;
            }
-         else if (ELF32_R_TYPE (rel->r_info) == R_386_TLS_GOTDESC)
+         else if (r_type == R_386_TLS_GOTDESC)
            {
              /* GDesc -> IE transition.
                 It's originally something like:
@@ -4728,7 +3252,7 @@ disallow_got32:
                          contents + roff);
              continue;
            }
-         else if (ELF32_R_TYPE (rel->r_info) == R_386_TLS_DESC_CALL)
+         else if (r_type == R_386_TLS_DESC_CALL)
            {
              /* GDesc -> IE transition.
                 It's originally:
@@ -4894,21 +3418,21 @@ disallow_got32:
        {
          _bfd_error_handler
            /* xgettext:c-format */
-           (_("%B(%A+%#Lx): unresolvable %s relocation against symbol `%s'"),
+           (_("%pB(%pA+%#" PRIx64 "): unresolvable %s relocation against symbol `%s'"),
             input_bfd,
             input_section,
-            rel->r_offset,
+            (uint64_t) rel->r_offset,
             howto->name,
             h->root.root.string);
          return FALSE;
        }
 
-do_relocation:
+    do_relocation:
       r = _bfd_final_link_relocate (howto, input_bfd, input_section,
                                    contents, rel->r_offset,
                                    relocation, 0);
 
-check_relocation_error:
+    check_relocation_error:
       if (r != bfd_reloc_ok)
        {
          const char *name;
@@ -4923,7 +3447,7 @@ check_relocation_error:
              if (name == NULL)
                return FALSE;
              if (*name == '\0')
-               name = bfd_section_name (input_bfd, sec);
+               name = bfd_section_name (sec);
            }
 
          if (r == bfd_reloc_overflow)
@@ -4934,9 +3458,9 @@ check_relocation_error:
            {
              _bfd_error_handler
                /* xgettext:c-format */
-               (_("%B(%A+%#Lx): reloc against `%s': error %d"),
+               (_("%pB(%pA+%#" PRIx64 "): reloc against `%s': error %d"),
                 input_bfd, input_section,
-                rel->r_offset, name, (int) r);
+                (uint64_t) rel->r_offset, name, (int) r);
              return FALSE;
            }
        }
@@ -4979,23 +3503,15 @@ elf_i386_finish_dynamic_symbol (bfd *output_bfd,
 {
   struct elf_x86_link_hash_table *htab;
   unsigned plt_entry_size;
-  const struct elf_i386_backend_data *abed;
   struct elf_x86_link_hash_entry *eh;
   bfd_boolean local_undefweak;
   bfd_boolean use_plt_second;
-  const struct elf_i386_plt_layout *plt_layout;
-  const struct elf_i386_lazy_plt_layout *lazy_plt_layout;
-  const struct elf_i386_non_lazy_plt_layout *non_lazy_plt_layout;
 
   htab = elf_x86_hash_table (info, I386_ELF_DATA);
   if (htab == NULL)
     return FALSE;
 
-  abed = get_elf_i386_backend_data (output_bfd);
-  plt_layout = &elf_i386_plt (htab);
-  lazy_plt_layout = elf_i386_lazy_plt (htab);
-  non_lazy_plt_layout = elf_i386_non_lazy_plt (htab);
-  plt_entry_size = plt_layout->plt_entry_size;
+  plt_entry_size = htab->plt.plt_entry_size;
 
   /* Use the second PLT section only if there is .plt section.  */
   use_plt_second = htab->elf.splt != NULL && htab->plt_second != NULL;
@@ -5007,9 +3523,7 @@ elf_i386_finish_dynamic_symbol (bfd *output_bfd,
   /* 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, I386_ELF_DATA,
-                                                    eh->has_got_reloc,
-                                                    eh);
+  local_undefweak = UNDEFINED_WEAK_RESOLVED_TO_ZERO (info, eh);
 
   if (h->plt.offset != (bfd_vma) -1)
     {
@@ -5034,18 +3548,7 @@ elf_i386_finish_dynamic_symbol (bfd *output_bfd,
          relplt = htab->elf.irelplt;
        }
 
-      /* This symbol has an entry in the procedure linkage table.  Set
-        it up.  */
-
-      if ((h->dynindx == -1
-          && !local_undefweak
-          && !((h->forced_local || bfd_link_executable (info))
-               && h->def_regular
-               && h->type == STT_GNU_IFUNC))
-         || plt == NULL
-         || gotplt == NULL
-         || relplt == NULL)
-       abort ();
+      VERIFY_PLT_ENTRY (info, h, plt, gotplt, relplt, local_undefweak)
 
       /* Get the index in the procedure linkage table which
         corresponds to this symbol.  This is the index of this symbol
@@ -5061,7 +3564,7 @@ elf_i386_finish_dynamic_symbol (bfd *output_bfd,
       if (plt == htab->elf.splt)
        {
          got_offset = (h->plt.offset / plt_entry_size
-                       - plt_layout->has_plt0);
+                       - htab->plt.has_plt0);
          got_offset = (got_offset + 3) * 4;
        }
       else
@@ -5072,18 +3575,18 @@ elf_i386_finish_dynamic_symbol (bfd *output_bfd,
 
       /* Fill in the entry in the procedure linkage table and update
         the first slot.  */
-      memcpy (plt->contents + h->plt.offset, plt_layout->plt_entry,
+      memcpy (plt->contents + h->plt.offset, htab->plt.plt_entry,
              plt_entry_size);
 
       if (use_plt_second)
        {
          const bfd_byte *plt_entry;
          if (bfd_link_pic (info))
-           plt_entry = non_lazy_plt_layout->pic_plt_entry;
+           plt_entry = htab->non_lazy_plt->pic_plt_entry;
          else
-           plt_entry = non_lazy_plt_layout->plt_entry;
+           plt_entry = htab->non_lazy_plt->plt_entry;
          memcpy (htab->plt_second->contents + eh->plt_second.offset,
-                 plt_entry, non_lazy_plt_layout->plt_entry_size);
+                 plt_entry, htab->non_lazy_plt->plt_entry_size);
 
          resolved_plt = htab->plt_second;
          plt_offset = eh->plt_second.offset;
@@ -5101,9 +3604,9 @@ elf_i386_finish_dynamic_symbol (bfd *output_bfd,
                       + gotplt->output_offset
                       + got_offset),
                      resolved_plt->contents + plt_offset
-                      + plt_layout->plt_got_offset);
+                     + htab->plt.plt_got_offset);
 
-         if (abed->os == is_vxworks)
+         if (htab->target_os == is_vxworks)
            {
              int s, k, reloc_index;
 
@@ -5111,8 +3614,8 @@ elf_i386_finish_dynamic_symbol (bfd *output_bfd,
                 for this PLT entry.  */
 
              /* S: Current slot number (zero-based).  */
-             s = ((h->plt.offset - plt_layout->plt_entry_size)
-                   / plt_layout->plt_entry_size);
+             s = ((h->plt.offset - htab->plt.plt_entry_size)
+                  / htab->plt.plt_entry_size);
              /* K: Number of relocations for PLTResolve. */
              if (bfd_link_pic (info))
                k = PLTRESOLVE_RELOCS_SHLIB;
@@ -5121,7 +3624,7 @@ elf_i386_finish_dynamic_symbol (bfd *output_bfd,
              /* Skip the PLTresolve relocations, and the relocations for
                 the other PLT slots. */
              reloc_index = k + s * PLT_NON_JUMP_SLOT_RELOCS;
-             loc = (elf_i386_srelplt2 (htab)->contents + reloc_index
+             loc = (htab->srelplt2->contents + reloc_index
                     * sizeof (Elf32_External_Rel));
 
              rel.r_offset = (plt->output_section->vma
@@ -5144,7 +3647,7 @@ elf_i386_finish_dynamic_symbol (bfd *output_bfd,
        {
          bfd_put_32 (output_bfd, got_offset,
                      resolved_plt->contents + plt_offset
-                      + plt_layout->plt_got_offset);
+                     + htab->plt.plt_got_offset);
        }
 
       /* Fill in the entry in the global offset table.  Leave the entry
@@ -5152,25 +3655,21 @@ elf_i386_finish_dynamic_symbol (bfd *output_bfd,
         against undefined weak symbol in PIE.  */
       if (!local_undefweak)
        {
-         if (plt_layout->has_plt0)
+         if (htab->plt.has_plt0)
            bfd_put_32 (output_bfd,
                        (plt->output_section->vma
                         + plt->output_offset
                         + h->plt.offset
-                        + lazy_plt_layout->plt_lazy_offset),
+                        + htab->lazy_plt->plt_lazy_offset),
                        gotplt->contents + got_offset);
 
          /* Fill in the entry in the .rel.plt section.  */
          rel.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 (PLT_LOCAL_IFUNC_P (info, h))
            {
-             info->callbacks->minfo (_("Local IFUNC function `%s' in %B\n"),
+             info->callbacks->minfo (_("Local IFUNC function `%s' in %pB\n"),
                                      h->root.root.string,
                                      h->root.u.def.section->owner);
 
@@ -5197,17 +3696,17 @@ elf_i386_finish_dynamic_symbol (bfd *output_bfd,
 
          /* Don't fill the second and third slots in PLT entry for
             static executables nor without PLT0.  */
-         if (plt == htab->elf.splt && plt_layout->has_plt0)
+         if (plt == htab->elf.splt && htab->plt.has_plt0)
            {
              bfd_put_32 (output_bfd,
                          plt_index * sizeof (Elf32_External_Rel),
                          plt->contents + h->plt.offset
-                         + lazy_plt_layout->plt_reloc_offset);
+                         + htab->lazy_plt->plt_reloc_offset);
              bfd_put_32 (output_bfd,
                          - (h->plt.offset
-                            + lazy_plt_layout->plt_plt_offset + 4),
+                            + htab->lazy_plt->plt_plt_offset + 4),
                          (plt->contents + h->plt.offset
-                          + lazy_plt_layout->plt_plt_offset));
+                          + htab->lazy_plt->plt_plt_offset));
            }
        }
     }
@@ -5232,12 +3731,12 @@ elf_i386_finish_dynamic_symbol (bfd *output_bfd,
       /* Fill in the entry in the GOT procedure linkage table.  */
       if (! bfd_link_pic (info))
        {
-         got_plt_entry = non_lazy_plt_layout->plt_entry;
+         got_plt_entry = htab->non_lazy_plt->plt_entry;
          got_offset += got->output_section->vma + got->output_offset;
        }
       else
        {
-         got_plt_entry = non_lazy_plt_layout->pic_plt_entry;
+         got_plt_entry = htab->non_lazy_plt->pic_plt_entry;
          got_offset += (got->output_section->vma
                         + got->output_offset
                         - gotplt->output_section->vma
@@ -5246,10 +3745,10 @@ elf_i386_finish_dynamic_symbol (bfd *output_bfd,
 
       plt_offset = eh->plt_got.offset;
       memcpy (plt->contents + plt_offset, got_plt_entry,
-             non_lazy_plt_layout->plt_entry_size);
+             htab->non_lazy_plt->plt_entry_size);
       bfd_put_32 (output_bfd, got_offset,
                  (plt->contents + plt_offset
-                  + non_lazy_plt_layout->plt_got_offset));
+                  + htab->non_lazy_plt->plt_got_offset));
     }
 
   if (!local_undefweak
@@ -5270,6 +3769,8 @@ elf_i386_finish_dynamic_symbol (bfd *output_bfd,
        sym->st_value = 0;
     }
 
+  _bfd_x86_elf_link_fixup_ifunc_symbol (info, htab, h, sym);
+
   /* Don't generate dynamic GOT relocation against undefined weak
      symbol in executable.  */
   if (h->got.offset != (bfd_vma) -1
@@ -5307,9 +3808,9 @@ elf_i386_finish_dynamic_symbol (bfd *output_bfd,
                     in static executable.  */
                  relgot = htab->elf.irelplt;
                }
-             if (SYMBOL_REFERENCES_LOCAL (info, h))
+             if (SYMBOL_REFERENCES_LOCAL_P (info, h))
                {
-                 info->callbacks->minfo (_("Local IFUNC function `%s' in %B\n"),
+                 info->callbacks->minfo (_("Local IFUNC function `%s' in %pB\n"),
                                          h->root.root.string,
                                          h->root.u.def.section->owner);
 
@@ -5357,7 +3858,7 @@ elf_i386_finish_dynamic_symbol (bfd *output_bfd,
            }
        }
       else if (bfd_link_pic (info)
-              && SYMBOL_REFERENCES_LOCAL (info, h))
+              && SYMBOL_REFERENCES_LOCAL_P (info, h))
        {
          BFD_ASSERT((h->got.offset & 1) != 0);
          rel.r_info = ELF32_R_INFO (0, R_386_RELATIVE);
@@ -5365,7 +3866,7 @@ elf_i386_finish_dynamic_symbol (bfd *output_bfd,
       else
        {
          BFD_ASSERT((h->got.offset & 1) == 0);
-do_glob_dat:
+       do_glob_dat:
          bfd_put_32 (output_bfd, (bfd_vma) 0,
                      htab->elf.sgot->contents + h->got.offset);
          rel.r_info = ELF32_R_INFO (h->dynindx, R_386_GLOB_DAT);
@@ -5380,13 +3881,7 @@ do_glob_dat:
       asection *s;
 
       /* This symbol needs a copy reloc.  Set it up.  */
-
-      if (h->dynindx == -1
-         || (h->root.type != bfd_link_hash_defined
-             && h->root.type != bfd_link_hash_defweak)
-         || htab->elf.srelbss == NULL
-         || htab->elf.sreldynrelro == NULL)
-       abort ();
+      VERIFY_COPY_RELOC (h, htab)
 
       rel.r_offset = (h->root.u.def.value
                      + h->root.u.def.section->output_section->vma
@@ -5433,7 +3928,7 @@ elf_i386_pie_finish_undefweak_symbol (struct bfd_hash_entry *bh,
     return TRUE;
 
   return elf_i386_finish_dynamic_symbol (info->output_bfd,
-                                            info, h, NULL);
+                                        info, h, NULL);
 }
 
 /* Used to decide how to sort relocs in an optimal manner for the
@@ -5452,7 +3947,7 @@ elf_i386_reloc_type_class (const struct bfd_link_info *info,
       && htab->dynsym->contents != NULL)
     {
       /* Check relocation against STT_GNU_IFUNC symbol if there are
-         dynamic symbols.  */
+        dynamic symbols.  */
       unsigned long r_symndx = ELF32_R_SYM (rela->r_info);
       if (r_symndx != STN_UNDEF)
        {
@@ -5490,269 +3985,99 @@ elf_i386_finish_dynamic_sections (bfd *output_bfd,
                                  struct bfd_link_info *info)
 {
   struct elf_x86_link_hash_table *htab;
-  bfd *dynobj;
-  asection *sdyn;
-  const struct elf_i386_backend_data *abed;
 
-  htab = elf_x86_hash_table (info, I386_ELF_DATA);
+  htab = _bfd_x86_elf_finish_dynamic_sections (output_bfd, info);
   if (htab == NULL)
     return FALSE;
 
-  dynobj = htab->elf.dynobj;
-  sdyn = bfd_get_linker_section (dynobj, ".dynamic");
-  abed = get_elf_i386_backend_data (output_bfd);
+  if (!htab->elf.dynamic_sections_created)
+    return TRUE;
 
-  if (htab->elf.dynamic_sections_created)
+  if (htab->elf.splt && htab->elf.splt->size > 0)
     {
-      Elf32_External_Dyn *dyncon, *dynconend;
-      const struct elf_i386_plt_layout *plt_layout;
-      const struct elf_i386_lazy_plt_layout *lazy_plt_layout;
-      const struct elf_i386_non_lazy_plt_layout *non_lazy_plt_layout;
-
-      if (sdyn == NULL || htab->elf.sgot == NULL)
-       abort ();
+      /* UnixWare sets the entsize of .plt to 4, although that doesn't
+        really seem like the right value.  */
+      elf_section_data (htab->elf.splt->output_section)
+       ->this_hdr.sh_entsize = 4;
 
-      dyncon = (Elf32_External_Dyn *) sdyn->contents;
-      dynconend = (Elf32_External_Dyn *) (sdyn->contents + sdyn->size);
-      for (; dyncon < dynconend; dyncon++)
+      if (htab->plt.has_plt0)
        {
-         Elf_Internal_Dyn dyn;
-         asection *s;
-
-         bfd_elf32_swap_dyn_in (dynobj, dyncon, &dyn);
-
-         switch (dyn.d_tag)
+         /* Fill in the special first entry in the procedure linkage
+            table.  */
+         memcpy (htab->elf.splt->contents, htab->plt.plt0_entry,
+                 htab->lazy_plt->plt0_entry_size);
+         memset (htab->elf.splt->contents + htab->lazy_plt->plt0_entry_size,
+                 htab->plt0_pad_byte,
+                 htab->plt.plt_entry_size - htab->lazy_plt->plt0_entry_size);
+         if (!bfd_link_pic (info))
            {
-           default:
-             if (abed->os == is_vxworks
-                  && elf_vxworks_finish_dynamic_entry (output_bfd, &dyn))
-               break;
-             continue;
-
-           case DT_PLTGOT:
-             s = htab->elf.sgotplt;
-             dyn.d_un.d_ptr = s->output_section->vma + s->output_offset;
-             break;
-
-           case DT_JMPREL:
-             s = htab->elf.srelplt;
-             dyn.d_un.d_ptr = s->output_section->vma + s->output_offset;
-             break;
-
-           case DT_PLTRELSZ:
-             s = htab->elf.srelplt;
-             dyn.d_un.d_val = s->size;
-             break;
-           }
-
-         bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon);
-       }
-
-      plt_layout = &elf_i386_plt (htab);
-      lazy_plt_layout = elf_i386_lazy_plt (htab);
-      non_lazy_plt_layout =  elf_i386_non_lazy_plt (htab);
-
-      if (htab->elf.splt && htab->elf.splt->size > 0)
-       {
-         /* UnixWare sets the entsize of .plt to 4, although that doesn't
-            really seem like the right value.  */
-         elf_section_data (htab->elf.splt->output_section)
-           ->this_hdr.sh_entsize = 4;
+             bfd_put_32 (output_bfd,
+                         (htab->elf.sgotplt->output_section->vma
+                          + htab->elf.sgotplt->output_offset
+                          + 4),
+                         htab->elf.splt->contents
+                         + htab->lazy_plt->plt0_got1_offset);
+             bfd_put_32 (output_bfd,
+                         (htab->elf.sgotplt->output_section->vma
+                          + htab->elf.sgotplt->output_offset
+                          + 8),
+                         htab->elf.splt->contents
+                         + htab->lazy_plt->plt0_got2_offset);
 
-         if (plt_layout->has_plt0)
-           {
-             /* Fill in the special first entry in the procedure linkage
-                table.  */
-             memcpy (htab->elf.splt->contents, plt_layout->plt0_entry,
-                     lazy_plt_layout->plt0_entry_size);
-             memset (htab->elf.splt->contents + lazy_plt_layout->plt0_entry_size,
-                     abed->plt0_pad_byte,
-                     plt_layout->plt_entry_size - lazy_plt_layout->plt0_entry_size);
-             if (!bfd_link_pic (info))
+             if (htab->target_os == is_vxworks)
                {
-                 bfd_put_32 (output_bfd,
-                             (htab->elf.sgotplt->output_section->vma
-                              + htab->elf.sgotplt->output_offset
-                              + 4),
-                             htab->elf.splt->contents
-                             + lazy_plt_layout->plt0_got1_offset);
-                 bfd_put_32 (output_bfd,
-                             (htab->elf.sgotplt->output_section->vma
-                              + htab->elf.sgotplt->output_offset
-                              + 8),
-                             htab->elf.splt->contents
-                             + lazy_plt_layout->plt0_got2_offset);
+                 Elf_Internal_Rela rel;
+                 int num_plts = (htab->elf.splt->size
+                                 / htab->plt.plt_entry_size) - 1;
+                 unsigned char *p;
+                 asection *srelplt2 = htab->srelplt2;
+
+                 /* Generate a relocation for _GLOBAL_OFFSET_TABLE_
+                    + 4.  On IA32 we use REL relocations so the
+                    addend goes in the PLT directly.  */
+                 rel.r_offset = (htab->elf.splt->output_section->vma
+                                 + htab->elf.splt->output_offset
+                                 + htab->lazy_plt->plt0_got1_offset);
+                 rel.r_info = ELF32_R_INFO (htab->elf.hgot->indx,
+                                            R_386_32);
+                 bfd_elf32_swap_reloc_out (output_bfd, &rel,
+                                           srelplt2->contents);
+                 /* Generate a relocation for _GLOBAL_OFFSET_TABLE_
+                    + 8.  */
+                 rel.r_offset = (htab->elf.splt->output_section->vma
+                                 + htab->elf.splt->output_offset
+                                 + htab->lazy_plt->plt0_got2_offset);
+                 rel.r_info = ELF32_R_INFO (htab->elf.hgot->indx,
+                                            R_386_32);
+                 bfd_elf32_swap_reloc_out (output_bfd, &rel,
+                                           srelplt2->contents +
+                                           sizeof (Elf32_External_Rel));
+                 /* Correct the .rel.plt.unloaded relocations.  */
+                 p = srelplt2->contents;
+                 if (bfd_link_pic (info))
+                   p += PLTRESOLVE_RELOCS_SHLIB * sizeof (Elf32_External_Rel);
+                 else
+                   p += PLTRESOLVE_RELOCS * sizeof (Elf32_External_Rel);
 
-                 if (abed->os == is_vxworks)
+                 for (; num_plts; num_plts--)
                    {
-                     Elf_Internal_Rela rel;
-                     int num_plts = (htab->elf.splt->size
-                                     / plt_layout->plt_entry_size) - 1;
-                     unsigned char *p;
-                     asection *srelplt2 = elf_i386_srelplt2 (htab);
-
-                     /* Generate a relocation for _GLOBAL_OFFSET_TABLE_
-                        + 4.  On IA32 we use REL relocations so the
-                        addend goes in the PLT directly.  */
-                     rel.r_offset = (htab->elf.splt->output_section->vma
-                                     + htab->elf.splt->output_offset
-                                     + lazy_plt_layout->plt0_got1_offset);
-                     rel.r_info = ELF32_R_INFO (htab->elf.hgot->indx,
-                                                R_386_32);
-                     bfd_elf32_swap_reloc_out (output_bfd, &rel,
-                                               srelplt2->contents);
-                     /* Generate a relocation for _GLOBAL_OFFSET_TABLE_
-                        + 8.  */
-                     rel.r_offset = (htab->elf.splt->output_section->vma
-                                     + htab->elf.splt->output_offset
-                                     + lazy_plt_layout->plt0_got2_offset);
+                     bfd_elf32_swap_reloc_in (output_bfd, p, &rel);
                      rel.r_info = ELF32_R_INFO (htab->elf.hgot->indx,
                                                 R_386_32);
-                     bfd_elf32_swap_reloc_out (output_bfd, &rel,
-                                               srelplt2->contents +
-                                               sizeof (Elf32_External_Rel));
-                     /* Correct the .rel.plt.unloaded relocations.  */
-                     p = srelplt2->contents;
-                     if (bfd_link_pic (info))
-                       p += PLTRESOLVE_RELOCS_SHLIB * sizeof (Elf32_External_Rel);
-                     else
-                       p += PLTRESOLVE_RELOCS * sizeof (Elf32_External_Rel);
+                     bfd_elf32_swap_reloc_out (output_bfd, &rel, p);
+                     p += sizeof (Elf32_External_Rel);
 
-                     for (; num_plts; num_plts--)
-                       {
-                         bfd_elf32_swap_reloc_in (output_bfd, p, &rel);
-                         rel.r_info = ELF32_R_INFO (htab->elf.hgot->indx,
-                                                    R_386_32);
-                         bfd_elf32_swap_reloc_out (output_bfd, &rel, p);
-                         p += sizeof (Elf32_External_Rel);
-
-                         bfd_elf32_swap_reloc_in (output_bfd, p, &rel);
-                         rel.r_info = ELF32_R_INFO (htab->elf.hplt->indx,
-                                                    R_386_32);
-                         bfd_elf32_swap_reloc_out (output_bfd, &rel, p);
-                         p += sizeof (Elf32_External_Rel);
-                       }
+                     bfd_elf32_swap_reloc_in (output_bfd, p, &rel);
+                     rel.r_info = ELF32_R_INFO (htab->elf.hplt->indx,
+                                                R_386_32);
+                     bfd_elf32_swap_reloc_out (output_bfd, &rel, p);
+                     p += sizeof (Elf32_External_Rel);
                    }
                }
            }
        }
-
-      if (htab->plt_got != NULL && htab->plt_got->size > 0)
-       elf_section_data (htab->plt_got->output_section)
-         ->this_hdr.sh_entsize = non_lazy_plt_layout->plt_entry_size;
-
-      if (htab->plt_second != NULL && htab->plt_second->size > 0)
-       elf_section_data (htab->plt_second->output_section)
-         ->this_hdr.sh_entsize = non_lazy_plt_layout->plt_entry_size;
-    }
-
-  /* Fill in the first three entries in the global offset table.  */
-  if (htab->elf.sgotplt && htab->elf.sgotplt->size > 0)
-    {
-      if (bfd_is_abs_section (htab->elf.sgotplt->output_section))
-       {
-         _bfd_error_handler
-           (_("discarded output section: `%A'"), htab->elf.sgotplt);
-         return FALSE;
-       }
-
-      bfd_put_32 (output_bfd,
-                 (sdyn == NULL ? 0
-                  : sdyn->output_section->vma + sdyn->output_offset),
-                 htab->elf.sgotplt->contents);
-      bfd_put_32 (output_bfd, 0, htab->elf.sgotplt->contents + 4);
-      bfd_put_32 (output_bfd, 0, htab->elf.sgotplt->contents + 8);
-
-      elf_section_data (htab->elf.sgotplt->output_section)->this_hdr.sh_entsize = 4;
-    }
-
-  /* Adjust .eh_frame for .plt section.  */
-  if (htab->plt_eh_frame != NULL
-      && htab->plt_eh_frame->contents != NULL)
-    {
-      if (htab->elf.splt != NULL
-         && htab->elf.splt->size != 0
-         && (htab->elf.splt->flags & SEC_EXCLUDE) == 0
-         && htab->elf.splt->output_section != NULL
-         && htab->plt_eh_frame->output_section != NULL)
-       {
-         bfd_vma plt_start = htab->elf.splt->output_section->vma;
-         bfd_vma eh_frame_start = htab->plt_eh_frame->output_section->vma
-                                  + htab->plt_eh_frame->output_offset
-                                  + PLT_FDE_START_OFFSET;
-         bfd_put_signed_32 (dynobj, plt_start - eh_frame_start,
-                            htab->plt_eh_frame->contents
-                            + PLT_FDE_START_OFFSET);
-       }
-      if (htab->plt_eh_frame->sec_info_type
-         == SEC_INFO_TYPE_EH_FRAME)
-       {
-         if (! _bfd_elf_write_section_eh_frame (output_bfd, info,
-                                                htab->plt_eh_frame,
-                                                htab->plt_eh_frame->contents))
-           return FALSE;
-       }
-    }
-
-  /* Adjust .eh_frame for .plt.got section.  */
-  if (htab->plt_got_eh_frame != NULL
-      && htab->plt_got_eh_frame->contents != NULL)
-    {
-      if (htab->plt_got != NULL
-         && htab->plt_got->size != 0
-         && (htab->plt_got->flags & SEC_EXCLUDE) == 0
-         && htab->plt_got->output_section != NULL
-         && htab->plt_got_eh_frame->output_section != NULL)
-       {
-         bfd_vma plt_start = htab->plt_got->output_section->vma;
-         bfd_vma eh_frame_start = htab->plt_got_eh_frame->output_section->vma
-                                  + htab->plt_got_eh_frame->output_offset
-                                  + PLT_FDE_START_OFFSET;
-         bfd_put_signed_32 (dynobj, plt_start - eh_frame_start,
-                            htab->plt_got_eh_frame->contents
-                            + PLT_FDE_START_OFFSET);
-       }
-      if (htab->plt_got_eh_frame->sec_info_type == SEC_INFO_TYPE_EH_FRAME)
-       {
-         if (! _bfd_elf_write_section_eh_frame (output_bfd, info,
-                                                htab->plt_got_eh_frame,
-                                                htab->plt_got_eh_frame->contents))
-           return FALSE;
-       }
-    }
-
-  /* Adjust .eh_frame for the second PLT section.  */
-  if (htab->plt_second_eh_frame != NULL
-      && htab->plt_second_eh_frame->contents != NULL)
-    {
-      if (htab->plt_second != NULL
-         && htab->plt_second->size != 0
-         && (htab->plt_second->flags & SEC_EXCLUDE) == 0
-         && htab->plt_second->output_section != NULL
-         && htab->plt_second_eh_frame->output_section != NULL)
-       {
-         bfd_vma plt_start = htab->plt_second->output_section->vma;
-         bfd_vma eh_frame_start
-           = (htab->plt_second_eh_frame->output_section->vma
-              + htab->plt_second_eh_frame->output_offset
-              + PLT_FDE_START_OFFSET);
-         bfd_put_signed_32 (dynobj, plt_start - eh_frame_start,
-                            htab->plt_second_eh_frame->contents
-                            + PLT_FDE_START_OFFSET);
-       }
-      if (htab->plt_second_eh_frame->sec_info_type
-         == SEC_INFO_TYPE_EH_FRAME)
-       {
-         if (! _bfd_elf_write_section_eh_frame (output_bfd, info,
-                                                htab->plt_second_eh_frame,
-                                                htab->plt_second_eh_frame->contents))
-           return FALSE;
-       }
     }
 
-  if (htab->elf.sgot && htab->elf.sgot->size > 0)
-    elf_section_data (htab->elf.sgot->output_section)->this_hdr.sh_entsize = 4;
-
   /* Fill PLT entries for undefined weak symbols in PIE.  */
   if (bfd_link_pie (info))
     bfd_hash_traverse (&info->hash->table,
@@ -5790,28 +4115,8 @@ elf_i386_output_arch_local_syms
   return TRUE;
 }
 
-enum elf_i386_plt_type
-{
-  plt_non_lazy = 0,
-  plt_lazy = 1 << 0,
-  plt_pic = 1 << 1,
-  plt_second = 1 << 2,
-  plt_unknown = -1
-};
-
-struct elf_i386_plt
-{
-  const char *name;
-  asection *sec;
-  bfd_byte *contents;
-  enum elf_i386_plt_type type;
-  unsigned int plt_got_offset;
-  unsigned int plt_entry_size;
-  long count;
-};
-
 /* Forward declaration.  */
-static const struct elf_i386_lazy_plt_layout elf_i386_nacl_plt;
+static const struct elf_x86_lazy_plt_layout elf_i386_nacl_plt;
 
 /* Similar to _bfd_elf_get_synthetic_symtab.  Support PLTs with all
    dynamic relocations.   */
@@ -5824,27 +4129,23 @@ elf_i386_get_synthetic_symtab (bfd *abfd,
                               asymbol **dynsyms,
                               asymbol **ret)
 {
-  long size, count, i, n, len;
+  long count, i, n;
   int j;
-  unsigned int plt_got_offset, plt_entry_size;
-  asymbol *s;
   bfd_byte *plt_contents;
-  long dynrelcount, relsize;
-  arelent **dynrelbuf, *p;
-  const struct elf_i386_lazy_plt_layout *lazy_plt;
-  const struct elf_i386_non_lazy_plt_layout *non_lazy_plt;
-  const struct elf_i386_lazy_plt_layout *lazy_ibt_plt;
-  const struct elf_i386_non_lazy_plt_layout *non_lazy_ibt_plt;
+  long relsize;
+  const struct elf_x86_lazy_plt_layout *lazy_plt;
+  const struct elf_x86_non_lazy_plt_layout *non_lazy_plt;
+  const struct elf_x86_lazy_plt_layout *lazy_ibt_plt;
+  const struct elf_x86_non_lazy_plt_layout *non_lazy_ibt_plt;
   asection *plt;
   bfd_vma got_addr;
-  char *names;
-  enum elf_i386_plt_type plt_type;
-  struct elf_i386_plt plts[] =
+  enum elf_x86_plt_type plt_type;
+  struct elf_x86_plt plts[] =
     {
-      { ".plt", NULL, NULL, plt_unknown, 0, 0, 0 },
-      { ".plt.got", NULL, NULL, plt_non_lazy, 0, 0, 0 },
-      { ".plt.sec", NULL, NULL, plt_second, 0, 0, 0 },
-      { NULL, NULL, NULL, plt_non_lazy, 0, 0, 0 }
+      { ".plt", NULL, NULL, plt_unknown, 0, 0, 0, 0 },
+      { ".plt.got", NULL, NULL, plt_non_lazy, 0, 0, 0, 0 },
+      { ".plt.sec", NULL, NULL, plt_second, 0, 0, 0, 0 },
+      { NULL, NULL, NULL, plt_non_lazy, 0, 0, 0, 0 }
     };
 
   *ret = NULL;
@@ -5864,9 +4165,10 @@ elf_i386_get_synthetic_symtab (bfd *abfd,
   lazy_plt = NULL;
   non_lazy_ibt_plt = NULL;
   lazy_ibt_plt = NULL;
-  switch (get_elf_i386_backend_data (abfd)->os)
+  switch (get_elf_x86_backend_data (abfd)->target_os)
     {
     case is_normal:
+    case is_solaris:
       non_lazy_plt = &elf_i386_non_lazy_plt;
       lazy_ibt_plt = &elf_i386_lazy_ibt_plt;
       non_lazy_ibt_plt = &elf_i386_non_lazy_ibt_plt;
@@ -6010,176 +4312,9 @@ elf_i386_get_synthetic_symtab (bfd *abfd,
        got_addr = (bfd_vma) -1;
     }
 
-  if (count == 0)
-    return -1;
-
-  dynrelbuf = (arelent **) bfd_malloc (relsize);
-  if (dynrelbuf == NULL)
-    return -1;
-
-  dynrelcount = bfd_canonicalize_dynamic_reloc (abfd, dynrelbuf,
-                                               dynsyms);
-
-  /* Sort the relocs by address.  */
-  qsort (dynrelbuf, dynrelcount, sizeof (arelent *),
-        _bfd_x86_elf_compare_relocs);
-
-  size = count * sizeof (asymbol);
-
-  /* Allocate space for @plt suffixes.  */
-  n = 0;
-  for (i = 0; i < dynrelcount; i++)
-    {
-      p = dynrelbuf[i];
-      size += strlen ((*p->sym_ptr_ptr)->name) + sizeof ("@plt");
-      if (p->addend != 0)
-       size += sizeof ("+0x") - 1 + 8;
-    }
-
-  s = *ret = (asymbol *) bfd_zmalloc (size);
-  if (s == NULL)
-    goto bad_return;
-
-  if (got_addr)
-    {
-      /* Check .got.plt and then .got to get the _GLOBAL_OFFSET_TABLE_
-        address.  */
-      asection *sec = bfd_get_section_by_name (abfd, ".got.plt");
-      if (sec != NULL)
-       got_addr = sec->vma;
-      else
-       {
-         sec = bfd_get_section_by_name (abfd, ".got");
-         if (sec != NULL)
-           got_addr = sec->vma;
-       }
-
-      if (got_addr == (bfd_vma) -1)
-       goto bad_return;
-    }
-
-  /* Check for each PLT section.  */
-  names = (char *) (s + count);
-  size = 0;
-  n = 0;
-  for (j = 0; plts[j].name != NULL; j++)
-    if ((plt_contents = plts[j].contents) != NULL)
-      {
-       long k;
-       bfd_vma offset;
-
-       plt_got_offset = plts[j].plt_got_offset;
-       plt_entry_size = plts[j].plt_entry_size;
-
-       plt = plts[j].sec;
-
-       if ((plts[j].type & plt_lazy))
-         {
-           /* Skip PLT0 in lazy PLT.  */
-           k = 1;
-           offset = plt_entry_size;
-         }
-       else
-         {
-           k = 0;
-           offset = 0;
-         }
-
-       /* Check each PLT entry against dynamic relocations.  */
-       for (; k < plts[j].count; k++)
-         {
-           int off;
-           bfd_vma got_vma;
-           long min, max, mid;
-
-           /* Get the GOT offset, a signed 32-bit integer.  */
-           off = H_GET_32 (abfd, (plt_contents + offset
-                                  + plt_got_offset));
-           got_vma = got_addr + off;
-
-           /* Binary search.  */
-           p = dynrelbuf[0];
-           min = 0;
-           max = dynrelcount;
-           while ((min + 1) < max)
-             {
-               arelent *r;
-
-               mid = (min + max) / 2;
-               r = dynrelbuf[mid];
-               if (got_vma > r->address)
-                 min = mid;
-               else if (got_vma < r->address)
-                 max = mid;
-               else
-                 {
-                   p = r;
-                   break;
-                 }
-             }
-
-           /* Skip unknown relocation.  PR 17512: file: bc9d6cf5.  */
-           if (got_vma == p->address
-               && p->howto != NULL
-               && (p->howto->type == R_386_JUMP_SLOT
-                   || p->howto->type == R_386_GLOB_DAT
-                   || p->howto->type == R_386_IRELATIVE))
-             {
-               *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;
-               /* This is no longer a section symbol.  */
-               s->flags &= ~BSF_SECTION_SYM;
-               s->section = plt;
-               s->the_bfd = plt->owner;
-               s->value = offset;
-               s->udata.p = NULL;
-               s->name = names;
-               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)
-                     ;
-                   size = strlen (a);
-                   memcpy (names, a, size);
-                   names += size;
-                 }
-               memcpy (names, "@plt", sizeof ("@plt"));
-               names += sizeof ("@plt");
-               n++;
-               s++;
-             }
-           offset += plt_entry_size;
-         }
-      }
-
-  /* PLT entries with R_386_TLS_DESC relocations are skipped.  */
-  if (n == 0)
-    {
-bad_return:
-      count = -1;
-    }
-  else
-    count = n;
-
-  for (j = 0; plts[j].name != NULL; j++)
-    if (plts[j].contents != NULL)
-      free (plts[j].contents);
-
-  free (dynrelbuf);
-
-  return count;
+  return _bfd_x86_elf_get_synthetic_symtab (abfd, count, relsize,
+                                           got_addr, plts, dynsyms,
+                                           ret);
 }
 
 /* Set up i386 GNU properties.  Return the first relocatable ELF input
@@ -6188,357 +4323,38 @@ bad_return:
 static bfd *
 elf_i386_link_setup_gnu_properties (struct bfd_link_info *info)
 {
-  bfd_boolean normal_target;
-  bfd_boolean lazy_plt;
-  asection *sec, *pltsec;
-  bfd *dynobj;
-  bfd_boolean use_ibt_plt;
-  unsigned int plt_alignment, features;
-  struct elf_x86_link_hash_table *htab;
-  bfd *pbfd;
-  bfd *ebfd = NULL;
-  elf_property *prop;
-  struct elf_i386_plt_layout *plt_layout;
-  const struct elf_i386_lazy_plt_layout *lazy_plt_layout;
-  const struct elf_i386_non_lazy_plt_layout *non_lazy_plt_layout;
-
-  features = 0;
-  if (info->ibt)
-    features = GNU_PROPERTY_X86_FEATURE_1_IBT;
-  if (info->shstk)
-    features |= GNU_PROPERTY_X86_FEATURE_1_SHSTK;
-
-  /* Find a normal input file with GNU property note.  */
-  for (pbfd = info->input_bfds;
-       pbfd != NULL;
-       pbfd = pbfd->link.next)
-    if (bfd_get_flavour (pbfd) == bfd_target_elf_flavour
-       && bfd_count_sections (pbfd) != 0)
-      {
-       ebfd = pbfd;
-
-       if (elf_properties (pbfd) != NULL)
-         break;
-      }
-
-  if (ebfd != NULL && features)
-    {
-      /* If features is set, add GNU_PROPERTY_X86_FEATURE_1_IBT and
-        GNU_PROPERTY_X86_FEATURE_1_SHSTK.  */
-      prop = _bfd_elf_get_property (ebfd,
-                                   GNU_PROPERTY_X86_FEATURE_1_AND,
-                                   4);
-      prop->u.number |= features;
-      prop->pr_kind = property_number;
-
-      /* Create the GNU property note section if needed.  */
-      if (pbfd == NULL)
-       {
-         sec = bfd_make_section_with_flags (ebfd,
-                                            NOTE_GNU_PROPERTY_SECTION_NAME,
-                                            (SEC_ALLOC
-                                             | SEC_LOAD
-                                             | SEC_IN_MEMORY
-                                             | SEC_READONLY
-                                             | SEC_HAS_CONTENTS
-                                             | SEC_DATA));
-         if (sec == NULL)
-           info->callbacks->einfo (_("%F: failed to create GNU property section\n"));
-
-         if (!bfd_set_section_alignment (ebfd, sec, 2))
-           {
-error_alignment:
-             info->callbacks->einfo (_("%F%A: failed to align section\n"),
-                                     sec);
-           }
-
-         elf_section_type (sec) = SHT_NOTE;
-       }
-    }
-
-  pbfd = _bfd_elf_link_setup_gnu_properties (info);
-
-  if (bfd_link_relocatable (info))
-    return pbfd;
-
-  htab = elf_x86_hash_table (info, I386_ELF_DATA);
-  if (htab == NULL)
-    return pbfd;
-
-  use_ibt_plt = info->ibtplt || info->ibt;
-  if (!use_ibt_plt && pbfd != NULL)
-    {
-      /* Check if GNU_PROPERTY_X86_FEATURE_1_IBT is on.  */
-      elf_property_list *p;
-
-      /* The property list is sorted in order of type.  */
-      for (p = elf_properties (pbfd); p; p = p->next)
-       {
-         if (GNU_PROPERTY_X86_FEATURE_1_AND == p->property.pr_type)
-           {
-             use_ibt_plt = !!(p->property.u.number
-                              & GNU_PROPERTY_X86_FEATURE_1_IBT);
-             break;
-           }
-         else if (GNU_PROPERTY_X86_FEATURE_1_AND < p->property.pr_type)
-           break;
-       }
-    }
-
-  dynobj = htab->elf.dynobj;
-
-  /* Set htab->elf.dynobj here so that there is no need to check and
-     set it in check_relocs.  */
-  if (dynobj == NULL)
-    {
-      if (pbfd != NULL)
-       {
-         htab->elf.dynobj = pbfd;
-         dynobj = pbfd;
-       }
-      else
-       {
-         bfd *abfd;
-
-         /* Find a normal input file to hold linker created
-            sections.  */
-         for (abfd = info->input_bfds;
-              abfd != NULL;
-              abfd = abfd->link.next)
-           if (bfd_get_flavour (abfd) == bfd_target_elf_flavour
-               && (abfd->flags
-                   & (DYNAMIC | BFD_LINKER_CREATED | BFD_PLUGIN)) == 0)
-             {
-               htab->elf.dynobj = abfd;
-               dynobj = abfd;
-               break;
-             }
-       }
-    }
-
-  plt_layout = &elf_i386_plt (htab);
+  struct elf_x86_init_table init_table;
 
-  /* Even when lazy binding is disabled by "-z now", the PLT0 entry may
-     still be used with LD_AUDIT or LD_PROFILE if PLT entry is used for
-     canonical function address.  */
-  plt_layout->has_plt0 = 1;
-  normal_target = FALSE;
-
-  switch (get_elf_i386_backend_data (info->output_bfd)->os)
+  switch (get_elf_x86_backend_data (info->output_bfd)->target_os)
     {
     case is_normal:
-      if (use_ibt_plt)
-       {
-         elf_i386_lazy_plt (htab) = &elf_i386_lazy_ibt_plt;
-         elf_i386_non_lazy_plt (htab) = &elf_i386_non_lazy_ibt_plt;
-       }
-      else
-       {
-         elf_i386_lazy_plt (htab) = &elf_i386_lazy_plt;
-         elf_i386_non_lazy_plt (htab) = &elf_i386_non_lazy_plt;
-       }
-      normal_target = TRUE;
+    case is_solaris:
+      init_table.plt0_pad_byte = 0x0;
+      init_table.lazy_plt = &elf_i386_lazy_plt;
+      init_table.non_lazy_plt = &elf_i386_non_lazy_plt;
+      init_table.lazy_ibt_plt = &elf_i386_lazy_ibt_plt;
+      init_table.non_lazy_ibt_plt = &elf_i386_non_lazy_ibt_plt;
       break;
     case is_vxworks:
-      elf_i386_lazy_plt (htab) = &elf_i386_lazy_plt;
-      elf_i386_non_lazy_plt (htab) = NULL;
-      if (!elf_vxworks_create_dynamic_sections (dynobj, info,
-                                               &elf_i386_srelplt2 (htab)))
-       info->callbacks->einfo (_("%F: failed to create VxWorks dynamic sections\n"));
+      init_table.plt0_pad_byte = 0x90;
+      init_table.lazy_plt = &elf_i386_lazy_plt;
+      init_table.non_lazy_plt = NULL;
+      init_table.lazy_ibt_plt = NULL;
+      init_table.non_lazy_ibt_plt = NULL;
       break;
     case is_nacl:
-      elf_i386_lazy_plt (htab) = &elf_i386_nacl_plt;
-      elf_i386_non_lazy_plt (htab) = NULL;
+      init_table.plt0_pad_byte = 0x90;
+      init_table.lazy_plt = &elf_i386_nacl_plt;
+      init_table.non_lazy_plt = NULL;
+      init_table.lazy_ibt_plt = NULL;
+      init_table.non_lazy_ibt_plt = NULL;
       break;
     }
 
-  lazy_plt_layout = elf_i386_lazy_plt (htab);
-  non_lazy_plt_layout = elf_i386_non_lazy_plt (htab);
-
-  pltsec = htab->elf.splt;
-
-  /* If the non-lazy PLT is available, use it for all PLT entries if
-     there are no PLT0 or no .plt section.  */
-  if (non_lazy_plt_layout != NULL
-      && (!plt_layout->has_plt0 || pltsec == NULL))
-    {
-      lazy_plt = FALSE;
-      if (bfd_link_pic (info))
-       plt_layout->plt_entry
-         = non_lazy_plt_layout->pic_plt_entry;
-      else
-       plt_layout->plt_entry
-         = non_lazy_plt_layout->plt_entry;
-      plt_layout->plt_entry_size
-       = non_lazy_plt_layout->plt_entry_size;
-      plt_layout->plt_got_offset
-       = non_lazy_plt_layout->plt_got_offset;
-      plt_layout->eh_frame_plt_size
-       = non_lazy_plt_layout->eh_frame_plt_size;
-      plt_layout->eh_frame_plt
-       = non_lazy_plt_layout->eh_frame_plt;
-    }
-  else
-    {
-      lazy_plt = TRUE;
-      if (bfd_link_pic (info))
-       {
-         plt_layout->plt0_entry
-           = lazy_plt_layout->pic_plt0_entry;
-         plt_layout->plt_entry
-           = lazy_plt_layout->pic_plt_entry;
-       }
-      else
-       {
-         plt_layout->plt0_entry
-           = lazy_plt_layout->plt0_entry;
-         plt_layout->plt_entry
-           = lazy_plt_layout->plt_entry;
-       }
-      plt_layout->plt_entry_size
-       = lazy_plt_layout->plt_entry_size;
-      plt_layout->plt_got_offset
-       = lazy_plt_layout->plt_got_offset;
-      plt_layout->eh_frame_plt_size
-       = lazy_plt_layout->eh_frame_plt_size;
-      plt_layout->eh_frame_plt
-       = lazy_plt_layout->eh_frame_plt;
-    }
-
-  /* Return if there are no normal input files.  */
-  if (dynobj == NULL)
-    return pbfd;
-
-  /* Since create_dynamic_sections isn't always called, but GOT
-     relocations need GOT sections, create them here so that we
-     don't need to do it in check_relocs.  */
-  if (htab->elf.sgot == NULL
-      && !_bfd_elf_create_got_section (dynobj, info))
-    info->callbacks->einfo (_("%F: failed to create GOT sections\n"));
-
-  /* Create the ifunc sections here so that check_relocs can be
-     simplified.  */
-  if (!_bfd_elf_create_ifunc_sections (dynobj, info))
-    info->callbacks->einfo (_("%F: failed to create ifunc sections\n"));
-
-  plt_alignment = bfd_log2 (plt_layout->plt_entry_size);
-
-  if (pltsec != NULL)
-    {
-      /* Whe creating executable, set the contents of the .interp
-        section to the interpreter.  */
-      if (bfd_link_executable (info) && !info->nointerp)
-       {
-         asection *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;
-       }
-
-      /* Don't change PLT section alignment for NaCl since it uses
-        64-byte PLT entry and sets PLT section alignment to 32
-        bytes.  */
-      if (normal_target)
-       {
-         const struct elf_backend_data *bed
-           = get_elf_backend_data (dynobj);
-         flagword pltflags = (bed->dynamic_sec_flags
-                              | SEC_ALLOC
-                              | SEC_CODE
-                              | SEC_LOAD
-                              | SEC_READONLY);
-         unsigned int non_lazy_plt_alignment
-           = bfd_log2 (non_lazy_plt_layout->plt_entry_size);
-
-         sec = pltsec;
-         if (!bfd_set_section_alignment (sec->owner, sec,
-                                         plt_alignment))
-           goto error_alignment;
-
-         /* Create the GOT procedure linkage table.  */
-         sec = bfd_make_section_anyway_with_flags (dynobj,
-                                                   ".plt.got",
-                                                   pltflags);
-         if (sec == NULL)
-           info->callbacks->einfo (_("%F: failed to create GOT PLT section\n"));
-
-         if (!bfd_set_section_alignment (dynobj, sec,
-                                         non_lazy_plt_alignment))
-           goto error_alignment;
-
-         htab->plt_got = sec;
-
-         if (lazy_plt)
-           {
-             sec = NULL;
-
-             if (use_ibt_plt)
-               {
-                 /* Create the second PLT for Intel IBT support.  IBT
-                    PLT is supported only for non-NaCl target and is
-                    is needed only for lazy binding.  */
-                 sec = bfd_make_section_anyway_with_flags (dynobj,
-                                                           ".plt.sec",
-                                                           pltflags);
-                 if (sec == NULL)
-                   info->callbacks->einfo (_("%F: failed to create IBT-enabled PLT section\n"));
-
-                 if (!bfd_set_section_alignment (dynobj, sec,
-                                                 plt_alignment))
-                   goto error_alignment;
-               }
-
-             htab->plt_second = sec;
-           }
-       }
-
-      if (!info->no_ld_generated_unwind_info)
-       {
-         flagword flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY
-                           | SEC_HAS_CONTENTS | SEC_IN_MEMORY
-                           | SEC_LINKER_CREATED);
-
-         sec = bfd_make_section_anyway_with_flags (dynobj,
-                                                   ".eh_frame",
-                                                   flags);
-         if (sec == NULL)
-           info->callbacks->einfo (_("%F: failed to create PLT .eh_frame section\n"));
-
-         if (!bfd_set_section_alignment (dynobj, sec, 2))
-           goto error_alignment;
-
-         htab->plt_eh_frame = sec;
-
-         if (htab->plt_got != NULL)
-           {
-             sec = bfd_make_section_anyway_with_flags (dynobj,
-                                                       ".eh_frame",
-                                                       flags);
-             if (sec == NULL)
-               info->callbacks->einfo (_("%F: failed to create GOT PLT .eh_frame section\n"));
-
-             if (!bfd_set_section_alignment (dynobj, sec, 2))
-               goto error_alignment;
-
-             htab->plt_got_eh_frame = sec;
-           }
-       }
-    }
-
-  if (normal_target)
-    {
-      /* The .iplt section is used for IFUNC symbols in static
-        executables.  */
-      sec = htab->elf.iplt;
-      if (sec != NULL
-         && !bfd_set_section_alignment (sec->owner, sec,
-                                        plt_alignment))
-       goto error_alignment;
-    }
+  init_table.r_info = elf32_r_info;
+  init_table.r_sym = elf32_r_sym;
 
-  return pbfd;
+  return _bfd_x86_elf_link_setup_gnu_properties (info, &init_table);
 }
 
 #define TARGET_LITTLE_SYM              i386_elf32_vec
@@ -6564,15 +4380,11 @@ error_alignment:
 #define elf_info_to_howto                    elf_i386_info_to_howto_rel
 #define elf_info_to_howto_rel                elf_i386_info_to_howto_rel
 
-#define bfd_elf32_mkobject                   elf_i386_mkobject
-
 #define bfd_elf32_bfd_is_local_label_name     elf_i386_is_local_label_name
-#define bfd_elf32_bfd_link_hash_table_create  elf_i386_link_hash_table_create
 #define bfd_elf32_bfd_reloc_type_lookup              elf_i386_reloc_type_lookup
 #define bfd_elf32_bfd_reloc_name_lookup              elf_i386_reloc_name_lookup
 #define bfd_elf32_get_synthetic_symtab       elf_i386_get_synthetic_symtab
 
-#define elf_backend_adjust_dynamic_symbol     elf_i386_adjust_dynamic_symbol
 #define elf_backend_relocs_compatible        _bfd_elf_relocs_compatible
 #define elf_backend_check_relocs             elf_i386_check_relocs
 #define elf_backend_create_dynamic_sections   _bfd_elf_create_dynamic_sections
@@ -6580,13 +4392,16 @@ error_alignment:
 #define elf_backend_finish_dynamic_sections   elf_i386_finish_dynamic_sections
 #define elf_backend_finish_dynamic_symbol     elf_i386_finish_dynamic_symbol
 #define elf_backend_output_arch_local_syms     elf_i386_output_arch_local_syms
-#define elf_backend_gc_mark_hook             elf_i386_gc_mark_hook
 #define elf_backend_grok_prstatus            elf_i386_grok_prstatus
 #define elf_backend_grok_psinfo                      elf_i386_grok_psinfo
 #define elf_backend_reloc_type_class         elf_i386_reloc_type_class
 #define elf_backend_relocate_section         elf_i386_relocate_section
-#define elf_backend_size_dynamic_sections     elf_i386_size_dynamic_sections
 #define elf_backend_setup_gnu_properties      elf_i386_link_setup_gnu_properties
+#define elf_backend_hide_symbol                      _bfd_x86_elf_hide_symbol
+
+#define elf_backend_linux_prpsinfo32_ugid16    TRUE
+
+#define        elf32_bed                             elf32_i386_bed
 
 #include "elf32-target.h"
 
@@ -6603,10 +4418,11 @@ error_alignment:
    "FreeBSD" label in the ELF header.  So we put this label on all
    executables and (for simplicity) also all other object files.  */
 
-static void
-elf_i386_fbsd_post_process_headers (bfd *abfd, struct bfd_link_info *info)
+static bfd_boolean
+elf_i386_fbsd_init_file_header (bfd *abfd, struct bfd_link_info *info)
 {
-  _bfd_elf_post_process_headers (abfd, info);
+  if (!_bfd_elf_init_file_header (abfd, info))
+    return FALSE;
 
 #ifdef OLD_FREEBSD_ABI_LABEL
   {
@@ -6615,10 +4431,11 @@ elf_i386_fbsd_post_process_headers (bfd *abfd, struct bfd_link_info *info)
     memcpy (&i_ehdrp->e_ident[EI_ABIVERSION], "FreeBSD", 8);
   }
 #endif
+  return TRUE;
 }
 
-#undef elf_backend_post_process_headers
-#define        elf_backend_post_process_headers        elf_i386_fbsd_post_process_headers
+#undef elf_backend_init_file_header
+#define        elf_backend_init_file_header    elf_i386_fbsd_init_file_header
 #undef elf32_bed
 #define        elf32_bed                               elf32_i386_fbsd_bed
 
@@ -6626,6 +4443,8 @@ elf_i386_fbsd_post_process_headers (bfd *abfd, struct bfd_link_info *info)
 
 #include "elf32-target.h"
 
+#undef elf_backend_init_file_header
+
 /* Solaris 2.  */
 
 #undef TARGET_LITTLE_SYM
@@ -6633,7 +4452,13 @@ elf_i386_fbsd_post_process_headers (bfd *abfd, struct bfd_link_info *info)
 #undef TARGET_LITTLE_NAME
 #define        TARGET_LITTLE_NAME              "elf32-i386-sol2"
 
-#undef elf_backend_post_process_headers
+static const struct elf_x86_backend_data elf_i386_solaris_arch_bed =
+  {
+    is_solaris                         /* os */
+  };
+
+#undef elf_backend_arch_data
+#define        elf_backend_arch_data           &elf_i386_solaris_arch_bed
 
 /* Restore default: we cannot use ELFOSABI_SOLARIS, otherwise ELFOSABI_NONE
    objects won't be recognized.  */
@@ -6658,7 +4483,7 @@ elf_i386_fbsd_post_process_headers (bfd *abfd, struct bfd_link_info *info)
 #define elf_backend_strtab_flags       SHF_STRINGS
 
 /* Called to set the sh_flags, sh_link and sh_info fields of OSECTION which
-   has a type >= SHT_LOOS.  Returns TRUE if these fields were initialised 
+   has a type >= SHT_LOOS.  Returns TRUE if these fields were initialised
    FALSE otherwise.  ISECTION is the best guess matching section from the
    input bfd IBFD, but it might be NULL.  */
 
@@ -6678,60 +4503,60 @@ elf32_i386_copy_solaris_special_section_fields (const bfd *ibfd ATTRIBUTE_UNUSED
 http://docs.oracle.com/cd/E53394_01/html/E54813/chapter6-94076.html#scrolltoc
 
      The following values should be set:
-     
-Type                 Link                           Info
+
+Type                Link                           Info
 -----------------------------------------------------------------------------
 SHT_SUNW_ancillary   The section header index of    0
- [0x6fffffee]        the associated string table.
-       
+ [0x6fffffee]       the associated string table.
+
 SHT_SUNW_capinfo     The section header index of    For a dynamic object, the
- [0x6ffffff0]        the associated symbol table.   section header index of
-                                                    the associated
+ [0x6ffffff0]       the associated symbol table.   section header index of
+                                                   the associated
                                                    SHT_SUNW_capchain table,
                                                    otherwise 0.
 
 SHT_SUNW_symsort     The section header index of    0
- [0x6ffffff1]        the associated symbol table.
+ [0x6ffffff1]       the associated symbol table.
 
 SHT_SUNW_tlssort     The section header index of    0
- [0x6ffffff2]        the associated symbol table.
-       
-SHT_SUNW_LDYNSYM     The section header index of    One greater than the 
- [0x6ffffff3]        the associated string table.   symbol table index of the
-                    This index is the same string  last local symbol, 
+ [0x6ffffff2]       the associated symbol table.
+
+SHT_SUNW_LDYNSYM     The section header index of    One greater than the
+ [0x6ffffff3]       the associated string table.   symbol table index of the
+                    This index is the same string  last local symbol,
                     table used by the SHT_DYNSYM   STB_LOCAL. Since
-                    section.                       SHT_SUNW_LDYNSYM only
-                                                   contains local symbols,
+                    section.                       SHT_SUNW_LDYNSYM only
+                                                   contains local symbols,
                                                    sh_info is equivalent to
                                                    the number of symbols in
                                                    the table.
 
-SHT_SUNW_cap         If symbol capabilities exist,  If any capabilities refer
- [0x6ffffff5]        the section header index of    to named strings, the
-                     the associated                 section header index of
-                    SHT_SUNW_capinfo table,        the associated string 
-                         otherwise 0.              table, otherwise 0.
+SHT_SUNW_cap        If symbol capabilities exist,  If any capabilities refer
+ [0x6ffffff5]       the section header index of    to named strings, the
+                    the associated                 section header index of
+                    SHT_SUNW_capinfo table,        the associated string
+                         otherwise 0.              table, otherwise 0.
 
-SHT_SUNW_move        The section header index of    0
- [0x6ffffffa]        the associated symbol table.
-       
-SHT_SUNW_COMDAT      0                              0
+SHT_SUNW_move       The section header index of    0
+ [0x6ffffffa]       the associated symbol table.
+
+SHT_SUNW_COMDAT             0                              0
  [0x6ffffffb]
 
 SHT_SUNW_syminfo     The section header index of    The section header index
- [0x6ffffffc]        the associated symbol table.   of the associated
-                                                   .dynamic section.
+ [0x6ffffffc]       the associated symbol table.   of the associated
+                                                   .dynamic section.
 
-SHT_SUNW_verdef      The section header index of    The number of version 
- [0x6ffffffd]        the associated string table.   definitions within the
-                                                   section.
+SHT_SUNW_verdef             The section header index of    The number of version
+ [0x6ffffffd]       the associated string table.   definitions within the
+                                                   section.
 
 SHT_SUNW_verneed     The section header index of    The number of version
- [0x6ffffffe]        the associated string table.   dependencies within the
-                                                    section.
+ [0x6ffffffe]       the associated string table.   dependencies within the
+                                                   section.
 
-SHT_SUNW_versym      The section header index of    0
- [0x6fffffff]        the associated symbol table.  */
+SHT_SUNW_versym             The section header index of    0
+ [0x6fffffff]       the associated symbol table.  */
 }
 
 #undef  elf_backend_copy_special_section_fields
@@ -6759,6 +4584,9 @@ elf32_iamcu_elf_object_p (bfd *abfd)
 #undef ELF_MACHINE_CODE
 #define        ELF_MACHINE_CODE                EM_IAMCU
 
+#undef elf_backend_arch_data
+#define        elf_backend_arch_data           &elf_i386_arch_bed
+
 #undef ELF_OSABI
 
 #undef  elf32_bed
@@ -6770,7 +4598,7 @@ elf32_iamcu_elf_object_p (bfd *abfd)
 #undef elf_backend_static_tls_alignment
 
 #undef elf_backend_want_plt_sym
-#define elf_backend_want_plt_sym           0
+#define elf_backend_want_plt_sym       0
 
 #undef  elf_backend_strtab_flags
 #undef  elf_backend_copy_special_section_fields
@@ -6799,7 +4627,6 @@ elf32_iamcu_elf_object_p (bfd *abfd)
 #undef ELF_OSABI
 #undef elf_backend_want_plt_sym
 #define elf_backend_want_plt_sym       0
-#undef elf_backend_post_process_headers
 #undef elf_backend_static_tls_alignment
 
 /* NaCl uses substantially different PLT entries for the same effects.  */
@@ -6812,9 +4639,9 @@ elf32_iamcu_elf_object_p (bfd *abfd)
 static const bfd_byte elf_i386_nacl_plt0_entry[] =
   {
     0xff, 0x35,                          /* pushl contents of address */
-    0, 0, 0, 0,                          /* replaced with address of .got + 4.  */
-    0x8b, 0x0d,                   /* movl contents of address, %ecx */
-    0, 0, 0, 0,                          /* replaced with address of .got + 8.  */
+    0, 0, 0, 0,                          /* replaced with address of .got + 4.  */
+    0x8b, 0x0d,                          /* movl contents of address, %ecx */
+    0, 0, 0, 0,                          /* replaced with address of .got + 8.  */
     0x83, 0xe1, NACLMASK,        /* andl $NACLMASK, %ecx */
     0xff, 0xe1                   /* jmp *%ecx */
   };
@@ -6826,7 +4653,7 @@ static const bfd_byte elf_i386_nacl_plt_entry[NACL_PLT_ENTRY_SIZE] =
     0x83, 0xe1, NACLMASK,              /* andl $NACLMASK, %ecx */
     0xff, 0xe1,                                /* jmp *%ecx */
 
-    /* Pad to the next 32-byte boundary with nop instructions. */
+    /* Pad to the next 32-byte boundary with nop instructions.  */
     0x90,
     0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
     0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
@@ -6835,9 +4662,9 @@ static const bfd_byte elf_i386_nacl_plt_entry[NACL_PLT_ENTRY_SIZE] =
     0x68,                             /* pushl immediate */
     0, 0, 0, 0,                               /* replaced with reloc offset.  */
     0xe9,                             /* jmp relative */
-    0, 0, 0, 0,                               /* replaced with offset to .plt.  */
+    0, 0, 0, 0,                               /* replaced with offset to .plt.  */
 
-    /* Pad to the next 32-byte boundary with nop instructions. */
+    /* Pad to the next 32-byte boundary with nop instructions.  */
     0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
     0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
     0x90, 0x90
@@ -6858,23 +4685,23 @@ elf_i386_nacl_pic_plt0_entry[sizeof (elf_i386_nacl_plt0_entry)] =
 
 static const bfd_byte elf_i386_nacl_pic_plt_entry[NACL_PLT_ENTRY_SIZE] =
   {
-    0x8b, 0x8b,          /* movl offset(%ebx), %ecx */
-    0, 0, 0, 0,          /* replaced with offset of this symbol in .got.  */
-    0x83, 0xe1, 0xe0,    /* andl $NACLMASK, %ecx */
-    0xff, 0xe1,          /* jmp *%ecx */
+    0x8b, 0x8b,                 /* movl offset(%ebx), %ecx */
+    0, 0, 0, 0,                 /* replaced with offset of this symbol in .got.  */
+    0x83, 0xe1, 0xe0,   /* andl $NACLMASK, %ecx */
+    0xff, 0xe1,                 /* jmp *%ecx */
 
-    /* Pad to the next 32-byte boundary with nop instructions. */
+    /* Pad to the next 32-byte boundary with nop instructions.  */
     0x90,
     0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
     0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
 
     /* Lazy GOT entries point here (32-byte aligned).  */
-    0x68,                /* pushl immediate */
-    0, 0, 0, 0,          /* replaced with offset into relocation table.  */
-    0xe9,                /* jmp relative */
-    0, 0, 0, 0,          /* replaced with offset to start of .plt.  */
+    0x68,               /* pushl immediate */
+    0, 0, 0, 0,                 /* replaced with offset into relocation table.  */
+    0xe9,               /* jmp relative */
+    0, 0, 0, 0,                 /* replaced with offset to start of .plt.  */
 
-    /* Pad to the next 32-byte boundary with nop instructions. */
+    /* Pad to the next 32-byte boundary with nop instructions.  */
     0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
     0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
     0x90, 0x90
@@ -6882,54 +4709,63 @@ static const bfd_byte elf_i386_nacl_pic_plt_entry[NACL_PLT_ENTRY_SIZE] =
 
 static const bfd_byte elf_i386_nacl_eh_frame_plt[] =
   {
-#if (PLT_CIE_LENGTH != 20                               \
-     || PLT_FDE_LENGTH != 36                            \
-     || PLT_FDE_START_OFFSET != 4 + PLT_CIE_LENGTH + 8  \
+#if (PLT_CIE_LENGTH != 20                              \
+     || PLT_FDE_LENGTH != 36                           \
+     || PLT_FDE_START_OFFSET != 4 + PLT_CIE_LENGTH + 8 \
      || PLT_FDE_LEN_OFFSET != 4 + PLT_CIE_LENGTH + 12)
-# error "Need elf_i386_backend_data parameters for eh_frame_plt offsets!"
+# error "Need elf_x86_backend_data parameters for eh_frame_plt offsets!"
 #endif
     PLT_CIE_LENGTH, 0, 0, 0,           /* CIE length */
-    0, 0, 0, 0,                         /* CIE ID */
-    1,                                  /* CIE version */
-    'z', 'R', 0,                        /* Augmentation string */
-    1,                                  /* Code alignment factor */
-    0x7c,                               /* Data alignment factor: -4 */
-    8,                                  /* Return address column */
+    0, 0, 0, 0,                                /* CIE ID */
+    1,                                 /* CIE version */
+    'z', 'R', 0,                       /* Augmentation string */
+    1,                                 /* Code alignment factor */
+    0x7c,                              /* Data alignment factor: -4 */
+    8,                                 /* Return address column */
     1,                                 /* Augmentation size */
     DW_EH_PE_pcrel | DW_EH_PE_sdata4,  /* FDE encoding */
     DW_CFA_def_cfa, 4, 4,              /* DW_CFA_def_cfa: r4 (esp) ofs 4 */
     DW_CFA_offset + 8, 1,              /* DW_CFA_offset: r8 (eip) at cfa-4 */
     DW_CFA_nop, DW_CFA_nop,
 
-    PLT_FDE_LENGTH, 0, 0, 0,     /* FDE length */
+    PLT_FDE_LENGTH, 0, 0, 0,    /* FDE length */
     PLT_CIE_LENGTH + 8, 0, 0, 0, /* CIE pointer */
-    0, 0, 0, 0,                  /* R_386_PC32 .plt goes here */
-    0, 0, 0, 0,                  /* .plt size goes here */
-    0,                           /* Augmentation size */
-    DW_CFA_def_cfa_offset, 8,    /* DW_CFA_def_cfa_offset: 8 */
-    DW_CFA_advance_loc + 6,      /* DW_CFA_advance_loc: 6 to __PLT__+6 */
-    DW_CFA_def_cfa_offset, 12,   /* DW_CFA_def_cfa_offset: 12 */
-    DW_CFA_advance_loc + 58,     /* DW_CFA_advance_loc: 58 to __PLT__+64 */
-    DW_CFA_def_cfa_expression,   /* DW_CFA_def_cfa_expression */
-    13,                          /* Block length */
-    DW_OP_breg4, 4,              /* DW_OP_breg4 (esp): 4 */
-    DW_OP_breg8, 0,              /* DW_OP_breg8 (eip): 0 */
+    0, 0, 0, 0,                         /* R_386_PC32 .plt goes here */
+    0, 0, 0, 0,                         /* .plt size goes here */
+    0,                          /* Augmentation size */
+    DW_CFA_def_cfa_offset, 8,   /* DW_CFA_def_cfa_offset: 8 */
+    DW_CFA_advance_loc + 6,     /* DW_CFA_advance_loc: 6 to __PLT__+6 */
+    DW_CFA_def_cfa_offset, 12,  /* DW_CFA_def_cfa_offset: 12 */
+    DW_CFA_advance_loc + 58,    /* DW_CFA_advance_loc: 58 to __PLT__+64 */
+    DW_CFA_def_cfa_expression,  /* DW_CFA_def_cfa_expression */
+    13,                                 /* Block length */
+    DW_OP_breg4, 4,             /* DW_OP_breg4 (esp): 4 */
+    DW_OP_breg8, 0,             /* DW_OP_breg8 (eip): 0 */
     DW_OP_const1u, 63, DW_OP_and, DW_OP_const1u, 37, DW_OP_ge,
     DW_OP_lit2, DW_OP_shl, DW_OP_plus,
     DW_CFA_nop, DW_CFA_nop
   };
 
-static const struct elf_i386_lazy_plt_layout elf_i386_nacl_plt =
+static const struct elf_x86_lazy_plt_layout elf_i386_nacl_plt =
   {
     elf_i386_nacl_plt0_entry,          /* plt0_entry */
     sizeof (elf_i386_nacl_plt0_entry), /* plt0_entry_size */
-    2,                                 /* plt0_got1_offset */
-    8,                                 /* plt0_got2_offset */
     elf_i386_nacl_plt_entry,           /* plt_entry */
     NACL_PLT_ENTRY_SIZE,               /* plt_entry_size */
+    NULL,                              /* plt_tlsdesc_entry */
+    0,                                 /* plt_tlsdesc_entry_size*/
+    0,                                 /* plt_tlsdesc_got1_offset */
+    0,                                 /* plt_tlsdesc_got2_offset */
+    0,                                 /* plt_tlsdesc_got1_insn_end */
+    0,                                 /* plt_tlsdesc_got2_insn_end */
+    2,                                 /* plt0_got1_offset */
+    8,                                 /* plt0_got2_offset */
+    0,                                 /* plt0_got2_insn_end */
     2,                                 /* plt_got_offset */
     33,                                        /* plt_reloc_offset */
     38,                                        /* plt_plt_offset */
+    0,                                 /* plt_got_insn_size */
+    0,                                 /* plt_plt_insn_end */
     32,                                        /* plt_lazy_offset */
     elf_i386_nacl_pic_plt0_entry,      /* pic_plt0_entry */
     elf_i386_nacl_pic_plt_entry,       /* pic_plt_entry */
@@ -6937,10 +4773,9 @@ static const struct elf_i386_lazy_plt_layout elf_i386_nacl_plt =
     sizeof (elf_i386_nacl_eh_frame_plt) /* eh_frame_plt_size */
   };
 
-static const struct elf_i386_backend_data elf_i386_nacl_arch_bed =
+static const struct elf_x86_backend_data elf_i386_nacl_arch_bed =
   {
-    0x90,                               /* plt0_pad_byte: nop insn */
-    is_nacl                             /* os */
+    is_nacl                            /* os */
   };
 
 static bfd_boolean
@@ -6958,8 +4793,8 @@ elf32_i386_nacl_elf_object_p (bfd *abfd)
 #define elf_backend_object_p                   elf32_i386_nacl_elf_object_p
 #undef elf_backend_modify_segment_map
 #define        elf_backend_modify_segment_map          nacl_modify_segment_map
-#undef elf_backend_modify_program_headers
-#define        elf_backend_modify_program_headers      nacl_modify_program_headers
+#undef elf_backend_modify_headers
+#define        elf_backend_modify_headers              nacl_modify_headers
 #undef elf_backend_final_write_processing
 #define elf_backend_final_write_processing     nacl_final_write_processing
 
@@ -6968,7 +4803,7 @@ elf32_i386_nacl_elf_object_p (bfd *abfd)
 /* Restore defaults.  */
 #undef elf_backend_object_p
 #undef elf_backend_modify_segment_map
-#undef elf_backend_modify_program_headers
+#undef elf_backend_modify_headers
 #undef elf_backend_final_write_processing
 
 /* VxWorks support.  */
@@ -6983,10 +4818,9 @@ elf32_i386_nacl_elf_object_p (bfd *abfd)
 #undef elf_backend_plt_alignment
 #define elf_backend_plt_alignment      4
 
-static const struct elf_i386_backend_data elf_i386_vxworks_arch_bed =
+static const struct elf_x86_backend_data elf_i386_vxworks_arch_bed =
   {
-    0x90,                               /* plt0_pad_byte */
-    is_vxworks                          /* os */
+    is_vxworks                         /* os */
   };
 
 #undef elf_backend_arch_data
This page took 0.081828 seconds and 4 git commands to generate.