diff --git a/sysdeps/unix/sysv/linux/x86/sys/ucontext.h b/sysdeps/unix/sysv/linux/x86/sys/ucontext.h
index afb7c181bf..7367726a50 100644
--- a/sysdeps/unix/sysv/linux/x86/sys/ucontext.h
+++ b/sysdeps/unix/sysv/linux/x86/sys/ucontext.h
@@ -147,6 +147,7 @@ typedef struct ucontext_t
     mcontext_t uc_mcontext;
     sigset_t uc_sigmask;
     struct _libc_fpstate __fpregs_mem;
+    __extension__ unsigned long long int __ssp[4];
   } ucontext_t;
 
 #else /* !__x86_64__ */
@@ -251,6 +252,7 @@ typedef struct ucontext_t
     mcontext_t uc_mcontext;
     sigset_t uc_sigmask;
     struct _libc_fpstate __fpregs_mem;
+    unsigned long int __ssp[4];
   } ucontext_t;
 
 #endif /* !__x86_64__ */
diff --git a/sysdeps/unix/sysv/linux/x86_64/__start_context.S b/sysdeps/unix/sysv/linux/x86_64/__start_context.S
index 0bfde5fc31..01e672c09b 100644
--- a/sysdeps/unix/sysv/linux/x86_64/__start_context.S
+++ b/sysdeps/unix/sysv/linux/x86_64/__start_context.S
@@ -18,6 +18,80 @@
 
 #include <sysdep.h>
 
+#if SHSTK_ENABLED
+# include <bits/prctl.h>
+# include "ucontext_i.h"
+
+/* Use CALL to push __start_context onto the new stack as well as the new
+   shadow stack.  RDI points to ucontext:
+   Incoming:
+     __ssp[0]: The original caller's shadow stack pointer.
+     __ssp[1]: The size of the new shadow stack.
+     __ssp[2]: The size of the new shadow stack.
+   Outgoing:
+     __ssp[0]: The new shadow stack pointer.
+     __ssp[1]: The base address of the new shadow stack.
+     __ssp[2]: The size of the new shadow stack.
+ */
+
+ENTRY(__push___start_context)
+	/* Save the pointer to ucontext.  */
+	movq	%rdi, %r9
+	/* Get the original shadow stack pointer.  */
+	rdsspq	%r8
+	/* Save the original stack pointer.  */
+	movq	%rsp, %rdx
+	/* Load the top of the new stack into RSI.  */
+	movq 	oRSP(%rdi), %rsi
+	/* Add 8 bytes to RSI since CALL will push the 8-byte return
+	   address onto stack.  */
+	leaq	8(%rsi), %rsp
+	/* Allocate the new shadow stack.  The size of the new shadow
+	   stack is passed in __ssp[1].  */
+	lea	(oSSP + 8)(%rdi), %RSI_LP
+	movl	$ARCH_CET_ALLOC_SHSTK, %edi
+	movl	$__NR_arch_prctl, %eax
+	/* The new shadow stack base is returned in __ssp[1].  */
+	syscall
+	testq	%rax, %rax
+	jne	L(hlt)		/* This should never happen.  */
+
+	/* Get the size of the new shadow stack.  */
+	movq	8(%rsi), %rdi
+
+	/* Get the base address of the new shadow stack.  */
+	movq	(%rsi), %rsi
+
+	/* Use the restore stoken to restore the new shadow stack.  */
+	rstorssp -8(%rsi, %rdi)
+
+	/* Save the restore token on the original shadow stack.  */
+	saveprevssp
+
+	/* Push the address of "jmp __start_context" onto the new stack
+	   as well as the new shadow stack.  */
+	call	1f
+	jmp	__start_context
+1:
+
+	/* Get the new shadow stack pointer.  */
+	rdsspq	%rdi
+
+	/* Use the restore stoken to restore the original shadow stack.  */
+	rstorssp -8(%r8)
+
+	/* Save the restore token on the new shadow stack.  */
+	saveprevssp
+
+	/* Store the new shadow stack pointer in __ssp[0].  */
+	movq	%rdi, oSSP(%r9)
+
+	/* Restore the original stack.  */
+	mov	%rdx, %rsp
+	ret
+END(__push___start_context)
+#endif
+
 /* This is the helper code which gets called if a function which is
    registered with 'makecontext' returns.  In this case we have to
    install the context listed in the uc_link element of the context
@@ -45,5 +119,6 @@ ENTRY(__start_context)
 	call	HIDDEN_JUMPTARGET(exit)
 	/* The 'exit' call should never return.  In case it does cause
 	   the process to terminate.  */
