diff --git a/htl/Versions b/htl/Versions
index 4aea321016..4e0ebac285 100644
--- a/htl/Versions
+++ b/htl/Versions
@@ -168,8 +168,6 @@ libpthread {
   GLIBC_PRIVATE {
     __pthread_initialize_minimal;
 
-    __pthread_threads;
-
     __cthread_detach;
     __cthread_fork;
     __pthread_detach;
diff --git a/htl/pt-alloc.c b/htl/pt-alloc.c
index acc67f2711..f6708a60bf 100644
--- a/htl/pt-alloc.c
+++ b/htl/pt-alloc.c
@@ -28,19 +28,9 @@
    of the threads functions "shall fail" if "No thread could be found
    corresponding to that specified by the given thread ID."  */
 
-/* Thread ID lookup table.  */
-struct __pthread **__pthread_threads;
-
 /* The size of the thread ID lookup table.  */
 int __pthread_max_threads;
 
-/* The total number of thread IDs currently in use, or on the list of
-   available thread IDs.  */
-int __pthread_num_threads;
-
-/* A lock for the table, and the other variables above.  */
-pthread_rwlock_t __pthread_threads_lock;
-
 /* List of thread structures corresponding to free thread IDs.  */
 struct __pthread *__pthread_free_threads;
 pthread_mutex_t __pthread_free_threads_lock;
@@ -132,25 +122,25 @@ __pthread_alloc (struct __pthread **pthread)
     }
 
 retry:
-  __pthread_rwlock_wrlock (&__pthread_threads_lock);
+  lll_lock (GL (dl_pthread_threads_lock), LLL_PRIVATE);
 
-  if (__pthread_num_threads < __pthread_max_threads)
+  if (GL (dl_pthread_num_threads) < __pthread_max_threads)
     {
       /* We have a free slot.  Use the slot number plus one as the
          thread ID for the new thread.  */
-      new->thread = 1 + __pthread_num_threads++;
-      __pthread_threads[new->thread - 1] = NULL;
+      new->thread = 1 + GL (dl_pthread_num_threads)++;
+      GL (dl_pthread_threads)[new->thread - 1] = NULL;
 
-      __pthread_rwlock_unlock (&__pthread_threads_lock);
+      lll_unlock (GL (dl_pthread_threads_lock), LLL_PRIVATE);
 
       *pthread = new;
       return 0;
     }
 #ifdef PTHREAD_THREADS_MAX
-  else if (__pthread_num_threads >= PTHREAD_THREADS_MAX)
+  else if (GL (dl_pthread_num_threads) >= PTHREAD_THREADS_MAX)
     {
       /* We have reached the limit on the number of threads per process.  */
-      __pthread_rwlock_unlock (&__pthread_threads_lock);
+      lll_unlock (GL (dl_pthread_threads_lock), LLL_PRIVATE);
 
       free (new);
       return EAGAIN;
@@ -162,7 +152,7 @@ retry:
      memory allocation, since that's a potentially blocking operation.  */
   max_threads = __pthread_max_threads;
 
-  __pthread_rwlock_unlock (&__pthread_threads_lock);
+  lll_unlock (GL (dl_pthread_threads_lock), LLL_PRIVATE);
 
   /* Allocate a new lookup table that's twice as large.  */
   new_max_threads
@@ -174,13 +164,13 @@ retry:
       return ENOMEM;
     }
 
-  __pthread_rwlock_wrlock (&__pthread_threads_lock);
+  lll_lock (GL (dl_pthread_threads_lock), LLL_PRIVATE);
 
   /* Check if nobody else has already enlarged the table.  */
   if (max_threads != __pthread_max_threads)
     {
       /* Yep, they did.  */
-      __pthread_rwlock_unlock (&__pthread_threads_lock);
+      lll_unlock (GL (dl_pthread_threads_lock), LLL_PRIVATE);
 
       /* Free the newly allocated table and try again to allocate a slot.  */
       free (threads);
@@ -188,22 +178,22 @@ retry:
     }
 
   /* Copy over the contents of the old table.  */
-  memcpy (threads, __pthread_threads,
+  memcpy (threads, GL (dl_pthread_threads),
 	  __pthread_max_threads * sizeof (struct __pthread *));
 
   /* Save the location of the old table.  We want to deallocate its
      storage after we released the lock.  */
-  old_threads = __pthread_threads;
+  old_threads = GL (dl_pthread_threads);
 
   /* Replace the table with the new one.  */
   __pthread_max_threads = new_max_threads;
-  __pthread_threads = threads;
+  GL (dl_pthread_threads) = threads;
 
   /* And allocate ourselves one of the newly created slots.  */
-  new->thread = 1 + __pthread_num_threads++;
-  __pthread_threads[new->thread - 1] = NULL;
+  new->thread = 1 + GL (dl_pthread_num_threads)++;
+  GL (dl_pthread_threads)[new->thread - 1] = NULL;
 
-  __pthread_rwlock_unlock (&__pthread_threads_lock);
+  lll_unlock (GL (dl_pthread_threads_lock), LLL_PRIVATE);
 
   free (old_threads);
 
@@ -217,10 +207,10 @@ __pthread_init_static_tls (struct link_map *map)
 {
   int i;
 
-  __pthread_rwlock_wrlock (&__pthread_threads_lock);
-  for (i = 0; i < __pthread_num_threads; ++i)
+  lll_lock (GL (dl_pthread_threads_lock), LLL_PRIVATE);
+  for (i = 0; i < GL (dl_pthread_num_threads); ++i)
     {
-      struct __pthread *t = __pthread_threads[i];
+      struct __pthread *t = GL (dl_pthread_threads)[i];
 
       if (t == NULL)
 	continue;
@@ -237,5 +227,5 @@ __pthread_init_static_tls (struct link_map *map)
       memset (__mempcpy (dest, map->l_tls_initimage, map->l_tls_initimage_size),
 	      '\0', map->l_tls_blocksize - map->l_tls_initimage_size);
     }
-  __pthread_rwlock_unlock (&__pthread_threads_lock);
+  lll_unlock (GL (dl_pthread_threads_lock), LLL_PRIVATE);
 }
diff --git a/htl/pt-create.c b/htl/pt-create.c
index f0a1f1ab09..4e16cbbdc9 100644
--- a/htl/pt-create.c
+++ b/htl/pt-create.c
@@ -207,7 +207,7 @@ __pthread_create_internal (struct __pthread **thread,
      creating thread.  The set of signals pending for the new thread
      shall be empty."  If the currnet thread is not a pthread then we
      just inherit the process' sigmask.  */
-  if (__pthread_num_threads == 1)
+  if (GL (dl_pthread_num_threads) == 1)
     err = __sigprocmask (0, 0, &pthread->init_sigset);
   else
     err = __pthread_sigstate (_pthread_self (), 0, 0, &pthread->init_sigset, 0);
@@ -227,13 +227,8 @@ __pthread_create_internal (struct __pthread **thread,
      new thread runs.  */
   atomic_increment (&__pthread_total);
 
-  /* Store a pointer to this thread in the thread ID lookup table.  We
-     could use __thread_setid, however, we only lock for reading as no
-     other thread should be using this entry (we also assume that the
-     store is atomic).  */
-  __pthread_rwlock_rdlock (&__pthread_threads_lock);
-  __pthread_threads[pthread->thread - 1] = pthread;
-  __pthread_rwlock_unlock (&__pthread_threads_lock);
+  /* Store a pointer to this thread in the thread ID lookup table.  */
+  __pthread_setid (pthread->thread, pthread);
 
   /* At this point it is possible to guess our pthread ID.  We have to
      make sure that all functions taking a pthread_t argument can
diff --git a/htl/pt-internal.h b/htl/pt-internal.h
index 34e6da338e..7c16f8744d 100644
--- a/htl/pt-internal.h
+++ b/htl/pt-internal.h
@@ -166,33 +166,24 @@ __pthread_dequeue (struct __pthread *thread)
 /* The total number of threads currently active.  */
 extern unsigned int __pthread_total;
 
-/* The total number of thread IDs currently in use, or on the list of
-   available thread IDs.  */
-extern int __pthread_num_threads;
-
 /* Concurrency hint.  */
 extern int __pthread_concurrency;
 
-/* Array of __pthread structures and its lock.  Indexed by the pthread
-   id minus one.  (Why not just use the pthread id?  Because some
-   brain-dead users of the pthread interface incorrectly assume that 0
-   is an invalid pthread id.)  */
-extern struct __pthread **__pthread_threads;
+/* The size of the thread ID lookup table.  */
 extern int __pthread_max_threads;
-extern pthread_rwlock_t __pthread_threads_lock;
 
 #define __pthread_getid(thread) \
   ({ struct __pthread *__t = NULL;                                           \
-     __pthread_rwlock_rdlock (&__pthread_threads_lock);                      \
+     lll_lock (GL (dl_pthread_threads_lock), LLL_PRIVATE);                   \
      if (thread <= __pthread_max_threads)                                    \
-       __t = __pthread_threads[thread - 1];                                  \
-     __pthread_rwlock_unlock (&__pthread_threads_lock);                      \
+       __t = GL (dl_pthread_threads)[thread - 1];                            \
+     lll_unlock (GL (dl_pthread_threads_lock), LLL_PRIVATE);                 \
      __t; })
 
 #define __pthread_setid(thread, pthread) \
-  __pthread_rwlock_wrlock (&__pthread_threads_lock);                         \
-  __pthread_threads[thread - 1] = pthread;                                   \
-  __pthread_rwlock_unlock (&__pthread_threads_lock);
+  lll_lock (GL (dl_pthread_threads_lock), LLL_PRIVATE);                      \
+  GL (dl_pthread_threads)[thread - 1] = pthread;                             \
+  lll_unlock (GL (dl_pthread_threads_lock), LLL_PRIVATE);
 
 /* Similar to pthread_self, but returns the thread descriptor instead
    of the thread ID.  */
diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h
index 02bd579ef8..3092bbc924 100644
--- a/sysdeps/generic/ldsodefs.h
+++ b/sysdeps/generic/ldsodefs.h
@@ -486,7 +486,16 @@ struct rtld_global
 
   /* Mutex protecting the stack lists.  */
   EXTERN int _dl_stack_cache_lock;
+#else
+  /* The total number of thread IDs currently in use, or on the list of
+     available thread IDs.  */
+  EXTERN int _dl_pthread_num_threads;
+
+  /* Array of __pthread structures and its lock.  */
+  EXTERN struct __pthread **_dl_pthread_threads;
+  EXTERN int _dl_pthread_threads_lock;
 #endif
+
 #if !THREAD_GSCOPE_IN_TCB
   EXTERN int _dl_thread_gscope_count;
 #endif
diff --git a/sysdeps/htl/dl-support.c b/sysdeps/htl/dl-support.c
new file mode 100644
index 0000000000..21a391a59f
--- /dev/null
+++ b/sysdeps/htl/dl-support.c
@@ -0,0 +1,23 @@
+/* Support for dynamic linking code in static libc.
+   Copyright (C) 2007-2021 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <elf/dl-support.c>
+
+int _dl_pthread_num_threads;
+struct __pthread **_dl_pthread_threads;
+int _dl_pthread_threads_lock;
diff --git a/sysdeps/htl/pt-key-delete.c b/sysdeps/htl/pt-key-delete.c
index 4e77ef7521..4acd8dd755 100644
--- a/sysdeps/htl/pt-key-delete.c
+++ b/sysdeps/htl/pt-key-delete.c
@@ -39,12 +39,12 @@ __pthread_key_delete (pthread_key_t key)
       __pthread_key_destructors[key] = PTHREAD_KEY_INVALID;
       __pthread_key_invalid_count++;
 
-      __pthread_rwlock_rdlock (&__pthread_threads_lock);
-      for (i = 0; i < __pthread_num_threads; ++i)
+      lll_lock (GL (dl_pthread_threads_lock), LLL_PRIVATE);
+      for (i = 0; i < GL (dl_pthread_num_threads); ++i)
 	{
 	  struct __pthread *t;
 
-	  t = __pthread_threads[i];
+	  t = GL (dl_pthread_threads)[i];
 
 	  if (t == NULL)
 	    continue;
@@ -54,7 +54,7 @@ __pthread_key_delete (pthread_key_t key)
 	  if (key < t->thread_specifics_size)
 	    t->thread_specifics[key] = 0;
 	}
-      __pthread_rwlock_unlock (&__pthread_threads_lock);
+      lll_unlock (GL (dl_pthread_threads_lock), LLL_PRIVATE);
     }
 
   __pthread_mutex_unlock (&__pthread_key_lock);
diff --git a/sysdeps/htl/pthreadP.h b/sysdeps/htl/pthreadP.h
index 3fd774269f..8b02bef355 100644
--- a/sysdeps/htl/pthreadP.h
+++ b/sysdeps/htl/pthreadP.h
@@ -31,8 +31,6 @@ extern void __pthread_init_static_tls (struct link_map *) attribute_hidden;
 
 /* These represent the interface used by glibc itself.  */
 
-extern struct __pthread **__pthread_threads;
-
 extern int __pthread_mutex_init (pthread_mutex_t *__mutex, const pthread_mutexattr_t *__attr);
 extern int __pthread_mutex_destroy (pthread_mutex_t *__mutex);
 extern int __pthread_mutex_lock (pthread_mutex_t *__mutex);
diff --git a/sysdeps/htl/raise.c b/sysdeps/htl/raise.c
index 5a0f37d3b8..8c17db6f65 100644
--- a/sysdeps/htl/raise.c
+++ b/sysdeps/htl/raise.c
@@ -17,6 +17,7 @@
    License along with this program.  If not, see
    <https://www.gnu.org/licenses/>.  */
 
+#include <ldsodefs.h>
 #include <pthreadP.h>
 #include <signal.h>
 #include <unistd.h>
@@ -24,6 +25,11 @@
 #pragma weak __pthread_kill
 #pragma weak __pthread_self
 #pragma weak __pthread_threads
+
+#ifndef SHARED
+#pragma weak _dl_pthread_threads
+#endif
+
 int
 raise (int signo)
 {
@@ -31,7 +37,7 @@ raise (int signo)
      "the effect of the raise() function shall be equivalent to
      calling: pthread_kill(pthread_self(), sig);"  */
 
-  if (__pthread_kill != NULL && __pthread_threads != NULL)
+  if (__pthread_kill != NULL && GL (dl_pthread_threads) != NULL)
     {
       int err;
       err = __pthread_kill (__pthread_self (), signo);
diff --git a/sysdeps/htl/thrd_current.c b/sysdeps/htl/thrd_current.c
index eecb86af85..87359677d6 100644
--- a/sysdeps/htl/thrd_current.c
+++ b/sysdeps/htl/thrd_current.c
@@ -17,14 +17,19 @@
    <https://www.gnu.org/licenses/>.  */
 
 #include "thrd_priv.h"
+#include <ldsodefs.h>
 
 #pragma weak __pthread_self
 #pragma weak __pthread_threads
 
+#ifndef SHARED
+#pragma weak _dl_pthread_threads
+#endif
+
 thrd_t
 thrd_current (void)
 {
-  if (__pthread_threads)
+  if (GL (dl_pthread_threads))
     return (thrd_t) __pthread_self ();
 
   return (thrd_t) 0;
diff --git a/sysdeps/mach/hurd/htl/pt-sigstate-init.c b/sysdeps/mach/hurd/htl/pt-sigstate-init.c
index 399068ca78..6f43ade653 100644
--- a/sysdeps/mach/hurd/htl/pt-sigstate-init.c
+++ b/sysdeps/mach/hurd/htl/pt-sigstate-init.c
@@ -37,7 +37,7 @@ __pthread_sigstate_init (struct __pthread *thread)
       struct hurd_sigstate *ss = _hurd_thread_sigstate (thread->kernel_thread);
       _hurd_sigstate_set_global_rcv (ss);
     }
-  else if (__pthread_num_threads >= 2)
+  else if (GL (dl_pthread_num_threads) >= 2)
     do_init_global = 1;
 
   return 0;
diff --git a/sysdeps/mach/hurd/htl/pt-sysdep.c b/sysdeps/mach/hurd/htl/pt-sysdep.c
index 03ff8079ba..2fd0a8d6e7 100644
--- a/sysdeps/mach/hurd/htl/pt-sysdep.c
+++ b/sysdeps/mach/hurd/htl/pt-sysdep.c
@@ -45,7 +45,7 @@ _init_routine (void *stack)
   int err;
   pthread_attr_t attr, *attrp = 0;
 
-  if (__pthread_threads != NULL)
+  if (GL (dl_pthread_threads) != NULL)
     /* Already initialized */
     return;
 
diff --git a/sysdeps/mach/hurd/htl/pt-sysdep.h b/sysdeps/mach/hurd/htl/pt-sysdep.h
index acd4fce9c4..d90563af0c 100644
--- a/sysdeps/mach/hurd/htl/pt-sysdep.h
+++ b/sysdeps/mach/hurd/htl/pt-sysdep.h
@@ -37,7 +37,7 @@ extern __thread struct __pthread *___pthread_self;
 	({                                                         \
 	  struct __pthread *thread;                                \
 	                                                           \
-	  assert (__pthread_threads);                              \
+	  assert (GL (dl_pthread_threads));                        \
 	  thread = ___pthread_self;                                \
 	                                                           \
 	  assert (thread);                                         \
