From owner-dev-commits-src-all@freebsd.org Tue Apr 6 21:28:26 2021 Return-Path: Delivered-To: dev-commits-src-all@mailman.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mailman.nyi.freebsd.org (Postfix) with ESMTP id 8E48D5BEC7A; Tue, 6 Apr 2021 21:28:26 +0000 (UTC) (envelope-from kostikbel@gmail.com) Received: from kib.kiev.ua (kib.kiev.ua [IPv6:2001:470:d5e7:1::1]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 4FFLH936nKz4xvs; Tue, 6 Apr 2021 21:28:21 +0000 (UTC) (envelope-from kostikbel@gmail.com) Received: from tom.home (kib@localhost [127.0.0.1]) by kib.kiev.ua (8.16.1/8.16.1) with ESMTPS id 136LS9mw080659 (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384 bits=256 verify=NO); Wed, 7 Apr 2021 00:28:12 +0300 (EEST) (envelope-from kostikbel@gmail.com) DKIM-Filter: OpenDKIM Filter v2.10.3 kib.kiev.ua 136LS9mw080659 Received: (from kostik@localhost) by tom.home (8.16.1/8.16.1/Submit) id 136LS9Cb080658; Wed, 7 Apr 2021 00:28:09 +0300 (EEST) (envelope-from kostikbel@gmail.com) X-Authentication-Warning: tom.home: kostik set sender to kostikbel@gmail.com using -f Date: Wed, 7 Apr 2021 00:28:09 +0300 From: Konstantin Belousov To: Jung-uk Kim 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: References: <202104060037.1360bKwT029051@gitrepo.freebsd.org> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: X-Spam-Status: No, score=0.0 required=5.0 tests=ALL_TRUSTED,BAYES_00, DKIM_ADSP_CUSTOM_MED,FORGED_GMAIL_RCVD,FREEMAIL_FROM,FREEMAIL_REPLY, NML_ADSP_CUSTOM_MED autolearn=no autolearn_force=no version=3.4.4 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on tom.home X-Rspamd-Queue-Id: 4FFLH936nKz4xvs X-Spamd-Bar: / Authentication-Results: mx1.freebsd.org; dkim=none; dmarc=fail reason="No valid SPF, No valid DKIM" header.from=gmail.com (policy=none); spf=softfail (mx1.freebsd.org: 2001:470:d5e7:1::1 is neither permitted nor denied by domain of kostikbel@gmail.com) smtp.mailfrom=kostikbel@gmail.com X-Spamd-Result: default: False [0.99 / 15.00]; ARC_NA(0.00)[]; RBL_DBL_DONT_QUERY_IPS(0.00)[2001:470:d5e7:1::1:from]; DMARC_POLICY_SOFTFAIL(0.10)[gmail.com : No valid SPF, No valid DKIM,none]; RCVD_TLS_ALL(0.00)[]; FROM_HAS_DN(0.00)[]; RCPT_COUNT_THREE(0.00)[4]; FREEMAIL_FROM(0.00)[gmail.com]; TO_MATCH_ENVRCPT_ALL(0.00)[]; MIME_GOOD(-0.10)[text/plain]; HAS_XAW(0.00)[]; NEURAL_HAM_LONG(-1.00)[-1.000]; R_SPF_SOFTFAIL(0.00)[~all:c]; NEURAL_SPAM_MEDIUM(1.00)[1.000]; SPAMHAUS_ZRD(0.00)[2001:470:d5e7:1::1:from:127.0.2.255]; TO_DN_SOME(0.00)[]; NEURAL_SPAM_SHORT(0.99)[0.986]; FROM_EQ_ENVFROM(0.00)[]; R_DKIM_NA(0.00)[]; FREEMAIL_ENVFROM(0.00)[gmail.com]; ASN(0.00)[asn:6939, ipnet:2001:470::/32, country:US]; MIME_TRACE(0.00)[0:+]; MAILMAN_DEST(0.00)[dev-commits-src-all,dev-commits-src-main]; RCVD_COUNT_TWO(0.00)[2] X-BeenThere: dev-commits-src-all@freebsd.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: Commit messages for all branches of the src repository List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 06 Apr 2021 21:28:27 -0000 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 > > > AuthorDate: 2021-04-05 03:05:44 +0000 > > > Commit: Konstantin Belousov > > > 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 +#include +#include +#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 #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 #include +#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 +#include +#include +#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