From 25647d4e7f72138563da1da8492855321e77695d Mon Sep 17 00:00:00 2001
From: "H.J. Lu" <hjl.tools@gmail.com>
Date: Sun, 25 Feb 2018 09:48:39 -0800
Subject: [PATCH] x86: Add __sigsetjmp_cancel and __setjmp_cancel

Functions, like LIBC_START_MAIN, START_THREAD_DEFN as well as these
with thread cancellation, call setjmp, but never return to their
callers after longjmp returns.  This patch adds <bits/setjmp-cancel.h>
and <setjmp-cancelP.h> to provide a version of setjmp family functions,
__setjmp_cancel and __sigsetjmp_cancel, which are used to implement
thread cancellation.  The default __setjmp_cancel and __sigsetjmp_cancel
are defined as setjmp and __sigsetjmp, respectively, which are the same
as before.

On x86, __sigsetjmp_cancel, which is a public function used by macros
in <pthread.h>, and __setjmp_cancel, which is a private interface for
cancellation implementation in libpthread, are added to avoid saving
and restoring shadow stack register.  A new version of __sigsetjmp is
added to save and restore shadow stack register. The compatible version
of __sigsetjmp, which doesn't save and restore shadow stack register,
is provided for shared libraries built with glibc 2.27 or older.
__libc_longjmp, which is a private interface for cancellation
implementation in libpthread, is changed to call __longjmp_cancel
instead of __longjmp.  Since libpthread provides compatible versions
of longjmp and siglongjmp which don't save and restore shadow stack,
new versions of longjmp and siglongjmp, which save and restore shadow
stack, are also added to libc.

NB: Shared libraries built with glibc 2.27 or older are compatible with
glibc 2.28.  Relocatable objects compiled against glibc 2.27 or older
are incompatible with glibc 2.28 since they reference the older version
of __sigsetjmp.

Tested with build-many-glibcs.py.

	* bits/setjmp-cancel.h: New file.
	* sysdeps/generic/setjmp-cancelP.h: Likewise.
	* sysdeps/x86/__longjmp_cancel.S: Likewise.
	* sysdeps/x86/bsd-_setjmp_cancel.S: Likewise.
	* sysdeps/x86/longjmp.c: Likewise.
	* sysdeps/x86/setjmp-cancelP.h: Likewise.
	* sysdeps/x86/setjmp_cancel.S: Likewise.
	* sysdeps/x86/bits/setjmp-cancel.h: Likewise.
	* sysdeps/x86_64/setjmp_cancel.S: Likewise.
	* csu/libc-start.c (LIBC_START_MAIN): Replace setjmp with
	__setjmp_cancel.
	* nptl/pthread_create.c (START_THREAD_DEFN): Likewise.
	* include/setjmp.h: Include <setjmp-cancelP.h> and
	<bits/setjmp-cancel.h>.
	* misc/sys/cdefs.h (__attribute_returns_twice__): New.
	* nptl/Makefile (headers): Add bits/setjmp-cancel.h.
	* setjmp/longjmp.c (__libc_longjmp): Don't define alias if
	defined.
	(longjmp): Likewise.
	(siglongjmp): Likewise.
	* sysdeps/i386/bsd-_setjmp.S (_setjmp): Don't add hidden_def.
	* sysdeps/x86_64/bsd-_setjmp.S (_setjmp): Likewise.
	* sysdeps/i386/setjmp.S (__sigsetjmp): Don't add hidden_def and
	redefined to __redirect___sigsetjmp in libc.so if __sigsetjmp
	is undefined.
	(__GI___sigsetjmp): New.  Defined if __redirect___sigsetjmp is
	defined.
	(__sigsetjmp): Add to GLIBC_2_28 if __redirect___sigsetjmp is
	defined.
	* sysdeps/x86_64/setjmp.S: Likewise.
	* sysdeps/nptl/pthread.h (pthread_cleanup_push): Replace
	__sigsetjmp with __sigsetjmp_cancel.
	(pthread_cleanup_push_defer_np): Likewise.
	(__jmp_buf_tag): Removed.
	(__sigsetjmp): Likewise.
	Include <bits/setjmp-cancel.h>.
	* sysdeps/unix/sysv/linux/i386/libc.abilist: Regenerated.
	* sysdeps/unix/sysv/linux/x86_64/64/libc.abilist: Likewise.
	* sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist: Likewise.
	* sysdeps/x86/Makefile (sysdep_routines): Add
	bsd-_setjmp_cancel, __longjmp_cancel and setjmp_cancel.
	* sysdeps/x86/Versions (longjmp): Add to GLIBC_2.28 in libc.
	(siglongjmp): Likewise.
	(__sigsetjmp_cancel): Likewise.
	(__setjmp_cancel): Add to GLIBC_PRIVATE in libc.
	* sysdeps/x86_64/bsd-_setjmp.S (SIGSETJMP): New.
	(_setjmp): Jmp to SIGSETJMP.
