This is the mail archive of the libc-alpha@sourceware.org mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] Support i386 TLS code sequences without PLT


On Mon, Jun 6, 2016 at 11:04 AM, H.J. Lu <hjl.tools@gmail.com> wrote:
> On Mon, Jun 6, 2016 at 8:01 AM, Carlos O'Donell <carlos@redhat.com> wrote:
>> On 06/03/2016 05:21 PM, H.J. Lu wrote:
>>> We can generate x86-64 TLS code sequences for general and local dynamic
>>> models without PLT, which uses indirect call via GOT:
>>>
>>> call *__tls_get_addr@GOTPCREL(%rip)
>>>
>>> instead of direct call:
>>>
>>> call __tls_get_addr[@PLT]
>>
>> What are the actual pros and cons of this change?
>
> Pros:  improved security and performance since GOT can be
> RELRO and one direct branch is removed.
> Cons: Code size is bigger when there are more than 16 calls
> to __tls_get_addr since direct branch is 4 byte and indirect
> branch is 5 byte. Also there is no lazy binding.
>
>> Does this improve security? Performance?
>>
>> The __tls_get_addr symbol, on x86_64, lives in ld.so, which generally
>> means that all shared objects (GD usage) indirect through their PLT/GOT
>> to make the call. In this model, and because of lazy linking, the
>> PLT-related GOT entries are left read-write to be updated after resolution
>> (ignore the BIND_NOW + RELRO case since in that case we do all of this
>> up front).
>>
>> After your change, without a PLT entry, these symbols can no longer be
>> interposed? The static linker would generate a binding (a got reloc for
>
> It can still be interposed.  Just lazy binding is disabled.
>
>> the symbol which is resolved by the dynamic loader) that cannot be changed,
>> becomes RO after RELRO?
>>
>> Is the security benefit worth the loss of interposition for this symbol?
>
> There is no loss of interposition.
>
>> Is there any performance gains?
>
> One direct branch to PLT entry is removed.
>
> This is what I am checking in.

Here is a similar patch for i386.  Similar pros and cons.  For
i386, since EBX is no longer required to call ___tls_get_addr,
other registers can be used. It will further improve performance
on i386.  I will check it in this week.

-- 
H.J.
From bf5feaddba6b8372f4c2a2b311b4df248d6e59ce Mon Sep 17 00:00:00 2001
From: "H.J. Lu" <hjl.tools@gmail.com>
Date: Sun, 5 Jun 2016 07:18:06 -0700
Subject: [PATCH] Support i386 TLS code sequences without PLT

We can generate i386 TLS code sequences for general and local dynamic
models without PLT, which uses indirect call via GOT:

call *___tls_get_addr@GOT(%reg)

where EBX register isn't required as GOT base, instead of direct call:

call ___tls_get_addr[@PLT]

which requires EBX register as GOT base.

Since direct call is 4-byte long and indirect call, is 5-byte long, the
extra one byte must be handled properly.

For general dynamic model, 7-byte lea instruction before call instruction
is replaced by 6-byte one to make room for indirect call.  For local
dynamic model, we simply use 5-byte indirect call.

TLS linker optimization is updated to recognize new instruction patterns.
For local dynamic model to local exec model transition, we generate
a 6-byte lea instruction as nop, instead of a 1-byte nop plus a 4-byte
lea instruction.  Since linker may convert

call ___tls_get_addr[@PLT]

to

addr32 call ____tls_get_addr

when producing static executable, both patterns are recognized.

bfd/

	* elf64-i386.c (elf_i386_link_hash_entry): Add tls_get_addr.
	(elf_i386_link_hash_newfunc): Initialize tls_get_addr to 2.
	(elf_i386_check_tls_transition): Check indirect call and direct
	call with the addr32 prefix for general and local dynamic models.
	Set the tls_get_addr feild.
	(elf_i386_convert_load_reloc): Always use addr32 prefix for
	indirect ___tls_get_addr call via GOT.
	(elf_i386_relocate_section): Handle GD->LE, GD->IE and LD->LE
	transitions with indirect call and direct call with the addr32
	prefix.

ld/

	* testsuite/ld-i386/i386.exp: Run libtlspic2.so, tlsbin2,
	tlsgd3, tlsld2, tlsgd4, tlspie3a, tlspie3b and tlspie3c.
	* testsuite/ld-i386/pass.out: New file.
	* testsuite/ld-i386/tls-def1.c: Likewise.
	* testsuite/ld-i386/tls-gd1.S: Likewise.
	* testsuite/ld-i386/tls-ld1.S: Likewise.
	* testsuite/ld-i386/tls-main1.c: Likewise.
	* testsuite/ld-i386/tls.exp: Likewise.
	* testsuite/ld-i386/tlsbin2-nacl.rd: Likewise.
	* testsuite/ld-i386/tlsbin2.dd: Likewise.
	* testsuite/ld-i386/tlsbin2.rd: Likewise.
	* testsuite/ld-i386/tlsbin2.sd: Likewise.
	* testsuite/ld-i386/tlsbin2.td: Likewise.
	* testsuite/ld-i386/tlsbinpic2.s: Likewise.
	* testsuite/ld-i386/tlsgd3.dd: Likewise.
	* testsuite/ld-i386/tlsgd3.s: Likewise.
	* testsuite/ld-i386/tlsgd4.d: Likewise.
	* testsuite/ld-i386/tlsgd4.s: Likewise.
	* testsuite/ld-i386/tlsld2.s: Likewise.
	* testsuite/ld-i386/tlspic2-nacl.rd: Likewise.
	* testsuite/ld-i386/tlspic2.dd: Likewise.
	* testsuite/ld-i386/tlspic2.rd: Likewise.
	* testsuite/ld-i386/tlspic2.sd: Likewise.
	* testsuite/ld-i386/tlspic2.td: Likewise.
	* testsuite/ld-i386/tlspic3.s: Likewise.
	* testsuite/ld-i386/tlspie3.s: Likewise.
	* testsuite/ld-i386/tlspie3a.d: Likewise.
	* testsuite/ld-i386/tlspie3b.d: Likewise.
	* testsuite/ld-i386/tlspie3c.d: Likewise.
---
 bfd/elf32-i386.c                     | 249 ++++++++++++++-----
 ld/testsuite/ld-i386/i386.exp        |  26 ++
 ld/testsuite/ld-i386/pass.out        |   1 +
 ld/testsuite/ld-i386/tls-def1.c      |   1 +
 ld/testsuite/ld-i386/tls-gd1.S       |  65 +++++
 ld/testsuite/ld-i386/tls-ld1.S       |  71 ++++++
 ld/testsuite/ld-i386/tls-main1.c     |  29 +++
 ld/testsuite/ld-i386/tls.exp         | 125 ++++++++++
 ld/testsuite/ld-i386/tlsbin2-nacl.rd | 156 ++++++++++++
 ld/testsuite/ld-i386/tlsbin2.dd      | 460 +++++++++++++++++++++++++++++++++++
 ld/testsuite/ld-i386/tlsbin2.rd      | 154 ++++++++++++
 ld/testsuite/ld-i386/tlsbin2.sd      |  13 +
 ld/testsuite/ld-i386/tlsbin2.td      |  16 ++
 ld/testsuite/ld-i386/tlsbinpic2.s    | 172 +++++++++++++
 ld/testsuite/ld-i386/tlsgd3.dd       |  16 ++
 ld/testsuite/ld-i386/tlsgd3.s        |  15 ++
 ld/testsuite/ld-i386/tlsgd4.d        |   4 +
 ld/testsuite/ld-i386/tlsgd4.s        |  11 +
 ld/testsuite/ld-i386/tlsld2.dd       |  14 ++
 ld/testsuite/ld-i386/tlsld2.s        |  12 +
 ld/testsuite/ld-i386/tlspic2-nacl.rd | 149 ++++++++++++
 ld/testsuite/ld-i386/tlspic2.dd      | 405 ++++++++++++++++++++++++++++++
 ld/testsuite/ld-i386/tlspic2.rd      | 147 +++++++++++
 ld/testsuite/ld-i386/tlspic2.sd      |  18 ++
 ld/testsuite/ld-i386/tlspic2.td      |  16 ++
 ld/testsuite/ld-i386/tlspic3.s       | 282 +++++++++++++++++++++
 ld/testsuite/ld-i386/tlspie3.s       |  64 +++++
 ld/testsuite/ld-i386/tlspie3a.d      |   6 +
 ld/testsuite/ld-i386/tlspie3b.d      |  37 +++
 ld/testsuite/ld-i386/tlspie3c.d      |  37 +++
 30 files changed, 2706 insertions(+), 65 deletions(-)
 create mode 100644 ld/testsuite/ld-i386/pass.out
 create mode 100644 ld/testsuite/ld-i386/tls-def1.c
 create mode 100644 ld/testsuite/ld-i386/tls-gd1.S
 create mode 100644 ld/testsuite/ld-i386/tls-ld1.S
 create mode 100644 ld/testsuite/ld-i386/tls-main1.c
 create mode 100644 ld/testsuite/ld-i386/tls.exp
 create mode 100644 ld/testsuite/ld-i386/tlsbin2-nacl.rd
 create mode 100644 ld/testsuite/ld-i386/tlsbin2.dd
 create mode 100644 ld/testsuite/ld-i386/tlsbin2.rd
 create mode 100644 ld/testsuite/ld-i386/tlsbin2.sd
 create mode 100644 ld/testsuite/ld-i386/tlsbin2.td
 create mode 100644 ld/testsuite/ld-i386/tlsbinpic2.s
 create mode 100644 ld/testsuite/ld-i386/tlsgd3.dd
 create mode 100644 ld/testsuite/ld-i386/tlsgd3.s
 create mode 100644 ld/testsuite/ld-i386/tlsgd4.d
 create mode 100644 ld/testsuite/ld-i386/tlsgd4.s
 create mode 100644 ld/testsuite/ld-i386/tlsld2.dd
 create mode 100644 ld/testsuite/ld-i386/tlsld2.s
 create mode 100644 ld/testsuite/ld-i386/tlspic2-nacl.rd
 create mode 100644 ld/testsuite/ld-i386/tlspic2.dd
 create mode 100644 ld/testsuite/ld-i386/tlspic2.rd
 create mode 100644 ld/testsuite/ld-i386/tlspic2.sd
 create mode 100644 ld/testsuite/ld-i386/tlspic2.td
 create mode 100644 ld/testsuite/ld-i386/tlspic3.s
 create mode 100644 ld/testsuite/ld-i386/tlspie3.s
 create mode 100644 ld/testsuite/ld-i386/tlspie3a.d
 create mode 100644 ld/testsuite/ld-i386/tlspie3b.d
 create mode 100644 ld/testsuite/ld-i386/tlspie3c.d

diff --git a/bfd/elf32-i386.c b/bfd/elf32-i386.c
index d46ece7..38c0520 100644
--- a/bfd/elf32-i386.c
+++ b/bfd/elf32-i386.c
@@ -787,6 +787,11 @@ struct elf_i386_link_hash_entry
   /* Symbol has non-GOT/non-PLT relocations in text sections.  */
   unsigned int has_non_got_reloc : 1;
 
+  /* 0: symbol isn't ___tls_get_addr.
+     1: symbol is ___tls_get_addr.
+     2: symbol is unknown.  */
+  unsigned int tls_get_addr : 2;
+
   /* Reference count of C/C++ function pointer relocations in read-write
      section which can be resolved at run-time.  */
   bfd_signed_vma func_pointer_refcount;
