bfd/
authorNathan Sidwell <nathan@codesourcery.com>
Mon, 10 Jan 2011 08:40:19 +0000 (08:40 +0000)
committerNathan Sidwell <nathan@codesourcery.com>
Mon, 10 Jan 2011 08:40:19 +0000 (08:40 +0000)
* reloc.c (BFD_RELOC_ARM_TLS_GOTDESC, BFD_RELOC_ARM_TLS_CALL,
BFD_RELOC_ARM_THM_TLS_CALL, BFD_RELOC_ARM_TLS_DESCSEQ,
BFD_RELOC_ARM_THM_TLS_DESCSEQ, BFD_RELOC_ARM_TLS_DESC): New
relocations.
* libbfd.h: Rebuilt.
* bfd-in2.h: Rebuilt.
* elf32-arm.c (elf32_arm_howto_table_1): Add new relocations.
(elf32_arm_reloc_map): Likewise.
(tls_trampoline, dl_tlsdesc_lazy_trampoline): New PLT templates.
(elf32_arm_stub_long_branch_any_tls_pic,
elf32_arm_stub_long_branch_v4t_thumb_tls_pic): New stub templates.
(DEF_STUBS): Add new stubs.
(struct_elf_arm_obj_data): Add local_tlsdesc_gotent field.
(elf32_arm_local_tlsdesc_gotent): New.
(GOT_TLS_GDESC): New mask.
(GOT_TLS_GD_ANY): Define.
(struct elf32_arm_link_hash_entry): Add tlsdesc_got field.
(elf32_arm_compute_jump_table_size): New.
(struct elf32_arm_link_hash_table): Add next_tls_desc_index,
num_tls_desc, dt_tlsdesc_plt, dt_tlsdesc_got, tls_trampoline,
sgotplt_jump_table_size fields.
(elf32_arm_link_hash_newfunc): Initialize tlsdesc_got field.
(elf32_arm_link_hash_table_create): Initialize new fields.
(arm_type_of_stub): Check TLS desc relocs too.
(elf32_arm_stub_name): TLS desc relocs can be shared.
(elf32_arm_tls_transition): Determine relaxation.
(arm_stub_required_alignment): Add tls stubs.
(elf32_arm_size_stubs): Likewise.
(elf32_arm_tls_relax): Perform TLS relaxing.
(elf32_arm_final_link_relocate): Process TLS DESC relocations.
(IS_ARM_TLS_GNU_RELOC): New.
(IS_ARM_TLS_RELOC): Use it.
(elf32_arm_relocate_section): Perform TLS relaxing.
(elf32_arm_check_relocs): Anticipate TLS relaxing, process tls
desc relocations.
(allocate_dynrelocs): Allocate tls desc relcoations.
(elf32_arm_output_arch_local_syms): Emit tls trampoline mapping
symbols.
(elf32_arm_size_dynamic_sections): Allocate tls trampolines and
got slots.
(elf32_arm_always_size_sections): New. Create _TLS_MODULE_BASE
symbol.
(elf32_arm_finish_dynamic_symbol): Adjust.
(arm_put_trampoline): New.
(elf32_arm_finish_dynamic_sections): Emit new dynamic tags and tls
trampolines.
(elf_backend_always_size_sections): Define.

include/elf/
* arm.h (R_ARM_TLS_DESC, R_ARM_TLS_GOTDESC, R_ARM_TLS_CALL,
R_ARM_TLS_DESCSEQ, T_ARM_THM_TLS_CALL, R_ARM_THM_TLS_DESCSEQ): New
relocations.

gas/
* doc/c-arm.texi: Document TLSDESC and TLSCALL relocations, and
.tlsdescseq directive.
* config/tc-arm.c (arm_typed_reg_parse): Check for potential reloc
following a symbol.
(s_arm_tls_descseq): New directive.
(md_pseudo_table): Add it.
(encode_branch): Allow TLS_CALL relocs too.
(do_t_blx, do_t_branch23): Use encode_branch.
(reloc_names): Add tlsdesc and tlscall.
(md_apply_fix): Process tls desc relocations.
(tc_gen_reloc): Likewise.
(arm_fix_adjustable): Likewise.

gas/testsuite/
* gas/arm/tls.s: Add tlsdesc tests.
* gas/arm/tls.d: Adjust.

ld/testsuite/
* ld-arm/arm-elf.exp: Added tests for new TLS handling
relocations.
* ld-arm/tls-descrelax-be32.d: New.
* ld-arm/tls-descrelax-be32.s: New.
* ld-arm/tls-descrelax-be8.d: New.
* ld-arm/tls-descrelax-be8.s: New.
* ld-arm/tls-descrelax-v7.d: New.
* ld-arm/tls-descrelax-v7.s: New.
* ld-arm/tls-descrelax.d: New.
* ld-arm/tls-descrelax.s: New.
* ld-arm/tls-descseq.d: New.
* ld-arm/tls-descseq.r: New.
* ld-arm/tls-descseq.s: New.
* ld-arm/tls-gdesc-got.d: New.
* ld-arm/tls-gdesc-got.s: New.
* ld-arm/tls-gdesc-nlazy.g: New.
* ld-arm/tls-gdesc-nlazy.s: New.
* ld-arm/tls-gdesc.d: New.
* ld-arm/tls-gdesc.r: New.
* ld-arm/tls-gdesc.s: New.
* ld-arm/tls-gdierelax.d: New.
* ld-arm/tls-gdierelax.s: New.
* ld-arm/tls-gdierelax2.d: New.
* ld-arm/tls-gdierelax2.s: New.
* ld-arm/tls-gdlerelax.d: New.
* ld-arm/tls-gdlerelax.s: New.
* ld-arm/tls-lib-loc.d: New.
* ld-arm/tls-lib-loc.r: New.
* ld-arm/tls-lib-loc.s: New.
* ld-arm/tls-longplt-lib.d: New.
* ld-arm/tls-longplt-lib.s: New.
* ld-arm/tls-longplt.d: New.
* ld-arm/tls-longplt.s: New.
* ld-arm/tls-mixed.r: New.
* ld-arm/tls-mixed.s: New.
* ld-arm/tls-thumb1.d: New.
* ld-arm/tls-thumb1.s: New.
* ld-arm/arm-elf.exp: New.

50 files changed:
bfd/ChangeLog
bfd/bfd-in2.h
bfd/elf32-arm.c
bfd/libbfd.h
bfd/reloc.c
gas/ChangeLog
gas/config/tc-arm.c
gas/doc/c-arm.texi
gas/testsuite/ChangeLog
gas/testsuite/gas/arm/tls.d
gas/testsuite/gas/arm/tls.s
include/elf/ChangeLog
include/elf/arm.h
ld/testsuite/ChangeLog
ld/testsuite/ld-arm/arm-elf.exp
ld/testsuite/ld-arm/tls-descrelax-be32.d [new file with mode: 0644]
ld/testsuite/ld-arm/tls-descrelax-be32.s [new file with mode: 0644]
ld/testsuite/ld-arm/tls-descrelax-be8.d [new file with mode: 0644]
ld/testsuite/ld-arm/tls-descrelax-be8.s [new file with mode: 0644]
ld/testsuite/ld-arm/tls-descrelax-v7.d [new file with mode: 0644]
ld/testsuite/ld-arm/tls-descrelax-v7.s [new file with mode: 0644]
ld/testsuite/ld-arm/tls-descrelax.d [new file with mode: 0644]
ld/testsuite/ld-arm/tls-descrelax.s [new file with mode: 0644]
ld/testsuite/ld-arm/tls-descseq.d [new file with mode: 0644]
ld/testsuite/ld-arm/tls-descseq.r [new file with mode: 0644]
ld/testsuite/ld-arm/tls-descseq.s [new file with mode: 0644]
ld/testsuite/ld-arm/tls-gdesc-got.d [new file with mode: 0644]
ld/testsuite/ld-arm/tls-gdesc-got.s [new file with mode: 0644]
ld/testsuite/ld-arm/tls-gdesc-nlazy.g [new file with mode: 0644]
ld/testsuite/ld-arm/tls-gdesc-nlazy.s [new file with mode: 0644]
ld/testsuite/ld-arm/tls-gdesc.d [new file with mode: 0644]
ld/testsuite/ld-arm/tls-gdesc.r [new file with mode: 0644]
ld/testsuite/ld-arm/tls-gdesc.s [new file with mode: 0644]
ld/testsuite/ld-arm/tls-gdierelax.d [new file with mode: 0644]
ld/testsuite/ld-arm/tls-gdierelax.s [new file with mode: 0644]
ld/testsuite/ld-arm/tls-gdierelax2.d [new file with mode: 0644]
ld/testsuite/ld-arm/tls-gdierelax2.s [new file with mode: 0644]
ld/testsuite/ld-arm/tls-gdlerelax.d [new file with mode: 0644]
ld/testsuite/ld-arm/tls-gdlerelax.s [new file with mode: 0644]
ld/testsuite/ld-arm/tls-lib-loc.d [new file with mode: 0644]
ld/testsuite/ld-arm/tls-lib-loc.r [new file with mode: 0644]
ld/testsuite/ld-arm/tls-lib-loc.s [new file with mode: 0644]
ld/testsuite/ld-arm/tls-longplt-lib.d [new file with mode: 0644]
ld/testsuite/ld-arm/tls-longplt-lib.s [new file with mode: 0644]
ld/testsuite/ld-arm/tls-longplt.d [new file with mode: 0644]
ld/testsuite/ld-arm/tls-longplt.s [new file with mode: 0644]
ld/testsuite/ld-arm/tls-mixed.r [new file with mode: 0644]
ld/testsuite/ld-arm/tls-mixed.s [new file with mode: 0644]
ld/testsuite/ld-arm/tls-thumb1.d [new file with mode: 0644]
ld/testsuite/ld-arm/tls-thumb1.s [new file with mode: 0644]

index c2c015708dfa8a487e974438b9f64e5b25247343..42b07c6d227b4734a4f96a0b91c80d24af06108c 100644 (file)
@@ -1,3 +1,54 @@
+2011-01-10  Nathan Sidwell  <nathan@codesourcery.com>
+           Glauber de Oliveira Costa  <glommer@gmail.com>
+
+       * reloc.c (BFD_RELOC_ARM_TLS_GOTDESC, BFD_RELOC_ARM_TLS_CALL,
+       BFD_RELOC_ARM_THM_TLS_CALL, BFD_RELOC_ARM_TLS_DESCSEQ,
+       BFD_RELOC_ARM_THM_TLS_DESCSEQ, BFD_RELOC_ARM_TLS_DESC): New
+       relocations.
+       * libbfd.h: Rebuilt.
+       * bfd-in2.h: Rebuilt.
+       * elf32-arm.c (elf32_arm_howto_table_1): Add new relocations.
+       (elf32_arm_reloc_map): Likewise.
+       (tls_trampoline, dl_tlsdesc_lazy_trampoline): New PLT templates.
+       (elf32_arm_stub_long_branch_any_tls_pic,
+       elf32_arm_stub_long_branch_v4t_thumb_tls_pic): New stub templates.
+       (DEF_STUBS): Add new stubs.
+       (struct_elf_arm_obj_data): Add local_tlsdesc_gotent field.
+       (elf32_arm_local_tlsdesc_gotent): New.
+       (GOT_TLS_GDESC): New mask.
+       (GOT_TLS_GD_ANY): Define.
+       (struct elf32_arm_link_hash_entry): Add tlsdesc_got field.
+       (elf32_arm_compute_jump_table_size): New.
+       (struct elf32_arm_link_hash_table): Add next_tls_desc_index,
+       num_tls_desc, dt_tlsdesc_plt, dt_tlsdesc_got, tls_trampoline,
+       sgotplt_jump_table_size fields.
+       (elf32_arm_link_hash_newfunc): Initialize tlsdesc_got field.
+       (elf32_arm_link_hash_table_create): Initialize new fields.
+       (arm_type_of_stub): Check TLS desc relocs too.
+       (elf32_arm_stub_name): TLS desc relocs can be shared.
+       (elf32_arm_tls_transition): Determine relaxation.
+       (arm_stub_required_alignment): Add tls stubs.
+       (elf32_arm_size_stubs): Likewise.
+       (elf32_arm_tls_relax): Perform TLS relaxing.
+       (elf32_arm_final_link_relocate): Process TLS DESC relocations.
+       (IS_ARM_TLS_GNU_RELOC): New.
+       (IS_ARM_TLS_RELOC): Use it.
+       (elf32_arm_relocate_section): Perform TLS relaxing.
+       (elf32_arm_check_relocs): Anticipate TLS relaxing, process tls
+       desc relocations.
+       (allocate_dynrelocs): Allocate tls desc relcoations.
+       (elf32_arm_output_arch_local_syms): Emit tls trampoline mapping
+       symbols.
+       (elf32_arm_size_dynamic_sections): Allocate tls trampolines and
+       got slots.
+       (elf32_arm_always_size_sections): New. Create _TLS_MODULE_BASE
+       symbol.
+       (elf32_arm_finish_dynamic_symbol): Adjust.
+       (arm_put_trampoline): New.
+       (elf32_arm_finish_dynamic_sections): Emit new dynamic tags and tls
+       trampolines.
+       (elf_backend_always_size_sections): Define.
+
 2011-01-06  H.J. Lu  <hongjiu.lu@intel.com>
 
        * elf-ifunc.c (_bfd_elf_allocate_ifunc_dyn_relocs): Optimized.
index 8531f8de5295a9f7cdd6d51a361ebda020b720a5..84fc75d2eb4f3f905714fca3dbad8788b97c1f2c 100644 (file)
@@ -3146,6 +3146,12 @@ pc-relative or some form of GOT-indirect relocation.  */
   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_THM_TLS_CALL,
+  BFD_RELOC_ARM_TLS_DESCSEQ,
+  BFD_RELOC_ARM_THM_TLS_DESCSEQ,
+  BFD_RELOC_ARM_TLS_DESC,
 
 /* ARM group relocations.  */
   BFD_RELOC_ARM_ALU_PC_G0_NC,
index 7c8eb68a77ebc047c86dde1bb1d4a40425ffa2e0..ea1e485bc9500d73220eee60e03a6ea4c1baecb2 100644 (file)
@@ -261,18 +261,18 @@ static reloc_howto_type elf32_arm_howto_table_1[] =
         0xffffffff,            /* dst_mask */
         FALSE),                /* pcrel_offset */
 
-  HOWTO (R_ARM_SWI24,          /* type */
+  HOWTO (R_ARM_TLS_DESC,       /* type */
         0,                     /* rightshift */
-        0,                     /* size (0 = byte, 1 = short, 2 = long) */
-        0,                     /* bitsize */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        32,                    /* bitsize */
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
-        complain_overflow_signed,/* complain_on_overflow */
+        complain_overflow_bitfield,/* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
-        "R_ARM_SWI24",         /* name */
+        "R_ARM_TLS_DESC",      /* name */
         FALSE,                 /* partial_inplace */
-        0x00000000,            /* src_mask */
-        0x00000000,            /* dst_mask */
+        0xffffffff,            /* src_mask */
+        0xffffffff,            /* dst_mask */
         FALSE),                /* pcrel_offset */
 
   HOWTO (R_ARM_THM_SWI8,       /* type */
@@ -1352,10 +1352,61 @@ static reloc_howto_type elf32_arm_howto_table_1[] =
         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_THM_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_THM_TLS_CALL",  /* name */
+        FALSE,                 /* partial_inplace */
+        0x07ff07ff,            /* src_mask */
+        0x07ff07ff,            /* dst_mask */
+        FALSE),                /* pcrel_offset */
 
   HOWTO (R_ARM_PLT32_ABS,      /* type */
         0,                     /* rightshift */
@@ -1599,6 +1650,38 @@ static reloc_howto_type elf32_arm_howto_table_1[] =
         0x00000fff,            /* src_mask */
         0x00000fff,            /* dst_mask */
         FALSE),                /* pcrel_offset */
+
+  EMPTY_HOWTO (112),
+  EMPTY_HOWTO (113),
+  EMPTY_HOWTO (114),
+  EMPTY_HOWTO (115),
+  EMPTY_HOWTO (116),
+  EMPTY_HOWTO (117),
+  EMPTY_HOWTO (118),
+  EMPTY_HOWTO (119),
+  EMPTY_HOWTO (120),
+  EMPTY_HOWTO (121),
+  EMPTY_HOWTO (122),
+  EMPTY_HOWTO (123),
+  EMPTY_HOWTO (124),
+  EMPTY_HOWTO (125),
+  EMPTY_HOWTO (126),
+  EMPTY_HOWTO (127),
+  EMPTY_HOWTO (128),
+
+  HOWTO (R_ARM_THM_TLS_DESCSEQ,        /* type */
+        0,                     /* rightshift */
+        1,                     /* 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_THM_TLS_DESCSEQ",/* name */
+        FALSE,                 /* partial_inplace */
+        0x00000000,            /* src_mask */
+        0x00000000,            /* dst_mask */
+        FALSE),                /* pcrel_offset */
 };
 
 /* 112-127 private relocations
@@ -1730,6 +1813,12 @@ static const struct elf32_arm_reloc_map 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_THM_TLS_CALL,     R_ARM_THM_TLS_CALL},
+    {BFD_RELOC_ARM_TLS_DESCSEQ,      R_ARM_TLS_DESCSEQ},
+    {BFD_RELOC_ARM_THM_TLS_DESCSEQ,  R_ARM_THM_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},
@@ -1912,6 +2001,26 @@ 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 [] =
+  {
+    0xe52d2004, /*     push    {r2}                    */
+    0xe59f200c, /*      ldr     r2, [pc, #3f - . - 8]  */
+    0xe59f100c, /*      ldr     r1, [pc, #4f - . - 8]  */
+    0xe79f2002, /* 1:   ldr     r2, [pc, r2]           */
+    0xe081100f, /* 2:   add     r1, pc                 */
+    0xe12fff12, /*      bx      r2                     */
+    0x00000014, /* 3:   .word  _GLOBAL_OFFSET_TABLE_ - 1b - 8
+                               + dl_tlsdesc_lazy_resolver(GOT)   */
+    0x00000018, /* 4:   .word  _GLOBAL_OFFSET_TABLE_ - 2b - 8 */ 
+  };
+
 #ifdef FOUR_WORD_PLT
 
 /* The first entry in a procedure linkage table looks like
@@ -2167,6 +2276,26 @@ static const insn_sequence elf32_arm_stub_long_branch_v4t_thumb_thumb_pic[] =
     DATA_WORD(0, R_ARM_REL32, 0),     /* dcd  R_ARM_REL32(X) */
   };
 
+/* Thumb2/ARM -> TLS trampoline.  Lowest common denominator, which is a
+   long PIC stub.  We can use r1 as a scratch -- and cannot use ip.  */
+static const insn_sequence elf32_arm_stub_long_branch_any_tls_pic[] =
+{
+    ARM_INSN(0xe59f1000),             /* ldr   r1, [pc] */
+    ARM_INSN(0xe08ff001),             /* add   pc, pc, r1 */
+    DATA_WORD(0, R_ARM_REL32, -4),    /* dcd   R_ARM_REL32(X-4) */
+};
+
+/* V4T Thumb -> TLS trampoline.  lowest common denominator, which is a
+   long PIC stub.  We can use r1 as a scratch -- and cannot use ip.  */
+static const insn_sequence elf32_arm_stub_long_branch_v4t_thumb_tls_pic[] =
+{
+    THUMB16_INSN(0x4778),             /* bx   pc */
+    THUMB16_INSN(0x46c0),             /* nop */
+    ARM_INSN(0xe59f1000),             /* ldr  r1, [pc, #0] */
+    ARM_INSN(0xe081f00f),             /* add  pc, r1, pc */
+    DATA_WORD(0, R_ARM_REL32, -4),    /* dcd  R_ARM_REL32(X) */
+};
+
 /* Cortex-A8 erratum-workaround stubs.  */
 
 /* Stub used for conditional branches (which may be beyond +/-1MB away, so we
@@ -2218,6 +2347,8 @@ static const insn_sequence elf32_arm_stub_a8_veneer_blx[] =
   DEF_STUB(long_branch_v4t_arm_thumb_pic) \
   DEF_STUB(long_branch_v4t_thumb_arm_pic) \
   DEF_STUB(long_branch_thumb_only_pic) \
+  DEF_STUB(long_branch_any_tls_pic) \
+  DEF_STUB(long_branch_v4t_thumb_tls_pic) \
   DEF_STUB(a8_veneer_b_cond) \
   DEF_STUB(a8_veneer_b) \
   DEF_STUB(a8_veneer_bl) \
@@ -2426,6 +2557,9 @@ struct elf_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;
+
   /* Zero to warn when linking objects with incompatible enum sizes.  */
   int no_enum_size_warning;
 
