Add initial Intel K1OM support.
[external/binutils.git] / bfd / elf64-x86-64.c
index 6066330..975b558 100644 (file)
@@ -1,6 +1,7 @@
 /* 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.
 #include "bfd_stdint.h"
 #include "objalloc.h"
 #include "hashtab.h"
+#include "dwarf2.h"
 
 #include "elf/x86-64.h"
 
+#ifdef CORE_HEADER
+#include <stdarg.h>
+#include CORE_HEADER
+#endif
+
 /* In case we're on a 32-bit machine, construct a 64-bit "-1" value.  */
 #define MINUS_ONE (~ (bfd_vma) 0)
 
@@ -310,6 +317,19 @@ elf_x86_64_grok_prstatus (bfd *abfd, Elf_Internal_Note *note)
       default:
        return FALSE;
 
+      case 296:                /* sizeof(istruct elf_prstatus) on Linux/x32 */
+       /* pr_cursig */
+       elf_tdata (abfd)->core_signal = bfd_get_16 (abfd, note->descdata + 12);
+
+       /* pr_pid */
+       elf_tdata (abfd)->core_lwpid = bfd_get_32 (abfd, note->descdata + 24);
+
+       /* pr_reg */
+       offset = 72;
+       size = 216;
+
+       break;
+
       case 336:                /* sizeof(istruct elf_prstatus) on Linux/x86_64 */
        /* pr_cursig */
        elf_tdata (abfd)->core_signal
@@ -339,6 +359,15 @@ elf_x86_64_grok_psinfo (bfd *abfd, Elf_Internal_Note *note)
       default:
        return FALSE;
 
+      case 124:                /* sizeof(struct elf_prpsinfo) on Linux/x32 */
+       elf_tdata (abfd)->core_pid
+         = bfd_get_32 (abfd, note->descdata + 12);
+       elf_tdata (abfd)->core_program
+         = _bfd_elfcore_strndup (abfd, note->descdata + 28, 16);
+       elf_tdata (abfd)->core_command
+         = _bfd_elfcore_strndup (abfd, note->descdata + 44, 80);
+       break;
+
       case 136:                /* sizeof(struct elf_prpsinfo) on Linux/x86_64 */
        elf_tdata (abfd)->core_pid
          = bfd_get_32 (abfd, note->descdata + 24);
@@ -362,6 +391,99 @@ elf_x86_64_grok_psinfo (bfd *abfd, Elf_Internal_Note *note)
 
   return TRUE;
 }