---
 bits/setjmp-cancel.h                            | 33 +++++++++++++++
 csu/libc-start.c                                |  2 +-
 include/setjmp.h                                |  3 ++
 misc/sys/cdefs.h                                |  6 +++
 nptl/Makefile                                   |  2 +-
 nptl/pthread_create.c                           |  2 +-
 setjmp/longjmp.c                                |  4 +-
 sysdeps/generic/setjmp-cancelP.h                | 19 +++++++++
 sysdeps/i386/bsd-_setjmp.S                      |  2 +
 sysdeps/i386/setjmp.S                           | 16 +++++++-
 sysdeps/nptl/pthread.h                          | 15 ++++---
 sysdeps/unix/sysv/linux/i386/libc.abilist       |  5 +++
 sysdeps/unix/sysv/linux/x86_64/64/libc.abilist  |  5 +++
 sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist |  5 +++
 sysdeps/x86/Makefile                            |  4 ++
 sysdeps/x86/Versions                            | 15 +++++++
 sysdeps/x86/__longjmp_cancel.S                  | 20 +++++++++
 sysdeps/x86/bits/setjmp-cancel.h                | 31 ++++++++++++++
 sysdeps/x86/bsd-_setjmp_cancel.S                | 22 ++++++++++
 sysdeps/x86/longjmp.c                           | 54 +++++++++++++++++++++++++
 sysdeps/x86/setjmp-cancelP.h                    | 24 +++++++++++
 sysdeps/x86/setjmp_cancel.S                     | 26 ++++++++++++
 sysdeps/x86_64/bsd-_setjmp.S                    | 25 +++++++++---
 sysdeps/x86_64/setjmp.S                         | 16 +++++++-
 sysdeps/x86_64/setjmp_cancel.S                  | 21 ++++++++++
 25 files changed, 358 insertions(+), 19 deletions(-)
 create mode 100644 bits/setjmp-cancel.h
 create mode 100644 sysdeps/generic/setjmp-cancelP.h
 create mode 100644 sysdeps/x86/__longjmp_cancel.S
 create mode 100644 sysdeps/x86/bits/setjmp-cancel.h
 create mode 100644 sysdeps/x86/bsd-_setjmp_cancel.S
 create mode 100644 sysdeps/x86/longjmp.c
 create mode 100644 sysdeps/x86/setjmp-cancelP.h
 create mode 100644 sysdeps/x86/setjmp_cancel.S
 create mode 100644 sysdeps/x86_64/setjmp_cancel.S

