Message ID | 20230817181228.122674-2-ishitatsuyuki@gmail.com |
---|---|
State | New |
Headers | show |
Series | RISC-V: Implement TLS Descriptors. | expand |
On Aug 18 2023, Tatsuyuki Ishi via Libc-alpha wrote:
> \ No newline at end of file
Please fix that.
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 >
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