+
+#ifdef CORE_HEADER
+static char *
+elf_x86_64_write_core_note (bfd *abfd, char *buf, int *bufsiz,
+                           int note_type, ...)
+{
+  const struct elf_backend_data *bed = get_elf_backend_data (abfd);
+  const void *p;
+  int size;
+  va_list ap;
+  const char *fname, *psargs;
+  long pid;
+  int cursig;
+  const void *gregs;
+
+  switch (note_type)
+    {
+    default:
+      return NULL;
+
+    case NT_PRPSINFO:
+      va_start (ap, note_type);
+      fname = va_arg (ap, const char *);
+      psargs = va_arg (ap, const char *);
+      va_end (ap);
+
+      if (bed->s->elfclass == ELFCLASS32)
+       {
+         prpsinfo32_t data;
+         memset (&data, 0, sizeof (data));
+         strncpy (data.pr_fname, fname, sizeof (data.pr_fname));
+         strncpy (data.pr_psargs, psargs, sizeof (data.pr_psargs));
+         p = (const void *) &data;
+         size = sizeof (data);
+       }
+      else
+       {
+         prpsinfo_t data;
+         memset (&data, 0, sizeof (data));
+         strncpy (data.pr_fname, fname, sizeof (data.pr_fname));
+         strncpy (data.pr_psargs, psargs, sizeof (data.pr_psargs));
+         p = (const void *) &data;
+         size = sizeof (data);
+       }
+      break;
+
+    case NT_PRSTATUS:
+      va_start (ap, note_type);
+      pid = va_arg (ap, long);
+      cursig = va_arg (ap, int);
+      gregs = va_arg (ap, const void *);
+      va_end (ap);
+
+      if (bed->s->elfclass == ELFCLASS32)
+       {
+         if (bed->elf_machine_code == EM_X86_64)
+           {
+             prstatusx32_t prstat;
+             memset (&prstat, 0, sizeof (prstat));
+             prstat.pr_pid = pid;
+             prstat.pr_cursig = cursig;
+             memcpy (&prstat.pr_reg, gregs, sizeof (prstat.pr_reg));
+             p = (const void *) &prstat;
+             size = sizeof (prstat);
+           }
+         else
+           {
+             prstatus32_t prstat;
+             memset (&prstat, 0, sizeof (prstat));
+             prstat.pr_pid = pid;
+             prstat.pr_cursig = cursig;
+             memcpy (&prstat.pr_reg, gregs, sizeof (prstat.pr_reg));
+             p = (const void *) &prstat;
+             size = sizeof (prstat);
+           }
+       }
+      else
+       {
+         prstatus_t prstat;
+         memset (&prstat, 0, sizeof (prstat));
+         prstat.pr_pid = pid;
+         prstat.pr_cursig = cursig;
+         memcpy (&prstat.pr_reg, gregs, sizeof (prstat.pr_reg));
+         p = (const void *) &prstat;
+         size = sizeof (prstat);
+       }
+      break;
+    }
+
+  return elfcore_write_note (abfd, buf, bufsiz, "CORE", note_type, p,
+                            size);
+}
+#endif
 \f
 /* Functions for the x86-64 ELF linker.         */
 
@@ -407,6 +529,45 @@ static const bfd_byte elf_x86_64_plt_entry[PLT_ENTRY_SIZE] =
   0, 0, 0, 0   /* replaced with offset to start of .plt0.  */
 };
 
+/* .eh_frame covering the .plt section.  */
+
+static const bfd_byte elf_x86_64_eh_frame_plt[] =
+{
+#define PLT_CIE_LENGTH         20
+#define PLT_FDE_LENGTH         36
+#define PLT_FDE_START_OFFSET   4 + PLT_CIE_LENGTH + 8
+#define PLT_FDE_LEN_OFFSET     4 + PLT_CIE_LENGTH + 12
+  PLT_CIE_LENGTH, 0, 0, 0,     /* CIE length */
+  0, 0, 0, 0,                  /* CIE ID */
+  1,                           /* CIE version */
+  'z', 'R', 0,                 /* Augmentation string */
+  1,                           /* Code alignment factor */
+  0x78,                                /* Data alignment factor */
+  16,                          /* Return address column */
+  1,                           /* Augmentation size */
+  DW_EH_PE_pcrel | DW_EH_PE_sdata4, /* FDE encoding */
+  DW_CFA_def_cfa, 7, 8,                /* DW_CFA_def_cfa: r7 (rsp) ofs 8 */
+  DW_CFA_offset + 16, 1,       /* DW_CFA_offset: r16 (rip) at cfa-8 */
+  DW_CFA_nop, DW_CFA_nop,
+
+  PLT_FDE_LENGTH, 0, 0, 0,     /* FDE length */
+  PLT_CIE_LENGTH + 8, 0, 0, 0, /* CIE pointer */
+  0, 0, 0, 0,                  /* R_X86_64_PC32 .plt goes here */
+  0, 0, 0, 0,                  /* .plt size goes here */
+  0,                           /* Augmentation size */
+  DW_CFA_def_cfa_offset, 16,   /* DW_CFA_def_cfa_offset: 16 */
+  DW_CFA_advance_loc + 6,      /* DW_CFA_advance_loc: 6 to __PLT__+6 */
+  DW_CFA_def_cfa_offset, 24,   /* DW_CFA_def_cfa_offset: 24 */
+  DW_CFA_advance_loc + 10,     /* DW_CFA_advance_loc: 10 to __PLT__+16 */
+  DW_CFA_def_cfa_expression,   /* DW_CFA_def_cfa_expression */
+  11,                          /* Block length */
+  DW_OP_breg7, 8,              /* DW_OP_breg7 (rsp): 8 */
+  DW_OP_breg16, 0,             /* DW_OP_breg16 (rip): 0 */
+  DW_OP_lit15, DW_OP_and, DW_OP_lit11, DW_OP_ge,
+  DW_OP_lit3, DW_OP_shl, DW_OP_plus,
+  DW_CFA_nop, DW_CFA_nop, DW_CFA_nop, DW_CFA_nop
+};
+
 /* x86-64 ELF linker hash entry.  */
 
 struct elf_x86_64_link_hash_entry
