public inbox for libc-alpha@sourceware.org
 help / color / mirror / Atom feed
* [PATCH] RISC-V: Implement TLS Descriptors.
@ 2023-08-17 18:12 Tatsuyuki Ishi
  2023-08-17 18:35 ` Andreas Schwab
                   ` (6 more replies)
  0 siblings, 7 replies; 37+ messages in thread
From: Tatsuyuki Ishi @ 2023-08-17 18:12 UTC (permalink / raw)
  To: libc-alpha; +Cc: rui314, ruiu, Tatsuyuki Ishi

This is mostly based off AArch64 implementation, with some adaptations
to different TLS DTV offsets and calling conventions.
---
No regression in binutils and gcc tests for rv64gc, tested alongside the
gcc and binutils implementation (posted at the same time).

This contribution is made on behalf of Blue Whale Systems, which has
copyright assignment on file with the FSF.

 sysdeps/riscv/Makefile       |   8 ++
 sysdeps/riscv/dl-lookupcfg.h |  27 +++++
 sysdeps/riscv/dl-machine.h   |  27 +++++
 sysdeps/riscv/dl-tlsdesc.S   | 204 +++++++++++++++++++++++++++++++++++
 sysdeps/riscv/dl-tlsdesc.h   |  49 +++++++++
 sysdeps/riscv/linkmap.h      |   1 +
 sysdeps/riscv/tlsdesc.c      |  38 +++++++
 sysdeps/riscv/tlsdesc.sym    |  19 ++++
 8 files changed, 373 insertions(+)
 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

diff --git a/sysdeps/riscv/Makefile b/sysdeps/riscv/Makefile
index 8fb10b164f..bb4bcd29b2 100644
--- a/sysdeps/riscv/Makefile
+++ b/sysdeps/riscv/Makefile
@@ -2,6 +2,14 @@ ifeq ($(subdir),misc)
 sysdep_headers += sys/asm.h
 endif
 
+ifeq ($(subdir),elf)
+sysdep-dl-routines += tlsdesc dl-tlsdesc
+endif
+
+ifeq ($(subdir),csu)
+gen-as-const-headers += tlsdesc.sym
+endif
+
 # RISC-V's assembler also needs to know about PIC as it changes the definition
 # of some assembler macros.
 ASFLAGS-.os += $(pic-ccflag)
diff --git a/sysdeps/riscv/dl-lookupcfg.h b/sysdeps/riscv/dl-lookupcfg.h
new file mode 100644
index 0000000000..c003a27f63
--- /dev/null
+++ b/sysdeps/riscv/dl-lookupcfg.h
@@ -0,0 +1,27 @@
+/* Configuration of lookup functions.
+   Copyright (C) 2006-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
+   <https://www.gnu.org/licenses/>.  */
+
+#define DL_UNMAP_IS_SPECIAL
+
+#include_next <dl-lookupcfg.h>
+
+struct link_map;
+
+extern void _dl_unmap (struct link_map *map);
+
+#define DL_UNMAP(map) _dl_unmap (map)
\ No newline at end of file
diff --git a/sysdeps/riscv/dl-machine.h b/sysdeps/riscv/dl-machine.h
index c0c9bd93ad..ad5b3b20d0 100644
--- a/sysdeps/riscv/dl-machine.h
+++ b/sysdeps/riscv/dl-machine.h
@@ -25,6 +25,7 @@
 #include <elf/elf.h>
 #include <sys/asm.h>
 #include <dl-tls.h>
+#include <dl-tlsdesc.h>
 #include <dl-irel.h>
 #include <dl-static-tls.h>
 #include <dl-machine-rel.h>
