[2/8] Consolidate pointer guard to use a relro variable instead of the TCB

Message ID 20260603000656.3287796-3-adhemerval.zanella@linaro.org (mailing list archive)
State Superseded
Delegated to: DJ Delorie
Headers
Series Pointer guard hardening and consolidation |

Checks

Context Check Description
redhat-pt-bot/TryBot-apply_patch success Patch applied to master at the time it was sent
linaro-tcwg-bot/tcwg_glibc_build--master-aarch64 success Build passed
linaro-tcwg-bot/tcwg_glibc_check--master-aarch64 success Test passed
linaro-tcwg-bot/tcwg_glibc_build--master-arm success Build passed
linaro-tcwg-bot/tcwg_glibc_check--master-arm success Test passed

Commit Message

Adhemerval Zanella Netto June 3, 2026, 12:04 a.m. UTC
  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.

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.
---
 sysdeps/i386/htl/tcb-offsets.sym              |  1 -
 sysdeps/i386/nptl/tcb-offsets.sym             |  1 -
 sysdeps/i386/nptl/tls.h                       | 10 +---
 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/pointer_guard.h  | 50 +++++++++++++----
 .../unix/sysv/linux/powerpc/pointer_guard.h   | 55 ++++++++++++++-----
 sysdeps/unix/sysv/linux/s390/pointer_guard.h  | 33 +++++++----
 sysdeps/unix/sysv/linux/sh/pointer_guard.h    | 53 +++++++++++++++---
 .../sysv/linux/sparc/sparc32/pointer_guard.h  | 40 ++++++++++++--
 .../sysv/linux/sparc/sparc64/pointer_guard.h  | 38 +++++++++++--
 .../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 +++-
 31 files changed, 290 insertions(+), 189 deletions(-)
  

Comments

DJ Delorie June 10, 2026, 3:03 a.m. UTC | #1
LGTM
Reviewed-by: DJ Delorie <dj@redhat.com>

Adhemerval Zanella <adhemerval.zanella@linaro.org> writes:
> diff --git a/sysdeps/i386/htl/tcb-offsets.sym b/sysdeps/i386/htl/tcb-offsets.sym
> index 7b7c7193695..b36cfd6848a 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)

Ok.

> diff --git a/sysdeps/i386/nptl/tcb-offsets.sym b/sysdeps/i386/nptl/tcb-offsets.sym
> index 2ec9e787c1f..48f79845129 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)

Ok.

> diff --git a/sysdeps/i386/nptl/tls.h b/sysdeps/i386/nptl/tls.h
> index 87dcf5dc1f4..fb8684230fb 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;

Ok.

> @@ -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))
> -
> -

Ok.

> diff --git a/sysdeps/i386/stackguard-macros.h b/sysdeps/i386/stackguard-macros.h
> +#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

Ok.

> diff --git a/sysdeps/mach/hurd/i386/tls.h b/sysdeps/mach/hurd/i386/tls.h
>    int multiple_threads;
>    uintptr_t sysinfo;
>    uintptr_t stack_guard;
> -  uintptr_t pointer_guard;
> +  uintptr_t __unused;

Ok.

> @@ -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))
> -

Ok.

> diff --git a/sysdeps/mach/hurd/x86_64/tls.h b/sysdeps/mach/hurd/x86_64/tls.h
> index 85ea75b5b51..3543e9be347 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;

Ok.

> @@ -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))

Ok.

> diff --git a/sysdeps/powerpc/nptl/tcb-offsets.sym b/sysdeps/powerpc/nptl/tcb-offsets.sym
>  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))

Ok.

> diff --git a/sysdeps/powerpc/nptl/tls.h b/sysdeps/powerpc/nptl/tls.h
>  /* 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.  */

Ok.

> @@ -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;

Ok.

> @@ -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())
> -

Ok.

> diff --git a/sysdeps/powerpc/powerpc32/stackguard-macros.h b/sysdeps/powerpc/powerpc32/stackguard-macros.h
> -#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

Ok.

> diff --git a/sysdeps/powerpc/powerpc64/stackguard-macros.h b/sysdeps/powerpc/powerpc64/stackguard-macros.h
>  #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

Ok.