@@ -480,6 +641,7 @@ struct elf_x86_64_link_hash_table
   /* Short-cuts to get to dynamic linker sections.  */
   asection *sdynbss;
   asection *srelbss;
+  asection *plt_eh_frame;
 
   union
   {
@@ -495,6 +657,7 @@ struct elf_x86_64_link_hash_table
 
   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;
 
@@ -647,6 +810,7 @@ elf_x86_64_link_hash_table_create (bfd *abfd)
 
   ret->sdynbss = NULL;
   ret->srelbss = NULL;
+  ret->plt_eh_frame = NULL;
   ret->sym_cache.abfd = NULL;
   ret->tlsdesc_plt = 0;
   ret->tlsdesc_got = 0;
@@ -658,6 +822,7 @@ elf_x86_64_link_hash_table_create (bfd *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;
     }
@@ -665,6 +830,7 @@ elf_x86_64_link_hash_table_create (bfd *abfd)
     {
       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;
     }
@@ -723,6 +889,24 @@ elf_x86_64_create_dynamic_sections (bfd *dynobj,
       || (!info->shared && !htab->srelbss))
     abort ();
 
+  if (!info->no_ld_generated_unwind_info
+      && bfd_get_section_by_name (dynobj, ".eh_frame") == NULL
+      && htab->elf.splt != NULL)
+    {
+      flagword flags = get_elf_backend_data (dynobj)->dynamic_sec_flags;
+      htab->plt_eh_frame
+       = bfd_make_section_with_flags (dynobj, ".eh_frame",
+                                      flags | SEC_READONLY);
+      if (htab->plt_eh_frame == NULL
+         || !bfd_set_section_alignment (dynobj, htab->plt_eh_frame, 3))
+       return FALSE;
+
+      htab->plt_eh_frame->size = sizeof (elf_x86_64_eh_frame_plt);
+      htab->plt_eh_frame->contents
+       = bfd_alloc (dynobj, htab->plt_eh_frame->size);
+      memcpy (htab->plt_eh_frame->contents, elf_x86_64_eh_frame_plt,
+             sizeof (elf_x86_64_eh_frame_plt));
+    }
   return TRUE;
 }
 
@@ -862,18 +1046,34 @@ elf_x86_64_check_tls_transition (bfd *abfd,
 
       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
        {
@@ -910,16 +1110,29 @@ elf_x86_64_check_tls_transition (bfd *abfd,
 
     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)
@@ -1176,6 +1389,46 @@ elf_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:
+           /* Allow R_X86_64_64 relocations in SEC_DEBUGGING sections
+              when building shared libraries.  */
+           if (info->shared
+               && !info->executable
+               && (sec->flags & SEC_DEBUGGING) != 0)
+             break;
+
+         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
@@ -1195,7 +1448,9 @@ elf_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info,
            case R_X86_64_PLT32:
            case R_X86_64_GOTPCREL:
            case R_X86_64_GOTPCREL64:
-             if (!_bfd_elf_create_ifunc_sections (abfd, info))
+             if (htab->elf.dynobj == NULL)
+               htab->elf.dynobj = abfd;
+             if (!_bfd_elf_create_ifunc_sections (htab->elf.dynobj, info))
                return FALSE;
              break;
            }
@@ -1232,6 +1487,9 @@ elf_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;
@@ -1249,9 +1507,9 @@ elf_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info,
                  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)
