diff --git a/nptl/Makefile b/nptl/Makefile
index 94be92c789..18fbdfbee7 100644
--- a/nptl/Makefile
+++ b/nptl/Makefile
@@ -120,9 +120,10 @@ libpthread-routines = nptl-init vars events version pt-interp \
 		      cancellation \
 		      lowlevellock \
 		      lll_timedlock_wait lll_timedwait_tid \
-		      pt-fork pt-vfork \
+		      pt-fork \
 		      $(pthread-compat-wrappers) \
 		      pt-raise pt-system \
+		      pt-compat-stubs \
 		      flockfile ftrylockfile funlockfile \
 		      sigaction \
 		      herrno res pt-allocrtsig \
@@ -146,7 +147,7 @@ libpthread-routines = nptl-init vars events version pt-interp \
 #		      pthread_setresgid
 
 libpthread-shared-only-routines = version pt-interp pt-allocrtsig \
-				  unwind-forcedunwind
+				  pt-compat-stubs unwind-forcedunwind
 
 # Since cancellation handling is in large parts handled using exceptions
 # we have to compile some files with exception handling enabled, some
diff --git a/nptl/pt-vfork.c b/nptl/pt-vfork.c
deleted file mode 100644
index 2f890d3f30..0000000000
--- a/nptl/pt-vfork.c
+++ /dev/null
@@ -1,65 +0,0 @@
-/* vfork ABI-compatibility entry points for libpthread.
-   Copyright (C) 2014-2018 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/>.  */
-
-#include <unistd.h>
-#include <shlib-compat.h>
-
-/* libpthread used to have its own vfork implementation that differed
-   from libc's only in having a pointless micro-optimization.  There
-   is no longer any use to having a separate copy in libpthread, but
-   the historical ABI requires it.  For static linking, there is no
-   need to provide anything here--the libc version will be linked in.
-   For shared library ABI compatibility, there must be __vfork and
-   vfork symbols in libpthread.so; so we define them using IFUNC to
-   redirect to the libc function.  */
-
-/* Note! If the architecture doesn't support IFUNC, then we need an
-   alternate target-specific mechanism to implement this.  So we just
-   assume IFUNC here and require that the target override this file
-   if necessary.
-
-   If the architecture can assume all supported versions of gcc will
-   produce a tail-call to __libc_vfork, consider including the version
-   in sysdeps/unix/sysv/linux/aarch64/pt-vfork.c.  */
-
-#if !HAVE_IFUNC
-# error "must write pt-vfork for this machine or get IFUNC support"
-#endif
-
-#if (SHLIB_COMPAT (libpthread, GLIBC_2_0, GLIBC_2_20) \
-     || SHLIB_COMPAT (libpthread, GLIBC_2_1_2, GLIBC_2_20))
-
-extern __typeof (vfork) __libc_vfork;   /* Defined in libc.  */
-
-# undef INIT_ARCH
-# define INIT_ARCH()
-# define DEFINE_VFORK(name) libc_ifunc (name, &__libc_vfork)
-
-#endif
-
-#if SHLIB_COMPAT (libpthread, GLIBC_2_0, GLIBC_2_20)
-extern __typeof(vfork) vfork_ifunc;
-DEFINE_VFORK (vfork_ifunc)
-compat_symbol (libpthread, vfork_ifunc, vfork, GLIBC_2_0);
-#endif
-
-#if SHLIB_COMPAT (libpthread, GLIBC_2_1_2, GLIBC_2_20)
-extern __typeof(vfork) __vfork_ifunc;
-DEFINE_VFORK (__vfork_ifunc)
-compat_symbol (libpthread, __vfork_ifunc, __vfork, GLIBC_2_1_2);
-#endif
diff --git a/posix/vfork.c b/posix/vfork.c
index d4e76ad21e..07cfca1885 100644
--- a/posix/vfork.c
+++ b/posix/vfork.c
@@ -21,10 +21,10 @@
 /* If we don't have vfork, fork is close enough.  */
 
 __pid_t
-__vfork (void)
+__libc_vfork (void)
 {
   return __fork ();
 }