@@ -219,6 +220,32 @@ 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 = 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))
diff --git a/sysdeps/riscv/dl-tlsdesc.S b/sysdeps/riscv/dl-tlsdesc.S
new file mode 100644
index 0000000000..bc48939739
--- /dev/null
+++ b/sysdeps/riscv/dl-tlsdesc.S
@@ -0,0 +1,204 @@
+/* Thread-local storage 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
+   <https://www.gnu.org/licenses/>.  */
+
+#include <sysdep.h>
+#include <tls.h>
+#include <tlsdesc.h>
+
+#ifdef __riscv_float_abi_soft
+# define FRAME_SIZE (-((-12 * SZREG) & ALMASK))
+#else
+# define FRAME_SIZE (-((-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, SZREG(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, SZREG(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, -3*SZREG
+	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, 3*SZREG
+	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
+	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
+
+	addi	a0, a0, SZREG
+	call	__tls_get_addr
+	addi	a0, a0, -TLS_DTV_OFFSET
+
+	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
+	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..3156f34e9c
--- /dev/null
+++ b/sysdeps/riscv/dl-tlsdesc.h
@@ -0,0 +1,49 @@
+/* Thread-local storage descriptor handling in the ELF dynamic linker.
+   RISC-V version.
+   Copyright (C) 2011-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
+   <https://www.gnu.org/licenses/>.  */
+
+#ifndef _DL_TLSDESC_H
+# define _DL_TLSDESC_H 1
+
+#include <dl-tls.h>
+
+/* Type used to represent a TLS descriptor in the GOT.  */
+struct tlsdesc
+{
+  ptrdiff_t (*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 attribute_hidden
+  _dl_tlsdesc_return(struct tlsdesc *),
+  _dl_tlsdesc_undefweak(struct tlsdesc *);
+
+# ifdef SHARED
+extern void *_dl_make_tlsdesc_dynamic (struct link_map *, size_t);
+extern unsigned long attribute_hidden _dl_tlsdesc_dynamic(struct tlsdesc *);
+# endif
+
+#endif /* _DL_TLSDESC_H */
\ No newline at end of file
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/tlsdesc.c b/sysdeps/riscv/tlsdesc.c
new file mode 100644
index 0000000000..a76aaa9fc5
--- /dev/null
+++ b/sysdeps/riscv/tlsdesc.c
@@ -0,0 +1,38 @@
+/* Manage TLS descriptors.  RISC-V version.
+   Copyright (C) 2005-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
+   <https://www.gnu.org/licenses/>.  */
+
+#include <ldsodefs.h>
+#include <tls.h>
+#include <dl-tls.h>
+#include <dl-tlsdesc.h>
+#include <dl-unmap-segments.h>
+#include <tlsdeschtab.h>
+
+/* 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 <stddef.h>
+#include <sysdep.h>
+#include <tls.h>
+#include <link.h>
+#include <dl-tls.h>
+#include <dl-tlsdesc.h>
+
+--
+
+-- 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
-- 
2.41.0


^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH] RISC-V: Implement TLS Descriptors.
  2023-08-17 18:12 [PATCH] RISC-V: Implement TLS Descriptors Tatsuyuki Ishi
@ 2023-08-17 18:35 ` Andreas Schwab
  2023-09-08 10:55 ` [PATCH v2] " Tatsuyuki Ishi
                   ` (5 subsequent siblings)
  6 siblings, 0 replies; 37+ messages in thread
From: Andreas Schwab @ 2023-08-17 18:35 UTC (permalink / raw)
  To: Tatsuyuki Ishi via Libc-alpha; +Cc: Tatsuyuki Ishi, rui314, ruiu

On Aug 18 2023, Tatsuyuki Ishi via Libc-alpha wrote:

> \ No newline at end of file

Please fix that.

-- 
Andreas Schwab, schwab@linux-m68k.org
GPG Key fingerprint = 7578 EB47 D4E5 4D69 2510  2552 DF73 E780 A9DA AEC1
"And now for something completely different."

^ permalink raw reply	[flat|nested] 37+ messages in thread

* [PATCH v2] RISC-V: Implement TLS Descriptors.
  2023-08-17 18:12 [PATCH] RISC-V: Implement TLS Descriptors Tatsuyuki Ishi
  2023-08-17 18:35 ` Andreas Schwab
@ 2023-09-08 10:55 ` Tatsuyuki Ishi
  2023-09-13 17:26 ` [PATCH v3] " Tatsuyuki Ishi
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 37+ messages in thread
From: Tatsuyuki Ishi @ 2023-09-08 10:55 UTC (permalink / raw)
  To: ishitatsuyuki; +Cc: libc-alpha, rui314, ruiu, schwab

This is mostly based off AArch64 implementation, with some adaptations to
different TLS DTV offsets and calling conventions.

No regression in binutils and gcc tests for rv64gc, tested alongside the
gcc and binutils implementation (posted at the same time).
---
v2: Fix end-of-file newlines.

This contribution is made on behalf of Blue Whale Systems, which has
copyright assignment on file with the FSF.

 sysdeps/riscv/Makefile       |   8 ++
 sysdeps/riscv/dl-lookupcfg.h |  27 +++++
 sysdeps/riscv/dl-machine.h   |  27 +++++
 sysdeps/riscv/dl-tlsdesc.S   | 204 +++++++++++++++++++++++++++++++++++
 sysdeps/riscv/dl-tlsdesc.h   |  49 +++++++++
 sysdeps/riscv/linkmap.h      |   1 +
 sysdeps/riscv/tlsdesc.c      |  38 +++++++
 sysdeps/riscv/tlsdesc.sym    |  19 ++++
 8 files changed, 373 insertions(+)
 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

diff --git a/sysdeps/riscv/Makefile b/sysdeps/riscv/Makefile
index 8fb10b164f..bb4bcd29b2 100644
--- a/sysdeps/riscv/Makefile
+++ b/sysdeps/riscv/Makefile
@@ -2,6 +2,14 @@ ifeq ($(subdir),misc)
 sysdep_headers += sys/asm.h
 endif
 
+ifeq ($(subdir),elf)
+sysdep-dl-routines += tlsdesc dl-tlsdesc
+endif
+
+ifeq ($(subdir),csu)
+gen-as-const-headers += tlsdesc.sym
+endif
+
 # RISC-V's assembler also needs to know about PIC as it changes the definition
 # of some assembler macros.
 ASFLAGS-.os += $(pic-ccflag)
diff --git a/sysdeps/riscv/dl-lookupcfg.h b/sysdeps/riscv/dl-lookupcfg.h
new file mode 100644
index 0000000000..d7fe73636b
--- /dev/null
+++ b/sysdeps/riscv/dl-lookupcfg.h
@@ -0,0 +1,27 @@
+/* Configuration of lookup functions.
+   Copyright (C) 2006-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
+   <https://www.gnu.org/licenses/>.  */
+
+#define DL_UNMAP_IS_SPECIAL
+
+#include_next <dl-lookupcfg.h>
+
+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 c0c9bd93ad..ad5b3b20d0 100644
--- a/sysdeps/riscv/dl-machine.h
+++ b/sysdeps/riscv/dl-machine.h
@@ -25,6 +25,7 @@
 #include <elf/elf.h>
 #include <sys/asm.h>
 #include <dl-tls.h>
+#include <dl-tlsdesc.h>
 #include <dl-irel.h>
 #include <dl-static-tls.h>
 #include <dl-machine-rel.h>
@@ -219,6 +220,32 @@ 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 = 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))
diff --git a/sysdeps/riscv/dl-tlsdesc.S b/sysdeps/riscv/dl-tlsdesc.S
new file mode 100644
index 0000000000..bc48939739
--- /dev/null
+++ b/sysdeps/riscv/dl-tlsdesc.S
@@ -0,0 +1,204 @@
+/* Thread-local storage 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
+   <https://www.gnu.org/licenses/>.  */
+
+#include <sysdep.h>
+#include <tls.h>
+#include <tlsdesc.h>
+
+#ifdef __riscv_float_abi_soft
+# define FRAME_SIZE (-((-12 * SZREG) & ALMASK))
+#else
+# define FRAME_SIZE (-((-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, SZREG(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, SZREG(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, -3*SZREG
+	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, 3*SZREG
+	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
+	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
+
+	addi	a0, a0, SZREG
+	call	__tls_get_addr
+	addi	a0, a0, -TLS_DTV_OFFSET
+
+	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
+	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..c7d1bb6d2e
--- /dev/null
+++ b/sysdeps/riscv/dl-tlsdesc.h
@@ -0,0 +1,49 @@
+/* Thread-local storage descriptor handling in the ELF dynamic linker.
+   RISC-V version.
+   Copyright (C) 2011-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
+   <https://www.gnu.org/licenses/>.  */
+
+#ifndef _DL_TLSDESC_H
+# define _DL_TLSDESC_H 1
+
+#include <dl-tls.h>
+
+/* Type used to represent a TLS descriptor in the GOT.  */
+struct tlsdesc
+{
+  ptrdiff_t (*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 attribute_hidden
+  _dl_tlsdesc_return(struct tlsdesc *),
+  _dl_tlsdesc_undefweak(struct tlsdesc *);
+
+# ifdef SHARED
+extern void *_dl_make_tlsdesc_dynamic (struct link_map *, size_t);
+extern unsigned long attribute_hidden _dl_tlsdesc_dynamic(struct tlsdesc *);
+# 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/tlsdesc.c b/sysdeps/riscv/tlsdesc.c
new file mode 100644
index 0000000000..a76aaa9fc5
--- /dev/null
+++ b/sysdeps/riscv/tlsdesc.c
@@ -0,0 +1,38 @@
+/* Manage TLS descriptors.  RISC-V version.
+   Copyright (C) 2005-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
+   <https://www.gnu.org/licenses/>.  */
+
+#include <ldsodefs.h>
+#include <tls.h>
+#include <dl-tls.h>
+#include <dl-tlsdesc.h>
+#include <dl-unmap-segments.h>
+#include <tlsdeschtab.h>
+
+/* 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 <stddef.h>
+#include <sysdep.h>
+#include <tls.h>
+#include <link.h>
+#include <dl-tls.h>
+#include <dl-tlsdesc.h>
+
+--
+
+-- 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
-- 
2.42.0


^ permalink raw reply	[flat|nested] 37+ messages in thread

* [PATCH v3] RISC-V: Implement TLS Descriptors.
  2023-08-17 18:12 [PATCH] RISC-V: Implement TLS Descriptors Tatsuyuki Ishi
  2023-08-17 18:35 ` Andreas Schwab
  2023-09-08 10:55 ` [PATCH v2] " Tatsuyuki Ishi
@ 2023-09-13 17:26 ` Tatsuyuki Ishi
  2023-09-13 19:14   ` Adhemerval Zanella Netto
  2023-09-13 19:07 ` [PATCH] " Andrew Waterman
                   ` (3 subsequent siblings)
  6 siblings, 1 reply; 37+ messages in thread
From: Tatsuyuki Ishi @ 2023-09-13 17:26 UTC (permalink / raw)
  To: ishitatsuyuki; +Cc: libc-alpha, rui314, ruiu, schwab

This is mostly based off AArch64 implementation, with some adaptations
to different TLS DTV offsets and calling conventions.

No regression in binutils and gcc tests for rv64gc, tested alongside the
gcc and binutils implementation (posted at the same time).
---
v2: Fix end-of-file newlines.
v3: Fix segfaulting on the slow path of TLSDESC resolver.
    Fix handling of lazy relocations.

This contribution is made on behalf of Blue Whale Systems, which has
copyright assignment on file with the FSF.

 sysdeps/riscv/Makefile       |   8 ++
 sysdeps/riscv/dl-lookupcfg.h |  27 +++++
 sysdeps/riscv/dl-machine.h   |  48 ++++++++-
 sysdeps/riscv/dl-tlsdesc.S   | 203 +++++++++++++++++++++++++++++++++++
 sysdeps/riscv/dl-tlsdesc.h   |  49 +++++++++
 sysdeps/riscv/linkmap.h      |   1 +
 sysdeps/riscv/tlsdesc.c      |  38 +++++++
 sysdeps/riscv/tlsdesc.sym    |  19 ++++
 8 files changed, 392 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

diff --git a/sysdeps/riscv/Makefile b/sysdeps/riscv/Makefile
index 8fb10b164f..bb4bcd29b2 100644
--- a/sysdeps/riscv/Makefile
+++ b/sysdeps/riscv/Makefile
@@ -2,6 +2,14 @@ ifeq ($(subdir),misc)
 sysdep_headers += sys/asm.h
 endif
 
+ifeq ($(subdir),elf)
+sysdep-dl-routines += tlsdesc dl-tlsdesc
+endif
+
+ifeq ($(subdir),csu)
+gen-as-const-headers += tlsdesc.sym
+endif
+
 # RISC-V's assembler also needs to know about PIC as it changes the definition
 # of some assembler macros.
 ASFLAGS-.os += $(pic-ccflag)
diff --git a/sysdeps/riscv/dl-lookupcfg.h b/sysdeps/riscv/dl-lookupcfg.h
new file mode 100644
index 0000000000..d7fe73636b
--- /dev/null
+++ b/sysdeps/riscv/dl-lookupcfg.h
@@ -0,0 +1,27 @@
+/* Configuration of lookup functions.
+   Copyright (C) 2006-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
+   <https://www.gnu.org/licenses/>.  */
+
+#define DL_UNMAP_IS_SPECIAL
+
+#include_next <dl-lookupcfg.h>
+
+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 c0c9bd93ad..eb0c874e72 100644
--- a/sysdeps/riscv/dl-machine.h
+++ b/sysdeps/riscv/dl-machine.h
@@ -25,6 +25,7 @@
 #include <elf/elf.h>
 #include <sys/asm.h>
 #include <dl-tls.h>
+#include <dl-tlsdesc.h>
 #include <dl-irel.h>
 #include <dl-static-tls.h>
 #include <dl-machine-rel.h>
@@ -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,32 @@ 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 = 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 +317,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..bf241ef76a
--- /dev/null
+++ b/sysdeps/riscv/dl-tlsdesc.S
@@ -0,0 +1,203 @@
+/* Thread-local storage 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
+   <https://www.gnu.org/licenses/>.  */
+
+#include <sysdep.h>
+#include <tls.h>
+#include <tlsdesc.h>
+
+#ifdef __riscv_float_abi_soft
+# define FRAME_SIZE (-((-12 * SZREG) & ALMASK))
+#else
+# define FRAME_SIZE (-((-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, -3*SZREG
+	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, 3*SZREG
+	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
+	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
+
+	call	__tls_get_addr
+	addi	a0, a0, -TLS_DTV_OFFSET
+
+	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
+	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..c7d1bb6d2e
--- /dev/null
+++ b/sysdeps/riscv/dl-tlsdesc.h
@@ -0,0 +1,49 @@
+/* Thread-local storage descriptor handling in the ELF dynamic linker.
+   RISC-V version.
+   Copyright (C) 2011-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
+   <https://www.gnu.org/licenses/>.  */
+
+#ifndef _DL_TLSDESC_H
+# define _DL_TLSDESC_H 1
+
+#include <dl-tls.h>
+
+/* Type used to represent a TLS descriptor in the GOT.  */
+struct tlsdesc
+{
+  ptrdiff_t (*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 attribute_hidden
+  _dl_tlsdesc_return(struct tlsdesc *),
+  _dl_tlsdesc_undefweak(struct tlsdesc *);
+
+# ifdef SHARED
+extern void *_dl_make_tlsdesc_dynamic (struct link_map *, size_t);
+extern unsigned long attribute_hidden _dl_tlsdesc_dynamic(struct tlsdesc *);
+# 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/tlsdesc.c b/sysdeps/riscv/tlsdesc.c
new file mode 100644
index 0000000000..a76aaa9fc5
--- /dev/null
+++ b/sysdeps/riscv/tlsdesc.c
@@ -0,0 +1,38 @@
+/* Manage TLS descriptors.  RISC-V version.
+   Copyright (C) 2005-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
+   <https://www.gnu.org/licenses/>.  */
+
+#include <ldsodefs.h>
+#include <tls.h>
+#include <dl-tls.h>
+#include <dl-tlsdesc.h>
+#include <dl-unmap-segments.h>
+#include <tlsdeschtab.h>
+
+/* 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 <stddef.h>
+#include <sysdep.h>
+#include <tls.h>
+#include <link.h>
+#include <dl-tls.h>
+#include <dl-tlsdesc.h>
+
+--
+
+-- 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
-- 
2.42.0


^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH] RISC-V: Implement TLS Descriptors.
  2023-08-17 18:12 [PATCH] RISC-V: Implement TLS Descriptors Tatsuyuki Ishi
                   ` (2 preceding siblings ...)
  2023-09-13 17:26 ` [PATCH v3] " Tatsuyuki Ishi
@ 2023-09-13 19:07 ` Andrew Waterman
  2023-09-14  8:40 ` [PATCH v4 0/3] " Tatsuyuki Ishi
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 37+ messages in thread
From: Andrew Waterman @ 2023-09-13 19:07 UTC (permalink / raw)
  To: Tatsuyuki Ishi; +Cc: libc-alpha, rui314, ruiu

The 3*SZREG stack-frame size won't maintain the ABI stack alignment; I
suggest masking it with ALMASK.


On Thu, Aug 17, 2023 at 11:13 AM Tatsuyuki Ishi via Libc-alpha
<libc-alpha@sourceware.org> wrote:
>
> This is mostly based off AArch64 implementation, with some adaptations
> to different TLS DTV offsets and calling conventions.
> ---
> No regression in binutils and gcc tests for rv64gc, tested alongside the
> gcc and binutils implementation (posted at the same time).
>
> This contribution is made on behalf of Blue Whale Systems, which has
> copyright assignment on file with the FSF.
>
>  sysdeps/riscv/Makefile       |   8 ++
>  sysdeps/riscv/dl-lookupcfg.h |  27 +++++
>  sysdeps/riscv/dl-machine.h   |  27 +++++
>  sysdeps/riscv/dl-tlsdesc.S   | 204 +++++++++++++++++++++++++++++++++++
>  sysdeps/riscv/dl-tlsdesc.h   |  49 +++++++++
>  sysdeps/riscv/linkmap.h      |   1 +
>  sysdeps/riscv/tlsdesc.c      |  38 +++++++
>  sysdeps/riscv/tlsdesc.sym    |  19 ++++
>  8 files changed, 373 insertions(+)
>  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
>
> diff --git a/sysdeps/riscv/Makefile b/sysdeps/riscv/Makefile
> index 8fb10b164f..bb4bcd29b2 100644
> --- a/sysdeps/riscv/Makefile
> +++ b/sysdeps/riscv/Makefile
> @@ -2,6 +2,14 @@ ifeq ($(subdir),misc)
>  sysdep_headers += sys/asm.h
>  endif
>
> +ifeq ($(subdir),elf)
> +sysdep-dl-routines += tlsdesc dl-tlsdesc
> +endif
> +
> +ifeq ($(subdir),csu)
> +gen-as-const-headers += tlsdesc.sym
> +endif
> +
>  # RISC-V's assembler also needs to know about PIC as it changes the definition
>  # of some assembler macros.
>  ASFLAGS-.os += $(pic-ccflag)
> diff --git a/sysdeps/riscv/dl-lookupcfg.h b/sysdeps/riscv/dl-lookupcfg.h
> new file mode 100644
> index 0000000000..c003a27f63
> --- /dev/null
> +++ b/sysdeps/riscv/dl-lookupcfg.h
> @@ -0,0 +1,27 @@
> +/* Configuration of lookup functions.
> +   Copyright (C) 2006-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
> +   <https://www.gnu.org/licenses/>.  */
> +
> +#define DL_UNMAP_IS_SPECIAL
> +
> +#include_next <dl-lookupcfg.h>
> +
> +struct link_map;
> +
> +extern void _dl_unmap (struct link_map *map);
> +
> +#define DL_UNMAP(map) _dl_unmap (map)
> \ No newline at end of file
> diff --git a/sysdeps/riscv/dl-machine.h b/sysdeps/riscv/dl-machine.h
> index c0c9bd93ad..ad5b3b20d0 100644
> --- a/sysdeps/riscv/dl-machine.h
> +++ b/sysdeps/riscv/dl-machine.h
> @@ -25,6 +25,7 @@
>  #include <elf/elf.h>
>  #include <sys/asm.h>
>  #include <dl-tls.h>
> +#include <dl-tlsdesc.h>
>  #include <dl-irel.h>
>  #include <dl-static-tls.h>
>  #include <dl-machine-rel.h>
> @@ -219,6 +220,32 @@ 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 = 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))
> diff --git a/sysdeps/riscv/dl-tlsdesc.S b/sysdeps/riscv/dl-tlsdesc.S
> new file mode 100644
> index 0000000000..bc48939739
> --- /dev/null
> +++ b/sysdeps/riscv/dl-tlsdesc.S
> @@ -0,0 +1,204 @@
> +/* Thread-local storage 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
> +   <https://www.gnu.org/licenses/>.  */
> +
> +#include <sysdep.h>
> +#include <tls.h>
> +#include <tlsdesc.h>
> +
> +#ifdef __riscv_float_abi_soft
> +# define FRAME_SIZE (-((-12 * SZREG) & ALMASK))
> +#else
> +# define FRAME_SIZE (-((-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, SZREG(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, SZREG(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, -3*SZREG
> +       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, 3*SZREG
> +       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
> +       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
> +
> +       addi    a0, a0, SZREG
> +       call    __tls_get_addr
> +       addi    a0, a0, -TLS_DTV_OFFSET
> +
> +       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
> +       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..3156f34e9c
> --- /dev/null
> +++ b/sysdeps/riscv/dl-tlsdesc.h
> @@ -0,0 +1,49 @@
> +/* Thread-local storage descriptor handling in the ELF dynamic linker.
> +   RISC-V version.
> +   Copyright (C) 2011-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
> +   <https://www.gnu.org/licenses/>.  */
> +
> +#ifndef _DL_TLSDESC_H
> +# define _DL_TLSDESC_H 1
> +
> +#include <dl-tls.h>
> +
> +/* Type used to represent a TLS descriptor in the GOT.  */
> +struct tlsdesc
> +{
> +  ptrdiff_t (*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 attribute_hidden
> +  _dl_tlsdesc_return(struct tlsdesc *),
> +  _dl_tlsdesc_undefweak(struct tlsdesc *);
> +
> +# ifdef SHARED
> +extern void *_dl_make_tlsdesc_dynamic (struct link_map *, size_t);
> +extern unsigned long attribute_hidden _dl_tlsdesc_dynamic(struct tlsdesc *);
> +# endif
> +
> +#endif /* _DL_TLSDESC_H */
> \ No newline at end of file
> 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/tlsdesc.c b/sysdeps/riscv/tlsdesc.c
> new file mode 100644
> index 0000000000..a76aaa9fc5
> --- /dev/null
> +++ b/sysdeps/riscv/tlsdesc.c
> @@ -0,0 +1,38 @@
> +/* Manage TLS descriptors.  RISC-V version.
> +   Copyright (C) 2005-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
> +   <https://www.gnu.org/licenses/>.  */
> +
> +#include <ldsodefs.h>
> +#include <tls.h>
> +#include <dl-tls.h>
> +#include <dl-tlsdesc.h>
> +#include <dl-unmap-segments.h>
> +#include <tlsdeschtab.h>
> +
> +/* 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 <stddef.h>
> +#include <sysdep.h>
> +#include <tls.h>
> +#include <link.h>
> +#include <dl-tls.h>
> +#include <dl-tlsdesc.h>
> +
> +--
> +
> +-- 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
> --
> 2.41.0
>

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH v3] RISC-V: Implement TLS Descriptors.
  2023-09-13 17:26 ` [PATCH v3] " Tatsuyuki Ishi
@ 2023-09-13 19:14   ` Adhemerval Zanella Netto
  2023-09-14  8:39     ` Tatsuyuki Ishi
  0 siblings, 1 reply; 37+ messages in thread
From: Adhemerval Zanella Netto @ 2023-09-13 19:14 UTC (permalink / raw)
  To: Tatsuyuki Ishi; +Cc: libc-alpha, rui314, ruiu, schwab



On 13/09/23 14:26, Tatsuyuki Ishi wrote:
> This is mostly based off AArch64 implementation, with some adaptations
> to different TLS DTV offsets and calling conventions.
> 
> No regression in binutils and gcc tests for rv64gc, tested alongside the
> gcc and binutils implementation (posted at the same time).

How did you actually build glibc? I saw multiple build issues with default
configuration and even with --disable-werror, so I am doubtful that this
patch was really proper tested. Please ensure that have-mtls-dialect-gnu2
is set to 'yes' on config.make so the tests are actually run.

The lack of include guards at dl-tls.h make the sysdeps/riscv/tlsdesc.sym 
generation fail with confling types:

In file included from ../sysdeps/riscv/dl-tlsdesc.h:23,
                 from <stdin>:6:
../sysdeps/riscv/dl-tls.h:25:3: error: conflicting types for ‘tls_index’; have ‘struct <anonymous>’
   25 | } tls_index;
      |   ^~~~~~~~~
In file included from <stdin>:5:
../sysdeps/riscv/dl-tls.h:25:3: note: previous declaration of ‘tls_index’ with type ‘tls_index’
   25 | } tls_index;
      |   ^~~~~~~~~
../sysdeps/riscv/dl-tls.h:42:14: error: conflicting types for ‘__tls_get_addr’; have ‘void *(tls_index *)’
   42 | extern void *__tls_get_addr (tls_index *ti);
      |              ^~~~~~~~~~~~~~
../sysdeps/riscv/dl-tls.h:42:14: note: previous declaration of ‘__tls_get_addr’ with type ‘void *(tls_index *)’
   42 | extern void *__tls_get_addr (tls_index *ti);
      |              ^~~~~~~~~~~~~~

Removing '#include <dl-tls.h>' fixes it, but it fails later trying
to build dl-load. It is better to add proper guards:

diff --git a/sysdeps/riscv/dl-tls.h b/sysdeps/riscv/dl-tls.h
index 67c8ae639c..6c569509bd 100644
--- a/sysdeps/riscv/dl-tls.h
+++ b/sysdeps/riscv/dl-tls.h
@@ -16,6 +16,8 @@
    License along with the GNU C Library.  If not, see
    <https://www.gnu.org/licenses/>.  */

+#ifndef _RISCV_DL_TLS_H
+#define _RISCV_DL_TLS_H

 /* Type used for the representation of TLS information in the GOT.  */
 typedef struct
@@ -46,3 +48,5 @@ extern void *__tls_get_addr (tls_index *ti);

 /* Value used for dtv entries for which the allocation is delayed.  */
 #define TLS_DTV_UNALLOCATED    ((void *) -1l)
+
+#endif /* _RISCV_DL_TLS_H */


There are other build failures as well.

> ---
> v2: Fix end-of-file newlines.
> v3: Fix segfaulting on the slow path of TLSDESC resolver.
>     Fix handling of lazy relocations.
> 
> This contribution is made on behalf of Blue Whale Systems, which has
> copyright assignment on file with the FSF.
> 
>  sysdeps/riscv/Makefile       |   8 ++
>  sysdeps/riscv/dl-lookupcfg.h |  27 +++++
>  sysdeps/riscv/dl-machine.h   |  48 ++++++++-
>  sysdeps/riscv/dl-tlsdesc.S   | 203 +++++++++++++++++++++++++++++++++++
>  sysdeps/riscv/dl-tlsdesc.h   |  49 +++++++++
>  sysdeps/riscv/linkmap.h      |   1 +
>  sysdeps/riscv/tlsdesc.c      |  38 +++++++
>  sysdeps/riscv/tlsdesc.sym    |  19 ++++
>  8 files changed, 392 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
> 
> diff --git a/sysdeps/riscv/Makefile b/sysdeps/riscv/Makefile
> index 8fb10b164f..bb4bcd29b2 100644
> --- a/sysdeps/riscv/Makefile
> +++ b/sysdeps/riscv/Makefile
> @@ -2,6 +2,14 @@ ifeq ($(subdir),misc)
>  sysdep_headers += sys/asm.h
>  endif
>  
> +ifeq ($(subdir),elf)
> +sysdep-dl-routines += tlsdesc dl-tlsdesc
> +endif
> +
> +ifeq ($(subdir),csu)
> +gen-as-const-headers += tlsdesc.sym
> +endif
> +


Minor style issue, for new code we are prefering a new line per entry,
alphabetically sorted: 

  ifeq ($(subdir),elf)
  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
>  # of some assembler macros.
>  ASFLAGS-.os += $(pic-ccflag)
> diff --git a/sysdeps/riscv/dl-lookupcfg.h b/sysdeps/riscv/dl-lookupcfg.h
> new file mode 100644
> index 0000000000..d7fe73636b
> --- /dev/null
> +++ b/sysdeps/riscv/dl-lookupcfg.h
> @@ -0,0 +1,27 @@
> +/* Configuration of lookup functions.
> +   Copyright (C) 2006-2023 Free Software Foundation, Inc.

I think it should be only 2023 for new code.

> +   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
> +   <https://www.gnu.org/licenses/>.  */
> +
> +#define DL_UNMAP_IS_SPECIAL
> +
> +#include_next <dl-lookupcfg.h>
> +
> +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 c0c9bd93ad..eb0c874e72 100644
> --- a/sysdeps/riscv/dl-machine.h
> +++ b/sysdeps/riscv/dl-machine.h
> @@ -25,6 +25,7 @@
>  #include <elf/elf.h>
>  #include <sys/asm.h>
>  #include <dl-tls.h>
> +#include <dl-tlsdesc.h>
>  #include <dl-irel.h>
>  #include <dl-static-tls.h>
>  #include <dl-machine-rel.h>
> @@ -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)))	\

This seems wrong, even with a R_RISCV_TLSDESC definition compiler fails
with:

dl-reloc.c: In function ‘resolve_map’:
../sysdeps/riscv/dl-machine.h:48:25: error: ‘*’ in boolean context, suggest ‘&&’ instead [-Werror=int-in-bool-context]
   48 |   ((ELF_RTYPE_CLASS_PLT * ((type) == ELF_MACHINE_JMP_SLOT       \
dl-reloc.c:175:10: note: in expansion of macro ‘elf_machine_type_class’
  175 |       && elf_machine_type_class (r_type) == l->l_lookup_cache.type_class)

I think you want to add the final ')' *after* R_RISCV_TLSDESC.  Something
like:

diff --git a/sysdeps/riscv/dl-machine.h b/sysdeps/riscv/dl-machine.h
index eb0c874e72..b10dfe4954 100644
--- a/sysdeps/riscv/dl-machine.h
+++ b/sysdeps/riscv/dl-machine.h
@@ -51,8 +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))   \
-     || ((type) == R_RISCV_TLSDESC))                           \
+     || (__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.  */

> +     || (__WORDSIZE == 64 && (type) == R_RISCV_TLS_TPREL64))	\
> +     || ((type) == R_RISCV_TLSDESC))				\

