bfd/
authorJakub Jelinek <jakub@redhat.com>
Fri, 27 Sep 2002 19:29:18 +0000 (19:29 +0000)
committerJakub Jelinek <jakub@redhat.com>
Fri, 27 Sep 2002 19:29:18 +0000 (19:29 +0000)
* reloc.c: Add x86-64 TLS relocs.
* bfd-in2.h, libbfd.h: Rebuilt.
* elf64-x86-64.c (x86_64_elf_howto): Fix size fields for 32-bit
relocs.  Add TLS relocs.
(x86_64_reloc_map): Add TLS relocs.
(elf64_x86_64_info_to_howto): Adjust for added TLS relocs.
(struct elf64_x86_64_link_hash_entry): Add tls_type field.
(GOT_UNKNOWN, GOT_NORMAL, GOT_TLS_GD, GOT_TLS_IE): Define.
(elf64_x86_64_hash_entry): Define.
(struct elf64_x86_64_obj_tdata): New.
(elf64_x86_64_tdata, elf64_x86_64_local_got_tls_type): Define.
(struct elf64_x86_64_link_hash_table): Add tls_ld_got.
(link_hash_newfunc): Initialize tls_type.
(elf64_x86_64_link_hash_table_create): Initialize tls_ld_got.
(elf64_x86_64_copy_indirect_symbol): Swap tls_type if necessary.
(elf64_x86_64_mkobject): New.
(elf64_x86_64_elf_object_p): Allocate struct elf64_x86_64_obj_tdata.
(elf64_x86_64_tls_transition): New.
(elf64_x86_64_check_relocs): Add r_type variable and use it.
Handle TLS relocs.
(elf64_x86_64_gc_sweep_hook): Handle TLS relocs.
(allocate_dynrelocs): Allocate GOT space for TLS relocs.
(elf64_x86_64_size_dynamic_sections): Likewise.
(dtpoff_base, tpoff): New.
(elf64_x86_64_relocate_section): Handle TLS relocs.
(elf64_x86_64_finish_dynamic_symbol): Only handle non-TLS GOT
entries.
(bfd_elf64_mkobject): Define.

* elf32-i386.c (elf_i386_check_relocs) [R_386_TLS_LE]: Set
DF_STATIC_TLS if shared.
gas/
* config/tc-i386.c (tc_i386_fix_adjustable): Add x86-64 TLS relocs.
Define them if not BFD_ASSEMBLER.
(lex_got): Handle @tlsgd, @dtpoff and @tpoff in 64-bit mode, add
@tlsld.
(md_apply_fix3): No addend for BFD_RELOC_X86_64_TLSGD,
BFD_RELOC_X86_64_TLSLD and BFD_RELOC_X86_64_GOTTPOFF.
(tc_gen_reloc): Handle x86-64 TLS relocs.
include/
* elf/x86-64.h: Add TLS relocs.
ld/testsuite/
* lib/ld-lib.exp (run_ld_link_tests): Add.
* ld-sh/sh64/sh64.exp (run_ld_link_tests, regexp_diff,
file_contents): Remove.
(sh64tests): Add 6th field to the tests array.
* ld-i386/i386.exp (run_ld_link_tests): Remove.
* ld-x86-64/x86-64.exp: New.
* ld-x86-64/tlsbin.dd: New test.
* ld-x86-64/tlsbinpic.s: New test.
* ld-x86-64/tlsbin.rd: New test.
* ld-x86-64/tlsbin.s: New test.
* ld-x86-64/tlsbin.sd: New test.
* ld-x86-64/tlsbin.td: New test.
* ld-x86-64/tlslib.s: New test.
* ld-x86-64/tlspic1.s: New test.
* ld-x86-64/tlspic2.s: New test.
* ld-x86-64/tlspic.dd: New test.
* ld-x86-64/tlspic.rd: New test.
* ld-x86-64/tlspic.sd: New test.
* ld-x86-64/tlspic.td: New test.

28 files changed:
bfd/ChangeLog
bfd/bfd-in2.h
bfd/elf32-i386.c
bfd/elf64-x86-64.c
bfd/libbfd.h
bfd/reloc.c
gas/ChangeLog
gas/config/tc-i386.c
include/ChangeLog
include/elf/x86-64.h
ld/testsuite/ChangeLog
ld/testsuite/ld-i386/i386.exp
ld/testsuite/ld-sh/sh64/sh64.exp
ld/testsuite/ld-x86-64/tlsbin.dd [new file with mode: 0644]
ld/testsuite/ld-x86-64/tlsbin.rd [new file with mode: 0644]
ld/testsuite/ld-x86-64/tlsbin.s [new file with mode: 0644]
ld/testsuite/ld-x86-64/tlsbin.sd [new file with mode: 0644]
ld/testsuite/ld-x86-64/tlsbin.td [new file with mode: 0644]
ld/testsuite/ld-x86-64/tlsbinpic.s [new file with mode: 0644]
ld/testsuite/ld-x86-64/tlslib.s [new file with mode: 0644]
ld/testsuite/ld-x86-64/tlspic.dd [new file with mode: 0644]
ld/testsuite/ld-x86-64/tlspic.rd [new file with mode: 0644]
ld/testsuite/ld-x86-64/tlspic.sd [new file with mode: 0644]
ld/testsuite/ld-x86-64/tlspic.td [new file with mode: 0644]
ld/testsuite/ld-x86-64/tlspic1.s [new file with mode: 0644]
ld/testsuite/ld-x86-64/tlspic2.s [new file with mode: 0644]
ld/testsuite/ld-x86-64/x86-64.exp [new file with mode: 0644]
ld/testsuite/lib/ld-lib.exp

index 3d1c4aa..27bff18 100644 (file)
@@ -1,3 +1,37 @@
+2002-09-27  Jakub Jelinek  <jakub@redhat.com>
+
+       * reloc.c: Add x86-64 TLS relocs.
+       * bfd-in2.h, libbfd.h: Rebuilt.
+       * elf64-x86-64.c (x86_64_elf_howto): Fix size fields for 32-bit
+       relocs.  Add TLS relocs.
+       (x86_64_reloc_map): Add TLS relocs.
+       (elf64_x86_64_info_to_howto): Adjust for added TLS relocs.
+       (struct elf64_x86_64_link_hash_entry): Add tls_type field.
+       (GOT_UNKNOWN, GOT_NORMAL, GOT_TLS_GD, GOT_TLS_IE): Define.
+       (elf64_x86_64_hash_entry): Define.
+       (struct elf64_x86_64_obj_tdata): New.
+       (elf64_x86_64_tdata, elf64_x86_64_local_got_tls_type): Define.
+       (struct elf64_x86_64_link_hash_table): Add tls_ld_got.
+       (link_hash_newfunc): Initialize tls_type.
+       (elf64_x86_64_link_hash_table_create): Initialize tls_ld_got.
+       (elf64_x86_64_copy_indirect_symbol): Swap tls_type if necessary.
+       (elf64_x86_64_mkobject): New.
+       (elf64_x86_64_elf_object_p): Allocate struct elf64_x86_64_obj_tdata.
+       (elf64_x86_64_tls_transition): New.
+       (elf64_x86_64_check_relocs): Add r_type variable and use it.
+       Handle TLS relocs.
+       (elf64_x86_64_gc_sweep_hook): Handle TLS relocs.
+       (allocate_dynrelocs): Allocate GOT space for TLS relocs.
+       (elf64_x86_64_size_dynamic_sections): Likewise.
+       (dtpoff_base, tpoff): New.
+       (elf64_x86_64_relocate_section): Handle TLS relocs.
+       (elf64_x86_64_finish_dynamic_symbol): Only handle non-TLS GOT
+       entries.
+       (bfd_elf64_mkobject): Define.
+
+       * elf32-i386.c (elf_i386_check_relocs) [R_386_TLS_LE]: Set
+       DF_STATIC_TLS if shared.
+
 2002-09-26  Thiemo Seufer <seufer@csv.ica.uni-stuttgart.de>
 
        * elfxx-mips.c (_bfd_mips_elf_fake_sections): Don't emit unneeded
index 0525594..c7dfe33 100644 (file)
@@ -2286,6 +2286,14 @@ to compensate for the borrow when the low bits are added.  */
   BFD_RELOC_X86_64_RELATIVE,
   BFD_RELOC_X86_64_GOTPCREL,
   BFD_RELOC_X86_64_32S,
+  BFD_RELOC_X86_64_DTPMOD64,
+  BFD_RELOC_X86_64_DTPOFF64,
+  BFD_RELOC_X86_64_TPOFF64,
+  BFD_RELOC_X86_64_TLSGD,
+  BFD_RELOC_X86_64_TLSLD,
+  BFD_RELOC_X86_64_DTPOFF32,
+  BFD_RELOC_X86_64_GOTTPOFF,
+  BFD_RELOC_X86_64_TPOFF32,
 
 /* ns32k relocations  */
   BFD_RELOC_NS32K_IMM_8,
index d52d5a7..b71d78e 100644 (file)
@@ -1057,6 +1057,7 @@ elf_i386_check_relocs (abfd, info, sec, relocs)
        case R_386_TLS_LE:
          if (!info->shared)
            break;
+         info->flags |= DF_STATIC_TLS;
          /* Fall through */        
 
        case R_386_32:
index 9c4a9d4..fa2f2ee 100644 (file)
@@ -40,16 +40,16 @@ static reloc_howto_type x86_64_elf_howto_table[] =
   HOWTO(R_X86_64_64, 0, 4, 64, false, 0, complain_overflow_bitfield,
        bfd_elf_generic_reloc, "R_X86_64_64", false, MINUS_ONE, MINUS_ONE,
        false),