@@ -1448,16 +1706,17 @@ elf_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
             sections we don't care about, such as debug sections or
             non-constant sections.  */
          if (info->shared
-             && ABI_64_P (abfd)
              && (sec->flags & SEC_ALLOC) != 0
              && (sec->flags & SEC_READONLY) != 0)
            {
@@ -1478,6 +1737,7 @@ elf_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
@@ -1959,8 +2219,6 @@ elf_x86_64_allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf)
   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 elf_x86_64_link_hash_entry *) h;
 
   info = (struct bfd_link_info *) inf;
@@ -2225,8 +2483,9 @@ elf_x86_64_readonly_dynrelocs (struct elf_link_hash_entry *h,
   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;
+  /* Skip local IFUNC symbols. */
+  if (h->forced_local && h->type == STT_GNU_IFUNC)
+    return TRUE;
 
   eh = (struct elf_x86_64_link_hash_entry *) h;
   for (p = eh->dyn_relocs; p != NULL; p = p->next)
@@ -2239,6 +2498,11 @@ elf_x86_64_readonly_dynrelocs (struct elf_link_hash_entry *h,
 
          info->flags |= DF_TEXTREL;
 
+         if (info->warn_shared_textrel && info->shared)
+           info->callbacks->einfo (_("%P: %B: warning: relocation against `%s' in readonly section `%A'.\n"),
+                                   p->sec->owner, h->root.root.string,
+                                   p->sec);
+
          /* Not an error, just cut short the traversal.  */
          return FALSE;
        }
@@ -2317,8 +2581,14 @@ elf_x86_64_size_dynamic_sections (bfd *output_bfd,
                {
                  srel = elf_section_data (p->sec)->sreloc;
                  srel->size += p->count * bed->s->sizeof_rela;
-                 if ((p->sec->output_section->flags & SEC_READONLY) != 0)
-                   info->flags |= DF_TEXTREL;
+                 if ((p->sec->output_section->flags & SEC_READONLY) != 0
+                     && (info->flags & DF_TEXTREL) == 0)
+                   {
+                     info->flags |= DF_TEXTREL;
+                     if (info->warn_shared_textrel && info->shared)
+                       info->callbacks->einfo (_("%P: %B: warning: relocation in readonly section `%A'.\n"),
+                                               p->sec->owner, p->sec);
+                   }
                }
            }
        }
@@ -2511,6 +2781,13 @@ elf_x86_64_size_dynamic_sections (bfd *output_bfd,
        return FALSE;
     }
 
