ARM TLS descriptors support.
authorNathan Sidwell <nathan@codesourcery.com>
Sat, 5 Mar 2011 03:39:15 +0000 (03:39 +0000)
committerJoseph Myers <joseph@codesourcery.com>
Sat, 5 Mar 2011 03:39:15 +0000 (03:39 +0000)
ChangeLog.arm
sysdeps/arm/Makefile [new file with mode: 0644]
sysdeps/arm/bits/linkmap.h
sysdeps/arm/dl-lookupcfg.h [new file with mode: 0644]
sysdeps/arm/dl-machine.h
sysdeps/arm/dl-tls.h
sysdeps/arm/dl-tlsdesc.S [new file with mode: 0644]
sysdeps/arm/dl-tlsdesc.h [new file with mode: 0644]
sysdeps/arm/tlsdesc.c [new file with mode: 0644]
sysdeps/arm/tlsdesc.sym [new file with mode: 0644]

index 5e59f09..1e05d41 100644 (file)
@@ -1,3 +1,23 @@
+2011-03-05  Nathan Sidwell  <nathan@codesourcery.com>
+           Glauber de Oliveira Costa  <glommer@gmail.com>
+
+       * sysdeps/arm/dl-tlsdesc.h: New.
+       * sysdeps/arm/dl-tls.h (struct dl_tls_index): Make non-anonymous.
+       * sysdeps/arm/Makefile: Add tlsdesc, dl-tlsdesc for elf
+       subdirectory.
+       * sysdeps/arm/tlsdesc.c: New.
+       * sysdeps/arm/dl-machine.h: #include sysdeps and dl-tlsdesc.h.
+       (elf_machine_runtime_setup): Record dl_tlsdesc_lazy_resolver
+       address.
+       (elf_machine_type_class): Check R_ARM_TLS_DESC.
+       (elf_machine_rel): Add R_ARM_TLS_DESC case.
+       (elf_machine_lazy_rel): Likewise.
+       * sysdeps/arm/dl-tlsdesc.S: New.
+       * sysdeps/arm/bits/linkmap.h (struct link_map_machine): Add
+       tlsdesc_table field.
+       * sysdeps/arm/tlsdesc.sym: New.
+       * sysdeps/arm/dl-lookupcfg.h: New.
+
 2011-02-16  Manjunath Matti  <manjunath81@gmail.com>
 
        * sysdeps/arm/sysdep.h (CALL_MCOUNT): Use __gnu_mcount_nc
diff --git a/sysdeps/arm/Makefile b/sysdeps/arm/Makefile
new file mode 100644 (file)
index 0000000..5651161
--- /dev/null
@@ -0,0 +1,9 @@
+ifeq ($(subdir),elf)
+sysdep-dl-routines += tlsdesc dl-tlsdesc
+sysdep_routines += tlsdesc dl-tlsdesc
+sysdep-rtld-routines += tlsdesc dl-tlsdesc
+endif
+
+ifeq ($(subdir),csu)
+gen-as-const-headers += tlsdesc.sym
+endif
index 648976d..7c2b4a6 100644 (file)
@@ -1,4 +1,5 @@
 struct link_map_machine
   {
     Elf32_Addr plt; /* Address of .plt */
+    void *tlsdesc_table; /* Address of TLS descriptor hash table.  */
   };
diff --git a/sysdeps/arm/dl-lookupcfg.h b/sysdeps/arm/dl-lookupcfg.h
new file mode 100644 (file)
index 0000000..29b2587
--- /dev/null
@@ -0,0 +1,28 @@
+/* Configuration of lookup functions.
+   Copyright (C) 2006, 2010 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#define DL_UNMAP_IS_SPECIAL
+
+#include_next <dl-lookupcfg.h>
+
+struct link_map;
+
+extern void internal_function _dl_unmap (struct link_map *map);
+
+#define DL_UNMAP(map) _dl_unmap (map)
index c555763..9929f76 100644 (file)
@@ -25,6 +25,7 @@
 
 #include <sys/param.h>
 #include <tls.h>
+#include <dl-tlsdesc.h>
 
 #define CLEAR_CACHE(BEG,END)                                           \
   INTERNAL_SYSCALL_ARM (cacheflush, , 3, (BEG), (END), 0)
@@ -127,6 +128,11 @@ elf_machine_runtime_setup (struct link_map *l, int lazy, int profile)
           the offset on the stack, and then jump to the resolved address.  */
        got[2] = (Elf32_Addr) &_dl_runtime_resolve;
     }