R_RISCV_TLSDESC is not define in this patch, you need to either sync with
binutils elf.h or add it on this patch.

>     | (ELF_RTYPE_CLASS_COPY * ((type) == R_RISCV_COPY)))
>  
>  /* Return nonzero iff ELF header is compatible with the running host.  */
> @@ -219,6 +221,32 @@ 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;


This triggers multiple compiler warnings:

../sysdeps/riscv/dl-machine.h: In function ‘elf_machine_rela’:
../sysdeps/riscv/dl-machine.h:228:21: error: assignment to ‘ptrdiff_t (*)(struct tlsdesc *)’ {aka ‘long int (*)(struct tlsdesc *)’} from incompatible pointer type ‘long unsigned int (*)(struct tlsdesc *)’ [-Werror=incompatible-pointer-types]
  228 |           td->entry = _dl_tlsdesc_undefweak;
      |                     ^
../sysdeps/riscv/dl-machine.h:244:25: error: assignment to ‘ptrdiff_t (*)(struct tlsdesc *)’ {aka ‘long int (*)(struct tlsdesc *)’} from incompatible pointer type ‘long unsigned int (*)(struct tlsdesc *)’ [-Werror=incompatible-pointer-types]
  244 |               td->entry = _dl_tlsdesc_return;
      |                         ^

Because you declare _dl_tlsdesc_undefweak as:

  unsigned long _dl_tlsdesc_dynamic (struct tlsdesc *);

But the 'entry' at tlsdesc as:

   ptrdiff_t (*entry) (struct tlsdesc *);

Based on TLSDESC ABI I think using a unsigned as return value is wrong here.

> +	  td->arg = reloc->r_addend;

This triggers another build issue:

../sysdeps/riscv/dl-machine.h: In function ‘elf_machine_rela’:
../sysdeps/riscv/dl-machine.h:229:19: error: assignment to ‘void *’ from ‘Elf64_Sxword’ {aka ‘long int’} makes pointer from integer without a cast [-Werror=int-conversion]
  229 |           td->arg = reloc->r_addend;

You need to explicit cast to 'void *' here.


> +	}
> +      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);


Space after TLS_TPREL_VALUE

