From 4f4d5acc34046954aea9e8ea10b5f71ff5f0fbd5 Mon Sep 17 00:00:00 2001
From: bb-cat <ningyu9@huawei.com>
Date: Wed, 2 Mar 2022 15:01:34 +0800
Subject: [PATCH 11/16] zdtm/static/rseq00: fix rseq test when linking with a
 fresh Glibc Fresh Glibc does rseq() register by default. We need to
 unregister rseq before registering our own.

Signed-off-by: Alexander Mikhalitsyn <alexander.mikhalitsyn@virtuozzo.com>
---
 test/zdtm/static/rseq00.c | 76 ++++++++++++++++++++-------
 1 file changed, 58 insertions(+), 18 deletions(-)

diff --git a/test/zdtm/static/rseq00.c b/test/zdtm/static/rseq00.c
index 26f41a2..87053b8 100644
--- a/test/zdtm/static/rseq00.c
+++ b/test/zdtm/static/rseq00.c
@@ -19,13 +19,48 @@
 
 #include "zdtmtst.h"
 
-#if defined(__x86_64__)
+#ifdef __has_include
+#if __has_include("sys/rseq.h")
+#include <sys/rseq.h>
+#endif
+#endif
+
+#if defined(__i386__) || defined(__x86_64__)
+
+#if defined(RSEQ_SIG)
+static inline void *__criu_thread_pointer(void)
+{
+#if __GNUC_PREREQ(11, 1)
+	return __builtin_thread_pointer();
+#else
+	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 */
+}
+
+static inline void unregister_glibc_rseq(void)
+{
+	/* unregister rseq */
+	syscall(__NR_rseq, (void *)((char *)__criu_thread_pointer() + __rseq_offset), __rseq_size, 1, RSEQ_SIG);
+}
+#else
+static inline void unregister_glibc_rseq(void)
+{
+}
+#endif
 
 const char *test_doc = "Check that rseq() basic C/R works";
 const char *test_author = "Alexander Mikhalitsyn <alexander.mikhalitsyn@virtuozzo.com>";
 /* parts of code borrowed from https://www.efficios.com/blog/2019/02/08/linux-restartable-sequences/ */
 
 /* some useful definitions from kernel uapi */
+#ifndef RSEQ_SIG
+
 enum rseq_flags {
 	RSEQ_FLAG_UNREGISTER = (1 << 0),
 };
@@ -37,14 +72,21 @@ struct rseq {
 	uint32_t flags;
 } __attribute__((aligned(4 * sizeof(uint64_t))));
 
+#define RSEQ_SIG 0x53053053
+
+#endif
+
 #ifndef __NR_rseq
 #define __NR_rseq 334
 #endif
 /* EOF */
 
-static __thread volatile struct rseq __rseq_abi;
+#define RSEQ_TLS_ALLOC 0
 
-#define RSEQ_SIG 0x53053053
+static volatile struct rseq *rseq_ptr;
+#if RSEQ_TLS_ALLOC
+static __thread volatile struct rseq __rseq_abi;
+#endif
 
 static int sys_rseq(volatile struct rseq *rseq_abi, uint32_t rseq_len, int flags, uint32_t sig)
 {
@@ -54,27 +96,18 @@ static int sys_rseq(volatile struct rseq *rseq_abi, uint32_t rseq_len, int flags
 static void register_thread(void)
 {
 	int rc;
-	rc = sys_rseq(&__rseq_abi, sizeof(struct rseq), 0, RSEQ_SIG);
+	unregister_glibc_rseq();
+	rc = sys_rseq(rseq_ptr, sizeof(struct rseq), 0, RSEQ_SIG);
 	if (rc) {
 		fail("Failed to register rseq");
 		exit(1);
 	}
 }
 
-static void unregister_thread(void)
-{
-	int rc;
-	rc = sys_rseq(&__rseq_abi, sizeof(struct rseq), RSEQ_FLAG_UNREGISTER, RSEQ_SIG);
-	if (rc) {
-		fail("Failed to unregister rseq");
-		exit(1);
-	}
-}
-
 static void check_thread(void)
 {
 	int rc;
-	rc = sys_rseq(&__rseq_abi, sizeof(struct rseq), 0, RSEQ_SIG);
+	rc = sys_rseq(rseq_ptr, sizeof(struct rseq), 0, RSEQ_SIG);
 	if (!(rc && errno == EBUSY)) {
 		fail("Failed to check rseq %d", rc);
 		exit(1);
@@ -111,8 +144,8 @@ static int rseq_addv(intptr_t *v, intptr_t count, int cpu)
 		".popsection\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_ptr->cpu_id),
+		[rseq_cs]             "m" (rseq_ptr->rseq_cs),
 		/* final store input */
 		[v]                   "m" (*v),
 		[count]               "er" (count)
@@ -132,6 +165,13 @@ int main(int argc, char *argv[])
 	intptr_t *cpu_data;
 	long nr_cpus = sysconf(_SC_NPROCESSORS_ONLN);
 
+#if RSEQ_TLS_ALLOC
+	rseq_ptr = &__rseq_abi;
+#else
+	//rseq_ptr = malloc(sizeof(struct rseq));
+	rseq_ptr = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_SHARED, 0, 0);
+#endif
+
 	test_init(argc, argv);
 
 	cpu_data = calloc(nr_cpus, sizeof(*cpu_data));
@@ -147,7 +187,7 @@ int main(int argc, char *argv[])
 
 	check_thread();
 
-	cpu = RSEQ_ACCESS_ONCE(__rseq_abi.cpu_id_start);
+	cpu = RSEQ_ACCESS_ONCE(rseq_ptr->cpu_id_start);
 	ret = rseq_addv(&cpu_data[cpu], 2, cpu);
 	if (ret)
 		fail("Failed to increment per-cpu counter");
-- 
2.30.0