+strong_alias (__libc_vfork, __vfork)
 libc_hidden_def (__vfork)
-
-weak_alias (__vfork, vfork)
+weak_alias (__libc_vfork, vfork)
diff --git a/sysdeps/aarch64/sysdep.h b/sysdeps/aarch64/sysdep.h
index 5b30709436..a790e3b4ea 100644
--- a/sysdeps/aarch64/sysdep.h
+++ b/sysdeps/aarch64/sysdep.h
@@ -151,6 +151,15 @@
 	movk	PTR_REG (R), #:abs_g0_nc:NAME;
 #endif
 
+/* Make a "sibling call" to DEST -- that is, transfer control to DEST
+   as-if it had been the function called by the caller of this function.
+   DEST is likely to be defined in a different shared object.  Only
+   ever used immediately after ENTRY.  Must not touch the stack at
+   all, and must preserve all argument and call-saved registers.  */
+#undef SIBCALL
+#define SIBCALL(dest)					\
+  b JUMPTARGET(dest)
+
 /* Since C identifiers are not normally prefixed with an underscore
    on this system, the asm identifier `syscall_error' intrudes on the
    C name space.  Make sure we use an innocuous name.  */
diff --git a/sysdeps/arm/sysdep.h b/sysdeps/arm/sysdep.h
index 21673feea2..b3a233bff5 100644
--- a/sysdeps/arm/sysdep.h
+++ b/sysdeps/arm/sysdep.h
@@ -121,6 +121,15 @@
 #define CALL_MCOUNT		/* Do nothing.  */
 #endif
 
+/* Make a "sibling call" to DEST -- that is, transfer control to DEST
+   as-if it had been the function called by the caller of this function.
+   DEST is likely to be defined in a different shared object.  Only
+   ever used immediately after ENTRY.  Must not touch the stack at
+   all, and must preserve all argument and call-saved registers.  */
+#undef SIBCALL
+#define SIBCALL(dest)					\
+	b	PLTJMP(dest)
+
 /* Since C identifiers are not normally prefixed with an underscore
    on this system, the asm identifier `syscall_error' intrudes on the
    C name space.  Make sure we use an innocuous name.  */