+L(hlt):
 	hlt
 END(__start_context)
diff --git a/sysdeps/unix/sysv/linux/x86_64/getcontext.S b/sysdeps/unix/sysv/linux/x86_64/getcontext.S
index 33347bc02e..cbbe4cc9fc 100644
--- a/sysdeps/unix/sysv/linux/x86_64/getcontext.S
+++ b/sysdeps/unix/sysv/linux/x86_64/getcontext.S
@@ -53,6 +53,23 @@ ENTRY(__getcontext)
 	leaq	8(%rsp), %rcx		/* Exclude the return address.  */
 	movq	%rcx, oRSP(%rdi)
 
+#if SHSTK_ENABLED
+	/* Check if shadow stack is enabled.  */
+	testl	$X86_FEATURE_1_SHSTK, %fs:FEATURE_1_OFFSET
+	jz	L(no_shstk)
+
+	/* Get the current shadow stack pointer.  */
+	rdsspq	%rax
+	/* NB: Save the caller's shadow stack so that we can jump back
+	   to the caller directly.  */
+	addq	$8, %rax
+	movq	%rax, oSSP(%rdi)
+	xorl	%edx, %edx
+	movq	%rdx, (oSSP + 8)(%rdi)
+	movq	%rdx, (oSSP + 16)(%rdi)
+
+L(no_shstk):
+#endif
 	/* We have separate floating-point register content memory on the
 	   stack.  We use the __fpregs_mem block in the context.  Set the
 	   links up correctly.  */
diff --git a/sysdeps/unix/sysv/linux/x86_64/makecontext.c b/sysdeps/unix/sysv/linux/x86_64/makecontext.c
index 0d0802bf43..97f9bbbd2d 100644
--- a/sysdeps/unix/sysv/linux/x86_64/makecontext.c
+++ b/sysdeps/unix/sysv/linux/x86_64/makecontext.c
@@ -21,6 +21,11 @@
 #include <stdarg.h>
 #include <stdint.h>
 #include <ucontext.h>
+#if SHSTK_ENABLED
+# include <pthread.h>
+# include <libc-pointer-arith.h>
+# include <sys/prctl.h>
+#endif
 
 #include "ucontext_i.h"
 
