about summary refs log tree commit diff
diff options
context:
space:
mode:
authorH.J. Lu <hjl.tools@gmail.com>2012-09-13 06:01:04 -0700
committerH.J. Lu <hjl.tools@gmail.com>2015-09-23 09:03:45 -0700
commit7c846b63a8321c6822a6b5ad82b1134ff8d1d18b (patch)
tree56c09f594f27c761633e05d3b5f23f597411502c
parent6e1ae9bae180f0cf43d73ee2ee395252d1e22e17 (diff)
downloadglibc-hjl/pthread/2.22.tar.gz
glibc-hjl/pthread/2.22.tar.xz
glibc-hjl/pthread/2.22.zip
Use STB_SECONDARY on pthread functions in libc hjl/pthread/2.22
Use STB_SECONDARY binding on pthread functions in libc so that they will
be preempted by definitions in libpthread at link-time as well as at
run-time.

	* csu/libc-tls.c (__pthread_initialize_minimal): Mark it
	secondary if HAVE_ASM_SECONDARY_DIRECTIVE is defined.
	* misc/error.c (error): Replace pthread_setcancelstate with
	__pthread_setcancelstate.
	(error_at_line): Likewise.
	* posix/wordexp.c (parse_comm): Likewise.
	* stdlib/fmtmsg.c (fmtmsg): Likewise.
	* nptl/Makefile:
	(routines): Add libc-pthread-secondary.
	(CFLAGS-libc-pthread-secondary.c): New.
	* nptl/Versions [HAVE_ASM_SECONDARY_DIRECTIVE] (libc:GLIBC_2.0):
	Add pthread_once.
	[HAVE_ASM_SECONDARY_DIRECTIVE] (libc:GLIBC_PRIVATE): Add
	_pthread_cleanup_pop_restore, _pthread_cleanup_push_defer,
	__pthread_getspecific, __pthread_setspecific,
	__pthread_key_create, __pthread_mutex_lock,
	__pthread_mutex_unlock, __pthread_once,
	__pthread_rwlock_rdlock, __pthread_rwlock_wrlock,
	__pthread_rwlock_unlock and __pthread_unwind.
	[HAVE_ASM_SECONDARY_DIRECTIVE] (libpthread:GLIBC_PRIVATE):
	Likewise.
	* cleanup_defer_compat.c: Include <shlib-compat.h>.
	Add GLIBC_2_0 and GLIBC_PRIVATE versions for
	_pthread_cleanup_pop_restore and _pthread_cleanup_push_defer.
	* nptl/forward.c [HAVE_ASM_SECONDARY_DIRECTIVE] (FORWARD2): New.
	(FORWARD_NORETURN): Likewise.
	(pthread_setcancelstate): Renamed to ...
	(__pthread_setcancelstate): This.
	(pthread_setcancelstate): Add an alias.
	* nptl/libc-pthread-secondary.c: New file.
	* nptl/nptl-init.c (pthread_functions): Don't include secondary
	pthread functions in libc if HAVE_ASM_SECONDARY_DIRECTIVE is
	defined.  Replace ptr_pthread_setcancelstate with
	ptr___pthread_setcancelstate.
	* sysdeps/nptl/pthread-functions.h (pthread_functions): Likewise.
	* nptl/pthread_getspecific.c: Include <shlib-compat.h>.
	Add GLIBC_2_0 and GLIBC_PRIVATE versions for
	__pthread_getspecific.
	* nptl/pthread_key_create.c: Include <shlib-compat.h>.
	Add GLIBC_2_0 and GLIBC_PRIVATE versions for
	__pthread_key_create.
	* nptl/pthread_mutex_lock.c: Include <shlib-compat.h>.
	Add GLIBC_2_0 and GLIBC_PRIVATE versions for
	__pthread_mutex_lock.
	* nptl/pthread_mutex_unlock.c: Include <shlib-compat.h>.
	Add GLIBC_2_0 and GLIBC_PRIVATE versions for
	__pthread_mutex_unlock.
	* nptl/pthread_once.c: Include <shlib-compat.h>.
	Add GLIBC_2_0 and GLIBC_PRIVATE versions for
	__pthread_once.
	* nptl/pthread_rwlock_rdlock.c: Include <shlib-compat.h>.
	Add GLIBC_2_0 and GLIBC_PRIVATE versions for
	__pthread_rwlock_rdlock.
	* nptl/pthread_rwlock_unlock.c: Include <shlib-compat.h>.
	Add GLIBC_2_0 and GLIBC_PRIVATE versions for
	__pthread_rwlock_unlock.
	* nptl/pthread_rwlock_wrlock.c: Include <shlib-compat.h>.
	Add GLIBC_2_0 and GLIBC_PRIVATE versions for
	__pthread_rwlock_wrlock.
	* nptl/pthread_setspecific.c: Include <shlib-compat.h>.
	Add GLIBC_2_0 and GLIBC_PRIVATE versions for
	__pthread_setspecific.
	* nptl/pthreadP.h (__pthread_unwind): Don't mark it weak if
	HAVE_ASM_SECONDARY_DIRECTIVE is defined.
	(__pthread_cond_broadcast_2_0): Declare only if not in libc.
	(__pthread_cond_destroy_2_0): Likewise.
	(__pthread_cond_init_2_0): Likewise.
	(__pthread_cond_signal_2_0): Likewise.
	(__pthread_cond_timedwait_2_0): Likewise.
	(__pthread_cond_wait_2_0): Likewise.
	* scripts/abilist.awk: Support secondary symbols.
	* sysdeps/generic/localplt.data: Add __pthread_getspecific,
	__pthread_key_create, __pthread_once, __pthread_rwlock_rdlock,
	__pthread_rwlock_wrlock, __pthread_rwlock_unlock,
	__pthread_setcancelstate, __pthread_setspecific,
	__pthread_unwind.  _pthread_cleanup_pop_restore and
	_pthread_cleanup_push_defer.
	* sysdeps/unix/sysv/linux/i386/localplt.data: Likewise.
	* sysdeps/x86_64/localplt.data: Likewise.
	* sysdeps/nptl/bits/libc-lockP.h (PTFAVAIL): Defined as 1 if
	HAVE_ASM_SECONDARY_DIRECTIVE is defined.
	(__libc_maybe_call): Always call FUNC if
	HAVE_ASM_SECONDARY_DIRECTIVE is defined.
	(__libc_ptf_call): Likewise.
	(__libc_ptf_call_always): Likewise.
	(__pthread_mutex_init): Don't mark it weak if
	HAVE_ASM_SECONDARY_DIRECTIVE is defined.
	(__pthread_mutex_destroy): Likewise.
	(__pthread_mutex_lock): Likewise.
	(__pthread_mutex_trylock): Likewise.
	(__pthread_mutex_unlock): Likewise.
	(__pthread_mutexattr_init): Likewise.
	(__pthread_mutexattr_destroy): Likewise.
	(__pthread_mutexattr_settype): Likewise.
	(__pthread_rwlock_destroy): Likewise.
	(__pthread_rwlock_rdlock): Likewise.
	(__pthread_rwlock_tryrdlock): Likewise.
	(__pthread_rwlock_wrlock): Likewise.
	(__pthread_rwlock_trywrlock): Likewise.
	(__pthread_rwlock_unlock): Likewise.
	(__pthread_key_create): Likewise.
	(__pthread_setspecific): Likewise.
	(__pthread_getspecific): Likewise.
	(__pthread_once): Likewise.
	(__pthread_initialize): Likewise.
	(__pthread_atfork): Likewise.
	(_pthread_cleanup_push_defer): Likewise.
	(_pthread_cleanup_pop_restore): Likewise.
	(__pthread_setcancelstate): New prototype.
	(pthread_setcancelstate): Renamed to ...
	(__pthread_setcancelstate): This.  Don't mark it weak if
	HAVE_ASM_SECONDARY_DIRECTIVE is defined.
	* sysdeps/nptl/jmp-unwind.c: Include <bits/libc-lock.h>
	instead of <nptl/pthreadP.h>.
	(__pthread_cleanup_upto): Don't mark it weak if
	HAVE_ASM_SECONDARY_DIRECTIVE is defined.
	(_longjmp_unwind): Use __libc_ptf_call.
	* sysdeps/unix/sysv/linux/s390/jmp-unwind.c: Likewise.
	* sysdeps/unix/sysv/linux/fatal-prepare.h (FATAL_PREPARE): Always
	call __pthread_setcancelstate if HAVE_ASM_SECONDARY_DIRECTIVE is
	defined.  Replace pthread_setcancelstate with
	__pthread_setcancelstate.
	* sysdeps/unix/sysv/linux/i386/libc.abilist: Add pthread_once.
	* sysdeps/unix/sysv/linux/x86_64/64/libc.abilist: Likewise.
	* sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist: Likewise.
	* sysdeps/unix/sysv/linux/i386/i486/libc-lowlevellock.S: Make
	__lll_lock_wait_private and __lll_unlock_wake_private weak in
	libc.a.
	* sysdeps/unix/sysv/linux/x86_64/libc-lowlevellock.S: Likewise.
	* sysdeps/unix/sysv/linux/x86_64/cancellation.S (__pthread_unwind):
	Don't mark it weak if HAVE_ASM_SECONDARY_DIRECTIVE is defined.