+  if (htab->plt_eh_frame != NULL
+      && htab->elf.splt != NULL
+      && htab->elf.splt->size != 0
+      && (htab->elf.splt->flags & SEC_EXCLUDE) == 0)
+    bfd_put_32 (dynobj, htab->elf.splt->size,
+               htab->plt_eh_frame->contents + PLT_FDE_LEN_OFFSET);
+
   if (htab->elf.dynamic_sections_created)
     {
       /* Add some entries to the .dynamic section.  We fill in the
@@ -2830,6 +3107,10 @@ elf_x86_64_relocate_section (bfd *output_bfd,
                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)
                {
@@ -2893,8 +3174,7 @@ elf_x86_64_relocate_section (bfd *output_bfd,
                     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:
@@ -2956,18 +3236,6 @@ elf_x86_64_relocate_section (bfd *output_bfd,
              relocation = (base_got->output_section->vma
                            + base_got->output_offset + off);
 
-             if (r_type != R_X86_64_GOTPCREL
-                 && r_type != R_X86_64_GOTPCREL64)
-               {
-                 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;
            }
        }
@@ -3307,7 +3575,7 @@ elf_x86_64_relocate_section (bfd *output_bfd,
              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 = htab->r_info (0, R_X86_64_RELATIVE);
@@ -3350,7 +3618,11 @@ elf_x86_64_relocate_section (bfd *output_bfd,
 
              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;
+               }
 
              elf_append_rela (output_bfd, sreloc, &outrel);
 
@@ -3389,15 +3661,26 @@ elf_x86_64_relocate_section (bfd *output_bfd,
 
              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,
                              elf_x86_64_tpoff (info, relocation),
                              contents + roff + 8);
@@ -3462,6 +3745,9 @@ elf_x86_64_relocate_section (bfd *output_bfd,
                      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,
@@ -3474,6 +3760,9 @@ elf_x86_64_relocate_section (bfd *output_bfd,
                      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,
@@ -3485,6 +3774,9 @@ elf_x86_64_relocate_section (bfd *output_bfd,
                      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),
@@ -3616,15 +3908,26 @@ elf_x86_64_relocate_section (bfd *output_bfd,
 
              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
@@ -3693,12 +3996,18 @@ elf_x86_64_relocate_section (bfd *output_bfd,
            {
              /* 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;
@@ -3743,6 +4052,7 @@ elf_x86_64_relocate_section (bfd *output_bfd,
          break;
 
        case R_X86_64_TPOFF32:
+       case R_X86_64_TPOFF64:
          BFD_ASSERT (info->executable);
          relocation = elf_x86_64_tpoff (info, relocation);
          break;
@@ -3770,6 +4080,7 @@ do_relocation:
                                    contents, rel->r_offset,
                                    relocation, rel->r_addend);
 
+check_relocation_error:
       if (r != bfd_reloc_ok)
        {
          const char *name;
@@ -3857,7 +4168,7 @@ elf_x86_64_finish_dynamic_symbol (bfd *output_bfd,
          || plt == NULL
          || gotplt == NULL
          || relplt == NULL)
-       abort ();
+       return FALSE;
 
       /* Get the index in the procedure linkage table which
         corresponds to this symbol.  This is the index of this symbol
@@ -4277,6 +4588,33 @@ elf_x86_64_finish_dynamic_sections (bfd *output_bfd,
        GOT_ENTRY_SIZE;
     }
 
+  /* Adjust .eh_frame for .plt section.  */
+  if (htab->plt_eh_frame != NULL)
+    {
+      if (htab->elf.splt != NULL
+         && htab->elf.splt->size != 0
+         && (htab->elf.splt->flags & SEC_EXCLUDE) == 0
+         && htab->elf.splt->output_section != NULL
+         && htab->plt_eh_frame->output_section != NULL)
+       {
+         bfd_vma plt_start = htab->elf.splt->output_section->vma;
+         bfd_vma eh_frame_start = htab->plt_eh_frame->output_section->vma
+                                  + htab->plt_eh_frame->output_offset
+                                  + PLT_FDE_START_OFFSET;
+         bfd_put_signed_32 (dynobj, plt_start - eh_frame_start,
+                            htab->plt_eh_frame->contents
+                            + PLT_FDE_START_OFFSET);
+       }
+      if (htab->plt_eh_frame->sec_info_type
+         == ELF_INFO_TYPE_EH_FRAME)
+       {
+         if (! _bfd_elf_write_section_eh_frame (output_bfd, info,
+                                                htab->plt_eh_frame,
+                                                htab->plt_eh_frame->contents))
+           return FALSE;
+       }
+    }
+
   if (htab->elf.sgot && htab->elf.sgot->size > 0)
     elf_section_data (htab->elf.sgot->output_section)->this_hdr.sh_entsize
       = GOT_ENTRY_SIZE;
@@ -4353,8 +4691,9 @@ elf_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;
 }