+
+  if (l->l_info[ADDRIDX (DT_TLSDESC_GOT)] && lazy)
+    *(Elf32_Addr*)(D_PTR (l, l_info[ADDRIDX (DT_TLSDESC_GOT)]) + l->l_addr)
+      = (Elf32_Addr) &_dl_tlsdesc_lazy_resolver;
+
   return lazy;
 }
 
@@ -239,7 +245,8 @@ _dl_start_user:\n\
 #if defined USE_TLS && (!defined RTLD_BOOTSTRAP || USE___THREAD)
 # define elf_machine_type_class(type) \
   ((((type) == R_ARM_JUMP_SLOT || (type) == R_ARM_TLS_DTPMOD32         \
-     || (type) == R_ARM_TLS_DTPOFF32 || (type) == R_ARM_TLS_TPOFF32)   \
+     || (type) == R_ARM_TLS_DTPOFF32 || (type) == R_ARM_TLS_TPOFF32    \
+     || (type) == R_ARM_TLS_DESC)                                      \
     * ELF_RTYPE_CLASS_PLT)                                             \
    | (((type) == R_ARM_COPY) * ELF_RTYPE_CLASS_COPY))
 #else
@@ -421,6 +428,39 @@ elf_machine_rel (struct link_map *map, const Elf32_Rel *reloc,
            *reloc_addr += value;
            break;
          }
+       case R_ARM_TLS_DESC:
+         {
+            struct tlsdesc volatile *td =
+             (struct tlsdesc volatile *)reloc_addr;
+
+# ifndef RTLD_BOOTSTRAP
+           if (! sym)
+             td->entry = _dl_tlsdesc_undefweak;
+           else
+# endif
+             {
+               value = sym->st_value + td->argument.value;
+
+# ifndef RTLD_BOOTSTRAP
+#  ifndef SHARED
+               CHECK_STATIC_TLS (map, sym_map);
+#  else
+               if (!TRY_STATIC_TLS (map, sym_map))
+                 {
+                   td->argument.pointer
+                     = _dl_make_tlsdesc_dynamic (sym_map, value);
+                   td->entry = _dl_tlsdesc_dynamic;
+                 }
+               else
+#  endif
+# endif
+               {
+                 td->argument.value = value + sym_map->l_tls_offset;
+                 td->entry = _dl_tlsdesc_return;
+               }
+             }
+           }
+           break;
        case R_ARM_PC24:
          {
             Elf32_Sword addend;
@@ -612,6 +652,20 @@ elf_machine_lazy_rel (struct link_map *map,
       else
        *reloc_addr = map->l_mach.plt;
     }
+#ifdef USE_TLS
+  else if (__builtin_expect (r_type == R_ARM_TLS_DESC, 1))
+    {
+      struct tlsdesc volatile *td =
+       (struct tlsdesc volatile *)reloc_addr;
+
+      /* The linker must have given us the parameter we need in the
+         first GOT entry, and left the second one empty. We fill the
+         last with the resolver address */
+      assert (td->entry == 0);
+      td->entry = (void*)(D_PTR (map, l_info[ADDRIDX (DT_TLSDESC_PLT)])
+                         + map->l_addr);
+    }
+#endif
   else
     _dl_reloc_bad_type (map, r_type, 1);
 }
index e0324a7..02285a7 100644 (file)
@@ -19,7 +19,7 @@
 
 
 /* Type used for the representation of TLS information in the GOT.  */
