]> git.ipfire.org Git - thirdparty/glibc.git/commitdiff
s390: Prevent hoisting the thread-pointer read in THREAD_SET_STACK_GUARD (BZ 34297)
authorAdhemerval Zanella <adhemerval.zanella@linaro.org>
Wed, 17 Jun 2026 14:25:47 +0000 (11:25 -0300)
committerAdhemerval Zanella <adhemerval.zanella@linaro.org>
Mon, 6 Jul 2026 13:47:30 +0000 (10:47 -0300)
THREAD_SET_STACK_GUARD reads the thread pointer via THREAD_SELF
(__builtin_thread_pointer), which the compiler treats as invariant.  In the
static startup path the thread pointer is installed by the __libc_setup_tls
call that immediately precedes the guard store, so the read must stay below
it.  The existing barrier only clobbered the access registers a0/a1, which
creates no dependency on the call, so the compiler could move the whole
barrier and read above __libc_setup_tls.

This is sensitive to instruction scheduling and recent TLS startup
changes exposed it on s390x.

Add a "memory" clobber to the barrier so it is tied to the call's memory
effects and cannot be hoisted above it.  The macro is shared with the
dynamic loader, so both startup paths are covered.

I checked on s390x-linux-gnu build for arch5, arch8, arch9, and arch11
by running the elf tests on qemu system (kernel 6.1.0).

Reviewed-by: Stefan Liebler <stli@linux.ibm.com>
sysdeps/s390/nptl/tls.h

index 41fd473d14a9256da48112ab5ca2bce29ffe715d..6ecaa2438414b1ecb1a9df9036f8f90ded9ed882 100644 (file)
@@ -131,7 +131,7 @@ typedef struct
 #define THREAD_SET_STACK_GUARD(value) \
   do                                                                         \
    {                                                                         \
-     __asm__ __volatile__ ("" : : : "a0", "a1");                             \
+     __asm__ __volatile__ ("" : : : "a0", "a1", "memory");                   \
      THREAD_SETMEM (THREAD_SELF, header.stack_guard, value);                 \
    }                                                                         \
   while (0)