2011-04-18 Tristan Gingold <gingold@adacore.com>
[deliverable/binutils-gdb.git] / bfd / elf64-x86-64.c
index 9da73a1f500063b85544ad8e1c4762223f3e0ecd..84ee1017831ce865a48511d68e878abce95cef89 100644 (file)
@@ -1,6 +1,7 @@
-/* X86-64 specific support for 64-bit ELF
+/* X86-64 specific support for ELF
    Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,
-   2010  Free Software Foundation, Inc.
+   2010, 2011
+   Free Software Foundation, Inc.
    Contributed by Jan Hubicka <jh@suse.cz>.
 
    This file is part of BFD, the Binary File Descriptor library.
 /* In case we're on a 32-bit machine, construct a 64-bit "-1" value.  */
 #define MINUS_ONE (~ (bfd_vma) 0)
 
+/* Since both 32-bit and 64-bit x86-64 encode relocation type in the
+   identical manner, we use ELF32_R_TYPE instead of ELF64_R_TYPE to get
+   relocation type.  We also use ELF_ST_TYPE instead of ELF64_ST_TYPE
+   since they are the same.  */
+
+#define ABI_64_P(abfd) \
+  (get_elf_backend_data (abfd)->s->elfclass == ELFCLASS64)
+
 /* The relocation "howto" table.  Order of fields:
    type, rightshift, size, bitsize, pc_relative, bitpos, complain_on_overflow,
    special_function, name, partial_inplace, src_mask, dst_mask, pcrel_offset.  */
@@ -222,7 +231,7 @@ static const struct elf_reloc_map x86_64_reloc_map[] =
 };
 
 static reloc_howto_type *
