public inbox for binutils@sourceware.org
 help / color / mirror / Atom feed
* [PATCH] Support for Thread Local Storage Descriptors in ARM platform
@ 2006-08-15  1:48 Glauber de Oliveira Costa
  2006-08-15 11:48 ` Richard Earnshaw
  0 siblings, 1 reply; 3+ messages in thread
From: Glauber de Oliveira Costa @ 2006-08-15  1:48 UTC (permalink / raw)
  To: binutils, Richard Earnshaw, Alexandre Oliva, aldenor

[-- Attachment #1: Type: text/plain, Size: 894 bytes --]

Hello All,

Troughout the last months, Alexandre Oliva and I developed an ABI
extension to allow ARM binaries to benefit from his newly devised TLS
Descriptor method for accessing TLS variables
(http://www.lsd.ic.unicamp.br/~aoliva/writeups/TLS/paper-gcc2006.pdf).
Our proposed ABI can be found at
http://www.lsd.ic.unicamp.br/~aoliva/writeups/TLS/RFC-TLSDESC-ARM.txt
,  and a paper describing the ARM implementation, to be presented at
Linux Kongress in the first week of September at
http://www.lsd.ic.unicamp.br/~oliva/writeups/TLS/paper-lk2006.pdf. We
there describes some results we've got, that indicates a speedup of
more than 2 times for the most common case.

Attached to this message, follows the GNU linker and assembler part of
the work. Please, feel free to send me feedbacks on the
implementation, and consider it for merging.

-- 
"Free as in Freedom"
Glauber de Oliveira Costa.

[-- Attachment #2: patch-binutils-final --]
[-- Type: application/octet-stream, Size: 62963 bytes --]

Index: bfd/ChangeLog
===================================================================
RCS file: /cvs/src/src/bfd/ChangeLog,v
retrieving revision 1.3588
diff -u -p -r1.3588 ChangeLog
--- bfd/ChangeLog	14 Aug 2006 12:19:20 -0000	1.3588
+++ bfd/ChangeLog	14 Aug 2006 21:16:39 -0000
@@ -1,3 +1,48 @@
+2006-08-14  Glauber de Oliveira Costa  <glommer@gmail.com>
+
+	* Added support for gnu extensions for TLS handling
+	* bfd-in2.h (BFD_RELOC_ARM_TLS_GOTDESC): Added new relocation.
+	(BFD_RELOC_ARM_TLS_CALL): Likewise.
+	(BFD_RELOC_ARM_TLS_DESCSEQ): Likewise.
+	(BFD_RELOC_ARM_TLS_DESC): Likewise.
+	* libbfd.h : Likewise.
+	* reloc.c : Likewise.
+	* elf32-arm.c: (elf32_arm_howto_table_1): Added howto for new relocations.
+	(elf32_arm_reloc_map): Added mappings for new relocations.
+	(tls_trampoline): Added.
+	(dl_tlsdesc_lazy_trampoline): Likewise.
+	(elf32_arm_obj_tdata): Added local_tlsdesc_gotent, which is accessed
+	trough ... 
+	(elf32_arm_local_tlsdesc_gotent): New macro added.
+	(GOT_TLS_DESC): New definition.
+	(GOT_TLS_GD_ANY_P): New macro, checks for one of GD TLS models.
+	(elf32_arm_link_hash_entry): Added tlsdesc_got.
+	(elf32_arm_compute_jump_table_size): New macro.
+	(elf32_arm_link_hash_table): Added next_tls_desc_index, 
+	num_tls_desc, dt_tlsdesc_plt, dt_tlsdesc_got , tls_trampoline and
+	sgotplt_jump_table_size.
+	(elf32_arm_link_hash_newfunc): New initializations.
+	(elf32_arm_link_hash_table_create): Likewise.
+	(elf32_arm_tls_transition): New function.  Checks relaxation
+	possibilites.
+	(elf32_arm_tls_relax): New function.  Performs steps necessaries for
+	relaxing a TLS code sequence.
+	(elf32_arm_final_link_relocate): Deploy dynamic relocation for the TLS
+	gnu extensions.  Generate R_ARM_TLS_DESC, adjust addend for
+	R_ARM_TLS_CALL, and fix addend for R_ARM_TLS_GOTDESC.
+	(IS_ARM_TLS_RELOC): Add new relocations to check.
+	(IS_ARM_TLS_GNU_RELOC): New check.
+	(elf32_arm_relocate_section): Try to relax the code sequence, and call
+	elf32_arm_final_link_relocate only if there is still work to be done.
+	(elf32_arm_check_relocs): Settle up needed steps for new relocations
+	placement and handling.
+	(allocate_dynrelocs): Find a place for R_ARM_TLS_DESC.
+	(elf32_arm_size_dynamic_sections): Likewise.  Also creates the lazy 
+	trampoline whenever needed. 
+	(elf32_arm_always_size_sections): Create entry for _TLS_MODULE_BASE_
+	(elf32_arm_finish_dynamic_symbol): Fill the contents of dynamic table
+	entries and sets up .plt entries for the trampolines.
+
 2006-08-14  Thiemo Seufer  <ths@mips.com>
 
 	* elfxx-mips.c (_bfd_mips_elf_symbol_processing,
Index: bfd/bfd-in2.h
===================================================================
RCS file: /cvs/src/src/bfd/bfd-in2.h,v
retrieving revision 1.397
diff -u -p -r1.397 bfd-in2.h
--- bfd/bfd-in2.h	19 Jul 2006 01:50:23 -0000	1.397
+++ bfd/bfd-in2.h	14 Aug 2006 21:16:55 -0000
@@ -2936,6 +2936,10 @@ pc-relative or some form of GOT-indirect
   BFD_RELOC_ARM_TLS_TPOFF32,
   BFD_RELOC_ARM_TLS_IE32,
   BFD_RELOC_ARM_TLS_LE32,
+  BFD_RELOC_ARM_TLS_GOTDESC,
+  BFD_RELOC_ARM_TLS_CALL,
+  BFD_RELOC_ARM_TLS_DESCSEQ,
+  BFD_RELOC_ARM_TLS_DESC,
 
 /* ARM group relocations.  */
   BFD_RELOC_ARM_ALU_PC_G0_NC,
Index: bfd/elf32-arm.c
===================================================================
RCS file: /cvs/src/src/bfd/elf32-arm.c,v
retrieving revision 1.83
diff -u -p -r1.83 elf32-arm.c
--- bfd/elf32-arm.c	23 Jun 2006 02:58:00 -0000	1.83
+++ bfd/elf32-arm.c	14 Aug 2006 21:17:52 -0000
@@ -1351,10 +1351,61 @@ static reloc_howto_type elf32_arm_howto_
 	 0x040f70ff,		/* dst_mask */
 	 FALSE),		/* pcrel_offset */
 
-  EMPTY_HOWTO (90),   /* unallocated */
-  EMPTY_HOWTO (91),
-  EMPTY_HOWTO (92),
-  EMPTY_HOWTO (93),
+  HOWTO (R_ARM_TLS_GOTDESC,	/* type */
+	 0,			/* rightshift */
+	 2,			/* size (0 = byte, 1 = short, 2 = long) */
+	 32,			/* bitsize */
+	 FALSE,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_bitfield,/* complain_on_overflow */
+	 NULL,			/* special_function */
+	 "R_ARM_TLS_GOTDESC",	/* name */
+	 TRUE,			/* partial_inplace */
+	 0xffffffff,		/* src_mask */
+	 0xffffffff,		/* dst_mask */
+	 FALSE),		/* pcrel_offset */
+
+  HOWTO (R_ARM_TLS_CALL,	/* type */
+	 0,			/* rightshift */
+	 2,			/* size (0 = byte, 1 = short, 2 = long) */
+	 24,			/* bitsize */
+	 FALSE,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_dont,/* complain_on_overflow */
+	 bfd_elf_generic_reloc,	/* special_function */
+	 "R_ARM_TLS_CALL",	/* name */
+	 FALSE,			/* partial_inplace */
+	 0x00ffffff,		/* src_mask */
+	 0x00ffffff,		/* dst_mask */
+	 FALSE),		/* pcrel_offset */
+
+  HOWTO (R_ARM_TLS_DESCSEQ,	/* type */
+	 0,			/* rightshift */
+	 2,			/* size (0 = byte, 1 = short, 2 = long) */
+	 0,			/* bitsize */
+	 FALSE,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_bitfield,/* complain_on_overflow */
+	 bfd_elf_generic_reloc,	/* special_function */
+	 "R_ARM_TLS_DESCSEQ",	/* name */
+	 FALSE,			/* partial_inplace */
+	 0x00000000,		/* src_mask */
+	 0x00000000,		/* dst_mask */
+	 FALSE),		/* pcrel_offset */
+
+  HOWTO (R_ARM_TLS_DESC,	/* type */
+	 0,			/* rightshift */
+	 2,			/* size (0 = byte, 1 = short, 2 = long) */
+	 32,			/* bitsize */
+	 FALSE,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_bitfield,/* complain_on_overflow */
+	 bfd_elf_generic_reloc,	/* special_function */
+	 "R_ARM_TLS_DESC",	/* name */
+	 FALSE,			/* partial_inplace */
+	 0xffffffff,		/* src_mask */
+	 0xffffffff,		/* dst_mask */
+	 FALSE),		/* pcrel_offset */
 
   HOWTO (R_ARM_PLT32_ABS,	/* type */
 	 0,			/* rightshift */
@@ -1728,6 +1779,10 @@ static const struct elf32_arm_reloc_map 
     {BFD_RELOC_ARM_PREL31,	     R_ARM_PREL31},
     {BFD_RELOC_ARM_TARGET2,	     R_ARM_TARGET2},
     {BFD_RELOC_ARM_PLT32,            R_ARM_PLT32},
+    {BFD_RELOC_ARM_TLS_GOTDESC,      R_ARM_TLS_GOTDESC},
+    {BFD_RELOC_ARM_TLS_CALL,         R_ARM_TLS_CALL},
+    {BFD_RELOC_ARM_TLS_DESCSEQ,      R_ARM_TLS_DESCSEQ},
+    {BFD_RELOC_ARM_TLS_DESC,         R_ARM_TLS_DESC},
     {BFD_RELOC_ARM_TLS_GD32,	     R_ARM_TLS_GD32},
     {BFD_RELOC_ARM_TLS_LDO32,	     R_ARM_TLS_LDO32},
     {BFD_RELOC_ARM_TLS_LDM32,	     R_ARM_TLS_LDM32},
@@ -1880,6 +1935,25 @@ typedef unsigned short int insn16;
    section.  */
 #define ELF_DYNAMIC_INTERPRETER     "/usr/lib/ld.so.1"
 
+static const unsigned long tls_trampoline [] =
+  {
+    0xe08e0000,		/* add r0, lr, r0 */
+    0xe5901004,		/* ldr r1, [r0,#4] */
+    0xe12fff11,		/* bx r1 */
+  };
+
+static const unsigned long dl_tlsdesc_lazy_trampoline [] =
+  {
+    0xe92d0004, /*       stmdb   sp!, {r2} */
+    0xe59f200c, /*       ldr     r2, [pc, #.Lt0 - . - 8] */
+    0xe59f100c, /*       ldr     r1, [pc, #.Lt1 - . - 8] */
+    0xe79f2002, /* .L0:  ldr     r2, [pc, r2]*/
+    0xe08f1001, /* .L1:  add     r1, pc, r1 */ 
+    0xe12fff12, /*       bx      r2 */
+    0x00000000, /* .Lt0: .word  _GLOBAL_OFFSET_TABLE_ - .L0 - 8 + 
+		   			dl_tlsdesc_lazy_resolver(GOT)   */
+    0x00000000, /* .Lt1: .word  _GLOBAL_OFFSET_TABLE_ - .L1 - 8 */ 
+  }; 
 #ifdef FOUR_WORD_PLT
 
 /* The first entry in a procedure linkage table looks like
@@ -2025,6 +2099,9 @@ struct elf32_arm_obj_tdata
   /* tls_type for each local got entry.  */
   char *local_got_tls_type;
 
+  /* GOTPLT entries for TLS descriptors.  */
+  bfd_vma *local_tlsdesc_gotent;
+
   aeabi_attribute known_eabi_attributes[NUM_KNOWN_ATTRIBUTES];
   aeabi_attribute_list *other_eabi_attributes;
 };
@@ -2035,6 +2112,9 @@ struct elf32_arm_obj_tdata
 #define elf32_arm_local_got_tls_type(abfd) \
   (elf32_arm_tdata (abfd)->local_got_tls_type)
 
+#define elf32_arm_local_tlsdesc_gotent(abfd) \
+  (elf32_arm_tdata (abfd)->local_tlsdesc_gotent)
+
 static bfd_boolean
 elf32_arm_mkobject (bfd *abfd)
 {
@@ -2091,7 +2171,14 @@ struct elf32_arm_link_hash_entry
 #define GOT_NORMAL	1
 #define GOT_TLS_GD	2
 #define GOT_TLS_IE	4
+#define GOT_TLS_GDESC	8
+#define GOT_TLS_GD_ANY_P(type)						\
+  ((type & GOT_TLS_GD) || (type & GOT_TLS_GDESC))
     unsigned char tls_type;
+
+  /* Offset of the GOTPLT entry reserved for the TLS descriptor,
+     starting at the end of the jump table.  */
+  bfd_vma tlsdesc_got;
   };
 
 /* Traverse an arm ELF linker hash table.  */
@@ -2105,6 +2192,9 @@ struct elf32_arm_link_hash_entry
 #define elf32_arm_hash_table(info) \
   ((struct elf32_arm_link_hash_table *) ((info)->hash))
 
+#define elf32_arm_compute_jump_table_size(htab) \
+  ((htab)->next_tls_desc_index * 4)
+
 /* ARM ELF linker hash table.  */
 struct elf32_arm_link_hash_table
   {
@@ -2151,6 +2241,12 @@ struct elf32_arm_link_hash_table
     /* True if the target uses REL relocations.  */
     int use_rel;
 
+    /* The index of the next unused R_ARM_TLS_DESC slot in .rel.plt.  */
+    bfd_vma next_tls_desc_index;
+
+    /* How many R_ARM_TLS_DESC relocations were generated so far */
+    bfd_vma num_tls_desc;
+      
     /* Short-cuts to get to dynamic linker sections.  */
     asection *sgot;
     asection *sgotplt;
@@ -2163,6 +2259,19 @@ struct elf32_arm_link_hash_table
     /* The (unloaded but important) VxWorks .rela.plt.unloaded section.  */
     asection *srelplt2;
 
+   /* The offset into splt of the PLT entry for the TLS descriptor
+    * resolver.  Special values are 0, if not necessary (or not found
+    * to be necessary yet), and -1 if needed but not determined
+    * yet.  */
+    bfd_vma dt_tlsdesc_plt;
+
+   /* The offset into sgot of the GOT entry used by the PLT entry
+    * above.  */
+    bfd_vma dt_tlsdesc_got;    
+
+    /* Offset in .plt section of tls_trampoline */
+    bfd_vma tls_trampoline;
+    
     /* Data for R_ARM_TLS_LDM32 relocations.  */
     union {
       bfd_signed_vma refcount;
@@ -2174,6 +2283,10 @@ struct elf32_arm_link_hash_table
 
     /* For convenience in allocate_dynrelocs.  */
     bfd * obfd;
+    
+    /* The amount of space used by the reserved portion of the sgotplt
+     * section, plus whatever space is used by the jump slots.  */
+    bfd_vma sgotplt_jump_table_size;
   };
 
 /* Create an entry in an ARM ELF linker hash table.  */
@@ -2201,6 +2314,7 @@ elf32_arm_link_hash_newfunc (struct bfd_
     {
       ret->relocs_copied = NULL;
       ret->tls_type = GOT_UNKNOWN;
+      ret->tlsdesc_got = (bfd_vma) -1;
       ret->plt_thumb_refcount = 0;
       ret->plt_got_offset = -1;
     }
@@ -2393,6 +2507,11 @@ elf32_arm_link_hash_table_create (bfd *a
   ret->sdynbss = NULL;
   ret->srelbss = NULL;
   ret->srelplt2 = NULL;
+  ret->dt_tlsdesc_plt = 0;
+  ret->dt_tlsdesc_got = 0;
+  ret->tls_trampoline = 0;
+  ret->next_tls_desc_index = 0;
+  ret->num_tls_desc = 0;
   ret->thumb_glue_size = 0;
   ret->arm_glue_size = 0;
   ret->bfd_of_glue_owner = NULL;
@@ -3323,6 +3442,31 @@ arm_real_reloc_type (struct elf32_arm_li
       return r_type;
     }
 }
+/* Checks wether it's possible to change to a more efficient access 
+ * model, given the information we have about the current link */
+static int
+elf32_arm_tls_transition (struct bfd_link_info *info, int r_type, 
+			  struct elf_link_hash_entry *h)
+{
+  int is_local = (h == NULL);
+
+  if ((h && (h->root.type == bfd_link_hash_undefweak))
+		  || info->shared)
+    return r_type;
+
+  /* We do not support relaxations for Old TLS models */ 
+  switch (r_type)
+    {
+    case R_ARM_TLS_GOTDESC:
+    case R_ARM_TLS_CALL:
+    case R_ARM_TLS_DESCSEQ:
+      if (is_local)
+	return R_ARM_TLS_LE32;
+      return R_ARM_TLS_IE32;
+    }
+
+  return r_type;
+}
 
 /* Return the base VMA address which should be subtracted from real addresses
    when resolving @dtpoff relocation.
@@ -3367,6 +3511,111 @@ elf32_arm_abs12_reloc (bfd *abfd, void *
   return bfd_reloc_ok;
 }
 
+/* Function that handles TLS relaxations. Relaxing is possible for symbols
+ * that uses R_ARM_GOTDESC, R_ARM_TLS_CALL and R_ARM_TLS_DESCSEQ relocations,
+ * during a static link. 
+ *
+ * The status parameter receives TRUE if no more work needs to be done or 
+ * an error happened and FALSE if after exiting it's still desirable to call 
+ * final_link_relocate. */
+static bfd_reloc_status_type 
+elf32_arm_tls_relax (	bfd_byte *		contents,
+			bfd *			input_bfd, 
+			Elf_Internal_Rela *	rel,
+			unsigned long		is_local,
+			bfd_boolean *		status) 
+
+  {  
+    unsigned long insn;
+    unsigned long op;
+
+    *status = TRUE;
+    switch (ELF32_R_TYPE (rel->r_info))
+      {
+	case R_ARM_TLS_GOTDESC:
+	  /* No addend adjustments for local exec relaxation */
+	  if (!is_local)
+	    {
+	      insn = bfd_get_32 (input_bfd, contents + rel->r_offset);
+
+	      BFD_ASSERT (insn - 8 < insn);
+
+	      bfd_put_32 (input_bfd, insn - 8,contents + rel->r_offset);
+	    }
+	  *status = FALSE;
+	  break;
+	case R_ARM_TLS_DESCSEQ:
+	  if (is_local)
+	    {
+	       insn = bfd_get_32 (input_bfd, contents + rel->r_offset);
+	       op = insn >> (32 - 8);
+	       switch (op)
+	         {
+	         case 0xe0: /* add */
+		   /* mov rx,rt */
+	           bfd_put_32 (input_bfd, 0xe1a00000 | (0x0000ffff & insn), 
+				   contents + rel->r_offset);
+		   break;
+	         case 0xe1: /* blx */
+	         case 0xe5: /* ldr */
+		   /* mov r0,r0 */
+	           bfd_put_32 (input_bfd, 0xe1a00000, contents + rel->r_offset);
+		   break;
+		 default:
+		   (*_bfd_error_handler)
+			   (_("Unexpected instruction in TLS trampoline '0x%x'."),
+				      insn);
+		   return bfd_reloc_notsupported;
+	         }
+
+	    }
+	  else
+	    {
+	       insn = bfd_get_32 (input_bfd, contents + rel->r_offset);
+	       op = insn >> (32 - 8);
+	       switch (op)
+	         {
+		 case 0xe0: /* add */
+		   /* keep it */
+		   break;
+	         case 0xe5: /* ldr */
+		   /* get rid of #4, in case it's there */
+		   BFD_ASSERT ((insn & 0xff) == 0x4);
+	           bfd_put_32 (input_bfd, (insn & 0xffffff00), contents + 
+						               rel->r_offset);
+		   break;
+	         case 0xe1: /* blx */
+	           /* mov */
+		   insn &= 0xf;
+		   insn |= 0xe1a00000;
+	           bfd_put_32 (input_bfd, insn, contents + rel->r_offset);
+		   break;
+		 default:
+		   (*_bfd_error_handler)
+			   (_("Unexpected instruction in TLS trampoline '0x%x'."),
+			    insn);
+		   return bfd_reloc_notsupported;
+	         } 
+	    }
+	  break;
+	case R_ARM_TLS_CALL:
+	    if (is_local)
+	      {
+		/* mov r0,r0 */
+	        bfd_put_32 (input_bfd, 0xe1a00000, contents + rel->r_offset);
+	      }
+	    else
+	      {
+	        /* GD->IE relaxation 
+	         * turn the instruction into a ldr one 
+	         * ldr r0, [pc,r0]  */
+	        bfd_put_32 (input_bfd, 0xe79f0000, contents + rel->r_offset);
+	      }
+	    break;
+      }
+    return bfd_reloc_ok;
+  }
+
 /* For a given value of n, calculate the value of G_n as required to
    deal with group relocations.  We return it in the form of an
    encoded constant-and-rotation, together with the final residual.  If n is
@@ -3459,6 +3708,7 @@ elf32_arm_final_link_relocate (reloc_how
   Elf_Internal_Shdr *           symtab_hdr;
   struct elf_link_hash_entry ** sym_hashes;
   bfd_vma *                     local_got_offsets;
+  bfd_vma *                     local_tlsdesc_gotents;
   asection *                    sgot = NULL;
   asection *                    splt = NULL;
   asection *                    sreloc = NULL;
@@ -3471,6 +3721,11 @@ elf32_arm_final_link_relocate (reloc_how
   /* Some relocation type map to different relocations depending on the
      target.  We pick the right one here.  */
   r_type = arm_real_reloc_type (globals, r_type);
+
+  /* Besides that, it is possible to have linker relaxations on some 
+   * TLS acces models. Update our information here */
+  r_type = elf32_arm_tls_transition (info, r_type, h);
+
   if (r_type != howto->type)
     howto = elf32_arm_howto_from_type (r_type);
 
@@ -3495,6 +3750,8 @@ elf32_arm_final_link_relocate (reloc_how
   symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr;
   sym_hashes = elf_sym_hashes (input_bfd);
   local_got_offsets = elf_local_got_offsets (input_bfd);
+  local_tlsdesc_gotents = elf32_arm_local_tlsdesc_gotent (input_bfd);
+
   r_symndx = ELF32_R_SYM (rel->r_info);
 
   if (globals->use_rel)
@@ -4398,10 +4655,13 @@ elf32_arm_final_link_relocate (reloc_how
 					 rel->r_addend);
       }
 
+    case R_ARM_TLS_CALL:
     case R_ARM_TLS_GD32:
     case R_ARM_TLS_IE32:
+    case R_ARM_TLS_GOTDESC:
+    case R_ARM_TLS_DESCSEQ:
       {
-	bfd_vma off;
+	bfd_vma off,offplt;
 	int indx;
 	char tls_type;
 
@@ -4421,6 +4681,7 @@ elf32_arm_final_link_relocate (reloc_how
 		indx = h->dynindx;
 	      }
 	    off = h->got.offset;
+	    offplt = elf32_arm_hash_entry (h)->tlsdesc_got;
 	    tls_type = ((struct elf32_arm_link_hash_entry *) h)->tls_type;
 	  }
 	else
@@ -4428,9 +4689,16 @@ elf32_arm_final_link_relocate (reloc_how
 	    if (local_got_offsets == NULL)
 	      abort ();
 	    off = local_got_offsets[r_symndx];
+	    offplt = local_tlsdesc_gotents[r_symndx];
 	    tls_type = elf32_arm_local_got_tls_type (input_bfd)[r_symndx];
 	  }
 
+	/* linker relaxations happens from one of the 
+	 * R_ARM_{GOTDESC,CALL,DESCSEQ} relocations to IE or LE */ 
+	if (ELF32_R_TYPE(rel->r_info) != r_type){
+		tls_type = GOT_TLS_IE; 
+	}
+
 	if (tls_type == GOT_UNKNOWN)
 	  abort ();
 
@@ -4455,10 +4723,57 @@ elf32_arm_final_link_relocate (reloc_how
 		need_relocs = TRUE;
 		if (globals->srelgot == NULL)
 		  abort ();
-		loc = globals->srelgot->contents;
-		loc += globals->srelgot->reloc_count * RELOC_SIZE (globals);
 	      }
 
+	    if (tls_type & GOT_TLS_GDESC)
+	      {
+		/* We should have relaxed, unless we're talking about an
+		 * undefined weak symbol */
+		BFD_ASSERT (info->shared || 
+			(h && (h->root.type == bfd_link_hash_undefweak)));
+
+		bfd_vma param;
+		    
+		BFD_ASSERT (globals->sgotplt_jump_table_size + offplt + 8
+                            <= globals->sgotplt->size);
+
+		outrel.r_addend = 0;
+		outrel.r_offset = ( globals->sgotplt->output_section->vma
+				    + globals->sgotplt->output_offset
+				    + offplt
+				    + globals->sgotplt_jump_table_size);
+		
+		outrel.r_info = ELF32_R_INFO (indx, R_ARM_TLS_DESC);
+		sreloc = globals->srelplt;
+		loc = sreloc->contents;
+		loc += (globals->next_tls_desc_index++ 
+			* RELOC_SIZE(globals)) ;
+		BFD_ASSERT(loc + RELOC_SIZE (globals)
+		   	   <= sreloc->contents + sreloc->size);
+
+
+		SWAP_RELOC_OUT(globals) (output_bfd,&outrel,loc);
+
+		/* With lazy relocations on, there's still work to do, 
+		 * and we store the relocation index in the first 
+		 * parameter, to allow it to be done. Otherwise, store 0 */
+		if ((info->flags & DF_BIND_NOW)) 
+		  param = 0;
+	 	else
+		  param = ELF32_R_SYM (outrel.r_info);
+
+		/* First word in the relocation gets the relocation index, 
+		 * or zero, if we're not allowing lazy relocs */
+	    	bfd_put_32 (output_bfd, param,
+			    globals->sgotplt->contents + offplt +
+			    globals->sgotplt_jump_table_size);
+
+		/* Second word in the relocation is always zero */
+	    	bfd_put_32 (output_bfd, 0,
+			    globals->sgotplt->contents + offplt +
+			    globals->sgotplt_jump_table_size + 4);
+
+	      }
 	    if (tls_type & GOT_TLS_GD)
 	      {
 		if (need_relocs)
@@ -4472,10 +4787,10 @@ elf32_arm_final_link_relocate (reloc_how
 		    if (globals->use_rel)
 		      bfd_put_32 (output_bfd, outrel.r_addend,
 				  globals->sgot->contents + cur_off);
+		    loc = globals->srelgot->contents;
+		    loc += (globals->srelgot->reloc_count++ * RELOC_SIZE (globals));
 
 		    SWAP_RELOC_OUT (globals) (output_bfd, &outrel, loc);
-		    globals->srelgot->reloc_count++;
-		    loc += RELOC_SIZE (globals);
 
 		    if (indx == 0)
 		      bfd_put_32 (output_bfd, value - dtpoff_base (info),
@@ -4491,10 +4806,10 @@ elf32_arm_final_link_relocate (reloc_how
 			  bfd_put_32 (output_bfd, outrel.r_addend,
 				      globals->sgot->contents + cur_off + 4);
 
+		    	loc = globals->srelgot->contents;
+		   	loc += (globals->srelgot->reloc_count++ * RELOC_SIZE (globals));
 
 			SWAP_RELOC_OUT (globals) (output_bfd, &outrel, loc);
-			globals->srelgot->reloc_count++;
-			loc += RELOC_SIZE (globals);
 		      }
 		  }
 		else
@@ -4530,9 +4845,10 @@ elf32_arm_final_link_relocate (reloc_how
 		      bfd_put_32 (output_bfd, outrel.r_addend,
 				  globals->sgot->contents + cur_off);
 
+		    loc = globals->srelgot->contents;
+		    loc += (globals->srelgot->reloc_count++ * RELOC_SIZE (globals));
+
 		    SWAP_RELOC_OUT (globals) (output_bfd, &outrel, loc);
-		    globals->srelgot->reloc_count++;
-		    loc += RELOC_SIZE (globals);
 		  }
 		else
 		  bfd_put_32 (output_bfd, tpoff (info, value),
@@ -4548,9 +4864,63 @@ elf32_arm_final_link_relocate (reloc_how
 
 	if ((tls_type & GOT_TLS_GD) && r_type != R_ARM_TLS_GD32)
 	  off += 8;
-	value = globals->sgot->output_section->vma + globals->sgot->output_offset + off 
-	  - (input_section->output_section->vma + input_section->output_offset + rel->r_offset);
+	else if (tls_type & GOT_TLS_GDESC )
+	  off = offplt;
 
+	if (ELF32_R_TYPE(rel->r_info) == R_ARM_TLS_CALL)
+	  {
+            long inst;
+
+            inst = (globals->splt->output_section->vma + 
+		   globals->splt->output_offset + globals->tls_trampoline) -
+                   (input_section->output_section->vma + 
+		    input_section->output_offset + rel->r_offset) - 8;
+
+
+	    /* Make sure we're not throwing any useful data away */ 
+            BFD_ASSERT ((inst & 3) == 0);
+            inst >>= 2;
+	    /* The offset have to fit in a howto->bitsize sized field. Otherwise, we  
+	     * may be computing a branch to the wrong place. We then refuse t
+	     * relocate */	
+            BFD_ASSERT (inst < (1 <<  howto->bitsize));
+            BFD_ASSERT (inst > -(1 <<  howto->bitsize));
+
+            inst &= ((1 << howto->bitsize) - 1);
+            inst |= 0xeb000000; /* branch & link */
+
+            value = inst;
+        }    
+	/* These relocations needs special care, as besides the fact they 
+	 * point somewhere in .gotplt, the addend must be adjusted accordingly
+	 * depending on the type of instruction we refer to */
+	else if ((r_type == R_ARM_TLS_GOTDESC) && (tls_type & GOT_TLS_GDESC))
+	  { 
+	    unsigned long data,insn;
+	    data = bfd_get_32 (input_bfd, hit_data);
+	    insn = bfd_get_32 (input_bfd, contents + rel->r_offset - data);
+	    insn >>= 32 - 8;
+
+	    if (insn == 0xeb) /* branch */
+	      value = -4;
+	    else /* add */
+	      {
+	        BFD_ASSERT (insn == 0xe0);
+	        value = -8;
+	      } 
+ 
+	    value += globals->sgotplt->output_section->vma + 
+		     globals->sgotplt->output_offset + off - 
+		     (input_section->output_section->vma + 
+		      input_section->output_offset + 
+		      rel->r_offset) + 
+		     globals->sgotplt_jump_table_size;
+        }
+
+	else
+	  value = globals->sgot->output_section->vma + globals->sgot->output_offset + off 
+	  	- (input_section->output_section->vma + input_section->output_offset + 
+		  rel->r_offset);
 	return _bfd_final_link_relocate (howto, input_bfd, input_section,
 					 contents, rel->r_offset, value,
 					 rel->r_addend);
@@ -4567,7 +4937,7 @@ elf32_arm_final_link_relocate (reloc_how
 	}
       else
 	value = tpoff (info, value);
-      
+
       return _bfd_final_link_relocate (howto, input_bfd, input_section,
 				       contents, rel->r_offset, value,
 				       rel->r_addend);
@@ -5323,8 +5693,17 @@ arm_add_to_rel (bfd *              abfd,
    || (R_TYPE) == R_ARM_TLS_DTPMOD32	\
    || (R_TYPE) == R_ARM_TLS_TPOFF32	\
    || (R_TYPE) == R_ARM_TLS_LE32	\
+   || (R_TYPE) == R_ARM_TLS_GOTDESC	\
+   || (R_TYPE) == R_ARM_TLS_CALL	\
+   || (R_TYPE) == R_ARM_TLS_DESCSEQ	\
    || (R_TYPE) == R_ARM_TLS_IE32)
 
+/* Specific set of relocations for the gnu tls dialect */
+#define IS_ARM_TLS_GNU_RELOC(R_TYPE)	\
+  ((R_TYPE) == R_ARM_TLS_GOTDESC	\
+   || (R_TYPE) == R_ARM_TLS_CALL	\
+   || (R_TYPE) == R_ARM_TLS_DESCSEQ)
+
 /* Relocate an ARM ELF section.  */
 static bfd_boolean
 elf32_arm_relocate_section (bfd *                  output_bfd,
@@ -5365,6 +5744,8 @@ elf32_arm_relocate_section (bfd *       
       arelent                      bfd_reloc;
       char                         sym_type;
       bfd_boolean                  unresolved_reloc = FALSE;
+      bfd_boolean                  tls_relaxed = FALSE;		
+      int			   tls_type = 0;
 
       r_symndx = ELF32_R_SYM (rel->r_info);
       r_type   = ELF32_R_TYPE (rel->r_info);
@@ -5466,7 +5847,10 @@ elf32_arm_relocate_section (bfd *       
 	}
 
       if (h != NULL)
-	name = h->root.root.string;
+        {
+	  name = h->root.root.string;
+	  tls_type = elf32_arm_hash_entry (h)->tls_type;
+        }
       else
 	{
 	  name = (bfd_elf_string_from_elf_section
@@ -5493,14 +5877,24 @@ elf32_arm_relocate_section (bfd *       
 	     name);
 	}
 
-      r = elf32_arm_final_link_relocate (howto, input_bfd, output_bfd,
-					 input_section, contents, rel,
-					 relocation, info, sec, name,
-					 (h ? ELF_ST_TYPE (h->type) :
-					  ELF_ST_TYPE (sym->st_info)), h,
-					 &unresolved_reloc);
-
-      /* Dynamic relocs are not propagated for SEC_DEBUGGING sections
+      /* We call elf32_arm_final_link_relocate unless we're completely
+       * done, i.e., the relaxation produced the final output we want, 
+       * and we won't let anybody mess with it. Also, we have to do 
+       * addend adjustments in case of a R_ARM_TLS_GOTDESC relocation
+       * both in relaxed and non-relaxed cases */
+     if ((elf32_arm_tls_transition (info, r_type, h) != r_type) ||
+	  (IS_ARM_TLS_GNU_RELOC (r_type) &&  !(tls_type & GOT_TLS_GDESC)))
+       r = elf32_arm_tls_relax (contents, input_bfd, rel, h == NULL,
+							&tls_relaxed);
+     
+      if (tls_relaxed == FALSE)
+        r = elf32_arm_final_link_relocate (howto, input_bfd, output_bfd,
+					   input_section, contents, rel,
+					   relocation, info, sec, name,
+					   (h ? ELF_ST_TYPE (h->type) :
+					    ELF_ST_TYPE (sym->st_info)), h,
+					   &unresolved_reloc);
+       /* Dynamic relocs are not propagated for SEC_DEBUGGING sections
 	 because such sections are not SEC_ALLOC and thus ld.so will
 	 not process them.  */
       if (unresolved_reloc
@@ -6744,12 +7138,17 @@ elf32_arm_check_relocs (bfd *abfd, struc
 
       eh = (struct elf32_arm_link_hash_entry *) h;
 
+      /* Could be done earlier, if h were already available */
+      r_type = elf32_arm_tls_transition(info, r_type, h);
       switch (r_type)
         {
 	  case R_ARM_GOT32:
 	  case R_ARM_GOT_PREL:
 	  case R_ARM_TLS_GD32:
 	  case R_ARM_TLS_IE32:
+	  case R_ARM_TLS_GOTDESC:
+	  case R_ARM_TLS_DESCSEQ:
+	  case R_ARM_TLS_CALL:
 	    /* This symbol requires a global offset table entry.  */
 	    {
 	      int tls_type, old_tls_type;
@@ -6758,6 +7157,10 @@ elf32_arm_check_relocs (bfd *abfd, struc
 		{
 		case R_ARM_TLS_GD32: tls_type = GOT_TLS_GD; break;
 		case R_ARM_TLS_IE32: tls_type = GOT_TLS_IE; break;
+		case R_ARM_TLS_GOTDESC:
+		case R_ARM_TLS_CALL:
+		case R_ARM_TLS_DESCSEQ:
+		  tls_type = GOT_TLS_GDESC; break;	
 		default: tls_type = GOT_NORMAL; break;
 		}
 
@@ -6777,25 +7180,38 @@ elf32_arm_check_relocs (bfd *abfd, struc
 		      bfd_size_type size;
 		      
 		      size = symtab_hdr->sh_info;
-		      size *= (sizeof (bfd_signed_vma) + sizeof(char));
+		      size *= (sizeof (bfd_signed_vma) + 
+				sizeof (bfd_vma) + sizeof (char));
 		      local_got_refcounts = bfd_zalloc (abfd, size);
 		      if (local_got_refcounts == NULL)
 			return FALSE;
 		      elf_local_got_refcounts (abfd) = local_got_refcounts;
+		      elf32_arm_local_tlsdesc_gotent (abfd)
+		        = (bfd_vma *) (local_got_refcounts + symtab_hdr->sh_info);
 		      elf32_arm_local_got_tls_type (abfd)
-			= (char *) (local_got_refcounts + symtab_hdr->sh_info);
+			= (char *) (local_got_refcounts + 2 * symtab_hdr->sh_info);
 		    }
 		  local_got_refcounts[r_symndx] += 1;
 		  old_tls_type = elf32_arm_local_got_tls_type (abfd) [r_symndx];
 		}
 
+	      /* If a variable is accessed in both tld methods,
+	       * two slots may be created */
+	      if (GOT_TLS_GD_ANY_P (old_tls_type) && GOT_TLS_GD_ANY_P (tls_type))
+		tls_type |= old_tls_type;
+
 	      /* We will already have issued an error message if there is a
-		 TLS / non-TLS mismatch, based on the symbol type.  We don't
-		 support any linker relaxations.  So just combine any TLS
-		 types needed.  */
+		 TLS / non-TLS mismatch, based on the symbol type. So just 
+		 combine any TLS types needed. */
 	      if (old_tls_type != GOT_UNKNOWN && old_tls_type != GOT_NORMAL
 		  && tls_type != GOT_NORMAL)
 		tls_type |= old_tls_type;
+	        
+	      /* If the symbol is accessed in both IE and GDESC method, we're
+	       * able to relax. Turn off the GDESC flag, without messing up with
+	       * any other kind of tls types that may be involved */
+	      if ((tls_type & GOT_TLS_IE) && (tls_type & GOT_TLS_GDESC))
+		      tls_type &= ~GOT_TLS_GDESC;
 
 	      if (old_tls_type != tls_type)
 		{
@@ -7361,12 +7777,13 @@ allocate_dynrelocs (struct elf_link_hash
 	    {
 	      /* We also need to make an entry in the .got.plt section, which
 		 will be placed in the .got section by the linker script.  */
-	      eh->plt_got_offset = htab->sgotplt->size;
+	      eh->plt_got_offset = htab->sgotplt->size - 8* htab->num_tls_desc;
 	      htab->sgotplt->size += 4;
 	    }
 
 	  /* We also need to make an entry in the .rel(a).plt section.  */
 	  htab->srelplt->size += RELOC_SIZE (htab);
+	  htab->next_tls_desc_index++;
 
 	  /* VxWorks executables have a second set of relocations for
 	     each PLT entry.  They go in a separate relocation section,
@@ -7396,6 +7813,9 @@ allocate_dynrelocs (struct elf_link_hash
       h->needs_plt = 0;
     }
 
+  eh = (struct elf32_arm_link_hash_entry *) h;
+  eh->tlsdesc_got = (bfd_vma) -1;
+
   if (h->got.refcount > 0)
     {
       asection *s;
@@ -7425,8 +7845,21 @@ allocate_dynrelocs (struct elf_link_hash
 	    s->size += 4;
 	  else
 	    {
+              if (tls_type & GOT_TLS_GDESC)
+	        {
+		  /* R_ARM_TLS_DESC needs 2 GOT slots.  */
+	          eh->tlsdesc_got = htab->sgotplt->size
+	          - elf32_arm_compute_jump_table_size (htab);
+	          htab->sgotplt->size += 8;
+	          h->got.offset = (bfd_vma) -2;
+		  /* plt_got_offset needs to know there's a TLS_DESC reloc
+		   * in the middle of .got.plt */
+                  htab->num_tls_desc++;
+	        }
 	      if (tls_type & GOT_TLS_GD)
-		/* R_ARM_TLS_GD32 needs 2 consecutive GOT slots.  */
+	  	/* R_ARM_TLS_GD32 needs 2 consecutive GOT slots.  
+	         * If the symbol is both GD and GDESC, got.offset may have
+		 * been overwritten */
 		s->size += 8;
 	      if (tls_type & GOT_TLS_IE)
 		/* R_ARM_TLS_IE32 needs one GOT slot.  */
@@ -7452,8 +7885,26 @@ allocate_dynrelocs (struct elf_link_hash
 	      if (tls_type & GOT_TLS_GD)
 		htab->srelgot->size += RELOC_SIZE (htab);
 
-	      if ((tls_type & GOT_TLS_GD) && indx != 0)
-		htab->srelgot->size += RELOC_SIZE (htab);
+	      if (tls_type & GOT_TLS_GDESC) 
+		{
+	 	  htab->dt_tlsdesc_plt = (bfd_vma)-1;	
+		  htab->srelplt->size += RELOC_SIZE (htab); 
+		  /* GDESC needs a trampoline to jump to. Allocate it if not 
+		   * yet done */
+		  if (htab->tls_trampoline == 0)
+		    {
+		      if (htab->splt->size == 0)
+			htab->splt->size += htab->plt_header_size;
+
+		      htab->tls_trampoline  = htab->splt->size;
+		      htab->splt->size += htab->plt_entry_size;
+			
+		    }
+		}
+
+	      /* Only GD need it. GDESC just emits one relocation per 2 entries */
+	      if ((tls_type & GOT_TLS_GD) && indx != 0)  
+		htab->srelgot->size += RELOC_SIZE (htab); 
 	    }
 	  else if ((ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
 		    || h->root.type != bfd_link_hash_undefweak)
@@ -7635,6 +8086,7 @@ elf32_arm_size_dynamic_sections (bfd * o
       bfd_signed_vma *local_got;
       bfd_signed_vma *end_local_got;
       char *local_tls_type;
+      bfd_vma *local_tlsdesc_gotent;
       bfd_size_type locsymcount;
       Elf_Internal_Shdr *symtab_hdr;
       asection *srel;
@@ -7674,23 +8126,46 @@ elf32_arm_size_dynamic_sections (bfd * o
       locsymcount = symtab_hdr->sh_info;
       end_local_got = local_got + locsymcount;
       local_tls_type = elf32_arm_local_got_tls_type (ibfd);
+      local_tlsdesc_gotent = elf32_arm_local_tlsdesc_gotent (ibfd);
       s = htab->sgot;
       srel = htab->srelgot;
-      for (; local_got < end_local_got; ++local_got, ++local_tls_type)
+      for (; local_got < end_local_got; 
+	   ++local_got, ++local_tls_type, ++local_tlsdesc_gotent)
 	{
+	  *local_tlsdesc_gotent = (bfd_vma) -1;
 	  if (*local_got > 0)
 	    {
 	      *local_got = s->size;
 	      if (*local_tls_type & GOT_TLS_GD)
 		/* TLS_GD relocs need an 8-byte structure in the GOT.  */
 		s->size += 8;
+	      if (*local_tls_type & GOT_TLS_GDESC)
+		{
+		  *local_tlsdesc_gotent = htab->sgotplt->size
+		    - elf32_arm_compute_jump_table_size (htab);
+		  htab->sgotplt->size += 8;
+		  *local_got = (bfd_vma) -2;
+
+		}
 	      if (*local_tls_type & GOT_TLS_IE)
 		s->size += 4;
-	      if (*local_tls_type == GOT_NORMAL)
-		s->size += 4;
 
-	      if (info->shared || *local_tls_type == GOT_TLS_GD)
-		srel->size += RELOC_SIZE (htab);
+	      if (*local_tls_type & GOT_NORMAL)
+		{
+		  /* If the symbol is both GD and GDESC, *local_got may have
+		   * been overwritten */
+		  *local_got = s->size;
+		  s->size += 4;
+		}
+
+	      if (info->shared)
+		{
+		  if (*local_tls_type & GOT_TLS_GD)
+		    srel->size += RELOC_SIZE (htab);
+
+		  if (*local_tls_type & GOT_TLS_GDESC)
+		    htab->srelplt->size += RELOC_SIZE (htab); 
+		}
 	    }
 	  else
 	    *local_got = (bfd_vma) -1;
@@ -7713,6 +8188,34 @@ elf32_arm_size_dynamic_sections (bfd * o
      sym dynamic relocs.  */
   elf_link_hash_traverse (& htab->root, allocate_dynrelocs, info);
 
+  /* For every jump slot reserved in the sgotplt, reloc_count is
+   * incremented.  However, when we reserve space for TLS descriptors,
+   * it's not incremented, so in order to compute the space reserved
+   * for them, it suffices to multiply the reloc count by the jump
+   * slot size.  */
+  if (htab->srelplt)
+    htab->sgotplt_jump_table_size = elf32_arm_compute_jump_table_size(htab);
+
+  if (htab->dt_tlsdesc_plt)
+    {
+      /* If we're not using lazy TLS relocations, don't generate the
+       * PLT and GOT entries they require.  */
+      if ((info->flags & DF_BIND_NOW))
+	htab->dt_tlsdesc_plt = 0;	
+      else
+	{
+	  htab->dt_tlsdesc_got = htab->sgot->size;
+	  htab->sgot->size += 4;
+
+	  /* FIXME: If it does not break anything, we could probably just not
+	   * emit the DT_TLSDESC_{PLT,GOT} entries. Not sure :-(*/
+	  if (htab->splt->size == 0)
+	    htab->splt->size += htab->plt_header_size;
+	  htab->dt_tlsdesc_plt = htab->splt->size;
+	  htab->splt->size += 4 * ARRAY_SIZE (dl_tlsdesc_lazy_trampoline);
+	}
+    }
+	       
   /* The check_relocs and adjust_dynamic_symbol entry points have
      determined the sizes of the various dynamic sections.  Allocate
      memory for them.  */
@@ -7803,6 +8306,11 @@ elf32_arm_size_dynamic_sections (bfd * o
 				     htab->use_rel ? DT_REL : DT_RELA)
 	      || !add_dynamic_entry (DT_JMPREL, 0))
 	    return FALSE;
+
+	  if (htab->dt_tlsdesc_plt &&
+		(!add_dynamic_entry(DT_TLSDESC_PLT,0) 
+		 || !add_dynamic_entry(DT_TLSDESC_GOT,0)))
+	    return FALSE; 
 	}
 
       if (relocs)
@@ -7840,6 +8348,44 @@ elf32_arm_size_dynamic_sections (bfd * o
   return TRUE;
 }
 
+/* Size sections even tough they're not dynamic. We use it to setup
+ * _TLS_MODULE_BASE_ if needed */
+static bfd_boolean
+elf32_arm_always_size_sections (bfd *output_bfd,
+	                        struct bfd_link_info *info)
+{
+  asection *tls_sec = elf_hash_table (info)->tls_sec;
+
+  if (tls_sec)
+    {
+      struct elf_link_hash_entry *tlsbase;
+
+      tlsbase = elf_link_hash_lookup (elf_hash_table (info),
+                                       "_TLS_MODULE_BASE_",
+                                        TRUE, TRUE, FALSE);
+
+      if (tlsbase)
+        {
+          struct bfd_link_hash_entry *bh = NULL;
+           const struct elf_backend_data *bed
+            = get_elf_backend_data (output_bfd);
+
+          if (!(_bfd_generic_link_add_one_symbol
+               (info, output_bfd, "_TLS_MODULE_BASE_", BSF_LOCAL,
+	        tls_sec, 0, NULL, FALSE,
+                bed->collect, &bh)))
+	          return FALSE;
+
+      	  tlsbase->type = STT_TLS;
+          tlsbase = (struct elf_link_hash_entry *)bh;
+          tlsbase->def_regular = 1;
+          tlsbase->other = STV_HIDDEN;
+          (*bed->elf_backend_hide_symbol) (info, tlsbase, TRUE);
+       }
+     }
+     return TRUE;
+}
+
 /* Finish up dynamic symbol handling.  We set the contents of various
    dynamic sections here.  */
 
@@ -8048,7 +8594,7 @@ elf32_arm_finish_dynamic_symbol (bfd * o
     }
 
   if (h->got.offset != (bfd_vma) -1
-      && (elf32_arm_hash_entry (h)->tls_type & GOT_TLS_GD) == 0
+      && (! GOT_TLS_GD_ANY_P (elf32_arm_hash_entry (h)->tls_type)) 
       && (elf32_arm_hash_entry (h)->tls_type & GOT_TLS_IE) == 0)
     {
       asection * sgot;
@@ -8279,6 +8825,20 @@ elf32_arm_finish_dynamic_sections (bfd *
 		}
 	      break;
 
+	    case DT_TLSDESC_PLT:
+              s = htab->splt;
+	      dyn.d_un.d_ptr = s->output_section->vma + s->output_offset +
+		      		htab->dt_tlsdesc_plt;
+	      bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon);
+	      break;
+
+	    case DT_TLSDESC_GOT:
+              s = htab->sgot;
+	      dyn.d_un.d_ptr = s->output_section->vma + s->output_offset +
+		      		htab->dt_tlsdesc_got;
+	      bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon);
+	      break;
+
 	      /* Set the bottom bit of DT_INIT/FINI if the
 		 corresponding function is Thumb.  */
 	    case DT_INIT:
@@ -8366,7 +8926,54 @@ elf32_arm_finish_dynamic_sections (bfd *
       /* UnixWare sets the entsize of .plt to 4, although that doesn't
 	 really seem like the right value.  */
       elf_section_data (splt->output_section)->this_hdr.sh_entsize = 4;
+      
+      if (htab->dt_tlsdesc_plt)
+	{
+	  bfd_vma got_address,gotplt_address, plt_address;
 
+	  got_address = sgot->output_section->vma + 
+		  			sgot->output_offset;
+	  gotplt_address = htab->sgot->output_section->vma + 
+		  			htab->sgot->output_offset;
+	  plt_address = splt->output_section->vma + 
+		  			splt->output_offset;
+
+	  bfd_put_32 (output_bfd, dl_tlsdesc_lazy_trampoline[0], splt->contents + 
+			  htab->dt_tlsdesc_plt);
+	  bfd_put_32 (output_bfd, dl_tlsdesc_lazy_trampoline[1], splt->contents + 
+			  htab->dt_tlsdesc_plt+4);
+
+	  bfd_put_32 (output_bfd, dl_tlsdesc_lazy_trampoline[2], splt->contents + 
+			  htab->dt_tlsdesc_plt+8);
+	  bfd_put_32 (output_bfd, dl_tlsdesc_lazy_trampoline[3], splt->contents + 
+			  htab->dt_tlsdesc_plt+12);
+	  bfd_put_32 (output_bfd, dl_tlsdesc_lazy_trampoline[4], splt->contents + 
+			  htab->dt_tlsdesc_plt+16);
+	  bfd_put_32 (output_bfd, dl_tlsdesc_lazy_trampoline[5], splt->contents + 
+			  htab->dt_tlsdesc_plt+20); 
+
+	  /* the numbers being added to dt_tlsdesc_plt are .L0 and .L1 respectively */
+	  bfd_put_32 (output_bfd, gotplt_address + htab->dt_tlsdesc_got
+			  	  - (plt_address + htab->dt_tlsdesc_plt + 0xc) - 8,
+				  splt->contents + htab->dt_tlsdesc_plt+24);
+	  bfd_put_32 (output_bfd, got_address - 
+			  	  (plt_address + htab->dt_tlsdesc_plt + 0x10) - 8,
+				  splt->contents + htab->dt_tlsdesc_plt+28); 
+	}
+
+      if (htab->tls_trampoline)
+	{
+	  bfd_put_32 (output_bfd, tls_trampoline[0], splt->contents + 
+			  				htab->tls_trampoline);
+	  bfd_put_32 (output_bfd, tls_trampoline[1], splt->contents + 
+			  				htab->tls_trampoline + 4);
+	  bfd_put_32 (output_bfd, tls_trampoline[2], splt->contents + 
+			  				htab->tls_trampoline + 8);
+#ifdef FOUR_WORD_PLT
+	  bfd_put_32 (output_bfd, 0x00000000, splt->contents + 
+			  				htab->tls_trampoline + 0xc);
+#endif 
+	}
       if (htab->vxworks_p && !info->shared && htab->splt->size > 0)
 	{
 	  /* Correct the .rel(a).plt.unloaded relocations.  They will have
@@ -9312,6 +9919,7 @@ const struct elf_size_info elf32_arm_siz
 #define elf_backend_finish_dynamic_sections	elf32_arm_finish_dynamic_sections
 #define elf_backend_link_output_symbol_hook	elf32_arm_output_symbol_hook
 #define elf_backend_size_dynamic_sections	elf32_arm_size_dynamic_sections
+#define elf_backend_always_size_sections	elf32_arm_always_size_sections
 #define elf_backend_post_process_headers	elf32_arm_post_process_headers
 #define elf_backend_reloc_type_class		elf32_arm_reloc_type_class
 #define elf_backend_object_p			elf32_arm_object_p
Index: bfd/libbfd.h
===================================================================
RCS file: /cvs/src/src/bfd/libbfd.h,v
retrieving revision 1.185
diff -u -p -r1.185 libbfd.h
--- bfd/libbfd.h	18 Jul 2006 16:44:46 -0000	1.185
+++ bfd/libbfd.h	14 Aug 2006 21:17:57 -0000
@@ -1232,6 +1232,10 @@ static const char *const bfd_reloc_code_
   "BFD_RELOC_ARM_TLS_TPOFF32",
   "BFD_RELOC_ARM_TLS_IE32",
   "BFD_RELOC_ARM_TLS_LE32",
+  "BFD_RELOC_ARM_TLS_GOTDESC",
+  "BFD_RELOC_ARM_TLS_CALL",
+  "BFD_RELOC_ARM_TLS_DESCSEQ",
+  "BFD_RELOC_ARM_TLS_DESC",
   "BFD_RELOC_ARM_ALU_PC_G0_NC",
   "BFD_RELOC_ARM_ALU_PC_G0",
   "BFD_RELOC_ARM_ALU_PC_G1_NC",
Index: bfd/reloc.c
===================================================================
RCS file: /cvs/src/src/bfd/reloc.c,v
retrieving revision 1.156
diff -u -p -r1.156 reloc.c
--- bfd/reloc.c	18 Jul 2006 16:44:46 -0000	1.156
+++ bfd/reloc.c	14 Aug 2006 21:18:08 -0000
@@ -2753,6 +2753,14 @@ ENUMX
   BFD_RELOC_ARM_TLS_IE32
 ENUMX
   BFD_RELOC_ARM_TLS_LE32
+ENUMX
+  BFD_RELOC_ARM_TLS_GOTDESC
+ENUMX
+  BFD_RELOC_ARM_TLS_CALL
+ENUMX
+  BFD_RELOC_ARM_TLS_DESCSEQ
+ENUMX
+  BFD_RELOC_ARM_TLS_DESC
 ENUMDOC
   ARM thread-local storage relocations.
 
Index: gas/ChangeLog
===================================================================
RCS file: /cvs/src/src/gas/ChangeLog,v
retrieving revision 1.2983
diff -u -p -r1.2983 ChangeLog
--- gas/ChangeLog	12 Aug 2006 23:00:34 -0000	1.2983
+++ gas/ChangeLog	14 Aug 2006 21:18:17 -0000
@@ -1,3 +1,13 @@
+2006-08-14  Glauber de Oliveira Costa  <glommer@gmail.com>
+
+	* config/tc-arm.c (s_arm_tls_descseq): Handles new TLS_ARM_DESCSEQ
+	relocation.
+	(md_pseudo_table): Added string for the aforementioned relocation.
+	(encode_branch): Adds R_ARM_TLS_CALL to the allowed branch relocs.
+	(reloc_names): Adds new relocations.
+	(md_apply_fix): Sets symbols as thread local in face of new relocs.
+	(tc_gen_reloc): Handles new relocations.
+
 2006-08-12  Thiemo Seufer  <ths@networkno.de>
 
 	* config/tc-mips.c (mips16_ip): Fix argument register handling
Index: gas/config/tc-arm.c
===================================================================
RCS file: /cvs/src/src/gas/config/tc-arm.c,v
retrieving revision 1.284
diff -u -p -r1.284 tc-arm.c
--- gas/config/tc-arm.c	8 Aug 2006 08:23:25 -0000	1.284
+++ gas/config/tc-arm.c	14 Aug 2006 21:19:32 -0000
@@ -3874,6 +3874,28 @@ bad:
 }
 #endif /* OBJ_ELF */
 
+/* Emit a fix for the symbol */ 
+static void
+s_arm_tls_descseq (int ignored ATTRIBUTE_UNUSED)
+{
+  char *p;
+  expressionS exp;
+#ifdef md_flush_pending_output
+  md_flush_pending_output ();
+#endif
+
+#ifdef md_cons_align
+  md_cons_align (4);
+#endif
+
+  /* Since we're just labeling the code, there's no need to define
+   * a mapping symbol */
+  expression (&exp);
+  p = obstack_next_free (&frchain_now->frch_obstack);
+  fix_new_arm (frag_now, p - frag_now->fr_literal, 4, &exp, 0,
+	      BFD_RELOC_ARM_TLS_DESCSEQ);
+}
+
 static void s_arm_arch (int);
 static void s_arm_cpu (int);
 static void s_arm_fpu (int);
@@ -3946,6 +3968,7 @@ const pseudo_typeS md_pseudo_table[] =
   { "setfp",		s_arm_unwind_setfp,	0 },
   { "unwind_raw",	s_arm_unwind_raw,	0 },
   { "eabi_attribute",	s_arm_eabi_attribute,	0 },
+  { "tlsdescseq",	s_arm_tls_descseq,      0 },
 #else
   { "word",	   cons, 4},
 
@@ -6622,9 +6645,17 @@ encode_branch (int default_reloc)
 {
   if (inst.operands[0].hasreloc)
     {
-      constraint (inst.operands[0].imm != BFD_RELOC_ARM_PLT32,
-		  _("the only suffix valid here is '(plt)'"));
-      inst.reloc.type	= BFD_RELOC_ARM_PLT32;
+      constraint ((inst.operands[0].imm != BFD_RELOC_ARM_PLT32) &&
+		  (inst.operands[0].imm != BFD_RELOC_ARM_TLS_CALL),
+		  _("the only valid suffixes here are '(plt)' and '(tlscall)'"));
+      if (inst.operands[0].imm == BFD_RELOC_ARM_PLT32)
+        {
+          inst.reloc.type = BFD_RELOC_ARM_PLT32;
+        }
+      else
+        {
+          inst.reloc.type = BFD_RELOC_ARM_TLS_CALL;
+        }
     }
   else
     {
@@ -14187,17 +14218,20 @@ static const struct asm_shift_name shift
 #ifdef OBJ_ELF
 static struct reloc_entry reloc_names[] =
 {
-  { "got",     BFD_RELOC_ARM_GOT32   },	 { "GOT",     BFD_RELOC_ARM_GOT32   },
-  { "gotoff",  BFD_RELOC_ARM_GOTOFF  },	 { "GOTOFF",  BFD_RELOC_ARM_GOTOFF  },
-  { "plt",     BFD_RELOC_ARM_PLT32   },	 { "PLT",     BFD_RELOC_ARM_PLT32   },
-  { "target1", BFD_RELOC_ARM_TARGET1 },	 { "TARGET1", BFD_RELOC_ARM_TARGET1 },
-  { "target2", BFD_RELOC_ARM_TARGET2 },	 { "TARGET2", BFD_RELOC_ARM_TARGET2 },
-  { "sbrel",   BFD_RELOC_ARM_SBREL32 },	 { "SBREL",   BFD_RELOC_ARM_SBREL32 },
-  { "tlsgd",   BFD_RELOC_ARM_TLS_GD32},  { "TLSGD",   BFD_RELOC_ARM_TLS_GD32},
-  { "tlsldm",  BFD_RELOC_ARM_TLS_LDM32}, { "TLSLDM",  BFD_RELOC_ARM_TLS_LDM32},
-  { "tlsldo",  BFD_RELOC_ARM_TLS_LDO32}, { "TLSLDO",  BFD_RELOC_ARM_TLS_LDO32},
-  { "gottpoff",BFD_RELOC_ARM_TLS_IE32},  { "GOTTPOFF",BFD_RELOC_ARM_TLS_IE32},
-  { "tpoff",   BFD_RELOC_ARM_TLS_LE32},  { "TPOFF",   BFD_RELOC_ARM_TLS_LE32}
+  { "got",     BFD_RELOC_ARM_GOT32   },		{ "GOT",     BFD_RELOC_ARM_GOT32   },
+  { "gotoff",  BFD_RELOC_ARM_GOTOFF  },		{ "GOTOFF",  BFD_RELOC_ARM_GOTOFF  },
+  { "plt",     BFD_RELOC_ARM_PLT32   },		{ "PLT",     BFD_RELOC_ARM_PLT32   },
+  { "target1", BFD_RELOC_ARM_TARGET1 },		{ "TARGET1", BFD_RELOC_ARM_TARGET1 },
+  { "target2", BFD_RELOC_ARM_TARGET2 },		{ "TARGET2", BFD_RELOC_ARM_TARGET2 },
+  { "sbrel",   BFD_RELOC_ARM_SBREL32 },		{ "SBREL",   BFD_RELOC_ARM_SBREL32 },
+  { "tlsgd",   BFD_RELOC_ARM_TLS_GD32},		{ "TLSGD",   BFD_RELOC_ARM_TLS_GD32},
+  { "tlsldm",  BFD_RELOC_ARM_TLS_LDM32},	{ "TLSLDM",  BFD_RELOC_ARM_TLS_LDM32},
+  { "tlsldo",  BFD_RELOC_ARM_TLS_LDO32},	{ "TLSLDO",  BFD_RELOC_ARM_TLS_LDO32},
+  { "gottpoff",BFD_RELOC_ARM_TLS_IE32},		{ "GOTTPOFF",BFD_RELOC_ARM_TLS_IE32},
+  { "tpoff",   BFD_RELOC_ARM_TLS_LE32},		{ "TPOFF",   BFD_RELOC_ARM_TLS_LE32},
+  { "tlsdesc", BFD_RELOC_ARM_TLS_GOTDESC},	{ "TLSDESC",BFD_RELOC_ARM_TLS_GOTDESC},
+  { "tlscall", BFD_RELOC_ARM_TLS_CALL},		{ "TLSCALL", BFD_RELOC_ARM_TLS_CALL},
+  { "tlsdescseq", BFD_RELOC_ARM_TLS_DESCSEQ},	{ "TLSDESCSEQ", BFD_RELOC_ARM_TLS_DESCSEQ} 
 };
 #endif
 
@@ -17926,6 +17960,12 @@ md_apply_fix (fixS *	fixP,
       break;
 
 #ifdef OBJ_ELF
+    case BFD_RELOC_ARM_TLS_CALL:
+    case BFD_RELOC_ARM_TLS_DESCSEQ:
+      S_SET_THREAD_LOCAL (fixP->fx_addsy);
+      break;
+
+    case BFD_RELOC_ARM_TLS_GOTDESC:
     case BFD_RELOC_ARM_TLS_GD32:
     case BFD_RELOC_ARM_TLS_LE32:
     case BFD_RELOC_ARM_TLS_IE32:
@@ -18504,6 +18544,8 @@ tc_gen_reloc (asection *section, fixS *f
       return NULL;
 
 #ifdef OBJ_ELF
+    case BFD_RELOC_ARM_TLS_CALL:
+    case BFD_RELOC_ARM_TLS_DESCSEQ:
     case BFD_RELOC_ARM_GOT32:
     case BFD_RELOC_ARM_GOTOFF:
     case BFD_RELOC_ARM_PLT32:
@@ -18547,6 +18589,7 @@ tc_gen_reloc (asection *section, fixS *f
       code = fixp->fx_r_type;
       break;
 
+    case BFD_RELOC_ARM_TLS_GOTDESC:
     case BFD_RELOC_ARM_TLS_GD32:
     case BFD_RELOC_ARM_TLS_IE32:
     case BFD_RELOC_ARM_TLS_LDM32:
@@ -18801,6 +18844,10 @@ arm_fix_adjustable (fixS * fixP)
       || fixP->fx_r_type == BFD_RELOC_ARM_TLS_IE32
       || fixP->fx_r_type == BFD_RELOC_ARM_TLS_LDM32
       || fixP->fx_r_type == BFD_RELOC_ARM_TLS_LDO32
+      || fixP->fx_r_type == BFD_RELOC_ARM_TLS_GOTDESC
+      || fixP->fx_r_type == BFD_RELOC_ARM_TLS_CALL
+      || fixP->fx_r_type == BFD_RELOC_ARM_TLS_DESCSEQ
+      || fixP->fx_r_type == BFD_RELOC_ARM_TLS_DESC
       || fixP->fx_r_type == BFD_RELOC_ARM_TARGET2)
     return 0;
 
Index: gas/testsuite/ChangeLog
===================================================================
RCS file: /cvs/src/src/gas/testsuite/ChangeLog,v
retrieving revision 1.1062
diff -u -p -r1.1062 ChangeLog
--- gas/testsuite/ChangeLog	12 Aug 2006 23:00:35 -0000	1.1062
+++ gas/testsuite/ChangeLog	14 Aug 2006 21:19:37 -0000
@@ -1,3 +1,8 @@
+2006-08-14  Glauber de Oliveira Costa  <glommer@gmail.com>
+
+	* gas/arm/tls.s: Generate new relocation types.
+	* gas/arm/tls.d: Adds checks for new TLS relocation types.
+
 2006-08-12  Thiemo Seufer  <ths@networkno.de>
 
 	* gas/mips/mips16-save.d: Fix testcase.
Index: gas/testsuite/gas/arm/tls.d
===================================================================
RCS file: /cvs/src/src/gas/testsuite/gas/arm/tls.d,v
retrieving revision 1.3
diff -u -p -r1.3 tls.d
--- gas/testsuite/gas/arm/tls.d	4 Jul 2005 14:55:52 -0000	1.3
+++ gas/testsuite/gas/arm/tls.d	14 Aug 2006 21:19:39 -0000
@@ -14,12 +14,17 @@ Disassembly of section .text:
 00+0 <main>:
    0:	e1a00000 	nop			\(mov r0,r0\)
    4:	e1a00000 	nop			\(mov r0,r0\)
-   8:	e1a0f00e 	mov	pc, lr
-   c:	00000000 	andeq	r0, r0, r0
-			c: R_ARM_TLS_GD32	a
+			4: R_ARM_TLS_DESCSEQ	f
+   8:	eb000000 	bl	8 .*
+			8: R_ARM_TLS_CALL	e
+   c:	e1a0f00e 	mov	pc, lr
   10:	00000004 	andeq	r0, r0, r4
-			10: R_ARM_TLS_LDM32	b
+			10: R_ARM_TLS_GD32	a
   14:	00000008 	andeq	r0, r0, r8
-			14: R_ARM_TLS_IE32	c
-  18:	00000000 	andeq	r0, r0, r0
-			18: R_ARM_TLS_LE32	d
+			14: R_ARM_TLS_LDM32	b
+  18:	0000000c 	andeq	r0, r0, ip
+			18: R_ARM_TLS_IE32	c
+  1c:	00000000 	andeq	r0, r0, r0
+			1c: R_ARM_TLS_LE32	d
+  20:	0000001c 	andeq	r0, r0, ip, lsl r0
+			20: R_ARM_TLS_GOTDESC	e
Index: gas/testsuite/gas/arm/tls.s
===================================================================
RCS file: /cvs/src/src/gas/testsuite/gas/arm/tls.s,v
retrieving revision 1.2
diff -u -p -r1.2 tls.s
--- gas/testsuite/gas/arm/tls.s	29 Mar 2005 16:54:22 -0000	1.2
+++ gas/testsuite/gas/arm/tls.s	14 Aug 2006 21:19:39 -0000
@@ -4,7 +4,9 @@
 main:
 	nop
 .L2:
+.tlsdescseq f
 	nop
+	bl	e(tlscall)
 	mov	pc, lr
 
 .Lpool:
@@ -12,3 +14,5 @@ main:
 	.word	b(tlsldm) + (. - .L2 - 8)
 	.word	c(gottpoff) + (. - .L2 - 8)
 	.word	d(tpoff)
+	.word	e(tlsdesc) + (. - .L2)
+	
Index: include/elf/ChangeLog
===================================================================
RCS file: /cvs/src/src/include/elf/ChangeLog,v
retrieving revision 1.272
diff -u -p -r1.272 ChangeLog
--- include/elf/ChangeLog	10 Jul 2006 21:40:23 -0000	1.272
+++ include/elf/ChangeLog	14 Aug 2006 21:19:58 -0000
@@ -1,3 +1,8 @@
+2006-08-14  Glauber de Oliveira Costa  <glommer@gmail.com>
+
+	* arm.h: Assigned new relocation numbers for new TLS
+	relocations
+
 2006-07-10  Jakub Jelinek  <jakub@redhat.com>
 
 	* common.h (SHT_GNU_HASH, DT_GNU_HASH): Define.
Index: include/elf/arm.h
===================================================================
RCS file: /cvs/src/src/include/elf/arm.h,v
retrieving revision 1.30
diff -u -p -r1.30 arm.h
--- include/elf/arm.h	15 Jun 2006 11:03:01 -0000	1.30
+++ include/elf/arm.h	14 Aug 2006 21:20:00 -0000
@@ -178,7 +178,10 @@ START_RELOC_NUMBERS (elf_arm_reloc_type)
   RELOC_NUMBER (R_ARM_THM_MOVW_BREL_NC,	 87)
   RELOC_NUMBER (R_ARM_THM_MOVT_BREL,   	 88)
   RELOC_NUMBER (R_ARM_THM_MOVW_BREL,   	 89)
-  /* 90-93 unallocated */
+  RELOC_NUMBER (R_ARM_TLS_GOTDESC,   	 90)
+  RELOC_NUMBER (R_ARM_TLS_CALL,   	 91)
+  RELOC_NUMBER (R_ARM_TLS_DESCSEQ,   	 92)
+  RELOC_NUMBER (R_ARM_TLS_DESC,   	 93)
   RELOC_NUMBER (R_ARM_PLT32_ABS,       	 94)
   RELOC_NUMBER (R_ARM_GOT_ABS,	       	 95)
   RELOC_NUMBER (R_ARM_GOT_PREL,	       	 96)
Index: ld/testsuite/ChangeLog
===================================================================
RCS file: /cvs/src/src/ld/testsuite/ChangeLog,v
retrieving revision 1.671
diff -u -p -r1.671 ChangeLog
--- ld/testsuite/ChangeLog	11 Aug 2006 14:05:12 -0000	1.671
+++ ld/testsuite/ChangeLog	14 Aug 2006 21:20:07 -0000
@@ -1,3 +1,22 @@
+2006-08-14  Glauber de Oliveira Costa  <glommer@gmail.com>
+
+	* ld-arm/arm-elf.exp: Added tests for new TLS handling relocations.
+	* ld-arm/tls-gdierelax.s: New file.
+	* ld-arm/tls-gdierelax.d: Likewise.
+	* ld-arm/tls-gdierelax2.s: Likewise.
+	* ld-arm/tls-gdierelax2.d: Likewise.
+	* ld-arm/tls-gdlerelax.s: Likewise.
+	* ld-arm/tls-gdlerelax.d: Likewise.
+	* ld-arm/tls-gdesc-nlazy.s: Likewise.
+	* ld-arm/tls-gdesc-nlazy.g: Likewise.
+	* ld-arm/tls-gdesc.r: Likewise.
+	* ld-arm/tls-descseq.d: Likewise.
+	* ld-arm/tls-descseq.r: Likewise.
+	* ld-arm/tls-descseq.s: Likewise.
+	* ld-arm/tls-gdesc.s: Likewise.
+	* ld-arm/tls-gdesc.r: Likewise.
+	* ld-arm/tls-gdesc.d: Likewise.
+		
 2006-08-11  Thiemo Seufer  <ths@mips.com>
 
 	* ld-elfcomm/elfcomm.exp (dump_common1): Extend regexp to match also
Index: ld/testsuite/ld-arm/arm-elf.exp
===================================================================
RCS file: /cvs/src/src/ld/testsuite/ld-arm/arm-elf.exp,v
retrieving revision 1.16
diff -u -p -r1.16 arm-elf.exp
--- ld/testsuite/ld-arm/arm-elf.exp	19 Jun 2006 14:22:27 -0000	1.16
+++ ld/testsuite/ld-arm/arm-elf.exp	14 Aug 2006 21:20:07 -0000
@@ -119,6 +119,27 @@ set armelftests {
     {"TLS dynamic application" "-T arm-dyn.ld tmpdir/tls-lib.so" "" {tls-app.s}
      {{objdump -fdw tls-app.d} {objdump -Rw tls-app.r}}
      "tls-app"}
+    {"TLS gnu shared library" "-shared -T arm-dyn.ld" "" {tls-gdesc.s}
+     {{objdump -fdw tls-gdesc.d} {objdump -Rw tls-gdesc.r}}
+     "tls-lib2.so"}
+    {"TLS gnu shared library inlined trampoline" "-shared -T arm-dyn.ld" "" {tls-descseq.s}
+     {{objdump -fdw tls-descseq.d} {objdump -Rw tls-descseq.r}}
+     "tls-lib2inline.so"}
+    {"TLS gnu shared library non-lazy" "-z now -shared -T arm-dyn.ld" "" {tls-gdesc.s}
+     {{readelf "-x .got" tls-gdesc-nlazy.g}}
+     "tls-lib2-nlazy.so"}
+    {"TLS gnu GD to IE relaxation" "-static -T arm-dyn.ld" "" {tls-gdierelax.s}
+     {{objdump -fdw tls-gdierelax.d}}
+     "tls-app-rel-ie"}
+    {"TLS gnu GD to IE shared relaxation" "-shared -T arm-dyn.ld" "" {tls-gdierelax2.s}
+     {{objdump -fdw tls-gdierelax2.d}}
+     "tls-app-rel-ie2"}
+    {"TLS gnu GD to LE relaxation" "-T arm-dyn.ld" "" {tls-gdlerelax.s}
+     {{objdump -fdw tls-gdlerelax.d}}
+     "tls-app-rel-le"}
+    {"TLS mixed models shared lib" "-shared -T arm-dyn.ld" "" {tls-mixed.s}
+     {{objdump -Rw tls-mixed.r}}
+     "tls-mixed.so"}
     {"Thumb entry point" "-T arm.ld" "" {thumb-entry.s}
      {{readelf -h thumb-entry.d}}
      "thumb-entry"}
--- /dev/null	2006-05-22 11:25:23.000000000 -0300
+++ ld/testsuite/ld-arm/tls-descseq.d	2006-08-14 14:36:40.000000000 -0300
@@ -0,0 +1,34 @@
+
+tmpdir/tls-lib2inline.so:     file format elf32-.*arm
+architecture: arm, flags 0x[0-9a-f]+:
+HAS_SYMS, DYNAMIC, D_PAGED
+start address 0x[0-9a-f]+
+
+Disassembly of section .plt:
+
+[0-9a-f]+ <.plt>:
+    [0-9a-f]+:	e52de004 	str	lr, \[sp, #-4\]!
+    [0-9a-f]+:	e59fe004 	ldr	lr, \[pc, #4\]	; .*
+    [0-9a-f]+:	e08fe00e 	add	lr, pc, lr
+    [0-9a-f]+:	e5bef008 	ldr	pc, \[lr, #8\]!
+    [0-9a-f]+:	000080d4 	ldreqd	r8, \[r0\], -r4
+    [0-9a-f]+:	e08e0000 	add	r0, lr, r0
+    [0-9a-f]+:	e5901004 	ldr	r1, \[r0, #4\]
+    [0-9a-f]+:	e12fff11 	bx	r1
+    [0-9a-f]+:	e92d0004 	stmdb	sp!, {r2}
+    [0-9a-f]+:	e59f200c 	ldr	r2, \[pc, #12\]	; .*
+    [0-9a-f]+:	e59f100c 	ldr	r1, \[pc, #12\]	; .*
+    [0-9a-f]+:	e79f2002 	ldr	r2, \[pc, r2\]
+    [0-9a-f]+:	e08f1001 	add	r1, pc, r1
+    [0-9a-f]+:	e12fff12 	bx	r2
+    [0-9a-f]+:	000080c4 	andeq	r8, r0, r4, asr #1
+    [0-9a-f]+:	000080ac 	andeq	r8, r0, ip, lsr #1
+Dis[0-9a-f]+ssembly of section .text:
+
+[0-9a-f]+ <foo>:
+    [0-9a-f]+:	e1a00000 	nop			\(mov r0,r0\)
+    [0-9a-f]+:	e08f0000 	add	r0, pc, r0
+    [0-9a-f]+:	e5901004 	ldr	r1, \[r0, #4\]
+    [0-9a-f]+:	e12fff31 	blx	r1
+    [0-9a-f]+:	e1a0f00e 	mov	pc, lr
+    [0-9a-f]+:	000080a4 	andeq	r8, r0, r4, lsr #1
--- /dev/null	2006-05-22 11:25:23.000000000 -0300
+++ ld/testsuite/ld-arm/tls-descseq.r	2006-07-04 23:36:50.000000000 -0300
@@ -0,0 +1,6 @@
+
+.*:     file format elf32-.*arm
+
+DYNAMIC RELOCATION RECORDS
+OFFSET   TYPE              VALUE 
+[0-9a-f]+ R_ARM_TLS_DESC    lib_gd2
--- /dev/null	2006-05-22 11:25:23.000000000 -0300
+++ ld/testsuite/ld-arm/tls-descseq.s	2006-07-04 23:38:35.000000000 -0300
@@ -0,0 +1,22 @@
+	.text
+	.globl foo
+	.type foo, %function
+foo:
+	nop
+.L2:
+.tlsdescseq lib_gd2
+	add r0,pc,r0
+.tlsdescseq lib_gd2
+	ldr r1,[r0,#4]
+.tlsdescseq lib_gd2
+	blx r1
+	mov	pc, lr
+
+.Lpool:
+	.word	lib_gd2(tlsdesc) + (. - .L2)
+
+	.section .tdata,"awT"
+	.global lib_gd2
+lib_gd2:
+	.space	4
+
--- /dev/null	2006-05-22 11:25:23.000000000 -0300
+++ ld/testsuite/ld-arm/tls-gdesc.d	2006-08-14 14:34:41.000000000 -0300
@@ -0,0 +1,32 @@
+
+tmpdir/tls-lib2.so:     file format elf32-littlearm
+architecture: arm, flags 0x[0-9a-f]+:
+HAS_SYMS, DYNAMIC, D_PAGED
+start address 0x[0-9a-f]+
+
+Disassembly of section .plt:
+
+[0-9a-f]+ <.plt>:
+    [0-9a-f]+:	e52de004 	str	lr, \[sp, #-4\]!
+    [0-9a-f]+:	e59fe004 	ldr	lr, \[pc, #4\]	; .*
+    [0-9a-f]+:	e08fe00e 	add	lr, pc, lr
+    [0-9a-f]+:	e5bef008 	ldr	pc, \[lr, #8\]!
+    [0-9a-f]+:	000080cc 	andeq	r8, r0, ip, asr #1
+    [0-9a-f]+:	e08e0000 	add	r0, lr, r0
+    [0-9a-f]+:	e5901004 	ldr	r1, \[r0, #4\]
+    [0-9a-f]+:	e12fff11 	bx	r1
+    [0-9a-f]+:	e92d0004 	stmdb	sp!, {r2}
+    [0-9a-f]+:	e59f200c 	ldr	r2, \[pc, #12\]	; .*
+    [0-9a-f]+:	e59f100c 	ldr	r1, \[pc, #12\]	; .*
+    [0-9a-f]+:	e79f2002 	ldr	r2, \[pc, r2\]
+    [0-9a-f]+:	e08f1001 	add	r1, pc, r1
+    [0-9a-f]+:	e12fff12 	bx	r2
+    [0-9a-f]+:	000080bc 	streqh	r8, \[r0\], -ip
+    [0-9a-f]+:	000080a4 	andeq	r8, r0, r4, lsr #1
+Disassembly of section .text:
+
+[0-9a-f]+ <foo>:
+    [0-9a-f]+:	e1a00000 	nop			\(mov r0,r0\)
+    [0-9a-f]+:	ebfffff2 	bl	81e0 .*
+    [0-9a-f]+:	e1a0f00e 	mov	pc, lr
+    [0-9a-f]+:	000080a0 	andeq	r8, r0, r0, lsr #1
--- /dev/null	2006-05-22 11:25:23.000000000 -0300
+++ ld/testsuite/ld-arm/tls-gdesc.r	2006-07-04 23:26:09.000000000 -0300
@@ -0,0 +1,6 @@
+
+.*:     file format elf32-.*arm
+
+DYNAMIC RELOCATION RECORDS
+OFFSET   TYPE              VALUE 
+[0-9a-f]+ R_ARM_TLS_DESC    lib_gd2
--- /dev/null	2006-05-22 11:25:23.000000000 -0300
+++ ld/testsuite/ld-arm/tls-gdesc.s	2006-07-09 00:47:18.000000000 -0300
@@ -0,0 +1,17 @@
+	.text
+	.globl foo
+	.type foo, %function
+foo:
+	nop
+.L2:
+	bl	lib_gd2(tlscall) 
+	mov	pc, lr
+
+.Lpool:
+	.word	lib_gd2(tlsdesc) + (. - .L2)
+
+	.section .tdata,"awT"
+	.global lib_gd2
+lib_gd2:
+	.space	4
+
--- /dev/null	2006-05-22 11:25:23.000000000 -0300
+++ ld/testsuite/ld-arm/tls-gdesc-nlazy.g	2006-07-09 01:13:19.000000000 -0300
@@ -0,0 +1,4 @@
+
+Hex dump of section '.got':
+  0x[0-9a-f]+ 00000000 00000000 00000000 [0-9a-f]+ ................
+  0x[0-9a-f]+                            00000000 ....
--- /dev/null	2006-05-22 11:25:23.000000000 -0300
+++ ld/testsuite/ld-arm/tls-gdesc-nlazy.s	2006-07-04 23:53:15.000000000 -0300
@@ -0,0 +1,17 @@
+	.text
+	.globl foo
+	.type foo, %function
+foo:
+	nop
+.L2:
+	blx	lib_gd2(tlscall) 
+	mov	pc, lr
+
+.Lpool:
+	.word	lib_gd2(tlsdesc) + (. - .L2)
+
+	.section .tdata,"awT"
+	.global lib_gd2
+lib_gd2:
+	.space	4
+
--- /dev/null	2006-05-22 11:25:23.000000000 -0300
+++ ld/testsuite/ld-arm/tls-gdierelax.d	2006-07-10 00:25:30.000000000 -0300
@@ -0,0 +1,13 @@
+
+tmpdir/tls-app-rel-ie:     file format elf32-.*arm
+architecture: arm, flags 0x[0-9a-f]+:
+EXEC_P, HAS_SYMS, D_PAGED
+start address 0x[0-9a-f]+
+
+Disassembly of section .text:
+
+[0-9a-f]+ <foo>:
+    [0-9a-f]+:	e1a00000 	nop			\(mov r0,r0\)
+    [0-9a-f]+:	e79f0000 	ldr	r0, \[pc, r0\]
+    [0-9a-f]+:	e1a0f00e 	mov	pc, lr
+    [0-9a-f]+:	00008014 	andeq	r8, r0, r4, lsl r0
--- /dev/null	2006-05-22 11:25:23.000000000 -0300
+++ ld/testsuite/ld-arm/tls-gdierelax.s	2006-07-05 10:31:04.000000000 -0300
@@ -0,0 +1,17 @@
+	.text
+	.globl foo
+	.type foo, %function
+foo:
+	nop
+.L2:
+	blx	lib_gd2(tlscall) 
+	mov	pc, lr
+
+.Lpool:
+	.word	lib_gd2(tlsdesc) + (. - .L2)
+
+	.section .tdata,"awT"
+	.global lib_gd2
+lib_gd2:
+	.space	4
+
--- /dev/null	2006-05-22 11:25:23.000000000 -0300
+++ ld/testsuite/ld-arm/tls-gdlerelax.d	2006-07-10 00:25:54.000000000 -0300
@@ -0,0 +1,13 @@
+
+tmpdir/tls-app-rel-le:     file format elf32-.*arm
+architecture: arm, flags 0x[0-9a-f]+:
+EXEC_P, HAS_SYMS, D_PAGED
+start address 0x[0-9a-f]+
+
+Disassembly of section .text:
+
+[0-9a-f]+ <foo>:
+    [0-9a-f]+:	e1a00000 	nop			\(mov r0,r0\)
+    [0-9a-f]+:	e1a00000 	nop			\(mov r0,r0\)
+    [0-9a-f]+:	e1a0f00e 	mov	pc, lr
+    [0-9a-f]+:	00000010 	andeq	r0, r0, r0, lsl r0
--- /dev/null	2006-05-22 11:25:23.000000000 -0300
+++ ld/testsuite/ld-arm/tls-gdlerelax.s	2006-07-05 00:01:13.000000000 -0300
@@ -0,0 +1,16 @@
+	.text
+	.globl foo
+	.type foo, %function
+foo:
+	nop
+.L2:
+	blx	lib_gd2(tlscall) 
+	mov	pc, lr
+
+.Lpool:
+	.word	lib_gd2(tlsdesc) + (. - .L2)
+
+	.section .tdata,"awT"
+lib_gd2:
+	.space	4
+
--- /dev/null	2006-05-22 11:25:23.000000000 -0300
+++ ld/testsuite/ld-arm/tls-gdierelax2.d	2006-08-14 15:09:49.000000000 -0300
@@ -0,0 +1,15 @@
+
+tmpdir/tls-app-rel-ie2:     file format elf32-.*arm
+architecture: arm, flags 0x[0-9a-f]+:
+HAS_SYMS, DYNAMIC, D_PAGED
+start address 0x[0-9a-f]+
+
+Disassembly of section .text:
+
+[0-9a-f]+ <foo>:
+    [0-9a-f]+:	e1a00000 	nop			\(mov r0,r0\)
+    [0-9a-f]+:	e1a00000 	nop			\(mov r0,r0\)
+    [0-9a-f]+:	e79f0000 	ldr	r0, \[pc, r0\]
+    [0-9a-f]+:	e1a0f00e 	mov	pc, lr
+    [0-9a-f]+:	00008088 	andeq	r8, r0, r8, lsl #1
+    [0-9a-f]+:	0000808c 	andeq	r8, r0, ip, lsl #1
--- /dev/null	2006-05-22 11:25:23.000000000 -0300
+++ ld/testsuite/ld-arm/tls-gdierelax2.s	2006-08-14 15:03:47.000000000 -0300
@@ -0,0 +1,19 @@
+	.text
+	.globl foo
+	.type foo, %function
+foo:
+	nop
+.L1:	nop
+.L2:
+	bl	lib_gd2(tlscall) 
+	mov	pc, lr
+
+.Lpool:
+	.word	lib_gd2(tlsdesc) + (. - .L2)
+	.word	lib_gd2(gottpoff) + (. - .L1 - 8)
+
+	.section .tdata,"awT"
+	.global lib_gd2
+lib_gd2:
+	.space	4
+
--- /dev/null	2006-05-22 11:25:23.000000000 -0300
+++ ld/testsuite/ld-arm/tls-mixed.r	2006-07-06 02:33:02.000000000 -0300
@@ -0,0 +1,10 @@
+
+.*:     file format elf32-.*arm
+
+DYNAMIC RELOCATION RECORDS
+OFFSET   TYPE              VALUE 
+[0-9a-f]+ R_ARM_TLS_DTPMOD32  lib_gd2
+[0-9a-f]+ R_ARM_TLS_DTPOFF32  lib_gd2
+[0-9a-f]+ R_ARM_TLS_DTPMOD32  lib_gd
+[0-9a-f]+ R_ARM_TLS_DTPOFF32  lib_gd
+[0-9a-f]+ R_ARM_TLS_DESC    lib_gd2
--- /dev/null	2006-05-22 11:25:23.000000000 -0300
+++ ld/testsuite/ld-arm/tls-mixed.s	2006-07-09 01:14:10.000000000 -0300
@@ -0,0 +1,25 @@
+	.text
+	.globl foo
+	.type foo, %function
+foo:
+	nop
+.L1:
+	nop	
+.L2:
+	bl	lib_gd2(tlscall) 
+	mov	pc, lr
+
+.Lpool:
+	.word	lib_gd(tlsgd)	+  (. - .L1 - 8)
+.Lpool2:
+	.word	lib_gd2(tlsdesc) + (. - .L2)
+	.word	lib_gd2(tlsgd)	+  (. - .L2 - 8)
+
+	.section .tdata,"awT"
+	.global lib_gd
+lib_gd:
+	.space	4 
+	.global lib_gd2
+lib_gd2:
+	.space	4
+

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCH] Support for Thread Local Storage Descriptors in ARM  platform
  2006-08-15  1:48 [PATCH] Support for Thread Local Storage Descriptors in ARM platform Glauber de Oliveira Costa
@ 2006-08-15 11:48 ` Richard Earnshaw
  2006-08-15 16:40   ` Glauber de Oliveira Costa
  0 siblings, 1 reply; 3+ messages in thread
From: Richard Earnshaw @ 2006-08-15 11:48 UTC (permalink / raw)
  To: Glauber de Oliveira Costa; +Cc: binutils, Alexandre Oliva, aldenor

On Tue, 2006-08-15 at 01:29, Glauber de Oliveira Costa wrote:
> Hello All,
> 
> Troughout the last months, Alexandre Oliva and I developed an ABI
> extension to allow ARM binaries to benefit from his newly devised TLS
> Descriptor method for accessing TLS variables
> (http://www.lsd.ic.unicamp.br/~aoliva/writeups/TLS/paper-gcc2006.pdf).
> Our proposed ABI can be found at
> http://www.lsd.ic.unicamp.br/~aoliva/writeups/TLS/RFC-TLSDESC-ARM.txt
> ,  and a paper describing the ARM implementation, to be presented at
> Linux Kongress in the first week of September at
> http://www.lsd.ic.unicamp.br/~oliva/writeups/TLS/paper-lk2006.pdf. We
> there describes some results we've got, that indicates a speedup of
> more than 2 times for the most common case.
> 
> Attached to this message, follows the GNU linker and assembler part of
> the work. Please, feel free to send me feedbacks on the
> implementation, and consider it for merging.

Sorry, you can't just claim relocations like this.  The allocation
process has to be co-ordinated by the ARM EABI, since the numbers you
have used may have been requested by some other third party.  If you are
at the stage where you believe you have proved your model then you
should make a formal request (you can do that via me).

R.

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCH] Support for Thread Local Storage Descriptors in ARM platform
  2006-08-15 11:48 ` Richard Earnshaw
@ 2006-08-15 16:40   ` Glauber de Oliveira Costa
  0 siblings, 0 replies; 3+ messages in thread
From: Glauber de Oliveira Costa @ 2006-08-15 16:40 UTC (permalink / raw)
  To: Richard Earnshaw; +Cc: Alexandre Oliva, binutils, aldenor

> Sorry, you can't just claim relocations like this.  The allocation
> process has to be co-ordinated by the ARM EABI, since the numbers you
> have used may have been requested by some other third party.  If you are
> at the stage where you believe you have proved your model then you
> should make a formal request (you can do that via me).
>
> R.
Thanks Richard,

At this point, at least me and Oliva do think the model has been
proved, since we obtained very good practical results. I want to give
other people the chance to pronounce themselves about it, but our
relocations needs will probably be unchanged. I'd then would like to
start that formal process for number assigning, unless somebody
opposes.

How do we do that?

-- 
"Free as in Freedom"
Glauber de Oliveira Costa.

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2006-08-15 13:29 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2006-08-15  1:48 [PATCH] Support for Thread Local Storage Descriptors in ARM platform Glauber de Oliveira Costa
2006-08-15 11:48 ` Richard Earnshaw
2006-08-15 16:40   ` Glauber de Oliveira Costa

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).