-  HOWTO(R_X86_64_PC32, 0, 4, 32, true, 0, complain_overflow_signed,
+  HOWTO(R_X86_64_PC32, 0, 2, 32, true, 0, complain_overflow_signed,
        bfd_elf_generic_reloc, "R_X86_64_PC32", false, 0xffffffff, 0xffffffff,
        true),
-  HOWTO(R_X86_64_GOT32, 0, 4, 32, false, 0, complain_overflow_signed,
+  HOWTO(R_X86_64_GOT32, 0, 2, 32, false, 0, complain_overflow_signed,
        bfd_elf_generic_reloc, "R_X86_64_GOT32", false, 0xffffffff, 0xffffffff,
        false),
-  HOWTO(R_X86_64_PLT32, 0, 4, 32, true, 0, complain_overflow_signed,
+  HOWTO(R_X86_64_PLT32, 0, 2, 32, true, 0, complain_overflow_signed,
        bfd_elf_generic_reloc, "R_X86_64_PLT32", false, 0xffffffff, 0xffffffff,
        true),
-  HOWTO(R_X86_64_COPY, 0, 4, 32, false, 0, complain_overflow_bitfield,
+  HOWTO(R_X86_64_COPY, 0, 2, 32, false, 0, complain_overflow_bitfield,
        bfd_elf_generic_reloc, "R_X86_64_COPY", false, 0xffffffff, 0xffffffff,
        false),
   HOWTO(R_X86_64_GLOB_DAT, 0, 4, 64, false, 0, complain_overflow_bitfield,
@@ -61,13 +61,13 @@ static reloc_howto_type x86_64_elf_howto_table[] =
   HOWTO(R_X86_64_RELATIVE, 0, 4, 64, false, 0, complain_overflow_bitfield,
        bfd_elf_generic_reloc, "R_X86_64_RELATIVE", false, MINUS_ONE,
        MINUS_ONE, false),
-  HOWTO(R_X86_64_GOTPCREL, 0, 4, 32, true,0 , complain_overflow_signed,
+  HOWTO(R_X86_64_GOTPCREL, 0, 2, 32, true, 0, complain_overflow_signed,
        bfd_elf_generic_reloc, "R_X86_64_GOTPCREL", false, 0xffffffff,
        0xffffffff, true),
-  HOWTO(R_X86_64_32, 0, 4, 32, false, 0, complain_overflow_unsigned,
+  HOWTO(R_X86_64_32, 0, 2, 32, false, 0, complain_overflow_unsigned,
        bfd_elf_generic_reloc, "R_X86_64_32", false, 0xffffffff, 0xffffffff,
        false),
-  HOWTO(R_X86_64_32S, 0, 4, 32, false, 0, complain_overflow_signed,
+  HOWTO(R_X86_64_32S, 0, 2, 32, false, 0, complain_overflow_signed,
        bfd_elf_generic_reloc, "R_X86_64_32S", false, 0xffffffff, 0xffffffff,
        false),
   HOWTO(R_X86_64_16, 0, 1, 16, false, 0, complain_overflow_bitfield,
@@ -78,6 +78,30 @@ static reloc_howto_type x86_64_elf_howto_table[] =
        bfd_elf_generic_reloc, "R_X86_64_8", false, 0xff, 0xff, false),
   HOWTO(R_X86_64_PC8, 0, 0, 8, true, 0, complain_overflow_signed,
        bfd_elf_generic_reloc, "R_X86_64_PC8", false, 0xff, 0xff, true),
+  HOWTO(R_X86_64_DTPMOD64, 0, 4, 64, false, 0, complain_overflow_bitfield,
+       bfd_elf_generic_reloc, "R_X86_64_DTPMOD64", false, MINUS_ONE,
+       MINUS_ONE, false),
+  HOWTO(R_X86_64_DTPOFF64, 0, 4, 64, false, 0, complain_overflow_bitfield,
+       bfd_elf_generic_reloc, "R_X86_64_DTPOFF64", false, MINUS_ONE,
+       MINUS_ONE, false),
+  HOWTO(R_X86_64_TPOFF64, 0, 4, 64, false, 0, complain_overflow_bitfield,
+       bfd_elf_generic_reloc, "R_X86_64_TPOFF64", false, MINUS_ONE,
+       MINUS_ONE, false),
+  HOWTO(R_X86_64_TLSGD, 0, 2, 32, true, 0, complain_overflow_signed,
+       bfd_elf_generic_reloc, "R_X86_64_TLSGD", false, 0xffffffff,
+       0xffffffff, true),
+  HOWTO(R_X86_64_TLSLD, 0, 2, 32, true, 0, complain_overflow_signed,
+       bfd_elf_generic_reloc, "R_X86_64_TLSLD", false, 0xffffffff,
+       0xffffffff, true),
+  HOWTO(R_X86_64_DTPOFF32, 0, 2, 32, false, 0, complain_overflow_bitfield,
+       bfd_elf_generic_reloc, "R_X86_64_DTPOFF32", false, 0xffffffff,
+       0xffffffff, false),
+  HOWTO(R_X86_64_GOTTPOFF, 0, 2, 32, true, 0, complain_overflow_signed,
+       bfd_elf_generic_reloc, "R_X86_64_GOTTPOFF", false, 0xffffffff,
+       0xffffffff, true),
+  HOWTO(R_X86_64_TPOFF32, 0, 2, 32, false, 0, complain_overflow_signed,
+       bfd_elf_generic_reloc, "R_X86_64_TPOFF32", false, 0xffffffff,
+       0xffffffff, false),
 
 /* GNU extension to record C++ vtable hierarchy.  */
   HOWTO (R_X86_64_GNU_VTINHERIT, 0, 4, 0, false, 0, complain_overflow_dont,
@@ -114,6 +138,14 @@ static const struct elf_reloc_map x86_64_reloc_map[] =
   { BFD_RELOC_16_PCREL,                R_X86_64_PC16, },
   { BFD_RELOC_8,               R_X86_64_8, },
   { BFD_RELOC_8_PCREL,         R_X86_64_PC8, },
+  { BFD_RELOC_X86_64_DTPMOD64, R_X86_64_DTPMOD64, },
+  { BFD_RELOC_X86_64_DTPOFF64, R_X86_64_DTPOFF64, },
+  { BFD_RELOC_X86_64_TPOFF64,  R_X86_64_TPOFF64, },
+  { BFD_RELOC_X86_64_TLSGD,    R_X86_64_TLSGD, },
+  { BFD_RELOC_X86_64_TLSLD,    R_X86_64_TLSLD, },
+  { BFD_RELOC_X86_64_DTPOFF32, R_X86_64_DTPOFF32, },
+  { BFD_RELOC_X86_64_GOTTPOFF, R_X86_64_GOTTPOFF, },
+  { BFD_RELOC_X86_64_TPOFF32,  R_X86_64_TPOFF32, },
   { BFD_RELOC_VTABLE_INHERIT,  R_X86_64_GNU_VTINHERIT, },
   { BFD_RELOC_VTABLE_ENTRY,    R_X86_64_GNU_VTENTRY, },
 };
@@ -128,6 +160,10 @@ static boolean elf64_x86_64_grok_psinfo
   PARAMS ((bfd *, Elf_Internal_Note *));
 static struct bfd_link_hash_table *elf64_x86_64_link_hash_table_create
   PARAMS ((bfd *));
+static int elf64_x86_64_tls_transition
+  PARAMS ((struct bfd_link_info *, int, int));
+static boolean elf64_x86_64_mkobject
+  PARAMS((bfd *));
 static boolean elf64_x86_64_elf_object_p PARAMS ((bfd *abfd));
 static boolean create_got_section
   PARAMS((bfd *, struct bfd_link_info *));
@@ -158,6 +194,10 @@ static boolean readonly_dynrelocs
   PARAMS ((struct elf_link_hash_entry *, PTR));
 static boolean elf64_x86_64_size_dynamic_sections
   PARAMS ((bfd *, struct bfd_link_info *));
+static bfd_vma dtpoff_base
+  PARAMS ((struct bfd_link_info *));
+static bfd_vma tpoff
+  PARAMS ((struct bfd_link_info *, bfd_vma));
 static boolean elf64_x86_64_relocate_section
   PARAMS ((bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *,
         Elf_Internal_Rela *, Elf_Internal_Sym *, asection **));
@@ -198,13 +238,13 @@ elf64_x86_64_info_to_howto (abfd, cache_ptr, dst)
   r_type = ELF64_R_TYPE (dst->r_info);
   if (r_type < (unsigned int) R_X86_64_GNU_VTINHERIT)
     {
-      BFD_ASSERT (r_type <= (unsigned int) R_X86_64_PC8);
+      BFD_ASSERT (r_type <= (unsigned int) R_X86_64_TPOFF32);
       i = r_type;
     }
   else
     {
       BFD_ASSERT (r_type < (unsigned int) R_X86_64_max);
-      i = r_type - ((unsigned int) R_X86_64_GNU_VTINHERIT - R_X86_64_PC8 - 1);
+      i = r_type - ((unsigned int) R_X86_64_GNU_VTINHERIT - R_X86_64_TPOFF32 - 1);
     }
   cache_ptr->howto = &x86_64_elf_howto_table[i];
   BFD_ASSERT (r_type == cache_ptr->howto->type);
@@ -343,8 +383,32 @@ struct elf64_x86_64_link_hash_entry
 
   /* Track dynamic relocs copied for this symbol.  */
   struct elf64_x86_64_dyn_relocs *dyn_relocs;
+
+#define GOT_UNKNOWN    0
+#define GOT_NORMAL     1
+#define GOT_TLS_GD     2
+#define GOT_TLS_IE     3
+  unsigned char tls_type;
+};
+
+#define elf64_x86_64_hash_entry(ent) \
+  ((struct elf64_x86_64_link_hash_entry *)(ent))
+
+struct elf64_x86_64_obj_tdata
+{
+  struct elf_obj_tdata root;
+
+  /* tls_type for each local got entry.  */
+  char *local_got_tls_type;
 };
 
+#define elf64_x86_64_tdata(abfd) \
+  ((struct elf64_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)
+
+
 /* x86-64 ELF linker hash table.  */
 
 struct elf64_x86_64_link_hash_table
@@ -360,6 +424,11 @@ struct elf64_x86_64_link_hash_table
   asection *sdynbss;
   asection *srelbss;
 
+  union {
+    bfd_signed_vma refcount;
+    bfd_vma offset;
+  } tls_ld_got;
+
   /* Small local sym to section mapping cache.  */
   struct sym_sec_cache sym_sec;
 };
@@ -395,6 +464,7 @@ link_hash_newfunc (entry, table, string)
 
       eh = (struct elf64_x86_64_link_hash_entry *) entry;
       eh->dyn_relocs = NULL;
+      eh->tls_type = GOT_UNKNOWN;
     }
 
   return entry;
@@ -427,6 +497,7 @@ elf64_x86_64_link_hash_table_create (abfd)
   ret->sdynbss = NULL;
   ret->srelbss = NULL;
   ret->sym_sec.abfd = NULL;
+  ret->tls_ld_got.refcount = 0;
 
   return &ret->elf.root;
 }
@@ -538,18 +609,67 @@ elf64_x86_64_copy_indirect_symbol (bed, dir, ind)
       eind->dyn_relocs = NULL;
     }
 
+  if (ind->root.type == bfd_link_hash_indirect
+      && dir->got.refcount <= 0)
+    {
+      edir->tls_type = eind->tls_type;
+      eind->tls_type = GOT_UNKNOWN;
+    }
+
   _bfd_elf_link_hash_copy_indirect (bed, dir, ind);
 }
 
 static boolean
-elf64_x86_64_elf_object_p (abfd)
+elf64_x86_64_mkobject (abfd)
      bfd *abfd;
 {
+  bfd_size_type amt = sizeof (struct elf64_x86_64_obj_tdata);
+  abfd->tdata.any = bfd_zalloc (abfd, amt);
+  if (abfd->tdata.any == NULL)
+    return false;
+  return true;
+}
+
+static boolean
+elf64_x86_64_elf_object_p (abfd)
+  bfd *abfd;
+{
+  /* Allocate our special target data.  */
+  struct elf64_x86_64_obj_tdata *new_tdata;
+  bfd_size_type amt = sizeof (struct elf64_x86_64_obj_tdata);
+  new_tdata = bfd_zalloc (abfd, amt);
+  if (new_tdata == NULL)
+    return false;
+  new_tdata->root = *abfd->tdata.elf_obj_data;
+  abfd->tdata.any = new_tdata;
   /* Set the right machine number for an x86-64 elf64 file.  */
   bfd_default_set_arch_mach (abfd, bfd_arch_i386, bfd_mach_x86_64);
   return true;
 }
 
+static int
+elf64_x86_64_tls_transition (info, r_type, is_local)
+     struct bfd_link_info *info;
+     int r_type;
+     int is_local;
+{
+  if (info->shared)
+    return r_type;
+
+  switch (r_type)
+    {
+    case R_X86_64_TLSGD:
+    case R_X86_64_GOTTPOFF:
+      if (is_local)
+       return R_X86_64_TPOFF32;
+      return R_X86_64_GOTTPOFF;
+    case R_X86_64_TLSLD:
+      return R_X86_64_TPOFF32;
+    }
+
+   return r_type;
+}
+
 /* Look through the relocs for a section during the first phase, and
    calculate needed space in the global offset table, procedure
    linkage table, and dynamic reloc sections.  */
@@ -580,10 +700,12 @@ elf64_x86_64_check_relocs (abfd, info, sec, relocs)
   rel_end = relocs + sec->reloc_count;
   for (rel = relocs; rel < rel_end; rel++)
     {
+      unsigned int r_type;
       unsigned long r_symndx;
       struct elf_link_hash_entry *h;
 
       r_symndx = ELF64_R_SYM (rel->r_info);
+      r_type = ELF64_R_TYPE (rel->r_info);
 
       if (r_symndx >= NUM_SHDR_ENTRIES (symtab_hdr))
        {
@@ -598,38 +720,103 @@ elf64_x86_64_check_relocs (abfd, info, sec, relocs)
       else
        h = sym_hashes[r_symndx - symtab_hdr->sh_info];
 
-      switch (ELF64_R_TYPE (rel->r_info))
+      r_type = elf64_x86_64_tls_transition (info, r_type, h == NULL);
+      switch (r_type)
        {
-       case R_X86_64_GOT32:
-       case R_X86_64_GOTPCREL:
-         /* This symbol requires a global offset table entry.  */
-         if (h != NULL)
+       case R_X86_64_TLSLD:
+         htab->tls_ld_got.refcount += 1;
+         goto create_got;
+
+       case R_X86_64_TPOFF32:
+         if (info->shared)
            {
-             h->got.refcount += 1;
+             (*_bfd_error_handler)
+               (_("%s: relocation %s can not be used when making a shared object; recompile with -fPIC"),
+                bfd_archive_filename (abfd),
+                x86_64_elf_howto_table[r_type].name);
+             bfd_set_error (bfd_error_bad_value);
+             return false;
            }
-         else
-           {
-             bfd_signed_vma *local_got_refcounts;
+         break;
 
-             /* This is a global offset table entry for a local symbol.  */
-             local_got_refcounts = elf_local_got_refcounts (abfd);
-             if (local_got_refcounts == NULL)
-               {
-                 bfd_size_type size;
+       case R_X86_64_GOTTPOFF:
+         if (info->shared)
+           info->flags |= DF_STATIC_TLS;
+         /* Fall through */
 
-                 size = symtab_hdr->sh_info;
-                 size *= sizeof (bfd_signed_vma);
-                 local_got_refcounts = ((bfd_signed_vma *)
-                                        bfd_zalloc (abfd, size));
-                 if (local_got_refcounts == NULL)
+       case R_X86_64_GOT32:
+       case R_X86_64_GOTPCREL:
+       case R_X86_64_TLSGD:
+         /* This symbol requires a global offset table entry.  */
+         {
+           int tls_type, old_tls_type;
+
+           switch (r_type)
+             {
+             default: tls_type = GOT_NORMAL; break;
+             case R_X86_64_TLSGD: tls_type = GOT_TLS_GD; break;
+             case R_X86_64_GOTTPOFF: tls_type = GOT_TLS_IE; break;
+             }
+
+           if (h != NULL)
+             {
+               h->got.refcount += 1;
+               old_tls_type = elf64_x86_64_hash_entry (h)->tls_type;
+             }
+           else
+             {
+               bfd_signed_vma *local_got_refcounts;
+
+               /* This is a global offset table entry for a local symbol.  */
+               local_got_refcounts = elf_local_got_refcounts (abfd);
+               if (local_got_refcounts == NULL)
+                 {
+                   bfd_size_type size;
+
+                   size = symtab_hdr->sh_info;
+                   size *= sizeof (bfd_signed_vma) + sizeof (char);
+                   local_got_refcounts = ((bfd_signed_vma *)
+                                          bfd_zalloc (abfd, size));
+                   if (local_got_refcounts == NULL)
+                     return false;
+                   elf_local_got_refcounts (abfd) = local_got_refcounts;
+                   elf64_x86_64_local_got_tls_type (abfd)
+                     = (char *) (local_got_refcounts + symtab_hdr->sh_info);
+                 }
+               local_got_refcounts[r_symndx] += 1;
+               old_tls_type
+                 = elf64_x86_64_local_got_tls_type (abfd) [r_symndx];
+             }
+
+           /* If a TLS symbol is accessed using IE at least once,
+              there is no point to use dynamic model for it.  */
+           if (old_tls_type != tls_type && old_tls_type != GOT_UNKNOWN
+               && (old_tls_type != GOT_TLS_GD || tls_type != GOT_TLS_IE))
+             {
+               if (old_tls_type == GOT_TLS_IE && tls_type == GOT_TLS_GD)
+                 tls_type = old_tls_type;
+               else
+                 {
+                   (*_bfd_error_handler)
+                     (_("%s: %s' accessed both as normal and thread local symbol"),
+                      bfd_archive_filename (abfd),
+                      h ? h->root.root.string : "<local>");
                    return false;
-                 elf_local_got_refcounts (abfd) = local_got_refcounts;
-               }
-             local_got_refcounts[r_symndx] += 1;
-           }
+                 }
+             }
+
+           if (old_tls_type != tls_type)
+             {
+               if (h != NULL)
+                 elf64_x86_64_hash_entry (h)->tls_type = tls_type;
+               else
+                 elf64_x86_64_local_got_tls_type (abfd) [r_symndx] = tls_type;
+             }
+         }
          /* Fall through */
 
          //case R_X86_64_GOTPCREL:
+       create_got:
          if (htab->sgot == NULL)
            {
              if (htab->elf.dynobj == NULL)
@@ -671,7 +858,7 @@ elf64_x86_64_check_relocs (abfd, info, sec, relocs)
              (*_bfd_error_handler)
                (_("%s: relocation %s can not be used when making a shared object; recompile with -fPIC"),
                 bfd_archive_filename (abfd),
-                x86_64_elf_howto_table[ELF64_R_TYPE (rel->r_info)].name);
+                x86_64_elf_howto_table[r_type].name);
              bfd_set_error (bfd_error_bad_value);
              return false;
            }
@@ -719,9 +906,9 @@ elf64_x86_64_check_relocs (abfd, info, sec, relocs)
             symbol.  */
          if ((info->shared
               && (sec->flags & SEC_ALLOC) != 0
-              && (((ELF64_R_TYPE (rel->r_info) != R_X86_64_PC8)
-                   && (ELF64_R_TYPE (rel->r_info) != R_X86_64_PC16)
-                   && (ELF64_R_TYPE (rel->r_info) != R_X86_64_PC32))
+              && (((r_type != R_X86_64_PC8)
+                   && (r_type != R_X86_64_PC16)
+                   && (r_type != R_X86_64_PC32))
                   || (h != NULL
                       && (! info->symbolic
                           || h->root.type == bfd_link_hash_defweak
@@ -822,9 +1009,9 @@ elf64_x86_64_check_relocs (abfd, info, sec, relocs)
                }
 
              p->count += 1;
-             if (ELF64_R_TYPE (rel->r_info) == R_X86_64_PC8
-                 || ELF64_R_TYPE (rel->r_info) == R_X86_64_PC16
-                 || ELF64_R_TYPE (rel->r_info) == R_X86_64_PC32)
+             if (r_type == R_X86_64_PC8
+                 || r_type == R_X86_64_PC16
+                 || r_type == R_X86_64_PC32)
                p->pc_count += 1;
            }
          break;
@@ -905,6 +1092,7 @@ elf64_x86_64_gc_sweep_hook (abfd, info, sec, relocs)
   bfd_signed_vma *local_got_refcounts;
   const Elf_Internal_Rela *rel, *relend;
   unsigned long r_symndx;
+  int r_type;
   struct elf_link_hash_entry *h;
 
   elf_section_data (sec)->local_dynrel = NULL;
@@ -915,8 +1103,18 @@ elf64_x86_64_gc_sweep_hook (abfd, info, sec, relocs)
 
   relend = relocs + sec->reloc_count;
   for (rel = relocs; rel < relend; rel++)
-    switch (ELF64_R_TYPE (rel->r_info))
+    switch ((r_type = elf64_x86_64_tls_transition (info,
+                                                  ELF64_R_TYPE (rel->r_info),
+                                                  ELF64_R_SYM (rel->r_info)
+                                                  >= symtab_hdr->sh_info)))
       {
+      case R_X86_64_TLSLD:
+       if (elf64_x86_64_hash_table (info)->tls_ld_got.refcount > 0)
+         elf64_x86_64_hash_table (info)->tls_ld_got.refcount -= 1;
+       break;
+
+      case R_X86_64_TLSGD:
+      case R_X86_64_GOTTPOFF:
       case R_X86_64_GOT32:
       case R_X86_64_GOTPCREL:
        r_symndx = ELF64_R_SYM (rel->r_info);
@@ -1226,10 +1424,18 @@ allocate_dynrelocs (h, inf)
       h->elf_link_hash_flags &= ~ELF_LINK_HASH_NEEDS_PLT;
     }
 
-  if (h->got.refcount > 0)
+  /* If R_X86_64_GOTTPOFF symbol is now local to the binary,
+     make it a R_X86_64_TPOFF32 requiring no GOT entry.  */
+  if (h->got.refcount > 0
+      && !info->shared
+      && h->dynindx == -1
+      && elf64_x86_64_hash_entry (h)->tls_type == GOT_TLS_IE)
+    h->got.offset = (bfd_vma) -1;
+  else if (h->got.refcount > 0)
     {
       asection *s;
       boolean dyn;
+      int tls_type = elf64_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.  */
@@ -1243,8 +1449,19 @@ allocate_dynrelocs (h, inf)
       s = htab->sgot;
       h->got.offset = s->_raw_size;
       s->_raw_size += GOT_ENTRY_SIZE;
+      /* R_X86_64_TLSGD needs 2 consecutive GOT slots.  */
+      if (tls_type == GOT_TLS_GD)
+       s->_raw_size += GOT_ENTRY_SIZE;
       dyn = htab->elf.dynamic_sections_created;
-      if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, info, h))
+      /* R_X86_64_TLSGD needs one dynamic relocation if local symbol
+        and two if global.
+        R_X86_64_GOTTPOFF needs one dynamic relocation.  */
+      if ((tls_type == GOT_TLS_GD && h->dynindx == -1)
+         || tls_type == GOT_TLS_IE)
+       htab->srelgot->_raw_size += sizeof (Elf64_External_Rela);
+      else if (tls_type == GOT_TLS_GD)
+       htab->srelgot->_raw_size += 2 * sizeof (Elf64_External_Rela);
+      else if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, info, h))
        htab->srelgot->_raw_size += sizeof (Elf64_External_Rela);
     }
   else
@@ -1390,6 +1607,7 @@ elf64_x86_64_size_dynamic_sections (output_bfd, info)
     {
       bfd_signed_vma *local_got;
       bfd_signed_vma *end_local_got;
+      char *local_tls_type;
       bfd_size_type locsymcount;
       Elf_Internal_Shdr *symtab_hdr;
       asection *srel;
@@ -1432,15 +1650,20 @@ elf64_x86_64_size_dynamic_sections (output_bfd, info)
       symtab_hdr = &elf_tdata (ibfd)->symtab_hdr;
       locsymcount = symtab_hdr->sh_info;
       end_local_got = local_got + locsymcount;
+      local_tls_type = elf64_x86_64_local_got_tls_type (ibfd);
       s = htab->sgot;
       srel = htab->srelgot;
-      for (; local_got < end_local_got; ++local_got)
+      for (; local_got < end_local_got; ++local_got, ++local_tls_type)
        {
          if (*local_got > 0)
            {
              *local_got = s->_raw_size;
              s->_raw_size += GOT_ENTRY_SIZE;
-             if (info->shared)
+             if (*local_tls_type == GOT_TLS_GD)
+               s->_raw_size += GOT_ENTRY_SIZE;
+             if (info->shared
+                 || *local_tls_type == GOT_TLS_GD
+                 || *local_tls_type == GOT_TLS_IE)
                srel->_raw_size += sizeof (Elf64_External_Rela);
            }
          else
@@ -1448,6 +1671,17 @@ elf64_x86_64_size_dynamic_sections (output_bfd, info)
        }
     }
 
+  if (htab->tls_ld_got.refcount > 0)
+    {
+      /* Allocate 2 got entries and 1 dynamic reloc for R_X86_64_TLSLD
+        relocs.  */
+      htab->tls_ld_got.offset = htab->sgot->_raw_size;
+      htab->sgot->_raw_size += 2 * GOT_ENTRY_SIZE;
+      htab->srelgot->_raw_size += sizeof (Elf64_External_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, allocate_dynrelocs, (PTR) info);
@@ -1558,6 +1792,38 @@ elf64_x86_64_size_dynamic_sections (output_bfd, info)
   return true;
 }
 
+/* Return the base VMA address which should be subtracted from real addresses
+   when resolving @dtpoff relocation.
+   This is PT_TLS segment p_vaddr.  */
+
+static bfd_vma
+dtpoff_base (info)
+     struct bfd_link_info *info;
+{
+  /* If tls_segment is NULL, we should have signalled an error already.  */
+  if (elf_hash_table (info)->tls_segment == NULL)
+    return 0;
+  return elf_hash_table (info)->tls_segment->start;
+}
+
+/* Return the relocation value for @tpoff relocation
+   if STT_TLS virtual address is ADDRESS.  */
+
+static bfd_vma
+tpoff (info, address)
+     struct bfd_link_info *info;
+     bfd_vma address;
+{
+  struct elf_link_tls_segment *tls_segment
+    = elf_hash_table (info)->tls_segment;
+
+  /* If tls_segment is NULL, we should have signalled an error already.  */
+  if (tls_segment == NULL)
+    return 0;
+  return address - align_power (tls_segment->size, tls_segment->align)
+        - tls_segment->start;
+}
+
 /* Relocate an x86_64 ELF section.  */
 
 static boolean
@@ -1591,7 +1857,7 @@ elf64_x86_64_relocate_section (output_bfd, info, input_bfd, input_section,
   relend = relocs + input_section->reloc_count;
   for (; rel < relend; rel++)
     {
-      int r_type;
+      unsigned int r_type;
       reloc_howto_type *howto;
       unsigned long r_symndx;
       struct elf_link_hash_entry *h;
@@ -1601,13 +1867,14 @@ elf64_x86_64_relocate_section (output_bfd, info, input_bfd, input_section,
       bfd_vma relocation;
       boolean unresolved_reloc;
       bfd_reloc_status_type r;
+      int tls_type;
 
       r_type = ELF64_R_TYPE (rel->r_info);
       if (r_type == (int) R_X86_64_GNU_VTINHERIT
          || r_type == (int) R_X86_64_GNU_VTENTRY)
        continue;
 
-      if (r_type < 0 || r_type >= R_X86_64_max)
+      if (r_type >= R_X86_64_max)
        {
          bfd_set_error (bfd_error_bad_value);
          return false;
@@ -1933,6 +2200,313 @@ elf64_x86_64_relocate_section (output_bfd, info, input_bfd, input_section,
 
          break;
 
+       case R_X86_64_TLSGD:
+       case R_X86_64_GOTTPOFF:
+         r_type = elf64_x86_64_tls_transition (info, r_type, h == NULL);
+         tls_type = GOT_UNKNOWN;
+         if (h == NULL && local_got_offsets)
+           tls_type = elf64_x86_64_local_got_tls_type (input_bfd) [r_symndx];
+         else if (h != NULL)
+           {
+             tls_type = elf64_x86_64_hash_entry (h)->tls_type;
+             if (!info->shared && h->dynindx == -1 && tls_type == GOT_TLS_IE)
+               r_type = R_X86_64_TPOFF32;
+           }
+         if (r_type == R_X86_64_TLSGD)
+           {
+             if (tls_type == GOT_TLS_IE)
+               r_type = R_X86_64_GOTTPOFF;
+           }
+
+         if (r_type == R_X86_64_TPOFF32)
+           {
+             BFD_ASSERT (! unresolved_reloc);
+             if (ELF64_R_TYPE (rel->r_info) == R_X86_64_TLSGD)
+               {
+                 unsigned int i;
+                 static unsigned char tlsgd[7]
+                   = { 0x66, 0x66, 0x66, 0x66, 0x48, 0x8d, 0x3d };
+
+                 /* GD->LE transition.
+                    .long 0x66666666; leaq foo@tlsgd(%rip), %rdi
+                    callq __tls_get_addr@plt
+                    Change it into:
+                    movq %fs:0, %rax
+                    leaq foo@tpoff(%rax), %rax */
+                 BFD_ASSERT (rel->r_offset >= 7);
+                 for (i = 0; i < 7; i++)
+                   BFD_ASSERT (bfd_get_8 (input_bfd,
+                                          contents + rel->r_offset - 7 + i)
+                               == tlsgd[i]);
+                 BFD_ASSERT (rel->r_offset + 9 <= input_section->_raw_size);
+                 BFD_ASSERT (bfd_get_8 (input_bfd,
+                                        contents + rel->r_offset + 4)
+                             == 0xe8);
+                 BFD_ASSERT (rel + 1 < relend);
+                 BFD_ASSERT (ELF64_R_TYPE (rel[1].r_info) == R_X86_64_PLT32);
+                 memcpy (contents + rel->r_offset - 7,
+                         "\x64\x48\x8b\x04\x25\0\0\0\0\x48\x8d\x80\0\0\0",
+                         16);
+                 bfd_put_32 (output_bfd, tpoff (info, relocation),
+                             contents + rel->r_offset + 5);
+                 /* Skip R_X86_64_PLT32.  */
+                 rel++;
+                 continue;
+               }
+             else
+               {
+                 unsigned int val, type, reg;
+
+                 /* IE->LE transition:
+                    Originally it can be one of:
+                    movq foo@gottpoff(%rip), %reg
+                    addq foo@gottpoff(%rip), %reg
+                    We change it into:
+                    movq $foo, %reg
+                    leaq foo(%reg), %reg
+                    addq $foo, %reg.  */
+                 BFD_ASSERT (rel->r_offset >= 3);
+                 val = bfd_get_8 (input_bfd, contents + rel->r_offset - 3);
+                 BFD_ASSERT (val == 0x48 || val == 0x4c);
+                 type = bfd_get_8 (input_bfd, contents + rel->r_offset - 2);
+                 BFD_ASSERT (type == 0x8b || type == 0x03);
+                 reg = bfd_get_8 (input_bfd, contents + rel->r_offset - 1);
+                 BFD_ASSERT ((reg & 0xc7) == 5);
+                 reg >>= 3;
+                 BFD_ASSERT (rel->r_offset + 4 <= input_section->_raw_size);
+                 if (type == 0x8b)
+                   {
+                     /* movq */
+                     if (val == 0x4c)
+                       bfd_put_8 (output_bfd, 0x49,
+                                  contents + rel->r_offset - 3);
+                     bfd_put_8 (output_bfd, 0xc7,
+                                contents + rel->r_offset - 2);
+                     bfd_put_8 (output_bfd, 0xc0 | reg,
+                                contents + rel->r_offset - 1);
+                   }
+                 else if (reg == 4)
+                   {
+                     /* addq -> addq - addressing with %rsp/%r12 is
+                        special  */
+                     if (val == 0x4c)
+                       bfd_put_8 (output_bfd, 0x49,
+                                  contents + rel->r_offset - 3);
+                     bfd_put_8 (output_bfd, 0x81,
+                                contents + rel->r_offset - 2);
+                     bfd_put_8 (output_bfd, 0xc0 | reg,
+                                contents + rel->r_offset - 1);
+                   }
+                 else
+                   {
+                     /* addq -> leaq */
+                     if (val == 0x4c)
+                       bfd_put_8 (output_bfd, 0x4d,
+                                  contents + rel->r_offset - 3);
+                     bfd_put_8 (output_bfd, 0x8d,
+                                contents + rel->r_offset - 2);
+                     bfd_put_8 (output_bfd, 0x80 | reg | (reg << 3),
+                                contents + rel->r_offset - 1);
+                   }
+                 bfd_put_32 (output_bfd, tpoff (info, relocation),
+                             contents + rel->r_offset);
+                 continue;
+               }
+           }
+
+         if (htab->sgot == NULL)
+           abort ();
+
+         if (h != NULL)
+           off = h->got.offset;
+         else
+           {
+             if (local_got_offsets == NULL)
+               abort ();
+
+             off = local_got_offsets[r_symndx];
+           }
+
+         if ((off & 1) != 0)
+           off &= ~1;
+          else
+           {
+             Elf_Internal_Rela outrel;
+             Elf64_External_Rela *loc;
+             int dr_type, indx;
+
+             if (htab->srelgot == NULL)
+               abort ();
+
+             outrel.r_offset = (htab->sgot->output_section->vma
+                                + htab->sgot->output_offset + off);
+
+             indx = h && h->dynindx != -1 ? h->dynindx : 0;
+             if (r_type == R_X86_64_TLSGD)
+               dr_type = R_X86_64_DTPMOD64;
+             else
+               dr_type = R_X86_64_TPOFF64;
+
+             bfd_put_64 (output_bfd, 0, htab->sgot->contents + off);
+             outrel.r_addend = 0;
+             if (dr_type == R_X86_64_TPOFF64 && indx == 0)
+               outrel.r_addend = relocation - dtpoff_base (info);
+             outrel.r_info = ELF64_R_INFO (indx, dr_type);
+
+             loc = (Elf64_External_Rela *) htab->srelgot->contents;
+             loc += htab->srelgot->reloc_count++;
+             bfd_elf64_swap_reloca_out (output_bfd, &outrel, loc);
+
+             if (r_type == R_X86_64_TLSGD)
+               {
+                 if (indx == 0)
+                   {
+                     BFD_ASSERT (! unresolved_reloc);
+                     bfd_put_64 (output_bfd,
+                                 relocation - dtpoff_base (info),
+                                 htab->sgot->contents + off + GOT_ENTRY_SIZE);
+                   }
+                 else
+                   {
+                     bfd_put_64 (output_bfd, 0,
+                                 htab->sgot->contents + off + GOT_ENTRY_SIZE);
+                     outrel.r_info = ELF64_R_INFO (indx,
+                                                   R_X86_64_DTPOFF64);
+                     outrel.r_offset += GOT_ENTRY_SIZE;
+                     htab->srelgot->reloc_count++;
+                     loc++;
+                     bfd_elf64_swap_reloca_out (output_bfd, &outrel,
+                                                loc);
+                   }
+               }
+
+             if (h != NULL)
+               h->got.offset |= 1;
+             else
+               local_got_offsets[r_symndx] |= 1;
+           }
+
+         if (off >= (bfd_vma) -2)
+           abort ();
+         if (r_type == ELF64_R_TYPE (rel->r_info))
+           {
+             relocation = htab->sgot->output_section->vma
+                          + htab->sgot->output_offset + off;
+             unresolved_reloc = false;
+           }
+         else
+           {
+             unsigned int i;
+             static unsigned char tlsgd[7]
+               = { 0x66, 0x66, 0x66, 0x66, 0x48, 0x8d, 0x3d };
+
+             /* GD->IE transition.
+                .long 0x66666666; leaq foo@tlsgd(%rip), %rdi
+                callq __tls_get_addr@plt
+                Change it into:
+                movq %fs:0, %rax
+                addq foo@gottpoff(%rip), %rax */
+             BFD_ASSERT (rel->r_offset >= 7);
+             for (i = 0; i < 7; i++)
+               BFD_ASSERT (bfd_get_8 (input_bfd,
+                                      contents + rel->r_offset - 7 + i)
+                           == tlsgd[i]);
+             BFD_ASSERT (rel->r_offset + 9 <= input_section->_raw_size);
+             BFD_ASSERT (bfd_get_8 (input_bfd,
+                                    contents + rel->r_offset + 4)
+                         == 0xe8);
+             BFD_ASSERT (rel + 1 < relend);
+             BFD_ASSERT (ELF64_R_TYPE (rel[1].r_info) == R_X86_64_PLT32);
+             memcpy (contents + rel->r_offset - 7,
+                     "\x64\x48\x8b\x04\x25\0\0\0\0\x48\x03\x05\0\0\0",
+                     16);
+
+             relocation = (htab->sgot->output_section->vma
+                           + htab->sgot->output_offset + off
+                           - rel->r_offset
+                           - input_section->output_section->vma
+                           - input_section->output_offset
+                           - 9);
+             bfd_put_32 (output_bfd, relocation,
+                         contents + rel->r_offset + 5);
+             /* Skip R_X86_64_PLT32.  */
+             rel++;
+             continue;
+           }
+         break;
+
+       case R_X86_64_TLSLD:
+         if (! info->shared)
+           {
+             /* LD->LE transition:
+                Ensure it is:
+                leaq foo@tlsld(%rip), %rdi; call __tls_get_addr@plt.
+                We change it into:
+                .word 0x6666; .byte 0x66; movl %fs:0, %rax.  */
+             BFD_ASSERT (rel->r_offset >= 3);
+             BFD_ASSERT (bfd_get_8 (input_bfd, contents + rel->r_offset - 3)
+                         == 0x48);
+             BFD_ASSERT (bfd_get_8 (input_bfd, contents + rel->r_offset - 2)
+                         == 0x8d);
+             BFD_ASSERT (bfd_get_8 (input_bfd, contents + rel->r_offset - 1)
+                         == 0x3d);
+             BFD_ASSERT (rel->r_offset + 9 <= input_section->_raw_size);
+             BFD_ASSERT (bfd_get_8 (input_bfd, contents + rel->r_offset + 4)
+                         == 0xe8);
+             BFD_ASSERT (rel + 1 < relend);
+             BFD_ASSERT (ELF64_R_TYPE (rel[1].r_info) == R_X86_64_PLT32);
+             memcpy (contents + rel->r_offset - 3,
+                     "\x66\x66\x66\x64\x48\x8b\x04\x25\0\0\0", 12);
+             /* Skip R_X86_64_PLT32.  */
+             rel++;
+             continue;
+           }
+
+         if (htab->sgot == NULL)
+           abort ();
+
+         off = htab->tls_ld_got.offset;
+         if (off & 1)
+           off &= ~1;
+         else
+           {
+             Elf_Internal_Rela outrel;
+             Elf64_External_Rela *loc;
+
+             if (htab->srelgot == NULL)
+               abort ();
+
+             outrel.r_offset = (htab->sgot->output_section->vma
+                                + htab->sgot->output_offset + off);
+
+             bfd_put_64 (output_bfd, 0,
+                         htab->sgot->contents + off);
+             bfd_put_64 (output_bfd, 0,
+                         htab->sgot->contents + off + GOT_ENTRY_SIZE);
+             outrel.r_info = ELF64_R_INFO (0, R_X86_64_DTPMOD64);
+             outrel.r_addend = 0;
+             loc = (Elf64_External_Rela *) htab->srelgot->contents;
+             loc += htab->srelgot->reloc_count++;
+             bfd_elf64_swap_reloca_out (output_bfd, &outrel, loc);
+             htab->tls_ld_got.offset |= 1;
+           }
+         relocation = htab->sgot->output_section->vma
+                      + htab->sgot->output_offset + off;
+         unresolved_reloc = false;
+         break;
+
+       case R_X86_64_DTPOFF32:
+         if (info->shared)
+           relocation -= dtpoff_base (info);
+         else
+           relocation = tpoff (info, relocation);
+         break;
+
+       case R_X86_64_TPOFF32:
+         BFD_ASSERT (! info->shared);
+         relocation = tpoff (info, relocation);
+         break;
+
        default:
          break;
        }
@@ -2087,13 +2661,15 @@ elf64_x86_64_finish_dynamic_symbol (output_bfd, info, h, sym)
        }
     }
 
-  if (h->got.offset != (bfd_vma) -1)
+  if (h->got.offset != (bfd_vma) -1
+      && elf64_x86_64_hash_entry (h)->tls_type != GOT_TLS_GD
+      && elf64_x86_64_hash_entry (h)->tls_type != GOT_TLS_IE)
     {
       Elf_Internal_Rela rela;
       Elf64_External_Rela *loc;
 
       /* This symbol has an entry in the global offset table.  Set it
-         up.  */
+        up.  */
 
       if (htab->sgot == NULL || htab->srelgot == NULL)
        abort ();
@@ -2351,5 +2927,6 @@ elf64_x86_64_finish_dynamic_sections (output_bfd, info)
 #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_object_p               elf64_x86_64_elf_object_p
+#define bfd_elf64_mkobject                 elf64_x86_64_mkobject
 
 #include "elf64-target.h"
index 3971ea6..96e55d7 100644 (file)
@@ -819,6 +819,14 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@",
   "BFD_RELOC_X86_64_RELATIVE",
   "BFD_RELOC_X86_64_GOTPCREL",
   "BFD_RELOC_X86_64_32S",
+  "BFD_RELOC_X86_64_DTPMOD64",
+  "BFD_RELOC_X86_64_DTPOFF64",
+  "BFD_RELOC_X86_64_TPOFF64",
+  "BFD_RELOC_X86_64_TLSGD",
+  "BFD_RELOC_X86_64_TLSLD",
+  "BFD_RELOC_X86_64_DTPOFF32",
+  "BFD_RELOC_X86_64_GOTTPOFF",
+  "BFD_RELOC_X86_64_TPOFF32",
   "BFD_RELOC_NS32K_IMM_8",
   "BFD_RELOC_NS32K_IMM_16",
   "BFD_RELOC_NS32K_IMM_32",
index 504359f..71f1740 100644 (file)
@@ -2165,6 +2165,22 @@ ENUMX
   BFD_RELOC_X86_64_GOTPCREL
 ENUMX
   BFD_RELOC_X86_64_32S
+ENUMX
+  BFD_RELOC_X86_64_DTPMOD64
+ENUMX
+  BFD_RELOC_X86_64_DTPOFF64
+ENUMX
+  BFD_RELOC_X86_64_TPOFF64
+ENUMX
+  BFD_RELOC_X86_64_TLSGD
+ENUMX
+  BFD_RELOC_X86_64_TLSLD
+ENUMX
+  BFD_RELOC_X86_64_DTPOFF32
+ENUMX
+  BFD_RELOC_X86_64_GOTTPOFF
+ENUMX
+  BFD_RELOC_X86_64_TPOFF32
 ENUMDOC
   x86-64/elf relocations
 
index 48b179e..705ef53 100644 (file)
@@ -1,3 +1,13 @@
+2002-09-26  Jakub Jelinek  <jakub@redhat.com>
+
+       * config/tc-i386.c (tc_i386_fix_adjustable): Add x86-64 TLS relocs.
+       Define them if not BFD_ASSEMBLER.
+       (lex_got): Handle @tlsgd, @dtpoff and @tpoff in 64-bit mode, add
+       @tlsld.
+       (md_apply_fix3): No addend for BFD_RELOC_X86_64_TLSGD,
+       BFD_RELOC_X86_64_TLSLD and BFD_RELOC_X86_64_GOTTPOFF.
+       (tc_gen_reloc): Handle x86-64 TLS relocs.
+
 2002-09-27  Alan Modra  <amodra@bigpond.net.au>
 
        * config/tc-avr.c (md_apply_fix3): Reinstate code handling pcrel
index 4db65b8..b91b2bb 100644 (file)
@@ -1235,6 +1235,11 @@ tc_i386_fix_adjustable (fixP)
       || fixP->fx_r_type == BFD_RELOC_X86_64_PLT32
       || fixP->fx_r_type == BFD_RELOC_X86_64_GOT32
       || fixP->fx_r_type == BFD_RELOC_X86_64_GOTPCREL
+      || fixP->fx_r_type == BFD_RELOC_X86_64_TLSGD
+      || fixP->fx_r_type == BFD_RELOC_X86_64_TLSLD
+      || fixP->fx_r_type == BFD_RELOC_X86_64_DTPOFF32
+      || fixP->fx_r_type == BFD_RELOC_X86_64_GOTTPOFF
+      || fixP->fx_r_type == BFD_RELOC_X86_64_TPOFF32
       || fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT
       || fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
     return 0;
@@ -1263,6 +1268,11 @@ tc_i386_fix_adjustable (fixP)
 #define BFD_RELOC_X86_64_PLT32         0
 #define BFD_RELOC_X86_64_GOT32         0
 #define BFD_RELOC_X86_64_GOTPCREL      0
+#define BFD_RELOC_X86_64_TLSGD         0
+#define BFD_RELOC_X86_64_TLSLD         0
+#define BFD_RELOC_X86_64_DTPOFF32      0
+#define BFD_RELOC_X86_64_GOTTPOFF      0
+#define BFD_RELOC_X86_64_TPOFF32       0
 #endif
 
 static int intel_float_operand PARAMS ((const char *mnemonic));
@@ -3484,12 +3494,13 @@ lex_got (reloc, adjust)
     { "PLT",      { BFD_RELOC_386_PLT32,      0, BFD_RELOC_X86_64_PLT32    } },
     { "GOTOFF",   { BFD_RELOC_386_GOTOFF,     0, 0                         } },
     { "GOTPCREL", { 0,                        0, BFD_RELOC_X86_64_GOTPCREL } },
-    { "TLSGD",    { BFD_RELOC_386_TLS_GD,     0, 0                         } },
+    { "TLSGD",    { BFD_RELOC_386_TLS_GD,     0, BFD_RELOC_X86_64_TLSGD    } },
     { "TLSLDM",   { BFD_RELOC_386_TLS_LDM,    0, 0                         } },
-    { "GOTTPOFF", { BFD_RELOC_386_TLS_IE_32,  0, 0                         } },
-    { "TPOFF",    { BFD_RELOC_386_TLS_LE_32,  0, 0                         } },
+    { "TLSLD",    { 0,                        0, BFD_RELOC_X86_64_TLSLD    } },
+    { "GOTTPOFF", { BFD_RELOC_386_TLS_IE_32,  0, BFD_RELOC_X86_64_GOTTPOFF } },
+    { "TPOFF",    { BFD_RELOC_386_TLS_LE_32,  0, BFD_RELOC_X86_64_TPOFF32  } },
     { "NTPOFF",   { BFD_RELOC_386_TLS_LE,     0, 0                         } },
-    { "DTPOFF",   { BFD_RELOC_386_TLS_LDO_32, 0, 0                         } },
+    { "DTPOFF",   { BFD_RELOC_386_TLS_LDO_32, 0, BFD_RELOC_X86_64_DTPOFF32 } },
     { "GOTNTPOFF",{ BFD_RELOC_386_TLS_GOTIE,  0, 0                         } },
     { "INDNTPOFF",{ BFD_RELOC_386_TLS_IE,     0, 0                         } },
     { "GOT",      { BFD_RELOC_386_GOT32,      0, BFD_RELOC_X86_64_GOT32    } }
@@ -4665,6 +4676,9 @@ md_apply_fix3 (fixP, valP, seg)
       case BFD_RELOC_386_TLS_IE:
       case BFD_RELOC_386_TLS_GOTIE:
       case BFD_RELOC_X86_64_GOT32:
+      case BFD_RELOC_X86_64_TLSGD:
+      case BFD_RELOC_X86_64_TLSLD:
+      case BFD_RELOC_X86_64_GOTTPOFF:
        value = 0; /* Fully resolved at runtime.  No addend.  */
        break;
 
@@ -5149,6 +5163,11 @@ tc_gen_reloc (section, fixp)
     case BFD_RELOC_386_TLS_LE_32:
     case BFD_RELOC_386_TLS_LE:
     case BFD_RELOC_X86_64_32S:
+    case BFD_RELOC_X86_64_TLSGD:
+    case BFD_RELOC_X86_64_TLSLD:
+    case BFD_RELOC_X86_64_DTPOFF32:
+    case BFD_RELOC_X86_64_GOTTPOFF:
+    case BFD_RELOC_X86_64_TPOFF32:
     case BFD_RELOC_RVA:
     case BFD_RELOC_VTABLE_ENTRY:
     case BFD_RELOC_VTABLE_INHERIT:
@@ -5226,6 +5245,9 @@ tc_gen_reloc (section, fixp)
          case BFD_RELOC_X86_64_PLT32:
          case BFD_RELOC_X86_64_GOT32:
          case BFD_RELOC_X86_64_GOTPCREL:
+         case BFD_RELOC_X86_64_TLSGD:
+         case BFD_RELOC_X86_64_TLSLD:
+         case BFD_RELOC_X86_64_GOTTPOFF:
            rel->addend = fixp->fx_offset - fixp->fx_size;
            break;
          default:
index 136d8bc..257e381 100644 (file)
@@ -1,3 +1,7 @@
+2002-09-26  Jakub Jelinek  <jakub@redhat.com>
+
+       * elf/x86-64.h: Add TLS relocs.
+
 2002-09-26  Andrew Cagney  <ac131313@redhat.com>
 
        * regs/: Delete directory.
index 74febc2..7e9100d 100644 (file)
@@ -1,5 +1,5 @@
 /* x86_64 ELF support for BFD.
-   Copyright (C) 2000 Free Software Foundation, Inc.
+   Copyright (C) 2000, 2002 Free Software Foundation, Inc.
    Contributed by Jan Hubicka <jh@suse.cz>
 
    This file is part of BFD, the Binary File Descriptor library.
 
 START_RELOC_NUMBERS (elf_x86_64_reloc_type)
      RELOC_NUMBER (R_X86_64_NONE,     0)      /* No reloc */
-     RELOC_NUMBER (R_X86_64_64,               1)      /* Direct 64 bit  */
+     RELOC_NUMBER (R_X86_64_64,       1)      /* Direct 64 bit  */
      RELOC_NUMBER (R_X86_64_PC32,     2)      /* PC relative 32 bit signed */
      RELOC_NUMBER (R_X86_64_GOT32,    3)      /* 32 bit GOT entry */
      RELOC_NUMBER (R_X86_64_PLT32,    4)      /* 32 bit PLT address */
      RELOC_NUMBER (R_X86_64_COPY,     5)      /* Copy symbol at runtime */
      RELOC_NUMBER (R_X86_64_GLOB_DAT, 6)      /* Create GOT entry */
-     RELOC_NUMBER (R_X86_64_JUMP_SLOT,        7)      /* Create PLT entry */
+     RELOC_NUMBER (R_X86_64_JUMP_SLOT,7)      /* Create PLT entry */
      RELOC_NUMBER (R_X86_64_RELATIVE, 8)      /* Adjust by program base */
      RELOC_NUMBER (R_X86_64_GOTPCREL, 9)      /* 32 bit signed pc relative
                                                  offset to GOT */
-     RELOC_NUMBER (R_X86_64_32,               10)     /* Direct 32 bit zero extended */
-     RELOC_NUMBER (R_X86_64_32S,              11)     /* Direct 32 bit sign extended */
-     RELOC_NUMBER (R_X86_64_16,               12)     /* Direct 16 bit zero extended */
+     RELOC_NUMBER (R_X86_64_32,       10)     /* Direct 32 bit zero extended */
+     RELOC_NUMBER (R_X86_64_32S,      11)     /* Direct 32 bit sign extended */
+     RELOC_NUMBER (R_X86_64_16,       12)     /* Direct 16 bit zero extended */
      RELOC_NUMBER (R_X86_64_PC16,     13)     /* 16 bit sign extended pc relative*/
-     RELOC_NUMBER (R_X86_64_8,                14)     /* Direct 8 bit sign extended */
-     RELOC_NUMBER (R_X86_64_PC8,              15)     /* 8 bit sign extended pc relative*/
+     RELOC_NUMBER (R_X86_64_8,        14)     /* Direct 8 bit sign extended */
+     RELOC_NUMBER (R_X86_64_PC8,      15)     /* 8 bit sign extended pc relative*/
+     RELOC_NUMBER (R_X86_64_DTPMOD64, 16)     /* ID of module containing symbol */
+     RELOC_NUMBER (R_X86_64_DTPOFF64, 17)     /* Offset in TLS block */
+     RELOC_NUMBER (R_X86_64_TPOFF64,  18)     /* Offset in initial TLS block */
+     RELOC_NUMBER (R_X86_64_TLSGD,    19)     /* PC relative offset to GD GOT block */
+     RELOC_NUMBER (R_X86_64_TLSLD,    20)     /* PC relative offset to LD GOT block */
+     RELOC_NUMBER (R_X86_64_DTPOFF32, 21)     /* Offset in TLS block */
+     RELOC_NUMBER (R_X86_64_GOTTPOFF, 22)     /* PC relative offset to IE GOT entry */
+     RELOC_NUMBER (R_X86_64_TPOFF32,  23)     /* Offset in initial TLS block */
      RELOC_NUMBER (R_X86_64_GNU_VTINHERIT, 250)       /* GNU C++ hack  */
      RELOC_NUMBER (R_X86_64_GNU_VTENTRY, 251)         /* GNU C++ hack  */
 END_RELOC_NUMBERS (R_X86_64_max)
index ec1aad9..7b830dc 100644 (file)
@@ -1,3 +1,25 @@
+2002-09-27  Jakub Jelinek  <jakub@redhat.com>
+
+       * lib/ld-lib.exp (run_ld_link_tests): Add.
+       * ld-sh/sh64/sh64.exp (run_ld_link_tests, regexp_diff,
+       file_contents): Remove.
+       (sh64tests): Add 6th field to the tests array.
+       * ld-i386/i386.exp (run_ld_link_tests): Remove.
+       * ld-x86-64/x86-64.exp: New.
+       * ld-x86-64/tlsbin.dd: New test.
+       * ld-x86-64/tlsbinpic.s: New test.
+       * ld-x86-64/tlsbin.rd: New test.
+       * ld-x86-64/tlsbin.s: New test.
+       * ld-x86-64/tlsbin.sd: New test.
+       * ld-x86-64/tlsbin.td: New test.
+       * ld-x86-64/tlslib.s: New test.
+       * ld-x86-64/tlspic1.s: New test.
+       * ld-x86-64/tlspic2.s: New test.
+       * ld-x86-64/tlspic.dd: New test.
+       * ld-x86-64/tlspic.rd: New test.
+       * ld-x86-64/tlspic.sd: New test.
+       * ld-x86-64/tlspic.td: New test.
+
 2002-09-21  Alan Modra  <amodra@bigpond.net.au>
 
        * ld-undefined/undefined.exp: Adjust function test.
index 09526f8..4ccb9f6 100644 (file)
@@ -1,5 +1,5 @@
 # Expect script for ld-i386 tests
-#   Copyright (C) 2000, 2001, 2002 Free Software Foundation
+#   Copyright (C) 2002 Free Software Foundation
 #
 # This file is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
@@ -26,11 +26,6 @@ if { !([istarget "i?86-*-elf*"]
     return
 }
 
-# FIXME: This isn't set by testsuite/config/default.exp; make it.
-if ![info exists readelf] then {
-    set readelf [findfile $base_dir/../binutils/readelf]
-}
-
 # List contains test-items with 3 items followed by 2 lists:
 # 0:name 1:ld options 2:assembler options
 # 3:filenames of assembler files 4: action and options. 5: name of output file
@@ -59,126 +54,4 @@ set i386tests {
       {objdump -sj.got tlsnopic.sd}} "libtlsnopic.so"}
 }
 
-# FIXME: Generalize and move this to ld-lib.exp
-
-proc run_ld_link_tests { ldtests } {
-    global ld
-    global as
-    global nm
-    global objdump
-    global readelf
-    global srcdir
-    global subdir
-    global env
-
-    foreach testitem $ldtests {
-       set testname [lindex $testitem 0]
-       set ld_options [lindex $testitem 1]
-       set as_options [lindex $testitem 2]
-       set as_files  [lindex $testitem 3]
-       set actions [lindex $testitem 4]
-       set binfile tmpdir/[lindex $testitem 5]
-       set objfiles {}
-       set is_unresolved 0
-       set failed 0
-
-#      verbose -log "Testname is $testname"
-#      verbose -log "ld_options is $ld_options"
-#      verbose -log "as_options is $as_options"
-#      verbose -log "as_files is $as_files"
-#      verbose -log "actions is $actions"
-#      verbose -log "binfile is $binfile"
-
-       # Assemble each file in the test.
-       foreach as_file $as_files {
-           set objfile "tmpdir/[file rootname $as_file].o"
-           lappend objfiles $objfile
-
-           if ![ld_assemble $as "$as_options $srcdir/$subdir/$as_file" $objfile] {
-               set is_unresolved 1
-               break
-           }
-       }
-
-       # Catch assembler errors.
-       if { $is_unresolved != 0 } {
-           unresolved $testname
-           continue
-       }
-
-       if ![ld_simple_link $ld $binfile "-L$srcdir/$subdir $ld_options $objfiles"] {
-           fail $testname
-       } else {
-           set failed 0
-           foreach actionlist $actions {
-               set action [lindex $actionlist 0]
-               set progopts [lindex $actionlist 1]
-
-               # There are actions where we run regexp_diff on the
-               # output, and there are other actions (presumably).
-               # Handling of the former look the same.
-               set dump_prog ""
-               switch -- $action {
-                   objdump
-                       { set dump_prog $objdump }
-                   nm
-                       { set dump_prog $nm }
-                   readelf
-                       { set dump_prog $readelf }
-                   default
-                       {
-                           perror "Unrecognized action $action"
-                           set is_unresolved 1
-                           break
-                       }
-                   }
-
-               if { $dump_prog != "" } {
-                   set dumpfile [lindex $actionlist 2]
-                   set binary $dump_prog
-
-                   # Ensure consistent sorting of symbols
-                   if {[info exists env(LC_ALL)]} {
-                       set old_lc_all $env(LC_ALL)
-                   }
-                   set env(LC_ALL) "C"
-                   set cmd "$binary $progopts $binfile > dump.out"
-                   send_log "$cmd\n"
-                   catch "exec $cmd" comp_output
-                   if {[info exists old_lc_all]} {
-                       set env(LC_ALL) $old_lc_all
-                   } else {
-                       unset env(LC_ALL)
-                   }
-                   set comp_output [prune_warnings $comp_output]
-
-                   if ![string match "" $comp_output] then {
-                       send_log "$comp_output\n"
-                       set failed 1
-                       break
-                   }
-
-                   if { [regexp_diff "dump.out" "$srcdir/$subdir/$dumpfile"] } then {
-                       verbose "output is [file_contents "dump.out"]" 2
-                       set failed 1
-                       break
-                   }
-               }
-           }
-
-           if { $failed != 0 } {
-               fail $testname
-           } else { if { $is_unresolved == 0 } {
-               pass $testname
-           } }
-       }
-
-       # Catch action errors.
-       if { $is_unresolved != 0 } {
-           unresolved $testname
-           continue
-       }
-    }
-}
-
 run_ld_link_tests $i386tests
index f939441..557542d 100644 (file)
@@ -23,18 +23,14 @@ if ![istarget sh64-*-*] {
     return
 }
 
-# FIXME: This isn't set by testsuite/config/default.exp; make it.
-if ![info exists readelf] then {
-    set readelf [findfile $base_dir/../binutils/readelf]
-}
-
 # List contains test-items with 3 items followed by 2 lists:
 # 0:name 1:ld options 2:assembler options
-# 3:filenames of assembler files 4: action and options.
+# 3:filenames of assembler files 4: action and options. 5: name of output file
 
 # Actions:
 # objdump: Apply objdump options on result.  Compare with regex (last arg).
 # nm: Apply nm options on result.  Compare with regex (last arg).
+# readelf: Apply readelf options on result.  Compare with regex (last arg).
 
 # Note that the contents dump is the same for "inter-file datalabel
 # references, 64-bit ABI" as for 32-bit ABI and ELF so we re-use it.
@@ -42,323 +38,89 @@ if ![info exists readelf] then {
 set sh64tests {
     {"SH64 linking, 64-bit ABI" "-mshelf64"
      "--abi=64" {sh64-1.s sh64-2.s}
-     {{objdump -sr abi64.sd} {objdump -x abi64.xd}}}
+     {{objdump -sr abi64.sd} {objdump -x abi64.xd}} "abi64.bin" }
     {"SH64 linking, 64-bit ABI, -no-expand" "-mshelf64"
      "--abi=64 -no-expand" {sh64-1.s sh64-2.s}
-     {{objdump -sr abixx-noexp.sd}}}
+     {{objdump -sr abixx-noexp.sd}} "abi64-noexp.bin" }
     {"SH64 linking, 32-bit ABI" "-mshelf32"
      "--abi=32" {sh64-1.s sh64-2.s}
-     {{objdump -sr abi32.sd} {objdump -x abi32.xd}}}
+     {{objdump -sr abi32.sd} {objdump -x abi32.xd}} "abi32.bin" }
     {"SH64 linking, 32-bit ABI, -no-expand" "-mshelf32"
      "--abi=32 -no-expand" {sh64-1.s sh64-2.s}
-     {{objdump -sr abixx-noexp.sd}}}
+     {{objdump -sr abixx-noexp.sd}} "abi32-noexp.bin" }
     {"SH64 linking, single multi-ISA object" "-mshelf32"
      "--abi=32" {shmix-1.s}
-     {{objdump -sr mix1.sd} {objdump -x mix1.xd}}}
+     {{objdump -sr mix1.sd} {objdump -x mix1.xd}} "mix1.bin" }
     {"SH64 linking, single multi-ISA object, -no-expand" "-mshelf32"
      "--abi=32 -no-expand" {shmix-1.s}
-     {{objdump -sr mix1-noexp.sd}}}
+     {{objdump -sr mix1-noexp.sd}} "mix1-noexp.bin" }
     {"SH64 linking, two different-ISA objects" "-mshelf32"
      "--abi=32" {shmix-2.s shmix-3.s}
-     {{objdump -sr mix2.sd} {objdump -x mix2.xd}}}
+     {{objdump -sr mix2.sd} {objdump -x mix2.xd}} "mix2.bin" }
     {"SH64 linking, two different-ISA objects, -no-expand" "-mshelf32"
      "--abi=32 -no-expand" {shmix-2.s shmix-3.s}
-     {{objdump -sr mix2-noexp.sd}}}
+     {{objdump -sr mix2-noexp.sd}} "mix2-noexp.bin" }
     {"SH64 linking, single SHcompact" "-mshelf32"
      "--isa=SHcompact" {shcmp-1.s}
-     {{objdump -sr cmpct1.sd} {objdump -x cmpct1.xd}}}
+     {{objdump -sr cmpct1.sd} {objdump -x cmpct1.xd}} "cmpct1.bin" }
     {"SH64 inter-file datalabel references, 64-bit ABI" "-mshelf64"
      "--abi=64" {shdl-1.s shdl-2.s}
-     {{objdump -sr shdl64.sd} {objdump -x shdl64.xd}}}
+     {{objdump -sr shdl64.sd} {objdump -x shdl64.xd}} "shdl64.bin" }
     {"SH64 inter-file datalabel references, 32-bit ABI" "-mshelf32"
      "--abi=32" {shdl-1.s shdl-2.s}
-     {{objdump -sr shdl64.sd} {objdump -x shdl32.xd}}}
+     {{objdump -sr shdl64.sd} {objdump -x shdl32.xd}} "shdl32.bin" }
     {"SH64 inter-file datalabel references and gc-sections, 32-bit ABI" "-mshelf32 --gc-sections"
      "--abi=32" {dlsection-1.s }
-     {{objdump -sr dlsection.sd}}}
+     {{objdump -sr dlsection.sd}} "dlsection32.bin" }
     {"SH64 inter-file datalabel references and gc-sections, 64-bit ABI" "-mshelf64 --gc-sections"
      "--abi=64" {dlsection-1.s }
-     {{objdump -sr dlsection.sd}}}
+     {{objdump -sr dlsection.sd}} "dlsection64.bin" }
     {"SH64 simple partial linking, 32-bit ABI" "-mshelf32 -r"
      "--abi=32" {rel-1.s rel-2.s}
-     {{objdump -sx rel32.xd}}}
+     {{objdump -sx rel32.xd}} "rel32.bin" }
     {"SH64 simple partial linking, 64-bit ABI" "-mshelf64 -r"
      "--abi=64" {rel-1.s rel-2.s}
-     {{objdump -sx rel64.xd}}}
+     {{objdump -sx rel64.xd}} "rel64.bin" }
     {"SH64 partial linking with datalabel references, 32-bit ABI" "-mshelf32 -r"
      "--abi=32" {reldl-1.s reldl-2.s}
-     {{readelf {-s -r -x 1 -x 3} reldl32.rd}}}
+     {{readelf {-s -r -x 1 -x 3} reldl32.rd}} "reldl32.bin" }
     {"SH64 partial linking with datalabel references, 64-bit ABI" "-mshelf64 -r"
      "--abi=64" {reldl-1.s reldl-2.s}
-     {{readelf {-s -r -x 1 -x 3} reldl64.rd}}}
+     {{readelf {-s -r -x 1 -x 3} reldl64.rd}} "reldl64.bin" }
     {"Handling SH64 assembler-generated .cranges" "-mshelf32"
      "--abi=32" {crange-2a.s crange-1.s}
-     {{readelf {-S -s -r -x 1 -x 2 -x 9} crange1.rd}}}
+     {{readelf {-S -s -r -x 1 -x 2 -x 9} crange1.rd}} "crange1.bin" }
     {"Handling SH64 assembler-generated .cranges, partial linking" "-mshelf32 -r"
      "--abi=32" {crange-2a.s}
-     {{readelf {-S -s -r -x 2 -x 5} crangerel1.rd}}}
+     {{readelf {-S -s -r -x 2 -x 5} crangerel1.rd}} "crangerel1.bin" }
     {"Mixing SH64 assembler-generated with linker-generated .cranges" "-mshelf32"
      "--abi=32" {crange-2a.s crange-2b.s crange-1.s}
-     {{readelf {-S -s -r -x 2 -x 9} crange2.rd}}}
+     {{readelf {-S -s -r -x 2 -x 9} crange2.rd}} "crange2.bin" }
     {"Mixing SH64 assembler-generated with linker-generated .cranges, partial linking"
      "-mshelf32 -r"
      "--abi=32" {crange-2a.s crange-2c.s crange-2d.s crange-2e.s}
-     {{readelf {-S -s -r -x 2 -x 5} crangerel2.rd}}}
+     {{readelf {-S -s -r -x 2 -x 5} crangerel2.rd}} "crangerel2.bin" }
     {"Merge and use of SH64 .cranges, some not originally in order" "-mshelf32"
      "--abi=32"
      {crange-2e.s crange-2f.s crange-2g.s crange-2a.s crange-2d.s crange-2i.s
       crange-2h.s crange-1.s}
-      {{readelf {-S -s -x 2 -x 9} crange3.rd} {objdump -d crange3.dd}}}
+      {{readelf {-S -s -x 2 -x 9} crange3.rd} {objdump -d crange3.dd}} "crange3.bin" }
     {"Sorted SH64 .cranges, entry at SHcompact code" "-mshelf32 --entry diversion"
      "--abi=32"
      {crange-2e.s crange-2f.s crange-2g.s crange-2a.s crange-2d.s crange-2i.s
       crange-2h.s crange-1.s}
-      {{readelf {-h -S -s -x 2 -x 9} crange3-cmpct.rd}}}
+      {{readelf {-h -S -s -x 2 -x 9} crange3-cmpct.rd}} "crange3-cmpct.bin" }
     {"Sorted SH64 .cranges, entry at SHmedia code" "-mshelf32 --entry diversion2"
      "--abi=32"
      {crange-2e.s crange-2f.s crange-2g.s crange-2a.s crange-2d.s crange-2i.s
       crange-2h.s crange-1.s}
-      {{readelf {-h -S -s -x 2 -x 9} crange3-media.rd}}}
+      {{readelf {-h -S -s -x 2 -x 9} crange3-media.rd}} "crange3-media.bin" }
     {"SH64 Big Endianness" "-mshelf64 -Tendian.ld"
      "--abi=64" {endian.s}
-     {{objdump -s endian.sbd} {objdump -d endian.dbd}}}
+     {{objdump -s endian.sbd} {objdump -d endian.dbd}} "endianb.bin" }
     {"SH64 Little Endianness" "-mshlelf64 -Tendian.ld"
      "--abi=64 --little" {endian.s}
-     {{objdump -s endian.sld} {objdump -d endian.dld}}}
-
-}
-
-# FIXME: Generalize and move this to ld-lib.exp
-
-proc run_ld_link_tests { ldtests } {
-    global ld
-    global as
-    global nm
-    global objdump
-    global readelf
-    global srcdir
-    global subdir
-    global env
-
-    set binfile "tmpdir/linked"
-
-    foreach testitem $ldtests {
-       set testname [lindex $testitem 0]
-       set ld_options [lindex $testitem 1]
-       set as_options [lindex $testitem 2]
-       set as_files  [lindex $testitem 3]
-       set actions [lindex $testitem 4]
-       set objfiles {}
-       set is_unresolved 0
-       set failed 0
-
-#      verbose -log "Testname is $testname"
-#      verbose -log "ld_options is $ld_options"
-#      verbose -log "as_options is $as_options"
-#      verbose -log "as_files is $as_files"
-#      verbose -log "actions is $actions"
-
-       # Assemble each file in the test.
-       foreach as_file $as_files {
-           set objfile "tmpdir/[file rootname $as_file].o"
-           lappend objfiles $objfile
-
-           if ![ld_assemble $as "$as_options $srcdir/$subdir/$as_file" $objfile] {
-               set is_unresolved 1
-               break
-           }
-       }
-
-       # Catch assembler errors.
-       if { $is_unresolved != 0 } {
-           unresolved $testname
-           continue
-       }
-
-       if ![ld_simple_link $ld $binfile "-L$srcdir/$subdir $ld_options $objfiles"] {
-           fail $testname
-       } else {
-           set failed 0
-           foreach actionlist $actions {
-               set action [lindex $actionlist 0]
-               set progopts [lindex $actionlist 1]
-
-               # There are actions where we run regexp_diff on the
-               # output, and there are other actions (presumably).
-               # Handling of the former look the same.
-               set dump_prog ""
-               switch -- $action {
-                   objdump
-                       { set dump_prog $objdump }
-                   nm
-                       { set dump_prog $nm }
-                   readelf
-                       { set dump_prog $readelf }
-                   default
-                       {
-                           perror "Unrecognized action $action"
-                           set is_unresolved 1
-                           break
-                       }
-                   }
-
-               if { $dump_prog != "" } {
-                   set dumpfile [lindex $actionlist 2]
-                   set binary $dump_prog
-
-                   # Ensure consistent sorting of symbols
-                   if {[info exists env(LC_ALL)]} {
-                       set old_lc_all $env(LC_ALL)
-                   }
-                   set env(LC_ALL) "C"
-                   set cmd "$binary $progopts $binfile > dump.out"
-                   send_log "$cmd\n"
-                   catch "exec $cmd" comp_output
-                   if {[info exists old_lc_all]} {
-                       set env(LC_ALL) $old_lc_all
-                   } else {
-                       unset env(LC_ALL)
-                   }
-                   set comp_output [prune_warnings $comp_output]
-
-                   if ![string match "" $comp_output] then {
-                       send_log "$comp_output\n"
-                       set failed 1
-                       break
-                   }
-
-                   if { [regexp_diff "dump.out" "$srcdir/$subdir/$dumpfile"] } then {
-                       verbose "output is [file_contents "dump.out"]" 2
-                       set failed 1
-                       break
-                   }
-               }
-           }
-
-           if { $failed != 0 } {
-               fail $testname
-           } else { if { $is_unresolved == 0 } {
-               pass $testname
-           } }
-       }
-
-       # Catch action errors.
-       if { $is_unresolved != 0 } {
-           unresolved $testname
-           continue
-       }
-    }
-}
-
-# FIXME: Move this to ld-lib.exp or higher up.
-
-# regexp_diff, based on simple_diff taken from ld test suite
-#      compares two files line-by-line
-#      file1 contains strings, file2 contains regexps and #-comments
-#      blank lines are ignored in either file
-#      returns non-zero if differences exist
-#
-proc regexp_diff { file_1 file_2 } {
-
-    set eof -1
-    set end_1 0
-    set end_2 0
-    set differences 0
-    set diff_pass 0
-
-    if [file exists $file_1] then {
-       set file_a [open $file_1 r]
-    } else {
-       warning "$file_1 doesn't exist"
-       return 1
-    }
-
-    if [file exists $file_2] then {
-       set file_b [open $file_2 r]
-    } else {
-       fail "$file_2 doesn't exist"
-       close $file_a
-       return 1
-    }
-
-    verbose " Regexp-diff'ing: $file_1 $file_2" 2
-
-    while { 1 } {
-       set line_a ""
-       set line_b ""
-       while { [string length $line_a] == 0 } {
-           if { [gets $file_a line_a] == $eof } {
-               set end_1 1
-               break
-           }
-       }
-       while { [string length $line_b] == 0 || [string match "#*" $line_b] } {
-           if [ string match "#pass" $line_b ] {
-               set end_2 1
-               set diff_pass 1
-               break
-           } elseif [ string match "#..." $line_b ] {
-               if { [gets $file_b line_b] == $eof } {
-                   set end_2 1
-                   break
-               }
-               verbose "looking for \"^$line_b$\"" 3
-               while { ![regexp "^$line_b$" "$line_a"] } {
-                   verbose "skipping    \"$line_a\"" 3
-                   if { [gets $file_a line_a] == $eof } {
-                       set end_1 1
-                       break
-                   }
-               }
-               break
-           }
-           if { [gets $file_b line_b] == $eof } {
-               set end_2 1
-               break
-           }
-       }
-
-        if { $diff_pass } {
-            break
-        } elseif { $end_1 && $end_2 } {
-            break
-        } elseif { $end_1 } {
-            send_log "extra regexps in $file_2 starting with \"^$line_b$\"\nEOF from $file_1\n"
-            verbose "extra regexps in $file_2 starting with \"^$line_b$\"\nEOF from $file_1" 3
-            set differences 1
-            break
-        } elseif { $end_2 } {
-            send_log "extra lines in $file_1 starting with \"^$line_a$\"\nEOF from $file_2\n"
-            verbose "extra lines in $file_1 starting with \"^$line_a$\"\nEOF from $file_2\n" 3
-            set differences 1
-            break
-        } else {
-            verbose "regexp \"^$line_b$\"\nline   \"$line_a\"" 3
-            if ![regexp "^$line_b$" "$line_a"] {
-               send_log "regexp_diff match failure\n"
-               send_log "regexp \"^$line_b$\"\nline   \"$line_a\"\n"
-               set differences 1
-            }
-        }
-    }
-
-    if { $differences == 0 && !$diff_pass && [eof $file_a] != [eof $file_b] } {
-       send_log "$file_1 and $file_2 are different lengths\n"
-       verbose "$file_1 and $file_2 are different lengths" 3
-       set differences 1
-    }
-
-    close $file_a
-    close $file_b
-
-    return $differences
-}
-
-proc file_contents { filename } {
-    set file [open $filename r]
-    set contents [read $file]
-    close $file
-    return $contents
+     {{objdump -s endian.sld} {objdump -d endian.dld}} "endinanl.bin" }
 }
 
 run_ld_link_tests $sh64tests