@@ -2439,6 +2573,9 @@ struct elf_arm_obj_tdata
 #define elf32_arm_local_got_tls_type(bfd) \
   (elf_arm_tdata (bfd)->local_got_tls_type)
 
+#define elf32_arm_local_tlsdesc_gotent(bfd) \
+  (elf_arm_tdata (bfd)->local_tlsdesc_gotent)
+
 #define is_arm_elf(bfd) \
   (bfd_get_flavour (bfd) == bfd_target_elf_flavour \
    && elf_tdata (bfd) != NULL \
@@ -2478,8 +2615,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;
+
     /* The symbol marking the real symbol location for exported thumb
        symbols with Arm stubs.  */
     struct elf_link_hash_entry *export_glue;
@@ -2516,6 +2659,9 @@ struct map_stub
   asection *stub_sec;
 };
 
+#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
 {
@@ -2594,6 +2740,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 *sdynbss;
   asection *srelbss;
@@ -2601,6 +2753,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_arm_trampoline.  */
+  bfd_vma tls_trampoline;
+
   /* Data for R_ARM_TLS_LDM32 relocations.  */
   union
   {
@@ -2614,6 +2779,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;
+
   /* The stub hash table.  */
   struct bfd_hash_table stub_hash_table;
 
@@ -2663,6 +2832,7 @@ elf32_arm_link_hash_newfunc (struct bfd_hash_entry * entry,
     {
       ret->dyn_relocs = NULL;
       ret->tls_type = GOT_UNKNOWN;
+      ret->tlsdesc_got = (bfd_vma) -1;
       ret->plt_thumb_refcount = 0;
       ret->plt_maybe_thumb_refcount = 0;
       ret->plt_got_offset = -1;
@@ -2877,6 +3047,11 @@ elf32_arm_link_hash_table_create (bfd *abfd)
   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->bx_glue_size = 0;
@@ -3075,7 +3250,8 @@ arm_type_of_stub (struct bfd_link_info *info,
 
   branch_offset = (bfd_signed_vma)(destination - location);
 
-  if (r_type == R_ARM_THM_CALL || r_type == R_ARM_THM_JUMP24)
+  if (r_type == R_ARM_THM_CALL || r_type == R_ARM_THM_JUMP24
+      || r_type == R_ARM_THM_TLS_CALL)
     {
       /* Handle cases where:
         - this call goes too far (different Thumb/Thumb2 max
@@ -3092,7 +3268,8 @@ arm_type_of_stub (struct bfd_link_info *info,
              && (branch_offset > THM2_MAX_FWD_BRANCH_OFFSET
                  || (branch_offset < THM2_MAX_BWD_BRANCH_OFFSET)))
          || ((st_type != STT_ARM_TFUNC)
-             && (((r_type == R_ARM_THM_CALL) && !globals->use_blx)
+             && (((r_type == R_ARM_THM_CALL
+                   || r_type == R_ARM_THM_TLS_CALL) && !globals->use_blx)
                  || (r_type == R_ARM_THM_JUMP24))
              && !use_plt))
        {
@@ -3143,18 +3320,21 @@ arm_type_of_stub (struct bfd_link_info *info,
                     sym_sec->owner, input_bfd, name);
                }
 
-             stub_type = (info->shared | globals->pic_veneer)
+             stub_type =
+               (info->shared | globals->pic_veneer)
                /* PIC stubs.  */
-               ? ((globals->use_blx
-                   && (r_type ==R_ARM_THM_CALL))
-                  /* V5T and above.  */
-                  ? arm_stub_long_branch_any_arm_pic
-                  /* V4T PIC stub.  */
-                  : arm_stub_long_branch_v4t_thumb_arm_pic)
+               ? (r_type == R_ARM_THM_TLS_CALL
+                  /* TLS PIC stubs */
+                  ? (globals->use_blx ? arm_stub_long_branch_any_tls_pic
+                     : arm_stub_long_branch_v4t_thumb_tls_pic)
+                  : ((globals->use_blx && r_type == R_ARM_THM_CALL)
+                     /* V5T PIC and above.  */
+                     ? arm_stub_long_branch_any_arm_pic
+                     /* V4T PIC stub.  */
+                     : arm_stub_long_branch_v4t_thumb_arm_pic))
 
                /* non-PIC stubs.  */
-               : ((globals->use_blx
-                   && (r_type ==R_ARM_THM_CALL))
+               : ((globals->use_blx && r_type == R_ARM_THM_CALL)
                   /* V5T and above.  */
                   ? arm_stub_long_branch_any_any
                   /* V4T.  */
@@ -3170,7 +3350,8 @@ arm_type_of_stub (struct bfd_link_info *info,
     }
   else if (r_type == R_ARM_CALL
           || r_type == R_ARM_JUMP24
-          || r_type == R_ARM_PLT32)
+          || r_type == R_ARM_PLT32
+          || r_type == R_ARM_TLS_CALL)
     {
       if (st_type == STT_ARM_TFUNC)
        {
@@ -3190,7 +3371,7 @@ arm_type_of_stub (struct bfd_link_info *info,
             the mode change (bit 24 (H) of BLX encoding).  */
          if (branch_offset > (ARM_MAX_FWD_BRANCH_OFFSET + 2)
              || (branch_offset < ARM_MAX_BWD_BRANCH_OFFSET)
-             || ((r_type == R_ARM_CALL) && !globals->use_blx)
+             || (r_type == R_ARM_CALL && !globals->use_blx)
              || (r_type == R_ARM_JUMP24)
              || (r_type == R_ARM_PLT32))
            {
@@ -3216,9 +3397,13 @@ arm_type_of_stub (struct bfd_link_info *info,
          if (branch_offset > ARM_MAX_FWD_BRANCH_OFFSET
              || (branch_offset < ARM_MAX_BWD_BRANCH_OFFSET))
            {
-             stub_type = (info->shared | globals->pic_veneer)
+             stub_type =
+               (info->shared | globals->pic_veneer)
                /* PIC stubs.  */
-               ? arm_stub_long_branch_any_arm_pic
+               ? (r_type == R_ARM_TLS_CALL
+                  /* TLS PIC Stub */
+                  ? arm_stub_long_branch_any_tls_pic
+                  : arm_stub_long_branch_any_arm_pic)
                /* non-PIC stubs.  */
                : arm_stub_long_branch_any_any;
            }
@@ -3263,7 +3448,9 @@ elf32_arm_stub_name (const asection *input_section,
        sprintf (stub_name, "%08x_%x:%x+%x_%d",
                 input_section->id & 0xffffffff,
                 sym_sec->id & 0xffffffff,
-                (int) ELF32_R_SYM (rel->r_info) & 0xffffffff,
+                ELF32_R_TYPE (rel->r_info) == R_ARM_TLS_CALL
+                || ELF32_R_TYPE (rel->r_info) == R_ARM_THM_TLS_CALL
+                ? 0 : (int) ELF32_R_SYM (rel->r_info) & 0xffffffff,
                 (int) rel->r_addend & 0xffffffff,
                 (int) stub_type);
     }
@@ -3426,6 +3613,32 @@ put_thumb_insn (struct elf32_arm_link_hash_table * htab,
     bfd_putb16 (val, ptr);
 }
 
+/* If it's possible to change R_TYPE to a more efficient access
+   model, return the new reloc type.  */
+
+static unsigned
+elf32_arm_tls_transition (struct bfd_link_info *info, int r_type, 
+                         struct elf_link_hash_entry *h)
+{
+  int is_local = (h == NULL);
+
+  if (info->shared || (h && h->root.type == bfd_link_hash_undefweak))
+    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_THM_TLS_CALL:
+    case R_ARM_TLS_DESCSEQ:
+    case R_ARM_THM_TLS_DESCSEQ:
+      return is_local ? R_ARM_TLS_LE32 : R_ARM_TLS_IE32;
+    }
+
+  return r_type;
+}
+
 static bfd_reloc_status_type elf32_arm_final_link_relocate
   (reloc_howto_type *, bfd *, bfd *, asection *, bfd_byte *,
    Elf_Internal_Rela *, bfd_vma, struct bfd_link_info *, asection *,
@@ -3453,6 +3666,8 @@ arm_stub_required_alignment (enum elf32_arm_stub_type stub_type)
     case arm_stub_long_branch_v4t_arm_thumb_pic:
     case arm_stub_long_branch_v4t_thumb_arm_pic:
     case arm_stub_long_branch_thumb_only_pic:
+    case arm_stub_long_branch_any_tls_pic:
+    case arm_stub_long_branch_v4t_thumb_tls_pic:
     case arm_stub_a8_veneer_blx:
       return 4;
     
@@ -4419,15 +4634,30 @@ elf32_arm_size_stubs (bfd *output_bfd,
                        free (internal_relocs);
                      goto error_ret_free_local;
                    }
-
-                 /* Only look for stubs on branch instructions.  */
+                 
+                 hash = NULL;
+                 if (r_indx >= symtab_hdr->sh_info)
+                   hash = elf32_arm_hash_entry
+                     (elf_sym_hashes (input_bfd)
+                      [r_indx - symtab_hdr->sh_info]);
+                 
+                 /* Only look for stubs on branch instructions, or
+                    non-relaxed TLSCALL  */
                  if ((r_type != (unsigned int) R_ARM_CALL)
                      && (r_type != (unsigned int) R_ARM_THM_CALL)
                      && (r_type != (unsigned int) R_ARM_JUMP24)
                      && (r_type != (unsigned int) R_ARM_THM_JUMP19)
                      && (r_type != (unsigned int) R_ARM_THM_XPC22)
                      && (r_type != (unsigned int) R_ARM_THM_JUMP24)
-                     && (r_type != (unsigned int) R_ARM_PLT32))
+                     && (r_type != (unsigned int) R_ARM_PLT32)
+                     && !((r_type == (unsigned int) R_ARM_TLS_CALL
+                           || r_type == (unsigned int) R_ARM_THM_TLS_CALL)
+                          && r_type == elf32_arm_tls_transition
+                              (info, r_type, &hash->root)
+                          && ((hash ? hash->tls_type
+                               : (elf32_arm_local_got_tls_type
+                                  (input_bfd)[r_indx]))
+                              & GOT_TLS_GDESC) != 0))
                    continue;
 
                  /* Now determine the call target, its name, value,
@@ -4435,9 +4665,21 @@ elf32_arm_size_stubs (bfd *output_bfd,
                  sym_sec = NULL;
                  sym_value = 0;
                  destination = 0;
-                 hash = NULL;
                  sym_name = NULL;
-                 if (r_indx < symtab_hdr->sh_info)
+                 
+                 if (r_type == (unsigned int) R_ARM_TLS_CALL
+                     || r_type == (unsigned int) R_ARM_THM_TLS_CALL)
+                   {
+                     /* A non-relaxed TLS call.  The target is the
+                        plt-resident trampoline and nothing to do
+                        with the symbol.  */
+                     BFD_ASSERT (htab->tls_trampoline > 0);
+                     sym_sec = htab->root.splt;
+                     sym_value = htab->tls_trampoline;
+                     hash = 0;
+                     st_type = STT_FUNC;
+                   }
+                 else if (!hash)
                    {
                      /* It's a local symbol.  */
                      Elf_Internal_Sym *sym;
@@ -4485,12 +4727,6 @@ elf32_arm_size_stubs (bfd *output_bfd,
                  else
                    {
                      /* It's an external symbol.  */
-                     int e_indx;
-
-                     e_indx = r_indx - symtab_hdr->sh_info;
-                     hash = ((struct elf32_arm_link_hash_entry *)
-                             elf_sym_hashes (input_bfd)[e_indx]);
-
                      while (hash->root.root.type == bfd_link_hash_indirect
                             || hash->root.root.type == bfd_link_hash_warning)
                        hash = ((struct elf32_arm_link_hash_entry *)
@@ -6743,6 +6979,148 @@ elf32_arm_abs12_reloc (bfd *abfd, void *data, bfd_vma value)
   return bfd_reloc_ok;
 }
 
+/* Handle TLS relaxations.  Relaxing is possible for symbols that use
+   R_ARM_GOTDESC, R_ARM_{,THM_}TLS_CALL or
+   R_ARM_{,THM_}TLS_DESCSEQ relocations, during a static link.
+
+   Return bfd_reloc_ok if we're done, bfd_reloc_continue if the caller
+   is to then call final_link_relocate.  Return other values in the
+   case of error.  */
+
+static bfd_reloc_status_type 
+elf32_arm_tls_relax (struct elf32_arm_link_hash_table *globals,
+                    bfd *input_bfd, asection *input_sec, bfd_byte *contents, 
+                    Elf_Internal_Rela *rel, unsigned long is_local)
+{
+  unsigned long insn;
+  
+  switch (ELF32_R_TYPE (rel->r_info))
+    {
+    default:
+      return bfd_reloc_notsupported;
+      
+    case R_ARM_TLS_GOTDESC:
+      if (is_local)
+       insn = 0;
+      else
+       {
+         insn = bfd_get_32 (input_bfd, contents + rel->r_offset);
+         if (insn & 1)
+           insn -= 5; /* THUMB */
+         else
+           insn -= 8; /* ARM */
+       }
+      bfd_put_32 (input_bfd, insn, contents + rel->r_offset);
+      return bfd_reloc_continue;
+
+    case R_ARM_THM_TLS_DESCSEQ:
+      /* Thumb insn.  */
+      insn = bfd_get_16 (input_bfd, contents + rel->r_offset);
+      if ((insn & 0xff78) == 0x4478)     /* add rx, pc */
+       {
+         if (is_local)
+           /* nop */
+           bfd_put_16 (input_bfd, 0x46c0, contents + rel->r_offset);
+       }
+      else if ((insn & 0xffc0) == 0x6840)  /* ldr rx,[ry,#4] */
+       {
+         if (is_local)
+           /* nop */
+           bfd_put_16 (input_bfd, 0x46c0, contents + rel->r_offset);
+         else
+           /* ldr rx,[ry] */
+           bfd_put_16 (input_bfd, insn & 0xf83f, contents + rel->r_offset);
+       }
+      else if ((insn & 0xff87) == 0x4780)  /* blx rx */
+       {
+         if (is_local)
+           /* nop */
+           bfd_put_16 (input_bfd, 0x46c0, contents + rel->r_offset);
+         else
+           /* mov r0, rx */
+           bfd_put_16 (input_bfd, 0x4600 | (insn & 0x78),
+                       contents + rel->r_offset);
+       }
+      else
+       {
+         if ((insn & 0xf000) == 0xf000 || (insn & 0xf800) == 0xe800)
+           /* It's a 32 bit instruction, fetch the rest of it for
+              error generation.  */
+           insn = (insn << 16)
+             | bfd_get_16 (input_bfd, contents + rel->r_offset + 2);
+         (*_bfd_error_handler)
+           (_("%B(%A+0x%lx):unexpected Thumb instruction '0x%x' in TLS trampoline"),
+            input_bfd, input_sec, (unsigned long)rel->r_offset, insn);
+         return bfd_reloc_notsupported;
+       }
+      break;
+      
+    case R_ARM_TLS_DESCSEQ:
+      /* arm insn.  */
+      insn = bfd_get_32 (input_bfd, contents + rel->r_offset);
+      if ((insn & 0xffff0ff0) == 0xe08f0000) /* add rx,pc,ry */
+       {
+         if (is_local)
+           /* mov rx, ry */
+           bfd_put_32 (input_bfd, 0xe1a00000 | (insn & 0xffff),
+                       contents + rel->r_offset);
+       }
+      else if ((insn & 0xfff00fff) == 0xe5900004) /* ldr rx,[ry,#4]*/
+       {
+         if (is_local)
+           /* nop */
+           bfd_put_32 (input_bfd, 0xe1a00000, contents + rel->r_offset);
+         else
+           /* ldr rx,[ry] */
+           bfd_put_32 (input_bfd, insn & 0xfffff000,
+                       contents + rel->r_offset);
+       }
+      else if ((insn & 0xfffffff0) == 0xe12fff30) /* blx rx */
+       {
+         if (is_local)
+           /* nop */
+           bfd_put_32 (input_bfd, 0xe1a00000, contents + rel->r_offset);
+         else
+           /* mov r0, rx */
+           bfd_put_32 (input_bfd, 0xe1a00000 | (insn & 0xf),
+                       contents + rel->r_offset);
+       }
+      else
+       {
+         (*_bfd_error_handler)
+           (_("%B(%A+0x%lx):unexpected ARM instruction '0x%x' in TLS trampoline"),
+            input_bfd, input_sec, (unsigned long)rel->r_offset, insn);
+         return bfd_reloc_notsupported;
+       }
+      break;
+
+    case R_ARM_TLS_CALL:
+      /* GD->IE relaxation, turn the instruction into 'nop' or
+        'ldr r0, [pc,r0]'  */
+      insn = is_local ? 0xe1a00000 : 0xe79f0000;
+      bfd_put_32 (input_bfd, insn, contents + rel->r_offset);
+      break;
+      
+    case R_ARM_THM_TLS_CALL:
+      /* GD->IE relaxation */
+      if (!is_local)
+       /* add r0,pc; ldr r0, [r0]  */
+       insn = 0x44786800;
+      else if (arch_has_thumb2_nop (globals))
+       /* nop.w */
+       insn = 0xf3af8000;
+      else
+       /* nop; nop */
+       insn = 0xbf00bf00;
+       
+      bfd_put_16 (input_bfd, insn >> 16, contents + rel->r_offset);
+      bfd_put_16 (input_bfd, insn & 0xffff, contents + rel->r_offset + 2);
+      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
@@ -6834,6 +7212,7 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
   unsigned long                 r_symndx;
   bfd_byte *                    hit_data = contents + rel->r_offset;
   bfd_vma *                     local_got_offsets;
+  bfd_vma *                     local_tlsdesc_gotents;
   asection *                    sgot = NULL;
   asection *                    splt = NULL;
   asection *                    sreloc = NULL;
@@ -6851,6 +7230,11 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
   /* Some relocation types map to different relocations depending on the
      target.  We pick the right one here.  */
   r_type = arm_real_reloc_type (globals, r_type);
+
+  /* It is possible to have linker relaxations on some TLS access
+     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);
 
@@ -6870,6 +7254,8 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
   splt = globals->root.splt;
   srelgot = globals->root.srelgot;
   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)
@@ -8010,17 +8396,20 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
                                         rel->r_addend);
       }
 
+    case R_ARM_TLS_CALL:
+    case R_ARM_THM_TLS_CALL:
     case R_ARM_TLS_GD32:
     case R_ARM_TLS_IE32:
+    case R_ARM_TLS_GOTDESC:
+    case R_ARM_TLS_DESCSEQ:
+    case R_ARM_THM_TLS_DESCSEQ:
       {
-       bfd_vma off;
-       int indx;
+       bfd_vma off, offplt;
+       int indx = 0;
        char tls_type;
 
-       if (sgot == NULL)
-         abort ();
+       BFD_ASSERT (sgot != NULL);
 
-       indx = 0;
        if (h != NULL)
          {
            bfd_boolean dyn;
@@ -8033,18 +8422,23 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
                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
          {
-           if (local_got_offsets == NULL)
-             abort ();
+           BFD_ASSERT (local_got_offsets != NULL);
            off = local_got_offsets[r_symndx];
+           offplt = local_tlsdesc_gotents[r_symndx];
            tls_type = elf32_arm_local_got_tls_type (input_bfd)[r_symndx];
          }
 
-       if (tls_type == GOT_UNKNOWN)
-         abort ();
+       /* 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; 
+
+       BFD_ASSERT (tls_type != GOT_UNKNOWN);
 
        if ((off & 1) != 0)
          off &= ~1;
@@ -8065,12 +8459,49 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
                    || h->root.type != bfd_link_hash_undefweak))
              {
                need_relocs = TRUE;
-               if (srelgot == NULL)
-                 abort ();
-               loc = srelgot->contents;
-               loc += srelgot->reloc_count * RELOC_SIZE (globals);
+               BFD_ASSERT (srelgot != NULL);
              }
 
+           if (tls_type & GOT_TLS_GDESC)
+             {
+               /* We should have relaxed, unless this is an undefined
+                  weak symbol.  */
+               BFD_ASSERT ((h && (h->root.type == bfd_link_hash_undefweak))
+                           || info->shared);
+               BFD_ASSERT (globals->sgotplt_jump_table_size + offplt + 8
+                            <= globals->root.sgotplt->size);
+
+               outrel.r_addend = 0;
+               outrel.r_offset = (globals->root.sgotplt->output_section->vma
+                                  + globals->root.sgotplt->output_offset
+                                  + offplt
+                                  + globals->sgotplt_jump_table_size);
+               
+               outrel.r_info = ELF32_R_INFO (indx, R_ARM_TLS_DESC);
+               sreloc = globals->root.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);
+
+               /* For globals, the first word in the relocation gets
+                  the relocation index and the top bit set, or zero,
+                  if we're binding now.  For locals, it gets the
+                  symbol's offset in the tls section.  */
+               bfd_put_32 (output_bfd,
+                           !h ? value - elf_hash_table (info)->tls_sec->vma
+                           : info->flags & DF_BIND_NOW ? 0
+                           : 0x80000000 | ELF32_R_SYM (outrel.r_info),
+                           globals->root.sgotplt->contents + offplt +
+                           globals->sgotplt_jump_table_size);
+               
+               /* Second word in the relocation is always zero.  */
+               bfd_put_32 (output_bfd, 0,
+                           globals->root.sgotplt->contents + offplt +
+                           globals->sgotplt_jump_table_size + 4);
+             }
            if (tls_type & GOT_TLS_GD)
              {
                if (need_relocs)
@@ -8084,10 +8515,10 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
                    if (globals->use_rel)
                      bfd_put_32 (output_bfd, outrel.r_addend,
                                  sgot->contents + cur_off);
+                   loc = srelgot->contents;
+                   loc += srelgot->reloc_count++ * RELOC_SIZE (globals);
 
                    SWAP_RELOC_OUT (globals) (output_bfd, &outrel, loc);
-                   srelgot->reloc_count++;
-                   loc += RELOC_SIZE (globals);
 
                    if (indx == 0)
                      bfd_put_32 (output_bfd, value - dtpoff_base (info),
@@ -8103,10 +8534,10 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
                          bfd_put_32 (output_bfd, outrel.r_addend,
                                      sgot->contents + cur_off + 4);
 
+                       loc = srelgot->contents;
+                       loc += srelgot->reloc_count++ * RELOC_SIZE (globals);
 
                        SWAP_RELOC_OUT (globals) (output_bfd, &outrel, loc);
-                       srelgot->reloc_count++;
-                       loc += RELOC_SIZE (globals);
                      }
                  }
                else
@@ -8142,9 +8573,10 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
                      bfd_put_32 (output_bfd, outrel.r_addend,
                                  sgot->contents + cur_off);
 
+                   loc = srelgot->contents;
+                   loc += srelgot->reloc_count++ * RELOC_SIZE (globals);
+
                    SWAP_RELOC_OUT (globals) (output_bfd, &outrel, loc);
-                   srelgot->reloc_count++;
-                   loc += RELOC_SIZE (globals);
                  }
                else
                  bfd_put_32 (output_bfd, tpoff (info, value),
@@ -8160,8 +8592,142 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
 
        if ((tls_type & GOT_TLS_GD) && r_type != R_ARM_TLS_GD32)
          off += 8;
-       value = sgot->output_section->vma + 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
+           || ELF32_R_TYPE(rel->r_info) == R_ARM_THM_TLS_CALL)
+         {
+           bfd_signed_vma offset;
+           enum elf32_arm_stub_type stub_type
+             = arm_type_of_stub (info, input_section, rel, &sym_flags,
+                                 (struct elf32_arm_link_hash_entry *)h,
+                                 globals->tls_trampoline, globals->root.splt,
+                                 input_bfd, sym_name);
+
+           if (stub_type != arm_stub_none)
+             {
+               struct elf32_arm_stub_hash_entry *stub_entry
+                 = elf32_arm_get_stub_entry
+                 (input_section, globals->root.splt, 0, rel,
+                  globals, stub_type);
+               offset = (stub_entry->stub_offset
+                         + stub_entry->stub_sec->output_offset
+                         + stub_entry->stub_sec->output_section->vma);
+             }
+           else
+             offset = (globals->root.splt->output_section->vma
+                       + globals->root.splt->output_offset
+                       + globals->tls_trampoline);
+
+           if (ELF32_R_TYPE(rel->r_info) == R_ARM_TLS_CALL)
+             {
+               unsigned long inst;
+               
+               offset -= (input_section->output_section->vma +
+                          input_section->output_offset + rel->r_offset + 8);
+
+               inst = offset >> 2;
+               inst &= 0x00ffffff;
+               value = inst | (globals->use_blx ? 0xfa000000 : 0xeb000000);
+             }
+           else
+             {
+               /* Thumb blx encodes the offset in a complicated
+                  fashion.  */
+               unsigned upper_insn, lower_insn;
+               unsigned neg;
+
+               offset -= (input_section->output_section->vma + 
+                          input_section->output_offset
+                          + rel->r_offset + 4);
+           
+               /* Round up the offset to a word boundary */
+               offset = (offset + 2) & ~2;
+               neg = offset < 0;
+               upper_insn = (0xf000
+                             | ((offset >> 12) & 0x3ff)
+                             | (neg << 10));
+               lower_insn = (0xc000
+                             | (((!((offset >> 23) & 1)) ^ neg) << 13)
+                             | (((!((offset >> 22) & 1)) ^ neg) << 11)
+                             | ((offset >> 1) & 0x7ff));
+               bfd_put_16 (input_bfd, upper_insn, hit_data);
+               bfd_put_16 (input_bfd, lower_insn, hit_data + 2);
+               return bfd_reloc_ok;
+             }
+         }
+       /* 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;
+           unsigned thumb;
+           
+           data = bfd_get_32 (input_bfd, hit_data);
+           thumb = data & 1;
+           data &= ~1u;
+           
+           if (thumb)
+             {
+               insn = bfd_get_16 (input_bfd, contents + rel->r_offset - data);
+               if ((insn & 0xf000) == 0xf000 || (insn & 0xf800) == 0xe800)
+                 insn = (insn << 16)
+                   | bfd_get_16 (input_bfd,
+                                 contents + rel->r_offset - data + 2);
+               if ((insn & 0xf800c000) == 0xf000c000)
+                 /* bl/blx */
+                 value = -6;
+               else if ((insn & 0xffffff00) == 0x4400)
+                 /* add */
+                 value = -5;
+               else
+                 {
+                   (*_bfd_error_handler)
+                     (_("%B(%A+0x%lx):unexpected Thumb instruction '0x%x' referenced by TLS_GOTDESC"),
+                      input_bfd, input_section,
+                      (unsigned long)rel->r_offset, insn);
+                   return bfd_reloc_notsupported;
+                 }
+             }
+           else
+             {
+               insn = bfd_get_32 (input_bfd, contents + rel->r_offset - data);
+
+               switch (insn >> 24)
+                 {
+                 case 0xeb:  /* bl */
+                 case 0xfa:  /* blx */
+                   value = -4;
+                   break;
+
+                 case 0xe0:    /* add */
+                   value = -8;
+                   break;
+                   
+                 default:
+                   (*_bfd_error_handler)
+                     (_("%B(%A+0x%lx):unexpected ARM instruction '0x%x' referenced by TLS_GOTDESC"),
+                      input_bfd, input_section,
+                      (unsigned long)rel->r_offset, insn);
+                   return bfd_reloc_notsupported;
+                 }
+             }
+           value += ((globals->root.sgotplt->output_section->vma
+                      + globals->root.sgotplt->output_offset + off)
+                     - (input_section->output_section->vma
+                        + input_section->output_offset
+                        + rel->r_offset)
+                     + globals->sgotplt_jump_table_size);
+         }
+       else
+         value = ((globals->root.sgot->output_section->vma
+                   + globals->root.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,
@@ -8789,7 +9355,16 @@ 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_IE32)
+   || (R_TYPE) == R_ARM_TLS_IE32       \
+   || IS_ARM_TLS_GNU_RELOC (R_TYPE))
+
+/* 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_THM_TLS_CALL   \
+   || (R_TYPE) == R_ARM_TLS_DESCSEQ    \
+   || (R_TYPE) == R_ARM_THM_TLS_DESCSEQ)
 
 /* Relocate an ARM ELF section.  */
 
@@ -9032,12 +9607,33 @@ elf32_arm_relocate_section (bfd *                  output_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, &error_message);
+      /* 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) != (unsigned)r_type)
+        || (IS_ARM_TLS_GNU_RELOC (r_type)
+            && !((h ? elf32_arm_hash_entry (h)->tls_type : 
+                  elf32_arm_local_got_tls_type (input_bfd)[r_symndx])
+                 & GOT_TLS_GDESC)))
+       {
+        r = elf32_arm_tls_relax (globals, input_bfd, input_section,
+                                 contents, rel, h == NULL);
+        /* This may have been marked unresolved because it came from
+           a shared library.  But we've just dealt with that.  */
+        unresolved_reloc = 0;
+       }
+     else
+       r = bfd_reloc_continue;
+     
+     if (r == bfd_reloc_continue)
+       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, &error_message);
 
       /* Dynamic relocs are not propagated for SEC_DEBUGGING sections
         because such sections are not SEC_ALLOC and thus ld.so will
@@ -10780,12 +11376,19 @@ elf32_arm_check_relocs (bfd *abfd, struct bfd_link_info *info,
 
       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_THM_TLS_DESCSEQ:
+         case R_ARM_TLS_CALL:
+         case R_ARM_THM_TLS_CALL:
            /* This symbol requires a global offset table entry.  */
            {
              int tls_type, old_tls_type;
@@ -10793,7 +11396,14 @@ elf32_arm_check_relocs (bfd *abfd, struct bfd_link_info *info,
              switch (r_type)
                {
                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_THM_TLS_CALL:
+               case R_ARM_TLS_DESCSEQ: case R_ARM_THM_TLS_DESCSEQ:
+                 tls_type = GOT_TLS_GDESC; break;
+                 
                default: tls_type = GOT_NORMAL; break;
                }
 
@@ -10813,27 +11423,44 @@ elf32_arm_check_relocs (bfd *abfd, struct bfd_link_info *info,
                      bfd_size_type size;
 
                      size = symtab_hdr->sh_info;
-                     size *= (sizeof (bfd_signed_vma) + sizeof (char));
+                     size *= (sizeof (bfd_signed_vma)
+                              + sizeof (bfd_vma) + sizeof (char));
                      local_got_refcounts = (bfd_signed_vma *)
                           bfd_zalloc (abfd, size);
                      if (local_got_refcounts == NULL)
                        return FALSE;
                      elf_local_got_refcounts (abfd) = local_got_refcounts;
+                     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 *) (elf32_arm_local_tlsdesc_gotent (abfd)
+                                   + symtab_hdr->sh_info);
                    }
                  local_got_refcounts[r_symndx] += 1;
                  old_tls_type = elf32_arm_local_got_tls_type (abfd) [r_symndx];
                }
 
-             /* 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.  */
+             /* If a variable is accessed with both tls 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.  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)
                {
                  if (h != NULL)
@@ -11454,12 +12081,14 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf)
            {
              /* 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->root.sgotplt->size;
+             eh->plt_got_offset = (htab->root.sgotplt->size
+                                   - 8 * htab->num_tls_desc);
              htab->root.sgotplt->size += 4;
            }
 
          /* We also need to make an entry in the .rel(a).plt section.  */
          htab->root.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,
@@ -11489,6 +12118,9 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf)
       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;
@@ -11518,9 +12150,28 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf)
            s->size += 4;
          else
            {
+              if (tls_type & GOT_TLS_GDESC)
+               {
+                 /* R_ARM_TLS_DESC needs 2 GOT slots.  */
+                 eh->tlsdesc_got
+                   = (htab->root.sgotplt->size
+                      - elf32_arm_compute_jump_table_size (htab));
+                 htab->root.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.  */
-               s->size += 8;
+               {
+                 /* R_ARM_TLS_GD32 needs 2 consecutive GOT slots.  If
+                    the symbol is both GD and GDESC, got.offset may
+                    have been overwritten.  */
+                 h->got.offset = s->size;
+                 s->size += 8;
+               }
+
              if (tls_type & GOT_TLS_IE)
                /* R_ARM_TLS_IE32 needs one GOT slot.  */
                s->size += 4;
@@ -11545,8 +12196,17 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf)
              if (tls_type & GOT_TLS_GD)
                htab->root.srelgot->size += RELOC_SIZE (htab);
 
-             if ((tls_type & GOT_TLS_GD) && indx != 0)
-               htab->root.srelgot->size += RELOC_SIZE (htab);
+             if (tls_type & GOT_TLS_GDESC) 
+               {
+                 htab->root.srelplt->size += RELOC_SIZE (htab); 
+                 /* GDESC needs a trampoline to jump to.  */
+                 htab->tls_trampoline = -1;
+               }
+
+             /* Only GD needs it.  GDESC just emits one relocation per
+                2 entries.  */
+             if ((tls_type & GOT_TLS_GD) && indx != 0)  
+               htab->root.srelgot->size += RELOC_SIZE (htab); 
            }
          else if ((ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
                    || h->root.type != bfd_link_hash_undefweak)
@@ -11788,6 +12448,7 @@ elf32_arm_size_dynamic_sections (bfd * output_bfd ATTRIBUTE_UNUSED,
       bfd_signed_vma *local_got;
       bfd_signed_vma *end_local_got;
       char *local_tls_type;
+      bfd_vma *local_tlsdesc_gotent;
       bfd_size_type locsymcount;
       Elf_Internal_Shdr *symtab_hdr;
       asection *srel;
@@ -11836,23 +12497,49 @@ elf32_arm_size_dynamic_sections (bfd * output_bfd ATTRIBUTE_UNUSED,
       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->root.sgot;
       srel = htab->root.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->root.sgotplt->size
+                   - elf32_arm_compute_jump_table_size (htab);
+                 htab->root.sgotplt->size += 8;
+                 *local_got = (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 (*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)
+             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 && !(*local_tls_type & GOT_TLS_GDESC))
+                 || *local_tls_type & GOT_TLS_GD)
                srel->size += RELOC_SIZE (htab);
+
+             if (info->shared && *local_tls_type & GOT_TLS_GDESC)
+               {
+                 htab->root.srelplt->size += RELOC_SIZE (htab);
+                 htab->tls_trampoline = -1;
+               }
            }
          else
            *local_got = (bfd_vma) -1;
@@ -11894,6 +12581,34 @@ elf32_arm_size_dynamic_sections (bfd * output_bfd ATTRIBUTE_UNUSED,
   /* Allocate space for the glue sections now that we've sized them.  */
   bfd_elf32_arm_allocate_interworking_sections (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->root.srelplt)
+    htab->sgotplt_jump_table_size = elf32_arm_compute_jump_table_size(htab);
+
+  if (htab->tls_trampoline)
+    {
+      if (htab->root.splt->size == 0)
+       htab->root.splt->size += htab->plt_header_size;
+      
+      htab->tls_trampoline = htab->root.splt->size;
+      htab->root.splt->size += htab->plt_entry_size;
+      
+      /* 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_got = htab->root.sgot->size;
+         htab->root.sgot->size += 4;
+
+         htab->dt_tlsdesc_plt = htab->root.splt->size;
+         htab->root.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.  */
@@ -11984,6 +12699,11 @@ elf32_arm_size_dynamic_sections (bfd * output_bfd ATTRIBUTE_UNUSED,
                                     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)
@@ -12024,6 +12744,49 @@ elf32_arm_size_dynamic_sections (bfd * output_bfd ATTRIBUTE_UNUSED,
   return TRUE;
 }
 
+/* Size sections even though 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;
+
+  if (info->relocatable)
+    return TRUE;
+
+  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.  */
 
@@ -12240,7 +13003,7 @@ elf32_arm_finish_dynamic_symbol (bfd * output_bfd,
     }
 
   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;
@@ -12321,6 +13084,24 @@ elf32_arm_finish_dynamic_symbol (bfd * output_bfd,
   return TRUE;
 }
 
+static void
+arm_put_trampoline (struct elf32_arm_link_hash_table *htab, bfd *output_bfd,
+                   void *contents,
+                   const unsigned long *template, unsigned count)
+{
+  unsigned ix;
+  
+  for (ix = 0; ix != count; ix++)
+    {
+      unsigned long insn = template[ix];
+
+      /* Emit mov pc,rx if bx is not permitted.  */
+      if (htab->fix_v4bx == 1 && (insn & 0x0ffffff0) == 0x012fff10)
+       insn = (insn & 0xf000000f) | 0x01a0f000;
+      put_arm_insn (htab, output_bfd, insn, (char *)contents + ix*4);
+    }
+}
+
 /* Finish up the dynamic sections.  */
 
 static bfd_boolean
@@ -12474,6 +13255,20 @@ elf32_arm_finish_dynamic_sections (bfd * output_bfd, struct bfd_link_info * info
                }
              break;
 
+           case DT_TLSDESC_PLT:
+              s = htab->root.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->root.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:
@@ -12563,6 +13358,41 @@ elf32_arm_finish_dynamic_sections (bfd * output_bfd, struct bfd_link_info * info
       if (splt->output_section->owner == output_bfd)
        elf_section_data (splt->output_section)->this_hdr.sh_entsize = 4;
 
+      if (htab->dt_tlsdesc_plt)
+       {
+         bfd_vma got_address
+           = sgot->output_section->vma + sgot->output_offset;
+         bfd_vma gotplt_address = (htab->root.sgot->output_section->vma
+                                   + htab->root.sgot->output_offset);
+         bfd_vma plt_address
+           = splt->output_section->vma + splt->output_offset;
+
+         arm_put_trampoline (htab, output_bfd, 
+                             splt->contents + htab->dt_tlsdesc_plt,
+                             dl_tlsdesc_lazy_trampoline, 6);
+
+         bfd_put_32 (output_bfd,
+                     gotplt_address + htab->dt_tlsdesc_got
+                     - (plt_address + htab->dt_tlsdesc_plt)
+                     - dl_tlsdesc_lazy_trampoline[6],
+                     splt->contents + htab->dt_tlsdesc_plt + 24);
+         bfd_put_32 (output_bfd,
+                     got_address - (plt_address + htab->dt_tlsdesc_plt)
+                     - dl_tlsdesc_lazy_trampoline[7],
+                     splt->contents + htab->dt_tlsdesc_plt + 24 + 4);
+       }
+
+      if (htab->tls_trampoline)
+       {
+         arm_put_trampoline (htab, output_bfd, 
+                             splt->contents + htab->tls_trampoline,
+                             tls_trampoline, 3);
+#ifdef FOUR_WORD_PLT
+         bfd_put_32 (output_bfd, 0x00000000,
+                     splt->contents + htab->tls_trampoline + 12);
+#endif 
+       }
+
       if (htab->vxworks_p && !info->shared && htab->root.splt->size > 0)
        {
          /* Correct the .rel(a).plt.unloaded relocations.  They will have
@@ -13137,6 +13967,28 @@ elf32_arm_output_arch_local_syms (bfd *output_bfd,
 #endif
     }
 
+  if (htab->dt_tlsdesc_plt != 0)
+    {
+      /* Mapping symbols for the lazy tls trampoline.  */
+      if (!elf32_arm_output_map_sym (&osi, ARM_MAP_ARM, htab->dt_tlsdesc_plt))
+       return FALSE;
+       
+      if (!elf32_arm_output_map_sym (&osi, ARM_MAP_DATA,
+                                    htab->dt_tlsdesc_plt + 24))
+       return FALSE;
+    }
+  if (htab->tls_trampoline != 0)
+    {
+      /* Mapping symbols for the tls trampoline.  */
+      if (!elf32_arm_output_map_sym (&osi, ARM_MAP_ARM, htab->tls_trampoline))
+       return FALSE;
+#ifdef FOUR_WORD_PLT
+      if (!elf32_arm_output_map_sym (&osi, ARM_MAP_DATA,
+                                    htab->tls_trampoline + 12))
+       return FALSE;
+#endif 
+    }
+  
   elf_link_hash_traverse (&htab->root, elf32_arm_output_plt_map, (void *) &osi);
   return TRUE;
 }
@@ -13795,6 +14647,7 @@ const struct elf_size_info elf32_arm_size_info =
 #define elf_backend_finish_dynamic_symbol      elf32_arm_finish_dynamic_symbol
 #define elf_backend_finish_dynamic_sections    elf32_arm_finish_dynamic_sections
 #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_init_index_section         _bfd_elf_init_2_index_sections
 #define elf_backend_post_process_headers       elf32_arm_post_process_headers
 #define elf_backend_reloc_type_class           elf32_arm_reloc_type_class
index 1cf63ceec4df87c502ee27eeaf98e481ee31f59c..8c5b3b50faa60f3fe1fdb51a9f99f5dd5c885881 100644 (file)
@@ -1377,6 +1377,12 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@",
   "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_THM_TLS_CALL",
+  "BFD_RELOC_ARM_TLS_DESCSEQ",
+  "BFD_RELOC_ARM_THM_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 30919f2662c87504cc30e32efae7a90a4b3ed07e..719eb00dfbac1be2f7a03f3246267a8205344b12 100644 (file)
@@ -2962,6 +2962,18 @@ 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_THM_TLS_CALL
+ENUMX
+  BFD_RELOC_ARM_TLS_DESCSEQ
+ENUMX
+  BFD_RELOC_ARM_THM_TLS_DESCSEQ
+ENUMX
+  BFD_RELOC_ARM_TLS_DESC
 ENUMDOC
   ARM thread-local storage relocations.
 
index 9d3d46e9f6c4b7761c4426ec56ab5f75684d8f92..63d2301ad07ee9e9a1083dfc6b324fc9e629577f 100644 (file)
@@ -1,3 +1,19 @@
+2011-01-10  Nathan Sidwell  <nathan@codesourcery.com>
+           Glauber de Oliveira Costa  <glommer@gmail.com>
+
+       * doc/c-arm.texi: Document TLSDESC and TLSCALL relocations, and
+       .tlsdescseq directive.
+       * config/tc-arm.c (arm_typed_reg_parse): Check for potential reloc
+       following a symbol.
+       (s_arm_tls_descseq): New directive.
+       (md_pseudo_table): Add it.
+       (encode_branch): Allow TLS_CALL relocs too.
+       (do_t_blx, do_t_branch23): Use encode_branch.
+       (reloc_names): Add tlsdesc and tlscall.
+       (md_apply_fix): Process tls desc relocations.
+       (tc_gen_reloc): Likewise.
+       (arm_fix_adjustable): Likewise.
+
 2011-01-07  Quentin Neill  <quentin.neill@amd.com>
 
        * config/tc-i386.c (cpu_arch): Add CPU_BMI_FLAGS.
index f4ebdc4e24901bd17cd9645cf087b78d6ad6eac3..ae389f5d8a57d5dee2ea2521a308dcc59e2f0d7b 100644 (file)
@@ -1472,6 +1472,10 @@ arm_typed_reg_parse (char **ccp, enum arm_reg_type type,
   if (reg == FAIL)
     return FAIL;
 
+  /* Do not allow regname(... to parse as a register.  */
+  if (*str == '(')
+    return FAIL;
+
   /* Do not allow a scalar (reg+index) to parse as a register.  */
   if ((atype.defined & NTA_HASINDEX) != 0)
     {
@@ -4273,6 +4277,30 @@ s_arm_eabi_attribute (int ignored ATTRIBUTE_UNUSED)
 }
 #endif /* OBJ_ELF */
 
+/* Emit a tls 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 labelling 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,
+              thumb_mode ? BFD_RELOC_ARM_THM_TLS_DESCSEQ
+              : BFD_RELOC_ARM_TLS_DESCSEQ);
+}
+
 static void s_arm_arch (int);
 static void s_arm_object_arch (int);
 static void s_arm_cpu (int);
@@ -4352,6 +4380,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},
 
@@ -7281,9 +7310,12 @@ 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)'"));
+      inst.reloc.type = inst.operands[0].imm == BFD_RELOC_ARM_PLT32
+       ? BFD_RELOC_ARM_PLT32
+       : thumb_mode ? BFD_RELOC_ARM_THM_TLS_CALL : BFD_RELOC_ARM_TLS_CALL;
     }
   else
     inst.reloc.type = (bfd_reloc_code_real_type) default_reloc;
@@ -9655,8 +9687,7 @@ do_t_blx (void)
     {
       /* No register.  This must be BLX(1).  */
       inst.instruction = 0xf000e800;
-      inst.reloc.type = BFD_RELOC_THUMB_PCREL_BLX;
-      inst.reloc.pc_rel = 1;
+      encode_branch (BFD_RELOC_THUMB_PCREL_BLX);
     }
 }
 
@@ -9734,8 +9765,15 @@ static void
 do_t_branch23 (void)
 {
   set_it_insn_type_last ();
-  inst.reloc.type   = BFD_RELOC_THUMB_PCREL_BRANCH23;
-  inst.reloc.pc_rel = 1;
+  encode_branch (BFD_RELOC_THUMB_PCREL_BRANCH23);
+  
+  /* md_apply_fix blows up with 'bl foo(PLT)' where foo is defined in
+     this file.  We used to simply ignore the PLT reloc type here --
+     the branch encoding is now needed to deal with TLSCALL relocs.
+     So if we see a PLT reloc now, put it back to how it used to be to
+     keep the preexisting behaviour.  */
+  if (inst.reloc.type == BFD_RELOC_ARM_PLT32)
+    inst.reloc.type = BFD_RELOC_THUMB_PCREL_BRANCH23;
 
 #if defined(OBJ_COFF)
   /* If the destination of the branch is a defined symbol which does not have
@@ -16517,7 +16555,13 @@ static struct reloc_entry reloc_names[] =
   { "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_prel", BFD_RELOC_ARM_GOT_PREL}, { "GOT_PREL", BFD_RELOC_ARM_GOT_PREL}
+  { "got_prel", BFD_RELOC_ARM_GOT_PREL}, { "GOT_PREL", BFD_RELOC_ARM_GOT_PREL},
+  { "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
 
@@ -20835,6 +20879,14 @@ md_apply_fix (fixS *   fixP,
       break;
 
 #ifdef OBJ_ELF
+    case BFD_RELOC_ARM_TLS_CALL:
+    case BFD_RELOC_ARM_THM_TLS_CALL:
+    case BFD_RELOC_ARM_TLS_DESCSEQ:
+    case BFD_RELOC_ARM_THM_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:
@@ -21436,6 +21488,10 @@ tc_gen_reloc (asection *section, fixS *fixp)
       return NULL;
 
 #ifdef OBJ_ELF
+    case BFD_RELOC_ARM_TLS_CALL:
+    case BFD_RELOC_ARM_THM_TLS_CALL:
+    case BFD_RELOC_ARM_TLS_DESCSEQ:
+    case BFD_RELOC_ARM_THM_TLS_DESCSEQ:
     case BFD_RELOC_ARM_GOT32:
     case BFD_RELOC_ARM_GOTOFF:
     case BFD_RELOC_ARM_GOT_PREL:
@@ -21481,6 +21537,7 @@ tc_gen_reloc (asection *section, fixS *fixp)
       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:
@@ -21742,6 +21799,11 @@ 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_THM_TLS_CALL
+      || fixP->fx_r_type == BFD_RELOC_ARM_TLS_DESCSEQ
+      || fixP->fx_r_type == BFD_RELOC_ARM_THM_TLS_DESCSEQ
       || fixP->fx_r_type == BFD_RELOC_ARM_TARGET2)
     return FALSE;
 
index d3cccf4a49828faf5e27c382d1cc0db55e35d0c9..e14cc2e0e4bcd62d5fc0c7e109505722c6f7e0ef 100644 (file)
@@ -478,6 +478,8 @@ The following relocations are supported:
 @code{TLSGD},
 @code{TLSLDM},
 @code{TLSLDO},
+@code{TLSDESC},
+@code{TLSCALL},
 @code{GOTTPOFF},
 @code{GOT_PREL}
 and
@@ -864,6 +866,12 @@ defined).  This directive also has the added property in that it marks
 the aliased symbol as being a thumb function entry point, in the same
 way that the @code{.thumb_func} directive does.
 
+@cindex @code{.tlsdescseq} directive, ARM
+@item .tlsdescseq @var{tls-variable}
+This directive is used to annotate parts of an inlined TLS descriptor
+trampoline.  Normally the trampoline is provided by the linker, and
+this directive is not needed.
+
 @c UUUUUUUUUUUUUUUUUUUUUUUUUU
 
 @cindex @code{.unreq} directive, ARM
index 67eee86d7f796c4e6c57b787f1706cd0e2e4eabf..d28da8dfe781658d0e7c65161bdb22bf9097a03f 100644 (file)
@@ -1,3 +1,9 @@
+2011-01-10  Nathan Sidwell  <nathan@codesourcery.com>
+           Glauber de Oliveira Costa  <glommer@gmail.com>
+
+       * gas/arm/tls.s: Add tlsdesc tests.
+       * gas/arm/tls.d: Adjust.
+
 2011-01-07  H.J. Lu  <hongjiu.lu@intel.com>
 
        * gas/i386/ilp32/x86-64-arch-2.d: Add bmi flag and BMI instruction
index 6401f29f53e4760aaad52807b89f69361ffccd43..727f8e4e0b96be5826900e7750693393fdefcebc 100644 (file)
 
 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        .word   0x00000000
-                       c: R_ARM_TLS_GD32       a
-  10:  00000004        .word   0x00000004
-                       10: R_ARM_TLS_LDM32     b
-  14:  00000008        .word   0x00000008
-                       14: R_ARM_TLS_IE32      c
-  18:  00000000        .word   0x00000000
-                       18: R_ARM_TLS_LE32      d
+0+00 <arm_fn>:
+   0:  e1a00000        nop                     ; .*
+                       0: R_ARM_TLS_DESCSEQ    af
+   4:  e59f0014        ldr     r0, \[pc, #20\] ; 20 .*
+   8:  fa000000        blx     8 <ae\+.*>
+                       8: R_ARM_TLS_CALL       ae
+   c:  e1a00000        nop                     ; .*
+0+10 <.arm_pool>:
+  10:  00000008        .word   0x00000008
+                       10: R_ARM_TLS_GD32      aa
+  14:  0000000c        .word   0x0000000c
+                       14: R_ARM_TLS_LDM32     ab
+  18:  00000010        .word   0x00000010
+                       18: R_ARM_TLS_IE32      ac
+  1c:  00000000        .word   0x00000000
+                       1c: R_ARM_TLS_LE32      ad
+  20:  00000018        .word   0x00000018
+                       20: R_ARM_TLS_GOTDESC   ae
+0+24 <thumb_fn>:
+  24:  46c0            nop                     ; .*
+  26:  46c0            nop                     ; .*
+                       26: R_ARM_THM_TLS_DESCSEQ       tf
+  28:  4805            ldr     r0, \[pc, #20\] ; \(40 .*\)
+  2a:  f000 e800       blx     4 <te\+0x4>
+                       2a: R_ARM_THM_TLS_CALL  te
+  2e:  46c0            nop                     ; .*
+  30:  00000002        .word   0x00000002
+                       30: R_ARM_TLS_GD32      ta
+  34:  00000006        .word   0x00000006
+                       34: R_ARM_TLS_LDM32     tb
+  38:  0000000a        .word   0x0000000a
+                       38: R_ARM_TLS_IE32      tc
+  3c:  00000000        .word   0x00000000
+                       3c: R_ARM_TLS_LE32      td
+  40:  00000017        .word   0x00000017
+                       40: R_ARM_TLS_GOTDESC   te
index 48722a42b3a200a5136918cccbb4afa5db4adc93..96a25f56f88d5fbddac0fcaed2a713c972aaf231 100644 (file)
@@ -1,14 +1,38 @@
        .text
-       .globl main
-       .type main, %function
-main:
+       .arm
+       .globl arm_fn
+       .type arm_fn, %function
+arm_fn:
+1:
+.tlsdescseq  af
        nop
-.L2:
+       ldr     r0, 1f
+2:     blx     ae(tlscall)
        nop
-       mov     pc, lr
 
+.arm_pool:
+       .word   aa(tlsgd) + (. - 1b - 8)
+       .word   ab(tlsldm) + (. - 1b- 8)
+       .word   ac(gottpoff) + (. - 1b - 8)
+       .word   ad(tpoff)
+1:     .word   ae(tlsdesc) + (. - 2b)
+       
+       .thumb
+       .globl  thumb_fn
+       .type thumb_fn, %function
+thumb_fn:
+       nop
+1:     
+.tlsdescseq tf
+       nop
+       ldr     r0, 1f
+2:     blx     te(tlscall)
+       nop
+
+       .p2align 2
 .Lpool:
-       .word   a(tlsgd) + (. - .L2 - 8)
-       .word   b(tlsldm) + (. - .L2 - 8)
-       .word   c(gottpoff) + (. - .L2 - 8)
-       .word   d(tpoff)
+       .word   ta(tlsgd) + (. - 1b - 8)
+       .word   tb(tlsldm) + (. - 1b - 8)
+       .word   tc(gottpoff) + (. - 1b - 8)
+       .word   td(tpoff)
+1:     .word   te(tlsdesc) + (. - 2b + 1)
index 47a884e210b7f806db00faaf489a9b0dcd8fd9d5..d178b641bb4f7e375e52707124d8fa88de3cc733 100644 (file)
@@ -1,3 +1,10 @@
+2011-01-10  Nathan Sidwell  <nathan@codesourcery.com>
+           Glauber de Oliveira Costa  <glommer@gmail.com>
+
+       * arm.h (R_ARM_TLS_DESC, R_ARM_TLS_GOTDESC, R_ARM_TLS_CALL,
+       R_ARM_TLS_DESCSEQ, T_ARM_THM_TLS_CALL, R_ARM_THM_TLS_DESCSEQ): New
+       relocations.
+
 2010-11-11  Mingming Sun  <mingm.sun@gmail.com>
 
        * mips.h (E_MIPS_MACH_LS3A): Defined.
index 0a5c87d58b416877c4b828ebb677ef0adc73c345..18aa5592e6aedaae01c2e516f839531bd8cdc3d0 100644 (file)
@@ -123,7 +123,7 @@ START_RELOC_NUMBERS (elf_arm_reloc_type)
   RELOC_NUMBER (R_ARM_THM_CALL,                 10)
   RELOC_NUMBER (R_ARM_THM_PC8,                  11)
   RELOC_NUMBER (R_ARM_BREL_ADJ,                 12)
-  RELOC_NUMBER (R_ARM_SWI24,                    13)   /* obsolete */
+  RELOC_NUMBER (R_ARM_TLS_DESC,          13)
   RELOC_NUMBER (R_ARM_THM_SWI8,                 14)   /* obsolete */
   RELOC_NUMBER (R_ARM_XPC25,                    15)   /* obsolete */
   RELOC_NUMBER (R_ARM_THM_XPC22,                16)   /* obsolete */
@@ -200,7 +200,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_THM_TLS_CALL,      93)
   RELOC_NUMBER (R_ARM_PLT32_ABS,                94)
   RELOC_NUMBER (R_ARM_GOT_ABS,          95)
   RELOC_NUMBER (R_ARM_GOT_PREL,                 96)
@@ -221,6 +224,7 @@ START_RELOC_NUMBERS (elf_arm_reloc_type)
   RELOC_NUMBER (R_ARM_TLS_IE12GP,      111)
   /* 112 - 127 private range */
   RELOC_NUMBER (R_ARM_ME_TOO,          128)   /* obsolete */
+  RELOC_NUMBER (R_ARM_THM_TLS_DESCSEQ  ,129)
 
   /* Extensions?  R=read-only?  */
   RELOC_NUMBER (R_ARM_RXPC25,          249)
index 0eb510647a7f6fec863320f40a70f317ed1b8f4e..0910af2b24177a88ce6cfb40615a4abbb04c6dee 100644 (file)
@@ -1,3 +1,45 @@
+2011-01-10  Nathan Sidwell  <nathan@codesourcery.com>
+           Glauber de Oliveira Costa  <glommer@gmail.com>
+
+       * ld-arm/arm-elf.exp: Added tests for new TLS handling
+       relocations.
+       * ld-arm/tls-descrelax-be32.d: New.
+       * ld-arm/tls-descrelax-be32.s: New.
+       * ld-arm/tls-descrelax-be8.d: New.
+       * ld-arm/tls-descrelax-be8.s: New.
+       * ld-arm/tls-descrelax-v7.d: New.
+       * ld-arm/tls-descrelax-v7.s: New.
+       * ld-arm/tls-descrelax.d: New.
+       * ld-arm/tls-descrelax.s: New.
+       * ld-arm/tls-descseq.d: New.
+       * ld-arm/tls-descseq.r: New.
+       * ld-arm/tls-descseq.s: New.
+       * ld-arm/tls-gdesc-got.d: New.
+       * ld-arm/tls-gdesc-got.s: New.
+       * ld-arm/tls-gdesc-nlazy.g: New.
+       * ld-arm/tls-gdesc-nlazy.s: New.
+       * ld-arm/tls-gdesc.d: New.
+       * ld-arm/tls-gdesc.r: New.
+       * ld-arm/tls-gdesc.s: New.
+       * ld-arm/tls-gdierelax.d: New.
+       * ld-arm/tls-gdierelax.s: New.
+       * ld-arm/tls-gdierelax2.d: New.
+       * ld-arm/tls-gdierelax2.s: New.
+       * ld-arm/tls-gdlerelax.d: New.
+       * ld-arm/tls-gdlerelax.s: New.
+       * ld-arm/tls-lib-loc.d: New.
+       * ld-arm/tls-lib-loc.r: New.
+       * ld-arm/tls-lib-loc.s: New.
+       * ld-arm/tls-longplt-lib.d: New.
+       * ld-arm/tls-longplt-lib.s: New.
+       * ld-arm/tls-longplt.d: New.
+       * ld-arm/tls-longplt.s: New.
+       * ld-arm/tls-mixed.r: New.
+       * ld-arm/tls-mixed.s: New.
+       * ld-arm/tls-thumb1.d: New.
+       * ld-arm/tls-thumb1.s: New.
+       * ld-arm/arm-elf.exp: New.
+
 2011-01-08  Nick Clifton  <nickc@redhat.com>
 
        * ld-misc/defsym1.d: Add a -e linker command line option.
index 80f521ec48f0a3ad862d157247d515dcff758c0e..9ba7b56097203602a6331ba9d76adb4b895589cb 100644 (file)
@@ -135,6 +135,39 @@ 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 got" "-shared -T arm-dyn.ld" "" {tls-gdesc-got.s}
+     {{objdump "-fDR -j .got" tls-gdesc-got.d}}
+     "tls-lib2-got.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 shared library gdesc local" "-shared -T arm-dyn.ld" "" {tls-lib-loc.s}
+     {{objdump -fdw tls-lib-loc.d} {objdump -Rw tls-lib-loc.r}}
+     "tls-lib-loc.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"}
+    {"TLS descseq relaxation" "-T arm-dyn.ld" "" {tls-descrelax.s}
+     {{objdump -fdw tls-descrelax.d}}
+     "tls-descrelax"}
+    {"TLS descseq relaxation v7" "-T arm-dyn.ld" "" {tls-descrelax-v7.s}
+     {{objdump -fdw tls-descrelax-v7.d}}
+     "tls-descrelax-v7"}
+    {"TLS descseq relaxation BE8" "-T arm-dyn.ld -EB --be8" "-mbig-endian" {tls-descrelax-be8.s}
+     {{objdump -fdw tls-descrelax-be8.d}}
+     "tls-descrelax-be8"}
+    {"TLS descseq relaxation BE32" "-T arm-dyn.ld -EB" "-mbig-endian" {tls-descrelax-be32.s}
+     {{objdump -fdw tls-descrelax-be32.d}}
+     "tls-descrelax-be32"}
     {"Thumb entry point" "-T arm.ld" "" {thumb-entry.s}
      {{readelf -h thumb-entry.d}}
      "thumb-entry"}
@@ -481,6 +514,21 @@ set armeabitests {
      {jump-reloc-veneers.s}
      {{objdump -d jump-reloc-veneers-long.d}}
      "jump-reloc-veneers-long"}
+    {"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 non-lazy" "-z now -shared -T arm-dyn.ld" "" {tls-gdesc.s}
+     {{readelf "-x .got" tls-gdesc-nlazy.g}}
+     "tls-lib2-nlazy.so"}
+    {"TLS long plt library" "-shared -T arm-dyn.ld --section-start .foo=0x4001000" "" {tls-longplt-lib.s}
+     {{objdump -fdw tls-longplt-lib.d}}
+     "tls-longplt-lib.so"}
+    {"TLS long plt" "-T arm-dyn.ld --section-start .foo=0x4001000 tmpdir/tls-longplt-lib.so" "" {tls-longplt.s}
+     {{objdump -fdw tls-longplt.d}}
+     "tls-longplt"}
+    {"TLS thumb1" "-shared -T arm-dyn.ld --section-start .foo=0x4001000" "" {tls-thumb1.s}
+     {{objdump -fdw tls-thumb1.d}}
+     "tls-thumb1"}
 }
 
 run_ld_link_tests $armeabitests
diff --git a/ld/testsuite/ld-arm/tls-descrelax-be32.d b/ld/testsuite/ld-arm/tls-descrelax-be32.d
new file mode 100644 (file)
index 0000000..150e331
--- /dev/null
@@ -0,0 +1,108 @@
+.*:     file format elf32-.*
+architecture: arm, flags 0x[0-9a-f]+:
+EXEC_P, HAS_SYMS, D_PAGED
+start address 0x[0-9a-f]+
+
+Disassembly of section .text:
+
+00008000 <foo>:
+    8000:      e59f0004        ldr     r0, \[pc, #4\]  ; 800c <foo\+0xc>
+    8004:      e79f0000        ldr     r0, \[pc, r0\]
+    8008:      e1a00000        nop                     ; .*
+    800c:      00008138        .word   0x00008138
+    8010:      e59f0004        ldr     r0, \[pc, #4\]  ; 801c <foo\+0x1c>
+    8014:      e79f0000        ldr     r0, \[pc, r0\]
+    8018:      e1a00000        nop                     ; .*
+    801c:      00008128        .word   0x00008128
+    8020:      e59f0004        ldr     r0, \[pc, #4\]  ; 802c <foo\+0x2c>
+    8024:      e1a00000        nop                     ; .*
+    8028:      e1a00000        nop                     ; .*
+    802c:      0000000c        .word   0x0000000c
+    8030:      e59f0004        ldr     r0, \[pc, #4\]  ; 803c <foo\+0x3c>
+    8034:      e1a00000        nop                     ; .*
+    8038:      e1a00000        nop                     ; .*
+    803c:      0000000c        .word   0x0000000c
+    8040:      e59f000c        ldr     r0, \[pc, #12\] ; 8054 <foo\+0x54>
+    8044:      e08f0000        add     r0, pc, r0
+    8048:      e5901000        ldr     r1, \[r0\]
+    804c:      e1a00001        mov     r0, r1
+    8050:      e1a00000        nop                     ; .*
+    8054:      000080f8        .word   0x000080f8
+    8058:      e59f000c        ldr     r0, \[pc, #12\] ; 806c <foo\+0x6c>
+    805c:      e08f0000        add     r0, pc, r0
+    8060:      e5901000        ldr     r1, \[r0\]
+    8064:      e1a00001        mov     r0, r1
+    8068:      e1a00000        nop                     ; .*
+    806c:      000080e0        .word   0x000080e0
+    8070:      e59f000c        ldr     r0, \[pc, #12\] ; 8084 <foo\+0x84>
+    8074:      e1a00000        nop                     ; .*
+    8078:      e1a00000        nop                     ; .*
+    807c:      e1a00000        nop                     ; .*
+    8080:      e1a00000        nop                     ; .*
+    8084:      0000000c        .word   0x0000000c
+    8088:      e59f000c        ldr     r0, \[pc, #12\] ; 809c <foo\+0x9c>
+    808c:      e1a00000        nop                     ; .*
+    8090:      e1a00000        nop                     ; .*
+    8094:      e1a00000        nop                     ; .*
+    8098:      e1a00000        nop                     ; .*
+    809c:      0000000c        .word   0x0000000c
+
+000080a0 <bar>:
+    80a0:      4801            ldr     r0, \[pc, #4\]  ; \(80a8 <bar\+0x8>\)
+    80a2:      4478            add     r0, pc
+    80a4:      6800            ldr     r0, \[r0, #0\]
+    80a6:      46c0            nop                     ; .*
+    80a8:      0000809e        .word   0x0000809e
+    80ac:      4801            ldr     r0, \[pc, #4\]  ; \(80b4 <bar\+0x14>\)
+    80ae:      4478            add     r0, pc
+    80b0:      6800            ldr     r0, \[r0, #0\]
+    80b2:      46c0            nop                     ; .*
+    80b4:      00008092        .word   0x00008092
+    80b8:      4801            ldr     r0, \[pc, #4\]  ; \(80c0 <bar\+0x20>\)
+    80ba:      4478            add     r0, pc
+    80bc:      6800            ldr     r0, \[r0, #0\]
+    80be:      46c0            nop                     ; .*
+    80c0:      0000808a        .word   0x0000808a
+    80c4:      4801            ldr     r0, \[pc, #4\]  ; \(80cc <bar\+0x2c>\)
+    80c6:      46c0            nop                     ; .*
+    80c8:      46c0            nop                     ; .*
+    80ca:      46c0            nop                     ; .*
+    80cc:      0000000c        .word   0x0000000c
+    80d0:      4801            ldr     r0, \[pc, #4\]  ; \(80d8 <bar\+0x38>\)
+    80d2:      bf00            nop
+    80d4:      bf00            nop
+    80d6:      46c0            nop                     ; .*
+    80d8:      0000000c        .word   0x0000000c
+    80dc:      4801            ldr     r0, \[pc, #4\]  ; \(80e4 <bar\+0x44>\)
+    80de:      bf00            nop
+    80e0:      bf00            nop
+    80e2:      46c0            nop                     ; .*
+    80e4:      00000014        .word   0x00000014
+    80e8:      4802            ldr     r0, \[pc, #8\]  ; \(80f4 <bar\+0x54>\)
+    80ea:      4478            add     r0, pc
+    80ec:      6801            ldr     r1, \[r0, #0\]
+    80ee:      1c08            adds    r0, r1, #0
+    80f0:      46c0            nop                     ; .*
+    80f2:      46c0            nop                     ; .*
+    80f4:      00008056        .word   0x00008056
+    80f8:      4802            ldr     r0, \[pc, #8\]  ; \(8104 <bar\+0x64>\)
+    80fa:      4478            add     r0, pc
+    80fc:      6801            ldr     r1, \[r0, #0\]
+    80fe:      4608            mov     r0, r1
+    8100:      46c0            nop                     ; .*
+    8102:      46c0            nop                     ; .*
+    8104:      00008046        .word   0x00008046
+    8108:      4802            ldr     r0, \[pc, #8\]  ; \(8114 <bar\+0x74>\)
+    810a:      46c0            nop                     ; .*
+    810c:      46c0            nop                     ; .*
+    810e:      46c0            nop                     ; .*
+    8110:      46c0            nop                     ; .*
+    8112:      46c0            nop                     ; .*
+    8114:      0000000c        .word   0x0000000c
+    8118:      4802            ldr     r0, \[pc, #8\]  ; \(8124 <bar\+0x84>\)
+    811a:      46c0            nop                     ; .*
+    811c:      46c0            nop                     ; .*
+    811e:      46c0            nop                     ; .*
+    8120:      46c0            nop                     ; .*
+    8122:      46c0            nop                     ; .*
+    8124:      0000000c        .word   0x0000000c
diff --git a/ld/testsuite/ld-arm/tls-descrelax-be32.s b/ld/testsuite/ld-arm/tls-descrelax-be32.s
new file mode 100644 (file)
index 0000000..dae5458
--- /dev/null
@@ -0,0 +1,198 @@
+@ we can relax local and non-weak globals for non-shared links
+
+       .arch   armv5te
+       .text
+       .arm
+
+       .p2align 2
+foo:
+@tlscall global, manually relaxed to IE
+       ldr     r0, 1f
+2:     ldr     r0, [pc, r0]
+       nop
+       .p2align 2
+1:     .word   gd1(gottpoff) + (. - 2b - 8)
+       
+       .p2align 2
+@tlscall global, should relax to IE
+       ldr     r0, 1f
+2:     blx     gd1(tlscall)
+       nop
+       .p2align 2
+1:     .word   gd1(tlsdesc) + (. - 2b)
+
+       .p2align 2
+@tlscall local, manually relaxed to LE
+       ldr     r0, 1f
+       nop
+       nop
+       .p2align 2
+1:     .word   ld1(tpoff)
+
+       .p2align 2
+@tlscall local, should relax to LE
+       ldr     r0, 1f
+2:     blx     ld1(tlscall)
+       nop
+       .p2align 2
+1:     .word   ld1(tlsdesc) + (. - 2b)
+
+       .p2align 2
+@open coded global, manually relaxed to IE
+       ldr     r0, 1f
+2:
+       add     r0, pc, r0
+       ldr     r1, [r0]
+       mov     r0, r1
+       nop
+       .p2align 2
+1:     .word   gd1(gottpoff) + (. - 2b - 8)
+
+       .p2align 2
+@open coded global, should relax to IE
+       ldr     r0, 1f
+2:
+.tlsdescseq gd1
+       add     r0, pc, r0
+.tlsdescseq gd1
+       ldr     r1, [r0,#4]
+.tlsdescseq gd1
+       blx     r1
+       nop
+       .p2align 2
+1:     .word   gd1(tlsdesc) + (. - 2b)
+
+       .p2align 2
+@open coded local, manually relaxed to LE
+       ldr     r0, 1f
+2:
+       nop
+       nop
+       nop
+       nop
+       .p2align 2
+1:     .word   ld1(tpoff)
+       
+       .p2align 2
+@open coded local, should relax to LE
+       ldr     r0, 1f
+2:
+.tlsdescseq ld1
+       add     r0, pc, r0
+.tlsdescseq ld1
+       ldr     r1, [r0,#4]
+.tlsdescseq ld1
+       blx     r1
+       nop
+       .p2align 2
+1:     .word   ld1(tlsdesc) + (. - 2b)
+
+
+       .thumb
+       .p2align 1
+bar:   
+@tlscall global, manually relaxed to IE
+       ldr     r0, 1f
+2:     add     r0, pc, r0
+       ldr     r0, [r0]
+       nop
+       .p2align 2
+1:     .word   gd1(gottpoff) + (. - 2b - 4)
+       
+       .p2align 1
+@tlscall global, should relax to IE
+       ldr     r0, 1f
+2:     blx     gd1(tlscall)
+       nop
+       .p2align 2
+1:     .word   gd1(tlsdesc) + (. - 2b + 1)
+
+       .p2align 1
+@tlscall global, should relax to IE
+       ldr     r0, 1f
+2:     blx     r1(tlscall)
+       nop
+       .p2align 2
+1:     .word   r1(tlsdesc) + (. - 2b + 1)
+
+       .p2align 1
+@tlscall local, manually relaxed to LE
+       ldr     r0, 1f
+       nop
+       nop
+       .p2align 2
+1:     .word   ld1(tpoff)
+
+       .p2align 1
+@tlscall local, should relax to LE
+       ldr     r0, 1f
+2:     blx     ld1(tlscall)
+       nop
+       .p2align 2
+1:     .word   ld1(tlsdesc) + (. - 2b + 1)
+
+       .p2align 1
+@tlscall local, should relax to LE
+       ldr     r0, 1f
+2:     blx     r0(tlscall)
+       nop
+       .p2align 2
+1:     .word   r0(tlsdesc) + (. - 2b + 1)
+
+       .p2align 1
+@open coded global, manually relaxed to IE
+       ldr     r0, 1f
+2:
+       add     r0, pc
+       ldr     r1, [r0]
+       mov     r0, r1
+       nop
+       .p2align 2
+1:     .word   gd1(gottpoff) + (. - 2b - 4)
+
+       .p2align 1
+@open coded global, should relax to IE
+       ldr     r0, 1f
+2:
+.tlsdescseq gd1
+       add     r0, pc
+.tlsdescseq gd1
+       ldr     r1, [r0,#4]
+.tlsdescseq gd1
+       blx     r1
+       nop
+       .p2align 2
+1:     .word   gd1(tlsdesc) + (. - 2b + 1)
+
+       .p2align 1
+@open coded local, manually relaxed to LE
+       ldr     r0, 1f
+2:
+       nop
+       nop
+       nop
+       nop
+       .p2align 2
+1:     .word   ld1(tpoff)
+       
+       .p2align 1
+@open coded local, should relax to LE
+       ldr     r0, 1f
+2:
+.tlsdescseq ld1
+       add     r0, pc
+.tlsdescseq ld1
+       ldr     r1, [r0,#4]
+.tlsdescseq ld1
+       blx     r1
+       nop
+       .p2align 2
+1:     .word   ld1(tlsdesc) + (. - 2b + 1)
+
+       .section .tdata,"awT"
+       .global gd1
+gd1:   .space 4
+ld1:   .space 4
+       .globl r1
+r1:    .space 4
+r0:    .space 4
diff --git a/ld/testsuite/ld-arm/tls-descrelax-be8.d b/ld/testsuite/ld-arm/tls-descrelax-be8.d
new file mode 100644 (file)
index 0000000..1b2159c
--- /dev/null
@@ -0,0 +1,108 @@
+.*:     file format elf32-.*
+architecture: arm, flags 0x[0-9a-f]+:
+EXEC_P, HAS_SYMS, D_PAGED
+start address 0x[0-9a-f]+
+
+Disassembly of section .text:
+
+00008000 <foo>:
+    8000:      e59f0004        ldr     r0, \[pc, #4\]  ; 800c <foo\+0xc>
+    8004:      e79f0000        ldr     r0, \[pc, r0\]
+    8008:      e320f000        nop     \{0\}
+    800c:      00008138        .word   0x00008138
+    8010:      e59f0004        ldr     r0, \[pc, #4\]  ; 801c <foo\+0x1c>
+    8014:      e79f0000        ldr     r0, \[pc, r0\]
+    8018:      e320f000        nop     \{0\}
+    801c:      00008128        .word   0x00008128
+    8020:      e59f0004        ldr     r0, \[pc, #4\]  ; 802c <foo\+0x2c>
+    8024:      e320f000        nop     \{0\}
+    8028:      e320f000        nop     \{0\}
+    802c:      0000000c        .word   0x0000000c
+    8030:      e59f0004        ldr     r0, \[pc, #4\]  ; 803c <foo\+0x3c>
+    8034:      e1a00000        nop                     ; .*
+    8038:      e320f000        nop     \{0\}
+    803c:      0000000c        .word   0x0000000c
+    8040:      e59f000c        ldr     r0, \[pc, #12\] ; 8054 <foo\+0x54>
+    8044:      e08f0000        add     r0, pc, r0
+    8048:      e5901000        ldr     r1, \[r0\]
+    804c:      e1a00001        mov     r0, r1
+    8050:      e320f000        nop     \{0\}
+    8054:      000080f8        .word   0x000080f8
+    8058:      e59f000c        ldr     r0, \[pc, #12\] ; 806c <foo\+0x6c>
+    805c:      e08f0000        add     r0, pc, r0
+    8060:      e5901000        ldr     r1, \[r0\]
+    8064:      e1a00001        mov     r0, r1
+    8068:      e320f000        nop     \{0\}
+    806c:      000080e0        .word   0x000080e0
+    8070:      e59f000c        ldr     r0, \[pc, #12\] ; 8084 <foo\+0x84>
+    8074:      e320f000        nop     \{0\}
+    8078:      e320f000        nop     \{0\}
+    807c:      e320f000        nop     \{0\}
+    8080:      e320f000        nop     \{0\}
+    8084:      0000000c        .word   0x0000000c
+    8088:      e59f000c        ldr     r0, \[pc, #12\] ; 809c <foo\+0x9c>
+    808c:      e1a00000        nop                     ; .*
+    8090:      e1a00000        nop                     ; .*
+    8094:      e1a00000        nop                     ; .*
+    8098:      e320f000        nop     \{0\}
+    809c:      0000000c        .word   0x0000000c
+
+000080a0 <bar>:
+    80a0:      4801            ldr     r0, \[pc, #4\]  ; \(80a8 <bar\+0x8>\)
+    80a2:      4478            add     r0, pc
+    80a4:      6800            ldr     r0, \[r0, #0\]
+    80a6:      46c0            nop                     ; .*
+    80a8:      0000809e        .word   0x0000809e
+    80ac:      4801            ldr     r0, \[pc, #4\]  ; \(80b4 <bar\+0x14>\)
+    80ae:      4478            add     r0, pc
+    80b0:      6800            ldr     r0, \[r0, #0\]
+    80b2:      46c0            nop                     ; \(mov r8, r8\)
+    80b4:      00008092        .word   0x00008092
+    80b8:      4801            ldr     r0, \[pc, #4\]  ; \(80c0 <bar\+0x20>\)
+    80ba:      4478            add     r0, pc
+    80bc:      6800            ldr     r0, \[r0, #0\]
+    80be:      46c0            nop                     ; \(mov r8, r8\)
+    80c0:      0000808a        .word   0x0000808a
+    80c4:      4801            ldr     r0, \[pc, #4\]  ; \(80cc <bar\+0x2c>\)
+    80c6:      46c0            nop                     ; \(mov r8, r8\)
+    80c8:      46c0            nop                     ; \(mov r8, r8\)
+    80ca:      bf00            nop
+    80cc:      0000000c        .word   0x0000000c
+    80d0:      4801            ldr     r0, \[pc, #4\]  ; \(80d8 <bar\+0x38>\)
+    80d2:      (f3af 8000)|(bf00     )         nop(.w)?
+#...
+    80d6:      46c0            nop                     ; \(mov r8, r8\)
+    80d8:      0000000c        .word   0x0000000c
+    80dc:      4801            ldr     r0, \[pc, #4\]  ; \(80e4 <bar\+0x44>\)
+    80de:      (f3af 8000)|(bf00     )         nop(.w)?
+#...
+    80e2:      46c0            nop                     ; \(mov r8, r8\)
+    80e4:      00000014        .word   0x00000014
+    80e8:      4802            ldr     r0, \[pc, #8\]  ; \(80f4 <bar\+0x54>\)
+    80ea:      4478            add     r0, pc
+    80ec:      6801            ldr     r1, \[r0, #0\]
+    80ee:      1c08            adds    r0, r1, #0
+    80f0:      46c0            nop                     ; \(mov r8, r8\)
+    80f2:      bf00            nop
+    80f4:      00008056        .word   0x00008056
+    80f8:      4802            ldr     r0, \[pc, #8\]  ; \(8104 <bar\+0x64>\)
+    80fa:      4478            add     r0, pc
+    80fc:      6801            ldr     r1, \[r0, #0\]
+    80fe:      4608            mov     r0, r1
+    8100:      46c0            nop                     ; \(mov r8, r8\)
+    8102:      bf00            nop
+    8104:      00008046        .word   0x00008046
+    8108:      4802            ldr     r0, \[pc, #8\]  ; \(8114 <bar\+0x74>\)
+    810a:      46c0            nop                     ; \(mov r8, r8\)
+    810c:      46c0            nop                     ; \(mov r8, r8\)
+    810e:      46c0            nop                     ; \(mov r8, r8\)
+    8110:      46c0            nop                     ; \(mov r8, r8\)
+    8112:      bf00            nop
+    8114:      0000000c        .word   0x0000000c
+    8118:      4802            ldr     r0, \[pc, #8\]  ; \(8124 <bar\+0x84>\)
+    811a:      46c0            nop                     ; \(mov r8, r8\)
+    811c:      46c0            nop                     ; \(mov r8, r8\)
+    811e:      46c0            nop                     ; \(mov r8, r8\)
+    8120:      46c0            nop                     ; \(mov r8, r8\)
+    8122:      bf00            nop
+    8124:      0000000c        .word   0x0000000c
diff --git a/ld/testsuite/ld-arm/tls-descrelax-be8.s b/ld/testsuite/ld-arm/tls-descrelax-be8.s
new file mode 100644 (file)
index 0000000..a8c028b
--- /dev/null
@@ -0,0 +1,198 @@
+@ we can relax local and non-weak globals for non-shared links
+
+       .arch   armv7-a
+       .text
+       .arm
+
+       .p2align 2
+foo:
+@tlscall global, manually relaxed to IE
+       ldr     r0, 1f
+2:     ldr     r0, [pc, r0]
+       nop
+       .p2align 2
+1:     .word   gd1(gottpoff) + (. - 2b - 8)
+       
+       .p2align 2
+@tlscall global, should relax to IE
+       ldr     r0, 1f
+2:     blx     gd1(tlscall)
+       nop
+       .p2align 2
+1:     .word   gd1(tlsdesc) + (. - 2b)
+
+       .p2align 2
+@tlscall local, manually relaxed to LE
+       ldr     r0, 1f
+       nop
+       nop
+       .p2align 2
+1:     .word   ld1(tpoff)
+
+       .p2align 2
+@tlscall local, should relax to LE
+       ldr     r0, 1f
+2:     blx     ld1(tlscall)
+       nop
+       .p2align 2
+1:     .word   ld1(tlsdesc) + (. - 2b)
+
+       .p2align 2
+@open coded global, manually relaxed to IE
+       ldr     r0, 1f
+2:
+       add     r0, pc, r0
+       ldr     r1, [r0]
+       mov     r0, r1
+       nop
+       .p2align 2
+1:     .word   gd1(gottpoff) + (. - 2b - 8)
+
+       .p2align 2
+@open coded global, should relax to IE
+       ldr     r0, 1f
+2:
+.tlsdescseq gd1
+       add     r0, pc, r0
+.tlsdescseq gd1
+       ldr     r1, [r0,#4]
+.tlsdescseq gd1
+       blx     r1
+       nop
+       .p2align 2
+1:     .word   gd1(tlsdesc) + (. - 2b)
+
+       .p2align 2
+@open coded local, manually relaxed to LE
+       ldr     r0, 1f
+2:
+       nop
+       nop
+       nop
+       nop
+       .p2align 2
+1:     .word   ld1(tpoff)
+       
+       .p2align 2
+@open coded local, should relax to LE
+       ldr     r0, 1f
+2:
+.tlsdescseq ld1
+       add     r0, pc, r0
+.tlsdescseq ld1
+       ldr     r1, [r0,#4]
+.tlsdescseq ld1
+       blx     r1
+       nop
+       .p2align 2
+1:     .word   ld1(tlsdesc) + (. - 2b)
+
+
+       .thumb
+       .p2align 1
+bar:   
+@tlscall global, manually relaxed to IE
+       ldr     r0, 1f
+2:     add     r0, pc, r0
+       ldr     r0, [r0]
+       nop
+       .p2align 2
+1:     .word   gd1(gottpoff) + (. - 2b - 4)
+       
+       .p2align 1
+@tlscall global, should relax to IE
+       ldr     r0, 1f
+2:     blx     gd1(tlscall)
+       nop
+       .p2align 2
+1:     .word   gd1(tlsdesc) + (. - 2b + 1)
+
+       .p2align 1
+@tlscall global, should relax to IE
+       ldr     r0, 1f
+2:     blx     r1(tlscall)
+       nop
+       .p2align 2
+1:     .word   r1(tlsdesc) + (. - 2b + 1)
+
+       .p2align 1
+@tlscall local, manually relaxed to LE
+       ldr     r0, 1f
+       nop
+       nop
+       .p2align 2
+1:     .word   ld1(tpoff)
+
+       .p2align 1
+@tlscall local, should relax to LE
+       ldr     r0, 1f
+2:     blx     ld1(tlscall)
+       nop
+       .p2align 2
+1:     .word   ld1(tlsdesc) + (. - 2b + 1)
+
+       .p2align 1
+@tlscall local, should relax to LE
+       ldr     r0, 1f
+2:     blx     r0(tlscall)
+       nop
+       .p2align 2
+1:     .word   r0(tlsdesc) + (. - 2b + 1)
+
+       .p2align 1
+@open coded global, manually relaxed to IE
+       ldr     r0, 1f
+2:
+       add     r0, pc
+       ldr     r1, [r0]
+       mov     r0, r1
+       nop
+       .p2align 2
+1:     .word   gd1(gottpoff) + (. - 2b - 4)
+
+       .p2align 1
+@open coded global, should relax to IE
+       ldr     r0, 1f
+2:
+.tlsdescseq gd1
+       add     r0, pc
+.tlsdescseq gd1
+       ldr     r1, [r0,#4]
+.tlsdescseq gd1
+       blx     r1
+       nop
+       .p2align 2
+1:     .word   gd1(tlsdesc) + (. - 2b + 1)
+
+       .p2align 1
+@open coded local, manually relaxed to LE
+       ldr     r0, 1f
+2:
+       nop
+       nop
+       nop
+       nop
+       .p2align 2
+1:     .word   ld1(tpoff)
+       
+       .p2align 1
+@open coded local, should relax to LE
+       ldr     r0, 1f
+2:
+.tlsdescseq ld1
+       add     r0, pc
+.tlsdescseq ld1
+       ldr     r1, [r0,#4]
+.tlsdescseq ld1
+       blx     r1
+       nop
+       .p2align 2
+1:     .word   ld1(tlsdesc) + (. - 2b + 1)
+
+       .section .tdata,"awT"
+       .global gd1
+gd1:   .space 4
+ld1:   .space 4
+       .globl r1
+r1:    .space 4
+r0:    .space 4
diff --git a/ld/testsuite/ld-arm/tls-descrelax-v7.d b/ld/testsuite/ld-arm/tls-descrelax-v7.d
new file mode 100644 (file)
index 0000000..1b2159c
--- /dev/null
@@ -0,0 +1,108 @@
+.*:     file format elf32-.*
+architecture: arm, flags 0x[0-9a-f]+:
+EXEC_P, HAS_SYMS, D_PAGED
+start address 0x[0-9a-f]+
+
+Disassembly of section .text:
+
+00008000 <foo>:
+    8000:      e59f0004        ldr     r0, \[pc, #4\]  ; 800c <foo\+0xc>
+    8004:      e79f0000        ldr     r0, \[pc, r0\]
+    8008:      e320f000        nop     \{0\}
+    800c:      00008138        .word   0x00008138
+    8010:      e59f0004        ldr     r0, \[pc, #4\]  ; 801c <foo\+0x1c>
+    8014:      e79f0000        ldr     r0, \[pc, r0\]
+    8018:      e320f000        nop     \{0\}
+    801c:      00008128        .word   0x00008128
+    8020:      e59f0004        ldr     r0, \[pc, #4\]  ; 802c <foo\+0x2c>
+    8024:      e320f000        nop     \{0\}
+    8028:      e320f000        nop     \{0\}
+    802c:      0000000c        .word   0x0000000c
+    8030:      e59f0004        ldr     r0, \[pc, #4\]  ; 803c <foo\+0x3c>
+    8034:      e1a00000        nop                     ; .*
+    8038:      e320f000        nop     \{0\}
+    803c:      0000000c        .word   0x0000000c
+    8040:      e59f000c        ldr     r0, \[pc, #12\] ; 8054 <foo\+0x54>
+    8044:      e08f0000        add     r0, pc, r0
+    8048:      e5901000        ldr     r1, \[r0\]
+    804c:      e1a00001        mov     r0, r1
+    8050:      e320f000        nop     \{0\}
+    8054:      000080f8        .word   0x000080f8
+    8058:      e59f000c        ldr     r0, \[pc, #12\] ; 806c <foo\+0x6c>
+    805c:      e08f0000        add     r0, pc, r0
+    8060:      e5901000        ldr     r1, \[r0\]
+    8064:      e1a00001        mov     r0, r1
+    8068:      e320f000        nop     \{0\}
+    806c:      000080e0        .word   0x000080e0
+    8070:      e59f000c        ldr     r0, \[pc, #12\] ; 8084 <foo\+0x84>
+    8074:      e320f000        nop     \{0\}
+    8078:      e320f000        nop     \{0\}
+    807c:      e320f000        nop     \{0\}
+    8080:      e320f000        nop     \{0\}
+    8084:      0000000c        .word   0x0000000c
+    8088:      e59f000c        ldr     r0, \[pc, #12\] ; 809c <foo\+0x9c>
+    808c:      e1a00000        nop                     ; .*
+    8090:      e1a00000        nop                     ; .*
+    8094:      e1a00000        nop                     ; .*
+    8098:      e320f000        nop     \{0\}
+    809c:      0000000c        .word   0x0000000c
+
+000080a0 <bar>:
+    80a0:      4801            ldr     r0, \[pc, #4\]  ; \(80a8 <bar\+0x8>\)
+    80a2:      4478            add     r0, pc
+    80a4:      6800            ldr     r0, \[r0, #0\]
+    80a6:      46c0            nop                     ; .*
+    80a8:      0000809e        .word   0x0000809e
+    80ac:      4801            ldr     r0, \[pc, #4\]  ; \(80b4 <bar\+0x14>\)
+    80ae:      4478            add     r0, pc
+    80b0:      6800            ldr     r0, \[r0, #0\]
+    80b2:      46c0            nop                     ; \(mov r8, r8\)
+    80b4:      00008092        .word   0x00008092
+    80b8:      4801            ldr     r0, \[pc, #4\]  ; \(80c0 <bar\+0x20>\)
+    80ba:      4478            add     r0, pc
+    80bc:      6800            ldr     r0, \[r0, #0\]
+    80be:      46c0            nop                     ; \(mov r8, r8\)
+    80c0:      0000808a        .word   0x0000808a
+    80c4:      4801            ldr     r0, \[pc, #4\]  ; \(80cc <bar\+0x2c>\)
+    80c6:      46c0            nop                     ; \(mov r8, r8\)
+    80c8:      46c0            nop                     ; \(mov r8, r8\)
+    80ca:      bf00            nop
+    80cc:      0000000c        .word   0x0000000c
+    80d0:      4801            ldr     r0, \[pc, #4\]  ; \(80d8 <bar\+0x38>\)
+    80d2:      (f3af 8000)|(bf00     )         nop(.w)?
+#...
+    80d6:      46c0            nop                     ; \(mov r8, r8\)
+    80d8:      0000000c        .word   0x0000000c
+    80dc:      4801            ldr     r0, \[pc, #4\]  ; \(80e4 <bar\+0x44>\)
+    80de:      (f3af 8000)|(bf00     )         nop(.w)?
+#...
+    80e2:      46c0            nop                     ; \(mov r8, r8\)
+    80e4:      00000014        .word   0x00000014
+    80e8:      4802            ldr     r0, \[pc, #8\]  ; \(80f4 <bar\+0x54>\)
+    80ea:      4478            add     r0, pc
+    80ec:      6801            ldr     r1, \[r0, #0\]
+    80ee:      1c08            adds    r0, r1, #0
+    80f0:      46c0            nop                     ; \(mov r8, r8\)
+    80f2:      bf00            nop
+    80f4:      00008056        .word   0x00008056
+    80f8:      4802            ldr     r0, \[pc, #8\]  ; \(8104 <bar\+0x64>\)
+    80fa:      4478            add     r0, pc
+    80fc:      6801            ldr     r1, \[r0, #0\]
+    80fe:      4608            mov     r0, r1
+    8100:      46c0            nop                     ; \(mov r8, r8\)
+    8102:      bf00            nop
+    8104:      00008046        .word   0x00008046
+    8108:      4802            ldr     r0, \[pc, #8\]  ; \(8114 <bar\+0x74>\)
+    810a:      46c0            nop                     ; \(mov r8, r8\)
+    810c:      46c0            nop                     ; \(mov r8, r8\)
+    810e:      46c0            nop                     ; \(mov r8, r8\)
+    8110:      46c0            nop                     ; \(mov r8, r8\)
+    8112:      bf00            nop
+    8114:      0000000c        .word   0x0000000c
+    8118:      4802            ldr     r0, \[pc, #8\]  ; \(8124 <bar\+0x84>\)
+    811a:      46c0            nop                     ; \(mov r8, r8\)
+    811c:      46c0            nop                     ; \(mov r8, r8\)
+    811e:      46c0            nop                     ; \(mov r8, r8\)
+    8120:      46c0            nop                     ; \(mov r8, r8\)
+    8122:      bf00            nop
+    8124:      0000000c        .word   0x0000000c
diff --git a/ld/testsuite/ld-arm/tls-descrelax-v7.s b/ld/testsuite/ld-arm/tls-descrelax-v7.s
new file mode 100644 (file)
index 0000000..a8c028b
--- /dev/null
@@ -0,0 +1,198 @@
+@ we can relax local and non-weak globals for non-shared links
+
+       .arch   armv7-a
+       .text
+       .arm
+
+       .p2align 2
+foo:
+@tlscall global, manually relaxed to IE
+       ldr     r0, 1f
+2:     ldr     r0, [pc, r0]
+       nop
+       .p2align 2
+1:     .word   gd1(gottpoff) + (. - 2b - 8)
+       
+       .p2align 2
+@tlscall global, should relax to IE
+       ldr     r0, 1f
+2:     blx     gd1(tlscall)
+       nop
+       .p2align 2
+1:     .word   gd1(tlsdesc) + (. - 2b)
+
+       .p2align 2
+@tlscall local, manually relaxed to LE
+       ldr     r0, 1f
+       nop
+       nop
+       .p2align 2
+1:     .word   ld1(tpoff)
+
+       .p2align 2
+@tlscall local, should relax to LE
+       ldr     r0, 1f
+2:     blx     ld1(tlscall)
+       nop
+       .p2align 2
+1:     .word   ld1(tlsdesc) + (. - 2b)
+
+       .p2align 2
+@open coded global, manually relaxed to IE
+       ldr     r0, 1f
+2:
+       add     r0, pc, r0
+       ldr     r1, [r0]
+       mov     r0, r1
+       nop
+       .p2align 2
+1:     .word   gd1(gottpoff) + (. - 2b - 8)
+
+       .p2align 2
+@open coded global, should relax to IE
+       ldr     r0, 1f
+2:
+.tlsdescseq gd1
+       add     r0, pc, r0
+.tlsdescseq gd1
+       ldr     r1, [r0,#4]
+.tlsdescseq gd1
+       blx     r1
+       nop
+       .p2align 2
+1:     .word   gd1(tlsdesc) + (. - 2b)
+
+       .p2align 2
+@open coded local, manually relaxed to LE
+       ldr     r0, 1f
+2:
+       nop
+       nop
+       nop
+       nop
+       .p2align 2
+1:     .word   ld1(tpoff)
+       
+       .p2align 2
+@open coded local, should relax to LE
+       ldr     r0, 1f
+2:
+.tlsdescseq ld1
+       add     r0, pc, r0
+.tlsdescseq ld1
+       ldr     r1, [r0,#4]
+.tlsdescseq ld1
+       blx     r1
+       nop
+       .p2align 2
+1:     .word   ld1(tlsdesc) + (. - 2b)
+
+
+       .thumb
+       .p2align 1
+bar:   
+@tlscall global, manually relaxed to IE
+       ldr     r0, 1f
+2:     add     r0, pc, r0
+       ldr     r0, [r0]
+       nop
+       .p2align 2
+1:     .word   gd1(gottpoff) + (. - 2b - 4)
+       
+       .p2align 1
+@tlscall global, should relax to IE
+       ldr     r0, 1f
+2:     blx     gd1(tlscall)
+       nop
+       .p2align 2
+1:     .word   gd1(tlsdesc) + (. - 2b + 1)
+
+       .p2align 1
+@tlscall global, should relax to IE
+       ldr     r0, 1f
+2:     blx     r1(tlscall)
+       nop
+       .p2align 2
+1:     .word   r1(tlsdesc) + (. - 2b + 1)
+
+       .p2align 1
+@tlscall local, manually relaxed to LE
+       ldr     r0, 1f
+       nop
+       nop
+       .p2align 2
+1:     .word   ld1(tpoff)
+
+       .p2align 1
+@tlscall local, should relax to LE
+       ldr     r0, 1f
+2:     blx     ld1(tlscall)
+       nop
+       .p2align 2
+1:     .word   ld1(tlsdesc) + (. - 2b + 1)
+
+       .p2align 1
+@tlscall local, should relax to LE
+       ldr     r0, 1f
+2:     blx     r0(tlscall)
+       nop
+       .p2align 2
+1:     .word   r0(tlsdesc) + (. - 2b + 1)
+
+       .p2align 1
+@open coded global, manually relaxed to IE
+       ldr     r0, 1f
+2:
+       add     r0, pc
+       ldr     r1, [r0]
+       mov     r0, r1
+       nop
+       .p2align 2
+1:     .word   gd1(gottpoff) + (. - 2b - 4)
+
+       .p2align 1
+@open coded global, should relax to IE
+       ldr     r0, 1f
+2:
+.tlsdescseq gd1
+       add     r0, pc
+.tlsdescseq gd1
+       ldr     r1, [r0,#4]
+.tlsdescseq gd1
+       blx     r1
+       nop
+       .p2align 2
+1:     .word   gd1(tlsdesc) + (. - 2b + 1)
+
+       .p2align 1
+@open coded local, manually relaxed to LE
+       ldr     r0, 1f
+2:
+       nop
+       nop
+       nop
+       nop
+       .p2align 2
+1:     .word   ld1(tpoff)
+       
+       .p2align 1
+@open coded local, should relax to LE
+       ldr     r0, 1f
+2:
+.tlsdescseq ld1
+       add     r0, pc
+.tlsdescseq ld1
+       ldr     r1, [r0,#4]
+.tlsdescseq ld1
+       blx     r1
+       nop
+       .p2align 2
+1:     .word   ld1(tlsdesc) + (. - 2b + 1)
+
+       .section .tdata,"awT"
+       .global gd1
+gd1:   .space 4
+ld1:   .space 4
+       .globl r1
+r1:    .space 4
+r0:    .space 4
diff --git a/ld/testsuite/ld-arm/tls-descrelax.d b/ld/testsuite/ld-arm/tls-descrelax.d
new file mode 100644 (file)
index 0000000..9b06d6a
--- /dev/null
@@ -0,0 +1,108 @@
+.*:     file format elf32-.*
+architecture: arm, flags 0x[0-9a-f]+:
+EXEC_P, HAS_SYMS, D_PAGED
+start address 0x[0-9a-f]+
+
+Disassembly of section .text:
+
+00008000 <foo>:
+    8000:      e59f0004        ldr     r0, \[pc, #4\]  ; 800c <foo\+0xc>
+    8004:      e79f0000        ldr     r0, \[pc, r0\]
+    8008:      e1a00000        nop                     ; \(mov r0, r0\)
+    800c:      00008138        .word   0x00008138
+    8010:      e59f0004        ldr     r0, \[pc, #4\]  ; 801c <foo\+0x1c>
+    8014:      e79f0000        ldr     r0, \[pc, r0\]
+    8018:      e1a00000        nop                     ; \(mov r0, r0\)
+    801c:      00008128        .word   0x00008128
+    8020:      e59f0004        ldr     r0, \[pc, #4\]  ; 802c <foo\+0x2c>
+    8024:      e1a00000        nop                     ; \(mov r0, r0\)
+    8028:      e1a00000        nop                     ; \(mov r0, r0\)
+    802c:      0000000c        .word   0x0000000c
+    8030:      e59f0004        ldr     r0, \[pc, #4\]  ; 803c <foo\+0x3c>
+    8034:      e1a00000        nop                     ; \(mov r0, r0\)
+    8038:      e1a00000        nop                     ; \(mov r0, r0\)
+    803c:      0000000c        .word   0x0000000c
+    8040:      e59f000c        ldr     r0, \[pc, #12\] ; 8054 <foo\+0x54>
+    8044:      e08f0000        add     r0, pc, r0
+    8048:      e5901000        ldr     r1, \[r0\]
+    804c:      e1a00001        mov     r0, r1
+    8050:      e1a00000        nop                     ; \(mov r0, r0\)
+    8054:      000080f8        .word   0x000080f8
+    8058:      e59f000c        ldr     r0, \[pc, #12\] ; 806c <foo\+0x6c>
+    805c:      e08f0000        add     r0, pc, r0
+    8060:      e5901000        ldr     r1, \[r0\]
+    8064:      e1a00001        mov     r0, r1
+    8068:      e1a00000        nop                     ; \(mov r0, r0\)
+    806c:      000080e0        .word   0x000080e0
+    8070:      e59f000c        ldr     r0, \[pc, #12\] ; 8084 <foo\+0x84>
+    8074:      e1a00000        nop                     ; \(mov r0, r0\)
+    8078:      e1a00000        nop                     ; \(mov r0, r0\)
+    807c:      e1a00000        nop                     ; \(mov r0, r0\)
+    8080:      e1a00000        nop                     ; \(mov r0, r0\)
+    8084:      0000000c        .word   0x0000000c
+    8088:      e59f000c        ldr     r0, \[pc, #12\] ; 809c <foo\+0x9c>
+    808c:      e1a00000        nop                     ; \(mov r0, r0\)
+    8090:      e1a00000        nop                     ; \(mov r0, r0\)
+    8094:      e1a00000        nop                     ; \(mov r0, r0\)
+    8098:      e1a00000        nop                     ; \(mov r0, r0\)
+    809c:      0000000c        .word   0x0000000c
+
+000080a0 <bar>:
+    80a0:      4801            ldr     r0, \[pc, #4\]  ; \(80a8 <bar\+0x8>\)
+    80a2:      4478            add     r0, pc
+    80a4:      6800            ldr     r0, \[r0, #0\]
+    80a6:      46c0            nop                     ; \(mov r8, r8\)
+    80a8:      0000809e        .word   0x0000809e
+    80ac:      4801            ldr     r0, \[pc, #4\]  ; \(80b4 <bar\+0x14>\)
+    80ae:      4478            add     r0, pc
+    80b0:      6800            ldr     r0, \[r0, #0\]
+    80b2:      46c0            nop                     ; \(mov r8, r8\)
+    80b4:      00008092        .word   0x00008092
+    80b8:      4801            ldr     r0, \[pc, #4\]  ; \(80c0 <bar\+0x20>\)
+    80ba:      4478            add     r0, pc
+    80bc:      6800            ldr     r0, \[r0, #0\]
+    80be:      46c0            nop                     ; \(mov r8, r8\)
+    80c0:      0000808a        .word   0x0000808a
+    80c4:      4801            ldr     r0, \[pc, #4\]  ; \(80cc <bar\+0x2c>\)
+    80c6:      46c0            nop                     ; \(mov r8, r8\)
+    80c8:      46c0            nop                     ; \(mov r8, r8\)
+    80ca:      46c0            nop                     ; \(mov r8, r8\)
+    80cc:      0000000c        .word   0x0000000c
+    80d0:      4801            ldr     r0, \[pc, #4\]  ; \(80d8 <bar\+0x38>\)
+    80d2:      bf00            nop
+    80d4:      bf00            nop
+    80d6:      46c0            nop                     ; \(mov r8, r8\)
+    80d8:      0000000c        .word   0x0000000c
+    80dc:      4801            ldr     r0, \[pc, #4\]  ; \(80e4 <bar\+0x44>\)
+    80de:      bf00            nop
+    80e0:      bf00            nop
+    80e2:      46c0            nop                     ; \(mov r8, r8\)
+    80e4:      00000014        .word   0x00000014
+    80e8:      4802            ldr     r0, \[pc, #8\]  ; \(80f4 <bar\+0x54>\)
+    80ea:      4478            add     r0, pc
+    80ec:      6801            ldr     r1, \[r0, #0\]
+    80ee:      1c08            adds    r0, r1, #0
+    80f0:      46c0            nop                     ; \(mov r8, r8\)
+    80f2:      46c0            nop                     ; \(mov r8, r8\)
+    80f4:      00008056        .word   0x00008056
+    80f8:      4802            ldr     r0, \[pc, #8\]  ; \(8104 <bar\+0x64>\)
+    80fa:      4478            add     r0, pc
+    80fc:      6801            ldr     r1, \[r0, #0\]
+    80fe:      4608            mov     r0, r1
+    8100:      46c0            nop                     ; \(mov r8, r8\)
+    8102:      46c0            nop                     ; \(mov r8, r8\)
+    8104:      00008046        .word   0x00008046
+    8108:      4802            ldr     r0, \[pc, #8\]  ; \(8114 <bar\+0x74>\)
+    810a:      46c0            nop                     ; \(mov r8, r8\)
+    810c:      46c0            nop                     ; \(mov r8, r8\)
+    810e:      46c0            nop                     ; \(mov r8, r8\)
+    8110:      46c0            nop                     ; \(mov r8, r8\)
+    8112:      46c0            nop                     ; \(mov r8, r8\)
+    8114:      0000000c        .word   0x0000000c
+    8118:      4802            ldr     r0, \[pc, #8\]  ; \(8124 <bar\+0x84>\)
+    811a:      46c0            nop                     ; \(mov r8, r8\)
+    811c:      46c0            nop                     ; \(mov r8, r8\)
+    811e:      46c0            nop                     ; \(mov r8, r8\)
+    8120:      46c0            nop                     ; \(mov r8, r8\)
+    8122:      46c0            nop                     ; \(mov r8, r8\)
+    8124:      0000000c        .word   0x0000000c
diff --git a/ld/testsuite/ld-arm/tls-descrelax.s b/ld/testsuite/ld-arm/tls-descrelax.s
new file mode 100644 (file)
index 0000000..826f169
--- /dev/null
@@ -0,0 +1,197 @@
+@ we can relax local and non-weak globals for non-shared links
+
+       .text
+       .arm
+
+       .p2align 2
+foo:
+@tlscall global, manually relaxed to IE
+       ldr     r0, 1f
+2:     ldr     r0, [pc, r0]
+       nop
+       .p2align 2
+1:     .word   gd1(gottpoff) + (. - 2b - 8)
+       
+       .p2align 2
+@tlscall global, should relax to IE
+       ldr     r0, 1f
+2:     blx     gd1(tlscall)
+       nop
+       .p2align 2
+1:     .word   gd1(tlsdesc) + (. - 2b)
+
+       .p2align 2
+@tlscall local, manually relaxed to LE
+       ldr     r0, 1f
+       nop
+       nop
+       .p2align 2
+1:     .word   ld1(tpoff)
+
+       .p2align 2
+@tlscall local, should relax to LE
+       ldr     r0, 1f
+2:     blx     ld1(tlscall)
+       nop
+       .p2align 2
+1:     .word   ld1(tlsdesc) + (. - 2b)
+
+       .p2align 2
+@open coded global, manually relaxed to IE
+       ldr     r0, 1f
+2:
+       add     r0, pc, r0
+       ldr     r1, [r0]
+       mov     r0, r1
+       nop
+       .p2align 2
+1:     .word   gd1(gottpoff) + (. - 2b - 8)
+
+       .p2align 2
+@open coded global, should relax to IE
+       ldr     r0, 1f
+2:
+.tlsdescseq gd1
+       add     r0, pc, r0
+.tlsdescseq gd1
+       ldr     r1, [r0,#4]
+.tlsdescseq gd1
+       blx     r1
+       nop
+       .p2align 2
+1:     .word   gd1(tlsdesc) + (. - 2b)
+
+       .p2align 2
+@open coded local, manually relaxed to LE
+       ldr     r0, 1f
+2:
+       nop
+       nop
+       nop
+       nop
+       .p2align 2
+1:     .word   ld1(tpoff)
+       
+       .p2align 2
+@open coded local, should relax to LE
+       ldr     r0, 1f
+2:
+.tlsdescseq ld1
+       add     r0, pc, r0
+.tlsdescseq ld1
+       ldr     r1, [r0,#4]
+.tlsdescseq ld1
+       blx     r1
+       nop
+       .p2align 2
+1:     .word   ld1(tlsdesc) + (. - 2b)
+
+
+       .thumb
+       .p2align 1
+bar:   
+@tlscall global, manually relaxed to IE
+       ldr     r0, 1f
+2:     add     r0, pc, r0
+       ldr     r0, [r0]
+       nop
+       .p2align 2
+1:     .word   gd1(gottpoff) + (. - 2b - 4)
+       
+       .p2align 1
+@tlscall global, should relax to IE
+       ldr     r0, 1f
+2:     blx     gd1(tlscall)
+       nop
+       .p2align 2
+1:     .word   gd1(tlsdesc) + (. - 2b + 1)
+
+       .p2align 1
+@tlscall global, should relax to IE
+       ldr     r0, 1f
+2:     blx     r1(tlscall)
+       nop
+       .p2align 2
+1:     .word   r1(tlsdesc) + (. - 2b + 1)
+
+       .p2align 1
+@tlscall local, manually relaxed to LE
+       ldr     r0, 1f
+       nop
+       nop
+       .p2align 2
+1:     .word   ld1(tpoff)
+
+       .p2align 1
+@tlscall local, should relax to LE
+       ldr     r0, 1f
+2:     blx     ld1(tlscall)
+       nop
+       .p2align 2
+1:     .word   ld1(tlsdesc) + (. - 2b + 1)
+
+       .p2align 1
+@tlscall local, should relax to LE
+       ldr     r0, 1f
+2:     blx     r0(tlscall)
+       nop
+       .p2align 2
+1:     .word   r0(tlsdesc) + (. - 2b + 1)
+
+       .p2align 1
+@open coded global, manually relaxed to IE
+       ldr     r0, 1f
+2:
+       add     r0, pc
+       ldr     r1, [r0]
+       mov     r0, r1
+       nop
+       .p2align 2
+1:     .word   gd1(gottpoff) + (. - 2b - 4)
+
+       .p2align 1
+@open coded global, should relax to IE
+       ldr     r0, 1f
+2:
+.tlsdescseq gd1
+       add     r0, pc
+.tlsdescseq gd1
+       ldr     r1, [r0,#4]
+.tlsdescseq gd1
+       blx     r1
+       nop
+       .p2align 2
+1:     .word   gd1(tlsdesc) + (. - 2b + 1)
+
+       .p2align 1
+@open coded local, manually relaxed to LE
+       ldr     r0, 1f
+2:
+       nop
+       nop
+       nop
+       nop
+       .p2align 2
+1:     .word   ld1(tpoff)
+       
+       .p2align 1
+@open coded local, should relax to LE
+       ldr     r0, 1f
+2:
+.tlsdescseq ld1
+       add     r0, pc
+.tlsdescseq ld1
+       ldr     r1, [r0,#4]
+.tlsdescseq ld1
+       blx     r1
+       nop
+       .p2align 2
+1:     .word   ld1(tlsdesc) + (. - 2b + 1)
+
+       .section .tdata,"awT"
+       .global gd1
+gd1:   .space 4
+ld1:   .space 4
+       .globl r1
+r1:    .space 4
+r0:    .space 4
diff --git a/ld/testsuite/ld-arm/tls-descseq.d b/ld/testsuite/ld-arm/tls-descseq.d
new file mode 100644 (file)
index 0000000..1a04bb0
--- /dev/null
@@ -0,0 +1,44 @@
+
+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        push    {lr}            ; .*
+    [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]+: 000080e4        .word   0x000080e4
+    [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]+: e52d2004        push    {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]+: e081100f        add     r1, r1, pc
+    [0-9a-f]+: e12fff12        bx      r2
+    [0-9a-f]+: 000080d4        .word   0x000080d4
+    [0-9a-f]+: 000080bc        .word   0x000080bc
+
+Disassembly of section .text:
+
+[0-9a-f]+ <foo>:
+    [0-9a-f]+: e59f000c        ldr     r0, \[pc, #12\] ; .*
+    [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]+: e1a00000        nop                     ; .*
+    [0-9a-f]+: 000080b4        .word   0x000080b4
+
+[0-9a-f]+ <bar>:
+    [0-9a-f]+: 4802            ldr     r0, \[pc, #8\]  ; .*
+    [0-9a-f]+: 4478            add     r0, pc
+    [0-9a-f]+: 6841            ldr     r1, \[r0, #4\]
+    [0-9a-f]+: 4788            blx     r1
+    [0-9a-f]+: 46c0            nop                     ; .*
+    [0-9a-f]+: 46c0            nop                     ; .*
+    [0-9a-f]+: 000080a2        .word   0x000080a2
diff --git a/ld/testsuite/ld-arm/tls-descseq.r b/ld/testsuite/ld-arm/tls-descseq.r
new file mode 100644 (file)
index 0000000..23d4637
--- /dev/null
@@ -0,0 +1,6 @@
+
+.*:     file format elf32-.*arm
+
+DYNAMIC RELOCATION RECORDS
+OFFSET   TYPE              VALUE 
+[0-9a-f]+ R_ARM_TLS_DESC    lib_gd2
diff --git a/ld/testsuite/ld-arm/tls-descseq.s b/ld/testsuite/ld-arm/tls-descseq.s
new file mode 100644 (file)
index 0000000..9b2628d
--- /dev/null
@@ -0,0 +1,41 @@
+       .text
+       .arm
+       .globl foo
+       .type foo, %function
+foo:
+       ldr     r0, 1f
+2:
+.tlsdescseq lib_gd2
+       add     r0, pc, r0
+.tlsdescseq lib_gd2
+       ldr     r1, [r0,#4]
+.tlsdescseq lib_gd2
+       blx     r1
+       nop
+
+1:
+       .word   lib_gd2(tlsdesc) + (. - 2b)
+
+       .thumb
+       .globl bar
+       .type bar, %function
+bar:
+       ldr     r0, 1f
+2:
+.tlsdescseq lib_gd2
+       add     r0, pc
+.tlsdescseq lib_gd2
+       ldr     r1, [r0,#4]
+.tlsdescseq lib_gd2
+       blx     r1
+       nop
+
+       .p2align 2
+1:
+       .word   lib_gd2(tlsdesc) + (. - 2b + 1)
+
+       .section .tdata,"awT"
+       .global lib_gd2
+lib_gd2:
+       .space  4
+
diff --git a/ld/testsuite/ld-arm/tls-gdesc-got.d b/ld/testsuite/ld-arm/tls-gdesc-got.d
new file mode 100644 (file)
index 0000000..3b4a83b
--- /dev/null
@@ -0,0 +1,30 @@
+
+.*/tls-lib2-got.so:     file format elf32-.*arm
+architecture: arm, flags 0x00000150:
+HAS_SYMS, DYNAMIC, D_PAGED
+start address 0x00008210
+
+
+Disassembly of section .got:
+
+00010310 <.*>:
+   10310:      00010288        .*
+       ...
+   1031c:      00000008        .*
+                       1031c: R_ARM_TLS_DESC   \*ABS\*
+   10320:      00000000        .*
+   10324:      0000000c        .*
+                       10324: R_ARM_TLS_DESC   \*ABS\*
+   10328:      00000000        .*
+   1032c:      80000004        .*
+                       1032c: R_ARM_TLS_DESC   glob1
+   10330:      00000000        .*
+   10334:      80000006        .*
+                       10334: R_ARM_TLS_DESC   ext2
+   10338:      00000000        .*
+   1033c:      80000007        .*
+                       1033c: R_ARM_TLS_DESC   ext1
+   10340:      00000000        .*
+   10344:      80000009        .*
+                       10344: R_ARM_TLS_DESC   glob2
+       ...
diff --git a/ld/testsuite/ld-arm/tls-gdesc-got.s b/ld/testsuite/ld-arm/tls-gdesc-got.s
new file mode 100644 (file)
index 0000000..8128ff7
--- /dev/null
@@ -0,0 +1,45 @@
+
+       .arm
+foo:
+       ldr     r0,1f
+2:     bl      loc1(tlscall)
+       nop
+1:     .word   loc1(tlsdesc) + (. - 2b)
+
+       ldr     r0,1f
+2:     bl      loc2(tlscall)
+       nop
+1:     .word   loc2(tlsdesc) + (. - 2b)
+
+       ldr     r0,1f
+2:     bl      glob1(tlscall)
+       nop
+1:     .word   glob1(tlsdesc) + (. - 2b)
+
+       ldr     r0,1f
+2:     bl      glob2(tlscall)
+       nop
+1:     .word   glob2(tlsdesc) + (. - 2b)
+
+       ldr     r0,1f
+2:     bl      ext1(tlscall)
+       nop
+1:     .word   ext1(tlsdesc) + (. - 2b)
+
+       ldr     r0,1f
+2:     bl      ext2(tlscall)
+       nop
+1:     .word   ext2(tlsdesc) + (. - 2b)
+
+       .section        .tdata,"awT",%progbits
+       .space  8
+       .type   loc1, %object
+loc1:  .space  4
+       .type   loc2, %object
+loc2:  .space  4
+       .globl  glob1
+       .type   glob1, %object
+glob1: .space  4
+       .globl  glob2
+       .type   glob2, %object
+glob2: .space  4
diff --git a/ld/testsuite/ld-arm/tls-gdesc-nlazy.g b/ld/testsuite/ld-arm/tls-gdesc-nlazy.g
new file mode 100644 (file)
index 0000000..4b53a98
--- /dev/null
@@ -0,0 +1,4 @@
+
+Hex dump of section '.got':
+  0x[0-9a-f]+ [0-9a-f]+ 00000000 00000000 00000000 ................
+  0x[0-9a-f]+ 00000000 00000000 00000000          ............
diff --git a/ld/testsuite/ld-arm/tls-gdesc-nlazy.s b/ld/testsuite/ld-arm/tls-gdesc-nlazy.s
new file mode 100644 (file)
index 0000000..2cd8109
--- /dev/null
@@ -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
+
diff --git a/ld/testsuite/ld-arm/tls-gdesc.d b/ld/testsuite/ld-arm/tls-gdesc.d
new file mode 100644 (file)
index 0000000..ce18eac
--- /dev/null
@@ -0,0 +1,42 @@
+
+tmpdir/tls-lib2.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        push    {lr}            ; .*
+    [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]+: 000080e8        .word   0x000080e8
+    [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]+: e52d2004        push    {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]+: e081100f        add     r1, r1, pc
+    [0-9a-f]+: e12fff12        bx      r2
+    [0-9a-f]+: 000080e0        .word   0x000080e0
+    [0-9a-f]+: 000080c0        .word   0x000080c0
+Disassembly of section .text:
+
+[0-9a-f]+ <foo>:
+    [0-9a-f]+: e59f0004        ldr     r0, \[pc, #4\]  ; .*
+    [0-9a-f]+: fafffff2        blx     [0-9a-f]+ .*
+    [0-9a-f]+: e1a00000        nop                     ; .*
+    [0-9a-f]+: 000080c4        .word   0x000080c4
+
+[0-9a-f]+ <bar>:
+    [0-9a-f]+: 4801            ldr     r0, \[pc, #4\]  ; .*
+    [0-9a-f]+: f7ff efe0       blx     [0-9a-f]+ .*
+    [0-9a-f]+: 46c0            nop                     ; .*
+    [0-9a-f]+: 000080b5        .word   0x000080b5
+    [0-9a-f]+: 4801            ldr     r0, \[pc, #4\]  ; .*
+    [0-9a-f]+: f7ff efda       blx     [0-9a-f]+ .*
+    [0-9a-f]+: 46c0            nop                     ; .*
+    [0-9a-f]+: 000080a1        .word   0x000080a1
diff --git a/ld/testsuite/ld-arm/tls-gdesc.r b/ld/testsuite/ld-arm/tls-gdesc.r
new file mode 100644 (file)
index 0000000..3de3ae8
--- /dev/null
@@ -0,0 +1,7 @@
+
+.*:     file format elf32-.*arm
+
+DYNAMIC RELOCATION RECORDS
+OFFSET   TYPE              VALUE 
+[0-9a-f]+ R_ARM_TLS_DESC    lib_gd2
+[0-9a-f]+ R_ARM_TLS_DESC    r0
diff --git a/ld/testsuite/ld-arm/tls-gdesc.s b/ld/testsuite/ld-arm/tls-gdesc.s
new file mode 100644 (file)
index 0000000..482ee29
--- /dev/null
@@ -0,0 +1,41 @@
+       .text
+       .arm
+       .globl foo
+       .type foo, %function
+foo:
+       ldr     r0,1f
+2:
+       blx     lib_gd2(tlscall) 
+       nop
+
+1:
+       .word   lib_gd2(tlsdesc) + (. - 2b)
+
+       .thumb
+       .globl bar
+       .type bar, %function
+bar:
+       ldr     r0,1f
+2:
+       blx     lib_gd2(tlscall) 
+       nop
+
+       .p2align 2
+1:
+       .word   lib_gd2(tlsdesc) + (. - 2b + 1)
+
+       ldr     r0,1f
+2:
+       blx     r0(tlscall) 
+       nop
+
+       .p2align 2
+1:
+       .word   r0(tlsdesc) + (. - 2b + 1)
+
+       .section .tdata,"awT"
+       .global lib_gd2
+lib_gd2:
+       .space  4
+       .globl r0
+r0:    .space 4
diff --git a/ld/testsuite/ld-arm/tls-gdierelax.d b/ld/testsuite/ld-arm/tls-gdierelax.d
new file mode 100644 (file)
index 0000000..8d965fc
--- /dev/null
@@ -0,0 +1,20 @@
+
+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]+: e59f0004        ldr     r0, \[pc, #4\]  ; .*
+    [0-9a-f]+: e79f0000        ldr     r0, \[pc, r0\]
+    [0-9a-f]+: e1a00000        nop                     ; .*
+    [0-9a-f]+: 00008020        .word   0x00008020
+
+[0-9a-f]+ <bar>:
+    [0-9a-f]+: 4801            ldr     r0, \[pc, #4\]  ; .*
+    [0-9a-f]+: 4478            add     r0, pc
+    [0-9a-f]+: 6800            ldr     r0, \[r0, #0\]
+    [0-9a-f]+: 46c0            nop                     ; .*
+    [0-9a-f]+: 00008016        .word   0x00008016
diff --git a/ld/testsuite/ld-arm/tls-gdierelax.s b/ld/testsuite/ld-arm/tls-gdierelax.s
new file mode 100644 (file)
index 0000000..db62008
--- /dev/null
@@ -0,0 +1,34 @@
+       .text
+       .arm
+       .globl foo
+       .type foo, %function
+foo:
+       ldr     r0, 1f
+2:
+       blx     lib_gd2(tlscall) 
+       nop
+
+1:
+       .word   lib_gd2(tlsdesc) + (. - 2b)
+
+       .thumb
+       .globl bar
+       .type bar, %function
+bar:
+       ldr     r0,1f
+2:
+       blx     lib_gd2(tlscall) 
+       nop
+
+       .p2align 2
+1:
+       .word   lib_gd2(tlsdesc) + (. - 2b + 1)
+
+       .globl _start
+_start:
+       
+       .section .tdata,"awT"
+       .global lib_gd2
+lib_gd2:
+       .space  4
+
diff --git a/ld/testsuite/ld-arm/tls-gdierelax2.d b/ld/testsuite/ld-arm/tls-gdierelax2.d
new file mode 100644 (file)
index 0000000..055aad8
--- /dev/null
@@ -0,0 +1,23 @@
+
+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                     ; .*
+    [0-9a-f]+: e59f0004        ldr     r0, \[pc, #4\]  ; .*
+    [0-9a-f]+: e79f0000        ldr     r0, \[pc, r0\]
+    [0-9a-f]+: e1a00000        nop                     ; .*
+    [0-9a-f]+: 00008098        .word   0x00008098
+    [0-9a-f]+: 0000809c        .word   0x0000809c
+
+[0-9a-f]+ <bar>:
+    [0-9a-f]+: 4801            ldr     r0, \[pc, #4\]  ; .*
+    [0-9a-f]+: 4478            add     r0, pc
+    [0-9a-f]+: 6800            ldr     r0, \[r0, #0\]
+    [0-9a-f]+: 46c0            nop                     ; .*
+    [0-9a-f]+: 0000808a        .word   0x0000808a
+    [0-9a-f]+: 0000808c        .word   0x0000808c
diff --git a/ld/testsuite/ld-arm/tls-gdierelax2.s b/ld/testsuite/ld-arm/tls-gdierelax2.s
new file mode 100644 (file)
index 0000000..2f4edad
--- /dev/null
@@ -0,0 +1,35 @@
+       .text
+       .arm
+       .globl foo
+       .type foo, %function
+foo:
+       nop
+3:     ldr     r0,1f
+2:     bl      lib_gd2(tlscall) 
+       nop
+
+1:
+       .word   lib_gd2(tlsdesc) + (. - 2b)
+       .word   lib_gd2(gottpoff) + (. - 3b - 8)
+
+       .thumb
+       .globl bar
+       .type bar, %function
+bar:
+3:     ldr     r0,1f
+2:     blx     lib_gd2(tlscall) 
+       nop
+
+       .p2align 2
+1:
+       .word   lib_gd2(tlsdesc) + (. - 2b + 1)
+       .word   lib_gd2(gottpoff) + (. - 3b - 4)
+
+       .globl _start
+_start:
+
+       .section .tdata,"awT"
+       .global lib_gd2
+lib_gd2:
+       .space  4
+
diff --git a/ld/testsuite/ld-arm/tls-gdlerelax.d b/ld/testsuite/ld-arm/tls-gdlerelax.d
new file mode 100644 (file)
index 0000000..896aed7
--- /dev/null
@@ -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                     ; .*
+    [0-9a-f]+: e1a00000        nop                     ; .*
+    [0-9a-f]+: e1a0f00e        mov     pc, lr
+    [0-9a-f]+: 00000008        .word   0x00000008
diff --git a/ld/testsuite/ld-arm/tls-gdlerelax.s b/ld/testsuite/ld-arm/tls-gdlerelax.s
new file mode 100644 (file)
index 0000000..3952837
--- /dev/null
@@ -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
+
diff --git a/ld/testsuite/ld-arm/tls-lib-loc.d b/ld/testsuite/ld-arm/tls-lib-loc.d
new file mode 100644 (file)
index 0000000..2235dcb
--- /dev/null
@@ -0,0 +1,33 @@
+
+.*:     file format elf32-.*arm
+architecture: arm, flags 0x00000150:
+HAS_SYMS, DYNAMIC, D_PAGED
+start address 0x.*
+
+Disassembly of section .plt:
+
+[0-9a-f]+ <.plt>:
+    [0-9a-f]+: e52de004        push    {lr}            ; .*
+    [0-9a-f]+: e59fe004        ldr     lr, \[pc, #4\]  ; 8150 .*
+    [0-9a-f]+: e08fe00e        add     lr, pc, lr
+    [0-9a-f]+: e5bef008        ldr     pc, \[lr, #8\]!
+    8150:      000080cc        .word   0x000080cc
+    8154:      e08e0000        add     r0, lr, r0
+    [0-9a-f]+: e5901004        ldr     r1, \[r0, #4\]
+    [0-9a-f]+: e12fff11        bx      r1
+    [0-9a-f]+: e52d2004        push    {r2}            ; .*
+    8164:      e59f200c        ldr     r2, \[pc, #12\] ; 8178 .*
+    [0-9a-f]+: e59f100c        ldr     r1, \[pc, #12\] ; 817c .*
+    [0-9a-f]+: e79f2002        ldr     r2, \[pc, r2\]
+    [0-9a-f]+: e081100f        add     r1, r1, pc
+    [0-9a-f]+: e12fff12        bx      r2
+    8178:      000080bc        .word   0x000080bc
+    817c:      000080a4        .word   0x000080a4
+
+Disassembly of section .text:
+
+[0-9a-f]+ <foo>:
+    [0-9a-f]+: e59f0004        ldr     r0, \[pc, #4\]  ; 818c .*
+    [0-9a-f]+: fafffff2        blx     8154 <.*\+0x8154>
+    [0-9a-f]+: e1a00000        nop                     ; .*
+    818c:      000080a0        .word   0x000080a0
diff --git a/ld/testsuite/ld-arm/tls-lib-loc.r b/ld/testsuite/ld-arm/tls-lib-loc.r
new file mode 100644 (file)
index 0000000..ba54f61
--- /dev/null
@@ -0,0 +1,6 @@
+
+.*:     file format elf32-.*arm
+
+DYNAMIC RELOCATION RECORDS
+OFFSET   TYPE              VALUE 
+.* R_ARM_TLS_DESC    \*ABS\*
diff --git a/ld/testsuite/ld-arm/tls-lib-loc.s b/ld/testsuite/ld-arm/tls-lib-loc.s
new file mode 100644 (file)
index 0000000..a0e4dc7
--- /dev/null
@@ -0,0 +1,14 @@
+       .text
+       .arm
+
+foo:
+       ldr     r0,1f
+2:     blx     loc(tlscall)
+       nop
+
+       .p2align 2
+1:     .word   loc(tlsdesc) + (. - 2b)
+
+       .section .tdata,"awT"
+loc:
+       .space  4
diff --git a/ld/testsuite/ld-arm/tls-longplt-lib.d b/ld/testsuite/ld-arm/tls-longplt-lib.d
new file mode 100644 (file)
index 0000000..9032c61
--- /dev/null
@@ -0,0 +1,59 @@
+.*:     file format elf32-.*arm
+architecture: arm, flags 0x00000150:
+HAS_SYMS, DYNAMIC, D_PAGED
+start address 0x.*
+
+Disassembly of section .plt:
+
+00008198 <.plt>:
+    8198:      e52de004        push    {lr}            ; .*
+    819c:      e59fe004        ldr     lr, \[pc, #4\]  ; .*
+    81a0:      e08fe00e        add     lr, pc, lr
+    81a4:      e5bef008        ldr     pc, \[lr, #8\]!
+    81a8:      000080e0        .word   0x000080e0
+    81ac:      e08e0000        add     r0, lr, r0
+    81b0:      e5901004        ldr     r1, \[r0, #4\]
+    81b4:      e12fff11        bx      r1
+    81b8:      e52d2004        push    {r2}            ; .*
+    81bc:      e59f200c        ldr     r2, \[pc, #12\] ; .*
+    81c0:      e59f100c        ldr     r1, \[pc, #12\] ; .*
+    81c4:      e79f2002        ldr     r2, \[pc, r2\]
+    81c8:      e081100f        add     r1, r1, pc
+    81cc:      e12fff12        bx      r2
+    81d0:      000080d8        .word   0x000080d8
+    81d4:      000080b8        .word   0x000080b8
+
+Disassembly of section .text:
+
+000081d8 <text>:
+    81d8:      e59f0004        ldr     r0, \[pc, #4\]  ; .*
+    81dc:      fafffff2        blx     81ac .*
+    81e0:      e1a00000        nop                     ; .*
+    81e4:      000080b4        .word   0x000080b4
+    81e8:      4801            ldr     r0, \[pc, #4\]  ; .*
+    81ea:      f7ff efe0       blx     81ac <.*>
+    81ee:      46c0            nop                     ; .*
+    81f0:      000080a5        .word   0x000080a5
+
+Disassembly of section .foo:
+
+04001000 <foo>:
+ 4001000:      e59f0004        ldr     r0, \[pc, #4\]  ; .*
+ 4001004:      fa000009        blx     4001030 .*
+ 4001008:      e1a00000        nop                     ; .*
+ 400100c:      fc00f28c        .word   0xfc00f28c
+ 4001010:      e59f0004        ldr     r0, \[pc, #4\]  ; .*
+ 4001014:      fa000005        blx     4001030 .*
+ 4001018:      e1a00000        nop                     ; .*
+ 400101c:      fc00f284        .word   0xfc00f284
+ 4001020:      4801            ldr     r0, \[pc, #4\]  ; .*
+ 4001022:      f000 e806       blx     4001030 .*
+ 4001026:      46c0            nop                     ; .*
+ 4001028:      fc00f26d        .word   0xfc00f26d
+ 400102c:      00000000        .word   0x00000000
+
+04001030 <__unnamed_veneer>:
+ 4001030:      e59f1000        ldr     r1, \[pc, #0\]  ; .*
+ 4001034:      e08ff001        add     pc, pc, r1
+ 4001038:      fc007170        .word   0xfc007170
+ 400103c:      00000000        .word   0x00000000
diff --git a/ld/testsuite/ld-arm/tls-longplt-lib.s b/ld/testsuite/ld-arm/tls-longplt-lib.s
new file mode 100644 (file)
index 0000000..e0650cb
--- /dev/null
@@ -0,0 +1,51 @@
+       .syntax unified
+       .text
+text:
+       .arm
+       ldr     r0,1f
+2:     blx     loc(tlscall)
+       nop
+       .p2align 2
+1:     .word   loc(tlsdesc) + (. - 2b)
+
+       .thumb
+       ldr     r0,1f
+2:     blx     loc(tlscall)
+       nop
+       .p2align 2
+1:     .word   loc(tlsdesc) + (. - 2b + 1)
+
+       .section ".foo","ax"
+foo:
+       .arm
+       ldr     r0,1f
+2:     blx     loc(tlscall)
+       nop
+       .p2align 2
+1:     .word   loc(tlsdesc) + (. - 2b)
+
+       .arm
+       ldr     r0,1f
+2:     blx     glob(tlscall)
+       nop
+       .p2align 2
+1:     .word   glob(tlsdesc) + (. - 2b)
+
+       .thumb
+       ldr     r0,1f
+2:     blx     loc(tlscall)
+       nop
+       .p2align 2
+1:     .word   loc(tlsdesc) + (. - 2b + 1)
+
+       .section .tdata,"awT"
+       .type   loc, %object
+loc:   .space  4
+
+       @ glob1 and glob2 used by tls-longplt
+       .type   glob1, %object
+       .globl  glob1
+glob1: .space  4
+       .type   glob2, %object
+       .globl  glob2
+glob2: .space  4
diff --git a/ld/testsuite/ld-arm/tls-longplt.d b/ld/testsuite/ld-arm/tls-longplt.d
new file mode 100644 (file)
index 0000000..8729e74
--- /dev/null
@@ -0,0 +1,64 @@
+.*:     file format elf32-.*arm
+architecture: arm, flags 0x00000112:
+EXEC_P, HAS_SYMS, D_PAGED
+start address 0x.*
+
+Disassembly of section .plt:
+
+0000819c <.plt>:
+    819c:      e52de004        push    {lr}            ; .*
+    81a0:      e59fe004        ldr     lr, \[pc, #4\]  ; .*
+    81a4:      e08fe00e        add     lr, pc, lr
+    81a8:      e5bef008        ldr     pc, \[lr, #8\]!
+    81ac:      00008100        .word   0x00008100
+    81b0:      e08e0000        add     r0, lr, r0
+    81b4:      e5901004        ldr     r1, \[r0, #4]
+    81b8:      e12fff11        bx      r1
+    81bc:      e52d2004        push    {r2}            ; .*
+    81c0:      e59f200c        ldr     r2, \[pc, #12\] ; .*
+    81c4:      e59f100c        ldr     r1, \[pc, #12\] ; .*
+    81c8:      e79f2002        ldr     r2, \[pc, r2\]
+    81cc:      e081100f        add     r1, r1, pc
+    81d0:      e12fff12        bx      r2
+    81d4:      000080f4        .word   0x000080f4
+    81d8:      000080d8        .word   0x000080d8
+
+Disassembly of section .text:
+
+000081dc <text>:
+    81dc:      e59f0004        ldr     r0, \[pc, #4\]  ; .*
+    81e0:      fafffff2        blx     81b0 .*
+    81e4:      e1a00000        nop                     ; .*
+    81e8:      000080d4        .word   0x000080d4
+    81ec:      4801            ldr     r0, \[pc, #4\]  ; .*
+    81ee:      f7ff efe0       blx     81b0 .*
+    81f2:      46c0            nop                     ; .*
+    81f4:      000080c5        .word   0x000080c5
+
+Disassembly of section .foo:
+
+04001000 <foo>:
+ 4001000:      e59f0004        ldr     r0, \[pc, #4\]  ; .*
+ 4001004:      e79f0000        ldr     r0, \[pc, r0\]
+ 4001008:      e1a00000        nop                     ; .*
+ 400100c:      fc00f2b4        .word   0xfc00f2b4
+ 4001010:      e59f0004        ldr     r0, \[pc, #4\]  ; .*
+ 4001014:      fa000005        blx     4001030 .*
+ 4001018:      e1a00000        nop                     ; .*
+ 400101c:      fc00f2a0        .word   0xfc00f2a0
+ 4001020:      4801            ldr     r0, \[pc, #4\]  ; .*
+ 4001022:      f000 e80a       blx     4001038 .*
+ 4001026:      46c0            nop                     ; .*
+ 4001028:      fc00f291        .word   0xfc00f291
+ 400102c:      00000000        .word   0x00000000
+
+04001030 <__unnamed_veneer>:
+ 4001030:      e51ff004        ldr     pc, \[pc, #-4\] ; .*
+ 4001034:      000081b0        .word   0x000081b0
+
+04001038 <__unnamed_veneer>:
+ 4001038:      4778            bx      pc
+ 400103a:      46c0            nop                     ; .*
+ 400103c:      e51ff004        ldr     pc, \[pc, #-4\] ; .*
+ 4001040:      000081b0        .word   0x000081b0
+ 4001044:      00000000        .word   0x00000000
diff --git a/ld/testsuite/ld-arm/tls-longplt.s b/ld/testsuite/ld-arm/tls-longplt.s
new file mode 100644 (file)
index 0000000..42eea19
--- /dev/null
@@ -0,0 +1,47 @@
+       .syntax unified
+       .text
+text:
+       .arm
+       ldr     r0,1f
+2:     blx     udefw(tlscall)
+       nop
+       .p2align 2
+1:     .word   udefw(tlsdesc) + (. - 2b)
+
+       .thumb
+       ldr     r0,1f
+2:     blx     udefw(tlscall)
+       nop
+       .p2align 2
+1:     .word   udefw(tlsdesc) + (. - 2b + 1)
+
+       .section ".foo","ax"
+foo:
+       .arm
+       ldr     r0,1f
+2:     blx     glob1(tlscall)
+       nop
+       .p2align 2
+1:     .word   glob1(tlsdesc) + (. - 2b)
+
+       .arm
+       ldr     r0,1f
+2:     blx     udefw(tlscall)
+       nop
+       .p2align 2
+1:     .word   udefw(tlsdesc) + (. - 2b)
+
+       .thumb
+       ldr     r0,1f
+2:     blx     udefw(tlscall)
+       nop
+       .p2align 2
+1:     .word   udefw(tlsdesc) + (. - 2b + 1)
+
+       .section .tdata,"awT"
+       @ glob used by tls-longplt-lib
+       .type   glob, %object
+       .globl  glob
+glob:  .space  4
+       .globl  udefw
+       .weak   udefw
diff --git a/ld/testsuite/ld-arm/tls-mixed.r b/ld/testsuite/ld-arm/tls-mixed.r
new file mode 100644 (file)
index 0000000..79ccdeb
--- /dev/null
@@ -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
diff --git a/ld/testsuite/ld-arm/tls-mixed.s b/ld/testsuite/ld-arm/tls-mixed.s
new file mode 100644 (file)
index 0000000..af2377d
--- /dev/null
@@ -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
+
diff --git a/ld/testsuite/ld-arm/tls-thumb1.d b/ld/testsuite/ld-arm/tls-thumb1.d
new file mode 100644 (file)
index 0000000..26b65bb
--- /dev/null
@@ -0,0 +1,74 @@
+.*:     file format elf32-.*arm
+architecture: arm, flags 0x00000150:
+HAS_SYMS, DYNAMIC, D_PAGED
+start address 0x.*
+
+Disassembly of section .plt:
+
+00008164 <.plt>:
+    8164:      e52de004        push    {lr}            ; .*
+    8168:      e59fe004        ldr     lr, \[pc, #4\]  ; .*
+    816c:      e08fe00e        add     lr, pc, lr
+    8170:      e5bef008        ldr     pc, \[lr, #8\]!
+    8174:      000080f0        .word   0x000080f0
+    8178:      e08e0000        add     r0, lr, r0
+    817c:      e5901004        ldr     r1, \[r0, #4\]
+    8180:      e12fff11        bx      r1
+    8184:      e52d2004        push    {r2}            ; .*
+    8188:      e59f200c        ldr     r2, \[pc, #12\] ; .*
+    818c:      e59f100c        ldr     r1, \[pc, #12\] ; .*
+    8190:      e79f2002        ldr     r2, \[pc, r2\]
+    8194:      e081100f        add     r1, r1, pc
+    8198:      e12fff12        bx      r2
+    819c:      000080e8        .word   0x000080e8
+    81a0:      000080c8        .word   0x000080c8
+
+Disassembly of section .text:
+
+000081a8 <text>:
+    81a8:      e59f0004        ldr     r0, \[pc, #4\]  ; .*
+    81ac:      ebfffff1        bl      8178 .*
+    81b0:      e1a00000        nop                     ; .*
+    81b4:      000080c0        .word   0x000080c0
+    81b8:      4801            ldr     r0, \[pc, #4\]  ; .*
+    81ba:      f000 e806       blx     81c8 .*
+    81be:      46c0            nop                     ; .*
+    81c0:      000080b1        .word   0x000080b1
+    81c4:      00000000        .word   0x00000000
+
+000081c8 <__unnamed_veneer>:
+    81c8:      4778            bx      pc
+    81ca:      46c0            nop                     ; .*
+    81cc:      e59f1000        ldr     r1, \[pc, #0\]  ; .*
+    81d0:      e081f00f        add     pc, r1, pc
+    81d4:      ffffffa0        .word   0xffffffa0
+
+Disassembly of section .foo:
+
+04001000 <foo>:
+ 4001000:      e59f0004        ldr     r0, \[pc, #4\]  ; .*
+ 4001004:      eb000009        bl      4001030 .*
+ 4001008:      e1a00000        nop                     ; .*
+ 400100c:      fc00f268        .word   0xfc00f268
+ 4001010:      e59f0004        ldr     r0, \[pc, #4\]  ; .*
+ 4001014:      eb000005        bl      4001030 .*
+ 4001018:      e1a00000        nop                     ; .*
+ 400101c:      fc00f260        .word   0xfc00f260
+ 4001020:      4801            ldr     r0, \[pc, #4\]  ; .*
+ 4001022:      f000 e80c       blx     400103c .*
+ 4001026:      46c0            nop                     ; .*
+ 4001028:      fc00f249        .word   0xfc00f249
+ 400102c:      00000000        .word   0x00000000
+
+04001030 <__unnamed_veneer>:
+ 4001030:      e59f1000        ldr     r1, \[pc, #0\]  ; .*
+ 4001034:      e08ff001        add     pc, pc, r1
+ 4001038:      fc00713c        .word   0xfc00713c
+
+0400103c <__unnamed_veneer>:
+ 400103c:      4778            bx      pc
+ 400103e:      46c0            nop                     ; .*
+ 4001040:      e59f1000        ldr     r1, \[pc, #0\]  ; .*
+ 4001044:      e081f00f        add     pc, r1, pc
+ 4001048:      fc00712c        .word   0xfc00712c
+ 400104c:      00000000        .word   0x00000000
diff --git a/ld/testsuite/ld-arm/tls-thumb1.s b/ld/testsuite/ld-arm/tls-thumb1.s
new file mode 100644 (file)
index 0000000..634511e
--- /dev/null
@@ -0,0 +1,43 @@
+       .arch armv4t
+       .syntax unified
+       .text
+text:
+       .arm
+       ldr     r0,1f
+2:     bl      +loc(tlscall)
+       nop
+       .p2align 2
+1:     .word   loc(tlsdesc) + (. - 2b)
+
+       .thumb
+       ldr     r0,1f
+2:     bl      +loc(tlscall)
+       nop
+       .p2align 2
+1:     .word   loc(tlsdesc) + (. - 2b + 1)
+
+       .section ".foo","ax"
+foo:
+       .arm
+       ldr     r0,1f
+2:     bl      +loc(tlscall)
+       nop
+       .p2align 2
+1:     .word   loc(tlsdesc) + (. - 2b)
+
+       .arm
+       ldr     r0,1f
+2:     bl      +glob(tlscall)
+       nop
+       .p2align 2
+1:     .word   glob(tlsdesc) + (. - 2b)
+
+       .thumb
+       ldr     r0,1f
+2:     bl      +loc(tlscall)
+       nop
+       .p2align 2
+1:     .word   loc(tlsdesc) + (. - 2b + 1)
+
+       .section .tdata,"awT"
+loc:   .space  4