[glibc] Consolidate pointer guard to use a relro variable instead of the TCB

Adhemerval Zanella via Glibc-cvs <[email protected]> Tue, 16 Jun 2026 18:15:40 +0000 (GMT)
Newsgroups gmane.comp.lib.glibc.cvs
Message-ID <[email protected]>
https://sourceware.org/git/gitweb.cgi?p=glibc.git;h=a5ec880f808ee7268d985bed4f961799bdc0a4bf

commit a5ec880f808ee7268d985bed4f961799bdc0a4bf
Author: Adhemerval Zanella <[email protected]>
Date:   Fri Jun 12 13:10:10 2026 -0300

    Consolidate pointer guard to use a relro variable instead of the TCB
    
    For the targets that still read the pointer guard from the thread
    descriptor (i386, x86_64, powerpc, s390, sparc, and sh), mangle and
    demangle pointers using the module-local __pointer_chk_guard_local (in
    ld.so and static binaries) or the global __pointer_chk_guard provided by
    the dynamic loader (in shared objects), matching the scheme already used
    by aarch64, alpha, arm, csky and loongarch.
    
    On i386 the guard is no longer reachable as a single %gs-relative memory
    operand, so the assembly PTR_MANGLE/PTR_DEMANGLE PIC variants need a
    register to hold the GOT pointer and the guard address.
    
    This removes the dependency on the TCB pointer_guard slot: drop
    THREAD_{GET,SET,COPY}_POINTER_GUARD and the POINTER_GUARD tcb-offset,
    and point the POINTER_CHK_GUARD test macro at the relro variable.  The
    tcbhead_t slot is kept (renamed to an unused reserved field, except on
    s390 which reused the stack guard) to preserve the ABI.  s390 gains a
    distinct pointer guard rather than aliasing the stack guard.
    
    Checked on x86_64-linux-gnu, aarch64-linux-gnu, i686-linux-gnu, and
    armv7a-linux-gnueabihf.  I also run elf and setjmp checks on qemu
    loongarch64, powerpc64, powerpc64le, and s390x systems.
    
    Reviewed-by: DJ Delorie <[email protected]>

Diff:
---
 sysdeps/arc/nptl/tls.h                             |  2 +-
 sysdeps/i386/__longjmp.S                           |  4 +-
 sysdeps/i386/bsd-_setjmp.S                         |  6 +--
 sysdeps/i386/bsd-setjmp.S                          |  4 +-
 sysdeps/i386/htl/tcb-offsets.sym                   |  1 -
 sysdeps/i386/nptl/tcb-offsets.sym                  |  1 -
 sysdeps/i386/nptl/tls.h                            | 10 +---
 sysdeps/i386/setjmp.S                              |  4 +-
 sysdeps/i386/stackguard-macros.h                   | 10 +++-
 sysdeps/mach/hurd/i386/tls.h                       |  9 +---
 sysdeps/mach/hurd/x86_64/tls.h                     |  8 +---
 sysdeps/powerpc/nptl/tcb-offsets.sym               |  1 -
 sysdeps/powerpc/nptl/tls.h                         | 16 +------
 sysdeps/powerpc/powerpc32/stackguard-macros.h      | 16 +++----
 sysdeps/powerpc/powerpc64/stackguard-macros.h      | 16 +++----
 sysdeps/s390/__longjmp.c                           |  2 +-
 sysdeps/s390/nptl/tls.h                            |  7 ---
 sysdeps/s390/stackguard-macros.h                   | 20 +++-----
 sysdeps/sh/nptl/tcb-offsets.sym                    |  1 -
 sysdeps/sh/nptl/tls.h                              | 15 +-----
 sysdeps/sh/stackguard-macros.h                     |  8 +++-
 sysdeps/sparc/nptl/tcb-offsets.sym                 |  1 -
 sysdeps/sparc/nptl/tls.h                           | 10 +---
 sysdeps/sparc/sparc32/stackguard-macros.h          |  9 +++-
 sysdeps/sparc/sparc64/stackguard-macros.h          |  9 +++-
 sysdeps/unix/sysv/linux/i386/____longjmp_chk.S     |  4 +-
 sysdeps/unix/sysv/linux/i386/pointer_guard.h       | 53 +++++++++++++++++-----
 sysdeps/unix/sysv/linux/powerpc/pointer_guard.h    | 53 ++++++++++++++++------
 sysdeps/unix/sysv/linux/s390/pointer_guard.h       | 33 +++++++++-----
 sysdeps/unix/sysv/linux/sh/pointer_guard.h         | 53 ++++++++++++++++++----
 .../unix/sysv/linux/sparc/sparc32/pointer_guard.h  | 39 +++++++++++++---
 .../unix/sysv/linux/sparc/sparc64/pointer_guard.h  | 38 +++++++++++++---
 sysdeps/unix/sysv/linux/x86_64/pointer_guard.h     | 18 ++++----
 sysdeps/x86_64/htl/tcb-offsets.sym                 |  1 -
 sysdeps/x86_64/nptl/tcb-offsets.sym                |  1 -
 sysdeps/x86_64/nptl/tls.h                          | 10 +---
 sysdeps/x86_64/stackguard-macros.h                 | 10 +++-
 37 files changed, 303 insertions(+), 200 deletions(-)

diff --git a/sysdeps/arc/nptl/tls.h b/sysdeps/arc/nptl/tls.h
index 44862a32f3..38d61931bd 100644
--- a/sysdeps/arc/nptl/tls.h
+++ b/sysdeps/arc/nptl/tls.h
@@ -42,7 +42,7 @@
 typedef struct
 {
   dtv_t *dtv;
-  uintptr_t pointer_guard;
+  uintptr_t __unused;
 } tcbhead_t;
 
 /* This is the size of the initial TCB.  */
diff --git a/sysdeps/i386/__longjmp.S b/sysdeps/i386/__longjmp.S
index f188390fb5..c8f768d501 100644
--- a/sysdeps/i386/__longjmp.S
+++ b/sysdeps/i386/__longjmp.S
@@ -31,8 +31,8 @@ ENTRY (__longjmp)
 	movl (JB_PC*4)(%eax), %edx
 	/* Get the stack pointer.  */
 	movl (JB_SP*4)(%eax), %ecx
-	PTR_DEMANGLE (%edx)
-	PTR_DEMANGLE (%ecx)
+	PTR_DEMANGLE (%edx, bx)
+	PTR_DEMANGLE (%ecx, bx)
 	LIBC_PROBE (longjmp, 3, 4@%eax, -4@8(%esp), 4@%edx)
 	cfi_def_cfa(%eax, 0)
 	cfi_register(%eip, %edx)
diff --git a/sysdeps/i386/bsd-_setjmp.S b/sysdeps/i386/bsd-_setjmp.S
index cb049be42f..8f509b7d51 100644
--- a/sysdeps/i386/bsd-_setjmp.S
+++ b/sysdeps/i386/bsd-_setjmp.S
@@ -31,7 +31,6 @@
 
 ENTRY (_setjmp)
 
-	xorl %eax, %eax
 	movl JMPBUF(%esp), %edx
 
 	/* Save registers.  */
@@ -40,17 +39,18 @@ ENTRY (_setjmp)
 	movl %edi, (JB_DI*4)(%edx)
 	leal JMPBUF(%esp), %ecx	/* Save SP as it will be after we return.  */
 #ifdef PTR_MANGLE
-	PTR_MANGLE (%ecx)
+	PTR_MANGLE (%ecx, ax)
 #endif
 	movl %ecx, (JB_SP*4)(%edx)
 	movl 0(%esp), %ecx	/* Save PC we are returning to now.  */
 	LIBC_PROBE (setjmp, 3, 4@%edx, -4@$0, 4@%ecx)
 #ifdef PTR_MANGLE