> +	    }
> +	}
> +      break;
> +
>      case R_RISCV_COPY:
>        {
>  	if (__glibc_unlikely (sym == NULL))
> @@ -289,6 +317,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..bf241ef76a
> --- /dev/null
> +++ b/sysdeps/riscv/dl-tlsdesc.S
> @@ -0,0 +1,203 @@
> +/* Thread-local storage 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
> +   <https://www.gnu.org/licenses/>.  */
> +
> +#include <sysdep.h>
> +#include <tls.h>
> +#include <tlsdesc.h>
> +
> +#ifdef __riscv_float_abi_soft
> +# define FRAME_SIZE (-((-12 * SZREG) & ALMASK))
> +#else
> +# define FRAME_SIZE (-((-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, -3*SZREG
> +	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, 3*SZREG
> +	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
> +	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
> +
> +	call	__tls_get_addr
> +	addi	a0, a0, -TLS_DTV_OFFSET
> +
> +	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
> +	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..c7d1bb6d2e
> --- /dev/null
> +++ b/sysdeps/riscv/dl-tlsdesc.h
> @@ -0,0 +1,49 @@
> +/* Thread-local storage descriptor handling in the ELF dynamic linker.
> +   RISC-V version.
> +   Copyright (C) 2011-2023 Free Software Foundation, Inc.

I think it should be 2023 only here.

> +   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
> +   <https://www.gnu.org/licenses/>.  */
> +
> +#ifndef _DL_TLSDESC_H
> +# define _DL_TLSDESC_H 1
> +
> +#include <dl-tls.h>
> +
> +/* Type used to represent a TLS descriptor in the GOT.  */
> +struct tlsdesc
> +{
> +  ptrdiff_t (*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 attribute_hidden
> +  _dl_tlsdesc_return(struct tlsdesc *),
> +  _dl_tlsdesc_undefweak(struct tlsdesc *);
> +
> +# ifdef SHARED
> +extern void *_dl_make_tlsdesc_dynamic (struct link_map *, size_t);
> +extern unsigned long attribute_hidden _dl_tlsdesc_dynamic(struct tlsdesc *);
> +# endif

Multiple style issues here: do not use comma for function prototypes,
add the attributes after function declaration, and add proper scape
after names:

  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 attribute_hidden _dl_tlsdesc_dynamic (struct tlsdesc *);
  # endif

The return type for _dl_tlsdesc_return, _dl_tlsdesc_undefweak, and
_dl_tlsdesc_dynamic seems wrong.

> +
> +#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/tlsdesc.c b/sysdeps/riscv/tlsdesc.c
> new file mode 100644
> index 0000000000..a76aaa9fc5
> --- /dev/null
> +++ b/sysdeps/riscv/tlsdesc.c
> @@ -0,0 +1,38 @@
> +/* Manage TLS descriptors.  RISC-V version.
> +   Copyright (C) 2005-2023 Free Software Foundation, Inc.

I think it should be 2023 here.

> +   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
> +   <https://www.gnu.org/licenses/>.  */
> +
> +#include <ldsodefs.h>
> +#include <tls.h>
> +#include <dl-tls.h>
> +#include <dl-tlsdesc.h>
> +#include <dl-unmap-segments.h>
> +#include <tlsdeschtab.h>
> +
> +/* 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 <stddef.h>
> +#include <sysdep.h>
> +#include <tls.h>
> +#include <link.h>
> +#include <dl-tls.h>
> +#include <dl-tlsdesc.h>
> +
> +--
> +
> +-- 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

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH v3] RISC-V: Implement TLS Descriptors.
  2023-09-13 19:14   ` Adhemerval Zanella Netto
@ 2023-09-14  8:39     ` Tatsuyuki Ishi
  2023-09-14 12:09       ` Adhemerval Zanella Netto
  0 siblings, 1 reply; 37+ messages in thread
From: Tatsuyuki Ishi @ 2023-09-14  8:39 UTC (permalink / raw)
  To: Adhemerval Zanella Netto; +Cc: libc-alpha, Rui Ueyama, Rui Ueyama, schwab

[-- Attachment #1: Type: text/plain, Size: 3770 bytes --]


> On Sep 14, 2023, at 4:14, Adhemerval Zanella Netto <adhemerval.zanella@linaro.org> wrote:
> 
> How did you actually build glibc? I saw multiple build issues with default
> configuration and even with --disable-werror, so I am doubtful that this
> patch was really proper tested. Please ensure that have-mtls-dialect-gnu2
> is set to 'yes' on config.make so the tests are actually run.

I’m sorry I’ve made multiple mistakes here. There were actually two prerequisite commits but I’ve forgot to include them in the patch series. This will be included in v4.

I used [1] to build a full toolchain and it defaulted to --disable-werror. I’ve manually enabled -Werror and fixed all compiler warnings in v4.

As for have-mtls-dialect-gnu2, RISC-V will use AArch64-style flags (-mtls-dialect={trad,desc}), not gnu2. However, I have configured my GCC fork with --with-tls=desc and all compilation is done with TLSDESC by default for my testing.

I assumed most testing was done through GCC’s testsuite, and I’ve got GCC’s testsuite to the point of no regression, however I was wrong and there are more in glibc’s testsuite. For v4 I’ve ran all tests in glibc/elf/, and all but two tests for TLS on static executables are passing. More info on my plan for fixing that in v4.

> 
>> # RISC-V's assembler also needs to know about PIC as it changes the definition
>> # of some assembler macros.
>> ASFLAGS-.os += $(pic-ccflag)
>> diff --git a/sysdeps/riscv/dl-lookupcfg.h b/sysdeps/riscv/dl-lookupcfg.h
>> new file mode 100644
>> index 0000000000..d7fe73636b
>> --- /dev/null
>> +++ b/sysdeps/riscv/dl-lookupcfg.h
>> @@ -0,0 +1,27 @@
>> +/* Configuration of lookup functions.
>> +   Copyright (C) 2006-2023 Free Software Foundation, Inc.
> 
> I think it should be only 2023 for new code.

Ack, all copyright headers for new files will be 2023 only in v4.


>>    | (ELF_RTYPE_CLASS_COPY * ((type) == R_RISCV_COPY)))
>> 
>> /* Return nonzero iff ELF header is compatible with the running host.  */
>> @@ -219,6 +221,32 @@ 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;
> 
> 
> This triggers multiple compiler warnings:
> 
> ../sysdeps/riscv/dl-machine.h: In function ‘elf_machine_rela’:
> ../sysdeps/riscv/dl-machine.h:228:21: error: assignment to ‘ptrdiff_t (*)(struct tlsdesc *)’ {aka ‘long int (*)(struct tlsdesc *)’} from incompatible pointer type ‘long unsigned int (*)(struct tlsdesc *)’ [-Werror=incompatible-pointer-types]
>  228 |           td->entry = _dl_tlsdesc_undefweak;
>      |                     ^
> ../sysdeps/riscv/dl-machine.h:244:25: error: assignment to ‘ptrdiff_t (*)(struct tlsdesc *)’ {aka ‘long int (*)(struct tlsdesc *)’} from incompatible pointer type ‘long unsigned int (*)(struct tlsdesc *)’ [-Werror=incompatible-pointer-types]
>  244 |               td->entry = _dl_tlsdesc_return;
>      |                         ^
> 
> Because you declare _dl_tlsdesc_undefweak as:
> 
>  unsigned long _dl_tlsdesc_dynamic (struct tlsdesc *);
> 
> But the 'entry' at tlsdesc as:
> 
>   ptrdiff_t (*entry) (struct tlsdesc *);
> 
> Based on TLSDESC ABI I think using a unsigned as return value is wrong here.

I am opting to not using ptrdiff_t because the offset can be larger than PTRDIFF_MAX. Using unsigned arithmetic avoids the signed overflow concern.

The descriptor signature is also defined in the RISC-V psABI as returning unsigned long for the same reason.

[1]: https://github.com/riscv-collab/riscv-gnu-toolchain


^ permalink raw reply	[flat|nested] 37+ messages in thread

* [PATCH v4 0/3] RISC-V: Implement TLS Descriptors.
  2023-08-17 18:12 [PATCH] RISC-V: Implement TLS Descriptors Tatsuyuki Ishi
                   ` (3 preceding siblings ...)
  2023-09-13 19:07 ` [PATCH] " Andrew Waterman
@ 2023-09-14  8:40 ` Tatsuyuki Ishi
  2023-09-14  8:40   ` [PATCH v4 1/3] RISC-V: Add include guard for dl-tls.h Tatsuyuki Ishi
                     ` (2 more replies)
  2024-03-29  5:55 ` [PATCH v5 0/3] " Tatsuyuki Ishi
  2024-03-29  6:18 ` [PATCH v6 0/3] " Tatsuyuki Ishi
  6 siblings, 3 replies; 37+ messages in thread
From: Tatsuyuki Ishi @ 2023-09-14  8:40 UTC (permalink / raw)
  To: ishitatsuyuki
  Cc: libc-alpha, rui314, ruiu, schwab, adhemerval.zanella, andrew

This patchset implements TLS Descriptors (TLSDESC) for RISC-V targets, per
the ratified specification at [1].

The latest version of related binutils and gcc patches are at [2,3].

Passes binutils and gcc tests for rv64gc. For glibc I only tested elf/ as
other subsystems sometimes doesn't work well under qemu. These are the
regressions:

- elf/tst-tls1-static
- elf/tst-tls1-static-non-pie

The TLSDESC relocations always needs to be handled by the dynamic linker,
but the process is skipped for static executables. I will look into
changing binutils to always relax TLSDESC to LE such that we can avoid
this issue.

This contribution is made on behalf of Blue Whale Systems, which has
copyright assignment on file with the FSF.

v2: Fix end-of-file newlines.
v3: Fix segfaulting on the slow path of TLSDESC resolver.
    Fix handling of lazy relocations.
v4: Fix compiler warnings.
    Fix fast path stack alignment pointed out by Andrew.
    Fix style issues pointed out by Adhemerval.
    Include 2 missing prerequisite commits.
    Update localplt list.

[1]: https://github.com/riscv-non-isa/riscv-elf-psabi-doc/pull/373
[2]: https://inbox.sourceware.org/binutils/20230831171345.49052-1-ishitatsuyuki@gmail.com/
[3]: https://inbox.sourceware.org/gcc-patches/20230908104923.31154-1-ishitatsuyuki@gmail.com/

Tatsuyuki Ishi (3):
  RISC-V: Add include guard for dl-tls.h.
  RISC-V: Add TLSDESC reloc definitions.
  RISC-V: Implement TLS Descriptors.

 elf/elf.h                                   |   5 +
 sysdeps/riscv/Makefile                      |  13 ++
 sysdeps/riscv/dl-lookupcfg.h                |  27 +++
 sysdeps/riscv/dl-machine.h                  |  50 ++++-
 sysdeps/riscv/dl-tls.h                      |   4 +
 sysdeps/riscv/dl-tlsdesc.S                  | 205 ++++++++++++++++++++
 sysdeps/riscv/dl-tlsdesc.h                  |  48 +++++
 sysdeps/riscv/linkmap.h                     |   1 +
 sysdeps/riscv/tlsdesc.c                     |  38 ++++
 sysdeps/riscv/tlsdesc.sym                   |  19 ++
 sysdeps/unix/sysv/linux/riscv/localplt.data |   2 +
 11 files changed, 411 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

-- 
2.42.0


^ permalink raw reply	[flat|nested] 37+ messages in thread

* [PATCH v4 1/3] RISC-V: Add include guard for dl-tls.h.
  2023-09-14  8:40 ` [PATCH v4 0/3] " Tatsuyuki Ishi
@ 2023-09-14  8:40   ` Tatsuyuki Ishi
  2024-01-27  1:14     ` Fangrui Song
  2023-09-14  8:40   ` [PATCH v4 2/3] RISC-V: Add TLSDESC reloc definitions Tatsuyuki Ishi
  2023-09-14  8:40   ` [PATCH v4 3/3] RISC-V: Implement TLS Descriptors Tatsuyuki Ishi
  2 siblings, 1 reply; 37+ messages in thread
From: Tatsuyuki Ishi @ 2023-09-14  8:40 UTC (permalink / raw)
  To: ishitatsuyuki
  Cc: libc-alpha, rui314, ruiu, schwab, adhemerval.zanella, andrew

---
 sysdeps/riscv/dl-tls.h | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/sysdeps/riscv/dl-tls.h b/sysdeps/riscv/dl-tls.h
index 67c8ae639c..f11f335edf 100644
--- a/sysdeps/riscv/dl-tls.h
+++ b/sysdeps/riscv/dl-tls.h
@@ -16,6 +16,8 @@
    License along with the GNU C Library.  If not, see
    <https://www.gnu.org/licenses/>.  */
 
+#ifndef _DL_TLS_H
+# define _DL_TLS_H 1
 
 /* Type used for the representation of TLS information in the GOT.  */
 typedef struct
@@ -46,3 +48,5 @@ extern void *__tls_get_addr (tls_index *ti);
 
 /* Value used for dtv entries for which the allocation is delayed.  */
 #define TLS_DTV_UNALLOCATED	((void *) -1l)
+
+#endif /* _DL_TLS_H */
-- 
2.42.0


^ permalink raw reply	[flat|nested] 37+ messages in thread

* [PATCH v4 2/3] RISC-V: Add TLSDESC reloc definitions.
  2023-09-14  8:40 ` [PATCH v4 0/3] " Tatsuyuki Ishi
  2023-09-14  8:40   ` [PATCH v4 1/3] RISC-V: Add include guard for dl-tls.h Tatsuyuki Ishi
@ 2023-09-14  8:40   ` Tatsuyuki Ishi
  2024-01-27  1:12     ` Fangrui Song
  2023-09-14  8:40   ` [PATCH v4 3/3] RISC-V: Implement TLS Descriptors Tatsuyuki Ishi
  2 siblings, 1 reply; 37+ messages in thread
From: Tatsuyuki Ishi @ 2023-09-14  8:40 UTC (permalink / raw)
  To: ishitatsuyuki
  Cc: libc-alpha, rui314, ruiu, schwab, adhemerval.zanella, andrew

---
 elf/elf.h | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/elf/elf.h b/elf/elf.h
index 9c51073f75..c6247c1bae 100644
--- a/elf/elf.h
+++ b/elf/elf.h
@@ -3959,6 +3959,7 @@ enum
 #define R_RISCV_TLS_DTPREL64	 9
 #define R_RISCV_TLS_TPREL32	10
 #define R_RISCV_TLS_TPREL64	11
+#define R_RISCV_TLSDESC		12
 #define R_RISCV_BRANCH		16
 #define R_RISCV_JAL		17
 #define R_RISCV_CALL		18
@@ -4005,6 +4006,10 @@ enum
 #define R_RISCV_PLT32		59
 #define R_RISCV_SET_ULEB128	60
 #define R_RISCV_SUB_ULEB128	61
+#define R_RISCV_TLSDESC_HI20	62
+#define R_RISCV_TLSDESC_LOAD_LO12	63
+#define R_RISCV_TLSDESC_ADD_LO12	64
+#define R_RISCV_TLSDESC_CALL	65
 
 #define R_RISCV_NUM		62
 
-- 
2.42.0


^ permalink raw reply	[flat|nested] 37+ messages in thread

* [PATCH v4 3/3] RISC-V: Implement TLS Descriptors.
  2023-09-14  8:40 ` [PATCH v4 0/3] " Tatsuyuki Ishi
  2023-09-14  8:40   ` [PATCH v4 1/3] RISC-V: Add include guard for dl-tls.h Tatsuyuki Ishi
  2023-09-14  8:40   ` [PATCH v4 2/3] RISC-V: Add TLSDESC reloc definitions Tatsuyuki Ishi
@ 2023-09-14  8:40   ` Tatsuyuki Ishi
  2023-11-23 11:39     ` Florian Weimer
  2 siblings, 1 reply; 37+ messages in thread
From: Tatsuyuki Ishi @ 2023-09-14  8:40 UTC (permalink / raw)
  To: ishitatsuyuki
  Cc: libc-alpha, rui314, ruiu, schwab, adhemerval.zanella, andrew

This is mostly based off AArch64 implementation, with some adaptations
to different TLS DTV offsets and calling conventions.
---
 sysdeps/riscv/Makefile                      |  13 ++
 sysdeps/riscv/dl-lookupcfg.h                |  27 +++
 sysdeps/riscv/dl-machine.h                  |  50 ++++-
 sysdeps/riscv/dl-tlsdesc.S                  | 205 ++++++++++++++++++++
 sysdeps/riscv/dl-tlsdesc.h                  |  48 +++++
 sysdeps/riscv/linkmap.h                     |   1 +
 sysdeps/riscv/tlsdesc.c                     |  38 ++++
 sysdeps/riscv/tlsdesc.sym                   |  19 ++
 sysdeps/unix/sysv/linux/riscv/localplt.data |   2 +
 9 files changed, 402 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

diff --git a/sysdeps/riscv/Makefile b/sysdeps/riscv/Makefile
index 8fb10b164f..0fa1664cb1 100644
--- a/sysdeps/riscv/Makefile
+++ b/sysdeps/riscv/Makefile
@@ -2,6 +2,19 @@ ifeq ($(subdir),misc)
 sysdep_headers += sys/asm.h
 endif
 
+ifeq ($(subdir),elf)
+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
 # of some assembler macros.
 ASFLAGS-.os += $(pic-ccflag)
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
+   <https://www.gnu.org/licenses/>.  */
+
+#define DL_UNMAP_IS_SPECIAL
+
+#include_next <dl-lookupcfg.h>
+
+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 c0c9bd93ad..9f10160dbb 100644
--- a/sysdeps/riscv/dl-machine.h
+++ b/sysdeps/riscv/dl-machine.h
@@ -25,6 +25,7 @@
 #include <elf/elf.h>
 #include <sys/asm.h>
 #include <dl-tls.h>
+#include <dl-tlsdesc.h>
 #include <dl-irel.h>
 #include <dl-static-tls.h>
 #include <dl-machine-rel.h>
@@ -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..06fe134a38
--- /dev/null
+++ b/sysdeps/riscv/dl-tlsdesc.S
@@ -0,0 +1,205 @@
+/* Thread-local storage 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
+   <https://www.gnu.org/licenses/>.  */
+
+#include <sysdep.h>
+#include <tls.h>
+#include <tlsdesc.h>
+
+#define FRAME_SIZE_FAST (-((-3 * SZREG) & ALMASK))
+
+#ifdef __riscv_float_abi_soft
+# define FRAME_SIZE_SLOW (-((-12 * SZREG) & 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
+
+	call	__tls_get_addr
+	addi	a0, a0, -TLS_DTV_OFFSET
+
+	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
+   <https://www.gnu.org/licenses/>.  */
+
+#ifndef _DL_TLSDESC_H
+# define _DL_TLSDESC_H 1
+
+#include <dl-tls.h>
+
+/* 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/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
+   <https://www.gnu.org/licenses/>.  */
+
+#include <ldsodefs.h>
+#include <tls.h>
+#include <dl-tls.h>
+#include <dl-tlsdesc.h>
+#include <dl-unmap-segments.h>
+#include <tlsdeschtab.h>
+
+/* 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 <stddef.h>
+#include <sysdep.h>
+#include <tls.h>
+#include <link.h>
+#include <dl-tls.h>
+#include <dl-tlsdesc.h>
+
+--
+
+-- 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/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
-- 
2.42.0


^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH v3] RISC-V: Implement TLS Descriptors.
  2023-09-14  8:39     ` Tatsuyuki Ishi
@ 2023-09-14 12:09       ` Adhemerval Zanella Netto
  2024-01-27  2:22         ` Fangrui Song
  0 siblings, 1 reply; 37+ messages in thread
From: Adhemerval Zanella Netto @ 2023-09-14 12:09 UTC (permalink / raw)
  To: Tatsuyuki Ishi; +Cc: libc-alpha, Rui Ueyama, Rui Ueyama, schwab



On 14/09/23 05:39, Tatsuyuki Ishi wrote:
> 
>> On Sep 14, 2023, at 4:14, Adhemerval Zanella Netto <adhemerval.zanella@linaro.org> wrote:
>>
>> How did you actually build glibc? I saw multiple build issues with default
>> configuration and even with --disable-werror, so I am doubtful that this
>> patch was really proper tested. Please ensure that have-mtls-dialect-gnu2
>> is set to 'yes' on config.make so the tests are actually run.
> 
> I’m sorry I’ve made multiple mistakes here. There were actually two prerequisite commits but I’ve forgot to include them in the patch series. This will be included in v4.
> 
> I used [1] to build a full toolchain and it defaulted to --disable-werror. I’ve manually enabled -Werror and fixed all compiler warnings in v4.

For patch development I would advise strongly to use --disable-werror,
the patchwork hasn't flag it because we do not build/run on riscv.

> 
> As for have-mtls-dialect-gnu2, RISC-V will use AArch64-style flags (-mtls-dialect={trad,desc}), not gnu2. However, I have configured my GCC fork with --with-tls=desc and all compilation is done with TLSDESC by default for my testing.

So I take that the default would be still the -mtls-dialect=trad. In
this case I would suggest to change the have-mtls-dialect-gnu2 to be
enabled for -mtls-dialect=desc as well, the elf tests are generic and
should exercise both mode in a default configuration.

> 
> I assumed most testing was done through GCC’s testsuite, and I’ve got GCC’s testsuite to the point of no regression, however I was wrong and there are more in glibc’s testsuite. For v4 I’ve ran all tests in glibc/elf/, and all but two tests for TLS on static executables are passing. More info on my plan for fixing that in v4.
> 

I am not sure about gcc testsuite, but it would be good RISCV to check
for both mode and not only stress the compiler default. Unfortunately 
not all ports follow this.

>>
>>> # RISC-V's assembler also needs to know about PIC as it changes the definition
>>> # of some assembler macros.
>>> ASFLAGS-.os += $(pic-ccflag)
>>> diff --git a/sysdeps/riscv/dl-lookupcfg.h b/sysdeps/riscv/dl-lookupcfg.h
>>> new file mode 100644
>>> index 0000000000..d7fe73636b
>>> --- /dev/null
>>> +++ b/sysdeps/riscv/dl-lookupcfg.h
>>> @@ -0,0 +1,27 @@
>>> +/* Configuration of lookup functions.
>>> +   Copyright (C) 2006-2023 Free Software Foundation, Inc.
>>
>> I think it should be only 2023 for new code.
> 
> Ack, all copyright headers for new files will be 2023 only in v4.
> 
>>>    | (ELF_RTYPE_CLASS_COPY * ((type) == R_RISCV_COPY)))
>>>
>>> /* Return nonzero iff ELF header is compatible with the running host.  */
>>> @@ -219,6 +221,32 @@ 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;
>>
>>
>> This triggers multiple compiler warnings:
>>
>> ../sysdeps/riscv/dl-machine.h: In function ‘elf_machine_rela’:
>> ../sysdeps/riscv/dl-machine.h:228:21: error: assignment to ‘ptrdiff_t (*)(struct tlsdesc *)’ {aka ‘long int (*)(struct tlsdesc *)’} from incompatible pointer type ‘long unsigned int (*)(struct tlsdesc *)’ [-Werror=incompatible-pointer-types]
>>  228 |           td->entry = _dl_tlsdesc_undefweak;
>>      |                     ^
>> ../sysdeps/riscv/dl-machine.h:244:25: error: assignment to ‘ptrdiff_t (*)(struct tlsdesc *)’ {aka ‘long int (*)(struct tlsdesc *)’} from incompatible pointer type ‘long unsigned int (*)(struct tlsdesc *)’ [-Werror=incompatible-pointer-types]
>>  244 |               td->entry = _dl_tlsdesc_return;
>>      |                         ^
>>
>> Because you declare _dl_tlsdesc_undefweak as:
>>
>>  unsigned long _dl_tlsdesc_dynamic (struct tlsdesc *);
>>
>> But the 'entry' at tlsdesc as:
>>
>>   ptrdiff_t (*entry) (struct tlsdesc *);
>>
>> Based on TLSDESC ABI I think using a unsigned as return value is wrong here.
> 
> I am opting to not using ptrdiff_t because the offset can be larger than PTRDIFF_MAX. Using unsigned arithmetic avoids the signed overflow concern.
> 
> The descriptor signature is also defined in the RISC-V psABI as returning unsigned long for the same reason.
> 
> [1]: https://github.com/riscv-collab/riscv-gnu-toolchain
> 

The C standard specified that subtracting two points should be signed
integer type, which maps to ptrdiff_t on most C and POSIX interfaces.
The malloc would fail with requests larger than ptrdiff_t (check 
9bf8e29ca136094f73f69f725f15c51facc97206 and BZ#23741) and gcc might
generate wrong optimizations in such cases (we still allow values 
larger than ptrdiff_t for mmap, but some other libc like bionic and
musl will fail even for mmap).

Although the required code that operates with tlsdesc uses a 
non-standard ABI, meaning most code would either use assembly or C with 
some extra care, I really don't see a compelling reason to have RISCV 
deviates from other ports that implemented TLSDESC.

[1] https://sourceware.org/bugzilla/show_bug.cgi?id=23741
[2] https://gcc.gnu.org/bugzilla//show_bug.cgi?id=67999

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH v4 3/3] RISC-V: Implement TLS Descriptors.
  2023-09-14  8:40   ` [PATCH v4 3/3] RISC-V: Implement TLS Descriptors Tatsuyuki Ishi
@ 2023-11-23 11:39     ` Florian Weimer
  0 siblings, 0 replies; 37+ messages in thread
From: Florian Weimer @ 2023-11-23 11:39 UTC (permalink / raw)
  To: Tatsuyuki Ishi
  Cc: libc-alpha, rui314, ruiu, schwab, adhemerval.zanella, andrew

* Tatsuyuki Ishi:

> +	/* 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.  */

The ABI requires saving and restoring vector registers, too.  The
problem is that __tls_get_addr may end up calling a user-supplied
malloc, and that might clobber vector registers.  So it's not just
dynamic loader code that is involved here, and we can't control how all
relevant code is built.

Thanks,
Florian


^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH v4 2/3] RISC-V: Add TLSDESC reloc definitions.
  2023-09-14  8:40   ` [PATCH v4 2/3] RISC-V: Add TLSDESC reloc definitions Tatsuyuki Ishi
@ 2024-01-27  1:12     ` Fangrui Song
  0 siblings, 0 replies; 37+ messages in thread
From: Fangrui Song @ 2024-01-27  1:12 UTC (permalink / raw)
  To: Tatsuyuki Ishi
  Cc: libc-alpha, rui314, ruiu, schwab, adhemerval.zanella, andrew

On Thu, Sep 14, 2023 at 1:42 AM Tatsuyuki Ishi <ishitatsuyuki@gmail.com> wrote:
>
> ---
>  elf/elf.h | 5 +++++
>  1 file changed, 5 insertions(+)
>
> diff --git a/elf/elf.h b/elf/elf.h
> index 9c51073f75..c6247c1bae 100644
> --- a/elf/elf.h
> +++ b/elf/elf.h
> @@ -3959,6 +3959,7 @@ enum
>  #define R_RISCV_TLS_DTPREL64    9
>  #define R_RISCV_TLS_TPREL32    10
>  #define R_RISCV_TLS_TPREL64    11
> +#define R_RISCV_TLSDESC                12
>  #define R_RISCV_BRANCH         16
>  #define R_RISCV_JAL            17
>  #define R_RISCV_CALL           18
> @@ -4005,6 +4006,10 @@ enum
>  #define R_RISCV_PLT32          59
>  #define R_RISCV_SET_ULEB128    60
>  #define R_RISCV_SUB_ULEB128    61
> +#define R_RISCV_TLSDESC_HI20   62
> +#define R_RISCV_TLSDESC_LOAD_LO12      63
> +#define R_RISCV_TLSDESC_ADD_LO12       64
> +#define R_RISCV_TLSDESC_CALL   65
>
>  #define R_RISCV_NUM            62

R_RISCV_NUM should be updated.
Otherwise, this looks good. I think this patch can land before the
rtld implementation is done.

> --
> 2.42.0
>


-- 
宋方睿

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH v4 1/3] RISC-V: Add include guard for dl-tls.h.
  2023-09-14  8:40   ` [PATCH v4 1/3] RISC-V: Add include guard for dl-tls.h Tatsuyuki Ishi
@ 2024-01-27  1:14     ` Fangrui Song
  0 siblings, 0 replies; 37+ messages in thread
From: Fangrui Song @ 2024-01-27  1:14 UTC (permalink / raw)
  To: Tatsuyuki Ishi
  Cc: libc-alpha, rui314, ruiu, schwab, adhemerval.zanella, andrew

On Thu, Sep 14, 2023 at 1:41 AM Tatsuyuki Ishi <ishitatsuyuki@gmail.com> wrote:
>
> ---
>  sysdeps/riscv/dl-tls.h | 4 ++++
>  1 file changed, 4 insertions(+)
>
> diff --git a/sysdeps/riscv/dl-tls.h b/sysdeps/riscv/dl-tls.h
> index 67c8ae639c..f11f335edf 100644
> --- a/sysdeps/riscv/dl-tls.h
> +++ b/sysdeps/riscv/dl-tls.h
> @@ -16,6 +16,8 @@
>     License along with the GNU C Library.  If not, see
>     <https://www.gnu.org/licenses/>.  */
>
> +#ifndef _DL_TLS_H
> +# define _DL_TLS_H 1
>
>  /* Type used for the representation of TLS information in the GOT.  */
>  typedef struct
> @@ -46,3 +48,5 @@ extern void *__tls_get_addr (tls_index *ti);
>
>  /* Value used for dtv entries for which the allocation is delayed.  */
>  #define TLS_DTV_UNALLOCATED    ((void *) -1l)
> +
> +#endif /* _DL_TLS_H */
> --
> 2.42.0
>

This commit message should state why the header is needed.
Multiple sysdeps/*/dl-tls.h do not have a guard and they are good.


-- 
宋方睿

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH v3] RISC-V: Implement TLS Descriptors.
  2023-09-14 12:09       ` Adhemerval Zanella Netto
@ 2024-01-27  2:22         ` Fangrui Song
  0 siblings, 0 replies; 37+ messages in thread
From: Fangrui Song @ 2024-01-27  2:22 UTC (permalink / raw)
  To: Tatsuyuki Ishi
  Cc: Adhemerval Zanella Netto, libc-alpha, Rui Ueyama, Rui Ueyama, schwab

On Thu, Sep 14, 2023 at 5:09 AM Adhemerval Zanella Netto
<adhemerval.zanella@linaro.org> wrote:
>
>
>
> On 14/09/23 05:39, Tatsuyuki Ishi wrote:
> >
> >> On Sep 14, 2023, at 4:14, Adhemerval Zanella Netto <adhemerval.zanella@linaro.org> wrote:
> >>
> >> How did you actually build glibc? I saw multiple build issues with default
> >> configuration and even with --disable-werror, so I am doubtful that this
> >> patch was really proper tested. Please ensure that have-mtls-dialect-gnu2
> >> is set to 'yes' on config.make so the tests are actually run.
> >
> > I’m sorry I’ve made multiple mistakes here. There were actually two prerequisite commits but I’ve forgot to include them in the patch series. This will be included in v4.
> >
> > I used [1] to build a full toolchain and it defaulted to --disable-werror. I’ve manually enabled -Werror and fixed all compiler warnings in v4.
>
> For patch development I would advise strongly to use --disable-werror,
> the patchwork hasn't flag it because we do not build/run on riscv.
>
> >
> > As for have-mtls-dialect-gnu2, RISC-V will use AArch64-style flags (-mtls-dialect={trad,desc}), not gnu2. However, I have configured my GCC fork with --with-tls=desc and all compilation is done with TLSDESC by default for my testing.
>
> So I take that the default would be still the -mtls-dialect=trad. In
> this case I would suggest to change the have-mtls-dialect-gnu2 to be
> enabled for -mtls-dialect=desc as well, the elf tests are generic and
> should exercise both mode in a default configuration.

Agree. We need to test both -mtls-dialect=trad and -mtls-dialect=desc.
We will likely need a variable like have-mtls-dialect-desc...

> >
> > I assumed most testing was done through GCC’s testsuite, and I’ve got GCC’s testsuite to the point of no regression, however I was wrong and there are more in glibc’s testsuite. For v4 I’ve ran all tests in glibc/elf/, and all but two tests for TLS on static executables are passing. More info on my plan for fixing that in v4.
> >

Latest lld (https://github.com/llvm/llvm-project/pull/79239) supports
TLSDESC and it optimizes TLSDESC to LE/IE regardless of R_RISCV_RELAX,
so it is compatible with the static executable tests.

Reviewers can create /usr/local/bin/ld as a symlink to the latest lld
and do a GCC build:)

On the LLVM side, the RISC-V TLSDESC work (LLVM, Clang, lld) has been
completed today.
https://maskray.me/blog/2024-01-23-riscv-tlsdesc-works
Clang cannot build glibc, but there may be something to use Clang to
build just the elf/ tests :) ?

> I am not sure about gcc testsuite, but it would be good RISCV to check
> for both mode and not only stress the compiler default. Unfortunately
> not all ports follow this.
>
> >>
> >>> # RISC-V's assembler also needs to know about PIC as it changes the definition
> >>> # of some assembler macros.
> >>> ASFLAGS-.os += $(pic-ccflag)
> >>> diff --git a/sysdeps/riscv/dl-lookupcfg.h b/sysdeps/riscv/dl-lookupcfg.h
> >>> new file mode 100644
> >>> index 0000000000..d7fe73636b
> >>> --- /dev/null
> >>> +++ b/sysdeps/riscv/dl-lookupcfg.h
> >>> @@ -0,0 +1,27 @@
> >>> +/* Configuration of lookup functions.
> >>> +   Copyright (C) 2006-2023 Free Software Foundation, Inc.
> >>
> >> I think it should be only 2023 for new code.
> >
> > Ack, all copyright headers for new files will be 2023 only in v4.

Perhaps 2024 for v5 :)

> >>>    | (ELF_RTYPE_CLASS_COPY * ((type) == R_RISCV_COPY)))
> >>>
> >>> /* Return nonzero iff ELF header is compatible with the running host.  */
> >>> @@ -219,6 +221,32 @@ 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;
> >>
> >>
> >> This triggers multiple compiler warnings:
> >>
> >> ../sysdeps/riscv/dl-machine.h: In function ‘elf_machine_rela’:
> >> ../sysdeps/riscv/dl-machine.h:228:21: error: assignment to ‘ptrdiff_t (*)(struct tlsdesc *)’ {aka ‘long int (*)(struct tlsdesc *)’} from incompatible pointer type ‘long unsigned int (*)(struct tlsdesc *)’ [-Werror=incompatible-pointer-types]
> >>  228 |           td->entry = _dl_tlsdesc_undefweak;
> >>      |                     ^
> >> ../sysdeps/riscv/dl-machine.h:244:25: error: assignment to ‘ptrdiff_t (*)(struct tlsdesc *)’ {aka ‘long int (*)(struct tlsdesc *)’} from incompatible pointer type ‘long unsigned int (*)(struct tlsdesc *)’ [-Werror=incompatible-pointer-types]
> >>  244 |               td->entry = _dl_tlsdesc_return;
> >>      |                         ^
> >>
> >> Because you declare _dl_tlsdesc_undefweak as:
> >>
> >>  unsigned long _dl_tlsdesc_dynamic (struct tlsdesc *);
> >>
> >> But the 'entry' at tlsdesc as:
> >>
> >>   ptrdiff_t (*entry) (struct tlsdesc *);
> >>
> >> Based on TLSDESC ABI I think using a unsigned as return value is wrong here.
> >
> > I am opting to not using ptrdiff_t because the offset can be larger than PTRDIFF_MAX. Using unsigned arithmetic avoids the signed overflow concern.
> >
> > The descriptor signature is also defined in the RISC-V psABI as returning unsigned long for the same reason.
> >
> > [1]: https://github.com/riscv-collab/riscv-gnu-toolchain
> >
>
> The C standard specified that subtracting two points should be signed
> integer type, which maps to ptrdiff_t on most C and POSIX interfaces.
> The malloc would fail with requests larger than ptrdiff_t (check
> 9bf8e29ca136094f73f69f725f15c51facc97206 and BZ#23741) and gcc might
> generate wrong optimizations in such cases (we still allow values
> larger than ptrdiff_t for mmap, but some other libc like bionic and
> musl will fail even for mmap).
>
> Although the required code that operates with tlsdesc uses a
> non-standard ABI, meaning most code would either use assembly or C with
> some extra care, I really don't see a compelling reason to have RISCV
> deviates from other ports that implemented TLSDESC.
>
> [1] https://sourceware.org/bugzilla/show_bug.cgi?id=23741
> [2] https://gcc.gnu.org/bugzilla//show_bug.cgi?id=67999



-- 
宋方睿

^ permalink raw reply	[flat|nested] 37+ messages in thread

* [PATCH v5 0/3] RISC-V: Implement TLS Descriptors.
  2023-08-17 18:12 [PATCH] RISC-V: Implement TLS Descriptors Tatsuyuki Ishi
                   ` (4 preceding siblings ...)
  2023-09-14  8:40 ` [PATCH v4 0/3] " Tatsuyuki Ishi
@ 2024-03-29  5:55 ` Tatsuyuki Ishi
  2024-03-29  5:55   ` [PATCH v5 1/3] RISC-V: Add include guard for dl-tls.h Tatsuyuki Ishi
                     ` (2 more replies)
  2024-03-29  6:18 ` [PATCH v6 0/3] " Tatsuyuki Ishi
  6 siblings, 3 replies; 37+ messages in thread
From: Tatsuyuki Ishi @ 2024-03-29  5:55 UTC (permalink / raw)
  To: ishitatsuyuki
  Cc: libc-alpha, rui314, ruiu, schwab, adhemerval.zanella, andrew, fweimer

This patchset implements TLS Descriptors (TLSDESC) for RISC-V targets, per
the ratified specification at [1].

Partial support for TLSDESC is in binutils trunk. In [2] there is
additional support for relaxation which is required to pass
tst-tls1-static. GCC needs to be patched with [3].

Passes binutils and gcc tests for rv32gcv and rv64gcv. For glibc I only
tested elf/ as other subsystems sometimes doesn't work well under qemu.

This contribution is made on behalf of Blue Whale Systems, which has
copyright assignment on file with the FSF.

v2: Fix end-of-file newlines.
v3: Fix segfaulting on the slow path of TLSDESC resolver.
    Fix handling of lazy relocations.
v4: Fix compiler warnings.
    Fix fast path stack alignment pointed out by Andrew.
    Fix style issues pointed out by Adhemerval.
    Include 2 missing prerequisite commits.
    Update localplt list.
v5: Add stubs for save/restore of vector registers.
    Add comments and reordered sections for readability in the TLSDESC assembly.
    Add clobber test sequence for tst-gnu2-tls2.

[1]: https://github.com/riscv-non-isa/riscv-elf-psabi-doc/pull/373
[2]: https://inbox.sourceware.org/binutils/20240220175556.304692-1-ishitatsuyuki@gmail.com/
[3]: https://inbox.sourceware.org/gcc-patches/20240329055239.29719-1-ishitatsuyuki@gmail.com/

Tatsuyuki Ishi (3):
  RISC-V: Add include guard for dl-tls.h.
  RISC-V: Add TLSDESC reloc definitions.
  RISC-V: Implement TLS Descriptors.

 elf/elf.h                                   |   5 +
 sysdeps/riscv/Makefile                      |  10 +
 sysdeps/riscv/dl-lookupcfg.h                |  27 ++
 sysdeps/riscv/dl-machine.h                  |  50 +++-
 sysdeps/riscv/dl-tls.h                      |   4 +
 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 +
 13 files changed, 506 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

-- 
2.44.0


^ permalink raw reply	[flat|nested] 37+ messages in thread

* [PATCH v5 1/3] RISC-V: Add include guard for dl-tls.h.
  2024-03-29  5:55 ` [PATCH v5 0/3] " Tatsuyuki Ishi
@ 2024-03-29  5:55   ` Tatsuyuki Ishi
  2024-03-29  5:55   ` [PATCH v5 2/3] RISC-V: Add TLSDESC reloc definitions Tatsuyuki Ishi
  2024-03-29  5:55   ` [PATCH v5 3/3] RISC-V: Implement TLS Descriptors Tatsuyuki Ishi
  2 siblings, 0 replies; 37+ messages in thread
From: Tatsuyuki Ishi @ 2024-03-29  5:55 UTC (permalink / raw)
  To: ishitatsuyuki
  Cc: libc-alpha, rui314, ruiu, schwab, adhemerval.zanella, andrew, fweimer

---
 sysdeps/riscv/dl-tls.h | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/sysdeps/riscv/dl-tls.h b/sysdeps/riscv/dl-tls.h
index 049161f02f..42914c752b 100644
--- a/sysdeps/riscv/dl-tls.h
+++ b/sysdeps/riscv/dl-tls.h
@@ -16,6 +16,8 @@
    License along with the GNU C Library.  If not, see
    <https://www.gnu.org/licenses/>.  */
 
+#ifndef _DL_TLS_H
+# define _DL_TLS_H 1
 
 /* Type used for the representation of TLS information in the GOT.  */
 typedef struct
@@ -46,3 +48,5 @@ extern void *__tls_get_addr (tls_index *ti);
 
 /* Value used for dtv entries for which the allocation is delayed.  */
 #define TLS_DTV_UNALLOCATED	((void *) -1l)
+
+#endif /* _DL_TLS_H */
-- 
2.44.0


^ permalink raw reply	[flat|nested] 37+ messages in thread

* [PATCH v5 2/3] RISC-V: Add TLSDESC reloc definitions.
  2024-03-29  5:55 ` [PATCH v5 0/3] " Tatsuyuki Ishi
  2024-03-29  5:55   ` [PATCH v5 1/3] RISC-V: Add include guard for dl-tls.h Tatsuyuki Ishi
@ 2024-03-29  5:55   ` Tatsuyuki Ishi
  2024-03-29  5:55   ` [PATCH v5 3/3] RISC-V: Implement TLS Descriptors Tatsuyuki Ishi
  2 siblings, 0 replies; 37+ messages in thread
From: Tatsuyuki Ishi @ 2024-03-29  5:55 UTC (permalink / raw)
  To: ishitatsuyuki
  Cc: libc-alpha, rui314, ruiu, schwab, adhemerval.zanella, andrew, fweimer

---
 elf/elf.h | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/elf/elf.h b/elf/elf.h
index 55b2e87860..84e8766437 100644
--- a/elf/elf.h
+++ b/elf/elf.h
@@ -4080,6 +4080,7 @@ enum
 #define R_RISCV_TLS_DTPREL64	 9
 #define R_RISCV_TLS_TPREL32	10
 #define R_RISCV_TLS_TPREL64	11
+#define R_RISCV_TLSDESC		12
 #define R_RISCV_BRANCH		16
 #define R_RISCV_JAL		17
 #define R_RISCV_CALL		18
@@ -4126,6 +4127,10 @@ enum
 #define R_RISCV_PLT32		59
 #define R_RISCV_SET_ULEB128	60
 #define R_RISCV_SUB_ULEB128	61
+#define R_RISCV_TLSDESC_HI20	62
+#define R_RISCV_TLSDESC_LOAD_LO12	63
+#define R_RISCV_TLSDESC_ADD_LO12	64
+#define R_RISCV_TLSDESC_CALL	65
 
 #define R_RISCV_NUM		62
 
-- 
2.44.0


^ permalink raw reply	[flat|nested] 37+ messages in thread

* [PATCH v5 3/3] RISC-V: Implement TLS Descriptors.
  2024-03-29  5:55 ` [PATCH v5 0/3] " Tatsuyuki Ishi
  2024-03-29  5:55   ` [PATCH v5 1/3] RISC-V: Add include guard for dl-tls.h Tatsuyuki Ishi
  2024-03-29  5:55   ` [PATCH v5 2/3] RISC-V: Add TLSDESC reloc definitions Tatsuyuki Ishi
@ 2024-03-29  5:55   ` Tatsuyuki Ishi
  2 siblings, 0 replies; 37+ messages in thread
From: Tatsuyuki Ishi @ 2024-03-29  5:55 UTC (permalink / raw)
  To: ishitatsuyuki
  Cc: libc-alpha, rui314, ruiu, schwab, adhemerval.zanella, andrew, fweimer

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
+   <https://www.gnu.org/licenses/>.  */
+
+#define DL_UNMAP_IS_SPECIAL
+
+#include_next <dl-lookupcfg.h>
+
+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 <elf/elf.h>
 #include <sys/asm.h>
 #include <dl-tls.h>
+#include <dl-tlsdesc.h>
 #include <dl-irel.h>
 #include <dl-static-tls.h>
 #include <dl-machine-rel.h>
@@ -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
+   <https://www.gnu.org/licenses/>.  */
+
+#include <sysdep.h>
+#include <tls.h>
+#include <tlsdesc.h>
+
+/* 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
+   <https://www.gnu.org/licenses/>.  */
+
+#ifndef _DL_TLSDESC_H
+# define _DL_TLSDESC_H 1
+
+#include <dl-tls.h>
+
+/* 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
+   <https://www.gnu.org/licenses/>.  */
+
+#include <ldsodefs.h>
+#include <tls.h>
+#include <dl-tls.h>
+#include <dl-tlsdesc.h>
+#include <dl-unmap-segments.h>
+#include <tlsdeschtab.h>
+
+/* 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 <stddef.h>
+#include <sysdep.h>
+#include <tls.h>
+#include <link.h>
+#include <dl-tls.h>
+#include <dl-tlsdesc.h>
+
+--
+
+-- 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
+   <https://www.gnu.org/licenses/>.  */
+
+#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 <tst-gnu2-tls2.c>
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
-- 
2.44.0


^ permalink raw reply	[flat|nested] 37+ messages in thread

* [PATCH v6 0/3] RISC-V: Implement TLS Descriptors.
  2023-08-17 18:12 [PATCH] RISC-V: Implement TLS Descriptors Tatsuyuki Ishi
                   ` (5 preceding siblings ...)
  2024-03-29  5:55 ` [PATCH v5 0/3] " Tatsuyuki Ishi
@ 2024-03-29  6:18 ` Tatsuyuki Ishi
  2024-03-29  6:18   ` [PATCH v6 1/3] RISC-V: Add include guard for dl-tls.h Tatsuyuki Ishi
                     ` (3 more replies)
  6 siblings, 4 replies; 37+ messages in thread
From: Tatsuyuki Ishi @ 2024-03-29  6:18 UTC (permalink / raw)
  To: ishitatsuyuki
  Cc: libc-alpha, rui314, ruiu, schwab, adhemerval.zanella, andrew, fweimer

This patchset implements TLS Descriptors (TLSDESC) for RISC-V targets, per
the ratified specification at [1].

Partial support for TLSDESC is in binutils trunk. In [2] there is
additional support for relaxation which is required to pass
tst-tls1-static. GCC needs to be patched with [3].

Passes binutils and gcc tests for rv32gcv and rv64gcv. For glibc I only
tested elf/ as other subsystems sometimes doesn't work well under qemu.

This contribution is made on behalf of Blue Whale Systems, which has
copyright assignment on file with the FSF.

v2: Fix end-of-file newlines.
v3: Fix segfaulting on the slow path of TLSDESC resolver.
    Fix handling of lazy relocations.
v4: Fix compiler warnings.
    Fix fast path stack alignment pointed out by Andrew.
    Fix style issues pointed out by Adhemerval.
    Include 2 missing prerequisite commits.
    Update localplt list.
v5: Add stubs for save/restore of vector registers.
    Add comments and reordered sections for readability in the TLSDESC assembly.
    Add clobber test sequence for tst-gnu2-tls2.
v6: Fix R_RISCV_NUM.
    Elaborate on the include guard commit (thanks Fangrui).

[1]: https://github.com/riscv-non-isa/riscv-elf-psabi-doc/pull/373
[2]: https://inbox.sourceware.org/binutils/20240220175556.304692-1-ishitatsuyuki@gmail.com/
[3]: https://inbox.sourceware.org/gcc-patches/20240329055239.29719-1-ishitatsuyuki@gmail.com/

Tatsuyuki Ishi (3):
  RISC-V: Add include guard for dl-tls.h.
  RISC-V: Add TLSDESC reloc definitions.
  RISC-V: Implement TLS Descriptors.

 elf/elf.h                                   |   7 +-
 sysdeps/riscv/Makefile                      |  10 +
 sysdeps/riscv/dl-lookupcfg.h                |  27 ++
 sysdeps/riscv/dl-machine.h                  |  50 +++-
 sysdeps/riscv/dl-tls.h                      |   4 +
 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 +
 13 files changed, 507 insertions(+), 2 deletions(-)
 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

-- 
2.44.0


^ permalink raw reply	[flat|nested] 37+ messages in thread

* [PATCH v6 1/3] RISC-V: Add include guard for dl-tls.h.
  2024-03-29  6:18 ` [PATCH v6 0/3] " Tatsuyuki Ishi
@ 2024-03-29  6:18   ` Tatsuyuki Ishi
  2024-04-03 11:48     ` Adhemerval Zanella Netto
  2024-03-29  6:18   ` [PATCH v6 2/3] RISC-V: Add TLSDESC reloc definitions Tatsuyuki Ishi
                     ` (2 subsequent siblings)
  3 siblings, 1 reply; 37+ messages in thread
From: Tatsuyuki Ishi @ 2024-03-29  6:18 UTC (permalink / raw)
  To: ishitatsuyuki
  Cc: libc-alpha, rui314, ruiu, schwab, adhemerval.zanella, andrew, fweimer

The to-be-added dl-tlsdesc.h will depend on tls_index from dl-tls.h.
Add an include guard to avoid confusing issues when including both.
---
 sysdeps/riscv/dl-tls.h | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/sysdeps/riscv/dl-tls.h b/sysdeps/riscv/dl-tls.h
index 049161f02f..42914c752b 100644
--- a/sysdeps/riscv/dl-tls.h
+++ b/sysdeps/riscv/dl-tls.h
@@ -16,6 +16,8 @@
    License along with the GNU C Library.  If not, see
    <https://www.gnu.org/licenses/>.  */
 
+#ifndef _DL_TLS_H
+# define _DL_TLS_H 1
 
 /* Type used for the representation of TLS information in the GOT.  */
 typedef struct
@@ -46,3 +48,5 @@ extern void *__tls_get_addr (tls_index *ti);
 
 /* Value used for dtv entries for which the allocation is delayed.  */
 #define TLS_DTV_UNALLOCATED	((void *) -1l)
+
+#endif /* _DL_TLS_H */
-- 
2.44.0


^ permalink raw reply	[flat|nested] 37+ messages in thread

* [PATCH v6 2/3] RISC-V: Add TLSDESC reloc definitions.
  2024-03-29  6:18 ` [PATCH v6 0/3] " Tatsuyuki Ishi
  2024-03-29  6:18   ` [PATCH v6 1/3] RISC-V: Add include guard for dl-tls.h Tatsuyuki Ishi
@ 2024-03-29  6:18   ` Tatsuyuki Ishi
  2024-04-03  5:10     ` Fangrui Song
  2024-04-03  8:03     ` Andreas Schwab
  2024-03-29  6:18   ` [PATCH v6 3/3] RISC-V: Implement TLS Descriptors Tatsuyuki Ishi
  2024-04-30 17:05   ` [PATCH v6 0/3] " Palmer Dabbelt
  3 siblings, 2 replies; 37+ messages in thread
From: Tatsuyuki Ishi @ 2024-03-29  6:18 UTC (permalink / raw)
  To: ishitatsuyuki
  Cc: libc-alpha, rui314, ruiu, schwab, adhemerval.zanella, andrew, fweimer

---
 elf/elf.h | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/elf/elf.h b/elf/elf.h
index 55b2e87860..649547b949 100644
--- a/elf/elf.h
+++ b/elf/elf.h
@@ -4080,6 +4080,7 @@ enum
 #define R_RISCV_TLS_DTPREL64	 9
 #define R_RISCV_TLS_TPREL32	10
 #define R_RISCV_TLS_TPREL64	11
+#define R_RISCV_TLSDESC		12
 #define R_RISCV_BRANCH		16
 #define R_RISCV_JAL		17
 #define R_RISCV_CALL		18
@@ -4126,8 +4127,12 @@ enum
 #define R_RISCV_PLT32		59
 #define R_RISCV_SET_ULEB128	60
 #define R_RISCV_SUB_ULEB128	61
+#define R_RISCV_TLSDESC_HI20	62
+#define R_RISCV_TLSDESC_LOAD_LO12	63
+#define R_RISCV_TLSDESC_ADD_LO12	64
+#define R_RISCV_TLSDESC_CALL	65
 
-#define R_RISCV_NUM		62
+#define R_RISCV_NUM		66
 
 /* RISC-V specific values for the st_other field.  */
 #define STO_RISCV_VARIANT_CC	0x80	/* Function uses variant calling
-- 
2.44.0


^ permalink raw reply	[flat|nested] 37+ messages in thread

* [PATCH v6 3/3] RISC-V: Implement TLS Descriptors.
  2024-03-29  6:18 ` [PATCH v6 0/3] " Tatsuyuki Ishi
  2024-03-29  6:18   ` [PATCH v6 1/3] RISC-V: Add include guard for dl-tls.h Tatsuyuki Ishi
  2024-03-29  6:18   ` [PATCH v6 2/3] RISC-V: Add TLSDESC reloc definitions Tatsuyuki Ishi
@ 2024-03-29  6:18   ` Tatsuyuki Ishi
  2024-04-01 13:23     ` Florian Weimer
  2024-04-01 19:29     ` Adhemerval Zanella Netto
  2024-04-30 17:05   ` [PATCH v6 0/3] " Palmer Dabbelt
  3 siblings, 2 replies; 37+ messages in thread
From: Tatsuyuki Ishi @ 2024-03-29  6:18 UTC (permalink / raw)
  To: ishitatsuyuki
  Cc: libc-alpha, rui314, ruiu, schwab, adhemerval.zanella, andrew, fweimer

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
+   <https://www.gnu.org/licenses/>.  */
+
+#define DL_UNMAP_IS_SPECIAL
+
+#include_next <dl-lookupcfg.h>
+
+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 <elf/elf.h>
 #include <sys/asm.h>
 #include <dl-tls.h>
+#include <dl-tlsdesc.h>
 #include <dl-irel.h>
 #include <dl-static-tls.h>
 #include <dl-machine-rel.h>
@@ -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
+   <https://www.gnu.org/licenses/>.  */
+
+#include <sysdep.h>
+#include <tls.h>
+#include <tlsdesc.h>
+
+/* 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
+   <https://www.gnu.org/licenses/>.  */
+
+#ifndef _DL_TLSDESC_H
+# define _DL_TLSDESC_H 1
+
+#include <dl-tls.h>
+
+/* 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
+   <https://www.gnu.org/licenses/>.  */
+
+#include <ldsodefs.h>
+#include <tls.h>
+#include <dl-tls.h>
+#include <dl-tlsdesc.h>
+#include <dl-unmap-segments.h>
+#include <tlsdeschtab.h>
+
+/* 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 <stddef.h>
+#include <sysdep.h>
+#include <tls.h>
+#include <link.h>
+#include <dl-tls.h>
+#include <dl-tlsdesc.h>
+
+--
+
+-- 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
+   <https://www.gnu.org/licenses/>.  */
+
+#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 <tst-gnu2-tls2.c>
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
-- 
2.44.0


^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH v6 3/3] RISC-V: Implement TLS Descriptors.
  2024-03-29  6:18   ` [PATCH v6 3/3] RISC-V: Implement TLS Descriptors Tatsuyuki Ishi
@ 2024-04-01 13:23     ` Florian Weimer
  2024-04-01 19:29     ` Adhemerval Zanella Netto
  1 sibling, 0 replies; 37+ messages in thread
From: Florian Weimer @ 2024-04-01 13:23 UTC (permalink / raw)
  To: Tatsuyuki Ishi
  Cc: libc-alpha, rui314, ruiu, schwab, adhemerval.zanella, andrew

* Tatsuyuki Ishi:

> 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

This shouldn't be needed if you add a proper hidden alias.

Thanks,
Florian


^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH v6 3/3] RISC-V: Implement TLS Descriptors.
  2024-03-29  6:18   ` [PATCH v6 3/3] RISC-V: Implement TLS Descriptors Tatsuyuki Ishi
  2024-04-01 13:23     ` Florian Weimer
@ 2024-04-01 19:29     ` Adhemerval Zanella Netto
  2024-04-02  3:36       ` Tatsuyuki Ishi
  1 sibling, 1 reply; 37+ messages in thread
From: Adhemerval Zanella Netto @ 2024-04-01 19:29 UTC (permalink / raw)
  To: Tatsuyuki Ishi; +Cc: libc-alpha, rui314, ruiu, schwab, andrew, fweimer



On 29/03/24 03:18, Tatsuyuki Ishi wrote:
> 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.
> ---

> +/* 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))

We already have 6 different RISC-V abis on build-many-glibcs.py, plus
the ZBB/XTHREADB usage on string-fza.h. With this we will another 
sub-variant we will need to build/check, which will make RISC-V even
more MIPS-like with its unfeasible number of ABIs.

Maybe a better option, now that glibc has internally riscv_hwprobe
support and that RVV is only support for 6.5, to use instead of adding
another ABI variant. 

It could either through ifunc variants, like x86, or by embedding the
ABI check within the _dl_tlsdesc_dynamic, like ARM.

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH v6 3/3] RISC-V: Implement TLS Descriptors.
  2024-04-01 19:29     ` Adhemerval Zanella Netto
@ 2024-04-02  3:36       ` Tatsuyuki Ishi
  2024-04-02 13:35         ` Adhemerval Zanella Netto
  0 siblings, 1 reply; 37+ messages in thread
From: Tatsuyuki Ishi @ 2024-04-02  3:36 UTC (permalink / raw)
  To: Adhemerval Zanella Netto
  Cc: libc-alpha, Rui Ueyama, Rui Ueyama, schwab, andrew, Florian Weimer

> On Apr 2, 2024, at 4:29, Adhemerval Zanella Netto <adhemerval.zanella@linaro.org> wrote:
> 
> Maybe a better option, now that glibc has internally riscv_hwprobe
> support and that RVV is only support for 6.5, to use instead of adding
> another ABI variant. 

Does this mean that it can be assumed that RVV code will only be executed on an environment that also supports riscv_hwprobe? In that case, I agree that we should switch the RVV path to use feature detection.

I suppose the softfp path will remain the same since not all softfp environment will support hwprobe per the reasoning.

Tatsuyuki.

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH v6 3/3] RISC-V: Implement TLS Descriptors.
  2024-04-02  3:36       ` Tatsuyuki Ishi
@ 2024-04-02 13:35         ` Adhemerval Zanella Netto
  2024-04-02 15:25           ` Palmer Dabbelt
  0 siblings, 1 reply; 37+ messages in thread
From: Adhemerval Zanella Netto @ 2024-04-02 13:35 UTC (permalink / raw)
  To: Tatsuyuki Ishi
  Cc: libc-alpha, Rui Ueyama, Rui Ueyama, schwab, andrew, Florian Weimer



On 02/04/24 00:36, Tatsuyuki Ishi wrote:
>> On Apr 2, 2024, at 4:29, Adhemerval Zanella Netto <adhemerval.zanella@linaro.org> wrote:
>>
>> Maybe a better option, now that glibc has internally riscv_hwprobe
>> support and that RVV is only support for 6.5, to use instead of adding
>> another ABI variant. 
> 
> Does this mean that it can be assumed that RVV code will only be executed on an environment that also supports riscv_hwprobe? In that case, I agree that we should switch the RVV path to use feature detection.

Unless RVV support is backported without backporting riscv_hwprobe as well,
although I expected that RISC-V maintainer would avoid it because the
whole riscv_hwprobe is to enable runtime selection for RVV and alike
features.

> 
> I suppose the softfp path will remain the same since not all softfp environment will support hwprobe per the reasoning.

I take that softfp is a de-facto ABI for RISC-V, at least this what we
have on build-many-glibcs.py:

  riscv64-linux-gnu-rv64imac-lp64
  riscv64-linux-gnu-rv64imafdc-lp64
  riscv64-linux-gnu-rv64imafdc-lp64d

I am not sure whether RISC-V maintainer would like to move to profilers
or would keep this extensions composability manner.

> 
> Tatsuyuki.

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH v6 3/3] RISC-V: Implement TLS Descriptors.
  2024-04-02 13:35         ` Adhemerval Zanella Netto