-typedef struct
+typedef struct dl_tls_index
 {
   unsigned long int ti_module;
   unsigned long int ti_offset;
diff --git a/sysdeps/arm/dl-tlsdesc.S b/sysdeps/arm/dl-tlsdesc.S
new file mode 100644 (file)
index 0000000..19e4ed3
--- /dev/null
@@ -0,0 +1,222 @@
+/* Thread-local storage handling in the ELF dynamic linker.  ARM version.
+   Copyright (C) 2006, 2010 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <sysdep.h>
+#include <tls.h>
+#include "tlsdesc.h"
+
+#ifdef __USE_BX__
+  #define BX(x)        bx x
+#else
+  #define BX(x)        mov pc, x
+#endif
+
+       .text
+       @ emit debug information with cfi
+       @ use arm-specific pseudos for unwinding itself
+       .cfi_sections .debug_frame
+#ifdef USE_TLS
+       .hidden _dl_tlsdesc_return
+       .global _dl_tlsdesc_return
+       .type   _dl_tlsdesc_return,#function
+       cfi_startproc
+       .fnstart
+       .align 2
+_dl_tlsdesc_return:
+       ldr     r0, [r0]
+       BX      (lr)
+       .fnend
+       cfi_endproc
+       .size   _dl_tlsdesc_return, .-_dl_tlsdesc_return
+
+       .hidden _dl_tlsdesc_undefweak
+       .global _dl_tlsdesc_undefweak
+       .type   _dl_tlsdesc_undefweak,#function
+       cfi_startproc
+       .fnstart
+       .align 2
+_dl_tlsdesc_undefweak:
+       @ Are we allowed a misaligned stack pointer calling read_tp?
+       .save   {lr}
+       stmdb   sp!, {lr}
+       cfi_adjust_cfa_offset (4)
+       cfi_rel_offset (lr,0)
+       bl      __aeabi_read_tp
+       rsb     r0, r0, #0
+       ldmia   sp!, {lr}
+       cfi_adjust_cfa_offset (-4)
+       cfi_restore (lr)
+       BX      (lr)
+
+       cfi_endproc
+       .fnend
+       .size   _dl_tlsdesc_undefweak, .-_dl_tlsdesc_undefweak
+
+#ifdef SHARED
+       .hidden _dl_tlsdesc_dynamic
+       .global _dl_tlsdesc_dynamic
+       .type   _dl_tlsdesc_dynamic,#function
+
+
+/*
+       The assembly code that follows is a rendition of the following
+       C code, hand-optimized a little bit.
+
+ptrdiff_t
+_dl_tlsdesc_dynamic(struct tlsdesc *tdp)
+{
+       struct tlsdesc_dynamic_arg *td = tdp->argument.pointer;
+       dtv_t *dtv = (dtv_t *)THREAD_DTV();
+       if (__builtin_expect (td->gen_count <= dtv[0].counter
+                             && dtv[td->tlsinfo.ti_module].pointer.val
+                                != TLS_DTV_UNALLOCATED,
+                             1))
+               return dtv[td->tlsinfo.ti_module].pointer.val +
+                       td->tlsinfo.ti_offset - __builtin_thread_pointer();
+
+       return __tls_get_addr (&td->tlsinfo) - __builtin_thread_pointer();
+}
+
+*/
+       cfi_startproc
+       .fnstart
+       .align 2
+_dl_tlsdesc_dynamic:
+       /* Our calling convention is to clobber r0, r1 and the processor
+          flags.  All others that are modified must be saved */
+       .save   {r2,r3,r4,lr}
+       stmdb   sp!, {r2,r3,r4,lr}
+       cfi_adjust_cfa_offset (16)
+       cfi_rel_offset (r2,0)
+       cfi_rel_offset (r3,4)
+       cfi_rel_offset (r4,8)
+       cfi_rel_offset (lr,12)
+       ldr     r1, [r0] /* td */
+       bl      __aeabi_read_tp
+       mov     r4, r0 /* r4 = tp */
+       ldr     r0, [r0]
+       ldr     r2, [r1, #8] /* gen_count */
+       ldr     r3, [r0]
+       cmp     r2, r3
+       bhi     1f
+       ldr     r3, [r1]
+       ldr     r2, [r0, r3, lsl #3]
+       cmn     r2, #1
+       ldrne   r3, [r1, #4]
+       addne   r3, r2, r3
+       rsbne   r0, r4, r3
+       bne     2f
+1:     mov     r0, r1
+       bl      __tls_get_addr
+       rsb     r0, r4, r0
+2:     ldmia   sp!, {r2,r3,r4, lr}
+       cfi_adjust_cfa_offset (-16)
+       cfi_restore (lr)
+       cfi_restore (r4)
+       cfi_restore (r3)
+       cfi_restore (r2)
+       BX      (lr)
+       .fnend
+       cfi_endproc
+       .size   _dl_tlsdesc_dynamic, .-_dl_tlsdesc_dynamic
+#endif /* SHARED */
+
+/* lazy resolved for tls descriptors.  */
+       .hidden _dl_tlsdesc_lazy_resolver
+       .global _dl_tlsdesc_lazy_resolver
+       .type   _dl_tlsdesc_lazy_resolver,#function
+       cfi_startproc
+       .fnstart
+       .align 2
+_dl_tlsdesc_lazy_resolver:
+       /* r0 points at the tlsdesc,
+          r1 points at the GOT
+          r2 was pushed by the trampoline and used as a temp,
+             we need to pop it here.
+         We push the remaining call-clobbered registers here, and also
+         R1 -- to keep the stack correctly aligned.  */
+       /* Tell the unwinder that r2 has already been pushed.  */
+       .save   {r2}
+       cfi_adjust_cfa_offset (4)
+       cfi_rel_offset (r2, 0)
+       .save   {r0,r1,r3,ip,lr}
+       stmdb   sp!, {r0, r1, r3, ip, lr}
+       cfi_adjust_cfa_offset (20)
+       cfi_rel_offset (r0, 0)
+       cfi_rel_offset (r1, 4)
+       cfi_rel_offset (r3, 8)
+       cfi_rel_offset (ip, 12)
+       cfi_rel_offset (lr, 16)
+       bl      _dl_tlsdesc_lazy_resolver_fixup
+       ldmia   sp!, {r0, r1, r3, ip, lr}
+       cfi_adjust_cfa_offset (-20)
+       cfi_restore (lr)
+       cfi_restore (ip)
+       cfi_restore (r3)
+       cfi_restore (r1)
+       cfi_restore (r0)
+       ldmia   sp!, {r2}
+       cfi_adjust_cfa_offset (-4)
+       cfi_restore (r2)
+       ldr     r1, [r0, #4]
+       BX      (r1)
+       .fnend
+       cfi_endproc
+       .size   _dl_tlsdesc_lazy_resolver, .-_dl_tlsdesc_lazy_resolver
+
+/* Holder for lazy tls descriptors being resolve in another thread.
+   Same ABI as the lazy resolver itself.  */
+       .hidden _dl_tlsdesc_resolve_hold
+       .global _dl_tlsdesc_resolve_hold
+       .type   _dl_tlsdesc_resolve_hold,#function
+       cfi_startproc
+       .fnstart
+       .align 2
+_dl_tlsdesc_resolve_hold:
+       /* Tell the unwinder that r2 has already been pushed.  */
+       .save   {r2}
+       cfi_adjust_cfa_offset (4)
+       cfi_rel_offset (r2, 0)
+       .save   {r0,r1,r3,ip,lr}
+       stmdb   sp!, {r0, r1, r3, ip, lr}
+       cfi_adjust_cfa_offset (20)
+       cfi_rel_offset (r0, 0)
+       cfi_rel_offset (r1, 4)
+       cfi_rel_offset (r3, 8)
+       cfi_rel_offset (ip, 12)
+       cfi_rel_offset (lr, 16)
+       adr     r2, _dl_tlsdesc_resolve_hold
+       bl      _dl_tlsdesc_resolve_hold_fixup
+       ldmia   sp!, {r0, r1, r3, ip, lr}
+       cfi_adjust_cfa_offset (-20)
+       cfi_restore (lr)
+       cfi_restore (ip)
+       cfi_restore (r3)
+       cfi_restore (r1)
+       cfi_restore (r0)
+       ldmia   sp!, {r2}
+       cfi_adjust_cfa_offset (-4)
+       cfi_restore (r2)
+       ldr     r1, [r0, #4]
+       BX      (r1)
+       .fnend
+       cfi_endproc
+       .size   _dl_tlsdesc_resolve_hold, .-_dl_tlsdesc_resolve_hold
+
+#endif /* USE_TLS */
diff --git a/sysdeps/arm/dl-tlsdesc.h b/sysdeps/arm/dl-tlsdesc.h
new file mode 100644 (file)
index 0000000..3817d7e
--- /dev/null
@@ -0,0 +1,69 @@
+/* Thread-local storage descriptor handling in the ELF dynamic linker.
+   ARM version.
+   Copyright (C) 2005, 2010 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; witout even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#ifndef _ARM_DL_TLSDESC_H
+# define _ARM_DL_TLSDESC_H 1
+
+/* Use this to access DT_TLSDESC_PLT and DT_TLSDESC_GOT.  */
+#ifndef ADDRIDX
+# define ADDRIDX(tag) (DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGNUM \
+                      + DT_EXTRANUM + DT_VALNUM + DT_ADDRTAGIDX (tag))
+#endif
+
+/* Type used to represent a TLS descriptor in the GOT.  */
+struct tlsdesc
+{
+  union
+    {
+      void *pointer;
+      long value;
+    } argument;
+  ptrdiff_t (*entry)(struct tlsdesc *);
+};
+
+
+typedef struct dl_tls_index
+{
+  unsigned long int ti_module;
+  unsigned long int ti_offset;
+} tls_index;
+
+/* Type used as the argument in a TLS descriptor for a symbol that
+   needs dynamic TLS offsets.  */
+struct tlsdesc_dynamic_arg
+{
+  tls_index tlsinfo;
+  size_t gen_count;
+};
+
+extern ptrdiff_t attribute_hidden
+  _dl_tlsdesc_return(struct tlsdesc *),
+  _dl_tlsdesc_undefweak(struct tlsdesc *),
+  _dl_tlsdesc_resolve_hold(struct tlsdesc *),
+  _dl_tlsdesc_lazy_resolver(struct tlsdesc *);
+
+# ifdef SHARED
+extern void *_dl_make_tlsdesc_dynamic (struct link_map *map, size_t ti_offset);
+
+extern ptrdiff_t attribute_hidden
+  _dl_tlsdesc_dynamic(struct tlsdesc *);
+# endif
+
+#endif
diff --git a/sysdeps/arm/tlsdesc.c b/sysdeps/arm/tlsdesc.c
new file mode 100644 (file)
index 0000000..e0b970f
--- /dev/null
@@ -0,0 +1,164 @@
+/* Manage TLS descriptors.  ARM version.
+   Copyright (C) 2005, 2010 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <link.h>
+#include <ldsodefs.h>
+#include <elf/dynamic-link.h>
+#include <tls.h>
+#include <dl-tlsdesc.h>
+#include <tlsdeschtab.h>
+
+#ifdef USE_TLS
+
+/* This function is used to lazily resolve TLS_DESC REL relocations
+   Besides the TLS descriptor itself, we get the module's got address
+   as the second parameter. */
+
+void
+attribute_hidden
+_dl_tlsdesc_lazy_resolver_fixup (struct tlsdesc volatile *td,
+                                Elf32_Addr *got)
+{
+  struct link_map *l = (struct link_map *)got[1];
+  lookup_t result;
+  unsigned long value;
+
+  if (_dl_tlsdesc_resolve_early_return_p
+      (td, (void*)(D_PTR (l, l_info[ADDRIDX (DT_TLSDESC_PLT)]) + l->l_addr)))
+    return;
+
+  if (td->argument.value & 0x80000000)
+    {
+      /* A global symbol, this is the symbol index.  */
+      /* The code below was borrowed from _dl_fixup().  */
+      const Elf_Symndx symndx = td->argument.value ^ 0x80000000;
+      const ElfW(Sym) *const symtab
+       = (const void *) D_PTR (l, l_info[DT_SYMTAB]);
+      const char *strtab = (const void *) D_PTR (l, l_info[DT_STRTAB]);
+      const ElfW(Sym) *sym = &symtab[symndx];
+
+      /* Look up the target symbol.  If the normal lookup rules are not
+        used don't look in the global scope.  */
+      if (ELFW(ST_BIND) (sym->st_info) != STB_LOCAL
+         && __builtin_expect (ELFW(ST_VISIBILITY) (sym->st_other), 0) == 0)
+       {
+         const struct r_found_version *version = NULL;
+
+         if (l->l_info[VERSYMIDX (DT_VERSYM)] != NULL)
+           {
+             const ElfW(Half) *vernum =
+               (const void *) D_PTR (l, l_info[VERSYMIDX (DT_VERSYM)]);
+             ElfW(Half) ndx = vernum[symndx] & 0x7fff;
+             version = &l->l_versions[ndx];
+             if (version->hash == 0)
+               version = NULL;
+           }
+
+         result = _dl_lookup_symbol_x
+           (strtab + sym->st_name, l, &sym,
+            l->l_scope, version, ELF_RTYPE_CLASS_PLT,
+            DL_LOOKUP_ADD_DEPENDENCY, NULL);
+         if (sym)
+           value = sym->st_value;
+         else
+           {
+             td->entry = _dl_tlsdesc_undefweak;
+             goto done;
+           }
+       }
+      else
+       {
+         /* We already found the symbol.  The module (and therefore its load
+            address) is also known.  */
+         result = l;
+         value = sym->st_value;
+       }
+    }
+  else
+    {
+      /* A local symbol, this is the offset within our tls section.
+        */
+      value = td->argument.value;
+      result = l;
+    }
+
+#ifndef SHARED
+  CHECK_STATIC_TLS (l, result);
+#else
+  if (!TRY_STATIC_TLS (l, result))
+    {
+      td->argument.pointer = _dl_make_tlsdesc_dynamic (result, value);
+      td->entry = _dl_tlsdesc_dynamic;
+    }
+  else
+#endif
+    {
+      td->argument.value = value + result->l_tls_offset;
+      td->entry = _dl_tlsdesc_return;
+    }
+
+ done:
+  _dl_tlsdesc_wake_up_held_fixups ();
+}
+
+/* This function is used to avoid busy waiting for other threads to
+   complete the lazy relocation.  Once another thread wins the race to
+   relocate a TLS descriptor, it sets the descriptor up such that this
+   function is called to wait until the resolver releases the
+   lock.  */
+
+void
+attribute_hidden
+_dl_tlsdesc_resolve_hold_fixup (struct tlsdesc volatile *td,
+                               void *caller)
+{
+  /* Maybe we're lucky and can return early.  */
+  if (caller != td->entry)
+    return;
+
+  /* Locking here will stop execution until the running resolver runs
+     _dl_tlsdesc_wake_up_held_fixups(), releasing the lock.
+
+     FIXME: We'd be better off waiting on a condition variable, such
+     that we didn't have to hold the lock throughout the relocation
+     processing.  */
+  __rtld_lock_lock_recursive (GL(dl_load_lock));
+  __rtld_lock_unlock_recursive (GL(dl_load_lock));
+}
+
+/* Unmap the dynamic object, but also release its TLS descriptor table
+   if there is one.  */
+
+void
+internal_function
+_dl_unmap (struct link_map *map)
+{
+  __munmap ((void *) (map)->l_map_start,
+           (map)->l_map_end - (map)->l_map_start);
+
+#if SHARED
+  /* _dl_unmap is only called for dlopen()ed libraries, for which
+     calling free() is safe, or before we've completed the initial
+     relocation, in which case calling free() is probably pointless,
+     but still safe.  */
+  if (map->l_mach.tlsdesc_table)
+    htab_delete (map->l_mach.tlsdesc_table);
+#endif
+}
+#endif
diff --git a/sysdeps/arm/tlsdesc.sym b/sysdeps/arm/tlsdesc.sym
new file mode 100644 (file)
index 0000000..a1deb21
--- /dev/null
@@ -0,0 +1,19 @@
+#include <stddef.h>
+#include <sysdep.h>
+#include <tls.h>
+#include <link.h>
+#include <dl-tlsdesc.h>
+
+--
+
+-- Abuse tls.h macros to derive offsets relative to the thread register.
+#if defined USE_TLS
+
+
+TLSDESC_ARG                    offsetof(struct tlsdesc, argument.pointer)
+
+TLSDESC_GEN_COUNT              offsetof(struct tlsdesc_dynamic_arg, gen_count)
+TLSDESC_MODID                  offsetof(struct tlsdesc_dynamic_arg, tlsinfo.ti_module)
+TLSDESC_MODOFF                 offsetof(struct tlsdesc_dynamic_arg, tlsinfo.ti_offset)
+
+#endif