git: d36d68161517 - main - rtld dl_iterate_phdr(): dlpi_tls_data is wrong
Konstantin Belousov
kostikbel at gmail.com
Tue Apr 6 21:28:27 UTC 2021
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 at FreeBSD.org>
> > > AuthorDate: 2021-04-05 03:05:44 +0000
> > > Commit: Konstantin Belousov <kib at 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 at 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
More information about the dev-commits-src-all
mailing list