@ 2024-04-02 15:25           ` Palmer Dabbelt
  2024-04-02 15:32             ` Adhemerval Zanella Netto
  0 siblings, 1 reply; 37+ messages in thread
From: Palmer Dabbelt @ 2024-04-02 15:25 UTC (permalink / raw)
  To: adhemerval.zanella
  Cc: ishitatsuyuki, libc-alpha, rui314, ruiu, schwab, Andrew Waterman,
	fweimer

On Tue, 02 Apr 2024 06:35:21 PDT (-0700), adhemerval.zanella@linaro.org wrote:
>
>
> On 02/04/24 00:36, Tatsuyuki Ishi wrote:
>>> On Apr 2, 2024, at 4:29, Adhemerval Zanella Netto <adhemerval.zanella@linaro.org> wrote:
>>>
>>> Maybe a better option, now that glibc has internally riscv_hwprobe
>>> support and that RVV is only support for 6.5, to use instead of adding
>>> another ABI variant.

We might end up with a new ABI variant for the hard-vector calling 
convention (ie, passing vector registers in arguments)
at some point, but that's a little way off.  We don't even support it as 
a base ABI in GCC yet, and it's too late to do something like that for 
14.

Either way we'd need to make tlsdesc work on systems with the V 
extension and the soft-vector ABI, which means dynamically probing for 
it.

