|
|
Message-ID: <5930553c4721863d05921789c4a1681d@bu.edu>
Date: Sun, 6 Sep 2026 19:15:29 +0000
From: Khosro Moeini <khosro@...edu>
To: musl@...ts.openwall.com
Cc: khosro@...edu
Subject: [PATCH v2] x86_64: add CET shadow stack support
Enable CET shadow stack on x86_64 when the executable and all loaded
shared objects have the GNU_PROPERTY_X86_FEATURE_1_SHSTK bit set in
their .note.gnu.property note. If shadow stack is enabled for a process
dlopen of an object without the shadow stack property note fails.
Unlike glibc, this implementation does not check environment variables.
All the changes are guarded by SHSTK_ENABLED which is set through
the --enable-cet configuration option.
Signed-off-by: Khosro Moeini <khosro@...edu>
---
Thanks for the feedback. Regarding the concerns discussed in the older
thread:
sigaltstack: The main program and its signal handlers use the same
shadow stack, so there won't be resource problems. Please see:
https://docs.kernel.org/next/x86/shstk.html#signal
ucontext: removed from POSIX and not supported in musl
threads: musl uses clone for thread creation so shadow stack allocation
is handled by the kernel. pthread_cancel is fine as it only changes the
program counter.
setjmp and longjmp: setjmp and sigsetjmp are modified to store the
shadow stack pointer in __ss[2] and longjmp restores it.
vfork: vfork is modified to directly jmp back to caller when in child,
instead of going through __syscall_ret to not pop from the shadow stack,
which is shared with parent.
Changes since the last patch:
I separated the arch-dependent and independent code. shstk_arch.h is
the arch-dependent header and has the shadow stack related syscalls
and defines the arch-specific macros.
This patch is entirely hand-written.
Please CC on reply. Thanks.
Makefile | 11 +-
arch/generic/shstk_arch.h | 35 ++++++
arch/x86_64/note.s | 12 ++
arch/x86_64/shstk_arch.h | 40 ++++++
configure | 29 +++++
ldso/dynlink.c | 25 ++++
src/env/__libc_start_main.c | 12 ++
src/internal/shstk.h | 30 +++++
src/ldso/shstk.c | 117 ++++++++++++++++++
src/process/x86_64/{vfork.s => vfork.S} | 13 ++
src/setjmp/x86_64/{longjmp.s => longjmp.S} | 24 ++++
src/setjmp/x86_64/{setjmp.s => setjmp.S} | 6 +
.../x86_64/{sigsetjmp.s => sigsetjmp.S} | 17 +++
13 files changed, 367 insertions(+), 4 deletions(-)
create mode 100644 arch/generic/shstk_arch.h
create mode 100644 arch/x86_64/note.s
create mode 100644 arch/x86_64/shstk_arch.h
create mode 100644 src/internal/shstk.h
create mode 100644 src/ldso/shstk.c
rename src/process/x86_64/{vfork.s => vfork.S} (35%)
rename src/setjmp/x86_64/{longjmp.s => longjmp.S} (52%)
rename src/setjmp/x86_64/{setjmp.s => setjmp.S} (82%)
rename src/signal/x86_64/{sigsetjmp.s => sigsetjmp.S} (56%)
diff --git a/Makefile b/Makefile
index 3ad88b3..0aa23b3 100644
--- a/Makefile
+++ b/Makefile
@@ -45,6 +45,7 @@ CPPFLAGS =
CFLAGS =
CFLAGS_AUTO = -Os -pipe
CFLAGS_C99FSE = -std=c99 -ffreestanding -nostdinc
+ASM_NOTE =
CFLAGS_ALL = $(CFLAGS_C99FSE)
CFLAGS_ALL += -D_XOPEN_SOURCE=700 -I$(srcdir)/arch/$(ARCH) -I$(srcdir)/arch/generic -Iobj/src/internal -I$(srcdir)/src/include -I$(srcdir)/src/internal -Iobj/include -I$(srcdir)/include
@@ -135,16 +136,18 @@ CC_CMD = $(CC) $(CFLAGS_ALL) -c -o $@ $<
# Choose invocation of assembler to be used
ifeq ($(ADD_CFI),yes)
- AS_CMD = LC_ALL=C awk -f $(srcdir)/tools/add-cfi.common.awk -f $(srcdir)/tools/add-cfi.$(ARCH).awk $< | $(CC) $(CFLAGS_ALL) -x assembler -c -o $@ -
+ AS_CMD = LC_ALL=C awk -f $(srcdir)/tools/add-cfi.common.awk -f $(srcdir)/tools/add-cfi.$(ARCH).awk $< $(ASM_NOTE) | $(CC) $(CFLAGS_ALL) -x assembler -c -o $@ -
else
- AS_CMD = $(CC_CMD)
+ AS_CMD = cat $< $(ASM_NOTE) | $(CC) $(CFLAGS_ALL) -x assembler -c -o $@ -
endif
+ASCPP_CMD = cat $< $(ASM_NOTE) | $(CC) $(CFLAGS_ALL) -iquote $(dir $<) -x assembler-with-cpp -c -o $@ -
+
obj/%.o: $(srcdir)/%.s
$(AS_CMD)
obj/%.o: $(srcdir)/%.S
- $(CC_CMD)
+ $(ASCPP_CMD)
obj/%.o: $(srcdir)/%.c $(GENH) $(IMPH)
$(CC_CMD)
@@ -153,7 +156,7 @@ obj/%.lo: $(srcdir)/%.s
$(AS_CMD)
obj/%.lo: $(srcdir)/%.S
- $(CC_CMD)
+ $(ASCPP_CMD)
obj/%.lo: $(srcdir)/%.c $(GENH) $(IMPH)
$(CC_CMD)
diff --git a/arch/generic/shstk_arch.h b/arch/generic/shstk_arch.h
new file mode 100644
index 0000000..3c28dd3
--- /dev/null
+++ b/arch/generic/shstk_arch.h
@@ -0,0 +1,35 @@
+#ifndef SHSTK_ARCH_H
+#define SHSTK_ARCH_H
+
+#if SHSTK_ENABLED
+
+#include <errno.h>
+#include <features.h>
+
+#define GNU_PROPERTY_FEATURE_1_AND 0xc0000002
+
+#define GNU_PROPERTY_FEATURE_1_SHSTK (1U << 1)
+
+#define ARCH_SHSTK_ENABLE 0x5001
+#define ARCH_SHSTK_LOCK 0x5003
+#define ARCH_SHSTK_STATUS 0x5005
+
+#define ARCH_SHSTK_SHSTK 1
+
+extern hidden unsigned long __shstk_status;
+
+static inline int __init_shstk_status(void)
+{
+ return -ENOTSUP;
+}
+
+static inline int __lock_shstk(void)
+{
+ return -ENOTSUP;
+}
+
+#define SHSTK_ENABLE() do { } while (0)
+
+#endif
+
+#endif
diff --git a/arch/x86_64/note.s b/arch/x86_64/note.s
new file mode 100644
index 0000000..cb03e5a
--- /dev/null
+++ b/arch/x86_64/note.s
@@ -0,0 +1,12 @@
+/* .note.gnu.property is 8-byte aligned in 64-bit objects */
+.section .note.gnu.property,"a"
+.balign 8
+.long 4 /* n_namesz: sizeof "GNU" */
+.long 16 /* n_descsz: one 8-byte-padded property */
+.long 5 /* n_type: NT_GNU_PROPERTY_TYPE_0 */
+.asciz "GNU"
+.long 0xc0000002 /* pr_type: GNU_PROPERTY_X86_FEATURE_1_AND */
+.long 4 /* pr_datasz */
+.long 2 /* GNU_PROPERTY_X86_FEATURE_1_SHSTK */
+.long 0 /* padding to 8-byte alignment */
+.previous
diff --git a/arch/x86_64/shstk_arch.h b/arch/x86_64/shstk_arch.h
new file mode 100644
index 0000000..c9c3561
--- /dev/null
+++ b/arch/x86_64/shstk_arch.h
@@ -0,0 +1,40 @@
+#ifndef SHSTK_ARCH_H
+#define SHSTK_ARCH_H
+
+#if SHSTK_ENABLED
+
+#include "syscall.h"
+
+#define GNU_PROPERTY_FEATURE_1_AND 0xc0000002
+
+#define GNU_PROPERTY_FEATURE_1_SHSTK (1U << 1)
+
+#define ARCH_SHSTK_ENABLE 0x5001
+#define ARCH_SHSTK_LOCK 0x5003
+#define ARCH_SHSTK_STATUS 0x5005
+
+#define ARCH_SHSTK_SHSTK 1
+
+extern hidden unsigned long __shstk_status;
+
+static inline int __init_shstk_status(void)
+{
+ return syscall(SYS_arch_prctl, ARCH_SHSTK_STATUS, &__shstk_status);
+}
+
+static inline int __lock_shstk(void)
+{
+ return syscall(SYS_arch_prctl, ARCH_SHSTK_LOCK, -1UL);
+}
+
+#define SHSTK_ENABLE() do { \
+ unsigned long ret; \
+ __asm__ __volatile__ ( "syscall" \
+ : "=a"(ret) \
+ : "a"(SYS_arch_prctl), "D"(ARCH_SHSTK_ENABLE), "S"(ARCH_SHSTK_SHSTK) \
+ : "rcx", "r11", "memory" ); \
+ } while (0)
+
+#endif
+
+#endif
diff --git a/configure b/configure
index bc9fbe4..a278c81 100755
--- a/configure
+++ b/configure
@@ -34,6 +34,7 @@ Optional features:
--enable-wrapper=... build given musl toolchain wrapper [auto]
--disable-shared inhibit building shared library [enabled]
--disable-static inhibit building static library [enabled]
+ --enable-cet build with CET shadow stack support [disabled]
Optional packages:
--with-malloc=... choose malloc implementation [mallocng]
@@ -142,6 +143,7 @@ static=yes
wrapper=auto
gcc_wrapper=no
clang_wrapper=no
+cet=no
malloc_dir=mallocng
for arg ; do
@@ -172,6 +174,8 @@ case "$arg" in
--disable-wrapper|--enable-wrapper=no) wrapper=no ;;
--enable-gcc-wrapper|--enable-gcc-wrapper=yes) wrapper=yes ; gcc_wrapper=yes ;;
--disable-gcc-wrapper|--enable-gcc-wrapper=no) wrapper=no ;;
+--enable-cet|--enable-cet=yes) cet=yes ;;
+--disable-cet|--enable-cet=no) cet=no ;;
--with-malloc=*) malloc_dir=${arg#*=} ;;
--enable-*|--disable-*|--with-*|--without-*|--*dir=*) ;;
--host=*|--target=*) target=${arg#*=} ;;
@@ -759,6 +763,30 @@ fi
test "$SUBARCH" \
&& printf "configured for %s variant: %s\n" "$ARCH" "$ARCH$SUBARCH"
+ASM_NOTE=
+if test "$cet" = yes ; then
+
+if test "$ARCH" != "x86_64" ; then
+fail "$0: error: --enable-cet is only supported on x86_64"
+fi
+
+tryflag CFLAGS_AUTO -fcf-protection=return \
+|| fail "$0: error: --enable-cet requires compiler support for -fcf-protection"
+
+printf "checking whether assembler supports rdssp/incssp instructions... "
+echo "__asm__(\"xor %eax,%eax ; rdsspq %rax ; incsspq %rax\");" > "$tmpc"
+if $CC -c -o /dev/null "$tmpc" >/dev/null 2>&1 ; then
+printf "yes\n"
+else
+printf "no\n"
+fail "$0: error: --enable-cet requires assembler support for rdssp/incssp"
+fi
+
+CFLAGS_AUTO="$CFLAGS_AUTO -DSHSTK_ENABLED=1"
+
+ASM_NOTE="arch/$ARCH/note.s"
+fi
+
#
# Some archs (powerpc) have different possible long double formats
# that the compiler can be configured for. The logic for whether this
@@ -820,6 +848,7 @@ CFLAGS_AUTO = $CFLAGS_AUTO
CFLAGS_C99FSE = $CFLAGS_C99FSE
CFLAGS_MEMOPS = $CFLAGS_MEMOPS
CFLAGS_NOSSP = $CFLAGS_NOSSP
+ASM_NOTE = $ASM_NOTE
CPPFLAGS = $CPPFLAGS
LDFLAGS = $LDFLAGS
LDFLAGS_AUTO = $LDFLAGS_AUTO
diff --git a/ldso/dynlink.c b/ldso/dynlink.c
index 10471b2..61c989a 100644
--- a/ldso/dynlink.c
+++ b/ldso/dynlink.c
@@ -23,6 +23,7 @@
#include "fork_impl.h"
#include "libc.h"
#include "dynlink.h"
+#include "shstk.h"
static size_t ldso_page_size;
/* libc.h may have defined a macro for dynamic PAGE_SIZE already, but
@@ -702,6 +703,9 @@ static void *map_library(int fd, struct dso *dso)
size_t dyn=0;
size_t tls_image=0;
size_t i;
+#if SHSTK_ENABLED
+ Phdr *gnu_prop_ph = NULL;
+#endif
ssize_t l = read(fd, buf, sizeof buf);
eh = buf;
@@ -741,6 +745,10 @@ static void *map_library(int fd, struct dso *dso)
ph->p_memsz < DEFAULT_STACK_MAX ?
ph->p_memsz : DEFAULT_STACK_MAX;
}
+#if SHSTK_ENABLED
+ } else if (ph->p_type == PT_GNU_PROPERTY) {
+ gnu_prop_ph = ph;
+#endif
}
if (ph->p_type != PT_LOAD) continue;
nsegs++;
@@ -862,6 +870,13 @@ done_mapping:
dso->base = base;
dso->dynv = laddr(dso, dyn);
if (dso->tls.size) dso->tls.image = laddr(dso, tls_image);
+#if SHSTK_ENABLED
+ int ret = __try_update_feature_1_and((size_t)base, gnu_prop_ph);
+ if (ret) {
+ errno = ret;
+ goto error;
+ }
+#endif
free(allocated_buf);
return map;
noexec:
@@ -1455,6 +1470,10 @@ static void kernel_mapped_dso(struct dso *p)
ph->p_memsz < DEFAULT_STACK_MAX ?
ph->p_memsz : DEFAULT_STACK_MAX;
}
+#if SHSTK_ENABLED
+ } else if (ph->p_type == PT_GNU_PROPERTY) {
+ __update_feature_1_and((size_t)p->base, ph);
+#endif
}
if (ph->p_type != PT_LOAD) continue;
if (ph->p_vaddr < min_addr)
@@ -1637,6 +1656,12 @@ void __init_tls(size_t *auxv)
{
}
+#if SHSTK_ENABLED
+void __init_feature_1_and(void)
+{
+}
+#endif
+
static void update_tls_size()
{
libc.tls_cnt = tls_cnt;
diff --git a/src/env/__libc_start_main.c b/src/env/__libc_start_main.c
index c5b277b..7a1e960 100644
--- a/src/env/__libc_start_main.c
+++ b/src/env/__libc_start_main.c
@@ -6,6 +6,8 @@
#include "syscall.h"
#include "atomic.h"
#include "libc.h"
+#include "shstk.h"
+#include "shstk_arch.h"
static void dummy(void) {}
weak_alias(dummy, _init);
@@ -89,6 +91,16 @@ int __libc_start_main(int (*main)(int,char **,char **), int argc, char **argv,
static int libc_start_main_stage2(int (*main)(int,char **,char **), int argc, char **argv)
{
char **envp = argv+argc+1;
+
+#if SHSTK_ENABLED
+ __init_feature_1_and();
+ if (__feature_1_and & GNU_PROPERTY_FEATURE_1_SHSTK) {
+ SHSTK_ENABLE();
+ __lock_shstk();
+ }
+ __init_shstk_status();
+#endif
+
__libc_start_init();
/* Pass control to the application */
diff --git a/src/internal/shstk.h b/src/internal/shstk.h
new file mode 100644
index 0000000..8d97c4a
--- /dev/null
+++ b/src/internal/shstk.h
@@ -0,0 +1,30 @@
+#ifndef SHSTK_H
+#define SHSTK_H
+
+#if SHSTK_ENABLED
+
+#include <elf.h>
+#include <stddef.h>
+#include <features.h>
+
+#if ULONG_MAX == 0xffffffff
+typedef Elf32_Addr Addr;
+typedef Elf32_Phdr Phdr;
+typedef Elf32_Nhdr Nhdr;
+#else
+typedef Elf64_Addr Addr;
+typedef Elf64_Phdr Phdr;
+typedef Elf64_Nhdr Nhdr;
+#endif
+
+extern hidden unsigned __feature_1_and;
+
+hidden void __init_feature_1_and(void);
+
+hidden void __update_feature_1_and(size_t base, Phdr *ph);
+
+hidden int __try_update_feature_1_and(size_t base, Phdr *ph);
+
+#endif
+
+#endif
diff --git a/src/ldso/shstk.c b/src/ldso/shstk.c
new file mode 100644
index 0000000..ddcd5aa
--- /dev/null
+++ b/src/ldso/shstk.c
@@ -0,0 +1,117 @@
+#if SHSTK_ENABLED
+
+#include <errno.h>
+#include <string.h>
+#include <stddef.h>
+#include "libc.h"
+#include "shstk.h"
+#include "shstk_arch.h"
+
+hidden unsigned __feature_1_and = -1;
+hidden unsigned long __shstk_status = 0;
+
+#define ALIGNMENT sizeof(Addr)
+#define ALIGN_UP(x,y) ((x)+(y)-1 & -(y))
+#define DESC_HDR_SIZE 8
+
+/* gnu properties are a sequence of type/size/value */
+static unsigned get_feature_from_note(size_t p, size_t len)
+{
+ size_t end = p + len;
+ while (p + DESC_HDR_SIZE <= end) {
+ uint32_t type, datasz;
+ type = *(uint32_t *)p;
+ p += sizeof(uint32_t);
+ datasz = *(uint32_t *)p;
+ p += sizeof(uint32_t);
+ if (p + datasz > end) return 0;
+ if (type == GNU_PROPERTY_FEATURE_1_AND) {
+ uint32_t feature;
+ if (datasz != 4) return 0;
+ feature = *(uint32_t *)p;
+ return feature;
+ }
+ /* kernel v6.18 /fs/bifmt_efl.c:758 says: */
+ /* Properties are supposed to be unique and sorted on pr_type: */
+ if (type > GNU_PROPERTY_FEATURE_1_AND) return 0;
+ p += ALIGN_UP(datasz, ALIGNMENT);
+ }
+ return 0;
+}
+
+static unsigned get_feature_from_header(size_t base, Phdr *ph)
+{
+ if (!ph || ph->p_align != ALIGNMENT) return 0;
+ size_t end = base + ph->p_vaddr + ph->p_memsz;
+ size_t p = base + ph->p_vaddr;
+ while (p + sizeof(Nhdr) <= end) {
+ Nhdr *nh = (Nhdr *)p;
+ size_t desc_offset = ALIGN_UP(sizeof(Nhdr) + nh->n_namesz, ALIGNMENT);
+ if (nh->n_namesz == 4
+ && nh->n_type == NT_GNU_PROPERTY_TYPE_0
+ && p + desc_offset + nh->n_descsz <= end
+ && !memcmp((void *)(p + sizeof(Nhdr)), "GNU", 4)) {
+ return get_feature_from_note(p + desc_offset, nh->n_descsz);
+ }
+ p += desc_offset;
+ p += ALIGN_UP(nh->n_descsz, ALIGNMENT);
+ }
+ return 0;
+}
+
+/* four cases here:
+ * (1) feature set, shstk set -> dlopen, should fail if no shstk note
+ * (2) feature set, shstk not set -> initial loading, should update feature
+ * (3) feature not set, shstk not set -> no update needed
+ * (4) feature not set, shstk set -> impossible */
+hidden int __try_update_feature_1_and(size_t base, Phdr *ph)
+{
+ if (!(__feature_1_and & GNU_PROPERTY_FEATURE_1_SHSTK))
+ return 0;
+ /* feature is set */
+ unsigned long dso_features = get_feature_from_header(base, ph);
+ if (!(__shstk_status & ARCH_SHSTK_SHSTK)) {
+ __feature_1_and &= dso_features;
+ return 0;
+ }
+ /* feature and shstk are set */
+ if (dso_features & GNU_PROPERTY_FEATURE_1_SHSTK)
+ return 0;
+ return ENOTSUP;
+}
+
+hidden void __update_feature_1_and(size_t base, Phdr *ph)
+{
+ __feature_1_and &= get_feature_from_header(base, ph);
+}
+
+#define AUX_CNT 38
+extern weak hidden const size_t _DYNAMIC[];
+
+static void static_init_feature_1_and(void)
+{
+ unsigned char *p;
+ Phdr *phdr, *gnu_prop_ph = NULL;
+ size_t base = 0;
+ size_t n;
+ size_t i, aux[AUX_CNT] = { 0 };
+
+ for (i=0; libc.auxv[i]; i+=2)
+ if (libc.auxv[i]<AUX_CNT) aux[libc.auxv[i]] = libc.auxv[i+1];
+
+ for (p=(void *)aux[AT_PHDR],n=aux[AT_PHNUM]; n; n--,p+=aux[AT_PHENT]) {
+ phdr = (void *)p;
+ if (phdr->p_type == PT_PHDR)
+ base = aux[AT_PHDR] - phdr->p_vaddr;
+ if (phdr->p_type == PT_DYNAMIC && _DYNAMIC)
+ base = (size_t)_DYNAMIC - phdr->p_vaddr;
+ if (phdr->p_type == PT_GNU_PROPERTY)
+ gnu_prop_ph = phdr;
+ }
+
+ __feature_1_and = get_feature_from_header(base, gnu_prop_ph);
+}
+
+weak_alias(static_init_feature_1_and, __init_feature_1_and);
+
+#endif
diff --git a/src/process/x86_64/vfork.s b/src/process/x86_64/vfork.S
similarity index 35%
rename from src/process/x86_64/vfork.s
rename to src/process/x86_64/vfork.S
index 9114439..da4aea5 100644
--- a/src/process/x86_64/vfork.s
+++ b/src/process/x86_64/vfork.S
@@ -4,6 +4,19 @@ vfork:
pop %rdx
mov $58,%eax
syscall
+#if SHSTK_ENABLED
+ /* If parent normal return */
+ test %eax,%eax
+ jnz 1f
+ /* If child and no shstk normal return */
+ xor %ecx,%ecx
+ rdsspq %rcx
+ test %rcx,%rcx
+ jz 1f
+ /* If child and shstk jmp instead, no need to call __syscall_ret */
+ jmp *%rdx
+1:
+#endif
push %rdx
mov %rax,%rdi
.hidden __syscall_ret
diff --git a/src/setjmp/x86_64/longjmp.s b/src/setjmp/x86_64/longjmp.S
similarity index 52%
rename from src/setjmp/x86_64/longjmp.s
rename to src/setjmp/x86_64/longjmp.S
index 1b2661c..9169996 100644
--- a/src/setjmp/x86_64/longjmp.s
+++ b/src/setjmp/x86_64/longjmp.S
@@ -5,6 +5,30 @@
.type longjmp,@function
_longjmp:
longjmp:
+#if SHSTK_ENABLED
+ xor %ecx,%ecx
+ rdsspq %rcx
+ test %rcx,%rcx
+ jz 2f
+ /* if shstk is active */
+ mov 88(%rdi),%rdx /* shadow stack pointer saved by setjmp */
+ sub %rcx,%rdx
+ /* target below current */
+ jb 2f
+ /* slots between current and target */
+ /* 3^2 = 8 = q in incsspq */
+ shr $3,%rdx
+ /* plus the slot setjmp itself returned to */
+ add $1,%rdx
+ /* incssp pops at most 255 slots at a time */
+1: mov $255,%rcx
+ cmp %rcx,%rdx
+ cmovb %rdx,%rcx
+ incsspq %rcx
+ sub %rcx,%rdx
+ ja 1b
+2:
+#endif
xor %eax,%eax
cmp $1,%esi /* CF = val ? 0 : 1 */
adc %esi,%eax /* eax = val + !val */
diff --git a/src/setjmp/x86_64/setjmp.s b/src/setjmp/x86_64/setjmp.S
similarity index 82%
rename from src/setjmp/x86_64/setjmp.s
rename to src/setjmp/x86_64/setjmp.S
index d95e485..47ce57a 100644
--- a/src/setjmp/x86_64/setjmp.s
+++ b/src/setjmp/x86_64/setjmp.S
@@ -18,5 +18,11 @@ setjmp:
mov %rdx,48(%rdi)
mov (%rsp),%rdx /* save return addr ptr for new rip */
mov %rdx,56(%rdi)
+#if SHSTK_ENABLED
+ /* store shstk pointer in __ss[2] = (72 + 2*8) = 88 */
+ xor %eax,%eax
+ rdsspq %rax
+ mov %rax,88(%rdi)
+#endif
xor %eax,%eax /* always return 0 */
ret
diff --git a/src/signal/x86_64/sigsetjmp.s b/src/signal/x86_64/sigsetjmp.S
similarity index 56%
rename from src/signal/x86_64/sigsetjmp.s
rename to src/signal/x86_64/sigsetjmp.S
index 9a7695f..e88d277 100644
--- a/src/signal/x86_64/sigsetjmp.s
+++ b/src/signal/x86_64/sigsetjmp.S
@@ -18,7 +18,24 @@ __sigsetjmp:
mov %eax,%esi
mov 72+8(%rbx),%rbx
+#if SHSTK_ENABLED
+ test %eax,%eax
+ jnz 2f
+
+ /* original call */
+ xor %edx,%edx
+ rdsspq %rdx
+ /* store shstk pointer in __ss[2] */
+ /* rdi holds the jmp_buf now */
+ mov %rdx,88(%rdi)
+#endif
.hidden __sigsetjmp_tail
jmp __sigsetjmp_tail
+#if SHSTK_ENABLED
+2: call __sigsetjmp_tail
+ pop %rdx
+ jmp *%rdx
+#endif
+
1: jmp setjmp@PLT
--
2.49.1
Powered by blists - more mailing lists
Confused about mailing lists and their use? Read about mailing lists on Wikipedia and check out these guidelines on proper formatting of your messages.