svn commit: r281014 - head/libexec/rtld-elf/aarch64

Andrew Turner andrew at FreeBSD.org
Fri Apr 3 09:35:54 UTC 2015


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)


More information about the svn-src-head mailing list