>> Does this mean that it can be assumed that RVV code will only be executed on an environment that also supports riscv_hwprobe? In that case, I agree that we should switch the RVV path to use feature detection.
>
> Unless RVV support is backported without backporting riscv_hwprobe as well,
> although I expected that RISC-V maintainer would avoid it because the
> whole riscv_hwprobe is to enable runtime selection for RVV and alike
> features.

Ya, that seems like a way to just make headaches.  V is particularly 
tricky because it has use-visible state and thus everything needs to 
know about it to work.

There's also a prctl() for enabling/disabling the V extension at 
runtime that we'll need to check, but that's in the same spot.

>> I suppose the softfp path will remain the same since not all softfp environment will support hwprobe per the reasoning.

hwprobe doesn't change anything about the soft float ABI, that needs to 
be linked with compatible objects in order to function correctly.  
That's the same spot we'd end up in for the hard-vector ABI, if we added 
one.

> I take that softfp is a de-facto ABI for RISC-V, at least this what we
> have on build-many-glibcs.py:
>
>   riscv64-linux-gnu-rv64imac-lp64
>   riscv64-linux-gnu-rv64imafdc-lp64
>   riscv64-linux-gnu-rv64imafdc-lp64d

Ya, we have soft-float and double-float ABIs in glibc.  There's also a 
single-float ABI in GCC, but we decided not to add that to glibc to 
avoid the complexity.

