From patchwork Fri Mar 29 05:55:49 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tatsuyuki Ishi X-Patchwork-Id: 1917635 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256 header.s=20230601 header.b=K9MSqug8; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=sourceware.org (client-ip=8.43.85.97; helo=server2.sourceware.org; envelope-from=libc-alpha-bounces+incoming=patchwork.ozlabs.org@sourceware.org; receiver=patchwork.ozlabs.org) Received: from server2.sourceware.org (server2.sourceware.org [8.43.85.97]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4V5V6r1N9Pz1yXw for ; Fri, 29 Mar 2024 16:57:24 +1100 (AEDT) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 5BDC03858433 for ; Fri, 29 Mar 2024 05:57:22 +0000 (GMT) X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from mail-pf1-x433.google.com (mail-pf1-x433.google.com [IPv6:2607:f8b0:4864:20::433]) by sourceware.org (Postfix) with ESMTPS id 3BD6B385843A for ; Fri, 29 Mar 2024 05:56:13 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 3BD6B385843A Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=gmail.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 3BD6B385843A Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=2607:f8b0:4864:20::433 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1711691777; cv=none; b=pFdirxM9ppZ3mWJBtdZf3rNQ8FJGFw6CUIv/eee6yFUY4D0bJ9vZ18MrGjkSTPRbN221INnjC5ADm24r/rdTPH5NQCx78q9FuC/EVkxeZzj88KF+jOKKO5AHJNlnYLmeSi7bM5HEr82HIuqgszlHmg/CZenTj01Eg/He0sihwn0= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1711691777; c=relaxed/simple; bh=Gm02yLW9tDaTy4YzWeClyU/AlaNIkMAiEexM10MUJ64=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=E22lAJeoemnj3NC0QAoO6kx9/jSnnDVG4ghYG84YqxBh7eZkKcrLrM70Q8eFqFwNKeJXvjFY14zrSYfjYmwHkmW3YQ6zRyyaJfY7DXC5Sw3BxADE3Q1uobg7RaX9f0iy5bImcoSyhZ0tsX1mticRgjSCGnVGLwVAlYkS2Lu+fbU= ARC-Authentication-Results: i=1; server2.sourceware.org Received: by mail-pf1-x433.google.com with SMTP id d2e1a72fcca58-6ea895eaaadso350256b3a.1 for ; Thu, 28 Mar 2024 22:56:13 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1711691772; x=1712296572; darn=sourceware.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=/drRencOPdS1qtRYV/oMRRdDgrOClak7KgHS+qVOqWM=; b=K9MSqug8AyE6+NGh7aB3MonD/GmN+Gm/yxIYEc2Uuuhn3vWMWjStAIz/OeTH1BVj7G NQGjYRzKgEL91hOt9I9fooIKqKHKQfjcnaO9kYQmv/GH4Qyv8ETbxpYfmBl2HVzElNWO A/OnQUXy/eV1J9Cn29nhy3ZCptGQM9wlGE5Z5TKX+phQ4FOAZSYx4iSouOJe1AG9y/pv O7R7UCST8U5xFNvd9P6GuQRsa+hBFwclZmpab6zmHu5dKVt9GBJnYCSjLgU8xpzhx8VQ NESBz1rvCDf/7bew2133r+w7yZd7cdkx/yeP/KLH7u/T71EiGjDa6pwI/bA5J7AIND5L gAGQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1711691772; x=1712296572; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=/drRencOPdS1qtRYV/oMRRdDgrOClak7KgHS+qVOqWM=; b=kKjfDCVaHizBp2NadOKqLYExkOJGTobVsoZnBMasfsafhlz4+F+5SSzdCyOlS+2pTK EC8WBYkWEWpvMfQHsy3/kZHdASbTqrvtYd2QD+4F6ilgwzkxsLg9t3OF+AUdp3tMesip 6At8cmGgj65ZIQwRPa8fDbrAoGJnQx93yZX3CJUeywbKBDNPgW6xKTAg+Ak1nX00ZrcL 7W2h9w+66yeqXIi6aBh/RpQXFENYpIAfTfbKRUA0KCyaSq3NUG9FJKfiiTB/cktsSMh2 okJyWW6sVRXuRmdbcka2K8tfmvRBRwva9yeS/99BgOQHmmhtCAGRBd6s643ThetaQ7vU b0MQ== X-Gm-Message-State: AOJu0Ywam5jdDfgjuJOKlM2rEDrBozWjfZLpNSpGdaJIQRrgJhlX9jg9 Z7h/gfdTydyPdDGmpMGWWGup1z+p2KHhOiIzi177t7dXoh/NxCrP X-Google-Smtp-Source: AGHT+IEibchy1OxNT8i8vsZz3zp5otqfiGHeOj5LS4jMH/1K1mpKfGHLqipuXteEIqxWgvzyFRzFPA== X-Received: by 2002:a05:6a20:549a:b0:1a5:69bb:116d with SMTP id i26-20020a056a20549a00b001a569bb116dmr1254051pzk.3.1711691771995; Thu, 28 Mar 2024 22:56:11 -0700 (PDT) Received: from localhost (zz20184013906F627101.userreverse.dion.ne.jp. [111.98.113.1]) by smtp.gmail.com with ESMTPSA id l1-20020a170902d04100b001e02cd75dd2sm2635954pll.237.2024.03.28.22.56.11 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 28 Mar 2024 22:56:11 -0700 (PDT) From: Tatsuyuki Ishi To: ishitatsuyuki@gmail.com Cc: libc-alpha@sourceware.org, rui314@gmail.com, ruiu@bluewhale.systems, schwab@linux-m68k.org, adhemerval.zanella@linaro.org, andrew@sifive.com, fweimer@redhat.com Subject: [PATCH v5 3/3] RISC-V: Implement TLS Descriptors. Date: Fri, 29 Mar 2024 14:55:49 +0900 Message-ID: <20240329055549.31940-4-ishitatsuyuki@gmail.com> X-Mailer: git-send-email 2.44.0 In-Reply-To: <20240329055549.31940-1-ishitatsuyuki@gmail.com> References: <20230817181228.122674-2-ishitatsuyuki@gmail.com> <20240329055549.31940-1-ishitatsuyuki@gmail.com> MIME-Version: 1.0 X-Spam-Status: No, score=-11.3 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, FREEMAIL_FROM, GIT_PATCH_0, KAM_SHORT, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: libc-alpha@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Libc-alpha mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libc-alpha-bounces+incoming=patchwork.ozlabs.org@sourceware.org This is mostly based off AArch64 implementation, with some adaptations to different TLS DTV offsets and calling conventions. As we have not officially committed to a vector calling convention, all vector registers are saved in the calling convention wrapper. This can be revisited once we decide which registers will be callee-saved. --- sysdeps/riscv/Makefile | 10 + sysdeps/riscv/dl-lookupcfg.h | 27 ++ sysdeps/riscv/dl-machine.h | 50 +++- sysdeps/riscv/dl-tlsdesc.S | 269 ++++++++++++++++++++ sysdeps/riscv/dl-tlsdesc.h | 48 ++++ sysdeps/riscv/linkmap.h | 1 + sysdeps/riscv/preconfigure | 1 + sysdeps/riscv/tlsdesc.c | 38 +++ sysdeps/riscv/tlsdesc.sym | 19 ++ sysdeps/riscv/tst-gnu2-tls2.c | 33 +++ sysdeps/unix/sysv/linux/riscv/localplt.data | 2 + 11 files changed, 497 insertions(+), 1 deletion(-) create mode 100644 sysdeps/riscv/dl-lookupcfg.h create mode 100644 sysdeps/riscv/dl-tlsdesc.S create mode 100644 sysdeps/riscv/dl-tlsdesc.h create mode 100644 sysdeps/riscv/tlsdesc.c create mode 100644 sysdeps/riscv/tlsdesc.sym create mode 100644 sysdeps/riscv/tst-gnu2-tls2.c diff --git a/sysdeps/riscv/Makefile b/sysdeps/riscv/Makefile index c08753ae8a..fc16081cde 100644 --- a/sysdeps/riscv/Makefile +++ b/sysdeps/riscv/Makefile @@ -4,6 +4,16 @@ endif ifeq ($(subdir),elf) gen-as-const-headers += dl-link.sym +sysdep-dl-routines += \ + dl-tlsdesc \ + tlsdesc \ + # routines +endif + +ifeq ($(subdir),csu) +gen-as-const-headers += \ + tlsdesc.sym \ + # gen-as-const-headers endif # RISC-V's assembler also needs to know about PIC as it changes the definition diff --git a/sysdeps/riscv/dl-lookupcfg.h b/sysdeps/riscv/dl-lookupcfg.h new file mode 100644 index 0000000000..d75a48f50c --- /dev/null +++ b/sysdeps/riscv/dl-lookupcfg.h @@ -0,0 +1,27 @@ +/* Configuration of lookup functions. + Copyright (C) 2023 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library. If not, see + . */ + +#define DL_UNMAP_IS_SPECIAL + +#include_next + +struct link_map; + +extern void _dl_unmap (struct link_map *map); + +#define DL_UNMAP(map) _dl_unmap (map) diff --git a/sysdeps/riscv/dl-machine.h b/sysdeps/riscv/dl-machine.h index b2f28697f7..3d5e63040d 100644 --- a/sysdeps/riscv/dl-machine.h +++ b/sysdeps/riscv/dl-machine.h @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -50,7 +51,8 @@ || (__WORDSIZE == 32 && (type) == R_RISCV_TLS_TPREL32) \ || (__WORDSIZE == 64 && (type) == R_RISCV_TLS_DTPREL64) \ || (__WORDSIZE == 64 && (type) == R_RISCV_TLS_DTPMOD64) \ - || (__WORDSIZE == 64 && (type) == R_RISCV_TLS_TPREL64))) \ + || (__WORDSIZE == 64 && (type) == R_RISCV_TLS_TPREL64) \ + || ((type) == R_RISCV_TLSDESC))) \ | (ELF_RTYPE_CLASS_COPY * ((type) == R_RISCV_COPY))) /* Return nonzero iff ELF header is compatible with the running host. */ @@ -219,6 +221,34 @@ elf_machine_rela (struct link_map *map, struct r_scope_elem *scope[], } break; + case R_RISCV_TLSDESC: + struct tlsdesc *td = (struct tlsdesc *) addr_field; + if (sym == NULL) + { + td->entry = _dl_tlsdesc_undefweak; + td->arg = (void *) reloc->r_addend; + } + else + { +# ifndef SHARED + CHECK_STATIC_TLS (map, sym_map); +# else + if (!TRY_STATIC_TLS (map, sym_map)) + { + td->entry = _dl_tlsdesc_dynamic; + td->arg = _dl_make_tlsdesc_dynamic ( + sym_map, sym->st_value + reloc->r_addend); + } + else +# endif + { + td->entry = _dl_tlsdesc_return; + td->arg + = (void *) (TLS_TPREL_VALUE (sym_map, sym) + reloc->r_addend); + } + } + break; + case R_RISCV_COPY: { if (__glibc_unlikely (sym == NULL)) @@ -289,6 +319,24 @@ elf_machine_lazy_rel (struct link_map *map, struct r_scope_elem *scope[], else *reloc_addr = map->l_mach.plt; } + else if (__glibc_likely (r_type == R_RISCV_TLSDESC)) + { + const Elf_Symndx symndx = ELFW (R_SYM) (reloc->r_info); + const ElfW (Sym) *symtab = (const void *)D_PTR (map, l_info[DT_SYMTAB]); + const ElfW (Sym) *sym = &symtab[symndx]; + const struct r_found_version *version = NULL; + + if (map->l_info[VERSYMIDX (DT_VERSYM)] != NULL) + { + const ElfW (Half) *vernum = + (const void *)D_PTR (map, l_info[VERSYMIDX (DT_VERSYM)]); + version = &map->l_versions[vernum[symndx] & 0x7fff]; + } + + /* Always initialize TLS descriptors completely, because lazy + initialization requires synchronization at every TLS access. */ + elf_machine_rela (map, scope, reloc, sym, version, reloc_addr, skip_ifunc); + } else if (__glibc_unlikely (r_type == R_RISCV_IRELATIVE)) { ElfW(Addr) value = map->l_addr + reloc->r_addend; diff --git a/sysdeps/riscv/dl-tlsdesc.S b/sysdeps/riscv/dl-tlsdesc.S new file mode 100644 index 0000000000..69acdb6428 --- /dev/null +++ b/sysdeps/riscv/dl-tlsdesc.S @@ -0,0 +1,269 @@ +/* Thread-local storage handling in the ELF dynamic linker. + RISC-V version. + Copyright (C) 2024 Free Software Foundation, Inc. + + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include +#include + +/* The fast path does not call function and does not need to align sp, but + to simplify handling when going into the slow path, keep sp aligned all + the time. + */ +#define FRAME_SIZE_FAST (-((-3 * SZREG) & ALMASK)) + +/* The slow path save slot layout, from lower address to higher address, is: + 1. 32 vector registers + 2. 12 GP registers + 3. 20 FP registers + 4. 3 vector CSR registers + + 1. has machine-dependent size, and hence is not included in FRAME_SIZE_SLOW. + Additionally, the vector register save area needs to be naturally aligned: + this is satisfied as a side effect of 16-byte stack alignment. + The size of vector save area, OTOH, also needs to satisfy stack alignment, as + implementations can have vector registers smaller than 16 bytes. + For now, the size is guaranteed to be a multiple of 16 as we save all 32 vector registers. + */ +#if defined(__riscv_float_abi_soft) +# define FRAME_SIZE_SLOW (-((-12 * SZREG) & ALMASK)) +#elif defined(__riscv_vector) +# define FRAME_SIZE_SLOW (-((-15 * SZREG - 20 * SZFREG) & ALMASK)) +#else +# define FRAME_SIZE_SLOW (-((-12 * SZREG - 20 * SZFREG) & ALMASK)) +#endif + + .text + + /* Compute the thread pointer offset for symbols in the static + TLS block. The offset is the same for all threads. + Prototype: + _dl_tlsdesc_return (tlsdesc *) ; + */ +ENTRY (_dl_tlsdesc_return) + REG_L a0, TLSDESC_ARG(a0) + jr t0 +END (_dl_tlsdesc_return) + + /* Handler for undefined weak TLS symbols. + Prototype: + _dl_tlsdesc_undefweak (tlsdesc *); + + The second word of the descriptor contains the addend. + Return the addend minus the thread pointer. This ensures + that when the caller adds on the thread pointer it gets back + the addend. */ + +ENTRY (_dl_tlsdesc_undefweak) + REG_L a0, TLSDESC_ARG(a0) + sub a0, a0, tp + jr t0 +END (_dl_tlsdesc_undefweak) + +#ifdef SHARED + /* Handler for dynamic TLS symbols. + Prototype: + _dl_tlsdesc_dynamic (tlsdesc *) ; + + The second word of the descriptor points to a + tlsdesc_dynamic_arg structure. + + Returns the offset between the thread pointer and the + object referenced by the argument. + + unsigned long + _dl_tlsdesc_dynamic (struct tlsdesc *tdp) + { + struct tlsdesc_dynamic_arg *td = tdp->arg; + dtv_t *dtv = *(dtv_t **)((char *)__thread_pointer + TCBHEAD_DTV); + if (__builtin_expect (td->gen_count <= dtv[0].counter + && (dtv[td->tlsinfo.ti_module].pointer.val + != TLS_DTV_UNALLOCATED), + 1)) + return dtv[td->tlsinfo.ti_module].pointer.val + + td->tlsinfo.ti_offset + - __thread_pointer; + + return ___tls_get_addr (&td->tlsinfo) - __thread_pointer; + } + */ + +ENTRY (_dl_tlsdesc_dynamic) + /* Save just enough registers to support fast path, if we fall + into slow path we will save additional registers. */ + add sp, sp, -FRAME_SIZE_FAST + REG_S t0, 0*SZREG(sp) + REG_S t1, 1*SZREG(sp) + REG_S t2, 2*SZREG(sp) + + /* t0 = dtv */ + REG_L t0, TCBHEAD_DTV(tp) + /* a0 = tdp->arg */ + REG_L a0, TLSDESC_ARG(a0) + /* t1 = td->gen_count */ + REG_L t1, TLSDESC_GEN_COUNT(a0) + /* t2 = dtv[0].counter */ + REG_L t2, DTV_COUNTER(t0) + bltu t2, t1, .Lslow + /* t1 = td->tlsinfo.ti_module */ + REG_L t1, TLSDESC_MODID(a0) + slli t1, t1, PTRLOG + 1 /* sizeof(dtv_t) == sizeof(void*) * 2 */ + add t1, t1, t0 + /* t1 = dtv[td->tlsinfo.ti_module].pointer.val */ + REG_L t1, 0(t1) + li t2, TLS_DTV_UNALLOCATED + beq t1, t2, .Lslow + /* t2 = td->tlsinfo.ti_offset */ + REG_L t2, TLSDESC_MODOFF(a0) + add a0, t1, t2 +.Lret: + sub a0, a0, tp + REG_L t0, 0*SZREG(sp) + REG_L t1, 1*SZREG(sp) + REG_L t2, 2*SZREG(sp) + add sp, sp, FRAME_SIZE_FAST + jr t0 +.Lslow: + /* This is the slow path. We need to call __tls_get_addr() which + means we need to save and restore all the register that the + callee will trash. */ + + /* Save the remaining registers that we must treat as caller save. */ + addi sp, sp, -FRAME_SIZE_SLOW + REG_S ra, 0*SZREG(sp) + REG_S a1, 1*SZREG(sp) + REG_S a2, 2*SZREG(sp) + REG_S a3, 3*SZREG(sp) + REG_S a4, 4*SZREG(sp) + REG_S a5, 5*SZREG(sp) + REG_S a6, 6*SZREG(sp) + REG_S a7, 7*SZREG(sp) + REG_S t3, 8*SZREG(sp) + REG_S t4, 9*SZREG(sp) + REG_S t5, 10*SZREG(sp) + REG_S t6, 11*SZREG(sp) + +#ifndef __riscv_float_abi_soft + FREG_S ft0, (12*SZREG + 0*SZFREG)(sp) + FREG_S ft1, (12*SZREG + 1*SZFREG)(sp) + FREG_S ft2, (12*SZREG + 2*SZFREG)(sp) + FREG_S ft3, (12*SZREG + 3*SZFREG)(sp) + FREG_S ft4, (12*SZREG + 4*SZFREG)(sp) + FREG_S ft5, (12*SZREG + 5*SZFREG)(sp) + FREG_S ft6, (12*SZREG + 6*SZFREG)(sp) + FREG_S ft7, (12*SZREG + 7*SZFREG)(sp) + FREG_S fa0, (12*SZREG + 8*SZFREG)(sp) + FREG_S fa1, (12*SZREG + 9*SZFREG)(sp) + FREG_S fa2, (12*SZREG + 10*SZFREG)(sp) + FREG_S fa3, (12*SZREG + 11*SZFREG)(sp) + FREG_S fa4, (12*SZREG + 12*SZFREG)(sp) + FREG_S fa5, (12*SZREG + 13*SZFREG)(sp) + FREG_S fa6, (12*SZREG + 14*SZFREG)(sp) + FREG_S fa7, (12*SZREG + 15*SZFREG)(sp) + FREG_S ft8, (12*SZREG + 16*SZFREG)(sp) + FREG_S ft9, (12*SZREG + 17*SZFREG)(sp) + FREG_S ft10, (12*SZREG + 18*SZFREG)(sp) + FREG_S ft11, (12*SZREG + 19*SZFREG)(sp) +#endif + +#ifdef __riscv_vector + csrr t0, vl + csrr t1, vtype + csrr t2, vstart + REG_S t0, (12*SZREG + 20*SZFREG)(sp) + REG_S t1, (13*SZREG + 20*SZFREG)(sp) + REG_S t2, (14*SZREG + 20*SZFREG)(sp) + + csrr t0, vlenb + slli t1, t0, 5 + slli t0, t0, 3 + sub sp, sp, t1 + vs8r.v v0, (sp) + add sp, sp, t0 + vs8r.v v8, (sp) + add sp, sp, t0 + vs8r.v v16, (sp) + add sp, sp, t0 + vs8r.v v24, (sp) + sub t0, t1, t0 + sub sp, sp, t0 +#endif + + call __tls_get_addr + addi a0, a0, -TLS_DTV_OFFSET + +#ifdef __riscv_vector + csrr t0, vlenb + slli t0, t0, 3 + vl8r.v v0, (sp) + add sp, sp, t0 + vl8r.v v8, (sp) + add sp, sp, t0 + vl8r.v v16, (sp) + add sp, sp, t0 + vl8r.v v24, (sp) + add sp, sp, t0 + + REG_L t0, (12*SZREG + 20*SZFREG)(sp) + REG_L t1, (13*SZREG + 20*SZFREG)(sp) + REG_L t2, (14*SZREG + 20*SZFREG)(sp) + vsetvl zero, t0, t1 + csrw vstart, t2 +#endif + + REG_L ra, 0*SZREG(sp) + REG_L a1, 1*SZREG(sp) + REG_L a2, 2*SZREG(sp) + REG_L a3, 3*SZREG(sp) + REG_L a4, 4*SZREG(sp) + REG_L a5, 5*SZREG(sp) + REG_L a6, 6*SZREG(sp) + REG_L a7, 7*SZREG(sp) + REG_L t3, 8*SZREG(sp) + REG_L t4, 9*SZREG(sp) + REG_L t5, 10*SZREG(sp) + REG_L t6, 11*SZREG(sp) + +#ifndef __riscv_float_abi_soft + FREG_L ft0, (12*SZREG + 0*SZFREG)(sp) + FREG_L ft1, (12*SZREG + 1*SZFREG)(sp) + FREG_L ft2, (12*SZREG + 2*SZFREG)(sp) + FREG_L ft3, (12*SZREG + 3*SZFREG)(sp) + FREG_L ft4, (12*SZREG + 4*SZFREG)(sp) + FREG_L ft5, (12*SZREG + 5*SZFREG)(sp) + FREG_L ft6, (12*SZREG + 6*SZFREG)(sp) + FREG_L ft7, (12*SZREG + 7*SZFREG)(sp) + FREG_L fa0, (12*SZREG + 8*SZFREG)(sp) + FREG_L fa1, (12*SZREG + 9*SZFREG)(sp) + FREG_L fa2, (12*SZREG + 10*SZFREG)(sp) + FREG_L fa3, (12*SZREG + 11*SZFREG)(sp) + FREG_L fa4, (12*SZREG + 12*SZFREG)(sp) + FREG_L fa5, (12*SZREG + 13*SZFREG)(sp) + FREG_L fa6, (12*SZREG + 14*SZFREG)(sp) + FREG_L fa7, (12*SZREG + 15*SZFREG)(sp) + FREG_L ft8, (12*SZREG + 16*SZFREG)(sp) + FREG_L ft9, (12*SZREG + 17*SZFREG)(sp) + FREG_L ft10, (12*SZREG + 18*SZFREG)(sp) + FREG_L ft11, (12*SZREG + 19*SZFREG)(sp) +#endif + + addi sp, sp, FRAME_SIZE_SLOW + j .Lret +END (_dl_tlsdesc_dynamic) +#endif diff --git a/sysdeps/riscv/dl-tlsdesc.h b/sysdeps/riscv/dl-tlsdesc.h new file mode 100644 index 0000000000..0c9b83f43d --- /dev/null +++ b/sysdeps/riscv/dl-tlsdesc.h @@ -0,0 +1,48 @@ +/* Thread-local storage descriptor handling in the ELF dynamic linker. + RISC-V version. + Copyright (C) 2023 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library. If not, see + . */ + +#ifndef _DL_TLSDESC_H +# define _DL_TLSDESC_H 1 + +#include + +/* Type used to represent a TLS descriptor in the GOT. */ +struct tlsdesc +{ + unsigned long (*entry) (struct tlsdesc *); + void *arg; +}; + +/* Type used as the argument in a TLS descriptor for a symbol that + needs dynamic TLS offsets. */ +struct tlsdesc_dynamic_arg +{ + tls_index tlsinfo; + size_t gen_count; +}; + +extern unsigned long _dl_tlsdesc_return (struct tlsdesc *) attribute_hidden; +extern unsigned long _dl_tlsdesc_undefweak (struct tlsdesc *) attribute_hidden; + +# ifdef SHARED +extern void *_dl_make_tlsdesc_dynamic (struct link_map *, size_t); +extern unsigned long _dl_tlsdesc_dynamic (struct tlsdesc *) attribute_hidden; +# endif + +#endif /* _DL_TLSDESC_H */ diff --git a/sysdeps/riscv/linkmap.h b/sysdeps/riscv/linkmap.h index ac170bb342..2fa3f6d43f 100644 --- a/sysdeps/riscv/linkmap.h +++ b/sysdeps/riscv/linkmap.h @@ -1,4 +1,5 @@ struct link_map_machine { ElfW(Addr) plt; /* Address of .plt. */ + void *tlsdesc_table; /* Address of TLS descriptor hash table. */ }; diff --git a/sysdeps/riscv/preconfigure b/sysdeps/riscv/preconfigure index a5de5ccb7d..493d7d98f5 100644 --- a/sysdeps/riscv/preconfigure +++ b/sysdeps/riscv/preconfigure @@ -57,6 +57,7 @@ riscv*) base_machine=riscv machine=riscv/rv$xlen/$float_machine + mtls_descriptor=desc printf "%s\n" "#define RISCV_ABI_XLEN $xlen" >>confdefs.h diff --git a/sysdeps/riscv/tlsdesc.c b/sysdeps/riscv/tlsdesc.c new file mode 100644 index 0000000000..d013bc7135 --- /dev/null +++ b/sysdeps/riscv/tlsdesc.c @@ -0,0 +1,38 @@ +/* Manage TLS descriptors. RISC-V version. + Copyright (C) 2023 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include +#include +#include +#include +#include + +/* Unmap the dynamic object, but also release its TLS descriptor table + if there is one. */ + +void +_dl_unmap (struct link_map *map) +{ + _dl_unmap_segments (map); + +#ifdef SHARED + if (map->l_mach.tlsdesc_table) + htab_delete (map->l_mach.tlsdesc_table); +#endif +} diff --git a/sysdeps/riscv/tlsdesc.sym b/sysdeps/riscv/tlsdesc.sym new file mode 100644 index 0000000000..652e72ea58 --- /dev/null +++ b/sysdeps/riscv/tlsdesc.sym @@ -0,0 +1,19 @@ +#include +#include +#include +#include +#include +#include + +-- + +-- Abuse tls.h macros to derive offsets relative to the thread register. + +TLSDESC_ARG offsetof(struct tlsdesc, arg) +TLSDESC_GEN_COUNT offsetof(struct tlsdesc_dynamic_arg, gen_count) +TLSDESC_MODID offsetof(struct tlsdesc_dynamic_arg, tlsinfo.ti_module) +TLSDESC_MODOFF offsetof(struct tlsdesc_dynamic_arg, tlsinfo.ti_offset) +TCBHEAD_DTV offsetof(tcbhead_t, dtv) - sizeof(tcbhead_t) - TLS_TCB_OFFSET +DTV_COUNTER offsetof(dtv_t, counter) +TLS_DTV_UNALLOCATED TLS_DTV_UNALLOCATED +TLS_DTV_OFFSET TLS_DTV_OFFSET diff --git a/sysdeps/riscv/tst-gnu2-tls2.c b/sysdeps/riscv/tst-gnu2-tls2.c new file mode 100644 index 0000000000..d0b0334eab --- /dev/null +++ b/sysdeps/riscv/tst-gnu2-tls2.c @@ -0,0 +1,33 @@ +/* Test TLSDESC relocation. RISC-V version. + Copyright (C) 2024 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#ifdef __riscv_vector + +/* Clear vector registers. Also clobbers vl and vtype. */ +#define PREPARE_MALLOC() \ +{ \ + asm volatile ("vsetvli zero, zero, e8, m8, ta, ma"); \ + asm volatile ("vmv.v.i v0, 0" : : : "v0" ); \ + asm volatile ("vmv.v.i v8, 0" : : : "v8" ); \ + asm volatile ("vmv.v.i v16, 0" : : : "v16" ); \ + asm volatile ("vmv.v.i v24, 0" : : : "v24" ); \ +} + +#endif /* __riscv_vector */ + +#include_next diff --git a/sysdeps/unix/sysv/linux/riscv/localplt.data b/sysdeps/unix/sysv/linux/riscv/localplt.data index ea887042e0..01710df22d 100644 --- a/sysdeps/unix/sysv/linux/riscv/localplt.data +++ b/sysdeps/unix/sysv/linux/riscv/localplt.data @@ -6,3 +6,5 @@ libc.so: free libc.so: malloc libc.so: memset ? libc.so: realloc +# The dynamic loader needs __tls_get_addr for TLS. +ld.so: __tls_get_addr