diff --git a/nptl/Makefile b/nptl/Makefile
index 02862d1c04b..72edba04f64 100644
--- a/nptl/Makefile
+++ b/nptl/Makefile
@@ -387,6 +387,7 @@ tests-internal := \
   tst-sem13 \
   tst-setgetname \
   tst-signal7 \
+  tst-tls-guard \
   # tests-internal
 
 xtests = \
diff --git a/nptl/allocatestack.c b/nptl/allocatestack.c
index b2ecb001136..d15dbe367d8 100644
--- a/nptl/allocatestack.c
+++ b/nptl/allocatestack.c
@@ -150,6 +150,125 @@ get_cached_stack (size_t *sizep, void **memp)
   return result;
 }
 
+/*
+  The thread stack layout depends on whether the ABI places the static TLS
+  (TLS_TCB_AT_TP or TLS_TCB_DTV_TP), if the kernel supports lightweight guard
+  pages (MADV_GUARD_INSTALL), and if the ABI adds an extra TLS guard page
+  (ARCH_HAS_TLS_GUARD).
+
+  For TLS_TCB_AT_TP with !ARCH_HAS_TLS_GUARD:
+
+  * !MADV_GUARD_INSTALL (2 VMAs):
+
+  |------------|-------------------------------------------------------------|
+  | R--        | RW-                                                         |
+  |------------|-----------------------|--------------------|----------------|
+  |            |                       |                    | struct pthread |
+  | GUARD PAGE |        STACK          |                    |                |
+  |            |                       | initial-exec +     |----------------|
+  |            |                       | local-exec TLS     | tcbhead_t      |
+  |------------|-----------------------|--------------------|----------------|
+  low                                                       ^
+                                                            thread pointer
+  * MADV_GUARD_INSTALL (1 VMA):
+  |--------------------------------------------------------------------------|
+  | RW                                                                       |
+  |------------------------------------|--------------------|----------------|
+  |                                    |                    | struct pthread |
+  | (GUARD PAGE)        STACK          |                    |                |
+  |                                    | initial-exec +     |----------------|
+  |                                    | local-exec TLS     | tcbhead_t      |
+  |------------------------------------|--------------------|----------------|
+  low                                                       ^
+                                                            thread pointer
+
+  And with ARCH_HAS_TLS_GUARD:
+
+  * !MADV_GUARD_INSTALL (4 VMAs)
+
+  |------------|-----------------------|-----------|-------------------------|
+  | R--        | RW-                   | R--       | RW-                     |
+  |------------|-----------------------|-----------|---|-----------|---------|
+  |            |                       |           |   |           | struct  |
+  | GUARD PAGE |        STACK          | TLS GUARD |pad| init-exec | pthread |
+  |            |                       |           |   | + loc-exec|---------|
+  |            |                       |           |   | TLS       |tcbhead_t|
+  |------------|-----------------------|-----------|---|-----------|---------|
+  low                                  ^                           ^
+                                       page-aligned                TP
+
+  * MADV_GUARD_INSTALL (1 VMA):
+  |--------------------------------------------------------------------------|
+  | RW                                                                       |
+  |------------------------------------------------|---------------|---------|
+  |                                                |   |           | struct  |
+  | (GUARD PAGE)        STACK          (TLS GUARD) |pad|           | pthread |
+  |                                                |   | init-exec |---------|
+  |                                                |   | + loc-exec|tcbhead_t|
+  |------------------------------------------------|---------------|---------|
+  low                                              ^               ^
+                                                   page-aligned    TP
+
+
+  For TLS_DTV_AT_TP, the thread pointer (TP) points to the start of the static
+  TLS block, and struct pthread sits just before TP.  With !ARCH_HAS_TLS_GUARD:
+
+
+  * !MADV_GUARD_INSTALL (2 VMAs):
+
+  |------------|-------------------------------------------------------------|
+  | R--        | RW-                                                         |
+  |------------|----------------------|----------------|---------------------|
+  |            |                      | struct pthread | initial-exec        |
+  | GUARD PAGE |        STACK         |                | + local-exec TLS    |
+  |            |                      |                |                     |
+  |------------|-------------------------------------------------------------|
+  low                                                  ^                  high
+                                                       thread pointer
+
+  * MADV_GUARD_INSTALL (1 VMA):
+
+  |--------------------------------------------------------------------------|
+  | RW                                                                       |
+  |--------------------------------------------------------------------------|
+  |                                   |struct pthread | initial-exec         |
+  | (GUARD PAGE)        STACK         |               | + local-exec TLS     |
+  |                                   |               |                      |
+  |--------------------------------------------------------------------------|
+  low                                                 ^ thread pointer    high
+
+
+  And with ARCH_HAS_TLS_GUARD:
+
+  * !MADV_GUARD_INSTALL (4 VMAs):
+
+  |------------|-------------------------------------------------------------|
+  | R--        | RW-                  | R--       | RW-                      |
+  |------------|----------------------|-----------|--------------------------|
+  |            |                      |           | struct  | initial-exec   |
+  | GUARD PAGE |        STACK         | TLS GUARD | pthread | + local-exec   |
+  |            |                      |           |         |                |
+  |------------|-------------------------------------------------------------|
+  low                                             ^ thread pointer        high
+
+  * MADV_GUARD_INSTALL (1 VMA):
+
+  |--------------------------------------------------------------------------|
+  | RW                                                                       |
+  |--------------------------------------------------------------------------|
+  |                                               | struct  | initial-exec   |
+  | (GUARD PAGE)        STACK         (TLS GUARD) | pthread | + local-exec   |
+  |                                               |         |                |
+  |--------------------------------------------------------------------------|
+  low                                                 ^ thread pointer    high
+
+
+  - The TLS guard is placed between the usable stack and the static TLS block
+    and takes space from the thread stack.
+  - Its high end is page-aligned at or below the start of static TLS and it
+    is omitted when guardsize == 0.
+  - TLS_TCB_AT_TP only supports _STACK_GROWS_DOWN.  */
+
 /* Assume support for MADV_ADVISE_GUARD, setup_stack_prot will disable it
    and fallback to ALLOCATE_GUARD_PROT_NONE if the madvise call fails.  */
 static int allocate_stack_mode = ALLOCATE_GUARD_MADV_GUARD;
@@ -184,43 +303,129 @@ guard_position (void *mem, size_t size, size_t guardsize, const struct pthread *
 #endif
 }
 
