Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 7 Apr 2021 00:28:09 +0300
From:      Konstantin Belousov <kostikbel@gmail.com>
To:        Jung-uk Kim <jkim@freebsd.org>
Cc:        src-committers@freebsd.org, dev-commits-src-all@freebsd.org, dev-commits-src-main@freebsd.org
Subject:   Re: git: d36d68161517 - main - rtld dl_iterate_phdr(): dlpi_tls_data is wrong
Message-ID:  <YGzSaTULw00GTtR3@kib.kiev.ua>
In-Reply-To: <YGysnYc0qhYojZ4j@kib.kiev.ua>
References:  <202104060037.1360bKwT029051@gitrepo.freebsd.org> <a8d3236a-99cf-df0a-1c33-aa62709bf630@FreeBSD.org> <YGysnYc0qhYojZ4j@kib.kiev.ua>

next in thread | previous in thread | raw e-mail | index | archive | help
On Tue, Apr 06, 2021 at 09:46:59PM +0300, Konstantin Belousov wrote:
> On Tue, Apr 06, 2021 at 02:35:59PM -0400, Jung-uk Kim wrote:
> > On 21. 4. 5., Konstantin Belousov wrote:
> > > The branch main has been updated by kib:
> > > 
> > > URL: https://cgit.FreeBSD.org/src/commit/?id=d36d6816151705907393889d661cbfd25c630ca8
> > > 
> > > commit d36d6816151705907393889d661cbfd25c630ca8
> > > Author:     Konstantin Belousov <kib@FreeBSD.org>
> > > AuthorDate: 2021-04-05 03:05:44 +0000
> > > Commit:     Konstantin Belousov <kib@FreeBSD.org>
> > > CommitDate: 2021-04-06 00:23:08 +0000
> > > 
> > >     rtld dl_iterate_phdr(): dlpi_tls_data is wrong
> > >     
> > >     dl_iterate_phdr() dlpi_tls_data should provide the TLS module segment
> > >     address, and not the TLS init segment address as it does now.
> > >     
> > >     Reported by:    emacsray@gmail.com
> > >     PR:     254774
> > >     Sponsored by:   The FreeBSD Foundation
> > >     MFC after:      1 week
> > 
> > I started having strange hangs in various applications from yesterday,
> > e.g., Xorg, Thunderbird, etc.  Today, I updated ports tree from Git for
> > the first time and started updating packages.  Then, I experienced
> > similar problems, e.g., building editors/kate, multimedia/vlc, etc.,
> > were hanging.  I noticed some tools were stuck in urwlck state and I
> > found reverting this commit fixed the problem for me.
> > 
> > Please take a look.
> 
> Can you get backtrace for all threads in hanging process?
> I do not need debugging symbols for the apps, libc/libthr/rtld with debug
> info, installed by default from the base, should be enough.

Also you might try this.  It should help if my guess is right.
Only x86 handled ATM.

diff --git a/lib/libc/amd64/gen/Makefile.inc b/lib/libc/amd64/gen/Makefile.inc
index 30fb05f89cb7..4df3c044493e 100644
--- a/lib/libc/amd64/gen/Makefile.inc
+++ b/lib/libc/amd64/gen/Makefile.inc
@@ -1,7 +1,7 @@
 #	@(#)Makefile.inc	8.1 (Berkeley) 6/4/93
 # $FreeBSD$
 
-SRCS+=	_setjmp.S _set_tp.c rfork_thread.S setjmp.S sigsetjmp.S \
+SRCS+=	_setjmp.S _get_tp.c _set_tp.c rfork_thread.S setjmp.S sigsetjmp.S \
 	fabs.S \
 	infinity.c ldexp.c makecontext.c signalcontext.c \
 	flt_rounds.c fpgetmask.c fpsetmask.c fpgetprec.c fpsetprec.c \