@@ -4431,14 +4770,14 @@ elf_x86_64_merge_symbol (struct bfd_link_info *info 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 *newdyn ATTRIBUTE_UNUSED,
+                        bfd_boolean *newdef,
                         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 *olddyn ATTRIBUTE_UNUSED,
+                        bfd_boolean *olddef,
                         bfd_boolean *olddyncommon ATTRIBUTE_UNUSED,
                         bfd_boolean *oldweak ATTRIBUTE_UNUSED,
                         bfd *oldbfd,
@@ -4447,9 +4786,9 @@ elf_x86_64_merge_symbol (struct bfd_link_info *info ATTRIBUTE_UNUSED,
   /* A normal common symbol and a large common symbol result in a
      normal common symbol.  We turn the large common symbol into a
      normal one.  */
-  if (!*olddyn
+  if (!*olddef
       && h->root.type == bfd_link_hash_common
-      && !*newdyn
+      && !*newdef
       && bfd_is_com_section (*sec)
       && *oldsec != *sec)
     {
@@ -4542,6 +4881,7 @@ static const struct bfd_elf_special_section
 #define elf_backend_want_plt_sym           0
 #define elf_backend_got_header_size        (GOT_ENTRY_SIZE*3)
 #define elf_backend_rela_normal                    1
+#define elf_backend_plt_alignment           4
 
 #define elf_info_to_howto                  elf_x86_64_info_to_howto
 
@@ -4564,6 +4904,9 @@ static const struct bfd_elf_special_section
 #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
+#ifdef CORE_HEADER
+#define elf_backend_write_core_note        elf_x86_64_write_core_note
+#endif
 #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
@@ -4597,7 +4940,6 @@ static const struct bfd_elf_special_section
 #define elf_backend_hash_symbol \
   elf_x86_64_hash_symbol
 
-#undef  elf_backend_post_process_headers
 #define elf_backend_post_process_headers  _bfd_elf_set_osabi
 
 #include "elf64-target.h"
@@ -4673,9 +5015,11 @@ elf64_l1om_elf_object_p (bfd *abfd)
 #undef elf_backend_object_p
 #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"
 
 /* FreeBSD L1OM support.  */
@@ -4691,8 +5035,55 @@ elf64_l1om_elf_object_p (bfd *abfd)
 #undef  elf64_bed
 #define elf64_bed elf64_l1om_fbsd_bed
 
-#undef  elf_backend_post_process_headers
-#define elf_backend_post_process_headers  _bfd_elf_set_osabi
+#include "elf64-target.h"
+
+/* Intel K1OM support.  */
+
+static bfd_boolean
+elf64_k1om_elf_object_p (bfd *abfd)
+{
+  /* Set the right machine number for an K1OM elf64 file.  */
+  bfd_default_set_arch_mach (abfd, bfd_arch_k1om, bfd_mach_k1om);
+  return TRUE;
+}
+
+#undef  TARGET_LITTLE_SYM
+#define TARGET_LITTLE_SYM                  bfd_elf64_k1om_vec
+#undef  TARGET_LITTLE_NAME
+#define TARGET_LITTLE_NAME                 "elf64-k1om"
+#undef ELF_ARCH
+#define ELF_ARCH                           bfd_arch_k1om
+
+#undef ELF_MACHINE_CODE
+#define ELF_MACHINE_CODE                   EM_K1OM
+
+#undef ELF_OSABI
+
+#undef  elf64_bed
+#define elf64_bed elf64_k1om_bed
+
+#undef elf_backend_object_p
+#define elf_backend_object_p               elf64_k1om_elf_object_p
+
+#undef  elf_backend_static_tls_alignment
+
+#undef elf_backend_want_plt_sym
+#define elf_backend_want_plt_sym           0
+
+#include "elf64-target.h"
+
+/* FreeBSD K1OM support.  */
+
+#undef  TARGET_LITTLE_SYM
+#define TARGET_LITTLE_SYM                  bfd_elf64_k1om_freebsd_vec
+#undef  TARGET_LITTLE_NAME
+#define TARGET_LITTLE_NAME                 "elf64-k1om-freebsd"
+
+#undef ELF_OSABI
+#define        ELF_OSABI                           ELFOSABI_FREEBSD
+
+#undef  elf64_bed
+#define elf64_bed elf64_k1om_fbsd_bed
 
 #include "elf64-target.h"
 
@@ -4730,8 +5121,6 @@ elf32_x86_64_elf_object_p (bfd *abfd)
 
 #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