[PATCH v3] i386: Update ___tls_get_addr to preserve vector registers

H.J. Lu hjl.tools@gmail.com
Tue Jun 17 01:56:14 GMT 2025


On Tue, Jun 17, 2025 at 4:55 AM Adhemerval Zanella Netto
<adhemerval.zanella@linaro.org> wrote:
>
>
>
> On 12/06/25 19:53, H.J. Lu wrote:
> > On Tue, Jun 10, 2025 at 8:01 PM H.J. Lu <hjl.tools@gmail.com> wrote:
> >>
> >> On Tue, Jun 10, 2025, 7:47 PM H. Peter Anvin <hpa@zytor.com> wrote:
> >>>
> >>> On 2025-06-09 14:25, H.J. Lu wrote:
> >>>> On Mon, Jun 9, 2025 at 1:47 PM H.J. Lu <hjl.tools@gmail.com> wrote:
> >>>>>
> >>>>> Compiler generates the following instruction sequence for dynamic TLS
> >>>>> access:
> >>>>>
> >>>>> leal tls_var@tlsgd(,%ebx,1), %eax
> >>>>> call ___tls_get_addr@PLT
> >>>>>
> >>>>> CALL instruction is transparent to compiler which assumes all registers,
> >>>>> except for EFLAGS, AX, CX, and DX, are unchanged after CALL.  But
> >>>>> ___tls_get_addr is a normal function which doesn't preserve any vector
> >>>>> registers.
> >>>>>
> >>>>> 1. Rename the generic __tls_get_addr function to ___tls_get_addr_internal.
> >>>>> 2. Change ___tls_get_addr to a wrapper function with implementations for
> >>>>> FNSAVE, FXSAVE, XSAVE and XSAVEC to save and restore all vector registers.
> >>>>> 3. dl-tlsdesc-dynamic.h:
> >>>>>
> >>>
> >>> Would it not make more sense to build this functon with
> >>> -mgeneral-regs-only? There doesn't seem to be any reason for this
> >>> function to use vector registers, and that's a huge overhead.
> >>
> >>
> >> It won't work since that function calls other functions.
> >> In my test included in my patch, malloc is called, which uses vector registers.
> >
> > Here is the v3 patch.  Changes are
> >
> > 1. Define DL_RUNTIME_RESOLVE_REALIGN_STACK in sysdeps/x86/sysdep.h.
> > 2. Add
> >
> > +ifneq (no,$(have-test-mtls-traditional))
> >  CFLAGS-tst-tls23-mod.c += -mtls-dialect=$(have-test-mtls-traditional)
> > +endif
>
> On the weekly call during patchwork status, we noted that only the first
> version of this patch was registered [1].
>
> So I think it would be better to send possible newer versions in its own
> thread and as inline to 1. make patchwork to proper register and trigger
> CI (since this version also fixes the aarch64 regression on v1) and to
> make it review easier (since on some email client attachments are not
> readily added in the reply message).
>
> [1] https://patchwork.sourceware.org/project/glibc/patch/CAMe9rOrYHrH91_qTB5e4kdWxdgamaCf19BCaSeVpuzV0R=8i=A@mail.gmail.com/
>
> > > From 48ca104d680cdcc782e6ba26d4c0f4b146fb2e7f Mon Sep 17 00:00:00 2001
> > From: "H.J. Lu" <hjl.tools@gmail.com>
> > Date: Mon, 9 Jun 2025 05:22:10 +0800
> > Subject: [PATCH v3] i386: Update ___tls_get_addr to preserve vector registers
> >
> > Compiler generates the following instruction sequence for dynamic TLS
> > access:
> >
> >       leal    tls_var@tlsgd(,%ebx,1), %eax
> >       call    ___tls_get_addr@PLT
> >
> > CALL instruction is transparent to compiler which assumes all registers,
> > except for EFLAGS, AX, CX, and DX, are unchanged after CALL.  But
> > ___tls_get_addr is a normal function which doesn't preserve any vector
> > registers.
>
> So if I understand correctly re-reading the TLS ABI documents, the
> ___tls_get_addr is the GNU variant that has a slight different calling
> convention than the double score __tls_get_addr (SUN variantion), where
> the GNU is as defined with __attribute__ ((regparam (1))).  And that's
> why also x86_64 is not affected by this very issue (since it always
> used __tls_get_addr, which follows the usual ABI convention).
>
> Just a minor nit below (line too long), but the rest looks ok.  There is
> not regression on aarch64, arm, or loongarch (all the other ABI that
> support TLS ABI variant).
>
> Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>
>
> >
> > 1. Rename the generic __tls_get_addr function to ___tls_get_addr_internal.
> > 2. Change ___tls_get_addr to a wrapper function with implementations for
> > FNSAVE, FXSAVE, XSAVE and XSAVEC to save and restore all vector registers.
> > 3. dl-tlsdesc-dynamic.h has:
> >
> > _dl_tlsdesc_dynamic:
> >       /* Like all TLS resolvers, preserve call-clobbered registers.
> >          We need two scratch regs anyway.  */
> >       subl    $32, %esp
> >       cfi_adjust_cfa_offset (32)
> >
> > It is wrong to use
> >
> >       movl    %ebx, -28(%esp)
> >       movl    %esp, %ebx
> >       cfi_def_cfa_register(%ebx)
> >       ...
> >       mov     %ebx, %esp
> >       cfi_def_cfa_register(%esp)
> >       movl    -28(%esp), %ebx
> >
> > to preserve EBX on stack.  Fix it with:
> >
> >       movl    %ebx, 28(%esp)
> >       movl    %esp, %ebx
> >       cfi_def_cfa_register(%ebx)
> >       ...
> >       mov     %ebx, %esp
> >       cfi_def_cfa_register(%esp)
> >       movl    28(%esp), %ebx
> >
> > 4. Update _dl_tlsdesc_dynamic to call ___tls_get_addr_internal directly.
> > 5. Add have-test-mtls-traditional to compile tst-tls23-mod.c with
> > traditional TLS variant to verify the fix.
> > 6. Define DL_RUNTIME_RESOLVE_REALIGN_STACK in sysdeps/x86/sysdep.h.
> >
> > This fixes BZ #32996.
> >
> > Signed-off-by: H.J. Lu <hjl.tools@gmail.com>
> > ---
> >  configure                                     |  38 ++++++
> >  configure.ac                                  |  13 ++
> >  elf/Makefile                                  |   9 ++
> >  elf/tst-tls23-mod.c                           |  32 +++++
> >  elf/tst-tls23.c                               | 106 +++++++++++++++
> >  .../dl-trampoline-save.h => elf/tst-tls23.h   |  34 +++--
> >  sysdeps/aarch64/preconfigure                  |   1 +
> >  sysdeps/i386/Makefile                         |   7 +-
> >  sysdeps/i386/dl-tls-get-addr.c                |  68 ++++++++++
> >  sysdeps/i386/dl-tls.h                         |  28 +---
> >  sysdeps/i386/dl-tlsdesc-dynamic.h             | 108 +--------------
> >  sysdeps/i386/dl-tlsdesc.S                     |  17 ---
> >  sysdeps/i386/tls-get-addr-wrapper.h           | 126 ++++++++++++++++++
> >  sysdeps/i386/tls-get-addr.S                   |  57 ++++++++
> >  sysdeps/i386/tls-get-addr.h                   |  42 ++++++
> >  sysdeps/loongarch/preconfigure                |   1 +
> >  sysdeps/loongarch/preconfigure.ac             |   1 +
> >  sysdeps/x86/Makefile                          |   8 ++
> >  sysdeps/x86/sysdep.h                          |  23 ++++
> >  sysdeps/x86/tst-tls23.c                       |  22 +++
> >  sysdeps/x86/tst-tls23.h                       |  35 +++++
> >  sysdeps/x86_64/dl-tlsdesc.S                   |   1 -
> >  sysdeps/x86_64/dl-trampoline.S                |   1 -
> >  23 files changed, 613 insertions(+), 165 deletions(-)
> >  create mode 100644 elf/tst-tls23-mod.c
> >  create mode 100644 elf/tst-tls23.c
> >  rename sysdeps/x86_64/dl-trampoline-save.h => elf/tst-tls23.h (52%)
> >  create mode 100644 sysdeps/i386/dl-tls-get-addr.c
> >  create mode 100644 sysdeps/i386/tls-get-addr-wrapper.h
> >  create mode 100644 sysdeps/i386/tls-get-addr.S
> >  create mode 100644 sysdeps/i386/tls-get-addr.h
> >  create mode 100644 sysdeps/x86/tst-tls23.c
> >  create mode 100644 sysdeps/x86/tst-tls23.h
> >
> > diff --git a/configure b/configure
> > index efc9203dda..53f7d1fce8 100755
> > --- a/configure
> > +++ b/configure
> > @@ -4931,6 +4931,9 @@ with_fp_cond=1
> >  # A preconfigure script may define another name to TLS descriptor variant
> >  mtls_descriptor=gnu2
> >
> > +# A preconfigure script may define another name to traditional TLS variant
> > +mtls_traditional=gnu
> > +
> >  if frags=`ls -d $srcdir/sysdeps/*/preconfigure 2> /dev/null`
> >  then
> >    { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for sysdeps preconfigure fragments" >&5
> > @@ -7490,6 +7493,41 @@ rm -f conftest*
> >  config_vars="$config_vars
> >  have-test-mtls-descriptor = $libc_cv_test_mtls_descriptor"
> >
> > +
> > +cat > conftest.c <<EOF
> > +$conftest_code
> > +EOF
> > +
> > +saved_CC="$CC"
> > +CC="$TEST_CC"
> > +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for traditional tls support in testing" >&5
> > +printf %s "checking for traditional tls support in testing... " >&6; }
> > +if test ${libc_cv_test_mtls_traditional+y}
> > +then :
> > +  printf %s "(cached) " >&6
> > +else case e in #(
> > +  e)     if { ac_try='${CC-cc} $CFLAGS $CPPFLAGS -fPIC -mtls-dialect=$mtls_traditional -nostdlib -nostartfiles -shared conftest.c -o conftest 1>&5'
> > +  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
> > +  (eval $ac_try) 2>&5
> > +  ac_status=$?
> > +  printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
> > +  test $ac_status = 0; }; }
> > +    then
> > +      libc_cv_test_mtls_traditional=$mtls_traditional
> > +    else
> > +      libc_cv_test_mtls_traditional=no
> > +    fi ;;
> > +esac
> > +fi
> > +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $libc_cv_test_mtls_traditional" >&5
> > +printf "%s\n" "$libc_cv_test_mtls_traditional" >&6; }
> > +
> > +CC="$saved_CC"
> > +
> > +rm -f conftest*
> > +config_vars="$config_vars
> > +have-test-mtls-traditional = $libc_cv_test_mtls_traditional"
> > +
> >  conftest_code="
> >  void __foo (void)
> >  {
> > diff --git a/configure.ac b/configure.ac
> > index 6d00b473e8..09d2ab721c 100644
> > --- a/configure.ac
> > +++ b/configure.ac
> > @@ -483,6 +483,9 @@ with_fp_cond=1
> >  # A preconfigure script may define another name to TLS descriptor variant
> >  mtls_descriptor=gnu2
> >
> > +# A preconfigure script may define another name to traditional TLS variant
> > +mtls_traditional=gnu
> > +
> >  dnl Let sysdeps/*/preconfigure act here.
> >  LIBC_PRECONFIGURE([$srcdir], [for sysdeps])
> >
> > @@ -1401,6 +1404,16 @@ LIBC_TRY_TEST_CC_COMMAND([for tls descriptor support],
> >  LIBC_CONFIG_VAR([have-test-mtls-descriptor],
> >               [$libc_cv_test_mtls_descriptor])
> >
> > +dnl Check if TEST_CC support traditional tls.
> > +LIBC_TRY_TEST_CC_COMMAND([for traditional tls support],
> > +  [$conftest_code],
> > +  [-fPIC -mtls-dialect=$mtls_traditional -nostdlib -nostartfiles -shared],
> > +  libc_cv_test_mtls_traditional,
> > +  [libc_cv_test_mtls_traditional=$mtls_traditional],
> > +  [libc_cv_test_mtls_traditional=no])
> > +LIBC_CONFIG_VAR([have-test-mtls-traditional],
> > +             [$libc_cv_test_mtls_traditional])
> > +
> >  dnl clang emits an warning for a double alias redirection, to warn the
> >  dnl original symbol is sed even when weak definition overrides it.
> >  dnl It is a usual pattern for weak_alias, where multiple alias point to
>
> Ok.
>
> > diff --git a/elf/Makefile b/elf/Makefile
> > index 362523ff11..05a78dc9a5 100644
> > --- a/elf/Makefile
> > +++ b/elf/Makefile
> > @@ -496,6 +496,7 @@ tests += \
> >    tst-tls21 \
> >    tst-tls22 \
> >    tst-tls22-gnu2 \
> > +  tst-tls23 \
> >    tst-tlsalign \
> >    tst-tlsalign-extern \
> >    tst-tlsgap \
> > @@ -1023,6 +1024,7 @@ modules-names += \
> >    tst-tls22-mod1-gnu2 \
> >    tst-tls22-mod2 \
> >    tst-tls22-mod2-gnu2 \
> > +  tst-tls23-mod \
> >    tst-tlsalign-lib \
> >    tst-tlsgap-mod0 \
> >    tst-tlsgap-mod1 \
> > @@ -3410,6 +3412,13 @@ tst-tls22-mod1-gnu2.so-no-z-defs = yes
> >  tst-tls22-mod2.so-no-z-defs = yes
> >  tst-tls22-mod2-gnu2.so-no-z-defs = yes
> >
> > +$(objpfx)tst-tls23: $(shared-thread-library)
> > +$(objpfx)tst-tls23.out: $(objpfx)tst-tls23-mod.so
> > +
> > +ifneq (no,$(have-test-mtls-traditional))
> > +CFLAGS-tst-tls23-mod.c += -mtls-dialect=$(have-test-mtls-traditional)
> > +endif
> > +
> >  ifeq ($(have-test-cc-cflags-fsemantic-interposition),yes)
> >  # Compiler may default to -fno-semantic-interposition.  These modules
> >  # must be compiled with -fsemantic-interposition.
>
> Ok.
>
> > diff --git a/elf/tst-tls23-mod.c b/elf/tst-tls23-mod.c
> > new file mode 100644
> > index 0000000000..3ee4c70e40
> > --- /dev/null
> > +++ b/elf/tst-tls23-mod.c
> > @@ -0,0 +1,32 @@
> > +/* DSO used by tst-tls23.
> > +   Copyright (C) 2025 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 <tst-tls23.h>
> > +
> > +__thread struct tls tls_var0 __attribute__ ((visibility ("hidden")));
> > +
> > +struct tls *
> > +apply_tls (struct tls *p)
> > +{
> > +  INIT_TLS_CALL ();
> > +  BEFORE_TLS_CALL ();
> > +  tls_var0 = *p;
> > +  struct tls *ret = &tls_var0;
> > +  AFTER_TLS_CALL ();
> > +  return ret;
> > +}
> > diff --git a/elf/tst-tls23.c b/elf/tst-tls23.c
> > new file mode 100644
> > index 0000000000..afe594c067
> > --- /dev/null
> > +++ b/elf/tst-tls23.c
> > @@ -0,0 +1,106 @@
> > +/* Test that __tls_get_addr preserves caller-saved registers.
> > +   Copyright (C) 2025 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
> > +   <http://www.gnu.org/licenses/>.  */
> > +
> > +#include <stdio.h>
> > +#include <stdlib.h>
> > +#include <string.h>
> > +#include <dlfcn.h>
> > +#include <pthread.h>
> > +#include <support/xdlfcn.h>
> > +#include <support/xthread.h>
> > +#include <support/check.h>
> > +#include <support/test-driver.h>
> > +#include <tst-tls23.h>
> > +
> > +#ifndef IS_SUPPORTED
> > +# define IS_SUPPORTED() true
> > +#endif
> > +
> > +/* An architecture can define it to clobber caller-saved registers in
> > +   malloc below to verify that __tls_get_addr won't change caller-saved
> > +   registers.  */
> > +#ifndef PREPARE_MALLOC
> > +# define PREPARE_MALLOC()
> > +#endif
> > +
> > +extern void * __libc_malloc (size_t);
> > +
> > +size_t malloc_counter = 0;
> > +
> > +void *
> > +malloc (size_t n)
> > +{
> > +  PREPARE_MALLOC ();
> > +  malloc_counter++;
> > +  return __libc_malloc (n);
> > +}
> > +
> > +static void *mod;
> > +static const char *modname = "tst-tls23-mod.so";
> > +
> > +static void
> > +open_mod (void)
> > +{
> > +  mod = xdlopen (modname, RTLD_LAZY);
> > +  printf ("open %s\n", modname);
> > +}
> > +
> > +static void
> > +close_mod (void)
> > +{
> > +  xdlclose (mod);
> > +  mod = NULL;
> > +  printf ("close %s\n", modname);
> > +}
> > +
> > +static void
> > +access_mod (const char *sym)
> > +{
> > +  struct tls var = { -4, -4, -4, -4 };
> > +  struct tls *(*f) (struct tls *) = xdlsym (mod, sym);
> > +  /* Check that our malloc is called.  */
> > +  malloc_counter = 0;
> > +  struct tls *p = f (&var);
> > +  TEST_VERIFY (malloc_counter != 0);
> > +  printf ("access %s: %s() = %p\n", modname, sym, p);
> > +  TEST_VERIFY_EXIT (memcmp (p, &var, sizeof (var)) == 0);
> > +  ++(p->a);
> > +}
> > +
> > +static void *
> > +start (void *arg)
> > +{
> > +  access_mod ("apply_tls");
> > +  return arg;
> > +}
> > +
> > +static int
> > +do_test (void)
> > +{
> > +  if (!IS_SUPPORTED ())
> > +    return EXIT_UNSUPPORTED;
> > +
> > +  open_mod ();
> > +  pthread_t t = xpthread_create (NULL, start, NULL);
> > +  xpthread_join (t);
> > +  close_mod ();
> > +
> > +  return 0;
> > +}
> > +
> > +#include <support/test-driver.c>
>
> Ok.
>
> > diff --git a/sysdeps/x86_64/dl-trampoline-save.h b/elf/tst-tls23.h
> > similarity index 52%
> > rename from sysdeps/x86_64/dl-trampoline-save.h
> > rename to elf/tst-tls23.h
> > index 761128d980..d0e734569c 100644
> > --- a/sysdeps/x86_64/dl-trampoline-save.h
> > +++ b/elf/tst-tls23.h
> > @@ -1,5 +1,5 @@
> > -/* x86-64 PLT trampoline register save macros.
> > -   Copyright (C) 2024-2025 Free Software Foundation, Inc.
> > +/* Test that __tls_get_addr preserves caller-saved registers.
> > +   Copyright (C) 2025 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
> > @@ -16,19 +16,25 @@
> >     License along with the GNU C Library; if not, see
> >     <https://www.gnu.org/licenses/>.  */
> >
> > -#ifndef DL_STACK_ALIGNMENT
> > -/* Due to GCC bug:
> > +#include <stdint.h>
> >
> > -   https://gcc.gnu.org/bugzilla/show_bug.cgi?id=58066
> > +struct tls
> > +{
> > +  int64_t a, b, c, d;
> > +};
> >
> > -   __tls_get_addr may be called with 8-byte stack alignment.  Although
> > -   this bug has been fixed in GCC 4.9.4, 5.3 and 6, we can't assume
> > -   that stack will be always aligned at 16 bytes.  */
> > -# define DL_STACK_ALIGNMENT 8
> > +extern struct tls *apply_tls (struct tls *);
> > +
> > +/* An architecture can define them to verify that caller-saved registers
> > +   aren't changed by __tls_get_addr.  */
> > +#ifndef INIT_TLS_CALL
> > +# define INIT_TLS_CALL()
> > +#endif
> > +
> > +#ifndef BEFORE_TLS_CALL
> > +# define BEFORE_TLS_CALL()
> >  #endif
> >
> > -/* True if _dl_runtime_resolve should align stack for STATE_SAVE or align
> > -   stack to 16 bytes before calling _dl_fixup.  */
> > -#define DL_RUNTIME_RESOLVE_REALIGN_STACK \
> > -  (STATE_SAVE_ALIGNMENT > DL_STACK_ALIGNMENT \
> > -   || 16 > DL_STACK_ALIGNMENT)
> > +#ifndef AFTER_TLS_CALL
> > +# define AFTER_TLS_CALL()
> > +#endif
>
> Ok.
>
> > diff --git a/sysdeps/aarch64/preconfigure b/sysdeps/aarch64/preconfigure
> > index 19657b627b..e1b772c586 100644
> > --- a/sysdeps/aarch64/preconfigure
> > +++ b/sysdeps/aarch64/preconfigure
> > @@ -3,5 +3,6 @@ aarch64*)
> >       base_machine=aarch64
> >       machine=aarch64
> >       mtls_descriptor=desc
> > +     mtls_traditional=trad
> >       ;;
> >  esac
> > diff --git a/sysdeps/i386/Makefile b/sysdeps/i386/Makefile
> > index a2e8c0b128..87f113eca1 100644
> > --- a/sysdeps/i386/Makefile
> > +++ b/sysdeps/i386/Makefile
> > @@ -30,7 +30,12 @@ stack-align-test-flags += -malign-double
> >  endif
> >
> >  ifeq ($(subdir),elf)
> > -sysdep-dl-routines += tlsdesc dl-tlsdesc
> > +sysdep-dl-routines += \
> > +  dl-tls-get-addr \
> > +  dl-tlsdesc \
> > +  tls-get-addr \
> > +  tlsdesc \
> > +# sysdep-dl-routines
> >
> >  tests += tst-audit3
> >  modules-names += tst-auditmod3a tst-auditmod3b
>
> I think you can move dl-tlsdesc, tls-get-addr, and tlsdesc to sysdep/x86/Makefile.