+#if ARCH_HAS_TLS_GUARD
+/* For TLS_TCB_AT_TP the TLS guard sits between the stack and the static TLS
+   area.  Its end is page-aligned at or below the start of static TLS; the
+   caller supplies TGUARDSIZE (already a page multiple).
+
+   For TLS_DTV_AT_TP with a downward-growing stack the TLS guard sits between
+   the usable stack and struct pthread.  Its end is page-aligned at or below
+   the start of struct pthread.
+
+   Returns a pointer to the first byte of the TLS guard, or NULL when
+   TGUARDSIZE is zero.  */
+static __always_inline char *
+tls_guard_end_position (const struct pthread *pd,
+			size_t tls_static_size_for_stack,
+			size_t pagesize_m1)
+{
+# if TLS_TCB_AT_TP
+  char *tls_start = (char *) (pd + 1) - tls_static_size_for_stack;
+  return (char *) ((uintptr_t) tls_start & ~pagesize_m1);
+# elif TLS_DTV_AT_TP
+#  if _STACK_GROWS_DOWN
+  return (char *) ((uintptr_t) pd & ~pagesize_m1);
+#  else
+#   error "TLS guard page does not support _STACK_GROWS_UP"
+#  endif
+# endif
+}
+
+static __always_inline char *
+tls_guard_position (const struct pthread *pd,
+		    size_t tls_static_size_for_stack,
+		    size_t guardsize,
+		    size_t pagesize_m1)
+{
+  return tls_guard_end_position (pd, tls_static_size_for_stack, pagesize_m1)
+    - guardsize;
+}
+#endif
+
 /* Setup the MEM thread stack of SIZE bytes with the required protection flags
-   along with a guard area of GUARDSIZE size.  It first tries with
-   MADV_GUARD_INSTALL, and then fallback to setup the guard area using the
-   extra PROT_NONE mapping.  Update PD with the type of guard area setup.  */
+   along with a guard area of GUARDSIZE size and, when ARCH_HAS_TLS_GUARD is
+   set, a TLS guard area of the same GUARDSIZE between the stack and the
+   static TLS block.
+
+   It first tries with MADV_GUARD_INSTALL, and then falls back to setting up
+   the guard areas using extra PROT_NONE mappings.  Updates PD with the type
+   of guard area setup.  */
 static inline bool
 setup_stack_prot (char *mem, size_t size, struct pthread *pd,
-		  size_t guardsize, size_t pagesize_m1)
+		  size_t guardsize, size_t tls_static_size_for_stack,
+		  size_t pagesize_m1)
 {
   if (__glibc_unlikely (guardsize == 0))
     return true;
 
   char *guard = guard_position (mem, size, guardsize, pd, pagesize_m1);
+
+#if ARCH_HAS_TLS_GUARD
+  /* guardsize > 0 is guaranteed by the early return above.  */
+  char *tls_guard = tls_guard_position (pd, tls_static_size_for_stack,
+					guardsize, pagesize_m1);
+#endif
+
   if (atomic_load_relaxed (&allocate_stack_mode) == ALLOCATE_GUARD_MADV_GUARD)
     {
-      if (__madvise (guard, guardsize, MADV_GUARD_INSTALL) == 0)
+      bool stack_guard_ok = __madvise (guard, guardsize,
+				       MADV_GUARD_INSTALL) == 0;
+      bool tls_guard_ok =
+#if ARCH_HAS_TLS_GUARD
+	__madvise (tls_guard, guardsize, MADV_GUARD_INSTALL) == 0;
+#else
+        true;
+#endif
+
+      if (stack_guard_ok && tls_guard_ok)
 	{
 	  pd->stack_mode = ALLOCATE_GUARD_MADV_GUARD;
 	  return true;
 	}
 
+      /* At least one madvise failed; undo any successful madvise and fall
+	 back to PROT_NONE for both this allocation and future ones.  The
+	 stack memory is already RW (MADV_GUARD mode initial allocation), so
+	 we only need to PROT_NONE the guard regions.  */
+      if (stack_guard_ok)
+	__madvise (guard, guardsize, MADV_GUARD_REMOVE);
+#if ARCH_HAS_TLS_GUARD
+      if (tls_guard_ok)
+	__madvise (tls_guard, guardsize, MADV_GUARD_REMOVE);
+#endif
+
       /* If madvise fails it means the kernel does not support the guard
 	 advise (we assume that the syscall is available, guard is page-aligned
 	 and length is non negative).  The stack has already the expected
-	 protection flags, so it just need to PROT_NONE the guard area.  */
+	 protection flags, so it just need to PROT_NONE the guard areas.  */
       atomic_store_relaxed (&allocate_stack_mode, ALLOCATE_GUARD_PROT_NONE);
+
       if (__mprotect (guard, guardsize, PROT_NONE) != 0)
 	return false;
+#if ARCH_HAS_TLS_GUARD
+      if (__mprotect (tls_guard, guardsize, PROT_NONE) != 0)
+	return false;
+#endif
     }
   else
     {
       const int prot = GL(dl_stack_prot_flags);
       char *guardend = guard + guardsize;
 #if _STACK_GROWS_DOWN
-      /* As defined at guard_position, for architectures with downward stack
-	 the guard page is always at start of the allocated area.  */
+      /* For architectures with downward stack the guard page is always at the
+	 start of the allocated area.  */
+# if ARCH_HAS_TLS_GUARD
+      /* Make the stack area RW (between stack guard and TLS guard).  */
+      if (__mprotect (guardend, tls_guard - guardend, prot) != 0)
+	return false;
+      /* Make the pad + TLS + TCB area RW (after TLS guard).  */
+      char *tls_guardend = tls_guard + guardsize;
+      if (__mprotect (tls_guardend, (mem + size) - tls_guardend, prot) != 0)
+	return false;
+# else
       if (__mprotect (guardend, size - guardsize, prot) != 0)
 	return false;
+# endif /* ARCH_HAS_TLS_GUARD */
 #else
       size_t mprots1 = (uintptr_t) guard - (uintptr_t) mem;
       if (__mprotect (mem, mprots1, prot) != 0)
@@ -235,11 +440,14 @@ setup_stack_prot (char *mem, size_t size, struct pthread *pd,
   return true;
 }
 
-/* Update the guard area of the thread stack MEM of size SIZE with the new
-   GUARDISZE.  It uses the method defined by PD stack_mode.  */
+/* Update the guard areas of the thread stack MEM of size SIZE with the new
+   GUARDSIZE.  Uses the method defined by PD stack_mode.  When
+   ARCH_HAS_TLS_GUARD is set the TLS guard sits between the stack and struct
+   pthread and always has the same size as the stack guard.  */
 static inline bool
 adjust_stack_prot (char *mem, size_t size, struct pthread *pd,
-		   size_t guardsize, size_t pagesize_m1)
+		   size_t guardsize,
+		   size_t tls_static_size_for_stack, size_t pagesize_m1)
 {
   /* The required guard area is larger than the current one.  For
      _STACK_GROWS_DOWN it means the guard should increase as:
@@ -252,27 +460,56 @@ adjust_stack_prot (char *mem, size_t size, struct pthread *pd,
      |stack---------------------------|guard|-----|
      |stack--------------------|new guard---|-----|
 
-     Both madvise and mprotect allows overlap the required region,
+     With ARCH_HAS_TLS_GUARD the TLS guard also need to be increased
+     (TLS guard only supports _STACK_GROWS_DOWN):
+
+     |guard|----------------------|tls_guard|stack|
+     |new guard--|--------------|new guard--|stack|
+
+     Both madvise and mprotect allow overlapping the required region,
      so use the new guard placement with the new size.  */
   if (guardsize > pd->guardsize)
     {
       /* There was no need to previously setup a guard page, so we need
 	 to check whether the kernel supports guard advise.  */
       char *guard = guard_position (mem, size, guardsize, pd, pagesize_m1);
+
+#if ARCH_HAS_TLS_GUARD
+      /* guardsize > 0 is guaranteed by the outer condition.  */
+      char *tls_guard = tls_guard_position (pd, tls_static_size_for_stack,
+					    guardsize, pagesize_m1);
+#endif
+
       if (atomic_load_relaxed (&allocate_stack_mode)
 	  == ALLOCATE_GUARD_MADV_GUARD)
 	{
-	  if (__madvise (guard, guardsize, MADV_GUARD_INSTALL) == 0)
+	  bool stack_ok = __madvise (guard, guardsize,
+				     MADV_GUARD_INSTALL) == 0;
+	  bool tls_ok =
+#if ARCH_HAS_TLS_GUARD
+	    __madvise (tls_guard, guardsize, MADV_GUARD_INSTALL) == 0;
+#else
+	    true;
+#endif
+	  if (stack_ok && tls_ok)
 	    {
 	      pd->stack_mode = ALLOCATE_GUARD_MADV_GUARD;
 	      return true;
 	    }
+	  if (stack_ok)
+	    __madvise (guard, guardsize, MADV_GUARD_REMOVE);
 	  atomic_store_relaxed (&allocate_stack_mode,
 				ALLOCATE_GUARD_PROT_NONE);
 	}
 
       pd->stack_mode = ALLOCATE_GUARD_PROT_NONE;
-      return __mprotect (guard, guardsize, PROT_NONE) == 0;
+      if (__mprotect (guard, guardsize, PROT_NONE) != 0)
+	return false;
+#if ARCH_HAS_TLS_GUARD
+      if (__mprotect (tls_guard, guardsize, PROT_NONE) != 0)
+	return false;
+#endif
+      return true;
     }
   /* The current guard area is larger than the required one.  For
      _STACK_GROWS_DOWN is means change the guard as:
@@ -285,28 +522,48 @@ adjust_stack_prot (char *mem, size_t size, struct pthread *pd,
      |stack---------------------|guard-------|---|
      |stack------------------------|new guard|---|
 
+     With ARCH_HAS_TLS_GUARD the TLS guard also need to be decreased
+     (TLS guard only supports _STACK_GROWS_DOWN):
+
+     |guard-------|----------|tls_guard-----|stack|
+     |new guard|------------------|new guard|stack|
+
      For ALLOCATE_GUARD_MADV_GUARD it means remove the slack area
      (disjointed region of guard and new guard), while for
      ALLOCATE_GUARD_PROT_NONE it requires to mprotect it with the stack
-     protection flags.  */
+     protection flags.  Same logic applies to the TLS guard.  */
   else if (pd->guardsize > guardsize)
     {
-      size_t slacksize = pd->guardsize - guardsize;
       if (pd->stack_mode == ALLOCATE_GUARD_MADV_GUARD)
 	{
+	  size_t slacksize = pd->guardsize - guardsize;
 	  void *slack =
 #if _STACK_GROWS_DOWN
 	    mem + guardsize;
 #else
 	    guard_position (mem, size, pd->guardsize, pd, pagesize_m1);
 #endif
-	  return __madvise (slack, slacksize, MADV_GUARD_REMOVE) == 0;
+	  bool stack_ok = __madvise (slack, slacksize, MADV_GUARD_REMOVE) == 0;
+
+#if ARCH_HAS_TLS_GUARD
+	  char *tls_guard_end =
+	    tls_guard_end_position (pd, tls_static_size_for_stack,
+				    pagesize_m1);
+	  char *old_tls_guard_start = tls_guard_end - pd->guardsize;
+	  bool tls_ok = __madvise (old_tls_guard_start, slacksize,
+				   MADV_GUARD_REMOVE) == 0;
+	  return stack_ok && tls_ok;
+#else
+	  return stack_ok;
+#endif
 	}
       else if (pd->stack_mode == ALLOCATE_GUARD_PROT_NONE)
 	{
 	  const int prot = GL(dl_stack_prot_flags);
+	  bool stack_ok = true;
 #if _STACK_GROWS_DOWN
-	  return __mprotect (mem + guardsize, slacksize, prot) == 0;
+	  size_t slacksize = pd->guardsize - guardsize;
+	  stack_ok = __mprotect (mem + guardsize, slacksize, prot) == 0;
 #else
 	  char *new_guard = (char *)(((uintptr_t) pd - guardsize)
 				     & ~pagesize_m1);
@@ -316,7 +573,20 @@ adjust_stack_prot (char *mem, size_t size, struct pthread *pd,
 	     to the nearest page the size difference might be zero.  */
 	  if (new_guard > old_guard
 	      && __mprotect (old_guard, new_guard - old_guard, prot) != 0)
-	    return false;
+	    stack_ok = false;
+#endif
+
+#if ARCH_HAS_TLS_GUARD
+	  size_t tls_slacksize = pd->guardsize - guardsize;
+	  char *tls_guard_end =
+	    tls_guard_end_position (pd, tls_static_size_for_stack,
+				    pagesize_m1);
+	  char *old_tls_guard_start = tls_guard_end - pd->guardsize;
+	  bool tls_ok = __mprotect (old_tls_guard_start, tls_slacksize,
+				    prot) == 0;
+	  return stack_ok && tls_ok;
+#else
+	  return stack_ok;
 #endif
 	}
     }
@@ -490,14 +760,29 @@ allocate_stack (const struct pthread_attr *attr, struct pthread **pdp,
       reported_guardsize = guardsize;
       if (guardsize > 0 && guardsize < ARCH_MIN_GUARD_SIZE)
 	guardsize = ARCH_MIN_GUARD_SIZE;
-      if (guardsize < attr->guardsize || size + guardsize < guardsize)
+      if (guardsize < attr->guardsize
+	  || INT_ADD_WRAPV (size, guardsize, &size))
 	/* Arithmetic overflow.  */
 	return EINVAL;
-      size += guardsize;
-      if (__builtin_expect (size < ((guardsize + tls_static_size_for_stack
-				     + MINIMAL_REST_STACK + pagesize_m1)
-				    & ~pagesize_m1),
-			    0))
+
+#if ARCH_HAS_TLS_GUARD
+      /* A TLS guard of the same size as the stack guard is placed between the
+	 stack and the static TLS (or struct pthread for TLS_DTV_AT_TP) to
+	 harden against stack buffer overflows that overwrite TLS data.  */
+      if (INT_ADD_WRAPV (size, guardsize, &size))
+	return EINVAL;
+#endif
+
+      size_t min_size;
+      if (INT_ADD_WRAPV (guardsize, tls_static_size_for_stack, &min_size)
+#if ARCH_HAS_TLS_GUARD
+	  || INT_ADD_WRAPV (min_size, guardsize, &min_size)
+#endif
+	  || INT_ADD_WRAPV (min_size, (size_t) MINIMAL_REST_STACK, &min_size)
+	  || INT_ADD_WRAPV (min_size, pagesize_m1, &min_size))
+	return EINVAL;
+      min_size &= ~pagesize_m1;
+      if (__glibc_unlikely (size < min_size))
 	/* The stack is too small (or the guard too large).  */
 	return EINVAL;
 
@@ -531,8 +816,9 @@ allocate_stack (const struct pthread_attr *attr, struct pthread **pdp,
 				   - TLS_PRE_TCB_SIZE);
 #endif
 
-	  /* Now mprotect the required region excluding the guard area.  */
-	  if (!setup_stack_prot (mem, size, pd, guardsize, pagesize_m1))
+	  /* Now mprotect the required region excluding the guard areas.  */
+	  if (!setup_stack_prot (mem, size, pd, guardsize,
+				 tls_static_size_for_stack, pagesize_m1))
 	    {
 	      __munmap (mem, size);
 	      return errno;
@@ -593,9 +879,10 @@ allocate_stack (const struct pthread_attr *attr, struct pthread **pdp,
 	     which will be read next.  */
 	}
 
-      /* Create or resize the guard area if necessary on an already
+      /* Create or resize the guard areas if necessary on an already
 	 allocated stack.  */
-      if (!adjust_stack_prot (mem, size, pd, guardsize, pagesize_m1))
+      if (!adjust_stack_prot (mem, size, pd, guardsize,
+			      tls_static_size_for_stack, pagesize_m1))
 	{
 	  lll_lock (GL (dl_stack_cache_lock), LLL_PRIVATE);
 
@@ -645,11 +932,23 @@ allocate_stack (const struct pthread_attr *attr, struct pthread **pdp,
 
   void *stacktop;
 
+  /* The stack begins before the TLS guard (if any), static TLS, and TCB.
+     When a TLS guard is in use, its start (page-aligned below the static TLS)
+     is the top of the usable stack.
+
+     With TLS_DTV_AT_TP and a downward-growing stack, struct pthread sits just
+     above the usable stack.  When a TLS guard is in use it occupies the pages
+     between the usable stack top and struct pthread.  */
+#if ARCH_HAS_TLS_GUARD
+  if (pd->guardsize > 0)
+    stacktop = tls_guard_position (pd, tls_static_size_for_stack,
+				   pd->guardsize, pagesize_m1);
+  else
+#endif
 #if TLS_TCB_AT_TP
-  /* The stack begins before the TCB and the static TLS block.  */
-  stacktop = ((char *) (pd + 1) - tls_static_size_for_stack);
+    stacktop = (char *) (pd + 1) - tls_static_size_for_stack;
 #elif TLS_DTV_AT_TP
-  stacktop = (char *) (pd - 1);
+    stacktop = (char *) (pd - 1);
 #endif
 
   *stacksize = stacktop - pd->stackblock;
@@ -673,8 +972,8 @@ allocate_stack (const struct pthread_attr *attr, struct pthread **pdp,
 static void
 name_stack_maps (struct pthread *pd, bool set)
 {
-  size_t adjust = pd->stack_mode == ALLOCATE_GUARD_PROT_NONE ?
-    pd->guardsize : 0;
+  enum allocate_stack_mode_t mode = pd->stack_mode;
+  size_t adjust = mode == ALLOCATE_GUARD_PROT_NONE ? pd->guardsize : 0;
 #if _STACK_GROWS_DOWN
   void *stack = pd->stackblock + adjust;
 #else
@@ -682,6 +981,24 @@ name_stack_maps (struct pthread *pd, bool set)
 #endif
   size_t stacksize = pd->stackblock_size - adjust;
 
+#if ARCH_HAS_TLS_GUARD
+  /* With PROT_NONE guards and ARCH_HAS_TLS_GUARD, the TLS guard and TLS
+     data are separate VMAs (mprotect splits the mapping).  Naming the full
+     [stack, stack+stacksize) region would apply the name to all three VMAs
+     (usable stack, TLS guard, TLS data), making the test count 3x too many
+     "pthread stack:" entries.  Limit the name to the usable stack only.
+     With MADV_GUARD_INSTALL the whole block remains one VMA, so no
+     adjustment is needed there.  */
+  if (mode == ALLOCATE_GUARD_PROT_NONE && pd->guardsize > 0)
+    {
+      size_t tls_static_size_for_stack = __nptl_tls_static_size_for_stack ();
+      size_t pagesize_m1 = __getpagesize () - 1;
+      char *tls_guard = tls_guard_position (pd, tls_static_size_for_stack,
+                                           pd->guardsize, pagesize_m1);
+      stacksize = (char *) tls_guard - (char *) stack;
+    }
+#endif
+
   if (!set)
     __set_vma_name (stack, stacksize, " glibc: unused stack");
   else
diff --git a/nptl/pthread_getattr_np.c b/nptl/pthread_getattr_np.c
index b0d2343a59a..359fd8932ff 100644
--- a/nptl/pthread_getattr_np.c
+++ b/nptl/pthread_getattr_np.c
@@ -61,15 +61,33 @@ __pthread_getattr_np (pthread_t thread_id, pthread_attr_t *attr)
   /* The sizes are subject to alignment.  */
   if (__glibc_likely (thread->stackblock != NULL))
     {
-      /* The stack size reported to the user should not include the
-	 guard size.  */
-      iattr->stacksize = thread->stackblock_size - thread->guardsize;
+      /* The reported stack size excludes all guard pages.  The TLS guard
+	 (when ARCH_HAS_TLS_GUARD and guardsize > 0) is allocated on top of
+	 the user-requested size, just like the regular stack guard, so it is
+	 also excluded.  stackaddr is kept at the top of the user-requested
+	 region (excluding the TLS guard overhead).  */
+#if ARCH_HAS_TLS_GUARD
+      if (thread->guardsize > 0)
+	{
+	  iattr->stacksize = thread->stackblock_size - 2 * thread->guardsize;
+# if _STACK_GROWS_DOWN
+	  iattr->stackaddr = (char *) thread->stackblock
+			     + thread->stackblock_size - thread->guardsize;
+# else
+#  error "TLS guard page does not support _STACK_GROWS_UP"
+# endif
+	}
+      else
+#endif /* ARCH_HAS_TLS_GUARD */
+	{
+	  iattr->stacksize = thread->stackblock_size - thread->guardsize;
 #if _STACK_GROWS_DOWN
-      iattr->stackaddr = (char *) thread->stackblock
-			 + thread->stackblock_size;
+	  iattr->stackaddr = (char *) thread->stackblock
+			     + thread->stackblock_size;
 #else
-      iattr->stackaddr = (char *) thread->stackblock;
+	  iattr->stackaddr = (char *) thread->stackblock;
 #endif
+	}
     }
   else
     {
diff --git a/nptl/tst-guard1.c b/nptl/tst-guard1.c
index b97ad23de41..3ac791a13fb 100644
--- a/nptl/tst-guard1.c
+++ b/nptl/tst-guard1.c
@@ -17,6 +17,7 @@
    <https://www.gnu.org/licenses/>.  */
 
 #include <array_length.h>
+#include <pthread.h>
 #include <pthreaddef.h>
 #include <setjmp.h>
 #include <stackinfo.h>
@@ -149,14 +150,38 @@ tf (void *closure)
 
   if (args != NULL)
     {
+      /* pthread_getattr_np must report at least the requested stacksize
+	 and for a freshly allocated stack it reports the exact requested
+	 size.  With ARCH_HAS_TLS_GUARD the value may be larger when the
+	 thread reuses a cached stack that is bigger than strictly needed
+	 (because the TLS guard adds an extra guardsize to every allocation,
+	 shifting  the cached-size distribution so that an exact-fit hit is
+	 unlikely).
+
+	 Without ARCH_HAS_TLS_GUARD the test cases are designed to always
+	 reuse an exact-fit cached stack, so exact equality holds there.  */
+#if ARCH_HAS_TLS_GUARD
+      TEST_VERIFY (s.stacksize >= adjust_stacksize (args->stacksize));
+#else
       TEST_COMPARE (adjust_stacksize (args->stacksize), s.stacksize);
+#endif
       TEST_COMPARE (args->guardsize, s.guardsize);
     }
 
   /* Ensure we can access the stack area.  */
   TEST_COMPARE (try_read_buf (s.stack), true);
   TEST_COMPARE (try_read_buf (&s.stack[s.stacksize / 2]), true);
+  /* With ARCH_HAS_TLS_GUARD and a guard installed, the reported stacksize
+     spans the TLS guard area too (it is part of the overhead like the stack
+     guard).  The last byte may land inside the TLS guard when guardsize >=
+     tls_static_size; only check s.stacksize - 1 when no TLS guard is
+     active to avoid a spurious fault.  */
+#if ARCH_HAS_TLS_GUARD
+  if (s.guardsize == 0)
+    TEST_COMPARE (try_read_buf (&s.stack[s.stacksize - 1]), true);
+#else
   TEST_COMPARE (try_read_buf (&s.stack[s.stacksize - 1]), true);
+#endif
 
   /* Check if accessing the guard area results in SIGSEGV.  */
   if (s.guardsize > 0)
diff --git a/nptl/tst-tls-guard.c b/nptl/tst-tls-guard.c
new file mode 100644
index 00000000000..f416d88e31e
--- /dev/null
+++ b/nptl/tst-tls-guard.c
@@ -0,0 +1,281 @@
+/* Tests for the TLS guard page between stack and static TLS.
+   Copyright (C) 2026 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+/* For architectures that set ARCH_HAS_TLS_GUARD, glibc inserts a guard page
+   between the thread stack and the static TLS / struct pthread area.
+   This test verifies:
+     1. The TLS guard is inaccessible (traps on read/write).
+     2. The stack area below the TLS guard is accessible.
+     3. When guardsize == 0 no TLS guard is added.
+     4. The behaviour is consistent across kernel support for
+        MADV_GUARD_INSTALL and the PROT_NONE fallback.  */
+
+#include <array_length.h>
+#include <pthread.h>
+#include <pthreaddef.h>
+#include <setjmp.h>
+#include <stackinfo.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <support/capture_subprocess.h>
+#include <support/check.h>
+#include <support/check_mem_access.h>
+#include <support/test-driver.h>
+#include <support/xsignal.h>
+#include <support/xthread.h>
+#include <support/xunistd.h>
+#include <tls.h>
+
+#if ARCH_HAS_TLS_GUARD
+
+static long int pagesz;
+
+/* Locate the TLS guard region by probing pages backward from STACK_TOP
+   (which equals (char *)stack + stacksize from pthread_attr_getstack, i.e.
+   approximately the first byte above the TLS guard) down to SCAN_LIMIT.
+   Works for both MADV_GUARD_INSTALL (guard stays inside one RW VMA but
+   pages are inaccessible) and the PROT_NONE fallback (separate ---p VMA).
+   Returns 1 and fills the output pointers on success, 0 if no inaccessible
+   region is found within the scan range.  */
+static int
+find_tls_guard (char *stack_top, char *scan_limit, long pagesize,
+                char **guard_start_out, size_t *guard_size_out)
+{
+  char *guard_end = NULL;
+  char *guard_start = NULL;
+  char *p = stack_top;
+  /* Probe at most 128 pages.  The TLS guard sits within a few pages of
+     stack_top (static-TLS alignment overhead is typically 1–2 pages);
+     128 pages gives ample headroom for large-TLS workloads.  */
+  char *stop = stack_top - 128 * pagesize;
+  if (stop < scan_limit)
+    stop = scan_limit;
+
+  while (p > stop)
+    {
+      p -= pagesize;
+      if (!check_mem_access (p, false))
+        {
+          if (guard_end == NULL)
+            guard_end = p + pagesize;
+          guard_start = p;
+        }
+      else if (guard_end != NULL)
+        break;
+    }
+
+  if (guard_end == NULL)
+    return 0;
+
+  *guard_start_out = guard_start;
+  *guard_size_out  = (size_t) (guard_end - guard_start);
+  return 1;
+}
+
+struct thread_args
+{
+  int expect_tls_guard;  /* 1: TLS guard expected, 0: not expected */
+};
+
+static void *
+tf (void *closure)
+{
+  struct thread_args *args = closure;
+
+  pthread_attr_t attr;
+  TEST_VERIFY_EXIT (pthread_getattr_np (pthread_self (), &attr) == 0);
+
+  void *stack;
+  size_t stacksize;
+  TEST_VERIFY_EXIT (pthread_attr_getstack (&attr, &stack, &stacksize) == 0);
+
+  size_t guardsize;
+  TEST_VERIFY_EXIT (pthread_attr_getguardsize (&attr, &guardsize) == 0);
+  if (guardsize != 0 && guardsize < ARCH_MIN_GUARD_SIZE)
+    guardsize = ARCH_MIN_GUARD_SIZE;
+  pthread_attr_destroy (&attr);
+
+  /* Verify the stack area is accessible (start and midpoint are always in
+     the usable stack region below the TLS guard).  */
+  TEST_VERIFY (check_mem_access (stack, false));
+  TEST_VERIFY (check_mem_access ((char *) stack + stacksize / 4, false));
+
+  /* pthread_getattr_np reports stacksize as the user-requested size (both
+     the stack guard and the TLS guard are excluded) and stackaddr as the
+     top of that region.  For _STACK_GROWS_DOWN:
+       stack              == stackblock + guardsize  (low end of usable stack)
+       stack + stacksize + guardsize == end of the mmap'd allocation
+     Scan from the end of the allocation downward; the TLS guard is the
+     first inaccessible region encountered.  */
+  char *scan_top = (char *) stack + stacksize + guardsize;
+  char  *guard_start = NULL;
+  size_t guard_size  = 0;
+  int    found = find_tls_guard (scan_top, (char *) stack,
+                                 pagesz, &guard_start, &guard_size);
+
+  if (args->expect_tls_guard)
+    {
+      TEST_VERIFY (found != 0);
+      if (!found)
+        return NULL;
+
+      if (test_verbose)
+        printf ("debug: [tid=%jd] TLS guard at %p+%#zx, guardsize=%#zx\n",
+                (intmax_t) gettid (), guard_start, guard_size, guardsize);
+
+      /* The TLS guard should be the same size as the stack guard.  */
+      TEST_COMPARE (guard_size, guardsize);
+
+      /* Every byte of the TLS guard must be inaccessible.  */
+      TEST_VERIFY (!check_mem_access (guard_start, false));
+      TEST_VERIFY (!check_mem_access (guard_start, true));
+      TEST_VERIFY (!check_mem_access (guard_start + guard_size / 2, false));
+      TEST_VERIFY (!check_mem_access (guard_start + guard_size - 1, false));
+
+      /* The byte just below the TLS guard must be accessible (stack area).  */
+      TEST_VERIFY (check_mem_access (guard_start - 1, false));
+    }
+  else
+    {
+      /* With guardsize == 0 there must be no TLS guard.  */
+      TEST_VERIFY (found == 0);
+    }
+
+  return NULL;
+}
+
+/* Test with default pthread attributes (guard present).  */
+static void
+do_test_default (void *closure)
+{
+  struct thread_args args = {
+    .expect_tls_guard = 1
+  };
+  pthread_t t = xpthread_create (NULL, tf, &args);
+  void *status = xpthread_join (t);
+  TEST_VERIFY (status == 0);
+}
+
+/* Test with explicit guard size > 0 (guard present).  */
+static void
+do_test_with_guard (void *closure)
+{
+  pthread_attr_t attr;
+  xpthread_attr_init (&attr);
+  xpthread_attr_setstacksize (&attr, 2 * 1024 * 1024);
+  xpthread_attr_setguardsize (&attr, pagesz);
+
+  struct thread_args args = {
+    .expect_tls_guard = 1
+  };
+  pthread_t t = xpthread_create (&attr, tf, &args);
+  void *status = xpthread_join (t);
+  TEST_VERIFY (status == 0);
+
+  xpthread_attr_destroy (&attr);
+}
+
+/* Test with guardsize == 0 (no TLS guard expected).  */
+static void
+do_test_no_guard (void *closure)
+{
+  pthread_attr_t attr;
+  xpthread_attr_init (&attr);
+  /* Use a larger stack so the thread still fits after removing the guard.  */
+  xpthread_attr_setstacksize (&attr, 2 * 1024 * 1024);
+  xpthread_attr_setguardsize (&attr, 0);
+
+  struct thread_args args = {
+    .expect_tls_guard = 0
+  };
+  pthread_t t = xpthread_create (&attr, tf, &args);
+  void *status = xpthread_join (t);
+  TEST_VERIFY (status == 0);
+
+  xpthread_attr_destroy (&attr);
+}
+
+/* Test guard after cache reuse: create without guard, then with guard.  */
+static void
+do_test_cache_reuse (void *closure)
+{
+  /* First thread: no guard, puts stack in cache.  */
+  do_test_no_guard (NULL);
+
+  /* Second thread: default guard, retrieves cached stack and installs guard.  */
+  do_test_default (NULL);
+
+  /* Third thread: larger guard, exercises guard expansion.  */
+  pthread_attr_t attr;
+  xpthread_attr_init (&attr);
+  xpthread_attr_setstacksize (&attr, 2 * 1024 * 1024);
+  xpthread_attr_setguardsize (&attr, 2 * pagesz);
+
+  struct thread_args args = {
+    .expect_tls_guard = 1
+  };
+  pthread_t t = xpthread_create (&attr, tf, &args);
+  xpthread_join (t);
+  xpthread_attr_destroy (&attr);
+}
+#endif /* ARCH_HAS_TLS_GUARD */
+
+static int
+do_test (void)
+{
+#if ARCH_HAS_TLS_GUARD
+  pagesz = sysconf (_SC_PAGESIZE);
+
+  static const struct
+  {
+    const char *descr;
+    void (*fn) (void *);
+  } tests[] = {
+    { "default attributes (TLS guard expected)",       do_test_default     },
+    { "explicit guard size > 0 (TLS guard expected)",  do_test_with_guard  },
+    { "guardsize == 0 (no TLS guard expected)",        do_test_no_guard    },
+    { "cache reuse: no-guard then with-guard",         do_test_cache_reuse },
+  };
+
+  /* Run each sub-test in a forked subprocess for isolation.  */
+  for (size_t i = 0; i < array_length (tests); i++)
+    {
+      printf ("info: fork: %s\n", tests[i].descr);
+      struct support_capture_subprocess r =
+        support_capture_subprocess (tests[i].fn, NULL);
+      support_capture_subprocess_check (&r, tests[i].descr, 0,
+                                        sc_allow_none);
+      support_capture_subprocess_free (&r);
+    }
+
+  /* Then run them without fork so the stack cache is exercised.  */
+  for (size_t i = 0; i < array_length (tests); i++)
+    {
+      printf ("info: %s\n", tests[i].descr);
+      tests[i].fn (NULL);
+    }
+
+  return 0;
+#else
+  puts ("SKIP: TLS guard not enabled for this architecture");
+  return EXIT_SUCCESS;
+#endif
+}
+
+#include <support/test-driver.c>
diff --git a/sysdeps/aarch64/nptl/pthreaddef.h b/sysdeps/aarch64/nptl/pthreaddef.h
index 93d3e267a43..9ef8d0f0cca 100644
--- a/sysdeps/aarch64/nptl/pthreaddef.h
+++ b/sysdeps/aarch64/nptl/pthreaddef.h
@@ -22,6 +22,9 @@
 /* Minimum guard size.  */
 #define ARCH_MIN_GUARD_SIZE (64 * 1024)
 
+/* TLS guard page between thread stack and static TLS.  */
+#define ARCH_HAS_TLS_GUARD 0
+
 /* Required stack pointer alignment at beginning.  */
 #define STACK_ALIGN 16
 
diff --git a/sysdeps/alpha/nptl/pthreaddef.h b/sysdeps/alpha/nptl/pthreaddef.h
index 72d2c281cc9..d1f4e2e1c0b 100644
--- a/sysdeps/alpha/nptl/pthreaddef.h
+++ b/sysdeps/alpha/nptl/pthreaddef.h
@@ -21,6 +21,9 @@
 /* Minimum guard size.  */
 #define ARCH_MIN_GUARD_SIZE 0
 
+/* TLS guard page between thread stack and static TLS.  */
+#define ARCH_HAS_TLS_GUARD 0
+
 /* Required stack pointer alignment at beginning.  The ABI requires 16.  */
 #define STACK_ALIGN		16
 
diff --git a/sysdeps/arc/nptl/pthreaddef.h b/sysdeps/arc/nptl/pthreaddef.h
index 5c374b6bf27..fe22afc4591 100644
--- a/sysdeps/arc/nptl/pthreaddef.h
+++ b/sysdeps/arc/nptl/pthreaddef.h
@@ -22,6 +22,9 @@
 /* Minimum guard size.  */
 #define ARCH_MIN_GUARD_SIZE 0
 
+/* TLS guard page between thread stack and static TLS.  */
+#define ARCH_HAS_TLS_GUARD 0
+
 /* Required stack pointer alignment at beginning.  */
 #define STACK_ALIGN		4
 
diff --git a/sysdeps/arm/nptl/pthreaddef.h b/sysdeps/arm/nptl/pthreaddef.h
index a67721e7461..53eca415197 100644
--- a/sysdeps/arm/nptl/pthreaddef.h
+++ b/sysdeps/arm/nptl/pthreaddef.h
@@ -21,6 +21,9 @@
 /* Minimum guard size.  */
 #define ARCH_MIN_GUARD_SIZE 0
 
+/* TLS guard page between thread stack and static TLS.  */
+#define ARCH_HAS_TLS_GUARD 0
+
 /* Required stack pointer alignment at beginning.  SSE requires 16
    bytes.  */
 #define STACK_ALIGN		16
diff --git a/sysdeps/csky/nptl/pthreaddef.h b/sysdeps/csky/nptl/pthreaddef.h
index e57286423a3..19130f26cda 100644
--- a/sysdeps/csky/nptl/pthreaddef.h
+++ b/sysdeps/csky/nptl/pthreaddef.h
@@ -22,6 +22,9 @@
 /* Minimum guard size.  */
 #define ARCH_MIN_GUARD_SIZE 0
 
+/* TLS guard page between thread stack and static TLS.  */
+#define ARCH_HAS_TLS_GUARD 0
+
 /* Required stack pointer alignment at beginning.  */
 #define STACK_ALIGN		8
 
diff --git a/sysdeps/hppa/nptl/pthreaddef.h b/sysdeps/hppa/nptl/pthreaddef.h
index 5b54f4864f7..7640b271695 100644
--- a/sysdeps/hppa/nptl/pthreaddef.h
+++ b/sysdeps/hppa/nptl/pthreaddef.h
@@ -21,6 +21,9 @@
 /* Minimum guard size.  */
 #define ARCH_MIN_GUARD_SIZE 0
 
+/* TLS guard page between thread stack and static TLS.  */
+#define ARCH_HAS_TLS_GUARD 0
+
 /* Required stack pointer alignment at beginning.  */
 #define STACK_ALIGN		64
 
diff --git a/sysdeps/loongarch/nptl/pthreaddef.h b/sysdeps/loongarch/nptl/pthreaddef.h
index e500d60b777..df45b84957e 100644
--- a/sysdeps/loongarch/nptl/pthreaddef.h
+++ b/sysdeps/loongarch/nptl/pthreaddef.h
@@ -22,6 +22,9 @@
 /* Minimum guard size.  */
 #define ARCH_MIN_GUARD_SIZE 0
 
+/* TLS guard page between thread stack and static TLS.  */
+#define ARCH_HAS_TLS_GUARD 0
+
 /* Required stack pointer alignment at beginning.  */
 #define STACK_ALIGN 16
 
diff --git a/sysdeps/m68k/nptl/pthreaddef.h b/sysdeps/m68k/nptl/pthreaddef.h
index d29a061b745..dad964b98cc 100644
--- a/sysdeps/m68k/nptl/pthreaddef.h
+++ b/sysdeps/m68k/nptl/pthreaddef.h
@@ -21,6 +21,9 @@
 /* Minimum guard size.  */
 #define ARCH_MIN_GUARD_SIZE 0
 
+/* TLS guard page between thread stack and static TLS.  */
+#define ARCH_HAS_TLS_GUARD 0
+
 /* Required stack pointer alignment at beginning.  */
 #define STACK_ALIGN		16
 
diff --git a/sysdeps/microblaze/nptl/pthreaddef.h b/sysdeps/microblaze/nptl/pthreaddef.h
index 10c7257a574..9c7f7d96812 100644
--- a/sysdeps/microblaze/nptl/pthreaddef.h
+++ b/sysdeps/microblaze/nptl/pthreaddef.h
@@ -25,6 +25,9 @@
 /* Minimum guard size.  */
 #define ARCH_MIN_GUARD_SIZE 0
 
+/* TLS guard page between thread stack and static TLS.  */
+#define ARCH_HAS_TLS_GUARD 0
+
 /* Required stack pointer alignment at beginning.  */
 #define STACK_ALIGN         16
 
diff --git a/sysdeps/mips/nptl/pthreaddef.h b/sysdeps/mips/nptl/pthreaddef.h
index 518e8486b91..ec57cf4179e 100644
--- a/sysdeps/mips/nptl/pthreaddef.h
+++ b/sysdeps/mips/nptl/pthreaddef.h
@@ -21,6 +21,9 @@
 /* Minimum guard size.  */
 #define ARCH_MIN_GUARD_SIZE 0
 
+/* TLS guard page between thread stack and static TLS.  */
+#define ARCH_HAS_TLS_GUARD 0
+
 /* Required stack pointer alignment at beginning.  */
 #define STACK_ALIGN		16
 
diff --git a/sysdeps/or1k/nptl/pthreaddef.h b/sysdeps/or1k/nptl/pthreaddef.h
index cc92affca22..ca55c9c6605 100644
--- a/sysdeps/or1k/nptl/pthreaddef.h
+++ b/sysdeps/or1k/nptl/pthreaddef.h
@@ -23,6 +23,9 @@
 /* Minimum guard size.  */
 #define ARCH_MIN_GUARD_SIZE 0
 
+/* TLS guard page between thread stack and static TLS.  */
+#define ARCH_HAS_TLS_GUARD 0
+
 /* Required stack pointer alignment at beginning.  */
 #define STACK_ALIGN 4
 
diff --git a/sysdeps/powerpc/nptl/pthreaddef.h b/sysdeps/powerpc/nptl/pthreaddef.h
index 5598dd3afc2..0ae1a8777d3 100644
--- a/sysdeps/powerpc/nptl/pthreaddef.h
+++ b/sysdeps/powerpc/nptl/pthreaddef.h
@@ -21,6 +21,9 @@
 /* Minimum guard size.  */
 #define ARCH_MIN_GUARD_SIZE 0
 
+/* TLS guard page between thread stack and static TLS.  */
+#define ARCH_HAS_TLS_GUARD 0
+
 /* Required stack pointer alignment at beginning.  The ABI requires 16
    bytes (for both 32-bit and 64-bit PowerPC).  */
 #define STACK_ALIGN		16
diff --git a/sysdeps/riscv/nptl/pthreaddef.h b/sysdeps/riscv/nptl/pthreaddef.h
index 219ef54b538..26abfd16df8 100644
--- a/sysdeps/riscv/nptl/pthreaddef.h
+++ b/sysdeps/riscv/nptl/pthreaddef.h
@@ -22,6 +22,9 @@
 /* Minimum guard size.  */
 #define ARCH_MIN_GUARD_SIZE 0
 
+/* TLS guard page between thread stack and static TLS.  */
+#define ARCH_HAS_TLS_GUARD 0
+
 /* Required stack pointer alignment at beginning.  */
 #define STACK_ALIGN		16
 
diff --git a/sysdeps/s390/nptl/pthreaddef.h b/sysdeps/s390/nptl/pthreaddef.h
index f1d413db3d1..4f33be70c8e 100644
--- a/sysdeps/s390/nptl/pthreaddef.h
+++ b/sysdeps/s390/nptl/pthreaddef.h
@@ -21,6 +21,9 @@
 /* Minimum guard size.  */
 #define ARCH_MIN_GUARD_SIZE 0
 
+/* TLS guard page between thread stack and static TLS.  */
+#define ARCH_HAS_TLS_GUARD 0
+
 /* Required stack pointer alignment at beginning.  SSE requires 16
    bytes.  */
 #define STACK_ALIGN		16
diff --git a/sysdeps/sh/nptl/pthreaddef.h b/sysdeps/sh/nptl/pthreaddef.h
index ea6099a2e4c..96ecc406a30 100644
--- a/sysdeps/sh/nptl/pthreaddef.h
+++ b/sysdeps/sh/nptl/pthreaddef.h
@@ -21,6 +21,9 @@
 /* Minimum guard size.  */
 #define ARCH_MIN_GUARD_SIZE 0
 
+/* TLS guard page between thread stack and static TLS.  */
+#define ARCH_HAS_TLS_GUARD 0
+
 /* Required stack pointer alignment at beginning.  */
 #define STACK_ALIGN		8
 
diff --git a/sysdeps/sparc/sparc32/pthreaddef.h b/sysdeps/sparc/sparc32/pthreaddef.h
index 04676ef307d..7b40593da79 100644
--- a/sysdeps/sparc/sparc32/pthreaddef.h
+++ b/sysdeps/sparc/sparc32/pthreaddef.h
@@ -21,6 +21,9 @@
 /* Minimum guard size.  */
 #define ARCH_MIN_GUARD_SIZE 0
 
+/* TLS guard page between thread stack and static TLS.  */
+#define ARCH_HAS_TLS_GUARD 0
+
 /* Required stack pointer alignment at beginning.  */
 #define STACK_ALIGN		16
 
diff --git a/sysdeps/sparc/sparc64/pthreaddef.h b/sysdeps/sparc/sparc64/pthreaddef.h
index 94192f8b75d..27e465271bb 100644
--- a/sysdeps/sparc/sparc64/pthreaddef.h
+++ b/sysdeps/sparc/sparc64/pthreaddef.h
@@ -21,6 +21,9 @@
 /* Minimum guard size.  */
 #define ARCH_MIN_GUARD_SIZE 0
 
+/* TLS guard page between thread stack and static TLS.  */
+#define ARCH_HAS_TLS_GUARD 0
+
 /* Required stack pointer alignment at beginning.  */
 #define STACK_ALIGN		16
 
diff --git a/sysdeps/x86/nptl/pthreaddef.h b/sysdeps/x86/nptl/pthreaddef.h
index 0764503f944..730453e6ce1 100644
--- a/sysdeps/x86/nptl/pthreaddef.h
+++ b/sysdeps/x86/nptl/pthreaddef.h
@@ -21,6 +21,9 @@
 /* Minimum guard size.  */
 #define ARCH_MIN_GUARD_SIZE 0
 
+/* TLS guard page between thread stack and static TLS.  */
+#define ARCH_HAS_TLS_GUARD 1
+
 /* Required stack pointer alignment at beginning.  SSE requires 16
    bytes.  */
 #define STACK_ALIGN		16