> diff --git a/sysdeps/s390/__longjmp.c b/sysdeps/s390/__longjmp.c
>  __longjmp (__jmp_buf env, int val)
>  {
>  #ifdef PTR_DEMANGLE
> -  uintptr_t guard = THREAD_GET_POINTER_GUARD ();
> +  uintptr_t guard = PTR_GUARD_VALUE;

Ok.

> diff --git a/sysdeps/s390/nptl/tls.h b/sysdeps/s390/nptl/tls.h
>    ((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)
> -

Ok.

> diff --git a/sysdeps/s390/stackguard-macros.h b/sysdeps/s390/stackguard-macros.h
>  #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

Ok.

> diff --git a/sysdeps/sh/nptl/tcb-offsets.sym b/sysdeps/sh/nptl/tcb-offsets.sym
>  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)

Ok.

> diff --git a/sysdeps/sh/nptl/tls.h b/sysdeps/sh/nptl/tls.h
>  typedef struct
>  {
>    dtv_t *dtv;
> -  uintptr_t pointer_guard;
> +  uintptr_t __unused;
>  } tcbhead_t;

Ok.

> @@ -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;})
> -

Ok.

> diff --git a/sysdeps/sh/stackguard-macros.h b/sysdeps/sh/stackguard-macros.h
>  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

Ok.

> diff --git a/sysdeps/sparc/nptl/tcb-offsets.sym b/sysdeps/sparc/nptl/tcb-offsets.sym
>  #include <tls.h>
>  
>  MULTIPLE_THREADS_OFFSET		offsetof (tcbhead_t, multiple_threads)
> -POINTER_GUARD			offsetof (tcbhead_t, pointer_guard)

Ok.

> diff --git a/sysdeps/sparc/nptl/tls.h b/sysdeps/sparc/nptl/tls.h
>  #endif
>    uintptr_t sysinfo;
>    uintptr_t stack_guard;
> -  uintptr_t pointer_guard;
> +  uintptr_t __unused;

Ok.

> @@ -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 ())
> -

Ok.

> diff --git a/sysdeps/sparc/sparc32/stackguard-macros.h b/sysdeps/sparc/sparc32/stackguard-macros.h
>  #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

Ok.

> diff --git a/sysdeps/sparc/sparc64/stackguard-macros.h b/sysdeps/sparc/sparc64/stackguard-macros.h
>  #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

Ok.

> diff --git a/sysdeps/unix/sysv/linux/i386/pointer_guard.h b/sysdeps/unix/sysv/linux/i386/pointer_guard.h
>  #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.  */

Ok.

>  # include <sysdeps/generic/pointer_guard.h>
>  #else
>  # ifdef __ASSEMBLER__
> +#  include <sysdep.h>
> +#  ifdef SHARED
> +/* The global guard is reached through the GOT.  setjmp/__longjmp save and
> +   restore %ebx and %esi around the mangling, so they can be used here as
> +   the GOT pointer and a scratch register.  */

Ok; at the moment this is only used for i386 setjmp/__longjmp (the
non-asm PTR_MANGLE is used many other places)

> -#  define PTR_MANGLE(reg)	xorl %gs:POINTER_GUARD, reg;		      \
> +#   define PTR_MANGLE(reg)	LOAD_PIC_REG (bx);			      \
> +				movl __pointer_chk_guard@GOT(%ebx), %esi;     \
> +				xorl (%esi), reg;			      \
>  				roll $9, reg

Ok.

> -#  define PTR_DEMANGLE(reg)	rorl $9, reg;				      \
> -				xorl %gs:POINTER_GUARD, reg
> +#   define PTR_DEMANGLE(reg)	rorl $9, reg;				      \
> +				LOAD_PIC_REG (bx);			      \
> +				movl __pointer_chk_guard@GOT(%ebx), %esi;     \
> +				xorl (%esi), reg

Ok.

> +#  elif defined PIC
> +/* Static PIE: the module-local guard is reached via @GOTOFF.  */
> +#   define PTR_MANGLE(reg)	LOAD_PIC_REG (bx);			      \
> +				xorl __pointer_chk_guard_local@GOTOFF(%ebx), reg; \
> +				roll $9, reg

Ok.

> +#   define PTR_DEMANGLE(reg)	rorl $9, reg;				      \
> +				LOAD_PIC_REG (bx);			      \
> +				xorl __pointer_chk_guard_local@GOTOFF(%ebx), reg

Ok.