diff --git a/lib/libc/amd64/gen/_get_tp.c b/lib/libc/amd64/gen/_get_tp.c
new file mode 100644
index 000000000000..73770ca7fa08
--- /dev/null
+++ b/lib/libc/amd64/gen/_get_tp.c
@@ -0,0 +1,46 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2021 The FreeBSD Foundation
+ *
+ * This software were developed by Konstantin Belousov
+ * 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.
+ *
+ *	$FreeBSD$
+ */
+
+#include <string.h>
+#include <stdint.h>
+#include <machine/sysarch.h>
+#include "libc_private.h"
+
+void *
+_get_tp(void)
+{
+	void **res;
+
+	/* This function is used by rtld, avoid ifuncs. */
+	__asm __volatile("movq %%fs:0, %0" : "=r" (res));
+	return (&res[1]);
+}
diff --git a/lib/libc/gen/Makefile.inc b/lib/libc/gen/Makefile.inc
index 0ab717600e56..ab2c1409f879 100644
--- a/lib/libc/gen/Makefile.inc
+++ b/lib/libc/gen/Makefile.inc
@@ -172,6 +172,11 @@ SRCS+=	__getosreldate.c \
 
 CFLAGS.arc4random.c= -I${SRCTOP}/sys -I${SRCTOP}/sys/crypto/chacha20
 
+RTLD_HDRS= -I${SRCTOP}/libexec/rtld-elf \
+    -I${SRCTOP}/libexec/rtld-elf/${MACHINE_CPUARCH}
+CFLAGS.dlfcn.c= ${RTLD_HDRS}
+CFLAGS.tls.c= ${RTLD_HDRS}
+
 .PATH: ${SRCTOP}/contrib/libc-pwcache
 SRCS+=	pwcache.c pwcache.h
 
diff --git a/lib/libc/gen/dlfcn.c b/lib/libc/gen/dlfcn.c
index 395a6d9402e8..337ad48fd691 100644
--- a/lib/libc/gen/dlfcn.c
+++ b/lib/libc/gen/dlfcn.c
@@ -43,10 +43,11 @@ __FBSDID("$FreeBSD$");
 #include "namespace.h"
 #include <pthread.h>
 #include "un-namespace.h"
+#include "rtld.h"
 #include "libc_private.h"
 #include "reentrant.h"
 
-static char sorry[] = "Service unavailable";
+static const char sorry[] = "Service unavailable";
 
 void _rtld_thread_init(void *);
 void _rtld_atfork_pre(int *);
@@ -91,7 +92,7 @@ char *
 dlerror(void)
 {
 
-	return (sorry);
+	return (__DECONST(char *, sorry));
 }
 
 #pragma weak dllockinit
@@ -195,8 +196,6 @@ dl_init_phdr_info(void)
 	for (i = 0; i < phdr_info.dlpi_phnum; i++) {
 		if (phdr_info.dlpi_phdr[i].p_type == PT_TLS) {
 			phdr_info.dlpi_tls_modid = 1;
-			phdr_info.dlpi_tls_data =
-			    (void*)phdr_info.dlpi_phdr[i].p_vaddr;
 		}
 	}
 	phdr_info.dlpi_adds = 1;