diff --git a/ld/testsuite/ld-x86-64/tlsbin.dd b/ld/testsuite/ld-x86-64/tlsbin.dd
new file mode 100644 (file)
index 0000000..288b2cd
--- /dev/null
@@ -0,0 +1,310 @@
+#source: tlsbinpic.s
+#source: tlsbin.s
+#as: --64
+#ld: -shared -melf_x86_64
+#objdump: -drj.text
+#target: x86_64-*-*
+
+# PT_TLS layout is:
+# Offset from   Offset from     Name
+# TCB base      TCB end
+# 0x00          -0xa0           sg1..sg8
+# 0x20          -0x80           sl1..sl8
+# 0x40          -0x60           sh1..sh8
+# 0x60          -0x40           bg1..bg8
+# 0x80          -0x20           bl1..bl8
+
+.*: +file format elf64-x86-64
+
+Disassembly of section .text:
+
+0+401000 <fn2>:
+  401000:      55[     ]+push   %rbp
+  401001:      48 89 e5[       ]+mov    %rsp,%rbp
+#  GD -> IE because variable is not defined in executable
+  401004:      64 48 8b 04 25 00 00[   ]+mov    %fs:0x0,%rax
+  40100b:      00 00 *
+  40100d:      48 03 05 c4 11 10 00[   ]+add    1053124\(%rip\),%rax +# 5021d8 <_GLOBAL_OFFSET_TABLE_\+0x38>
+#                              -> R_X86_64_TPOFF64     sG1
+  401014:      90[     ]+nop *
+  401015:      90[     ]+nop *
+  401016:      90[     ]+nop *
+  401017:      90[     ]+nop *
+#  GD -> IE because variable is not defined in executable where
+#  the variable is referenced through IE too
+  401018:      64 48 8b 04 25 00 00[   ]+mov    %fs:0x0,%rax
+  40101f:      00 00 *
+  401021:      48 03 05 a0 11 10 00[   ]+add    1053088\(%rip\),%rax +# 5021c8 <_GLOBAL_OFFSET_TABLE_\+0x28>
+#                              -> R_X86_64_TPOFF64     sG2
+  401028:      90[     ]+nop *
+  401029:      90[     ]+nop *
+  40102a:      90[     ]+nop *
+  40102b:      90[     ]+nop *
+#  GD -> LE with global variable defined in executable
+  40102c:      64 48 8b 04 25 00 00[   ]+mov    %fs:0x0,%rax
+  401033:      00 00 *
+  401035:      48 8d 80 60 ff ff ff[   ]+lea    0xf+60\(%rax\),%rax
+#                                                      sg1
+  40103c:      90[     ]+nop *
+  40103d:      90[     ]+nop *
+  40103e:      90[     ]+nop *
+  40103f:      90[     ]+nop *
+#  GD -> LE with local variable defined in executable
+  401040:      64 48 8b 04 25 00 00[   ]+mov    %fs:0x0,%rax
+  401047:      00 00 *
+  401049:      48 8d 80 80 ff ff ff[   ]+lea    0xf+80\(%rax\),%rax
+#                                                      sl1
+  401050:      90[     ]+nop *
+  401051:      90[     ]+nop *
+  401052:      90[     ]+nop *
+  401053:      90[     ]+nop *
+#  GD -> LE with hidden variable defined in executable
+  401054:      64 48 8b 04 25 00 00[   ]+mov    %fs:0x0,%rax
+  40105b:      00 00 *
+  40105d:      48 8d 80 a0 ff ff ff[   ]+lea    0xf+a0\(%rax\),%rax
+#                                                      sh1
+  401064:      90[     ]+nop *
+  401065:      90[     ]+nop *
+  401066:      90[     ]+nop *
+  401067:      90[     ]+nop *
+#  LD
+  401068:      66 66 66 64 48 8b 04[   ]+mov    %fs:0x0,%rax
+  40106f:      25 00 00 00 00 *
+  401074:      90[     ]+nop *
+  401075:      90[     ]+nop *
+  401076:      48 8d 90 81 ff ff ff[   ]+lea    0xf+81\(%rax\),%rdx
+#                                                      sl1+1
+  40107d:      90[     ]+nop *
+  40107e:      90[     ]+nop *
+  40107f:      4c 8d 88 86 ff ff ff[   ]+lea    0xf+86\(%rax\),%r9
+#                                                      sl2+2
+  401086:      90[     ]+nop *
+  401087:      90[     ]+nop *
+  401088:      90[     ]+nop *
+  401089:      90[     ]+nop *
+#  LD against hidden variables
+  40108a:      66 66 66 64 48 8b 04[   ]+mov    %fs:0x0,%rax
+  401091:      25 00 00 00 00 *
+  401096:      90[     ]+nop *
+  401097:      90[     ]+nop *
+  401098:      48 8d 90 a0 ff ff ff[   ]+lea    0xf+a0\(%rax\),%rdx
+#                                                      sh1
+  40109f:      90[     ]+nop *
+  4010a0:      90[     ]+nop *
+  4010a1:      48 8d 88 a7 ff ff ff[   ]+lea    0xf+a7\(%rax\),%rcx
+#                                                      sh2+3
+  4010a8:      90[     ]+nop *
+  4010a9:      90[     ]+nop *
+  4010aa:      90[     ]+nop *
+  4010ab:      90[     ]+nop *
+#  IE against global var
+  4010ac:      64 4c 8b 0c 25 00 00[   ]+mov    %fs:0x0,%r9
+  4010b3:      00 00 *
+  4010b5:      90[     ]+nop *
+  4010b6:      90[     ]+nop *
+  4010b7:      4c 03 0d 0a 11 10 00[   ]+add    1052938\(%rip\),%r9 +# 5021c8 <_GLOBAL_OFFSET_TABLE_\+0x28>
+#                              -> R_X86_64_TPOFF64     sG2
+  4010be:      90[     ]+nop *
+  4010bf:      90[     ]+nop *
+  4010c0:      90[     ]+nop *
+  4010c1:      90[     ]+nop *
+#  IE -> LE against global var defined in exec
+  4010c2:      64 4c 8b 14 25 00 00[   ]+mov    %fs:0x0,%r10
+  4010c9:      00 00 *
+  4010cb:      90[     ]+nop *
+  4010cc:      90[     ]+nop *
+  4010cd:      4d 8d 92 60 ff ff ff[   ]+lea    0xf+60\(%r10\),%r10
+#                                                      sg1
+  4010d4:      90[     ]+nop *
+  4010d5:      90[     ]+nop *
+  4010d6:      90[     ]+nop *
+  4010d7:      90[     ]+nop *
+#  IE -> LE against local var
+  4010d8:      64 48 8b 04 25 00 00[   ]+mov    %fs:0x0,%rax
+  4010df:      00 00 *
+  4010e1:      90[     ]+nop *
+  4010e2:      90[     ]+nop *
+  4010e3:      48 8d 80 80 ff ff ff[   ]+lea    0xf+80\(%rax\),%rax
+#                                                      sl1
+  4010ea:      90[     ]+nop *
+  4010eb:      90[     ]+nop *
+  4010ec:      90[     ]+nop *
+  4010ed:      90[     ]+nop *
+#  IE -> LE against hidden var
+  4010ee:      64 48 8b 0c 25 00 00[   ]+mov    %fs:0x0,%rcx
+  4010f5:      00 00 *
+  4010f7:      90[     ]+nop *
+  4010f8:      90[     ]+nop *
+  4010f9:      48 8d 89 a0 ff ff ff[   ]+lea    0xf+a0\(%rcx\),%rcx
+#                                                      sh1
+  401100:      90[     ]+nop *
+  401101:      90[     ]+nop *
+  401102:      90[     ]+nop *
+  401103:      90[     ]+nop *
+#  Direct access through %fs
+#  IE against global var
+  401104:      48 8b 0d b5 10 10 00[   ]+mov    1052853\(%rip\),%rcx +# 5021c0 <_GLOBAL_OFFSET_TABLE_\+0x20>
+#                              -> R_X86_64_TPOFF64     sG5
+  40110b:      90[     ]+nop *
+  40110c:      90[     ]+nop *
+  40110d:      64 48 8b 11[    ]+mov    %fs:\(%rcx\),%rdx
+  401111:      90[     ]+nop *
+  401112:      90[     ]+nop *
+  401113:      90[     ]+nop *
+  401114:      90[     ]+nop *
+#  IE->LE against local var
+  401115:      49 c7 c3 90 ff ff ff[   ]+mov    \$0xf+90,%r11
+#                                                      sl5
+  40111c:      90[     ]+nop *
+  40111d:      90[     ]+nop *
+  40111e:      64 4d 8b 23[    ]+mov    %fs:\(%r11\),%r12
+  401122:      90[     ]+nop *
+  401123:      90[     ]+nop *
+  401124:      90[     ]+nop *
+  401125:      90[     ]+nop *
+#  IE->LE against hidden var
+  401126:      48 c7 c2 b0 ff ff ff[   ]+mov    \$0xf+b0,%rdx
+  40112d:      90[     ]+nop *
+  40112e:      90[     ]+nop *
+  40112f:      64 48 8b 12[    ]+mov    %fs:\(%rdx\),%rdx
+#                                                      sh5
+  401133:      90[     ]+nop *
+  401134:      90[     ]+nop *
+  401135:      90[     ]+nop *
+  401136:      90[     ]+nop *
+  401137:      c9[     ]+leaveq *
+  401138:      c3[     ]+retq *
+  401139:      90[     ]+nop *
+  40113a:      90[     ]+nop *
+  40113b:      90[     ]+nop *
+
+0+40113c <_start>:
+  40113c:      55[     ]+push   %rbp
+  40113d:      48 89 e5[       ]+mov    %rsp,%rbp
+#  IE against global var
+  401140:      64 4c 8b 1c 25 00 00[   ]+mov    %fs:0x0,%r11
+  401147:      00 00 *
+  401149:      90[     ]+nop *
+  40114a:      90[     ]+nop *
+  40114b:      4c 03 1d 7e 10 10 00[   ]+add    1052798\(%rip\),%r11 +# 5021d0 <_GLOBAL_OFFSET_TABLE_\+0x30>
+#                              -> R_X86_64_TPOFF64     sG6
+  401152:      90[     ]+nop *
+  401153:      90[     ]+nop *
+  401154:      90[     ]+nop *
+  401155:      90[     ]+nop *
+#  IE -> LE against global var defined in exec
+  401156:      64 48 8b 14 25 00 00[   ]+mov    %fs:0x0,%rdx
+  40115d:      00 00 *
+  40115f:      90[     ]+nop *
+  401160:      90[     ]+nop *
+  401161:      48 8d 92 d4 ff ff ff[   ]+lea    0xf+d4\(%rdx\),%rdx
+#                                                      bg6
+  401168:      90[     ]+nop *
+  401169:      90[     ]+nop *
+  40116a:      90[     ]+nop *
+  40116b:      90[     ]+nop *
+#  IE -> LE against local var
+  40116c:      64 4c 8b 24 25 00 00[   ]+mov    %fs:0x0,%r12
+  401173:      00 00 *
+  401175:      90[     ]+nop *
+  401176:      90[     ]+nop *
+  401177:      49 81 c4 f4 ff ff ff[   ]+add    \$0xf+f4,%r12
+#                                                      bl6
+  40117e:      90[     ]+nop *
+  40117f:      90[     ]+nop *
+  401180:      90[     ]+nop *
+  401181:      90[     ]+nop *
+#  direct %fs access IE -> LE against local var
+  401182:      48 c7 c2 fc ff ff ff[   ]+mov    \$0xf+fc,%rdx
+#                                                      bl8
+  401189:      90[     ]+nop *
+  40118a:      90[     ]+nop *
+  40118b:      64 48 8b 02[    ]+mov    %fs:\(%rdx\),%rax
+  40118f:      90[     ]+nop *
+  401190:      90[     ]+nop *
+  401191:      90[     ]+nop *
+  401192:      90[     ]+nop *
+#  IE -> LE against hidden but not local var
+  401193:      64 48 8b 14 25 00 00[   ]+mov    %fs:0x0,%rdx
+  40119a:      00 00 *
+  40119c:      90[     ]+nop *
+  40119d:      90[     ]+nop *
+  40119e:      48 8d 92 b4 ff ff ff[   ]+lea    0xf+b4\(%rdx\),%rdx
+#                                                      sh6
+  4011a5:      90[     ]+nop *
+  4011a6:      90[     ]+nop *
+  4011a7:      90[     ]+nop *
+  4011a8:      90[     ]+nop *
+#  direct %fs access IE -> LE against hidden but not local var
+  4011a9:      48 c7 c2 bc ff ff ff[   ]+mov    \$0xf+bc,%rdx
+#                                                      sh8
+  4011b0:      90[     ]+nop *
+  4011b1:      90[     ]+nop *
+  4011b2:      64 48 8b 02[    ]+mov    %fs:\(%rdx\),%rax
+  4011b6:      90[     ]+nop *
+  4011b7:      90[     ]+nop *
+  4011b8:      90[     ]+nop *
+  4011b9:      90[     ]+nop *
+#  LE, global var defined in exec
+  4011ba:      64 48 8b 04 25 00 00[   ]+mov    %fs:0x0,%rax
+  4011c1:      00 00 *
+  4011c3:      90[     ]+nop *
+  4011c4:      90[     ]+nop *
+  4011c5:      48 8d 90 64 ff ff ff[   ]+lea    0xf+64\(%rax\),%rdx
+#                                                      sg2
+  4011cc:      90[     ]+nop *
+  4011cd:      90[     ]+nop *
+  4011ce:      90[     ]+nop *
+  4011cf:      90[     ]+nop *
+#  LE, local var, non-canonical sequence
+  4011d0:      49 c7 c1 e6 ff ff ff[   ]+mov    \$0xf+e6,%r9
+#                                                      bl2+2
+  4011d7:      90[     ]+nop *
+  4011d8:      90[     ]+nop *
+  4011d9:      64 48 8b 14 25 00 00[   ]+mov    %fs:0x0,%rdx
+  4011e0:      00 00 *
+  4011e2:      90[     ]+nop *
+  4011e3:      90[     ]+nop *
+  4011e4:      4c 01 ca[       ]+add    %r9,%rdx
+  4011e7:      90[     ]+nop *
+  4011e8:      90[     ]+nop *
+  4011e9:      90[     ]+nop *
+  4011ea:      90[     ]+nop *
+#  LE, hidden var defined in exec, non-canonical sequence
+  4011eb:      64 48 8b 14 25 00 00[   ]+mov    %fs:0x0,%rdx
+  4011f2:      00 00 *
+  4011f4:      90[     ]+nop *
+  4011f5:      90[     ]+nop *
+  4011f6:      48 81 c2 a5 ff ff ff[   ]+add    \$0xf+a5,%rdx
+#                                                      sh2+1
+  4011fd:      90[     ]+nop *
+  4011fe:      90[     ]+nop *
+  4011ff:      90[     ]+nop *
+  401200:      90[     ]+nop *
+#  Direct %fs access
+#  LE, global var defined in exec
+  401201:      64 48 8b 04 25 68 ff[   ]+mov    %fs:0xf+68,%rax
+  401208:      ff ff *
+#                                                      sg3
+  40120a:      90[     ]+nop *
+  40120b:      90[     ]+nop *
+  40120c:      90[     ]+nop *
+  40120d:      90[     ]+nop *
+#  LE, local var
+  40120e:      64 4c 8b 14 25 eb ff[   ]+mov    %fs:0xf+eb,%r10
+  401215:      ff ff *
+#                                                      bl3+3
+  401217:      90[     ]+nop *
+  401218:      90[     ]+nop *
+  401219:      90[     ]+nop *
+  40121a:      90[     ]+nop *
+#  LE, hidden var defined in exec
+  40121b:      64 48 8b 14 25 a9 ff[   ]+mov    %fs:0xf+a9,%rdx
+  401222:      ff ff *
+#                                                      sh3+1
+  401224:      90[     ]+nop *
+  401225:      90[     ]+nop *
+  401226:      90[     ]+nop *
+  401227:      90[     ]+nop *
+  401228:      c9[     ]+leaveq *
+  401229:      c3[     ]+retq *
diff --git a/ld/testsuite/ld-x86-64/tlsbin.rd b/ld/testsuite/ld-x86-64/tlsbin.rd
new file mode 100644 (file)
index 0000000..9f163d9
--- /dev/null
@@ -0,0 +1,154 @@
+#source: tlsbinpic.s
+#source: tlsbin.s
+#as: --64
+#ld: -shared -melf_x86_64
+#readelf: -WSsrl
+#target: x86_64-*-*
+
+There are 18 section headers, starting at offset 0x[0-9a-f]+:
+
+Section Headers:
+  \[Nr\] Name +Type +Address +Off +Size +ES Flg Lk Inf Al
+  \[ 0\] +NULL +0+ 0+ 0+ 00 +0 +0 +0
+  \[ 1\] .interp +.*
+  \[ 2\] .hash +.*
+  \[ 3\] .dynsym +.*
+  \[ 4\] .dynstr +.*
+  \[ 5\] .rela.dyn +.*
+  \[ 6\] .rela.plt +.*
+  \[ 7\] .plt +.*
+  \[ 8\] .text +PROGBITS +0+401000 0+1000 0+22a 00 +AX +0 +0 +4096
+  \[ 9\] .data +.*
+  \[10\] .tdata +PROGBITS +0+502000 0+2000 0+60 00 WAT +0 +0 +1
+  \[11\] .tbss +NOBITS +0+502060 0+2060 0+40 00 WAT +0 +0 +1
+  \[12\] .dynamic +DYNAMIC +0+502060 0+2060 0+140 10 +WA +4 +0 +8
+  \[13\] .got +PROGBITS +0+5021a0 0+21a0 0+40 08 +WA +0 +0 +8
+  \[14\] .bss +.*
+  \[15\] .shstrtab +.*
+  \[16\] .symtab +.*
+  \[17\] .strtab +.*
+Key to Flags:
+.*
+.*
+.*
+
+Elf file type is EXEC \(Executable file\)
+Entry point 0x40113c
+There are 6 program headers, starting at offset [0-9]+
+
+Program Headers:
+  Type +Offset +VirtAddr +PhysAddr +FileSiz +MemSiz +Flg Align
+  PHDR +0x0+40 0x0+400040 0x0+400040 0x0+150 0x0+150 R E 0x8
+  INTERP +0x0+190 0x0+400190 0x0+400190 0x0+f 0x0+f R +0x1
+.*Requesting program interpreter.*
+  LOAD +0x0+ 0x0+400000 0x0+400000 0x0+122a 0x0+122a R E 0x100000
+  LOAD +0x0+2000 0x0+502000 0x0+502000 0x0+1e0 0x0+1e0 RW  0x100000
+  DYNAMIC +0x0+2060 0x0+502060 0x0+502060 0x0+140 0x0+140 RW  0x8
+  TLS +0x0+2000 0x0+502000 0x0+502000 0x0+60 0x0+a0 R +0x1
+
+ Section to Segment mapping:
+  Segment Sections...
+   00 *
+   01 +.interp *
+   02 +.interp .hash .dynsym .dynstr .rela.dyn .rela.plt .plt .text *
+   03 +.tdata .tbss .dynamic .got *
+   04 +.tbss .dynamic *
+   05 +.tdata .tbss *
+
+Relocation section '.rela.dyn' at offset 0x358 contains 4 entries:
+ +Offset +Info +Type +Symbol's Value  Symbol's Name \+ Addend
+0+5021c0  0+100000012 R_X86_64_TPOFF64 +0+ sG5 \+ 0
+0+5021c8  0+300000012 R_X86_64_TPOFF64 +0+ sG2 \+ 0
+0+5021d0  0+600000012 R_X86_64_TPOFF64 +0+ sG6 \+ 0
+0+5021d8  0+700000012 R_X86_64_TPOFF64 +0+ sG1 \+ 0
+
+Relocation section '.rela.plt' at offset 0x3b8 contains 1 entries:
+ +Offset +Info +Type +Symbol's Value  Symbol's Name \+ Addend
+0+[0-9a-f]+  0+400000007 R_X86_64_JUMP_SLOT +0+[0-9a-f]+ __tls_get_addr \+ 0
+
+Symbol table '.dynsym' contains 11 entries:
+ +Num: +Value +Size Type +Bind +Vis +Ndx Name
+ +0: 0+ +0 NOTYPE  LOCAL  DEFAULT  UND *
+ +1: 0+ +0 TLS +GLOBAL DEFAULT  UND sG5
+ +2: 0+502060 +0 OBJECT  GLOBAL DEFAULT  ABS _DYNAMIC
+ +3: 0+ +0 TLS +GLOBAL DEFAULT  UND sG2
+ +4: 0+[0-9a-f]+ +0 FUNC +GLOBAL DEFAULT  UND __tls_get_addr
+ +5: 0+[0-9a-f]+ +0 NOTYPE  GLOBAL DEFAULT  ABS __bss_start
+ +6: 0+ +0 TLS +GLOBAL DEFAULT  UND sG6
+ +7: 0+ +0 TLS +GLOBAL DEFAULT  UND sG1
+ +8: 0+[0-9a-f]+ +0 NOTYPE  GLOBAL DEFAULT  ABS _edata
+ +9: 0+5021a0 +0 OBJECT  GLOBAL DEFAULT  ABS _GLOBAL_OFFSET_TABLE_
+ +10: 0+[0-9a-f]+ +0 NOTYPE  GLOBAL DEFAULT  ABS _end
+
+Symbol table '.symtab' contains 70 entries:
+ +Num: +Value +Size Type +Bind +Vis +Ndx Name
+ +0: 0+ +0 NOTYPE  LOCAL  DEFAULT  UND *
+ +1: [0-9a-f]+ +0 SECTION LOCAL  DEFAULT +1 *
+ +2: [0-9a-f]+ +0 SECTION LOCAL  DEFAULT +2 *
+ +3: [0-9a-f]+ +0 SECTION LOCAL  DEFAULT +3 *
+ +4: [0-9a-f]+ +0 SECTION LOCAL  DEFAULT +4 *
+ +5: [0-9a-f]+ +0 SECTION LOCAL  DEFAULT +5 *
+ +6: [0-9a-f]+ +0 SECTION LOCAL  DEFAULT +6 *
+ +7: [0-9a-f]+ +0 SECTION LOCAL  DEFAULT +7 *
+ +8: [0-9a-f]+ +0 SECTION LOCAL  DEFAULT +8 *
+ +9: [0-9a-f]+ +0 SECTION LOCAL  DEFAULT +9 *
+ +10: [0-9a-f]+ +0 SECTION LOCAL  DEFAULT +10 *
+ +11: [0-9a-f]+ +0 SECTION LOCAL  DEFAULT +11 *
+ +12: [0-9a-f]+ +0 SECTION LOCAL  DEFAULT +12 *
+ +13: [0-9a-f]+ +0 SECTION LOCAL  DEFAULT +13 *
+ +14: [0-9a-f]+ +0 SECTION LOCAL  DEFAULT +14 *
+ +15: [0-9a-f]+ +0 SECTION LOCAL  DEFAULT +15 *
+ +16: [0-9a-f]+ +0 SECTION LOCAL  DEFAULT +16 *
+ +17: [0-9a-f]+ +0 SECTION LOCAL  DEFAULT +17 *
+ +18: 0+20 +0 TLS +LOCAL  DEFAULT +10 sl1
+ +19: 0+24 +0 TLS +LOCAL  DEFAULT +10 sl2
+ +20: 0+28 +0 TLS +LOCAL  DEFAULT +10 sl3
+ +21: 0+2c +0 TLS +LOCAL  DEFAULT +10 sl4
+ +22: 0+30 +0 TLS +LOCAL  DEFAULT +10 sl5
+ +23: 0+34 +0 TLS +LOCAL  DEFAULT +10 sl6
+ +24: 0+38 +0 TLS +LOCAL  DEFAULT +10 sl7
+ +25: 0+3c +0 TLS +LOCAL  DEFAULT +10 sl8
+ +26: 0+80 +0 TLS +LOCAL  DEFAULT +11 bl1
+ +27: 0+84 +0 TLS +LOCAL  DEFAULT +11 bl2
+ +28: 0+88 +0 TLS +LOCAL  DEFAULT +11 bl3
+ +29: 0+8c +0 TLS +LOCAL  DEFAULT +11 bl4
+ +30: 0+90 +0 TLS +LOCAL  DEFAULT +11 bl5
+ +31: 0+94 +0 TLS +LOCAL  DEFAULT +11 bl6
+ +32: 0+98 +0 TLS +LOCAL  DEFAULT +11 bl7
+ +33: 0+9c +0 TLS +LOCAL  DEFAULT +11 bl8
+ +34: 0+1c +0 TLS +GLOBAL DEFAULT +10 sg8
+ +35: 0+7c +0 TLS +GLOBAL DEFAULT +11 bg8
+ +36: 0+74 +0 TLS +GLOBAL DEFAULT +11 bg6
+ +37: 0+ +0 TLS +GLOBAL DEFAULT  UND sG5
+ +38: 0+68 +0 TLS +GLOBAL DEFAULT +11 bg3
+ +39: 0+502060 +0 OBJECT  GLOBAL DEFAULT  ABS _DYNAMIC
+ +40: 0+8 +0 TLS +GLOBAL DEFAULT +10 sg3
+ +41: 0+48 +0 TLS +GLOBAL HIDDEN +10 sh3
+ +42: 0+ +0 TLS +GLOBAL DEFAULT  UND sG2
+ +43: 0+c +0 TLS +GLOBAL DEFAULT +10 sg4
+ +44: 0+10 +0 TLS +GLOBAL DEFAULT +10 sg5
+ +45: 0+70 +0 TLS +GLOBAL DEFAULT +11 bg5
+ +46: [0-9a-f]+ +0 FUNC +GLOBAL DEFAULT  UND __tls_get_addr
+ +47: 0+58 +0 TLS +GLOBAL HIDDEN +10 sh7
+ +48: 0+5c +0 TLS +GLOBAL HIDDEN +10 sh8
+ +49: 0+ +0 TLS +GLOBAL DEFAULT +10 sg1
+ +50: 0+40113c +0 FUNC +GLOBAL DEFAULT +8 _start
+ +51: 0+4c +0 TLS +GLOBAL HIDDEN +10 sh4
+ +52: 0+78 +0 TLS +GLOBAL DEFAULT +11 bg7
+ +53: 0+50 +0 TLS +GLOBAL HIDDEN +10 sh5
+ +54: [0-9a-f]+ +0 NOTYPE  GLOBAL DEFAULT  ABS __bss_start
+ +55: 0+ +0 TLS +GLOBAL DEFAULT  UND sG6
+ +56: 0+401000 +0 FUNC +GLOBAL DEFAULT +8 fn2
+ +57: 0+4 +0 TLS +GLOBAL DEFAULT +10 sg2
+ +58: 0+ +0 TLS +GLOBAL DEFAULT  UND sG1
+ +59: 0+40 +0 TLS +GLOBAL HIDDEN +10 sh1
+ +60: 0+14 +0 TLS +GLOBAL DEFAULT +10 sg6
+ +61: 0+18 +0 TLS +GLOBAL DEFAULT +10 sg7
+ +62: [0-9a-f]+ +0 NOTYPE  GLOBAL DEFAULT  ABS _edata
+ +63: 0+5021a0 +0 OBJECT  GLOBAL DEFAULT  ABS _GLOBAL_OFFSET_TABLE_
+ +64: [0-9a-f]+ +0 NOTYPE  GLOBAL DEFAULT  ABS _end
+ +65: 0+44 +0 TLS +GLOBAL HIDDEN +10 sh2
+ +66: 0+54 +0 TLS +GLOBAL HIDDEN +10 sh6
+ +67: 0+64 +0 TLS +GLOBAL DEFAULT +11 bg2
+ +68: 0+60 +0 TLS +GLOBAL DEFAULT +11 bg1
+ +69: 0+6c +0 TLS +GLOBAL DEFAULT +11 bg4
diff --git a/ld/testsuite/ld-x86-64/tlsbin.s b/ld/testsuite/ld-x86-64/tlsbin.s
new file mode 100644 (file)
index 0000000..eb9bfbc
--- /dev/null
@@ -0,0 +1,97 @@
+       .section ".tbss", "awT", @nobits
+       .globl bg1, bg2, bg3, bg4, bg5, bg6, bg7, bg8
+bg1:   .space 4
+bg2:   .space 4
+bg3:   .space 4
+bg4:   .space 4
+bg5:   .space 4
+bg6:   .space 4
+bg7:   .space 4
+bg8:   .space 4
+bl1:   .space 4
+bl2:   .space 4
+bl3:   .space 4
+bl4:   .space 4
+bl5:   .space 4
+bl6:   .space 4
+bl7:   .space 4
+bl8:   .space 4
+       .text
+       .globl  _start
+       .type   _start,@function
+_start:
+       pushq   %rbp
+       movq    %rsp, %rbp
+
+       /* IE against global var  */
+       movq    %fs:0, %r11
+       nop;nop
+       addq    sG6@gottpoff(%rip), %r11
+       nop;nop;nop;nop
+
+       /* IE -> LE against global var defined in exec  */
+       movq    %fs:0, %rdx
+       nop;nop
+       addq    bg6@gottpoff(%rip), %rdx
+       nop;nop;nop;nop
+
+       /* IE -> LE against local var  */
+       movq    %fs:0, %r12
+       nop;nop
+       addq    bl6@gottpoff(%rip), %r12
+       nop;nop;nop;nop
+
+       /* direct %fs access IE -> LE against local var  */
+       movq    bl8@gottpoff(%rip), %rdx
+       nop;nop
+       movq    %fs:(%rdx), %rax
+       nop;nop;nop;nop
+
+       /* IE -> LE against hidden but not local var  */
+       movq    %fs:0, %rdx
+       nop;nop
+       addq    sh6@gottpoff(%rip), %rdx
+       nop;nop;nop;nop
+
+       /* direct %fs access IE -> LE against hidden but not local var  */
+       movq    sh8@gottpoff(%rip), %rdx
+       nop;nop
+       movq    %fs:(%rdx), %rax
+       nop;nop;nop;nop
+
+       /* LE, global var defined in exec  */
+       movq    %fs:0, %rax
+       nop;nop
+       leaq    sg2@tpoff(%rax), %rdx
+       nop;nop;nop;nop
+
+       /* LE, local var, non-canonical sequence  */
+       movq    $2+bl2@tpoff, %r9
+       nop;nop
+       movq    %fs:0, %rdx
+       nop;nop
+       addq    %r9, %rdx
+       nop;nop;nop;nop
+
+       /* LE, hidden var defined in exec, non-canonical sequence */
+       movq    %fs:0, %rdx
+       nop;nop
+       addq    $sh2@tpoff+1, %rdx
+       nop;nop;nop;nop
+
+       /* Direct %fs access  */
+
+       /* LE, global var defined in exec  */
+       movq    %fs:sg3@tpoff, %rax
+       nop;nop;nop;nop
+
+       /* LE, local var  */
+       movq    %fs:bl3@tpoff+3, %r10
+       nop;nop;nop;nop
+
+       /* LE, hidden var defined in exec  */
+       movq    %fs:1+sh3@tpoff, %rdx
+       nop;nop;nop;nop
+
+       leave
+       ret
diff --git a/ld/testsuite/ld-x86-64/tlsbin.sd b/ld/testsuite/ld-x86-64/tlsbin.sd
new file mode 100644 (file)
index 0000000..d378325
--- /dev/null
@@ -0,0 +1,14 @@
+#source: tlsbinpic.s
+#source: tlsbin.s
+#as: --64
+#ld: -shared -melf_x86_64
+#objdump: -sj.got
+#target: x86_64-*-*
+
+.*: +file format elf64-x86-64
+
+Contents of section .got:
+ 5021a0 [0-9a-f]+ [0-9a-f]+ 00000000 00000000  .*
+ 5021b0 00000000 00000000 [0-9a-f]+ [0-9a-f]+  .*
+ 5021c0 00000000 00000000 00000000 00000000  .*
+ 5021d0 00000000 00000000 00000000 00000000  .*
diff --git a/ld/testsuite/ld-x86-64/tlsbin.td b/ld/testsuite/ld-x86-64/tlsbin.td
new file mode 100644 (file)
index 0000000..f2ba1b4
--- /dev/null
@@ -0,0 +1,16 @@
+#source: tlsbinpic.s
+#source: tlsbin.s
+#as: --64
+#ld: -shared -melf_x86_64
+#objdump: -sj.tdata
+#target: x86_64-*-*
+
+.*: +file format elf64-x86-64
+
+Contents of section .tdata:
+ 502000 11000000 12000000 13000000 14000000  .*
+ 502010 15000000 16000000 17000000 18000000  .*
+ 502020 41000000 42000000 43000000 44000000  .*
+ 502030 45000000 46000000 47000000 48000000  .*
+ 502040 01010000 02010000 03010000 04010000  .*
+ 502050 05010000 06010000 07010000 08010000  .*
diff --git a/ld/testsuite/ld-x86-64/tlsbinpic.s b/ld/testsuite/ld-x86-64/tlsbinpic.s
new file mode 100644 (file)
index 0000000..da6085f
--- /dev/null
@@ -0,0 +1,136 @@
+       /* Force .data aligned to 4K, so that .got very likely gets at
+          0x5021a0 (0x60 bytes .tdata and 0x140 bytes .dynamic)  */
+       .data
+       .balign 4096
+       .section ".tdata", "awT", @progbits
+       .globl sg1, sg2, sg3, sg4, sg5, sg6, sg7, sg8
+       .globl sh1, sh2, sh3, sh4, sh5, sh6, sh7, sh8
+       .hidden sh1, sh2, sh3, sh4, sh5, sh6, sh7, sh8
+sg1:   .long 17
+sg2:   .long 18
+sg3:   .long 19
+sg4:   .long 20
+sg5:   .long 21
+sg6:   .long 22
+sg7:   .long 23
+sg8:   .long 24
+sl1:   .long 65
+sl2:   .long 66
+sl3:   .long 67
+sl4:   .long 68
+sl5:   .long 69
+sl6:   .long 70
+sl7:   .long 71
+sl8:   .long 72
+sh1:   .long 257
+sh2:   .long 258
+sh3:   .long 259
+sh4:   .long 260
+sh5:   .long 261
+sh6:   .long 262
+sh7:   .long 263
+sh8:   .long 264
+       /* Force .text aligned to 4K, so it very likely gets at 0x401000.  */
+       .text
+       .balign 4096
+       .globl  fn2
+       .type   fn2,@function
+fn2:
+       pushq   %rbp
+       movq    %rsp, %rbp
+
+       /* GD -> IE because variable is not defined in executable */
+       .long   0x66666666
+       leaq    sG1@tlsgd(%rip), %rdi
+       call    __tls_get_addr@plt
+       nop;nop;nop;nop
+
+       /* GD -> IE because variable is not defined in executable where
+          the variable is referenced through IE too */
+       .long   0x66666666
+       leaq    sG2@tlsgd(%rip), %rdi
+       call    __tls_get_addr@plt
+       nop;nop;nop;nop
+
+       /* GD -> LE with global variable defined in executable */
+       .long   0x66666666
+       leaq    sg1@tlsgd(%rip), %rdi
+       call    __tls_get_addr@plt
+       nop;nop;nop;nop
+
+       /* GD -> LE with local variable defined in executable */
+       .long   0x66666666
+       leaq    sl1@tlsgd(%rip), %rdi
+       call    __tls_get_addr@plt
+       nop;nop;nop;nop
+
+       /* GD -> LE with hidden variable defined in executable */
+       .long   0x66666666
+       leaq    sh1@tlsgd(%rip), %rdi
+       call    __tls_get_addr@plt
+       nop;nop;nop;nop
+
+       /* LD */
+       leaq    sl1@tlsld(%rip), %rdi
+       call    __tls_get_addr@plt
+       nop;nop
+       leaq    1+sl1@dtpoff(%rax), %rdx
+       nop;nop
+       leaq    sl2@dtpoff+2(%rax), %r9
+       nop;nop;nop;nop
+
+       /* LD against hidden variables */
+       leaq    sh1@tlsld(%rip), %rdi
+       call    __tls_get_addr@plt
+       nop;nop
+       leaq    sh1@dtpoff(%rax), %rdx
+       nop;nop
+       leaq    3+sh2@dtpoff(%rax), %rcx
+       nop;nop;nop;nop
+
+       /* IE against global var  */
+       movq    %fs:0, %r9
+       nop;nop
+       addq    sG2@gottpoff(%rip), %r9
+       nop;nop;nop;nop
+
+       /* IE -> LE against global var defined in exec */
+       movq    %fs:0, %r10
+       nop;nop
+       addq    sg1@gottpoff(%rip), %r10
+       nop;nop;nop;nop
+
+       /* IE -> LE against local var */
+       movq    %fs:0, %rax
+       nop;nop
+       addq    sl1@gottpoff(%rip), %rax
+       nop;nop;nop;nop
+
+       /* IE -> LE against hidden var */
+       movq    %fs:0, %rcx
+       nop;nop
+       addq    sh1@gottpoff(%rip), %rcx
+       nop;nop;nop;nop
+
+       /* Direct access through %fs  */
+
+       /* IE against global var  */
+       movq    sG5@gottpoff(%rip), %rcx
+       nop;nop
+       movq    %fs:(%rcx), %rdx
+       nop;nop;nop;nop
+
+       /* IE->LE against local var  */
+       movq    sl5@gottpoff(%rip), %r11
+       nop;nop
+       movq    %fs:(%r11), %r12
+       nop;nop;nop;nop
+
+       /* IE->LE against hidden var  */
+       movq    sh5@gottpoff(%rip), %rdx
+       nop;nop
+       movq    %fs:(%rdx), %rdx
+       nop;nop;nop;nop
+
+       leave
+       ret
diff --git a/ld/testsuite/ld-x86-64/tlslib.s b/ld/testsuite/ld-x86-64/tlslib.s
new file mode 100644 (file)
index 0000000..9eccc08
--- /dev/null
@@ -0,0 +1,18 @@
+       .section ".tdata", "awT", @progbits
+       .globl sG1, sG2, sG3, sG4, sG5, sG6, sG7, sG8
+sG1:   .long 513
+sG2:   .long 514
+sG3:   .long 515
+sG4:   .long 516
+sG5:   .long 517
+sG6:   .long 518
+sG7:   .long 519
+sG8:   .long 520
+
+       .text
+       /* Dummy.  */
+       .globl __tls_get_addr
+       .type   __tls_get_addr,@function
+__tls_get_addr:
+       movq    %rdi, %rax
+       ret
diff --git a/ld/testsuite/ld-x86-64/tlspic.dd b/ld/testsuite/ld-x86-64/tlspic.dd
new file mode 100644 (file)
index 0000000..8c0909a
--- /dev/null
@@ -0,0 +1,226 @@
+#source: tlspic1.s
+#source: tlspic2.s
+#as: --64
+#ld: -shared -melf_x86_64
+#objdump: -drj.text
+#target: x86_64-*-*
+
+.*: +file format elf64-x86-64
+
+Disassembly of section .text:
+
+0+1000 <fn1>:
+ +1000:        55[     ]+push   %rbp
+ +1001:        48 89 e5[       ]+mov    %rsp,%rbp
+ +1004:        90[     ]+nop *
+ +1005:        90[     ]+nop *
+ +1006:        90[     ]+nop *
+ +1007:        90[     ]+nop *
+#  GD
+ +1008:        66 66 66 66 48 8d 3d[   ]+lea    1053165\(%rip\),%rdi +# 102200 <_GLOBAL_OFFSET_TABLE_\+0x70>
+ +100f:        ed 11 10 00 *
+#                              -> R_X86_64_DTPMOD64    sg1
+ +1013:        e8 68 f6 ff ff[         ]+callq  [0-9a-f]+ <.*>
+#                              -> R_X86_64_JUMP_SLOT   __tls_get_addr
+ +1018:        90[     ]+nop *
+ +1019:        90[     ]+nop *
+ +101a:        90[     ]+nop *
+ +101b:        90[     ]+nop *
+#  GD -> IE because variable is referenced through IE too
+ +101c:        64 48 8b 04 25 00 00[   ]+mov    %fs:0x0,%rax
+ +1023:        00 00 *
+ +1025:        48 03 05 f4 11 10 00[   ]+add    1053172\(%rip\),%rax +# 102220 <_GLOBAL_OFFSET_TABLE_\+0x90>
+#                              -> R_X86_64_TPOFF64     sg2
+ +102c:        90[     ]+nop *
+ +102d:        90[     ]+nop *
+ +102e:        90[     ]+nop *
+ +102f:        90[     ]+nop *
+#  GD against local variable
+ +1030:        66 66 66 66 48 8d 3d[   ]+lea    1053045\(%rip\),%rdi +# 1021b0 <_GLOBAL_OFFSET_TABLE_\+0x20>
+ +1037:        75 11 10 00 *
+#                              -> R_X86_64_DTPMOD64    [0 0x2000000000000000]
+ +103b:        e8 40 f6 ff ff[         ]+callq  [0-9a-f]+ <.*>
+#                              -> R_X86_64_JUMP_SLOT   __tls_get_addr
+ +1040:        90[     ]+nop *
+ +1041:        90[     ]+nop *
+ +1042:        90[     ]+nop *
+ +1043:        90[     ]+nop *
+#  GD -> IE against local variable referenced through IE too
+ +1044:        64 48 8b 04 25 00 00[   ]+mov    %fs:0x0,%rax
+ +104b:        00 00 *
+ +104d:        48 03 05 6c 11 10 00[   ]+add    1053036\(%rip\),%rax +# 1021c0 <_GLOBAL_OFFSET_TABLE_\+0x30>
+#                              -> R_X86_64_TPOFF64     *ABS*+0x24
+ +1054:        90[     ]+nop *
+ +1055:        90[     ]+nop *
+ +1056:        90[     ]+nop *
+ +1057:        90[     ]+nop *
+#  GD against hidden and local variable
+ +1058:        66 66 66 66 48 8d 3d[   ]+lea    1053125\(%rip\),%rdi +# 102228 <_GLOBAL_OFFSET_TABLE_\+0x98>
+ +105f:        c5 11 10 00 *
+#                              -> R_X86_64_DTPMOD64    [0 0x4000000000000000]
+ +1063:        e8 18 f6 ff ff[         ]+callq  [0-9a-f]+ <.*>
+#                              -> R_X86_64_JUMP_SLOT   __tls_get_addr
+ +1068:        90[     ]+nop *
+ +1069:        90[     ]+nop *
+ +106a:        90[     ]+nop *
+ +106b:        90[     ]+nop *
+#  GD -> IE against hidden and local variable referenced through IE too
+ +106c:        64 48 8b 04 25 00 00[   ]+mov    %fs:0x0,%rax
+ +1073:        00 00 *
+ +1075:        48 03 05 bc 11 10 00[   ]+add    1053116\(%rip\),%rax +# 102238 <_GLOBAL_OFFSET_TABLE_\+0xa8>
+#                              -> R_X86_64_TPOFF64     *ABS*+0x44
+ +107c:        90[     ]+nop *
+ +107d:        90[     ]+nop *
+ +107e:        90[     ]+nop *
+ +107f:        90[     ]+nop *
+#  GD against hidden but not local variable
+ +1080:        66 66 66 66 48 8d 3d[   ]+lea    1053013\(%rip\),%rdi +# 1021e0 <_GLOBAL_OFFSET_TABLE_\+0x50>
+ +1087:        55 11 10 00 *
+#                              -> R_X86_64_DTPMOD64    [0 0x6000000000000000]
+ +108b:        e8 f0 f5 ff ff[         ]+callq  [0-9a-f]+ <.*>
+#                              -> R_X86_64_JUMP_SLOT   __tls_get_addr
+ +1090:        90[     ]+nop *
+ +1091:        90[     ]+nop *
+ +1092:        90[     ]+nop *
+ +1093:        90[     ]+nop *
+#  GD -> IE against hidden but not local variable referenced through IE too
+ +1094:        64 48 8b 04 25 00 00[   ]+mov    %fs:0x0,%rax
+ +109b:        00 00 *
+ +109d:        48 03 05 4c 11 10 00[   ]+add    1053004\(%rip\),%rax +# 1021f0 <_GLOBAL_OFFSET_TABLE_\+0x60>
+#                              -> R_X86_64_TPOFF64     *ABS*+0x64
+ +10a4:        90[     ]+nop *
+ +10a5:        90[     ]+nop *
+ +10a6:        90[     ]+nop *
+ +10a7:        90[     ]+nop *
+#  LD
+ +10a8:        48 8d 3d 21 11 10 00[   ]+lea    1052961\(%rip\),%rdi +# 1021d0 <_GLOBAL_OFFSET_TABLE_\+0x40>
+#                              -> R_X86_64_DTPMOD64    [0 0x000000000000000]
+ +10af:        e8 cc f5 ff ff[         ]+callq  [0-9a-f]+ <.*>
+#                              -> R_X86_64_JUMP_SLOT   __tls_get_addr
+ +10b4:        90[     ]+nop *
+ +10b5:        90[     ]+nop *
+ +10b6:        48 8d 90 20 00 00 00[   ]+lea    0x20\(%rax\),%rdx
+ +10bd:        90[     ]+nop *
+ +10be:        90[     ]+nop *
+ +10bf:        4c 8d 88 26 00 00 00[   ]+lea    0x26\(%rax\),%r9
+ +10c6:        90[     ]+nop *
+ +10c7:        90[     ]+nop *
+ +10c8:        90[     ]+nop *
+ +10c9:        90[     ]+nop *
+#  LD against hidden and local variables
+ +10ca:        48 8d 3d ff 10 10 00[   ]+lea    1052927\(%rip\),%rdi +# 1021d0 <_GLOBAL_OFFSET_TABLE_\+0x40>
+#                              -> R_X86_64_DTPMOD64    [0 0x000000000000000]
+ +10d1:        e8 aa f5 ff ff[         ]+callq  [0-9a-f]+ <.*>
+#                              -> R_X86_64_JUMP_SLOT   __tls_get_addr
+ +10d6:        90[     ]+nop *
+ +10d7:        90[     ]+nop *
+ +10d8:        48 8d 90 40 00 00 00[   ]+lea    0x40\(%rax\),%rdx
+ +10df:        90[     ]+nop *
+ +10e0:        90[     ]+nop *
+ +10e1:        48 8d 88 47 00 00 00[   ]+lea    0x47\(%rax\),%rcx
+ +10e8:        90[     ]+nop *
+ +10e9:        90[     ]+nop *
+ +10ea:        90[     ]+nop *
+ +10eb:        90[     ]+nop *
+#  LD against hidden but not local variables
+ +10ec:        48 8d 3d dd 10 10 00[   ]+lea    1052893\(%rip\),%rdi +# 1021d0 <_GLOBAL_OFFSET_TABLE_\+0x40>
+#                              -> R_X86_64_DTPMOD64    [0 0x000000000000000]
+ +10f3:        e8 88 f5 ff ff[         ]+callq  [0-9a-f]+ <.*>
+#                              -> R_X86_64_JUMP_SLOT   __tls_get_addr
+ +10f8:        90[     ]+nop *
+ +10f9:        90[     ]+nop *
+ +10fa:        4c 8d a0 60 00 00 00[   ]+lea    0x60\(%rax\),%r12
+ +1101:        90[     ]+nop *
+ +1102:        90[     ]+nop *
+ +1103:        48 8d 88 65 00 00 00[   ]+lea    0x65\(%rax\),%rcx
+ +110a:        90[     ]+nop *
+ +110b:        90[     ]+nop *
+#  IE against global var
+ +110c:        64 48 8b 0c 25 00 00[   ]+mov    %fs:0x0,%rcx
+ +1113:        00 00 *
+ +1115:        90[     ]+nop *
+ +1116:        90[     ]+nop *
+ +1117:        48 03 0d 02 11 10 00[   ]+add    1052930\(%rip\),%rcx +# 102220 <_GLOBAL_OFFSET_TABLE_\+0x90>
+#                              -> R_X86_64_TPOFF64     sg2
+ +111e:        90[     ]+nop *
+ +111f:        90[     ]+nop *
+ +1120:        90[     ]+nop *
+ +1121:        90[     ]+nop *
+#  IE against local var
+ +1122:        64 4c 8b 34 25 00 00[   ]+mov    %fs:0x0,%r14
+ +1129:        00 00 *
+ +112b:        90[     ]+nop *
+ +112c:        90[     ]+nop *
+ +112d:        4c 03 35 8c 10 10 00[   ]+add    1052812\(%rip\),%r14 +# 1021c0 <_GLOBAL_OFFSET_TABLE_\+0x30>
+#                              -> R_X86_64_TPOFF64     *ABS*+0x24
+ +1134:        90[     ]+nop *
+ +1135:        90[     ]+nop *
+ +1136:        90[     ]+nop *
+ +1137:        90[     ]+nop *
+#  IE against hidden and local var
+ +1138:        64 48 8b 0c 25 00 00[   ]+mov    %fs:0x0,%rcx
+ +113f:        00 00 *
+ +1141:        90[     ]+nop *
+ +1142:        90[     ]+nop *
+ +1143:        48 03 0d ee 10 10 00[   ]+add    1052910\(%rip\),%rcx +# 102238 <_GLOBAL_OFFSET_TABLE_\+0xa8>
+#                              -> R_X86_64_TPOFF64     *ABS*+0x44
+ +114a:        90[     ]+nop *
+ +114b:        90[     ]+nop *
+ +114c:        90[     ]+nop *
+ +114d:        90[     ]+nop *
+#  IE against hidden but not local var
+ +114e:        64 48 8b 0c 25 00 00[   ]+mov    %fs:0x0,%rcx
+ +1155:        00 00 *
+ +1157:        90[     ]+nop *
+ +1158:        90[     ]+nop *
+ +1159:        48 03 0d 90 10 10 00[   ]+add    1052816\(%rip\),%rcx +# 1021f0 <_GLOBAL_OFFSET_TABLE_\+0x60>
+#                              -> R_X86_64_TPOFF64     *ABS*+0x64
+ +1160:        90[     ]+nop *
+ +1161:        90[     ]+nop *
+ +1162:        90[     ]+nop *
+ +1163:        90[     ]+nop *
+#  Direct access through %fs
+#  IE against global var
+ +1164:        48 8b 0d 8d 10 10 00[   ]+mov    1052813\(%rip\),%rcx +# 1021f8 <_GLOBAL_OFFSET_TABLE_\+0x68>
+#                              -> R_X86_64_TPOFF64     sg5
+ +116b:        90[     ]+nop *
+ +116c:        90[     ]+nop *
+ +116d:        64 48 8b 11[    ]+mov    %fs:\(%rcx\),%rdx
+ +1171:        90[     ]+nop *
+ +1172:        90[     ]+nop *
+ +1173:        90[     ]+nop *
+ +1174:        90[     ]+nop *
+#  IE against local var
+ +1175:        4c 8b 15 4c 10 10 00[   ]+mov    1052748\(%rip\),%r10 +# 1021c8 <_GLOBAL_OFFSET_TABLE_\+0x38>
+#                              -> R_X86_64_TPOFF64     *ABS*+0x30
+ +117c:        90[     ]+nop *
+ +117d:        90[     ]+nop *
+ +117e:        64 4d 8b 22[    ]+mov    %fs:\(%r10\),%r12
+ +1182:        90[     ]+nop *
+ +1183:        90[     ]+nop *
+ +1184:        90[     ]+nop *
+ +1185:        90[     ]+nop *
+#  IE against hidden and local var
+ +1186:        48 8b 15 83 10 10 00[   ]+mov    1052803\(%rip\),%rdx +# 102210 <_GLOBAL_OFFSET_TABLE_\+0x80>
+#                              -> R_X86_64_TPOFF64     *ABS*+0x50
+ +118d:        90[     ]+nop *
+ +118e:        90[     ]+nop *
+ +118f:        64 48 8b 12[    ]+mov    %fs:\(%rdx\),%rdx
+ +1193:        90[     ]+nop *
+ +1194:        90[     ]+nop *
+ +1195:        90[     ]+nop *
+ +1196:        90[     ]+nop *
+#  IE against hidden but not local var
+ +1197:        48 8b 0d 7a 10 10 00[   ]+mov    1052794\(%rip\),%rcx +# 102218 <_GLOBAL_OFFSET_TABLE_\+0x88>
+#                              -> R_X86_64_TPOFF64     *ABS*+0x70
+ +119e:        90[     ]+nop *
+ +119f:        90[     ]+nop *
+ +11a0:        64 48 8b 11[    ]+mov    %fs:\(%rcx\),%rdx
+ +11a4:        90[     ]+nop *
+ +11a5:        90[     ]+nop *
+ +11a6:        90[     ]+nop *
+ +11a7:        90[     ]+nop *
+ +11a8:        c9[     ]+leaveq *
+ +11a9:        c3[     ]+retq *
+ +11aa:        90[     ]+nop *
+ +11ab:        90[     ]+nop *
diff --git a/ld/testsuite/ld-x86-64/tlspic.rd b/ld/testsuite/ld-x86-64/tlspic.rd
new file mode 100644 (file)
index 0000000..d8190db
--- /dev/null
@@ -0,0 +1,162 @@
+#source: tlspic1.s
+#source: tlspic2.s
+#as: --64
+#ld: -shared -melf_x86_64
+#readelf: -WSsrl
+#target: x86_64-*-*
+
+There are 17 section headers, starting at offset 0x[0-9a-f]+:
+
+Section Headers:
+  \[Nr\] Name +Type +Address +Off +Size +ES Flg Lk Inf Al
+  \[ 0\] +NULL +0+ 0+ 0+ 00 +0 +0 +0
+  \[ 1\] .hash +.*
+  \[ 2\] .dynsym +.*
+  \[ 3\] .dynstr +.*
+  \[ 4\] .rela.dyn +.*
+  \[ 5\] .rela.plt +.*
+  \[ 6\] .plt +.*
+  \[ 7\] .text +PROGBITS +0+1000 0+1000 0+1ac 00 +AX +0 +0 4096
+  \[ 8\] .data +.*
+  \[ 9\] .tdata +PROGBITS +0+102000 0+2000 0+60 00 WAT +0 +0 +1
+  \[10\] .tbss +NOBITS +0+102060 0+2060 0+20 00 WAT +0 +0 +1
+  \[11\] .dynamic +DYNAMIC +0+102060 0+2060 0+130 10 +WA +3 +0 +8
+  \[12\] .got +PROGBITS +0+102190 0+2190 0+b0 08 +WA +0 +0 +8
+  \[13\] .bss +.*
+  \[14\] .shstrtab +.*
+  \[15\] .symtab +.*
+  \[16\] .strtab +.*
+Key to Flags:
+.*
+.*
+.*
+
+Elf file type is DYN \(Shared object file\)
+Entry point 0x1000
+There are 4 program headers, starting at offset [0-9]+
+
+Program Headers:
+  Type +Offset +VirtAddr +PhysAddr +FileSiz +MemSiz +Flg Align
+  LOAD +0x0+ 0x0+ 0x0+ 0x[0-9a-f]+ 0x[0-9a-f]+ R E 0x100000
+  LOAD +0x0+2000 0x0+102000 0x0+102000 0x0+240 0x0+240 RW +0x100000
+  DYNAMIC +0x0+2060 0x0+102060 0x0+102060 0x0+130 0x0+130 RW +0x8
+  TLS +0x0+2000 0x0+102000 0x0+102000 0x0+60 0x0+80 R +0x1
+
+ Section to Segment mapping:
+  Segment Sections...
+   00 +.hash .dynsym .dynstr .rela.dyn .rela.plt .plt .text *
+   01 +.tdata .tbss .dynamic .got *
+   02 +.tbss .dynamic *
+   03 +.tdata .tbss *
+
+Relocation section '.rela.dyn' at offset 0x[0-9a-f]+ contains 14 entries:
+ +Offset +Info +Type +Symbol's Value +Symbol's Name \+ Addend
+0+1021b0  0+10 R_X86_64_DTPMOD64 +0+
+0+1021c0  0+12 R_X86_64_TPOFF64 +0+24
+0+1021c8  0+12 R_X86_64_TPOFF64 +0+30
+0+1021d0  0+10 R_X86_64_DTPMOD64 +0+
+0+1021e0  0+10 R_X86_64_DTPMOD64 +0+
+0+1021f0  0+12 R_X86_64_TPOFF64 +0+64
+0+102210  0+12 R_X86_64_TPOFF64 +0+50
+0+102218  0+12 R_X86_64_TPOFF64 +0+70
+0+102228  0+10 R_X86_64_DTPMOD64 +0+
+0+102238  0+12 R_X86_64_TPOFF64 +0+44
+0+1021f8  0+1200000012 R_X86_64_TPOFF64 +0+10 sg5 \+ 0
+0+102200  0+1400000010 R_X86_64_DTPMOD64 +0+ sg1 \+ 0
+0+102208  0+1400000011 R_X86_64_DTPOFF64 +0+ sg1 \+ 0
+0+102220  0+1700000012 R_X86_64_TPOFF64 +0+4 sg2 \+ 0
+
+Relocation section '.rela.plt' at offset 0x658 contains 1 entries:
+ +Offset +Info +Type +Symbol's Value  Symbol's Name \+ Addend
+0+[0-9a-f]+  0+1300000007 R_X86_64_JUMP_SLOT +0+ __tls_get_addr \+ 0
+
+Symbol table '.dynsym' contains 29 entries:
+ +Num: +Value +Size Type +Bind +Vis +Ndx Name
+ +0: 0+ +0 NOTYPE  LOCAL  DEFAULT  UND *
+ +1: [0-9a-f]+ +0 SECTION LOCAL  DEFAULT +1 *
+ +2: [0-9a-f]+ +0 SECTION LOCAL  DEFAULT +2 *
+ +3: [0-9a-f]+ +0 SECTION LOCAL  DEFAULT +3 *
+ +4: [0-9a-f]+ +0 SECTION LOCAL  DEFAULT +4 *
+ +5: [0-9a-f]+ +0 SECTION LOCAL  DEFAULT +5 *
+ +6: [0-9a-f]+ +0 SECTION LOCAL  DEFAULT +6 *
+ +7: [0-9a-f]+ +0 SECTION LOCAL  DEFAULT +7 *
+ +8: [0-9a-f]+ +0 SECTION LOCAL  DEFAULT +8 *
+ +9: [0-9a-f]+ +0 SECTION LOCAL  DEFAULT +9 *
+ +10: [0-9a-f]+ +0 SECTION LOCAL  DEFAULT +10 *
+ +11: [0-9a-f]+ +0 SECTION LOCAL  DEFAULT +11 *
+ +12: [0-9a-f]+ +0 SECTION LOCAL  DEFAULT +12 *
+ +13: [0-9a-f]+ +0 SECTION LOCAL  DEFAULT +13 *
+ +14: 0+1c +0 TLS +GLOBAL DEFAULT +9 sg8
+ +15: 0+102060 +0 OBJECT  GLOBAL DEFAULT  ABS _DYNAMIC
+ +16: 0+8 +0 TLS +GLOBAL DEFAULT +9 sg3
+ +17: 0+c +0 TLS +GLOBAL DEFAULT +9 sg4
+ +18: 0+10 +0 TLS +GLOBAL DEFAULT +9 sg5
+ +19: 0+ +0 NOTYPE  GLOBAL DEFAULT  UND __tls_get_addr
+ +20: 0+ +0 TLS +GLOBAL DEFAULT +9 sg1
+ +21: 0+1000 +0 FUNC +GLOBAL DEFAULT +7 fn1
+ +22: 0+102240 +0 NOTYPE  GLOBAL DEFAULT  ABS __bss_start
+ +23: 0+4 +0 TLS +GLOBAL DEFAULT +9 sg2
+ +24: 0+14 +0 TLS +GLOBAL DEFAULT +9 sg6
+ +25: 0+18 +0 TLS +GLOBAL DEFAULT +9 sg7
+ +26: 0+102240 +0 NOTYPE  GLOBAL DEFAULT  ABS _edata
+ +27: 0+102190 +0 OBJECT  GLOBAL DEFAULT  ABS _GLOBAL_OFFSET_TABLE_
+ +28: 0+102240 +0 NOTYPE  GLOBAL DEFAULT  ABS _end
+
+Symbol table '.symtab' contains 56 entries:
+ +Num: +Value +Size Type +Bind +Vis +Ndx Name
+ +0: 0+ +0 NOTYPE  LOCAL  DEFAULT  UND *
+ +1: [0-9a-f]+ +0 SECTION LOCAL  DEFAULT +1 *
+ +2: [0-9a-f]+ +0 SECTION LOCAL  DEFAULT +2 *
+ +3: [0-9a-f]+ +0 SECTION LOCAL  DEFAULT +3 *
+ +4: [0-9a-f]+ +0 SECTION LOCAL  DEFAULT +4 *
+ +5: [0-9a-f]+ +0 SECTION LOCAL  DEFAULT +5 *
+ +6: [0-9a-f]+ +0 SECTION LOCAL  DEFAULT +6 *
+ +7: [0-9a-f]+ +0 SECTION LOCAL  DEFAULT +7 *
+ +8: [0-9a-f]+ +0 SECTION LOCAL  DEFAULT +8 *
+ +9: [0-9a-f]+ +0 SECTION LOCAL  DEFAULT +9 *
+ +10: [0-9a-f]+ +0 SECTION LOCAL  DEFAULT +10 *
+ +11: [0-9a-f]+ +0 SECTION LOCAL  DEFAULT +11 *
+ +12: [0-9a-f]+ +0 SECTION LOCAL  DEFAULT +12 *
+ +13: [0-9a-f]+ +0 SECTION LOCAL  DEFAULT +13 *
+ +14: [0-9a-f]+ +0 SECTION LOCAL  DEFAULT +14 *
+ +15: [0-9a-f]+ +0 SECTION LOCAL  DEFAULT +15 *
+ +16: [0-9a-f]+ +0 SECTION LOCAL  DEFAULT +16 *
+ +17: 0+20 +0 TLS +LOCAL  DEFAULT +9 sl1
+ +18: 0+24 +0 TLS +LOCAL  DEFAULT +9 sl2
+ +19: 0+28 +0 TLS +LOCAL  DEFAULT +9 sl3
+ +20: 0+2c +0 TLS +LOCAL  DEFAULT +9 sl4
+ +21: 0+30 +0 TLS +LOCAL  DEFAULT +9 sl5
+ +22: 0+34 +0 TLS +LOCAL  DEFAULT +9 sl6
+ +23: 0+38 +0 TLS +LOCAL  DEFAULT +9 sl7
+ +24: 0+3c +0 TLS +LOCAL  DEFAULT +9 sl8
+ +25: 0+60 +0 TLS +LOCAL  HIDDEN +10 sH1
+ +26: 0+48 +0 TLS +LOCAL  HIDDEN +9 sh3
+ +27: 0+64 +0 TLS +LOCAL  HIDDEN +10 sH2
+ +28: 0+78 +0 TLS +LOCAL  HIDDEN +10 sH7
+ +29: 0+58 +0 TLS +LOCAL  HIDDEN +9 sh7
+ +30: 0+5c +0 TLS +LOCAL  HIDDEN +9 sh8
+ +31: 0+6c +0 TLS +LOCAL  HIDDEN +10 sH4
+ +32: 0+4c +0 TLS +LOCAL  HIDDEN +9 sh4
+ +33: 0+68 +0 TLS +LOCAL  HIDDEN +10 sH3
+ +34: 0+50 +0 TLS +LOCAL  HIDDEN +9 sh5
+ +35: 0+70 +0 TLS +LOCAL  HIDDEN +10 sH5
+ +36: 0+74 +0 TLS +LOCAL  HIDDEN +10 sH6
+ +37: 0+7c +0 TLS +LOCAL  HIDDEN +10 sH8
+ +38: 0+40 +0 TLS +LOCAL  HIDDEN +9 sh1
+ +39: 0+44 +0 TLS +LOCAL  HIDDEN +9 sh2
+ +40: 0+54 +0 TLS +LOCAL  HIDDEN +9 sh6
+ +41: 0+1c +0 TLS +GLOBAL DEFAULT +9 sg8
+ +42: 0+102060 +0 OBJECT  GLOBAL DEFAULT  ABS _DYNAMIC
+ +43: 0+8 +0 TLS +GLOBAL DEFAULT +9 sg3
+ +44: 0+c +0 TLS +GLOBAL DEFAULT +9 sg4
+ +45: 0+10 +0 TLS +GLOBAL DEFAULT +9 sg5
+ +46: 0+ +0 NOTYPE  GLOBAL DEFAULT  UND __tls_get_addr
+ +47: 0+ +0 TLS +GLOBAL DEFAULT +9 sg1
+ +48: 0+1000 +0 FUNC +GLOBAL DEFAULT +7 fn1
+ +49: [0-9a-f]+ +0 NOTYPE  GLOBAL DEFAULT  ABS __bss_start
+ +50: 0+4 +0 TLS +GLOBAL DEFAULT +9 sg2
+ +51: 0+14 +0 TLS +GLOBAL DEFAULT +9 sg6
+ +52: 0+18 +0 TLS +GLOBAL DEFAULT +9 sg7
+ +53: [0-9a-f]+ +0 NOTYPE  GLOBAL DEFAULT  ABS _edata
+ +54: 0+102190 +0 OBJECT  GLOBAL DEFAULT  ABS _GLOBAL_OFFSET_TABLE_
+ +55: [0-9a-f]+ +0 NOTYPE  GLOBAL DEFAULT  ABS _end
diff --git a/ld/testsuite/ld-x86-64/tlspic.sd b/ld/testsuite/ld-x86-64/tlspic.sd
new file mode 100644 (file)
index 0000000..a79ebad
--- /dev/null
@@ -0,0 +1,21 @@
+#source: tlspic1.s
+#source: tlspic2.s
+#as: --64
+#ld: -shared -melf_x86_64
+#objdump: -sj.got
+#target: x86_64-*-*
+
+.*: +file format elf64-x86-64
+
+Contents of section .got:
+ 102190 [0-9a-f]+ [0-9a-f]+ 00000000 00000000  .*
+ 1021a0 00000000 00000000 [0-9a-f]+ [0-9a-f]+  .*
+ 1021b0 00000000 00000000 20000000 00000000  .*
+ 1021c0 00000000 00000000 00000000 00000000  .*
+ 1021d0 00000000 00000000 00000000 00000000  .*
+ 1021e0 00000000 00000000 60000000 00000000  .*
+ 1021f0 00000000 00000000 00000000 00000000  .*
+ 102200 00000000 00000000 00000000 00000000  .*
+ 102210 00000000 00000000 00000000 00000000  .*
+ 102220 00000000 00000000 00000000 00000000  .*
+ 102230 40000000 00000000 00000000 00000000  .*
diff --git a/ld/testsuite/ld-x86-64/tlspic.td b/ld/testsuite/ld-x86-64/tlspic.td
new file mode 100644 (file)
index 0000000..18ec846
--- /dev/null
@@ -0,0 +1,16 @@
+#source: tlspic1.s
+#source: tlspic2.s
+#as: --64
+#ld: -shared -melf_x86_64
+#objdump: -sj.tdata
+#target: x86_64-*-*
+
+.*: +file format elf64-x86-64
+
+Contents of section .tdata:
+ 102000 11000000 12000000 13000000 14000000  .*
+ 102010 15000000 16000000 17000000 18000000  .*
+ 102020 41000000 42000000 43000000 44000000  .*
+ 102030 45000000 46000000 47000000 48000000  .*
+ 102040 01010000 02010000 03010000 04010000  .*
+ 102050 05010000 06010000 07010000 08010000  .*
diff --git a/ld/testsuite/ld-x86-64/tlspic1.s b/ld/testsuite/ld-x86-64/tlspic1.s
new file mode 100644 (file)
index 0000000..64ffc3f
--- /dev/null
@@ -0,0 +1,171 @@
+       /* Force .data aligned to 4K, so .got very likely gets at 0x102190
+          (0x60 bytes .tdata and 0x130 bytes .dynamic)  */
+        .data
+        .balign 4096
+       .section ".tdata", "awT", @progbits
+       .globl sg1, sg2, sg3, sg4, sg5, sg6, sg7, sg8
+       .globl sh1, sh2, sh3, sh4, sh5, sh6, sh7, sh8
+       .hidden sh1, sh2, sh3, sh4, sh5, sh6, sh7, sh8
+sg1:   .long 17
+sg2:   .long 18
+sg3:   .long 19
+sg4:   .long 20
+sg5:   .long 21
+sg6:   .long 22
+sg7:   .long 23
+sg8:   .long 24
+sl1:   .long 65
+sl2:   .long 66
+sl3:   .long 67
+sl4:   .long 68
+sl5:   .long 69
+sl6:   .long 70
+sl7:   .long 71
+sl8:   .long 72
+sh1:   .long 257
+sh2:   .long 258
+sh3:   .long 259
+sh4:   .long 260
+sh5:   .long 261
+sh6:   .long 262
+sh7:   .long 263
+sh8:   .long 264
+       /* Force .text aligned to 4K, so it very likely gets at 0x1000.  */
+       .text
+       .balign 4096
+       .globl  fn1
+       .type   fn1,@function
+fn1:
+       pushq   %rbp
+       movq    %rsp, %rbp
+       nop;nop;nop;nop
+
+       /* GD */
+       .long   0x66666666
+       leaq    sg1@tlsgd(%rip), %rdi
+       call    __tls_get_addr@plt
+       nop;nop;nop;nop
+
+       /* GD -> IE because variable is referenced through IE too */
+       .long   0x66666666
+       leaq    sg2@tlsgd(%rip), %rdi
+       call    __tls_get_addr@plt
+       nop;nop;nop;nop
+
+       /* GD against local variable */
+       .long   0x66666666
+       leaq    sl1@tlsgd(%rip), %rdi
+       call    __tls_get_addr@plt
+       nop;nop;nop;nop
+
+       /* GD -> IE against local variable referenced through IE too */
+       .long   0x66666666
+       leaq    sl2@tlsgd(%rip), %rdi
+       call    __tls_get_addr@plt
+       nop;nop;nop;nop
+
+       /* GD against hidden and local variable */
+       .long   0x66666666
+       leaq    sh1@tlsgd(%rip), %rdi
+       call    __tls_get_addr@plt
+       nop;nop;nop;nop
+
+       /* GD -> IE against hidden and local variable referenced through
+          IE too */
+       .long   0x66666666
+       leaq    sh2@tlsgd(%rip), %rdi
+       call    __tls_get_addr@plt
+       nop;nop;nop;nop
+
+       /* GD against hidden but not local variable */
+       .long   0x66666666
+       leaq    sH1@tlsgd(%rip), %rdi
+       call    __tls_get_addr@plt
+       nop;nop;nop;nop
+
+       /* GD -> IE against hidden but not local variable referenced through
+          IE too */
+       .long   0x66666666
+       leaq    sH2@tlsgd(%rip), %rdi
+       call    __tls_get_addr@plt
+       nop;nop;nop;nop
+
+       /* LD */
+       leaq    sl1@tlsld(%rip), %rdi
+       call    __tls_get_addr@plt
+       nop;nop
+       leaq    sl1@dtpoff(%rax), %rdx
+       nop;nop
+       leaq    2+sl2@dtpoff(%rax), %r9
+       nop;nop;nop;nop
+
+       /* LD against hidden and local variables */
+       leaq    sh1@tlsld(%rip), %rdi
+       call    __tls_get_addr@plt
+       nop;nop
+       leaq    sh1@dtpoff(%rax), %rdx
+       nop;nop
+       leaq    sh2@dtpoff+3(%rax), %rcx
+       nop;nop;nop;nop
+
+       /* LD against hidden but not local variables */
+       leaq    sH1@tlsld(%rip), %rdi
+       call    __tls_get_addr@plt
+       nop;nop
+       leaq    sH1@dtpoff(%rax), %r12
+       nop;nop
+       leaq    sH2@dtpoff+1(%rax), %rcx
+       nop;nop
+
+       /* IE against global var  */
+       movq    %fs:0, %rcx
+       nop;nop
+       addq    sg2@gottpoff(%rip), %rcx
+       nop;nop;nop;nop
+
+       /* IE against local var  */
+       movq    %fs:0, %r14
+       nop;nop
+       addq    sl2@gottpoff(%rip), %r14
+       nop;nop;nop;nop
+
+       /* IE against hidden and local var  */
+       movq    %fs:0, %rcx
+       nop;nop
+       addq    sh2@gottpoff(%rip), %rcx
+       nop;nop;nop;nop
+
+       /* IE against hidden but not local var  */
+       movq    %fs:0, %rcx
+       nop;nop
+       addq    sH2@gottpoff(%rip), %rcx
+       nop;nop;nop;nop
+
+       /* Direct access through %fs  */
+
+       /* IE against global var  */
+       movq    sg5@gottpoff(%rip), %rcx
+       nop;nop
+       movq    %fs:(%rcx), %rdx
+       nop;nop;nop;nop
+
+       /* IE against local var  */
+       movq    sl5@gottpoff(%rip), %r10
+       nop;nop
+       movq    %fs:(%r10), %r12
+       nop;nop;nop;nop
+
+       /* IE against hidden and local var  */
+       movq    sh5@gottpoff(%rip), %rdx
+       nop;nop
+       movq    %fs:(%rdx), %rdx
+       nop;nop;nop;nop
+
+       /* IE against hidden but not local var  */
+       movq    sH5@gottpoff(%rip), %rcx
+       nop;nop
+       movq    %fs:(%rcx), %rdx
+       nop;nop;nop;nop
+
+       leave
+       ret
diff --git a/ld/testsuite/ld-x86-64/tlspic2.s b/ld/testsuite/ld-x86-64/tlspic2.s
new file mode 100644 (file)
index 0000000..5513f9b
--- /dev/null
@@ -0,0 +1,11 @@
+       .section ".tbss", "awT", @nobits
+       .globl sH1, sH2, sH3, sH4, sH5, sH6, sH7, sH8
+       .hidden sH1, sH2, sH3, sH4, sH5, sH6, sH7, sH8
+sH1:   .space 4
+sH2:   .space 4
+sH3:   .space 4
+sH4:   .space 4
+sH5:   .space 4
+sH6:   .space 4
+sH7:   .space 4
+sH8:   .space 4
diff --git a/ld/testsuite/ld-x86-64/x86-64.exp b/ld/testsuite/ld-x86-64/x86-64.exp
new file mode 100644 (file)
index 0000000..edfae9a
--- /dev/null
@@ -0,0 +1,51 @@
+# Expect script for ld-x86_64 tests
+#   Copyright (C) 2002 Free Software Foundation
+#
+# This file is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+
+# Test x86_64 linking; all types of relocs.  This tests the assembler and
+# tools like objdump as well as the linker.
+
+if { !([istarget "x86_64-*-elf*"]
+       || [istarget "x86_64-*-linux*"]) } {
+    return
+}
+
+# List contains test-items with 3 items followed by 2 lists:
+# 0:name 1:ld options 2:assembler options
+# 3:filenames of assembler files 4: action and options. 5: name of output file
+
+# Actions:
+# objdump: Apply objdump options on result.  Compare with regex (last arg).
+# nm: Apply nm options on result.  Compare with regex (last arg).
+# readelf: Apply readelf options on result.  Compare with regex (last arg).
+
+set x86_64tests {
+    {"TLS -fpic -shared transitions" "-shared -melf_x86_64"
+     "--64" {tlspic1.s tlspic2.s}
+     {{readelf -WSsrl tlspic.rd} {objdump -drj.text tlspic.dd}
+      {objdump -sj.got tlspic.sd} {objdump -sj.tdata tlspic.td}}
+      "libtlspic.so"}
+    {"Helper shared library" "-shared -melf_x86_64"
+     "--64" {tlslib.s} {} "libtlslib.so"}
+    {"TLS -fpic and -fno-pic exec transitions"
+     "-melf_x86_64 tmpdir/libtlslib.so" "--64" {tlsbinpic.s tlsbin.s}
+     {{readelf -WSsrl tlsbin.rd} {objdump -drj.text tlsbin.dd}
+      {objdump -sj.got tlsbin.sd} {objdump -sj.tdata tlsbin.td}}
+      "tlsbin"}
+}
+
+run_ld_link_tests $x86_64tests
index 356819f..c70cf5b 100644 (file)
@@ -961,6 +961,136 @@ proc file_contents { filename } {
     return $contents
 }
 