-	PTR_MANGLE (%ecx)
+	PTR_MANGLE (%ecx, ax)
 #endif
 	movl %ecx, (JB_PC*4)(%edx)
 	movl %ebp, (JB_BP*4)(%edx) /* Save caller's frame pointer.  */
 
+	xorl %eax, %eax
 	movl %eax, JB_SIZE(%edx) /* No signal mask set.  */
 	ret
 END (_setjmp)
diff --git a/sysdeps/i386/bsd-setjmp.S b/sysdeps/i386/bsd-setjmp.S
index 70336a119b..5f3a4694f3 100644
--- a/sysdeps/i386/bsd-setjmp.S
+++ b/sysdeps/i386/bsd-setjmp.S
@@ -42,13 +42,13 @@ ENTRY (setjmp)
 	movl %edi, (JB_DI*4)(%eax)
 	leal JMPBUF(%esp), %ecx	/* Save SP as it will be after we return.  */
 #ifdef PTR_MANGLE
-	PTR_MANGLE (%ecx)
+	PTR_MANGLE (%ecx, dx)
 #endif
 	movl %ecx, (JB_SP*4)(%eax)
 	movl 0(%esp), %ecx	/* Save PC we are returning to now.  */
 	LIBC_PROBE (setjmp, 3, 4@%eax, -4@$1, 4@%ecx)
 #ifdef PTR_MANGLE
-	PTR_MANGLE (%ecx)
+	PTR_MANGLE (%ecx, dx)
 #endif
 	movl %ecx, (JB_PC*4)(%eax)
 	movl %ebp, (JB_BP*4)(%eax) /* Save caller's frame pointer.  */
diff --git a/sysdeps/i386/htl/tcb-offsets.sym b/sysdeps/i386/htl/tcb-offsets.sym
index 7b7c719369..b36cfd6848 100644
--- a/sysdeps/i386/htl/tcb-offsets.sym
+++ b/sysdeps/i386/htl/tcb-offsets.sym
@@ -4,5 +4,4 @@
 
 MULTIPLE_THREADS_OFFSET offsetof (tcbhead_t, multiple_threads)
 SYSINFO_OFFSET          offsetof (tcbhead_t, sysinfo)
-POINTER_GUARD           offsetof (tcbhead_t, pointer_guard)
 SIGSTATE_OFFSET         offsetof (tcbhead_t, _hurd_sigstate)
diff --git a/sysdeps/i386/nptl/tcb-offsets.sym b/sysdeps/i386/nptl/tcb-offsets.sym
index 2ec9e787c1..48f7984512 100644
--- a/sysdeps/i386/nptl/tcb-offsets.sym
+++ b/sysdeps/i386/nptl/tcb-offsets.sym
@@ -11,6 +11,5 @@ SYSINFO_OFFSET		offsetof (tcbhead_t, sysinfo)
 CLEANUP			offsetof (struct pthread, cleanup)
 CLEANUP_PREV		offsetof (struct _pthread_cleanup_buffer, __prev)
 MUTEX_FUTEX		offsetof (pthread_mutex_t, __data.__lock)
-POINTER_GUARD		offsetof (tcbhead_t, pointer_guard)
 FEATURE_1_OFFSET	offsetof (tcbhead_t, feature_1)
 SSP_BASE_OFFSET		offsetof (tcbhead_t, ssp_base)
diff --git a/sysdeps/i386/nptl/tls.h b/sysdeps/i386/nptl/tls.h
index 87dcf5dc1f..fb8684230f 100644
--- a/sysdeps/i386/nptl/tls.h
+++ b/sysdeps/i386/nptl/tls.h
@@ -39,7 +39,7 @@ typedef struct
   int multiple_threads;
   uintptr_t sysinfo;
   uintptr_t stack_guard;
-  uintptr_t pointer_guard;
+  uintptr_t __unused;
   int gscope_flag;
   /* Bit 0: X86_FEATURE_1_IBT.
      Bit 1: X86_FEATURE_1_SHSTK.
@@ -240,14 +240,6 @@ tls_fill_user_desc (union user_desc_init *desc,
    = THREAD_GETMEM (THREAD_SELF, header.stack_guard))
 
 
-/* Set the pointer guard field in the TCB head.  */
-#define THREAD_SET_POINTER_GUARD(value) \
-  THREAD_SETMEM (THREAD_SELF, header.pointer_guard, value)
-#define THREAD_COPY_POINTER_GUARD(descr) \
-  ((descr)->header.pointer_guard					      \
-   = THREAD_GETMEM (THREAD_SELF, header.pointer_guard))
-
-
 /* Get and set the global scope generation counter in the TCB head.  */
 #define THREAD_GSCOPE_FLAG_UNUSED 0
 #define THREAD_GSCOPE_FLAG_USED   1
diff --git a/sysdeps/i386/setjmp.S b/sysdeps/i386/setjmp.S
index 1cf1796040..8787be4ede 100644
--- a/sysdeps/i386/setjmp.S
+++ b/sysdeps/i386/setjmp.S
@@ -36,13 +36,13 @@ ENTRY (__sigsetjmp)
 	movl %edi, (JB_DI*4)(%eax)
 	leal JMPBUF(%esp), %ecx	/* Save SP as it will be after we return.  */
 #ifdef PTR_MANGLE
-	PTR_MANGLE (%ecx)
+	PTR_MANGLE (%ecx, dx)
 #endif
 	movl %ecx, (JB_SP*4)(%eax)
 	movl 0(%esp), %ecx	/* Save PC we are returning to now.  */
 	LIBC_PROBE (setjmp, 3, 4@%eax, -4@SIGMSK(%esp), 4@%ecx)
 #ifdef PTR_MANGLE
-	PTR_MANGLE (%ecx)
+	PTR_MANGLE (%ecx, dx)
 #endif
 	movl %ecx, (JB_PC*4)(%eax)
 	movl %ebp, (JB_BP*4)(%eax) /* Save caller's frame pointer.  */
diff --git a/sysdeps/i386/stackguard-macros.h b/sysdeps/i386/stackguard-macros.h
index 2939934ef1..696a977702 100644
--- a/sysdeps/i386/stackguard-macros.h
+++ b/sysdeps/i386/stackguard-macros.h
@@ -1,3 +1,11 @@
+#include <stdint.h>
+
 #define STACK_CHK_GUARD (((tcbhead_t __seg_gs *)0)->stack_guard)
 
-#define POINTER_CHK_GUARD (((tcbhead_t __seg_gs *)0)->pointer_guard)
+#ifdef PTRGUARD_LOCAL
+extern uintptr_t __pointer_chk_guard_local;
+# define POINTER_CHK_GUARD __pointer_chk_guard_local
+#else
+extern uintptr_t __pointer_chk_guard;
+# define POINTER_CHK_GUARD __pointer_chk_guard
+#endif
diff --git a/sysdeps/mach/hurd/i386/tls.h b/sysdeps/mach/hurd/i386/tls.h
index 8cd643cdcf..403395db9a 100644
--- a/sysdeps/mach/hurd/i386/tls.h
+++ b/sysdeps/mach/hurd/i386/tls.h
@@ -36,7 +36,7 @@ typedef struct
   int multiple_threads;
   uintptr_t sysinfo;
   uintptr_t stack_guard;
-  uintptr_t pointer_guard;
+  uintptr_t __unused;
   int gscope_flag;
   unsigned int feature_1;
   /* Reservation of some values for the TM ABI.  */
@@ -238,13 +238,6 @@ out:
   ((descr)->stack_guard							      \
    = THREAD_GETMEM (THREAD_SELF, stack_guard))
 
-/* Set the pointer guard field in the TCB head.  */
-#define THREAD_SET_POINTER_GUARD(value) \
-  THREAD_SETMEM (THREAD_SELF, pointer_guard, value)
-#define THREAD_COPY_POINTER_GUARD(descr) \
-  ((descr)->pointer_guard						      \
-   = THREAD_GETMEM (THREAD_SELF, pointer_guard))
-
 
 # include <mach/machine/thread_status.h>
 
