# AC_FUNC_MALLOC causes problems when cross-compiling.
#AC_FUNC_MALLOC
+# Check dor dlopen() in -ldl or -lc
+AC_CHECK_LIB([dl], [dlopen], [
+ libdl_name=dl
+ DL_LIBS="-ldl"
+], [
+ # dlopen not found in libdl, check in libc
+ AC_CHECK_LIB([c], [dlopen], [
+ libdl_name=c
+ DL_LIBS="-lc"
+ ], [
+ AC_MSG_ERROR([Cannot find dlopen in libdl nor libc. Use [LDFLAGS]=-Ldir to specify their location.])
+ ])
+])
+AC_SUBST(DL_LIBS)
## ##
## Substitute variables for use in Makefile.am ##
"5:\n\t"
: /* gcc asm goto does not allow outputs */
: [cpu_id] "r" (cpu),
- [current_cpu_id] "m" (__rseq_abi.cpu_id),
- [rseq_cs] "m" (__rseq_abi.rseq_cs),
+ [current_cpu_id] "m" (rseq_get_abi()->cpu_id),
+ [rseq_cs] "m" (rseq_get_abi()->rseq_cs),
[v] "m" (*v),
[expect] "r" (expect),
[newv] "r" (newv)
"5:\n\t"
: /* gcc asm goto does not allow outputs */
: [cpu_id] "r" (cpu),
- [current_cpu_id] "m" (__rseq_abi.cpu_id),
- [rseq_cs] "m" (__rseq_abi.rseq_cs),
+ [current_cpu_id] "m" (rseq_get_abi()->cpu_id),
+ [rseq_cs] "m" (rseq_get_abi()->rseq_cs),
/* final store input */
[v] "m" (*v),
[expectnot] "r" (expectnot),
"5:\n\t"
: /* gcc asm goto does not allow outputs */
: [cpu_id] "r" (cpu),
- [current_cpu_id] "m" (__rseq_abi.cpu_id),
- [rseq_cs] "m" (__rseq_abi.rseq_cs),
+ [current_cpu_id] "m" (rseq_get_abi()->cpu_id),
+ [rseq_cs] "m" (rseq_get_abi()->rseq_cs),
[v] "m" (*v),
[count] "Ir" (count)
RSEQ_INJECT_INPUT
"5:\n\t"
: /* gcc asm goto does not allow outputs */
: [cpu_id] "r" (cpu),
- [current_cpu_id] "m" (__rseq_abi.cpu_id),
- [rseq_cs] "m" (__rseq_abi.rseq_cs),
+ [current_cpu_id] "m" (rseq_get_abi()->cpu_id),
+ [rseq_cs] "m" (rseq_get_abi()->rseq_cs),
/* try store input */
[v2] "m" (*v2),
[newv2] "r" (newv2),
"5:\n\t"
: /* gcc asm goto does not allow outputs */
: [cpu_id] "r" (cpu),
- [current_cpu_id] "m" (__rseq_abi.cpu_id),
- [rseq_cs] "m" (__rseq_abi.rseq_cs),
+ [current_cpu_id] "m" (rseq_get_abi()->cpu_id),
+ [rseq_cs] "m" (rseq_get_abi()->rseq_cs),
/* try store input */
[v2] "m" (*v2),
[newv2] "r" (newv2),
"5:\n\t"
: /* gcc asm goto does not allow outputs */
: [cpu_id] "r" (cpu),
- [current_cpu_id] "m" (__rseq_abi.cpu_id),
- [rseq_cs] "m" (__rseq_abi.rseq_cs),
+ [current_cpu_id] "m" (rseq_get_abi()->cpu_id),
+ [rseq_cs] "m" (rseq_get_abi()->rseq_cs),
/* cmp2 input */
[v2] "m" (*v2),
[expect2] "r" (expect2),
"8:\n\t"
: /* gcc asm goto does not allow outputs */
: [cpu_id] "r" (cpu),
- [current_cpu_id] "m" (__rseq_abi.cpu_id),
- [rseq_cs] "m" (__rseq_abi.rseq_cs),
+ [current_cpu_id] "m" (rseq_get_abi()->cpu_id),
+ [rseq_cs] "m" (rseq_get_abi()->rseq_cs),
/* final store input */
[v] "m" (*v),
[expect] "r" (expect),
"8:\n\t"
: /* gcc asm goto does not allow outputs */
: [cpu_id] "r" (cpu),
- [current_cpu_id] "m" (__rseq_abi.cpu_id),
- [rseq_cs] "m" (__rseq_abi.rseq_cs),
+ [current_cpu_id] "m" (rseq_get_abi()->cpu_id),
+ [rseq_cs] "m" (rseq_get_abi()->rseq_cs),
/* final store input */
[v] "m" (*v),
[expect] "r" (expect),
RSEQ_ASM_DEFINE_ABORT(4, abort)
: /* gcc asm goto does not allow outputs */
: [cpu_id] "r" (cpu),
- [current_cpu_id] "Qo" (__rseq_abi.cpu_id),
- [rseq_cs] "m" (__rseq_abi.rseq_cs),
+ [current_cpu_id] "Qo" (rseq_get_abi()->cpu_id),
+ [rseq_cs] "m" (rseq_get_abi()->rseq_cs),
[v] "Qo" (*v),
[expect] "r" (expect),
[newv] "r" (newv)
RSEQ_ASM_DEFINE_ABORT(4, abort)
: /* gcc asm goto does not allow outputs */
: [cpu_id] "r" (cpu),
- [current_cpu_id] "Qo" (__rseq_abi.cpu_id),
- [rseq_cs] "m" (__rseq_abi.rseq_cs),
+ [current_cpu_id] "Qo" (rseq_get_abi()->cpu_id),
+ [rseq_cs] "m" (rseq_get_abi()->rseq_cs),
[v] "Qo" (*v),
[expectnot] "r" (expectnot),
[load] "Qo" (*load),
RSEQ_ASM_DEFINE_ABORT(4, abort)
: /* gcc asm goto does not allow outputs */
: [cpu_id] "r" (cpu),
- [current_cpu_id] "Qo" (__rseq_abi.cpu_id),
- [rseq_cs] "m" (__rseq_abi.rseq_cs),
+ [current_cpu_id] "Qo" (rseq_get_abi()->cpu_id),
+ [rseq_cs] "m" (rseq_get_abi()->rseq_cs),
[v] "Qo" (*v),
[count] "r" (count)
RSEQ_INJECT_INPUT
RSEQ_ASM_DEFINE_ABORT(4, abort)
: /* gcc asm goto does not allow outputs */
: [cpu_id] "r" (cpu),
- [current_cpu_id] "Qo" (__rseq_abi.cpu_id),
- [rseq_cs] "m" (__rseq_abi.rseq_cs),
+ [current_cpu_id] "Qo" (rseq_get_abi()->cpu_id),
+ [rseq_cs] "m" (rseq_get_abi()->rseq_cs),
[expect] "r" (expect),
[v] "Qo" (*v),
[newv] "r" (newv),
RSEQ_ASM_DEFINE_ABORT(4, abort)
: /* gcc asm goto does not allow outputs */
: [cpu_id] "r" (cpu),
- [current_cpu_id] "Qo" (__rseq_abi.cpu_id),
- [rseq_cs] "m" (__rseq_abi.rseq_cs),
+ [current_cpu_id] "Qo" (rseq_get_abi()->cpu_id),
+ [rseq_cs] "m" (rseq_get_abi()->rseq_cs),
[expect] "r" (expect),
[v] "Qo" (*v),
[newv] "r" (newv),
RSEQ_ASM_DEFINE_ABORT(4, abort)
: /* gcc asm goto does not allow outputs */
: [cpu_id] "r" (cpu),
- [current_cpu_id] "Qo" (__rseq_abi.cpu_id),
- [rseq_cs] "m" (__rseq_abi.rseq_cs),
+ [current_cpu_id] "Qo" (rseq_get_abi()->cpu_id),
+ [rseq_cs] "m" (rseq_get_abi()->rseq_cs),
[v] "Qo" (*v),
[expect] "r" (expect),
[v2] "Qo" (*v2),
RSEQ_ASM_DEFINE_ABORT(4, abort)
: /* gcc asm goto does not allow outputs */
: [cpu_id] "r" (cpu),
- [current_cpu_id] "Qo" (__rseq_abi.cpu_id),
- [rseq_cs] "m" (__rseq_abi.rseq_cs),
+ [current_cpu_id] "Qo" (rseq_get_abi()->cpu_id),
+ [rseq_cs] "m" (rseq_get_abi()->rseq_cs),
[expect] "r" (expect),
[v] "Qo" (*v),
[newv] "r" (newv),
RSEQ_ASM_DEFINE_ABORT(4, abort)
: /* gcc asm goto does not allow outputs */
: [cpu_id] "r" (cpu),
- [current_cpu_id] "Qo" (__rseq_abi.cpu_id),
- [rseq_cs] "m" (__rseq_abi.rseq_cs),
+ [current_cpu_id] "Qo" (rseq_get_abi()->cpu_id),
+ [rseq_cs] "m" (rseq_get_abi()->rseq_cs),
[expect] "r" (expect),
[v] "Qo" (*v),
[newv] "r" (newv),
"5:\n\t"
: /* gcc asm goto does not allow outputs */
: [cpu_id] "r" (cpu),
- [current_cpu_id] "m" (__rseq_abi.cpu_id),
- [rseq_cs] "m" (__rseq_abi.rseq_cs),
+ [current_cpu_id] "m" (rseq_get_abi()->cpu_id),
+ [rseq_cs] "m" (rseq_get_abi()->rseq_cs),
[v] "m" (*v),
[expect] "r" (expect),
[newv] "r" (newv)
"5:\n\t"
: /* gcc asm goto does not allow outputs */
: [cpu_id] "r" (cpu),
- [current_cpu_id] "m" (__rseq_abi.cpu_id),
- [rseq_cs] "m" (__rseq_abi.rseq_cs),
+ [current_cpu_id] "m" (rseq_get_abi()->cpu_id),
+ [rseq_cs] "m" (rseq_get_abi()->rseq_cs),
/* final store input */
[v] "m" (*v),
[expectnot] "r" (expectnot),
"5:\n\t"
: /* gcc asm goto does not allow outputs */
: [cpu_id] "r" (cpu),
- [current_cpu_id] "m" (__rseq_abi.cpu_id),
- [rseq_cs] "m" (__rseq_abi.rseq_cs),
+ [current_cpu_id] "m" (rseq_get_abi()->cpu_id),
+ [rseq_cs] "m" (rseq_get_abi()->rseq_cs),
[v] "m" (*v),
[count] "Ir" (count)
RSEQ_INJECT_INPUT
"5:\n\t"
: /* gcc asm goto does not allow outputs */
: [cpu_id] "r" (cpu),
- [current_cpu_id] "m" (__rseq_abi.cpu_id),
- [rseq_cs] "m" (__rseq_abi.rseq_cs),
+ [current_cpu_id] "m" (rseq_get_abi()->cpu_id),
+ [rseq_cs] "m" (rseq_get_abi()->rseq_cs),
/* try store input */
[v2] "m" (*v2),
[newv2] "r" (newv2),
"5:\n\t"
: /* gcc asm goto does not allow outputs */
: [cpu_id] "r" (cpu),
- [current_cpu_id] "m" (__rseq_abi.cpu_id),
- [rseq_cs] "m" (__rseq_abi.rseq_cs),
+ [current_cpu_id] "m" (rseq_get_abi()->cpu_id),
+ [rseq_cs] "m" (rseq_get_abi()->rseq_cs),
/* try store input */
[v2] "m" (*v2),
[newv2] "r" (newv2),
"5:\n\t"
: /* gcc asm goto does not allow outputs */
: [cpu_id] "r" (cpu),
- [current_cpu_id] "m" (__rseq_abi.cpu_id),
- [rseq_cs] "m" (__rseq_abi.rseq_cs),
+ [current_cpu_id] "m" (rseq_get_abi()->cpu_id),
+ [rseq_cs] "m" (rseq_get_abi()->rseq_cs),
/* cmp2 input */
[v2] "m" (*v2),
[expect2] "r" (expect2),
"8:\n\t"
: /* gcc asm goto does not allow outputs */
: [cpu_id] "r" (cpu),
- [current_cpu_id] "m" (__rseq_abi.cpu_id),
- [rseq_cs] "m" (__rseq_abi.rseq_cs),
+ [current_cpu_id] "m" (rseq_get_abi()->cpu_id),
+ [rseq_cs] "m" (rseq_get_abi()->rseq_cs),
/* final store input */
[v] "m" (*v),
[expect] "r" (expect),
"8:\n\t"
: /* gcc asm goto does not allow outputs */
: [cpu_id] "r" (cpu),
- [current_cpu_id] "m" (__rseq_abi.cpu_id),
- [rseq_cs] "m" (__rseq_abi.rseq_cs),
+ [current_cpu_id] "m" (rseq_get_abi()->cpu_id),
+ [rseq_cs] "m" (rseq_get_abi()->rseq_cs),
/* final store input */
[v] "m" (*v),
[expect] "r" (expect),
--- /dev/null
+/* SPDX-License-Identifier: LGPL-2.1-only OR MIT */
+/*
+ * rseq-ppc-thread-pointer.h
+ *
+ * (C) Copyright 2021 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ */
+
+#ifndef _RSEQ_PPC_THREAD_POINTER
+#define _RSEQ_PPC_THREAD_POINTER
+
+static inline void *rseq_thread_pointer(void)
+{
+#ifdef __powerpc64__
+ register void *__result asm ("r13");
+#else
+ register void *__result asm ("r2");
+#endif
+ return __result;
+}
+
+#endif
RSEQ_ASM_DEFINE_ABORT(4, abort)
: /* gcc asm goto does not allow outputs */
: [cpu_id] "r" (cpu),
- [current_cpu_id] "m" (__rseq_abi.cpu_id),
- [rseq_cs] "m" (__rseq_abi.rseq_cs),
+ [current_cpu_id] "m" (rseq_get_abi()->cpu_id),
+ [rseq_cs] "m" (rseq_get_abi()->rseq_cs),
[v] "m" (*v),
[expect] "r" (expect),
[newv] "r" (newv)
RSEQ_ASM_DEFINE_ABORT(4, abort)
: /* gcc asm goto does not allow outputs */
: [cpu_id] "r" (cpu),
- [current_cpu_id] "m" (__rseq_abi.cpu_id),
- [rseq_cs] "m" (__rseq_abi.rseq_cs),
+ [current_cpu_id] "m" (rseq_get_abi()->cpu_id),
+ [rseq_cs] "m" (rseq_get_abi()->rseq_cs),
/* final store input */
[v] "m" (*v),
[expectnot] "r" (expectnot),
RSEQ_ASM_DEFINE_ABORT(4, abort)
: /* gcc asm goto does not allow outputs */
: [cpu_id] "r" (cpu),
- [current_cpu_id] "m" (__rseq_abi.cpu_id),
- [rseq_cs] "m" (__rseq_abi.rseq_cs),
+ [current_cpu_id] "m" (rseq_get_abi()->cpu_id),
+ [rseq_cs] "m" (rseq_get_abi()->rseq_cs),
/* final store input */
[v] "m" (*v),
[count] "r" (count)
RSEQ_ASM_DEFINE_ABORT(4, abort)
: /* gcc asm goto does not allow outputs */
: [cpu_id] "r" (cpu),
- [current_cpu_id] "m" (__rseq_abi.cpu_id),
- [rseq_cs] "m" (__rseq_abi.rseq_cs),
+ [current_cpu_id] "m" (rseq_get_abi()->cpu_id),
+ [rseq_cs] "m" (rseq_get_abi()->rseq_cs),
/* try store input */
[v2] "m" (*v2),
[newv2] "r" (newv2),
RSEQ_ASM_DEFINE_ABORT(4, abort)
: /* gcc asm goto does not allow outputs */
: [cpu_id] "r" (cpu),
- [current_cpu_id] "m" (__rseq_abi.cpu_id),
- [rseq_cs] "m" (__rseq_abi.rseq_cs),
+ [current_cpu_id] "m" (rseq_get_abi()->cpu_id),
+ [rseq_cs] "m" (rseq_get_abi()->rseq_cs),
/* try store input */
[v2] "m" (*v2),
[newv2] "r" (newv2),
RSEQ_ASM_DEFINE_ABORT(4, abort)
: /* gcc asm goto does not allow outputs */
: [cpu_id] "r" (cpu),
- [current_cpu_id] "m" (__rseq_abi.cpu_id),
- [rseq_cs] "m" (__rseq_abi.rseq_cs),
+ [current_cpu_id] "m" (rseq_get_abi()->cpu_id),
+ [rseq_cs] "m" (rseq_get_abi()->rseq_cs),
/* cmp2 input */
[v2] "m" (*v2),
[expect2] "r" (expect2),
RSEQ_ASM_DEFINE_ABORT(4, abort)
: /* gcc asm goto does not allow outputs */
: [cpu_id] "r" (cpu),
- [current_cpu_id] "m" (__rseq_abi.cpu_id),
- [rseq_cs] "m" (__rseq_abi.rseq_cs),
+ [current_cpu_id] "m" (rseq_get_abi()->cpu_id),
+ [rseq_cs] "m" (rseq_get_abi()->rseq_cs),
/* final store input */
[v] "m" (*v),
[expect] "r" (expect),
RSEQ_ASM_DEFINE_ABORT(4, abort)
: /* gcc asm goto does not allow outputs */
: [cpu_id] "r" (cpu),
- [current_cpu_id] "m" (__rseq_abi.cpu_id),
- [rseq_cs] "m" (__rseq_abi.rseq_cs),
+ [current_cpu_id] "m" (rseq_get_abi()->cpu_id),
+ [rseq_cs] "m" (rseq_get_abi()->rseq_cs),
/* final store input */
[v] "m" (*v),
[expect] "r" (expect),
RSEQ_ASM_DEFINE_ABORT(4, "", abort)
: /* gcc asm goto does not allow outputs */
: [cpu_id] "r" (cpu),
- [current_cpu_id] "m" (__rseq_abi.cpu_id),
- [rseq_cs] "m" (__rseq_abi.rseq_cs),
+ [current_cpu_id] "m" (rseq_get_abi()->cpu_id),
+ [rseq_cs] "m" (rseq_get_abi()->rseq_cs),
[v] "m" (*v),
[expect] "r" (expect),
[newv] "r" (newv)
RSEQ_ASM_DEFINE_ABORT(4, "", abort)
: /* gcc asm goto does not allow outputs */
: [cpu_id] "r" (cpu),
- [current_cpu_id] "m" (__rseq_abi.cpu_id),
- [rseq_cs] "m" (__rseq_abi.rseq_cs),
+ [current_cpu_id] "m" (rseq_get_abi()->cpu_id),
+ [rseq_cs] "m" (rseq_get_abi()->rseq_cs),
/* final store input */
[v] "m" (*v),
[expectnot] "r" (expectnot),
RSEQ_ASM_DEFINE_ABORT(4, "", abort)
: /* gcc asm goto does not allow outputs */
: [cpu_id] "r" (cpu),
- [current_cpu_id] "m" (__rseq_abi.cpu_id),
- [rseq_cs] "m" (__rseq_abi.rseq_cs),
+ [current_cpu_id] "m" (rseq_get_abi()->cpu_id),
+ [rseq_cs] "m" (rseq_get_abi()->rseq_cs),
/* final store input */
[v] "m" (*v),
[count] "r" (count)
RSEQ_ASM_DEFINE_ABORT(4, "", abort)
: /* gcc asm goto does not allow outputs */
: [cpu_id] "r" (cpu),
- [current_cpu_id] "m" (__rseq_abi.cpu_id),
- [rseq_cs] "m" (__rseq_abi.rseq_cs),
+ [current_cpu_id] "m" (rseq_get_abi()->cpu_id),
+ [rseq_cs] "m" (rseq_get_abi()->rseq_cs),
/* try store input */
[v2] "m" (*v2),
[newv2] "r" (newv2),
RSEQ_ASM_DEFINE_ABORT(4, "", abort)
: /* gcc asm goto does not allow outputs */
: [cpu_id] "r" (cpu),
- [current_cpu_id] "m" (__rseq_abi.cpu_id),
- [rseq_cs] "m" (__rseq_abi.rseq_cs),
+ [current_cpu_id] "m" (rseq_get_abi()->cpu_id),
+ [rseq_cs] "m" (rseq_get_abi()->rseq_cs),
/* cmp2 input */
[v2] "m" (*v2),
[expect2] "r" (expect2),
#endif
: /* gcc asm goto does not allow outputs */
: [cpu_id] "r" (cpu),
- [current_cpu_id] "m" (__rseq_abi.cpu_id),
- [rseq_cs] "m" (__rseq_abi.rseq_cs),
+ [current_cpu_id] "m" (rseq_get_abi()->cpu_id),
+ [rseq_cs] "m" (rseq_get_abi()->rseq_cs),
/* final store input */
[v] "m" (*v),
[expect] "r" (expect),
--- /dev/null
+/* SPDX-License-Identifier: LGPL-2.1-only OR MIT */
+/*
+ * rseq-x86-thread-pointer.h
+ *
+ * (C) Copyright 2021 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ */
+
+#ifndef _RSEQ_X86_THREAD_POINTER
+#define _RSEQ_X86_THREAD_POINTER
+
+#include <features.h>
+
+#if __GNUC_PREREQ (11, 1)
+static inline void *rseq_thread_pointer(void)
+{
+ return __builtin_thread_pointer();
+}
+#else
+static inline void *rseq_thread_pointer(void)
+{
+ void *__result;
+
+# ifdef __x86_64__
+ __asm__ ("mov %%fs:0, %0" : "=r" (__result));
+# else
+ __asm__ ("mov %%gs:0, %0" : "=r" (__result));
+# endif
+ return __result;
+}
+#endif /* !GCC 11 */
+
+#endif
* Due to a compiler optimization bug in gcc-8 with asm goto and TLS asm input
* operands, we cannot use "m" input operands, and rather pass the __rseq_abi
* address through a "r" input operand.
+ * (TODO: revisit after migration to glibc's ABI)
*/
/* Offset of cpu_id and rseq_cs fields in struct rseq. */
RSEQ_ASM_DEFINE_ABORT(4, "", abort)
: /* gcc asm goto does not allow outputs */
: [cpu_id] "r" (cpu),
- [rseq_abi] "r" (&__rseq_abi),
+ [rseq_abi] "r" (rseq_get_abi()),
[v] "m" (*v),
[expect] "r" (expect),
[newv] "r" (newv)
RSEQ_ASM_DEFINE_ABORT(4, "", abort)
: /* gcc asm goto does not allow outputs */
: [cpu_id] "r" (cpu),
- [rseq_abi] "r" (&__rseq_abi),
+ [rseq_abi] "r" (rseq_get_abi()),
/* final store input */
[v] "m" (*v),
[expectnot] "r" (expectnot),
RSEQ_ASM_DEFINE_ABORT(4, "", abort)
: /* gcc asm goto does not allow outputs */
: [cpu_id] "r" (cpu),
- [rseq_abi] "r" (&__rseq_abi),
+ [rseq_abi] "r" (rseq_get_abi()),
/* final store input */
[v] "m" (*v),
[count] "er" (count)
RSEQ_ASM_DEFINE_ABORT(4, "", abort)
: /* gcc asm goto does not allow outputs */
: [cpu_id] "r" (cpu),
- [rseq_abi] "r" (&__rseq_abi),
+ [rseq_abi] "r" (rseq_get_abi()),
/* try store input */
[v2] "m" (*v2),
[newv2] "r" (newv2),
RSEQ_ASM_DEFINE_ABORT(4, "", abort)
: /* gcc asm goto does not allow outputs */
: [cpu_id] "r" (cpu),
- [rseq_abi] "r" (&__rseq_abi),
+ [rseq_abi] "r" (rseq_get_abi()),
/* cmp2 input */
[v2] "m" (*v2),
[expect2] "r" (expect2),
#endif
: /* gcc asm goto does not allow outputs */
: [cpu_id] "r" (cpu),
- [rseq_abi] "r" (&__rseq_abi),
+ [rseq_abi] "r" (rseq_get_abi()),
/* final store input */
[v] "m" (*v),
[expect] "r" (expect),
RSEQ_ASM_DEFINE_ABORT(4, "", abort)
: /* gcc asm goto does not allow outputs */
: [cpu_id] "r" (cpu),
- [rseq_abi] "r" (&__rseq_abi),
+ [rseq_abi] "r" (rseq_get_abi()),
/* final store input */
[p] "m" (*p),
[voffp] "er" (voffp),
RSEQ_ASM_DEFINE_ABORT(4, "", abort)
: /* gcc asm goto does not allow outputs */
: [cpu_id] "r" (cpu),
- [rseq_abi] "r" (&__rseq_abi),
+ [rseq_abi] "r" (rseq_get_abi()),
[v] "m" (*v),
[expect] "r" (expect),
[newv] "r" (newv)
RSEQ_ASM_DEFINE_ABORT(4, "", abort)
: /* gcc asm goto does not allow outputs */
: [cpu_id] "r" (cpu),
- [rseq_abi] "r" (&__rseq_abi),
+ [rseq_abi] "r" (rseq_get_abi()),
/* final store input */
[v] "m" (*v),
[expectnot] "r" (expectnot),
RSEQ_ASM_DEFINE_ABORT(4, "", abort)
: /* gcc asm goto does not allow outputs */
: [cpu_id] "r" (cpu),
- [rseq_abi] "r" (&__rseq_abi),
+ [rseq_abi] "r" (rseq_get_abi()),
/* final store input */
[v] "m" (*v),
[count] "ir" (count)
RSEQ_ASM_DEFINE_ABORT(4, "", abort)
: /* gcc asm goto does not allow outputs */
: [cpu_id] "r" (cpu),
- [rseq_abi] "r" (&__rseq_abi),
+ [rseq_abi] "r" (rseq_get_abi()),
/* try store input */
[v2] "m" (*v2),
[newv2] "m" (newv2),
RSEQ_ASM_DEFINE_ABORT(4, "", abort)
: /* gcc asm goto does not allow outputs */
: [cpu_id] "r" (cpu),
- [rseq_abi] "r" (&__rseq_abi),
+ [rseq_abi] "r" (rseq_get_abi()),
/* try store input */
[v2] "m" (*v2),
[newv2] "r" (newv2),
RSEQ_ASM_DEFINE_ABORT(4, "", abort)
: /* gcc asm goto does not allow outputs */
: [cpu_id] "r" (cpu),
- [rseq_abi] "r" (&__rseq_abi),
+ [rseq_abi] "r" (rseq_get_abi()),
/* cmp2 input */
[v2] "m" (*v2),
[expect2] "r" (expect2),
#endif
: /* gcc asm goto does not allow outputs */
: [cpu_id] "r" (cpu),
- [rseq_abi] "r" (&__rseq_abi),
+ [rseq_abi] "r" (rseq_get_abi()),
/* final store input */
[v] "m" (*v),
[expect] "m" (expect),
#endif
: /* gcc asm goto does not allow outputs */
: [cpu_id] "r" (cpu),
- [rseq_abi] "r" (&__rseq_abi),
+ [rseq_abi] "r" (rseq_get_abi()),
/* final store input */
[v] "m" (*v),
[expect] "m" (expect),
RSEQ_ASM_DEFINE_ABORT(4, "", abort)
: /* gcc asm goto does not allow outputs */
: [cpu_id] "r" (cpu),
- [rseq_abi] "r" (&__rseq_abi),
+ [rseq_abi] "r" (rseq_get_abi()),
/* final store input */
[p] "m" (*p),
[voffp] "ir" (voffp),
extern "C" {
#endif
-extern __thread struct rseq __rseq_abi;
+/* Offset from the thread pointer to the rseq area. */
+extern int rseq_offset;
+/* Size of the registered rseq area. 0 if the registration was
+ unsuccessful. */
+extern unsigned int rseq_size;
+/* Flags used during rseq registration. */
+extern unsigned int rseq_flags;
#ifdef __cplusplus
}
abort(); \
} while (0)
+#if defined(__x86_64__) || defined(__i386__)
+#include <rseq/rseq-x86-thread-pointer.h>
+#elif defined(__PPC__)
+#include <rseq/rseq-ppc-thread-pointer.h>
+#else
+/* Use gcc builtin thread pointer. */
+static inline void *rseq_thread_pointer(void)
+{
+ return __builtin_thread_pointer();
+}
+#endif
+
+static inline struct rseq *rseq_get_abi(void)
+{
+ return (struct rseq *) (rseq_thread_pointer() + rseq_offset);
+}
+
#if defined(__x86_64__) || defined(__i386__)
#include <rseq/rseq-x86.h>
#elif defined(__ARMEL__) || defined(__ARMEB__)
*/
static inline int32_t rseq_current_cpu_raw(void)
{
- return RSEQ_READ_ONCE(__rseq_abi.cpu_id);
+ return RSEQ_READ_ONCE(rseq_get_abi()->cpu_id);
}
/*
*/
static inline uint32_t rseq_cpu_start(void)
{
- return RSEQ_READ_ONCE(__rseq_abi.cpu_id_start);
+ return RSEQ_READ_ONCE(rseq_get_abi()->cpu_id_start);
}
static inline uint32_t rseq_current_cpu(void)
static inline void rseq_clear_rseq_cs(void)
{
#ifdef __LP64__
- RSEQ_WRITE_ONCE(__rseq_abi.rseq_cs.ptr, 0);
+ RSEQ_WRITE_ONCE(rseq_get_abi()->rseq_cs.ptr, 0);
#else
- RSEQ_WRITE_ONCE(__rseq_abi.rseq_cs.ptr.ptr32, 0);
+ RSEQ_WRITE_ONCE(rseq_get_abi()->rseq_cs.ptr.ptr32, 0);
#endif
}
rseq.c
librseq_la_LDFLAGS = -no-undefined -version-info $(RSEQ_LIBRARY_VERSION)
+librseq_la_LIBADD = $(DL_LIBS)
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = librseq.pc
#include <assert.h>
#include <signal.h>
#include <limits.h>
+#include <dlfcn.h>
#include <rseq/rseq.h>
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
-__thread struct rseq __rseq_abi = {
+static const int *libc_rseq_offset_p;
+static const unsigned int *libc_rseq_size_p;
+static const unsigned int *libc_rseq_flags_p;
+
+/* Offset from the thread pointer to the rseq area. */
+int rseq_offset;
+
+/* Size of the registered rseq area. 0 if the registration was
+ unsuccessful. */
+unsigned int rseq_size = -1U;
+
+/* Flags used during rseq registration. */
+unsigned int rseq_flags;
+
+static int rseq_ownership;
+
+static
+__thread struct rseq __rseq_abi __attribute__((tls_model("initial-exec"))) = {
.cpu_id = RSEQ_CPU_ID_UNINITIALIZED,
};
-static __thread uint32_t __rseq_refcount;
-
static int sys_rseq(struct rseq *rseq_abi, uint32_t rseq_len,
int flags, uint32_t sig)
{
}
}
-static void signal_off_save(sigset_t *oldset)
+int rseq_register_current_thread(void)
{
- sigset_t set;
- int ret;
+ int rc;
- sigfillset(&set);
- ret = pthread_sigmask(SIG_BLOCK, &set, oldset);
- if (ret)
- abort();
+ if (!rseq_ownership) {
+ /* Treat libc's ownership as a successful registration. */
+ return 0;
+ }
+ rc = sys_rseq(&__rseq_abi, sizeof(struct rseq), 0, RSEQ_SIG);
+ if (rc)
+ return -1;
+ assert(rseq_current_cpu_raw() >= 0);
+ return 0;
}
-static void signal_restore(sigset_t oldset)
+int rseq_unregister_current_thread(void)
{
- int ret;
+ int rc;
- ret = pthread_sigmask(SIG_SETMASK, &oldset, NULL);
- if (ret)
- abort();
+ if (!rseq_ownership) {
+ /* Treat libc's ownership as a successful unregistration. */
+ return 0;
+ }
+ rc = sys_rseq(&__rseq_abi, sizeof(struct rseq), RSEQ_FLAG_UNREGISTER, RSEQ_SIG);
+ if (rc)
+ return -1;
+ return 0;
}
-int rseq_register_current_thread(void)
+static __attribute__((constructor))
+void rseq_init(void)
{
- int rc, ret = 0, cpu_id;
- sigset_t oldset;
-
- signal_off_save(&oldset);
- cpu_id = rseq_current_cpu_raw();
- if (cpu_id == RSEQ_CPU_ID_REGISTRATION_FAILED) {
- errno = EPERM;
- ret = -1;
- goto end;
+ libc_rseq_offset_p = dlsym(RTLD_NEXT, "__rseq_offset");
+ libc_rseq_size_p = dlsym(RTLD_NEXT, "__rseq_size");
+ libc_rseq_flags_p = dlsym(RTLD_NEXT, "__rseq_flags");
+ if (libc_rseq_size_p && libc_rseq_offset_p && libc_rseq_flags_p) {
+ /* rseq registration owned by glibc */
+ rseq_offset = *libc_rseq_offset_p;
+ rseq_size = *libc_rseq_size_p;
+ rseq_flags = *libc_rseq_flags_p;
+ return;
}
- /*
- * If cpu_id >= 0, rseq is already successfully registered either by
- * libc (__rseq_refcount == 0) or by another user library
- * (__rseq_refcount > 0) for this thread.
- */
- if (cpu_id >= 0) {
- /* Treat libc's ownership as a successful registration. */
- if (__rseq_refcount == 0)
- goto end;
- if (__rseq_refcount == UINT_MAX) {
- errno = EOVERFLOW;
- ret = -1;
- goto end;
- }
- } else {
- assert(__rseq_refcount == 0);
- rc = sys_rseq(&__rseq_abi, sizeof(struct rseq), 0, RSEQ_SIG);
- if (rc) {
- assert(errno != EBUSY);
- __rseq_abi.cpu_id = RSEQ_CPU_ID_REGISTRATION_FAILED;
- ret = -1;
- goto end;
- }
- assert(rseq_current_cpu_raw() >= 0);
- }
- __rseq_refcount++;
-end:
- signal_restore(oldset);
- return ret;
+ if (!rseq_available())
+ return;
+ rseq_ownership = 1;
+ rseq_offset = (void *)&__rseq_abi - rseq_thread_pointer();
+ rseq_size = sizeof(struct rseq);
+ rseq_flags = 0;
}
-int rseq_unregister_current_thread(void)
+static __attribute__((destructor))
+void rseq_exit(void)
{
- int rc, ret = 0, cpu_id;
- sigset_t oldset;
-
- signal_off_save(&oldset);
- cpu_id = rseq_current_cpu_raw();
- /* cpu_id < 0 means rseq is either uninitialized or registration failed. */
- if (cpu_id < 0) {
- errno = EPERM;
- ret = -1;
- goto end;
- }
- /*
- * If cpu_id >= 0, rseq is currently successfully registered either by
- * libc (__rseq_refcount == 0) or by another user library
- * (__rseq_refcount > 0) for this thread.
- *
- * Treat libc's ownership as a successful unregistration.
- */
- if (__rseq_refcount == 0) {
- goto end;
- }
- if (__rseq_refcount == 1) {
- rc = sys_rseq(&__rseq_abi, sizeof(struct rseq),
- RSEQ_FLAG_UNREGISTER, RSEQ_SIG);
- if (rc) {
- ret = -1;
- goto end;
- }
- }
- __rseq_refcount--;
-end:
- signal_restore(oldset);
- return ret;
+ if (!rseq_ownership)
+ return;
+ rseq_offset = 0;
+ rseq_size = -1U;
+ rseq_ownership = 0;
}
int32_t rseq_fallback_current_cpu(void)
dist_noinst_SCRIPTS = run_param_test.tap
basic_percpu_ops_test_tap_SOURCES = basic_percpu_ops_test.c
-basic_percpu_ops_test_tap_LDADD = $(top_builddir)/src/librseq.la $(top_builddir)/tests/utils/libtap.la
+basic_percpu_ops_test_tap_LDADD = $(top_builddir)/src/librseq.la $(top_builddir)/tests/utils/libtap.la $(DL_LIBS)
basic_test_tap_SOURCES = basic_test.c
-basic_test_tap_LDADD = $(top_builddir)/src/librseq.la $(top_builddir)/tests/utils/libtap.la
+basic_test_tap_LDADD = $(top_builddir)/src/librseq.la $(top_builddir)/tests/utils/libtap.la $(DL_LIBS)
param_test_SOURCES = param_test.c
-param_test_LDADD = $(top_builddir)/src/librseq.la
+param_test_LDADD = $(top_builddir)/src/librseq.la $(DL_LIBS)
param_test_benchmark_SOURCES = param_test.c
param_test_benchmark_CPPFLAGS = $(AM_CPPFLAGS) -DBENCHMARK
-param_test_benchmark_LDADD = $(top_builddir)/src/librseq.la
+param_test_benchmark_LDADD = $(top_builddir)/src/librseq.la $(DL_LIBS)
param_test_compare_twice_SOURCES = param_test.c
param_test_compare_twice_CPPFLAGS = $(AM_CPPFLAGS) -DRSEQ_COMPARE_TWICE
-param_test_compare_twice_LDADD = $(top_builddir)/src/librseq.la
+param_test_compare_twice_LDADD = $(top_builddir)/src/librseq.la $(DL_LIBS)
TESTS = basic_percpu_ops_test.tap basic_test.tap run_param_test.tap