Fixed.

> > diff --git a/sysdeps/i386/dl-tls-get-addr.c b/sysdeps/i386/dl-tls-get-addr.c
> > new file mode 100644
> > index 0000000000..c97e5c57be
> > --- /dev/null
> > +++ b/sysdeps/i386/dl-tls-get-addr.c
> > @@ -0,0 +1,68 @@
> > +/* Ifunc selector for ___tls_get_addr.
> > +   Copyright (C) 2025 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 SHARED
> > +# define ___tls_get_addr __redirect____tls_get_addr
> > +# include <dl-tls.h>
> > +# undef ___tls_get_addr
> > +# undef __tls_get_addr
> > +
> > +# define SYMBOL_NAME ___tls_get_addr
> > +# include <init-arch.h>
> > +
> > +extern __typeof (REDIRECT_NAME) OPTIMIZE (fnsave) attribute_hidden;
> > +extern __typeof (REDIRECT_NAME) OPTIMIZE (fxsave) attribute_hidden;
> > +extern __typeof (REDIRECT_NAME) OPTIMIZE (xsave) attribute_hidden;
> > +extern __typeof (REDIRECT_NAME) OPTIMIZE (xsavec) attribute_hidden;
> > +
> > +static inline void *
> > +IFUNC_SELECTOR (void)
> > +{
> > +  const struct cpu_features* cpu_features = __get_cpu_features ();
> > +
> > +  if (cpu_features->xsave_state_size != 0)
> > +    {
> > +      if (CPU_FEATURE_USABLE_P (cpu_features, XSAVEC))
> > +     return OPTIMIZE (xsavec);
> > +      else
> > +     return OPTIMIZE (xsave);
> > +    }
> > +  else if (CPU_FEATURE_USABLE_P (cpu_features, FXSR))
> > +    return OPTIMIZE (fxsave);
> > +  return OPTIMIZE (fnsave);
> > +}
> > +
> > +libc_ifunc_redirected (__redirect____tls_get_addr, ___tls_get_addr,
> > +                    IFUNC_SELECTOR ());
> > +
> > +/* The special thing about the x86 TLS ABI is that we have two
> > +   variants of the __tls_get_addr function with different calling
> > +   conventions.  The GNU version, which we are mostly concerned here,
> > +   takes the parameter in a register.  The name is changed by adding
> > +   an additional underscore at the beginning.  The Sun version uses
> > +   the normal calling convention.  */
> > +
> > +rtld_hidden_proto (___tls_get_addr)
> > +rtld_hidden_def (___tls_get_addr)
> > +
> > +void *
> > +__tls_get_addr (tls_index *ti)
> > +{
> > +  return ___tls_get_addr (ti);
> > +}
> > +#endif
>
> Ok.
>
> > diff --git a/sysdeps/i386/dl-tls.h b/sysdeps/i386/dl-tls.h
> > index f453931d78..ef605c5b0d 100644
> > --- a/sysdeps/i386/dl-tls.h
> > +++ b/sysdeps/i386/dl-tls.h
> > @@ -37,34 +37,14 @@ typedef struct dl_tls_index
> >  /* This is the prototype for the GNU version.  */
> >  extern void *___tls_get_addr (tls_index *ti)
> >       __attribute__ ((__regparm__ (1)));
> > -extern void *___tls_get_addr_internal (tls_index *ti)
> > -     __attribute__ ((__regparm__ (1))) attribute_hidden;
> > -
> >  # if IS_IN (rtld)
> > -/* The special thing about the x86 TLS ABI is that we have two
> > -   variants of the __tls_get_addr function with different calling
> > -   conventions.  The GNU version, which we are mostly concerned here,
> > -   takes the parameter in a register.  The name is changed by adding
> > -   an additional underscore at the beginning.  The Sun version uses
> > -   the normal calling convention.  */
> > -void *
> > -__tls_get_addr (tls_index *ti)
> > -{
> > -  return ___tls_get_addr_internal (ti);
> > -}
> > -
> > -
> >  /* Prepare using the definition of __tls_get_addr in the generic
> >     version of this file.  */
> > -# define __tls_get_addr __attribute__ ((__regparm__ (1))) ___tls_get_addr
> > -strong_alias (___tls_get_addr, ___tls_get_addr_internal)
> > -rtld_hidden_proto (___tls_get_addr)
> > -rtld_hidden_def (___tls_get_addr)
> > -#else
> > -
> > +# define __tls_get_addr \
> > +    __attribute__ ((__regparm__ (1))) ___tls_get_addr_internal
> > +# else
> >  /* Users should get the better interface.  */
> > -# define __tls_get_addr ___tls_get_addr
> > -
> > +#  define __tls_get_addr ___tls_get_addr
> >  # endif
> >  #endif
> >
>
> Ok.
>
> > diff --git a/sysdeps/i386/dl-tlsdesc-dynamic.h b/sysdeps/i386/dl-tlsdesc-dynamic.h
> > index 6aec06d15c..be9ecd659b 100644
> > --- a/sysdeps/i386/dl-tlsdesc-dynamic.h
> > +++ b/sysdeps/i386/dl-tlsdesc-dynamic.h
> > @@ -16,34 +16,6 @@
> >     License along with the GNU C Library; if not, see
> >     <https://www.gnu.org/licenses/>.  */
> >
> > -#undef REGISTER_SAVE_AREA
> > -
> > -#if !defined USE_FNSAVE && (STATE_SAVE_ALIGNMENT % 16) != 0
> > -# error STATE_SAVE_ALIGNMENT must be multiple of 16
> > -#endif
> > -
> > -#if DL_RUNTIME_RESOLVE_REALIGN_STACK
> > -# ifdef USE_FNSAVE
> > -#  error USE_FNSAVE shouldn't be defined
> > -# endif
> > -# ifdef USE_FXSAVE
> > -/* Use fxsave to save all registers.  */
> > -#  define REGISTER_SAVE_AREA 512
> > -# endif
> > -#else
> > -# ifdef USE_FNSAVE
> > -/* Use fnsave to save x87 FPU stack registers.  */
> > -#  define REGISTER_SAVE_AREA 108
> > -# else
> > -#  ifndef USE_FXSAVE
> > -#   error USE_FXSAVE must be defined
> > -#  endif
> > -/* Use fxsave to save all registers.  Add 12 bytes to align the stack
> > -   to 16 bytes.  */
> > -#  define REGISTER_SAVE_AREA (512 + 12)
> > -# endif
> > -#endif
> > -
> >       .hidden _dl_tlsdesc_dynamic
> >       .global _dl_tlsdesc_dynamic
> >       .type   _dl_tlsdesc_dynamic,@function
> > @@ -104,85 +76,7 @@ _dl_tlsdesc_dynamic:
> >       ret
> >       .p2align 4,,7
> >  2:
> > -     cfi_adjust_cfa_offset (32)
> > -#if DL_RUNTIME_RESOLVE_REALIGN_STACK
> > -     movl    %ebx, -28(%esp)
> > -     movl    %esp, %ebx
> > -     cfi_def_cfa_register(%ebx)
> > -     and     $-STATE_SAVE_ALIGNMENT, %esp
> > -#endif
> > -#ifdef REGISTER_SAVE_AREA
> > -     subl    $REGISTER_SAVE_AREA, %esp
> > -# if !DL_RUNTIME_RESOLVE_REALIGN_STACK
> > -     cfi_adjust_cfa_offset(REGISTER_SAVE_AREA)
> > -# endif
> > -#else
> > -# if !DL_RUNTIME_RESOLVE_REALIGN_STACK
> > -#  error DL_RUNTIME_RESOLVE_REALIGN_STACK must be true
> > -# endif
> > -     /* Allocate stack space of the required size to save the state.  */
> > -     LOAD_PIC_REG (cx)
> > -     subl    RTLD_GLOBAL_RO_DL_X86_CPU_FEATURES_OFFSET+XSAVE_STATE_SIZE_OFFSET+_rtld_local_ro@GOTOFF(%ecx), %esp
> > -#endif
> > -#ifdef USE_FNSAVE
> > -     fnsave  (%esp)
> > -#elif defined USE_FXSAVE
> > -     fxsave  (%esp)
> > -#else
> > -     /* Save the argument for ___tls_get_addr in EAX.  */
> > -     movl    %eax, %ecx
> > -     movl    $TLSDESC_CALL_STATE_SAVE_MASK, %eax
> > -     xorl    %edx, %edx
> > -     /* Clear the XSAVE Header.  */
> > -# ifdef USE_XSAVE
> > -     movl    %edx, (512)(%esp)
> > -     movl    %edx, (512 + 4 * 1)(%esp)
> > -     movl    %edx, (512 + 4 * 2)(%esp)
> > -     movl    %edx, (512 + 4 * 3)(%esp)
> > -# endif
> > -     movl    %edx, (512 + 4 * 4)(%esp)
> > -     movl    %edx, (512 + 4 * 5)(%esp)
> > -     movl    %edx, (512 + 4 * 6)(%esp)
> > -     movl    %edx, (512 + 4 * 7)(%esp)
> > -     movl    %edx, (512 + 4 * 8)(%esp)
> > -     movl    %edx, (512 + 4 * 9)(%esp)
> > -     movl    %edx, (512 + 4 * 10)(%esp)
> > -     movl    %edx, (512 + 4 * 11)(%esp)
> > -     movl    %edx, (512 + 4 * 12)(%esp)
> > -     movl    %edx, (512 + 4 * 13)(%esp)
> > -     movl    %edx, (512 + 4 * 14)(%esp)
> > -     movl    %edx, (512 + 4 * 15)(%esp)
> > -# ifdef USE_XSAVE
> > -     xsave   (%esp)
> > -# else
> > -     xsavec  (%esp)
> > -# endif
> > -     /* Restore the argument for ___tls_get_addr in EAX.  */
> > -     movl    %ecx, %eax
> > -#endif
> > -     call    HIDDEN_JUMPTARGET (___tls_get_addr)
> > -     /* Get register content back.  */
> > -#ifdef USE_FNSAVE
> > -     frstor  (%esp)
> > -#elif defined USE_FXSAVE
> > -     fxrstor (%esp)
> > -#else
> > -     /* Save and retore ___tls_get_addr return value stored in EAX.  */
> > -     movl    %eax, %ecx
> > -     movl    $TLSDESC_CALL_STATE_SAVE_MASK, %eax
> > -     xorl    %edx, %edx
> > -     xrstor  (%esp)
> > -     movl    %ecx, %eax
> > -#endif
> > -#if DL_RUNTIME_RESOLVE_REALIGN_STACK
> > -     mov     %ebx, %esp
> > -     cfi_def_cfa_register(%esp)
> > -     movl    -28(%esp), %ebx
> > -     cfi_restore(%ebx)
> > -#else
> > -     addl    $REGISTER_SAVE_AREA, %esp
> > -     cfi_adjust_cfa_offset(-REGISTER_SAVE_AREA)
> > -#endif
> > +#include "tls-get-addr-wrapper.h"
> >       jmp     1b
> >       cfi_endproc
> >       .size   _dl_tlsdesc_dynamic, .-_dl_tlsdesc_dynamic
>
> Ok.
>
> > diff --git a/sysdeps/i386/dl-tlsdesc.S b/sysdeps/i386/dl-tlsdesc.S
> > index c080993a60..c914ca4220 100644
> > --- a/sysdeps/i386/dl-tlsdesc.S
> > +++ b/sysdeps/i386/dl-tlsdesc.S
> > @@ -22,23 +22,6 @@
> >  #include <features-offsets.h>
> >  #include "tlsdesc.h"
> >
> > -#ifndef DL_STACK_ALIGNMENT
> > -/* Due to GCC bug:
> > -
> > -   https://gcc.gnu.org/bugzilla/show_bug.cgi?id=58066
> > -
> > -   __tls_get_addr may be called with 4-byte stack alignment.  Although
> > -   this bug has been fixed in GCC 4.9.4, 5.3 and 6, we can't assume
> > -   that stack will be always aligned at 16 bytes.  */
> > -# define DL_STACK_ALIGNMENT 4
> > -#endif
> > -
> > -/* True if _dl_tlsdesc_dynamic should align stack for STATE_SAVE or align
> > -   stack to MINIMUM_ALIGNMENT bytes before calling ___tls_get_addr.  */
> > -#define DL_RUNTIME_RESOLVE_REALIGN_STACK \
> > -  (STATE_SAVE_ALIGNMENT > DL_STACK_ALIGNMENT \
> > -   || MINIMUM_ALIGNMENT > DL_STACK_ALIGNMENT)
> > -
> >       .text
> >
> >       /* This function is used to compute the TP offset for symbols in
>
>
> Ok.
>
> > diff --git a/sysdeps/i386/tls-get-addr-wrapper.h b/sysdeps/i386/tls-get-addr-wrapper.h
> > new file mode 100644
> > index 0000000000..cb05c6d1c5
> > --- /dev/null
> > +++ b/sysdeps/i386/tls-get-addr-wrapper.h
> > @@ -0,0 +1,126 @@
> > +/* Wrapper of i386 ___tls_get_addr to save and restore vector registers.
> > +   Copyright (C) 2025 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/>.  */
> > +
> > +#undef REGISTER_SAVE_AREA
> > +
> > +#if !defined USE_FNSAVE && (STATE_SAVE_ALIGNMENT % 16) != 0
> > +# error STATE_SAVE_ALIGNMENT must be multiple of 16
> > +#endif
> > +
> > +#if DL_RUNTIME_RESOLVE_REALIGN_STACK
> > +# ifdef USE_FNSAVE
> > +#  error USE_FNSAVE shouldn't be defined
> > +# endif
> > +# ifdef USE_FXSAVE
> > +/* Use fxsave to save all registers.  */
> > +#  define REGISTER_SAVE_AREA 512
> > +# endif
> > +#else
> > +# ifdef USE_FNSAVE
> > +/* Use fnsave to save x87 FPU stack registers.  */
> > +#  define REGISTER_SAVE_AREA 108
> > +# else
> > +#  ifndef USE_FXSAVE
> > +#   error USE_FXSAVE must be defined
> > +#  endif
> > +/* Use fxsave to save all registers.  Add 12 bytes to align the stack
> > +   to 16 bytes.  */
> > +#  define REGISTER_SAVE_AREA (512 + 12)
> > +# endif
> > +#endif
> > +
> > +#if DL_RUNTIME_RESOLVE_REALIGN_STACK
> > +     movl    %ebx, 28(%esp)
> > +     movl    %esp, %ebx
> > +     cfi_def_cfa_register(%ebx)
> > +     and     $-STATE_SAVE_ALIGNMENT, %esp
> > +#endif
> > +#ifdef REGISTER_SAVE_AREA
> > +     subl    $REGISTER_SAVE_AREA, %esp
> > +# if !DL_RUNTIME_RESOLVE_REALIGN_STACK
> > +     cfi_adjust_cfa_offset(REGISTER_SAVE_AREA)
> > +# endif
> > +#else
> > +# if !DL_RUNTIME_RESOLVE_REALIGN_STACK
> > +#  error DL_RUNTIME_RESOLVE_REALIGN_STACK must be true
> > +# endif
> > +     /* Allocate stack space of the required size to save the state.  */
> > +     LOAD_PIC_REG (cx)
> > +     subl    RTLD_GLOBAL_RO_DL_X86_CPU_FEATURES_OFFSET+XSAVE_STATE_SIZE_OFFSET+_rtld_local_ro@GOTOFF(%ecx), %esp
>
> Line too long.