+# List contains test-items with 3 items followed by 2 lists:
+# 0:name 1:ld options 2:assembler options
+# 3:filenames of assembler files 4: action and options. 5: name of output file
+
+# Actions:
+# objdump: Apply objdump options on result.  Compare with regex (last arg).
+# nm: Apply nm options on result.  Compare with regex (last arg).
+# readelf: Apply readelf options on result.  Compare with regex (last arg).
+
+proc run_ld_link_tests { ldtests } {
+    global ld
+    global as
+    global nm
+    global objdump
+    global READELF
+    global srcdir
+    global subdir
+    global env
+
+    foreach testitem $ldtests {
+       set testname [lindex $testitem 0]
+       set ld_options [lindex $testitem 1]
+       set as_options [lindex $testitem 2]
+       set as_files  [lindex $testitem 3]
+       set actions [lindex $testitem 4]
+       set binfile tmpdir/[lindex $testitem 5]
+       set objfiles {}
+       set is_unresolved 0
+       set failed 0
+
+#      verbose -log "Testname is $testname"
+#      verbose -log "ld_options is $ld_options"
+#      verbose -log "as_options is $as_options"
+#      verbose -log "as_files is $as_files"
+#      verbose -log "actions is $actions"
+#      verbose -log "binfile is $binfile"
+
+       # Assemble each file in the test.
+       foreach as_file $as_files {
+           set objfile "tmpdir/[file rootname $as_file].o"
+           lappend objfiles $objfile
+
+           if ![ld_assemble $as "$as_options $srcdir/$subdir/$as_file" $objfile] {
+               set is_unresolved 1
+               break
+           }
+       }
+
+       # Catch assembler errors.
+       if { $is_unresolved != 0 } {
+           unresolved $testname
+           continue
+       }
+
+       if ![ld_simple_link $ld $binfile "-L$srcdir/$subdir $ld_options $objfiles"] {
+           fail $testname
+       } else {
+           set failed 0
+           foreach actionlist $actions {
+               set action [lindex $actionlist 0]
+               set progopts [lindex $actionlist 1]
+
+               # There are actions where we run regexp_diff on the
+               # output, and there are other actions (presumably).
+               # Handling of the former look the same.
+               set dump_prog ""
+               switch -- $action {
+                   objdump
+                       { set dump_prog $objdump }
+                   nm
+                       { set dump_prog $nm }
+                   readelf
+                       { set dump_prog $READELF }
+                   default
+                       {
+                           perror "Unrecognized action $action"
+                           set is_unresolved 1
+                           break
+                       }
+                   }
+
+               if { $dump_prog != "" } {
+                   set dumpfile [lindex $actionlist 2]
+                   set binary $dump_prog
+
+                   # Ensure consistent sorting of symbols
+                   if {[info exists env(LC_ALL)]} {
+                       set old_lc_all $env(LC_ALL)
+                   }
+                   set env(LC_ALL) "C"
+                   set cmd "$binary $progopts $binfile > dump.out"
+                   send_log "$cmd\n"
+                   catch "exec $cmd" comp_output
+                   if {[info exists old_lc_all]} {
+                       set env(LC_ALL) $old_lc_all
+                   } else {
+                       unset env(LC_ALL)
+                   }
+                   set comp_output [prune_warnings $comp_output]
+
+                   if ![string match "" $comp_output] then {
+                       send_log "$comp_output\n"
+                       set failed 1
+                       break
+                   }
+
+                   if { [regexp_diff "dump.out" "$srcdir/$subdir/$dumpfile"] } then {
+                       verbose "output is [file_contents "dump.out"]" 2
+                       set failed 1
+                       break
+                   }
+               }
+           }
+
+           if { $failed != 0 } {
+               fail $testname
+           } else { if { $is_unresolved == 0 } {
+               pass $testname
+           } }
+       }
+
+       # Catch action errors.
+       if { $is_unresolved != 0 } {
+           unresolved $testname
+           continue
+       }
+    }
+}
+
+
 proc verbose_eval { expr { level 1 } } {
     global verbose
     if $verbose>$level then { eval verbose "$expr" $level }