> I am not sure whether RISC-V maintainer would like to move to profilers
> or would keep this extensions composability manner.

What do you mean by "move to profilers"?  "move to profiles"?

We have the profiles in RISC-V, but they don't really fix anything here: 
there's a ton of them, they still have various optional extensions, and 
the HW support is all over the place (we don't even have compatibility 
guarantees with individual extensions, for example).

So I think for just sticking to the current base ABIs is the way to go.  
Maybe at some point HW vendors will start shipping systems that are 
compatible with some common extension set and we can promote that to a 
new base ABI, but we're a way off from that happening.

>
>>
>> Tatsuyuki.

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH v6 3/3] RISC-V: Implement TLS Descriptors.
  2024-04-02 15:25           ` Palmer Dabbelt
@ 2024-04-02 15:32             ` Adhemerval Zanella Netto
  2024-04-02 16:37               ` Palmer Dabbelt
  0 siblings, 1 reply; 37+ messages in thread
From: Adhemerval Zanella Netto @ 2024-04-02 15:32 UTC (permalink / raw)
  To: Palmer Dabbelt
  Cc: ishitatsuyuki, libc-alpha, rui314, ruiu, schwab, Andrew Waterman,
	fweimer



On 02/04/24 12:25, Palmer Dabbelt wrote:

> 
>> I am not sure whether RISC-V maintainer would like to move to profilers
>> or would keep this extensions composability manner.
> 
> What do you mean by "move to profilers"?  "move to profiles"?
> 
> We have the profiles in RISC-V, but they don't really fix anything here: there's a ton of them, they still have various optional extensions, and the HW support is all over the place (we don't even have compatibility guarantees with individual extensions, for example).
> 
> So I think for just sticking to the current base ABIs is the way to go.  Maybe at some point HW vendors will start shipping systems that are compatible with some common extension set and we can promote that to a new base ABI, but we're a way off from that happening.

Indeed I meant 'profiles' here and my understanding was that something like
RVA22U64 as base would simplify things a bit (at least with the possible
testing/checking the multiple build permutations that using optional
extensions would incur).

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH v6 3/3] RISC-V: Implement TLS Descriptors.
  2024-04-02 15:32             ` Adhemerval Zanella Netto
@ 2024-04-02 16:37               ` Palmer Dabbelt
  0 siblings, 0 replies; 37+ messages in thread
From: Palmer Dabbelt @ 2024-04-02 16:37 UTC (permalink / raw)
  To: adhemerval.zanella
  Cc: ishitatsuyuki, libc-alpha, rui314, ruiu, schwab, Andrew Waterman,
	fweimer

On Tue, 02 Apr 2024 08:32:59 PDT (-0700), adhemerval.zanella@linaro.org wrote:
>
>
> On 02/04/24 12:25, Palmer Dabbelt wrote:
>
>>
>>> I am not sure whether RISC-V maintainer would like to move to profilers
>>> or would keep this extensions composability manner.
>>
>> What do you mean by "move to profilers"?  "move to profiles"?
>>
>> We have the profiles in RISC-V, but they don't really fix anything here: there's a ton of them, they still have various optional extensions, and the HW support is all over the place (we don't even have compatibility guarantees with individual extensions, for example).
>>
>> So I think for just sticking to the current base ABIs is the way to go.  Maybe at some point HW vendors will start shipping systems that are compatible with some common extension set and we can promote that to a new base ABI, but we're a way off from that happening.
>
> Indeed I meant 'profiles' here and my understanding was that something like
> RVA22U64 as base would simplify things a bit (at least with the possible
> testing/checking the multiple build permutations that using optional
> extensions would incur).

If we could get all the HW vendors to agree to something it wouldn't 
hurt, but trying to move to one of the newer profiles would mean 
dropping support for existing hardware (and thus breaking users who are 
stuck with it, a lot of this newer hardware seems pretty buggy right 
now).  Vendors seem to be implementing stuff that's close to the 
profiles, but it's still a bit of a mess -- plus we end up with the 
whole vendor self-certification issue, which means it's really hard to 
tell what HW actually does from the marketing material.

I'm hoping that something like Android will help here, as there we'll 
have people who are actually shipping systems defining the compatibility 
requirements.  With any luck that will start getting these issues at 
least understood over at RVI, but it's still going to be a long process 
before we get stuff sane.

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH v6 2/3] RISC-V: Add TLSDESC reloc definitions.
  2024-03-29  6:18   ` [PATCH v6 2/3] RISC-V: Add TLSDESC reloc definitions Tatsuyuki Ishi
@ 2024-04-03  5:10     ` Fangrui Song
  2024-04-03  8:03     ` Andreas Schwab
  1 sibling, 0 replies; 37+ messages in thread
From: Fangrui Song @ 2024-04-03  5:10 UTC (permalink / raw)
  To: Tatsuyuki Ishi
  Cc: libc-alpha, rui314, ruiu, schwab, adhemerval.zanella, andrew, fweimer

On Thu, Mar 28, 2024 at 11:19 PM Tatsuyuki Ishi <ishitatsuyuki@gmail.com> wrote:
>
> ---
>  elf/elf.h | 7 ++++++-
>  1 file changed, 6 insertions(+), 1 deletion(-)
>
> diff --git a/elf/elf.h b/elf/elf.h
> index 55b2e87860..649547b949 100644
> --- a/elf/elf.h
> +++ b/elf/elf.h
> @@ -4080,6 +4080,7 @@ enum
>  #define R_RISCV_TLS_DTPREL64    9
>  #define R_RISCV_TLS_TPREL32    10
>  #define R_RISCV_TLS_TPREL64    11
> +#define R_RISCV_TLSDESC                12
>  #define R_RISCV_BRANCH         16
>  #define R_RISCV_JAL            17
>  #define R_RISCV_CALL           18
> @@ -4126,8 +4127,12 @@ enum
>  #define R_RISCV_PLT32          59
>  #define R_RISCV_SET_ULEB128    60
>  #define R_RISCV_SUB_ULEB128    61
> +#define R_RISCV_TLSDESC_HI20   62
> +#define R_RISCV_TLSDESC_LOAD_LO12      63
> +#define R_RISCV_TLSDESC_ADD_LO12       64
> +#define R_RISCV_TLSDESC_CALL   65
>
> -#define R_RISCV_NUM            62
> +#define R_RISCV_NUM            66
>
>  /* RISC-V specific values for the st_other field.  */
>  #define STO_RISCV_VARIANT_CC   0x80    /* Function uses variant calling
> --
> 2.44.0

Reviewed-by: Fangrui Song <maskray@google.com>


-- 
宋方睿

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH v6 2/3] RISC-V: Add TLSDESC reloc definitions.
  2024-03-29  6:18   ` [PATCH v6 2/3] RISC-V: Add TLSDESC reloc definitions Tatsuyuki Ishi
  2024-04-03  5:10     ` Fangrui Song
@ 2024-04-03  8:03     ` Andreas Schwab
  1 sibling, 0 replies; 37+ messages in thread
From: Andreas Schwab @ 2024-04-03  8:03 UTC (permalink / raw)
  To: Tatsuyuki Ishi
  Cc: libc-alpha, rui314, ruiu, adhemerval.zanella, andrew, fweimer

This should update the complete list, see <mvmzfwwauem.fsf@suse.de>.

-- 
Andreas Schwab, schwab@linux-m68k.org
GPG Key fingerprint = 7578 EB47 D4E5 4D69 2510  2552 DF73 E780 A9DA AEC1
"And now for something completely different."

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH v6 1/3] RISC-V: Add include guard for dl-tls.h.
  2024-03-29  6:18   ` [PATCH v6 1/3] RISC-V: Add include guard for dl-tls.h Tatsuyuki Ishi
@ 2024-04-03 11:48     ` Adhemerval Zanella Netto
  0 siblings, 0 replies; 37+ messages in thread
From: Adhemerval Zanella Netto @ 2024-04-03 11:48 UTC (permalink / raw)
  To: Tatsuyuki Ishi; +Cc: libc-alpha, rui314, ruiu, schwab, andrew, fweimer



On 29/03/24 03:18, Tatsuyuki Ishi wrote:
> The to-be-added dl-tlsdesc.h will depend on tls_index from dl-tls.h.
> Add an include guard to avoid confusing issues when including both.

This seems obvious enough.

Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>

> ---
>  sysdeps/riscv/dl-tls.h | 4 ++++
>  1 file changed, 4 insertions(+)
> 
> diff --git a/sysdeps/riscv/dl-tls.h b/sysdeps/riscv/dl-tls.h
> index 049161f02f..42914c752b 100644
> --- a/sysdeps/riscv/dl-tls.h
> +++ b/sysdeps/riscv/dl-tls.h
> @@ -16,6 +16,8 @@
>     License along with the GNU C Library.  If not, see
>     <https://www.gnu.org/licenses/>.  */
>  
> +#ifndef _DL_TLS_H
> +# define _DL_TLS_H 1
>  
>  /* Type used for the representation of TLS information in the GOT.  */
>  typedef struct
> @@ -46,3 +48,5 @@ extern void *__tls_get_addr (tls_index *ti);
>  
>  /* Value used for dtv entries for which the allocation is delayed.  */
>  #define TLS_DTV_UNALLOCATED	((void *) -1l)
> +
> +#endif /* _DL_TLS_H */

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH v6 0/3] RISC-V: Implement TLS Descriptors.
  2024-03-29  6:18 ` [PATCH v6 0/3] " Tatsuyuki Ishi
                     ` (2 preceding siblings ...)
  2024-03-29  6:18   ` [PATCH v6 3/3] RISC-V: Implement TLS Descriptors Tatsuyuki Ishi
