Module Name:    src
Committed By:   jakllsch
Date:           Thu Sep 20 18:41:05 UTC 2018

Modified Files:
        src/libexec/ld.elf_so/arch/aarch64: mdreloc.c rtld_start.S

Log Message:
Improve support for R_AARCH64_TLSDESC relocations.

In large part from FreeBSD.


To generate a diff of this commit:
cvs rdiff -u -r1.8 -r1.9 src/libexec/ld.elf_so/arch/aarch64/mdreloc.c
cvs rdiff -u -r1.2 -r1.3 src/libexec/ld.elf_so/arch/aarch64/rtld_start.S

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/libexec/ld.elf_so/arch/aarch64/mdreloc.c
diff -u src/libexec/ld.elf_so/arch/aarch64/mdreloc.c:1.8 src/libexec/ld.elf_so/arch/aarch64/mdreloc.c:1.9
--- src/libexec/ld.elf_so/arch/aarch64/mdreloc.c:1.8	Mon Jul 16 00:29:37 2018
+++ src/libexec/ld.elf_so/arch/aarch64/mdreloc.c	Thu Sep 20 18:41:05 2018
@@ -1,4 +1,4 @@
-/* $NetBSD: mdreloc.c,v 1.8 2018/07/16 00:29:37 christos Exp $ */
+/* $NetBSD: mdreloc.c,v 1.9 2018/09/20 18:41:05 jakllsch Exp $ */
 
 /*-
  * Copyright (c) 2014 The NetBSD Foundation, Inc.
@@ -29,9 +29,38 @@
  * POSSIBILITY OF SUCH DAMAGE.
  */
 
+/*-
+ * Copyright (c) 2014-2015 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * Portions of this software were developed by Andrew Turner
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
 #include <sys/cdefs.h>
 #ifndef lint
-__RCSID("$NetBSD: mdreloc.c,v 1.8 2018/07/16 00:29:37 christos Exp $");
+__RCSID("$NetBSD: mdreloc.c,v 1.9 2018/09/20 18:41:05 jakllsch Exp $");
 #endif /* not lint */
 
 #include <sys/types.h>
@@ -40,10 +69,18 @@ __RCSID("$NetBSD: mdreloc.c,v 1.8 2018/0
 #include "debug.h"
 #include "rtld.h"
 
+struct tls_data {
+	int64_t index;
+	Obj_Entry *obj;
+	const Elf_Rela *rela;
+};
+
 void _rtld_bind_start(void);
 void _rtld_relocate_nonplt_self(Elf_Dyn *, Elf_Addr);
 Elf_Addr _rtld_bind(const Obj_Entry *, Elf_Word);
 void *_rtld_tlsdesc(void *);
+void *_rtld_tlsdesc_dynamic(void *);
+int64_t _rtld_tlsdesc_handle(struct tls_data *, u_int);
 
 /*
  * AARCH64 PLT looks like this;
@@ -79,6 +116,71 @@ _rtld_setup_pltgot(const Obj_Entry *obj)
 	obj->pltgot[2] = (Elf_Addr) &_rtld_bind_start;
 }
 
+static struct tls_data *
+_rtld_tlsdesc_alloc(Obj_Entry *obj, const Elf_Rela *rela)
+{
+	struct tls_data *tlsdesc;
+
+	tlsdesc = xmalloc(sizeof(*tlsdesc));
+	tlsdesc->index = -1;
+	tlsdesc->obj = obj;
+	tlsdesc->rela = rela;
+
+	return tlsdesc;
+}
+
+static int64_t
+_rtld_tlsdesc_handle_locked(struct tls_data *tlsdesc, u_int flags)
+{
+	const Elf_Rela *rela;
+	const Elf_Sym *def;
+	const Obj_Entry *defobj;
+	Obj_Entry *obj;
+
+	rela = tlsdesc->rela;
+	obj = tlsdesc->obj;
+
+	def = _rtld_find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, flags);
+	if (def == NULL)
+		_rtld_die();
+
+	tlsdesc->index = defobj->tlsoffset + def->st_value + rela->r_addend +
+	    sizeof(struct tls_tcb);
+
+	return tlsdesc->index;
+}
+
+int64_t
+_rtld_tlsdesc_handle(struct tls_data *tlsdesc, u_int flags)
+{
+	sigset_t mask;
+
+	/* We have already found the index, return it */
+	if (tlsdesc->index >= 0)
+		return tlsdesc->index;
+
+	_rtld_exclusive_enter(&mask);
+	/* tlsdesc->index may have been set by another thread */
+	if (tlsdesc->index == -1)
+		_rtld_tlsdesc_handle_locked(tlsdesc, flags);
+	_rtld_exclusive_exit(&mask);
+
+	return tlsdesc->index;
+}
+
+static void
+_rtld_tlsdesc_fill(Obj_Entry *obj, const Elf_Rela *rela, Elf_Addr *where)
+{
+	if (ELF_R_SYM(rela->r_info) == 0) {
+		where[0] = (Elf_Addr)_rtld_tlsdesc;
+		where[1] = obj->tlsoffset + rela->r_addend +
+		    sizeof(struct tls_tcb);
+	} else {
+		where[0] = (Elf_Addr)_rtld_tlsdesc_dynamic;
+		where[1] = (Elf_Addr)_rtld_tlsdesc_alloc(obj, rela);
+	}
+}
+
 void
 _rtld_relocate_nonplt_self(Elf_Dyn *dynp, Elf_Addr relocbase)
 {
@@ -173,6 +275,10 @@ _rtld_relocate_nonplt_objects(Obj_Entry 
 			rdbg(("COPY (avoid in main)"));
 			break;
 
+		case R_TYPE(TLSDESC):
+			_rtld_tlsdesc_fill(obj, rela, where);
+			break;
+
 		case R_TLS_TYPE(TLS_DTPREL):
 			*where = (Elf_Addr)(def->st_value + rela->r_addend);
 
@@ -239,11 +345,7 @@ _rtld_relocate_plt_lazy(Obj_Entry *obj)
 			rdbg(("fixup !main in %s --> %p", obj->path, (void *)*where));
 			break;
 		case R_TYPE(TLSDESC):
-			assert(ELF_R_SYM(rela->r_info) == 0);	/* XXX */
-			if (ELF_R_SYM(rela->r_info) == 0) {
-				where[0] = (Elf_Addr)_rtld_tlsdesc;
-				where[1] = obj->tlsoffset + rela->r_addend + sizeof(struct tls_tcb);
-			}
+			_rtld_tlsdesc_fill(obj, rela, where);
 			break;
 		}
 	}