@@ -209,13 +208,17 @@ dl_iterate_phdr(int (*callback)(struct dl_phdr_info *, size_t, void *) __unused,
     void *data __unused)
 {
 #ifndef IN_LIBDL
+	tls_index ti;
 	int ret;
 
 	__init_elf_aux_vector();
 	if (__elf_aux_vector == NULL)
 		return (1);
 	_once(&dl_phdr_info_once, dl_init_phdr_info);
+	ti.ti_module = 1;
+	ti.ti_offset = 0;
 	mutex_lock(&dl_phdr_info_lock);
+	phdr_info.dlpi_tls_data = __tls_get_addr(&ti);
 	ret = callback(&phdr_info, sizeof(phdr_info), data);
 	mutex_unlock(&dl_phdr_info_lock);
 	return (ret);
diff --git a/lib/libc/gen/tls.c b/lib/libc/gen/tls.c
index 719391130827..8c525e3e996a 100644
--- a/lib/libc/gen/tls.c
+++ b/lib/libc/gen/tls.c
@@ -41,6 +41,7 @@
 #include <elf.h>
 #include <unistd.h>
 
+#include "rtld.h"
 #include "libc_private.h"
 
 #define	tls_assert(cond)	((cond) ? (void) 0 :			\
@@ -96,35 +97,41 @@ void __libc_free_tls(void *tls, size_t tcbsize, size_t tcbalign);
 
 #ifndef PIC
 
-static size_t tls_static_space;
-static size_t tls_init_size;
-static size_t tls_init_align;
-static void *tls_init;
+static size_t libc_tls_static_space;
+static size_t libc_tls_init_size;
+static size_t libc_tls_init_align;
+static void *libc_tls_init;
 #endif
 
+void *
+__libc_tls_get_addr(void *vti)
+{
+	Elf_Addr **dtvp, *dtv;
+	tls_index *ti;
+
+	dtvp = _get_tp();
+	dtv = *dtvp;
+	ti = vti;
+	return ((void *)(dtv[ti->ti_module + 1] + ti->ti_offset));
+}
+
 #ifdef __i386__
 
 /* GNU ABI */
 
 __attribute__((__regparm__(1)))
 void *
-___libc_tls_get_addr(void *ti __unused)
+___libc_tls_get_addr(void *vti)
 {
-	return (0);
+	return (__libc_tls_get_addr(vti));
 }
 
 #endif
 
-void *
-__libc_tls_get_addr(void *ti __unused)
-{
-	return (0);
-}
-
 #ifndef PIC
 
 static void *
-malloc_aligned(size_t size, size_t align)
+libc_malloc_aligned(size_t size, size_t align)
 {
 	void *mem, *res;
 
@@ -138,7 +145,7 @@ malloc_aligned(size_t size, size_t align)
 }
 
 static void
-free_aligned(void *ptr)
+libc_free_aligned(void *ptr)
 {
 	void *mem;
 	uintptr_t x;
@@ -201,12 +208,13 @@ get_tls_block_ptr(void *tcb, size_t tcbsize)
 	/* Compute fragments sizes. */
 	extra_size = tcbsize - TLS_TCB_SIZE;
 #if defined(__aarch64__) || defined(__arm__)
-	post_size =  roundup2(TLS_TCB_SIZE, tls_init_align) - TLS_TCB_SIZE;
+	post_size =  roundup2(TLS_TCB_SIZE, libc_tls_init_align) - TLS_TCB_SIZE;
 #else
 	post_size = 0;
 #endif
 	tls_block_size = tcbsize + post_size;
-	pre_size = roundup2(tls_block_size, tls_init_align) - tls_block_size;
+	pre_size = roundup2(tls_block_size, libc_tls_init_align) -
+	    tls_block_size;
 
 	return ((char *)tcb - pre_size - extra_size);
 }
@@ -225,7 +233,7 @@ __libc_free_tls(void *tcb, size_t tcbsize, size_t tcbalign __unused)
 	tls = (Elf_Addr **)tcb;
 	dtv = tls[0];
 	__je_bootstrap_free(dtv);
-	free_aligned(get_tls_block_ptr(tcb, tcbsize));
+	libc_free_aligned(get_tls_block_ptr(tcb, tcbsize));
 }
 
 /*
@@ -259,21 +267,22 @@ __libc_allocate_tls(void *oldtcb, size_t tcbsize, size_t tcbalign)
 		return (oldtcb);
 
 	tls_assert(tcbalign >= TLS_TCB_ALIGN);
-	maxalign = MAX(tcbalign, tls_init_align);
+	maxalign = MAX(tcbalign, libc_tls_init_align);
 
 	/* Compute fragmets sizes. */
 	extra_size = tcbsize - TLS_TCB_SIZE;
 #if defined(__aarch64__) || defined(__arm__)
-	post_size = roundup2(TLS_TCB_SIZE, tls_init_align) - TLS_TCB_SIZE;
+	post_size = roundup2(TLS_TCB_SIZE, libc_tls_init_align) - TLS_TCB_SIZE;
 #else
 	post_size = 0;
 #endif
 	tls_block_size = tcbsize + post_size;