-rw-r--r--csu/libc-tls.c5
-rw-r--r--misc/error.c12
-rw-r--r--nptl/Makefile3
-rw-r--r--nptl/Versions28
-rw-r--r--nptl/cleanup_defer_compat.c20
-rw-r--r--nptl/forward.c34
-rw-r--r--nptl/libc-pthread-secondary.c132
-rw-r--r--nptl/nptl-init.c12
-rw-r--r--nptl/pthreadP.h5
-rw-r--r--nptl/pthread_getspecific.c10
-rw-r--r--nptl/pthread_key_create.c10
-rw-r--r--nptl/pthread_mutex_lock.c10
-rw-r--r--nptl/pthread_mutex_unlock.c10
-rw-r--r--nptl/pthread_once.c10
-rw-r--r--nptl/pthread_rwlock_rdlock.c10
-rw-r--r--nptl/pthread_rwlock_unlock.c10
-rw-r--r--nptl/pthread_rwlock_wrlock.c10
-rw-r--r--nptl/pthread_setspecific.c10
-rw-r--r--posix/wordexp.c4
-rw-r--r--scripts/abilist.awk2
-rw-r--r--stdlib/fmtmsg.c6
-rw-r--r--sysdeps/generic/localplt.data12
-rw-r--r--sysdeps/nptl/bits/libc-lockP.h65
-rw-r--r--sysdeps/nptl/jmp-unwind.c14
-rw-r--r--sysdeps/nptl/pthread-functions.h10
-rw-r--r--sysdeps/unix/sysv/linux/fatal-prepare.h19
-rw-r--r--sysdeps/unix/sysv/linux/i386/i486/libc-lowlevellock.S6
-rw-r--r--sysdeps/unix/sysv/linux/i386/libc.abilist1
-rw-r--r--sysdeps/unix/sysv/linux/i386/localplt.data12
-rw-r--r--sysdeps/unix/sysv/linux/s390/jmp-unwind.c12
-rw-r--r--sysdeps/unix/sysv/linux/x86_64/64/libc.abilist1
-rw-r--r--sysdeps/unix/sysv/linux/x86_64/cancellation.S2
-rw-r--r--sysdeps/unix/sysv/linux/x86_64/libc-lowlevellock.S6
-rw-r--r--sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist1
-rw-r--r--sysdeps/x86_64/localplt.data12
35 files changed, 440 insertions, 86 deletions
diff --git a/csu/libc-tls.c b/csu/libc-tls.c
index 3f134252a3..cc7c4ff737 100644
--- a/csu/libc-tls.c
+++ b/csu/libc-tls.c
@@ -235,6 +235,11 @@ _dl_tls_setup (void)
 }
 
 
+#ifdef HAVE_ASM_SECONDARY_DIRECTIVE
+/* Make sure that it is used only when libpthread.a is not used  */
+asm (".secondary __pthread_initialize_minimal");
+#endif
+
 /* This is the minimal initialization function used when libpthread is
    not used.  */
 void
diff --git a/misc/error.c b/misc/error.c
index aaa120d5ab..9d479d196d 100644
--- a/misc/error.c
+++ b/misc/error.c
@@ -298,8 +298,8 @@ error (int status, int errnum, const char *message, ...)
   /* We do not want this call to be cut short by a thread
      cancellation.  Therefore disable cancellation for now.  */
   int state = PTHREAD_CANCEL_ENABLE;
-  __libc_ptf_call (pthread_setcancelstate, (PTHREAD_CANCEL_DISABLE, &state),
-		   0);
+  __libc_ptf_call (__pthread_setcancelstate,
+		   (PTHREAD_CANCEL_DISABLE, &state), 0);
 #endif
 
   flush_stdout ();
@@ -323,7 +323,7 @@ error (int status, int errnum, const char *message, ...)
 #ifdef _LIBC
   _IO_funlockfile (stderr);
 # ifdef __libc_ptf_call
-  __libc_ptf_call (pthread_setcancelstate, (state, NULL), 0);
+  __libc_ptf_call (__pthread_setcancelstate, (state, NULL), 0);
 # endif
 #endif
 }
@@ -360,8 +360,8 @@ error_at_line (int status, int errnum, const char *file_name,
   /* We do not want this call to be cut short by a thread
      cancellation.  Therefore disable cancellation for now.  */
   int state = PTHREAD_CANCEL_ENABLE;
-  __libc_ptf_call (pthread_setcancelstate, (PTHREAD_CANCEL_DISABLE, &state),
-		   0);
+  __libc_ptf_call (__pthread_setcancelstate,
+		   (PTHREAD_CANCEL_DISABLE, &state), 0);
 #endif
 
   flush_stdout ();
@@ -393,7 +393,7 @@ error_at_line (int status, int errnum, const char *file_name,
 #ifdef _LIBC
   _IO_funlockfile (stderr);
 # ifdef __libc_ptf_call
-  __libc_ptf_call (pthread_setcancelstate, (state, NULL), 0);
+  __libc_ptf_call (__pthread_setcancelstate, (state, NULL), 0);
 # endif
 #endif
 }
diff --git a/nptl/Makefile b/nptl/Makefile
index faf2c192d5..3a4970e135 100644
--- a/nptl/Makefile
+++ b/nptl/Makefile
@@ -30,7 +30,7 @@ install-lib-ldscripts := libpthread.so
 
 routines = alloca_cutoff forward libc-lowlevellock libc-cancellation \
 	   libc-cleanup libc_pthread_init libc_multiple_threads \
-	   register-atfork unregister-atfork
+	   register-atfork unregister-atfork libc-pthread-secondary
 shared-only-routines = forward
 
 libpthread-routines = nptl-init vars events version pt-interp \
@@ -170,6 +170,7 @@ CFLAGS-pthread_exit.c = -fexceptions
 # Among others, __pthread_unwind is forwarded.  This function must handle
 # exceptions.
 CFLAGS-forward.c = -fexceptions
+CFLAGS-libc-pthread-secondary.c = -fexceptions
 
 # The following are cancellation points.  Some of the functions can
 # block and therefore temporarily enable asynchronous cancellation.
diff --git a/nptl/Versions b/nptl/Versions
index 34e4b464ed..804fd947a1 100644
--- a/nptl/Versions
+++ b/nptl/Versions
@@ -16,6 +16,10 @@ libc {
     pthread_mutex_lock; pthread_mutex_unlock;
     pthread_self;
     pthread_setcancelstate; pthread_setcanceltype;
+#if HAVE_ASM_SECONDARY_DIRECTIVE
+    # Provide additional secondary pthread functions.
+    pthread_once;
+#endif
   }
   GLIBC_2.1 {
     pthread_attr_init;
@@ -36,6 +40,18 @@ libc {
     __libc_pthread_init;
     __libc_current_sigrtmin_private; __libc_current_sigrtmax_private;
     __libc_allocate_rtsig_private;
+#if HAVE_ASM_SECONDARY_DIRECTIVE
+    # Provide additional secondary pthread functions.
+    _pthread_cleanup_pop_restore; _pthread_cleanup_push_defer;
+    __pthread_getspecific; __pthread_setspecific;
+    __pthread_key_create;
+    __pthread_mutex_lock; __pthread_mutex_unlock;
+    __pthread_once;
+    __pthread_rwlock_rdlock; __pthread_rwlock_wrlock;
+    __pthread_rwlock_unlock;
+    __pthread_setcancelstate;
+    __pthread_unwind;
+#endif
   }
 }
 
@@ -274,6 +290,18 @@ libpthread {
     __pthread_clock_gettime; __pthread_clock_settime;
     __pthread_unwind; __pthread_get_minstack;
     __pthread_barrier_init; __pthread_barrier_wait;
+#if HAVE_ASM_SECONDARY_DIRECTIVE
+    # Provide additional secondary pthread functions.
+    _pthread_cleanup_pop_restore; _pthread_cleanup_push_defer;
+    __pthread_getspecific; __pthread_setspecific;
+    __pthread_key_create;
+    __pthread_mutex_lock; __pthread_mutex_unlock;
+    __pthread_once;
+    __pthread_rwlock_rdlock; __pthread_rwlock_wrlock;
+    __pthread_rwlock_unlock;
+    __pthread_setcancelstate;
+    __pthread_unwind;
+#endif
     __shm_directory;
   }
 }