diff --git a/bits/setjmp-cancel.h b/bits/setjmp-cancel.h
new file mode 100644
index 0000000000..a0c4566127
--- /dev/null
+++ b/bits/setjmp-cancel.h
@@ -0,0 +1,33 @@
+/* __sigsetjmp_cancel for thread cancellation.  Generic version.
+   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/>.  */
+
+#ifndef _BITS_SETJMP_CANCEL_H
+#define _BITS_SETJMP_CANCEL_H  1
+
+#if !defined _SETJMP_H && !defined _PTHREAD_H
+# error "Never include <bits/setjmp-cancel.h> directly; use <setjmp.h> instead."
+#endif
+
+#define __sigsetjmp_cancel __sigsetjmp
+
+struct __jmp_buf_tag;
+/* Function used in the macros.  */
+extern int __sigsetjmp (struct __jmp_buf_tag *__env,
+			int __savemask) __THROWNL;
+
+#endif  /* bits/setjmp-cancel.h */
diff --git a/csu/libc-start.c b/csu/libc-start.c
index 605222fa3f..0c1e2fa830 100644
--- a/csu/libc-start.c
+++ b/csu/libc-start.c
@@ -292,7 +292,7 @@ LIBC_START_MAIN (int (*main) (int, char **, char ** MAIN_AUXVEC_DECL),
   struct pthread_unwind_buf unwind_buf;
 
   int not_first_call;
-  not_first_call = setjmp ((struct __jmp_buf_tag *) unwind_buf.cancel_jmp_buf);
+  not_first_call = __setjmp_cancel ((struct __jmp_buf_tag *) unwind_buf.cancel_jmp_buf);
   if (__glibc_likely (! not_first_call))
     {
       struct pthread *self = THREAD_SELF;
diff --git a/include/setjmp.h b/include/setjmp.h
index 263bc64b3d..fa846c83cc 100644
--- a/include/setjmp.h
+++ b/include/setjmp.h
@@ -31,6 +31,9 @@ libc_hidden_proto (__sigsetjmp)
 extern __typeof (__sigsetjmp) __sigsetjmp attribute_hidden;
 # endif
 
+# include <setjmp-cancelP.h>
+# include <bits/setjmp-cancel.h>
+
 /* Check jmp_buf sizes, alignments and offsets.  */
 # include <stddef.h>
 # include <jmp_buf-macros.h>
diff --git a/misc/sys/cdefs.h b/misc/sys/cdefs.h
index e80a45ca68..5f704f41db 100644
--- a/misc/sys/cdefs.h
+++ b/misc/sys/cdefs.h
@@ -416,6 +416,12 @@
 # endif
 #endif
 
+#if __GNUC_PREREQ (4, 1)
+# define __attribute_returns_twice__ __attribute__ ((__returns_twice__))
+#else
+# define __attribute_returns_twice__ /* Ignore.  */
+#endif
+
 #if __GNUC_PREREQ (8, 0)
 /* Describes a char array whose address can safely be passed as the first
    argument to strncpy and strncat, as the char array is not necessarily
diff --git a/nptl/Makefile b/nptl/Makefile
index 94be92c789..fa3027072d 100644
--- a/nptl/Makefile
+++ b/nptl/Makefile
@@ -22,7 +22,7 @@ subdir	:= nptl
 
 include ../Makeconfig
 
-headers := pthread.h semaphore.h bits/semaphore.h
+headers := pthread.h semaphore.h bits/semaphore.h bits/setjmp-cancel.h
 
 extra-libs := libpthread
 extra-libs-others := $(extra-libs)
diff --git a/nptl/pthread_create.c b/nptl/pthread_create.c
index caaf07c134..0728779994 100644
--- a/nptl/pthread_create.c
+++ b/nptl/pthread_create.c
@@ -432,7 +432,7 @@ START_THREAD_DEFN
   unwind_buf.priv.data.cleanup = NULL;
 
   int not_first_call;
-  not_first_call = setjmp ((struct __jmp_buf_tag *) unwind_buf.cancel_jmp_buf);
+  not_first_call = __setjmp_cancel ((struct __jmp_buf_tag *) unwind_buf.cancel_jmp_buf);
   if (__glibc_likely (! not_first_call))
     {
       /* Store the new cleanup handler info.  */
diff --git a/setjmp/longjmp.c b/setjmp/longjmp.c
index a2a7065a85..4abf1662ac 100644
--- a/setjmp/longjmp.c
+++ b/setjmp/longjmp.c
@@ -40,10 +40,12 @@ __libc_siglongjmp (sigjmp_buf env, int val)
 }
 
 #ifndef __libc_siglongjmp
+# ifndef __libc_longjmp
 /* __libc_longjmp is a private interface for cancellation implementation
    in libpthread.  */
 strong_alias (__libc_siglongjmp, __libc_longjmp)
-weak_alias (__libc_siglongjmp, _longjmp)
 weak_alias (__libc_siglongjmp, longjmp)
 weak_alias (__libc_siglongjmp, siglongjmp)
+# endif
+weak_alias (__libc_siglongjmp, _longjmp)
 #endif
diff --git a/sysdeps/generic/setjmp-cancelP.h b/sysdeps/generic/setjmp-cancelP.h
new file mode 100644
index 0000000000..658a3306f3
--- /dev/null
+++ b/sysdeps/generic/setjmp-cancelP.h
@@ -0,0 +1,19 @@
+/* Internal header file for <bits/setjmp-cancel.h>.  Generic version.
+   Copyright (C) 2017-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/>.  */
+
+#define __setjmp_cancel setjmp
diff --git a/sysdeps/i386/bsd-_setjmp.S b/sysdeps/i386/bsd-_setjmp.S
index a626cc6d22..51446a5614 100644
--- a/sysdeps/i386/bsd-_setjmp.S
+++ b/sysdeps/i386/bsd-_setjmp.S
@@ -53,4 +53,6 @@ ENTRY (_setjmp)
 	movl %eax, JB_SIZE(%edx) /* No signal mask set.  */
 	ret
 END (_setjmp)
+#ifndef _setjmp
 libc_hidden_def (_setjmp)
+#endif
diff --git a/sysdeps/i386/setjmp.S b/sysdeps/i386/setjmp.S
index 6a08701717..e7ba7a7ce5 100644
--- a/sysdeps/i386/setjmp.S
+++ b/sysdeps/i386/setjmp.S
@@ -25,6 +25,11 @@
 #define JMPBUF	PARMS
 #define SIGMSK	JMPBUF+4
 
+#if !defined __sigsetjmp && defined SHARED && !IS_IN (rtld)
+# define __sigsetjmp __redirect___sigsetjmp
+# define __redirect___sigsetjmp __redirect___sigsetjmp
+#endif
+
 ENTRY (__sigsetjmp)
 
 	movl JMPBUF(%esp), %eax
@@ -55,4 +60,13 @@ ENTRY (__sigsetjmp)
 	jmp __sigjmp_save
 #endif
 END (__sigsetjmp)
-hidden_def (__sigsetjmp)
+#ifdef __redirect___sigsetjmp
+# undef __sigsetjmp
+
+	.globl __GI___sigsetjmp
+	.hidden __GI___sigsetjmp
+	__GI___sigsetjmp = __redirect___sigsetjmp
+
+# include <shlib-compat.h>
+versioned_symbol (libc, __redirect___sigsetjmp, __sigsetjmp, GLIBC_2_28);
+#endif
diff --git a/sysdeps/nptl/pthread.h b/sysdeps/nptl/pthread.h
index df049abf74..8568baff9d 100644
--- a/sysdeps/nptl/pthread.h
+++ b/sysdeps/nptl/pthread.h
@@ -667,8 +667,9 @@ __pthread_cleanup_routine (struct __pthread_cleanup_frame *__frame)
     __pthread_unwind_buf_t __cancel_buf;				      \
     void (*__cancel_routine) (void *) = (routine);			      \
     void *__cancel_arg = (arg);						      \
-    int __not_first_call = __sigsetjmp ((struct __jmp_buf_tag *) (void *)     \
-					__cancel_buf.__cancel_jmp_buf, 0);    \
+    int __not_first_call						      \
+      = __sigsetjmp_cancel ((struct __jmp_buf_tag *) (void *)		      \
+			    __cancel_buf.__cancel_jmp_buf, 0);		      \
     if (__glibc_unlikely (__not_first_call))				      \
       {									      \
 	__cancel_routine (__cancel_arg);				      \
@@ -702,8 +703,9 @@ extern void __pthread_unregister_cancel (__pthread_unwind_buf_t *__buf)
     __pthread_unwind_buf_t __cancel_buf;				      \
     void (*__cancel_routine) (void *) = (routine);			      \
     void *__cancel_arg = (arg);						      \
-    int __not_first_call = __sigsetjmp ((struct __jmp_buf_tag *) (void *)     \
-					__cancel_buf.__cancel_jmp_buf, 0);    \
+    int __not_first_call						      \
+      = __sigsetjmp_cancel ((struct __jmp_buf_tag *) (void *)		      \
+			    __cancel_buf.__cancel_jmp_buf, 0);		      \
     if (__glibc_unlikely (__not_first_call))				      \
       {									      \
 	__cancel_routine (__cancel_arg);				      \
@@ -739,10 +741,7 @@ extern void __pthread_unwind_next (__pthread_unwind_buf_t *__buf)
      ;
 #endif
 
-/* Function used in the macros.  */
-struct __jmp_buf_tag;
-extern int __sigsetjmp (struct __jmp_buf_tag *__env, int __savemask) __THROWNL;
-
+#include <bits/setjmp-cancel.h>
 
 /* Mutex handling.  */
 
diff --git a/sysdeps/unix/sysv/linux/i386/libc.abilist b/sysdeps/unix/sysv/linux/i386/libc.abilist
index 39c993fd79..4f1f689302 100644
--- a/sysdeps/unix/sysv/linux/i386/libc.abilist
+++ b/sysdeps/unix/sysv/linux/i386/libc.abilist
@@ -2064,6 +2064,11 @@ GLIBC_2.27 wcstof64 F
 GLIBC_2.27 wcstof64_l F
 GLIBC_2.27 wcstof64x F
 GLIBC_2.27 wcstof64x_l F
+GLIBC_2.28 GLIBC_2.28 A
+GLIBC_2.28 __sigsetjmp F
+GLIBC_2.28 __sigsetjmp_cancel F
+GLIBC_2.28 longjmp F
+GLIBC_2.28 siglongjmp F
 GLIBC_2.3 GLIBC_2.3 A
 GLIBC_2.3 __ctype_b_loc F
 GLIBC_2.3 __ctype_tolower_loc F
diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
index 2a3cc40674..a94347b8d6 100644
--- a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
@@ -1905,6 +1905,11 @@ GLIBC_2.27 wcstof64 F
 GLIBC_2.27 wcstof64_l F
 GLIBC_2.27 wcstof64x F
 GLIBC_2.27 wcstof64x_l F
+GLIBC_2.28 GLIBC_2.28 A
+GLIBC_2.28 __sigsetjmp F
+GLIBC_2.28 __sigsetjmp_cancel F
+GLIBC_2.28 longjmp F
+GLIBC_2.28 siglongjmp F
 GLIBC_2.3 GLIBC_2.3 A
 GLIBC_2.3 __ctype_b_loc F
 GLIBC_2.3 __ctype_tolower_loc F
diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
index 8bc16b9004..e8dd56c69a 100644
--- a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
@@ -2148,3 +2148,8 @@ GLIBC_2.27 wcstof64 F
 GLIBC_2.27 wcstof64_l F
 GLIBC_2.27 wcstof64x F
 GLIBC_2.27 wcstof64x_l F
+GLIBC_2.28 GLIBC_2.28 A
+GLIBC_2.28 __sigsetjmp F
+GLIBC_2.28 __sigsetjmp_cancel F
+GLIBC_2.28 longjmp F
+GLIBC_2.28 siglongjmp F
diff --git a/sysdeps/x86/Makefile b/sysdeps/x86/Makefile
index 0d0326c21a..d23ee462f7 100644
--- a/sysdeps/x86/Makefile
+++ b/sysdeps/x86/Makefile
@@ -8,3 +8,7 @@ sysdep-dl-routines += dl-get-cpu-features
 tests += tst-get-cpu-features
 tests-static += tst-get-cpu-features-static
 endif
+
+ifeq ($(subdir),setjmp)
+sysdep_routines += bsd-_setjmp_cancel __longjmp_cancel setjmp_cancel
+endif
diff --git a/sysdeps/x86/Versions b/sysdeps/x86/Versions
index e02923708e..bcb86a73e0 100644
--- a/sysdeps/x86/Versions
+++ b/sysdeps/x86/Versions
@@ -3,3 +3,18 @@ ld {
     __get_cpu_features;
   }
 }
+libc {
+  GLIBC_2.28 {
+   # New versions to avoid picking up old ones in libpthread.
+   longjmp;
+   siglongjmp;
+   __sigsetjmp;
+
+   # used to implement thread cancellation.
+   __sigsetjmp_cancel;
+  }
+  GLIBC_PRIVATE {
+   # used to implement thread cancellation.
+    __setjmp_cancel;
+  }
+}
diff --git a/sysdeps/x86/__longjmp_cancel.S b/sysdeps/x86/__longjmp_cancel.S
new file mode 100644
index 0000000000..b57dbfa376
--- /dev/null
+++ b/sysdeps/x86/__longjmp_cancel.S
@@ -0,0 +1,20 @@
+/* __longjmp_cancel for x86.
+   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/>.  */
+
+#define __longjmp __longjmp_cancel
+#include <__longjmp.S>
diff --git a/sysdeps/x86/bits/setjmp-cancel.h b/sysdeps/x86/bits/setjmp-cancel.h
new file mode 100644
index 0000000000..87fd6cf96f
--- /dev/null
+++ b/sysdeps/x86/bits/setjmp-cancel.h
@@ -0,0 +1,31 @@
+/* __sigsetjmp_cancel for thread cancellation.  x86 version.
+   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/>.  */
+
+#ifndef _BITS_SETJMP_CANCEL_H
+#define _BITS_SETJMP_CANCEL_H  1
+
+#if !defined _SETJMP_H && !defined _PTHREAD_H
+# error "Never include <bits/setjmp-cancel.h> directly; use <setjmp.h> instead."
+#endif
+
+/* Function used in the macros.  */
+struct __jmp_buf_tag;
+extern int __sigsetjmp_cancel (struct __jmp_buf_tag *__env, int __savemask)
+  __THROWNL __attribute_returns_twice__;
+
+#endif  /* bits/setjmp-cancel.h */
diff --git a/sysdeps/x86/bsd-_setjmp_cancel.S b/sysdeps/x86/bsd-_setjmp_cancel.S
new file mode 100644
index 0000000000..25b2a95960
--- /dev/null
+++ b/sysdeps/x86/bsd-_setjmp_cancel.S
@@ -0,0 +1,22 @@
+/* __setjmp_cancel for x86.
+   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/>.  */
+
+#define _setjmp __setjmp_cancel
+#include <bsd-_setjmp.S>
+
+libc_hidden_def (__setjmp_cancel)
diff --git a/sysdeps/x86/longjmp.c b/sysdeps/x86/longjmp.c
new file mode 100644
index 0000000000..72c04a9584
--- /dev/null
+++ b/sysdeps/x86/longjmp.c
@@ -0,0 +1,54 @@
+/* __libc_siglongjmp for x86.
+   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/>.  */
+
+#define __libc_longjmp __redirect___libc_longjmp
+#include <setjmp/longjmp.c>
+#undef __libc_longjmp
+
+/* Since __libc_longjmp is a private interface for cancellation
+   implementation in libpthread, there is no need to restore shadow
+   stack register.  */
+
+void
+__libc_longjmp (sigjmp_buf env, int val)
+{
+  /* Perform any cleanups needed by the frames being unwound.  */
+  _longjmp_unwind (env, val);
+
+  if (env[0].__mask_was_saved)
+    /* Restore the saved signal mask.  */
+    (void) __sigprocmask (SIG_SETMASK,
+			  (sigset_t *) &env[0].__saved_mask,
+			  (sigset_t *) NULL);
+
+  /* Call the machine-dependent function to restore machine state
+     without shadow stack.  */
+  __longjmp_cancel (env[0].__jmpbuf, val ?: 1);
+}
+
+#include <shlib-compat.h>
+
+versioned_symbol (libc, __libc_siglongjmp, siglongjmp, GLIBC_2_28);
+strong_alias (__libc_siglongjmp, __libc_siglongjmp_alias)
+versioned_symbol (libc, __libc_siglongjmp_alias, longjmp, GLIBC_2_28);
+
+#if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_28)
+compat_symbol (libc, __libc_longjmp, longjmp, GLIBC_2_0);
+strong_alias (__libc_longjmp, __libc_longjmp_alias)
+compat_symbol (libc, __libc_longjmp_alias, siglongjmp, GLIBC_2_0);
+#endif
diff --git a/sysdeps/x86/setjmp-cancelP.h b/sysdeps/x86/setjmp-cancelP.h
new file mode 100644
index 0000000000..1cd4f94b50
--- /dev/null
+++ b/sysdeps/x86/setjmp-cancelP.h
@@ -0,0 +1,24 @@
+/* Internal header file for <bits/setjmp-cancel.h>.  x86 version.
+   Copyright (C) 2017-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/>.  */
+
+extern int __setjmp_cancel (struct __jmp_buf_tag __env[1])
+  __attribute__((__returns_twice__));
+libc_hidden_proto (__setjmp_cancel, __returns_twice__)
+
+extern void __longjmp_cancel (__jmp_buf __env, int __val)
+     __attribute__ ((__noreturn__)) attribute_hidden;
diff --git a/sysdeps/x86/setjmp_cancel.S b/sysdeps/x86/setjmp_cancel.S
new file mode 100644
index 0000000000..b2bca39883
--- /dev/null
+++ b/sysdeps/x86/setjmp_cancel.S
@@ -0,0 +1,26 @@
+/* __sigsetjmp_cancel for x86.
+   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/>.  */
+
+#define __sigsetjmp __sigsetjmp_cancel
+#include <setjmp.S>
+#undef __sigsetjmp
+
+#include <shlib-compat.h>
+#if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_28)
+compat_symbol (libc, __sigsetjmp_cancel, __sigsetjmp, GLIBC_2_0);
+#endif
diff --git a/sysdeps/x86_64/bsd-_setjmp.S b/sysdeps/x86_64/bsd-_setjmp.S
index 58c997de59..e4908b0081 100644
--- a/sysdeps/x86_64/bsd-_setjmp.S
+++ b/sysdeps/x86_64/bsd-_setjmp.S
@@ -25,13 +25,28 @@
 #define _SETJMP_H
 #include <bits/setjmp.h>
 
+/* If _setjmp is defined for __setjmp_cancel, call __sigsetjmp_cancel
+   instead of __sigsetjmp.
+ */
+#ifdef _setjmp
+# ifdef PIC
+#  define SIGSETJMP HIDDEN_JUMPTARGET (__sigsetjmp_cancel)
+# else
+#  define SIGSETJMP __sigsetjmp_cancel
+# endif
+#else
+# ifdef PIC
+#  define SIGSETJMP HIDDEN_JUMPTARGET (__sigsetjmp)
+# else
+#  define SIGSETJMP __sigsetjmp
+# endif
+#endif
+
 ENTRY (_setjmp)
 	/* Set up arguments, we only need to set the second arg.  */
 	xorl %esi, %esi
-#ifdef PIC
-	jmp HIDDEN_JUMPTARGET (__sigsetjmp)
-#else
-	jmp __sigsetjmp
-#endif
+	jmp SIGSETJMP
 END (_setjmp)
+#ifndef _setjmp
 libc_hidden_def (_setjmp)
+#endif
diff --git a/sysdeps/x86_64/setjmp.S b/sysdeps/x86_64/setjmp.S
index e0a648e3e4..c7cbb29111 100644
--- a/sysdeps/x86_64/setjmp.S
+++ b/sysdeps/x86_64/setjmp.S
@@ -21,6 +21,11 @@
 #include <asm-syntax.h>
 #include <stap-probe.h>
 
+#if !defined __sigsetjmp && defined SHARED && !IS_IN (rtld)
+# define __sigsetjmp __redirect___sigsetjmp
+# define __redirect___sigsetjmp __redirect___sigsetjmp
+#endif
+
 ENTRY (__sigsetjmp)
 	/* Save registers.  */
 	movq %rbx, (JB_RBX*8)(%rdi)
@@ -63,4 +68,13 @@ ENTRY (__sigsetjmp)
 	jmp __sigjmp_save
 #endif
 END (__sigsetjmp)
-hidden_def (__sigsetjmp)
+#ifdef __redirect___sigsetjmp
+# undef __sigsetjmp
+
+	.globl __GI___sigsetjmp
+	.hidden __GI___sigsetjmp
+	__GI___sigsetjmp = __redirect___sigsetjmp
+
+# include <shlib-compat.h>
+versioned_symbol (libc, __redirect___sigsetjmp, __sigsetjmp, GLIBC_2_28);
+#endif
diff --git a/sysdeps/x86_64/setjmp_cancel.S b/sysdeps/x86_64/setjmp_cancel.S
new file mode 100644
index 0000000000..3727a9c7dc
--- /dev/null
+++ b/sysdeps/x86_64/setjmp_cancel.S
@@ -0,0 +1,21 @@
+/* __sigsetjmp_cancel for x86-64.
+   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/>.  */
+
+#include <sysdeps/x86/setjmp_cancel.S>
+
+libc_hidden_def (__sigsetjmp_cancel)
-- 
2.14.3