diff --git a/sysdeps/mach/hurd/x86_64/tls.h b/sysdeps/mach/hurd/x86_64/tls.h
index 85ea75b5b5..3543e9be34 100644
--- a/sysdeps/mach/hurd/x86_64/tls.h
+++ b/sysdeps/mach/hurd/x86_64/tls.h
@@ -41,7 +41,7 @@ typedef struct
   int gscope_flag;
   uintptr_t sysinfo;
   uintptr_t stack_guard;
-  uintptr_t pointer_guard;
+  uintptr_t __unused;
   long __glibc_padding2[2];
   int private_futex;
   int __glibc_padding3;
@@ -125,12 +125,6 @@ THREAD_TCB (thread_t thread,
   ((descr)->stack_guard							\
    = THREAD_GETMEM (THREAD_SELF, stack_guard))
 
-/* Set the pointer guard field in the TCB head.  */
-# define THREAD_SET_POINTER_GUARD(value)				\
-  THREAD_SETMEM (THREAD_SELF, pointer_guard, value)
-# define THREAD_COPY_POINTER_GUARD(descr)				\
-  ((descr)->pointer_guard						\
-   = THREAD_GETMEM (THREAD_SELF, pointer_guard))
 
 /* From hurd.h, reproduced here to avoid a circular include.  */
 extern thread_t __hurd_thread_self (void);
diff --git a/sysdeps/powerpc/nptl/tcb-offsets.sym b/sysdeps/powerpc/nptl/tcb-offsets.sym
index 9b29fe8d1a..bc88ecdddb 100644
--- a/sysdeps/powerpc/nptl/tcb-offsets.sym
+++ b/sysdeps/powerpc/nptl/tcb-offsets.sym
@@ -14,7 +14,6 @@
 MULTIPLE_THREADS_OFFSET		thread_offsetof (header.multiple_threads)
 #endif
 TID				thread_offsetof (tid)
-POINTER_GUARD			(offsetof (tcbhead_t, pointer_guard) - TLS_TCB_OFFSET - sizeof (tcbhead_t))
 TAR_SAVE			(offsetof (tcbhead_t, tar_save) - TLS_TCB_OFFSET - sizeof (tcbhead_t))
 DSO_SLOT1			(offsetof (tcbhead_t, dso_slot1) - TLS_TCB_OFFSET - sizeof (tcbhead_t))
 DSO_SLOT2			(offsetof (tcbhead_t, dso_slot2) - TLS_TCB_OFFSET - sizeof (tcbhead_t))
diff --git a/sysdeps/powerpc/nptl/tls.h b/sysdeps/powerpc/nptl/tls.h
index 4ef6dd1a2f..2e735c155b 100644
--- a/sysdeps/powerpc/nptl/tls.h
+++ b/sysdeps/powerpc/nptl/tls.h
@@ -60,8 +60,7 @@
 
 
 /* The stack_guard is accessed directly by GCC -fstack-protector code,
-   so it is a part of public ABI.  The dtv and pointer_guard fields
-   are private.  */
+   so it is a part of public ABI.  The dtv field is private.  */
 typedef struct
 {
   /* Reservation for HWCAP3 and HWCAP4 data.  To be accessed by GCC in
@@ -96,7 +95,7 @@ typedef struct
   uintptr_t ebb_ctx_pointer;
   uintptr_t ebb_reserved1;
   uintptr_t ebb_reserved2;
-  uintptr_t pointer_guard;
+  uintptr_t __unused2;
   uintptr_t stack_guard;
   dtv_t *dtv;
 } tcbhead_t;
@@ -186,17 +185,6 @@ extern tcbhead_t __tcb attribute_hidden;
      = ((tcbhead_t *) ((char *) __thread_register			      \
 		       - TLS_TCB_OFFSET))[-1].stack_guard)
 
-/* Set the stack guard field in TCB head.  */
-# define THREAD_GET_POINTER_GUARD() \
-    (((tcbhead_t *) ((char *) __thread_register				      \
-		     - TLS_TCB_OFFSET))[-1].pointer_guard)
-# define THREAD_SET_POINTER_GUARD(value) \
-    (THREAD_GET_POINTER_GUARD () = (value))
-# define THREAD_COPY_POINTER_GUARD(descr) \
-    (((tcbhead_t *) ((char *) (descr)					      \
-		     + TLS_PRE_TCB_SIZE))[-1].pointer_guard		      \
-     = THREAD_GET_POINTER_GUARD())
-
 /* hwcap & hwcap_extn fields in TCB head.  */
 # define THREAD_GET_HWCAP() \
     (((tcbhead_t *) ((char *) __thread_register				      \
diff --git a/sysdeps/powerpc/powerpc32/stackguard-macros.h b/sysdeps/powerpc/powerpc32/stackguard-macros.h
index b3d0af830f..0c94269a73 100644
--- a/sysdeps/powerpc/powerpc32/stackguard-macros.h
+++ b/sysdeps/powerpc/powerpc32/stackguard-macros.h
@@ -3,12 +3,10 @@
 #define STACK_CHK_GUARD \
   ({ uintptr_t x; asm ("lwz %0,-28680(2)" : "=r" (x)); x; })
 
-#define POINTER_CHK_GUARD \
-  ({												\
-     uintptr_t x;										\
-     asm ("lwz %0,%1(2)"									\
-	  : "=r" (x)										\
-	  : "i" (offsetof (tcbhead_t, pointer_guard) - TLS_TCB_OFFSET - sizeof (tcbhead_t))	\
-         );											\
-     x;												\
-   })
+#ifdef PTRGUARD_LOCAL
+extern uintptr_t __pointer_chk_guard_local;
+# define POINTER_CHK_GUARD __pointer_chk_guard_local
+#else
+extern uintptr_t __pointer_chk_guard;
+# define POINTER_CHK_GUARD __pointer_chk_guard
+#endif
diff --git a/sysdeps/powerpc/powerpc64/stackguard-macros.h b/sysdeps/powerpc/powerpc64/stackguard-macros.h
index e80a683e64..fec2e69f64 100644
--- a/sysdeps/powerpc/powerpc64/stackguard-macros.h
+++ b/sysdeps/powerpc/powerpc64/stackguard-macros.h
@@ -3,12 +3,10 @@
 #define STACK_CHK_GUARD \
   ({ uintptr_t x; asm ("ld %0,-28688(13)" : "=r" (x)); x; })
 
-#define POINTER_CHK_GUARD \
-  ({												\
-     uintptr_t x;										\
-     asm ("ld %0,%1(13)"										\
-	  : "=r" (x)										\
-	  : "i" (offsetof (tcbhead_t, pointer_guard) - TLS_TCB_OFFSET - sizeof (tcbhead_t))	\
-         );											\
-     x;												\
-   })
+#ifdef PTRGUARD_LOCAL
+extern uintptr_t __pointer_chk_guard_local;
+# define POINTER_CHK_GUARD __pointer_chk_guard_local
+#else
+extern uintptr_t __pointer_chk_guard;
+# define POINTER_CHK_GUARD __pointer_chk_guard
+#endif
diff --git a/sysdeps/s390/__longjmp.c b/sysdeps/s390/__longjmp.c
index 7c207e44c6..78aa70a943 100644
--- a/sysdeps/s390/__longjmp.c
+++ b/sysdeps/s390/__longjmp.c
@@ -35,7 +35,7 @@ void
 __longjmp (__jmp_buf env, int val)
 {
 #ifdef PTR_DEMANGLE
-  uintptr_t guard = THREAD_GET_POINTER_GUARD ();
+  uintptr_t guard = PTR_GUARD_VALUE;
 # ifdef CHECK_SP
   CHECK_SP (env, guard);
 # endif
diff --git a/sysdeps/s390/nptl/tls.h b/sysdeps/s390/nptl/tls.h
index de7e9c6482..41fd473d14 100644
--- a/sysdeps/s390/nptl/tls.h
+++ b/sysdeps/s390/nptl/tls.h
@@ -139,13 +139,6 @@ typedef struct
   ((descr)->header.stack_guard						      \
    = THREAD_GETMEM (THREAD_SELF, header.stack_guard))
 
-/* s390 doesn't have HP_TIMING_*, so for the time being
-   use stack_guard as pointer_guard.  */
-#define THREAD_GET_POINTER_GUARD() \
-  THREAD_GETMEM (THREAD_SELF, header.stack_guard)
-#define THREAD_SET_POINTER_GUARD(value)	((void) (value))
-#define THREAD_COPY_POINTER_GUARD(descr)
-
 /* Get and set the global scope generation counter in struct pthread.  */
 #define THREAD_GSCOPE_FLAG_UNUSED 0
 #define THREAD_GSCOPE_FLAG_USED   1
diff --git a/sysdeps/s390/stackguard-macros.h b/sysdeps/s390/stackguard-macros.h
index 3671c7cd7a..22e4751a73 100644
--- a/sysdeps/s390/stackguard-macros.h
+++ b/sysdeps/s390/stackguard-macros.h
@@ -3,16 +3,10 @@
 #define STACK_CHK_GUARD \
   ({ uintptr_t x; __asm__ ("ear %0,%%a0; sllg %0,%0,32; ear %0,%%a1; lg %0,0x28(%0)" : "=a" (x)); x; })
 
-/* On s390x there is no unique pointer guard, instead we use the
-   same value as the stack guard.  */
-#define POINTER_CHK_GUARD					\
-  ({								\
-    uintptr_t x;						\
-    __asm__ ("ear %0,%%a0;"					\
-	     "sllg %0,%0,32;"					\
-	     "ear %0,%%a1;"					\
-	     "lg %0,%1(%0)"					\
-	     : "=a" (x)						\
-	     : "i" (offsetof (tcbhead_t, stack_guard)));	\
-    x;								\
-  })
+#ifdef PTRGUARD_LOCAL
+extern uintptr_t __pointer_chk_guard_local;
+# define POINTER_CHK_GUARD __pointer_chk_guard_local
+#else
+extern uintptr_t __pointer_chk_guard;
+# define POINTER_CHK_GUARD __pointer_chk_guard
+#endif
diff --git a/sysdeps/sh/nptl/tcb-offsets.sym b/sysdeps/sh/nptl/tcb-offsets.sym
index 234207779d..f1da9a0515 100644
--- a/sysdeps/sh/nptl/tcb-offsets.sym
+++ b/sysdeps/sh/nptl/tcb-offsets.sym
@@ -9,4 +9,3 @@ CLEANUP_JMP_BUF		offsetof (struct pthread, cleanup_jmp_buf)
 MULTIPLE_THREADS_OFFSET	offsetof (struct pthread, header.multiple_threads)
 TLS_PRE_TCB_SIZE	sizeof (struct pthread)
 MUTEX_FUTEX		offsetof (pthread_mutex_t, __data.__lock)
-POINTER_GUARD		offsetof (tcbhead_t, pointer_guard)
diff --git a/sysdeps/sh/nptl/tls.h b/sysdeps/sh/nptl/tls.h
index eac95e14c7..7008003344 100644
--- a/sysdeps/sh/nptl/tls.h
+++ b/sysdeps/sh/nptl/tls.h
@@ -33,7 +33,7 @@
 typedef struct
 {
   dtv_t *dtv;
-  uintptr_t pointer_guard;
+  uintptr_t __unused;
 } tcbhead_t;
 
 # define TLS_MULTIPLE_THREADS_IN_TCB 1
@@ -109,19 +109,6 @@ typedef struct
 
 # include <tcb-access.h>
 
-#define THREAD_GET_POINTER_GUARD() \
-  ({ tcbhead_t *__tcbp;							      \
-     __asm __volatile ("stc gbr,%0" : "=r" (__tcbp));			      \
-     __tcbp->pointer_guard;})
- #define THREAD_SET_POINTER_GUARD(value) \
-  ({ tcbhead_t *__tcbp;							      \
-     __asm __volatile ("stc gbr,%0" : "=r" (__tcbp));			      \
-     __tcbp->pointer_guard = (value);})
-#define THREAD_COPY_POINTER_GUARD(descr) \
-  ({ tcbhead_t *__tcbp;							      \
-     __asm __volatile ("stc gbr,%0" : "=r" (__tcbp));			      \
-     ((tcbhead_t *) (descr + 1))->pointer_guard	= __tcbp->pointer_guard;})
-
 /* Get and set the global scope generation counter in struct pthread.  */
 #define THREAD_GSCOPE_FLAG_UNUSED 0
 #define THREAD_GSCOPE_FLAG_USED   1
diff --git a/sysdeps/sh/stackguard-macros.h b/sysdeps/sh/stackguard-macros.h
index 55a5771b62..b4a6b23ff8 100644
--- a/sysdeps/sh/stackguard-macros.h
+++ b/sysdeps/sh/stackguard-macros.h
@@ -3,4 +3,10 @@
 extern uintptr_t __stack_chk_guard;
 #define STACK_CHK_GUARD __stack_chk_guard
 
-#define POINTER_CHK_GUARD THREAD_GET_POINTER_GUARD()
+#ifdef PTRGUARD_LOCAL
+extern uintptr_t __pointer_chk_guard_local;
+# define POINTER_CHK_GUARD __pointer_chk_guard_local
+#else
+extern uintptr_t __pointer_chk_guard;
+# define POINTER_CHK_GUARD __pointer_chk_guard
+#endif
diff --git a/sysdeps/sparc/nptl/tcb-offsets.sym b/sysdeps/sparc/nptl/tcb-offsets.sym
index f75d02065e..a64180da03 100644
--- a/sysdeps/sparc/nptl/tcb-offsets.sym
+++ b/sysdeps/sparc/nptl/tcb-offsets.sym
@@ -2,5 +2,4 @@
 #include <tls.h>
 
 MULTIPLE_THREADS_OFFSET		offsetof (tcbhead_t, multiple_threads)
-POINTER_GUARD			offsetof (tcbhead_t, pointer_guard)
 TID				offsetof (struct pthread, tid)
diff --git a/sysdeps/sparc/nptl/tls.h b/sysdeps/sparc/nptl/tls.h
index cd2112a650..361fc11a43 100644
--- a/sysdeps/sparc/nptl/tls.h
+++ b/sysdeps/sparc/nptl/tls.h
@@ -41,7 +41,7 @@ typedef struct
 #endif
   uintptr_t sysinfo;
   uintptr_t stack_guard;
-  uintptr_t pointer_guard;
+  uintptr_t __unused;
 #if __WORDSIZE != 64
   int gscope_flag;
 #endif
@@ -115,14 +115,6 @@ register struct pthread *__thread_self __asm__("%g7");
   ((descr)->header.stack_guard \
    = THREAD_GETMEM (THREAD_SELF, header.stack_guard))
 
-/* Get/set the stack guard field in TCB head.  */
-#define THREAD_GET_POINTER_GUARD() \
-  THREAD_GETMEM (THREAD_SELF, header.pointer_guard)
-#define THREAD_SET_POINTER_GUARD(value) \
-  THREAD_SETMEM (THREAD_SELF, header.pointer_guard, value)
-# define THREAD_COPY_POINTER_GUARD(descr) \
-  ((descr)->header.pointer_guard = THREAD_GET_POINTER_GUARD ())
-
 /* Get and set the global scope generation counter in struct pthread.  */
 #define THREAD_GSCOPE_FLAG_UNUSED 0
 #define THREAD_GSCOPE_FLAG_USED   1
diff --git a/sysdeps/sparc/sparc32/stackguard-macros.h b/sysdeps/sparc/sparc32/stackguard-macros.h
index 1eef0f19f0..e8000a2899 100644
--- a/sysdeps/sparc/sparc32/stackguard-macros.h
+++ b/sysdeps/sparc/sparc32/stackguard-macros.h
@@ -3,5 +3,10 @@
 #define STACK_CHK_GUARD \
   ({ uintptr_t x; asm ("ld [%%g7+0x14], %0" : "=r" (x)); x; })
 
-#define POINTER_CHK_GUARD \
-  ({ uintptr_t x; asm ("ld [%%g7+0x18], %0" : "=r" (x)); x; })
+#ifdef PTRGUARD_LOCAL
+extern uintptr_t __pointer_chk_guard_local;
+# define POINTER_CHK_GUARD __pointer_chk_guard_local
+#else
+extern uintptr_t __pointer_chk_guard;
+# define POINTER_CHK_GUARD __pointer_chk_guard
+#endif
diff --git a/sysdeps/sparc/sparc64/stackguard-macros.h b/sysdeps/sparc/sparc64/stackguard-macros.h
index cc0c12c041..99978d8bec 100644
--- a/sysdeps/sparc/sparc64/stackguard-macros.h
+++ b/sysdeps/sparc/sparc64/stackguard-macros.h
@@ -3,5 +3,10 @@
 #define STACK_CHK_GUARD \
   ({ uintptr_t x; asm ("ldx [%%g7+0x28], %0" : "=r" (x)); x; })
 
-#define POINTER_CHK_GUARD \
-  ({ uintptr_t x; asm ("ldx [%%g7+0x30], %0" : "=r" (x)); x; })
+#ifdef PTRGUARD_LOCAL
+extern uintptr_t __pointer_chk_guard_local;
+# define POINTER_CHK_GUARD __pointer_chk_guard_local
+#else
+extern uintptr_t __pointer_chk_guard;
+# define POINTER_CHK_GUARD __pointer_chk_guard
+#endif
diff --git a/sysdeps/unix/sysv/linux/i386/____longjmp_chk.S b/sysdeps/unix/sysv/linux/i386/____longjmp_chk.S
index c7573fe927..aea4d156f7 100644
--- a/sysdeps/unix/sysv/linux/i386/____longjmp_chk.S
+++ b/sysdeps/unix/sysv/linux/i386/____longjmp_chk.S
@@ -52,8 +52,8 @@ ENTRY (____longjmp_chk)
 	/* Get the stack pointer.  */
 	movl	(JB_SP*4)(%ecx), %edi
 	cfi_undefined(%edi)
-	PTR_DEMANGLE (%edx)
-	PTR_DEMANGLE (%edi)
+	PTR_DEMANGLE (%edx, bx)
+	PTR_DEMANGLE (%edi, bx)
 
 	cmpl	%edi, %esp
 	jbe	.Lok
diff --git a/sysdeps/unix/sysv/linux/i386/pointer_guard.h b/sysdeps/unix/sysv/linux/i386/pointer_guard.h
index c8311be444..27fa8de465 100644
--- a/sysdeps/unix/sysv/linux/i386/pointer_guard.h
+++ b/sysdeps/unix/sysv/linux/i386/pointer_guard.h
@@ -19,26 +19,56 @@
 #ifndef POINTER_GUARD_H
 #define POINTER_GUARD_H
 
-#include <tcb-offsets.h>
-
 #if IS_IN (rtld)
 /* We cannot use the thread descriptor because in ld.so we use setjmp
-   earlier than the descriptor is initialized.  Using a global variable
-   is too complicated here since we have no PC-relative addressing mode.  */
+   earlier than the descriptor is initialized.  */
 # include <sysdeps/generic/pointer_guard.h>
 #else
 # ifdef __ASSEMBLER__
-#  define PTR_MANGLE(reg)	xorl %gs:POINTER_GUARD, reg;		      \
+#  include <sysdep.h>
+/* The PIC variants clobber TMP, a register name suffix as expected by
+   LOAD_PIC_REG (e.g. dx for %edx), to load the guard value.  */
+#  ifdef SHARED
+/* The global guard is reached through the GOT.  */
+#   define PTR_MANGLE(reg, tmp)	LOAD_PIC_REG (tmp);			      \
+				movl __pointer_chk_guard@GOT(%e##tmp), %e##tmp; \
+				xorl (%e##tmp), reg;			      \
+				roll $9, reg
+#   define PTR_DEMANGLE(reg, tmp) \
+				rorl $9, reg;				      \
+				LOAD_PIC_REG (tmp);			      \
+				movl __pointer_chk_guard@GOT(%e##tmp), %e##tmp; \
+				xorl (%e##tmp), reg
+#  elif defined PIC
+/* Static PIE: the module-local guard is reached via @GOTOFF.  */
+#   define PTR_MANGLE(reg, tmp)	LOAD_PIC_REG (tmp);			      \
+				xorl __pointer_chk_guard_local@GOTOFF(%e##tmp), reg; \
+				roll $9, reg
+#   define PTR_DEMANGLE(reg, tmp) \
+				rorl $9, reg;				      \
+				LOAD_PIC_REG (tmp);			      \
+				xorl __pointer_chk_guard_local@GOTOFF(%e##tmp), reg
+#  else
+/* Position-dependent code addresses the guard directly.  */
+#   define PTR_MANGLE(reg, tmp)	xorl __pointer_chk_guard_local, reg;	      \
 				roll $9, reg
-#  define PTR_DEMANGLE(reg)	rorl $9, reg;				      \
-				xorl %gs:POINTER_GUARD, reg
+#   define PTR_DEMANGLE(reg, tmp) \
+				rorl $9, reg;				      \
+				xorl __pointer_chk_guard_local, reg
+#  endif
 # else
 #  include <stdbit.h>
-#  include <tls.h>
+#  include <stdint.h>
+#  ifdef SHARED
+extern uintptr_t __pointer_chk_guard attribute_relro;
+#   define PTR_GUARD_VALUE	__pointer_chk_guard
+#  else
+extern uintptr_t __pointer_chk_guard_local attribute_relro attribute_hidden;
+#   define PTR_GUARD_VALUE	__pointer_chk_guard_local
+#  endif
 #  define PTR_MANGLE(var)						      \
     do {								      \
-      (var) = (__typeof (var)) ((uintptr_t) (var)			      \
-				^ ((tcbhead_t __seg_gs *)0)->pointer_guard);  \
+      (var) = (__typeof (var)) ((uintptr_t) (var) ^ PTR_GUARD_VALUE);	      \
       (var) = (__typeof (var)) stdc_rotate_left ((uintptr_t) (var),	      \
 						 2 * sizeof (uintptr_t) + 1); \
     } while (0)
@@ -46,8 +76,7 @@
     do {								      \
       (var) = (__typeof (var)) stdc_rotate_right ((uintptr_t) (var),	      \
 						  2 * sizeof (uintptr_t) + 1); \
-      (var) = (__typeof (var)) ((uintptr_t) (var)			      \
-				^ ((tcbhead_t __seg_gs *)0)->pointer_guard);  \
+      (var) = (__typeof (var)) ((uintptr_t) (var) ^ PTR_GUARD_VALUE);	      \
     } while (0)
 # endif
 #endif
diff --git a/sysdeps/unix/sysv/linux/powerpc/pointer_guard.h b/sysdeps/unix/sysv/linux/powerpc/pointer_guard.h
index 50d177224f..864a78ea53 100644
--- a/sysdeps/unix/sysv/linux/powerpc/pointer_guard.h
+++ b/sysdeps/unix/sysv/linux/powerpc/pointer_guard.h
@@ -20,34 +20,59 @@
 #define POINTER_GUARD_H
 
 #if IS_IN (rtld)
-/* We cannot use the thread descriptor because in ld.so we use setjmp
-   earlier than the descriptor is initialized.  */
 # include <sysdeps/generic/pointer_guard.h>
 #else
 # ifdef __ASSEMBLER__
+#  include <sysdep.h>
+#  ifdef SHARED
+#   define PTR_GUARD_SYM	__pointer_chk_guard
+#  else
+#   define PTR_GUARD_SYM	__pointer_chk_guard_local
+#  endif
+
 #  if defined(__PPC64__) || defined(__powerpc64__)
-#   define LOAD  ld
-#   define TPREG r13
+#   define PTR_GUARD_LOAD(tmpreg)					\
+	addis	tmpreg,r2,PTR_GUARD_SYM@got@ha;				\
+	ld	tmpreg,PTR_GUARD_SYM@got@l(tmpreg);			\
+	ld	tmpreg,0(tmpreg)
+#  elif defined PIC
+#   define PTR_GUARD_LOAD(tmpreg)					\
+	mflr	r12;							\
+	bcl	20,31,0f;						\
+0:	mflr	tmpreg;							\
+	addis	tmpreg,tmpreg,_GLOBAL_OFFSET_TABLE_-0b@ha;		\
+	addi	tmpreg,tmpreg,_GLOBAL_OFFSET_TABLE_-0b@l;		\
+	mtlr	r12;							\
+	lwz	tmpreg,PTR_GUARD_SYM@got(tmpreg);			\
+	lwz	tmpreg,0(tmpreg)
 #  else
-#   define LOAD  lwz
-#   define TPREG r2
+#   define PTR_GUARD_LOAD(tmpreg)					\
+	lis	tmpreg,PTR_GUARD_SYM@ha;				\
+	lwz	tmpreg,PTR_GUARD_SYM@l(tmpreg)
 #  endif
+
 #  define PTR_MANGLE(reg, tmpreg) \
-        LOAD    tmpreg,POINTER_GUARD(TPREG); \
-        xor     reg,tmpreg,reg
+	PTR_GUARD_LOAD (tmpreg); \
+	xor	reg,tmpreg,reg
 #  define PTR_MANGLE2(reg, tmpreg) \
-        xor     reg,tmpreg,reg
+	xor	reg,tmpreg,reg
 #  define PTR_MANGLE3(destreg, reg, tmpreg) \
-        LOAD    tmpreg,POINTER_GUARD(TPREG); \
-        xor     destreg,tmpreg,reg
+	PTR_GUARD_LOAD (tmpreg); \
+	xor	destreg,tmpreg,reg
 #  define PTR_DEMANGLE(reg, tmpreg) PTR_MANGLE (reg, tmpreg)
 #  define PTR_DEMANGLE2(reg, tmpreg) PTR_MANGLE2 (reg, tmpreg)
 #  define PTR_DEMANGLE3(destreg, reg, tmpreg) PTR_MANGLE3 (destreg, reg, tmpreg)
 # else
 #  include <stdint.h>
-#  include <tls.h>
-#  define PTR_MANGLE(var) \
-  (var) = (__typeof (var)) ((uintptr_t) (var) ^ THREAD_GET_POINTER_GUARD ())
+#  ifdef SHARED
+extern uintptr_t __pointer_chk_guard attribute_relro;
+#   define PTR_MANGLE(var) \
+  (var) = (__typeof (var)) ((uintptr_t) (var) ^ __pointer_chk_guard)
+#  else
+extern uintptr_t __pointer_chk_guard_local attribute_relro attribute_hidden;
+#   define PTR_MANGLE(var) \
+  (var) = (__typeof (var)) ((uintptr_t) (var) ^ __pointer_chk_guard_local)
+#  endif
 #  define PTR_DEMANGLE(var)     PTR_MANGLE (var)
 # endif
 #endif
diff --git a/sysdeps/unix/sysv/linux/s390/pointer_guard.h b/sysdeps/unix/sysv/linux/s390/pointer_guard.h
index d7a574e94c..aa75b8c42e 100644
--- a/sysdeps/unix/sysv/linux/s390/pointer_guard.h
+++ b/sysdeps/unix/sysv/linux/s390/pointer_guard.h
@@ -20,26 +20,37 @@
 #define POINTER_GUARD_H
 
 #if IS_IN (rtld)
-/* We cannot use the thread descriptor because in ld.so we use setjmp
-   earlier than the descriptor is initialized.  */
 # include <sysdeps/generic/pointer_guard.h>
 #else
-/* For the time being just use stack_guard rather than a separate
-   pointer_guard.  */
 # ifdef __ASSEMBLER__
+#  ifdef SHARED
+#   define PTR_GUARD_LOAD(tmpreg)					\
+	larl	tmpreg,__pointer_chk_guard@GOTENT;			\
+	lg	tmpreg,0(tmpreg);					\
+	lg	tmpreg,0(tmpreg)
+#  else
+#   define PTR_GUARD_LOAD(tmpreg)					\
+	larl	tmpreg,__pointer_chk_guard_local;			\
+	lg	tmpreg,0(tmpreg)
+#  endif
 #  define PTR_MANGLE(reg, tmpreg) \
-  ear     tmpreg,%a0;			\
-  sllg    tmpreg,tmpreg,32;		\
-  ear     tmpreg,%a1;			\
-  xg      reg,STACK_GUARD(tmpreg)
+	PTR_GUARD_LOAD (tmpreg);					\
+	xgr	reg,tmpreg
 #  define PTR_MANGLE2(reg, tmpreg) \
-  xg      reg,STACK_GUARD(tmpreg)
+	xgr	reg,tmpreg
 #  define PTR_DEMANGLE(reg, tmpreg) PTR_MANGLE (reg, tmpreg)
+#  define PTR_DEMANGLE2(reg, tmpreg) PTR_MANGLE2 (reg, tmpreg)
 # else
 #  include <stdint.h>
-#  include <tls.h>
+#  ifdef SHARED
+extern uintptr_t __pointer_chk_guard attribute_relro;
+#   define PTR_GUARD_VALUE	__pointer_chk_guard
+#  else
+extern uintptr_t __pointer_chk_guard_local attribute_relro attribute_hidden;
+#   define PTR_GUARD_VALUE	__pointer_chk_guard_local
+#  endif
 #  define PTR_MANGLE(var) \
-  (var) = (void *) ((uintptr_t) (var) ^ THREAD_GET_POINTER_GUARD ())
+  (var) = (void *) ((uintptr_t) (var) ^ PTR_GUARD_VALUE)
 #  define PTR_DEMANGLE(var)	PTR_MANGLE (var)
 # endif
 #endif
diff --git a/sysdeps/unix/sysv/linux/sh/pointer_guard.h b/sysdeps/unix/sysv/linux/sh/pointer_guard.h
index f1ec4b41f4..fa989573c9 100644
--- a/sysdeps/unix/sysv/linux/sh/pointer_guard.h
+++ b/sysdeps/unix/sysv/linux/sh/pointer_guard.h
@@ -1,4 +1,4 @@
-/* Pointer obfuscation implenentation.  Generic (no-op) version.
+/* Pointer obfuscation implenentation.  SH version.
    Copyright (C) 2005-2026 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
@@ -20,22 +20,59 @@
 #define POINTER_GUARD_H
 
 #if IS_IN (rtld)
-/* We cannot use the thread descriptor because in ld.so we use setjmp
-   earlier than the descriptor is initialized.  Using a global variable
-   is too complicated here since we have no PC-relative addressing mode.  */
 # include <sysdeps/generic/pointer_guard.h>
 #else
 # ifdef __ASSEMBLER__
+#  ifdef SHARED
+#   define PTR_GUARD_SYM	__pointer_chk_guard
+#  else
+#   define PTR_GUARD_SYM	__pointer_chk_guard_local
+#  endif
+#  ifdef PIC
+#   define PTR_GUARD_LOAD(tmp)						\
+	mov	r0, r3;							\
+	mova	.Lptrg_got, r0;						\
+	mov.l	.Lptrg_got, tmp;					\
+	add	r0, tmp;						\
+	mov.l	.Lptrg_sym, r0;						\
+	mov.l	@(r0, tmp), tmp;					\
+	mov	r3, r0;							\
+	mov.l	@tmp, tmp;						\
+	bra	.Lptrg_end;						\
+	 nop;								\
+	.align	2;							\
+.Lptrg_got:								\
+	.long	_GLOBAL_OFFSET_TABLE_;					\
+.Lptrg_sym:								\
+	.long	PTR_GUARD_SYM@GOT;					\
+.Lptrg_end:
+#  else
+#   define PTR_GUARD_LOAD(tmp)						\
+	mov.l	.Lptrg_sym, tmp;					\
+	mov.l	@tmp, tmp;						\
+	bra	.Lptrg_end;						\
+	 nop;								\
+	.align	2;							\
+.Lptrg_sym:								\
+	.long	PTR_GUARD_SYM;						\
+.Lptrg_end:
+#  endif
 #  define PTR_MANGLE(reg, tmp) \
-     stc gbr,tmp; mov.l @(POINTER_GUARD,tmp),tmp; xor tmp,reg
+     PTR_GUARD_LOAD (tmp); xor tmp,reg
 #  define PTR_MANGLE2(reg, tmp) xor tmp,reg
 #  define PTR_DEMANGLE(reg, tmp)        PTR_MANGLE (reg, tmp)
 #  define PTR_DEMANGLE2(reg, tmp)       PTR_MANGLE2 (reg, tmp)
 # else
 #  include <stdint.h>
-#  include <tls.h>
-#  define PTR_MANGLE(var) \
-     (var) = (void *) ((uintptr_t) (var) ^ THREAD_GET_POINTER_GUARD ())
+#  ifdef SHARED
+extern uintptr_t __pointer_chk_guard attribute_relro;
+#   define PTR_MANGLE(var) \
+     (var) = (void *) ((uintptr_t) (var) ^ __pointer_chk_guard)
+#  else
+extern uintptr_t __pointer_chk_guard_local attribute_relro attribute_hidden;
+#   define PTR_MANGLE(var) \
+     (var) = (void *) ((uintptr_t) (var) ^ __pointer_chk_guard_local)
+#  endif
 #  define PTR_DEMANGLE(var)     PTR_MANGLE (var)
 # endif
 #endif
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/pointer_guard.h b/sysdeps/unix/sysv/linux/sparc/sparc32/pointer_guard.h
index 4359bf9fca..f314f8598b 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc32/pointer_guard.h
+++ b/sysdeps/unix/sysv/linux/sparc/sparc32/pointer_guard.h
@@ -25,18 +25,45 @@
 # include <sysdeps/generic/pointer_guard.h>
 #else
 # ifdef __ASSEMBLER__
+#  include <sysdep.h>
+#  ifdef SHARED
+#   define PTR_GUARD_SYM	__pointer_chk_guard
+#  else
+#   define PTR_GUARD_SYM	__pointer_chk_guard_local
+#  endif
+#  ifdef PIC
+/* Load the guard through the GOT.  SETUP_PIC_REG_LEAF computes the GOT
+   pointer in %o2 while preserving %o7 (the return address, which setjmp
+   mangles), using %o3 as a scratch register.  */
+#   define PTR_GUARD_LOAD(tmpreg)					\
+	SETUP_PIC_REG_LEAF(o2, o3);					\
+	sethi	%gdop_hix22(PTR_GUARD_SYM), tmpreg;			\
+	xor	tmpreg, %gdop_lox10(PTR_GUARD_SYM), tmpreg;		\
+	ld	[%o2 + tmpreg], tmpreg, %gdop(PTR_GUARD_SYM);		\
+	ld	[tmpreg], tmpreg
+#  else
+#   define PTR_GUARD_LOAD(tmpreg)					\
+	sethi	%hi(PTR_GUARD_SYM), tmpreg;				\
+	ld	[tmpreg + %lo(PTR_GUARD_SYM)], tmpreg
+#  endif
 #  define PTR_MANGLE(dreg, reg, tmpreg) \
-  ld    [%g7 + POINTER_GUARD], tmpreg; \
-  xor   reg, tmpreg, dreg
+	PTR_GUARD_LOAD (tmpreg);					\
+	xor	reg, tmpreg, dreg
 #  define PTR_DEMANGLE(dreg, reg, tmpreg) PTR_MANGLE (dreg, reg, tmpreg)
 #  define PTR_MANGLE2(dreg, reg, tmpreg) \
-  xor   reg, tmpreg, dreg
+	xor	reg, tmpreg, dreg
 #  define PTR_DEMANGLE2(dreg, reg, tmpreg) PTR_MANGLE2 (dreg, reg, tmpreg)
 # else
 #  include <stdint.h>
-#  include <tls.h>
-#  define PTR_MANGLE(var) \
-  (var) = (__typeof (var)) ((uintptr_t) (var) ^ THREAD_GET_POINTER_GUARD ())
+#  ifdef SHARED
+extern uintptr_t __pointer_chk_guard attribute_relro;
+#   define PTR_MANGLE(var) \
+  (var) = (__typeof (var)) ((uintptr_t) (var) ^ __pointer_chk_guard)
+#  else
+extern uintptr_t __pointer_chk_guard_local attribute_relro attribute_hidden;
+#   define PTR_MANGLE(var) \
+  (var) = (__typeof (var)) ((uintptr_t) (var) ^ __pointer_chk_guard_local)
+#  endif
 #  define PTR_DEMANGLE(var)     PTR_MANGLE (var)
 # endif
 #endif
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/pointer_guard.h b/sysdeps/unix/sysv/linux/sparc/sparc64/pointer_guard.h
index 91bc1f4d85..6515e0dd07 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc64/pointer_guard.h
+++ b/sysdeps/unix/sysv/linux/sparc/sparc64/pointer_guard.h
@@ -25,18 +25,44 @@
 # include <sysdeps/generic/pointer_guard.h>
 #else
 # ifdef __ASSEMBLER__
+#  include <sysdep.h>
+#  ifdef SHARED
+#   define PTR_GUARD_SYM	__pointer_chk_guard
+#  else
+#   define PTR_GUARD_SYM	__pointer_chk_guard_local
+#  endif
+#  ifdef PIC
+/* Load the guard through the GOT.  SETUP_PIC_REG_LEAF computes the GOT
+   pointer in %o2 while preserving %o7, using %o3 as a scratch register.  */
+#   define PTR_GUARD_LOAD(tmpreg)					\
+	SETUP_PIC_REG_LEAF(o2, o3);					\
+	sethi	%gdop_hix22(PTR_GUARD_SYM), tmpreg;			\
+	xor	tmpreg, %gdop_lox10(PTR_GUARD_SYM), tmpreg;		\
+	ldx	[%o2 + tmpreg], tmpreg, %gdop(PTR_GUARD_SYM);		\
+	ldx	[tmpreg], tmpreg
+#  else
+#   define PTR_GUARD_LOAD(tmpreg)					\
+	sethi	%hi(PTR_GUARD_SYM), tmpreg;				\
+	ldx	[tmpreg + %lo(PTR_GUARD_SYM)], tmpreg
+#  endif
 #  define PTR_MANGLE(dreg, reg, tmpreg) \
-  ldx   [%g7 + POINTER_GUARD], tmpreg; \
-  xor   reg, tmpreg, dreg
+	PTR_GUARD_LOAD (tmpreg);					\
+	xor	reg, tmpreg, dreg
 #  define PTR_DEMANGLE(dreg, reg, tmpreg) PTR_MANGLE (dreg, reg, tmpreg)
 #  define PTR_MANGLE2(dreg, reg, tmpreg) \
-  xor   reg, tmpreg, dreg
+	xor	reg, tmpreg, dreg
 #  define PTR_DEMANGLE2(dreg, reg, tmpreg) PTR_MANGLE2 (dreg, reg, tmpreg)
 # else
 #  include <stdint.h>
-#  include <tls.h>
-#  define PTR_MANGLE(var) \
-  (var) = (__typeof (var)) ((uintptr_t) (var) ^ THREAD_GET_POINTER_GUARD ())
+#  ifdef SHARED
+extern uintptr_t __pointer_chk_guard attribute_relro;
+#   define PTR_MANGLE(var) \
+  (var) = (__typeof (var)) ((uintptr_t) (var) ^ __pointer_chk_guard)
+#  else
+extern uintptr_t __pointer_chk_guard_local attribute_relro attribute_hidden;
+#   define PTR_MANGLE(var) \
+  (var) = (__typeof (var)) ((uintptr_t) (var) ^ __pointer_chk_guard_local)
+#  endif
 #  define PTR_DEMANGLE(var)     PTR_MANGLE (var)
 # endif
 #endif
diff --git a/sysdeps/unix/sysv/linux/x86_64/pointer_guard.h b/sysdeps/unix/sysv/linux/x86_64/pointer_guard.h
index 4f7abc64f4..6d09b429cd 100644
--- a/sysdeps/unix/sysv/linux/x86_64/pointer_guard.h
+++ b/sysdeps/unix/sysv/linux/x86_64/pointer_guard.h
@@ -22,9 +22,8 @@
 #include <x86-lp_size.h>
 #include <tcb-offsets.h>
 
-#if IS_IN (rtld)
-/* We cannot use the thread descriptor because in ld.so we use setjmp
-   earlier than the descriptor is initialized.  */
+#if (IS_IN (rtld) \
+     || (!defined SHARED && (IS_IN (libc) || IS_IN (libpthread))))
 # ifdef __ASSEMBLER__
 #  define PTR_MANGLE(reg)	xor __pointer_chk_guard_local(%rip), reg;     \
 				rol $2*LP_SIZE+1, reg
@@ -51,17 +50,20 @@ extern uintptr_t __pointer_chk_guard_local attribute_relro attribute_hidden;
 # endif
 #else
 # ifdef __ASSEMBLER__
-#  define PTR_MANGLE(reg)	xor %fs:POINTER_GUARD, reg;		      \
+#  define PTR_MANGLE(reg)	mov __pointer_chk_guard@GOTPCREL(%rip), %R11_LP;\
+				xor (%R11_LP), reg;			      \
 				rol $2*LP_SIZE+1, reg
 #  define PTR_DEMANGLE(reg)	ror $2*LP_SIZE+1, reg;			      \
-				xor %fs:POINTER_GUARD, reg
+				mov __pointer_chk_guard@GOTPCREL(%rip), %R11_LP;\
+				xor (%R11_LP), reg
 # else
 #  include <stdbit.h>
-#  include <tls.h>
+#  include <stdint.h>
+extern uintptr_t __pointer_chk_guard attribute_relro;
 #  define PTR_MANGLE(var)						      \
     do {								      \
       (var) = (__typeof (var)) ((uintptr_t) (var)			      \
-				^ ((tcbhead_t __seg_fs *)0)->pointer_guard);  \
+				^ __pointer_chk_guard);			      \
       (var) = (__typeof (var)) stdc_rotate_left ((uintptr_t) (var),	      \
 						 2 * sizeof (uintptr_t) + 1); \
     } while (0)
@@ -70,7 +72,7 @@ extern uintptr_t __pointer_chk_guard_local attribute_relro attribute_hidden;
       (var) = (__typeof (var)) stdc_rotate_right ((uintptr_t) (var),	      \
 						  2 * sizeof (uintptr_t) + 1); \
       (var) = (__typeof (var)) ((uintptr_t) (var)			      \
-				^ ((tcbhead_t __seg_fs *)0)->pointer_guard);  \
+				^ __pointer_chk_guard);			      \
     } while (0)
 # endif
 #endif
diff --git a/sysdeps/x86_64/htl/tcb-offsets.sym b/sysdeps/x86_64/htl/tcb-offsets.sym
index 7b7c719369..b36cfd6848 100644
--- a/sysdeps/x86_64/htl/tcb-offsets.sym
+++ b/sysdeps/x86_64/htl/tcb-offsets.sym
@@ -4,5 +4,4 @@
 
 MULTIPLE_THREADS_OFFSET offsetof (tcbhead_t, multiple_threads)
 SYSINFO_OFFSET          offsetof (tcbhead_t, sysinfo)
-POINTER_GUARD           offsetof (tcbhead_t, pointer_guard)
 SIGSTATE_OFFSET         offsetof (tcbhead_t, _hurd_sigstate)
diff --git a/sysdeps/x86_64/nptl/tcb-offsets.sym b/sysdeps/x86_64/nptl/tcb-offsets.sym
index 988a4b8593..aaa1dacd0c 100644
--- a/sysdeps/x86_64/nptl/tcb-offsets.sym
+++ b/sysdeps/x86_64/nptl/tcb-offsets.sym
@@ -10,6 +10,5 @@ CLEANUP			offsetof (struct pthread, cleanup)
 CLEANUP_PREV		offsetof (struct _pthread_cleanup_buffer, __prev)
 MUTEX_FUTEX		offsetof (pthread_mutex_t, __data.__lock)
 MULTIPLE_THREADS_OFFSET	offsetof (tcbhead_t, multiple_threads)
-POINTER_GUARD		offsetof (tcbhead_t, pointer_guard)
 FEATURE_1_OFFSET	offsetof (tcbhead_t, feature_1)
 SSP_BASE_OFFSET		offsetof (tcbhead_t, ssp_base)
diff --git a/sysdeps/x86_64/nptl/tls.h b/sysdeps/x86_64/nptl/tls.h
index 836b2e2244..413ab074bf 100644
--- a/sysdeps/x86_64/nptl/tls.h
+++ b/sysdeps/x86_64/nptl/tls.h
@@ -49,7 +49,7 @@ typedef struct
   int gscope_flag;
   uintptr_t sysinfo;
   uintptr_t stack_guard;
-  uintptr_t pointer_guard;
+  uintptr_t __unused;
   unsigned long int unused_vgetcpu_cache[2];
   /* Bit 0: X86_FEATURE_1_IBT.
      Bit 1: X86_FEATURE_1_SHSTK.
@@ -186,14 +186,6 @@ _Static_assert (offsetof (tcbhead_t, __glibc_unused2) == 0x80,
      = THREAD_GETMEM (THREAD_SELF, header.stack_guard))
 
 
-/* Set the pointer guard field in the TCB head.  */
-# define THREAD_SET_POINTER_GUARD(value) \
-  THREAD_SETMEM (THREAD_SELF, header.pointer_guard, value)
-# define THREAD_COPY_POINTER_GUARD(descr) \
-  ((descr)->header.pointer_guard					      \
-   = THREAD_GETMEM (THREAD_SELF, header.pointer_guard))
-
-
 /* Get and set the global scope generation counter in the TCB head.  */
 # define THREAD_GSCOPE_FLAG_UNUSED 0
 # define THREAD_GSCOPE_FLAG_USED   1
diff --git a/sysdeps/x86_64/stackguard-macros.h b/sysdeps/x86_64/stackguard-macros.h
index 77f13c986d..3d685e0f82 100644
--- a/sysdeps/x86_64/stackguard-macros.h
+++ b/sysdeps/x86_64/stackguard-macros.h
@@ -1,3 +1,11 @@
+#include <stdint.h>
+
 #define STACK_CHK_GUARD (((tcbhead_t __seg_fs *)0)->stack_guard)
 
-#define POINTER_CHK_GUARD (((tcbhead_t __seg_fs *)0)->pointer_guard)
+#ifdef PTRGUARD_LOCAL
+extern uintptr_t __pointer_chk_guard_local;
+# define POINTER_CHK_GUARD __pointer_chk_guard_local
+#else
+extern uintptr_t __pointer_chk_guard;
+# define POINTER_CHK_GUARD __pointer_chk_guard
+#endif