@ 2024-04-30 17:05   ` Palmer Dabbelt
  2024-04-30 18:33     ` Adhemerval Zanella Netto
  3 siblings, 1 reply; 37+ messages in thread
From: Palmer Dabbelt @ 2024-04-30 17:05 UTC (permalink / raw)
  To: ishitatsuyuki
  Cc: ishitatsuyuki, libc-alpha, rui314, ruiu, schwab,
	adhemerval.zanella, Andrew Waterman, fweimer

On Thu, 28 Mar 2024 23:18:31 PDT (-0700), ishitatsuyuki@gmail.com wrote:
> This patchset implements TLS Descriptors (TLSDESC) for RISC-V targets, per
> the ratified specification at [1].
>
> Partial support for TLSDESC is in binutils trunk. In [2] there is
> additional support for relaxation which is required to pass
> tst-tls1-static. GCC needs to be patched with [3].
>
> Passes binutils and gcc tests for rv32gcv and rv64gcv. For glibc I only
> tested elf/ as other subsystems sometimes doesn't work well under qemu.
>
> This contribution is made on behalf of Blue Whale Systems, which has
> copyright assignment on file with the FSF.
>
> v2: Fix end-of-file newlines.
> v3: Fix segfaulting on the slow path of TLSDESC resolver.
>     Fix handling of lazy relocations.
> v4: Fix compiler warnings.
>     Fix fast path stack alignment pointed out by Andrew.
>     Fix style issues pointed out by Adhemerval.
>     Include 2 missing prerequisite commits.
>     Update localplt list.
> v5: Add stubs for save/restore of vector registers.
>     Add comments and reordered sections for readability in the TLSDESC assembly.
>     Add clobber test sequence for tst-gnu2-tls2.
> v6: Fix R_RISCV_NUM.
>     Elaborate on the include guard commit (thanks Fangrui).
>
> [1]: https://github.com/riscv-non-isa/riscv-elf-psabi-doc/pull/373
> [2]: https://inbox.sourceware.org/binutils/20240220175556.304692-1-ishitatsuyuki@gmail.com/
> [3]: https://inbox.sourceware.org/gcc-patches/20240329055239.29719-1-ishitatsuyuki@gmail.com/
>
> Tatsuyuki Ishi (3):
>   RISC-V: Add include guard for dl-tls.h.
>   RISC-V: Add TLSDESC reloc definitions.
>   RISC-V: Implement TLS Descriptors.
>
>  elf/elf.h                                   |   7 +-
>  sysdeps/riscv/Makefile                      |  10 +
>  sysdeps/riscv/dl-lookupcfg.h                |  27 ++
>  sysdeps/riscv/dl-machine.h                  |  50 +++-
>  sysdeps/riscv/dl-tls.h                      |   4 +
>  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 +
>  13 files changed, 507 insertions(+), 2 deletions(-)
>  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

This generally LGTM, but IIUC we're waiting on a glibc-wide decision as 
to what the stable ABIs should be around TLS before moving forward.

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH v6 0/3] RISC-V: Implement TLS Descriptors.
  2024-04-30 17:05   ` [PATCH v6 0/3] " Palmer Dabbelt
@ 2024-04-30 18:33     ` Adhemerval Zanella Netto
  2024-05-01  1:36       ` Tatsuyuki Ishi
  0 siblings, 1 reply; 37+ messages in thread
From: Adhemerval Zanella Netto @ 2024-04-30 18:33 UTC (permalink / raw)
  To: Palmer Dabbelt, ishitatsuyuki
  Cc: libc-alpha, rui314, ruiu, schwab, Andrew Waterman, fweimer



On 30/04/24 14:05, Palmer Dabbelt wrote:
> On Thu, 28 Mar 2024 23:18:31 PDT (-0700), ishitatsuyuki@gmail.com wrote:
>> This patchset implements TLS Descriptors (TLSDESC) for RISC-V targets, per
>> the ratified specification at [1].
>>
>> Partial support for TLSDESC is in binutils trunk. In [2] there is
>> additional support for relaxation which is required to pass
>> tst-tls1-static. GCC needs to be patched with [3].
>>
>> Passes binutils and gcc tests for rv32gcv and rv64gcv. For glibc I only
>> tested elf/ as other subsystems sometimes doesn't work well under qemu.
>>
>> This contribution is made on behalf of Blue Whale Systems, which has
>> copyright assignment on file with the FSF.
>>
>> v2: Fix end-of-file newlines.
>> v3: Fix segfaulting on the slow path of TLSDESC resolver.
>>     Fix handling of lazy relocations.
>> v4: Fix compiler warnings.
>>     Fix fast path stack alignment pointed out by Andrew.
>>     Fix style issues pointed out by Adhemerval.
>>     Include 2 missing prerequisite commits.
>>     Update localplt list.
>> v5: Add stubs for save/restore of vector registers.
>>     Add comments and reordered sections for readability in the TLSDESC assembly.
>>     Add clobber test sequence for tst-gnu2-tls2.
>> v6: Fix R_RISCV_NUM.
>>     Elaborate on the include guard commit (thanks Fangrui).
>>
>> [1]: https://github.com/riscv-non-isa/riscv-elf-psabi-doc/pull/373
>> [2]: https://inbox.sourceware.org/binutils/20240220175556.304692-1-ishitatsuyuki@gmail.com/
>> [3]: https://inbox.sourceware.org/gcc-patches/20240329055239.29719-1-ishitatsuyuki@gmail.com/
>>
>> Tatsuyuki Ishi (3):
>>   RISC-V: Add include guard for dl-tls.h.
>>   RISC-V: Add TLSDESC reloc definitions.
>>   RISC-V: Implement TLS Descriptors.
>>
>>  elf/elf.h                                   |   7 +-
>>  sysdeps/riscv/Makefile                      |  10 +
>>  sysdeps/riscv/dl-lookupcfg.h                |  27 ++
>>  sysdeps/riscv/dl-machine.h                  |  50 +++-
>>  sysdeps/riscv/dl-tls.h                      |   4 +
>>  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 +
>>  13 files changed, 507 insertions(+), 2 deletions(-)
>>  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
> 
> This generally LGTM, but IIUC we're waiting on a glibc-wide decision as to what the stable ABIs should be around TLS before moving forward.

If I recall correctly, my latest remarks for this patch was:

1. Missing gcc/binutils upstream support (usually we wait the patches 
   to be upstream on the required projects)

2. Call the internal __tls_get_addr on _dl_tlsdesc_dynamic to avoid
   the PLT call.

3. Decide how RISCV would like to handle different ABI constraint for
   the _dl_tlsdesc_dynamic, now that you are moving to support ifunc
   and thus allowing a more generic glibc build.  You can either make
   the _dl_tlsdesc_dynamic with multiple ifunc variants (as x86 does),
   or check the chip support through the riscv_hwprobe on the function
   itself and only save/restore the support ABI register.

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH v6 0/3] RISC-V: Implement TLS Descriptors.
  2024-04-30 18:33     ` Adhemerval Zanella Netto
@ 2024-05-01  1:36       ` Tatsuyuki Ishi
  0 siblings, 0 replies; 37+ messages in thread
From: Tatsuyuki Ishi @ 2024-05-01  1:36 UTC (permalink / raw)
  To: Adhemerval Zanella Netto
  Cc: Palmer Dabbelt, libc-alpha, Rui Ueyama, Rui Ueyama, schwab,
	Andrew Waterman, Florian Weimer

> On May 1, 2024, at 3:33, Adhemerval Zanella Netto <adhemerval.zanella@linaro.org> wrote:
> 
> On 30/04/24 14:05, Palmer Dabbelt wrote:
>> On Thu, 28 Mar 2024 23:18:31 PDT (-0700), ishitatsuyuki@gmail.com wrote:
>>> This patchset implements TLS Descriptors (TLSDESC) for RISC-V targets, per
>>> the ratified specification at [1].
>>> 
>>> Partial support for TLSDESC is in binutils trunk. In [2] there is
>>> additional support for relaxation which is required to pass
>>> tst-tls1-static. GCC needs to be patched with [3].
>>> 
>>> Passes binutils and gcc tests for rv32gcv and rv64gcv. For glibc I only
>>> tested elf/ as other subsystems sometimes doesn't work well under qemu.
>>> 
>>> This contribution is made on behalf of Blue Whale Systems, which has
>>> copyright assignment on file with the FSF.
>>> 
>>> v2: Fix end-of-file newlines.
>>> v3: Fix segfaulting on the slow path of TLSDESC resolver.
>>>     Fix handling of lazy relocations.
>>> v4: Fix compiler warnings.
>>>     Fix fast path stack alignment pointed out by Andrew.
>>>     Fix style issues pointed out by Adhemerval.
>>>     Include 2 missing prerequisite commits.
>>>     Update localplt list.
>>> v5: Add stubs for save/restore of vector registers.
>>>     Add comments and reordered sections for readability in the TLSDESC assembly.
>>>     Add clobber test sequence for tst-gnu2-tls2.
>>> v6: Fix R_RISCV_NUM.
>>>     Elaborate on the include guard commit (thanks Fangrui).
>>> 
>>> [1]: https://github.com/riscv-non-isa/riscv-elf-psabi-doc/pull/373
>>> [2]: https://inbox.sourceware.org/binutils/20240220175556.304692-1-ishitatsuyuki@gmail.com/
>>> [3]: https://inbox.sourceware.org/gcc-patches/20240329055239.29719-1-ishitatsuyuki@gmail.com/
>>> 
>>> Tatsuyuki Ishi (3):
>>>   RISC-V: Add include guard for dl-tls.h.
>>>   RISC-V: Add TLSDESC reloc definitions.
>>>   RISC-V: Implement TLS Descriptors.
>>> 
>>>  elf/elf.h                                   |   7 +-
>>>  sysdeps/riscv/Makefile                      |  10 +
>>>  sysdeps/riscv/dl-lookupcfg.h                |  27 ++
>>>  sysdeps/riscv/dl-machine.h                  |  50 +++-
>>>  sysdeps/riscv/dl-tls.h                      |   4 +
>>>  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 +
>>>  13 files changed, 507 insertions(+), 2 deletions(-)
>>>  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
>> 
>> This generally LGTM, but IIUC we're waiting on a glibc-wide decision as to what the stable ABIs should be around TLS before moving forward.
> 
> If I recall correctly, my latest remarks for this patch was:
> 
> 1. Missing gcc/binutils upstream support (usually we wait the patches 
>   to be upstream on the required projects)

For a status update, binutils have partial TLSDESC support (without relaxation) committed and GCC have all the required patches committed. This means tst-tls-static-1 will still fail with upstream toolchain, though.

> 2. Call the internal __tls_get_addr on _dl_tlsdesc_dynamic to avoid
>   the PLT call.

This was a trivial change, and I will include it in the next version.

> 3. Decide how RISCV would like to handle different ABI constraint for
>   the _dl_tlsdesc_dynamic, now that you are moving to support ifunc
>   and thus allowing a more generic glibc build.  You can either make
>   the _dl_tlsdesc_dynamic with multiple ifunc variants (as x86 does),
>   or check the chip support through the riscv_hwprobe on the function
>   itself and only save/restore the support ABI register.

Note that we don’t really have any of the cpu_features scaffolding in RISC-V, so going down the IFUNC route seems a lot more annoying. I’m working on adding a call to riscv_hwprobe in _dl_tlsdesc_dynamic. I need some more time to figure out how to configure user mode QEMU to test all the code paths.

As for TLS ABI decision, it would be good if we decide on a calling convention, but shipping a stub that saves / restores all vector registers should also be OK (which is what the current revision do).

Tatsuyuki

^ permalink raw reply	[flat|nested] 37+ messages in thread

end of thread, other threads:[~2024-05-01  1:36 UTC | newest]

Thread overview: 37+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-08-17 18:12 [PATCH] RISC-V: Implement TLS Descriptors Tatsuyuki Ishi
2023-08-17 18:35 ` Andreas Schwab
2023-09-08 10:55 ` [PATCH v2] " Tatsuyuki Ishi
2023-09-13 17:26 ` [PATCH v3] " Tatsuyuki Ishi
2023-09-13 19:14   ` Adhemerval Zanella Netto
2023-09-14  8:39     ` Tatsuyuki Ishi
2023-09-14 12:09       ` Adhemerval Zanella Netto
2024-01-27  2:22         ` Fangrui Song
2023-09-13 19:07 ` [PATCH] " Andrew Waterman
2023-09-14  8:40 ` [PATCH v4 0/3] " Tatsuyuki Ishi
2023-09-14  8:40   ` [PATCH v4 1/3] RISC-V: Add include guard for dl-tls.h Tatsuyuki Ishi
2024-01-27  1:14     ` Fangrui Song
2023-09-14  8:40   ` [PATCH v4 2/3] RISC-V: Add TLSDESC reloc definitions Tatsuyuki Ishi
2024-01-27  1:12     ` Fangrui Song
2023-09-14  8:40   ` [PATCH v4 3/3] RISC-V: Implement TLS Descriptors Tatsuyuki Ishi
2023-11-23 11:39     ` Florian Weimer
2024-03-29  5:55 ` [PATCH v5 0/3] " Tatsuyuki Ishi
2024-03-29  5:55   ` [PATCH v5 1/3] RISC-V: Add include guard for dl-tls.h Tatsuyuki Ishi
2024-03-29  5:55   ` [PATCH v5 2/3] RISC-V: Add TLSDESC reloc definitions Tatsuyuki Ishi
2024-03-29  5:55   ` [PATCH v5 3/3] RISC-V: Implement TLS Descriptors Tatsuyuki Ishi
2024-03-29  6:18 ` [PATCH v6 0/3] " Tatsuyuki Ishi
2024-03-29  6:18   ` [PATCH v6 1/3] RISC-V: Add include guard for dl-tls.h Tatsuyuki Ishi
2024-04-03 11:48     ` Adhemerval Zanella Netto
2024-03-29  6:18   ` [PATCH v6 2/3] RISC-V: Add TLSDESC reloc definitions Tatsuyuki Ishi
2024-04-03  5:10     ` Fangrui Song
2024-04-03  8:03     ` Andreas Schwab
2024-03-29  6:18   ` [PATCH v6 3/3] RISC-V: Implement TLS Descriptors Tatsuyuki Ishi
2024-04-01 13:23     ` Florian Weimer
2024-04-01 19:29     ` Adhemerval Zanella Netto
2024-04-02  3:36       ` Tatsuyuki Ishi
2024-04-02 13:35         ` Adhemerval Zanella Netto
2024-04-02 15:25           ` Palmer Dabbelt
2024-04-02 15:32             ` Adhemerval Zanella Netto
2024-04-02 16:37               ` Palmer Dabbelt
2024-04-30 17:05   ` [PATCH v6 0/3] " Palmer Dabbelt
2024-04-30 18:33     ` Adhemerval Zanella Netto
2024-05-01  1:36       ` Tatsuyuki Ishi

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).