diff --git a/sysdeps/generic/pt-compat-stubs.S b/sysdeps/generic/pt-compat-stubs.S
new file mode 100644
index 0000000000..9edf765c8c
--- /dev/null
+++ b/sysdeps/generic/pt-compat-stubs.S
@@ -0,0 +1,64 @@
+/* Compatibility stubs for functions formerly exposed by libpthread.
+   Copyright (C) 2018 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/>.  */
+
+/* The functions defined by this file used to have two different
+   definitions, one in libc.so and one in libpthread.so.  Nowadays,
+   only the version in libc is necessary, but libpthread must continue
+   to expose these symbols for compatibility's sake.  The stubs just
+   jump to the definition in libc.
+
+   This file is written in heavily macro-ized assembly language
+   because one of the stubs that it needs to define is vfork, and the
+   implementation of vfork must not touch the stack.  Having done the
+   work to handle that, we may as well reuse the mechanism for all of
+   the stubs.  */
+
+#include <shlib-compat.h>
+#include <sysdep.h>
+
+        compat_text_section
+
+#define define_stub(name)						      \
+  define_stub_1(__pstub_##name, __libc_##name)
+#define define_stub_1(pstub_name, libc_name)				      \
+  ENTRY(pstub_name)   ASM_LINE_SEP					      \
+  SIBCALL(libc_name)  ASM_LINE_SEP					      \
+  END(pstub_name)
+
+#define compat_stub(base, sym, ver)					      \
+  compat_stub_1(base, sym, ver, __COUNTER__)
+#define compat_stub_1(base, sym, ver, tag)				      \
+  compat_stub_2(base, sym, ver, tag)
+#define compat_stub_2(base, sym, ver, tag)				      \
+  compat_stub_3(__pstub_##base, __pstub_##base##_##tag, sym, ver)
+#define compat_stub_3(base, nonce, sym, ver)				      \
+  weak_alias(base, nonce) ASM_LINE_SEP					      \
+  compat_symbol(libpthread, nonce, sym, ver)
+
+#if SHLIB_COMPAT (libpthread, GLIBC_2_0, GLIBC_2_20) \
+ || SHLIB_COMPAT (libpthread, GLIBC_2_1_2, GLIBC_2_20)
+
+        define_stub(vfork)
+# if SHLIB_COMPAT (libpthread, GLIBC_2_0, GLIBC_2_20)
+        compat_stub(vfork, vfork, GLIBC_2_0)
+# endif
+# if SHLIB_COMPAT (libpthread, GLIBC_2_1_2, GLIBC_2_20)
+        compat_stub(vfork, __vfork, GLIBC_2_1_2)
+# endif
+
+#endif
diff --git a/sysdeps/generic/sysdep.h b/sysdeps/generic/sysdep.h
index 934d4da839..59e8ec237a 100644
--- a/sysdeps/generic/sysdep.h
+++ b/sysdeps/generic/sysdep.h
@@ -33,9 +33,20 @@
 # ifndef JUMPTARGET
 #  define JUMPTARGET(sym)	sym
 # endif
+
+/* Make a "sibling call" to DEST -- that is, transfer control to DEST
+   as-if it had been the function called by the caller of this function.
+   DEST is likely to be defined in a different shared object.  Only
+   ever used immediately after ENTRY.  Must not touch the stack at
+   all, and must preserve all argument and call-saved registers.  */
+# ifndef SIBCALL
+#  define SIBCALL(dest)				\
+  .error "Missing definition of SIBCALL"
+# endif
 #endif
 
-/* Makros to generate eh_frame unwind information.  */
+
+/* Macros to generate eh_frame unwind information.  */
 #ifdef __ASSEMBLER__
 # define cfi_startproc			.cfi_startproc
 # define cfi_endproc			.cfi_endproc
diff --git a/sysdeps/hppa/sysdep.h b/sysdeps/hppa/sysdep.h
index 4b139228a1..12cfe51dc3 100644
--- a/sysdeps/hppa/sysdep.h
+++ b/sysdeps/hppa/sysdep.h
@@ -62,6 +62,16 @@
 #define	PSEUDO_END(name)						      \
   END (name)
 
+
+/* Make a "sibling call" to DEST -- that is, transfer control to DEST
+   as-if it had been the function called by the caller of this function.
+   DEST is likely to be defined in a different shared object.  Only
+   ever used immediately after ENTRY.  Must not touch the stack at
+   all, and must preserve all argument and call-saved registers.  */
+#undef SIBCALL
+#define SIBCALL(dest)				\
+  b JUMPTARGET(dest)
+
 #undef JUMPTARGET
 #define JUMPTARGET(name)	name
 #define SYSCALL_PIC_SETUP	/* Nothing.  */
diff --git a/sysdeps/ia64/sysdep.h b/sysdeps/ia64/sysdep.h
index 6066ebd1d3..ba0e4a5ed2 100644
--- a/sysdeps/ia64/sysdep.h
+++ b/sysdeps/ia64/sysdep.h
@@ -59,4 +59,13 @@
 #undef END
 #define END(sym)	.endp C_SYMBOL_NAME(sym)
 
+/* Make a "sibling call" to DEST -- that is, transfer control to DEST
+   as-if it had been the function called by the caller of this function.
+   DEST is likely to be defined in a different shared object.  Only
+   ever used immediately after ENTRY.  Must not touch the stack at
+   all, and must preserve all argument and call-saved registers.  */
+#undef SIBCALL
+#define SIBCALL(dest)				\
+  .mib; nop 0; nop 0; br.sptk.many C_SYMBOL_NAME(dest);;
+
 #endif /* ASSEMBLER */
diff --git a/sysdeps/m68k/sysdep.h b/sysdeps/m68k/sysdep.h
index 0ecb3eae9f..ae085ed9f1 100644
--- a/sysdeps/m68k/sysdep.h
+++ b/sysdeps/m68k/sysdep.h
@@ -71,4 +71,13 @@
 #  define JUMPTARGET(name)	name
 # endif
 
+/* Make a "sibling call" to DEST -- that is, transfer control to DEST
+   as-if it had been the function called by the caller of this function.
+   DEST is likely to be defined in a different shared object.  Only
+   ever used immediately after ENTRY.  Must not touch the stack at
+   all, and must preserve all argument and call-saved registers.  */
+#undef SIBCALL
+#define SIBCALL(dest)							      \
+  jbra  JUMPTARGET(dest)
+
 #endif	/* __ASSEMBLER__ */
diff --git a/sysdeps/microblaze/sysdep.h b/sysdeps/microblaze/sysdep.h
index 86cd827a09..091986d221 100644
--- a/sysdeps/microblaze/sysdep.h
+++ b/sysdeps/microblaze/sysdep.h
@@ -70,6 +70,15 @@
 # define PSEUDO_END(name)                     \
   END (name)
 
+/* Make a "sibling call" to DEST -- that is, transfer control to DEST
+   as-if it had been the function called by the caller of this function.
+   DEST is likely to be defined in a different shared object.  Only
+   ever used immediately after ENTRY.  Must not touch the stack at
+   all, and must preserve all argument and call-saved registers.  */
+#undef SIBCALL
+#define SIBCALL(dest)				\
+  brid JUMPTARGET(dest); nop
+
 # undef JUMPTARGET
 # ifdef PIC
 #  define JUMPTARGET(name)   name##@PLTPC
diff --git a/sysdeps/nios2/sysdep.h b/sysdeps/nios2/sysdep.h
index 38ea9456af..97a3e2eb24 100644
--- a/sysdeps/nios2/sysdep.h
+++ b/sysdeps/nios2/sysdep.h
@@ -62,4 +62,25 @@
 # define CALL_MCOUNT		/* Do nothing.  */
 #endif
 
+/* Make a "sibling call" to DEST -- that is, transfer control to DEST
+   as-if it had been the function called by the caller of this function.
+   DEST is likely to be defined in a different shared object.  Only
+   ever used immediately after ENTRY.  Must not touch the stack at
+   all, and must preserve all argument and call-saved registers.  */
+#undef SIBCALL
+#ifdef __PIC__
+#define SIBCALL(dest)				\
+  nextpc  r2;					\
+1:						\
+  movhi	  r3, %hiadj(_gp_got - 1b);		\
+  addi	  r3, r3, %lo(_gp_got - 1b);		\
+  addi	  r2, r2, r3;				\
+  ldw	  r2, %call(dest)(r2);			\
+  jmp	  r2
+#else
+#define SIBCALL(dest)				\
+  jmpi	  dest
+#endif
+
+
 #endif	/* __ASSEMBLER__ */
diff --git a/sysdeps/powerpc/powerpc32/sysdep.h b/sysdeps/powerpc/powerpc32/sysdep.h
index 5f1294ead3..da67bf0e91 100644
--- a/sysdeps/powerpc/powerpc32/sysdep.h
+++ b/sysdeps/powerpc/powerpc32/sysdep.h
@@ -90,6 +90,14 @@ GOT_LABEL:			;					      \
   cfi_endproc;								      \
   ASM_SIZE_DIRECTIVE(name)
 
+/* Make a "sibling call" to DEST -- that is, transfer control to DEST
+   as-if it had been the function called by the caller of this function.
+   DEST is likely to be defined in a different shared object.  Only
+   ever used immediately after ENTRY.  Must not touch the stack at
+   all, and must preserve all argument and call-saved registers.  */
+#define SIBCALL(dest)							      \
+  b	JUMPTARGET(dest)
+
 #if !IS_IN(rtld) && !defined(__SPE__)
 # define ABORT_TRANSACTION_IMPL \
     cmpwi    2,0;		\
diff --git a/sysdeps/powerpc/powerpc64/sysdep.h b/sysdeps/powerpc/powerpc64/sysdep.h
index 2df1d9b6e6..10b778b244 100644
--- a/sysdeps/powerpc/powerpc64/sysdep.h
+++ b/sysdeps/powerpc/powerpc64/sysdep.h
@@ -359,6 +359,15 @@ LT_LABELSUFFIX(name,_name_end): ; \
 #define	PSEUDO_END_ERRVAL(name) \
   END (name)
 
+/* Make a "sibling call" to DEST -- that is, transfer control to DEST
+   as-if it had been the function called by the caller of this function.
+   DEST is likely to be defined in a different shared object.  Only
+   ever used immediately after ENTRY.  Must not touch the stack at
+   all, and must preserve all argument and call-saved registers.  */
+#define SIBCALL(dest)				\
+    b	JUMPTARGET(dest);			\
+    ori	r0, r0, 0
+
 #else /* !__ASSEMBLER__ */
 
 #if _CALL_ELF != 2
diff --git a/sysdeps/s390/s390-32/sysdep.h b/sysdeps/s390/s390-32/sysdep.h
index 7e2763fe92..6ba1496735 100644
--- a/sysdeps/s390/s390-32/sysdep.h
+++ b/sysdeps/s390/s390-32/sysdep.h
@@ -59,6 +59,15 @@
 #define CALL_MCOUNT		/* Do nothing.  */
 #endif
 
+/* Make a "sibling call" to DEST -- that is, transfer control to DEST
+   as-if it had been the function called by the caller of this function.
+   DEST is likely to be defined in a different shared object.  Only
+   ever used immediately after ENTRY.  Must not touch the stack at
+   all, and must preserve all argument and call-saved registers.  */
+#undef SIBCALL
+#define SIBCALL(dest)				\
+  jg JUMPTARGET(dest)
+
 /* Since C identifiers are not normally prefixed with an underscore
    on this system, the asm identifier `syscall_error' intrudes on the
    C name space.  Make sure we use an innocuous name.  */
diff --git a/sysdeps/s390/s390-64/sysdep.h b/sysdeps/s390/s390-64/sysdep.h
index a573e08e92..67f8f09542 100644
--- a/sysdeps/s390/s390-64/sysdep.h
+++ b/sysdeps/s390/s390-64/sysdep.h
@@ -57,6 +57,15 @@
 #define CALL_MCOUNT		/* Do nothing.  */
 #endif
 
+/* Make a "sibling call" to DEST -- that is, transfer control to DEST
+   as-if it had been the function called by the caller of this function.
+   DEST is likely to be defined in a different shared object.  Only
+   ever used immediately after ENTRY.  Must not touch the stack at
+   all, and must preserve all argument and call-saved registers.  */
+#undef SIBCALL
+#define SIBCALL(dest)				\
+  jg JUMPTARGET(dest)
+
 /* Since C identifiers are not normally prefixed with an underscore
    on this system, the asm identifier `syscall_error' intrudes on the
    C name space.  Make sure we use an innocuous name.  */
diff --git a/sysdeps/sh/sysdep.h b/sysdeps/sh/sysdep.h
index 37889fb0cc..63eab89001 100644
--- a/sysdeps/sh/sysdep.h
+++ b/sysdeps/sh/sysdep.h
@@ -66,6 +66,20 @@
 #define CALL_MCOUNT		/* Do nothing.  */
 #endif
 
+/* Make a "sibling call" to DEST -- that is, transfer control to DEST
+   as-if it had been the function called by the caller of this function.
+   DEST is likely to be defined in a different shared object.  Only
+   ever used immediately after ENTRY.  Must not touch the stack at
+   all, and must preserve all argument and call-saved registers.  */
+#undef SIBCALL
+#define SIBCALL(dest)				\
+	mov.l	1f, r1;				\
+	braf	r1;				\
+	nop;					\
+0:	.align 2;				\
+1:	.long	dest@PLT+(.-0b)
+
+
 /* Since C identifiers are not normally prefixed with an underscore
    on this system, the asm identifier `syscall_error' intrudes on the
    C name space.  Make sure we use an innocuous name.  */
diff --git a/sysdeps/sparc/sysdep.h b/sysdeps/sparc/sysdep.h
index 487852c7ec..130d782b11 100644
--- a/sysdeps/sparc/sysdep.h
+++ b/sysdeps/sparc/sysdep.h
@@ -79,4 +79,13 @@ C_LABEL(name)				\
 #undef LOC
 #define LOC(name)  .L##name
 
+/* Make a "sibling call" to DEST -- that is, transfer control to DEST
+   as-if it had been the function called by the caller of this function.
+   DEST is likely to be defined in a different shared object.  Only
+   ever used immediately after ENTRY.  Must not touch the stack at
+   all, and must preserve all argument and call-saved registers.  */
+#undef SIBCALL
+#define SIBCALL(dest)			\
+  jmp dest
+
 #endif	/* __ASSEMBLER__ */
diff --git a/sysdeps/tile/sysdep.h b/sysdeps/tile/sysdep.h
index bb82d3ca6c..aee9893233 100644
--- a/sysdeps/tile/sysdep.h
+++ b/sysdeps/tile/sysdep.h
@@ -56,6 +56,15 @@
 #define CALL_MCOUNT             /* Do nothing.  */
 #endif
 
+/* Make a "sibling call" to DEST -- that is, transfer control to DEST
+   as-if it had been the function called by the caller of this function.
+   DEST is likely to be defined in a different shared object.  Only
+   ever used immediately after ENTRY.  Must not touch the stack at
+   all, and must preserve all argument and call-saved registers.  */
+#undef SIBCALL
+#define SIBCALL(dest)				\
+	j	plt(dest)
+
 /* Local label name for asm code. */
 #define L(name)		.L##name
 
diff --git a/sysdeps/unix/alpha/sysdep.h b/sysdeps/unix/alpha/sysdep.h
index 104aa8e48b..263117f805 100644
--- a/sysdeps/unix/alpha/sysdep.h
+++ b/sysdeps/unix/alpha/sysdep.h
@@ -148,6 +148,16 @@ __LABEL(name)						\
 #undef PSEUDO_END_ERRVAL
 #define PSEUDO_END_ERRVAL(sym)  END(sym)
 
+/* Make a "sibling call" to DEST -- that is, transfer control to DEST
+   as-if it had been the function called by the caller of this function.
+   DEST is likely to be defined in a different shared object.  Only
+   ever used immediately after ENTRY.  Must not touch the stack at
+   all, and must preserve all argument and call-saved registers.  */
+#define SIBCALL(dest)				\
+	ldgp	gp, 0(pv);			\
+	lda	pv, dest;			\
+	jmp	(pv), dest
+
 #define ret_ERRVAL ret
 
 #define r0	v0
diff --git a/sysdeps/unix/mips/mips32/sysdep.h b/sysdeps/unix/mips/mips32/sysdep.h
index 825d007489..a45eba7430 100644
--- a/sysdeps/unix/mips/mips32/sysdep.h
+++ b/sysdeps/unix/mips/mips32/sysdep.h
@@ -54,3 +54,28 @@ L(syse1):
   bne a3, zero, 99b;							      \
 L(syse1):
 #endif
+
+/* Make a "sibling call" to DEST -- that is, transfer control to DEST
+   as-if it had been the function called by the caller of this function.
+   DEST is likely to be defined in a different shared object.  Only
+   ever used immediately after ENTRY.  Must not touch the stack at
+   all, and must preserve all argument and call-saved registers.  */
+#ifdef __PIC__
+#define SIBCALL(dest)							      \
+	.set	nomips16;						      \
+	.set	noreorder;						      \
+	.cpload $25;							      \
+	.set	nomacro;						      \
+	lw	$25, %call16(dest)($28);				      \
+	nop;								      \
+	.reloc	1f, R_MIPS_JALR, dest;					      \
+1:	jr	$25;							      \
+	nop
+#else
+#define SIBCALL(dest)							      \
+	.set	nomips16;						      \
+	.set	noreorder;						      \
+	.set	nomacro;						      \
+	j	dest;							      \
+	nop
+#endif
diff --git a/sysdeps/unix/mips/mips64/n32/sysdep.h b/sysdeps/unix/mips/mips64/n32/sysdep.h
index 78c1eca872..caae9a4b4d 100644
--- a/sysdeps/unix/mips/mips64/n32/sysdep.h
+++ b/sysdeps/unix/mips/mips64/n32/sysdep.h
@@ -61,4 +61,35 @@ L(syse1):
 L(syse1):
 #endif
 
+/* Make a "sibling call" to DEST -- that is, transfer control to DEST
+   as-if it had been the function called by the caller of this function.
+   DEST is likely to be defined in a different shared object.  Only
+   ever used immediately after ENTRY.  Must not touch the stack at
+   all, and must preserve all argument and call-saved registers.  */
+#ifdef __PIC__
+/* There's no PLT on MIPS/n32, we are expected to load the address by
+   hand, but the usual gp register on MIPS ($28) is call-saved so we
+   can't use it.  Use $at ($1) instead.  */
+#define SIBCALL(dest)							      \
+  .set	nomips16;							      \
+  .set	noreorder;							      \
+  .set	nomacro;							      \
+  .set	noat;								      \
+0:	lui	$1,	%hi(%neg(%gp_rel(0b)));				      \
+	addiu	$1, $1, %lo(%neg(%gp_rel(0b)));				      \
+	addu	$1, $1, $25;						      \
+	lw	$1, %call16(dest)($1);					      \
+	nop;								      \
+	.reloc	1f, R_MIPS_JALR, dest;					      \
+1:	jr	$25;							      \
+	nop
+#else
+#define SIBCALL(dest)							      \
+  .set	nomips16;							      \
+  .set	noreorder;							      \
+  .set	nomacro;							      \
+	j	dest;							      \
+	nop
 #endif
+
+#endif /* __ASSEMBLER__ */
diff --git a/sysdeps/unix/mips/mips64/n64/sysdep.h b/sysdeps/unix/mips/mips64/n64/sysdep.h
index a559917e64..167f330020 100644
--- a/sysdeps/unix/mips/mips64/n64/sysdep.h
+++ b/sysdeps/unix/mips/mips64/n64/sysdep.h
@@ -61,4 +61,27 @@ L(syse1):
 L(syse1):
 #endif
 
+/* Make a "sibling call" to DEST -- that is, transfer control to DEST
+   as-if it had been the function called by the caller of this function.
+   DEST is likely to be defined in a different shared object.  Only
+   ever used immediately after ENTRY.  Must not touch the stack at
+   all, and must preserve all argument and call-saved registers.  */
+#define SIBCALL(dest)							      \
+/* There's no PLT on MIPS/n64, we are expected to load the address by
+   hand, but the usual gp register on MIPS ($28) is call-saved so we
+   can't use it.  Use $at ($1) instead.  */
+#define SIBCALL(dest)							      \
+  .set	nomips16;							      \
+  .set	noreorder;							      \
+  .set	nomacro;							      \
+  .set	noat;								      \
+0:	lui	$1,	%hi(%neg(%gp_rel(0b)));				      \
+	daddiu	$1, $1, %lo(%neg(%gp_rel(0b)));				      \
+	daddu	$1, $1, $25;						      \
+	ld	$1, %call16(dest)($1);					      \
+	nop;								      \
+	.reloc	1f, R_MIPS_JALR, dest;					      \
+1:	jr	$25;							      \
+	nop
+
 #endif
diff --git a/sysdeps/unix/sysv/linux/aarch64/pt-vfork.c b/sysdeps/unix/sysv/linux/aarch64/pt-vfork.c
deleted file mode 100644
index 2b277f25ec..0000000000
--- a/sysdeps/unix/sysv/linux/aarch64/pt-vfork.c
+++ /dev/null
@@ -1,54 +0,0 @@
-/* vfork ABI-compatibility entry points for libpthread.
-   Copyright (C) 2014-2018 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/>.  */
-
-#include <shlib-compat.h>
-
-/* libpthread used to have its own vfork implementation that differed
-   from libc's only in having a pointless micro-optimization.  There
-   is no longer any use to having a separate copy in libpthread, but
-   the historical ABI requires it.  For static linking, there is no
-   need to provide anything here--the libc version will be linked in.
-   For shared library ABI compatibility, there must be __vfork and
-   vfork symbols in libpthread.so.  */
-
-#if HAVE_IFUNC
-# include <nptl/pt-vfork.c>
-#elif (SHLIB_COMPAT (libpthread, GLIBC_2_0, GLIBC_2_20) \
-       || SHLIB_COMPAT (libpthread, GLIBC_2_1_2, GLIBC_2_20))
-
-/* Thankfully, on AArch64 we can rely on the compiler generating
-   a tail call here.  */
-
-extern void __libc_vfork (void);
-
-void
-vfork_compat (void)
-{
-  __libc_vfork ();
-}
-
-# if SHLIB_COMPAT (libpthread, GLIBC_2_0, GLIBC_2_20)
-compat_symbol (libpthread, vfork_compat, vfork, GLIBC_2_0);
-# endif
-
-# if SHLIB_COMPAT (libpthread, GLIBC_2_1_2, GLIBC_2_20)
-strong_alias (vfork_compat, vfork_compat2)
-compat_symbol (libpthread, vfork_compat2, __vfork, GLIBC_2_1_2);
-# endif
-
-#endif
diff --git a/sysdeps/unix/sysv/linux/m68k/pt-vfork.c b/sysdeps/unix/sysv/linux/m68k/pt-vfork.c
deleted file mode 100644
index 5fbc6526aa..0000000000
--- a/sysdeps/unix/sysv/linux/m68k/pt-vfork.c
+++ /dev/null
@@ -1 +0,0 @@
-#include <sysdeps/unix/sysv/linux/aarch64/pt-vfork.c>
diff --git a/sysdeps/unix/sysv/linux/riscv/sysdep.h b/sysdeps/unix/sysv/linux/riscv/sysdep.h
index 5470ea3d2a..0a2c2f8696 100644
--- a/sysdeps/unix/sysv/linux/riscv/sysdep.h
+++ b/sysdeps/unix/sysv/linux/riscv/sysdep.h
@@ -107,6 +107,15 @@
 # undef ret_ERRVAL
 # define ret_ERRVAL ret
 
+/* Make a "sibling call" to DEST -- that is, transfer control to DEST
+   as-if it had been the function called by the caller of this function.
+   DEST is likely to be defined in a different shared object.  Only
+   ever used immediately after ENTRY.  Must not touch the stack at
+   all, and must preserve all argument and call-saved registers.  */
+#undef SIBCALL
+#define SIBCALL(dest)					\
+  tail	JUMPTARGET(dest)
+
 #endif /* __ASSEMBLER__ */
 
 /* In order to get __set_errno() definition in INLINE_SYSCALL.  */
diff --git a/sysdeps/unix/sysv/linux/tile/pt-vfork.c b/sysdeps/unix/sysv/linux/tile/pt-vfork.c
deleted file mode 100644
index 5fbc6526aa..0000000000
--- a/sysdeps/unix/sysv/linux/tile/pt-vfork.c
+++ /dev/null
@@ -1 +0,0 @@
-#include <sysdeps/unix/sysv/linux/aarch64/pt-vfork.c>
diff --git a/sysdeps/x86/sysdep.h b/sysdeps/x86/sysdep.h
index afcb7cfd76..6baf03de94 100644
--- a/sysdeps/x86/sysdep.h
+++ b/sysdeps/x86/sysdep.h
@@ -46,6 +46,15 @@
 #define ENTRY_CHK(name) ENTRY (name)
 #define END_CHK(name) END (name)
 
+/* Make a "sibling call" to DEST -- that is, transfer control to DEST
+   as-if it had been the function called by the caller of this function.
+   DEST is likely to be defined in a different shared object.  Only
+   ever used immediately after ENTRY.  Must not touch the stack at
+   all, and must preserve all argument and call-saved registers.  */
+#undef SIBCALL
+#define SIBCALL(dest)                           \
+  jmp JUMPTARGET(dest)
+
 /* Since C identifiers are not normally prefixed with an underscore
    on this system, the asm identifier `syscall_error' intrudes on the
    C name space.  Make sure we use an innocuous name.  */