diff --git a/nptl/cleanup_defer_compat.c b/nptl/cleanup_defer_compat.c
index bd70b89556..2c2b0bd5d5 100644
--- a/nptl/cleanup_defer_compat.c
+++ b/nptl/cleanup_defer_compat.c
@@ -95,3 +95,23 @@ _pthread_cleanup_pop_restore (buffer, execute)
     buffer->__routine (buffer->__arg);
 }
 strong_alias (_pthread_cleanup_pop_restore, __pthread_cleanup_pop_restore)
+
+#ifdef SHARED
+# include <shlib-compat.h>
+strong_alias (_pthread_cleanup_push_defer,
+	      _pthread_cleanup_push_defer_2_0)
+strong_alias (_pthread_cleanup_push_defer,
+	      _pthread_cleanup_push_defer_private)
+strong_alias (_pthread_cleanup_pop_restore,
+	      _pthread_cleanup_pop_restore_2_0)
+strong_alias (_pthread_cleanup_pop_restore,
+	      _pthread_cleanup_pop_restore_private)
+compat_symbol (libpthread, _pthread_cleanup_push_defer_2_0,
+	       _pthread_cleanup_push_defer, GLIBC_2_0);
+compat_symbol (libpthread, _pthread_cleanup_push_defer_private,
+	       _pthread_cleanup_push_defer, GLIBC_PRIVATE);
+compat_symbol (libpthread, _pthread_cleanup_pop_restore_2_0,
+	       _pthread_cleanup_pop_restore, GLIBC_2_0);
+compat_symbol (libpthread, _pthread_cleanup_pop_restore_private,
+	       _pthread_cleanup_pop_restore, GLIBC_PRIVATE);
+#endif
diff --git a/nptl/forward.c b/nptl/forward.c
index db74f8df92..2a358055e2 100644
--- a/nptl/forward.c
+++ b/nptl/forward.c
@@ -31,7 +31,26 @@ struct pthread_functions __libc_pthread_functions attribute_hidden;
 int __libc_pthread_functions_init attribute_hidden;
 
 