-	pre_size = roundup2(tls_block_size, tls_init_align) - tls_block_size;
-	tls_block_size += pre_size + tls_static_space;
+	pre_size = roundup2(tls_block_size, libc_tls_init_align) -
+	    tls_block_size;
+	tls_block_size += pre_size + libc_tls_static_space;
 
 	/* Allocate whole TLS block */
-	tls_block = malloc_aligned(tls_block_size, maxalign);
+	tls_block = libc_malloc_aligned(tls_block_size, maxalign);
 	if (tls_block == NULL) {
 		tls_msg("__libc_allocate_tls: Out of memory.\n");
 		abort();
@@ -285,7 +294,7 @@ __libc_allocate_tls(void *oldtcb, size_t tcbsize, size_t tcbalign)
 	if (oldtcb != NULL) {
 		memcpy(tls_block, get_tls_block_ptr(oldtcb, tcbsize),
 		    tls_block_size);
-		free_aligned(oldtcb);
+		libc_free_aligned(oldtcb);
 
 		/* Adjust the DTV. */
 		dtv = tcb[0];
@@ -302,8 +311,8 @@ __libc_allocate_tls(void *oldtcb, size_t tcbsize, size_t tcbalign)
 		dtv[1] = 1;		/* Segments count. */
 		dtv[2] = (Elf_Addr)(tls + DTV_OFFSET);
 
-		if (tls_init_size > 0)
-			memcpy(tls, tls_init, tls_init_size);
+		if (libc_tls_init_size > 0)
+			memcpy(tls, libc_tls_init, libc_tls_init_size);
 	}
 
 	return (tcb);
@@ -329,13 +338,13 @@ __libc_free_tls(void *tcb, size_t tcbsize __unused, size_t tcbalign)
 	 * Figure out the size of the initial TLS block so that we can
 	 * find stuff which ___tls_get_addr() allocated dynamically.
 	 */
-	tcbalign = MAX(tcbalign, tls_init_align);
-	size = roundup2(tls_static_space, tcbalign);
+	tcbalign = MAX(tcbalign, libc_tls_init_align);
+	size = roundup2(libc_tls_static_space, tcbalign);
 
 	dtv = ((Elf_Addr**)tcb)[1];
 	tlsend = (Elf_Addr) tcb;
 	tlsstart = tlsend - size;
-	free_aligned((void*)tlsstart);
+	libc_free_aligned((void*)tlsstart);
 	__je_bootstrap_free(dtv);
 }
 
@@ -350,12 +359,12 @@ __libc_allocate_tls(void *oldtls, size_t tcbsize, size_t tcbalign)
 	Elf_Addr *dtv;
 	Elf_Addr segbase, oldsegbase;
 
-	tcbalign = MAX(tcbalign, tls_init_align);
-	size = roundup2(tls_static_space, tcbalign);
+	tcbalign = MAX(tcbalign, libc_tls_init_align);
+	size = roundup2(libc_tls_static_space, tcbalign);
 
 	if (tcbsize < 2 * sizeof(Elf_Addr))
 		tcbsize = 2 * sizeof(Elf_Addr);