@@ -280,29 +382,40 @@ _rtld_relocate_plt_object(const Obj_Entr
 	Elf_Addr new_value;
 	const Elf_Sym  *def;
 	const Obj_Entry *defobj;
-	unsigned long info = rela->r_info;
-
-	assert(ELF_R_TYPE(info) == R_TYPE(JUMP_SLOT));
 
-	def = _rtld_find_plt_symdef(ELF_R_SYM(info), obj, &defobj, tp != NULL);
-	if (__predict_false(def == NULL))
-		return -1;
-	if (__predict_false(def == &_rtld_sym_zero))
-		return 0;
-
-	if (ELF_ST_TYPE(def->st_info) == STT_GNU_IFUNC) {
-		if (tp == NULL)
+	switch (ELF_R_TYPE(rela->r_info)) {
+	case R_TYPE(JUMP_SLOT):
+		def = _rtld_find_plt_symdef(ELF_R_SYM(rela->r_info), obj,
+		    &defobj, tp != NULL);
+		if (__predict_false(def == NULL))
+			return -1;
+		if (__predict_false(def == &_rtld_sym_zero))
 			return 0;
-		new_value = _rtld_resolve_ifunc(defobj, def);
-	} else {
-		new_value = (Elf_Addr)(defobj->relocbase + def->st_value);
+
+		if (ELF_ST_TYPE(def->st_info) == STT_GNU_IFUNC) {
+			if (tp == NULL)
+				return 0;
+			new_value = _rtld_resolve_ifunc(defobj, def);
+		} else {
+			new_value = (Elf_Addr)(defobj->relocbase +
+			     def->st_value);
+		}
+		rdbg(("bind now/fixup in %s --> old=%p new=%p",
+		    defobj->strtab + def->st_name, (void *)*where,
+		    (void *)new_value));
+		if (*where != new_value)
+			*where = new_value;
+		if (tp)
+			*tp = new_value;
+		break;
+	case R_TYPE(TLSDESC):
+		if (ELF_R_SYM(rela->r_info) != 0) {
+			struct tls_data *tlsdesc = (struct tls_data *)where[1];
+			if (tlsdesc->index == -1)
+				_rtld_tlsdesc_handle(tlsdesc, SYMLOOK_IN_PLT);
+		}
+		break;
 	}
-	rdbg(("bind now/fixup in %s --> old=%p new=%p",
-	    defobj->strtab + def->st_name, (void *)*where, (void *)new_value));
-	if (*where != new_value)
-		*where = new_value;
-	if (tp)
-		*tp = new_value;
 
 	return 0;
 }

Index: src/libexec/ld.elf_so/arch/aarch64/rtld_start.S
diff -u src/libexec/ld.elf_so/arch/aarch64/rtld_start.S:1.2 src/libexec/ld.elf_so/arch/aarch64/rtld_start.S:1.3
--- src/libexec/ld.elf_so/arch/aarch64/rtld_start.S:1.2	Sun Feb  4 21:49:51 2018
+++ src/libexec/ld.elf_so/arch/aarch64/rtld_start.S	Thu Sep 20 18:41:05 2018
@@ -1,4 +1,4 @@
-/* $NetBSD: rtld_start.S,v 1.2 2018/02/04 21:49:51 skrll Exp $ */
+/* $NetBSD: rtld_start.S,v 1.3 2018/09/20 18:41:05 jakllsch Exp $ */
 
 /*-
  * Copyright (c) 2014 The NetBSD Foundation, Inc.
@@ -29,9 +29,38 @@
  * POSSIBILITY OF SUCH DAMAGE.
  */
 
+/*-
+ * Copyright (c) 2014 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Andrew Turner under
+ * sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
 #include <machine/asm.h>
 
-RCSID("$NetBSD: rtld_start.S,v 1.2 2018/02/04 21:49:51 skrll Exp $")
+RCSID("$NetBSD: rtld_start.S,v 1.3 2018/09/20 18:41:05 jakllsch Exp $")
 
 /*
  * void _rtld_start(void (*cleanup)(void), const Obj_Entry *obj,
@@ -121,3 +150,42 @@ ENTRY(_rtld_tlsdesc)
 	ldr	x0, [x0, #8]
 	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)

Reply via email to