-#define FORWARD2(name, rettype, decl, params, defaction) \
+#ifdef HAVE_ASM_SECONDARY_DIRECTIVE
+/* Make sure that it is used only when libpthread is not used.  */
+# define FORWARD2(name, rettype, decl, params, defaction) \
+asm (".secondary "#name);						      \
+rettype									      \
+name decl								      \
+{									      \
+  defaction;								      \
+}
+
+/* Same as FORWARD2, only without return.  */
+# define FORWARD_NORETURN(name, rettype, decl, params, defaction) \
+asm (".secondary "#name);						      \
+rettype									      \
+name decl								      \
+{									      \
+  defaction;								      \
+}
+#else
+# define FORWARD2(name, rettype, decl, params, defaction) \
 rettype									      \
 name decl								      \
 {									      \
@@ -42,7 +61,7 @@ name decl								      \
 }
 
 /* Same as FORWARD2, only without return.  */
-#define FORWARD_NORETURN(name, rettype, decl, params, defaction) \
+# define FORWARD_NORETURN(name, rettype, decl, params, defaction) \
 rettype									      \
 name decl								      \
 {									      \
@@ -51,6 +70,7 @@ name decl								      \
 									      \
   PTHFCT_CALL (ptr_##name, params);					      \
 }
+#endif
 
 #define FORWARD(name, decl, params, defretval) \
   FORWARD2 (name, int, decl, params, return defretval)
@@ -197,13 +217,19 @@ FORWARD (pthread_mutex_unlock, (pthread_mutex_t *mutex), (mutex), 0)
 FORWARD2 (pthread_self, pthread_t, (void), (), return 0)
 
 
-FORWARD (pthread_setcancelstate, (int state, int *oldstate), (state, oldstate),
-	 0)
+FORWARD (__pthread_setcancelstate, (int state, int *oldstate),
+	 (state, oldstate), 0)
+strong_alias (__pthread_setcancelstate, pthread_setcancelstate)
+#ifdef HAVE_ASM_SECONDARY_DIRECTIVE
+asm (".secondary pthread_setcancelstate");
+#endif
 
 FORWARD (pthread_setcanceltype, (int type, int *oldtype), (type, oldtype), 0)
 
+#ifndef HAVE_ASM_SECONDARY_DIRECTIVE
 FORWARD_NORETURN (__pthread_unwind,
                   void attribute_hidden __attribute ((noreturn))
                   __cleanup_fct_attribute attribute_compat_text_section,
                   (__pthread_unwind_buf_t *buf), (buf),
                   __safe_fatal ())
+#endif
diff --git a/nptl/libc-pthread-secondary.c b/nptl/libc-pthread-secondary.c
new file mode 100644
index 0000000000..71ceea2036
--- /dev/null
+++ b/nptl/libc-pthread-secondary.c
@@ -0,0 +1,132 @@
+/* Copyright (C) 2015 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
+   <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_ASM_SECONDARY_DIRECTIVE
+# define pthread_mutex_lock __rename_pthread_mutex_lock
+# define pthread_mutex_unlock __rename_pthread_mutex_unlock
+# include <safe-fatal.h>
+# include <errno.h>
+# undef pthread_mutex_lock
+# undef pthread_mutex_unlock
+
+static void __attribute__ ((unused))
+pthread_secondary_void (void)
+{
+}
+
+static int __attribute__ ((unused))
+pthread_secondary_zero (void)
+{
+  return 0;
+}
+
+static int __attribute__ ((unused))
+pthread_secondary_einval (void)
+{
+  return EINVAL;
+}
+
+/* Use STB_SECONDARY on pthread functions in libc so that they are used
+   only when libpthread is not used.  */
+
+asm (".secondary _pthread_cleanup_push_defer");
+strong_alias (pthread_secondary_void, _pthread_cleanup_push_defer)
+
+asm (".secondary _pthread_cleanup_pop_restore");
+
+void
+_pthread_cleanup_pop_restore (struct _pthread_cleanup_buffer *buffer,
+			      int execute)
+{
+  if (execute)
+    buffer->__routine (buffer->__arg);
+}
+
+asm (".secondary __pthread_cleanup_upto");
+strong_alias (pthread_secondary_void, __pthread_cleanup_upto)
+
+asm (".secondary __pthread_getspecific");
+strong_alias (pthread_secondary_zero, __pthread_getspecific)
+
+asm (".secondary __pthread_setspecific");
+strong_alias (pthread_secondary_einval, __pthread_setspecific)
+
+asm (".secondary __pthread_key_create");
+strong_alias (pthread_secondary_einval, __pthread_key_create)
+
+asm (".secondary __pthread_mutex_lock");
+strong_alias (pthread_secondary_zero, __pthread_mutex_lock)
+
+asm (".secondary __pthread_mutex_unlock");
+strong_alias (pthread_secondary_zero, __pthread_mutex_unlock)
+
+asm (".secondary __pthread_once");
+asm (".secondary pthread_once");
+
+int
+__pthread_once (pthread_once_t *once_control,
+		void (*init_routine) (void))
+{
+  if (*once_control == PTHREAD_ONCE_INIT)
+    {
+      init_routine ();
+      *once_control |= 2;
+    }
+  return 0;
+}
+strong_alias (__pthread_once, pthread_once)
+
+asm (".secondary __pthread_rwlock_rdlock");
+strong_alias (pthread_secondary_zero, __pthread_rwlock_rdlock)
+
+asm (".secondary __pthread_rwlock_unlock");
+strong_alias (pthread_secondary_zero, __pthread_rwlock_unlock)
+
+asm (".secondary __pthread_rwlock_wrlock");
+strong_alias (pthread_secondary_zero, __pthread_rwlock_wrlock)
+
+asm (".secondary __pthread_unwind");
+
+void
+__attribute ((noreturn))
+__cleanup_fct_attribute
+attribute_compat_text_section
+__pthread_unwind (__pthread_unwind_buf_t *buf)
+{
+  /* We cannot call abort() here.  */
+  typedef __typeof (__safe_fatal) *fn_noreturn __attribute ((noreturn));
+  fn_noreturn fn = (fn_noreturn) __safe_fatal;
+  fn ();
+}
+
+# ifndef SHARED
+asm (".secondary __pthread_setcancelstate");
+strong_alias (pthread_secondary_zero, __pthread_setcancelstate)
+
+asm (".secondary pthread_mutex_lock");
+strong_alias (__pthread_mutex_lock, pthread_mutex_lock)
+
+asm (".secondary pthread_mutex_unlock");
+strong_alias (__pthread_mutex_unlock, pthread_mutex_unlock)
+
+asm (".secondary __pthread_rwlock_destroy");
+strong_alias (pthread_secondary_zero, __pthread_rwlock_destroy)
+
+asm (".secondary __pthread_rwlock_init");
+strong_alias (pthread_secondary_zero, __pthread_rwlock_init)
+# endif
+#endif
diff --git a/nptl/nptl-init.c b/nptl/nptl-init.c
index c043fb50ab..bda1df236d 100644
--- a/nptl/nptl-init.c
+++ b/nptl/nptl-init.c
@@ -87,10 +87,11 @@ static void nptl_freeres (void);
 
 static const struct pthread_functions pthread_functions =
   {
+# ifndef HAVE_ASM_SECONDARY_DIRECTIVE
     .ptr_pthread_attr_destroy = __pthread_attr_destroy,
-# if SHLIB_COMPAT(libpthread, GLIBC_2_0, GLIBC_2_1)
+#  if SHLIB_COMPAT(libpthread, GLIBC_2_0, GLIBC_2_1)
     .ptr___pthread_attr_init_2_0 = __pthread_attr_init_2_0,
-# endif
+#  endif
     .ptr___pthread_attr_init_2_1 = __pthread_attr_init_2_1,
     .ptr_pthread_attr_getdetachstate = __pthread_attr_getdetachstate,
     .ptr_pthread_attr_setdetachstate = __pthread_attr_setdetachstate,
@@ -127,9 +128,8 @@ static const struct pthread_functions pthread_functions =
     .ptr_pthread_mutex_lock = __pthread_mutex_lock,
     .ptr_pthread_mutex_unlock = __pthread_mutex_unlock,
     .ptr_pthread_self = __pthread_self,
-    .ptr_pthread_setcancelstate = __pthread_setcancelstate,
+    .ptr___pthread_setcancelstate = __pthread_setcancelstate,
     .ptr_pthread_setcanceltype = __pthread_setcanceltype,
-    .ptr___pthread_cleanup_upto = __pthread_cleanup_upto,
     .ptr___pthread_once = __pthread_once,
     .ptr___pthread_rwlock_rdlock = __pthread_rwlock_rdlock,
     .ptr___pthread_rwlock_wrlock = __pthread_rwlock_wrlock,
@@ -139,8 +139,10 @@ static const struct pthread_functions pthread_functions =
     .ptr___pthread_setspecific = __pthread_setspecific,
     .ptr__pthread_cleanup_push_defer = __pthread_cleanup_push_defer,
     .ptr__pthread_cleanup_pop_restore = __pthread_cleanup_pop_restore,
-    .ptr_nthreads = &__nptl_nthreads,
     .ptr___pthread_unwind = &__pthread_unwind,
+# endif
+    .ptr___pthread_cleanup_upto = __pthread_cleanup_upto,
+    .ptr_nthreads = &__nptl_nthreads,
     .ptr__nptl_deallocate_tsd = __nptl_deallocate_tsd,
 # ifdef SIGSETXID
     .ptr__nptl_setxid = __nptl_setxid,
diff --git a/nptl/pthreadP.h b/nptl/pthreadP.h
index 8cd51c65ad..d3e09651b9 100644
--- a/nptl/pthreadP.h
+++ b/nptl/pthreadP.h
@@ -244,7 +244,8 @@ extern int __pthread_debug attribute_hidden;
 
 extern void __pthread_unwind (__pthread_unwind_buf_t *__buf)
      __cleanup_fct_attribute __attribute ((__noreturn__))
-#if !defined SHARED && !IS_IN (libpthread)
+#if !defined SHARED && !IS_IN (libpthread) \
+    && !defined HAVE_ASM_SECONDARY_DIRECTIVE
      weak_function
 #endif
      ;
@@ -506,6 +507,7 @@ hidden_proto (__pthread_setspecific)
 hidden_proto (__pthread_once)
 #endif
 
+#if !IS_IN (libc)
 extern int __pthread_cond_broadcast_2_0 (pthread_cond_2_0_t *cond);
 extern int __pthread_cond_destroy_2_0 (pthread_cond_2_0_t *cond);
 extern int __pthread_cond_init_2_0 (pthread_cond_2_0_t *cond,
@@ -516,6 +518,7 @@ extern int __pthread_cond_timedwait_2_0 (pthread_cond_2_0_t *cond,
 					 const struct timespec *abstime);
 extern int __pthread_cond_wait_2_0 (pthread_cond_2_0_t *cond,
 				    pthread_mutex_t *mutex);
+#endif
 
 extern int __pthread_getaffinity_np (pthread_t th, size_t cpusetsize,
 				     cpu_set_t *cpuset);
diff --git a/nptl/pthread_getspecific.c b/nptl/pthread_getspecific.c
index 0bee354817..b68395f86f 100644
--- a/nptl/pthread_getspecific.c
+++ b/nptl/pthread_getspecific.c
@@ -66,3 +66,13 @@ __pthread_getspecific (key)
 }
 strong_alias (__pthread_getspecific, pthread_getspecific)
 hidden_def (__pthread_getspecific)
+
+#ifdef SHARED
+# include <shlib-compat.h>
+strong_alias (__pthread_getspecific, __pthread_getspecific_2_0)
+strong_alias (__pthread_getspecific, __pthread_getspecific_private)
+compat_symbol (libpthread, __pthread_getspecific_2_0,
+	       __pthread_getspecific, GLIBC_2_0);
+compat_symbol (libpthread, __pthread_getspecific_private,
+	       __pthread_getspecific, GLIBC_PRIVATE);
+#endif
diff --git a/nptl/pthread_key_create.c b/nptl/pthread_key_create.c
index a642c6929f..3f0071a4aa 100644
--- a/nptl/pthread_key_create.c
+++ b/nptl/pthread_key_create.c
@@ -51,3 +51,13 @@ __pthread_key_create (key, destr)
 }
 strong_alias (__pthread_key_create, pthread_key_create)
 hidden_def (__pthread_key_create)
+
+#ifdef SHARED
+# include <shlib-compat.h>
+strong_alias (__pthread_key_create, __pthread_key_create_2_0)
+strong_alias (__pthread_key_create, __pthread_key_create_private)
+compat_symbol (libpthread, __pthread_key_create_2_0,
+	       __pthread_key_create, GLIBC_2_0);
+compat_symbol (libpthread, __pthread_key_create_private,
+	       __pthread_key_create, GLIBC_PRIVATE);
+#endif
diff --git a/nptl/pthread_mutex_lock.c b/nptl/pthread_mutex_lock.c
index 9a3b46624d..9ebc9f4566 100644
--- a/nptl/pthread_mutex_lock.c
+++ b/nptl/pthread_mutex_lock.c
@@ -516,6 +516,16 @@ __pthread_mutex_lock_full (pthread_mutex_t *mutex)
 #ifndef __pthread_mutex_lock
 strong_alias (__pthread_mutex_lock, pthread_mutex_lock)
 hidden_def (__pthread_mutex_lock)
+
+# ifdef SHARED
+# include <shlib-compat.h>
+strong_alias (__pthread_mutex_lock, __pthread_mutex_lock_2_0)
+strong_alias (__pthread_mutex_lock, __pthread_mutex_lock_private)
+compat_symbol (libpthread, __pthread_mutex_lock_2_0,
+	       __pthread_mutex_lock, GLIBC_2_0);
+compat_symbol (libpthread, __pthread_mutex_lock_private,
+	       __pthread_mutex_lock, GLIBC_PRIVATE);
+# endif
 #endif
 
 
diff --git a/nptl/pthread_mutex_unlock.c b/nptl/pthread_mutex_unlock.c
index 80939ba8b0..bcb92b18e2 100644
--- a/nptl/pthread_mutex_unlock.c
+++ b/nptl/pthread_mutex_unlock.c
@@ -316,3 +316,13 @@ __pthread_mutex_unlock (mutex)
 }
 strong_alias (__pthread_mutex_unlock, pthread_mutex_unlock)
 hidden_def (__pthread_mutex_unlock)
+
+#ifdef SHARED
+# include <shlib-compat.h>
+strong_alias (__pthread_mutex_unlock, __pthread_mutex_unlock_2_0)
+strong_alias (__pthread_mutex_unlock, __pthread_mutex_unlock_private)
+compat_symbol (libpthread, __pthread_mutex_unlock_2_0,
+	       __pthread_mutex_unlock, GLIBC_2_0);
+compat_symbol (libpthread, __pthread_mutex_unlock_private,
+	       __pthread_mutex_unlock, GLIBC_PRIVATE);
+#endif
diff --git a/nptl/pthread_once.c b/nptl/pthread_once.c
index 3c5bc33622..81d3f25848 100644
--- a/nptl/pthread_once.c
+++ b/nptl/pthread_once.c
@@ -144,3 +144,13 @@ __pthread_once (pthread_once_t *once_control, void (*init_routine) (void))
 }
 weak_alias (__pthread_once, pthread_once)
 hidden_def (__pthread_once)
+
+#ifdef SHARED
+# include <shlib-compat.h>
+strong_alias (__pthread_once, __pthread_once_2_0)
+strong_alias (__pthread_once, __pthread_once_private)
+compat_symbol (libpthread, __pthread_once_2_0,
+	       __pthread_once, GLIBC_2_0);
+compat_symbol (libpthread, __pthread_once_private,
+	       __pthread_once, GLIBC_PRIVATE);
+#endif
diff --git a/nptl/pthread_rwlock_rdlock.c b/nptl/pthread_rwlock_rdlock.c
index eb7ac8d226..f81097627f 100644
--- a/nptl/pthread_rwlock_rdlock.c
+++ b/nptl/pthread_rwlock_rdlock.c
@@ -179,3 +179,13 @@ __pthread_rwlock_rdlock (pthread_rwlock_t *rwlock)
 
 weak_alias (__pthread_rwlock_rdlock, pthread_rwlock_rdlock)
 hidden_def (__pthread_rwlock_rdlock)
+
+#ifdef SHARED
+# include <shlib-compat.h>
+strong_alias (__pthread_rwlock_rdlock, __pthread_rwlock_rdlock_2_2)
+strong_alias (__pthread_rwlock_rdlock, __pthread_rwlock_rdlock_private)
+compat_symbol (libpthread, __pthread_rwlock_rdlock_2_2,
+	       __pthread_rwlock_rdlock, GLIBC_2_2);
+compat_symbol (libpthread, __pthread_rwlock_rdlock_private,
+	       __pthread_rwlock_rdlock, GLIBC_PRIVATE);
+#endif
diff --git a/nptl/pthread_rwlock_unlock.c b/nptl/pthread_rwlock_unlock.c
index bdd115d6bd..240dd495a5 100644
--- a/nptl/pthread_rwlock_unlock.c
+++ b/nptl/pthread_rwlock_unlock.c
@@ -73,3 +73,13 @@ __pthread_rwlock_unlock (pthread_rwlock_t *rwlock)
 
 weak_alias (__pthread_rwlock_unlock, pthread_rwlock_unlock)
 hidden_def (__pthread_rwlock_unlock)
+
+#ifdef SHARED
+# include <shlib-compat.h>
+strong_alias (__pthread_rwlock_unlock, __pthread_rwlock_unlock_2_2)
+strong_alias (__pthread_rwlock_unlock, __pthread_rwlock_unlock_private)
+compat_symbol (libpthread, __pthread_rwlock_unlock_2_2,
+	       __pthread_rwlock_unlock, GLIBC_2_2);
+compat_symbol (libpthread, __pthread_rwlock_unlock_private,
+	       __pthread_rwlock_unlock, GLIBC_PRIVATE);
+#endif
diff --git a/nptl/pthread_rwlock_wrlock.c b/nptl/pthread_rwlock_wrlock.c
index 60fa909340..5167f136be 100644
--- a/nptl/pthread_rwlock_wrlock.c
+++ b/nptl/pthread_rwlock_wrlock.c
@@ -127,3 +127,13 @@ __pthread_rwlock_wrlock (pthread_rwlock_t *rwlock)
 
 weak_alias (__pthread_rwlock_wrlock, pthread_rwlock_wrlock)
 hidden_def (__pthread_rwlock_wrlock)
+
+#ifdef SHARED
+# include <shlib-compat.h>
+strong_alias (__pthread_rwlock_wrlock, __pthread_rwlock_wrlock_2_2)
+strong_alias (__pthread_rwlock_wrlock, __pthread_rwlock_wrlock_private)
+compat_symbol (libpthread, __pthread_rwlock_wrlock_2_2,
+	       __pthread_rwlock_wrlock, GLIBC_2_2);
+compat_symbol (libpthread, __pthread_rwlock_wrlock_private,
+	       __pthread_rwlock_wrlock, GLIBC_PRIVATE);
+#endif
diff --git a/nptl/pthread_setspecific.c b/nptl/pthread_setspecific.c
index a9cf26c195..3bc64eeaf1 100644
--- a/nptl/pthread_setspecific.c
+++ b/nptl/pthread_setspecific.c
@@ -93,3 +93,13 @@ __pthread_setspecific (key, value)
 }
 strong_alias (__pthread_setspecific, pthread_setspecific)
 hidden_def (__pthread_setspecific)
