Author: andrew
Date: Fri Apr  3 09:35:52 2015
New Revision: 281014
URL: https://svnweb.freebsd.org/changeset/base/281014

Log:
  Add support for thread local storage on arm64 to the runtime linker. The
  ABI specifies that, for R_AARCH64_TLSDESC relocations, we use the symbol
  value, addend, and object tls offset to calculate the offset from the tls
  base. We then cache this value for future reference.
  
  Differential Revision:        https://reviews.freebsd.org/D2183
  Reviewed by:  kib
  Sponsored by: The FreeBSD Foundation

Modified:
  head/libexec/rtld-elf/aarch64/reloc.c
  head/libexec/rtld-elf/aarch64/rtld_start.S

Modified: head/libexec/rtld-elf/aarch64/reloc.c
==============================================================================
--- head/libexec/rtld-elf/aarch64/reloc.c       Fri Apr  3 06:17:24 2015        
(r281013)
+++ head/libexec/rtld-elf/aarch64/reloc.c       Fri Apr  3 09:35:52 2015        
(r281014)
@@ -50,6 +50,8 @@ __FBSDID("$FreeBSD$");
  * a function pointer to a simple asm function.
  */
 void *_rtld_tlsdesc(void *);
+void *_rtld_tlsdesc_dynamic(void *);
+
 void _exit(int);
 
 void
@@ -120,6 +122,68 @@ do_copy_relocations(Obj_Entry *dstobj)
        return (0);
 }
 
+struct tls_data {
+       int64_t index;
+       Obj_Entry *obj;
+       const Elf_Rela *rela;
+};
+
+static struct tls_data *
+reloc_tlsdesc_alloc(Obj_Entry *obj, const Elf_Rela *rela)
+{
+       struct tls_data *tlsdesc;
+
+       tlsdesc = xmalloc(sizeof(struct tls_data));
+       tlsdesc->index = -1;
+       tlsdesc->obj = obj;
+       tlsdesc->rela = rela;
+
+       return (tlsdesc);
+}
+
+/*
+ * Look up the symbol to find its tls index
+ */
+static int64_t
+rtld_tlsdesc_handle_locked(struct tls_data *tlsdesc, int flags,
+    RtldLockState *lockstate)
+{
+       const Elf_Rela *rela;
+       const Elf_Sym *def;
+       const Obj_Entry *defobj;
+       Obj_Entry *obj;
+
+       rela = tlsdesc->rela;
+       obj = tlsdesc->obj;
+
+       def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, flags, NULL,
+           lockstate);
+       if (def == NULL)
+               rtld_die();
+
+       tlsdesc->index = defobj->tlsindex + def->st_value + rela->r_addend;
+
+       return (tlsdesc->index);
+}
+
+int64_t
+rtld_tlsdesc_handle(struct tls_data *tlsdesc, int flags)
+{
+       RtldLockState lockstate;
+
+       /* We have already found the index, return it */
+       if (tlsdesc->index >= 0)
+               return (tlsdesc->index);
+
+       wlock_acquire(rtld_bind_lock, &lockstate);
+       /* tlsdesc->index may have been set by another thread */
+       if (tlsdesc->index == -1)
+               rtld_tlsdesc_handle_locked(tlsdesc, flags, &lockstate);
+       lock_release(rtld_bind_lock, &lockstate);
+
+       return (tlsdesc->index);
+}
+
 /*
  * Process the PLT relocations.
  */
@@ -142,11 +206,11 @@ reloc_plt(Obj_Entry *obj)
                case R_AARCH64_TLSDESC:
                        if (ELF_R_SYM(rela->r_info) == 0) {
                                where[0] = (Elf_Addr)_rtld_tlsdesc;
-                               where[1] = rela->r_addend;
+                               where[1] = obj->tlsindex + rela->r_addend;
                        } else {
-                               _rtld_error("Unable to handle "
-                                   "R_AARCH64_TLSDESC with a symbol set");
-                               return (-1);
+                               where[0] = (Elf_Addr)_rtld_tlsdesc_dynamic;
+                               where[1] = (Elf_Addr)reloc_tlsdesc_alloc(obj,
+                                   rela);
                        }
                        break;
                default:
@@ -169,14 +233,15 @@ reloc_jmpslots(Obj_Entry *obj, int flags
        const Elf_Rela *relalim;
        const Elf_Rela *rela;
        const Elf_Sym *def;
+       struct tls_data *tlsdesc;
 
        relalim = (const Elf_Rela *)((char *)obj->pltrela + obj->pltrelasize);
        for (rela = obj->pltrela; rela < relalim; rela++) {
                Elf_Addr *where;
 
+               where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
                switch(ELF_R_TYPE(rela->r_info)) {
                case R_AARCH64_JUMP_SLOT:
-                       where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
                        def = find_symdef(ELF_R_SYM(rela->r_info), obj,
                            &defobj, SYMLOOK_IN_PLT | flags, NULL, lockstate);
                        if (def == NULL) {
@@ -187,6 +252,12 @@ reloc_jmpslots(Obj_Entry *obj, int flags
                        *where = (Elf_Addr)(defobj->relocbase + def->st_value);
                        break;
                case R_AARCH64_TLSDESC:
+                       if (ELF_R_SYM(rela->r_info) != 0) {
+                               tlsdesc = (struct tls_data *)where[1];
+                               if (tlsdesc->index == -1)
+                                       rtld_tlsdesc_handle_locked(tlsdesc,
+                                           SYMLOOK_IN_PLT | flags, lockstate);
+                       }
                        break;
                default:
                        _rtld_error("Unknown relocation type %x in jmpslot",
@@ -285,6 +356,32 @@ reloc_non_plt(Obj_Entry *obj, Obj_Entry 
                                return (-1);
                        }
                        break;
+               case R_AARCH64_TLS_TPREL64:
+                       def = find_symdef(symnum, obj, &defobj, flags, cache,
+                           lockstate);
+                       if (def == NULL)
+                               return (-1);
+
+                       /*
+                        * We lazily allocate offsets for static TLS as we
+                        * see the first relocation that references the
+                        * TLS block. This allows us to support (small
+                        * amounts of) static TLS in dynamically loaded
+                        * modules. If we run out of space, we generate an
+                        * error.
+                        */
+                       if (!defobj->tls_done) {
+                               if (!allocate_tls_offset((Obj_Entry*) defobj)) {
+                                       _rtld_error(
+                                           "%s: No space available for static "
+                                           "Thread Local Storage", obj->path);
+                                       return (-1);
+                               }
+                       }
+
+                       *where = def->st_value + rela->r_addend +
+                           defobj->tlsoffset - TLS_TCB_SIZE;
+                       break;
                case R_AARCH64_RELATIVE:
                        *where = (Elf_Addr)(obj->relocbase + rela->r_addend);
                        break;

Modified: head/libexec/rtld-elf/aarch64/rtld_start.S
==============================================================================
--- head/libexec/rtld-elf/aarch64/rtld_start.S  Fri Apr  3 06:17:24 2015        
(r281013)
+++ head/libexec/rtld-elf/aarch64/rtld_start.S  Fri Apr  3 09:35:52 2015        
(r281014)
@@ -109,5 +109,44 @@ END(_rtld_bind_start)
  */
 ENTRY(_rtld_tlsdesc)
        ldr     x0, [x0, #8]
-       RET
+       ret
 END(_rtld_tlsdesc)
+
+/*
+ * uint64_t _rtld_tlsdesc_dynamic(struct tlsdesc *);
+ *
+ * TODO: We could lookup the saved index here to skip saving the entire stack.
+ */
+ENTRY(_rtld_tlsdesc_dynamic)
+       /* Store any registers we may use in rtld_tlsdesc_handle */
+       stp     x29, x30, [sp, #-(10 * 16)]!
+       mov     x29, sp
+       stp     x1, x2,   [sp, #(1 * 16)]
+       stp     x3, x4,   [sp, #(2 * 16)]
+       stp     x5, x6,   [sp, #(3 * 16)]
+       stp     x7, x8,   [sp, #(4 * 16)]
+       stp     x9, x10,  [sp, #(5 * 16)]
+       stp     x11, x12, [sp, #(6 * 16)]
+       stp     x13, x14, [sp, #(7 * 16)]
+       stp     x15, x16, [sp, #(8 * 16)]
+       stp     x17, x18, [sp, #(9 * 16)]
+
+       /* Find the tls offset */
+       ldr     x0, [x0, #8]
+       mov     x1, #1
+       bl      rtld_tlsdesc_handle
+
+       /* Restore the registers */
+       ldp     x17, x18, [sp, #(9 * 16)]
+       ldp     x15, x16, [sp, #(8 * 16)]
+       ldp     x13, x14, [sp, #(7 * 16)]
+       ldp     x11, x12, [sp, #(6 * 16)]
+       ldp     x9, x10,  [sp, #(5 * 16)]
+       ldp     x7, x8,   [sp, #(4 * 16)]
+       ldp     x5, x6,   [sp, #(3 * 16)]
+       ldp     x3, x4,   [sp, #(2 * 16)]
+       ldp     x1, x2,   [sp, #(1 * 16)]
+       ldp     x29, x30, [sp], #(10 * 16)
+
+       ret
+END(_rtld_tlsdesc_dynamic)
_______________________________________________
svn-src-head@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to