aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexandre Oliva <aoliva@redhat.com>2006-01-18 21:07:51 +0000
committerAlexandre Oliva <aoliva@redhat.com>2006-01-18 21:07:51 +0000
commit67a4f2b710581acc83afecff55424af285ecbc28 (patch)
tree2348b4780388dad65c840f222d372edc83a2088e
parentdd942754f0afab07734deed09d168afbc9ffb597 (diff)
downloadgdb-67a4f2b710581acc83afecff55424af285ecbc28.zip
gdb-67a4f2b710581acc83afecff55424af285ecbc28.tar.gz
gdb-67a4f2b710581acc83afecff55424af285ecbc28.tar.bz2
include/elf/ChangeLog:
Introduce TLS descriptors for i386 and x86_64. * common.h (DT_TLSDESC_GOT, DT_TLSDESC_PLT): New. * i386.h (R_386_TLS_GOTDESC, R_386_TLS_DESC_CALL, R_386_TLS_DESC): New. * x86-64.h (R_X86_64_GOTPC32_TLSDESC, R_X86_64_TLSDESC_CALL, R_X86_64_TLSDESC): New. bfd/ChangeLog: Introduce TLS descriptors for i386 and x86_64. * reloc.c (BFD_RELOC_386_TLS_GOTDESC, BFD_RELOC_386_TLS_DESC, BFD_RELOC_386_TLS_DESC_CALL, BFD_RELOC_X86_64_GOTPC32_TLSDESC, BFD_RELOC_X86_64_TLSDESC, BFD_RELOC_X86_64_TLSDESC_CALL): New. * libbfd.h, bfd-in2.h: Rebuilt. * elf32-i386.c (elf_howto_table): New relocations. (R_386_tls): Adjust. (elf_i386_reloc_type_lookup): Map new relocations. (GOT_TLS_GDESC, GOT_TLS_GD_BOTH_P): New macros. (GOT_TLS_GD_P, GOT_TLS_GDESC_P, GOT_TLS_GD_ANY_P): New macros. (struct elf_i386_link_hash_entry): Add tlsdesc_got field. (struct elf_i386_obj_tdata): Add local_tlsdesc_gotent field. (elf_i386_local_tlsdesc_gotent): New macro. (struct elf_i386_link_hash_table): Add sgotplt_jump_table_size. (elf_i386_compute_jump_table_size): New macro. (link_hash_newfunc): Initialize tlsdesc_got. (elf_i386_link_hash_table_create): Set sgotplt_jump_table_size. (elf_i386_tls_transition): Handle R_386_TLS_GOTDESC and R_386_TLS_DESC_CALL. (elf_i386_check_relocs): Likewise. Allocate space for local_tlsdesc_gotent. (elf_i386_gc_sweep_hook): Handle R_386_TLS_GOTDESC and R_386_TLS_DESC_CALL. (allocate_dynrelocs): Count function PLT relocations. Reserve space for TLS descriptors and relocations. (elf_i386_size_dynamic_sections): Reserve space for TLS descriptors and relocations. Set up sgotplt_jump_table_size. Don't zero reloc_count in srelplt. (elf_i386_always_size_sections): New. Set up _TLS_MODULE_BASE_. (elf_i386_relocate_section): Handle R_386_TLS_GOTDESC and R_386_TLS_DESC_CALL. (elf_i386_finish_dynamic_symbol): Use GOT_TLS_GD_ANY_P. (elf_backend_always_size_sections): Define. * elf64-x86-64.c (x86_64_elf_howto): Add R_X86_64_GOTPC32_TLSDESC, R_X86_64_TLSDESC, R_X86_64_TLSDESC_CALL. (R_X86_64_standard): Adjust. (x86_64_reloc_map): Map new relocs. (elf64_x86_64_rtype_to_howto): New, split out of... (elf64_x86_64_info_to_howto): ... this function, and... (elf64_x86_64_reloc_type_lookup): ... use it to map elf_reloc_val. (GOT_TLS_GDESC, GOT_TLS_GD_BOTH_P): New macros. (GOT_TLS_GD_P, GOT_TLS_GDESC_P, GOT_TLS_GD_ANY_P): New macros. (struct elf64_x86_64_link_hash_entry): Add tlsdesc_got field. (struct elf64_x86_64_obj_tdata): Add local_tlsdesc_gotent field. (elf64_x86_64_local_tlsdesc_gotent): New macro. (struct elf64_x86_64_link_hash_table): Add tlsdesc_plt, tlsdesc_got and sgotplt_jump_table_size fields. (elf64_x86_64_compute_jump_table_size): New macro. (link_hash_newfunc): Initialize tlsdesc_got. (elf64_x86_64_link_hash_table_create): Initialize new fields. (elf64_x86_64_tls_transition): Handle R_X86_64_GOTPC32_TLSDESC and R_X86_64_TLSDESC_CALL. (elf64_x86_64_check_relocs): Likewise. Allocate space for local_tlsdesc_gotent. (elf64_x86_64_gc_sweep_hook): Handle R_X86_64_GOTPC32_TLSDESC and R_X86_64_TLSDESC_CALL. (allocate_dynrelocs): Count function PLT relocations. Reserve space for TLS descriptors and relocations. (elf64_x86_64_size_dynamic_sections): Reserve space for TLS descriptors and relocations. Set up sgotplt_jump_table_size, tlsdesc_plt and tlsdesc_got. Make room for them. Don't zero reloc_count in srelplt. Add dynamic entries for DT_TLSDESC_PLT and DT_TLSDESC_GOT. (elf64_x86_64_always_size_sections): New. Set up _TLS_MODULE_BASE_. (elf64_x86_64_relocate_section): Handle R_386_TLS_GOTDESC and R_386_TLS_DESC_CALL. (elf64_x86_64_finish_dynamic_symbol): Use GOT_TLS_GD_ANY_P. (elf64_x86_64_finish_dynamic_sections): Set DT_TLSDESC_PLT and DT_TLSDESC_GOT. Set up TLS descriptor lazy resolver PLT entry. (elf_backend_always_size_sections): Define. binutils/ChangeLog: Introduce TLS descriptors for i386 and x86_64. * readelf.c (get_dynamic_type): Handle DT_TLSDESC_GOT and DT_TLSDESC_PLT. gas/ChangeLog: Introduce TLS descriptors for i386 and x86_64. * config/tc-i386.c (tc_i386_fix_adjustable): Handle BFD_RELOC_386_TLS_GOTDESC, BFD_RELOC_386_TLS_DESC_CALL, BFD_RELOC_X86_64_GOTPC32_TLSDESC, BFD_RELOC_X86_64_TLSDESC_CALL. (optimize_disp): Emit fix up for BFD_RELOC_386_TLS_DESC_CALL and BFD_RELOC_X86_64_TLSDESC_CALL immediately, and clear the displacement bits. (build_modrm_byte): Set up zero modrm for TLS desc calls. (lex_got): Handle @tlsdesc and @tlscall. (md_apply_fix, tc_gen_reloc): Handle the new relocations. ld/testsuite/ChangeLog: Introduce TLS descriptors for i386 and x86_64. * ld-i386/i386.exp: Run on x86_64-*-linux* and amd64-*-linux*. Add new tests. * ld-i386/pcrel16.d: Add -melf_i386. * ld-i386/pcrel8.d: Likewise. * ld-i386/tlsbindesc.dd: New. * ld-i386/tlsbindesc.rd: New. * ld-i386/tlsbindesc.s: New. * ld-i386/tlsbindesc.sd: New. * ld-i386/tlsbindesc.td: New. * ld-i386/tlsdesc.dd: New. * ld-i386/tlsdesc.rd: New. * ld-i386/tlsdesc.s: New. * ld-i386/tlsdesc.sd: New. * ld-i386/tlsdesc.td: New. * ld-i386/tlsgdesc.dd: New. * ld-i386/tlsgdesc.rd: New. * ld-i386/tlsgdesc.s: New. * ld-x86-64/x86-64.exp: Run new tests. * ld-x86-64/tlsbindesc.dd: New. * ld-x86-64/tlsbindesc.rd: New. * ld-x86-64/tlsbindesc.s: New. * ld-x86-64/tlsbindesc.sd: New. * ld-x86-64/tlsbindesc.td: New. * ld-x86-64/tlsdesc.dd: New. * ld-x86-64/tlsdesc.pd: New. * ld-x86-64/tlsdesc.rd: New. * ld-x86-64/tlsdesc.s: New. * ld-x86-64/tlsdesc.sd: New. * ld-x86-64/tlsdesc.td: New. * ld-x86-64/tlsgdesc.dd: New. * ld-x86-64/tlsgdesc.rd: New. * ld-x86-64/tlsgdesc.s: New.
-rw-r--r--bfd/ChangeLog74
-rw-r--r--bfd/bfd-in2.h9
-rw-r--r--bfd/elf32-i386.c434
-rw-r--r--bfd/elf64-x86-64.c540
-rw-r--r--bfd/libbfd.h8
-rw-r--r--bfd/reloc.c14
-rw-r--r--binutils/ChangeLog6
-rw-r--r--binutils/readelf.c2
-rw-r--r--gas/ChangeLog13
-rw-r--r--gas/config/tc-i386.c42
-rw-r--r--include/elf/ChangeLog9
-rw-r--r--include/elf/common.h4
-rw-r--r--include/elf/i386.h7
-rw-r--r--include/elf/x86-64.h11
-rw-r--r--ld/testsuite/ChangeLog36
-rw-r--r--ld/testsuite/ld-i386/i386.exp20
-rw-r--r--ld/testsuite/ld-i386/pcrel16.d3
-rw-r--r--ld/testsuite/ld-i386/pcrel8.d3
-rw-r--r--ld/testsuite/ld-i386/tlsbindesc.dd463
-rw-r--r--ld/testsuite/ld-i386/tlsbindesc.rd154
-rw-r--r--ld/testsuite/ld-i386/tlsbindesc.s167
-rw-r--r--ld/testsuite/ld-i386/tlsbindesc.sd13
-rw-r--r--ld/testsuite/ld-i386/tlsbindesc.td16
-rw-r--r--ld/testsuite/ld-i386/tlsdesc.dd399
-rw-r--r--ld/testsuite/ld-i386/tlsdesc.rd155
-rw-r--r--ld/testsuite/ld-i386/tlsdesc.s276
-rw-r--r--ld/testsuite/ld-i386/tlsdesc.sd20
-rw-r--r--ld/testsuite/ld-i386/tlsdesc.td16
-rw-r--r--ld/testsuite/ld-i386/tlsgdesc.dd158
-rw-r--r--ld/testsuite/ld-i386/tlsgdesc.rd107
-rw-r--r--ld/testsuite/ld-i386/tlsgdesc.s100
-rw-r--r--ld/testsuite/ld-x86-64/tlsbindesc.dd307
-rw-r--r--ld/testsuite/ld-x86-64/tlsbindesc.rd141
-rw-r--r--ld/testsuite/ld-x86-64/tlsbindesc.s128
-rw-r--r--ld/testsuite/ld-x86-64/tlsbindesc.sd12
-rw-r--r--ld/testsuite/ld-x86-64/tlsbindesc.td16
-rw-r--r--ld/testsuite/ld-x86-64/tlsdesc.dd204
-rw-r--r--ld/testsuite/ld-x86-64/tlsdesc.pd26
-rw-r--r--ld/testsuite/ld-x86-64/tlsdesc.rd164
-rw-r--r--ld/testsuite/ld-x86-64/tlsdesc.s157
-rw-r--r--ld/testsuite/ld-x86-64/tlsdesc.sd23
-rw-r--r--ld/testsuite/ld-x86-64/tlsdesc.td16
-rw-r--r--ld/testsuite/ld-x86-64/tlsgdesc.dd167
-rw-r--r--ld/testsuite/ld-x86-64/tlsgdesc.rd107
-rw-r--r--ld/testsuite/ld-x86-64/tlsgdesc.s106
-rw-r--r--ld/testsuite/ld-x86-64/x86-64.exp16
46 files changed, 4756 insertions, 113 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index 3012ba7..fade6a7 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -1,3 +1,77 @@
+2006-01-18 Alexandre Oliva <aoliva@redhat.com>
+
+ Introduce TLS descriptors for i386 and x86_64.
+ * reloc.c (BFD_RELOC_386_TLS_GOTDESC, BFD_RELOC_386_TLS_DESC,
+ BFD_RELOC_386_TLS_DESC_CALL, BFD_RELOC_X86_64_GOTPC32_TLSDESC,
+ BFD_RELOC_X86_64_TLSDESC, BFD_RELOC_X86_64_TLSDESC_CALL): New.
+ * libbfd.h, bfd-in2.h: Rebuilt.
+ * elf32-i386.c (elf_howto_table): New relocations.
+ (R_386_tls): Adjust.
+ (elf_i386_reloc_type_lookup): Map new relocations.
+ (GOT_TLS_GDESC, GOT_TLS_GD_BOTH_P): New macros.
+ (GOT_TLS_GD_P, GOT_TLS_GDESC_P, GOT_TLS_GD_ANY_P): New macros.
+ (struct elf_i386_link_hash_entry): Add tlsdesc_got field.
+ (struct elf_i386_obj_tdata): Add local_tlsdesc_gotent field.
+ (elf_i386_local_tlsdesc_gotent): New macro.
+ (struct elf_i386_link_hash_table): Add sgotplt_jump_table_size.
+ (elf_i386_compute_jump_table_size): New macro.
+ (link_hash_newfunc): Initialize tlsdesc_got.
+ (elf_i386_link_hash_table_create): Set sgotplt_jump_table_size.
+ (elf_i386_tls_transition): Handle R_386_TLS_GOTDESC and
+ R_386_TLS_DESC_CALL.
+ (elf_i386_check_relocs): Likewise. Allocate space for
+ local_tlsdesc_gotent.
+ (elf_i386_gc_sweep_hook): Handle R_386_TLS_GOTDESC and
+ R_386_TLS_DESC_CALL.
+ (allocate_dynrelocs): Count function PLT relocations. Reserve
+ space for TLS descriptors and relocations.
+ (elf_i386_size_dynamic_sections): Reserve space for TLS
+ descriptors and relocations. Set up sgotplt_jump_table_size.
+ Don't zero reloc_count in srelplt.
+ (elf_i386_always_size_sections): New. Set up _TLS_MODULE_BASE_.
+ (elf_i386_relocate_section): Handle R_386_TLS_GOTDESC and
+ R_386_TLS_DESC_CALL.
+ (elf_i386_finish_dynamic_symbol): Use GOT_TLS_GD_ANY_P.
+ (elf_backend_always_size_sections): Define.
+ * elf64-x86-64.c (x86_64_elf_howto): Add R_X86_64_GOTPC32_TLSDESC,
+ R_X86_64_TLSDESC, R_X86_64_TLSDESC_CALL.
+ (R_X86_64_standard): Adjust.
+ (x86_64_reloc_map): Map new relocs.
+ (elf64_x86_64_rtype_to_howto): New, split out of...
+ (elf64_x86_64_info_to_howto): ... this function, and...
+ (elf64_x86_64_reloc_type_lookup): ... use it to map elf_reloc_val.
+ (GOT_TLS_GDESC, GOT_TLS_GD_BOTH_P): New macros.
+ (GOT_TLS_GD_P, GOT_TLS_GDESC_P, GOT_TLS_GD_ANY_P): New macros.
+ (struct elf64_x86_64_link_hash_entry): Add tlsdesc_got field.
+ (struct elf64_x86_64_obj_tdata): Add local_tlsdesc_gotent field.
+ (elf64_x86_64_local_tlsdesc_gotent): New macro.
+ (struct elf64_x86_64_link_hash_table): Add tlsdesc_plt,
+ tlsdesc_got and sgotplt_jump_table_size fields.
+ (elf64_x86_64_compute_jump_table_size): New macro.
+ (link_hash_newfunc): Initialize tlsdesc_got.
+ (elf64_x86_64_link_hash_table_create): Initialize new fields.
+ (elf64_x86_64_tls_transition): Handle R_X86_64_GOTPC32_TLSDESC and
+ R_X86_64_TLSDESC_CALL.
+ (elf64_x86_64_check_relocs): Likewise. Allocate space for
+ local_tlsdesc_gotent.
+ (elf64_x86_64_gc_sweep_hook): Handle R_X86_64_GOTPC32_TLSDESC and
+ R_X86_64_TLSDESC_CALL.
+ (allocate_dynrelocs): Count function PLT relocations. Reserve
+ space for TLS descriptors and relocations.
+ (elf64_x86_64_size_dynamic_sections): Reserve space for TLS
+ descriptors and relocations. Set up sgotplt_jump_table_size,
+ tlsdesc_plt and tlsdesc_got. Make room for them. Don't zero
+ reloc_count in srelplt. Add dynamic entries for DT_TLSDESC_PLT
+ and DT_TLSDESC_GOT.
+ (elf64_x86_64_always_size_sections): New. Set up
+ _TLS_MODULE_BASE_.
+ (elf64_x86_64_relocate_section): Handle R_386_TLS_GOTDESC and
+ R_386_TLS_DESC_CALL.
+ (elf64_x86_64_finish_dynamic_symbol): Use GOT_TLS_GD_ANY_P.
+ (elf64_x86_64_finish_dynamic_sections): Set DT_TLSDESC_PLT and
+ DT_TLSDESC_GOT. Set up TLS descriptor lazy resolver PLT entry.
+ (elf_backend_always_size_sections): Define.
+
2006-01-17 H.J. Lu <hongjiu.lu@intel.com>
PR binutils/2096
diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h
index 3cf72f3..cae4ede 100644
--- a/bfd/bfd-in2.h
+++ b/bfd/bfd-in2.h
@@ -8,7 +8,8 @@
/* Main header file for the bfd library -- portable access to object files.
Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
- 1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+ 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006
+ Free Software Foundation, Inc.
Contributed by Cygnus Support.
@@ -2661,6 +2662,9 @@ in the instruction. */
BFD_RELOC_386_TLS_DTPMOD32,
BFD_RELOC_386_TLS_DTPOFF32,
BFD_RELOC_386_TLS_TPOFF32,
+ BFD_RELOC_386_TLS_GOTDESC,
+ BFD_RELOC_386_TLS_DESC_CALL,
+ BFD_RELOC_386_TLS_DESC,
/* x86-64/elf relocations */
BFD_RELOC_X86_64_GOT32,
@@ -2681,6 +2685,9 @@ in the instruction. */
BFD_RELOC_X86_64_TPOFF32,
BFD_RELOC_X86_64_GOTOFF64,
BFD_RELOC_X86_64_GOTPC32,
+ BFD_RELOC_X86_64_GOTPC32_TLSDESC,
+ BFD_RELOC_X86_64_TLSDESC_CALL,
+ BFD_RELOC_X86_64_TLSDESC,
/* ns32k relocations */
BFD_RELOC_NS32K_IMM_8,
diff --git a/bfd/elf32-i386.c b/bfd/elf32-i386.c
index 061a9cb..b8e8790 100644
--- a/bfd/elf32-i386.c
+++ b/bfd/elf32-i386.c
@@ -1,6 +1,6 @@
/* Intel 80386/80486-specific support for 32-bit ELF
Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
- 2003, 2004, 2005 Free Software Foundation, Inc.
+ 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
This file is part of BFD, the Binary File Descriptor library.
@@ -126,9 +126,19 @@ static reloc_howto_type elf_howto_table[]=
HOWTO(R_386_TLS_TPOFF32, 0, 2, 32, FALSE, 0, complain_overflow_bitfield,
bfd_elf_generic_reloc, "R_386_TLS_TPOFF32",
TRUE, 0xffffffff, 0xffffffff, FALSE),
+ EMPTY_HOWTO (38),
+ HOWTO(R_386_TLS_GOTDESC, 0, 2, 32, FALSE, 0, complain_overflow_bitfield,
+ bfd_elf_generic_reloc, "R_386_TLS_GOTDESC",
+ TRUE, 0xffffffff, 0xffffffff, FALSE),
+ HOWTO(R_386_TLS_DESC_CALL, 0, 0, 0, FALSE, 0, complain_overflow_dont,
+ bfd_elf_generic_reloc, "R_386_TLS_DESC_CALL",
+ FALSE, 0, 0, FALSE),
+ HOWTO(R_386_TLS_DESC, 0, 2, 32, FALSE, 0, complain_overflow_bitfield,
+ bfd_elf_generic_reloc, "R_386_TLS_DESC",
+ TRUE, 0xffffffff, 0xffffffff, FALSE),
/* Another gap. */
-#define R_386_tls (R_386_TLS_TPOFF32 + 1 - R_386_tls_offset)
+#define R_386_tls (R_386_TLS_DESC + 1 - R_386_tls_offset)
#define R_386_vt_offset (R_386_GNU_VTINHERIT - R_386_tls)
/* GNU extension to record C++ vtable hierarchy. */
@@ -292,6 +302,18 @@ elf_i386_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
TRACE ("BFD_RELOC_386_TLS_TPOFF32");
return &elf_howto_table[R_386_TLS_TPOFF32 - R_386_tls_offset];
+ case BFD_RELOC_386_TLS_GOTDESC:
+ TRACE ("BFD_RELOC_386_TLS_GOTDESC");
+ return &elf_howto_table[R_386_TLS_GOTDESC - R_386_tls_offset];
+
+ case BFD_RELOC_386_TLS_DESC_CALL:
+ TRACE ("BFD_RELOC_386_TLS_DESC_CALL");
+ return &elf_howto_table[R_386_TLS_DESC_CALL - R_386_tls_offset];
+
+ case BFD_RELOC_386_TLS_DESC:
+ TRACE ("BFD_RELOC_386_TLS_DESC");
+ return &elf_howto_table[R_386_TLS_DESC - R_386_tls_offset];
+
case BFD_RELOC_VTABLE_INHERIT:
TRACE ("BFD_RELOC_VTABLE_INHERIT");
return &elf_howto_table[R_386_GNU_VTINHERIT - R_386_vt_offset];
@@ -559,7 +581,20 @@ struct elf_i386_link_hash_entry
#define GOT_TLS_IE_POS 5
#define GOT_TLS_IE_NEG 6
#define GOT_TLS_IE_BOTH 7
+#define GOT_TLS_GDESC 8
+#define GOT_TLS_GD_BOTH_P(type) \
+ ((type) == (GOT_TLS_GD | GOT_TLS_GDESC))
+#define GOT_TLS_GD_P(type) \
+ ((type) == GOT_TLS_GD || GOT_TLS_GD_BOTH_P (type))
+#define GOT_TLS_GDESC_P(type) \
+ ((type) == GOT_TLS_GDESC || GOT_TLS_GD_BOTH_P (type))
+#define GOT_TLS_GD_ANY_P(type) \
+ (GOT_TLS_GD_P (type) || GOT_TLS_GDESC_P (type))
unsigned char tls_type;
+
+ /* Offset of the GOTPLT entry reserved for the TLS descriptor,
+ starting at the end of the jump table. */
+ bfd_vma tlsdesc_got;
};
#define elf_i386_hash_entry(ent) ((struct elf_i386_link_hash_entry *)(ent))
@@ -570,6 +605,9 @@ struct elf_i386_obj_tdata
/* tls_type for each local got entry. */
char *local_got_tls_type;
+
+ /* GOTPLT entries for TLS descriptors. */
+ bfd_vma *local_tlsdesc_gotent;
};
#define elf_i386_tdata(abfd) \
@@ -578,6 +616,9 @@ struct elf_i386_obj_tdata
#define elf_i386_local_got_tls_type(abfd) \
(elf_i386_tdata (abfd)->local_got_tls_type)
+#define elf_i386_local_tlsdesc_gotent(abfd) \
+ (elf_i386_tdata (abfd)->local_tlsdesc_gotent)
+
static bfd_boolean
elf_i386_mkobject (bfd *abfd)
{
@@ -620,6 +661,10 @@ struct elf_i386_link_hash_table
bfd_vma offset;
} tls_ldm_got;
+ /* The amount of space used by the reserved portion of the sgotplt
+ section, plus whatever space is used by the jump slots. */
+ bfd_vma sgotplt_jump_table_size;
+
/* Small local sym to section mapping cache. */
struct sym_sec_cache sym_sec;
};
@@ -629,6 +674,9 @@ struct elf_i386_link_hash_table
#define elf_i386_hash_table(p) \
((struct elf_i386_link_hash_table *) ((p)->hash))
+#define elf_i386_compute_jump_table_size(htab) \
+ ((htab)->srelplt->reloc_count * 4)
+
/* Create an entry in an i386 ELF linker hash table. */
static struct bfd_hash_entry *
@@ -655,6 +703,7 @@ link_hash_newfunc (struct bfd_hash_entry *entry,
eh = (struct elf_i386_link_hash_entry *) entry;
eh->dyn_relocs = NULL;
eh->tls_type = GOT_UNKNOWN;
+ eh->tlsdesc_got = (bfd_vma) -1;
}
return entry;
@@ -686,6 +735,7 @@ elf_i386_link_hash_table_create (bfd *abfd)
ret->sdynbss = NULL;
ret->srelbss = NULL;
ret->tls_ldm_got.refcount = 0;
+ ret->sgotplt_jump_table_size = 0;
ret->sym_sec.abfd = NULL;
ret->is_vxworks = 0;
ret->srelplt2 = NULL;
@@ -845,6 +895,8 @@ elf_i386_tls_transition (struct bfd_link_info *info, int r_type, int is_local)
switch (r_type)
{
case R_386_TLS_GD:
+ case R_386_TLS_GOTDESC:
+ case R_386_TLS_DESC_CALL:
case R_386_TLS_IE_32:
if (is_local)
return R_386_TLS_LE_32;
@@ -949,6 +1001,8 @@ elf_i386_check_relocs (bfd *abfd,
case R_386_GOT32:
case R_386_TLS_GD:
+ case R_386_TLS_GOTDESC:
+ case R_386_TLS_DESC_CALL:
/* This symbol requires a global offset table entry. */
{
int tls_type, old_tls_type;
@@ -958,6 +1012,9 @@ elf_i386_check_relocs (bfd *abfd,
default:
case R_386_GOT32: tls_type = GOT_NORMAL; break;
case R_386_TLS_GD: tls_type = GOT_TLS_GD; break;
+ case R_386_TLS_GOTDESC:
+ case R_386_TLS_DESC_CALL:
+ tls_type = GOT_TLS_GDESC; break;
case R_386_TLS_IE_32:
if (ELF32_R_TYPE (rel->r_info) == r_type)
tls_type = GOT_TLS_IE_NEG;
@@ -987,13 +1044,16 @@ elf_i386_check_relocs (bfd *abfd,
bfd_size_type size;
size = symtab_hdr->sh_info;
- size *= (sizeof (bfd_signed_vma) + sizeof(char));
+ size *= (sizeof (bfd_signed_vma)
+ + sizeof (bfd_vma) + sizeof(char));
local_got_refcounts = bfd_zalloc (abfd, size);
if (local_got_refcounts == NULL)
return FALSE;
elf_local_got_refcounts (abfd) = local_got_refcounts;
+ elf_i386_local_tlsdesc_gotent (abfd)
+ = (bfd_vma *) (local_got_refcounts + symtab_hdr->sh_info);
elf_i386_local_got_tls_type (abfd)
- = (char *) (local_got_refcounts + symtab_hdr->sh_info);
+ = (char *) (local_got_refcounts + 2 * symtab_hdr->sh_info);
}
local_got_refcounts[r_symndx] += 1;
old_tls_type = elf_i386_local_got_tls_type (abfd) [r_symndx];
@@ -1004,11 +1064,14 @@ elf_i386_check_relocs (bfd *abfd,
/* If a TLS symbol is accessed using IE at least once,
there is no point to use dynamic model for it. */
else if (old_tls_type != tls_type && old_tls_type != GOT_UNKNOWN
- && (old_tls_type != GOT_TLS_GD
+ && (! GOT_TLS_GD_ANY_P (old_tls_type)
|| (tls_type & GOT_TLS_IE) == 0))
{
- if ((old_tls_type & GOT_TLS_IE) && tls_type == GOT_TLS_GD)
+ if ((old_tls_type & GOT_TLS_IE) && GOT_TLS_GD_ANY_P (tls_type))
tls_type = old_tls_type;
+ else if (GOT_TLS_GD_ANY_P (old_tls_type)
+ && GOT_TLS_GD_ANY_P (tls_type))
+ tls_type |= old_tls_type;
else
{
(*_bfd_error_handler)
@@ -1316,6 +1379,8 @@ elf_i386_gc_sweep_hook (bfd *abfd,
break;
case R_386_TLS_GD:
+ case R_386_TLS_GOTDESC:
+ case R_386_TLS_DESC_CALL:
case R_386_TLS_IE_32:
case R_386_TLS_IE:
case R_386_TLS_GOTIE:
@@ -1579,6 +1644,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
/* We also need to make an entry in the .rel.plt section. */
htab->srelplt->size += sizeof (Elf32_External_Rel);
+ htab->srelplt->reloc_count++;
if (htab->is_vxworks && !info->shared)
{
@@ -1612,6 +1678,9 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
h->needs_plt = 0;
}
+ eh = (struct elf_i386_link_hash_entry *) h;
+ eh->tlsdesc_got = (bfd_vma) -1;
+
/* If R_386_TLS_{IE_32,IE,GOTIE} symbol is now local to the binary,
make it a R_386_TLS_LE_32 requiring no TLS entry. */
if (h->got.refcount > 0
@@ -1635,11 +1704,22 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
}
s = htab->sgot;
- h->got.offset = s->size;
- s->size += 4;
- /* R_386_TLS_GD needs 2 consecutive GOT slots. */
- if (tls_type == GOT_TLS_GD || tls_type == GOT_TLS_IE_BOTH)
- s->size += 4;
+ if (GOT_TLS_GDESC_P (tls_type))
+ {
+ eh->tlsdesc_got = htab->sgotplt->size
+ - elf_i386_compute_jump_table_size (htab);
+ htab->sgotplt->size += 8;
+ h->got.offset = (bfd_vma) -2;
+ }
+ if (! GOT_TLS_GDESC_P (tls_type)
+ || GOT_TLS_GD_P (tls_type))
+ {
+ h->got.offset = s->size;
+ s->size += 4;
+ /* R_386_TLS_GD needs 2 consecutive GOT slots. */
+ if (GOT_TLS_GD_P (tls_type) || tls_type == GOT_TLS_IE_BOTH)
+ s->size += 4;
+ }
dyn = htab->elf.dynamic_sections_created;
/* R_386_TLS_IE_32 needs one dynamic relocation,
R_386_TLS_IE resp. R_386_TLS_GOTIE needs one dynamic relocation,
@@ -1648,21 +1728,23 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
global. */
if (tls_type == GOT_TLS_IE_BOTH)
htab->srelgot->size += 2 * sizeof (Elf32_External_Rel);
- else if ((tls_type == GOT_TLS_GD && h->dynindx == -1)
+ else if ((GOT_TLS_GD_P (tls_type) && h->dynindx == -1)
|| (tls_type & GOT_TLS_IE))
htab->srelgot->size += sizeof (Elf32_External_Rel);
- else if (tls_type == GOT_TLS_GD)
+ else if (GOT_TLS_GD_P (tls_type))
htab->srelgot->size += 2 * sizeof (Elf32_External_Rel);
- else if ((ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
- || h->root.type != bfd_link_hash_undefweak)
+ else if (! GOT_TLS_GDESC_P (tls_type)
+ && (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
+ || h->root.type != bfd_link_hash_undefweak)
&& (info->shared
|| WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, 0, h)))
htab->srelgot->size += sizeof (Elf32_External_Rel);
+ if (GOT_TLS_GDESC_P (tls_type))
+ htab->srelplt->size += sizeof (Elf32_External_Rel);
}
else
h->got.offset = (bfd_vma) -1;
- eh = (struct elf_i386_link_hash_entry *) h;
if (eh->dyn_relocs == NULL)
return TRUE;
@@ -1810,6 +1892,7 @@ elf_i386_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
bfd_signed_vma *local_got;
bfd_signed_vma *end_local_got;
char *local_tls_type;
+ bfd_vma *local_tlsdesc_gotent;
bfd_size_type locsymcount;
Elf_Internal_Shdr *symtab_hdr;
asection *srel;
@@ -1852,25 +1935,42 @@ elf_i386_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
locsymcount = symtab_hdr->sh_info;
end_local_got = local_got + locsymcount;
local_tls_type = elf_i386_local_got_tls_type (ibfd);
+ local_tlsdesc_gotent = elf_i386_local_tlsdesc_gotent (ibfd);
s = htab->sgot;
srel = htab->srelgot;
- for (; local_got < end_local_got; ++local_got, ++local_tls_type)
+ for (; local_got < end_local_got;
+ ++local_got, ++local_tls_type, ++local_tlsdesc_gotent)
{
+ *local_tlsdesc_gotent = (bfd_vma) -1;
if (*local_got > 0)
{
- *local_got = s->size;
- s->size += 4;
- if (*local_tls_type == GOT_TLS_GD
- || *local_tls_type == GOT_TLS_IE_BOTH)
- s->size += 4;
+ if (GOT_TLS_GDESC_P (*local_tls_type))
+ {
+ *local_tlsdesc_gotent = htab->sgotplt->size
+ - elf_i386_compute_jump_table_size (htab);
+ htab->sgotplt->size += 8;
+ *local_got = (bfd_vma) -2;
+ }
+ if (! GOT_TLS_GDESC_P (*local_tls_type)
+ || GOT_TLS_GD_P (*local_tls_type))
+ {
+ *local_got = s->size;
+ s->size += 4;
+ if (GOT_TLS_GD_P (*local_tls_type)
+ || *local_tls_type == GOT_TLS_IE_BOTH)
+ s->size += 4;
+ }
if (info->shared
- || *local_tls_type == GOT_TLS_GD
+ || GOT_TLS_GD_ANY_P (*local_tls_type)
|| (*local_tls_type & GOT_TLS_IE))
{
if (*local_tls_type == GOT_TLS_IE_BOTH)
srel->size += 2 * sizeof (Elf32_External_Rel);
- else
+ else if (GOT_TLS_GD_P (*local_tls_type)
+ || ! GOT_TLS_GDESC_P (*local_tls_type))
srel->size += sizeof (Elf32_External_Rel);
+ if (GOT_TLS_GDESC_P (*local_tls_type))
+ htab->srelplt->size += sizeof (Elf32_External_Rel);
}
}
else
@@ -1914,6 +2014,14 @@ elf_i386_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
sym dynamic relocs. */
elf_link_hash_traverse (&htab->elf, allocate_dynrelocs, (PTR) info);
+ /* For every jump slot reserved in the sgotplt, reloc_count is
+ incremented. However, when we reserve space for TLS descriptors,
+ it's not incremented, so in order to compute the space reserved
+ for them, it suffices to multiply the reloc count by the jump
+ slot size. */
+ if (htab->srelplt)
+ htab->sgotplt_jump_table_size = htab->srelplt->reloc_count * 4;
+
/* We now have determined the sizes of the various dynamic sections.
Allocate memory for them. */
relocs = FALSE;
@@ -1945,7 +2053,8 @@ elf_i386_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
/* We use the reloc_count field as a counter if we need
to copy relocs into the output file. */
- s->reloc_count = 0;
+ if (s != htab->srelplt)
+ s->reloc_count = 0;
}
else
{
@@ -2032,6 +2141,41 @@ elf_i386_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
return TRUE;
}
+static bfd_boolean
+elf_i386_always_size_sections (bfd *output_bfd,
+ struct bfd_link_info *info)
+{
+ asection *tls_sec = elf_hash_table (info)->tls_sec;
+
+ if (tls_sec)
+ {
+ struct elf_link_hash_entry *tlsbase;
+
+ tlsbase = elf_link_hash_lookup (elf_hash_table (info),
+ "_TLS_MODULE_BASE_",
+ FALSE, FALSE, FALSE);
+
+ if (tlsbase && tlsbase->type == STT_TLS)
+ {
+ struct bfd_link_hash_entry *bh = NULL;
+ const struct elf_backend_data *bed
+ = get_elf_backend_data (output_bfd);
+
+ if (!(_bfd_generic_link_add_one_symbol
+ (info, output_bfd, "_TLS_MODULE_BASE_", BSF_LOCAL,
+ tls_sec, 0, NULL, FALSE,
+ bed->collect, &bh)))
+ return FALSE;
+ tlsbase = (struct elf_link_hash_entry *)bh;
+ tlsbase->def_regular = 1;
+ tlsbase->other = STV_HIDDEN;
+ (*bed->elf_backend_hide_symbol) (info, tlsbase, TRUE);
+ }
+ }
+
+ return TRUE;
+}
+
/* Set the correct type for an x86 ELF section. We do this by the
section name, which is a hack, but ought to work. */
@@ -2109,6 +2253,7 @@ elf_i386_relocate_section (bfd *output_bfd,
Elf_Internal_Shdr *symtab_hdr;
struct elf_link_hash_entry **sym_hashes;
bfd_vma *local_got_offsets;
+ bfd_vma *local_tlsdesc_gotents;
Elf_Internal_Rela *rel;
Elf_Internal_Rela *relend;
@@ -2116,6 +2261,7 @@ elf_i386_relocate_section (bfd *output_bfd,
symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
sym_hashes = elf_sym_hashes (input_bfd);
local_got_offsets = elf_local_got_offsets (input_bfd);
+ local_tlsdesc_gotents = elf_i386_local_tlsdesc_gotent (input_bfd);
rel = relocs;
relend = relocs + input_section->reloc_count;
@@ -2127,7 +2273,7 @@ elf_i386_relocate_section (bfd *output_bfd,
struct elf_link_hash_entry *h;
Elf_Internal_Sym *sym;
asection *sec;
- bfd_vma off;
+ bfd_vma off, offplt;
bfd_vma relocation;
bfd_boolean unresolved_reloc;
bfd_reloc_status_type r;
@@ -2549,6 +2695,8 @@ elf_i386_relocate_section (bfd *output_bfd,
/* Fall through */
case R_386_TLS_GD:
+ case R_386_TLS_GOTDESC:
+ case R_386_TLS_DESC_CALL:
case R_386_TLS_IE_32:
case R_386_TLS_GOTIE:
r_type = elf_i386_tls_transition (info, r_type, h == NULL);
@@ -2563,7 +2711,9 @@ elf_i386_relocate_section (bfd *output_bfd,
}
if (tls_type == GOT_TLS_IE)
tls_type = GOT_TLS_IE_NEG;
- if (r_type == R_386_TLS_GD)
+ if (r_type == R_386_TLS_GD
+ || r_type == R_386_TLS_GOTDESC
+ || r_type == R_386_TLS_DESC_CALL)
{
if (tls_type == GOT_TLS_IE_POS)
r_type = R_386_TLS_GOTIE;
@@ -2637,6 +2787,63 @@ elf_i386_relocate_section (bfd *output_bfd,
rel++;
continue;
}
+ else if (ELF32_R_TYPE (rel->r_info) == R_386_TLS_GOTDESC)
+ {
+ /* GDesc -> LE transition.
+ It's originally something like:
+ leal x@tlsdesc(%ebx), %eax
+
+ leal x@ntpoff, %eax
+
+ Registers other than %eax may be set up here. */
+
+ unsigned int val, type;
+ bfd_vma roff;
+
+ /* First, make sure it's a leal adding ebx to a
+ 32-bit offset into any register, although it's
+ probably almost always going to be eax. */
+ roff = rel->r_offset;
+ BFD_ASSERT (roff >= 2);
+ type = bfd_get_8 (input_bfd, contents + roff - 2);
+ BFD_ASSERT (type == 0x8d);
+ val = bfd_get_8 (input_bfd, contents + roff - 1);
+ BFD_ASSERT ((val & 0xc7) == 0x83);
+ BFD_ASSERT (roff + 4 <= input_section->size);
+
+ /* Now modify the instruction as appropriate. */
+ /* aoliva FIXME: remove the above and xor the byte
+ below with 0x86. */
+ bfd_put_8 (output_bfd, val ^ 0x86,
+ contents + roff - 1);
+ bfd_put_32 (output_bfd, -tpoff (info, relocation),
+ contents + roff);
+ continue;
+ }
+ else if (ELF32_R_TYPE (rel->r_info) == R_386_TLS_DESC_CALL)
+ {
+ /* GDesc -> LE transition.
+ It's originally:
+ call *(%eax)
+ Turn it into:
+ nop; nop */
+
+ unsigned int val, type;
+ bfd_vma roff;
+
+ /* First, make sure it's a call *(%eax). */
+ roff = rel->r_offset;
+ BFD_ASSERT (roff + 2 <= input_section->size);
+ type = bfd_get_8 (input_bfd, contents + roff);
+ BFD_ASSERT (type == 0xff);
+ val = bfd_get_8 (input_bfd, contents + roff + 1);
+ BFD_ASSERT (val == 0x10);
+
+ /* Now modify the instruction as appropriate. */
+ bfd_put_8 (output_bfd, 0x90, contents + roff);
+ bfd_put_8 (output_bfd, 0x90, contents + roff + 1);
+ continue;
+ }
else if (ELF32_R_TYPE (rel->r_info) == R_386_TLS_IE)
{
unsigned int val, type;
@@ -2751,13 +2958,17 @@ elf_i386_relocate_section (bfd *output_bfd,
abort ();
if (h != NULL)
- off = h->got.offset;
+ {
+ off = h->got.offset;
+ offplt = elf_i386_hash_entry (h)->tlsdesc_got;
+ }
else
{
if (local_got_offsets == NULL)
abort ();
off = local_got_offsets[r_symndx];
+ offplt = local_tlsdesc_gotents[r_symndx];
}
if ((off & 1) != 0)
@@ -2767,35 +2978,77 @@ elf_i386_relocate_section (bfd *output_bfd,
Elf_Internal_Rela outrel;
bfd_byte *loc;
int dr_type, indx;
+ asection *sreloc;
if (htab->srelgot == NULL)
abort ();
+ indx = h && h->dynindx != -1 ? h->dynindx : 0;
+
+ if (GOT_TLS_GDESC_P (tls_type))
+ {
+ outrel.r_info = ELF32_R_INFO (indx, R_386_TLS_DESC);
+ BFD_ASSERT (htab->sgotplt_jump_table_size + offplt + 8
+ <= htab->sgotplt->size);
+ outrel.r_offset = (htab->sgotplt->output_section->vma
+ + htab->sgotplt->output_offset
+ + offplt
+ + htab->sgotplt_jump_table_size);
+ sreloc = htab->srelplt;
+ loc = sreloc->contents;
+ loc += sreloc->reloc_count++
+ * sizeof (Elf32_External_Rel);
+ BFD_ASSERT (loc + sizeof (Elf32_External_Rel)
+ <= sreloc->contents + sreloc->size);
+ bfd_elf32_swap_reloc_out (output_bfd, &outrel, loc);
+ if (indx == 0)
+ {
+ BFD_ASSERT (! unresolved_reloc);
+ bfd_put_32 (output_bfd,
+ relocation - dtpoff_base (info),
+ htab->sgotplt->contents + offplt
+ + htab->sgotplt_jump_table_size + 4);
+ }
+ else
+ {
+ bfd_put_32 (output_bfd, 0,
+ htab->sgotplt->contents + offplt
+ + htab->sgotplt_jump_table_size + 4);
+ }
+ }
+
+ sreloc = htab->srelgot;
+
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_386_TLS_GD)
+ if (GOT_TLS_GD_P (tls_type))
dr_type = R_386_TLS_DTPMOD32;
+ else if (GOT_TLS_GDESC_P (tls_type))
+ goto dr_done;
else if (tls_type == GOT_TLS_IE_POS)
dr_type = R_386_TLS_TPOFF;
else
dr_type = R_386_TLS_TPOFF32;
+
if (dr_type == R_386_TLS_TPOFF && indx == 0)
bfd_put_32 (output_bfd, relocation - dtpoff_base (info),
htab->sgot->contents + off);
else if (dr_type == R_386_TLS_TPOFF32 && indx == 0)
bfd_put_32 (output_bfd, dtpoff_base (info) - relocation,
htab->sgot->contents + off);
- else
+ else if (dr_type != R_386_TLS_DESC)
bfd_put_32 (output_bfd, 0,
htab->sgot->contents + off);
outrel.r_info = ELF32_R_INFO (indx, dr_type);
- loc = htab->srelgot->contents;
- loc += htab->srelgot->reloc_count++ * sizeof (Elf32_External_Rel);
+
+ loc = sreloc->contents;
+ loc += sreloc->reloc_count++ * sizeof (Elf32_External_Rel);
+ BFD_ASSERT (loc + sizeof (Elf32_External_Rel)
+ <= sreloc->contents + sreloc->size);
bfd_elf32_swap_reloc_out (output_bfd, &outrel, loc);
- if (r_type == R_386_TLS_GD)
+ if (GOT_TLS_GD_P (tls_type))
{
if (indx == 0)
{
@@ -2811,8 +3064,10 @@ elf_i386_relocate_section (bfd *output_bfd,
outrel.r_info = ELF32_R_INFO (indx,
R_386_TLS_DTPOFF32);
outrel.r_offset += 4;
- htab->srelgot->reloc_count++;
+ sreloc->reloc_count++;
loc += sizeof (Elf32_External_Rel);
+ BFD_ASSERT (loc + sizeof (Elf32_External_Rel)
+ <= sreloc->contents + sreloc->size);
bfd_elf32_swap_reloc_out (output_bfd, &outrel, loc);
}
}
@@ -2823,25 +3078,33 @@ elf_i386_relocate_section (bfd *output_bfd,
htab->sgot->contents + off + 4);
outrel.r_info = ELF32_R_INFO (indx, R_386_TLS_TPOFF);
outrel.r_offset += 4;
- htab->srelgot->reloc_count++;
+ sreloc->reloc_count++;
loc += sizeof (Elf32_External_Rel);
bfd_elf32_swap_reloc_out (output_bfd, &outrel, loc);
}
+ dr_done:
if (h != NULL)
h->got.offset |= 1;
else
local_got_offsets[r_symndx] |= 1;
}
- if (off >= (bfd_vma) -2)
+ if (off >= (bfd_vma) -2
+ && ! GOT_TLS_GDESC_P (tls_type))
abort ();
- if (r_type == ELF32_R_TYPE (rel->r_info))
+ if (r_type == R_386_TLS_GOTDESC
+ || r_type == R_386_TLS_DESC_CALL)
+ {
+ relocation = htab->sgotplt_jump_table_size + offplt;
+ unresolved_reloc = FALSE;
+ }
+ else if (r_type == ELF32_R_TYPE (rel->r_info))
{
bfd_vma g_o_t = htab->sgotplt->output_section->vma
+ htab->sgotplt->output_offset;
relocation = htab->sgot->output_section->vma
- + htab->sgot->output_offset + off - g_o_t;
+ + htab->sgot->output_offset + off - g_o_t;
if ((r_type == R_386_TLS_IE || r_type == R_386_TLS_GOTIE)
&& tls_type == GOT_TLS_IE_BOTH)
relocation += 4;
@@ -2849,7 +3112,7 @@ elf_i386_relocate_section (bfd *output_bfd,
relocation += g_o_t;
unresolved_reloc = FALSE;
}
- else
+ else if (ELF32_R_TYPE (rel->r_info) == R_386_TLS_GD)
{
unsigned int val, type;
bfd_vma roff;
@@ -2913,6 +3176,94 @@ elf_i386_relocate_section (bfd *output_bfd,
rel++;
continue;
}
+ else if (ELF32_R_TYPE (rel->r_info) == R_386_TLS_GOTDESC)
+ {
+ /* GDesc -> IE transition.
+ It's originally something like:
+ leal x@tlsdesc(%ebx), %eax
+
+ Change it to:
+ movl x@gotntpoff(%ebx), %eax # before nop; nop
+ or:
+ movl x@gottpoff(%ebx), %eax # before negl %eax
+
+ Registers other than %eax may be set up here. */
+
+ unsigned int val, type;
+ bfd_vma roff;
+
+ /* First, make sure it's a leal adding ebx to a 32-bit
+ offset into any register, although it's probably
+ almost always going to be eax. */
+ roff = rel->r_offset;
+ BFD_ASSERT (roff >= 2);
+ type = bfd_get_8 (input_bfd, contents + roff - 2);
+ BFD_ASSERT (type == 0x8d);
+ val = bfd_get_8 (input_bfd, contents + roff - 1);
+ BFD_ASSERT ((val & 0xc7) == 0x83);
+ BFD_ASSERT (roff + 4 <= input_section->size);
+
+ /* Now modify the instruction as appropriate. */
+ /* To turn a leal into a movl in the form we use it, it
+ suffices to change the first byte from 0x8d to 0x8b.
+ aoliva FIXME: should we decide to keep the leal, all
+ we have to do is remove the statement below, and
+ adjust the relaxation of R_386_TLS_DESC_CALL. */
+ bfd_put_8 (output_bfd, 0x8b, contents + roff - 2);
+
+ if (tls_type == GOT_TLS_IE_BOTH)
+ off += 4;
+
+ bfd_put_32 (output_bfd,
+ htab->sgot->output_section->vma
+ + htab->sgot->output_offset + off
+ - htab->sgotplt->output_section->vma
+ - htab->sgotplt->output_offset,
+ contents + roff);
+ continue;
+ }
+ else if (ELF32_R_TYPE (rel->r_info) == R_386_TLS_DESC_CALL)
+ {
+ /* GDesc -> IE transition.
+ It's originally:
+ call *(%eax)
+
+ Change it to:
+ nop; nop
+ or
+ negl %eax
+ depending on how we transformed the TLS_GOTDESC above.
+ */
+
+ unsigned int val, type;
+ bfd_vma roff;
+
+ /* First, make sure it's a call *(%eax). */
+ roff = rel->r_offset;
+ BFD_ASSERT (roff + 2 <= input_section->size);
+ type = bfd_get_8 (input_bfd, contents + roff);
+ BFD_ASSERT (type == 0xff);
+ val = bfd_get_8 (input_bfd, contents + roff + 1);
+ BFD_ASSERT (val == 0x10);
+
+ /* Now modify the instruction as appropriate. */
+ if (tls_type != GOT_TLS_IE_NEG)
+ {
+ /* nop; nop */
+ bfd_put_8 (output_bfd, 0x90, contents + roff);
+ bfd_put_8 (output_bfd, 0x90, contents + roff + 1);
+ }
+ else
+ {
+ /* negl %eax */
+ bfd_put_8 (output_bfd, 0xf7, contents + roff);
+ bfd_put_8 (output_bfd, 0xd8, contents + roff + 1);
+ }
+
+ continue;
+ }
+ else
+ BFD_ASSERT (FALSE);
break;
case R_386_TLS_LDM:
@@ -3220,7 +3571,7 @@ elf_i386_finish_dynamic_symbol (bfd *output_bfd,
}
if (h->got.offset != (bfd_vma) -1
- && elf_i386_hash_entry(h)->tls_type != GOT_TLS_GD
+ && ! GOT_TLS_GD_ANY_P (elf_i386_hash_entry(h)->tls_type)
&& (elf_i386_hash_entry(h)->tls_type & GOT_TLS_IE) == 0)
{
Elf_Internal_Rela rel;
@@ -3555,6 +3906,7 @@ elf_i386_plt_sym_val (bfd_vma i, const asection *plt,
#define elf_backend_reloc_type_class elf_i386_reloc_type_class
#define elf_backend_relocate_section elf_i386_relocate_section
#define elf_backend_size_dynamic_sections elf_i386_size_dynamic_sections
+#define elf_backend_always_size_sections elf_i386_always_size_sections
#define elf_backend_plt_sym_val elf_i386_plt_sym_val
#include "elf32-target.h"
diff --git a/bfd/elf64-x86-64.c b/bfd/elf64-x86-64.c
index 54914ba..5433771 100644
--- a/bfd/elf64-x86-64.c
+++ b/bfd/elf64-x86-64.c
@@ -1,5 +1,5 @@
/* X86-64 specific support for 64-bit ELF
- Copyright 2000, 2001, 2002, 2003, 2004, 2005
+ Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2006
Free Software Foundation, Inc.
Contributed by Jan Hubicka <jh@suse.cz>.
@@ -112,12 +112,31 @@ static reloc_howto_type x86_64_elf_howto_table[] =
HOWTO(R_X86_64_GOTPC32, 0, 2, 32, TRUE, 0, complain_overflow_signed,
bfd_elf_generic_reloc, "R_X86_64_GOTPC32",
FALSE, 0xffffffff, 0xffffffff, TRUE),
+ EMPTY_HOWTO (27),
+ EMPTY_HOWTO (28),
+ EMPTY_HOWTO (29),
+ EMPTY_HOWTO (30),
+ EMPTY_HOWTO (31),
+ EMPTY_HOWTO (32),
+ EMPTY_HOWTO (33),
+ HOWTO(R_X86_64_GOTPC32_TLSDESC, 0, 2, 32, TRUE, 0,
+ complain_overflow_bitfield, bfd_elf_generic_reloc,
+ "R_X86_64_GOTPC32_TLSDESC",
+ FALSE, 0xffffffff, 0xffffffff, TRUE),
+ HOWTO(R_X86_64_TLSDESC_CALL, 0, 0, 0, FALSE, 0,
+ complain_overflow_dont, bfd_elf_generic_reloc,
+ "R_X86_64_TLSDESC_CALL",
+ FALSE, 0, 0, FALSE),
+ HOWTO(R_X86_64_TLSDESC, 0, 4, 64, FALSE, 0,
+ complain_overflow_bitfield, bfd_elf_generic_reloc,
+ "R_X86_64_TLSDESC",
+ FALSE, MINUS_ONE, MINUS_ONE, FALSE),
/* We have a gap in the reloc numbers here.
R_X86_64_standard counts the number up to this point, and
R_X86_64_vt_offset is the value to subtract from a reloc type of
R_X86_64_GNU_VT* to form an index into this table. */
-#define R_X86_64_standard (R_X86_64_GOTPC32 + 1)
+#define R_X86_64_standard (R_X86_64_TLSDESC + 1)
#define R_X86_64_vt_offset (R_X86_64_GNU_VTINHERIT - R_X86_64_standard)
/* GNU extension to record C++ vtable hierarchy. */
@@ -166,14 +185,38 @@ static const struct elf_reloc_map x86_64_reloc_map[] =
{ BFD_RELOC_64_PCREL, R_X86_64_PC64, },
{ BFD_RELOC_X86_64_GOTOFF64, R_X86_64_GOTOFF64, },
{ BFD_RELOC_X86_64_GOTPC32, R_X86_64_GOTPC32, },
+ { BFD_RELOC_X86_64_GOTPC32_TLSDESC, R_X86_64_GOTPC32_TLSDESC, },
+ { BFD_RELOC_X86_64_TLSDESC_CALL, R_X86_64_TLSDESC_CALL, },
+ { BFD_RELOC_X86_64_TLSDESC, R_X86_64_TLSDESC, },
{ BFD_RELOC_VTABLE_INHERIT, R_X86_64_GNU_VTINHERIT, },
{ BFD_RELOC_VTABLE_ENTRY, R_X86_64_GNU_VTENTRY, },
};
+static reloc_howto_type *
+elf64_x86_64_rtype_to_howto (bfd *abfd, unsigned r_type)
+{
+ unsigned i;
+
+ if (r_type < (unsigned int) R_X86_64_GNU_VTINHERIT
+ || r_type >= (unsigned int) R_X86_64_max)
+ {
+ if (r_type >= (unsigned int) R_X86_64_standard)
+ {
+ (*_bfd_error_handler) (_("%B: invalid relocation type %d"),
+ abfd, (int) r_type);
+ r_type = R_X86_64_NONE;
+ }
+ i = r_type;
+ }
+ else
+ i = r_type - (unsigned int) R_X86_64_vt_offset;
+ BFD_ASSERT (x86_64_elf_howto_table[i].type == r_type);
+ return &x86_64_elf_howto_table[i];
+}
/* Given a BFD reloc type, return a HOWTO structure. */
static reloc_howto_type *
-elf64_x86_64_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
+elf64_x86_64_reloc_type_lookup (bfd *abfd,
bfd_reloc_code_real_type code)
{
unsigned int i;
@@ -182,7 +225,8 @@ elf64_x86_64_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
i++)
{
if (x86_64_reloc_map[i].bfd_reloc_val == code)
- return &x86_64_elf_howto_table[i];
+ return elf64_x86_64_rtype_to_howto (abfd,
+ x86_64_reloc_map[i].elf_reloc_val);
}
return 0;
}
@@ -193,23 +237,10 @@ static void
elf64_x86_64_info_to_howto (bfd *abfd ATTRIBUTE_UNUSED, arelent *cache_ptr,
Elf_Internal_Rela *dst)
{
- unsigned r_type, i;
+ unsigned r_type;
r_type = ELF64_R_TYPE (dst->r_info);
- if (r_type < (unsigned int) R_X86_64_GNU_VTINHERIT
- || r_type >= (unsigned int) R_X86_64_max)
- {
- if (r_type >= (unsigned int) R_X86_64_standard)
- {
- (*_bfd_error_handler) (_("%B: invalid relocation type %d"),
- abfd, (int) r_type);
- r_type = R_X86_64_NONE;
- }
- i = r_type;
- }
- else
- i = r_type - (unsigned int) R_X86_64_vt_offset;
- cache_ptr->howto = &x86_64_elf_howto_table[i];
+ cache_ptr->howto = elf64_x86_64_rtype_to_howto (abfd, r_type);
BFD_ASSERT (r_type == cache_ptr->howto->type);
}
@@ -353,7 +384,20 @@ struct elf64_x86_64_link_hash_entry
#define GOT_NORMAL 1
#define GOT_TLS_GD 2
#define GOT_TLS_IE 3
+#define GOT_TLS_GDESC 4
+#define GOT_TLS_GD_BOTH_P(type) \
+ ((type) == (GOT_TLS_GD | GOT_TLS_GDESC))
+#define GOT_TLS_GD_P(type) \
+ ((type) == GOT_TLS_GD || GOT_TLS_GD_BOTH_P (type))
+#define GOT_TLS_GDESC_P(type) \
+ ((type) == GOT_TLS_GDESC || GOT_TLS_GD_BOTH_P (type))
+#define GOT_TLS_GD_ANY_P(type) \
+ (GOT_TLS_GD_P (type) || GOT_TLS_GDESC_P (type))
unsigned char tls_type;
+
+ /* Offset of the GOTPLT entry reserved for the TLS descriptor,
+ starting at the end of the jump table. */
+ bfd_vma tlsdesc_got;
};
#define elf64_x86_64_hash_entry(ent) \
@@ -365,6 +409,9 @@ struct elf64_x86_64_obj_tdata
/* tls_type for each local got entry. */
char *local_got_tls_type;
+
+ /* GOTPLT entries for TLS descriptors. */
+ bfd_vma *local_tlsdesc_gotent;
};
#define elf64_x86_64_tdata(abfd) \
@@ -373,6 +420,8 @@ struct elf64_x86_64_obj_tdata
#define elf64_x86_64_local_got_tls_type(abfd) \
(elf64_x86_64_tdata (abfd)->local_got_tls_type)
+#define elf64_x86_64_local_tlsdesc_gotent(abfd) \
+ (elf64_x86_64_tdata (abfd)->local_tlsdesc_gotent)
/* x86-64 ELF linker hash table. */
@@ -389,11 +438,23 @@ struct elf64_x86_64_link_hash_table
asection *sdynbss;
asection *srelbss;
+ /* The offset into splt of the PLT entry for the TLS descriptor
+ resolver. Special values are 0, if not necessary (or not found
+ to be necessary yet), and -1 if needed but not determined
+ yet. */
+ bfd_vma tlsdesc_plt;
+ /* The offset into sgot of the GOT entry used by the PLT entry
+ above. */
+ bfd_vma tlsdesc_got;
+
union {
bfd_signed_vma refcount;
bfd_vma offset;
} tls_ld_got;
+ /* The amount of space used by the jump slots in the GOT. */
+ bfd_vma sgotplt_jump_table_size;
+
/* Small local sym to section mapping cache. */
struct sym_sec_cache sym_sec;
};
@@ -403,6 +464,9 @@ struct elf64_x86_64_link_hash_table
#define elf64_x86_64_hash_table(p) \
((struct elf64_x86_64_link_hash_table *) ((p)->hash))
+#define elf64_x86_64_compute_jump_table_size(htab) \
+ ((htab)->srelplt->reloc_count * GOT_ENTRY_SIZE)
+
/* Create an entry in an x86-64 ELF linker hash table. */
static struct bfd_hash_entry *
@@ -428,6 +492,7 @@ link_hash_newfunc (struct bfd_hash_entry *entry, struct bfd_hash_table *table,
eh = (struct elf64_x86_64_link_hash_entry *) entry;
eh->dyn_relocs = NULL;
eh->tls_type = GOT_UNKNOWN;
+ eh->tlsdesc_got = (bfd_vma) -1;
}
return entry;
@@ -459,7 +524,10 @@ elf64_x86_64_link_hash_table_create (bfd *abfd)
ret->sdynbss = NULL;
ret->srelbss = NULL;
ret->sym_sec.abfd = NULL;
+ ret->tlsdesc_plt = 0;
+ ret->tlsdesc_got = 0;
ret->tls_ld_got.refcount = 0;
+ ret->sgotplt_jump_table_size = 0;
return &ret->elf.root;
}
@@ -616,6 +684,8 @@ elf64_x86_64_tls_transition (struct bfd_link_info *info, int r_type, int is_loca
switch (r_type)
{
case R_X86_64_TLSGD:
+ case R_X86_64_GOTPC32_TLSDESC:
+ case R_X86_64_TLSDESC_CALL:
case R_X86_64_GOTTPOFF:
if (is_local)
return R_X86_64_TPOFF32;
@@ -706,6 +776,8 @@ elf64_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info, asection *sec,
case R_X86_64_GOT32:
case R_X86_64_GOTPCREL:
case R_X86_64_TLSGD:
+ case R_X86_64_GOTPC32_TLSDESC:
+ case R_X86_64_TLSDESC_CALL:
/* This symbol requires a global offset table entry. */
{
int tls_type, old_tls_type;
@@ -715,6 +787,9 @@ elf64_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info, asection *sec,
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;
+ case R_X86_64_GOTPC32_TLSDESC:
+ case R_X86_64_TLSDESC_CALL:
+ tls_type = GOT_TLS_GDESC; break;
}
if (h != NULL)
@@ -733,14 +808,17 @@ elf64_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info, asection *sec,
bfd_size_type size;
size = symtab_hdr->sh_info;
- size *= sizeof (bfd_signed_vma) + sizeof (char);
+ size *= sizeof (bfd_signed_vma)
+ + sizeof (bfd_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_tlsdesc_gotent (abfd)
+ = (bfd_vma *) (local_got_refcounts + symtab_hdr->sh_info);
elf64_x86_64_local_got_tls_type (abfd)
- = (char *) (local_got_refcounts + symtab_hdr->sh_info);
+ = (char *) (local_got_refcounts + 2 * symtab_hdr->sh_info);
}
local_got_refcounts[r_symndx] += 1;
old_tls_type
@@ -750,10 +828,14 @@ elf64_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info, asection *sec,
/* 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))
+ && (! GOT_TLS_GD_ANY_P (old_tls_type)
+ || tls_type != GOT_TLS_IE))
{
- if (old_tls_type == GOT_TLS_IE && tls_type == GOT_TLS_GD)
+ if (old_tls_type == GOT_TLS_IE && GOT_TLS_GD_ANY_P (tls_type))
tls_type = old_tls_type;
+ else if (GOT_TLS_GD_ANY_P (old_tls_type)
+ && GOT_TLS_GD_ANY_P (tls_type))
+ tls_type |= old_tls_type;
else
{
(*_bfd_error_handler)
@@ -1101,6 +1183,8 @@ elf64_x86_64_gc_sweep_hook (bfd *abfd, struct bfd_link_info *info,
break;
case R_X86_64_TLSGD:
+ case R_X86_64_GOTPC32_TLSDESC:
+ case R_X86_64_TLSDESC_CALL:
case R_X86_64_GOTTPOFF:
case R_X86_64_GOT32:
case R_X86_64_GOTPCREL:
@@ -1368,6 +1452,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf)
/* We also need to make an entry in the .rela.plt section. */
htab->srelplt->size += sizeof (Elf64_External_Rela);
+ htab->srelplt->reloc_count++;
}
else
{
@@ -1381,6 +1466,9 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf)
h->needs_plt = 0;
}
+ eh = (struct elf64_x86_64_link_hash_entry *) h;
+ eh->tlsdesc_got = (bfd_vma) -1;
+
/* 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
@@ -1403,31 +1491,46 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf)
return FALSE;
}
- s = htab->sgot;
- h->got.offset = s->size;
- s->size += GOT_ENTRY_SIZE;
- /* R_X86_64_TLSGD needs 2 consecutive GOT slots. */
- if (tls_type == GOT_TLS_GD)
- s->size += GOT_ENTRY_SIZE;
+ if (GOT_TLS_GDESC_P (tls_type))
+ {
+ eh->tlsdesc_got = htab->sgotplt->size
+ - elf64_x86_64_compute_jump_table_size (htab);
+ htab->sgotplt->size += 2 * GOT_ENTRY_SIZE;
+ h->got.offset = (bfd_vma) -2;
+ }
+ if (! GOT_TLS_GDESC_P (tls_type)
+ || GOT_TLS_GD_P (tls_type))
+ {
+ s = htab->sgot;
+ h->got.offset = s->size;
+ s->size += GOT_ENTRY_SIZE;
+ if (GOT_TLS_GD_P (tls_type))
+ s->size += GOT_ENTRY_SIZE;
+ }
dyn = htab->elf.dynamic_sections_created;
/* 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)
+ if ((GOT_TLS_GD_P (tls_type) && h->dynindx == -1)
|| tls_type == GOT_TLS_IE)
htab->srelgot->size += sizeof (Elf64_External_Rela);
- else if (tls_type == GOT_TLS_GD)
+ else if (GOT_TLS_GD_P (tls_type))
htab->srelgot->size += 2 * sizeof (Elf64_External_Rela);
- else if ((ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
- || h->root.type != bfd_link_hash_undefweak)
+ else if (! GOT_TLS_GDESC_P (tls_type)
+ && (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
+ || h->root.type != bfd_link_hash_undefweak)
&& (info->shared
|| WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, 0, h)))
htab->srelgot->size += sizeof (Elf64_External_Rela);
+ if (GOT_TLS_GDESC_P (tls_type))
+ {
+ htab->srelplt->size += sizeof (Elf64_External_Rela);
+ htab->tlsdesc_plt = (bfd_vma) -1;
+ }
}
else
h->got.offset = (bfd_vma) -1;
- eh = (struct elf64_x86_64_link_hash_entry *) h;
if (eh->dyn_relocs == NULL)
return TRUE;
@@ -1575,6 +1678,7 @@ elf64_x86_64_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
bfd_signed_vma *local_got;
bfd_signed_vma *end_local_got;
char *local_tls_type;
+ bfd_vma *local_tlsdesc_gotent;
bfd_size_type locsymcount;
Elf_Internal_Shdr *symtab_hdr;
asection *srel;
@@ -1618,20 +1722,43 @@ elf64_x86_64_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
locsymcount = symtab_hdr->sh_info;
end_local_got = local_got + locsymcount;
local_tls_type = elf64_x86_64_local_got_tls_type (ibfd);
+ local_tlsdesc_gotent = elf64_x86_64_local_tlsdesc_gotent (ibfd);
s = htab->sgot;
srel = htab->srelgot;
- for (; local_got < end_local_got; ++local_got, ++local_tls_type)
+ for (; local_got < end_local_got;
+ ++local_got, ++local_tls_type, ++local_tlsdesc_gotent)
{
+ *local_tlsdesc_gotent = (bfd_vma) -1;
if (*local_got > 0)
{
- *local_got = s->size;
- s->size += GOT_ENTRY_SIZE;
- if (*local_tls_type == GOT_TLS_GD)
- s->size += GOT_ENTRY_SIZE;
+ if (GOT_TLS_GDESC_P (*local_tls_type))
+ {
+ *local_tlsdesc_gotent = htab->sgotplt->size
+ - elf64_x86_64_compute_jump_table_size (htab);
+ htab->sgotplt->size += 2 * GOT_ENTRY_SIZE;
+ *local_got = (bfd_vma) -2;
+ }
+ if (! GOT_TLS_GDESC_P (*local_tls_type)
+ || GOT_TLS_GD_P (*local_tls_type))
+ {
+ *local_got = s->size;
+ s->size += GOT_ENTRY_SIZE;
+ if (GOT_TLS_GD_P (*local_tls_type))
+ s->size += GOT_ENTRY_SIZE;
+ }
if (info->shared
- || *local_tls_type == GOT_TLS_GD
+ || GOT_TLS_GD_ANY_P (*local_tls_type)
|| *local_tls_type == GOT_TLS_IE)
- srel->size += sizeof (Elf64_External_Rela);
+ {
+ if (GOT_TLS_GDESC_P (*local_tls_type))
+ {
+ htab->srelplt->size += sizeof (Elf64_External_Rela);
+ htab->tlsdesc_plt = (bfd_vma) -1;
+ }
+ if (! GOT_TLS_GDESC_P (*local_tls_type)
+ || GOT_TLS_GD_P (*local_tls_type))
+ srel->size += sizeof (Elf64_External_Rela);
+ }
}
else
*local_got = (bfd_vma) -1;
@@ -1653,6 +1780,34 @@ elf64_x86_64_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
sym dynamic relocs. */
elf_link_hash_traverse (&htab->elf, allocate_dynrelocs, (PTR) info);
+ /* For every jump slot reserved in the sgotplt, reloc_count is
+ incremented. However, when we reserve space for TLS descriptors,
+ it's not incremented, so in order to compute the space reserved
+ for them, it suffices to multiply the reloc count by the jump
+ slot size. */
+ if (htab->srelplt)
+ htab->sgotplt_jump_table_size
+ = elf64_x86_64_compute_jump_table_size (htab);
+
+ if (htab->tlsdesc_plt)
+ {
+ /* If we're not using lazy TLS relocations, don't generate the
+ PLT and GOT entries they require. */
+ if ((info->flags & DF_BIND_NOW))
+ htab->tlsdesc_plt = 0;
+ else
+ {
+ htab->tlsdesc_got = htab->sgot->size;
+ htab->sgot->size += GOT_ENTRY_SIZE;
+ /* Reserve room for the initial entry.
+ FIXME: we could probably do away with it in this case. */
+ if (htab->splt->size == 0)
+ htab->splt->size += PLT_ENTRY_SIZE;
+ htab->tlsdesc_plt = htab->splt->size;
+ htab->splt->size += PLT_ENTRY_SIZE;
+ }
+ }
+
/* We now have determined the sizes of the various dynamic sections.
Allocate memory for them. */
relocs = FALSE;
@@ -1676,7 +1831,8 @@ elf64_x86_64_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
/* We use the reloc_count field as a counter if we need
to copy relocs into the output file. */
- s->reloc_count = 0;
+ if (s != htab->srelplt)
+ s->reloc_count = 0;
}
else
{
@@ -1736,6 +1892,11 @@ elf64_x86_64_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
|| !add_dynamic_entry (DT_PLTREL, DT_RELA)
|| !add_dynamic_entry (DT_JMPREL, 0))
return FALSE;
+
+ if (htab->tlsdesc_plt
+ && (!add_dynamic_entry (DT_TLSDESC_PLT, 0)
+ || !add_dynamic_entry (DT_TLSDESC_GOT, 0)))
+ return FALSE;
}
if (relocs)
@@ -1763,6 +1924,41 @@ elf64_x86_64_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
return TRUE;
}
+static bfd_boolean
+elf64_x86_64_always_size_sections (bfd *output_bfd,
+ struct bfd_link_info *info)
+{
+ asection *tls_sec = elf_hash_table (info)->tls_sec;
+
+ if (tls_sec)
+ {
+ struct elf_link_hash_entry *tlsbase;
+
+ tlsbase = elf_link_hash_lookup (elf_hash_table (info),
+ "_TLS_MODULE_BASE_",
+ FALSE, FALSE, FALSE);
+
+ if (tlsbase && tlsbase->type == STT_TLS)
+ {
+ struct bfd_link_hash_entry *bh = NULL;
+ const struct elf_backend_data *bed
+ = get_elf_backend_data (output_bfd);
+
+ if (!(_bfd_generic_link_add_one_symbol
+ (info, output_bfd, "_TLS_MODULE_BASE_", BSF_LOCAL,
+ tls_sec, 0, NULL, FALSE,
+ bed->collect, &bh)))
+ return FALSE;
+ tlsbase = (struct elf_link_hash_entry *)bh;
+ tlsbase->def_regular = 1;
+ tlsbase->other = STV_HIDDEN;
+ (*bed->elf_backend_hide_symbol) (info, tlsbase, TRUE);
+ }
+ }
+
+ 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. */
@@ -1821,6 +2017,7 @@ elf64_x86_64_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
Elf_Internal_Shdr *symtab_hdr;
struct elf_link_hash_entry **sym_hashes;
bfd_vma *local_got_offsets;
+ bfd_vma *local_tlsdesc_gotents;
Elf_Internal_Rela *rel;
Elf_Internal_Rela *relend;
@@ -1831,6 +2028,7 @@ elf64_x86_64_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
sym_hashes = elf_sym_hashes (input_bfd);
local_got_offsets = elf_local_got_offsets (input_bfd);
+ local_tlsdesc_gotents = elf64_x86_64_local_tlsdesc_gotent (input_bfd);
rel = relocs;
relend = relocs + input_section->reloc_count;
@@ -1842,7 +2040,7 @@ elf64_x86_64_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
struct elf_link_hash_entry *h;
Elf_Internal_Sym *sym;
asection *sec;
- bfd_vma off;
+ bfd_vma off, offplt;
bfd_vma relocation;
bfd_boolean unresolved_reloc;
bfd_reloc_status_type r;
@@ -2201,6 +2399,8 @@ elf64_x86_64_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
break;
case R_X86_64_TLSGD:
+ case R_X86_64_GOTPC32_TLSDESC:
+ case R_X86_64_TLSDESC_CALL:
case R_X86_64_GOTTPOFF:
r_type = elf64_x86_64_tls_transition (info, r_type, h == NULL);
tls_type = GOT_UNKNOWN;
@@ -2212,7 +2412,9 @@ elf64_x86_64_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
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 (r_type == R_X86_64_TLSGD
+ || r_type == R_X86_64_GOTPC32_TLSDESC
+ || r_type == R_X86_64_TLSDESC_CALL)
{
if (tls_type == GOT_TLS_IE)
r_type = R_X86_64_GOTTPOFF;
@@ -2254,6 +2456,67 @@ elf64_x86_64_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
rel++;
continue;
}
+ else if (ELF64_R_TYPE (rel->r_info) == R_X86_64_GOTPC32_TLSDESC)
+ {
+ /* GDesc -> LE transition.
+ It's originally something like:
+ leaq x@tlsdesc(%rip), %rax
+
+ Change it to:
+ movl $x@tpoff, %rax
+
+ Registers other than %rax may be set up here. */
+
+ unsigned int val, type, type2;
+ bfd_vma roff;
+
+ /* First, make sure it's a leaq adding rip to a
+ 32-bit offset into any register, although it's
+ probably almost always going to be rax. */
+ roff = rel->r_offset;
+ BFD_ASSERT (roff >= 3);
+ type = bfd_get_8 (input_bfd, contents + roff - 3);
+ BFD_ASSERT ((type & 0xfb) == 0x48);
+ type2 = bfd_get_8 (input_bfd, contents + roff - 2);
+ BFD_ASSERT (type2 == 0x8d);
+ val = bfd_get_8 (input_bfd, contents + roff - 1);
+ BFD_ASSERT ((val & 0xc7) == 0x05);
+ BFD_ASSERT (roff + 4 <= input_section->size);
+
+ /* Now modify the instruction as appropriate. */
+ bfd_put_8 (output_bfd, 0x48 | ((type >> 2) & 1),
+ contents + roff - 3);
+ bfd_put_8 (output_bfd, 0xc7, contents + roff - 2);
+ bfd_put_8 (output_bfd, 0xc0 | ((val >> 3) & 7),
+ contents + roff - 1);
+ bfd_put_32 (output_bfd, tpoff (info, relocation),
+ contents + roff);
+ continue;
+ }
+ else if (ELF64_R_TYPE (rel->r_info) == R_X86_64_TLSDESC_CALL)
+ {
+ /* GDesc -> LE transition.
+ It's originally:
+ call *(%rax)
+ Turn it into:
+ nop; nop. */
+
+ unsigned int val, type;
+ bfd_vma roff;
+
+ /* First, make sure it's a call *(%rax). */
+ roff = rel->r_offset;
+ BFD_ASSERT (roff + 2 <= input_section->size);
+ type = bfd_get_8 (input_bfd, contents + roff);
+ BFD_ASSERT (type == 0xff);
+ val = bfd_get_8 (input_bfd, contents + roff + 1);
+ BFD_ASSERT (val == 0x10);
+
+ /* Now modify the instruction as appropriate. */
+ bfd_put_8 (output_bfd, 0x90, contents + roff);
+ bfd_put_8 (output_bfd, 0x90, contents + roff + 1);
+ continue;
+ }
else
{
unsigned int val, type, reg;
@@ -2319,13 +2582,17 @@ elf64_x86_64_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
abort ();
if (h != NULL)
- off = h->got.offset;
+ {
+ off = h->got.offset;
+ offplt = elf64_x86_64_hash_entry (h)->tlsdesc_got;
+ }
else
{
if (local_got_offsets == NULL)
abort ();
off = local_got_offsets[r_symndx];
+ offplt = local_tlsdesc_gotents[r_symndx];
}
if ((off & 1) != 0)
@@ -2335,30 +2602,61 @@ elf64_x86_64_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
Elf_Internal_Rela outrel;
bfd_byte *loc;
int dr_type, indx;
+ asection *sreloc;
if (htab->srelgot == NULL)
abort ();
+ indx = h && h->dynindx != -1 ? h->dynindx : 0;
+
+ if (GOT_TLS_GDESC_P (tls_type))
+ {
+ outrel.r_info = ELF64_R_INFO (indx, R_X86_64_TLSDESC);
+ BFD_ASSERT (htab->sgotplt_jump_table_size + offplt
+ + 2 * GOT_ENTRY_SIZE <= htab->sgotplt->size);
+ outrel.r_offset = (htab->sgotplt->output_section->vma
+ + htab->sgotplt->output_offset
+ + offplt
+ + htab->sgotplt_jump_table_size);
+ sreloc = htab->srelplt;
+ loc = sreloc->contents;
+ loc += sreloc->reloc_count++
+ * sizeof (Elf64_External_Rela);
+ BFD_ASSERT (loc + sizeof (Elf64_External_Rela)
+ <= sreloc->contents + sreloc->size);
+ if (indx == 0)
+ outrel.r_addend = relocation - dtpoff_base (info);
+ else
+ outrel.r_addend = 0;
+ bfd_elf64_swap_reloca_out (output_bfd, &outrel, loc);
+ }
+
+ sreloc = htab->srelgot;
+
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)
+ if (GOT_TLS_GD_P (tls_type))
dr_type = R_X86_64_DTPMOD64;
+ else if (GOT_TLS_GDESC_P (tls_type))
+ goto dr_done;
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)
+ if ((dr_type == R_X86_64_TPOFF64
+ || dr_type == R_X86_64_TLSDESC) && indx == 0)
outrel.r_addend = relocation - dtpoff_base (info);
outrel.r_info = ELF64_R_INFO (indx, dr_type);
- loc = htab->srelgot->contents;
- loc += htab->srelgot->reloc_count++ * sizeof (Elf64_External_Rela);
+ loc = sreloc->contents;
+ loc += sreloc->reloc_count++ * sizeof (Elf64_External_Rela);
+ BFD_ASSERT (loc + sizeof (Elf64_External_Rela)
+ <= sreloc->contents + sreloc->size);
bfd_elf64_swap_reloca_out (output_bfd, &outrel, loc);
- if (r_type == R_X86_64_TLSGD)
+ if (GOT_TLS_GD_P (tls_type))
{
if (indx == 0)
{
@@ -2374,27 +2672,37 @@ elf64_x86_64_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
outrel.r_info = ELF64_R_INFO (indx,
R_X86_64_DTPOFF64);
outrel.r_offset += GOT_ENTRY_SIZE;
- htab->srelgot->reloc_count++;
+ sreloc->reloc_count++;
loc += sizeof (Elf64_External_Rela);
+ BFD_ASSERT (loc + sizeof (Elf64_External_Rela)
+ <= sreloc->contents + sreloc->size);
bfd_elf64_swap_reloca_out (output_bfd, &outrel, loc);
}
}
+ dr_done:
if (h != NULL)
h->got.offset |= 1;
else
local_got_offsets[r_symndx] |= 1;
}
- if (off >= (bfd_vma) -2)
+ if (off >= (bfd_vma) -2
+ && ! GOT_TLS_GDESC_P (tls_type))
abort ();
if (r_type == ELF64_R_TYPE (rel->r_info))
{
- relocation = htab->sgot->output_section->vma
- + htab->sgot->output_offset + off;
+ if (r_type == R_X86_64_GOTPC32_TLSDESC
+ || r_type == R_X86_64_TLSDESC_CALL)
+ relocation = htab->sgotplt->output_section->vma
+ + htab->sgotplt->output_offset
+ + offplt + htab->sgotplt_jump_table_size;
+ else
+ relocation = htab->sgot->output_section->vma
+ + htab->sgot->output_offset + off;
unresolved_reloc = FALSE;
}
- else
+ else if (ELF64_R_TYPE (rel->r_info) == R_X86_64_TLSGD)
{
unsigned int i;
static unsigned char tlsgd[8]
@@ -2434,6 +2742,77 @@ elf64_x86_64_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
rel++;
continue;
}
+ else if (ELF64_R_TYPE (rel->r_info) == R_X86_64_GOTPC32_TLSDESC)
+ {
+ /* GDesc -> IE transition.
+ It's originally something like:
+ leaq x@tlsdesc(%rip), %rax
+
+ Change it to:
+ movq x@gottpoff(%rip), %rax # before nop; nop
+
+ Registers other than %rax may be set up here. */
+
+ unsigned int val, type, type2;
+ bfd_vma roff;
+
+ /* First, make sure it's a leaq adding rip to a 32-bit
+ offset into any register, although it's probably
+ almost always going to be rax. */
+ roff = rel->r_offset;
+ BFD_ASSERT (roff >= 3);
+ type = bfd_get_8 (input_bfd, contents + roff - 3);
+ BFD_ASSERT ((type & 0xfb) == 0x48);
+ type2 = bfd_get_8 (input_bfd, contents + roff - 2);
+ BFD_ASSERT (type2 == 0x8d);
+ val = bfd_get_8 (input_bfd, contents + roff - 1);
+ BFD_ASSERT ((val & 0xc7) == 0x05);
+ BFD_ASSERT (roff + 4 <= input_section->size);
+
+ /* Now modify the instruction as appropriate. */
+ /* To turn a leaq into a movq in the form we use it, it
+ suffices to change the second byte from 0x8d to
+ 0x8b. */
+ bfd_put_8 (output_bfd, 0x8b, contents + roff - 2);
+
+ bfd_put_32 (output_bfd,
+ htab->sgot->output_section->vma
+ + htab->sgot->output_offset + off
+ - rel->r_offset
+ - input_section->output_section->vma
+ - input_section->output_offset
+ - 4,
+ contents + roff);
+ continue;
+ }
+ else if (ELF64_R_TYPE (rel->r_info) == R_X86_64_TLSDESC_CALL)
+ {
+ /* GDesc -> IE transition.
+ It's originally:
+ call *(%rax)
+
+ Change it to:
+ nop; nop. */
+
+ unsigned int val, type;
+ bfd_vma roff;
+
+ /* First, make sure it's a call *(%eax). */
+ roff = rel->r_offset;
+ BFD_ASSERT (roff + 2 <= input_section->size);
+ type = bfd_get_8 (input_bfd, contents + roff);
+ BFD_ASSERT (type == 0xff);
+ val = bfd_get_8 (input_bfd, contents + roff + 1);
+ BFD_ASSERT (val == 0x10);
+
+ /* Now modify the instruction as appropriate. */
+ bfd_put_8 (output_bfd, 0x90, contents + roff);
+ bfd_put_8 (output_bfd, 0x90, contents + roff + 1);
+
+ continue;
+ }
+ else
+ BFD_ASSERT (FALSE);
break;
case R_X86_64_TLSLD:
@@ -2672,7 +3051,7 @@ elf64_x86_64_finish_dynamic_symbol (bfd *output_bfd,
}
if (h->got.offset != (bfd_vma) -1
- && elf64_x86_64_hash_entry (h)->tls_type != GOT_TLS_GD
+ && ! GOT_TLS_GD_ANY_P (elf64_x86_64_hash_entry (h)->tls_type)
&& elf64_x86_64_hash_entry (h)->tls_type != GOT_TLS_IE)
{
Elf_Internal_Rela rela;
@@ -2827,6 +3206,18 @@ elf64_x86_64_finish_dynamic_sections (bfd *output_bfd, struct bfd_link_info *inf
dyn.d_un.d_val -= s->size;
}
break;
+
+ case DT_TLSDESC_PLT:
+ s = htab->splt;
+ dyn.d_un.d_ptr = s->output_section->vma + s->output_offset
+ + htab->tlsdesc_plt;
+ break;
+
+ case DT_TLSDESC_GOT:
+ s = htab->sgot;
+ dyn.d_un.d_ptr = s->output_section->vma + s->output_offset
+ + htab->tlsdesc_got;
+ break;
}
bfd_elf64_swap_dyn_out (output_bfd, &dyn, dyncon);
@@ -2861,6 +3252,40 @@ elf64_x86_64_finish_dynamic_sections (bfd *output_bfd, struct bfd_link_info *inf
elf_section_data (htab->splt->output_section)->this_hdr.sh_entsize =
PLT_ENTRY_SIZE;
+
+ if (htab->tlsdesc_plt)
+ {
+ bfd_put_64 (output_bfd, (bfd_vma) 0,
+ htab->sgot->contents + htab->tlsdesc_got);
+
+ memcpy (htab->splt->contents + htab->tlsdesc_plt,
+ elf64_x86_64_plt0_entry,
+ PLT_ENTRY_SIZE);
+
+ /* Add offset for pushq GOT+8(%rip), since the
+ instruction uses 6 bytes subtract this value. */
+ bfd_put_32 (output_bfd,
+ (htab->sgotplt->output_section->vma
+ + htab->sgotplt->output_offset
+ + 8
+ - htab->splt->output_section->vma
+ - htab->splt->output_offset
+ - htab->tlsdesc_plt
+ - 6),
+ htab->splt->contents + htab->tlsdesc_plt + 2);
+ /* Add offset for jmp *GOT+TDG(%rip), where TGD stands for
+ htab->tlsdesc_got. The 12 is the offset to the end of
+ the instruction. */
+ bfd_put_32 (output_bfd,
+ (htab->sgot->output_section->vma
+ + htab->sgot->output_offset
+ + htab->tlsdesc_got
+ - htab->splt->output_section->vma
+ - htab->splt->output_offset
+ - htab->tlsdesc_plt
+ - 12),
+ htab->splt->contents + htab->tlsdesc_plt + 8);
+ }
}
}
@@ -3132,6 +3557,7 @@ static const struct bfd_elf_special_section
#define elf_backend_reloc_type_class elf64_x86_64_reloc_type_class
#define elf_backend_relocate_section elf64_x86_64_relocate_section
#define elf_backend_size_dynamic_sections elf64_x86_64_size_dynamic_sections
+#define elf_backend_always_size_sections elf64_x86_64_always_size_sections
#define elf_backend_plt_sym_val elf64_x86_64_plt_sym_val
#define elf_backend_object_p elf64_x86_64_elf_object_p
#define bfd_elf64_mkobject elf64_x86_64_mkobject
diff --git a/bfd/libbfd.h b/bfd/libbfd.h
index 5a8c216..984ade3 100644
--- a/bfd/libbfd.h
+++ b/bfd/libbfd.h
@@ -7,7 +7,7 @@
(This include file is not for users of the library.)
Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
- 1999, 2000, 2001, 2002, 2003, 2004, 2005
+ 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006
Free Software Foundation, Inc.
Written by Cygnus Support.
@@ -1034,6 +1034,9 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@",
"BFD_RELOC_386_TLS_DTPMOD32",
"BFD_RELOC_386_TLS_DTPOFF32",
"BFD_RELOC_386_TLS_TPOFF32",
+ "BFD_RELOC_386_TLS_GOTDESC",
+ "BFD_RELOC_386_TLS_DESC_CALL",
+ "BFD_RELOC_386_TLS_DESC",
"BFD_RELOC_X86_64_GOT32",
"BFD_RELOC_X86_64_PLT32",
"BFD_RELOC_X86_64_COPY",
@@ -1052,6 +1055,9 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@",
"BFD_RELOC_X86_64_TPOFF32",
"BFD_RELOC_X86_64_GOTOFF64",
"BFD_RELOC_X86_64_GOTPC32",
+ "BFD_RELOC_X86_64_GOTPC32_TLSDESC",
+ "BFD_RELOC_X86_64_TLSDESC_CALL",
+ "BFD_RELOC_X86_64_TLSDESC",
"BFD_RELOC_NS32K_IMM_8",
"BFD_RELOC_NS32K_IMM_16",
"BFD_RELOC_NS32K_IMM_32",
diff --git a/bfd/reloc.c b/bfd/reloc.c
index 14c3392..98246c8 100644
--- a/bfd/reloc.c
+++ b/bfd/reloc.c
@@ -1,6 +1,6 @@
/* BFD support for handling relocation entries.
Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
- 2000, 2001, 2002, 2003, 2004, 2005
+ 2000, 2001, 2002, 2003, 2004, 2005, 2006
Free Software Foundation, Inc.
Written by Cygnus Support.
@@ -2298,6 +2298,12 @@ ENUMX
BFD_RELOC_386_TLS_DTPOFF32
ENUMX
BFD_RELOC_386_TLS_TPOFF32
+ENUMX
+ BFD_RELOC_386_TLS_GOTDESC
+ENUMX
+ BFD_RELOC_386_TLS_DESC_CALL
+ENUMX
+ BFD_RELOC_386_TLS_DESC
ENUMDOC
i386/elf relocations
@@ -2337,6 +2343,12 @@ ENUMX
BFD_RELOC_X86_64_GOTOFF64
ENUMX
BFD_RELOC_X86_64_GOTPC32
+ENUMX
+ BFD_RELOC_X86_64_GOTPC32_TLSDESC
+ENUMX
+ BFD_RELOC_X86_64_TLSDESC_CALL
+ENUMX
+ BFD_RELOC_X86_64_TLSDESC
ENUMDOC
x86-64/elf relocations
diff --git a/binutils/ChangeLog b/binutils/ChangeLog
index 999ebd8..bbc0c9a 100644
--- a/binutils/ChangeLog
+++ b/binutils/ChangeLog
@@ -1,3 +1,9 @@
+2006-01-18 Alexandre Oliva <aoliva@redhat.com>
+
+ Introduce TLS descriptors for i386 and x86_64.
+ * readelf.c (get_dynamic_type): Handle DT_TLSDESC_GOT and
+ DT_TLSDESC_PLT.
+
2006-01-18 Nick Clifton <nickc@redhat.com>
PR binutils/1391
diff --git a/binutils/readelf.c b/binutils/readelf.c
index b432b0b..f0385d0 100644
--- a/binutils/readelf.c
+++ b/binutils/readelf.c
@@ -1480,6 +1480,8 @@ get_dynamic_type (unsigned long type)
case DT_VERSYM: return "VERSYM";
+ case DT_TLSDESC_GOT: return "TLSDESC_GOT";
+ case DT_TLSDESC_PLT: return "TLSDESC_PLT";
case DT_RELACOUNT: return "RELACOUNT";
case DT_RELCOUNT: return "RELCOUNT";
case DT_FLAGS_1: return "FLAGS_1";
diff --git a/gas/ChangeLog b/gas/ChangeLog
index 977f5a1..e93cece 100644
--- a/gas/ChangeLog
+++ b/gas/ChangeLog
@@ -1,3 +1,16 @@
+2006-01-18 Alexandre Oliva <aoliva@redhat.com>
+
+ Introduce TLS descriptors for i386 and x86_64.
+ * config/tc-i386.c (tc_i386_fix_adjustable): Handle
+ BFD_RELOC_386_TLS_GOTDESC, BFD_RELOC_386_TLS_DESC_CALL,
+ BFD_RELOC_X86_64_GOTPC32_TLSDESC, BFD_RELOC_X86_64_TLSDESC_CALL.
+ (optimize_disp): Emit fix up for BFD_RELOC_386_TLS_DESC_CALL and
+ BFD_RELOC_X86_64_TLSDESC_CALL immediately, and clear the
+ displacement bits.
+ (build_modrm_byte): Set up zero modrm for TLS desc calls.
+ (lex_got): Handle @tlsdesc and @tlscall.
+ (md_apply_fix, tc_gen_reloc): Handle the new relocations.
+
2006-01-11 Nick Clifton <nickc@redhat.com>
Fixes for building on 64-bit hosts:
diff --git a/gas/config/tc-i386.c b/gas/config/tc-i386.c
index f9804e0..337149e 100644
--- a/gas/config/tc-i386.c
+++ b/gas/config/tc-i386.c
@@ -1,6 +1,6 @@
/* i386.c -- Assemble code for the Intel 80386
Copyright 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
- 2000, 2001, 2002, 2003, 2004, 2005
+ 2000, 2001, 2002, 2003, 2004, 2005, 2006
Free Software Foundation, Inc.
This file is part of GAS, the GNU Assembler.
@@ -1345,6 +1345,8 @@ tc_i386_fix_adjustable (fixP)
|| fixP->fx_r_type == BFD_RELOC_386_TLS_GOTIE
|| fixP->fx_r_type == BFD_RELOC_386_TLS_LE_32
|| fixP->fx_r_type == BFD_RELOC_386_TLS_LE
+ || fixP->fx_r_type == BFD_RELOC_386_TLS_GOTDESC
+ || fixP->fx_r_type == BFD_RELOC_386_TLS_DESC_CALL
|| 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
@@ -1356,6 +1358,8 @@ tc_i386_fix_adjustable (fixP)
|| fixP->fx_r_type == BFD_RELOC_X86_64_TPOFF32
|| fixP->fx_r_type == BFD_RELOC_X86_64_TPOFF64
|| fixP->fx_r_type == BFD_RELOC_X86_64_GOTOFF64
+ || fixP->fx_r_type == BFD_RELOC_X86_64_GOTPC32_TLSDESC
+ || fixP->fx_r_type == BFD_RELOC_X86_64_TLSDESC_CALL
|| fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT
|| fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
return 0;
@@ -2196,7 +2200,14 @@ optimize_disp ()
&& fits_in_signed_byte (disp))
i.types[op] |= Disp8;
}
- else
+ else if (i.reloc[op] == BFD_RELOC_386_TLS_DESC_CALL
+ || i.reloc[op] == BFD_RELOC_X86_64_TLSDESC_CALL)
+ {
+ fix_new_exp (frag_now, frag_more (0) - frag_now->fr_literal, 0,
+ i.op[op].disps, 0, i.reloc[op]);
+ i.types[op] &= ~Disp;
+ }
+ else
/* We only support 64bit displacement on constants. */
i.types[op] &= ~Disp64;
}
@@ -3157,7 +3168,13 @@ build_modrm_byte ()
if ((i.index_reg->reg_flags & RegRex) != 0)
i.rex |= REX_EXTY;
}
- i.rm.mode = mode_from_disp_size (i.types[op]);
+
+ if (i.disp_operands
+ && (i.reloc[op] == BFD_RELOC_386_TLS_DESC_CALL
+ || i.reloc[op] == BFD_RELOC_X86_64_TLSDESC_CALL))
+ i.rm.mode = 0;
+ else
+ i.rm.mode = mode_from_disp_size (i.types[op]);
}
if (fake_zero_displacement)
@@ -3856,7 +3873,9 @@ lex_got (enum bfd_reloc_code_real *reloc,
{ "DTPOFF", { BFD_RELOC_386_TLS_LDO_32, BFD_RELOC_X86_64_DTPOFF32 }, Imm32|Imm32S|Imm64|Disp32|Disp64 },
{ "GOTNTPOFF",{ BFD_RELOC_386_TLS_GOTIE, 0 }, 0 },
{ "INDNTPOFF",{ BFD_RELOC_386_TLS_IE, 0 }, 0 },
- { "GOT", { BFD_RELOC_386_GOT32, BFD_RELOC_X86_64_GOT32 }, Imm32|Imm32S|Disp32 }
+ { "GOT", { BFD_RELOC_386_GOT32, BFD_RELOC_X86_64_GOT32 }, Imm32|Imm32S|Disp32 },
+ { "TLSDESC", { BFD_RELOC_386_TLS_GOTDESC, BFD_RELOC_X86_64_GOTPC32_TLSDESC }, Imm32|Imm32S|Disp32 },
+ { "TLSCALL", { BFD_RELOC_386_TLS_DESC_CALL, BFD_RELOC_X86_64_TLSDESC_CALL }, Imm32|Imm32S|Disp32 }
};
char *cp;
unsigned int j;
@@ -5063,9 +5082,11 @@ md_apply_fix (fixP, valP, seg)
case BFD_RELOC_386_TLS_IE_32:
case BFD_RELOC_386_TLS_IE:
case BFD_RELOC_386_TLS_GOTIE:
+ case BFD_RELOC_386_TLS_GOTDESC:
case BFD_RELOC_X86_64_TLSGD:
case BFD_RELOC_X86_64_TLSLD:
case BFD_RELOC_X86_64_GOTTPOFF:
+ case BFD_RELOC_X86_64_GOTPC32_TLSDESC:
value = 0; /* Fully resolved at runtime. No addend. */
/* Fallthrough */
case BFD_RELOC_386_TLS_LE:
@@ -5078,6 +5099,13 @@ md_apply_fix (fixP, valP, seg)
S_SET_THREAD_LOCAL (fixP->fx_addsy);
break;
+ case BFD_RELOC_386_TLS_DESC_CALL:
+ case BFD_RELOC_X86_64_TLSDESC_CALL:
+ value = 0; /* Fully resolved at runtime. No addend. */
+ S_SET_THREAD_LOCAL (fixP->fx_addsy);
+ fixP->fx_done = 0;
+ return;
+
case BFD_RELOC_386_GOT32:
case BFD_RELOC_X86_64_GOT32:
value = 0; /* Fully resolved at runtime. No addend. */
@@ -5655,6 +5683,8 @@ tc_gen_reloc (section, fixp)
case BFD_RELOC_386_TLS_GOTIE:
case BFD_RELOC_386_TLS_LE_32:
case BFD_RELOC_386_TLS_LE:
+ case BFD_RELOC_386_TLS_GOTDESC:
+ case BFD_RELOC_386_TLS_DESC_CALL:
case BFD_RELOC_X86_64_TLSGD:
case BFD_RELOC_X86_64_TLSLD:
case BFD_RELOC_X86_64_DTPOFF32:
@@ -5664,6 +5694,8 @@ tc_gen_reloc (section, fixp)
case BFD_RELOC_X86_64_TPOFF64:
case BFD_RELOC_X86_64_GOTOFF64:
case BFD_RELOC_X86_64_GOTPC32:
+ case BFD_RELOC_X86_64_GOTPC32_TLSDESC:
+ case BFD_RELOC_X86_64_TLSDESC_CALL:
case BFD_RELOC_RVA:
case BFD_RELOC_VTABLE_ENTRY:
case BFD_RELOC_VTABLE_INHERIT:
@@ -5760,6 +5792,8 @@ tc_gen_reloc (section, fixp)
case BFD_RELOC_X86_64_TLSGD:
case BFD_RELOC_X86_64_TLSLD:
case BFD_RELOC_X86_64_GOTTPOFF:
+ case BFD_RELOC_X86_64_GOTPC32_TLSDESC:
+ case BFD_RELOC_X86_64_TLSDESC_CALL:
rel->addend = fixp->fx_offset - fixp->fx_size;
break;
default:
diff --git a/include/elf/ChangeLog b/include/elf/ChangeLog
index 372bef5..1bac01d 100644
--- a/include/elf/ChangeLog
+++ b/include/elf/ChangeLog
@@ -1,3 +1,12 @@
+2006-01-18 Alexandre Oliva <aoliva@redhat.com>
+
+ Introduce TLS descriptors for i386 and x86_64.
+ * common.h (DT_TLSDESC_GOT, DT_TLSDESC_PLT): New.
+ * i386.h (R_386_TLS_GOTDESC, R_386_TLS_DESC_CALL, R_386_TLS_DESC):
+ New.
+ * x86-64.h (R_X86_64_GOTPC32_TLSDESC, R_X86_64_TLSDESC_CALL,
+ R_X86_64_TLSDESC): New.
+
2006-01-09 Mike Frysinger <vapier@gentoo.org>:
* common.h (EM_ALTERA_NIOS2, EM_NIOS32) Define.
diff --git a/include/elf/common.h b/include/elf/common.h
index 0108c4f..350d63b 100644
--- a/include/elf/common.h
+++ b/include/elf/common.h
@@ -1,6 +1,6 @@
/* ELF support for BFD.
Copyright 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
- 2001, 2002, 2003, 2004
+ 2001, 2002, 2003, 2004, 2005, 2006
Free Software Foundation, Inc.
Written by Fred Fish @ Cygnus Support, from information published
@@ -576,6 +576,8 @@
#define DT_VALRNGHI 0x6ffffdff
#define DT_ADDRRNGLO 0x6ffffe00
+#define DT_TLSDESC_PLT 0x6ffffef6
+#define DT_TLSDESC_GOT 0x6ffffef7
#define DT_GNU_CONFLICT 0x6ffffef8
#define DT_GNU_LIBLIST 0x6ffffef9
#define DT_CONFIG 0x6ffffefa
diff --git a/include/elf/i386.h b/include/elf/i386.h
index 5a4d330..e167871 100644
--- a/include/elf/i386.h
+++ b/include/elf/i386.h
@@ -1,5 +1,6 @@
/* ix86 ELF support for BFD.
- Copyright 1998, 1999, 2000, 2002, 2004 Free Software Foundation, Inc.
+ Copyright 1998, 1999, 2000, 2002, 2004, 2005, 2006
+ Free Software Foundation, Inc.
This file is part of BFD, the Binary File Descriptor library.
@@ -61,6 +62,10 @@ START_RELOC_NUMBERS (elf_i386_reloc_type)
RELOC_NUMBER (R_386_TLS_DTPMOD32, 35)
RELOC_NUMBER (R_386_TLS_DTPOFF32, 36)
RELOC_NUMBER (R_386_TLS_TPOFF32, 37)
+/* 38 */
+ RELOC_NUMBER (R_386_TLS_GOTDESC, 39)
+ RELOC_NUMBER (R_386_TLS_DESC_CALL,40)
+ RELOC_NUMBER (R_386_TLS_DESC, 41)
/* Used by Intel. */
RELOC_NUMBER (R_386_USED_BY_INTEL_200, 200)
diff --git a/include/elf/x86-64.h b/include/elf/x86-64.h
index 309be6b..74655fb 100644
--- a/include/elf/x86-64.h
+++ b/include/elf/x86-64.h
@@ -1,5 +1,6 @@
/* x86_64 ELF support for BFD.
- Copyright (C) 2000, 2001, 2002, 2004 Free Software Foundation, Inc.
+ Copyright (C) 2000, 2001, 2002, 2004, 2005, 2006
+ Free Software Foundation, Inc.
Contributed by Jan Hubicka <jh@suse.cz>
This file is part of BFD, the Binary File Descriptor library.
@@ -53,6 +54,14 @@ START_RELOC_NUMBERS (elf_x86_64_reloc_type)
RELOC_NUMBER (R_X86_64_GOTOFF64, 25) /* 64 bit offset to GOT */
RELOC_NUMBER (R_X86_64_GOTPC32, 26) /* 32 bit signed pc relative
offset to GOT */
+ /* 27 .. 33 */
+ RELOC_NUMBER (R_X86_64_GOTPC32_TLSDESC, 34)
+ /* 32 bit signed pc relative
+ offset to TLS descriptor
+ in the GOT. */
+ RELOC_NUMBER (R_X86_64_TLSDESC_CALL, 35) /* Relaxable call through TLS
+ descriptor. */
+ RELOC_NUMBER (R_X86_64_TLSDESC, 36) /* 2x64-bit TLS descriptor. */
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)
diff --git a/ld/testsuite/ChangeLog b/ld/testsuite/ChangeLog
index 63da63d..62d6318 100644
--- a/ld/testsuite/ChangeLog
+++ b/ld/testsuite/ChangeLog
@@ -1,3 +1,39 @@
+2006-01-18 Alexandre Oliva <aoliva@redhat.com>
+
+ Introduce TLS descriptors for i386 and x86_64.
+ * ld-i386/i386.exp: Run on x86_64-*-linux* and amd64-*-linux*.
+ Add new tests.
+ * ld-i386/pcrel16.d: Add -melf_i386.
+ * ld-i386/pcrel8.d: Likewise.
+ * ld-i386/tlsbindesc.dd: New.
+ * ld-i386/tlsbindesc.rd: New.
+ * ld-i386/tlsbindesc.s: New.
+ * ld-i386/tlsbindesc.sd: New.
+ * ld-i386/tlsbindesc.td: New.
+ * ld-i386/tlsdesc.dd: New.
+ * ld-i386/tlsdesc.rd: New.
+ * ld-i386/tlsdesc.s: New.
+ * ld-i386/tlsdesc.sd: New.
+ * ld-i386/tlsdesc.td: New.
+ * ld-i386/tlsgdesc.dd: New.
+ * ld-i386/tlsgdesc.rd: New.
+ * ld-i386/tlsgdesc.s: New.
+ * ld-x86-64/x86-64.exp: Run new tests.
+ * ld-x86-64/tlsbindesc.dd: New.
+ * ld-x86-64/tlsbindesc.rd: New.
+ * ld-x86-64/tlsbindesc.s: New.
+ * ld-x86-64/tlsbindesc.sd: New.
+ * ld-x86-64/tlsbindesc.td: New.
+ * ld-x86-64/tlsdesc.dd: New.
+ * ld-x86-64/tlsdesc.pd: New.
+ * ld-x86-64/tlsdesc.rd: New.
+ * ld-x86-64/tlsdesc.s: New.
+ * ld-x86-64/tlsdesc.sd: New.
+ * ld-x86-64/tlsdesc.td: New.
+ * ld-x86-64/tlsgdesc.dd: New.
+ * ld-x86-64/tlsgdesc.rd: New.
+ * ld-x86-64/tlsgdesc.s: New.
+
2006-01-03 Hans-Peter Nilsson <hp@bitrange.com>
* ld-mmix/sec-1.d: Adjust for section order changes.
diff --git a/ld/testsuite/ld-i386/i386.exp b/ld/testsuite/ld-i386/i386.exp
index 05343f0..4a170cd 100644
--- a/ld/testsuite/ld-i386/i386.exp
+++ b/ld/testsuite/ld-i386/i386.exp
@@ -1,5 +1,5 @@
# Expect script for ld-i386 tests
-# Copyright (C) 2002 Free Software Foundation
+# Copyright (C) 2002, 2005, 2006 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
@@ -22,7 +22,9 @@
if { !([istarget "i?86-*-elf*"]
|| ([istarget "i?86-*-linux*"]
&& ![istarget "*-*-*aout*"]
- && ![istarget "*-*-*oldld*"])) } {
+ && ![istarget "*-*-*oldld*"])
+ || [istarget "x86_64-*-linux*"]
+ || [istarget "amd64-*-linux*"]) } {
return
}
@@ -41,6 +43,11 @@ set i386tests {
{{readelf -Ssrl tlspic.rd} {objdump -drj.text tlspic.dd}
{objdump -sj.got tlspic.sd} {objdump -sj.tdata tlspic.td}}
"libtlspic.so"}
+ {"TLS descriptor -fpic -shared transitions" "-shared -melf_i386"
+ "--32" {tlsdesc.s tlspic2.s}
+ {{readelf -Ssrl tlsdesc.rd} {objdump -drj.text tlsdesc.dd}
+ {objdump "-s -j.got -j.got.plt" tlsdesc.sd} {objdump -sj.tdata tlsdesc.td}}
+ "libtlsdesc.so"}
{"Helper shared library" "-shared -melf_i386"
"--32" {tlslib.s} {} "libtlslib.so"}
{"TLS -fpic and -fno-pic exec transitions"
@@ -48,10 +55,19 @@ set i386tests {
{{readelf -Ssrl tlsbin.rd} {objdump -drj.text tlsbin.dd}
{objdump -sj.got tlsbin.sd} {objdump -sj.tdata tlsbin.td}}
"tlsbin"}
+ {"TLS descriptor -fpic and -fno-pic exec transitions"
+ "-melf_i386 tmpdir/libtlslib.so" "--32" {tlsbindesc.s tlsbin.s}
+ {{readelf -Ssrl tlsbindesc.rd} {objdump -drj.text tlsbindesc.dd}
+ {objdump -sj.got tlsbindesc.sd} {objdump -sj.tdata tlsbindesc.td}}
+ "tlsbindesc"}
{"TLS -fno-pic -shared" "-shared -melf_i386"
"--32" {tlsnopic1.s tlsnopic2.s}
{{readelf -Ssrl tlsnopic.rd} {objdump -drj.text tlsnopic.dd}
{objdump -sj.got tlsnopic.sd}} "libtlsnopic.so"}
+ {"TLS with global dynamic and descriptors"
+ "-shared -melf_i386" "--32" {tlsgdesc.s}
+ {{readelf -Ssrl tlsgdesc.rd} {objdump -drj.text tlsgdesc.dd}}
+ "libtlsgdesc.so"}
{"TLS in debug sections" "-melf_i386"
"--32" {tlsg.s}
{{objdump -sj.debug_foobar tlsg.sd}} "tlsg"}
diff --git a/ld/testsuite/ld-i386/pcrel16.d b/ld/testsuite/ld-i386/pcrel16.d
index 0c438a9..3d45afe 100644
--- a/ld/testsuite/ld-i386/pcrel16.d
+++ b/ld/testsuite/ld-i386/pcrel16.d
@@ -1,5 +1,6 @@
#name: PCREL16 overflow
-#ld: -Ttext 0x0
+#as: --32
+#ld: -melf_i386 -Ttext 0x0
#objdump: -drj.text -m i8086
.*: +file format elf32-i386
diff --git a/ld/testsuite/ld-i386/pcrel8.d b/ld/testsuite/ld-i386/pcrel8.d
index ed939a3..208c64e 100644
--- a/ld/testsuite/ld-i386/pcrel8.d
+++ b/ld/testsuite/ld-i386/pcrel8.d
@@ -1,3 +1,4 @@
#name: PCREL8 overflow
-#ld:
+#as: --32
+#ld: -melf_i386
#error: .*relocation truncated to fit: R_386_PC8 .*
diff --git a/ld/testsuite/ld-i386/tlsbindesc.dd b/ld/testsuite/ld-i386/tlsbindesc.dd
new file mode 100644
index 0000000..071a5b3
--- /dev/null
+++ b/ld/testsuite/ld-i386/tlsbindesc.dd
@@ -0,0 +1,463 @@
+#source: tlsbindesc.s
+#source: tlsbin.s
+#as: --32
+#ld: -melf_i386 tmpdir/libtlslib.so
+#objdump: -drj.text
+#target: i?86-*-*
+
+# 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 elf32-i386
+
+Disassembly of section .text:
+
+[0-9a-f]+ <fn2>:
+ [0-9a-f]+: 55[ ]+push %ebp
+ [0-9a-f]+: 89 e5[ ]+mov %esp,%ebp
+ [0-9a-f]+: 53[ ]+push %ebx
+ [0-9a-f]+: 50[ ]+push %eax
+ [0-9a-f]+: e8 00 00 00 00[ ]+call [0-9a-f]+ <fn2\+0xa>
+ [0-9a-f]+: 5b[ ]+pop %ebx
+ [0-9a-f]+: 81 c3 fa 10 00 00[ ]+add \$0x10fa,%ebx
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+# GD -> IE because variable is not defined in executable
+ [0-9a-f]+: 8b 83 f8 ff ff ff[ ]+mov 0xfffffff8\(%ebx\),%eax
+# ->R_386_TLS_TPOFF32 sG1
+ [0-9a-f]+: f7 d8[ ]+neg %eax
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+# GD -> IE because variable is not defined in executable where
+# the variable is referenced through @gottpoff too
+ [0-9a-f]+: 8b 83 e8 ff ff ff[ ]+mov 0xffffffe8\(%ebx\),%eax
+# ->R_386_TLS_TPOFF32 sG2
+ [0-9a-f]+: f7 d8[ ]+neg %eax
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+# GD -> IE because variable is not defined in executable where
+# the variable is referenced through @gotntpoff too
+ [0-9a-f]+: 8b 83 dc ff ff ff[ ]+mov 0xffffffdc\(%ebx\),%eax
+# ->R_386_TLS_TPOFF sG3
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+# GD -> IE because variable is not defined in executable where
+# the variable is referenced through @gottpoff and @gotntpoff too
+ [0-9a-f]+: 8b 83 f0 ff ff ff[ ]+mov 0xfffffff0\(%ebx\),%eax
+# ->R_386_TLS_TPOFF32 sG4
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+# GD -> LE with global variable defined in executable
+ [0-9a-f]+: 8d 05 00 f0 ff ff[ ]+lea 0xfffff000,%eax
+# sg1
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+# GD -> LE with local variable defined in executable
+ [0-9a-f]+: 8d 05 20 f0 ff ff[ ]+lea 0xfffff020,%eax
+# sl1
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+# GD -> LE with hidden variable defined in executable
+ [0-9a-f]+: 8d 05 40 f0 ff ff[ ]+lea 0xfffff040,%eax
+# sh1
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+# LD -> LE
+ [0-9a-f]+: 8d 05 00 f0 ff ff[ ]+lea 0xfffff000,%eax
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 8d 90 20 f0 ff ff[ ]+lea 0xfffff020\(%eax\),%edx
+# sl1
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 8d 88 24 f0 ff ff[ ]+lea 0xfffff024\(%eax\),%ecx
+# sl2
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+# LD -> LE against hidden variables
+ [0-9a-f]+: 8d 05 00 f0 ff ff[ ]+lea 0xfffff000,%eax
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 8d 90 40 f0 ff ff[ ]+lea 0xfffff040\(%eax\),%edx
+# sh1
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 8d 88 44 f0 ff ff[ ]+lea 0xfffff044\(%eax\),%ecx
+# sh2
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+# @gottpoff IE against global var
+ [0-9a-f]+: 65 8b 0d 00 00 00 00[ ]+mov %gs:0x0,%ecx
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 2b 8b e8 ff ff ff[ ]+sub 0xffffffe8\(%ebx\),%ecx
+# ->R_386_TLS_TPOFF32 sG2
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+# @gottpoff IE against global var
+ [0-9a-f]+: 65 a1 00 00 00 00[ ]+mov %gs:0x0,%eax
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 2b 83 ec ff ff ff[ ]+sub 0xffffffec\(%ebx\),%eax
+# ->R_386_TLS_TPOFF32 sG4
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+# @gotntpoff IE against global var
+ [0-9a-f]+: 65 8b 0d 00 00 00 00[ ]+mov %gs:0x0,%ecx
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 03 8b dc ff ff ff[ ]+add 0xffffffdc\(%ebx\),%ecx
+# ->R_386_TLS_TPOFF sG3
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+# @gotntpoff IE against global var
+ [0-9a-f]+: 65 a1 00 00 00 00[ ]+mov %gs:0x0,%eax
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 03 83 f0 ff ff ff[ ]+add 0xfffffff0\(%ebx\),%eax
+# ->R_386_TLS_TPOFF sG4
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+# @gottpoff IE -> LE against global var defined in exec
+ [0-9a-f]+: 65 8b 0d 00 00 00 00[ ]+mov %gs:0x0,%ecx
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 81 e9 00 10 00 00[ ]+sub \$0x1000,%ecx
+# sg1
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+# @gotntpoff IE -> LE against local var
+ [0-9a-f]+: 65 8b 0d 00 00 00 00[ ]+mov %gs:0x0,%ecx
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 81 c0 20 f0 ff ff[ ]+add \$0xfffff020,%eax
+# sl1
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+# @gottpoff IE -> LE against hidden var
+ [0-9a-f]+: 65 8b 0d 00 00 00 00[ ]+mov %gs:0x0,%ecx
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 81 e9 c0 0f 00 00[ ]+sub \$0xfc0,%ecx
+# sh1
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+# Direct access through %gs
+# @gotntpoff IE against global var
+ [0-9a-f]+: 8b 8b e0 ff ff ff[ ]+mov 0xffffffe0\(%ebx\),%ecx
+# ->R_386_TLS_TPOFF sG5
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 65 8b 11[ ]+mov %gs:\(%ecx\),%edx
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+# @gotntpoff IE->LE against local var
+ [0-9a-f]+: c7 c0 30 f0 ff ff[ ]+mov \$0xfffff030,%eax
+# sl5
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 65 8b 10[ ]+mov %gs:\(%eax\),%edx
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+# @gotntpoff IE->LE against hidden var
+ [0-9a-f]+: c7 c2 50 f0 ff ff[ ]+mov \$0xfffff050,%edx
+# sh5
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 65 8b 12[ ]+mov %gs:\(%edx\),%edx
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 8b 5d fc[ ]+mov 0xfffffffc\(%ebp\),%ebx
+ [0-9a-f]+: c9[ ]+leave *
+ [0-9a-f]+: c3[ ]+ret *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+
+[0-9a-f]+ <_start>:
+ [0-9a-f]+: 55[ ]+push %ebp
+ [0-9a-f]+: 89 e5[ ]+mov %esp,%ebp
+ [0-9a-f]+: e8 00 00 00 00[ ]+call [0-9a-f]+ <_start\+0x8>
+ [0-9a-f]+: 59[ ]+pop %ecx
+ [0-9a-f]+: 81 c1 a4 0f 00 00[ ]+add \$0xfa4,%ecx
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+# @gottpoff IE against global var
+ [0-9a-f]+: 65 8b 15 00 00 00 00[ ]+mov %gs:0x0,%edx
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 2b 91 f4 ff ff ff[ ]+sub 0xfffffff4\(%ecx\),%edx
+# ->R_386_TLS_TPOFF32 sG6
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+# @indntpoff IE against global var
+ [0-9a-f]+: 65 a1 00 00 00 00[ ]+mov %gs:0x0,%eax
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 03 05 e8 a0 04 08[ ]+add 0x804a0e8,%eax
+# ->R_386_TLS_TPOFF sG7
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+# @indntpoff direct %gs access IE against global var
+ [0-9a-f]+: 8b 15 00 a1 04 08[ ]+mov 0x804a100,%edx
+# ->R_386_TLS_TPOFF sG8
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 65 8b 02[ ]+mov %gs:\(%edx\),%eax
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+# @gottpoff IE -> LE against global var defined in exec
+ [0-9a-f]+: 65 8b 15 00 00 00 00[ ]+mov %gs:0x0,%edx
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 81 ea 8c 0f 00 00[ ]+sub \$0xf8c,%edx
+# bg6
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+# @indntpoff IE -> LE against global var defined in exec
+ [0-9a-f]+: 65 a1 00 00 00 00[ ]+mov %gs:0x0,%eax
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 81 c0 78 f0 ff ff[ ]+add \$0xfffff078,%eax
+# bg7
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+# @indntpoff direct %gs access IE -> LE against global var defined
+# in exec
+ [0-9a-f]+: c7 c2 7c f0 ff ff[ ]+mov \$0xfffff07c,%edx
+# bg8
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 65 8b 02[ ]+mov %gs:\(%edx\),%eax
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+# @gottpoff IE -> LE against local var
+ [0-9a-f]+: 65 8b 15 00 00 00 00[ ]+mov %gs:0x0,%edx
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 81 ea 6c 0f 00 00[ ]+sub \$0xf6c,%edx
+# bl6
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+# @indntpoff IE -> LE against local var
+ [0-9a-f]+: 65 a1 00 00 00 00[ ]+mov %gs:0x0,%eax
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 81 c0 98 f0 ff ff[ ]+add \$0xfffff098,%eax
+# bl7
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+# @indntpoff direct %gs access IE -> LE against local var
+ [0-9a-f]+: c7 c2 9c f0 ff ff[ ]+mov \$0xfffff09c,%edx
+# bl8
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 65 8b 02[ ]+mov %gs:\(%edx\),%eax
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+# @gottpoff IE -> LE against hidden but not local var
+ [0-9a-f]+: 65 8b 15 00 00 00 00[ ]+mov %gs:0x0,%edx
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 81 ea ac 0f 00 00[ ]+sub \$0xfac,%edx
+# sh6
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+# @indntpoff IE -> LE against hidden but not local var
+ [0-9a-f]+: 65 a1 00 00 00 00[ ]+mov %gs:0x0,%eax
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 81 c0 58 f0 ff ff[ ]+add \$0xfffff058,%eax
+# sh7
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+# @indntpoff direct %gs access IE -> LE against hidden but not
+# local var
+ [0-9a-f]+: c7 c2 5c f0 ff ff[ ]+mov \$0xfffff05c,%edx
+# sh8
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 65 8b 02[ ]+mov %gs:\(%edx\),%eax
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+# LE @tpoff, global var defined in exec
+ [0-9a-f]+: ba 00 10 00 00[ ]+mov \$0x1000,%edx
+# sg1
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 65 a1 00 00 00 00[ ]+mov %gs:0x0,%eax
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 29 d0[ ]+sub %edx,%eax
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+# LE @tpoff, local var
+ [0-9a-f]+: b8 7f 0f 00 00[ ]+mov \$0xf7f,%eax
+# bl1+1
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 65 8b 15 00 00 00 00[ ]+mov %gs:0x0,%edx
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 29 c2[ ]+sub %eax,%edx
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+# LE @tpoff, hidden var defined in exec
+ [0-9a-f]+: b8 bd 0f 00 00[ ]+mov \$0xfbd,%eax
+# sh1+3
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 65 8b 15 00 00 00 00[ ]+mov %gs:0x0,%edx
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 29 c2[ ]+sub %eax,%edx
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+# LE @ntpoff, global var defined in exec
+ [0-9a-f]+: 65 a1 00 00 00 00[ ]+mov %gs:0x0,%eax
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 8d 90 04 f0 ff ff[ ]+lea 0xfffff004\(%eax\),%edx
+# sg2
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+# LE @ntpoff, local var, non-canonical sequence
+ [0-9a-f]+: b8 86 f0 ff ff[ ]+mov \$0xfffff086,%eax
+# bl2+2
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 65 8b 15 00 00 00 00[ ]+mov %gs:0x0,%edx
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 01 c2[ ]+add %eax,%edx
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+# LE @ntpoff, hidden var defined in exec, non-canonical sequence
+ [0-9a-f]+: 65 8b 15 00 00 00 00[ ]+mov %gs:0x0,%edx
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 81 c2 45 f0 ff ff[ ]+add \$0xfffff045,%edx
+# sh2+1
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+# LE @ntpoff, global var defined in exec
+ [0-9a-f]+: 65 a1 08 f0 ff ff[ ]+mov %gs:0xfffff008,%eax
+# sg3
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+# LE @ntpoff, local var
+ [0-9a-f]+: 65 8b 15 8b f0 ff ff[ ]+mov %gs:0xfffff08b,%edx
+# bl3+3
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+# LE @ntpoff, hidden var defined in exec
+ [0-9a-f]+: 65 8b 15 49 f0 ff ff[ ]+mov %gs:0xfffff049,%edx
+# sh3+1
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 8b 5d fc[ ]+mov 0xfffffffc\(%ebp\),%ebx
+ [0-9a-f]+: c9[ ]+leave *
+ [0-9a-f]+: c3[ ]+ret *
diff --git a/ld/testsuite/ld-i386/tlsbindesc.rd b/ld/testsuite/ld-i386/tlsbindesc.rd
new file mode 100644
index 0000000..27d0670
--- /dev/null
+++ b/ld/testsuite/ld-i386/tlsbindesc.rd
@@ -0,0 +1,154 @@
+#source: tlsbindesc.s
+#source: tlsbin.s
+#as: --32
+#ld: -melf_i386 tmpdir/libtlslib.so
+#readelf: -Ssrl
+#target: i?86-*-*
+
+There are 15 section headers, starting at offset 0x[0-9a-f]+:
+
+Section Headers:
+ \[Nr\] Name +Type +Addr +Off +Size +ES Flg Lk Inf Al
+ \[ 0\] +NULL +0+ 0+ 0+ 0+ +0 +0 +0
+ \[ 1\] \.interp +.*
+ \[ 2\] \.hash +.*
+ \[ 3\] \.dynsym +.*
+ \[ 4\] \.dynstr +.*
+ \[ 5\] \.rel.dyn +.*
+ \[ 6\] \.text +PROGBITS +0+8049000 .*
+ \[ 7\] \.tdata +PROGBITS +0+804a000 [0-9a-f]+ 000060 00 WAT 0 0 4096
+ \[ 8\] \.tbss +NOBITS +[0-9a-f]+ [0-9a-f]+ 000040 00 WAT 0 0 1
+ \[ 9\] \.dynamic +DYNAMIC +0+804a060 .*
+ \[10\] \.got +PROGBITS +0+804a0e0 .*
+ \[11\] \.got\.plt +PROGBITS +0+804a104 .*
+ \[12\] \.shstrtab +.*
+ \[13\] \.symtab +.*
+ \[14\] \.strtab +.*
+Key to Flags:
+.*
+.*
+.*
+
+Elf file type is EXEC \(Executable file\)
+Entry point 0x8049158
+There are 6 program headers, starting at offset [0-9]+
+
+Program Headers:
+ Type +Offset +VirtAddr +PhysAddr +FileSiz +MemSiz +Flg Align
+ PHDR.*
+ INTERP.*
+.*Requesting program interpreter.*
+ LOAD.*
+ LOAD.*
+ DYNAMIC.*
+ TLS +0x[0-9a-f]+ 0x[0-9a-f]+ 0x[0-9a-f]+ 0x0+60 0x0+a0 R +0x1000
+
+ Section to Segment mapping:
+ Segment Sections...
+ 00 +
+ 01 +.interp *
+ 02 +.interp .hash .dynsym .dynstr .rel.dyn .text *
+ 03 +.tdata .dynamic .got .got.plt *
+ 04 +.dynamic *
+ 05 +.tdata .tbss *
+
+Relocation section '.rel.dyn' at offset 0x[0-9a-f]+ contains 9 entries:
+ Offset +Info +Type +Sym.Value +Sym. Name
+0+804a0e0 0000010e R_386_TLS_TPOFF +0+ +sG3
+0+804a0e4 0000020e R_386_TLS_TPOFF +0+ +sG5
+0+804a0e8 0000030e R_386_TLS_TPOFF +0+ +sG7
+0+804a0ec 00000425 R_386_TLS_TPOFF32 0+ +sG2
+0+804a0f0 00000525 R_386_TLS_TPOFF32 0+ +sG4
+0+804a0f4 0000050e R_386_TLS_TPOFF +0+ +sG4
+0+804a0f8 00000725 R_386_TLS_TPOFF32 0+ +sG6
+0+804a0fc 00000825 R_386_TLS_TPOFF32 0+ +sG1
+0+804a100 00000b0e R_386_TLS_TPOFF +0+ +sG8
+
+Symbol table '.dynsym' contains 12 entries:
+ +Num: +Value Size Type +Bind +Vis +Ndx Name
+ +[0-9]+: 0+ +0 NOTYPE LOCAL DEFAULT UND *
+ +[0-9]+: 0+ +0 TLS +GLOBAL DEFAULT UND sG3
+ +[0-9]+: 0+ +0 TLS +GLOBAL DEFAULT UND sG5
+ +[0-9]+: 0+ +0 TLS +GLOBAL DEFAULT UND sG7
+ +[0-9]+: 0+ +0 TLS +GLOBAL DEFAULT UND sG2
+ +[0-9]+: 0+ +0 TLS +GLOBAL DEFAULT UND sG4
+ +[0-9]+: [0-9a-f]+ +0 NOTYPE GLOBAL DEFAULT ABS __bss_start
+ +[0-9]+: 0+ +0 TLS +GLOBAL DEFAULT UND sG6
+ +[0-9]+: 0+ +0 TLS +GLOBAL DEFAULT UND sG1
+ +[0-9]+: [0-9a-f]+ +0 NOTYPE GLOBAL DEFAULT ABS _edata
+ +[0-9]+: [0-9a-f]+ +0 NOTYPE GLOBAL DEFAULT ABS _end
+ +[0-9]+: 0+ +0 TLS +GLOBAL DEFAULT UND sG8
+
+Symbol table '.symtab' contains 71 entries:
+ +Num: +Value Size Type +Bind +Vis +Ndx Name
+ +[0-9]+: 0+ +0 NOTYPE LOCAL DEFAULT UND *
+ +[0-9]+: [0-9a-f]+ +0 SECTION LOCAL DEFAULT +1 *
+ +[0-9]+: [0-9a-f]+ +0 SECTION LOCAL DEFAULT +2 *
+ +[0-9]+: [0-9a-f]+ +0 SECTION LOCAL DEFAULT +3 *
+ +[0-9]+: [0-9a-f]+ +0 SECTION LOCAL DEFAULT +4 *
+ +[0-9]+: [0-9a-f]+ +0 SECTION LOCAL DEFAULT +5 *
+ +[0-9]+: [0-9a-f]+ +0 SECTION LOCAL DEFAULT +6 *
+ +[0-9]+: [0-9a-f]+ +0 SECTION LOCAL DEFAULT +7 *
+ +[0-9]+: [0-9a-f]+ +0 SECTION LOCAL DEFAULT +8 *
+ +[0-9]+: [0-9a-f]+ +0 SECTION LOCAL DEFAULT +9 *
+ +[0-9]+: [0-9a-f]+ +0 SECTION LOCAL DEFAULT +10 *
+ +[0-9]+: [0-9a-f]+ +0 SECTION LOCAL DEFAULT +11 *
+ +[0-9]+: [0-9a-f]+ +0 SECTION LOCAL DEFAULT +12 *
+ +[0-9]+: [0-9a-f]+ +0 SECTION LOCAL DEFAULT +13 *
+ +[0-9]+: [0-9a-f]+ +0 SECTION LOCAL DEFAULT +14 *
+ +[0-9]+: 00000020 +0 TLS +LOCAL DEFAULT +7 sl1
+ +[0-9]+: 00000024 +0 TLS +LOCAL DEFAULT +7 sl2
+ +[0-9]+: 00000028 +0 TLS +LOCAL DEFAULT +7 sl3
+ +[0-9]+: 0000002c +0 TLS +LOCAL DEFAULT +7 sl4
+ +[0-9]+: 00000030 +0 TLS +LOCAL DEFAULT +7 sl5
+ +[0-9]+: 00000034 +0 TLS +LOCAL DEFAULT +7 sl6
+ +[0-9]+: 00000038 +0 TLS +LOCAL DEFAULT +7 sl7
+ +[0-9]+: 0000003c +0 TLS +LOCAL DEFAULT +7 sl8
+ +[0-9]+: 00000080 +0 TLS +LOCAL DEFAULT +8 bl1
+ +[0-9]+: 00000084 +0 TLS +LOCAL DEFAULT +8 bl2
+ +[0-9]+: 00000088 +0 TLS +LOCAL DEFAULT +8 bl3
+ +[0-9]+: 0000008c +0 TLS +LOCAL DEFAULT +8 bl4
+ +[0-9]+: 00000090 +0 TLS +LOCAL DEFAULT +8 bl5
+ +[0-9]+: 00000094 +0 TLS +LOCAL DEFAULT +8 bl6
+ +[0-9]+: 00000098 +0 TLS +LOCAL DEFAULT +8 bl7
+ +[0-9]+: 0000009c +0 TLS +LOCAL DEFAULT +8 bl8
+ +[0-9]+: 00000000 +0 TLS +LOCAL HIDDEN +7 _TLS_MODULE_BASE_
+ +[0-9]+: 0+804a060 +0 OBJECT LOCAL HIDDEN 9 _DYNAMIC
+ +[0-9]+: [0-9a-f]+ +0 OBJECT LOCAL HIDDEN 11 _GLOBAL_OFFSET_TABLE_
+ +[0-9]+: 0+ +0 TLS +GLOBAL DEFAULT UND sG3
+ +[0-9]+: 0000001c +0 TLS +GLOBAL DEFAULT +7 sg8
+ +[0-9]+: 0000007c +0 TLS +GLOBAL DEFAULT +8 bg8
+ +[0-9]+: 00000074 +0 TLS +GLOBAL DEFAULT +8 bg6
+ +[0-9]+: 0+ +0 TLS +GLOBAL DEFAULT UND sG5
+ +[0-9]+: 00000068 +0 TLS +GLOBAL DEFAULT +8 bg3
+ +[0-9]+: 00000008 +0 TLS +GLOBAL DEFAULT +7 sg3
+ +[0-9]+: 0+ +0 TLS +GLOBAL DEFAULT UND sG7
+ +[0-9]+: 00000048 +0 TLS +GLOBAL HIDDEN +7 sh3
+ +[0-9]+: 0+ +0 TLS +GLOBAL DEFAULT UND sG2
+ +[0-9]+: 0000000c +0 TLS +GLOBAL DEFAULT +7 sg4
+ +[0-9]+: 0+ +0 TLS +GLOBAL DEFAULT UND sG4
+ +[0-9]+: 00000010 +0 TLS +GLOBAL DEFAULT +7 sg5
+ +[0-9]+: 00000070 +0 TLS +GLOBAL DEFAULT +8 bg5
+ +[0-9]+: 00000058 +0 TLS +GLOBAL HIDDEN +7 sh7
+ +[0-9]+: 0000005c +0 TLS +GLOBAL HIDDEN +7 sh8
+ +[0-9]+: 0+ +0 TLS +GLOBAL DEFAULT +7 sg1
+ +[0-9]+: 0+8049158 +0 FUNC +GLOBAL DEFAULT +6 _start
+ +[0-9]+: 0000004c +0 TLS +GLOBAL HIDDEN +7 sh4
+ +[0-9]+: 00000078 +0 TLS +GLOBAL DEFAULT +8 bg7
+ +[0-9]+: 00000050 +0 TLS +GLOBAL HIDDEN +7 sh5
+ +[0-9]+: [0-9a-f]+ +0 NOTYPE GLOBAL DEFAULT ABS __bss_start
+ +[0-9]+: 0+ +0 TLS +GLOBAL DEFAULT UND sG6
+ +[0-9]+: 0+8049000 +0 FUNC +GLOBAL DEFAULT +6 fn2
+ +[0-9]+: 00000004 +0 TLS +GLOBAL DEFAULT +7 sg2
+ +[0-9]+: 0+ +0 TLS +GLOBAL DEFAULT UND sG1
+ +[0-9]+: 00000040 +0 TLS +GLOBAL HIDDEN +7 sh1
+ +[0-9]+: 00000014 +0 TLS +GLOBAL DEFAULT +7 sg6
+ +[0-9]+: 00000018 +0 TLS +GLOBAL DEFAULT +7 sg7
+ +[0-9]+: [0-9a-f]+ +0 NOTYPE GLOBAL DEFAULT ABS _edata
+ +[0-9]+: [0-9a-f]+ +0 NOTYPE GLOBAL DEFAULT ABS _end
+ +[0-9]+: 00000044 +0 TLS +GLOBAL HIDDEN +7 sh2
+ +[0-9]+: 00000054 +0 TLS +GLOBAL HIDDEN +7 sh6
+ +[0-9]+: 0+ +0 TLS +GLOBAL DEFAULT UND sG8
+ +[0-9]+: 00000064 +0 TLS +GLOBAL DEFAULT +8 bg2
+ +[0-9]+: 00000060 +0 TLS +GLOBAL DEFAULT +8 bg1
+ +[0-9]+: 0000006c +0 TLS +GLOBAL DEFAULT +8 bg4
diff --git a/ld/testsuite/ld-i386/tlsbindesc.s b/ld/testsuite/ld-i386/tlsbindesc.s
new file mode 100644
index 0000000..9094d08
--- /dev/null
+++ b/ld/testsuite/ld-i386/tlsbindesc.s
@@ -0,0 +1,167 @@
+ /* Force .got aligned to 4K, so it very likely gets at 0x804a100
+ (0x60 bytes .tdata and 0xa0 bytes .dynamic) */
+ .section ".tdata", "awT", @progbits
+ .balign 4096
+ .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 0x8049000. */
+ .text
+ .balign 4096
+ .globl fn2
+ .type fn2,@function
+fn2:
+ pushl %ebp
+ movl %esp, %ebp
+ pushl %ebx
+ pushl %eax
+ call 1f
+1: popl %ebx
+ addl $_GLOBAL_OFFSET_TABLE_+[.-1b], %ebx
+ nop;nop;nop;nop
+
+ /* GD -> IE because variable is not defined in executable */
+ leal sG1@tlsdesc(%ebx), %eax
+ call *sG1@tlscall(%eax)
+ nop;nop;nop;nop
+
+ /* GD -> IE because variable is not defined in executable where
+ the variable is referenced through @gottpoff too */
+ leal sG2@tlsdesc(%ebx), %eax
+ call *sG2@tlscall(%eax)
+ nop;nop;nop;nop
+
+ /* GD -> IE because variable is not defined in executable where
+ the variable is referenced through @gotntpoff too */
+ leal sG3@tlsdesc(%ebx), %eax
+ call *sG3@tlscall(%eax)
+ nop;nop;nop;nop
+
+ /* GD -> IE because variable is not defined in executable where
+ the variable is referenced through @gottpoff and @gotntpoff too */
+ leal sG4@tlsdesc(%ebx), %eax
+ call *sG4@tlscall(%eax)
+ nop;nop;nop;nop
+
+ /* GD -> LE with global variable defined in executable */
+ leal sg1@tlsdesc(%ebx), %eax
+ call *sg1@tlscall(%eax)
+ nop;nop;nop;nop
+
+ /* GD -> LE with local variable defined in executable */
+ leal sl1@tlsdesc(%ebx), %eax
+ call *sl1@tlscall(%eax)
+ nop;nop;nop;nop
+
+ /* GD -> LE with hidden variable defined in executable */
+ leal sh1@tlsdesc(%ebx), %eax
+ call *sh1@tlscall(%eax)
+ nop;nop;nop;nop
+
+ /* LD -> LE */
+ leal _TLS_MODULE_BASE_@tlsdesc(%ebx), %eax
+ call *_TLS_MODULE_BASE_@tlscall(%eax)
+ nop;nop
+ leal sl1@dtpoff(%eax), %edx
+ nop;nop
+ leal sl2@dtpoff(%eax), %ecx
+ nop;nop;nop;nop
+
+ /* LD -> LE against hidden variables */
+ leal _TLS_MODULE_BASE_@tlsdesc(%ebx), %eax
+ call *_TLS_MODULE_BASE_@tlscall(%eax)
+ nop;nop
+ leal sh1@dtpoff(%eax), %edx
+ nop;nop
+ leal sh2@dtpoff(%eax), %ecx
+ nop;nop;nop;nop
+
+ /* @gottpoff IE against global var */
+ movl %gs:0, %ecx
+ nop;nop
+ subl sG2@gottpoff(%ebx), %ecx
+ nop;nop;nop;nop
+
+ /* @gottpoff IE against global var */
+ movl %gs:0, %eax
+ nop;nop
+ subl sG4@gottpoff(%ebx), %eax
+ nop;nop;nop;nop
+
+ /* @gotntpoff IE against global var */
+ movl %gs:0, %ecx
+ nop;nop
+ addl sG3@gotntpoff(%ebx), %ecx
+ nop;nop;nop;nop
+
+ /* @gotntpoff IE against global var */
+ movl %gs:0, %eax
+ nop;nop
+ addl sG4@gotntpoff(%ebx), %eax
+ nop;nop;nop;nop
+
+ /* @gottpoff IE -> LE against global var defined in exec */
+ movl %gs:0, %ecx
+ nop;nop
+ subl sg1@gottpoff(%ebx), %ecx
+ nop;nop;nop;nop
+
+ /* @gotntpoff IE -> LE against local var */
+ movl %gs:0, %ecx
+ nop;nop
+ addl sl1@gotntpoff(%ebx), %eax
+ nop;nop;nop;nop
+
+ /* @gottpoff IE -> LE against hidden var */
+ movl %gs:0, %ecx
+ nop;nop
+ subl sh1@gottpoff(%ebx), %ecx
+ nop;nop;nop;nop
+
+ /* Direct access through %gs */
+
+ /* @gotntpoff IE against global var */
+ movl sG5@gotntpoff(%ebx), %ecx
+ nop;nop
+ movl %gs:(%ecx), %edx
+ nop;nop;nop;nop
+
+ /* @gotntpoff IE->LE against local var */
+ movl sl5@gotntpoff(%ebx), %eax
+ nop;nop
+ movl %gs:(%eax), %edx
+ nop;nop;nop;nop
+
+ /* @gotntpoff IE->LE against hidden var */
+ movl sh5@gotntpoff(%ebx), %edx
+ nop;nop
+ movl %gs:(%edx), %edx
+ nop;nop;nop;nop
+
+ movl -4(%ebp), %ebx
+ leave
+ ret
diff --git a/ld/testsuite/ld-i386/tlsbindesc.sd b/ld/testsuite/ld-i386/tlsbindesc.sd
new file mode 100644
index 0000000..a87f5da
--- /dev/null
+++ b/ld/testsuite/ld-i386/tlsbindesc.sd
@@ -0,0 +1,13 @@
+#source: tlsbindesc.s
+#source: tlsbin.s
+#as: --32
+#ld: -melf_i386 tmpdir/libtlslib.so
+#objdump: -sj.got
+#target: i?86-*-*
+
+.*: file format elf32-i386
+
+Contents of section \.got:
+ 804a0e0 [0-9a-f]+ 00000000 00000000 [0-9a-f]+ .*
+ 804a0f0 00000000 00000000 00000000 00000000 .*
+ 804a100 00000000 +.*
diff --git a/ld/testsuite/ld-i386/tlsbindesc.td b/ld/testsuite/ld-i386/tlsbindesc.td
new file mode 100644
index 0000000..726df3e
--- /dev/null
+++ b/ld/testsuite/ld-i386/tlsbindesc.td
@@ -0,0 +1,16 @@
+#source: tlsbindesc.s
+#source: tlsbin.s
+#as: --32
+#ld: -melf_i386 tmpdir/libtlslib.so
+#objdump: -sj.tdata
+#target: i?86-*-*
+
+.*: file format elf32-i386
+
+Contents of section \.tdata:
+ 804a000 11000000 12000000 13000000 14000000 .*
+ 804a010 15000000 16000000 17000000 18000000 .*
+ 804a020 41000000 42000000 43000000 44000000 .*
+ 804a030 45000000 46000000 47000000 48000000 .*
+ 804a040 01010000 02010000 03010000 04010000 .*
+ 804a050 05010000 06010000 07010000 08010000 .*
diff --git a/ld/testsuite/ld-i386/tlsdesc.dd b/ld/testsuite/ld-i386/tlsdesc.dd
new file mode 100644
index 0000000..666f790
--- /dev/null
+++ b/ld/testsuite/ld-i386/tlsdesc.dd
@@ -0,0 +1,399 @@
+#source: tlsdesc.s
+#source: tlspic2.s
+#as: --32
+#ld: -shared -melf_i386
+#objdump: -drj.text
+#target: i?86-*-*
+
+.*: +file format elf32-i386
+
+Disassembly of section .text:
+
+[0-9a-f]+ <fn1>:
+ [0-9a-f]+: 55[ ]+push %ebp
+ [0-9a-f]+: 89 e5[ ]+mov %esp,%ebp
+ [0-9a-f]+: 53[ ]+push %ebx
+ [0-9a-f]+: 50[ ]+push %eax
+ [0-9a-f]+: e8 00 00 00 00[ ]+call [0-9a-f]+ <fn1\+0xa>
+ [0-9a-f]+: 5b[ ]+pop %ebx
+ [0-9a-f]+: 81 c3 9a 13 00 00[ ]+add \$0x[0-9a-f]+,%ebx
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+# GDesc
+ [0-9a-f]+: 8d 83 24 00 00 00[ ]+lea 0x24\(%ebx\),%eax
+# ->R_386_TLS_DESC sg1
+ [0-9a-f]+: ff 10[ ]+call \*\(%eax\)
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+# GD -> IE because variable is referenced through @gottpoff too
+ [0-9a-f]+: 8b 83 f8 ff ff ff[ ]+mov 0xfffffff8\(%ebx\),%eax
+# ->R_386_TLS_TPOFF sg2
+ [0-9a-f]+: f7 d8[ ]+neg %eax
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+# GD -> IE because variable is referenced through @gotntpoff too
+ [0-9a-f]+: 8b 83 c4 ff ff ff[ ]+mov 0xffffffc4\(%ebx\),%eax
+# ->R_386_TLS_TPOFF32 sg3
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+# GD -> IE because variable is referenced through @gottpoff and
+ [0-9a-f]+: 8b 83 d4 ff ff ff[ ]+mov 0xffffffd4\(%ebx\),%eax
+# ->R_386_TLS_TPOFF32 sg4
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+# GD against local variable
+ [0-9a-f]+: 8d 83 0c 00 00 00[ ]+lea 0xc\(%ebx\),%eax
+# ->R_386_TLS_DESC sl1
+ [0-9a-f]+: ff 10[ ]+call \*\(%eax\)
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+# GD -> IE against local variable referenced through @gottpoff too
+ [0-9a-f]+: 8b 83 b0 ff ff ff[ ]+mov 0xffffffb0\(%ebx\),%eax
+# ->R_386_TLS_TPOFF sl2
+ [0-9a-f]+: f7 d8[ ]+neg %eax
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+# GD -> IE against local variable referenced through @gotntpoff
+ [0-9a-f]+: 8b 83 b4 ff ff ff[ ]+mov 0xffffffb4\(%ebx\),%eax
+# ->R_386_TLS_TPOFF32 sl3
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+# GD -> IE against local variable referenced through @gottpoff and
+ [0-9a-f]+: 8b 83 bc ff ff ff[ ]+mov 0xffffffbc\(%ebx\),%eax
+# ->R_386_TLS_TPOFF32 sl4
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+# GD against hidden and local variable
+ [0-9a-f]+: 8d 83 2c 00 00 00[ ]+lea 0x2c\(%ebx\),%eax
+# ->R_386_TLS_DESC sh1
+ [0-9a-f]+: ff 10[ ]+call \*\(%eax\)
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+# GD -> IE against hidden and local variable referenced through @gottpoff too
+ [0-9a-f]+: 8b 83 fc ff ff ff[ ]+mov 0xfffffffc\(%ebx\),%eax
+# ->R_386_TLS_TPOFF sh2
+ [0-9a-f]+: f7 d8[ ]+neg %eax
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+# GD -> IE against hidden and local variable referenced through @gotntpoff too
+ [0-9a-f]+: 8b 83 c8 ff ff ff[ ]+mov 0xffffffc8\(%ebx\),%eax
+# ->R_386_TLS_TPOFF32 sh3
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+# GD -> IE against hidden and local variable referenced through @gottpoff and @gotntpoff too
+ [0-9a-f]+: 8b 83 e8 ff ff ff[ ]+mov 0xffffffe8\(%ebx\),%eax
+# ->R_386_TLS_TPOFF32 sh4
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+# GD against hidden but not local variable
+ [0-9a-f]+: 8d 83 14 00 00 00[ ]+lea 0x14\(%ebx\),%eax
+# ->R_386_TLS_DESC sH1
+ [0-9a-f]+: ff 10[ ]+call \*\(%eax\)
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+# GD -> IE against hidden but not local variable referenced through
+ [0-9a-f]+: 8b 83 cc ff ff ff[ ]+mov 0xffffffcc\(%ebx\),%eax
+# ->R_386_TLS_TPOFF sH2
+ [0-9a-f]+: f7 d8[ ]+neg %eax
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+# GD -> IE against hidden but not local variable referenced through
+ [0-9a-f]+: 8b 83 ec ff ff ff[ ]+mov 0xffffffec\(%ebx\),%eax
+# ->R_386_TLS_TPOFF32 sH3
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+# GD -> IE against hidden but not local variable referenced through
+ [0-9a-f]+: 8b 83 e0 ff ff ff[ ]+mov 0xffffffe0\(%ebx\),%eax
+# ->R_386_TLS_TPOFF32 sH4
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+# LD
+ [0-9a-f]+: 8d 83 1c 00 00 00[ ]+lea 0x1c\(%ebx\),%eax
+# ->R_386_TLS_DESC _TLS_MODULE_BASE_
+ [0-9a-f]+: ff 10[ ]+call \*\(%eax\)
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 8d 90 20 00 00 00[ ]+lea 0x20\(%eax\),%edx
+# sl1
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 8d 88 26 00 00 00[ ]+lea 0x26\(%eax\),%ecx
+# sl2+2
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+# LD against hidden and local variables
+ [0-9a-f]+: 8d 90 40 00 00 00[ ]+lea 0x40\(%eax\),%edx
+# sh1
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 8d 88 47 00 00 00[ ]+lea 0x47\(%eax\),%ecx
+# sh2+3
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+# LD against hidden but not local variables
+ [0-9a-f]+: 8d 90 60 00 00 00[ ]+lea 0x60\(%eax\),%edx
+# sH1
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 8d 88 65 00 00 00[ ]+lea 0x65\(%eax\),%ecx
+# sH2+1
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+# @gottpoff IE against global var
+ [0-9a-f]+: 65 8b 0d 00 00 00 00[ ]+mov %gs:0x0,%ecx
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 2b 8b f8 ff ff ff[ ]+sub 0xfffffff8\(%ebx\),%ecx
+# ->R_386_TLS_TPOFF32 sg2
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+# @gottpoff IE against global var
+ [0-9a-f]+: 65 a1 00 00 00 00[ ]+mov %gs:0x0,%eax
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 2b 83 d0 ff ff ff[ ]+sub 0xffffffd0\(%ebx\),%eax
+# ->R_386_TLS_TPOFF32 sg4
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+# @gotntpoff IE against global var
+ [0-9a-f]+: 65 8b 0d 00 00 00 00[ ]+mov %gs:0x0,%ecx
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 03 8b c4 ff ff ff[ ]+add 0xffffffc4\(%ebx\),%ecx
+# ->R_386_TLS_TPOFF sg3
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+# @gotntpoff IE against global var
+ [0-9a-f]+: 65 a1 00 00 00 00[ ]+mov %gs:0x0,%eax
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 03 83 d4 ff ff ff[ ]+add 0xffffffd4\(%ebx\),%eax
+# ->R_386_TLS_TPOFF sg4
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+# @gottpoff IE against local var
+ [0-9a-f]+: 65 8b 0d 00 00 00 00[ ]+mov %gs:0x0,%ecx
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 2b 8b b0 ff ff ff[ ]+sub 0xffffffb0\(%ebx\),%ecx
+# ->R_386_TLS_TPOFF32 [0xdcffffff]
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+# @gottpoff IE against local var
+ [0-9a-f]+: 65 a1 00 00 00 00[ ]+mov %gs:0x0,%eax
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 2b 83 b8 ff ff ff[ ]+sub 0xffffffb8\(%ebx\),%eax
+# ->R_386_TLS_TPOFF32 [0xd4ffffff]
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+# @gotntpoff IE against local var
+ [0-9a-f]+: 65 8b 0d 00 00 00 00[ ]+mov %gs:0x0,%ecx
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 03 8b b4 ff ff ff[ ]+add 0xffffffb4\(%ebx\),%ecx
+# ->R_386_TLS_TPOFF [0x28000000]
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+# @gotntpoff IE against local var
+ [0-9a-f]+: 65 a1 00 00 00 00[ ]+mov %gs:0x0,%eax
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 03 83 bc ff ff ff[ ]+add 0xffffffbc\(%ebx\),%eax
+# ->R_386_TLS_TPOFF [0x2c000000]
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+# @gottpoff IE against hidden and local var
+ [0-9a-f]+: 65 8b 0d 00 00 00 00[ ]+mov %gs:0x0,%ecx
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 2b 8b fc ff ff ff[ ]+sub 0xfffffffc\(%ebx\),%ecx
+# ->R_386_TLS_TPOFF32 [0xbcffffff]
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+# @gottpoff IE against hidden and local var
+ [0-9a-f]+: 65 a1 00 00 00 00[ ]+mov %gs:0x0,%eax
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 2b 83 e4 ff ff ff[ ]+sub 0xffffffe4\(%ebx\),%eax
+# ->R_386_TLS_TPOFF32 [0xb4ffffff]
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+# @gotntpoff IE against hidden and local var
+ [0-9a-f]+: 65 8b 0d 00 00 00 00[ ]+mov %gs:0x0,%ecx
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 03 8b c8 ff ff ff[ ]+add 0xffffffc8\(%ebx\),%ecx
+# ->R_386_TLS_TPOFF [0x48000000]
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+# @gotntpoff IE against hidden and local var
+ [0-9a-f]+: 65 a1 00 00 00 00[ ]+mov %gs:0x0,%eax
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 03 83 e8 ff ff ff[ ]+add 0xffffffe8\(%ebx\),%eax
+# ->R_386_TLS_TPOFF [0x4c000000]
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+# @gottpoff IE against hidden but not local var
+ [0-9a-f]+: 65 8b 0d 00 00 00 00[ ]+mov %gs:0x0,%ecx
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 2b 8b cc ff ff ff[ ]+sub 0xffffffcc\(%ebx\),%ecx
+# ->R_386_TLS_TPOFF32 [0x9cffffff]
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+# @gottpoff IE against hidden but not local var
+ [0-9a-f]+: 65 a1 00 00 00 00[ ]+mov %gs:0x0,%eax
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 2b 83 dc ff ff ff[ ]+sub 0xffffffdc\(%ebx\),%eax
+# ->R_386_TLS_TPOFF32 [0x94ffffff]
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+# @gotntpoff IE against hidden but not local var
+ [0-9a-f]+: 65 8b 0d 00 00 00 00[ ]+mov %gs:0x0,%ecx
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 03 8b ec ff ff ff[ ]+add 0xffffffec\(%ebx\),%ecx
+# ->R_386_TLS_TPOFF [0x68000000]
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+# @gotntpoff IE against hidden but not local var
+ [0-9a-f]+: 65 a1 00 00 00 00[ ]+mov %gs:0x0,%eax
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 03 83 e0 ff ff ff[ ]+add 0xffffffe0\(%ebx\),%eax
+# ->R_386_TLS_TPOFF [0x6c000000]
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+# Direct access through %gs
+# @gotntpoff IE against global var
+ [0-9a-f]+: 8b 8b d8 ff ff ff[ ]+mov 0xffffffd8\(%ebx\),%ecx
+# ->R_386_TLS_TPOFF sg5
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 65 8b 11[ ]+mov %gs:\(%ecx\),%edx
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+# @gotntpoff IE against local var
+ [0-9a-f]+: 8b 83 c0 ff ff ff[ ]+mov 0xffffffc0\(%ebx\),%eax
+# ->R_386_TLS_TPOFF [0x30000000]
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 65 8b 10[ ]+mov %gs:\(%eax\),%edx
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+# @gotntpoff IE against hidden and local var
+ [0-9a-f]+: 8b 93 f0 ff ff ff[ ]+mov 0xfffffff0\(%ebx\),%edx
+# ->R_386_TLS_TPOFF [0x50000000]
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 65 8b 12[ ]+mov %gs:\(%edx\),%edx
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+# @gotntpoff IE against hidden but not local var
+ [0-9a-f]+: 8b 8b f4 ff ff ff[ ]+mov 0xfffffff4\(%ebx\),%ecx
+# ->R_386_TLS_TPOFF [0x70000000]
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 65 8b 11[ ]+mov %gs:\(%ecx\),%edx
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 8b 5d fc[ ]+mov 0xfffffffc\(%ebp\),%ebx
+ [0-9a-f]+: c9[ ]+leave *
+ [0-9a-f]+: c3[ ]+ret *
diff --git a/ld/testsuite/ld-i386/tlsdesc.rd b/ld/testsuite/ld-i386/tlsdesc.rd
new file mode 100644
index 0000000..12fd5d4
--- /dev/null
+++ b/ld/testsuite/ld-i386/tlsdesc.rd
@@ -0,0 +1,155 @@
+#source: tlsdesc.s
+#source: tlspic2.s
+#as: --32
+#ld: -shared -melf_i386
+#readelf: -Ssrl
+#target: i?86-*-*
+
+There are [0-9]+ section headers, starting at offset 0x.*:
+
+Section Headers:
+ \[Nr\] Name +Type +Addr +Off +Size +ES Flg Lk Inf Al
+ \[ 0\] +NULL +0+ 0+ 0+ 0+ +0 +0 +0
+ \[ 1\] \.hash +.*
+ \[ 2\] \.dynsym +.*
+ \[ 3\] \.dynstr +.*
+ \[ 4\] \.rel.dyn +.*
+ \[ 5\] \.rel.plt +.*
+ \[ 6\] \.text +.*
+ \[ 7\] \.tdata +PROGBITS +[0-9a-f]+ [0-9a-f]+ 000060 00 WAT 0 0 1
+ \[ 8\] \.tbss +NOBITS +[0-9aa-f]+ [0-9a-f]+ 000020 00 WAT 0 0 1
+ \[ 9\] \.dynamic +.*
+ \[10\] \.got +.*
+ \[11\] \.got.plt +.*
+ \[12\] \.shstrtab +.*
+ \[13\] \.symtab +.*
+ \[14\] \.strtab +.*
+Key to Flags:
+.*
+.*
+.*
+
+Elf file type is DYN \(Shared object file\)
+Entry point 0x[0-9a-f]+
+There are [0-9]+ program headers, starting at offset [0-9]+
+
+Program Headers:
+ Type +Offset +VirtAddr +PhysAddr +FileSiz +MemSiz +Flg Align
+ LOAD.*
+ LOAD.*
+ DYNAMIC.*
+ TLS +0x[0-9a-f]+ 0x[0-9a-f]+ 0x[0-9a-f]+ 0x0+60 0x0+80 R +0x1
+
+ Section to Segment mapping:
+ Segment Sections...
+ 00 +.hash .dynsym .dynstr .rel.dyn .rel.plt .text *
+ 01 +.tdata .dynamic .got .got.plt *
+ 02 +.dynamic *
+ 03 +.tdata .tbss *
+
+Relocation section '.rel.dyn' at offset 0x[0-9a-f]+ contains 20 entries:
+ Offset +Info +Type +Sym.Value +Sym. Name
+[0-9a-f]+ +0+25 R_386_TLS_TPOFF32
+[0-9a-f]+ +0+0e R_386_TLS_TPOFF *
+[0-9a-f]+ +0+25 R_386_TLS_TPOFF32
+[0-9a-f]+ +0+0e R_386_TLS_TPOFF *
+[0-9a-f]+ +0+0e R_386_TLS_TPOFF *
+[0-9a-f]+ +0+0e R_386_TLS_TPOFF *
+[0-9a-f]+ +0+25 R_386_TLS_TPOFF32
+[0-9a-f]+ +0+25 R_386_TLS_TPOFF32
+[0-9a-f]+ +0+0e R_386_TLS_TPOFF *
+[0-9a-f]+ +0+25 R_386_TLS_TPOFF32
+[0-9a-f]+ +0+0e R_386_TLS_TPOFF *
+[0-9a-f]+ +0+0e R_386_TLS_TPOFF *
+[0-9a-f]+ +0+0e R_386_TLS_TPOFF *
+[0-9a-f]+ +0+0e R_386_TLS_TPOFF *
+[0-9a-f]+ +0+25 R_386_TLS_TPOFF32
+[0-9a-f]+ +0+50e R_386_TLS_TPOFF 0+8 sg3
+[0-9a-f]+ +0+625 R_386_TLS_TPOFF32 0+c sg4
+[0-9a-f]+ +0+60e R_386_TLS_TPOFF 0+c sg4
+[0-9a-f]+ +0+70e R_386_TLS_TPOFF 0+10 sg5
+[0-9a-f]+ +0+b25 R_386_TLS_TPOFF32 0+4 sg2
+
+Relocation section '.rel.plt' at offset 0x[0-9a-f]+ contains 5 entries:
+ Offset Info Type Sym.Value Sym. Name
+[0-9a-f]+ +0+829 R_386_TLS_DESC * 0+ sg1
+[0-9a-f]+ +0+29 R_386_TLS_DESC *
+[0-9a-f]+ +0+29 R_386_TLS_DESC *
+[0-9a-f]+ +0+29 R_386_TLS_DESC *
+[0-9a-f]+ +0+29 R_386_TLS_DESC *
+
+Symbol table '.dynsym' contains 16 entries:
+ +Num: + Value Size Type + Bind +Vis +Ndx Name
+ +[0-9]+: 0+ +0 NOTYPE LOCAL DEFAULT UND *
+ +[0-9]+: [0-9a-f]+ +0 SECTION LOCAL DEFAULT +6 *
+ +[0-9]+: [0-9a-f]+ +0 SECTION LOCAL DEFAULT +7 *
+ +[0-9]+: [0-9a-f]+ +0 SECTION LOCAL DEFAULT +8 *
+ +[0-9]+: 0+1c +0 TLS +GLOBAL DEFAULT +7 sg8
+ +[0-9]+: 0+8 +0 TLS +GLOBAL DEFAULT +7 sg3
+ +[0-9]+: 0+c +0 TLS +GLOBAL DEFAULT +7 sg4
+ +[0-9]+: 0+10 +0 TLS +GLOBAL DEFAULT +7 sg5
+ +[0-9]+: 0+ +0 TLS +GLOBAL DEFAULT +7 sg1
+ +[0-9]+: [0-9a-f]+ +0 FUNC +GLOBAL DEFAULT +6 fn1
+ +[0-9]+: [0-9a-f]+ +0 NOTYPE GLOBAL DEFAULT ABS __bss_start
+ +[0-9]+: 0+4 +0 TLS +GLOBAL DEFAULT +7 sg2
+ +[0-9]+: 0+14 +0 TLS +GLOBAL DEFAULT +7 sg6
+ +[0-9]+: 0+18 +0 TLS +GLOBAL DEFAULT +7 sg7
+ +[0-9]+: [0-9a-f]+ +0 NOTYPE GLOBAL DEFAULT ABS _edata
+ +[0-9]+: [0-9a-f]+ +0 NOTYPE GLOBAL DEFAULT ABS _end
+
+Symbol table '.symtab' contains 54 entries:
+ +Num: +Value Size Type +Bind +Vis +Ndx Name
+ +[0-9]+: 0+ +0 NOTYPE LOCAL DEFAULT UND *
+ +[0-9]+: [0-9a-f]+ +0 SECTION LOCAL DEFAULT +1 *
+ +[0-9]+: [0-9a-f]+ +0 SECTION LOCAL DEFAULT +2 *
+ +[0-9]+: [0-9a-f]+ +0 SECTION LOCAL DEFAULT +3 *
+ +[0-9]+: [0-9a-f]+ +0 SECTION LOCAL DEFAULT +4 *
+ +[0-9]+: [0-9a-f]+ +0 SECTION LOCAL DEFAULT +5 *
+ +[0-9]+: [0-9a-f]+ +0 SECTION LOCAL DEFAULT +6 *
+ +[0-9]+: [0-9a-f]+ +0 SECTION LOCAL DEFAULT +7 *
+ +[0-9]+: [0-9a-f]+ +0 SECTION LOCAL DEFAULT +8 *
+ +[0-9]+: [0-9a-f]+ +0 SECTION LOCAL DEFAULT +9 *
+ +[0-9]+: [0-9a-f]+ +0 SECTION LOCAL DEFAULT +10 *
+ +[0-9]+: [0-9a-f]+ +0 SECTION LOCAL DEFAULT +11 *
+ +[0-9]+: [0-9a-f]+ +0 SECTION LOCAL DEFAULT +12 *
+ +[0-9]+: [0-9a-f]+ +0 SECTION LOCAL DEFAULT +13 *
+ +[0-9]+: [0-9a-f]+ +0 SECTION LOCAL DEFAULT +14 *
+ +[0-9]+: 0+20 +0 TLS +LOCAL DEFAULT +7 sl1
+ +[0-9]+: 0+24 +0 TLS +LOCAL DEFAULT +7 sl2
+ +[0-9]+: 0+28 +0 TLS +LOCAL DEFAULT +7 sl3
+ +[0-9]+: 0+2c +0 TLS +LOCAL DEFAULT +7 sl4
+ +[0-9]+: 0+30 +0 TLS +LOCAL DEFAULT +7 sl5
+ +[0-9]+: 0+34 +0 TLS +LOCAL DEFAULT +7 sl6
+ +[0-9]+: 0+38 +0 TLS +LOCAL DEFAULT +7 sl7
+ +[0-9]+: 0+3c +0 TLS +LOCAL DEFAULT +7 sl8
+ +[0-9]+: 0+60 +0 TLS +LOCAL HIDDEN +8 sH1
+ +[0-9]+: 0+ +0 TLS +LOCAL HIDDEN +7 _TLS_MODULE_BASE_
+ +[0-9]+: [0-9a-f]+ +0 OBJECT LOCAL HIDDEN ABS _DYNAMIC
+ +[0-9]+: 0+48 +0 TLS +LOCAL HIDDEN +7 sh3
+ +[0-9]+: 0+64 +0 TLS +LOCAL HIDDEN +8 sH2
+ +[0-9]+: 0+78 +0 TLS +LOCAL HIDDEN +8 sH7
+ +[0-9]+: 0+58 +0 TLS +LOCAL HIDDEN +7 sh7
+ +[0-9]+: 0+5c +0 TLS +LOCAL HIDDEN +7 sh8
+ +[0-9]+: 0+6c +0 TLS +LOCAL HIDDEN +8 sH4
+ +[0-9]+: 0+4c +0 TLS +LOCAL HIDDEN +7 sh4
+ +[0-9]+: 0+68 +0 TLS +LOCAL HIDDEN +8 sH3
+ +[0-9]+: 0+50 +0 TLS +LOCAL HIDDEN +7 sh5
+ +[0-9]+: 0+70 +0 TLS +LOCAL HIDDEN +8 sH5
+ +[0-9]+: 0+74 +0 TLS +LOCAL HIDDEN +8 sH6
+ +[0-9]+: 0+7c +0 TLS +LOCAL HIDDEN +8 sH8
+ +[0-9]+: 0+40 +0 TLS +LOCAL HIDDEN +7 sh1
+ +[0-9]+: [0-9a-f]+ +0 OBJECT LOCAL HIDDEN ABS _GLOBAL_OFFSET_TABLE_
+ +[0-9]+: 0+44 +0 TLS +LOCAL HIDDEN +7 sh2
+ +[0-9]+: 0+54 +0 TLS +LOCAL HIDDEN +7 sh6
+ +[0-9]+: 0+1c +0 TLS +GLOBAL DEFAULT +7 sg8
+ +[0-9]+: 0+8 +0 TLS +GLOBAL DEFAULT +7 sg3
+ +[0-9]+: 0+c +0 TLS +GLOBAL DEFAULT +7 sg4
+ +[0-9]+: 0+10 +0 TLS +GLOBAL DEFAULT +7 sg5
+ +[0-9]+: 0+ +0 TLS +GLOBAL DEFAULT +7 sg1
+ +[0-9]+: [0-9a-f]+ +0 FUNC +GLOBAL DEFAULT +6 fn1
+ +[0-9]+: [0-9a-f]+ +0 NOTYPE GLOBAL DEFAULT ABS __bss_start
+ +[0-9]+: 0+4 +0 TLS +GLOBAL DEFAULT +7 sg2
+ +[0-9]+: 0+14 +0 TLS +GLOBAL DEFAULT +7 sg6
+ +[0-9]+: 0+18 +0 TLS +GLOBAL DEFAULT +7 sg7
+ +[0-9]+: [0-9a-f]+ +0 NOTYPE GLOBAL DEFAULT ABS _edata
+ +[0-9]+: [0-9a-f]+ +0 NOTYPE GLOBAL DEFAULT ABS _end
diff --git a/ld/testsuite/ld-i386/tlsdesc.s b/ld/testsuite/ld-i386/tlsdesc.s
new file mode 100644
index 0000000..8377f64
--- /dev/null
+++ b/ld/testsuite/ld-i386/tlsdesc.s
@@ -0,0 +1,276 @@
+ .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
+ .text
+ .globl fn1
+ .type fn1,@function
+fn1:
+ pushl %ebp
+ movl %esp, %ebp
+ pushl %ebx
+ pushl %eax
+ call 1f
+1: popl %ebx
+ addl $_GLOBAL_OFFSET_TABLE_+[.-1b], %ebx
+ nop;nop;nop;nop
+
+ /* GD */
+ leal sg1@tlsdesc(%ebx), %eax
+ call *sg1@tlscall(%eax)
+ nop;nop;nop;nop
+
+ /* GD -> IE because variable is referenced through @gottpoff too */
+ leal sg2@tlsdesc(%ebx), %eax
+ call *sg2@tlscall(%eax)
+ nop;nop;nop;nop
+
+ /* GD -> IE because variable is referenced through @gotntpoff too */
+ leal sg3@tlsdesc(%ebx), %eax
+ call *sg3@tlscall(%eax)
+ nop;nop;nop;nop
+
+ /* GD -> IE because variable is referenced through @gottpoff and
+ @gotntpoff too */
+ leal sg4@tlsdesc(%ebx), %eax
+ call *sg4@tlscall(%eax)
+ nop;nop;nop;nop
+
+ /* GD against local variable */
+ leal sl1@tlsdesc(%ebx), %eax
+ call *sl1@tlscall(%eax)
+ nop;nop;nop;nop
+
+ /* GD -> IE against local variable referenced through @gottpoff too */
+ leal sl2@tlsdesc(%ebx), %eax
+ call *sl2@tlscall(%eax)
+ nop;nop;nop;nop
+
+ /* GD -> IE against local variable referenced through @gotntpoff
+ too */
+ leal sl3@tlsdesc(%ebx), %eax
+ call *sl3@tlscall(%eax)
+ nop;nop;nop;nop
+
+ /* GD -> IE against local variable referenced through @gottpoff and
+ @gotntpoff too */
+ leal sl4@tlsdesc(%ebx), %eax
+ call *sl4@tlscall(%eax)
+ nop;nop;nop;nop
+
+ /* GD against hidden and local variable */
+ leal sh1@tlsdesc(%ebx), %eax
+ call *sh1@tlscall(%eax)
+ nop;nop;nop;nop
+
+ /* GD -> IE against hidden and local variable referenced through
+ @gottpoff too */
+ leal sh2@tlsdesc(%ebx), %eax
+ call *sh2@tlscall(%eax)
+ nop;nop;nop;nop
+
+ /* GD -> IE against hidden and local variable referenced through
+ @gotntpoff too */
+ leal sh3@tlsdesc(%ebx), %eax
+ call *sh3@tlscall(%eax)
+ nop;nop;nop;nop
+
+ /* GD -> IE against hidden and local variable referenced through
+ @gottpoff and @gotntpoff too */
+ leal sh4@tlsdesc(%ebx), %eax
+ call *sh4@tlscall(%eax)
+ nop;nop;nop;nop
+
+ /* GD against hidden but not local variable */
+ leal sH1@tlsdesc(%ebx), %eax
+ call *sH1@tlscall(%eax)
+ nop;nop;nop;nop
+
+ /* GD -> IE against hidden but not local variable referenced through
+ @gottpoff too */
+ leal sH2@tlsdesc(%ebx), %eax
+ call *sH2@tlscall(%eax)
+ nop;nop;nop;nop
+
+ /* GD -> IE against hidden but not local variable referenced through
+ @gotntpoff too */
+ leal sH3@tlsdesc(%ebx), %eax
+ call *sH3@tlscall(%eax)
+ nop;nop;nop;nop
+
+ /* GD -> IE against hidden but not local variable referenced through
+ @gottpoff and @gotntpoff too */
+ leal sH4@tlsdesc(%ebx), %eax
+ call *sH4@tlscall(%eax)
+ nop;nop;nop;nop
+
+ /* LD */
+ leal _TLS_MODULE_BASE_@tlsdesc(%ebx), %eax
+ call *_TLS_MODULE_BASE_@tlscall(%eax)
+ nop;nop
+ leal sl1@dtpoff(%eax), %edx
+ nop;nop
+ leal 2+sl2@dtpoff(%eax), %ecx
+ nop;nop;nop;nop
+
+ /* LD against hidden and local variables */
+ leal sh1@dtpoff(%eax), %edx
+ nop;nop
+ leal sh2@dtpoff+3(%eax), %ecx
+ nop;nop;nop;nop
+
+ /* LD against hidden but not local variables */
+ leal sH1@dtpoff(%eax), %edx
+ nop;nop
+ leal sH2@dtpoff+1(%eax), %ecx
+ nop;nop
+
+ /* @gottpoff IE against global var */
+ movl %gs:0, %ecx
+ nop;nop
+ subl sg2@gottpoff(%ebx), %ecx
+ nop;nop;nop;nop
+
+ /* @gottpoff IE against global var */
+ movl %gs:0, %eax
+ nop;nop
+ subl sg4@gottpoff(%ebx), %eax
+ nop;nop;nop;nop
+
+ /* @gotntpoff IE against global var */
+ movl %gs:0, %ecx
+ nop;nop
+ addl sg3@gotntpoff(%ebx), %ecx
+ nop;nop;nop;nop
+
+ /* @gotntpoff IE against global var */
+ movl %gs:0, %eax
+ nop;nop
+ addl sg4@gotntpoff(%ebx), %eax
+ nop;nop;nop;nop
+
+ /* @gottpoff IE against local var */
+ movl %gs:0, %ecx
+ nop;nop
+ subl sl2@gottpoff(%ebx), %ecx
+ nop;nop;nop;nop
+
+ /* @gottpoff IE against local var */
+ movl %gs:0, %eax
+ nop;nop
+ subl sl4@gottpoff(%ebx), %eax
+ nop;nop;nop;nop
+
+ /* @gotntpoff IE against local var */
+ movl %gs:0, %ecx
+ nop;nop
+ addl sl3@gotntpoff(%ebx), %ecx
+ nop;nop;nop;nop
+
+ /* @gotntpoff IE against local var */
+ movl %gs:0, %eax
+ nop;nop
+ addl sl4@gotntpoff(%ebx), %eax
+ nop;nop;nop;nop
+
+ /* @gottpoff IE against hidden and local var */
+ movl %gs:0, %ecx
+ nop;nop
+ subl sh2@gottpoff(%ebx), %ecx
+ nop;nop;nop;nop
+
+ /* @gottpoff IE against hidden and local var */
+ movl %gs:0, %eax
+ nop;nop
+ subl sh4@gottpoff(%ebx), %eax
+ nop;nop;nop;nop
+
+ /* @gotntpoff IE against hidden and local var */
+ movl %gs:0, %ecx
+ nop;nop
+ addl sh3@gotntpoff(%ebx), %ecx
+ nop;nop;nop;nop
+
+ /* @gotntpoff IE against hidden and local var */
+ movl %gs:0, %eax
+ nop;nop
+ addl sh4@gotntpoff(%ebx), %eax
+ nop;nop;nop;nop
+
+ /* @gottpoff IE against hidden but not local var */
+ movl %gs:0, %ecx
+ nop;nop
+ subl sH2@gottpoff(%ebx), %ecx
+ nop;nop;nop;nop
+
+ /* @gottpoff IE against hidden but not local var */
+ movl %gs:0, %eax
+ nop;nop
+ subl sH4@gottpoff(%ebx), %eax
+ nop;nop;nop;nop
+
+ /* @gotntpoff IE against hidden but not local var */
+ movl %gs:0, %ecx
+ nop;nop
+ addl sH3@gotntpoff(%ebx), %ecx
+ nop;nop;nop;nop
+
+ /* @gotntpoff IE against hidden but not local var */
+ movl %gs:0, %eax
+ nop;nop
+ addl sH4@gotntpoff(%ebx), %eax
+ nop;nop;nop;nop
+
+ /* Direct access through %gs */
+
+ /* @gotntpoff IE against global var */
+ movl sg5@gotntpoff(%ebx), %ecx
+ nop;nop
+ movl %gs:(%ecx), %edx
+ nop;nop;nop;nop
+
+ /* @gotntpoff IE against local var */
+ movl sl5@gotntpoff(%ebx), %eax
+ nop;nop
+ movl %gs:(%eax), %edx
+ nop;nop;nop;nop
+
+ /* @gotntpoff IE against hidden and local var */
+ movl sh5@gotntpoff(%ebx), %edx
+ nop;nop
+ movl %gs:(%edx), %edx
+ nop;nop;nop;nop
+
+ /* @gotntpoff IE against hidden but not local var */
+ movl sH5@gotntpoff(%ebx), %ecx
+ nop;nop
+ movl %gs:(%ecx), %edx
+ nop;nop;nop;nop
+
+ movl -4(%ebp), %ebx
+ leave
+ ret
diff --git a/ld/testsuite/ld-i386/tlsdesc.sd b/ld/testsuite/ld-i386/tlsdesc.sd
new file mode 100644
index 0000000..2af8c2d
--- /dev/null
+++ b/ld/testsuite/ld-i386/tlsdesc.sd
@@ -0,0 +1,20 @@
+#source: tlsdesc.s
+#source: tlspic2.s
+#as: --32
+#ld: -shared -melf_i386
+#objdump: -s -j.got -j.got.plt
+#target: i?86-*-*
+
+.*: file format elf32-i386
+
+Contents of section \.got:
+ [0-9a-f]+ dcffffff 28000000 d4ffffff 2c000000 .*
+ [0-9a-f]+ 30000000 00000000 48000000 9cffffff .*
+ [0-9a-f]+ 00000000 00000000 00000000 94ffffff .*
+ [0-9a-f]+ 6c000000 b4ffffff 4c000000 68000000 .*
+ [0-9a-f]+ 50000000 70000000 00000000 bcffffff .*
+Contents of section \.got\.plt:
+ [0-9a-f]+ ec150000 00000000 00000000 00000000 .*
+ [0-9a-f]+ 20000000 00000000 60000000 00000000 .*
+ [0-9a-f]+ 00000000 00000000 00000000 00000000 .*
+ [0-9a-f]+ 40000000 +.*
diff --git a/ld/testsuite/ld-i386/tlsdesc.td b/ld/testsuite/ld-i386/tlsdesc.td
new file mode 100644
index 0000000..f3612b3
--- /dev/null
+++ b/ld/testsuite/ld-i386/tlsdesc.td
@@ -0,0 +1,16 @@
+#source: tlsdesc.s
+#source: tlspic2.s
+#as: --32
+#ld: -shared -melf_i386
+#objdump: -sj.tdata
+#target: i?86-*-*
+
+.*: file format elf32-i386
+
+Contents of section \.tdata:
+ [0-9a-f]+ 11000000 12000000 13000000 14000000 .*
+ [0-9a-f]+ 15000000 16000000 17000000 18000000 .*
+ [0-9a-f]+ 41000000 42000000 43000000 44000000 .*
+ [0-9a-f]+ 45000000 46000000 47000000 48000000 .*
+ [0-9a-f]+ 01010000 02010000 03010000 04010000 .*
+ [0-9a-f]+ 05010000 06010000 07010000 08010000 .*
diff --git a/ld/testsuite/ld-i386/tlsgdesc.dd b/ld/testsuite/ld-i386/tlsgdesc.dd
new file mode 100644
index 0000000..ca4092e
--- /dev/null
+++ b/ld/testsuite/ld-i386/tlsgdesc.dd
@@ -0,0 +1,158 @@
+#source: tlsgdesc.s
+#as: --32
+#ld: -shared -melf_i386
+#objdump: -drj.text
+#target: i?86-*-*
+
+.*: +file format elf32-i386
+
+Disassembly of section .text:
+
+[0-9a-f]+ <fc1>:
+ [0-9a-f]+: 55[ ]+push %ebp
+ [0-9a-f]+: 89 e5[ ]+mov %esp,%ebp
+ [0-9a-f]+: 53[ ]+push %ebx
+ [0-9a-f]+: 50[ ]+push %eax
+ [0-9a-f]+: e8 00 00 00 00[ ]+call [0-9a-f]+ <.*>
+ [0-9a-f]+: 5b[ ]+pop %ebx
+ [0-9a-f]+: 81 c3 be 11 00 00[ ]+add \$0x[0-9a-f]+,%ebx
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+# @gottpoff IE against global var
+ [0-9a-f]+: 65 8b 0d 00 00 00 00[ ]+mov %gs:0x0,%ecx
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 2b 8b e0 ff ff ff[ ]+sub 0xffffffe0\(%ebx\),%ecx
+# ->R_386_TLS_TPOFF32 sG3
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+# @gotntpoff IE against global var
+ [0-9a-f]+: 65 8b 0d 00 00 00 00[ ]+mov %gs:0x0,%ecx
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 03 8b f0 ff ff ff[ ]+add 0xfffffff0\(%ebx\),%ecx
+# ->R_386_TLS_TPOFF sG4
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+# GD
+ [0-9a-f]+: 8d 04 1d f8 ff ff ff[ ]+lea 0xfffffff8\(,%ebx,1\),%eax
+# ->R_386_TLS_DTPMOD32 sG1
+ [0-9a-f]+: e8 a9 ff ff ff[ ]+call [0-9a-f]+ <___tls_get_addr@plt>
+# ->R_386_JUMP_SLOT ___tls_get_addr
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 8d 83 18 00 00 00[ ]+lea 0x18\(%ebx\),%eax
+# ->R_386_TLS_DESC sG1
+ [0-9a-f]+: ff 10[ ]+call \*\(%eax\)
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 8d 83 10 00 00 00[ ]+lea 0x10\(%ebx\),%eax
+# ->R_386_TLS_DESC sG2
+ [0-9a-f]+: ff 10[ ]+call \*\(%eax\)
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 8d 04 1d e8 ff ff ff[ ]+lea 0xffffffe8\(,%ebx,1\),%eax
+# ->R_386_TLS_DTPMOD32 sG2
+ [0-9a-f]+: e8 81 ff ff ff[ ]+call [0-9a-f]+ <___tls_get_addr@plt>
+# ->R_386_JUMP_SLOT ___tls_get_addr
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+# GD -> IE because variable is referenced through @gottpoff too
+ [0-9a-f]+: 65 a1 00 00 00 00[ ]+mov %gs:0x0,%eax
+ [0-9a-f]+: 2b 83 e0 ff ff ff[ ]+sub 0xffffffe0\(%ebx\),%eax
+# ->R_386_TLS_TPOFF32 sG3
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 8b 83 e0 ff ff ff[ ]+mov 0xffffffe0\(%ebx\),%eax
+# ->R_386_TLS_TPOFF32 sG3
+ [0-9a-f]+: f7 d8[ ]+neg %eax
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+# GD -> IE because variable is referenced through @gotntpoff too
+ [0-9a-f]+: 8b 83 f0 ff ff ff[ ]+mov 0xfffffff0\(%ebx\),%eax
+# ->R_386_TLS_TPOFF sG4
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 65 a1 00 00 00 00[ ]+mov %gs:0x0,%eax
+ [0-9a-f]+: 03 83 f0 ff ff ff[ ]+add 0xfffffff0\(%ebx\),%eax
+# ->R_386_TLS_TPOFF sG4
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+# GD -> IE because variable is referenced through @gotntpoff too
+ [0-9a-f]+: 65 a1 00 00 00 00[ ]+mov %gs:0x0,%eax
+ [0-9a-f]+: 03 83 e4 ff ff ff[ ]+add 0xffffffe4\(%ebx\),%eax
+# ->R_386_TLS_TPOFF sG5
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 8b 83 e4 ff ff ff[ ]+mov 0xffffffe4\(%ebx\),%eax
+# ->R_386_TLS_TPOFF sG5
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+# GD -> IE because variable is referenced through @gottpoff too
+ [0-9a-f]+: 8b 83 f4 ff ff ff[ ]+mov 0xfffffff4\(%ebx\),%eax
+# ->R_386_TLS_TPOFF32 sG6
+ [0-9a-f]+: f7 d8[ ]+neg %eax
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 65 a1 00 00 00 00[ ]+mov %gs:0x0,%eax
+ [0-9a-f]+: 2b 83 f4 ff ff ff[ ]+sub 0xfffffff4\(%ebx\),%eax
+# ->R_386_TLS_TPOFF32 sG6
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+# @gotntpoff IE against global var
+ [0-9a-f]+: 65 8b 0d 00 00 00 00[ ]+mov %gs:0x0,%ecx
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 03 8b e4 ff ff ff[ ]+add 0xffffffe4\(%ebx\),%ecx
+# ->R_386_TLS_TPOFF sG5
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+# @gottpoff IE against global var
+ [0-9a-f]+: 65 8b 0d 00 00 00 00[ ]+mov %gs:0x0,%ecx
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 2b 8b f4 ff ff ff[ ]+sub 0xfffffff4\(%ebx\),%ecx
+# ->R_386_TLS_TPOFF32 sG6
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 8b 5d fc[ ]+mov 0xfffffffc\(%ebp\),%ebx
+ [0-9a-f]+: c9[ ]+leave *
+ [0-9a-f]+: c3[ ]+ret *
diff --git a/ld/testsuite/ld-i386/tlsgdesc.rd b/ld/testsuite/ld-i386/tlsgdesc.rd
new file mode 100644
index 0000000..9253d22
--- /dev/null
+++ b/ld/testsuite/ld-i386/tlsgdesc.rd
@@ -0,0 +1,107 @@
+#source: tlsgdesc.s
+#as: --32
+#ld: -shared -melf_i386
+#readelf: -Ssrl
+#target: i?86-*-*
+
+There are [0-9]+ section headers, starting at offset 0x.*:
+
+Section Headers:
+ \[Nr\] Name +Type +Addr +Off +Size +ES Flg Lk Inf Al
+ \[ 0\] +NULL +0+ 0+ 0+ 0+ +0 +0 +0
+ \[ 1\] \.hash +.*
+ \[ 2\] \.dynsym +.*
+ \[ 3\] \.dynstr +.*
+ \[ 4\] \.rel.dyn +.*
+ \[ 5\] \.rel.plt +.*
+ \[ 6\] \.plt +.*
+ \[ 7\] \.text +.*
+ \[ 8\] \.dynamic +.*
+ \[ 9\] \.got +.*
+ \[10\] \.got.plt +.*
+ \[11\] \.shstrtab +.*
+ \[12\] \.symtab +.*
+ \[13\] \.strtab +.*
+Key to Flags:
+.*
+.*
+.*
+
+Elf file type is DYN \(Shared object file\)
+Entry point 0x[0-9a-f]+
+There are [0-9]+ program headers, starting at offset [0-9]+
+
+Program Headers:
+ Type +Offset +VirtAddr +PhysAddr +FileSiz +MemSiz +Flg Align
+ LOAD.*
+ LOAD.*
+ DYNAMIC.*
+
+ Section to Segment mapping:
+ Segment Sections...
+ 00 +.hash .dynsym .dynstr .rel.dyn .rel.plt .plt .text *
+ 01 +.dynamic .got .got.plt *
+ 02 +.dynamic *
+
+Relocation section '.rel.dyn' at offset 0x[0-9a-f]+ contains 8 entries:
+ Offset +Info +Type +Sym.Value +Sym. Name
+[0-9a-f]+ +0+225 R_386_TLS_TPOFF32 0+ sG3
+[0-9a-f]+ +0+30e R_386_TLS_TPOFF 0+ sG5
+[0-9a-f]+ +0+423 R_386_TLS_DTPMOD3 0+ sG2
+[0-9a-f]+ +0+424 R_386_TLS_DTPOFF3 0+ sG2
+[0-9a-f]+ +0+50e R_386_TLS_TPOFF 0+ sG4
+[0-9a-f]+ +0+725 R_386_TLS_TPOFF32 0+ sG6
+[0-9a-f]+ +0+923 R_386_TLS_DTPMOD3 0+ sG1
+[0-9a-f]+ +0+924 R_386_TLS_DTPOFF3 0+ sG1
+
+Relocation section '.rel.plt' at offset 0x[0-9a-f]+ contains 3 entries:
+ Offset Info Type Sym.Value Sym. Name
+[0-9a-f]+ 0+c07 R_386_JUMP_SLOT 0+ ___tls_get_addr
+[0-9a-f]+ 0+929 R_386_TLS_DESC 0+ sG1
+[0-9a-f]+ 0+429 R_386_TLS_DESC 0+ sG2
+
+Symbol table '.dynsym' contains 13 entries:
+ +Num: + Value Size Type + Bind +Vis +Ndx Name
+ +[0-9]+: 0+ +0 NOTYPE LOCAL DEFAULT UND *
+ +[0-9]+: [0-9a-f]+ +0 SECTION LOCAL DEFAULT +7 *
+ +[0-9]+: 0+ +0 TLS +GLOBAL DEFAULT UND sG3
+ +[0-9]+: 0+ +0 TLS +GLOBAL DEFAULT UND sG5
+ +[0-9]+: 0+ +0 TLS +GLOBAL DEFAULT UND sG2
+ +[0-9]+: 0+ +0 TLS +GLOBAL DEFAULT UND sG4
+ +[0-9]+: [0-9a-f]+ +0 NOTYPE GLOBAL DEFAULT ABS __bss_start
+ +[0-9]+: 0+ +0 TLS +GLOBAL DEFAULT UND sG6
+ +[0-9]+: [0-9a-f]+ +0 FUNC +GLOBAL DEFAULT +7 fc1
+ +[0-9]+: 0+ +0 TLS +GLOBAL DEFAULT UND sG1
+ +[0-9]+: [0-9a-f]+ +0 NOTYPE GLOBAL DEFAULT ABS _edata
+ +[0-9]+: [0-9a-f]+ +0 NOTYPE GLOBAL DEFAULT ABS _end
+ +[0-9]+: 0+ +0 NOTYPE GLOBAL DEFAULT UND ___tls_get_addr
+
+Symbol table '.symtab' contains 27 entries:
+ +Num: +Value Size Type +Bind +Vis +Ndx Name
+ +[0-9]+: 0+ +0 NOTYPE LOCAL DEFAULT UND *
+ +[0-9]+: [0-9a-f]+ +0 SECTION LOCAL DEFAULT +1 *
+ +[0-9]+: [0-9a-f]+ +0 SECTION LOCAL DEFAULT +2 *
+ +[0-9]+: [0-9a-f]+ +0 SECTION LOCAL DEFAULT +3 *
+ +[0-9]+: [0-9a-f]+ +0 SECTION LOCAL DEFAULT +4 *
+ +[0-9]+: [0-9a-f]+ +0 SECTION LOCAL DEFAULT +5 *
+ +[0-9]+: [0-9a-f]+ +0 SECTION LOCAL DEFAULT +6 *
+ +[0-9]+: [0-9a-f]+ +0 SECTION LOCAL DEFAULT +7 *
+ +[0-9]+: [0-9a-f]+ +0 SECTION LOCAL DEFAULT +8 *
+ +[0-9]+: [0-9a-f]+ +0 SECTION LOCAL DEFAULT +9 *
+ +[0-9]+: [0-9a-f]+ +0 SECTION LOCAL DEFAULT +10 *
+ +[0-9]+: [0-9a-f]+ +0 SECTION LOCAL DEFAULT +11 *
+ +[0-9]+: [0-9a-f]+ +0 SECTION LOCAL DEFAULT +12 *
+ +[0-9]+: [0-9a-f]+ +0 SECTION LOCAL DEFAULT +13 *
+ +[0-9]+: [0-9a-f]+ +0 OBJECT LOCAL HIDDEN ABS _DYNAMIC
+ +[0-9]+: [0-9a-f]+ +0 OBJECT LOCAL HIDDEN ABS _GLOBAL_OFFSET_TABLE_
+ +[0-9]+: 0+ +0 TLS +GLOBAL DEFAULT UND sG3
+ +[0-9]+: 0+ +0 TLS +GLOBAL DEFAULT UND sG5
+ +[0-9]+: 0+ +0 TLS +GLOBAL DEFAULT UND sG2
+ +[0-9]+: 0+ +0 TLS +GLOBAL DEFAULT UND sG4
+ +[0-9]+: [0-9a-f]+ +0 NOTYPE GLOBAL DEFAULT ABS __bss_start
+ +[0-9]+: 0+ +0 TLS +GLOBAL DEFAULT UND sG6
+ +[0-9]+: [0-9a-f]+ +0 FUNC +GLOBAL DEFAULT +7 fc1
+ +[0-9]+: 0+ +0 TLS +GLOBAL DEFAULT UND sG1
+ +[0-9]+: [0-9a-f]+ +0 NOTYPE GLOBAL DEFAULT ABS _edata
+ +[0-9]+: [0-9a-f]+ +0 NOTYPE GLOBAL DEFAULT ABS _end
+ +[0-9]+: 0+ +0 NOTYPE GLOBAL DEFAULT UND ___tls_get_addr
diff --git a/ld/testsuite/ld-i386/tlsgdesc.s b/ld/testsuite/ld-i386/tlsgdesc.s
new file mode 100644
index 0000000..9502a10
--- /dev/null
+++ b/ld/testsuite/ld-i386/tlsgdesc.s
@@ -0,0 +1,100 @@
+ .text
+ .globl fc1
+ .type fc1,@function
+fc1:
+ pushl %ebp
+ movl %esp, %ebp
+ pushl %ebx
+ pushl %eax
+ call 1f
+1: popl %ebx
+ addl $_GLOBAL_OFFSET_TABLE_+[.-1b], %ebx
+ nop;nop;nop;nop
+
+ /* @gottpoff IE against global var */
+ movl %gs:0, %ecx
+ nop;nop
+ subl sG3@gottpoff(%ebx), %ecx
+ nop;nop;nop;nop
+
+ /* @gotntpoff IE against global var */
+ movl %gs:0, %ecx
+ nop;nop
+ addl sG4@gotntpoff(%ebx), %ecx
+ nop;nop;nop;nop
+
+ /* GD */
+ leal sG1@tlsgd(,%ebx,1), %eax
+ call ___tls_get_addr@plt
+ nop;nop;nop;nop
+
+ /* GD */
+ leal sG1@tlsdesc(%ebx), %eax
+ call *sG1@tlscall(%eax)
+ nop;nop;nop;nop
+
+ /* GD */
+ leal sG2@tlsdesc(%ebx), %eax
+ call *sG2@tlscall(%eax)
+ nop;nop;nop;nop
+
+ /* GD */
+ leal sG2@tlsgd(,%ebx,1), %eax
+ call ___tls_get_addr@plt
+ nop;nop;nop;nop
+
+ /* GD -> IE tpoff */
+ leal sG3@tlsgd(,%ebx,1), %eax
+ call ___tls_get_addr@plt
+ nop;nop;nop;nop
+
+ /* GD -> IE tpoff */
+ leal sG3@tlsdesc(%ebx), %eax
+ call *sG3@tlscall(%eax)
+ nop;nop;nop;nop
+
+ /* GD -> IE ntpoff */
+ leal sG4@tlsdesc(%ebx), %eax
+ call *sG4@tlscall(%eax)
+ nop;nop;nop;nop
+
+ /* GD -> IE ntpoff */
+ leal sG4@tlsgd(,%ebx,1), %eax
+ call ___tls_get_addr@plt
+ nop;nop;nop;nop
+
+ /* GD -> IE ntpoff */
+ leal sG5@tlsgd(,%ebx,1), %eax
+ call ___tls_get_addr@plt
+ nop;nop;nop;nop
+
+ /* GD -> IE ntpoff */
+ leal sG5@tlsdesc(%ebx), %eax
+ call *sG5@tlscall(%eax)
+ nop;nop;nop;nop
+
+ /* GD -> IE tpoff */
+ leal sG6@tlsdesc(%ebx), %eax
+ call *sG6@tlscall(%eax)
+ nop;nop;nop;nop
+
+ /* GD -> IE tpoff */
+ leal sG6@tlsgd(,%ebx,1), %eax
+ call ___tls_get_addr@plt
+ nop;nop;nop;nop
+
+ /* @gotntpoff IE against global var */
+ movl %gs:0, %ecx
+ nop;nop
+ addl sG5@gotntpoff(%ebx), %ecx
+ nop;nop;nop;nop
+
+ /* @gottpoff IE against global var */
+ movl %gs:0, %ecx
+ nop;nop
+ subl sG6@gottpoff(%ebx), %ecx
+ nop;nop;nop;nop
+
+ movl -4(%ebp), %ebx
+ leave
+ ret
diff --git a/ld/testsuite/ld-x86-64/tlsbindesc.dd b/ld/testsuite/ld-x86-64/tlsbindesc.dd
new file mode 100644
index 0000000..c41efec
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/tlsbindesc.dd
@@ -0,0 +1,307 @@
+#source: tlsbindesc.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>:
+ [0-9a-f]+: 55[ ]+push %rbp
+ [0-9a-f]+: 48 89 e5[ ]+mov %rsp,%rbp
+# GD -> IE because variable is not defined in executable
+ [0-9a-f]+: 48 8b 05 65 03 10 00[ ]+mov 1049445\(%rip\),%rax +# 501370 <.*>
+# -> R_X86_64_TPOFF64 sG1
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+# GD -> IE because variable is not defined in executable where
+# the variable is referenced through IE too
+ [0-9a-f]+: 48 8b 05 48 03 10 00[ ]+mov 1049416\(%rip\),%rax +# 501360 <.*>
+# -> R_X86_64_TPOFF64 sG2
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+# GD -> LE with global variable defined in executable
+ [0-9a-f]+: 48 c7 c0 60 ff ff ff[ ]+mov \$0xf+60,%rax
+# sg1
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+# GD -> LE with local variable defined in executable
+ [0-9a-f]+: 48 c7 c0 80 ff ff ff[ ]+mov \$0xf+80,%rax
+# sl1
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+# GD -> LE with hidden variable defined in executable
+ [0-9a-f]+: 48 c7 c0 a0 ff ff ff[ ]+mov \$0xf+a0,%rax
+# sh1
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+# LD -> LE
+ [0-9a-f]+: 48 c7 c0 60 ff ff ff[ ]+mov \$0xf+60,%rax
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 48 8d 90 81 ff ff ff[ ]+lea 0xf+81\(%rax\),%rdx
+# sl1+1
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 4c 8d 88 86 ff ff ff[ ]+lea 0xf+86\(%rax\),%r9
+# sl2+2
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+# LD -> LE against hidden variables
+ [0-9a-f]+: 48 8d 90 a0 ff ff ff[ ]+lea 0xf+a0\(%rax\),%rdx
+# sh1
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 48 8d 88 a7 ff ff ff[ ]+lea 0xf+a7\(%rax\),%rcx
+# sh2+3
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+# IE against global var
+ [0-9a-f]+: 64 4c 8b 0c 25 00 00[ ]+mov %fs:0x0,%r9
+ [0-9a-f]+: 00 00 *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 4c 03 0d d6 02 10 00[ ]+add 1049302\(%rip\),%r9 +# 501360 <.*>
+# -> R_X86_64_TPOFF64 sG2
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+# IE -> LE against global var defined in exec
+ [0-9a-f]+: 64 4c 8b 14 25 00 00[ ]+mov %fs:0x0,%r10
+ [0-9a-f]+: 00 00 *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 4d 8d 92 60 ff ff ff[ ]+lea 0xf+60\(%r10\),%r10
+# sg1
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+# IE -> LE against local var
+ [0-9a-f]+: 64 48 8b 04 25 00 00[ ]+mov %fs:0x0,%rax
+ [0-9a-f]+: 00 00 *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 48 8d 80 80 ff ff ff[ ]+lea 0xf+80\(%rax\),%rax
+# sl1
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+# IE -> LE against hidden var
+ [0-9a-f]+: 64 48 8b 0c 25 00 00[ ]+mov %fs:0x0,%rcx
+ [0-9a-f]+: 00 00 *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 48 8d 89 a0 ff ff ff[ ]+lea 0xf+a0\(%rcx\),%rcx
+# sh1
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+# Direct access through %fs
+# IE against global var
+ [0-9a-f]+: 48 8b 0d 81 02 10 00[ ]+mov 1049217\(%rip\),%rcx +# 501358 <.*>
+# -> R_X86_64_TPOFF64 sG5
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 64 48 8b 11[ ]+mov %fs:\(%rcx\),%rdx
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+# IE->LE against local var
+ [0-9a-f]+: 49 c7 c3 90 ff ff ff[ ]+mov \$0xf+90,%r11
+# sl5
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 64 4d 8b 23[ ]+mov %fs:\(%r11\),%r12
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+# IE->LE against hidden var
+ [0-9a-f]+: 48 c7 c2 b0 ff ff ff[ ]+mov \$0xf+b0,%rdx
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 64 48 8b 12[ ]+mov %fs:\(%rdx\),%rdx
+# sh5
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: c9[ ]+leaveq *
+ [0-9a-f]+: c3[ ]+retq *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+
+[0-9a-f]+ <_start>:
+ [0-9a-f]+: 55[ ]+push %rbp
+ [0-9a-f]+: 48 89 e5[ ]+mov %rsp,%rbp
+# IE against global var
+ [0-9a-f]+: 64 4c 8b 1c 25 00 00[ ]+mov %fs:0x0,%r11
+ [0-9a-f]+: 00 00 *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 4c 03 1d 4a 02 10 00[ ]+add 1049162\(%rip\),%r11 +# 501368 <.*>
+# -> R_X86_64_TPOFF64 sG6
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+# IE -> LE against global var defined in exec
+ [0-9a-f]+: 64 48 8b 14 25 00 00[ ]+mov %fs:0x0,%rdx
+ [0-9a-f]+: 00 00 *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 48 8d 92 d4 ff ff ff[ ]+lea 0xf+d4\(%rdx\),%rdx
+# bg6
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+# IE -> LE against local var
+ [0-9a-f]+: 64 4c 8b 24 25 00 00[ ]+mov %fs:0x0,%r12
+ [0-9a-f]+: 00 00 *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 49 81 c4 f4 ff ff ff[ ]+add \$0xf+f4,%r12
+# bl6
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+# direct %fs access IE -> LE against local var
+ [0-9a-f]+: 48 c7 c2 fc ff ff ff[ ]+mov \$0xf+fc,%rdx
+# bl8
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 64 48 8b 02[ ]+mov %fs:\(%rdx\),%rax
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+# IE -> LE against hidden but not local var
+ [0-9a-f]+: 64 48 8b 14 25 00 00[ ]+mov %fs:0x0,%rdx
+ [0-9a-f]+: 00 00 *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 48 8d 92 b4 ff ff ff[ ]+lea 0xf+b4\(%rdx\),%rdx
+# sh6
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+# direct %fs access IE -> LE against hidden but not local var
+ [0-9a-f]+: 48 c7 c2 bc ff ff ff[ ]+mov \$0xf+bc,%rdx
+# sh8
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 64 48 8b 02[ ]+mov %fs:\(%rdx\),%rax
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+# LE, global var defined in exec
+ [0-9a-f]+: 64 48 8b 04 25 00 00[ ]+mov %fs:0x0,%rax
+ [0-9a-f]+: 00 00 *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 48 8d 90 64 ff ff ff[ ]+lea 0xf+64\(%rax\),%rdx
+# sg2
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+# LE, local var, non-canonical sequence
+ [0-9a-f]+: 49 c7 c1 e6 ff ff ff[ ]+mov \$0xf+e6,%r9
+# bl2+2
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 64 48 8b 14 25 00 00[ ]+mov %fs:0x0,%rdx
+ [0-9a-f]+: 00 00 *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 4c 01 ca[ ]+add %r9,%rdx
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+# LE, hidden var defined in exec, non-canonical sequence
+ [0-9a-f]+: 64 48 8b 14 25 00 00[ ]+mov %fs:0x0,%rdx
+ [0-9a-f]+: 00 00 *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 48 81 c2 a5 ff ff ff[ ]+add \$0xf+a5,%rdx
+# sh2+1
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+# Direct %fs access
+# LE, global var defined in exec
+ [0-9a-f]+: 64 48 8b 04 25 68 ff[ ]+mov %fs:0xf+68,%rax
+ [0-9a-f]+: ff ff *
+# sg3
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+# LE, local var
+ [0-9a-f]+: 64 4c 8b 14 25 eb ff[ ]+mov %fs:0xf+eb,%r10
+ [0-9a-f]+: ff ff *
+# bl3+3
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+# LE, hidden var defined in exec
+ [0-9a-f]+: 64 48 8b 14 25 a9 ff[ ]+mov %fs:0xf+a9,%rdx
+ [0-9a-f]+: ff ff *
+# sh3+1
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: 90[ ]+nop *
+ [0-9a-f]+: c9[ ]+leaveq *
+ [0-9a-f]+: c3[ ]+retq *
diff --git a/ld/testsuite/ld-x86-64/tlsbindesc.rd b/ld/testsuite/ld-x86-64/tlsbindesc.rd
new file mode 100644
index 0000000..787002d
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/tlsbindesc.rd
@@ -0,0 +1,141 @@
+#source: tlsbindesc.s
+#source: tlsbin.s
+#as: --64
+#ld: -shared -melf_x86_64
+#readelf: -WSsrl
+#target: x86_64-*-*
+
+There are 15 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\] .text +PROGBITS +0+401000 0+1000 0+1f6 00 +AX +0 +0 +4096
+ \[ 7\] .tdata +PROGBITS +0+5011f6 0+11f6 0+60 00 WAT +0 +0 +1
+ \[ 8\] .tbss +NOBITS +0+501256 0+1256 0+40 00 WAT +0 +0 +1
+ \[ 9\] .dynamic +DYNAMIC +0+501258 0+1258 0+100 10 +WA +4 +0 +8
+ \[10\] .got +PROGBITS +0+501358 0+1358 0+20 08 +WA +0 +0 +8
+ \[11\] .got.plt +PROGBITS +0+501378 0+1378 0+18 08 +WA +0 +0 +8
+ \[12\] .shstrtab +.*
+ \[13\] .symtab +.*
+ \[14\] .strtab +.*
+Key to Flags:
+.*
+.*
+.*
+
+Elf file type is EXEC \(Executable file\)
+Entry point 0x401108
+There are 6 program headers, starting at offset [0-9]+
+
+Program Headers:
+ Type +Offset +VirtAddr +PhysAddr +FileSiz +MemSiz +Flg Align
+ PHDR.*
+ INTERP.*
+.*Requesting program interpreter.*
+ LOAD +0x0+ 0x0+400000 0x0+400000 0x0+11f6 0x0+11f6 R E 0x100000
+ LOAD +0x0+11f6 0x0+5011f6 0x0+5011f6 0x0+19a 0x0+19a RW 0x100000
+ DYNAMIC +0x0+1258 0x0+501258 0x0+501258 0x0+100 0x0+100 RW 0x8
+ TLS +0x0+11f6 0x0+5011f6 0x0+5011f6 0x0+60 0x0+a0 R +0x1
+
+ Section to Segment mapping:
+ Segment Sections...
+ 00 *
+ 01 +.interp *
+ 02 +.interp .hash .dynsym .dynstr .rela.dyn .text *
+ 03 +.tdata .dynamic .got .got.plt *
+ 04 +.dynamic *
+ 05 +.tdata .tbss *
+
+Relocation section '.rela.dyn' at offset 0x[0-9a-f]+ contains 4 entries:
+ +Offset +Info +Type +Symbol's Value Symbol's Name \+ Addend
+0+501358 0+100000012 R_X86_64_TPOFF64 +0+ sG5 \+ 0
+0+501360 0+200000012 R_X86_64_TPOFF64 +0+ sG2 \+ 0
+0+501368 0+400000012 R_X86_64_TPOFF64 +0+ sG6 \+ 0
+0+501370 0+500000012 R_X86_64_TPOFF64 +0+ sG1 \+ 0
+
+Symbol table '.dynsym' contains 8 entries:
+ +Num: +Value +Size Type +Bind +Vis +Ndx Name
+ +[0-9]+: 0+ +0 NOTYPE LOCAL DEFAULT UND *
+ +[0-9]+: 0+ +0 TLS +GLOBAL DEFAULT UND sG5
+ +[0-9]+: 0+ +0 TLS +GLOBAL DEFAULT UND sG2
+ +[0-9]+: 0+[0-9a-f]+ +0 NOTYPE GLOBAL DEFAULT ABS __bss_start
+ +[0-9]+: 0+ +0 TLS +GLOBAL DEFAULT UND sG6
+ +[0-9]+: 0+ +0 TLS +GLOBAL DEFAULT UND sG1
+ +[0-9]+: 0+[0-9a-f]+ +0 NOTYPE GLOBAL DEFAULT ABS _edata
+ +[0-9]+: 0+[0-9a-f]+ +0 NOTYPE GLOBAL DEFAULT ABS _end
+
+Symbol table '.symtab' contains 67 entries:
+ +Num: +Value +Size Type +Bind +Vis +Ndx Name
+ +[0-9]+: 0+ +0 NOTYPE LOCAL DEFAULT UND *
+ +[0-9]+: [0-9a-f]+ +0 SECTION LOCAL DEFAULT +1 *
+ +[0-9]+: [0-9a-f]+ +0 SECTION LOCAL DEFAULT +2 *
+ +[0-9]+: [0-9a-f]+ +0 SECTION LOCAL DEFAULT +3 *
+ +[0-9]+: [0-9a-f]+ +0 SECTION LOCAL DEFAULT +4 *
+ +[0-9]+: [0-9a-f]+ +0 SECTION LOCAL DEFAULT +5 *
+ +[0-9]+: [0-9a-f]+ +0 SECTION LOCAL DEFAULT +6 *
+ +[0-9]+: [0-9a-f]+ +0 SECTION LOCAL DEFAULT +7 *
+ +[0-9]+: [0-9a-f]+ +0 SECTION LOCAL DEFAULT +8 *
+ +[0-9]+: [0-9a-f]+ +0 SECTION LOCAL DEFAULT +9 *
+ +[0-9]+: [0-9a-f]+ +0 SECTION LOCAL DEFAULT +10 *
+ +[0-9]+: [0-9a-f]+ +0 SECTION LOCAL DEFAULT +11 *
+ +[0-9]+: [0-9a-f]+ +0 SECTION LOCAL DEFAULT +12 *
+ +[0-9]+: [0-9a-f]+ +0 SECTION LOCAL DEFAULT +13 *
+ +[0-9]+: [0-9a-f]+ +0 SECTION LOCAL DEFAULT +14 *
+ +[0-9]+: 0+20 +0 TLS +LOCAL DEFAULT +7 sl1
+ +[0-9]+: 0+24 +0 TLS +LOCAL DEFAULT +7 sl2
+ +[0-9]+: 0+28 +0 TLS +LOCAL DEFAULT +7 sl3
+ +[0-9]+: 0+2c +0 TLS +LOCAL DEFAULT +7 sl4
+ +[0-9]+: 0+30 +0 TLS +LOCAL DEFAULT +7 sl5
+ +[0-9]+: 0+34 +0 TLS +LOCAL DEFAULT +7 sl6
+ +[0-9]+: 0+38 +0 TLS +LOCAL DEFAULT +7 sl7
+ +[0-9]+: 0+3c +0 TLS +LOCAL DEFAULT +7 sl8
+ +[0-9]+: 0+80 +0 TLS +LOCAL DEFAULT +8 bl1
+ +[0-9]+: 0+84 +0 TLS +LOCAL DEFAULT +8 bl2
+ +[0-9]+: 0+88 +0 TLS +LOCAL DEFAULT +8 bl3
+ +[0-9]+: 0+8c +0 TLS +LOCAL DEFAULT +8 bl4
+ +[0-9]+: 0+90 +0 TLS +LOCAL DEFAULT +8 bl5
+ +[0-9]+: 0+94 +0 TLS +LOCAL DEFAULT +8 bl6
+ +[0-9]+: 0+98 +0 TLS +LOCAL DEFAULT +8 bl7
+ +[0-9]+: 0+9c +0 TLS +LOCAL DEFAULT +8 bl8
+ +[0-9]+: 0+0 +0 TLS +LOCAL HIDDEN +7 _TLS_MODULE_BASE_
+ +[0-9]+: 0+501258 +0 OBJECT LOCAL HIDDEN 9 _DYNAMIC
+ +[0-9]+: 0+501378 +0 OBJECT LOCAL HIDDEN 11 _GLOBAL_OFFSET_TABLE_
+ +[0-9]+: 0+1c +0 TLS +GLOBAL DEFAULT +7 sg8
+ +[0-9]+: 0+7c +0 TLS +GLOBAL DEFAULT +8 bg8
+ +[0-9]+: 0+74 +0 TLS +GLOBAL DEFAULT +8 bg6
+ +[0-9]+: 0+ +0 TLS +GLOBAL DEFAULT UND sG5
+ +[0-9]+: 0+68 +0 TLS +GLOBAL DEFAULT +8 bg3
+ +[0-9]+: 0+8 +0 TLS +GLOBAL DEFAULT +7 sg3
+ +[0-9]+: 0+48 +0 TLS +GLOBAL HIDDEN +7 sh3
+ +[0-9]+: 0+ +0 TLS +GLOBAL DEFAULT UND sG2
+ +[0-9]+: 0+c +0 TLS +GLOBAL DEFAULT +7 sg4
+ +[0-9]+: 0+10 +0 TLS +GLOBAL DEFAULT +7 sg5
+ +[0-9]+: 0+70 +0 TLS +GLOBAL DEFAULT +8 bg5
+ +[0-9]+: 0+58 +0 TLS +GLOBAL HIDDEN +7 sh7
+ +[0-9]+: 0+5c +0 TLS +GLOBAL HIDDEN +7 sh8
+ +[0-9]+: 0+ +0 TLS +GLOBAL DEFAULT +7 sg1
+ +[0-9]+: 0+401108 +0 FUNC +GLOBAL DEFAULT +6 _start
+ +[0-9]+: 0+4c +0 TLS +GLOBAL HIDDEN +7 sh4
+ +[0-9]+: 0+78 +0 TLS +GLOBAL DEFAULT +8 bg7
+ +[0-9]+: 0+50 +0 TLS +GLOBAL HIDDEN +7 sh5
+ +[0-9]+: [0-9a-f]+ +0 NOTYPE GLOBAL DEFAULT ABS __bss_start
+ +[0-9]+: 0+ +0 TLS +GLOBAL DEFAULT UND sG6
+ +[0-9]+: 0+401000 +0 FUNC +GLOBAL DEFAULT +6 fn2
+ +[0-9]+: 0+4 +0 TLS +GLOBAL DEFAULT +7 sg2
+ +[0-9]+: 0+ +0 TLS +GLOBAL DEFAULT UND sG1
+ +[0-9]+: 0+40 +0 TLS +GLOBAL HIDDEN +7 sh1
+ +[0-9]+: 0+14 +0 TLS +GLOBAL DEFAULT +7 sg6
+ +[0-9]+: 0+18 +0 TLS +GLOBAL DEFAULT +7 sg7
+ +[0-9]+: [0-9a-f]+ +0 NOTYPE GLOBAL DEFAULT ABS _edata
+ +[0-9]+: [0-9a-f]+ +0 NOTYPE GLOBAL DEFAULT ABS _end
+ +[0-9]+: 0+44 +0 TLS +GLOBAL HIDDEN +7 sh2
+ +[0-9]+: 0+54 +0 TLS +GLOBAL HIDDEN +7 sh6
+ +[0-9]+: 0+64 +0 TLS +GLOBAL DEFAULT +8 bg2
+ +[0-9]+: 0+60 +0 TLS +GLOBAL DEFAULT +8 bg1
+ +[0-9]+: 0+6c +0 TLS +GLOBAL DEFAULT +8 bg4
diff --git a/ld/testsuite/ld-x86-64/tlsbindesc.s b/ld/testsuite/ld-x86-64/tlsbindesc.s
new file mode 100644
index 0000000..cbebf02
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/tlsbindesc.s
@@ -0,0 +1,128 @@
+ /* 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 */
+ leaq sG1@tlsdesc(%rip), %rax
+ call *sG1@tlscall(%rax)
+ nop;nop;nop;nop
+
+ /* GD -> IE because variable is not defined in executable where
+ the variable is referenced through IE too */
+ leaq sG2@tlsdesc(%rip), %rax
+ call *sG2@tlscall(%rax)
+ nop;nop;nop;nop
+
+ /* GD -> LE with global variable defined in executable */
+ leaq sg1@tlsdesc(%rip), %rax
+ call *sg1@tlscall(%rax)
+ nop;nop;nop;nop
+
+ /* GD -> LE with local variable defined in executable */
+ leaq sl1@tlsdesc(%rip), %rax
+ call *sl1@tlscall(%rax)
+ nop;nop;nop;nop
+
+ /* GD -> LE with hidden variable defined in executable */
+ leaq sh1@tlsdesc(%rip), %rax
+ call *sh1@tlscall(%rax)
+ nop;nop;nop;nop
+
+ /* LD -> LE */
+ leaq _TLS_MODULE_BASE_@tlsdesc(%rip), %rax
+ call *_TLS_MODULE_BASE_@tlscall(%rax)
+ nop;nop
+ leaq 1+sl1@dtpoff(%rax), %rdx
+ nop;nop
+ leaq sl2@dtpoff+2(%rax), %r9
+ nop;nop;nop;nop
+
+ /* LD -> LE against hidden variables */
+ 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/tlsbindesc.sd b/ld/testsuite/ld-x86-64/tlsbindesc.sd
new file mode 100644
index 0000000..fd0519f
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/tlsbindesc.sd
@@ -0,0 +1,12 @@
+#source: tlsbindesc.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:
+ 501358 00000000 00000000 00000000 00000000 .*
+ 501368 00000000 00000000 00000000 00000000 .*
diff --git a/ld/testsuite/ld-x86-64/tlsbindesc.td b/ld/testsuite/ld-x86-64/tlsbindesc.td
new file mode 100644
index 0000000..226e52e
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/tlsbindesc.td
@@ -0,0 +1,16 @@
+#source: tlsbindesc.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:
+ 5011f6 11000000 12000000 13000000 14000000 .*
+ 501206 15000000 16000000 17000000 18000000 .*
+ 501216 41000000 42000000 43000000 44000000 .*
+ 501226 45000000 46000000 47000000 48000000 .*
+ 501236 01010000 02010000 03010000 04010000 .*
+ 501246 05010000 06010000 07010000 08010000 .*
diff --git a/ld/testsuite/ld-x86-64/tlsdesc.dd b/ld/testsuite/ld-x86-64/tlsdesc.dd
new file mode 100644
index 0000000..656e241
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/tlsdesc.dd
@@ -0,0 +1,204 @@
+#source: tlsdesc.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+[0-9a-f]+ <fn1>:
+ +[0-9a-f]+: 55[ ]+push %rbp
+ +[0-9a-f]+: 48 89 e5[ ]+mov %rsp,%rbp
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+# GD
+ +[0-9a-f]+: 48 8d 05 89 03 10 00[ ]+lea 1049481\(%rip\),%rax +# 101398 <.*>
+# -> R_X86_64_TLSDESC sg1
+ +[0-9a-f]+: ff 10[ ]+callq \*\(%rax\)
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+# GD -> IE because variable is referenced through IE too
+ +[0-9a-f]+: 48 8b 05 1c 03 10 00[ ]+mov 1049372\(%rip\),%rax +# 101338 <.*>
+# -> R_X86_64_TPOFF64 sg2
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+# GD against local variable
+ +[0-9a-f]+: 48 8d 05 3f 03 10 00[ ]+lea 1049407\(%rip\),%rax +# 101368 <.*>
+# -> R_X86_64_TLSDESC [0 0x2000000000000000]
+ +[0-9a-f]+: ff 10[ ]+callq \*\(%rax\)
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+# GD -> IE against local variable referenced through IE too
+ +[0-9a-f]+: 48 8b 05 d2 02 10 00[ ]+mov 1049298\(%rip\),%rax +# 101308 <.*>
+# -> R_X86_64_TPOFF64 *ABS*+0x24
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+# GD against hidden and local variable
+ +[0-9a-f]+: 48 8d 05 65 03 10 00[ ]+lea 1049445\(%rip\),%rax +# 1013a8 <.*>
+# -> R_X86_64_TLSDESC [0 0x4000000000000000]
+ +[0-9a-f]+: ff 10[ ]+callq \*\(%rax\)
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+# GD -> IE against hidden and local variable referenced through IE too
+ +[0-9a-f]+: 48 8b 05 f0 02 10 00[ ]+mov 1049328\(%rip\),%rax +# 101340 <.*>
+# -> R_X86_64_TPOFF64 *ABS*+0x44
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+# GD against hidden but not local variable
+ +[0-9a-f]+: 48 8d 05 1b 03 10 00[ ]+lea 1049371\(%rip\),%rax +# 101378 <.*>
+# -> R_X86_64_TLSDESC [0 0x6000000000000000]
+ +[0-9a-f]+: ff 10[ ]+callq \*\(%rax\)
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+# GD -> IE against hidden but not local variable referenced through IE too
+ +[0-9a-f]+: 48 8b 05 ae 02 10 00[ ]+mov 1049262\(%rip\),%rax +# 101318 <.*>
+# -> R_X86_64_TPOFF64 *ABS*+0x64
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+# LD
+ +[0-9a-f]+: 48 8d 05 11 03 10 00[ ]+lea 1049361\(%rip\),%rax +# 101388 <.*>
+# -> R_X86_64_TLSDESC [0 0x000000000000000]
+ +[0-9a-f]+: ff 10[ ]+callq \*\(%rax\)
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 48 8d 90 20 00 00 00[ ]+lea 0x20\(%rax\),%rdx
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 4c 8d 88 26 00 00 00[ ]+lea 0x26\(%rax\),%r9
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+# LD against hidden and local variables
+ +[0-9a-f]+: 48 8d 90 40 00 00 00[ ]+lea 0x40\(%rax\),%rdx
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 48 8d 88 47 00 00 00[ ]+lea 0x47\(%rax\),%rcx
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+# LD against hidden but not local variables
+ +[0-9a-f]+: 4c 8d a0 60 00 00 00[ ]+lea 0x60\(%rax\),%r12
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 48 8d 88 65 00 00 00[ ]+lea 0x65\(%rax\),%rcx
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+# IE against global var
+ +[0-9a-f]+: 64 48 8b 0c 25 00 00[ ]+mov %fs:0x0,%rcx
+ +[0-9a-f]+: 00 00 *
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 48 03 0d 71 02 10 00[ ]+add 1049201\(%rip\),%rcx +# 101338 <.*>
+# -> R_X86_64_TPOFF64 sg2
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+# IE against local var
+ +[0-9a-f]+: 64 4c 8b 34 25 00 00[ ]+mov %fs:0x0,%r14
+ +[0-9a-f]+: 00 00 *
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 4c 03 35 2b 02 10 00[ ]+add 1049131\(%rip\),%r14 +# 101308 <.*>
+# -> R_X86_64_TPOFF64 *ABS*+0x24
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+# IE against hidden and local var
+ +[0-9a-f]+: 64 48 8b 0c 25 00 00[ ]+mov %fs:0x0,%rcx
+ +[0-9a-f]+: 00 00 *
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 48 03 0d 4d 02 10 00[ ]+add 1049165\(%rip\),%rcx +# 101340 <.*>
+# -> R_X86_64_TPOFF64 *ABS*+0x44
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+# IE against hidden but not local var
+ +[0-9a-f]+: 64 48 8b 0c 25 00 00[ ]+mov %fs:0x0,%rcx
+ +[0-9a-f]+: 00 00 *
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 48 03 0d 0f 02 10 00[ ]+add 1049103\(%rip\),%rcx +# 101318 <.*>
+# -> R_X86_64_TPOFF64 *ABS*+0x64
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+# Direct access through %fs
+# IE against global var
+ +[0-9a-f]+: 48 8b 0d 0c 02 10 00[ ]+mov 1049100\(%rip\),%rcx +# 101320 <.*>
+# -> R_X86_64_TPOFF64 sg5
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 64 48 8b 11[ ]+mov %fs:\(%rcx\),%rdx
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+# IE against local var
+ +[0-9a-f]+: 4c 8b 15 eb 01 10 00[ ]+mov 1049067\(%rip\),%r10 +# 101310 <.*>
+# -> R_X86_64_TPOFF64 *ABS*+0x30
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 64 4d 8b 22[ ]+mov %fs:\(%r10\),%r12
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+# IE against hidden and local var
+ +[0-9a-f]+: 48 8b 15 f2 01 10 00[ ]+mov 1049074\(%rip\),%rdx +# 101328 <.*>
+# -> R_X86_64_TPOFF64 *ABS*+0x50
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 64 48 8b 12[ ]+mov %fs:\(%rdx\),%rdx
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+# IE against hidden but not local var
+ +[0-9a-f]+: 48 8b 0d e9 01 10 00[ ]+mov 1049065\(%rip\),%rcx +# 101330 <.*>
+# -> R_X86_64_TPOFF64 *ABS*+0x70
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 64 48 8b 11[ ]+mov %fs:\(%rcx\),%rdx
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: c9[ ]+leaveq *
+ +[0-9a-f]+: c3[ ]+retq *
+ +[0-9a-f]+: 90[ ]+nop *
diff --git a/ld/testsuite/ld-x86-64/tlsdesc.pd b/ld/testsuite/ld-x86-64/tlsdesc.pd
new file mode 100644
index 0000000..aea1bab
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/tlsdesc.pd
@@ -0,0 +1,26 @@
+#source: tlsdesc.s
+#source: tlspic2.s
+#as: --64
+#ld: -shared -melf_x86_64
+#objdump: -drj.plt
+#target: x86_64-*-*
+
+.*: +file format elf64-x86-64
+
+Disassembly of section .plt:
+
+0000000000000470 <.*@plt-0x10>:
+ 470: ff 35 e2 0e 10 00 pushq 1052386\(%rip\) # 101358 <_GLOBAL_OFFSET_TABLE_\+0x8>
+ 476: ff 25 e4 0e 10 00 jmpq \*1052388\(%rip\) # 101360 <_GLOBAL_OFFSET_TABLE_\+0x10>
+ 47c: 90 nop *
+ 47d: 90 nop *
+ 47e: 90 nop *
+ 47f: 90 nop *
+0000000000000480 <.*@plt>:
+ 480: ff 35 d2 0e 10 00 pushq 1052370\(%rip\) # 101358 <_GLOBAL_OFFSET_TABLE_\+0x8>
+ 486: ff 25 bc 0e 10 00 jmpq \*1052348\(%rip\) # 101348 <_DYNAMIC\+0x190>
+ 48c: 90 nop *
+ 48d: 90 nop *
+ 48e: 90 nop *
+ 48f: 90 nop *
+
diff --git a/ld/testsuite/ld-x86-64/tlsdesc.rd b/ld/testsuite/ld-x86-64/tlsdesc.rd
new file mode 100644
index 0000000..e7e21ed
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/tlsdesc.rd
@@ -0,0 +1,164 @@
+#source: tlsdesc.s
+#source: tlspic2.s
+#as: --64
+#ld: -shared -melf_x86_64
+#readelf: -WSsrld
+#target: x86_64-*-*
+
+There are 16 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 +PROGBITS +0+470 0+470 0+20 10 +AX +0 +0 +4
+ \[ 7\] .text +PROGBITS +0+1000 0+1000 0+154 00 +AX +0 +0 4096
+ \[ 8\] .tdata +PROGBITS +0+101154 0+1154 0+60 00 WAT +0 +0 +1
+ \[ 9\] .tbss +NOBITS +0+1011b4 0+11b4 0+20 00 WAT +0 +0 +1
+ \[10\] .dynamic +DYNAMIC +0+1011b8 0+11b8 0+150 10 +WA +3 +0 +8
+ \[11\] .got +PROGBITS +0+101308 0+1308 0+48 08 +WA +0 +0 +8
+ \[12\] .got.plt +PROGBITS +0+101350 0+1350 0+68 08 +WA +0 +0 +8
+ \[13\] .shstrtab +.*
+ \[14\] .symtab +.*
+ \[15\] .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+1154 0x0+101154 0x0+101154 0x0+264 0x0+264 RW +0x100000
+ DYNAMIC +0x0+11b8 0x0+1011b8 0x0+1011b8 0x0+150 0x0+150 RW +0x8
+ TLS +0x0+1154 0x0+101154 0x0+101154 0x0+60 0x0+80 R +0x1
+
+ Section to Segment mapping:
+ Segment Sections...
+ 00 +.hash .dynsym .dynstr .rela.dyn .rela.plt .plt .text *
+ 01 +.tdata .dynamic .got .got.plt *
+ 02 +.dynamic *
+ 03 +.tdata .tbss *
+
+Dynamic section at offset 0x[0-9a-f]+ contains 16 entries:
+ +Tag +Type +Name/Value
+ 0x[0-9a-f]+ +\(HASH\).*
+ 0x[0-9a-f]+ +\(STRTAB\).*
+ 0x[0-9a-f]+ +\(SYMTAB\).*
+ 0x[0-9a-f]+ +\(STRSZ\).*
+ 0x[0-9a-f]+ +\(SYMENT\).*
+ 0x[0-9a-f]+ +\(PLTGOT\).*
+ 0x[0-9a-f]+ +\(PLTRELSZ\).*
+ 0x[0-9a-f]+ +\(PLTREL\).*
+ 0x[0-9a-f]+ +\(JMPREL\).*
+ 0x[0-9a-f]+ +\(TLSDESC_PLT\) +0x480
+ 0x[0-9a-f]+ +\(TLSDESC_GOT\) +0x101348
+ 0x[0-9a-f]+ +\(RELA\).*
+ 0x[0-9a-f]+ +\(RELASZ\).*
+ 0x[0-9a-f]+ +\(RELAENT\).*
+ 0x[0-9a-f]+ +\(FLAGS\).*
+ 0x[0-9a-f]+ +\(NULL\).*
+
+Relocation section '.rela.dyn' at offset 0x[0-9a-f]+ contains 8 entries:
+ +Offset +Info +Type +Symbol's Value +Symbol's Name \+ Addend
+0+101308 0+12 R_X86_64_TPOFF64 +0+24
+0+101310 0+12 R_X86_64_TPOFF64 +0+30
+0+101318 0+12 R_X86_64_TPOFF64 +0+64
+0+101328 0+12 R_X86_64_TPOFF64 +0+50
+0+101330 0+12 R_X86_64_TPOFF64 +0+70
+0+101340 0+12 R_X86_64_TPOFF64 +0+44
+0+101320 0+700000012 R_X86_64_TPOFF64 +0+10 sg5 \+ 0
+0+101338 0+b00000012 R_X86_64_TPOFF64 +0+4 sg2 \+ 0
+
+Relocation section '.rela.plt' at offset 0x[0-9a-f]+ contains 5 entries:
+ +Offset +Info +Type +Symbol's Value Symbol's Name \+ Addend
+0+101398 0+800000024 R_X86_64_TLSDESC +0+ sg1 \+ 0
+0+101368 0+24 R_X86_64_TLSDESC +0+20
+0+1013a8 0+24 R_X86_64_TLSDESC +0+40
+0+101378 0+24 R_X86_64_TLSDESC +0+60
+0+101388 0+24 R_X86_64_TLSDESC +0+
+
+Symbol table '.dynsym' contains 16 entries:
+ +Num: +Value +Size Type +Bind +Vis +Ndx Name
+ +[0-9]+: 0+ +0 NOTYPE LOCAL DEFAULT UND *
+ +[0-9]+: [0-9a-f]+ +0 SECTION LOCAL DEFAULT +7 *
+ +[0-9]+: [0-9a-f]+ +0 SECTION LOCAL DEFAULT +8 *
+ +[0-9]+: [0-9a-f]+ +0 SECTION LOCAL DEFAULT +9 *
+ +[0-9]+: 0+1c +0 TLS +GLOBAL DEFAULT +8 sg8
+ +[0-9]+: 0+8 +0 TLS +GLOBAL DEFAULT +8 sg3
+ +[0-9]+: 0+c +0 TLS +GLOBAL DEFAULT +8 sg4
+ +[0-9]+: 0+10 +0 TLS +GLOBAL DEFAULT +8 sg5
+ +[0-9]+: 0+ +0 TLS +GLOBAL DEFAULT +8 sg1
+ +[0-9]+: 0+1000 +0 FUNC +GLOBAL DEFAULT +7 fn1
+ +[0-9]+: [0-9a-f]+ +0 NOTYPE GLOBAL DEFAULT ABS __bss_start
+ +[0-9]+: 0+4 +0 TLS +GLOBAL DEFAULT +8 sg2
+ +[0-9]+: 0+14 +0 TLS +GLOBAL DEFAULT +8 sg6
+ +[0-9]+: 0+18 +0 TLS +GLOBAL DEFAULT +8 sg7
+ +[0-9]+: [0-9a-f]+ +0 NOTYPE GLOBAL DEFAULT ABS _edata
+ +[0-9]+: [0-9a-f]+ +0 NOTYPE GLOBAL DEFAULT ABS _end
+
+Symbol table '.symtab' contains 55 entries:
+ +Num: +Value +Size Type +Bind +Vis +Ndx Name
+ +[0-9]+: 0+ +0 NOTYPE LOCAL DEFAULT UND *
+ +[0-9]+: [0-9a-f]+ +0 SECTION LOCAL DEFAULT +1 *
+ +[0-9]+: [0-9a-f]+ +0 SECTION LOCAL DEFAULT +2 *
+ +[0-9]+: [0-9a-f]+ +0 SECTION LOCAL DEFAULT +3 *
+ +[0-9]+: [0-9a-f]+ +0 SECTION LOCAL DEFAULT +4 *
+ +[0-9]+: [0-9a-f]+ +0 SECTION LOCAL DEFAULT +5 *
+ +[0-9]+: [0-9a-f]+ +0 SECTION LOCAL DEFAULT +6 *
+ +[0-9]+: [0-9a-f]+ +0 SECTION LOCAL DEFAULT +7 *
+ +[0-9]+: [0-9a-f]+ +0 SECTION LOCAL DEFAULT +8 *
+ +[0-9]+: [0-9a-f]+ +0 SECTION LOCAL DEFAULT +9 *
+ +[0-9]+: [0-9a-f]+ +0 SECTION LOCAL DEFAULT +10 *
+ +[0-9]+: [0-9a-f]+ +0 SECTION LOCAL DEFAULT +11 *
+ +[0-9]+: [0-9a-f]+ +0 SECTION LOCAL DEFAULT +12 *
+ +[0-9]+: [0-9a-f]+ +0 SECTION LOCAL DEFAULT +13 *
+ +[0-9]+: [0-9a-f]+ +0 SECTION LOCAL DEFAULT +14 *
+ +[0-9]+: [0-9a-f]+ +0 SECTION LOCAL DEFAULT +15 *
+ +[0-9]+: 0+20 +0 TLS +LOCAL DEFAULT +8 sl1
+ +[0-9]+: 0+24 +0 TLS +LOCAL DEFAULT +8 sl2
+ +[0-9]+: 0+28 +0 TLS +LOCAL DEFAULT +8 sl3
+ +[0-9]+: 0+2c +0 TLS +LOCAL DEFAULT +8 sl4
+ +[0-9]+: 0+30 +0 TLS +LOCAL DEFAULT +8 sl5
+ +[0-9]+: 0+34 +0 TLS +LOCAL DEFAULT +8 sl6
+ +[0-9]+: 0+38 +0 TLS +LOCAL DEFAULT +8 sl7
+ +[0-9]+: 0+3c +0 TLS +LOCAL DEFAULT +8 sl8
+ +[0-9]+: 0+60 +0 TLS +LOCAL HIDDEN +9 sH1
+ +[0-9]+: 0+ +0 TLS +LOCAL HIDDEN +8 _TLS_MODULE_BASE_
+ +[0-9]+: 0+1011b8 +0 OBJECT LOCAL HIDDEN ABS _DYNAMIC
+ +[0-9]+: 0+48 +0 TLS +LOCAL HIDDEN +8 sh3
+ +[0-9]+: 0+64 +0 TLS +LOCAL HIDDEN +9 sH2
+ +[0-9]+: 0+78 +0 TLS +LOCAL HIDDEN +9 sH7
+ +[0-9]+: 0+58 +0 TLS +LOCAL HIDDEN +8 sh7
+ +[0-9]+: 0+5c +0 TLS +LOCAL HIDDEN +8 sh8
+ +[0-9]+: 0+6c +0 TLS +LOCAL HIDDEN +9 sH4
+ +[0-9]+: 0+4c +0 TLS +LOCAL HIDDEN +8 sh4
+ +[0-9]+: 0+68 +0 TLS +LOCAL HIDDEN +9 sH3
+ +[0-9]+: 0+50 +0 TLS +LOCAL HIDDEN +8 sh5
+ +[0-9]+: 0+70 +0 TLS +LOCAL HIDDEN +9 sH5
+ +[0-9]+: 0+74 +0 TLS +LOCAL HIDDEN +9 sH6
+ +[0-9]+: 0+7c +0 TLS +LOCAL HIDDEN +9 sH8
+ +[0-9]+: 0+40 +0 TLS +LOCAL HIDDEN +8 sh1
+ +[0-9]+: 0+101350 +0 OBJECT LOCAL HIDDEN ABS _GLOBAL_OFFSET_TABLE_
+ +[0-9]+: 0+44 +0 TLS +LOCAL HIDDEN +8 sh2
+ +[0-9]+: 0+54 +0 TLS +LOCAL HIDDEN +8 sh6
+ +[0-9]+: 0+1c +0 TLS +GLOBAL DEFAULT +8 sg8
+ +[0-9]+: 0+8 +0 TLS +GLOBAL DEFAULT +8 sg3
+ +[0-9]+: 0+c +0 TLS +GLOBAL DEFAULT +8 sg4
+ +[0-9]+: 0+10 +0 TLS +GLOBAL DEFAULT +8 sg5
+ +[0-9]+: 0+ +0 TLS +GLOBAL DEFAULT +8 sg1
+ +[0-9]+: 0+1000 +0 FUNC +GLOBAL DEFAULT +7 fn1
+ +[0-9]+: [0-9a-f]+ +0 NOTYPE GLOBAL DEFAULT ABS __bss_start
+ +[0-9]+: 0+4 +0 TLS +GLOBAL DEFAULT +8 sg2
+ +[0-9]+: 0+14 +0 TLS +GLOBAL DEFAULT +8 sg6
+ +[0-9]+: 0+18 +0 TLS +GLOBAL DEFAULT +8 sg7
+ +[0-9]+: [0-9a-f]+ +0 NOTYPE GLOBAL DEFAULT ABS _edata
+ +[0-9]+: [0-9a-f]+ +0 NOTYPE GLOBAL DEFAULT ABS _end
diff --git a/ld/testsuite/ld-x86-64/tlsdesc.s b/ld/testsuite/ld-x86-64/tlsdesc.s
new file mode 100644
index 0000000..ec6d190
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/tlsdesc.s
@@ -0,0 +1,157 @@
+ /* 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 */
+ leaq sg1@tlsdesc(%rip), %rax
+ call *sg1@tlscall(%rax)
+ nop;nop;nop;nop
+
+ /* GD -> IE because variable is referenced through IE too */
+ leaq sg2@tlsdesc(%rip), %rax
+ call *sg2@tlscall(%rax)
+ nop;nop;nop;nop
+
+ /* GD against local variable */
+ leaq sl1@tlsdesc(%rip), %rax
+ call *sl1@tlscall(%rax)
+ nop;nop;nop;nop
+
+ /* GD -> IE against local variable referenced through IE too */
+ leaq sl2@tlsdesc(%rip), %rax
+ call *sl2@tlscall(%rax)
+ nop;nop;nop;nop
+
+ /* GD against hidden and local variable */
+ leaq sh1@tlsdesc(%rip), %rax
+ call *sh1@tlscall(%rax)
+ nop;nop;nop;nop
+
+ /* GD -> IE against hidden and local variable referenced through
+ IE too */
+ leaq sh2@tlsdesc(%rip), %rax
+ call *sh2@tlscall(%rax)
+ nop;nop;nop;nop
+
+ /* GD against hidden but not local variable */
+ leaq sH1@tlsdesc(%rip), %rax
+ call *sH1@tlscall(%rax)
+ nop;nop;nop;nop
+
+ /* GD -> IE against hidden but not local variable referenced through
+ IE too */
+ leaq sH2@tlsdesc(%rip), %rax
+ call *sH2@tlscall(%rax)
+ nop;nop;nop;nop
+
+ /* LD */
+ leaq _TLS_MODULE_BASE_@tlsdesc(%rip), %rax
+ call *_TLS_MODULE_BASE_@tlscall(%rax)
+ 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@dtpoff(%rax), %rdx
+ nop;nop
+ leaq sh2@dtpoff+3(%rax), %rcx
+ nop;nop;nop;nop
+
+ /* LD against hidden but not local variables */
+ 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/tlsdesc.sd b/ld/testsuite/ld-x86-64/tlsdesc.sd
new file mode 100644
index 0000000..8eb5d9c
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/tlsdesc.sd
@@ -0,0 +1,23 @@
+#source: tlsdesc.s
+#source: tlspic2.s
+#as: --64
+#ld: -shared -melf_x86_64
+#objdump: -s -j.got -j.got.plt
+#target: x86_64-*-*
+
+.*: +file format elf64-x86-64
+
+Contents of section \.got:
+ 101308 00000000 00000000 00000000 00000000 .*
+ 101318 00000000 00000000 00000000 00000000 .*
+ 101328 00000000 00000000 00000000 00000000 .*
+ 101338 00000000 00000000 00000000 00000000 .*
+ 101348 00000000 00000000 .*
+Contents of section \.got\.plt:
+ 101350 b8111000 00000000 00000000 00000000 .*
+ 101360 00000000 00000000 00000000 00000000 .*
+ 101370 00000000 00000000 00000000 00000000 .*
+ 101380 00000000 00000000 00000000 00000000 .*
+ 101390 00000000 00000000 00000000 00000000 .*
+ 1013a0 00000000 00000000 00000000 00000000 .*
+ 1013b0 00000000 00000000 .*
diff --git a/ld/testsuite/ld-x86-64/tlsdesc.td b/ld/testsuite/ld-x86-64/tlsdesc.td
new file mode 100644
index 0000000..dd79816
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/tlsdesc.td
@@ -0,0 +1,16 @@
+#source: tlsdesc.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:
+ 101154 11000000 12000000 13000000 14000000 .*
+ 101164 15000000 16000000 17000000 18000000 .*
+ 101174 41000000 42000000 43000000 44000000 .*
+ 101184 45000000 46000000 47000000 48000000 .*
+ 101194 01010000 02010000 03010000 04010000 .*
+ 1011a4 05010000 06010000 07010000 08010000 .*
diff --git a/ld/testsuite/ld-x86-64/tlsgdesc.dd b/ld/testsuite/ld-x86-64/tlsgdesc.dd
new file mode 100644
index 0000000..b0e7c05
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/tlsgdesc.dd
@@ -0,0 +1,167 @@
+#source: tlsgdesc.s
+#as: --64
+#ld: -shared -melf_x86_64
+#objdump: -drj.text
+#target: x86_64-*-*
+
+.*: +file format elf64-x86-64
+
+Disassembly of section .text:
+
+0+[0-9a-f]+ <fc1>:
+ +[0-9a-f]+: 55[ ]+push %rbp
+ +[0-9a-f]+: 48 89 e5[ ]+mov %rsp,%rbp
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+# IE
+ +[0-9a-f]+: 64 48 8b 0c 25 00 00[ ]+mov %fs:0x0,%rcx
+ +[0-9a-f]+: 00 00 *
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 48 03 0d 5e 02 10 00[ ]+add 1049182\(%rip\),%rcx +# 100660 <.*>
+# -> R_X86_64_TPOFF64 sG3
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+# IE
+ +[0-9a-f]+: 64 48 8b 0c 25 00 00[ ]+mov %fs:0x0,%rcx
+ +[0-9a-f]+: 00 00 *
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 48 03 0d 68 02 10 00[ ]+add 1049192\(%rip\),%rcx +# 100680 <.*>
+# -> R_X86_64_TPOFF64 sG4
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+# GD, gd first
+ +[0-9a-f]+: 66 48 8d 3d 6c 02 10[ ]+lea 1049196\(%rip\),%rdi +# 100690 <.*>
+ +[0-9a-f]+: 00 *
+# -> R_X86_64_DTPMOD64 sG1
+ +[0-9a-f]+: 66 66 48 e8 9c ff ff[ ]+callq [0-9a-f]+ <.*>
+ +[0-9a-f]+: ff[ ]+
+# -> R_X86_64_JUMP_SLOT __tls_get_addr
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 48 8d 05 a1 02 10 00[ ]+lea 1049249\(%rip\),%rax +# 1006d8 <.*>
+# -> R_X86_64_TLSDESC sG1
+ +[0-9a-f]+: ff 10[ ]+callq \*\(%rax\)
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+# GD, desc first
+ +[0-9a-f]+: 48 8d 05 84 02 10 00[ ]+lea 1049220\(%rip\),%rax +# 1006c8 <.*>
+# -> R_X86_64_TLSDESC sG2
+ +[0-9a-f]+: ff 10[ ]+callq \*\(%rax\)
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 66 48 8d 3d 1e 02 10[ ]+lea 1049118\(%rip\),%rdi +# 100670 <.*>
+ +[0-9a-f]+: 00 *
+# -> R_X86_64_DTPMOD64 sG2
+ +[0-9a-f]+: 66 66 48 e8 6e ff ff[ ]+callq [0-9a-f]+ <.*>
+ +[0-9a-f]+: ff[ ]+
+# -> R_X86_64_JUMP_SLOT __tls_get_addr
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+# GD -> IE, gd first, after IE use
+ +[0-9a-f]+: 64 48 8b 04 25 00 00[ ]+mov %fs:0x0,%rax
+ +[0-9a-f]+: 00 00 *
+ +[0-9a-f]+: 48 03 05 f2 01 10 00[ ]+add 1049074\(%rip\),%rax +# 100660 <.*>
+# -> R_X86_64_TPOFF64 sG3
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 48 8b 05 e7 01 10 00[ ]+mov 1049063\(%rip\),%rax +# 100660 <.*>
+# -> R_X86_64_TPOFF64 sG3
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+# GD -> IE, desc first, after IE use
+ +[0-9a-f]+: 48 8b 05 fa 01 10 00[ ]+mov 1049082\(%rip\),%rax +# 100680 <.*>
+# -> R_X86_64_TPOFF64 sG4
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 64 48 8b 04 25 00 00[ ]+mov %fs:0x0,%rax
+ +[0-9a-f]+: 00 00 *
+ +[0-9a-f]+: 48 03 05 e4 01 10 00[ ]+add 1049060\(%rip\),%rax +# 100680 <.*>
+# -> R_X86_64_TPOFF64 sG4
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+# GD -> IE, gd first, before IE use
+ +[0-9a-f]+: 64 48 8b 04 25 00 00[ ]+mov %fs:0x0,%rax
+ +[0-9a-f]+: 00 00 *
+ +[0-9a-f]+: 48 03 05 b8 01 10 00[ ]+add 1049016\(%rip\),%rax +# 100668 <.*>
+# -> R_X86_64_TPOFF64 sG5
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 48 8b 05 ad 01 10 00[ ]+mov 1049005\(%rip\),%rax +# 100668 <.*>
+# -> R_X86_64_TPOFF64 sG5
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+# GD -> IE, desc first, before IE use
+ +[0-9a-f]+: 48 8b 05 c0 01 10 00[ ]+mov 1049024\(%rip\),%rax +# 100688 <.*>
+# -> R_X86_64_TPOFF64 sG6
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 64 48 8b 04 25 00 00[ ]+mov %fs:0x0,%rax
+ +[0-9a-f]+: 00 00 *
+ +[0-9a-f]+: 48 03 05 aa 01 10 00[ ]+add 1049002\(%rip\),%rax +# 100688 <.*>
+# -> R_X86_64_TPOFF64 sG6
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+# IE
+ +[0-9a-f]+: 64 48 8b 0c 25 00 00[ ]+mov %fs:0x0,%rcx
+ +[0-9a-f]+: 00 00 *
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 48 03 0d 74 01 10 00[ ]+add 1048948\(%rip\),%rcx +# 100668 <.*>
+# -> R_X86_64_TPOFF64 sG5
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+# IE
+ +[0-9a-f]+: 64 48 8b 0c 25 00 00[ ]+mov %fs:0x0,%rcx
+ +[0-9a-f]+: 00 00 *
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 48 03 0d 7e 01 10 00[ ]+add 1048958\(%rip\),%rcx +# 100688 <.*>
+# -> R_X86_64_TPOFF64 sG6
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: 90[ ]+nop *
+ +[0-9a-f]+: c9[ ]+leaveq *
+ +[0-9a-f]+: c3[ ]+retq *
diff --git a/ld/testsuite/ld-x86-64/tlsgdesc.rd b/ld/testsuite/ld-x86-64/tlsgdesc.rd
new file mode 100644
index 0000000..2f7621b
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/tlsgdesc.rd
@@ -0,0 +1,107 @@
+#source: tlsgdesc.s
+#as: --64
+#ld: -shared -melf64_x86_64
+#readelf: -WSsrl
+#target: x86_64-*-*
+
+There are [0-9]+ section headers, starting at offset 0x.*:
+
+Section Headers:
+ \[Nr\] Name +Type +Address +Off +Size +ES Flg Lk Inf Al
+ \[ 0\] +NULL +0+ 0+ 0+ 0+ +0 +0 +0
+ \[ 1\] \.hash +.*
+ \[ 2\] \.dynsym +.*
+ \[ 3\] \.dynstr +.*
+ \[ 4\] \.rela.dyn +.*
+ \[ 5\] \.rela.plt +.*
+ \[ 6\] \.plt +.*
+ \[ 7\] \.text +.*
+ \[ 8\] \.dynamic +.*
+ \[ 9\] \.got +.*
+ \[10\] \.got.plt +.*
+ \[11\] \.shstrtab +.*
+ \[12\] \.symtab +.*
+ \[13\] \.strtab +.*
+Key to Flags:
+.*
+.*
+.*
+
+Elf file type is DYN \(Shared object file\)
+Entry point 0x[0-9a-f]+
+There are [0-9]+ program headers, starting at offset [0-9]+
+
+Program Headers:
+ Type +Offset +VirtAddr +PhysAddr +FileSiz +MemSiz +Flg Align
+ LOAD.*
+ LOAD.*
+ DYNAMIC.*
+
+ Section to Segment mapping:
+ Segment Sections...
+ 00 +.hash .dynsym .dynstr .rela.dyn .rela.plt .plt .text *
+ 01 +.dynamic .got .got.plt *
+ 02 +.dynamic *
+
+Relocation section '.rela.dyn' at offset 0x[0-9a-f]+ contains 8 entries:
+ +Offset +Info +Type +Symbol's Value Symbol's Name \+ Addend
+[0-9a-f]+ 0+200000012 R_X86_64_TPOFF64 +0+ sG3 \+ 0
+[0-9a-f]+ 0+300000012 R_X86_64_TPOFF64 +0+ sG5 \+ 0
+[0-9a-f]+ 0+400000010 R_X86_64_DTPMOD64 +0+ sG2 \+ 0
+[0-9a-f]+ 0+400000011 R_X86_64_DTPOFF64 +0+ sG2 \+ 0
+[0-9a-f]+ 0+500000012 R_X86_64_TPOFF64 +0+ sG4 \+ 0
+[0-9a-f]+ 0+800000012 R_X86_64_TPOFF64 +0+ sG6 \+ 0
+[0-9a-f]+ 0+a00000010 R_X86_64_DTPMOD64 +0+ sG1 \+ 0
+[0-9a-f]+ 0+a00000011 R_X86_64_DTPOFF64 +0+ sG1 \+ 0
+
+Relocation section '.rela.plt' at offset 0x[0-9a-f]+ contains 3 entries:
+ +Offset +Info +Type +Symbol's Value Symbol's Name \+ Addend
+[0-9a-f]+ 0+600000007 R_X86_64_JUMP_SLOT +0+ __tls_get_addr \+ 0
+[0-9a-f]+ 0+a00000024 R_X86_64_TLSDESC +0+ sG1 \+ 0
+[0-9a-f]+ 0+400000024 R_X86_64_TLSDESC +0+ sG2 \+ 0
+
+Symbol table '.dynsym' contains 13 entries:
+ +Num: +Value +Size Type +Bind +Vis +Ndx Name
+ +[0-9]+: 0+ +0 NOTYPE LOCAL DEFAULT UND *
+ +[0-9]+: [0-9a-f]+ +0 SECTION LOCAL DEFAULT +7 *
+ +[0-9]+: 0+ +0 TLS +GLOBAL DEFAULT UND sG3
+ +[0-9]+: 0+ +0 TLS +GLOBAL DEFAULT UND sG5
+ +[0-9]+: 0+ +0 TLS +GLOBAL DEFAULT UND sG2
+ +[0-9]+: 0+ +0 TLS +GLOBAL DEFAULT UND sG4
+ +[0-9]+: 0+ +0 NOTYPE GLOBAL DEFAULT UND __tls_get_addr
+ +[0-9]+: [0-9a-f]+ +0 NOTYPE GLOBAL DEFAULT ABS __bss_start
+ +[0-9]+: 0+ +0 TLS +GLOBAL DEFAULT UND sG6
+ +[0-9]+: [0-9a-f]+ +0 FUNC +GLOBAL DEFAULT +7 fc1
+ +[0-9]+: 0+ +0 TLS +GLOBAL DEFAULT UND sG1
+ +[0-9]+: [0-9a-f]+ +0 NOTYPE GLOBAL DEFAULT ABS _edata
+ +[0-9]+: [0-9a-f]+ +0 NOTYPE GLOBAL DEFAULT ABS _end
+
+Symbol table '.symtab' contains 27 entries:
+ +Num: +Value +Size Type +Bind +Vis +Ndx Name
+ +[0-9]+: 0+ +0 NOTYPE LOCAL DEFAULT UND *
+ +[0-9]+: [0-9a-f]+ +0 SECTION LOCAL DEFAULT +1 *
+ +[0-9]+: [0-9a-f]+ +0 SECTION LOCAL DEFAULT +2 *
+ +[0-9]+: [0-9a-f]+ +0 SECTION LOCAL DEFAULT +3 *
+ +[0-9]+: [0-9a-f]+ +0 SECTION LOCAL DEFAULT +4 *
+ +[0-9]+: [0-9a-f]+ +0 SECTION LOCAL DEFAULT +5 *
+ +[0-9]+: [0-9a-f]+ +0 SECTION LOCAL DEFAULT +6 *
+ +[0-9]+: [0-9a-f]+ +0 SECTION LOCAL DEFAULT +7 *
+ +[0-9]+: [0-9a-f]+ +0 SECTION LOCAL DEFAULT +8 *
+ +[0-9]+: [0-9a-f]+ +0 SECTION LOCAL DEFAULT +9 *
+ +[0-9]+: [0-9a-f]+ +0 SECTION LOCAL DEFAULT +10 *
+ +[0-9]+: [0-9a-f]+ +0 SECTION LOCAL DEFAULT +11 *
+ +[0-9]+: [0-9a-f]+ +0 SECTION LOCAL DEFAULT +12 *
+ +[0-9]+: [0-9a-f]+ +0 SECTION LOCAL DEFAULT +13 *
+ +[0-9]+: [0-9a-f]+ +0 OBJECT LOCAL HIDDEN ABS _DYNAMIC
+ +[0-9]+: [0-9a-f]+ +0 OBJECT LOCAL HIDDEN ABS _GLOBAL_OFFSET_TABLE_
+ +[0-9]+: 0+ +0 TLS +GLOBAL DEFAULT UND sG3
+ +[0-9]+: 0+ +0 TLS +GLOBAL DEFAULT UND sG5
+ +[0-9]+: 0+ +0 TLS +GLOBAL DEFAULT UND sG2
+ +[0-9]+: 0+ +0 TLS +GLOBAL DEFAULT UND sG4
+ +[0-9]+: 0+ +0 NOTYPE GLOBAL DEFAULT UND __tls_get_addr
+ +[0-9]+: [0-9a-f]+ +0 NOTYPE GLOBAL DEFAULT ABS __bss_start
+ +[0-9]+: 0+ +0 TLS +GLOBAL DEFAULT UND sG6
+ +[0-9]+: [0-9a-f]+ +0 FUNC +GLOBAL DEFAULT +7 fc1
+ +[0-9]+: 0+ +0 TLS +GLOBAL DEFAULT UND sG1
+ +[0-9]+: [0-9a-f]+ +0 NOTYPE GLOBAL DEFAULT ABS _edata
+ +[0-9]+: [0-9a-f]+ +0 NOTYPE GLOBAL DEFAULT ABS _end
diff --git a/ld/testsuite/ld-x86-64/tlsgdesc.s b/ld/testsuite/ld-x86-64/tlsgdesc.s
new file mode 100644
index 0000000..6657e72
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/tlsgdesc.s
@@ -0,0 +1,106 @@
+ .text
+ .globl fc1
+ .type fc1,@function
+fc1:
+ pushq %rbp
+ movq %rsp, %rbp
+ nop;nop;nop;nop
+
+ /* IE against global var. */
+ movq %fs:0, %rcx
+ nop;nop
+ addq sG3@gottpoff(%rip), %rcx
+ nop;nop;nop;nop
+
+ /* IE against global var. */
+ movq %fs:0, %rcx
+ nop;nop
+ addq sG4@gottpoff(%rip), %rcx
+ nop;nop;nop;nop
+
+ /* GD, gd first. */
+ .byte 0x66
+ leaq sG1@tlsgd(%rip), %rdi
+ .word 0x6666
+ rex64
+ call __tls_get_addr@plt
+ nop;nop;nop;nop
+
+ leaq sG1@tlsdesc(%rip), %rax
+ call *sG1@tlscall(%rax)
+ nop;nop;nop;nop
+
+ /* GD, desc first. */
+ leaq sG2@tlsdesc(%rip), %rax
+ call *sG2@tlscall(%rax)
+ nop;nop;nop;nop
+
+ .byte 0x66
+ leaq sG2@tlsgd(%rip), %rdi
+ .word 0x6666
+ rex64
+ call __tls_get_addr@plt
+ nop;nop;nop;nop
+
+ /* GD -> IE, gd first, after IE use. */
+ .byte 0x66
+ leaq sG3@tlsgd(%rip), %rdi
+ .word 0x6666
+ rex64
+ call __tls_get_addr@plt
+ nop;nop;nop;nop
+
+ leaq sG3@tlsdesc(%rip), %rax
+ call *sG3@tlscall(%rax)
+ nop;nop;nop;nop
+
+ /* GD -> IE, desc first, after IE use. */
+ leaq sG4@tlsdesc(%rip), %rax
+ call *sG4@tlscall(%rax)
+ nop;nop;nop;nop
+
+ .byte 0x66
+ leaq sG4@tlsgd(%rip), %rdi
+ .word 0x6666
+ rex64
+ call __tls_get_addr@plt
+ nop;nop;nop;nop
+
+ /* GD -> IE, gd first, before IE use. */
+ .byte 0x66
+ leaq sG5@tlsgd(%rip), %rdi
+ .word 0x6666
+ rex64
+ call __tls_get_addr@plt
+ nop;nop;nop;nop
+
+ leaq sG5@tlsdesc(%rip), %rax
+ call *sG5@tlscall(%rax)
+ nop;nop;nop;nop
+
+ /* GD -> IE, desc first, before IE use. */
+ leaq sG6@tlsdesc(%rip), %rax
+ call *sG6@tlscall(%rax)
+ nop;nop;nop;nop
+
+ .byte 0x66
+ leaq sG6@tlsgd(%rip), %rdi
+ .word 0x6666
+ rex64
+ call __tls_get_addr@plt
+ nop;nop;nop;nop
+
+ /* IE against global var. */
+ movq %fs:0, %rcx
+ nop;nop
+ addq sG5@gottpoff(%rip), %rcx
+ nop;nop;nop;nop
+
+ /* IE against global var. */
+ movq %fs:0, %rcx
+ nop;nop
+ addq sG6@gottpoff(%rip), %rcx
+ nop;nop;nop;nop
+
+ leave
+ ret
diff --git a/ld/testsuite/ld-x86-64/x86-64.exp b/ld/testsuite/ld-x86-64/x86-64.exp
index 409a65d..5285f3e 100644
--- a/ld/testsuite/ld-x86-64/x86-64.exp
+++ b/ld/testsuite/ld-x86-64/x86-64.exp
@@ -1,5 +1,5 @@
# Expect script for ld-x86_64 tests
-# Copyright (C) 2002 Free Software Foundation
+# Copyright (C) 2002, 2005, 2006 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
@@ -39,6 +39,11 @@ set x86_64tests {
{{readelf -WSsrl tlspic.rd} {objdump -drj.text tlspic.dd}
{objdump -sj.got tlspic.sd} {objdump -sj.tdata tlspic.td}}
"libtlspic.so"}
+ {"TLS descriptor -fpic -shared transitions" "-shared -melf_x86_64"
+ "--64" {tlsdesc.s tlspic2.s}
+ {{readelf -WSsrld tlsdesc.rd} {objdump -drj.text tlsdesc.dd}
+ {objdump "-s -j.got -j.got.plt" tlsdesc.sd} {objdump -sj.tdata tlsdesc.td}
+ {objdump -drj.plt tlsdesc.pd}} "libtlsdesc.so"}
{"Helper shared library" "-shared -melf_x86_64"
"--64" {tlslib.s} {} "libtlslib.so"}
{"TLS -fpic and -fno-pic exec transitions"
@@ -46,6 +51,15 @@ set x86_64tests {
{{readelf -WSsrl tlsbin.rd} {objdump -drj.text tlsbin.dd}
{objdump -sj.got tlsbin.sd} {objdump -sj.tdata tlsbin.td}}
"tlsbin"}
+ {"TLS descriptor -fpic and -fno-pic exec transitions"
+ "-melf_x86_64 tmpdir/libtlslib.so" "--64" {tlsbindesc.s tlsbin.s}
+ {{readelf -WSsrl tlsbindesc.rd} {objdump -drj.text tlsbindesc.dd}
+ {objdump -sj.got tlsbindesc.sd} {objdump -sj.tdata tlsbindesc.td}}
+ "tlsbindesc"}
+ {"TLS with global dynamic and descriptors"
+ "-shared -melf_x86_64" "--64" {tlsgdesc.s}
+ {{readelf -WSsrl tlsgdesc.rd} {objdump -drj.text tlsgdesc.dd}}
+ "libtlsgdesc.so"}
{"TLS in debug sections" "-melf_x86_64"
"--64" {tlsg.s}
{{objdump -sj.debug_foobar tlsg.sd}} "tlsg"}