@@ -922,6 +927,7 @@ elf_i386_link_hash_newfunc (struct bfd_hash_entry *entry,
       eh->gotoff_ref = 0;
       eh->has_got_reloc = 0;
       eh->has_non_got_reloc = 0;
+      eh->tls_get_addr = 2;
       eh->func_pointer_refcount = 0;
       eh->plt_got.offset = (bfd_vma) -1;
       eh->tlsdesc_got = (bfd_vma) -1;
@@ -1216,10 +1222,12 @@ elf_i386_check_tls_transition (asection *sec,
 			       const Elf_Internal_Rela *rel,
 			       const Elf_Internal_Rela *relend)
 {
-  unsigned int val, type;
+  unsigned int val, type, reg;
   unsigned long r_symndx;
   struct elf_link_hash_entry *h;
   bfd_vma offset;
+  bfd_byte *call;
+  bfd_boolean indirect_call, tls_get_addr;
 
   offset = rel->r_offset;
   switch (r_type)
@@ -1229,69 +1237,130 @@ elf_i386_check_tls_transition (asection *sec,
       if (offset < 2 || (rel + 1) >= relend)
 	return FALSE;
 
-      type = bfd_get_8 (abfd, contents + offset - 2);
+      indirect_call = FALSE;
+      call = contents + offset + 4;
+      val = *(call - 5);
+      type = *(call - 6);
       if (r_type == R_386_TLS_GD)
 	{
 	  /* Check transition from GD access model.  Only
-		leal foo@tlsgd(,%reg,1), %eax; call ___tls_get_addr
-		leal foo@tlsgd(%reg), %eax; call ___tls_get_addr; nop
+		leal foo@tlsgd(,%ebx,1), %eax
+		call ___tls_get_addr@PLT
+	     or
+		leal foo@tlsgd(%ebx) %eax
+		call ___tls_get_addr@PLT
+		nop
+	     or
+		leal foo@tlsgd(%reg), %eax
+		call *___tls_get_addr@GOT(%reg)
+		which may be converted to
+		addr32 call ___tls_get_addr
 	     can transit to different access model.  */
-	  if ((offset + 10) > sec->size ||
-	      (type != 0x8d && type != 0x04))
+	  if ((offset + 10) > sec->size
+	      || (type != 0x8d && type != 0x04))
 	    return FALSE;
 
-	  val = bfd_get_8 (abfd, contents + offset - 1);
 	  if (type == 0x04)
 	    {
-	      /* leal foo@tlsgd(,%reg,1), %eax; call ___tls_get_addr */
+	      /* leal foo@tlsgd(,%ebx,1), %eax
+		 call ___tls_get_addr@PLT  */
 	      if (offset < 3)
 		return FALSE;
 
-	      if (bfd_get_8 (abfd, contents + offset - 3) != 0x8d)
-		return FALSE;
-
-	      if ((val & 0xc7) != 0x05 || val == (4 << 3))
+	      if (*(call - 7) != 0x8d
+		  || val != 0x1d
+		  || call[0] != 0xe8)
 		return FALSE;
 	    }
 	  else
 	    {
-	      /* leal foo@tlsgd(%reg), %eax; call ___tls_get_addr; nop  */
-	      if ((val & 0xf8) != 0x80 || (val & 7) == 4)
+	      /* This must be
+			leal foo@tlsgd(%ebx), %eax
+			call ___tls_get_addr@PLT
+			nop
+		 or
+			leal foo@tlsgd(%reg), %eax
+			call *___tls_get_addr@GOT(%reg)
+			which may be converted to
+			addr32 call ___tls_get_addr
+
+		 %eax can't be used as the GOT base register since it
+		 is used to pass parameter to ___tls_get_addr.  */
+	      reg = val & 7;
+	      if ((val & 0xf8) != 0x80 || reg == 4 || reg == 0)
 		return FALSE;
 
-	      if (bfd_get_8 (abfd, contents + offset + 9) != 0x90)
+	      indirect_call = call[0] == 0xff;
+	      if (!(reg == 3 && call[0] == 0xe8 && call[5] == 0x90)
+		  && !(call[0] == 0x67 && call[1] == 0xe8)
+		  && !(indirect_call
+		       && (call[1] & 0xf8) == 0x90
+		       && (call[1] & 0x7) == reg))
 		return FALSE;
 	    }
 	}
       else
 	{
 	  /* Check transition from LD access model.  Only
-		leal foo@tlsgd(%reg), %eax; call ___tls_get_addr
+		leal foo@tlsldm(%ebx), %eax
+		call ___tls_get_addr@PLT
+	     or
+		leal foo@tlsldm(%reg), %eax
+		call *___tls_get_addr@GOT(%reg)
+		which may be converted to
+		addr32 call ___tls_get_addr
 	     can transit to different access model.  */
 	  if (type != 0x8d || (offset + 9) > sec->size)
 	    return FALSE;
 
-	  val = bfd_get_8 (abfd, contents + offset - 1);
-	  if ((val & 0xf8) != 0x80 || (val & 7) == 4)
+	  /* %eax can't be used as the GOT base register since it is
+	     used to pass parameter to ___tls_get_addr.  */
+	  reg = val & 7;
+	  if ((val & 0xf8) != 0x80 || reg == 4 || reg == 0)
 	    return FALSE;
-	}
 
-      if (bfd_get_8 (abfd, contents + offset + 4) != 0xe8)
-	return FALSE;
+	  indirect_call = call[0] == 0xff;
+	  if (!(reg == 3 && call[0] == 0xe8)
+	      && !(call[0] == 0x67 && call[1] == 0xe8)
+	      && !(indirect_call
+		   && (call[1] & 0xf8) == 0x90
+		   && (call[1] & 0x7) == reg))
+	    return FALSE;
+	}
 
       r_symndx = ELF32_R_SYM (rel[1].r_info);
       if (r_symndx < symtab_hdr->sh_info)
 	return FALSE;
 
+      tls_get_addr = FALSE;
       h = sym_hashes[r_symndx - symtab_hdr->sh_info];
-      /* Use strncmp to check ___tls_get_addr since ___tls_get_addr
-	 may be versioned.  */
-      return (h != NULL
-	      && h->root.root.string != NULL
-	      && (ELF32_R_TYPE (rel[1].r_info) == R_386_PC32
-		  || ELF32_R_TYPE (rel[1].r_info) == R_386_PLT32)
-	      && (strncmp (h->root.root.string, "___tls_get_addr",
-			   15) == 0));
+      if (h != NULL && h->root.root.string != NULL)
+	{
+	  struct elf_i386_link_hash_entry *eh
+	    = (struct elf_i386_link_hash_entry *) h;
+	  tls_get_addr = eh->tls_get_addr == 1;
+	  if (eh->tls_get_addr > 1)
+	    {
+	      /* Use strncmp to check ___tls_get_addr since
+		 ___tls_get_addr may be versioned.  */
+	      if (strncmp (h->root.root.string, "___tls_get_addr", 15)
+		  == 0)
+		{
+		  eh->tls_get_addr = 1;
+		  tls_get_addr = TRUE;
+		}
+	      else
+		eh->tls_get_addr = 0;
+	    }
+	}
+
+      if (!tls_get_addr)
+	return FALSE;
+      else if (indirect_call)
+	return (ELF32_R_TYPE (rel[1].r_info) == R_386_GOT32X);
+      else
+	return (ELF32_R_TYPE (rel[1].r_info) == R_386_PC32
+		|| ELF32_R_TYPE (rel[1].r_info) == R_386_PLT32);
 
     case R_386_TLS_IE:
       /* Check transition from IE access model:
@@ -1353,13 +1422,13 @@ elf_i386_check_tls_transition (asection *sec,
 
     case R_386_TLS_DESC_CALL:
       /* Check transition from GDesc access model:
-		call *x@tlsdesc(%rax)
+		call *x@tlsdesc(%eax)
        */
       if (offset + 2 <= sec->size)
 	{
-	  /* Make sure that it's a call *x@tlsdesc(%rax).  */
-	  static const unsigned char call[] = { 0xff, 0x10 };
-	  return memcmp (contents + offset, call, 2) == 0;
+	  /* Make sure that it's a call *x@tlsdesc(%eax).  */
+	  call = contents + offset;
+	  return call[0] == 0xff && call[1] == 0x10;
 	}
 
       return FALSE;
@@ -1632,17 +1701,30 @@ convert_branch:
 	  /* Convert R_386_GOT32X to R_386_PC32.  */
 	  if (modrm == 0x15 || (modrm & 0xf8) == 0x90)
 	    {
+	      struct elf_i386_link_hash_entry *eh
+		= (struct elf_i386_link_hash_entry *) h;
+
 	      /* Convert to "nop call foo".  ADDR_PREFIX_OPCODE
 		 is a nop prefix.  */
 	      modrm = 0xe8;
-	      nop = link_info->call_nop_byte;
-	      if (link_info->call_nop_as_suffix)
+	      /* To support TLS optimization, always use addr32 prefix
+		 for "call *___tls_get_addr@GOT(%reg)".  */
+	      if (eh && eh->tls_get_addr == 1)
 		{
-		  nop_offset = roff + 3;
-		  irel->r_offset -= 1;
+		  nop = 0x67;
+		  nop_offset = irel->r_offset - 2;
 		}
 	      else
-		nop_offset = roff - 2;
+		{
+		  nop = link_info->call_nop_byte;
+		  if (link_info->call_nop_as_suffix)
+		    {
+		      nop_offset = roff + 3;
+		      irel->r_offset -= 1;
+		    }
+		  else
+		    nop_offset = roff - 2;
+		}
 	    }
 	  else
 	    {
@@ -4372,30 +4454,39 @@ r_386_got32:
 		  bfd_vma roff;
 
 		  /* GD->LE transition.  */
-		  type = bfd_get_8 (input_bfd, contents + rel->r_offset - 2);
+		  type = *(contents + rel->r_offset - 2);
 		  if (type == 0x04)
 		    {
-		      /* leal foo(,%reg,1), %eax; call ___tls_get_addr
-			 Change it into:
-			 movl %gs:0, %eax; subl $foo@tpoff, %eax
+		      /* Change
+				leal foo@tlsgd(,%ebx,1), %eax
+				call ___tls_get_addr@PLT
+			 into:
+				movl %gs:0, %eax
+				subl $foo@tpoff, %eax
 			 (6 byte form of subl).  */
-		      memcpy (contents + rel->r_offset - 3,
-			      "\x65\xa1\0\0\0\0\x81\xe8\0\0\0", 12);
 		      roff = rel->r_offset + 5;
 		    }
 		  else
 		    {
-		      /* leal foo(%reg), %eax; call ___tls_get_addr; nop
-			 Change it into:
-			 movl %gs:0, %eax; subl $foo@tpoff, %eax
+		      /* Change
+				leal foo@tlsgd(%ebx), %eax
+				call ___tls_get_addr@PLT
+				nop
+			 or
+				leal foo@tlsgd(%reg), %eax
+				call *___tls_get_addr@GOT(%reg)
+				which may be converted to
+				addr32 call ___tls_get_addr
+			 into:
+				movl %gs:0, %eax; subl $foo@tpoff, %eax
 			 (6 byte form of subl).  */
-		      memcpy (contents + rel->r_offset - 2,
-			      "\x65\xa1\0\0\0\0\x81\xe8\0\0\0", 12);
 		      roff = rel->r_offset + 6;
 		    }
+		  memcpy (contents + roff - 8,
+			  "\x65\xa1\0\0\0\0\x81\xe8\0\0\0", 12);
 		  bfd_put_32 (output_bfd, elf_i386_tpoff (info, relocation),
 			      contents + roff);
-		  /* Skip R_386_PC32/R_386_PLT32.  */
+		  /* Skip R_386_PC32, R_386_PLT32 and R_386_GOT32X.  */
 		  rel++;
 		  wrel++;
 		  continue;
@@ -4702,21 +4793,33 @@ r_386_got32:
 	      bfd_vma roff;
 
 	      /* GD->IE transition.  */
-	      type = bfd_get_8 (input_bfd, contents + rel->r_offset - 2);
-	      val = bfd_get_8 (input_bfd, contents + rel->r_offset - 1);
+	      type = *(contents + rel->r_offset - 2);
+	      val = *(contents + rel->r_offset - 1);
 	      if (type == 0x04)
 		{
-		  /* leal foo(,%reg,1), %eax; call ___tls_get_addr
-		     Change it into:
-		     movl %gs:0, %eax; subl $foo@gottpoff(%reg), %eax.  */
+		  /* Change
+			leal foo@tlsgd(,%ebx,1), %eax
+			call ___tls_get_addr@PLT
+		     into:
+			movl %gs:0, %eax
+			subl $foo@gottpoff(%ebx), %eax.  */
 		  val >>= 3;
 		  roff = rel->r_offset - 3;
 		}
 	      else
 		{
-		  /* leal foo(%reg), %eax; call ___tls_get_addr; nop
-		     Change it into:
-		     movl %gs:0, %eax; subl $foo@gottpoff(%reg), %eax.  */
+		  /* Change
+			leal foo@tlsgd(%ebx), %eax
+			call ___tls_get_addr@PLT
+			nop
+		     or
+			leal foo@tlsgd(%reg), %eax
+			call *___tls_get_addr@GOT(%reg)
+			which may be converted to
+			addr32 call ___tls_get_addr
+		     into:
+			movl %gs:0, %eax;
+			subl $foo@gottpoff(%reg), %eax.  */
 		  roff = rel->r_offset - 2;
 		}
 	      memcpy (contents + roff,
@@ -4735,7 +4838,7 @@ r_386_got32:
 			  - htab->elf.sgotplt->output_section->vma
 			  - htab->elf.sgotplt->output_offset,
 			  contents + roff + 8);
-	      /* Skip R_386_PLT32.  */
+	      /* Skip R_386_PLT32 and R_386_GOT32X.  */
 	      rel++;
 	      wrel++;
 	      continue;
@@ -4826,13 +4929,29 @@ r_386_got32:
 
 	  if (r_type != R_386_TLS_LDM)
 	    {
-	      /* LD->LE transition:
-		 leal foo(%reg), %eax; call ___tls_get_addr.
-		 We change it into:
-		 movl %gs:0, %eax; nop; leal 0(%esi,1), %esi.  */
+	      /* LD->LE transition.  Change
+			leal foo@tlsldm(%ebx) %eax
+			call ___tls_get_addr@PLT
+		 into:
+			movl %gs:0, %eax
+			nop
+			leal 0(%esi,1), %esi
+		 or change
+			leal foo@tlsldm(%reg) %eax
+			call *___tls_get_addr@GOT(%reg)
+			which may be converted to
+			addr32 call ___tls_get_addr
+		 into:
+			movl %gs:0, %eax
+			leal 0(%esi), %esi  */
 	      BFD_ASSERT (r_type == R_386_TLS_LE_32);
-	      memcpy (contents + rel->r_offset - 2,
-		      "\x65\xa1\0\0\0\0\x90\x8d\x74\x26", 11);
+	      if (*(contents + rel->r_offset + 4) == 0xff
+		  || *(contents + rel->r_offset + 4) == 0x67)
+		memcpy (contents + rel->r_offset - 2,
+			"\x65\xa1\0\0\0\0\x8d\xb6\0\0\0", 12);
+	      else
+		memcpy (contents + rel->r_offset - 2,
+			"\x65\xa1\0\0\0\0\x90\x8d\x74\x26", 11);
 	      /* Skip R_386_PC32/R_386_PLT32.  */
 	      rel++;
 	      wrel++;
diff --git a/ld/testsuite/ld-i386/i386.exp b/ld/testsuite/ld-i386/i386.exp
index d30f9fb..f6cbe43 100644
--- a/ld/testsuite/ld-i386/i386.exp
+++ b/ld/testsuite/ld-i386/i386.exp
@@ -133,6 +133,13 @@ set i386tests {
      {{readelf -Ssrl tlspic.rd} {objdump -drj.text tlspic.dd}
       {objdump -sj.got tlspic.sd} {objdump -sj.tdata tlspic.td}}
       "libtlspic.so"}
+    {"TLS -fpic -shared transitions without PLT"
+     "-shared -melf_i386 --no-ld-generated-unwind-info" ""
+     "-mrelax-relocations=yes --32"
+     {tlspic3.s tlspic2.s}
+     {{readelf -Ssrl tlspic2.rd} {objdump -drj.text tlspic2.dd}
+      {objdump -sj.got tlspic2.sd} {objdump -sj.tdata tlspic2.td}}
+      "libtlspic2.so"}
     {"TLS descriptor -fpic -shared transitions"
      "-shared -melf_i386 --no-ld-generated-unwind-info" ""
      "--32" {tlsdesc.s tlspic2.s}
@@ -147,6 +154,13 @@ set i386tests {
      {{readelf -Ssrl tlsbin.rd} {objdump -drj.text tlsbin.dd}
       {objdump -sj.got tlsbin.sd} {objdump -sj.tdata tlsbin.td}}
       "tlsbin"}
+    {"TLS -fpic and -fno-pic exec transitions without PLT"
+     "-melf_i386 tmpdir/libtlslib.so --no-ld-generated-unwind-info" ""
+     "-mrelax-relocations=yes --32"
+     {tlsbinpic2.s tlsbin.s}
+     {{readelf -Ssrl tlsbin2.rd} {objdump -drj.text tlsbin2.dd}
+      {objdump -sj.got tlsbin2.sd} {objdump -sj.tdata tlsbin2.td}}
+      "tlsbin2"}
     {"TLS descriptor -fpic and -fno-pic exec transitions"
      "-melf_i386 tmpdir/libtlslib.so --no-ld-generated-unwind-info" ""
      "--32" {tlsbindesc.s tlsbin.s}
@@ -177,9 +191,17 @@ set i386tests {
     {"TLS GD->LE transition" "-melf_i386" ""
      "--32" {tlsgd1.s}
      {{objdump -dwr tlsgd1.dd}} "tlsgd1"}
+    {"TLS GD->LE transition without PLT" "-melf_i386" ""
+     "-mrelax-relocations=yes --32"
+     {tlsgd3.s}
+     {{objdump -dwr tlsgd3.dd}} "tlsgd3"}
     {"TLS LD->LE transition" "-melf_i386" ""
      "--32" {tlsld1.s}
      {{objdump -dwr tlsld1.dd}} "tlsld1"}
+    {"TLS LD->LE transition without PLT" "-melf_i386" ""
+     "-mrelax-relocations=yes --32"
+     {tlsld2.s}
+     {{objdump -dwr tlsld2.dd}} "tlsld2"}
     {"TLS IE->LE transition" "-melf_i386" ""
      "--32" {tlsie1.s}
      {{objdump -dwr tlsie1.dd}} "tlsie1"}
@@ -270,6 +292,7 @@ run_dump_test "pcrel16abs"
 run_dump_test "alloc"
 run_dump_test "warn1"
 run_dump_test "tlsgd2"
+run_dump_test "tlsgd4"
 run_dump_test "tlsie2"
 run_dump_test "tlsie3"
 run_dump_test "tlsie4"
@@ -286,6 +309,9 @@ run_dump_test "protected6a"
 run_dump_test "protected6b"
 run_dump_test "tlspie1"
 run_dump_test "tlspie2"
+run_dump_test "tlspie3a"
+run_dump_test "tlspie3b"
+run_dump_test "tlspie3c"
 run_dump_test "nogot1"
 run_dump_test "nogot2"
 run_dump_test "discarded1"
diff --git a/ld/testsuite/ld-i386/pass.out b/ld/testsuite/ld-i386/pass.out
new file mode 100644
index 0000000..7ef22e9
--- /dev/null
+++ b/ld/testsuite/ld-i386/pass.out
@@ -0,0 +1 @@
+PASS
diff --git a/ld/testsuite/ld-i386/tls-def1.c b/ld/testsuite/ld-i386/tls-def1.c
new file mode 100644
index 0000000..62470a9
--- /dev/null
+++ b/ld/testsuite/ld-i386/tls-def1.c
@@ -0,0 +1 @@
+__thread int gd = 1;
diff --git a/ld/testsuite/ld-i386/tls-gd1.S b/ld/testsuite/ld-i386/tls-gd1.S
new file mode 100644
index 0000000..3b16eab
--- /dev/null
+++ b/ld/testsuite/ld-i386/tls-gd1.S
@@ -0,0 +1,65 @@
+	.text
+	.p2align 4,,15
+	.globl	get_gd
+	.type	get_gd, @function
+get_gd:
+	pushl	%ebx
+	call	__x86.get_pc_thunk.bx
+	addl	$_GLOBAL_OFFSET_TABLE_, %ebx
+	subl	$8, %esp
+	leal	gd@tlsgd(,%ebx,1), %eax
+	call	___tls_get_addr@PLT
+	addl	$8, %esp
+	popl	%ebx
+	ret
+	.size	get_gd, .-get_gd
+	.p2align 4,,15
+	.globl	set_gd
+	.type	set_gd, @function
+set_gd:
+	pushl	%ebx
+	call	__x86.get_pc_thunk.bx
+	addl	$_GLOBAL_OFFSET_TABLE_, %ebx
+	subl	$8, %esp
+	leal	gd@tlsgd(%ebx), %eax
+	call	___tls_get_addr@PLT
+	nop
+	movl	16(%esp), %edx
+	movl	%edx, (%eax)
+	addl	$8, %esp
+	popl	%ebx
+	ret
+	.size	set_gd, .-set_gd
+	.text
+	.p2align 4,,15
+	.globl	test_gd
+	.type	test_gd, @function
+test_gd:
+	call	__x86.get_pc_thunk.cx
+	addl	$_GLOBAL_OFFSET_TABLE_, %ecx
+	subl	$12, %esp
+	leal	gd@tlsgd(%ecx), %eax
+	call	*___tls_get_addr@GOT(%ecx)
+	movl	16(%esp), %ecx
+	cmpl	%ecx, (%eax)
+	sete	%al
+	addl	$12, %esp
+	movzbl	%al, %eax
+	ret
+	.size	test_gd, .-test_gd
+	.section	.text.unlikely
+	.section	.text.__x86.get_pc_thunk.bx,"axG",@progbits,__x86.get_pc_thunk.bx,comdat
+	.globl	__x86.get_pc_thunk.bx
+	.hidden	__x86.get_pc_thunk.bx
+	.type	__x86.get_pc_thunk.bx, @function
+__x86.get_pc_thunk.bx:
+	movl	(%esp), %ebx
+	ret
+	.section	.text.__x86.get_pc_thunk.cx,"axG",@progbits,__x86.get_pc_thunk.cx,comdat
+	.globl	__x86.get_pc_thunk.cx
+	.hidden	__x86.get_pc_thunk.cx
+	.type	__x86.get_pc_thunk.cx, @function
+__x86.get_pc_thunk.cx:
+	movl	(%esp), %ecx
+	ret
+	.section	.note.GNU-stack,"",@progbits
diff --git a/ld/testsuite/ld-i386/tls-ld1.S b/ld/testsuite/ld-i386/tls-ld1.S
new file mode 100644
index 0000000..f1295cf
--- /dev/null
+++ b/ld/testsuite/ld-i386/tls-ld1.S
@@ -0,0 +1,71 @@
+	.text
+	.p2align 4,,15
+	.globl	get_ld
+	.type	get_ld, @function
+get_ld:
+	pushl	%ebx
+	call	__x86.get_pc_thunk.bx
+	addl	$_GLOBAL_OFFSET_TABLE_, %ebx
+	subl	$8, %esp
+	leal	ld@tlsldm(%ebx), %eax
+	call	___tls_get_addr@PLT
+	leal	ld@dtpoff(%eax), %eax
+	addl	$8, %esp
+	popl	%ebx
+	ret
+	.size	get_ld, .-get_ld
+	.p2align 4,,15
+	.globl	set_ld
+	.type	set_ld, @function
+set_ld:
+	pushl	%ebx
+	call	__x86.get_pc_thunk.bx
+	addl	$_GLOBAL_OFFSET_TABLE_, %ebx
+	subl	$8, %esp
+	leal	ld@tlsldm(%ebx), %eax
+	call	___tls_get_addr@PLT
+	movl	16(%esp), %edx
+	leal	ld@dtpoff(%eax), %eax
+	movl	%edx, (%eax)
+	addl	$8, %esp
+	popl	%ebx
+	ret
+	.size	set_ld, .-set_ld
+	.p2align 4,,15
+	.globl	test_ld
+	.type	test_ld, @function
+test_ld:
+	call	__x86.get_pc_thunk.cx
+	addl	$_GLOBAL_OFFSET_TABLE_, %ecx
+	subl	$12, %esp
+	leal	ld@tlsldm(%ecx), %eax
+	call	*___tls_get_addr@GOT(%ecx)
+	movl	16(%esp), %ecx
+	leal	ld@dtpoff(%eax), %eax
+	cmpl	%ecx, (%eax)
+	sete	%al
+	addl	$12, %esp
+	movzbl	%al, %eax
+	ret
+	.size	test_ld, .-test_ld
+	.section	.tbss,"awT",@nobits
+	.align 4
+	.type	ld, @object
+	.size	ld, 4
+ld:
+	.zero	4
+	.section	.text.__x86.get_pc_thunk.bx,"axG",@progbits,__x86.get_pc_thunk.bx,comdat
+	.globl	__x86.get_pc_thunk.bx
+	.hidden	__x86.get_pc_thunk.bx
+	.type	__x86.get_pc_thunk.bx, @function
+__x86.get_pc_thunk.bx:
+	movl	(%esp), %ebx
+	ret
+	.section	.text.__x86.get_pc_thunk.cx,"axG",@progbits,__x86.get_pc_thunk.cx,comdat
+	.globl	__x86.get_pc_thunk.cx
+	.hidden	__x86.get_pc_thunk.cx
+	.type	__x86.get_pc_thunk.cx, @function
+__x86.get_pc_thunk.cx:
+	movl	(%esp), %ecx
+	ret
+	.section	.note.GNU-stack,"",@progbits
diff --git a/ld/testsuite/ld-i386/tls-main1.c b/ld/testsuite/ld-i386/tls-main1.c
new file mode 100644
index 0000000..5c33744
--- /dev/null
+++ b/ld/testsuite/ld-i386/tls-main1.c
@@ -0,0 +1,29 @@
+#include <stdio.h>
+#include <stdlib.h>
+
+extern int * get_gd (void);
+extern void set_gd (int);
+extern int test_gd (int);
+extern int * get_ld (void);
+extern void set_ld (int);
+extern int test_ld (int);
+
+int
+main ()
+{
+  int *p;
+ 
+  p = get_gd ();
+  set_gd (3);
+  if (*p != 3 || !test_gd (3))
+    abort ();
+
+  p = get_ld ();
+  set_ld (4);
+  if (*p != 4 || !test_ld (4))
+    abort ();
+
+  printf ("PASS\n");
+
+  return 0;
+}
diff --git a/ld/testsuite/ld-i386/tls.exp b/ld/testsuite/ld-i386/tls.exp
new file mode 100644
index 0000000..40d4851
--- /dev/null
+++ b/ld/testsuite/ld-i386/tls.exp
@@ -0,0 +1,125 @@
+# Expect script for i386 TLS tests.
+#   Copyright (C) 2016 Free Software Foundation, Inc.
+#
+# This file is part of the GNU Binutils.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+# MA 02110-1301, USA.
+#
+
+# The following tests require running the executable generated by ld,
+# or enough of a build environment to create a fully linked executable.
+# This is not commonly available when testing a cross-built linker.
+if ![isnative] {
+    return
+}
+
+# Only on Linux for now.
+if ![istarget "i?86-*-linux*"] {
+    return
+}
+
+# Check to see if the C compiler works
+if { [which $CC] == 0 } {
+    return
+}
+
+run_cc_link_tests [list \
+    [list \
+	"Build tls-def1.c tls-main1.c" \
+	"" \
+	"-fPIE" \
+	{tls-def1.c tls-main1.c} \
+    ] \
+    [list \
+	"Build tls-gd1.o tls-ld1.o" \
+	"" \
+	"-fPIC -Wa,-mrelax-relocations=yes" \
+	{tls-gd1.S tls-ld1.S} \
+    ] \
+    [list \
+	"Build libtls-1a.so" \
+	"-shared tmpdir/tls-def1.o" \
+	"" \
+	{dummy.s} \
+	{} \
+	"libtls-1a.so" \
+    ] \
+    [list \
+	"Build libtls-1b.so" \
+	"-shared tmpdir/tls-gd1.o tmpdir/tls-ld1.o" \
+	"" \
+	{dummy.s} \
+	{} \
+	"libtls-1b.so" \
+    ] \
+]
+
+run_ld_link_exec_tests [] [list \
+    [list \
+	"TLS GD/LD -> LE transition without PLT (dynamic)" \
+	"tmpdir/tls-def1.o tmpdir/tls-main1.o tmpdir/tls-gd1.o \
+	 tmpdir/tls-ld1.o" \
+	"" \
+	{ dummy.s } \
+	"tls-1a" \
+	"pass.out" \
+    ] \
+    [list \
+	"TLS GD/LD -> LE transition without PLT (PIE)" \
+	"-pie tmpdir/tls-def1.o tmpdir/tls-main1.o tmpdir/tls-gd1.o \
+	 tmpdir/tls-ld1.o" \
+	"" \
+	{ dummy.s } \
+	"tls-1b" \
+	"pass.out" \
+    ] \
+    [list \
+	"TLS GD/LD -> LE transition without PLT (static)" \
+	"-static tmpdir/tls-def1.o tmpdir/tls-main1.o tmpdir/tls-gd1.o \
+	 tmpdir/tls-ld1.o" \
+	"" \
+	{ dummy.s } \
+	"tls-1c" \
+	"pass.out" \
+    ] \
+    [list \
+	"TLS GD/LD -> IE transition without PLT" \
+	"tmpdir/tls-main1.o tmpdir/tls-gd1.o tmpdir/tls-ld1.o \
+	 tmpdir/libtls-1a.so -R tmpdir" \
+	"" \
+	{ dummy.s } \
+	"tls-1d" \
+	"pass.out" \
+    ] \
+    [list \
+	"TLS without PLT (1)" \
+	"tmpdir/tls-main1.o \
+	 tmpdir/libtls-1a.so tmpdir/libtls-1b.so -R tmpdir" \
+	"" \
+	{ dummy.s } \
+	"tls-1e" \
+	"pass.out" \
+    ] \
+    [list \
+	"TLS without PLT (2)" \
+	"tmpdir/tls-main1.o tmpdir/tls-def1.o \
+	 tmpdir/libtls-1b.so -R tmpdir" \
+	"" \
+	{ dummy.s } \
+	"tls-1f" \
+	"pass.out" \
+    ] \
+]
diff --git a/ld/testsuite/ld-i386/tlsbin2-nacl.rd b/ld/testsuite/ld-i386/tlsbin2-nacl.rd
new file mode 100644
index 0000000..b23bfe0
--- /dev/null
+++ b/ld/testsuite/ld-i386/tlsbin2-nacl.rd
@@ -0,0 +1,156 @@
+#source: tlsbinpic2.s
+#source: tlsbin.s
+#as: --32
+#ld: -melf_i386_nacl tmpdir/libtlslib.so --no-ld-generated-unwind-info
+#readelf: -Ssrl
+#target: i?86-*-nacl*
+
+There are [0-9]+ section headers, starting at offset 0x[0-9a-f]+:
+
+Section Headers:
+ +\[Nr\] Name +Type +Addr +Off +Size +ES Flg Lk Inf Al
+ +\[[ 0-9]+\] +NULL +0+ 0+ 0+ 0+ +0 +0 +0
+ +\[[ 0-9]+\] \.text +PROGBITS +0+20000 .*
+ +\[[ 0-9]+\] \.interp +.*
+ +\[[ 0-9]+\] \.hash +.*
+ +\[[ 0-9]+\] \.dynsym +.*
+ +\[[ 0-9]+\] \.dynstr +.*
+ +\[[ 0-9]+\] \.rel.dyn +.*
+ +\[[ 0-9]+\] \.tdata +PROGBITS +0*10031000 [0-9a-f]+ 000060 00 WAT +0 +0 4096
+ +\[[ 0-9]+\] \.tbss +NOBITS +[0-9a-f]+ [0-9a-f]+ 000040 00 WAT +0 +0 +1
+ +\[[ 0-9]+\] \.dynamic +DYNAMIC +0*10031060 .*
+ +\[[ 0-9]+\] \.got +PROGBITS +0*100310e0 .*
+ +\[[ 0-9]+\] \.got\.plt +PROGBITS +0*10031108 .*
+ +\[[ 0-9]+\] \.shstrtab +.*
+ +\[[ 0-9]+\] \.symtab +.*
+ +\[[ 0-9]+\] \.strtab +.*
+Key to Flags:
+#...
+
+Elf file type is EXEC \(Executable file\)
+Entry point 0x0*20188
+There are [0-9]+ program headers, starting at offset [0-9]+
+
+Program Headers:
+ +Type +Offset +VirtAddr +PhysAddr +FileSiz +MemSiz +Flg Align
+ +PHDR.*
+ +INTERP.*
+.*Requesting program interpreter.*
+ +LOAD.*
+ +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 +.text *
+ +03 +.interp .hash .dynsym .dynstr .rel.dyn *
+ +04 +.tdata .dynamic .got .got.plt *
+ +05 +.dynamic *
+ +06 +.tdata .tbss *
+
+Relocation section '.rel.dyn' at offset 0x[0-9a-f]+ contains 10 entries:
+ Offset +Info +Type +Sym.Value +Sym. Name
+[0-9a-f ]+R_386_TLS_TPOFF +0+ +sG3
+[0-9a-f ]+R_386_TLS_TPOFF +0+ +sG5
+[0-9a-f ]+R_386_TLS_TPOFF +0+ +sG7
+[0-9a-f ]+R_386_TLS_TPOFF32 0+ +sG2
+[0-9a-f ]+R_386_TLS_TPOFF32 0+ +sG4
+[0-9a-f ]+R_386_TLS_TPOFF +0+ +sG4
+[0-9a-f ]+R_386_TLS_TPOFF32 0+ +sG6
+[0-9a-f ]+R_386_TLS_TPOFF32 0+ +sG1
+[0-9a-f ]+R_386_TLS_TPOFF +0+ +sG8
+[0-9a-f ]+R_386_GLOB_DAT +[0-9a-f]+ +___tls_get_addr
+
+Symbol table '\.dynsym' contains [0-9]+ 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 +11 __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 +11 _edata
+ +[0-9]+: [0-9a-f]+ +0 +NOTYPE +GLOBAL +DEFAULT +11 _end
+ +[0-9]+: 0+ +0 +TLS +GLOBAL +DEFAULT +UND sG8
+ +[0-9]+: [0-9a-f]+ +0 +FUNC +GLOBAL +DEFAULT +UND ___tls_get_addr
+
+Symbol table '\.symtab' contains [0-9]+ 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 *
+.* FILE +LOCAL +DEFAULT +ABS tmpdir/tlsbinpic2.o
+ +[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
+.* FILE +LOCAL +DEFAULT +ABS tmpdir/tlsbin.o
+ +[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
+.* FILE +LOCAL +DEFAULT +ABS 
+ +[0-9]+: 0*10031060 +0 +OBJECT +LOCAL +DEFAULT +9 _DYNAMIC
+ +[0-9]+: [0-9a-f]+ +0 +OBJECT +LOCAL +DEFAULT +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+20188 +0 +FUNC +GLOBAL +DEFAULT +1 _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 +11 __bss_start
+ +[0-9]+: 0+ +0 +TLS +GLOBAL +DEFAULT +UND sG6
+ +[0-9]+: 0+20000 +0 +FUNC +GLOBAL +DEFAULT +1 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 +11 _edata
+ +[0-9]+: [0-9a-f]+ +0 +NOTYPE +GLOBAL +DEFAULT +11 _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]+: [0-9a-f]+ +0 +FUNC +GLOBAL +DEFAULT +UND ___tls_get_addr
+ +[0-9]+: 0000006c +0 +TLS +GLOBAL +DEFAULT +8 bg4
diff --git a/ld/testsuite/ld-i386/tlsbin2.dd b/ld/testsuite/ld-i386/tlsbin2.dd
new file mode 100644
index 0000000..1879316
--- /dev/null
+++ b/ld/testsuite/ld-i386/tlsbin2.dd
@@ -0,0 +1,460 @@
+#source: tlsbinpic2.s
+#source: tlsbin.s
+#as: --32
+#ld: -melf_i386 tmpdir/libtlslib.so --no-ld-generated-unwind-info
+#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 ([0-9a-f]{2} ){4}[ 	]+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 *
+#  GD -> IE because variable is not defined in executable
+ +[0-9a-f]+:	65 a1 00 00 00 00[ 	]+mov    %gs:0x0,%eax
+ +[0-9a-f]+:	2b 83 f4 ff ff ff[ 	]+sub    -0xc\(%ebx\),%eax
+#				->R_386_TLS_TPOFF32	sG1
+ +[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]+:	65 a1 00 00 00 00[ 	]+mov    %gs:0x0,%eax
+ +[0-9a-f]+:	2b 81 e4 ff ff ff[ 	]+sub    -0x1c\(%ecx\),%eax
+#				->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 *
+#  GD -> IE because variable is not defined in executable where
+#  the variable is referenced through @gotntpoff too
+ +[0-9a-f]+:	65 a1 00 00 00 00[ 	]+mov    %gs:0x0,%eax
+ +[0-9a-f]+:	03 82 d8 ff ff ff[ 	]+add    -0x28\(%edx\),%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 *
+#  GD -> IE because variable is not defined in executable where
+#  the variable is referenced through @gottpoff and @gotntpoff too
+ +[0-9a-f]+:	65 a1 00 00 00 00[ 	]+mov    %gs:0x0,%eax
+ +[0-9a-f]+:	2b 87 e8 ff ff ff[ 	]+sub    -0x18\(%edi\),%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 *
+#  GD -> LE with global variable defined in executable
+ +[0-9a-f]+:	65 a1 00 00 00 00[ 	]+mov    %gs:0x0,%eax
+ +[0-9a-f]+:	81 e8 00 10 00 00[ 	]+sub    \$0x1000,%eax
+#							sg1
+ +[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]+:	65 a1 00 00 00 00[ 	]+mov    %gs:0x0,%eax
+ +[0-9a-f]+:	81 e8 e0 0f 00 00[ 	]+sub    \$0xfe0,%eax
+#							sl1
+ +[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]+:	65 a1 00 00 00 00[ 	]+mov    %gs:0x0,%eax
+ +[0-9a-f]+:	81 e8 c0 0f 00 00[ 	]+sub    \$0xfc0,%eax
+#							sh1
+ +[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]+:	65 a1 00 00 00 00[ 	]+mov    %gs:0x0,%eax
+ +[0-9a-f]+:	8d b6 00 00 00 00[ 	]+lea    0x0\(%esi\),%esi
+ +[0-9a-f]+:	90[ 	]+nop *
+ +[0-9a-f]+:	8d 90 20 f0 ff ff[ 	]+lea    -0xfe0\(%eax\),%edx
+#							sl1
+ +[0-9a-f]+:	90[ 	]+nop *
+ +[0-9a-f]+:	90[ 	]+nop *
+ +[0-9a-f]+:	8d 88 24 f0 ff ff[ 	]+lea    -0xfdc\(%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]+:	65 a1 00 00 00 00[ 	]+mov    %gs:0x0,%eax
+ +[0-9a-f]+:	8d b6 00 00 00 00[ 	]+lea    0x0\(%esi\),%esi
+ +[0-9a-f]+:	90[ 	]+nop *
+ +[0-9a-f]+:	8d 90 40 f0 ff ff[ 	]+lea    -0xfc0\(%eax\),%edx
+#							sh1
+ +[0-9a-f]+:	90[ 	]+nop *
+ +[0-9a-f]+:	90[ 	]+nop *
+ +[0-9a-f]+:	8d 88 44 f0 ff ff[ 	]+lea    -0xfbc\(%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 e4 ff ff ff[ 	]+sub    -0x1c\(%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 e8 ff ff ff[ 	]+sub    -0x18\(%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 d8 ff ff ff[ 	]+add    -0x28\(%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 ec ff ff ff[ 	]+add    -0x14\(%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 dc ff ff ff[ 	]+mov    -0x24\(%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 *
+#  GD -> IE because variable is not defined in executable
+ +[0-9a-f]+:	65 a1 00 00 00 00[ 	]+mov    %gs:0x0,%eax
+ +[0-9a-f]+:	2b 87 f4 ff ff ff[ 	]+sub    -0xc\(%edi\),%eax
+#				->R_386_TLS_TPOFF32	sG1
+ +[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    -0x4\(%ebp\),%ebx
+ +[0-9a-f]+:	c9[ 	]+leave *
+ +[0-9a-f]+:	c3[ 	]+ret *
+
+[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 ([0-9a-f]{2} ){4}[ 	]+add    \$0x[0-9a-f]+,%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 f0 ff ff ff[ 	]+sub    -0x10\(%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 ([0-9a-f]{2} ){4}[ 	]+add    0x[0-9a-f]+,%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 ([0-9a-f]{2} ){4}[ 	]+mov    0x[0-9a-f]+,%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    -0xffc\(%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    -0x4\(%ebp\),%ebx
+ +[0-9a-f]+:	c9[ 	]+leave *
+ +[0-9a-f]+:	c3[ 	]+ret *
diff --git a/ld/testsuite/ld-i386/tlsbin2.rd b/ld/testsuite/ld-i386/tlsbin2.rd
new file mode 100644
index 0000000..05d4ddb
--- /dev/null
+++ b/ld/testsuite/ld-i386/tlsbin2.rd
@@ -0,0 +1,154 @@
+#source: tlsbinpic2.s
+#source: tlsbin.s
+#as: --32
+#ld: -melf_i386 tmpdir/libtlslib.so --no-ld-generated-unwind-info
+#readelf: -Ssrl
+#target: i?86-*-*
+
+There are [0-9]+ section headers, starting at offset 0x[0-9a-f]+:
+
+Section Headers:
+ +\[Nr\] Name +Type +Addr +Off +Size +ES Flg Lk Inf Al
+ +\[[ 0-9]+\] +NULL +0+ 0+ 0+ 0+ +0 +0 +0
+ +\[[ 0-9]+\] \.interp +.*
+ +\[[ 0-9]+\] \.hash +.*
+ +\[[ 0-9]+\] \.dynsym +.*
+ +\[[ 0-9]+\] \.dynstr +.*
+ +\[[ 0-9]+\] \.rel.dyn +.*
+ +\[[ 0-9]+\] \.text +PROGBITS +0+8049000 .*
+ +\[[ 0-9]+\] \.tdata +PROGBITS +0+804a000 [0-9a-f]+ 000060 00 WAT +0 +0 4096
+ +\[[ 0-9]+\] \.tbss +NOBITS +[0-9a-f]+ [0-9a-f]+ 000040 00 WAT +0 +0 +1
+ +\[[ 0-9]+\] \.dynamic +DYNAMIC +0+804a060 .*
+ +\[[ 0-9]+\] \.got +PROGBITS +0+804a0e0 .*
+ +\[[ 0-9]+\] \.got\.plt +PROGBITS +0+804a108 .*
+ +\[[ 0-9]+\] \.shstrtab +.*
+ +\[[ 0-9]+\] \.symtab +.*
+ +\[[ 0-9]+\] \.strtab +.*
+Key to Flags:
+#...
+
+Elf file type is EXEC \(Executable file\)
+Entry point 0x8049188
+There are [0-9]+ 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 10 entries:
+ Offset +Info +Type +Sym.Value +Sym. Name
+[0-9a-f ]+R_386_TLS_TPOFF +0+ +sG3
+[0-9a-f ]+R_386_TLS_TPOFF +0+ +sG5
+[0-9a-f ]+R_386_TLS_TPOFF +0+ +sG7
+[0-9a-f ]+R_386_TLS_TPOFF32 0+ +sG2
+[0-9a-f ]+R_386_TLS_TPOFF32 0+ +sG4
+[0-9a-f ]+R_386_TLS_TPOFF +0+ +sG4
+[0-9a-f ]+R_386_TLS_TPOFF32 0+ +sG6
+[0-9a-f ]+R_386_TLS_TPOFF32 0+ +sG1
+[0-9a-f ]+R_386_TLS_TPOFF +0+ +sG8
+[0-9a-f ]+R_386_GLOB_DAT +[0-9a-f]+ +___tls_get_addr
+
+Symbol table '\.dynsym' contains [0-9]+ 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 +11 __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 +11 _edata
+ +[0-9]+: [0-9a-f]+ +0 +NOTYPE +GLOBAL +DEFAULT +11 _end
+ +[0-9]+: 0+ +0 +TLS +GLOBAL +DEFAULT +UND sG8
+ +[0-9]+: [0-9a-f]+ +0 +FUNC +GLOBAL +DEFAULT +UND ___tls_get_addr
+
+Symbol table '\.symtab' contains [0-9]+ 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 *
+.* FILE +LOCAL +DEFAULT +ABS tmpdir/tlsbinpic2.o
+ +[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
+.* FILE +LOCAL +DEFAULT +ABS tmpdir/tlsbin.o
+ +[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
+.* FILE +LOCAL +DEFAULT +ABS 
+ +[0-9]+: 0+804a060 +0 +OBJECT +LOCAL +DEFAULT +9 _DYNAMIC
+ +[0-9]+: [0-9a-f]+ +0 +OBJECT +LOCAL +DEFAULT +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+8049188 +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 +11 __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 +11 _edata
+ +[0-9]+: [0-9a-f]+ +0 +NOTYPE +GLOBAL +DEFAULT +11 _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]+: [0-9a-f]+ +0 +FUNC +GLOBAL +DEFAULT +UND ___tls_get_addr
+ +[0-9]+: 0000006c +0 +TLS +GLOBAL +DEFAULT +8 bg4
diff --git a/ld/testsuite/ld-i386/tlsbin2.sd b/ld/testsuite/ld-i386/tlsbin2.sd
new file mode 100644
index 0000000..519e469
--- /dev/null
+++ b/ld/testsuite/ld-i386/tlsbin2.sd
@@ -0,0 +1,13 @@
+#source: tlsbinpic.s
+#source: tlsbin.s
+#as: --32
+#ld: -melf_i386 tmpdir/libtlslib.so --no-ld-generated-unwind-info
+#objdump: -sj.got
+#target: i?86-*-*
+
+.*:     file format elf32-i386.*
+
+Contents of section \.got:
+ [0-9a-f]+ 00000000 00000000 00000000 00000000  .*
+ [0-9a-f]+ 00000000 00000000 00000000 00000000  .*
+ [0-9a-f]+ 00000000 00000000  +.*
diff --git a/ld/testsuite/ld-i386/tlsbin2.td b/ld/testsuite/ld-i386/tlsbin2.td
new file mode 100644
index 0000000..d960295
--- /dev/null
+++ b/ld/testsuite/ld-i386/tlsbin2.td
@@ -0,0 +1,16 @@
+#source: tlsbinpic.s
+#source: tlsbin.s
+#as: --32
+#ld: -melf_i386 tmpdir/libtlslib.so --no-ld-generated-unwind-info
+#objdump: -sj.tdata
+#target: i?86-*-*
+
+.*:     file format elf32-i386.*
+
+Contents of section \.tdata:
+ [0-9a-f]+000 11000000 12000000 13000000 14000000  .*
+ [0-9a-f]+010 15000000 16000000 17000000 18000000  .*
+ [0-9a-f]+020 41000000 42000000 43000000 44000000  .*
+ [0-9a-f]+030 45000000 46000000 47000000 48000000  .*
+ [0-9a-f]+040 01010000 02010000 03010000 04010000  .*
+ [0-9a-f]+050 05010000 06010000 07010000 08010000  .*
diff --git a/ld/testsuite/ld-i386/tlsbinpic2.s b/ld/testsuite/ld-i386/tlsbinpic2.s
new file mode 100644
index 0000000..ebfcc6e6
--- /dev/null
+++ b/ld/testsuite/ld-i386/tlsbinpic2.s
@@ -0,0 +1,172 @@
+	/* 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@tlsgd(%ebx), %eax
+	call	*___tls_get_addr@GOT(%ebx)
+	nop;nop;nop;nop
+
+	/* GD -> IE because variable is not defined in executable where
+	   the variable is referenced through @gottpoff too */
+	leal	sG2@tlsgd(%ecx), %eax
+	call	*___tls_get_addr@GOT(%ecx)
+	nop;nop;nop;nop
+
+	/* GD -> IE because variable is not defined in executable where
+	   the variable is referenced through @gotntpoff too */
+	leal	sG3@tlsgd(%edx), %eax
+	call	*___tls_get_addr@GOT(%edx)
+	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@tlsgd(%edi), %eax
+	call	*___tls_get_addr@GOT(%edi)
+	nop;nop;nop;nop
+
+	/* GD -> LE with global variable defined in executable */
+	leal	sg1@tlsgd(%esi), %eax
+	call	*___tls_get_addr@GOT(%esi)
+	nop;nop;nop;nop
+
+	/* GD -> LE with local variable defined in executable */
+	leal	sl1@tlsgd(%ebp), %eax
+	call	*___tls_get_addr@GOT(%ebp)
+	nop;nop;nop;nop
+
+	/* GD -> LE with hidden variable defined in executable */
+	leal	sh1@tlsgd(%ebx), %eax
+	call	*___tls_get_addr@GOT(%ebx)
+	nop;nop;nop;nop
+
+	/* LD -> LE */
+	leal	sl1@tlsldm(%edi), %eax
+	call	*___tls_get_addr@GOT(%edi)
+	nop
+	leal	sl1@dtpoff(%eax), %edx
+	nop;nop
+	leal	sl2@dtpoff(%eax), %ecx
+	nop;nop;nop;nop
+
+	/* LD -> LE against hidden variables */
+	leal	sh1@tlsldm(%esi), %eax
+	call	*___tls_get_addr@GOT(%esi)
+	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
+
+	/* GD -> IE because variable is not defined in executable */
+	leal	sG1@tlsgd(%edi), %eax
+	call	*___tls_get_addr@GOT(%edi)
+	nop;nop;nop;nop
+
+	movl    -4(%ebp), %ebx
+	leave
+	ret
diff --git a/ld/testsuite/ld-i386/tlsgd3.dd b/ld/testsuite/ld-i386/tlsgd3.dd
new file mode 100644
index 0000000..c2c60ba
--- /dev/null
+++ b/ld/testsuite/ld-i386/tlsgd3.dd
@@ -0,0 +1,16 @@
+#source: tlsgd3.s
+#as: --32
+#ld: -melf_i386 tmpdir/tlsgd3
+#objdump: -drw
+#target: i?86-*-linux*
+
+.*: +file format .*
+
+Disassembly of section .text:
+
+[a-f0-9]+ <_start>:
+[ 	]*[a-f0-9]+:	65 a1 00 00 00 00    	mov    %gs:0x0,%eax
+[ 	]*[a-f0-9]+:	81 e8 04 00 00 00    	sub    \$0x4,%eax
+[ 	]*[a-f0-9]+:	65 a1 00 00 00 00    	mov    %gs:0x0,%eax
+[ 	]*[a-f0-9]+:	81 e8 04 00 00 00    	sub    \$0x4,%eax
+#pass
diff --git a/ld/testsuite/ld-i386/tlsgd3.s b/ld/testsuite/ld-i386/tlsgd3.s
new file mode 100644
index 0000000..df547d2
--- /dev/null
+++ b/ld/testsuite/ld-i386/tlsgd3.s
@@ -0,0 +1,15 @@
+	.text
+	.globl _start
+_start:
+	leal	foo@TLSGD(%ecx), %eax
+	call	*___tls_get_addr@GOT(%ecx)
+	leal	foo@TLSGD(%edx), %eax
+	call	*___tls_get_addr@GOT(%edx)
+	nop
+	.globl foo
+	.section	.tdata,"awT",@progbits
+	.align 4
+	.type	foo, @object
+	.size	foo, 4
+foo:
+	.long	100
diff --git a/ld/testsuite/ld-i386/tlsgd4.d b/ld/testsuite/ld-i386/tlsgd4.d
new file mode 100644
index 0000000..a7083d3
--- /dev/null
+++ b/ld/testsuite/ld-i386/tlsgd4.d
@@ -0,0 +1,4 @@
+#name: TLS GD->LE transition check without PLT
+#as: --32 -mrelax-relocations=yes
+#ld: -melf_i386
+#error: .*TLS transition from R_386_TLS_GD to R_386_TLS_LE_32 against `foo'.*failed.*
diff --git a/ld/testsuite/ld-i386/tlsgd4.s b/ld/testsuite/ld-i386/tlsgd4.s
new file mode 100644
index 0000000..8ad3e1d
--- /dev/null
+++ b/ld/testsuite/ld-i386/tlsgd4.s
@@ -0,0 +1,11 @@
+	.text
+	.globl _start
+_start:
+	leal	foo@TLSGD(%edx), %eax
+	call	*___tls_get_addr@GOT(%ecx)
+	.section	.tdata,"awT",@progbits
+	.align 4
+	.type	foo, @object
+	.size	foo, 4
+foo:
+	.long	100
diff --git a/ld/testsuite/ld-i386/tlsld2.dd b/ld/testsuite/ld-i386/tlsld2.dd
new file mode 100644
index 0000000..b7e082f
--- /dev/null
+++ b/ld/testsuite/ld-i386/tlsld2.dd
@@ -0,0 +1,14 @@
+#source: tlsld2.s
+#as: --32
+#ld: -melf_i386 tmpdir/tlsld1
+#objdump: -drw
+#target: i?86-*-linux*
+
+.*: +file format .*
+
+Disassembly of section .text:
+
+[a-f0-9]+ <_start>:
+[ 	]*[a-f0-9]+:	65 a1 00 00 00 00    	mov    %gs:0x0,%eax
+[ 	]*[a-f0-9]+:	8d b6 00 00 00 00    	lea    0x0\(%esi\),%esi
+#pass
diff --git a/ld/testsuite/ld-i386/tlsld2.s b/ld/testsuite/ld-i386/tlsld2.s
new file mode 100644
index 0000000..476267e
--- /dev/null
+++ b/ld/testsuite/ld-i386/tlsld2.s
@@ -0,0 +1,12 @@
+	.text
+	.globl _start
+_start:
+	leal	foo@TLSLDM(%edi), %eax
+	call	*___tls_get_addr@GOT(%edi)
+	.globl foo
+	.section	.tdata,"awT",@progbits
+	.align 4
+	.type	foo, @object
+	.size	foo, 4
+foo:
+	.long	100
diff --git a/ld/testsuite/ld-i386/tlspic2-nacl.rd b/ld/testsuite/ld-i386/tlspic2-nacl.rd
new file mode 100644
index 0000000..560e840
--- /dev/null
+++ b/ld/testsuite/ld-i386/tlspic2-nacl.rd
@@ -0,0 +1,149 @@
+#source: tlspic3.s
+#source: tlspic2.s
+#as: --32
+#ld: -shared -melf_i386_nacl --no-ld-generated-unwind-info
+#readelf: -Ssrl
+#target: i?86-*-nacl*
+
+There are [0-9]+ section headers, starting at offset 0x[0-9a-f]+:
+
+Section Headers:
+ +\[Nr\] Name +Type +Addr +Off +Size +ES Flg Lk Inf Al
+ +\[[ 0-9]+\] +NULL +0+ 0+ 0+ 0+ +0 +0 +0
+ +\[[ 0-9]+\] \.text +.*
+ +\[[ 0-9]+\] \.hash +.*
+ +\[[ 0-9]+\] \.dynsym +.*
+ +\[[ 0-9]+\] \.dynstr +.*
+ +\[[ 0-9]+\] \.rel.dyn +.*
+ +\[[ 0-9]+\] \.tdata +PROGBITS +[0-9a-f]+ [0-9a-f]+ 000060 00 WAT +0 +0 +1
+ +\[[ 0-9]+\] \.tbss +NOBITS +[0-9aa-f]+ [0-9a-f]+ 000020 00 WAT +0 +0 +1
+ +\[[ 0-9]+\] \.dynamic +.*
+ +\[[ 0-9]+\] \.got +.*
+ +\[[ 0-9]+\] \.got.plt +.*
+ +\[[ 0-9]+\] \.shstrtab +.*
+ +\[[ 0-9]+\] \.symtab +.*
+ +\[[ 0-9]+\] \.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.*
+ +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 +.text *
+ +01 +.hash .dynsym .dynstr .rel.dyn *
+ +02 +.tdata .dynamic .got .got.plt *
+ +03 +.dynamic *
+ +04 +.tdata .tbss *
+
+Relocation section '.rel.dyn' at offset 0x[0-9a-f]+ contains 27 entries:
+ Offset +Info +Type +Sym.Value +Sym. Name
+[0-9a-f ]+R_386_TLS_DTPMOD3
+[0-9a-f ]+R_386_TLS_TPOFF32
+[0-9a-f ]+R_386_TLS_TPOFF *
+[0-9a-f ]+R_386_TLS_TPOFF32
+[0-9a-f ]+R_386_TLS_TPOFF *
+[0-9a-f ]+R_386_TLS_TPOFF *
+[0-9a-f ]+R_386_TLS_DTPMOD3
+[0-9a-f ]+R_386_TLS_DTPMOD3
+[0-9a-f ]+R_386_TLS_TPOFF *
+[0-9a-f ]+R_386_TLS_TPOFF32
+[0-9a-f ]+R_386_TLS_TPOFF32
+[0-9a-f ]+R_386_TLS_TPOFF *
+[0-9a-f ]+R_386_TLS_TPOFF32
+[0-9a-f ]+R_386_TLS_TPOFF *
+[0-9a-f ]+R_386_TLS_TPOFF *
+[0-9a-f ]+R_386_TLS_TPOFF *
+[0-9a-f ]+R_386_TLS_TPOFF *
+[0-9a-f ]+R_386_TLS_DTPMOD3
+[0-9a-f ]+R_386_TLS_TPOFF32
+[0-9a-f ]+R_386_TLS_TPOFF +0+8 +sg3
+[0-9a-f ]+R_386_TLS_TPOFF32 0+c +sg4
+[0-9a-f ]+R_386_TLS_TPOFF +0+c +sg4
+[0-9a-f ]+R_386_TLS_TPOFF +0+10 +sg5
+[0-9a-f ]+R_386_TLS_DTPMOD3 0+ +sg1
+[0-9a-f ]+R_386_TLS_DTPOFF3 0+ +sg1
+[0-9a-f ]+R_386_TLS_TPOFF32 0+4 +sg2
+[0-9a-f ]+R_386_GLOB_DAT +0+ +___tls_get_addr
+
+Symbol table '\.dynsym' contains [0-9]+ entries:
+ +Num: +Value +Size +Type +Bind +Vis +Ndx +Name
+ +[0-9]+: 0+ +0 +NOTYPE +LOCAL +DEFAULT +UND *
+ +[0-9]+: 0+1c +0 +TLS +GLOBAL +DEFAULT +6 sg8
+ +[0-9]+: 0+8 +0 +TLS +GLOBAL +DEFAULT +6 sg3
+ +[0-9]+: 0+c +0 +TLS +GLOBAL +DEFAULT +6 sg4
+ +[0-9]+: 0+10 +0 +TLS +GLOBAL +DEFAULT +6 sg5
+ +[0-9]+: 0+ +0 +TLS +GLOBAL +DEFAULT +6 sg1
+ +[0-9]+: [0-9a-f]+ +0 +FUNC +GLOBAL +DEFAULT +1 fn1
+ +[0-9]+: [0-9a-f]+ +0 +NOTYPE +GLOBAL +DEFAULT +10 __bss_start
+ +[0-9]+: 0+4 +0 +TLS +GLOBAL +DEFAULT +6 sg2
+ +[0-9]+: 0+14 +0 +TLS +GLOBAL +DEFAULT +6 sg6
+ +[0-9]+: 0+18 +0 +TLS +GLOBAL +DEFAULT +6 sg7
+ +[0-9]+: [0-9a-f]+ +0 +NOTYPE +GLOBAL +DEFAULT +10 _edata
+ +[0-9]+: [0-9a-f]+ +0 +NOTYPE +GLOBAL +DEFAULT +10 _end
+ +[0-9]+: 0+ +0 +NOTYPE +GLOBAL +DEFAULT +UND ___tls_get_addr
+
+Symbol table '\.symtab' contains [0-9]+ 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 *
+.* FILE +LOCAL +DEFAULT +ABS tmpdir/tlspic3.o
+ +[0-9]+: 0+20 +0 +TLS +LOCAL +DEFAULT +6 sl1
+ +[0-9]+: 0+24 +0 +TLS +LOCAL +DEFAULT +6 sl2
+ +[0-9]+: 0+28 +0 +TLS +LOCAL +DEFAULT +6 sl3
+ +[0-9]+: 0+2c +0 +TLS +LOCAL +DEFAULT +6 sl4
+ +[0-9]+: 0+30 +0 +TLS +LOCAL +DEFAULT +6 sl5
+ +[0-9]+: 0+34 +0 +TLS +LOCAL +DEFAULT +6 sl6
+ +[0-9]+: 0+38 +0 +TLS +LOCAL +DEFAULT +6 sl7
+ +[0-9]+: 0+3c +0 +TLS +LOCAL +DEFAULT +6 sl8
+.* FILE +LOCAL +DEFAULT +ABS 
+ +[0-9]+: 0+60 +0 +TLS +LOCAL +DEFAULT +7 sH1
+ +[0-9]+: [0-9a-f]+ +0 +OBJECT +LOCAL +DEFAULT +8 _DYNAMIC
+ +[0-9]+: 0+48 +0 +TLS +LOCAL +DEFAULT +6 sh3
+ +[0-9]+: 0+64 +0 +TLS +LOCAL +DEFAULT +7 sH2
+ +[0-9]+: 0+78 +0 +TLS +LOCAL +DEFAULT +7 sH7
+ +[0-9]+: 0+58 +0 +TLS +LOCAL +DEFAULT +6 sh7
+ +[0-9]+: 0+5c +0 +TLS +LOCAL +DEFAULT +6 sh8
+ +[0-9]+: 0+6c +0 +TLS +LOCAL +DEFAULT +7 sH4
+ +[0-9]+: 0+4c +0 +TLS +LOCAL +DEFAULT +6 sh4
+ +[0-9]+: 0+68 +0 +TLS +LOCAL +DEFAULT +7 sH3
+ +[0-9]+: 0+50 +0 +TLS +LOCAL +DEFAULT +6 sh5
+ +[0-9]+: 0+70 +0 +TLS +LOCAL +DEFAULT +7 sH5
+ +[0-9]+: 0+74 +0 +TLS +LOCAL +DEFAULT +7 sH6
+ +[0-9]+: 0+7c +0 +TLS +LOCAL +DEFAULT +7 sH8
+ +[0-9]+: 0+40 +0 +TLS +LOCAL +DEFAULT +6 sh1
+ +[0-9]+: [0-9a-f]+ +0 +OBJECT +LOCAL +DEFAULT +10 _GLOBAL_OFFSET_TABLE_
+ +[0-9]+: 0+44 +0 +TLS +LOCAL +DEFAULT +6 sh2
+ +[0-9]+: 0+54 +0 +TLS +LOCAL +DEFAULT +6 sh6
+ +[0-9]+: 0+1c +0 +TLS +GLOBAL +DEFAULT +6 sg8
+ +[0-9]+: 0+8 +0 +TLS +GLOBAL +DEFAULT +6 sg3
+ +[0-9]+: 0+c +0 +TLS +GLOBAL +DEFAULT +6 sg4
+ +[0-9]+: 0+10 +0 +TLS +GLOBAL +DEFAULT +6 sg5
+ +[0-9]+: 0+ +0 +TLS +GLOBAL +DEFAULT +6 sg1
+ +[0-9]+: [0-9a-f]+ +0 +FUNC +GLOBAL +DEFAULT +1 fn1
+ +[0-9]+: [0-9a-f]+ +0 +NOTYPE +GLOBAL +DEFAULT +10 __bss_start
+ +[0-9]+: 0+4 +0 +TLS +GLOBAL +DEFAULT +6 sg2
+ +[0-9]+: 0+14 +0 +TLS +GLOBAL +DEFAULT +6 sg6
+ +[0-9]+: 0+18 +0 +TLS +GLOBAL +DEFAULT +6 sg7
+ +[0-9]+: [0-9a-f]+ +0 +NOTYPE +GLOBAL +DEFAULT +10 _edata
+ +[0-9]+: [0-9a-f]+ +0 +NOTYPE +GLOBAL +DEFAULT +10 _end
+ +[0-9]+: 0+ +0 +NOTYPE +GLOBAL +DEFAULT +UND ___tls_get_addr
diff --git a/ld/testsuite/ld-i386/tlspic2.dd b/ld/testsuite/ld-i386/tlspic2.dd
new file mode 100644
index 0000000..2524a31
--- /dev/null
+++ b/ld/testsuite/ld-i386/tlspic2.dd
@@ -0,0 +1,405 @@
+#source: tlspic3.s
+#source: tlspic2.s
+#as: --32
+#ld: -shared -melf_i386 --no-ld-generated-unwind-info
+#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]+ <.*>
+ +[0-9a-f]+:	5b[ 	]+pop    %ebx
+ +[0-9a-f]+:	81 c3 ([0-9a-f]{2} ){4}[ 	]+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 *
+#  GD
+ +[0-9a-f]+:	8d ([0-9a-f]{2} ){5}[ 	]+lea    -0x[0-9a-f]+\(%ebx\),%eax
+#				->R_386_TLS_DTPMOD32	sg1
+ +[0-9a-f]+:	ff ([0-9a-f]{2} ){5}[ 	]+call   \*-0x[0-9a-f]+\(%ebx\)
+#				->R_386_GLOB_DAT	___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 ([0-9a-f]{2} ){5}[ 	]+sub    -0x[0-9a-f]+\(%ecx\),%eax
+#				->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 *
+#  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 ([0-9a-f]{2} ){5}[ 	]+add    -0x[0-9a-f]+\(%edx\),%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 *
+#  GD -> IE because variable is referenced through @gottpoff and
+ +[0-9a-f]+:	65 a1 00 00 00 00[ 	]+mov    %gs:0x0,%eax
+ +[0-9a-f]+:	2b ([0-9a-f]{2} ){5}[ 	]+sub    -0x[0-9a-f]+\(%edi\),%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 *
+#  GD against local variable
+ +[0-9a-f]+:	8d ([0-9a-f]{2} ){5}[ 	]+lea    -0x[0-9a-f]+\(%esi\),%eax
+#				->R_386_TLS_DTPMOD32
+ +[0-9a-f]+:	ff ([0-9a-f]{2} ){5}[ 	]+call   \*-0x[0-9a-f]+\(%esi\)
+#				->R_386_GLOB_DAT	___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 against local variable referenced through @gottpoff too
+ +[0-9a-f]+:	65 a1 00 00 00 00[ 	]+mov    %gs:0x0,%eax
+ +[0-9a-f]+:	2b ([0-9a-f]{2} ){5}[ 	]+sub    -0x[0-9a-f]+\(%ebp\),%eax
+#				->R_386_TLS_TPOFF32
+ +[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]+:	65 a1 00 00 00 00[ 	]+mov    %gs:0x0,%eax
+ +[0-9a-f]+:	03 ([0-9a-f]{2} ){5}[ 	]+add    -0x[0-9a-f]+\(%ebx\),%eax
+#				->R_386_TLS_TPOFF
+ +[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]+:	65 a1 00 00 00 00[ 	]+mov    %gs:0x0,%eax
+ +[0-9a-f]+:	2b ([0-9a-f]{2} ){5}[ 	]+sub    -0x[0-9a-f]+\(%ebx\),%eax
+#				->R_386_TLS_TPOFF32
+ +[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 ([0-9a-f]{2} ){5}[ 	]+lea    -0x[0-9a-f]+\(%ebx\),%eax
+#				->R_386_TLS_DTPMOD32
+ +[0-9a-f]+:	ff ([0-9a-f]{2} ){5}[ 	]+call   \*-0x[0-9a-f]+\(%ebx\)
+#				->R_386_GLOB_DAT	___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 against hidden and local variable referenced through @gottpoff too
+ +[0-9a-f]+:	65 a1 00 00 00 00[ 	]+mov    %gs:0x0,%eax
+ +[0-9a-f]+:	2b ([0-9a-f]{2} ){5}[ 	]+sub    -0x[0-9a-f]+\(%ebx\),%eax
+#				->R_386_TLS_TPOFF32
+ +[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]+:	65 a1 00 00 00 00[ 	]+mov    %gs:0x0,%eax
+ +[0-9a-f]+:	03 ([0-9a-f]{2} ){5}[ 	]+add    -0x[0-9a-f]+\(%ebx\),%eax
+#				->R_386_TLS_TPOFF
+ +[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]+:	65 a1 00 00 00 00[ 	]+mov    %gs:0x0,%eax
+ +[0-9a-f]+:	2b ([0-9a-f]{2} ){5}[ 	]+sub    -0x[0-9a-f]+\(%ebx\),%eax
+#				->R_386_TLS_TPOFF32
+ +[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 ([0-9a-f]{2} ){5}[ 	]+lea    -0x[0-9a-f]+\(%ebx\),%eax
+#				->R_386_TLS_DTPMOD32
+ +[0-9a-f]+:	ff ([0-9a-f]{2} ){5}[ 	]+call   \*-0x[0-9a-f]+\(%ebx\)
+#				->R_386_GLOB_DAT	___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 against hidden but not local variable referenced through
+ +[0-9a-f]+:	65 a1 00 00 00 00[ 	]+mov    %gs:0x0,%eax
+ +[0-9a-f]+:	2b ([0-9a-f]{2} ){5}[ 	]+sub    -0x[0-9a-f]+\(%ebx\),%eax
+#				->R_386_TLS_TPOFF32
+ +[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]+:	65 a1 00 00 00 00[ 	]+mov    %gs:0x0,%eax
+ +[0-9a-f]+:	03 ([0-9a-f]{2} ){5}[ 	]+add    -0x[0-9a-f]+\(%ebx\),%eax
+#				->R_386_TLS_TPOFF
+ +[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]+:	65 a1 00 00 00 00[ 	]+mov    %gs:0x0,%eax
+ +[0-9a-f]+:	2b ([0-9a-f]{2} ){5}[ 	]+sub    -0x[0-9a-f]+\(%ebx\),%eax
+#				->R_386_TLS_TPOFF32
+ +[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 ([0-9a-f]{2} ){5}[ 	]+lea    -0x[0-9a-f]+\(%ebx\),%eax
+#				->R_386_TLS_DTPMOD32
+ +[0-9a-f]+:	ff ([0-9a-f]{2} ){5}[ 	]+call   \*-0x[0-9a-f]+\(%ebx\)
+#				->R_386_GLOB_DAT	___tls_get_addr
+ +[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 ([0-9a-f]{2} ){5}[ 	]+lea    -0x[0-9a-f]+\(%ecx\),%eax
+#				->R_386_TLS_DTPMOD32
+ +[0-9a-f]+:	ff ([0-9a-f]{2} ){5}[ 	]+call   \*-0x[0-9a-f]+\(%ecx\)
+#				->R_386_GLOB_DAT	___tls_get_addr
+ +[0-9a-f]+:	90[ 	]+nop *
+ +[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 ([0-9a-f]{2} ){5}[ 	]+lea    -0x[0-9a-f]+\(%edx\),%eax
+#				->R_386_TLS_DTPMOD32
+ +[0-9a-f]+:	ff ([0-9a-f]{2} ){5}[ 	]+call   \*-0x[0-9a-f]+\(%edx\)
+#				->R_386_GLOB_DAT	___tls_get_addr
+ +[0-9a-f]+:	90[ 	]+nop *
+ +[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 ([0-9a-f]{2} ){5}[ 	]+sub    -0x[0-9a-f]+\(%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 ([0-9a-f]{2} ){5}[ 	]+sub    -0x[0-9a-f]+\(%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 ([0-9a-f]{2} ){5}[ 	]+add    -0x[0-9a-f]+\(%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 ([0-9a-f]{2} ){5}[ 	]+add    -0x[0-9a-f]+\(%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 ([0-9a-f]{2} ){5}[ 	]+sub    -0x[0-9a-f]+\(%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 ([0-9a-f]{2} ){5}[ 	]+sub    -0x[0-9a-f]+\(%ebx\),%eax
+#				->R_386_TLS_TPOFF32
+ +[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 ([0-9a-f]{2} ){5}[ 	]+add    -0x[0-9a-f]+\(%ebx\),%ecx
+#				->R_386_TLS_TPOFF
+ +[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 ([0-9a-f]{2} ){5}[ 	]+add    -0x[0-9a-f]+\(%ebx\),%eax
+#				->R_386_TLS_TPOFF
+ +[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 ([0-9a-f]{2} ){5}[ 	]+sub    -0x[0-9a-f]+\(%ebx\),%ecx
+#				->R_386_TLS_TPOFF32
+ +[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 ([0-9a-f]{2} ){5}[ 	]+sub    -0x[0-9a-f]+\(%ebx\),%eax
+#				->R_386_TLS_TPOFF32
+ +[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 ([0-9a-f]{2} ){5}[ 	]+add    -0x[0-9a-f]+\(%ebx\),%ecx
+#				->R_386_TLS_TPOFF
+ +[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 ([0-9a-f]{2} ){5}[ 	]+add    -0x[0-9a-f]+\(%ebx\),%eax
+#				->R_386_TLS_TPOFF
+ +[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 ([0-9a-f]{2} ){5}[ 	]+sub    -0x[0-9a-f]+\(%ebx\),%ecx
+#				->R_386_TLS_TPOFF32
+ +[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 ([0-9a-f]{2} ){5}[ 	]+sub    -0x[0-9a-f]+\(%ebx\),%eax
+#				->R_386_TLS_TPOFF32
+ +[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 ([0-9a-f]{2} ){5}[ 	]+add    -0x[0-9a-f]+\(%ebx\),%ecx
+#				->R_386_TLS_TPOFF
+ +[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 ([0-9a-f]{2} ){5}[ 	]+add    -0x[0-9a-f]+\(%ebx\),%eax
+#				->R_386_TLS_TPOFF
+ +[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 ([0-9a-f]{2} ){5}[ 	]+mov    -0x[0-9a-f]+\(%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 ([0-9a-f]{2} ){5}[ 	]+mov    -0x[0-9a-f]+\(%ebx\),%eax
+#				->R_386_TLS_TPOFF
+ +[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 ([0-9a-f]{2} ){5}[ 	]+mov    -0x[0-9a-f]+\(%ebx\),%edx
+#				->R_386_TLS_TPOFF
+ +[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 ([0-9a-f]{2} ){5}[ 	]+mov    -0x[0-9a-f]+\(%ebx\),%ecx
+#				->R_386_TLS_TPOFF
+ +[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    -0x4\(%ebp\),%ebx
+ +[0-9a-f]+:	c9[ 	]+leave *
+ +[0-9a-f]+:	c3[ 	]+ret *
diff --git a/ld/testsuite/ld-i386/tlspic2.rd b/ld/testsuite/ld-i386/tlspic2.rd
new file mode 100644
index 0000000..a135547
--- /dev/null
+++ b/ld/testsuite/ld-i386/tlspic2.rd
@@ -0,0 +1,147 @@
+#source: tlspic3.s
+#source: tlspic2.s
+#as: --32
+#ld: -shared -melf_i386 --no-ld-generated-unwind-info
+#readelf: -Ssrl
+#target: i?86-*-*
+
+There are [0-9]+ section headers, starting at offset 0x[0-9a-f]+:
+
+Section Headers:
+ +\[Nr\] Name +Type +Addr +Off +Size +ES Flg Lk Inf Al
+ +\[[ 0-9]+\] +NULL +0+ 0+ 0+ 0+ +0 +0 +0
+ +\[[ 0-9]+\] \.hash +.*
+ +\[[ 0-9]+\] \.dynsym +.*
+ +\[[ 0-9]+\] \.dynstr +.*
+ +\[[ 0-9]+\] \.rel.dyn +.*
+ +\[[ 0-9]+\] \.text +.*
+ +\[[ 0-9]+\] \.tdata +PROGBITS +[0-9a-f]+ [0-9a-f]+ 000060 00 WAT +0 +0 +1
+ +\[[ 0-9]+\] \.tbss +NOBITS +[0-9aa-f]+ [0-9a-f]+ 000020 00 WAT +0 +0 +1
+ +\[[ 0-9]+\] \.dynamic +.*
+ +\[[ 0-9]+\] \.got +.*
+ +\[[ 0-9]+\] \.got.plt +.*
+ +\[[ 0-9]+\] \.shstrtab +.*
+ +\[[ 0-9]+\] \.symtab +.*
+ +\[[ 0-9]+\] \.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 .text *
+ +01 +.tdata .dynamic .got .got.plt *
+ +02 +.dynamic *
+ +03 +.tdata .tbss *
+
+Relocation section '.rel.dyn' at offset 0x[0-9a-f]+ contains 27 entries:
+ Offset +Info +Type +Sym.Value +Sym. Name
+[0-9a-f ]+R_386_TLS_DTPMOD3
+[0-9a-f ]+R_386_TLS_TPOFF32
+[0-9a-f ]+R_386_TLS_TPOFF *
+[0-9a-f ]+R_386_TLS_TPOFF32
+[0-9a-f ]+R_386_TLS_TPOFF *
+[0-9a-f ]+R_386_TLS_TPOFF *
+[0-9a-f ]+R_386_TLS_DTPMOD3
+[0-9a-f ]+R_386_TLS_DTPMOD3
+[0-9a-f ]+R_386_TLS_TPOFF *
+[0-9a-f ]+R_386_TLS_TPOFF32
+[0-9a-f ]+R_386_TLS_TPOFF32
+[0-9a-f ]+R_386_TLS_TPOFF *
+[0-9a-f ]+R_386_TLS_TPOFF32
+[0-9a-f ]+R_386_TLS_TPOFF *
+[0-9a-f ]+R_386_TLS_TPOFF *
+[0-9a-f ]+R_386_TLS_TPOFF *
+[0-9a-f ]+R_386_TLS_TPOFF *
+[0-9a-f ]+R_386_TLS_DTPMOD3
+[0-9a-f ]+R_386_TLS_TPOFF32
+[0-9a-f ]+R_386_TLS_TPOFF +0+8 +sg3
+[0-9a-f ]+R_386_TLS_TPOFF32 0+c +sg4
+[0-9a-f ]+R_386_TLS_TPOFF +0+c +sg4
+[0-9a-f ]+R_386_TLS_TPOFF +0+10 +sg5
+[0-9a-f ]+R_386_TLS_DTPMOD3 0+ +sg1
+[0-9a-f ]+R_386_TLS_DTPOFF3 0+ +sg1
+[0-9a-f ]+R_386_TLS_TPOFF32 0+4 +sg2
+[0-9a-f ]+R_386_GLOB_DAT +0+ +___tls_get_addr
+
+Symbol table '\.dynsym' contains [0-9]+ entries:
+ +Num: +Value +Size +Type +Bind +Vis +Ndx +Name
+ +[0-9]+: 0+ +0 +NOTYPE +LOCAL +DEFAULT +UND *
+ +[0-9]+: 0+1c +0 +TLS +GLOBAL +DEFAULT +6 sg8
+ +[0-9]+: 0+8 +0 +TLS +GLOBAL +DEFAULT +6 sg3
+ +[0-9]+: 0+c +0 +TLS +GLOBAL +DEFAULT +6 sg4
+ +[0-9]+: 0+10 +0 +TLS +GLOBAL +DEFAULT +6 sg5
+ +[0-9]+: 0+ +0 +TLS +GLOBAL +DEFAULT +6 sg1
+ +[0-9]+: [0-9a-f]+ +0 +FUNC +GLOBAL +DEFAULT +5 fn1
+ +[0-9]+: [0-9a-f]+ +0 +NOTYPE +GLOBAL +DEFAULT +10 __bss_start
+ +[0-9]+: 0+4 +0 +TLS +GLOBAL +DEFAULT +6 sg2
+ +[0-9]+: 0+14 +0 +TLS +GLOBAL +DEFAULT +6 sg6
+ +[0-9]+: 0+18 +0 +TLS +GLOBAL +DEFAULT +6 sg7
+ +[0-9]+: [0-9a-f]+ +0 +NOTYPE +GLOBAL +DEFAULT +10 _edata
+ +[0-9]+: [0-9a-f]+ +0 +NOTYPE +GLOBAL +DEFAULT +10 _end
+ +[0-9]+: 0+ +0 +NOTYPE +GLOBAL +DEFAULT +UND ___tls_get_addr
+
+Symbol table '\.symtab' contains [0-9]+ 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 *
+.* FILE +LOCAL +DEFAULT +ABS tmpdir/tlspic3.o
+ +[0-9]+: 0+20 +0 +TLS +LOCAL +DEFAULT +6 sl1
+ +[0-9]+: 0+24 +0 +TLS +LOCAL +DEFAULT +6 sl2
+ +[0-9]+: 0+28 +0 +TLS +LOCAL +DEFAULT +6 sl3
+ +[0-9]+: 0+2c +0 +TLS +LOCAL +DEFAULT +6 sl4
+ +[0-9]+: 0+30 +0 +TLS +LOCAL +DEFAULT +6 sl5
+ +[0-9]+: 0+34 +0 +TLS +LOCAL +DEFAULT +6 sl6
+ +[0-9]+: 0+38 +0 +TLS +LOCAL +DEFAULT +6 sl7
+ +[0-9]+: 0+3c +0 +TLS +LOCAL +DEFAULT +6 sl8
+.* FILE +LOCAL +DEFAULT +ABS 
+ +[0-9]+: 0+60 +0 +TLS +LOCAL +DEFAULT +7 sH1
+ +[0-9]+: [0-9a-f]+ +0 +OBJECT +LOCAL +DEFAULT +8 _DYNAMIC
+ +[0-9]+: 0+48 +0 +TLS +LOCAL +DEFAULT +6 sh3
+ +[0-9]+: 0+64 +0 +TLS +LOCAL +DEFAULT +7 sH2
+ +[0-9]+: 0+78 +0 +TLS +LOCAL +DEFAULT +7 sH7
+ +[0-9]+: 0+58 +0 +TLS +LOCAL +DEFAULT +6 sh7
+ +[0-9]+: 0+5c +0 +TLS +LOCAL +DEFAULT +6 sh8
+ +[0-9]+: 0+6c +0 +TLS +LOCAL +DEFAULT +7 sH4
+ +[0-9]+: 0+4c +0 +TLS +LOCAL +DEFAULT +6 sh4
+ +[0-9]+: 0+68 +0 +TLS +LOCAL +DEFAULT +7 sH3
+ +[0-9]+: 0+50 +0 +TLS +LOCAL +DEFAULT +6 sh5
+ +[0-9]+: 0+70 +0 +TLS +LOCAL +DEFAULT +7 sH5
+ +[0-9]+: 0+74 +0 +TLS +LOCAL +DEFAULT +7 sH6
+ +[0-9]+: 0+7c +0 +TLS +LOCAL +DEFAULT +7 sH8
+ +[0-9]+: 0+40 +0 +TLS +LOCAL +DEFAULT +6 sh1
+ +[0-9]+: [0-9a-f]+ +0 +OBJECT +LOCAL +DEFAULT +10 _GLOBAL_OFFSET_TABLE_
+ +[0-9]+: 0+44 +0 +TLS +LOCAL +DEFAULT +6 sh2
+ +[0-9]+: 0+54 +0 +TLS +LOCAL +DEFAULT +6 sh6
+ +[0-9]+: 0+1c +0 +TLS +GLOBAL +DEFAULT +6 sg8
+ +[0-9]+: 0+8 +0 +TLS +GLOBAL +DEFAULT +6 sg3
+ +[0-9]+: 0+c +0 +TLS +GLOBAL +DEFAULT +6 sg4
+ +[0-9]+: 0+10 +0 +TLS +GLOBAL +DEFAULT +6 sg5
+ +[0-9]+: 0+ +0 +TLS +GLOBAL +DEFAULT +6 sg1
+ +[0-9]+: [0-9a-f]+ +0 +FUNC +GLOBAL +DEFAULT +5 fn1
+ +[0-9]+: [0-9a-f]+ +0 +NOTYPE +GLOBAL +DEFAULT +10 __bss_start
+ +[0-9]+: 0+4 +0 +TLS +GLOBAL +DEFAULT +6 sg2
+ +[0-9]+: 0+14 +0 +TLS +GLOBAL +DEFAULT +6 sg6
+ +[0-9]+: 0+18 +0 +TLS +GLOBAL +DEFAULT +6 sg7
+ +[0-9]+: [0-9a-f]+ +0 +NOTYPE +GLOBAL +DEFAULT +10 _edata
+ +[0-9]+: [0-9a-f]+ +0 +NOTYPE +GLOBAL +DEFAULT +10 _end
+ +[0-9]+: 0+ +0 +NOTYPE +GLOBAL +DEFAULT +UND ___tls_get_addr
diff --git a/ld/testsuite/ld-i386/tlspic2.sd b/ld/testsuite/ld-i386/tlspic2.sd
new file mode 100644
index 0000000..f72febf
--- /dev/null
+++ b/ld/testsuite/ld-i386/tlspic2.sd
@@ -0,0 +1,18 @@
+#source: tlspic3.s
+#source: tlspic2.s
+#as: --32
+#ld: -shared -melf_i386 --no-ld-generated-unwind-info
+#objdump: -sj.got
+#target: i?86-*-*
+
+.*:     file format elf32-i386.*
+
+Contents of section \.got:
+ [0-9a-f]+ 00000000 20000000 dcffffff 28000000  .*
+ [0-9a-f]+ d4ffffff 2c000000 30000000 00000000  .*
+ [0-9a-f]+ 00000000 00000000 60000000 00000000  .*
+ [0-9a-f]+ 48000000 9cffffff 00000000 00000000  .*
+ [0-9a-f]+ 00000000 94ffffff 6c000000 00000000  .*
+ [0-9a-f]+ 00000000 b4ffffff 4c000000 68000000  .*
+ [0-9a-f]+ 50000000 70000000 00000000 00000000  .*
+ [0-9a-f]+ 40000000 bcffffff 00000000  +.*
diff --git a/ld/testsuite/ld-i386/tlspic2.td b/ld/testsuite/ld-i386/tlspic2.td
new file mode 100644
index 0000000..e1bd959
--- /dev/null
+++ b/ld/testsuite/ld-i386/tlspic2.td
@@ -0,0 +1,16 @@
+#source: tlspic3.s
+#source: tlspic2.s
+#as: --32
+#ld: -shared -melf_i386 --no-ld-generated-unwind-info
+#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/tlspic3.s b/ld/testsuite/ld-i386/tlspic3.s
new file mode 100644
index 0000000..4268045
--- /dev/null
+++ b/ld/testsuite/ld-i386/tlspic3.s
@@ -0,0 +1,282 @@
+	.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@tlsgd(%ebx), %eax
+	call	*___tls_get_addr@GOT(%ebx)
+	nop;nop;nop;nop
+
+	/* GD -> IE because variable is referenced through @gottpoff too */
+	leal	sg2@tlsgd(%ecx), %eax
+	call	*___tls_get_addr@GOT(%ecx)
+	nop;nop;nop;nop
+
+	/* GD -> IE because variable is referenced through @gotntpoff too */
+	leal	sg3@tlsgd(%edx), %eax
+	call	*___tls_get_addr@GOT(%edx)
+	nop;nop;nop;nop
+
+	/* GD -> IE because variable is referenced through @gottpoff and
+	   @gotntpoff too */
+	leal	sg4@tlsgd(%edi), %eax
+	call	*___tls_get_addr@GOT(%edi)
+	nop;nop;nop;nop
+
+	/* GD against local variable */
+	leal	sl1@tlsgd(%esi), %eax
+	call	*___tls_get_addr@GOT(%esi)
+	nop;nop;nop;nop
+
+	/* GD -> IE against local variable referenced through @gottpoff too */
+	leal	sl2@tlsgd(%ebp), %eax
+	call	*___tls_get_addr@GOT(%ebp)
+	nop;nop;nop;nop
+
+	/* GD -> IE against local variable referenced through @gotntpoff
+	   too */
+	leal	sl3@tlsgd(%ebx), %eax
+	call	*___tls_get_addr@GOT(%ebx)
+	nop;nop;nop;nop
+
+	/* GD -> IE against local variable referenced through @gottpoff and
+	   @gotntpoff too */
+	leal	sl4@tlsgd(%ebx), %eax
+	call	*___tls_get_addr@GOT(%ebx)
+	nop;nop;nop;nop
+
+	/* GD against hidden and local variable */
+	leal	sh1@tlsgd(%ebx), %eax
+	call	*___tls_get_addr@GOT(%ebx)
+	nop;nop;nop;nop
+
+	/* GD -> IE against hidden and local variable referenced through
+	   @gottpoff too */
+	leal	sh2@tlsgd(%ebx), %eax
+	call	*___tls_get_addr@GOT(%ebx)
+	nop;nop;nop;nop
+
+	/* GD -> IE against hidden and local variable referenced through
+	   @gotntpoff too */
+	leal	sh3@tlsgd(%ebx), %eax
+	call	*___tls_get_addr@GOT(%ebx)
+	nop;nop;nop;nop
+
+	/* GD -> IE against hidden and local variable referenced through
+	   @gottpoff and @gotntpoff too */
+	leal	sh4@tlsgd(%ebx), %eax
+	call	*___tls_get_addr@GOT(%ebx)
+	nop;nop;nop;nop
+
+	/* GD against hidden but not local variable */
+	leal	sH1@tlsgd(%ebx), %eax
+	call	*___tls_get_addr@GOT(%ebx)
+	nop;nop;nop;nop
+
+	/* GD -> IE against hidden but not local variable referenced through
+	   @gottpoff too */
+	leal	sH2@tlsgd(%ebx), %eax
+	call	*___tls_get_addr@GOT(%ebx)
+	nop;nop;nop;nop
+
+	/* GD -> IE against hidden but not local variable referenced through
+	   @gotntpoff too */
+	leal	sH3@tlsgd(%ebx), %eax
+	call	*___tls_get_addr@GOT(%ebx)
+	nop;nop;nop;nop
+
+	/* GD -> IE against hidden but not local variable referenced through
+	   @gottpoff and @gotntpoff too */
+	leal	sH4@tlsgd(%ebx), %eax
+	call	*___tls_get_addr@GOT(%ebx)
+	nop;nop;nop;nop
+
+	/* LD */
+	leal	sl1@tlsldm(%ebx), %eax
+	call	*___tls_get_addr@GOT(%ebx)
+	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@tlsldm(%ecx), %eax
+	call	*___tls_get_addr@GOT(%ecx)
+	nop
+	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@tlsldm(%edx), %eax
+	call	*___tls_get_addr@GOT(%edx)
+	nop
+	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/tlspie3.s b/ld/testsuite/ld-i386/tlspie3.s
new file mode 100644
index 0000000..b934f09
--- /dev/null
+++ b/ld/testsuite/ld-i386/tlspie3.s
@@ -0,0 +1,64 @@
+	.text
+	.globl ___tls_get_addr
+	.type	___tls_get_addr, @function
+___tls_get_addr:
+	ret
+	.size	___tls_get_addr, .-___tls_get_addr
+.globl _start
+	.type	_start, @function
+_start:
+	pushl	%ebp
+	movl	%esp, %ebp
+	pushl	%esi
+	pushl	%ebx
+	call	.L3
+.L3:
+	popl	%ebx
+	addl	$_GLOBAL_OFFSET_TABLE_+[.-.L3], %ebx
+	movl	%gs:foo2@NTPOFF, %esi
+	addl	%gs:foo1@NTPOFF, %esi
+	movl	foo3@GOTNTPOFF(%ebx), %eax
+	addl	%gs:(%eax), %esi
+	leal	foo4@TLSLDM(%edx), %eax
+	call	*___tls_get_addr@GOT(%edx)
+	addl	(%eax), %esi
+	leal	foo5@TLSGD(%ebx), %eax
+	call	*___tls_get_addr@GOT(%ebx)
+	addl	(%eax), %esi
+	movl	%esi, %eax
+	popl	%ebx
+	popl	%esi
+	leave
+	ret
+	.size	_start, .-_start
+.globl foo1
+	.section	.tbss,"awT",@nobits
+	.align 4
+	.type	foo1, @object
+	.size	foo1, 4
+foo1:
+	.zero	4
+.globl foo2
+	.align 4
+	.type	foo2, @object
+	.size	foo2, 4
+foo2:
+	.zero	4
+.globl foo3
+	.align 4
+	.type	foo3, @object
+	.size	foo3, 4
+foo3:
+	.zero	4
+.globl foo4
+	.align 4
+	.type	foo4, @object
+	.size	foo4, 4
+foo4:
+	.zero	4
+.globl foo5
+	.align 4
+	.type	foo5, @object
+	.size	foo5, 4
+foo5:
+	.zero	4
diff --git a/ld/testsuite/ld-i386/tlspie3a.d b/ld/testsuite/ld-i386/tlspie3a.d
new file mode 100644
index 0000000..f540c5a
--- /dev/null
+++ b/ld/testsuite/ld-i386/tlspie3a.d
@@ -0,0 +1,6 @@
+#source: tlspie3.s
+#as: --32 -mrelax-relocations=yes
+#ld: -melf_i386 -pie
+#readelf: -r
+
+There are no relocations in this file.
diff --git a/ld/testsuite/ld-i386/tlspie3b.d b/ld/testsuite/ld-i386/tlspie3b.d
new file mode 100644
index 0000000..7de0472
--- /dev/null
+++ b/ld/testsuite/ld-i386/tlspie3b.d
@@ -0,0 +1,37 @@
+#source: tlspie3.s
+#as: --32 -mrelax-relocations=yes
+#ld: -melf_i386 -pie
+#objdump: -dwr
+
+.*: +file format .*
+
+
+Disassembly of section .text:
+
+[0-9a-f]+ <___tls_get_addr>:
+[ 	]*[a-f0-9]+:	c3                   	ret    
+
+[0-9a-f]+ <_start>:
+[ 	]*[a-f0-9]+:	55                   	push   %ebp
+[ 	]*[a-f0-9]+:	89 e5                	mov    %esp,%ebp
+[ 	]*[a-f0-9]+:	56                   	push   %esi
+[ 	]*[a-f0-9]+:	53                   	push   %ebx
+[ 	]*[a-f0-9]+:	e8 00 00 00 00       	call   [0-9a-f]+ .*
+[ 	]*[a-f0-9]+:	5b                   	pop    %ebx
+[ 	]*[a-f0-9]+:	81 c3 ([0-9a-f]{2} ){4}[ 	]+add    \$0x[0-9a-f]+,%ebx
+[ 	]*[a-f0-9]+:	65 8b 35 f0 ff ff ff 	mov    %gs:0xfffffff0,%esi
+[ 	]*[a-f0-9]+:	65 03 35 ec ff ff ff 	add    %gs:0xffffffec,%esi
+[ 	]*[a-f0-9]+:	c7 c0 f4 ff ff ff    	mov    \$0xfffffff4,%eax
+[ 	]*[a-f0-9]+:	65 03 30             	add    %gs:\(%eax\),%esi
+[ 	]*[a-f0-9]+:	65 a1 00 00 00 00    	mov    %gs:0x0,%eax
+[ 	]*[a-f0-9]+:	8d b6 00 00 00 00    	lea    0x0\(%esi\),%esi
+[ 	]*[a-f0-9]+:	03 30                	add    \(%eax\),%esi
+[ 	]*[a-f0-9]+:	65 a1 00 00 00 00    	mov    %gs:0x0,%eax
+[ 	]*[a-f0-9]+:	81 e8 04 00 00 00    	sub    \$0x4,%eax
+[ 	]*[a-f0-9]+:	03 30                	add    \(%eax\),%esi
+[ 	]*[a-f0-9]+:	89 f0                	mov    %esi,%eax
+[ 	]*[a-f0-9]+:	5b                   	pop    %ebx
+[ 	]*[a-f0-9]+:	5e                   	pop    %esi
+[ 	]*[a-f0-9]+:	c9                   	leave  
+[ 	]*[a-f0-9]+:	c3                   	ret    
+#pass
diff --git a/ld/testsuite/ld-i386/tlspie3c.d b/ld/testsuite/ld-i386/tlspie3c.d
new file mode 100644
index 0000000..aa02f57
--- /dev/null
+++ b/ld/testsuite/ld-i386/tlspie3c.d
@@ -0,0 +1,37 @@
+#source: tlspie3.s
+#as: --32 -mrelax-relocations=yes
+#ld: -melf_i386 -pie -z call-nop=suffix-nop
+#objdump: -dwr
+
+.*: +file format .*
+
+
+Disassembly of section .text:
+
+[0-9a-f]+ <___tls_get_addr>:
+[ 	]*[a-f0-9]+:	c3                   	ret    
+
+[0-9a-f]+ <_start>:
+[ 	]*[a-f0-9]+:	55                   	push   %ebp
+[ 	]*[a-f0-9]+:	89 e5                	mov    %esp,%ebp
+[ 	]*[a-f0-9]+:	56                   	push   %esi
+[ 	]*[a-f0-9]+:	53                   	push   %ebx
+[ 	]*[a-f0-9]+:	e8 00 00 00 00       	call   [0-9a-f]+ .*
+[ 	]*[a-f0-9]+:	5b                   	pop    %ebx
+[ 	]*[a-f0-9]+:	81 c3 ([0-9a-f]{2} ){4}[ 	]+add    \$0x[0-9a-f]+,%ebx
+[ 	]*[a-f0-9]+:	65 8b 35 f0 ff ff ff 	mov    %gs:0xfffffff0,%esi
+[ 	]*[a-f0-9]+:	65 03 35 ec ff ff ff 	add    %gs:0xffffffec,%esi
+[ 	]*[a-f0-9]+:	c7 c0 f4 ff ff ff    	mov    \$0xfffffff4,%eax
+[ 	]*[a-f0-9]+:	65 03 30             	add    %gs:\(%eax\),%esi
+[ 	]*[a-f0-9]+:	65 a1 00 00 00 00    	mov    %gs:0x0,%eax
+[ 	]*[a-f0-9]+:	8d b6 00 00 00 00    	lea    0x0\(%esi\),%esi
+[ 	]*[a-f0-9]+:	03 30                	add    \(%eax\),%esi
+[ 	]*[a-f0-9]+:	65 a1 00 00 00 00    	mov    %gs:0x0,%eax
+[ 	]*[a-f0-9]+:	81 e8 04 00 00 00    	sub    \$0x4,%eax
+[ 	]*[a-f0-9]+:	03 30                	add    \(%eax\),%esi
+[ 	]*[a-f0-9]+:	89 f0                	mov    %esi,%eax
+[ 	]*[a-f0-9]+:	5b                   	pop    %ebx
+[ 	]*[a-f0-9]+:	5e                   	pop    %esi
+[ 	]*[a-f0-9]+:	c9                   	leave  
+[ 	]*[a-f0-9]+:	c3                   	ret    
+#pass
-- 
2.5.5


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]