-	tls = malloc_aligned(size + tcbsize, tcbalign);
+	tls = libc_malloc_aligned(size + tcbsize, tcbalign);
 	if (tls == NULL) {
 		tls_msg("__libc_allocate_tls: Out of memory.\n");
 		abort();
@@ -373,16 +382,16 @@ __libc_allocate_tls(void *oldtls, size_t tcbsize, size_t tcbalign)
 
 	dtv[0] = 1;
 	dtv[1] = 1;
-	dtv[2] = segbase - tls_static_space;
+	dtv[2] = segbase - libc_tls_static_space;
 
 	if (oldtls) {
 		/*
 		 * Copy the static TLS block over whole.
 		 */
 		oldsegbase = (Elf_Addr) oldtls;
-		memcpy((void *)(segbase - tls_static_space),
-		    (const void *)(oldsegbase - tls_static_space),
-		    tls_static_space);
+		memcpy((void *)(segbase - libc_tls_static_space),
+		    (const void *)(oldsegbase - libc_tls_static_space),
+		    libc_tls_static_space);
 
 		/*
 		 * We assume that this block was the one we created with
@@ -390,10 +399,11 @@ __libc_allocate_tls(void *oldtls, size_t tcbsize, size_t tcbalign)
 		 */
 		_rtld_free_tls(oldtls, 2*sizeof(Elf_Addr), sizeof(Elf_Addr));
 	} else {
-		memcpy((void *)(segbase - tls_static_space),
-		    tls_init, tls_init_size);
-		memset((void *)(segbase - tls_static_space + tls_init_size),
-		    0, tls_static_space - tls_init_size);
+		memcpy((void *)(segbase - libc_tls_static_space),
+		    libc_tls_init, libc_tls_init_size);
+		memset((void *)(segbase - libc_tls_static_space +
+		    libc_tls_init_size), 0,
+		    libc_tls_static_space - libc_tls_init_size);
 	}
 
 	return (void*) segbase;
@@ -457,11 +467,11 @@ _init_tls(void)
 
 	for (i = 0; (unsigned) i < phnum; i++) {
 		if (phdr[i].p_type == PT_TLS) {
-			tls_static_space = roundup2(phdr[i].p_memsz,
+			libc_tls_static_space = roundup2(phdr[i].p_memsz,
 			    phdr[i].p_align);
-			tls_init_size = phdr[i].p_filesz;
-			tls_init_align = phdr[i].p_align;
-			tls_init = (void*) phdr[i].p_vaddr;
+			libc_tls_init_size = phdr[i].p_filesz;
+			libc_tls_init_align = phdr[i].p_align;
+			libc_tls_init = (void *)phdr[i].p_vaddr;
 			break;
 		}
 	}
diff --git a/lib/libc/i386/gen/Makefile.inc b/lib/libc/i386/gen/Makefile.inc
index 45e69cad1d0f..bad73852f6eb 100644
--- a/lib/libc/i386/gen/Makefile.inc
+++ b/lib/libc/i386/gen/Makefile.inc
@@ -1,6 +1,6 @@
 #	@(#)Makefile.inc	8.1 (Berkeley) 6/4/93
 # $FreeBSD$
 
-SRCS+=	_ctx_start.S _setjmp.S _set_tp.c fabs.S \
+SRCS+=	_ctx_start.S _setjmp.S _set_tp.c _get_tp.c fabs.S \
 	flt_rounds.c infinity.c ldexp.c makecontext.c \
 	rfork_thread.S setjmp.S signalcontext.c sigsetjmp.S
diff --git a/lib/libc/i386/gen/_get_tp.c b/lib/libc/i386/gen/_get_tp.c
new file mode 100644
index 000000000000..7910d752753f
--- /dev/null
+++ b/lib/libc/i386/gen/_get_tp.c
@@ -0,0 +1,45 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2021 The FreeBSD Foundation
+ *
+ * This software were developed by Konstantin Belousov
+ * 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.
+ *
+ *	$FreeBSD$
+ */
+
+#include <string.h>
+#include <stdint.h>
+#include <machine/sysarch.h>
+#include "libc_private.h"
+
+void *
+_get_tp(void)
+{
+	void **res;
+
+	__asm __volatile("movl %%gs:0, %0" : "=r" (res));
+	return (&res[1]);
+}
diff --git a/lib/libc/include/libc_private.h b/lib/libc/include/libc_private.h
index 363e1057986b..5a524c0211d1 100644
--- a/lib/libc/include/libc_private.h
+++ b/lib/libc/include/libc_private.h
@@ -261,8 +261,9 @@ void _init_tls(void);
 int _once(pthread_once_t *, void (*)(void));
 
 /*
- * Set the TLS thread pointer
+ * Get/set the TLS thread pointer
  */
+void *_get_tp(void);
 void _set_tp(void *tp);
 
 /*
diff --git a/lib/libdl/Makefile b/lib/libdl/Makefile
index d91547352de4..831f0e68180c 100644
--- a/lib/libdl/Makefile
+++ b/lib/libdl/Makefile
@@ -6,6 +6,8 @@ SHLIB_MAJOR=1
 
 .PATH:	${SRCTOP}/lib/libc/gen
 CFLAGS+=-I${SRCTOP}/lib/libc/include
+CFLAGS+=-I${SRCTOP}/libexec/rtld-elf \
+    -I${SRCTOP}/libexec/rtld-elf/${MACHINE_CPUARCH}
 CFLAGS+=-DIN_LIBDL
 LDFLAGS+=-Wl,-F,libc.so.7
 VERSION_DEF=${SRCTOP}/lib/libc/Versions.def
diff --git a/libexec/rtld-elf/rtld-libc/Makefile.inc b/libexec/rtld-elf/rtld-libc/Makefile.inc
index d5f5993e3f16..7ffcb6e41ec7 100644
--- a/libexec/rtld-elf/rtld-libc/Makefile.inc
+++ b/libexec/rtld-elf/rtld-libc/Makefile.inc
@@ -67,6 +67,8 @@ _libc_other_objects+=syncicache abs
 _libc_other_objects+=syncicache
 .endif
 
+_libc_other_objects+=_get_tp
+
 # Extract all the .o files from libc_nossp_pic.a. This ensures that
 # we don't accidentally pull in the interposing table or similar by linking
 # directly against libc_nossp_pic.a
diff --git a/libexec/rtld-elf/rtld.c b/libexec/rtld-elf/rtld.c
index 19027518d3c2..2ed4c4c9cb44 100644
--- a/libexec/rtld-elf/rtld.c
+++ b/libexec/rtld-elf/rtld.c
@@ -166,6 +166,7 @@ static int symlook_list(SymLook *, const Objlist *, DoneList *);
 static int symlook_needed(SymLook *, const Needed_Entry *, DoneList *);
 static int symlook_obj1_sysv(SymLook *, const Obj_Entry *);
 static int symlook_obj1_gnu(SymLook *, const Obj_Entry *);
+static void *tls_get_addr_slow(Elf_Addr **, int, size_t, bool) __noinline;
 static void trace_loaded_objects(Obj_Entry *);
 static void unlink_object(Obj_Entry *);
 static void unload_object(Obj_Entry *, RtldLockState *lockstate);
@@ -3906,19 +3907,21 @@ dlinfo(void *handle, int request, void *p)
     return (error);
 }
 
+void *_get_tp(void);
+
 static void
 rtld_fill_dl_phdr_info(const Obj_Entry *obj, struct dl_phdr_info *phdr_info)
 {
-	tls_index ti;
+	Elf_Addr **dtvp;
 
 	phdr_info->dlpi_addr = (Elf_Addr)obj->relocbase;
 	phdr_info->dlpi_name = obj->path;
 	phdr_info->dlpi_phdr = obj->phdr;
 	phdr_info->dlpi_phnum = obj->phsize / sizeof(obj->phdr[0]);
 	phdr_info->dlpi_tls_modid = obj->tlsindex;
-	ti.ti_module = obj->tlsindex;
-	ti.ti_offset = 0;
-	phdr_info->dlpi_tls_data = __tls_get_addr(&ti);
+	dtvp = _get_tp();
+	phdr_info->dlpi_tls_data = tls_get_addr_slow(dtvp, obj->tlsindex,
+	    0, true);
 	phdr_info->dlpi_adds = obj_loads;
 	phdr_info->dlpi_subs = obj_loads - obj_count;
 }
@@ -4871,39 +4874,42 @@ unref_dag(Obj_Entry *root)
 /*
  * Common code for MD __tls_get_addr().
  */
-static void *tls_get_addr_slow(Elf_Addr **, int, size_t) __noinline;
 static void *
-tls_get_addr_slow(Elf_Addr **dtvp, int index, size_t offset)
+tls_get_addr_slow(Elf_Addr **dtvp, int index, size_t offset, bool locked)
 {
-    Elf_Addr *newdtv, *dtv;
-    RtldLockState lockstate;
-    int to_copy;
+	Elf_Addr *newdtv, *dtv;
+	RtldLockState lockstate;
+	int to_copy;
 
-    dtv = *dtvp;
-    /* Check dtv generation in case new modules have arrived */
-    if (dtv[0] != tls_dtv_generation) {
-	wlock_acquire(rtld_bind_lock, &lockstate);
-	newdtv = xcalloc(tls_max_index + 2, sizeof(Elf_Addr));
-	to_copy = dtv[1];
-	if (to_copy > tls_max_index)
-	    to_copy = tls_max_index;
-	memcpy(&newdtv[2], &dtv[2], to_copy * sizeof(Elf_Addr));
-	newdtv[0] = tls_dtv_generation;
-	newdtv[1] = tls_max_index;
-	free(dtv);
-	lock_release(rtld_bind_lock, &lockstate);
-	dtv = *dtvp = newdtv;
-    }
+	dtv = *dtvp;
+	/* Check dtv generation in case new modules have arrived */
+	if (dtv[0] != tls_dtv_generation) {
+		if (!locked)
+			wlock_acquire(rtld_bind_lock, &lockstate);
+		newdtv = xcalloc(tls_max_index + 2, sizeof(Elf_Addr));
+		to_copy = dtv[1];
+		if (to_copy > tls_max_index)
+			to_copy = tls_max_index;
+		memcpy(&newdtv[2], &dtv[2], to_copy * sizeof(Elf_Addr));
+		newdtv[0] = tls_dtv_generation;
+		newdtv[1] = tls_max_index;
+		free(dtv);
+		if (!locked)
+			lock_release(rtld_bind_lock, &lockstate);
+		dtv = *dtvp = newdtv;
+	}
 
-    /* Dynamically allocate module TLS if necessary */
-    if (dtv[index + 1] == 0) {
-	/* Signal safe, wlock will block out signals. */
-	wlock_acquire(rtld_bind_lock, &lockstate);
-	if (!dtv[index + 1])
-	    dtv[index + 1] = (Elf_Addr)allocate_module_tls(index);
-	lock_release(rtld_bind_lock, &lockstate);
-    }
-    return ((void *)(dtv[index + 1] + offset));
+	/* Dynamically allocate module TLS if necessary */
+	if (dtv[index + 1] == 0) {
+		/* Signal safe, wlock will block out signals. */
+		if (!locked)
+			wlock_acquire(rtld_bind_lock, &lockstate);
+		if (!dtv[index + 1])
+			dtv[index + 1] = (Elf_Addr)allocate_module_tls(index);
+		if (!locked)
+			lock_release(rtld_bind_lock, &lockstate);
+	}
+	return ((void *)(dtv[index + 1] + offset));
 }
 
 void *
@@ -4916,7 +4922,7 @@ tls_get_addr_common(Elf_Addr **dtvp, int index, size_t offset)
 	if (__predict_true(dtv[0] == tls_dtv_generation &&
 	    dtv[index + 1] != 0))
 		return ((void *)(dtv[index + 1] + offset));
-	return (tls_get_addr_slow(dtvp, index, offset));
+	return (tls_get_addr_slow(dtvp, index, offset, false));
 }
 
 #if defined(__aarch64__) || defined(__arm__) || defined(__mips__) || \
diff --git a/libexec/rtld-elf/rtld_lock.h b/libexec/rtld-elf/rtld_lock.h
index 339028c568dc..9aa769b1f7e6 100644
--- a/libexec/rtld-elf/rtld_lock.h
+++ b/libexec/rtld-elf/rtld_lock.h
@@ -46,9 +46,13 @@ struct RtldLockInfo
 	void  (*at_fork)(void);
 };
 
-extern void _rtld_thread_init(struct RtldLockInfo *) __exported;
-extern void _rtld_atfork_pre(int *) __exported;
-extern void _rtld_atfork_post(int *) __exported;
+#if defined(IN_RTLD) || defined(PTHREAD_KERNEL)
+
+void _rtld_thread_init(struct RtldLockInfo *) __exported;
+void _rtld_atfork_pre(int *) __exported;
+void _rtld_atfork_post(int *) __exported;
+
+#endif /* IN_RTLD || PTHREAD_KERNEL */
 
 #ifdef IN_RTLD
 



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?YGzSaTULw00GTtR3>