-elf64_x86_64_rtype_to_howto (bfd *abfd, unsigned r_type)
+elf_x86_64_rtype_to_howto (bfd *abfd, unsigned r_type)
 {
   unsigned i;
 
@@ -245,8 +254,8 @@ elf64_x86_64_rtype_to_howto (bfd *abfd, unsigned r_type)
 
 /* Given a BFD reloc type, return a HOWTO structure.  */
 static reloc_howto_type *
-elf64_x86_64_reloc_type_lookup (bfd *abfd,
-                               bfd_reloc_code_real_type code)
+elf_x86_64_reloc_type_lookup (bfd *abfd,
+                             bfd_reloc_code_real_type code)
 {
   unsigned int i;
 
@@ -254,15 +263,15 @@ elf64_x86_64_reloc_type_lookup (bfd *abfd,
        i++)
     {
       if (x86_64_reloc_map[i].bfd_reloc_val == code)
-       return elf64_x86_64_rtype_to_howto (abfd,
-                                           x86_64_reloc_map[i].elf_reloc_val);
+       return elf_x86_64_rtype_to_howto (abfd,
+                                         x86_64_reloc_map[i].elf_reloc_val);
     }
   return 0;
 }
 
 static reloc_howto_type *
-elf64_x86_64_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
-                               const char *r_name)
+elf_x86_64_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
+                             const char *r_name)
 {
   unsigned int i;
 
@@ -280,19 +289,19 @@ elf64_x86_64_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
 /* Given an x86_64 ELF reloc type, fill in an arelent structure.  */
 
 static void
-elf64_x86_64_info_to_howto (bfd *abfd ATTRIBUTE_UNUSED, arelent *cache_ptr,
-                           Elf_Internal_Rela *dst)
+elf_x86_64_info_to_howto (bfd *abfd ATTRIBUTE_UNUSED, arelent *cache_ptr,
+                         Elf_Internal_Rela *dst)
 {
   unsigned r_type;
 
-  r_type = ELF64_R_TYPE (dst->r_info);
-  cache_ptr->howto = elf64_x86_64_rtype_to_howto (abfd, r_type);
+  r_type = ELF32_R_TYPE (dst->r_info);
+  cache_ptr->howto = elf_x86_64_rtype_to_howto (abfd, r_type);
   BFD_ASSERT (r_type == cache_ptr->howto->type);
 }
 \f
 /* Support for core dump NOTE sections.  */
 static bfd_boolean
-elf64_x86_64_grok_prstatus (bfd *abfd, Elf_Internal_Note *note)
+elf_x86_64_grok_prstatus (bfd *abfd, Elf_Internal_Note *note)
 {
   int offset;
   size_t size;
@@ -324,7 +333,7 @@ elf64_x86_64_grok_prstatus (bfd *abfd, Elf_Internal_Note *note)
 }
 
 static bfd_boolean
-elf64_x86_64_grok_psinfo (bfd *abfd, Elf_Internal_Note *note)
+elf_x86_64_grok_psinfo (bfd *abfd, Elf_Internal_Note *note)
 {
   switch (note->descsz)
     {
@@ -360,7 +369,8 @@ elf64_x86_64_grok_psinfo (bfd *abfd, Elf_Internal_Note *note)
 /* The name of the dynamic interpreter.         This is put in the .interp
    section.  */
 
-#define ELF_DYNAMIC_INTERPRETER "/lib/ld64.so.1"
+#define ELF64_DYNAMIC_INTERPRETER "/lib/ld64.so.1"
+#define ELF32_DYNAMIC_INTERPRETER "/lib/ld32.so.1"
 
 /* If ELIMINATE_COPY_RELOCS is non-zero, the linker will try to avoid
    copying dynamic variables from a shared lib into an app's dynbss
@@ -379,7 +389,7 @@ elf64_x86_64_grok_psinfo (bfd *abfd, Elf_Internal_Note *note)
 /* The first entry in a procedure linkage table looks like this.  See the
    SVR4 ABI i386 supplement and the x86-64 ABI to see how this works.  */
 
-static const bfd_byte elf64_x86_64_plt0_entry[PLT_ENTRY_SIZE] =
+static const bfd_byte elf_x86_64_plt0_entry[PLT_ENTRY_SIZE] =
 {
   0xff, 0x35, 8, 0, 0, 0,      /* pushq GOT+8(%rip)  */
   0xff, 0x25, 16, 0, 0, 0,     /* jmpq *GOT+16(%rip) */
@@ -388,7 +398,7 @@ static const bfd_byte elf64_x86_64_plt0_entry[PLT_ENTRY_SIZE] =
 
 /* Subsequent entries in a procedure linkage table look like this.  */
 
-static const bfd_byte elf64_x86_64_plt_entry[PLT_ENTRY_SIZE] =
+static const bfd_byte elf_x86_64_plt_entry[PLT_ENTRY_SIZE] =
 {
   0xff, 0x25,  /* jmpq *name@GOTPC(%rip) */
   0, 0, 0, 0,  /* replaced with offset to this symbol in .got.  */
@@ -400,7 +410,7 @@ static const bfd_byte elf64_x86_64_plt_entry[PLT_ENTRY_SIZE] =
 
 /* x86-64 ELF linker hash entry.  */
 
-struct elf64_x86_64_link_hash_entry
+struct elf_x86_64_link_hash_entry
 {
   struct elf_link_hash_entry elf;
 
@@ -427,10 +437,10 @@ struct elf64_x86_64_link_hash_entry
   bfd_vma tlsdesc_got;
 };
 
-#define elf64_x86_64_hash_entry(ent) \
-  ((struct elf64_x86_64_link_hash_entry *)(ent))
+#define elf_x86_64_hash_entry(ent) \
+  ((struct elf_x86_64_link_hash_entry *)(ent))
 
-struct elf64_x86_64_obj_tdata
+struct elf_x86_64_obj_tdata
 {
   struct elf_obj_tdata root;
 
@@ -441,14 +451,14 @@ struct elf64_x86_64_obj_tdata
   bfd_vma *local_tlsdesc_gotent;
 };
 
-#define elf64_x86_64_tdata(abfd) \
-  ((struct elf64_x86_64_obj_tdata *) (abfd)->tdata.any)
+#define elf_x86_64_tdata(abfd) \
+  ((struct elf_x86_64_obj_tdata *) (abfd)->tdata.any)
 
-#define elf64_x86_64_local_got_tls_type(abfd) \
-  (elf64_x86_64_tdata (abfd)->local_got_tls_type)
+#define elf_x86_64_local_got_tls_type(abfd) \
+  (elf_x86_64_tdata (abfd)->local_got_tls_type)
 
-#define elf64_x86_64_local_tlsdesc_gotent(abfd) \
-  (elf64_x86_64_tdata (abfd)->local_tlsdesc_gotent)
+#define elf_x86_64_local_tlsdesc_gotent(abfd) \
+  (elf_x86_64_tdata (abfd)->local_tlsdesc_gotent)
 
 #define is_x86_64_elf(bfd)                             \
   (bfd_get_flavour (bfd) == bfd_target_elf_flavour     \
@@ -456,15 +466,15 @@ struct elf64_x86_64_obj_tdata
    && elf_object_id (bfd) == X86_64_ELF_DATA)
 
 static bfd_boolean
-elf64_x86_64_mkobject (bfd *abfd)
+elf_x86_64_mkobject (bfd *abfd)
 {
-  return bfd_elf_allocate_object (abfd, sizeof (struct elf64_x86_64_obj_tdata),
+  return bfd_elf_allocate_object (abfd, sizeof (struct elf_x86_64_obj_tdata),
                                  X86_64_ELF_DATA);
 }
 
 /* x86-64 ELF linker hash table.  */
 
-struct elf64_x86_64_link_hash_table
+struct elf_x86_64_link_hash_table
 {
   struct elf_link_hash_table elf;
 
@@ -484,6 +494,12 @@ struct elf64_x86_64_link_hash_table
   /* Small local sym cache.  */
   struct sym_cache sym_cache;
 
+  bfd_vma (*r_info) (bfd_vma, bfd_vma);
+  bfd_vma (*r_sym) (bfd_vma);
+  unsigned int pointer_r_type;
+  const char *dynamic_interpreter;
+  int dynamic_interpreter_size;
+
   /* _TLS_MODULE_BASE_ symbol.  */
   struct bfd_link_hash_entry *tls_module_base;
 
@@ -503,19 +519,19 @@ struct elf64_x86_64_link_hash_table
 
 /* Get the x86-64 ELF linker hash table from a link_info structure.  */
 
-#define elf64_x86_64_hash_table(p) \
+#define elf_x86_64_hash_table(p) \
   (elf_hash_table_id ((struct elf_link_hash_table *) ((p)->hash)) \
-  == X86_64_ELF_DATA ? ((struct elf64_x86_64_link_hash_table *) ((p)->hash)) : NULL)
+  == X86_64_ELF_DATA ? ((struct elf_x86_64_link_hash_table *) ((p)->hash)) : NULL)
 
-#define elf64_x86_64_compute_jump_table_size(htab) \
+#define elf_x86_64_compute_jump_table_size(htab) \
   ((htab)->elf.srelplt->reloc_count * GOT_ENTRY_SIZE)
 
 /* Create an entry in an x86-64 ELF linker hash table. */
 
 static struct bfd_hash_entry *
-elf64_x86_64_link_hash_newfunc (struct bfd_hash_entry *entry,
-                               struct bfd_hash_table *table,
-                               const char *string)
+elf_x86_64_link_hash_newfunc (struct bfd_hash_entry *entry,
+                             struct bfd_hash_table *table,
+                             const char *string)
 {
   /* Allocate the structure if it has not already been allocated by a
      subclass.  */
@@ -523,7 +539,7 @@ elf64_x86_64_link_hash_newfunc (struct bfd_hash_entry *entry,
     {
       entry = (struct bfd_hash_entry *)
           bfd_hash_allocate (table,
-                             sizeof (struct elf64_x86_64_link_hash_entry));
+                             sizeof (struct elf_x86_64_link_hash_entry));
       if (entry == NULL)
        return entry;
     }
@@ -532,9 +548,9 @@ elf64_x86_64_link_hash_newfunc (struct bfd_hash_entry *entry,
   entry = _bfd_elf_link_hash_newfunc (entry, table, string);
   if (entry != NULL)
     {
-      struct elf64_x86_64_link_hash_entry *eh;
+      struct elf_x86_64_link_hash_entry *eh;
 
-      eh = (struct elf64_x86_64_link_hash_entry *) entry;
+      eh = (struct elf_x86_64_link_hash_entry *) entry;
       eh->dyn_relocs = NULL;
       eh->tls_type = GOT_UNKNOWN;
       eh->tlsdesc_got = (bfd_vma) -1;
@@ -549,7 +565,7 @@ elf64_x86_64_link_hash_newfunc (struct bfd_hash_entry *entry,
   hash since they aren't used by global symbols in this backend.  */
 
 static hashval_t
-elf64_x86_64_local_htab_hash (const void *ptr)
+elf_x86_64_local_htab_hash (const void *ptr)
 {
   struct elf_link_hash_entry *h
     = (struct elf_link_hash_entry *) ptr;
@@ -559,7 +575,7 @@ elf64_x86_64_local_htab_hash (const void *ptr)
 /* Compare local hash entries.  */
 
 static int
-elf64_x86_64_local_htab_eq (const void *ptr1, const void *ptr2)
+elf_x86_64_local_htab_eq (const void *ptr1, const void *ptr2)
 {
   struct elf_link_hash_entry *h1
      = (struct elf_link_hash_entry *) ptr1;
@@ -572,18 +588,18 @@ elf64_x86_64_local_htab_eq (const void *ptr1, const void *ptr2)
 /* Find and/or create a hash entry for local symbol.  */
 
 static struct elf_link_hash_entry *
-elf64_x86_64_get_local_sym_hash (struct elf64_x86_64_link_hash_table *htab,
-                                bfd *abfd, const Elf_Internal_Rela *rel,
-                                bfd_boolean create)
+elf_x86_64_get_local_sym_hash (struct elf_x86_64_link_hash_table *htab,
+                              bfd *abfd, const Elf_Internal_Rela *rel,
+                              bfd_boolean create)
 {
-  struct elf64_x86_64_link_hash_entry e, *ret;
+  struct elf_x86_64_link_hash_entry e, *ret;
   asection *sec = abfd->sections;
   hashval_t h = ELF_LOCAL_SYMBOL_HASH (sec->id,
-                                      ELF64_R_SYM (rel->r_info));
+                                      htab->r_sym (rel->r_info));
   void **slot;
 
   e.elf.indx = sec->id;
-  e.elf.dynstr_index = ELF64_R_SYM (rel->r_info);
+  e.elf.dynstr_index = htab->r_sym (rel->r_info);
   slot = htab_find_slot_with_hash (htab->loc_hash_table, &e, h,
                                   create ? INSERT : NO_INSERT);
 
@@ -592,18 +608,18 @@ elf64_x86_64_get_local_sym_hash (struct elf64_x86_64_link_hash_table *htab,
 
   if (*slot)
     {
-      ret = (struct elf64_x86_64_link_hash_entry *) *slot;
+      ret = (struct elf_x86_64_link_hash_entry *) *slot;
       return &ret->elf;
     }
 
-  ret = (struct elf64_x86_64_link_hash_entry *)
+  ret = (struct elf_x86_64_link_hash_entry *)
        objalloc_alloc ((struct objalloc *) htab->loc_hash_memory,
-                       sizeof (struct elf64_x86_64_link_hash_entry));
+                       sizeof (struct elf_x86_64_link_hash_entry));
   if (ret)
     {
       memset (ret, 0, sizeof (*ret));
       ret->elf.indx = sec->id;
-      ret->elf.dynstr_index = ELF64_R_SYM (rel->r_info);
+      ret->elf.dynstr_index = htab->r_sym (rel->r_info);
       ret->elf.dynindx = -1;
       *slot = ret;
     }
@@ -613,18 +629,18 @@ elf64_x86_64_get_local_sym_hash (struct elf64_x86_64_link_hash_table *htab,
 /* Create an X86-64 ELF linker hash table.  */
 
 static struct bfd_link_hash_table *
-elf64_x86_64_link_hash_table_create (bfd *abfd)
+elf_x86_64_link_hash_table_create (bfd *abfd)
 {
-  struct elf64_x86_64_link_hash_table *ret;
-  bfd_size_type amt = sizeof (struct elf64_x86_64_link_hash_table);
+  struct elf_x86_64_link_hash_table *ret;
+  bfd_size_type amt = sizeof (struct elf_x86_64_link_hash_table);
 
-  ret = (struct elf64_x86_64_link_hash_table *) bfd_malloc (amt);
+  ret = (struct elf_x86_64_link_hash_table *) bfd_malloc (amt);
   if (ret == NULL)
     return NULL;
 
   if (!_bfd_elf_link_hash_table_init (&ret->elf, abfd,
-                                     elf64_x86_64_link_hash_newfunc,
-                                     sizeof (struct elf64_x86_64_link_hash_entry),
+                                     elf_x86_64_link_hash_newfunc,
+                                     sizeof (struct elf_x86_64_link_hash_entry),
                                      X86_64_ELF_DATA))
     {
       free (ret);
@@ -640,9 +656,26 @@ elf64_x86_64_link_hash_table_create (bfd *abfd)
   ret->sgotplt_jump_table_size = 0;
   ret->tls_module_base = NULL;
 
+  if (ABI_64_P (abfd))
+    {
+      ret->r_info = elf64_r_info;
+      ret->r_sym = elf64_r_sym;
+      ret->pointer_r_type = R_X86_64_64;
+      ret->dynamic_interpreter = ELF64_DYNAMIC_INTERPRETER;
+      ret->dynamic_interpreter_size = sizeof ELF64_DYNAMIC_INTERPRETER;
+    }
+  else
+    {
+      ret->r_info = elf32_r_info;
+      ret->r_sym = elf32_r_sym;
+      ret->pointer_r_type = R_X86_64_32;
+      ret->dynamic_interpreter = ELF32_DYNAMIC_INTERPRETER;
+      ret->dynamic_interpreter_size = sizeof ELF32_DYNAMIC_INTERPRETER;
+    }
+
   ret->loc_hash_table = htab_try_create (1024,
-                                        elf64_x86_64_local_htab_hash,
-                                        elf64_x86_64_local_htab_eq,
+                                        elf_x86_64_local_htab_hash,
+                                        elf_x86_64_local_htab_eq,
                                         NULL);
   ret->loc_hash_memory = objalloc_create ();
   if (!ret->loc_hash_table || !ret->loc_hash_memory)
@@ -657,10 +690,10 @@ elf64_x86_64_link_hash_table_create (bfd *abfd)
 /* Destroy an X86-64 ELF linker hash table.  */
 
 static void
-elf64_x86_64_link_hash_table_free (struct bfd_link_hash_table *hash)
+elf_x86_64_link_hash_table_free (struct bfd_link_hash_table *hash)
 {
-  struct elf64_x86_64_link_hash_table *htab
-    = (struct elf64_x86_64_link_hash_table *) hash;
+  struct elf_x86_64_link_hash_table *htab
+    = (struct elf_x86_64_link_hash_table *) hash;
 
   if (htab->loc_hash_table)
     htab_delete (htab->loc_hash_table);
@@ -674,14 +707,15 @@ elf64_x86_64_link_hash_table_free (struct bfd_link_hash_table *hash)
    hash table.  */
 
 static bfd_boolean
-elf64_x86_64_create_dynamic_sections (bfd *dynobj, struct bfd_link_info *info)
+elf_x86_64_create_dynamic_sections (bfd *dynobj,
+                                   struct bfd_link_info *info)
 {
-  struct elf64_x86_64_link_hash_table *htab;
+  struct elf_x86_64_link_hash_table *htab;
 
   if (!_bfd_elf_create_dynamic_sections (dynobj, info))
     return FALSE;
 
-  htab = elf64_x86_64_hash_table (info);
+  htab = elf_x86_64_hash_table (info);
   if (htab == NULL)
     return FALSE;
 
@@ -699,14 +733,14 @@ elf64_x86_64_create_dynamic_sections (bfd *dynobj, struct bfd_link_info *info)
 /* Copy the extra info we tack onto an elf_link_hash_entry.  */
 
 static void
-elf64_x86_64_copy_indirect_symbol (struct bfd_link_info *info,
-                                  struct elf_link_hash_entry *dir,
-                                  struct elf_link_hash_entry *ind)
+elf_x86_64_copy_indirect_symbol (struct bfd_link_info *info,
+                                struct elf_link_hash_entry *dir,
+                                struct elf_link_hash_entry *ind)
 {
-  struct elf64_x86_64_link_hash_entry *edir, *eind;
+  struct elf_x86_64_link_hash_entry *edir, *eind;
 
-  edir = (struct elf64_x86_64_link_hash_entry *) dir;
-  eind = (struct elf64_x86_64_link_hash_entry *) ind;
+  edir = (struct elf_x86_64_link_hash_entry *) dir;
+  eind = (struct elf_x86_64_link_hash_entry *) ind;
 
   if (eind->dyn_relocs != NULL)
     {
@@ -789,18 +823,21 @@ x86_64_opcode32;
    from R_TYPE.  */
 
 static bfd_boolean
-elf64_x86_64_check_tls_transition (bfd *abfd, asection *sec,
-                                  bfd_byte *contents,
-                                  Elf_Internal_Shdr *symtab_hdr,
-                                  struct elf_link_hash_entry **sym_hashes,
-                                  unsigned int r_type,
-                                  const Elf_Internal_Rela *rel,
-                                  const Elf_Internal_Rela *relend)
+elf_x86_64_check_tls_transition (bfd *abfd,
+                                struct bfd_link_info *info,
+                                asection *sec,
+                                bfd_byte *contents,
+                                Elf_Internal_Shdr *symtab_hdr,
+                                struct elf_link_hash_entry **sym_hashes,
+                                unsigned int r_type,
+                                const Elf_Internal_Rela *rel,
+                                const Elf_Internal_Rela *relend)
 {
   unsigned int val;
   unsigned long r_symndx;
   struct elf_link_hash_entry *h;
   bfd_vma offset;
+  struct elf_x86_64_link_hash_table *htab;
 
   /* Get the section contents.  */
   if (contents == NULL)
@@ -818,6 +855,7 @@ elf64_x86_64_check_tls_transition (bfd *abfd, asection *sec,
        }
     }
 
+  htab = elf_x86_64_hash_table (info);
   offset = rel->r_offset;
   switch (r_type)
     {
@@ -828,18 +866,34 @@ elf64_x86_64_check_tls_transition (bfd *abfd, asection *sec,
 
       if (r_type == R_X86_64_TLSGD)
        {
-         /* Check transition from GD access model.  Only
+         /* Check transition from GD access model.  For 64bit, only
                .byte 0x66; leaq foo@tlsgd(%rip), %rdi
                .word 0x6666; rex64; call __tls_get_addr
+            can transit to different access model.  For 32bit, only
+               leaq foo@tlsgd(%rip), %rdi
+               .word 0x6666; rex64; call __tls_get_addr
             can transit to different access model.  */
 
-         static x86_64_opcode32 leaq = { { 0x66, 0x48, 0x8d, 0x3d } },
-                                call = { { 0x66, 0x66, 0x48, 0xe8 } };
-         if (offset < 4
-             || (offset + 12) > sec->size
-             || bfd_get_32 (abfd, contents + offset - 4) != leaq.i
+         static x86_64_opcode32 call = { { 0x66, 0x66, 0x48, 0xe8 } };
+         if ((offset + 12) > sec->size
              || bfd_get_32 (abfd, contents + offset + 4) != call.i)
            return FALSE;
+
+         if (ABI_64_P (abfd))
+           {
+             static x86_64_opcode32 leaq = { { 0x66, 0x48, 0x8d, 0x3d } };
+             if (offset < 4
+                 || bfd_get_32 (abfd, contents + offset - 4) != leaq.i)
+               return FALSE;
+           }
+         else
+           {
+             static x86_64_opcode16 lea = { { 0x8d, 0x3d } };
+             if (offset < 3
+                 || bfd_get_8 (abfd, contents + offset - 3) != 0x48
+                 || bfd_get_16 (abfd, contents + offset - 2) != lea.i)
+               return FALSE;
+           }
        }
       else
        {
@@ -860,7 +914,7 @@ elf64_x86_64_check_tls_transition (bfd *abfd, asection *sec,
            return FALSE;
        }
 
-      r_symndx = ELF64_R_SYM (rel[1].r_info);
+      r_symndx = htab->r_sym (rel[1].r_info);
       if (r_symndx < symtab_hdr->sh_info)
        return FALSE;
 
@@ -869,23 +923,36 @@ elf64_x86_64_check_tls_transition (bfd *abfd, asection *sec,
         may be versioned.  */ 
       return (h != NULL
              && h->root.root.string != NULL
-             && (ELF64_R_TYPE (rel[1].r_info) == R_X86_64_PC32
-                 || ELF64_R_TYPE (rel[1].r_info) == R_X86_64_PLT32)
+             && (ELF32_R_TYPE (rel[1].r_info) == R_X86_64_PC32
+                 || ELF32_R_TYPE (rel[1].r_info) == R_X86_64_PLT32)
              && (strncmp (h->root.root.string,
                           "__tls_get_addr", 14) == 0));
 
     case R_X86_64_GOTTPOFF:
       /* Check transition from IE access model:
-               movq foo@gottpoff(%rip), %reg
-               addq foo@gottpoff(%rip), %reg
+               mov foo@gottpoff(%rip), %reg
+               add foo@gottpoff(%rip), %reg
        */
 
-      if (offset < 3 || (offset + 4) > sec->size)
-       return FALSE;
-
-      val = bfd_get_8 (abfd, contents + offset - 3);
-      if (val != 0x48 && val != 0x4c)
-       return FALSE;
+      /* Check REX prefix first.  */
+      if (offset >= 3 && (offset + 4) <= sec->size)
+       {
+         val = bfd_get_8 (abfd, contents + offset - 3);
+         if (val != 0x48 && val != 0x4c)
+           {
+             /* X32 may have 0x44 REX prefix or no REX prefix.  */
+             if (ABI_64_P (abfd))
+               return FALSE;
+           }
+       }
+      else
+       {
+         /* X32 may not have any REX prefix.  */
+         if (ABI_64_P (abfd))
+           return FALSE;
+         if (offset < 2 || (offset + 3) > sec->size)
+           return FALSE;
+       }
 
       val = bfd_get_8 (abfd, contents + offset - 2);
       if (val != 0x8b && val != 0x03)
@@ -937,15 +1004,15 @@ elf64_x86_64_check_tls_transition (bfd *abfd, asection *sec,
    will be performed.  Update R_TYPE if there is a transition.  */
 
 static bfd_boolean
-elf64_x86_64_tls_transition (struct bfd_link_info *info, bfd *abfd,
-                            asection *sec, bfd_byte *contents,
-                            Elf_Internal_Shdr *symtab_hdr,
-                            struct elf_link_hash_entry **sym_hashes,
-                            unsigned int *r_type, int tls_type,
-                            const Elf_Internal_Rela *rel,
-                            const Elf_Internal_Rela *relend,
-                            struct elf_link_hash_entry *h,
-                            unsigned long r_symndx)
+elf_x86_64_tls_transition (struct bfd_link_info *info, bfd *abfd,
+                          asection *sec, bfd_byte *contents,
+                          Elf_Internal_Shdr *symtab_hdr,
+                          struct elf_link_hash_entry **sym_hashes,
+                          unsigned int *r_type, int tls_type,
+                          const Elf_Internal_Rela *rel,
+                          const Elf_Internal_Rela *relend,
+                          struct elf_link_hash_entry *h,
+                          unsigned long r_symndx)
 {
   unsigned int from_type = *r_type;
   unsigned int to_type = from_type;
@@ -971,7 +1038,7 @@ elf64_x86_64_tls_transition (struct bfd_link_info *info, bfd *abfd,
            to_type = R_X86_64_GOTTPOFF;
        }
 
-      /* When we are called from elf64_x86_64_relocate_section,
+      /* When we are called from elf_x86_64_relocate_section,
         CONTENTS isn't NULL and there may be additional transitions
         based on TLS_TYPE.  */
       if (contents != NULL)
@@ -993,7 +1060,7 @@ elf64_x86_64_tls_transition (struct bfd_link_info *info, bfd *abfd,
            }
 
          /* We checked the transition before when we were called from
-            elf64_x86_64_check_relocs.  We only want to check the new
+            elf_x86_64_check_relocs.  We only want to check the new
             transition which hasn't been checked before.  */
          check = new_to_type != to_type && from_type == to_type;
          to_type = new_to_type;
@@ -1016,23 +1083,23 @@ elf64_x86_64_tls_transition (struct bfd_link_info *info, bfd *abfd,
 
   /* Check if the transition can be performed.  */
   if (check
-      && ! elf64_x86_64_check_tls_transition (abfd, sec, contents,
-                                             symtab_hdr, sym_hashes,
-                                             from_type, rel, relend))
+      && ! elf_x86_64_check_tls_transition (abfd, info, sec, contents,
+                                           symtab_hdr, sym_hashes,
+                                           from_type, rel, relend))
     {
       reloc_howto_type *from, *to;
       const char *name;
 
-      from = elf64_x86_64_rtype_to_howto (abfd, from_type);
-      to = elf64_x86_64_rtype_to_howto (abfd, to_type);
+      from = elf_x86_64_rtype_to_howto (abfd, from_type);
+      to = elf_x86_64_rtype_to_howto (abfd, to_type);
 
       if (h)
        name = h->root.root.string;
       else
        {
-         struct elf64_x86_64_link_hash_table *htab;
+         struct elf_x86_64_link_hash_table *htab;
 
-         htab = elf64_x86_64_hash_table (info);
+         htab = elf_x86_64_hash_table (info);
          if (htab == NULL)
            name = "*unknown*";
          else
@@ -1063,11 +1130,11 @@ elf64_x86_64_tls_transition (struct bfd_link_info *info, bfd *abfd,
    linkage table, and dynamic reloc sections.  */
 
 static bfd_boolean
-elf64_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info,
-                          asection *sec,
-                          const Elf_Internal_Rela *relocs)
+elf_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info,
+                        asection *sec,
+                        const Elf_Internal_Rela *relocs)
 {
-  struct elf64_x86_64_link_hash_table *htab;
+  struct elf_x86_64_link_hash_table *htab;
   Elf_Internal_Shdr *symtab_hdr;
   struct elf_link_hash_entry **sym_hashes;
   const Elf_Internal_Rela *rel;
@@ -1079,7 +1146,7 @@ elf64_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info,
 
   BFD_ASSERT (is_x86_64_elf (abfd));
 
-  htab = elf64_x86_64_hash_table (info);
+  htab = elf_x86_64_hash_table (info);
   if (htab == NULL)
     return FALSE;
 
@@ -1097,8 +1164,8 @@ elf64_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info,
       Elf_Internal_Sym *isym;
       const char *name;
 
-      r_symndx = ELF64_R_SYM (rel->r_info);
-      r_type = ELF64_R_TYPE (rel->r_info);
+      r_symndx = htab->r_sym (rel->r_info);
+      r_type = ELF32_R_TYPE (rel->r_info);
 
       if (r_symndx >= NUM_SHDR_ENTRIES (symtab_hdr))
        {
@@ -1116,10 +1183,10 @@ elf64_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info,
            return FALSE;
 
          /* Check relocation against local STT_GNU_IFUNC symbol.  */
-         if (ELF64_ST_TYPE (isym->st_info) == STT_GNU_IFUNC)
+         if (ELF_ST_TYPE (isym->st_info) == STT_GNU_IFUNC)
            {
-             h = elf64_x86_64_get_local_sym_hash (htab, abfd, rel,
-                                                  TRUE);
+             h = elf_x86_64_get_local_sym_hash (htab, abfd, rel,
+                                                TRUE);
              if (h == NULL)
                return FALSE;
 
@@ -1142,6 +1209,39 @@ elf64_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info,
            h = (struct elf_link_hash_entry *) h->root.u.i.link;
        }
 
+      /* Check invalid x32 relocations.  */
+      if (!ABI_64_P (abfd))
+       switch (r_type)
+         {
+         default:
+           break;
+
+         case R_X86_64_64:
+         case R_X86_64_DTPOFF64:
+         case R_X86_64_TPOFF64:
+         case R_X86_64_PC64:
+         case R_X86_64_GOTOFF64:
+         case R_X86_64_GOT64:
+         case R_X86_64_GOTPCREL64:
+         case R_X86_64_GOTPC64:
+         case R_X86_64_GOTPLT64:
+         case R_X86_64_PLTOFF64:
+             {
+               if (h)
+                 name = h->root.root.string;
+               else
+                 name = bfd_elf_sym_name (abfd, symtab_hdr, isym,
+                                          NULL);
+               (*_bfd_error_handler)
+                 (_("%B: relocation %s against symbol `%s' isn't "
+                    "supported in x32 mode"), abfd,
+                  x86_64_elf_howto_table[r_type].name, name);
+               bfd_set_error (bfd_error_bad_value);
+               return FALSE;
+             }
+           break;
+         }
+
       if (h != NULL)
        {
          /* Create the ifunc sections for static executables.  If we
@@ -1198,6 +1298,9 @@ elf64_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info,
                  bfd_set_error (bfd_error_bad_value);
                  return FALSE;
 
+               case R_X86_64_32:
+                 if (ABI_64_P (abfd))
+                   goto not_pointer;
                case R_X86_64_64:
                  h->non_got_ref = 1;
                  h->pointer_equality_needed = 1;
@@ -1208,16 +1311,16 @@ elf64_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info,
                         make room for this reloc.  */
                      sreloc = _bfd_elf_create_ifunc_dyn_reloc
                        (abfd, info, sec, sreloc,
-                        &((struct elf64_x86_64_link_hash_entry *) h)->dyn_relocs);
+                        &((struct elf_x86_64_link_hash_entry *) h)->dyn_relocs);
                      if (sreloc == NULL)
                        return FALSE;
                    }
                  break;
 
                case R_X86_64_32S:
-               case R_X86_64_32:
                case R_X86_64_PC32:
                case R_X86_64_PC64:
+not_pointer:
                  h->non_got_ref = 1;
                  if (r_type != R_X86_64_PC32
                      && r_type != R_X86_64_PC64)
@@ -1241,10 +1344,10 @@ elf64_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info,
            }
        }
 
-      if (! elf64_x86_64_tls_transition (info, abfd, sec, NULL,
-                                        symtab_hdr, sym_hashes,
-                                        &r_type, GOT_UNKNOWN,
-                                        rel, rel_end, h, r_symndx))
+      if (! elf_x86_64_tls_transition (info, abfd, sec, NULL,
+                                      symtab_hdr, sym_hashes,
+                                      &r_type, GOT_UNKNOWN,
+                                      rel, rel_end, h, r_symndx))
        return FALSE;
 
       switch (r_type)
@@ -1254,7 +1357,7 @@ elf64_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info,
          goto create_got;
 
        case R_X86_64_TPOFF32:
-         if (!info->executable)
+         if (!info->executable && ABI_64_P (abfd))
            {
              if (h)
                name = h->root.root.string;
@@ -1308,7 +1411,7 @@ elf64_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info,
                    h->plt.refcount += 1;
                  }
                h->got.refcount += 1;
-               old_tls_type = elf64_x86_64_hash_entry (h)->tls_type;
+               old_tls_type = elf_x86_64_hash_entry (h)->tls_type;
              }
            else
              {
@@ -1328,14 +1431,14 @@ elf64_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info,
                    if (local_got_refcounts == NULL)
                      return FALSE;
                    elf_local_got_refcounts (abfd) = local_got_refcounts;
-                   elf64_x86_64_local_tlsdesc_gotent (abfd)
+                   elf_x86_64_local_tlsdesc_gotent (abfd)
                      = (bfd_vma *) (local_got_refcounts + symtab_hdr->sh_info);
-                   elf64_x86_64_local_got_tls_type (abfd)
+                   elf_x86_64_local_got_tls_type (abfd)
                      = (char *) (local_got_refcounts + 2 * symtab_hdr->sh_info);
                  }
                local_got_refcounts[r_symndx] += 1;
                old_tls_type
-                 = elf64_x86_64_local_got_tls_type (abfd) [r_symndx];
+                 = elf_x86_64_local_got_tls_type (abfd) [r_symndx];
              }
 
            /* If a TLS symbol is accessed using IE at least once,
@@ -1366,9 +1469,9 @@ elf64_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info,
            if (old_tls_type != tls_type)
              {
                if (h != NULL)
-                 elf64_x86_64_hash_entry (h)->tls_type = tls_type;
+                 elf_x86_64_hash_entry (h)->tls_type = tls_type;
                else
-                 elf64_x86_64_local_got_tls_type (abfd) [r_symndx] = tls_type;
+                 elf_x86_64_local_got_tls_type (abfd) [r_symndx] = tls_type;
              }
          }
          /* Fall through */
@@ -1414,9 +1517,11 @@ elf64_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info,
            }
          goto create_got;
 
+       case R_X86_64_32:
+         if (!ABI_64_P (abfd))
+           goto pointer;
        case R_X86_64_8:
        case R_X86_64_16:
-       case R_X86_64_32:
        case R_X86_64_32S:
          /* Let's help debug shared library creation.  These relocs
             cannot be used in shared libs.  Don't error out for
@@ -1443,6 +1548,7 @@ elf64_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info,
        case R_X86_64_PC32:
        case R_X86_64_PC64:
        case R_X86_64_64:
+pointer:
          if (h != NULL && info->executable)
            {
              /* If this reloc is in a read-only section, we might
@@ -1507,7 +1613,8 @@ elf64_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info,
                    htab->elf.dynobj = abfd;
 
                  sreloc = _bfd_elf_make_dynamic_reloc_section
-                   (sec, htab->elf.dynobj, 3, abfd, /*rela?*/ TRUE);
+                   (sec, htab->elf.dynobj, ABI_64_P (abfd) ? 3 : 2,
+                    abfd, /*rela?*/ TRUE);
 
                  if (sreloc == NULL)
                    return FALSE;
@@ -1517,7 +1624,7 @@ elf64_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info,
                 relocations we need for this symbol.  */
              if (h != NULL)
                {
-                 head = &((struct elf64_x86_64_link_hash_entry *) h)->dyn_relocs;
+                 head = &((struct elf_x86_64_link_hash_entry *) h)->dyn_relocs;
                }
              else
                {
@@ -1592,14 +1699,14 @@ elf64_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info,
    relocation. */
 
 static asection *
-elf64_x86_64_gc_mark_hook (asection *sec,
-                          struct bfd_link_info *info,
-                          Elf_Internal_Rela *rel,
-                          struct elf_link_hash_entry *h,
-                          Elf_Internal_Sym *sym)
+elf_x86_64_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 (ELF64_R_TYPE (rel->r_info))
+    switch (ELF32_R_TYPE (rel->r_info))
       {
       case R_X86_64_GNU_VTINHERIT:
       case R_X86_64_GNU_VTENTRY:
@@ -1612,11 +1719,11 @@ elf64_x86_64_gc_mark_hook (asection *sec,
 /* Update the got entry reference counts for the section being removed.         */
 
 static bfd_boolean
-elf64_x86_64_gc_sweep_hook (bfd *abfd, struct bfd_link_info *info,
-                           asection *sec,
-                           const Elf_Internal_Rela *relocs)
+elf_x86_64_gc_sweep_hook (bfd *abfd, struct bfd_link_info *info,
+                         asection *sec,
+                         const Elf_Internal_Rela *relocs)
 {
-  struct elf64_x86_64_link_hash_table *htab;
+  struct elf_x86_64_link_hash_table *htab;
   Elf_Internal_Shdr *symtab_hdr;
   struct elf_link_hash_entry **sym_hashes;
   bfd_signed_vma *local_got_refcounts;
@@ -1625,7 +1732,7 @@ elf64_x86_64_gc_sweep_hook (bfd *abfd, struct bfd_link_info *info,
   if (info->relocatable)
     return TRUE;
 
-  htab = elf64_x86_64_hash_table (info);
+  htab = elf_x86_64_hash_table (info);
   if (htab == NULL)
     return FALSE;
 
@@ -1635,6 +1742,7 @@ elf64_x86_64_gc_sweep_hook (bfd *abfd, struct bfd_link_info *info,
   sym_hashes = elf_sym_hashes (abfd);
   local_got_refcounts = elf_local_got_refcounts (abfd);
 
+  htab = elf_x86_64_hash_table (info);
   relend = relocs + sec->reloc_count;
   for (rel = relocs; rel < relend; rel++)
     {
@@ -1642,26 +1750,13 @@ elf64_x86_64_gc_sweep_hook (bfd *abfd, struct bfd_link_info *info,
       unsigned int r_type;
       struct elf_link_hash_entry *h = NULL;
 
-      r_symndx = ELF64_R_SYM (rel->r_info);
+      r_symndx = htab->r_sym (rel->r_info);
       if (r_symndx >= symtab_hdr->sh_info)
        {
-         struct elf64_x86_64_link_hash_entry *eh;
-         struct elf_dyn_relocs **pp;
-         struct elf_dyn_relocs *p;
-
          h = sym_hashes[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;
-         eh = (struct elf64_x86_64_link_hash_entry *) h;
-
-         for (pp = &eh->dyn_relocs; (p = *pp) != NULL; pp = &p->next)
-           if (p->sec == sec)
-             {
-               /* Everything must go for SEC.  */
-               *pp = p->next;
-               break;
-             }
        }
       else
        {
@@ -1673,20 +1768,36 @@ elf64_x86_64_gc_sweep_hook (bfd *abfd, struct bfd_link_info *info,
 
          /* Check relocation against local STT_GNU_IFUNC symbol.  */
          if (isym != NULL
-             && ELF64_ST_TYPE (isym->st_info) == STT_GNU_IFUNC)
+             && ELF_ST_TYPE (isym->st_info) == STT_GNU_IFUNC)
            {
-             h = elf64_x86_64_get_local_sym_hash (htab, abfd, rel,
-                                                  FALSE);
+             h = elf_x86_64_get_local_sym_hash (htab, abfd, rel, FALSE);
              if (h == NULL)
                abort ();
            }
        }
 
-      r_type = ELF64_R_TYPE (rel->r_info);
-      if (! elf64_x86_64_tls_transition (info, abfd, sec, NULL,
-                                        symtab_hdr, sym_hashes,
-                                        &r_type, GOT_UNKNOWN,
-                                        rel, relend, h, r_symndx))
+      if (h)
+       {
+         struct elf_x86_64_link_hash_entry *eh;
+         struct elf_dyn_relocs **pp;
+         struct elf_dyn_relocs *p;
+
+         eh = (struct elf_x86_64_link_hash_entry *) h;
+
+         for (pp = &eh->dyn_relocs; (p = *pp) != NULL; pp = &p->next)
+           if (p->sec == sec)
+             {
+               /* Everything must go for SEC.  */
+               *pp = p->next;
+               break;
+             }
+       }
+
+      r_type = ELF32_R_TYPE (rel->r_info);
+      if (! elf_x86_64_tls_transition (info, abfd, sec, NULL,
+                                      symtab_hdr, sym_hashes,
+                                      &r_type, GOT_UNKNOWN,
+                                      rel, relend, h, r_symndx))
        return FALSE;
 
       switch (r_type)
@@ -1733,7 +1844,8 @@ elf64_x86_64_gc_sweep_hook (bfd *abfd, struct bfd_link_info *info,
        case R_X86_64_PC16:
        case R_X86_64_PC32:
        case R_X86_64_PC64:
-         if (info->shared)
+         if (info->shared
+             && (h == NULL || h->type != STT_GNU_IFUNC))
            break;
          /* Fall thru */
 
@@ -1761,10 +1873,10 @@ elf64_x86_64_gc_sweep_hook (bfd *abfd, struct bfd_link_info *info,
    understand. */
 
 static bfd_boolean
-elf64_x86_64_adjust_dynamic_symbol (struct bfd_link_info *info,
-                                   struct elf_link_hash_entry *h)
+elf_x86_64_adjust_dynamic_symbol (struct bfd_link_info *info,
+                                 struct elf_link_hash_entry *h)
 {
-  struct elf64_x86_64_link_hash_table *htab;
+  struct elf_x86_64_link_hash_table *htab;
   asection *s;
 
   /* STT_GNU_IFUNC symbol must go through PLT. */
@@ -1846,10 +1958,10 @@ elf64_x86_64_adjust_dynamic_symbol (struct bfd_link_info *info,
 
   if (ELIMINATE_COPY_RELOCS)
     {
-      struct elf64_x86_64_link_hash_entry * eh;
+      struct elf_x86_64_link_hash_entry * eh;
       struct elf_dyn_relocs *p;
 
-      eh = (struct elf64_x86_64_link_hash_entry *) h;
+      eh = (struct elf_x86_64_link_hash_entry *) h;
       for (p = eh->dyn_relocs; p != NULL; p = p->next)
        {
          s = p->sec->output_section;
@@ -1883,7 +1995,7 @@ elf64_x86_64_adjust_dynamic_symbol (struct bfd_link_info *info,
      both the dynamic object and the regular object will refer to the
      same memory location for the variable.  */
 
-  htab = elf64_x86_64_hash_table (info);
+  htab = elf_x86_64_hash_table (info);
   if (htab == NULL)
     return FALSE;
 
@@ -1892,7 +2004,9 @@ elf64_x86_64_adjust_dynamic_symbol (struct bfd_link_info *info,
      runtime process image.  */
   if ((h->root.u.def.section->flags & SEC_ALLOC) != 0)
     {
-      htab->srelbss->size += sizeof (Elf64_External_Rela);
+      const struct elf_backend_data *bed;
+      bed = get_elf_backend_data (info->output_bfd);
+      htab->srelbss->size += bed->s->sizeof_rela;
       h->needs_copy = 1;
     }
 
@@ -1905,24 +2019,26 @@ elf64_x86_64_adjust_dynamic_symbol (struct bfd_link_info *info,
    dynamic relocs.  */
 
 static bfd_boolean
-elf64_x86_64_allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf)
+elf_x86_64_allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf)
 {
   struct bfd_link_info *info;
-  struct elf64_x86_64_link_hash_table *htab;
-  struct elf64_x86_64_link_hash_entry *eh;
+  struct elf_x86_64_link_hash_table *htab;
+  struct elf_x86_64_link_hash_entry *eh;
   struct elf_dyn_relocs *p;
+  const struct elf_backend_data *bed;
 
   if (h->root.type == bfd_link_hash_indirect)
     return TRUE;
 
   if (h->root.type == bfd_link_hash_warning)
     h = (struct elf_link_hash_entry *) h->root.u.i.link;
-  eh = (struct elf64_x86_64_link_hash_entry *) h;
+  eh = (struct elf_x86_64_link_hash_entry *) h;
 
   info = (struct bfd_link_info *) inf;
-  htab = elf64_x86_64_hash_table (info);
+  htab = elf_x86_64_hash_table (info);
   if (htab == NULL)
     return FALSE;
+  bed = get_elf_backend_data (info->output_bfd);
 
   /* Since STT_GNU_IFUNC symbol must go through PLT, we handle it
      here if it is defined and referenced in a non-shared object.  */
@@ -1976,7 +2092,7 @@ elf64_x86_64_allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf)
          htab->elf.sgotplt->size += GOT_ENTRY_SIZE;
 
          /* We also need to make an entry in the .rela.plt section.  */
-         htab->elf.srelplt->size += sizeof (Elf64_External_Rela);
+         htab->elf.srelplt->size += bed->s->sizeof_rela;
          htab->elf.srelplt->reloc_count++;
        }
       else
@@ -1998,7 +2114,7 @@ elf64_x86_64_allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf)
   if (h->got.refcount > 0
       && info->executable
       && h->dynindx == -1
-      && elf64_x86_64_hash_entry (h)->tls_type == GOT_TLS_IE)
+      && elf_x86_64_hash_entry (h)->tls_type == GOT_TLS_IE)
     {
       h->got.offset = (bfd_vma) -1;
     }
@@ -2006,7 +2122,7 @@ elf64_x86_64_allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf)
     {
       asection *s;
       bfd_boolean dyn;
-      int tls_type = elf64_x86_64_hash_entry (h)->tls_type;
+      int tls_type = elf_x86_64_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.  */
@@ -2020,7 +2136,7 @@ elf64_x86_64_allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf)
       if (GOT_TLS_GDESC_P (tls_type))
        {
          eh->tlsdesc_got = htab->elf.sgotplt->size
-           - elf64_x86_64_compute_jump_table_size (htab);
+           - elf_x86_64_compute_jump_table_size (htab);
          htab->elf.sgotplt->size += 2 * GOT_ENTRY_SIZE;
          h->got.offset = (bfd_vma) -2;
        }
@@ -2039,18 +2155,18 @@ elf64_x86_64_allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf)
         R_X86_64_GOTTPOFF needs one dynamic relocation.  */
       if ((GOT_TLS_GD_P (tls_type) && h->dynindx == -1)
          || tls_type == GOT_TLS_IE)
-       htab->elf.srelgot->size += sizeof (Elf64_External_Rela);
+       htab->elf.srelgot->size += bed->s->sizeof_rela;
       else if (GOT_TLS_GD_P (tls_type))
-       htab->elf.srelgot->size += 2 * sizeof (Elf64_External_Rela);
+       htab->elf.srelgot->size += 2 * bed->s->sizeof_rela;
       else if (! GOT_TLS_GDESC_P (tls_type)
               && (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
                   || h->root.type != bfd_link_hash_undefweak)
               && (info->shared
                   || WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, 0, h)))
-       htab->elf.srelgot->size += sizeof (Elf64_External_Rela);
+       htab->elf.srelgot->size += bed->s->sizeof_rela;
       if (GOT_TLS_GDESC_P (tls_type))
        {
-         htab->elf.srelplt->size += sizeof (Elf64_External_Rela);
+         htab->elf.srelplt->size += bed->s->sizeof_rela;
          htab->tlsdesc_plt = (bfd_vma) -1;
        }
     }
@@ -2146,7 +2262,7 @@ elf64_x86_64_allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf)
 
       BFD_ASSERT (sreloc != NULL);
 
-      sreloc->size += p->count * sizeof (Elf64_External_Rela);
+      sreloc->size += p->count * bed->s->sizeof_rela;
     }
 
   return TRUE;
@@ -2156,7 +2272,7 @@ elf64_x86_64_allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf)
    local dynamic relocs.  */
 
 static bfd_boolean
-elf64_x86_64_allocate_local_dynrelocs (void **slot, void *inf)
+elf_x86_64_allocate_local_dynrelocs (void **slot, void *inf)
 {
   struct elf_link_hash_entry *h
     = (struct elf_link_hash_entry *) *slot;
@@ -2168,21 +2284,22 @@ elf64_x86_64_allocate_local_dynrelocs (void **slot, void *inf)
       || h->root.type != bfd_link_hash_defined)
     abort ();
 
-  return elf64_x86_64_allocate_dynrelocs (h, inf);
+  return elf_x86_64_allocate_dynrelocs (h, inf);
 }
 
 /* Find any dynamic relocs that apply to read-only sections.  */
 
 static bfd_boolean
-elf64_x86_64_readonly_dynrelocs (struct elf_link_hash_entry *h, void * inf)
+elf_x86_64_readonly_dynrelocs (struct elf_link_hash_entry *h,
+                              void * inf)
 {
-  struct elf64_x86_64_link_hash_entry *eh;
+  struct elf_x86_64_link_hash_entry *eh;
   struct elf_dyn_relocs *p;
 
   if (h->root.type == bfd_link_hash_warning)
     h = (struct elf_link_hash_entry *) h->root.u.i.link;
 
-  eh = (struct elf64_x86_64_link_hash_entry *) h;
+  eh = (struct elf_x86_64_link_hash_entry *) h;
   for (p = eh->dyn_relocs; p != NULL; p = p->next)
     {
       asection *s = p->sec->output_section;
@@ -2203,18 +2320,20 @@ elf64_x86_64_readonly_dynrelocs (struct elf_link_hash_entry *h, void * inf)
 /* Set the sizes of the dynamic sections.  */
 
 static bfd_boolean
-elf64_x86_64_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
-                                   struct bfd_link_info *info)
+elf_x86_64_size_dynamic_sections (bfd *output_bfd,
+                                 struct bfd_link_info *info)
 {
-  struct elf64_x86_64_link_hash_table *htab;
+  struct elf_x86_64_link_hash_table *htab;
   bfd *dynobj;
   asection *s;
   bfd_boolean relocs;
   bfd *ibfd;
+  const struct elf_backend_data *bed;
 
-  htab = elf64_x86_64_hash_table (info);
+  htab = elf_x86_64_hash_table (info);
   if (htab == NULL)
     return FALSE;
+  bed = get_elf_backend_data (output_bfd);
 
   dynobj = htab->elf.dynobj;
   if (dynobj == NULL)
@@ -2228,8 +2347,8 @@ elf64_x86_64_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
          s = bfd_get_section_by_name (dynobj, ".interp");
          if (s == NULL)
            abort ();
-         s->size = sizeof ELF_DYNAMIC_INTERPRETER;
-         s->contents = (unsigned char *) ELF_DYNAMIC_INTERPRETER;
+         s->size = htab->dynamic_interpreter_size;
+         s->contents = (unsigned char *) htab->dynamic_interpreter;
        }
     }
 
@@ -2268,7 +2387,7 @@ elf64_x86_64_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
              else if (p->count != 0)
                {
                  srel = elf_section_data (p->sec)->sreloc;
-                 srel->size += p->count * sizeof (Elf64_External_Rela);
+                 srel->size += p->count * bed->s->sizeof_rela;
                  if ((p->sec->output_section->flags & SEC_READONLY) != 0)
                    info->flags |= DF_TEXTREL;
                }
@@ -2282,8 +2401,8 @@ elf64_x86_64_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
       symtab_hdr = &elf_symtab_hdr (ibfd);
       locsymcount = symtab_hdr->sh_info;
       end_local_got = local_got + locsymcount;
-      local_tls_type = elf64_x86_64_local_got_tls_type (ibfd);
-      local_tlsdesc_gotent = elf64_x86_64_local_tlsdesc_gotent (ibfd);
+      local_tls_type = elf_x86_64_local_got_tls_type (ibfd);
+      local_tlsdesc_gotent = elf_x86_64_local_tlsdesc_gotent (ibfd);
       s = htab->elf.sgot;
       srel = htab->elf.srelgot;
       for (; local_got < end_local_got;
@@ -2295,7 +2414,7 @@ elf64_x86_64_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
              if (GOT_TLS_GDESC_P (*local_tls_type))
                {
                  *local_tlsdesc_gotent = htab->elf.sgotplt->size
-                   - elf64_x86_64_compute_jump_table_size (htab);
+                   - elf_x86_64_compute_jump_table_size (htab);
                  htab->elf.sgotplt->size += 2 * GOT_ENTRY_SIZE;
                  *local_got = (bfd_vma) -2;
                }
@@ -2314,12 +2433,12 @@ elf64_x86_64_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
                  if (GOT_TLS_GDESC_P (*local_tls_type))
                    {
                      htab->elf.srelplt->size
-                       += sizeof (Elf64_External_Rela);
+                       += bed->s->sizeof_rela;
                      htab->tlsdesc_plt = (bfd_vma) -1;
                    }
                  if (! GOT_TLS_GDESC_P (*local_tls_type)
                      || GOT_TLS_GD_P (*local_tls_type))
-                   srel->size += sizeof (Elf64_External_Rela);
+                   srel->size += bed->s->sizeof_rela;
                }
            }
          else
@@ -2333,19 +2452,19 @@ elf64_x86_64_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
         relocs.  */
       htab->tls_ld_got.offset = htab->elf.sgot->size;
       htab->elf.sgot->size += 2 * GOT_ENTRY_SIZE;
-      htab->elf.srelgot->size += sizeof (Elf64_External_Rela);
+      htab->elf.srelgot->size += bed->s->sizeof_rela;
     }
   else
     htab->tls_ld_got.offset = -1;
 
   /* Allocate global sym .plt and .got entries, and space for global
      sym dynamic relocs.  */
-  elf_link_hash_traverse (&htab->elf, elf64_x86_64_allocate_dynrelocs,
+  elf_link_hash_traverse (&htab->elf, elf_x86_64_allocate_dynrelocs,
                          info);
 
   /* Allocate .plt and .got entries, and space for local symbols.  */
   htab_traverse (htab->loc_hash_table,
-                elf64_x86_64_allocate_local_dynrelocs,
+                elf_x86_64_allocate_local_dynrelocs,
                 info);
 
   /* For every jump slot reserved in the sgotplt, reloc_count is
@@ -2355,7 +2474,7 @@ elf64_x86_64_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
      slot size.  */
   if (htab->elf.srelplt)
     htab->sgotplt_jump_table_size
-      = elf64_x86_64_compute_jump_table_size (htab);
+      = elf_x86_64_compute_jump_table_size (htab);
 
   if (htab->tlsdesc_plt)
     {
@@ -2378,10 +2497,17 @@ elf64_x86_64_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
 
   if (htab->elf.sgotplt)
     {
+      struct elf_link_hash_entry *got;
+      got = elf_link_hash_lookup (elf_hash_table (info),
+                                 "_GLOBAL_OFFSET_TABLE_",
+                                 FALSE, FALSE, FALSE);
+
       /* Don't allocate .got.plt section if there are no GOT nor PLT
-         entries.  */
-      if ((htab->elf.sgotplt->size
-          == get_elf_backend_data (output_bfd)->got_header_size)
+         entries and there is no refeence to _GLOBAL_OFFSET_TABLE_.  */
+      if ((got == NULL
+          || !got->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
@@ -2459,7 +2585,7 @@ elf64_x86_64_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
   if (htab->elf.dynamic_sections_created)
     {
       /* Add some entries to the .dynamic section.  We fill in the
-        values later, in elf64_x86_64_finish_dynamic_sections, but we
+        values later, in elf_x86_64_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.  */
@@ -2490,14 +2616,14 @@ elf64_x86_64_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
        {
          if (!add_dynamic_entry (DT_RELA, 0)
              || !add_dynamic_entry (DT_RELASZ, 0)
-             || !add_dynamic_entry (DT_RELAENT, sizeof (Elf64_External_Rela)))
+             || !add_dynamic_entry (DT_RELAENT, bed->s->sizeof_rela))
            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, 
-                                   elf64_x86_64_readonly_dynrelocs,
+                                   elf_x86_64_readonly_dynrelocs,
                                    info);
 
          if ((info->flags & DF_TEXTREL) != 0)
@@ -2513,8 +2639,8 @@ elf64_x86_64_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
 }
 
 static bfd_boolean
-elf64_x86_64_always_size_sections (bfd *output_bfd,
-                                  struct bfd_link_info *info)
+elf_x86_64_always_size_sections (bfd *output_bfd,
+                                struct bfd_link_info *info)
 {
   asection *tls_sec = elf_hash_table (info)->tls_sec;
 
@@ -2528,12 +2654,12 @@ elf64_x86_64_always_size_sections (bfd *output_bfd,
 
       if (tlsbase && tlsbase->type == STT_TLS)
        {
-         struct elf64_x86_64_link_hash_table *htab;
+         struct elf_x86_64_link_hash_table *htab;
          struct bfd_link_hash_entry *bh = NULL;
          const struct elf_backend_data *bed
            = get_elf_backend_data (output_bfd);
 
-         htab = elf64_x86_64_hash_table (info);
+         htab = elf_x86_64_hash_table (info);
          if (htab == NULL)
            return FALSE;
 
@@ -2561,15 +2687,15 @@ elf64_x86_64_always_size_sections (bfd *output_bfd,
    multiple times, it is idempotent.  */
 
 static void
-elf64_x86_64_set_tls_module_base (struct bfd_link_info *info)
+elf_x86_64_set_tls_module_base (struct bfd_link_info *info)
 {
-  struct elf64_x86_64_link_hash_table *htab;
+  struct elf_x86_64_link_hash_table *htab;
   struct bfd_link_hash_entry *base;
 
   if (!info->executable)
     return;
 
-  htab = elf64_x86_64_hash_table (info);
+  htab = elf_x86_64_hash_table (info);
   if (htab == NULL)
     return;
 
@@ -2585,7 +2711,7 @@ elf64_x86_64_set_tls_module_base (struct bfd_link_info *info)
    This is PT_TLS segment p_vaddr.  */
 
 static bfd_vma
-elf64_x86_64_dtpoff_base (struct bfd_link_info *info)
+elf_x86_64_dtpoff_base (struct bfd_link_info *info)
 {
   /* If tls_sec is NULL, we should have signalled an error already.  */
   if (elf_hash_table (info)->tls_sec == NULL)
@@ -2597,14 +2723,19 @@ elf64_x86_64_dtpoff_base (struct bfd_link_info *info)
    if STT_TLS virtual address is ADDRESS.  */
 
 static bfd_vma
-elf64_x86_64_tpoff (struct bfd_link_info *info, bfd_vma address)
+elf_x86_64_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_segment is NULL, we should have signalled an error already.  */
   if (htab->tls_sec == NULL)
     return 0;
-  return address - htab->tls_size - htab->tls_sec->vma;
+
+  /* Consider special static TLS alignment requirements.  */
+  static_tls_size = BFD_ALIGN (htab->tls_size, bed->static_tls_alignment);
+  return address - static_tls_size - htab->tls_sec->vma;
 }
 
 /* Is the instruction before OFFSET in CONTENTS a 32bit relative
@@ -2625,26 +2756,19 @@ is_32bit_relative_branch (bfd_byte *contents, bfd_vma offset)
              && (contents [offset - 1] & 0xf0) == 0x80));
 }
 
-static void
-elf64_x86_64_append_rela (bfd *abfd, asection *s, Elf_Internal_Rela *rel)
-{
-  bfd_byte *loc = s->contents;
-  loc += s->reloc_count++ * sizeof (Elf64_External_Rela);
-  BFD_ASSERT (loc + sizeof (Elf64_External_Rela)
-             <= s->contents + s->size);
-  bfd_elf64_swap_reloca_out (abfd, rel, loc);
-}
-
 /* Relocate an x86_64 ELF section.  */
 
 static bfd_boolean
-elf64_x86_64_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)
+elf_x86_64_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 elf64_x86_64_link_hash_table *htab;
+  struct elf_x86_64_link_hash_table *htab;
   Elf_Internal_Shdr *symtab_hdr;
   struct elf_link_hash_entry **sym_hashes;
   bfd_vma *local_got_offsets;
@@ -2654,15 +2778,15 @@ elf64_x86_64_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
 
   BFD_ASSERT (is_x86_64_elf (input_bfd));
 
-  htab = elf64_x86_64_hash_table (info);
+  htab = elf_x86_64_hash_table (info);
   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 = elf64_x86_64_local_tlsdesc_gotent (input_bfd);
+  local_tlsdesc_gotents = elf_x86_64_local_tlsdesc_gotent (input_bfd);
 
-  elf64_x86_64_set_tls_module_base (info);
+  elf_x86_64_set_tls_module_base (info);
 
   rel = relocs;
   relend = relocs + input_section->reloc_count;
@@ -2681,7 +2805,7 @@ elf64_x86_64_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
       int tls_type;
       asection *base_got;
 
-      r_type = ELF64_R_TYPE (rel->r_info);
+      r_type = ELF32_R_TYPE (rel->r_info);
       if (r_type == (int) R_X86_64_GNU_VTINHERIT
          || r_type == (int) R_X86_64_GNU_VTENTRY)
        continue;
@@ -2693,7 +2817,7 @@ elf64_x86_64_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
        }
 
       howto = x86_64_elf_howto_table + r_type;
-      r_symndx = ELF64_R_SYM (rel->r_info);
+      r_symndx = htab->r_sym (rel->r_info);
       h = NULL;
       sym = NULL;
       sec = NULL;
@@ -2708,10 +2832,10 @@ elf64_x86_64_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
 
          /* Relocate against local STT_GNU_IFUNC symbol.  */
          if (!info->relocatable
-             && ELF64_ST_TYPE (sym->st_info) == STT_GNU_IFUNC)
+             && ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC)
            {
-             h = elf64_x86_64_get_local_sym_hash (htab, input_bfd,
-                                                  rel, FALSE);
+             h = elf_x86_64_get_local_sym_hash (htab, input_bfd,
+                                                rel, FALSE);
              if (h == NULL)
                abort ();
 
@@ -2777,6 +2901,10 @@ elf64_x86_64_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
                abort ();
              goto do_relocation;
 
+           case R_X86_64_32:
+             if (ABI_64_P (output_bfd))
+               goto do_relocation;
+             /* FALLTHROUGH */
            case R_X86_64_64: 
              if (rel->r_addend != 0)
                {
@@ -2819,19 +2947,19 @@ elf64_x86_64_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
                      || info->executable)
                    {
                      /* This symbol is resolved locally.  */
-                     outrel.r_info = ELF64_R_INFO (0, R_X86_64_IRELATIVE);
+                     outrel.r_info = htab->r_info (0, R_X86_64_IRELATIVE);
                      outrel.r_addend = (h->root.u.def.value
                                         + h->root.u.def.section->output_section->vma
                                         + h->root.u.def.section->output_offset);
                    }
                  else
                    {
-                     outrel.r_info = ELF64_R_INFO (h->dynindx, r_type);
+                     outrel.r_info = htab->r_info (h->dynindx, r_type);
                      outrel.r_addend = 0;
                    }
 
                  sreloc = htab->elf.irelifunc;
-                 elf64_x86_64_append_rela (output_bfd, sreloc, &outrel);
+                 elf_append_rela (output_bfd, sreloc, &outrel);
 
                  /* If this reloc is against an external symbol, we
                     do not want to fiddle with the addend.  Otherwise,
@@ -2840,8 +2968,7 @@ elf64_x86_64_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
                     internal symbol, we have updated addend.  */
                  continue;
                }
-
-           case R_X86_64_32:
+             /* FALLTHROUGH */
            case R_X86_64_PC32:
            case R_X86_64_PC64:
            case R_X86_64_PLT32:
@@ -2903,18 +3030,6 @@ elf64_x86_64_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
              relocation = (base_got->output_section->vma
                            + base_got->output_offset + off);
 
-             if (r_type != R_X86_64_GOTPCREL
-                 && r_type != R_X86_64_GOTPCREL64)
-               {
-                 asection *gotplt;
-                 if (htab->elf.splt != NULL)
-                   gotplt = htab->elf.sgotplt;
-                 else
-                   gotplt = htab->elf.igotplt;
-                 relocation -= (gotplt->output_section->vma
-                                - gotplt->output_offset);
-               }
-
              goto do_relocation;
            }
        }
@@ -3024,9 +3139,9 @@ elf64_x86_64_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
                      outrel.r_offset = (base_got->output_section->vma
                                         + base_got->output_offset
                                         + off);
-                     outrel.r_info = ELF64_R_INFO (0, R_X86_64_RELATIVE);
+                     outrel.r_info = htab->r_info (0, R_X86_64_RELATIVE);
                      outrel.r_addend = relocation;
-                     elf64_x86_64_append_rela (output_bfd, s, &outrel);
+                     elf_append_rela (output_bfd, s, &outrel);
                    }
 
                  local_got_offsets[r_symndx] |= 1;
@@ -3127,6 +3242,7 @@ elf64_x86_64_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
        case R_X86_64_PC16:
        case R_X86_64_PC32:
          if (info->shared
+             && ABI_64_P (output_bfd)
              && (input_section->flags & SEC_ALLOC) != 0
              && (input_section->flags & SEC_READONLY) != 0
              && h != NULL)
@@ -3247,16 +3363,16 @@ elf64_x86_64_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
                           || ! SYMBOLIC_BIND (info, h)
                           || ! h->def_regular))
                {
-                 outrel.r_info = ELF64_R_INFO (h->dynindx, r_type);
+                 outrel.r_info = htab->r_info (h->dynindx, r_type);
                  outrel.r_addend = rel->r_addend;
                }
              else
                {
                  /* This symbol is local, or marked to become local.  */
-                 if (r_type == R_X86_64_64)
+                 if (r_type == htab->pointer_r_type)
                    {
                      relocate = TRUE;
-                     outrel.r_info = ELF64_R_INFO (0, R_X86_64_RELATIVE);
+                     outrel.r_info = htab->r_info (0, R_X86_64_RELATIVE);
                      outrel.r_addend = relocation + rel->r_addend;
                    }
                  else
@@ -3289,16 +3405,20 @@ elf64_x86_64_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
                          BFD_ASSERT (sindx != 0);
                        }
 
-                     outrel.r_info = ELF64_R_INFO (sindx, r_type);
+                     outrel.r_info = htab->r_info (sindx, r_type);
                      outrel.r_addend = relocation + rel->r_addend;
                    }
                }
 
              sreloc = elf_section_data (input_section)->sreloc;
 
-             BFD_ASSERT (sreloc != NULL && sreloc->contents != NULL);
+             if (sreloc == NULL || sreloc->contents == NULL)
+               {
+                 r = bfd_reloc_notsupported;
+                 goto check_relocation_error;
+               }
 
-             elf64_x86_64_append_rela (output_bfd, sreloc, &outrel);
+             elf_append_rela (output_bfd, sreloc, &outrel);
 
              /* If this reloc is against an external symbol, we do
                 not want to fiddle with the addend.  Otherwise, we
@@ -3316,15 +3436,15 @@ elf64_x86_64_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
        case R_X86_64_GOTTPOFF:
          tls_type = GOT_UNKNOWN;
          if (h == NULL && local_got_offsets)
-           tls_type = elf64_x86_64_local_got_tls_type (input_bfd) [r_symndx];
+           tls_type = elf_x86_64_local_got_tls_type (input_bfd) [r_symndx];
          else if (h != NULL)
-           tls_type = elf64_x86_64_hash_entry (h)->tls_type;
+           tls_type = elf_x86_64_hash_entry (h)->tls_type;
 
-         if (! elf64_x86_64_tls_transition (info, input_bfd,
-                                            input_section, contents,
-                                            symtab_hdr, sym_hashes,
-                                            &r_type, tls_type, rel,
-                                            relend, h, r_symndx))
+         if (! elf_x86_64_tls_transition (info, input_bfd,
+                                          input_section, contents,
+                                          symtab_hdr, sym_hashes,
+                                          &r_type, tls_type, rel,
+                                          relend, h, r_symndx))
            return FALSE;
 
          if (r_type == R_X86_64_TPOFF32)
@@ -3333,25 +3453,36 @@ elf64_x86_64_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
 
              BFD_ASSERT (! unresolved_reloc);
 
-             if (ELF64_R_TYPE (rel->r_info) == R_X86_64_TLSGD)
+             if (ELF32_R_TYPE (rel->r_info) == R_X86_64_TLSGD)
                {
-                 /* GD->LE transition.
+                 /* GD->LE transition.  For 64bit, change
                     .byte 0x66; leaq foo@tlsgd(%rip), %rdi
                     .word 0x6666; rex64; call __tls_get_addr
-                    Change it into:
+                    into:
                     movq %fs:0, %rax
+                    leaq foo@tpoff(%rax), %rax
+                    For 32bit, change
+                    leaq foo@tlsgd(%rip), %rdi
+                    .word 0x6666; rex64; call __tls_get_addr
+                    into:
+                    movl %fs:0, %eax
                     leaq foo@tpoff(%rax), %rax */
-                 memcpy (contents + roff - 4,
-                         "\x64\x48\x8b\x04\x25\0\0\0\0\x48\x8d\x80\0\0\0",
-                         16);
+                 if (ABI_64_P (output_bfd))
+                   memcpy (contents + roff - 4,
+                           "\x64\x48\x8b\x04\x25\0\0\0\0\x48\x8d\x80\0\0\0",
+                           16);
+                 else
+                   memcpy (contents + roff - 3,
+                           "\x64\x8b\x04\x25\0\0\0\0\x48\x8d\x80\0\0\0",
+                           15);
                  bfd_put_32 (output_bfd,
-                             elf64_x86_64_tpoff (info, relocation),
+                             elf_x86_64_tpoff (info, relocation),
                              contents + roff + 8);
                  /* Skip R_X86_64_PC32/R_X86_64_PLT32.  */
                  rel++;
                  continue;
                }
-             else if (ELF64_R_TYPE (rel->r_info) == R_X86_64_GOTPC32_TLSDESC)
+             else if (ELF32_R_TYPE (rel->r_info) == R_X86_64_GOTPC32_TLSDESC)
                {
                  /* GDesc -> LE transition.
                     It's originally something like:
@@ -3370,11 +3501,11 @@ elf64_x86_64_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
                  bfd_put_8 (output_bfd, 0xc0 | ((val >> 3) & 7),
                             contents + roff - 1);
                  bfd_put_32 (output_bfd,
-                             elf64_x86_64_tpoff (info, relocation),
+                             elf_x86_64_tpoff (info, relocation),
                              contents + roff);
                  continue;
                }
-             else if (ELF64_R_TYPE (rel->r_info) == R_X86_64_TLSDESC_CALL)
+             else if (ELF32_R_TYPE (rel->r_info) == R_X86_64_TLSDESC_CALL)
                {
                  /* GDesc -> LE transition.
                     It's originally:
@@ -3385,7 +3516,7 @@ elf64_x86_64_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
                  bfd_put_8 (output_bfd, 0x90, contents + roff + 1);
                  continue;
                }
-             else if (ELF64_R_TYPE (rel->r_info) == R_X86_64_GOTTPOFF)
+             else if (ELF32_R_TYPE (rel->r_info) == R_X86_64_GOTTPOFF)
                {
                  /* IE->LE transition:
                     Originally it can be one of:
@@ -3408,6 +3539,9 @@ elf64_x86_64_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
                      if (val == 0x4c)
                        bfd_put_8 (output_bfd, 0x49,
                                   contents + roff - 3);
+                     else if (!ABI_64_P (output_bfd) && val == 0x44)
+                       bfd_put_8 (output_bfd, 0x41,
+                                  contents + roff - 3);
                      bfd_put_8 (output_bfd, 0xc7,
                                 contents + roff - 2);
                      bfd_put_8 (output_bfd, 0xc0 | reg,
@@ -3420,6 +3554,9 @@ elf64_x86_64_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
                      if (val == 0x4c)
                        bfd_put_8 (output_bfd, 0x49,
                                   contents + roff - 3);
+                     else if (!ABI_64_P (output_bfd) && val == 0x44)
+                       bfd_put_8 (output_bfd, 0x41,
+                                  contents + roff - 3);
                      bfd_put_8 (output_bfd, 0x81,
                                 contents + roff - 2);
                      bfd_put_8 (output_bfd, 0xc0 | reg,
@@ -3431,13 +3568,16 @@ elf64_x86_64_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
                      if (val == 0x4c)
                        bfd_put_8 (output_bfd, 0x4d,
                                   contents + roff - 3);
+                     else if (!ABI_64_P (output_bfd) && val == 0x44)
+                       bfd_put_8 (output_bfd, 0x45,
+                                  contents + roff - 3);
                      bfd_put_8 (output_bfd, 0x8d,
                                 contents + roff - 2);
                      bfd_put_8 (output_bfd, 0x80 | reg | (reg << 3),
                                 contents + roff - 1);
                    }
                  bfd_put_32 (output_bfd,
-                             elf64_x86_64_tpoff (info, relocation),
+                             elf_x86_64_tpoff (info, relocation),
                              contents + roff);
                  continue;
                }
@@ -3451,7 +3591,7 @@ elf64_x86_64_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
          if (h != NULL)
            {
              off = h->got.offset;
-             offplt = elf64_x86_64_hash_entry (h)->tlsdesc_got;
+             offplt = elf_x86_64_hash_entry (h)->tlsdesc_got;
            }
          else
            {
@@ -3477,7 +3617,7 @@ elf64_x86_64_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
 
              if (GOT_TLS_GDESC_P (tls_type))
                {
-                 outrel.r_info = ELF64_R_INFO (indx, R_X86_64_TLSDESC);
+                 outrel.r_info = htab->r_info (indx, R_X86_64_TLSDESC);
                  BFD_ASSERT (htab->sgotplt_jump_table_size + offplt
                              + 2 * GOT_ENTRY_SIZE <= htab->elf.sgotplt->size);
                  outrel.r_offset = (htab->elf.sgotplt->output_section->vma
@@ -3486,10 +3626,10 @@ elf64_x86_64_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
                                     + htab->sgotplt_jump_table_size);
                  sreloc = htab->elf.srelplt;
                  if (indx == 0)
-                   outrel.r_addend = relocation - elf64_x86_64_dtpoff_base (info);
+                   outrel.r_addend = relocation - elf_x86_64_dtpoff_base (info);
                  else
                    outrel.r_addend = 0;
-                 elf64_x86_64_append_rela (output_bfd, sreloc, &outrel);
+                 elf_append_rela (output_bfd, sreloc, &outrel);
                }
 
              sreloc = htab->elf.srelgot;
@@ -3508,10 +3648,10 @@ elf64_x86_64_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
              outrel.r_addend = 0;
              if ((dr_type == R_X86_64_TPOFF64
                   || dr_type == R_X86_64_TLSDESC) && indx == 0)
-               outrel.r_addend = relocation - elf64_x86_64_dtpoff_base (info);
-             outrel.r_info = ELF64_R_INFO (indx, dr_type);
+               outrel.r_addend = relocation - elf_x86_64_dtpoff_base (info);
+             outrel.r_info = htab->r_info (indx, dr_type);
 
-             elf64_x86_64_append_rela (output_bfd, sreloc, &outrel);
+             elf_append_rela (output_bfd, sreloc, &outrel);
 
              if (GOT_TLS_GD_P (tls_type))
                {
@@ -3519,17 +3659,17 @@ elf64_x86_64_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
                    {
                      BFD_ASSERT (! unresolved_reloc);
                      bfd_put_64 (output_bfd,
-                                 relocation - elf64_x86_64_dtpoff_base (info),
+                                 relocation - elf_x86_64_dtpoff_base (info),
                                  htab->elf.sgot->contents + off + GOT_ENTRY_SIZE);
                    }
                  else
                    {
                      bfd_put_64 (output_bfd, 0,
                                  htab->elf.sgot->contents + off + GOT_ENTRY_SIZE);
-                     outrel.r_info = ELF64_R_INFO (indx,
+                     outrel.r_info = htab->r_info (indx,
                                                    R_X86_64_DTPOFF64);
                      outrel.r_offset += GOT_ENTRY_SIZE;
-                     elf64_x86_64_append_rela (output_bfd, sreloc,
+                     elf_append_rela (output_bfd, sreloc,
                                                &outrel);
                    }
                }
@@ -3544,7 +3684,7 @@ elf64_x86_64_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
          if (off >= (bfd_vma) -2
              && ! GOT_TLS_GDESC_P (tls_type))
            abort ();
-         if (r_type == ELF64_R_TYPE (rel->r_info))
+         if (r_type == ELF32_R_TYPE (rel->r_info))
            {
              if (r_type == R_X86_64_GOTPC32_TLSDESC
                  || r_type == R_X86_64_TLSDESC_CALL)
@@ -3560,17 +3700,28 @@ elf64_x86_64_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
            {
              bfd_vma roff = rel->r_offset;
 
-             if (ELF64_R_TYPE (rel->r_info) == R_X86_64_TLSGD)
+             if (ELF32_R_TYPE (rel->r_info) == R_X86_64_TLSGD)
                {
-                 /* GD->IE transition.
+                 /* GD->IE transition.  For 64bit, change
                     .byte 0x66; leaq foo@tlsgd(%rip), %rdi
                     .word 0x6666; rex64; call __tls_get_addr@plt
-                    Change it into:
+                    into:
                     movq %fs:0, %rax
+                    addq foo@gottpoff(%rip), %rax
+                    For 32bit, change
+                    leaq foo@tlsgd(%rip), %rdi
+                    .word 0x6666; rex64; call __tls_get_addr@plt
+                    into:
+                    movl %fs:0, %eax
                     addq foo@gottpoff(%rip), %rax */
-                 memcpy (contents + roff - 4,
-                         "\x64\x48\x8b\x04\x25\0\0\0\0\x48\x03\x05\0\0\0",
-                         16);
+                 if (ABI_64_P (output_bfd))
+                   memcpy (contents + roff - 4,
+                           "\x64\x48\x8b\x04\x25\0\0\0\0\x48\x03\x05\0\0\0",
+                           16);
+                 else
+                   memcpy (contents + roff - 3,
+                           "\x64\x8b\x04\x25\0\0\0\0\x48\x03\x05\0\0\0",
+                           15);
 
                  relocation = (htab->elf.sgot->output_section->vma
                                + htab->elf.sgot->output_offset + off
@@ -3584,7 +3735,7 @@ elf64_x86_64_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
                  rel++;
                  continue;
                }
-             else if (ELF64_R_TYPE (rel->r_info) == R_X86_64_GOTPC32_TLSDESC)
+             else if (ELF32_R_TYPE (rel->r_info) == R_X86_64_GOTPC32_TLSDESC)
                {
                  /* GDesc -> IE transition.
                     It's originally something like:
@@ -3609,7 +3760,7 @@ elf64_x86_64_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
                              contents + roff);
                  continue;
                }
-             else if (ELF64_R_TYPE (rel->r_info) == R_X86_64_TLSDESC_CALL)
+             else if (ELF32_R_TYPE (rel->r_info) == R_X86_64_TLSDESC_CALL)
                {
                  /* GDesc -> IE transition.
                     It's originally:
@@ -3628,23 +3779,29 @@ elf64_x86_64_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
          break;
 
        case R_X86_64_TLSLD:
-         if (! elf64_x86_64_tls_transition (info, input_bfd,
-                                            input_section, contents,
-                                            symtab_hdr, sym_hashes,
-                                            &r_type, GOT_UNKNOWN,
-                                            rel, relend, h, r_symndx))
+         if (! elf_x86_64_tls_transition (info, input_bfd,
+                                          input_section, contents,
+                                          symtab_hdr, sym_hashes,
+                                          &r_type, GOT_UNKNOWN,
+                                          rel, relend, h, r_symndx))
            return FALSE;
 
          if (r_type != R_X86_64_TLSLD)
            {
              /* LD->LE transition:
                 leaq foo@tlsld(%rip), %rdi; call __tls_get_addr.
-                We change it into:
-                .word 0x6666; .byte 0x66; movl %fs:0, %rax.  */
+                For 64bit, we change it into:
+                .word 0x6666; .byte 0x66; movq %fs:0, %rax.
+                For 32bit, we change it into:
+                nopl 0x0(%rax); movl %fs:0, %eax.  */
 
              BFD_ASSERT (r_type == R_X86_64_TPOFF32);
-             memcpy (contents + rel->r_offset - 3,
-                     "\x66\x66\x66\x64\x48\x8b\x04\x25\0\0\0", 12);
+             if (ABI_64_P (output_bfd))
+               memcpy (contents + rel->r_offset - 3,
+                       "\x66\x66\x66\x64\x48\x8b\x04\x25\0\0\0", 12);
+             else
+               memcpy (contents + rel->r_offset - 3,
+                       "\x0f\x1f\x40\x00\x64\x8b\x04\x25\0\0\0", 12);
              /* Skip R_X86_64_PC32/R_X86_64_PLT32.  */
              rel++;
              continue;
@@ -3670,9 +3827,9 @@ elf64_x86_64_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
                          htab->elf.sgot->contents + off);
              bfd_put_64 (output_bfd, 0,
                          htab->elf.sgot->contents + off + GOT_ENTRY_SIZE);
-             outrel.r_info = ELF64_R_INFO (0, R_X86_64_DTPMOD64);
+             outrel.r_info = htab->r_info (0, R_X86_64_DTPMOD64);
              outrel.r_addend = 0;
-             elf64_x86_64_append_rela (output_bfd, htab->elf.srelgot,
+             elf_append_rela (output_bfd, htab->elf.srelgot,
                                        &outrel);
              htab->tls_ld_got.offset |= 1;
            }
@@ -3683,14 +3840,14 @@ elf64_x86_64_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
 
        case R_X86_64_DTPOFF32:
          if (!info->executable|| (input_section->flags & SEC_CODE) == 0)
-           relocation -= elf64_x86_64_dtpoff_base (info);
+           relocation -= elf_x86_64_dtpoff_base (info);
          else
-           relocation = elf64_x86_64_tpoff (info, relocation);
+           relocation = elf_x86_64_tpoff (info, relocation);
          break;
 
        case R_X86_64_TPOFF32:
          BFD_ASSERT (info->executable);
-         relocation = elf64_x86_64_tpoff (info, relocation);
+         relocation = elf_x86_64_tpoff (info, relocation);
          break;
 
        default:
@@ -3716,6 +3873,7 @@ do_relocation:
                                    contents, rel->r_offset,
                                    relocation, rel->r_addend);
 
+check_relocation_error:
       if (r != bfd_reloc_ok)
        {
          const char *name;
@@ -3759,14 +3917,14 @@ do_relocation:
    dynamic sections here.  */
 
 static bfd_boolean
-elf64_x86_64_finish_dynamic_symbol (bfd *output_bfd,
-                                   struct bfd_link_info *info,
-                                   struct elf_link_hash_entry *h,
-                                   Elf_Internal_Sym *sym)
+elf_x86_64_finish_dynamic_symbol (bfd *output_bfd,
+                                 struct bfd_link_info *info,
+                                 struct elf_link_hash_entry *h,
+                                 Elf_Internal_Sym *sym)
 {
-  struct elf64_x86_64_link_hash_table *htab;
+  struct elf_x86_64_link_hash_table *htab;
 
-  htab = elf64_x86_64_hash_table (info);
+  htab = elf_x86_64_hash_table (info);
   if (htab == NULL)
     return FALSE;
 
@@ -3777,6 +3935,7 @@ elf64_x86_64_finish_dynamic_symbol (bfd *output_bfd,
       Elf_Internal_Rela rela;
       bfd_byte *loc;
       asection *plt, *gotplt, *relplt;
+      const struct elf_backend_data *bed;
 
       /* When building a static executable, use .iplt, .igot.plt and
         .rela.iplt sections for STT_GNU_IFUNC symbols.  */
@@ -3827,7 +3986,7 @@ elf64_x86_64_finish_dynamic_symbol (bfd *output_bfd,
        }
 
       /* Fill in the entry in the procedure linkage table.  */
-      memcpy (plt->contents + h->plt.offset, elf64_x86_64_plt_entry,
+      memcpy (plt->contents + h->plt.offset, elf_x86_64_plt_entry,
              PLT_ENTRY_SIZE);
 
       /* Insert the relocation positions of the plt section.  The magic
@@ -3875,18 +4034,20 @@ elf64_x86_64_finish_dynamic_symbol (bfd *output_bfd,
        {
          /* If an STT_GNU_IFUNC symbol is locally defined, generate
             R_X86_64_IRELATIVE instead of R_X86_64_JUMP_SLOT.  */
-         rela.r_info = ELF64_R_INFO (0, R_X86_64_IRELATIVE);
+         rela.r_info = htab->r_info (0, R_X86_64_IRELATIVE);
          rela.r_addend = (h->root.u.def.value
                           + h->root.u.def.section->output_section->vma
                           + h->root.u.def.section->output_offset);
        }
       else
        {
-         rela.r_info = ELF64_R_INFO (h->dynindx, R_X86_64_JUMP_SLOT);
+         rela.r_info = htab->r_info (h->dynindx, R_X86_64_JUMP_SLOT);
          rela.r_addend = 0;
        }
-      loc = relplt->contents + plt_index * sizeof (Elf64_External_Rela);
-      bfd_elf64_swap_reloca_out (output_bfd, &rela, loc);
+
+      bed = get_elf_backend_data (output_bfd);
+      loc = relplt->contents + plt_index * bed->s->sizeof_rela;
+      bed->s->swap_reloca_out (output_bfd, &rela, loc);
 
       if (!h->def_regular)
        {
@@ -3905,8 +4066,8 @@ elf64_x86_64_finish_dynamic_symbol (bfd *output_bfd,
     }
 
   if (h->got.offset != (bfd_vma) -1
-      && ! GOT_TLS_GD_ANY_P (elf64_x86_64_hash_entry (h)->tls_type)
-      && elf64_x86_64_hash_entry (h)->tls_type != GOT_TLS_IE)
+      && ! GOT_TLS_GD_ANY_P (elf_x86_64_hash_entry (h)->tls_type)
+      && elf_x86_64_hash_entry (h)->tls_type != GOT_TLS_IE)
     {
       Elf_Internal_Rela rela;
 
@@ -3956,7 +4117,7 @@ elf64_x86_64_finish_dynamic_symbol (bfd *output_bfd,
          if (!h->def_regular)
            return FALSE;
          BFD_ASSERT((h->got.offset & 1) != 0);
-         rela.r_info = ELF64_R_INFO (0, R_X86_64_RELATIVE);
+         rela.r_info = htab->r_info (0, R_X86_64_RELATIVE);
          rela.r_addend = (h->root.u.def.value
                           + h->root.u.def.section->output_section->vma
                           + h->root.u.def.section->output_offset);
@@ -3967,11 +4128,11 @@ elf64_x86_64_finish_dynamic_symbol (bfd *output_bfd,
 do_glob_dat:
          bfd_put_64 (output_bfd, (bfd_vma) 0,
                      htab->elf.sgot->contents + h->got.offset);
-         rela.r_info = ELF64_R_INFO (h->dynindx, R_X86_64_GLOB_DAT);
+         rela.r_info = htab->r_info (h->dynindx, R_X86_64_GLOB_DAT);
          rela.r_addend = 0;
        }
 
-      elf64_x86_64_append_rela (output_bfd, htab->elf.srelgot, &rela);
+      elf_append_rela (output_bfd, htab->elf.srelgot, &rela);
     }
 
   if (h->needs_copy)
@@ -3989,9 +4150,9 @@ do_glob_dat:
       rela.r_offset = (h->root.u.def.value
                       + h->root.u.def.section->output_section->vma
                       + h->root.u.def.section->output_offset);
-      rela.r_info = ELF64_R_INFO (h->dynindx, R_X86_64_COPY);
+      rela.r_info = htab->r_info (h->dynindx, R_X86_64_COPY);
       rela.r_addend = 0;
-      elf64_x86_64_append_rela (output_bfd, htab->srelbss, &rela);
+      elf_append_rela (output_bfd, htab->srelbss, &rela);
     }
 
   /* Mark _DYNAMIC and _GLOBAL_OFFSET_TABLE_ as absolute.  SYM may
@@ -4008,14 +4169,14 @@ do_glob_dat:
    various dynamic sections here.  */
 
 static bfd_boolean
-elf64_x86_64_finish_local_dynamic_symbol (void **slot, void *inf)
+elf_x86_64_finish_local_dynamic_symbol (void **slot, void *inf)
 {
   struct elf_link_hash_entry *h
     = (struct elf_link_hash_entry *) *slot;
   struct bfd_link_info *info
     = (struct bfd_link_info *) inf; 
 
-  return elf64_x86_64_finish_dynamic_symbol (info->output_bfd,
+  return elf_x86_64_finish_dynamic_symbol (info->output_bfd,
                                             info, h, NULL);
 }
 
@@ -4023,9 +4184,9 @@ elf64_x86_64_finish_local_dynamic_symbol (void **slot, void *inf)
    dynamic linker, before writing them out.  */
 
 static enum elf_reloc_type_class
-elf64_x86_64_reloc_type_class (const Elf_Internal_Rela *rela)
+elf_x86_64_reloc_type_class (const Elf_Internal_Rela *rela)
 {
-  switch ((int) ELF64_R_TYPE (rela->r_info))
+  switch ((int) ELF32_R_TYPE (rela->r_info))
     {
     case R_X86_64_RELATIVE:
       return reloc_class_relative;
@@ -4041,13 +4202,14 @@ elf64_x86_64_reloc_type_class (const Elf_Internal_Rela *rela)
 /* Finish up the dynamic sections.  */
 
 static bfd_boolean
-elf64_x86_64_finish_dynamic_sections (bfd *output_bfd, struct bfd_link_info *info)
+elf_x86_64_finish_dynamic_sections (bfd *output_bfd,
+                                   struct bfd_link_info *info)
 {
-  struct elf64_x86_64_link_hash_table *htab;
+  struct elf_x86_64_link_hash_table *htab;
   bfd *dynobj;
   asection *sdyn;
 
-  htab = elf64_x86_64_hash_table (info);
+  htab = elf_x86_64_hash_table (info);
   if (htab == NULL)
     return FALSE;
 
@@ -4056,19 +4218,23 @@ elf64_x86_64_finish_dynamic_sections (bfd *output_bfd, struct bfd_link_info *inf
 
   if (htab->elf.dynamic_sections_created)
     {
-      Elf64_External_Dyn *dyncon, *dynconend;
+      bfd_byte *dyncon, *dynconend;
+      const struct elf_backend_data *bed;
+      bfd_size_type sizeof_dyn;
 
       if (sdyn == NULL || htab->elf.sgot == NULL)
        abort ();
 
-      dyncon = (Elf64_External_Dyn *) sdyn->contents;
-      dynconend = (Elf64_External_Dyn *) (sdyn->contents + sdyn->size);
-      for (; dyncon < dynconend; dyncon++)
+      bed = get_elf_backend_data (dynobj);
+      sizeof_dyn = bed->s->sizeof_dyn;
+      dyncon = sdyn->contents;
+      dynconend = sdyn->contents + sdyn->size;
+      for (; dyncon < dynconend; dyncon += sizeof_dyn)
        {
          Elf_Internal_Dyn dyn;
          asection *s;
 
-         bfd_elf64_swap_dyn_in (dynobj, dyncon, &dyn);
+         (*bed->s->swap_dyn_in) (dynobj, dyncon, &dyn);
 
          switch (dyn.d_tag)
            {
@@ -4117,14 +4283,14 @@ elf64_x86_64_finish_dynamic_sections (bfd *output_bfd, struct bfd_link_info *inf
              break;
            }
 
-         bfd_elf64_swap_dyn_out (output_bfd, &dyn, dyncon);
+         (*bed->s->swap_dyn_out) (output_bfd, &dyn, dyncon);
        }
 
       /* Fill in the special first entry in the procedure linkage table.  */
       if (htab->elf.splt && htab->elf.splt->size > 0)
        {
          /* Fill in the first entry in the procedure linkage table.  */
-         memcpy (htab->elf.splt->contents, elf64_x86_64_plt0_entry,
+         memcpy (htab->elf.splt->contents, elf_x86_64_plt0_entry,
                  PLT_ENTRY_SIZE);
          /* Add offset for pushq GOT+8(%rip), since the instruction
             uses 6 bytes subtract this value.  */
@@ -4156,7 +4322,7 @@ elf64_x86_64_finish_dynamic_sections (bfd *output_bfd, struct bfd_link_info *inf
                          htab->elf.sgot->contents + htab->tlsdesc_got);
 
              memcpy (htab->elf.splt->contents + htab->tlsdesc_plt,
-                     elf64_x86_64_plt0_entry,
+                     elf_x86_64_plt0_entry,
                      PLT_ENTRY_SIZE);
 
              /* Add offset for pushq GOT+8(%rip), since the
@@ -4221,7 +4387,7 @@ elf64_x86_64_finish_dynamic_sections (bfd *output_bfd, struct bfd_link_info *inf
 
   /* Fill PLT and GOT entries for local STT_GNU_IFUNC symbols.  */
   htab_traverse (htab->loc_hash_table,
-                elf64_x86_64_finish_local_dynamic_symbol,
+                elf_x86_64_finish_local_dynamic_symbol,
                 info);
 
   return TRUE;
@@ -4231,8 +4397,8 @@ elf64_x86_64_finish_dynamic_sections (bfd *output_bfd, struct bfd_link_info *inf
    or (bfd_vma) -1 if it should not be included.  */
 
 static bfd_vma
-elf64_x86_64_plt_sym_val (bfd_vma i, const asection *plt,
-                         const arelent *rel ATTRIBUTE_UNUSED)
+elf_x86_64_plt_sym_val (bfd_vma i, const asection *plt,
+                       const arelent *rel ATTRIBUTE_UNUSED)
 {
   return plt->vma + (i + 1) * PLT_ENTRY_SIZE;
 }
@@ -4241,7 +4407,7 @@ elf64_x86_64_plt_sym_val (bfd_vma i, const asection *plt,
    is called when elfcode.h finds a section with an unknown type.  */
 
 static bfd_boolean
-elf64_x86_64_section_from_shdr (bfd *abfd,
+elf_x86_64_section_from_shdr (bfd *abfd,
                                Elf_Internal_Shdr *hdr,
                                const char *name,
                                int shindex)
@@ -4260,13 +4426,13 @@ elf64_x86_64_section_from_shdr (bfd *abfd,
    of .bss.  */
 
 static bfd_boolean
-elf64_x86_64_add_symbol_hook (bfd *abfd,
-                             struct bfd_link_info *info,
-                             Elf_Internal_Sym *sym,
-                             const char **namep ATTRIBUTE_UNUSED,
-                             flagword *flagsp ATTRIBUTE_UNUSED,
-                             asection **secp,
-                             bfd_vma *valp)
+elf_x86_64_add_symbol_hook (bfd *abfd,
+                           struct bfd_link_info *info,
+                           Elf_Internal_Sym *sym,
+                           const char **namep ATTRIBUTE_UNUSED,
+                           flagword *flagsp ATTRIBUTE_UNUSED,
+                           asection **secp,
+                           bfd_vma *valp)
 {
   asection *lcomm;
 
@@ -4291,8 +4457,9 @@ elf64_x86_64_add_symbol_hook (bfd *abfd,
     }
 
   if ((abfd->flags & DYNAMIC) == 0
-      && ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC)
-    elf_tdata (info->output_bfd)->has_ifunc_symbols = TRUE;
+      && (ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC
+         || ELF_ST_BIND (sym->st_info) == STB_GNU_UNIQUE))
+    elf_tdata (info->output_bfd)->has_gnu_symbols = TRUE;
 
   return TRUE;
 }
@@ -4302,8 +4469,8 @@ elf64_x86_64_add_symbol_hook (bfd *abfd,
    index.  */
 
 static bfd_boolean
-elf64_x86_64_elf_section_from_bfd_section (bfd *abfd ATTRIBUTE_UNUSED,
-                                          asection *sec, int *index_return)
+elf_x86_64_elf_section_from_bfd_section (bfd *abfd ATTRIBUTE_UNUSED,
+                                        asection *sec, int *index_return)
 {
   if (sec == &_bfd_elf_large_com_section)
     {
@@ -4316,8 +4483,8 @@ elf64_x86_64_elf_section_from_bfd_section (bfd *abfd ATTRIBUTE_UNUSED,
 /* Process a symbol.  */
 
 static void
-elf64_x86_64_symbol_processing (bfd *abfd ATTRIBUTE_UNUSED,
-                               asymbol *asym)
+elf_x86_64_symbol_processing (bfd *abfd ATTRIBUTE_UNUSED,
+                             asymbol *asym)
 {
   elf_symbol_type *elfsym = (elf_symbol_type *) asym;
 
@@ -4333,14 +4500,14 @@ elf64_x86_64_symbol_processing (bfd *abfd ATTRIBUTE_UNUSED,
 }
 
 static bfd_boolean
-elf64_x86_64_common_definition (Elf_Internal_Sym *sym)
+elf_x86_64_common_definition (Elf_Internal_Sym *sym)
 {
   return (sym->st_shndx == SHN_COMMON
          || sym->st_shndx == SHN_X86_64_LCOMMON);
 }
 
 static unsigned int
-elf64_x86_64_common_section_index (asection *sec)
+elf_x86_64_common_section_index (asection *sec)
 {
   if ((elf_section_flags (sec) & SHF_X86_64_LARGE) == 0)
     return SHN_COMMON;
@@ -4349,7 +4516,7 @@ elf64_x86_64_common_section_index (asection *sec)
 }
 
 static asection *
-elf64_x86_64_common_section (asection *sec)
+elf_x86_64_common_section (asection *sec)
 {
   if ((elf_section_flags (sec) & SHF_X86_64_LARGE) == 0)
     return bfd_com_section_ptr;
@@ -4358,29 +4525,29 @@ elf64_x86_64_common_section (asection *sec)
 }
 
 static bfd_boolean
-elf64_x86_64_merge_symbol (struct bfd_link_info *info ATTRIBUTE_UNUSED,
-                          struct elf_link_hash_entry **sym_hash ATTRIBUTE_UNUSED,
-                          struct elf_link_hash_entry *h,
-                          Elf_Internal_Sym *sym,
-                          asection **psec,
-                          bfd_vma *pvalue ATTRIBUTE_UNUSED,
-                          unsigned int *pold_alignment ATTRIBUTE_UNUSED,
-                          bfd_boolean *skip ATTRIBUTE_UNUSED,
-                          bfd_boolean *override ATTRIBUTE_UNUSED,
-                          bfd_boolean *type_change_ok ATTRIBUTE_UNUSED,
-                          bfd_boolean *size_change_ok ATTRIBUTE_UNUSED,
-                          bfd_boolean *newdef ATTRIBUTE_UNUSED,
-                          bfd_boolean *newdyn,
-                          bfd_boolean *newdyncommon ATTRIBUTE_UNUSED,
-                          bfd_boolean *newweak ATTRIBUTE_UNUSED,
-                          bfd *abfd ATTRIBUTE_UNUSED,
-                          asection **sec,
-                          bfd_boolean *olddef ATTRIBUTE_UNUSED,
-                          bfd_boolean *olddyn,
-                          bfd_boolean *olddyncommon ATTRIBUTE_UNUSED,
-                          bfd_boolean *oldweak ATTRIBUTE_UNUSED,
-                          bfd *oldbfd,
-                          asection **oldsec)
+elf_x86_64_merge_symbol (struct bfd_link_info *info ATTRIBUTE_UNUSED,
+                        struct elf_link_hash_entry **sym_hash ATTRIBUTE_UNUSED,
+                        struct elf_link_hash_entry *h,
+                        Elf_Internal_Sym *sym,
+                        asection **psec,
+                        bfd_vma *pvalue ATTRIBUTE_UNUSED,
+                        unsigned int *pold_alignment ATTRIBUTE_UNUSED,
+                        bfd_boolean *skip ATTRIBUTE_UNUSED,
+                        bfd_boolean *override ATTRIBUTE_UNUSED,
+                        bfd_boolean *type_change_ok ATTRIBUTE_UNUSED,
+                        bfd_boolean *size_change_ok ATTRIBUTE_UNUSED,
+                        bfd_boolean *newdef ATTRIBUTE_UNUSED,
+                        bfd_boolean *newdyn,
+                        bfd_boolean *newdyncommon ATTRIBUTE_UNUSED,
+                        bfd_boolean *newweak ATTRIBUTE_UNUSED,
+                        bfd *abfd ATTRIBUTE_UNUSED,
+                        asection **sec,
+                        bfd_boolean *olddef ATTRIBUTE_UNUSED,
+                        bfd_boolean *olddyn,
+                        bfd_boolean *olddyncommon ATTRIBUTE_UNUSED,
+                        bfd_boolean *oldweak ATTRIBUTE_UNUSED,
+                        bfd *oldbfd,
+                        asection **oldsec)
 {
   /* A normal common symbol and a large common symbol result in a
      normal common symbol.  We turn the large common symbol into a
@@ -4407,8 +4574,8 @@ elf64_x86_64_merge_symbol (struct bfd_link_info *info ATTRIBUTE_UNUSED,
 }
 
 static int
-elf64_x86_64_additional_program_headers (bfd *abfd,
-                                        struct bfd_link_info *info ATTRIBUTE_UNUSED)
+elf_x86_64_additional_program_headers (bfd *abfd,
+                                      struct bfd_link_info *info ATTRIBUTE_UNUSED)
 {
   asection *s;
   int count = 0;
@@ -4431,7 +4598,7 @@ elf64_x86_64_additional_program_headers (bfd *abfd,
 /* Return TRUE if symbol should be hashed in the `.gnu.hash' section.  */
 
 static bfd_boolean
-elf64_x86_64_hash_symbol (struct elf_link_hash_entry *h)
+elf_x86_64_hash_symbol (struct elf_link_hash_entry *h)
 {
   if (h->plt.offset != (bfd_vma) -1
       && !h->def_regular
@@ -4441,8 +4608,19 @@ elf64_x86_64_hash_symbol (struct elf_link_hash_entry *h)
   return _bfd_elf_hash_symbol (h);
 }
 
+/* Return TRUE iff relocations for INPUT are compatible with OUTPUT. */
+
+static bfd_boolean
+elf_x86_64_relocs_compatible (const bfd_target *input,
+                             const bfd_target *output)
+{
+  return ((xvec_get_elf_backend_data (input)->s->elfclass
+          == xvec_get_elf_backend_data (output)->s->elfclass)
+         && _bfd_elf_relocs_compatible (input, output));
+}
+
 static const struct bfd_elf_special_section
-  elf64_x86_64_special_sections[]=
+  elf_x86_64_special_sections[]=
 {
   { STRING_COMMA_LEN (".gnu.linkonce.lb"), -2, SHT_NOBITS,   SHF_ALLOC + SHF_WRITE + SHF_X86_64_LARGE},
   { STRING_COMMA_LEN (".gnu.linkonce.lr"), -2, SHT_PROGBITS, SHF_ALLOC + SHF_X86_64_LARGE},
@@ -4470,59 +4648,59 @@ static const struct bfd_elf_special_section
 #define elf_backend_got_header_size        (GOT_ENTRY_SIZE*3)
 #define elf_backend_rela_normal                    1
 
-#define elf_info_to_howto                  elf64_x86_64_info_to_howto
+#define elf_info_to_howto                  elf_x86_64_info_to_howto
 
 #define bfd_elf64_bfd_link_hash_table_create \
-  elf64_x86_64_link_hash_table_create
+  elf_x86_64_link_hash_table_create
 #define bfd_elf64_bfd_link_hash_table_free \
-  elf64_x86_64_link_hash_table_free
-#define bfd_elf64_bfd_reloc_type_lookup            elf64_x86_64_reloc_type_lookup
+  elf_x86_64_link_hash_table_free
+#define bfd_elf64_bfd_reloc_type_lookup            elf_x86_64_reloc_type_lookup
 #define bfd_elf64_bfd_reloc_name_lookup \
-  elf64_x86_64_reloc_name_lookup
-
-#define elf_backend_adjust_dynamic_symbol   elf64_x86_64_adjust_dynamic_symbol
-#define elf_backend_relocs_compatible      _bfd_elf_relocs_compatible
-#define elf_backend_check_relocs           elf64_x86_64_check_relocs
-#define elf_backend_copy_indirect_symbol    elf64_x86_64_copy_indirect_symbol
-#define elf_backend_create_dynamic_sections elf64_x86_64_create_dynamic_sections
-#define elf_backend_finish_dynamic_sections elf64_x86_64_finish_dynamic_sections
-#define elf_backend_finish_dynamic_symbol   elf64_x86_64_finish_dynamic_symbol
-#define elf_backend_gc_mark_hook           elf64_x86_64_gc_mark_hook
-#define elf_backend_gc_sweep_hook          elf64_x86_64_gc_sweep_hook
-#define elf_backend_grok_prstatus          elf64_x86_64_grok_prstatus
-#define elf_backend_grok_psinfo                    elf64_x86_64_grok_psinfo
-#define elf_backend_reloc_type_class       elf64_x86_64_reloc_type_class
-#define elf_backend_relocate_section       elf64_x86_64_relocate_section
-#define elf_backend_size_dynamic_sections   elf64_x86_64_size_dynamic_sections
-#define elf_backend_always_size_sections    elf64_x86_64_always_size_sections
+  elf_x86_64_reloc_name_lookup
+
+#define elf_backend_adjust_dynamic_symbol   elf_x86_64_adjust_dynamic_symbol
+#define elf_backend_relocs_compatible      elf_x86_64_relocs_compatible
+#define elf_backend_check_relocs           elf_x86_64_check_relocs
+#define elf_backend_copy_indirect_symbol    elf_x86_64_copy_indirect_symbol
+#define elf_backend_create_dynamic_sections elf_x86_64_create_dynamic_sections
+#define elf_backend_finish_dynamic_sections elf_x86_64_finish_dynamic_sections
+#define elf_backend_finish_dynamic_symbol   elf_x86_64_finish_dynamic_symbol
+#define elf_backend_gc_mark_hook           elf_x86_64_gc_mark_hook
+#define elf_backend_gc_sweep_hook          elf_x86_64_gc_sweep_hook
+#define elf_backend_grok_prstatus          elf_x86_64_grok_prstatus
+#define elf_backend_grok_psinfo                    elf_x86_64_grok_psinfo
+#define elf_backend_reloc_type_class       elf_x86_64_reloc_type_class
+#define elf_backend_relocate_section       elf_x86_64_relocate_section
+#define elf_backend_size_dynamic_sections   elf_x86_64_size_dynamic_sections
+#define elf_backend_always_size_sections    elf_x86_64_always_size_sections
 #define elf_backend_init_index_section     _bfd_elf_init_1_index_section
-#define elf_backend_plt_sym_val                    elf64_x86_64_plt_sym_val
+#define elf_backend_plt_sym_val                    elf_x86_64_plt_sym_val
 #define elf_backend_object_p               elf64_x86_64_elf_object_p
-#define bfd_elf64_mkobject                 elf64_x86_64_mkobject
+#define bfd_elf64_mkobject                 elf_x86_64_mkobject
 
 #define elf_backend_section_from_shdr \
-       elf64_x86_64_section_from_shdr
+       elf_x86_64_section_from_shdr
 
 #define elf_backend_section_from_bfd_section \
-  elf64_x86_64_elf_section_from_bfd_section
+  elf_x86_64_elf_section_from_bfd_section
 #define elf_backend_add_symbol_hook \
-  elf64_x86_64_add_symbol_hook
+  elf_x86_64_add_symbol_hook
 #define elf_backend_symbol_processing \
-  elf64_x86_64_symbol_processing
+  elf_x86_64_symbol_processing
 #define elf_backend_common_section_index \
-  elf64_x86_64_common_section_index
+  elf_x86_64_common_section_index
 #define elf_backend_common_section \
-  elf64_x86_64_common_section
+  elf_x86_64_common_section
 #define elf_backend_common_definition \
-  elf64_x86_64_common_definition
+  elf_x86_64_common_definition
 #define elf_backend_merge_symbol \
-  elf64_x86_64_merge_symbol
+  elf_x86_64_merge_symbol
 #define elf_backend_special_sections \
-  elf64_x86_64_special_sections
+  elf_x86_64_special_sections
 #define elf_backend_additional_program_headers \
-  elf64_x86_64_additional_program_headers
+  elf_x86_64_additional_program_headers
 #define elf_backend_hash_symbol \
-  elf64_x86_64_hash_symbol
+  elf_x86_64_hash_symbol
 
 #undef  elf_backend_post_process_headers
 #define elf_backend_post_process_headers  _bfd_elf_set_osabi
@@ -4558,6 +4736,11 @@ static const struct bfd_elf_special_section
 #undef  elf64_bed
 #define elf64_bed                          elf64_x86_64_sol2_bed
 
+/* The 64-bit static TLS arena size is rounded to the nearest 16-byte
+   boundary.  */
+#undef elf_backend_static_tls_alignment
+#define elf_backend_static_tls_alignment    16
+
 /* The Solaris 2 ABI requires a plt symbol on all platforms.
 
    Cf. Linker and Libraries Guide, Ch. 2, Link-Editor, Generating the Output
@@ -4596,6 +4779,10 @@ elf64_l1om_elf_object_p (bfd *abfd)
 #define elf_backend_object_p               elf64_l1om_elf_object_p
 
 #undef  elf_backend_post_process_headers
+#undef  elf_backend_static_tls_alignment
+
+#undef elf_backend_want_plt_sym
+#define elf_backend_want_plt_sym           0
 
 #include "elf64-target.h"
 
@@ -4616,3 +4803,53 @@ elf64_l1om_elf_object_p (bfd *abfd)
 #define elf_backend_post_process_headers  _bfd_elf_set_osabi
 
 #include "elf64-target.h"
+
+/* 32bit x86-64 support.  */
+
+static bfd_boolean
+elf32_x86_64_elf_object_p (bfd *abfd)
+{
+  /* Set the right machine number for an x86-64 elf32 file.  */
+  bfd_default_set_arch_mach (abfd, bfd_arch_i386, bfd_mach_x64_32);
+  return TRUE;
+}
+
+#undef  TARGET_LITTLE_SYM
+#define TARGET_LITTLE_SYM                  bfd_elf32_x86_64_vec
+#undef  TARGET_LITTLE_NAME
+#define TARGET_LITTLE_NAME                 "elf32-x86-64"
+
+#undef ELF_ARCH
+#define ELF_ARCH                           bfd_arch_i386
+
+#undef ELF_MACHINE_CODE
+#define ELF_MACHINE_CODE                   EM_X86_64
+
+#define bfd_elf32_bfd_link_hash_table_create \
+  elf_x86_64_link_hash_table_create
+#define bfd_elf32_bfd_link_hash_table_free \
+  elf_x86_64_link_hash_table_free
+#define bfd_elf32_bfd_reloc_type_lookup        \
+  elf_x86_64_reloc_type_lookup
+#define bfd_elf32_bfd_reloc_name_lookup \
+  elf_x86_64_reloc_name_lookup
+#define bfd_elf32_mkobject \
+  elf_x86_64_mkobject
+
+#undef ELF_OSABI
+
+#undef elf_backend_post_process_headers
+
+#undef elf_backend_object_p
+#define elf_backend_object_p \
+  elf32_x86_64_elf_object_p
+
+#undef elf_backend_bfd_from_remote_memory
+#define elf_backend_bfd_from_remote_memory \
+  _bfd_elf32_bfd_from_remote_memory
+
+#undef elf_backend_size_info
+#define elf_backend_size_info \
+  _bfd_elf32_size_info
+
+#include "elf32-target.h"
This page took 0.065937 seconds and 4 git commands to generate.