> +#  else
> +/* Position-dependent code addresses the guard directly.  */
> +#   define PTR_MANGLE(reg)	xorl __pointer_chk_guard_local, reg;	      \
> +				roll $9, reg
> +#   define PTR_DEMANGLE(reg)	rorl $9, reg;				      \
> +				xorl __pointer_chk_guard_local, reg
> +#  endif

Ok.

>  # 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)

ok.

> @@ -46,8 +73,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)

Ok.

> diff --git a/sysdeps/unix/sysv/linux/powerpc/pointer_guard.h b/sysdeps/unix/sysv/linux/powerpc/pointer_guard.h
> -/* 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__
> -#  if defined(__PPC64__) || defined(__powerpc64__)
> -#   define LOAD  ld
> -#   define TPREG r13
> +#  include <sysdep.h>
> +#  ifdef SHARED
> +#   define PTR_GUARD_SYM	__pointer_chk_guard
>  #  else
> -#   define LOAD  lwz
> -#   define TPREG r2
> +#   define PTR_GUARD_SYM	__pointer_chk_guard_local
>  #  endif
> +
> +#  if defined(__PPC64__) || defined(__powerpc64__)
> +#   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 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

Ok.

> -#  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

Ok.

> diff --git a/sysdeps/unix/sysv/linux/s390/pointer_guard.h b/sysdeps/unix/sysv/linux/s390/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

Ok.

>  #  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)

Ok.

>  # 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

Ok.

> diff --git a/sysdeps/unix/sysv/linux/sh/pointer_guard.h b/sysdeps/unix/sysv/linux/sh/pointer_guard.h
> -/* Pointer obfuscation implenentation.  Generic (no-op) version.
> +/* Pointer obfuscation implenentation.  SH version.

Ok.

> @@ -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

Ok.

> +#  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:

Ok.

> +#  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:

Ok.

>  #  define PTR_MANGLE(reg, tmp) \
> -     stc gbr,tmp; mov.l @(POINTER_GUARD,tmp),tmp; xor tmp,reg
> +     PTR_GUARD_LOAD (tmp); xor tmp,reg

Ok.

> -#  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

Ok.

> diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/pointer_guard.h b/sysdeps/unix/sysv/linux/sparc/sparc32/pointer_guard.h
>  # 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; both are dead at every
> +   mangling site.  */
> +#   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

Ok.

>  #  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)

Ok.

>  # 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

Ok.

> diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/pointer_guard.h b/sysdeps/unix/sysv/linux/sparc/sparc64/pointer_guard.h
>  # 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

Ok.

>  #  define PTR_MANGLE(dreg, reg, tmpreg) \
> -  ldx   [%g7 + POINTER_GUARD], tmpreg; \
> -  xor   reg, tmpreg, dreg
> +	PTR_GUARD_LOAD (tmpreg);					\
> +	xor	reg, tmpreg, dreg

Ok.

>  #  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

Ok.

> diff --git a/sysdeps/unix/sysv/linux/x86_64/pointer_guard.h b/sysdeps/unix/sysv/linux/x86_64/pointer_guard.h
>  #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))))

Ok.

> @@ -51,17 +50,20 @@ extern uintptr_t __pointer_chk_guard_local attribute_relro attribute_hidden;
> -#  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

Ok.

>  #  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

Ok.

>  #  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

Ok.

> diff --git a/sysdeps/x86_64/htl/tcb-offsets.sym b/sysdeps/x86_64/htl/tcb-offsets.sym
>  
>  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)

Ok.

> diff --git a/sysdeps/x86_64/nptl/tcb-offsets.sym b/sysdeps/x86_64/nptl/tcb-offsets.sym
> -POINTER_GUARD		offsetof (tcbhead_t, pointer_guard)

Ok.

> diff --git a/sysdeps/x86_64/nptl/tls.h b/sysdeps/x86_64/nptl/tls.h
>    int gscope_flag;
>    uintptr_t sysinfo;
>    uintptr_t stack_guard;
> -  uintptr_t pointer_guard;
> +  uintptr_t __unused;

Ok.

> @@ -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))
> -
> -

Ok.

> diff --git a/sysdeps/x86_64/stackguard-macros.h b/sysdeps/x86_64/stackguard-macros.h
> index 77f13c986d8..3d685e0f828 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

Ok.
  

Patch