@@ -52,6 +57,8 @@ void
 __makecontext (ucontext_t *ucp, void (*func) (void), int argc, ...)
 {
   extern void __start_context (void) attribute_hidden;
+  extern void __push___start_context (ucontext_t *)
+    attribute_hidden;
   greg_t *sp;
   unsigned int idx_uc_link;
   va_list ap;
@@ -74,7 +81,54 @@ __makecontext (ucontext_t *ucp, void (*func) (void), int argc, ...)
   ucp->uc_mcontext.gregs[REG_RSP] = (uintptr_t) sp;
 
   /* Setup stack.  */
-  sp[0] = (uintptr_t) &__start_context;
+#if SHSTK_ENABLED
+  struct pthread *self = THREAD_SELF;
+  unsigned int feature_1 = THREAD_GETMEM (self, header.feature_1);
+  /* NB: We must check feature_1 before accessing __ssp since caller
+	 may be compiled against ucontext_t without __ssp.  */
+  if ((feature_1 & X86_FEATURE_1_SHSTK) != 0)
+    {
+      /* Shadow stack is enabled.  We need to allocate a new shadow
+         stack.  */
+      unsigned long ssp_size = (((uintptr_t) sp
+				 - (uintptr_t) ucp->uc_stack.ss_sp)
+				>> STACK_SIZE_TO_SHADOW_STACK_SIZE_SHIFT);
+      /* Align shadow stack to 8 bytes.  */
+      ssp_size = ALIGN_UP (ssp_size, 8);
+
+      ucp->__ssp[1] = ssp_size;
+      ucp->__ssp[2] = ssp_size;
+
+      /* Call __push___start_context to allocate a new shadow stack,
+	 push __start_context onto the new stack as well as the new
+	 shadow stack.  NB: After __push___start_context returns,
+	   ucp->__ssp[0]: The new shadow stack pointer.
+	   ucp->__ssp[1]: The base address of the new shadow stack.
+	   ucp->__ssp[2]: The size of the new shadow stack.
+       */
+      __push___start_context (ucp);
+
+      /* Update the lowest shadow stack base.  NB: Since a new shadow
+         stack may be switch by clone syscall, we need to get the
+	 current default shadow stack base via ARCH_CET_STATUS.  */
+      unsigned long long cet_status[3];
+      INTERNAL_SYSCALL_DECL (err);
+      if (INTERNAL_SYSCALL (arch_prctl, err, 2, ARCH_CET_STATUS,
+			    cet_status) == 0)
+	{
+	  unsigned long long new_ssp_base = ucp->__ssp[1];
+	  if (new_ssp_base > cet_status[1])
+	    new_ssp_base = cet_status[1];
+
+	  unsigned long long current_ssp_base
+	    = THREAD_GETMEM (self, header.ssp_base);
+	  if (!current_ssp_base || current_ssp_base > new_ssp_base)
+	    THREAD_SETMEM (self, header.ssp_base, new_ssp_base);
+	}
+    }
+  else
+#endif
+    sp[0] = (uintptr_t) &__start_context;
   sp[idx_uc_link] = (uintptr_t) ucp->uc_link;
 
   va_start (ap, argc);
diff --git a/sysdeps/unix/sysv/linux/x86_64/setcontext.S b/sysdeps/unix/sysv/linux/x86_64/setcontext.S
index b42af8e291..88c4df5e45 100644
--- a/sysdeps/unix/sysv/linux/x86_64/setcontext.S
+++ b/sysdeps/unix/sysv/linux/x86_64/setcontext.S
@@ -18,6 +18,7 @@
    <http://www.gnu.org/licenses/>.  */
 
 #include <sysdep.h>
+#include <bits/prctl.h>
 
 #include "ucontext_i.h"
 
@@ -79,6 +80,144 @@ ENTRY(__setcontext)
 	movq	oR14(%rdx), %r14
 	movq	oR15(%rdx), %r15
 
+#if SHSTK_ENABLED
+	/* Check if shadow stack is enabled.  */
+	testl	$X86_FEATURE_1_SHSTK, %fs:FEATURE_1_OFFSET
+	jz	L(no_shstk)
+
+	/* Get the base address and size of the default shadow stack.
+	   NB: We can't cache them since CLONE syscall switches the
+	   default shadow stack.  */
+	sub	$24, %RSP_LP
+	mov	%RSP_LP, %RSI_LP
+	movl	$ARCH_CET_STATUS, %edi
+	movl	$__NR_arch_prctl, %eax
+	syscall
+	testq	%rax, %rax
+	jne	L(hlt)      /* This should never happen.  */
+
+	/* Get the current shadow stack pointer.  */
+	rdsspq	%rcx
+
+	/* NB: If both the target shadow stack pointer and the current
+	   shadow stack pointer are on the original shadow stack, we
+	   can unwind the stack.  Otherwise, find the restore token
+	   pushed by rstorssp and saveprevssp to restore the target
+	   shadow stack.  */
+	movq	oSSP(%rdx), %rdi
+	movq	%rdi, %rsi
+	subq	8(%rsp), %rsi
+	jb	L(find_restore_token)
+	cmpq	16(%rsp), %rsi
+	jae	L(find_restore_token)
+
+	/* Check if both shadow stack pointers are on the original
+	   shadow stack.  */
+	movq	%rcx, %rsi
+	subq	8(%rsp), %rsi
+	jb	L(find_restore_token)
+	cmpq	16(%rsp), %rsi
+	jae	L(find_restore_token)
+
+	jmp	L(unwind_shadow_stack)
+
+L(find_restore_token):
+	/* Save the target shadow stack pointer.  */
+	movq	%rdi, %rsi
+
+	/* Check if the target shadow stack pointer came from
+	   __push___start_context.  */
+	movq	(%rsi), %rax
+	andq	$-8, %rax
+	leaq	8(%rsi), %r8
+	cmpq	%r8, %rax
+	jne	L(skip_restore_shadow_stack_special)
+
+	/* Pop return address from the shadow stack since setcontext
+	   will not return.   */
+	movq	$1, %rax
+	incsspq	%rax
+
+	/* Use the restore stoken to restore the target shadow stack.  */
+	rstorssp (%rsi)
+
+	jmp	L(unwind_shadow_stack_special)
+
+L(skip_restore_shadow_stack_special):
+	movq	%fs:SSP_BASE_OFFSET, %r8
+L(find_restore_token_loop):
+	/* Check if there is a restore token.  */
+	movq	-8(%rsi), %rax
+	andq	$-8, %rax
+	cmpq	%rsi, %rax
+	je	L(restore_shadow_stack)
+
+	/* Try the next slot.  */
+	subq	$8, %rsi
+
+	/* Don't check restore token below the lowest shadow stack
+	   base.  */
+	cmpq	%r8, %rsi
+	ja	L(find_restore_token_loop)
+
+	jmp	L(unwind_shadow_stack)
+
+L(restore_shadow_stack):
+	/* Pop return address from the shadow stack since setcontext
+	   will not return.   */
+	movq	$1, %rax
+	incsspq	%rax
+
+	/* Use the restore stoken to restore the target shadow stack.  */
+	rstorssp -8(%rsi)
+
+	/* Save the restore token on the old shadow stack.  NB: This
+	   restore token may be checked by setcontext or swapcontext
+	   later.  */
+	saveprevssp
+
+L(unwind_shadow_stack_special):
+	/* Get the current shadow stack.  */
+	rdsspq	%rcx
+
+L(unwind_shadow_stack):
+	add	$24, %RSP_LP
+	/* Unwind the shadow stack.  */
+	subq	%rdi, %rcx
+	je	L(skip_unwind_shadow_stack)
+	negq	%rcx
+	shrq	$3, %rcx
+	movl	$255, %esi
+L(loop):
+	cmpq	%rsi, %rcx
+	cmovb	%rcx, %rsi
+	incsspq	%rsi
+	subq	%rsi, %rcx
+	ja	L(loop)
+
+L(skip_unwind_shadow_stack):
+	movq	oRSI(%rdx), %rsi
+	movq	oRDI(%rdx), %rdi
+	movq	oRCX(%rdx), %rcx
+	movq	oR8(%rdx), %r8
+	movq	oR9(%rdx), %r9
+
+	/* Get the return address set with getcontext.  */
+	movq	oRIP(%rdx), %r10
+
+	/* Setup finally %rdx.  */
+	movq	oRDX(%rdx), %rdx
+
+	/* Clear rax to indicate success.  */
+	xorl	%eax, %eax
+	/* Jump to the new context directly.  */
+	jmp	*%r10
+
+L(hlt):
+	hlt
+
+L(no_shstk):
+#endif
 	/* The following ret should return to the address set with
 	getcontext.  Therefore push the address on the stack.  */
 	movq	oRIP(%rdx), %rcx
diff --git a/sysdeps/unix/sysv/linux/x86_64/swapcontext.S b/sysdeps/unix/sysv/linux/x86_64/swapcontext.S
index 1110c479fa..7a47275727 100644
--- a/sysdeps/unix/sysv/linux/x86_64/swapcontext.S
+++ b/sysdeps/unix/sysv/linux/x86_64/swapcontext.S
@@ -18,6 +18,7 @@
    <http://www.gnu.org/licenses/>.  */
 
 #include <sysdep.h>
+#include <bits/prctl.h>
 
 #include "ucontext_i.h"
 
@@ -67,6 +68,7 @@ ENTRY(__swapcontext)
 
 	/* The syscall destroys some registers, save them.  */
 	movq	%rsi, %r12
+	movq	%rdi, %r9
 
 	/* Save the current signal mask and install the new one with
 	   rt_sigprocmask (SIG_BLOCK, newset, oldset,_NSIG/8).  */
@@ -99,6 +101,154 @@ ENTRY(__swapcontext)
 	movq	oR14(%rdx), %r14
 	movq	oR15(%rdx), %r15
 
+#if SHSTK_ENABLED
+	/* Check if shadow stack is enabled.  */
+	testl	$X86_FEATURE_1_SHSTK, %fs:FEATURE_1_OFFSET
+	jz	L(no_shstk)
+
+	/* Get the base address and size of the default shadow stack.
+	   NB: We can't cache them since CLONE syscall switches the
+	   default shadow stack.  */
+	sub	$24, %RSP_LP
+	mov	%RSP_LP, %RSI_LP
+	movl	$ARCH_CET_STATUS, %edi
+	movl	$__NR_arch_prctl, %eax
+	syscall
+	testq	%rax, %rax
+	jne	L(hlt)      /* This should never happen.  */
+
+	/* Get the current shadow stack pointer.  */
+	rdsspq	%rcx
+
+	/* On the original shadow stack, save the caller's shadow
+	   stack so that we can jump back to the caller directly.  */
+	leaq	8(%rcx), %rsi
+
+	/* Save the current shadow stack pointer in __ssp[0].  */
+	movq	%rsi, oSSP(%r9)
+
+	/* NB: If both the target shadow stack pointer and the current
+	   shadow stack pointer are on the original shadow stack, we
+	   can unwind the stack.  Otherwise, find the restore token
+	   pushed by rstorssp and saveprevssp to restore the target
+	   shadow stack.  */
+	movq	oSSP(%rdx), %rdi
+	movq	%rdi, %rsi
+	subq	8(%rsp), %rsi
+	jb	L(find_restore_token)
+	cmpq	16(%rsp), %rsi
+	jae	L(find_restore_token)
+
+	/* Check if both shadow stack pointers are on the original
+	   shadow stack.  */
+	movq	%rcx, %rsi
+	subq	8(%rsp), %rsi
+	jb	L(find_restore_token)
+	cmpq	16(%rsp), %rsi
+	jae	L(find_restore_token)
+
+	jmp	L(unwind_shadow_stack)
+
+L(find_restore_token):
+	/* Save the target shadow stack pointer.  */
+	movq	%rdi, %rsi
+
+	/* Check if the target shadow stack pointer came from
+	   __push___start_context.  */
+	movq	(%rsi), %rax
+	andq	$-8, %rax
+	leaq	8(%rsi), %r8
+	cmpq	%r8, %rax
+	jne	L(skip_restore_shadow_stack_special)
+
+	/* Pop return address from the shadow stack since setcontext
+	   will not return.   */
+	movq	$1, %rax
+	incsspq	%rax
+
+	/* Use the restore stoken to restore the target shadow stack.  */
+	rstorssp (%rsi)
+
+	jmp	L(unwind_shadow_stack_special)
+
+L(skip_restore_shadow_stack_special):
+	movq	%fs:SSP_BASE_OFFSET, %r8
+L(find_restore_token_loop):
+	/* Check if there is a restore token.  */
+	movq	-8(%rsi), %rax
+	andq	$-8, %rax
+	cmpq	%rsi, %rax
+	je	L(restore_shadow_stack)
+
+	/* Try the next slot.  */
+	subq	$8, %rsi
+
+	/* Don't check restore token below the lowest shadow stack
+	   base.  */
+	cmpq	%r8, %rsi
+	ja	L(find_restore_token_loop)
+
+	jmp	L(unwind_shadow_stack)
+
+L(restore_shadow_stack):
+	/* Pop return address from the shadow stack since setcontext
+	   will not return.   */
+	movq	$1, %rax
+	incsspq	%rax
+
+	/* Restore the target shadow stack.  */
+	rstorssp -8(%rsi)
+
+L(unwind_shadow_stack_special):
+	/* Save restore token on the old shadow stack.  */
+	saveprevssp
+
+	/* Get the current shadow stack.  */
+	rdsspq	%rcx
+
+L(unwind_shadow_stack):
+	add	$24, %RSP_LP
+	/* Unwind the shadow stack.  */
+	subq	%rdi, %rcx
+	je	L(skip_unwind_shadow_stack)
+	negq	%rcx
+	shrq	$3, %rcx
+	movl	$255, %esi
+L(loop):
+	cmpq	%rsi, %rcx
+	cmovb	%rcx, %rsi
+	incsspq	%rsi
+	subq	%rsi, %rcx
+	ja	L(loop)
+
+L(skip_unwind_shadow_stack):
+	xorl	%eax, %eax
+	movq	%rax, (oSSP + 8)(%r9)
+	movq	%rax, (oSSP + 16)(%r9)
+
+	/* Setup registers used for passing args.  */
+	movq	oRDI(%rdx), %rdi
+	movq	oRSI(%rdx), %rsi
+	movq	oRCX(%rdx), %rcx
+	movq	oR8(%rdx), %r8
+	movq	oR9(%rdx), %r9
+
+	/* Get the return address set with getcontext.  */
+	movq	oRIP(%rdx), %r10
+
+	/* Setup finally %rdx.  */
+	movq	oRDX(%rdx), %rdx
+
+	/* Clear rax to indicate success.  */
+	xorl	%eax, %eax
+	/* Jump to the new context directly.  */
+	jmp	*%r10
+
+L(hlt):
+	hlt
+
+L(no_shstk):
+#endif
 	/* The following ret should return to the address set with
 	getcontext.  Therefore push the address on the stack.  */
 	movq	oRIP(%rdx), %rcx
diff --git a/sysdeps/unix/sysv/linux/x86_64/sysdep.h b/sysdeps/unix/sysv/linux/x86_64/sysdep.h
index 1ef0f742ae..f07eb04962 100644
--- a/sysdeps/unix/sysv/linux/x86_64/sysdep.h
+++ b/sysdeps/unix/sysv/linux/x86_64/sysdep.h
@@ -423,4 +423,9 @@
 #undef LO_HI_LONG
 #define LO_HI_LONG(val) (val), 0
 
+/* Each shadow stack slot takes 8 bytes.  Assuming that each stack
+   frame takes 256 bytes, this is used to compute shadow stack size
+   from stack size.  */
+#define STACK_SIZE_TO_SHADOW_STACK_SIZE_SHIFT 5
+
 #endif /* linux/x86_64/sysdep.h */
diff --git a/sysdeps/unix/sysv/linux/x86_64/ucontext_i.sym b/sysdeps/unix/sysv/linux/x86_64/ucontext_i.sym
index af3e0e544b..c08b3b8b47 100644
--- a/sysdeps/unix/sysv/linux/x86_64/ucontext_i.sym
+++ b/sysdeps/unix/sysv/linux/x86_64/ucontext_i.sym
@@ -35,3 +35,4 @@ oFPREGS		mcontext (fpregs)
 oSIGMASK	ucontext (uc_sigmask)
 oFPREGSMEM	ucontext (__fpregs_mem)
 oMXCSR		ucontext (__fpregs_mem.mxcsr)
+oSSP		ucontext (__ssp)