+
+#ifdef SHARED
+# include <shlib-compat.h>
+strong_alias (__pthread_setspecific, __pthread_setspecific_2_0)
+strong_alias (__pthread_setspecific, __pthread_setspecific_private)
+compat_symbol (libpthread, __pthread_setspecific_2_0,
+	       __pthread_setspecific, GLIBC_2_0);
+compat_symbol (libpthread, __pthread_setspecific_private,
+	       __pthread_setspecific, GLIBC_PRIVATE);
+#endif
diff --git a/posix/wordexp.c b/posix/wordexp.c
index e711d43355..1e9fc85f99 100644
--- a/posix/wordexp.c
+++ b/posix/wordexp.c
@@ -1186,7 +1186,7 @@ parse_comm (char **word, size_t *word_length, size_t *max_length,
 		  // XXX Ideally we do want the thread being cancelable.
 		  // XXX If demand is there we'll change it.
 		  int state = PTHREAD_CANCEL_ENABLE;
-		  __libc_ptf_call (pthread_setcancelstate,
+		  __libc_ptf_call (__pthread_setcancelstate,
 				   (PTHREAD_CANCEL_DISABLE, &state), 0);
 #endif
 
@@ -1194,7 +1194,7 @@ parse_comm (char **word, size_t *word_length, size_t *max_length,
 				     flags, pwordexp, ifs, ifs_white);
 
 #ifdef __libc_ptf_call
-		  __libc_ptf_call (pthread_setcancelstate, (state, NULL), 0);
+		  __libc_ptf_call (__pthread_setcancelstate, (state, NULL), 0);
 #endif
 
 		  free (comm);
diff --git a/scripts/abilist.awk b/scripts/abilist.awk
index 52b5b32b75..cbc268694d 100644
--- a/scripts/abilist.awk
+++ b/scripts/abilist.awk
@@ -38,7 +38,7 @@ $4 == "*UND*" { next }
 $2 == "l" { next }
 
 # If the target uses ST_OTHER, it will be output before the symbol name.
-$2 == "g" || $2 == "w" && (NF == 7 || NF == 8) {
+$2 == "g" || $2 == "w" || $2 == "s" && (NF == 7 || NF == 8) {
   weak = $2;
   type = $3;
   size = $5;
diff --git a/stdlib/fmtmsg.c b/stdlib/fmtmsg.c
index b8133dca4d..c2a46bd46a 100644
--- a/stdlib/fmtmsg.c
+++ b/stdlib/fmtmsg.c
@@ -127,8 +127,8 @@ fmtmsg (long int classification, const char *label, int severity,
   /* We do not want this call to be cut short by a thread
      cancellation.  Therefore disable cancellation for now.  */
   int state = PTHREAD_CANCEL_ENABLE;
-  __libc_ptf_call (pthread_setcancelstate, (PTHREAD_CANCEL_DISABLE, &state),
-		   0);
+  __libc_ptf_call (__pthread_setcancelstate,
+		   (PTHREAD_CANCEL_DISABLE, &state), 0);
 #endif
 
   __libc_lock_lock (lock);
@@ -199,7 +199,7 @@ fmtmsg (long int classification, const char *label, int severity,
   __libc_lock_unlock (lock);
 
 #ifdef __libc_ptf_call
-  __libc_ptf_call (pthread_setcancelstate, (state, NULL), 0);
+  __libc_ptf_call (__pthread_setcancelstate, (state, NULL), 0);
 #endif
 
   return result;
diff --git a/sysdeps/generic/localplt.data b/sysdeps/generic/localplt.data
index 1a40cf9841..5b1463f584 100644
--- a/sysdeps/generic/localplt.data
+++ b/sysdeps/generic/localplt.data
@@ -1,6 +1,18 @@
 # See scripts/check-localplt.awk for how this file is processed.
 # PLT use is required for the malloc family and for matherr because
 # users can define their own functions and have library internals call them.
+# pthread functions may be preempted by libpthread at run-time.
+libc.so: __pthread_getspecific
+libc.so: __pthread_key_create
+libc.so: __pthread_once
+libc.so: __pthread_rwlock_rdlock
+libc.so: __pthread_rwlock_unlock
+libc.so: __pthread_rwlock_wrlock
+libc.so: __pthread_setcancelstate
+libc.so: __pthread_setspecific
+libc.so: __pthread_unwind
+libc.so: _pthread_cleanup_pop_restore
+libc.so: _pthread_cleanup_push_defer
 libc.so: calloc
 libc.so: free
 libc.so: malloc
diff --git a/sysdeps/nptl/bits/libc-lockP.h b/sysdeps/nptl/bits/libc-lockP.h
index f55f6212ec..f5753afb32 100644
--- a/sysdeps/nptl/bits/libc-lockP.h
+++ b/sysdeps/nptl/bits/libc-lockP.h
@@ -99,39 +99,51 @@ typedef pthread_key_t __libc_key_t;
 #define __rtld_lock_initialize(NAME) \
   (void) ((NAME) = (__rtld_lock_recursive_t) _RTLD_LOCK_RECURSIVE_INITIALIZER)
 
+#ifdef HAVE_ASM_SECONDARY_DIRECTIVE
+/* All pthread functions are available.  */
+# define PTFAVAIL(NAME) 1
+
+/* When secondary symbols are used, FUNC is implemented to return ELSE so
+   that we can always call FUNC.  */
+# define __libc_maybe_call(FUNC, ARGS, ELSE) FUNC ARGS
+# define __libc_ptf_call(FUNC, ARGS, ELSE) FUNC ARGS
+# define __libc_ptf_call_always(FUNC, ARGS) FUNC ARGS
+#else
 /* If we check for a weakly referenced symbol and then perform a
    normal jump to it te code generated for some platforms in case of
    PIC is unnecessarily slow.  What would happen is that the function
    is first referenced as data and then it is called indirectly
    through the PLT.  We can make this a direct jump.  */
-#ifdef __PIC__
-# define __libc_maybe_call(FUNC, ARGS, ELSE) \
-  (__extension__ ({ __typeof (FUNC) *_fn = (FUNC); \
-		    _fn != NULL ? (*_fn) ARGS : ELSE; }))
-#else
-# define __libc_maybe_call(FUNC, ARGS, ELSE) \
-  (FUNC != NULL ? FUNC ARGS : ELSE)
-#endif
+# ifdef __PIC__
+#  define __libc_maybe_call(FUNC, ARGS, ELSE) \
+   (__extension__ ({ __typeof (FUNC) *_fn = (FUNC); \
+		     _fn != NULL ? (*_fn) ARGS : ELSE; }))
+# else
+#  define __libc_maybe_call(FUNC, ARGS, ELSE) \
+   (FUNC != NULL ? FUNC ARGS : ELSE)
+# endif
 
 /* Call thread functions through the function pointer table.  */
-#if defined SHARED && IS_IN (libc)
-# define PTFAVAIL(NAME) __libc_pthread_functions_init
-# define __libc_ptf_call(FUNC, ARGS, ELSE) \
+# if defined SHARED && IS_IN (libc) \
+     && !defined HAVE_ASM_SECONDARY_DIRECTIVE
+#  define PTFAVAIL(NAME) __libc_pthread_functions_init
+#  define __libc_ptf_call(FUNC, ARGS, ELSE) \
   (__libc_pthread_functions_init ? PTHFCT_CALL (ptr_##FUNC, ARGS) : ELSE)
-# define __libc_ptf_call_always(FUNC, ARGS) \
+#  define __libc_ptf_call_always(FUNC, ARGS) \
   PTHFCT_CALL (ptr_##FUNC, ARGS)
-#elif IS_IN (libpthread)
-# define PTFAVAIL(NAME) 1
-# define __libc_ptf_call(FUNC, ARGS, ELSE) \
+# elif IS_IN (libpthread)
+#  define PTFAVAIL(NAME) 1
+#  define __libc_ptf_call(FUNC, ARGS, ELSE) \
   FUNC ARGS
-# define __libc_ptf_call_always(FUNC, ARGS) \
+#  define __libc_ptf_call_always(FUNC, ARGS) \
   FUNC ARGS
-#else
-# define PTFAVAIL(NAME) (NAME != NULL)
-# define __libc_ptf_call(FUNC, ARGS, ELSE) \
-  __libc_maybe_call (FUNC, ARGS, ELSE)
-# define __libc_ptf_call_always(FUNC, ARGS) \
+# else
+#  define PTFAVAIL(NAME) (NAME != NULL)
+#  define __libc_ptf_call(FUNC, ARGS, ELSE) \
+   __libc_maybe_call (FUNC, ARGS, ELSE)
+#  define __libc_ptf_call_always(FUNC, ARGS) \
   FUNC ARGS
+# endif
 #endif
 
 
@@ -364,6 +376,8 @@ extern int __pthread_rwlock_unlock (pthread_rwlock_t *__rwlock);
 extern int __pthread_key_create (pthread_key_t *__key,
 				 void (*__destr_function) (void *));
 
+extern int __pthread_setcancelstate (int state, int *oldstate);
+
 extern int __pthread_setspecific (pthread_key_t __key,
 				  const void *__pointer);
 
@@ -379,8 +393,9 @@ extern int __pthread_atfork (void (*__prepare) (void),
 
 
 /* Make the pthread functions weak so that we can elide them from
-   single-threaded processes.  */
-#ifndef __NO_WEAK_PTHREAD_ALIASES
+   single-threaded processes unless secondary symbols are used.  */
+#if !defined __NO_WEAK_PTHREAD_ALIASES \
+    && !defined HAVE_ASM_SECONDARY_DIRECTIVE
 # ifdef weak_extern
 weak_extern (__pthread_mutex_init)
 weak_extern (__pthread_mutex_destroy)
@@ -405,7 +420,7 @@ weak_extern (__pthread_initialize)
 weak_extern (__pthread_atfork)
 weak_extern (_pthread_cleanup_push_defer)
 weak_extern (_pthread_cleanup_pop_restore)
-weak_extern (pthread_setcancelstate)
+weak_extern (__pthread_setcancelstate)
 # else
 #  pragma weak __pthread_mutex_init
 #  pragma weak __pthread_mutex_destroy
@@ -429,7 +444,7 @@ weak_extern (pthread_setcancelstate)
 #  pragma weak __pthread_atfork
 #  pragma weak _pthread_cleanup_push_defer
 #  pragma weak _pthread_cleanup_pop_restore
-#  pragma weak pthread_setcancelstate
+#  pragma weak __pthread_setcancelstate
 # endif
 #endif
 
diff --git a/sysdeps/nptl/jmp-unwind.c b/sysdeps/nptl/jmp-unwind.c
index 8e019867a7..6f19c6215d 100644
--- a/sysdeps/nptl/jmp-unwind.c
+++ b/sysdeps/nptl/jmp-unwind.c
@@ -18,21 +18,17 @@
 
 #include <setjmp.h>
 #include <stddef.h>
-#include <nptl/pthreadP.h>
+#include <bits/libc-lock.h>
 
 extern void __pthread_cleanup_upto (__jmp_buf env, char *targetframe);
+#ifndef HAVE_ASM_SECONDARY_DIRECTIVE
 #pragma weak __pthread_cleanup_upto
+#endif
 
 
 void
 _longjmp_unwind (jmp_buf env, int val)
 {
-#ifdef SHARED
-  if (__libc_pthread_functions_init)
-    PTHFCT_CALL (ptr___pthread_cleanup_upto, (env->__jmpbuf,
-					      CURRENT_STACK_FRAME));
-#else
-  if (__pthread_cleanup_upto != NULL)
-    __pthread_cleanup_upto (env->__jmpbuf, CURRENT_STACK_FRAME);
-#endif
+  __libc_ptf_call (__pthread_cleanup_upto, (env->__jmpbuf,
+					    CURRENT_STACK_FRAME), 0);
 }
diff --git a/sysdeps/nptl/pthread-functions.h b/sysdeps/nptl/pthread-functions.h
index 0784c59cab..f6238ab663 100644
--- a/sysdeps/nptl/pthread-functions.h
+++ b/sysdeps/nptl/pthread-functions.h
@@ -30,6 +30,7 @@ struct xid_command;
    the thread functions.  */
 struct pthread_functions
 {
+#ifndef HAVE_ASM_SECONDARY_DIRECTIVE
   int (*ptr_pthread_attr_destroy) (pthread_attr_t *);
   int (*ptr___pthread_attr_init_2_0) (pthread_attr_t *);
   int (*ptr___pthread_attr_init_2_1) (pthread_attr_t *);
@@ -75,9 +76,8 @@ struct pthread_functions
   int (*ptr_pthread_mutex_lock) (pthread_mutex_t *);
   int (*ptr_pthread_mutex_unlock) (pthread_mutex_t *);
   pthread_t (*ptr_pthread_self) (void);
-  int (*ptr_pthread_setcancelstate) (int, int *);
+  int (*ptr___pthread_setcancelstate) (int, int *);
   int (*ptr_pthread_setcanceltype) (int, int *);
-  void (*ptr___pthread_cleanup_upto) (__jmp_buf, char *);
   int (*ptr___pthread_once) (pthread_once_t *, void (*) (void));
   int (*ptr___pthread_rwlock_rdlock) (pthread_rwlock_t *);
   int (*ptr___pthread_rwlock_wrlock) (pthread_rwlock_t *);
@@ -89,10 +89,12 @@ struct pthread_functions
 					   void (*) (void *), void *);
   void (*ptr__pthread_cleanup_pop_restore) (struct _pthread_cleanup_buffer *,
 					    int);
-#define HAVE_PTR_NTHREADS
-  unsigned int *ptr_nthreads;
   void (*ptr___pthread_unwind) (__pthread_unwind_buf_t *)
        __attribute ((noreturn)) __cleanup_fct_attribute;
+#endif
+  void (*ptr___pthread_cleanup_upto) (__jmp_buf, char *);
+#define HAVE_PTR_NTHREADS
+  unsigned int *ptr_nthreads;
   void (*ptr__nptl_deallocate_tsd) (void);
   int (*ptr__nptl_setxid) (struct xid_command *);
   void (*ptr_freeres) (void);
diff --git a/sysdeps/unix/sysv/linux/fatal-prepare.h b/sysdeps/unix/sysv/linux/fatal-prepare.h
index 45d88ce911..2a89567299 100644
--- a/sysdeps/unix/sysv/linux/fatal-prepare.h
+++ b/sysdeps/unix/sysv/linux/fatal-prepare.h
@@ -19,19 +19,6 @@
 
 /* We have to completely disable cancellation.  assert() must not be a
    cancellation point but the implementation uses write() etc.  */
-#ifdef SHARED
-# include <pthread-functions.h>
-# define FATAL_PREPARE \
-  {									      \
-    if (__libc_pthread_functions_init)					      \
-      PTHFCT_CALL (ptr_pthread_setcancelstate, (PTHREAD_CANCEL_DISABLE,	      \
-						NULL));			      \
-  }
-#else
-# pragma weak pthread_setcancelstate
-# define FATAL_PREPARE \
-  {									      \
-    if (pthread_setcancelstate != NULL)					      \
-      pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, NULL);		      \
-  }
-#endif
+#define FATAL_PREPARE \
+  __libc_ptf_call (__pthread_setcancelstate, \
+		   (PTHREAD_CANCEL_DISABLE, NULL), 0)
diff --git a/sysdeps/unix/sysv/linux/i386/i486/libc-lowlevellock.S b/sysdeps/unix/sysv/linux/i386/i486/libc-lowlevellock.S
index 111e9c88ed..cf3f206445 100644
--- a/sysdeps/unix/sysv/linux/i386/i486/libc-lowlevellock.S
+++ b/sysdeps/unix/sysv/linux/i386/i486/libc-lowlevellock.S
@@ -16,4 +16,10 @@
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
+#if IS_IN (libc) && !defined SHARED
+/* Allow libpthread.a to override the ones in libc.a.  */
+	weak_extern (__lll_lock_wait_private)
+	weak_extern (__lll_unlock_wake_private)
+#endif
+
 #include "lowlevellock.S"
diff --git a/sysdeps/unix/sysv/linux/i386/libc.abilist b/sysdeps/unix/sysv/linux/i386/libc.abilist
index fcf1b72ab5..fe41fbd6ac 100644
--- a/sysdeps/unix/sysv/linux/i386/libc.abilist
+++ b/sysdeps/unix/sysv/linux/i386/libc.abilist
@@ -868,6 +868,7 @@ GLIBC_2.0
  pthread_mutex_init F
  pthread_mutex_lock F
  pthread_mutex_unlock F
+ pthread_once F
  pthread_self F
  pthread_setcancelstate F
  pthread_setcanceltype F
diff --git a/sysdeps/unix/sysv/linux/i386/localplt.data b/sysdeps/unix/sysv/linux/i386/localplt.data
index 2e03821dfd..f9efb05c41 100644
--- a/sysdeps/unix/sysv/linux/i386/localplt.data
+++ b/sysdeps/unix/sysv/linux/i386/localplt.data
@@ -6,6 +6,18 @@ libc.so: free + REL R_386_GLOB_DAT
 libc.so: malloc + REL R_386_GLOB_DAT
 libc.so: memalign
 libc.so: realloc
+# pthread functions may be preempted by libpthread at run-time.
+libc.so: __pthread_getspecific
+libc.so: __pthread_key_create
+libc.so: __pthread_once
+libc.so: __pthread_rwlock_rdlock
+libc.so: __pthread_rwlock_unlock
+libc.so: __pthread_rwlock_wrlock
+libc.so: __pthread_setcancelstate
+libc.so: __pthread_setspecific
+libc.so: __pthread_unwind
+libc.so: _pthread_cleanup_pop_restore
+libc.so: _pthread_cleanup_push_defer
 libm.so: matherr
 # The dynamic loader uses __libc_memalign internally to allocate aligned
 # TLS storage. The other malloc family of functions are expected to allow
diff --git a/sysdeps/unix/sysv/linux/s390/jmp-unwind.c b/sysdeps/unix/sysv/linux/s390/jmp-unwind.c
index 52fe1019f2..b7f9080e5a 100644
--- a/sysdeps/unix/sysv/linux/s390/jmp-unwind.c
+++ b/sysdeps/unix/sysv/linux/s390/jmp-unwind.c
@@ -18,10 +18,12 @@
 
 #include <setjmp.h>
 #include <stddef.h>
-#include <nptl/pthreadP.h>
+#include <bits/libc-lock.h>
 
 extern void __pthread_cleanup_upto (__jmp_buf env, char *targetframe);
+#ifndef HAVE_ASM_SECONDARY_DIRECTIVE
 #pragma weak __pthread_cleanup_upto
+#endif
 
 
 void
@@ -29,11 +31,5 @@ _longjmp_unwind (jmp_buf env, int val)
 {
   char local_var;
 
-#ifdef SHARED
-  if (__libc_pthread_functions_init)
-    PTHFCT_CALL (ptr___pthread_cleanup_upto, (env->__jmpbuf, &local_var));
-#else
-  if (__pthread_cleanup_upto != NULL)
-    __pthread_cleanup_upto (env->__jmpbuf, &local_var);
-#endif
+  __libc_ptf_call (__pthread_cleanup_upto, (env->__jmpbuf, &local_var), 0);
 }
diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
index b377b04e48..5be5d5ad05 100644
--- a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
@@ -1299,6 +1299,7 @@ GLIBC_2.2.5
  pthread_mutex_init F
  pthread_mutex_lock F
  pthread_mutex_unlock F
+ pthread_once F
  pthread_self F
  pthread_setcancelstate F
  pthread_setcanceltype F
diff --git a/sysdeps/unix/sysv/linux/x86_64/cancellation.S b/sysdeps/unix/sysv/linux/x86_64/cancellation.S
index 4c34bebc42..52a27dcc5e 100644
--- a/sysdeps/unix/sysv/linux/x86_64/cancellation.S
+++ b/sysdeps/unix/sysv/linux/x86_64/cancellation.S
@@ -26,7 +26,7 @@
 #  define __pthread_unwind __GI___pthread_unwind
 # endif
 #else
-# ifndef SHARED
+# if !defined SHARED && !defined HAVE_ASM_SECONDARY_DIRECTIVE
 	.weak __pthread_unwind
 # endif
 #endif
diff --git a/sysdeps/unix/sysv/linux/x86_64/libc-lowlevellock.S b/sysdeps/unix/sysv/linux/x86_64/libc-lowlevellock.S
index 111e9c88ed..cf3f206445 100644
--- a/sysdeps/unix/sysv/linux/x86_64/libc-lowlevellock.S
+++ b/sysdeps/unix/sysv/linux/x86_64/libc-lowlevellock.S
@@ -16,4 +16,10 @@
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
+#if IS_IN (libc) && !defined SHARED
+/* Allow libpthread.a to override the ones in libc.a.  */
+	weak_extern (__lll_lock_wait_private)
+	weak_extern (__lll_unlock_wake_private)
+#endif
+
 #include "lowlevellock.S"
diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
index 5f7032980b..ac95bfa196 100644
--- a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
@@ -1448,6 +1448,7 @@ GLIBC_2.16
  pthread_mutex_init F
  pthread_mutex_lock F
  pthread_mutex_unlock F
+ pthread_once F
  pthread_self F
  pthread_setcancelstate F
  pthread_setcanceltype F
diff --git a/sysdeps/x86_64/localplt.data b/sysdeps/x86_64/localplt.data
index d140476dfe..6ca015229d 100644
--- a/sysdeps/x86_64/localplt.data
+++ b/sysdeps/x86_64/localplt.data
@@ -3,6 +3,18 @@
 # users can define their own functions and have library internals call them.
 # Linker in binutils 2.26 and newer consolidates R_X86_64_JUMP_SLOT
 # relocation with R_X86_64_GLOB_DAT relocation against the same symbol.
+# pthread functions may be preempted by libpthread at run-time.
+libc.so: __pthread_getspecific
+libc.so: __pthread_key_create
+libc.so: __pthread_once
+libc.so: __pthread_rwlock_rdlock
+libc.so: __pthread_rwlock_unlock
+libc.so: __pthread_rwlock_wrlock
+libc.so: __pthread_setcancelstate
+libc.so: __pthread_setspecific
+libc.so: __pthread_unwind
+libc.so: _pthread_cleanup_pop_restore
+libc.so: _pthread_cleanup_push_defer
 libc.so: calloc
 libc.so: free + RELA R_X86_64_GLOB_DAT
 libc.so: malloc + RELA R_X86_64_GLOB_DAT