[PATCH] elf: Re-initialise static TLS after .tdata relocation (BZ 34164)
H.J. Lu
hjl.tools@gmail.com
Tue May 26 22:57:50 GMT 2026
On Wed, May 27, 2026 at 6:50 AM Adhemerval Zanella Netto
<adhemerval.zanella@linaro.org> wrote:
>
>
>
> On 26/05/26 19:47, H.J. Lu wrote:
> > On Wed, May 27, 2026 at 6:39 AM Adhemerval Zanella Netto
> > <adhemerval.zanella@linaro.org> wrote:
> >>
> >>
> >>
> >> On 26/05/26 18:36, H.J. Lu wrote:
> >>> On Wed, May 27, 2026 at 2:52 AM Adhemerval Zanella
> >>> <adhemerval.zanella@linaro.org> wrote:
> >>>>
> >>>> The af34b1376a37fa27e1de9d869ed9493fc569bfa6 changed the .tdata
> >>>> setup from:
> >>>>
> >>>> relocation loop (applies relocations to .tdata in DSO memory)
> >>>> _dl_allocate_tls_init copies relocated .tdata -> main thread TLS
> >>>>
> >>>> to a new order:
> >>>>
> >>>> _dl_allocate_tls_init copies unrelocated .tdata -> main thread TLS
> >>>> relocation loop (relocates .tdata in DSO memory, but the TLS block
> >>>> has stale copies)
> >>>>
> >>>> This broke file-scope thread-local initialised with the address of a
> >>>> function (for instance the cache structs in libmpfr).
> >>>
> >>> This is a regression. Please file a glibc bug report.
> >>
> >> I think there is no need to file a bug report, it is a regression for
> >> an unreleased version and it is really related to BZ#34164.
> >
> > If it is related to BZ #34164, please update BZ #34164 and mention it
> > in the commit message.
>
> It is with af34b1376a37fa27e1de9d869ed9493fc569bfa6 mention, the commit that
> introduced this regression. I think the commit message has all the information
> to track when, why, and how the issue was introduced.
Mention BZ #34164 makes the potential backport easier.
> >
> >>>
> >>>> Fix it by splitting ELF_DYNAMIC_RELOCATE inside
> >>>> _dl_relocate_object_no_relro into the non-IRELATIVE and IRELATIVE
> >>>> sub-passes (similar as done on static-pie startup by b75ad99d45b)
> >>>> and call _dl_init_static_tls between them. By the time the IFUNC
> >>>> pass fires, .tdata is fully relocated.
> >>>>
> >>>> Checked on x86_64-linux-gnu and aarch64-linux-gnu.
> >>>> ---
> >>>> elf/Makefile | 3 +++
> >>>> elf/dl-reloc.c | 24 ++++++++++++++++++--
> >>>> elf/tst-tls-tdata-reloc-lib.c | 42 +++++++++++++++++++++++++++++++++++
> >>>> elf/tst-tls-tdata-reloc.c | 32 ++++++++++++++++++++++++++
> >>>> 4 files changed, 99 insertions(+), 2 deletions(-)
> >>>> create mode 100644 elf/tst-tls-tdata-reloc-lib.c
> >>>> create mode 100644 elf/tst-tls-tdata-reloc.c
> >>>>
> >>>> diff --git a/elf/Makefile b/elf/Makefile
> >>>> index d7bab52cd97..a58a902451c 100644
> >>>> --- a/elf/Makefile
> >>>> +++ b/elf/Makefile
> >>>> @@ -1297,6 +1297,7 @@ tests += \
> >>>> tst-ifunc-resolver-protector \
> >>>> tst-ifunc-tls-init \
> >>>> tst-ifunc-tls-write \
> >>>> + tst-tls-tdata-reloc \
> >>>> # tests
> >>>> # Note: sysdeps/x86_64/ifuncmain8.c uses ifuncmain8.
> >>>> tests-internal += \
> >>>> @@ -1365,6 +1366,7 @@ modules-names += \
> >>>> tst-ifunc-tls-init-lib1 \
> >>>> tst-ifunc-tls-init-lib2 \
> >>>> tst-ifunc-tls-write-lib \
> >>>> + tst-tls-tdata-reloc-lib \
> >>>> # modules-names
> >>>> ifeq (no,$(with-lld))
> >>>> modules-names += ifuncmod5
> >>>> @@ -2518,6 +2520,7 @@ $(objpfx)tst-ifunc-tls-init: $(objpfx)tst-ifunc-tls-init-lib1.so
> >>>> $(objpfx)tst-ifunc-tls-init.out: \
> >>>> $(objpfx)tst-ifunc-tls-init-lib2.so
> >>>> $(objpfx)tst-ifunc-tls-write: $(objpfx)tst-ifunc-tls-write-lib.so
> >>>> +$(objpfx)tst-tls-tdata-reloc: $(objpfx)tst-tls-tdata-reloc-lib.so
> >>>>
> >>>> $(objpfx)tst-unique1.out: $(objpfx)tst-unique1mod1.so \
> >>>> $(objpfx)tst-unique1mod2.so
> >>>> diff --git a/elf/dl-reloc.c b/elf/dl-reloc.c
> >>>> index 91497b38397..15a6a4cffef 100644
> >>>> --- a/elf/dl-reloc.c
> >>>> +++ b/elf/dl-reloc.c
> >>>> @@ -269,9 +269,29 @@ _dl_relocate_object_no_relro (struct link_map *l, struct r_scope_elem *scope[],
> >>>> }
> >>>>
> >>>> {
> >>>> - /* Do the actual relocation of the object's GOT and other data. */
> >>>> + /* Do the actual relocation of the object's GOT and other data.
> >>>>
> >>>> - ELF_DYNAMIC_RELOCATE (l, scope, lazy, consider_profiling, skip_ifunc);
> >>>> + Process the non-IRELATIVE pass first so .tdata is fully relocated
> >>>> + (including R_*_RELATIVE / R_*_64 fixups for TLS initialisers, e.g. a
> >>>> + file-scope thread-local initialised with the address of a function),
> >>>> + then refresh the static TLS slot before the IRELATIVE pass runs the
> >>>> + IFUNC resolvers. Without this, a resolver would see the unrelocated
> >>>> + initialiser bytes that were placed into the slot by the early
> >>>> + _dl_allocate_tls_init. */
> >>>> + ELF_DYNAMIC_RELOCATE_NOIFUNC (l, scope, lazy, consider_profiling);
> >>>> +
> >>>> +#ifdef SHARED
> >>>> + /* Re-initialise the static TLS slot with the .tdata so the IRELATIVE
> >>>> + pass observes a fully-relocated initialiser image. Skipped for objects
> >>>> + without static TLS or before the main thread TCB has been set up. */
> >>>> + if (l->l_tls_blocksize != 0
> >>>> + && __rtld_tls_init_tp_called
> >>>> + && l->l_tls_offset != NO_TLS_OFFSET
> >>>> + && l->l_tls_offset != FORCED_DYNAMIC_TLS_OFFSET)
> >>>> + _dl_init_static_tls (l);
> >>>> +#endif
> >>>> +
> >>>> + ELF_DYNAMIC_RELOCATE_IFUNC (l, scope, lazy, skip_ifunc);
> >>>>
> >>>> if ((consider_profiling || consider_symbind)
> >>>> && l->l_info[DT_PLTRELSZ] != NULL)
> >>>> diff --git a/elf/tst-tls-tdata-reloc-lib.c b/elf/tst-tls-tdata-reloc-lib.c
> >>>> new file mode 100644
> >>>> index 00000000000..73aa58b0722
> >>>> --- /dev/null
> >>>> +++ b/elf/tst-tls-tdata-reloc-lib.c
> >>>> @@ -0,0 +1,42 @@
> >>>> +/* Shared library for tst-tls-tdata-reloc.
> >>>> + Copyright (C) 2026 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 EXPECTED 0x12345678
> >>>> +
> >>>> +static int
> >>>> +callee (void)
> >>>> +{
> >>>> + return EXPECTED;
> >>>> +}
> >>>> +
> >>>> +typedef struct
> >>>> +{
> >>>> + int (*func) (void);
> >>>> +} cache_t;
> >>>> +
> >>>> +/* General-dynamic TLS: the initialiser of '.func' produces an
> >>>> + R_*_RELATIVE on .tdata. */
> >>>> +__thread cache_t cache = { .func = callee };
> >>>> +
> >>>> +int
> >>>> +call_through_tls (void)
> >>>> +{
> >>>> + if (cache.func == 0)
> >>>> + return -1;
> >>>> + return cache.func ();
> >>>> +}
> >>>> diff --git a/elf/tst-tls-tdata-reloc.c b/elf/tst-tls-tdata-reloc.c
> >>>> new file mode 100644
> >>>> index 00000000000..1d38726e364
> >>>> --- /dev/null
> >>>> +++ b/elf/tst-tls-tdata-reloc.c
> >>>> @@ -0,0 +1,32 @@
> >>>> +/* Check that .tdata relocations are applied to the static TLS slot.
> >>>> + Copyright (C) 2026 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>
> >>>> +
> >>>> +#define EXPECTED 0x12345678
> >>>> +
> >>>> +extern int call_through_tls (void);
> >>>> +
> >>>> +static int
> >>>> +do_test (void)
> >>>> +{
> >>>> + TEST_COMPARE (call_through_tls (), EXPECTED);
> >>>> + return 0;
> >>>> +}
> >>>> +
> >>>> +#include <support/test-driver.c>
> >>>> --
> >>>> 2.43.0
> >>>>
> >>>
> >>>
> >>
> >
> >
>
--
H.J.
More information about the Libc-alpha
mailing list