Fixed.

> > +#endif
> > +#ifdef USE_FNSAVE
> > +     fnsave  (%esp)
> > +#elif defined USE_FXSAVE
> > +     fxsave  (%esp)
> > +#else
> > +     /* Save the argument for ___tls_get_addr in EAX.  */
> > +     movl    %eax, %ecx
> > +     movl    $TLSDESC_CALL_STATE_SAVE_MASK, %eax
> > +     xorl    %edx, %edx
> > +     /* Clear the XSAVE Header.  */
> > +# ifdef USE_XSAVE
> > +     movl    %edx, (512)(%esp)
> > +     movl    %edx, (512 + 4 * 1)(%esp)
> > +     movl    %edx, (512 + 4 * 2)(%esp)
> > +     movl    %edx, (512 + 4 * 3)(%esp)
> > +# endif
> > +     movl    %edx, (512 + 4 * 4)(%esp)
> > +     movl    %edx, (512 + 4 * 5)(%esp)
> > +     movl    %edx, (512 + 4 * 6)(%esp)
> > +     movl    %edx, (512 + 4 * 7)(%esp)
> > +     movl    %edx, (512 + 4 * 8)(%esp)
> > +     movl    %edx, (512 + 4 * 9)(%esp)
> > +     movl    %edx, (512 + 4 * 10)(%esp)
> > +     movl    %edx, (512 + 4 * 11)(%esp)
> > +     movl    %edx, (512 + 4 * 12)(%esp)
> > +     movl    %edx, (512 + 4 * 13)(%esp)
> > +     movl    %edx, (512 + 4 * 14)(%esp)
> > +     movl    %edx, (512 + 4 * 15)(%esp)
> > +# ifdef USE_XSAVE
> > +     xsave   (%esp)
> > +# else
> > +     xsavec  (%esp)
> > +# endif
> > +     /* Restore the argument for ___tls_get_addr in EAX.  */
> > +     movl    %ecx, %eax
> > +#endif
> > +     call    ___tls_get_addr_internal
> > +     /* Get register content back.  */
> > +#ifdef USE_FNSAVE
> > +     frstor  (%esp)
> > +#elif defined USE_FXSAVE
> > +     fxrstor (%esp)
> > +#else
> > +     /* Save and retore ___tls_get_addr return value stored in EAX.  */
> > +     movl    %eax, %ecx
> > +     movl    $TLSDESC_CALL_STATE_SAVE_MASK, %eax
> > +     xorl    %edx, %edx
> > +     xrstor  (%esp)
> > +     movl    %ecx, %eax
> > +#endif
> > +#if DL_RUNTIME_RESOLVE_REALIGN_STACK
> > +     mov     %ebx, %esp
> > +     cfi_def_cfa_register(%esp)
> > +     movl    28(%esp), %ebx
> > +     cfi_restore(%ebx)
> > +#else
> > +     addl    $REGISTER_SAVE_AREA, %esp
> > +     cfi_adjust_cfa_offset(-REGISTER_SAVE_AREA)
> > +#endif
> > +
> > +#undef STATE_SAVE_ALIGNMENT
>
> Ok.
>
> > diff --git a/sysdeps/i386/tls-get-addr.S b/sysdeps/i386/tls-get-addr.S
> > new file mode 100644
> > index 0000000000..9b5d6532fc
> > --- /dev/null
> > +++ b/sysdeps/i386/tls-get-addr.S
> > @@ -0,0 +1,57 @@
> > +/* Thread-local storage handling in the ELF dynamic linker.  i386 version.
> > +   Copyright (C) 2025 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 <cpu-features-offsets.h>
> > +#include <features-offsets.h>
> > +
> > +     .text
> > +#ifdef SHARED
> > +# define USE_FNSAVE
> > +# define MINIMUM_ALIGNMENT   4
> > +# define STATE_SAVE_ALIGNMENT        4
> > +# define ___tls_get_addr     _____tls_get_addr_fnsave
> > +# include "tls-get-addr.h"
> > +# undef ___tls_get_addr
> > +# undef MINIMUM_ALIGNMENT
> > +# undef USE_FNSAVE
> > +
> > +# define MINIMUM_ALIGNMENT   16
> > +
> > +# define USE_FXSAVE
> > +# define STATE_SAVE_ALIGNMENT        16
> > +# define ___tls_get_addr     _____tls_get_addr_fxsave
> > +# include "tls-get-addr.h"
> > +# undef ___tls_get_addr
> > +# undef USE_FXSAVE
> > +
> > +# define USE_XSAVE
> > +# define STATE_SAVE_ALIGNMENT        64
> > +# define ___tls_get_addr     _____tls_get_addr_xsave
> > +# include "tls-get-addr.h"
> > +# undef ___tls_get_addr
> > +# undef USE_XSAVE
> > +
> > +# define USE_XSAVEC
> > +# define STATE_SAVE_ALIGNMENT        64
> > +# define ___tls_get_addr     _____tls_get_addr_xsavec
> > +# include "tls-get-addr.h"
> > +# undef ___tls_get_addr
> > +# undef USE_XSAVEC
> > +#endif /* SHARED */
>
> Ok.
>
> > diff --git a/sysdeps/i386/tls-get-addr.h b/sysdeps/i386/tls-get-addr.h
> > new file mode 100644
> > index 0000000000..1825798724
> > --- /dev/null
> > +++ b/sysdeps/i386/tls-get-addr.h
> > @@ -0,0 +1,42 @@
> > +/* Thread-local storage handling in the ELF dynamic linker.  i386 version.
> > +   Copyright (C) 2025 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/>.  */
> > +
> > +     .hidden ___tls_get_addr
> > +     .global ___tls_get_addr
> > +     .type   ___tls_get_addr,@function
> > +
> > +     /* This function is a wrapper of ___tls_get_addr_internal to
> > +        preserve caller-saved vector registers.  */
> > +
> > +     cfi_startproc
> > +     .align 16
> > +___tls_get_addr:
> > +     /* Like all TLS resolvers, preserve call-clobbered registers.
> > +        We need two scratch regs anyway.  */
> > +     subl    $32, %esp
> > +     cfi_adjust_cfa_offset (32)
> > +     movl    %ecx, 20(%esp)
> > +     movl    %edx, 24(%esp)
> > +#include "tls-get-addr-wrapper.h"
> > +     movl    20(%esp), %ecx
> > +     movl    24(%esp), %edx
> > +     addl    $32, %esp
> > +     cfi_adjust_cfa_offset (-32)
> > +     ret
> > +     cfi_endproc
> > +     .size   ___tls_get_addr, .-___tls_get_addr
>
> Ok.
>
> > diff --git a/sysdeps/loongarch/preconfigure b/sysdeps/loongarch/preconfigure
> > index 0d1e9ed8df..6726ab8302 100644
> > --- a/sysdeps/loongarch/preconfigure
> > +++ b/sysdeps/loongarch/preconfigure
> > @@ -44,6 +44,7 @@ loongarch*)
> >
> >      base_machine=loongarch
> >      mtls_descriptor=desc
> > +    mtls_traditional=trad
> >      ;;
> >  esac
> >
> > diff --git a/sysdeps/loongarch/preconfigure.ac b/sysdeps/loongarch/preconfigure.ac
> > index df07dbf41f..56402261df 100644
> > --- a/sysdeps/loongarch/preconfigure.ac
> > +++ b/sysdeps/loongarch/preconfigure.ac
> > @@ -42,6 +42,7 @@ loongarch*)
> >
> >      base_machine=loongarch
> >      mtls_descriptor=desc
> > +    mtls_traditional=trad
> >      ;;
> >  esac
> >
>
> Ok.
>
> > diff --git a/sysdeps/x86/Makefile b/sysdeps/x86/Makefile
> > index 01b0192ddf..9ff00717ce 100644
> > --- a/sysdeps/x86/Makefile
> > +++ b/sysdeps/x86/Makefile
> > @@ -113,6 +113,14 @@ $(objpfx)tst-gnu2-tls2-x86-noxsavexsavec.out: \
> >    $(objpfx)tst-gnu2-tls2mod0.so \
> >    $(objpfx)tst-gnu2-tls2mod1.so \
> >    $(objpfx)tst-gnu2-tls2mod2.so
> > +
> > +CFLAGS-tst-tls23.c += -msse2
> > +CFLAGS-tst-tls23-mod.c += -msse2 -mtune=haswell
> > +
> > +LDFLAGS-tst-tls23 += -rdynamic
> > +tst-tls23-mod.so-no-z-defs = yes
> > +
> > +$(objpfx)tst-tls23-mod.so: $(libsupport)
> >  endif
> >
> >  ifeq ($(subdir),math)
>
> Ok.
>
> > diff --git a/sysdeps/x86/sysdep.h b/sysdeps/x86/sysdep.h
> > index c3c73e75dd..b8e963b654 100644
> > --- a/sysdeps/x86/sysdep.h
> > +++ b/sysdeps/x86/sysdep.h
> > @@ -183,6 +183,29 @@
> >
> >  #define atom_text_section .section ".text.atom", "ax"
> >
> > +#ifndef DL_STACK_ALIGNMENT
> > +/* Due to GCC bug:
> > +
> > +   https://gcc.gnu.org/bugzilla/show_bug.cgi?id=58066
> > +
> > +   __tls_get_addr may be called with 8-byte/4-byte stack alignment.
> > +   Although this bug has been fixed in GCC 4.9.4, 5.3 and 6, we can't
> > +   assume that stack will be always aligned at 16 bytes.  */
> > +# ifdef __x86_64__
> > +#  define DL_STACK_ALIGNMENT 8
> > +#  define MINIMUM_ALIGNMENT 16
> > +# else
> > +#  define DL_STACK_ALIGNMENT 4
> > +# endif
> > +#endif
> > +
> > +/* True if _dl_runtime_resolve/_dl_tlsdesc_dynamic should align stack for
> > +   STATE_SAVE or align stack to MINIMUM_ALIGNMENT bytes before calling
> > +   _dl_fixup/__tls_get_addr.  */
> > +#define DL_RUNTIME_RESOLVE_REALIGN_STACK \
> > +  (STATE_SAVE_ALIGNMENT > DL_STACK_ALIGNMENT \
> > +   || MINIMUM_ALIGNMENT > DL_STACK_ALIGNMENT)
> > +
> >  #endif       /* __ASSEMBLER__ */
> >
> >  #endif       /* _X86_SYSDEP_H */
>
> Ok.
>
> > diff --git a/sysdeps/x86/tst-tls23.c b/sysdeps/x86/tst-tls23.c
> > new file mode 100644
> > index 0000000000..6130d91cf8
> > --- /dev/null
> > +++ b/sysdeps/x86/tst-tls23.c
> > @@ -0,0 +1,22 @@
> > +#ifndef __x86_64__
> > +#include <sys/platform/x86.h>
> > +
> > +#define IS_SUPPORTED() CPU_FEATURE_ACTIVE (SSE2)
> > +#endif
> > +
> > +/* Set XMM0...XMM7 to all 1s.  */
> > +#define PREPARE_MALLOC()                                     \
> > +{                                                            \
> > +  asm volatile ("pcmpeqd %%xmm0, %%xmm0" : : : "xmm0" );     \
> > +  asm volatile ("pcmpeqd %%xmm1, %%xmm1" : : : "xmm1" );     \
> > +  asm volatile ("pcmpeqd %%xmm2, %%xmm2" : : : "xmm2" );     \
> > +  asm volatile ("pcmpeqd %%xmm3, %%xmm3" : : : "xmm3" );     \
> > +  asm volatile ("pcmpeqd %%xmm4, %%xmm4" : : : "xmm4" );     \
> > +  asm volatile ("pcmpeqd %%xmm5, %%xmm5" : : : "xmm5" );     \
> > +  asm volatile ("pcmpeqd %%xmm6, %%xmm6" : : : "xmm6" );     \
> > +  asm volatile ("pcmpeqd %%xmm7, %%xmm7" : : : "xmm7" );     \
> > +}
> > +
> > +#include <elf/tst-tls23.c>
> > +
> > +v2di v1, v2, v3;
> > diff --git a/sysdeps/x86/tst-tls23.h b/sysdeps/x86/tst-tls23.h
> > new file mode 100644
> > index 0000000000..21cee4ca07
> > --- /dev/null
> > +++ b/sysdeps/x86/tst-tls23.h
> > @@ -0,0 +1,35 @@
> > +/* Test that __tls_get_addr preserves XMM registers.
> > +   Copyright (C) 2025 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 <support/check.h>
> > +
> > +typedef long long v2di __attribute__((vector_size(16)));
> > +extern v2di v1, v2, v3;
> > +
> > +#define BEFORE_TLS_CALL()                                    \
> > +  v1 = __extension__(v2di){0, 0};                            \
> > +  v2 = __extension__(v2di){0, 0};
> > +
> > +#define AFTER_TLS_CALL()                                     \
> > +  v3 = __extension__(v2di){0, 0};                            \
> > +  asm volatile ("" : "+x" (v3));                             \
> > +  union { v2di x; long long a[2]; } u;                               \
> > +  u.x = v3;                                                  \
> > +  TEST_VERIFY_EXIT (u.a[0] == 0 && u.a[1] == 0);
> > +
> > +#include <elf/tst-tls23.h>
> > diff --git a/sysdeps/x86_64/dl-tlsdesc.S b/sysdeps/x86_64/dl-tlsdesc.S
> > index d1bb125560..9a55fc52bb 100644
> > --- a/sysdeps/x86_64/dl-tlsdesc.S
> > +++ b/sysdeps/x86_64/dl-tlsdesc.S
> > @@ -22,7 +22,6 @@
> >  #include <features-offsets.h>
> >  #include <isa-level.h>
> >  #include "tlsdesc.h"
> > -#include "dl-trampoline-save.h"
> >
> >  /* Area on stack to save and restore registers used for parameter
> >     passing when calling _dl_tlsdesc_dynamic.  */
> > diff --git a/sysdeps/x86_64/dl-trampoline.S b/sysdeps/x86_64/dl-trampoline.S
> > index a055722e64..ac85f96794 100644
> > --- a/sysdeps/x86_64/dl-trampoline.S
> > +++ b/sysdeps/x86_64/dl-trampoline.S
> > @@ -22,7 +22,6 @@
> >  #include <features-offsets.h>
> >  #include <link-defines.h>
> >  #include <isa-level.h>
> > -#include "dl-trampoline-save.h"
> >
> >  /* Area on stack to save and restore registers used for parameter
> >     passing when calling _dl_fixup.  */
> > --
> > 2.49.0
> >
>

The v4 patch is at

https://patchwork.sourceware.org/project/glibc/patch/CAMe9rOoaJ3RxjAiJev7utpWR33+1Tt_2nP7ys7tXMK57OSRRAQ@mail.gmail.com/
https://sourceware.org/pipermail/libc-alpha/2025-June/167782.html

--
H.J.


More information about the Libc-alpha mailing list