diff --git a/sysdeps/i386/htl/tcb-offsets.sym b/sysdeps/i386/htl/tcb-offsets.sym
index 7b7c7193695..b36cfd6848a 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 2ec9e787c1f..48f79845129 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 87dcf5dc1f4..fb8684230fb 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/stackguard-macros.h b/sysdeps/i386/stackguard-macros.h
index 2939934ef19..696a9777027 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 8cd643cdcf0..403395db9a8 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 85ea75b5b51..3543e9be347 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 9b29fe8d1a1..bc88ecdddbf 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 4ef6dd1a2fc..2e735c155bc 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 b3d0af830f2..0c94269a731 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 e80a683e64d..fec2e69f64c 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 7c207e44c6d..78aa70a943c 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 de7e9c64828..41fd473d14a 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 3671c7cd7a1..22e4751a73a 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 234207779dc..f1da9a05156 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 eac95e14c75..7008003344c 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 55a5771b629..b4a6b23ff87 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 f75d02065ed..a64180da039 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 cd2112a6500..361fc11a435 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 1eef0f19f00..e8000a28991 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 cc0c12c0412..99978d8beca 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/pointer_guard.h b/sysdeps/unix/sysv/linux/i386/pointer_guard.h
index c8311be444b..d91b2342055 100644
--- a/sysdeps/unix/sysv/linux/i386/pointer_guard.h
+++ b/sysdeps/unix/sysv/linux/i386/pointer_guard.h
@@ -19,26 +19,53 @@ 
 #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>
+#  ifdef SHARED
+/* The global guard is reached through the GOT.  setjmp/__longjmp save and
+   restore %ebx and %esi around the mangling, so they can be used here as
+   the GOT pointer and a scratch register.  */
+#   define PTR_MANGLE(reg)	LOAD_PIC_REG (bx);			      \
+				movl __pointer_chk_guard@GOT(%ebx), %esi;     \
+				xorl (%esi), reg;			      \
 				roll $9, reg
-#  define PTR_DEMANGLE(reg)	rorl $9, reg;				      \
-				xorl %gs:POINTER_GUARD, reg
+#   define PTR_DEMANGLE(reg)	rorl $9, reg;				      \
+				LOAD_PIC_REG (bx);			      \
+				movl __pointer_chk_guard@GOT(%ebx), %esi;     \
+				xorl (%esi), reg
+#  elif defined PIC
+/* Static PIE: the module-local guard is reached via @GOTOFF.  */
+#   define PTR_MANGLE(reg)	LOAD_PIC_REG (bx);			      \
+				xorl __pointer_chk_guard_local@GOTOFF(%ebx), reg; \
+				roll $9, reg
+#   define PTR_DEMANGLE(reg)	rorl $9, reg;				      \
+				LOAD_PIC_REG (bx);			      \
+				xorl __pointer_chk_guard_local@GOTOFF(%ebx), reg
+#  else
+/* Position-dependent code addresses the guard directly.  */
+#   define PTR_MANGLE(reg)	xorl __pointer_chk_guard_local, reg;	      \
+				roll $9, reg
+#   define PTR_DEMANGLE(reg)	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 +73,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 50d177224ff..864a78ea531 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__
-#  if defined(__PPC64__) || defined(__powerpc64__)
-#   define LOAD  ld
-#   define TPREG r13
+#  include <sysdep.h>
+#  ifdef SHARED
+#   define PTR_GUARD_SYM	__pointer_chk_guard
 #  else
-#   define LOAD  lwz
-#   define TPREG r2
+#   define PTR_GUARD_SYM	__pointer_chk_guard_local
 #  endif
+
+#  if defined(__PPC64__) || defined(__powerpc64__)
+#   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 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 d7a574e94c6..aa75b8c42e5 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 f1ec4b41f4f..fa989573c9e 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 4359bf9fca6..43531defe99 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc32/pointer_guard.h
+++ b/sysdeps/unix/sysv/linux/sparc/sparc32/pointer_guard.h
@@ -25,18 +25,46 @@ 
 # 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; both are dead at every
+   mangling site.  */
+#   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 91bc1f4d85e..6515e0dd072 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 4f7abc64f49..6d09b429cd2 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 7b7c7193695..b36cfd6848a 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 988a4b85936..aaa1dacd0cc 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 836b2e22440..413ab074bf8 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 77f13c986d8..3d685e0f828 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