[libc-commits] [libc] [libc] Implement getcontext and setcontext for x86_64 (PR #192343)

Pavel Labath via libc-commits libc-commits at lists.llvm.org
Thu Apr 16 08:56:17 PDT 2026


================
@@ -34,7 +34,124 @@ void basic_stub_test() {
   ASSERT_TRUE(true);
 }
 
+void register_preservation_test() {
+  ucontext_t ctx;
+  static volatile int jumped = 0;
+
+  register long r12_val asm("r12") = 0x1212121212121212;
+  register long r13_val asm("r13") = 0x1313131313131313;
+  register long r14_val asm("r14") = 0x1414141414141414;
+  register long r15_val asm("r15") = 0x1515151515151515;
+
+  register void *rdi_val asm("rdi") = &ctx;
+
+  asm volatile("call *%[getcontext_ptr]"
+               : "+r"(rdi_val), "+r"(r12_val), "+r"(r13_val), "+r"(r14_val),
+                 "+r"(r15_val)
+               : [getcontext_ptr] "r"((void *)LIBC_NAMESPACE::getcontext)
+               : "memory", "rax", "rcx", "rdx", "rsi");
+
+  if (!jumped) {
+    jumped = 1;
+
+    // Modify registers to ensure they are restored from context
+    asm volatile("movq $0, %%r12\n\t"
+                 "movq $0, %%r13\n\t"
+                 "movq $0, %%r14\n\t"
+                 "movq $0, %%r15\n\t" ::
+                     : "r12", "r13", "r14", "r15");
+
+    register const ucontext_t *rdi_set asm("rdi") = &ctx;
+    asm volatile("call *%[setcontext_ptr]" ::"r"(rdi_set),
+                 [setcontext_ptr] "r"((void *)LIBC_NAMESPACE::setcontext)
+                 : "memory");
+
+    ASSERT_TRUE(false); // Should not reach here
+  }
+
+  ASSERT_EQ(r12_val, (long)0x1212121212121212);
+  ASSERT_EQ(r13_val, (long)0x1313131313131313);
+  ASSERT_EQ(r14_val, (long)0x1414141414141414);
+  ASSERT_EQ(r15_val, (long)0x1515151515151515);
+}
+
+void test_rbx_rdx() {
+  ucontext_t ctx;
+  static volatile int jumped = 0;
+
+  register long rbx_val asm("rbx") = 0xBBBBBBBBBBBBBBBB;
+  register long rdx_val asm("rdx") = 0xDDDDDDDDDDDDDDDD;
+
+  register void *rdi_val asm("rdi") = &ctx;
+
+  asm volatile("call *%[getcontext_ptr]"
+               : "+r"(rdi_val), "+r"(rbx_val), "+r"(rdx_val)
+               : [getcontext_ptr] "r"((void *)LIBC_NAMESPACE::getcontext)
+               : "memory", "rax", "rcx", "rsi");
+
+  if (!jumped) {
+    jumped = 1;
+
+    asm volatile("movq $0, %%rbx\n\t"
+                 "movq $0, %%rdx\n\t" ::
+                     : "rbx", "rdx");
+
+    register const ucontext_t *rdi_set asm("rdi") = &ctx;
+    asm volatile("call *%[setcontext_ptr]" ::"r"(rdi_set),
+                 [setcontext_ptr] "r"((void *)LIBC_NAMESPACE::setcontext)
+                 : "memory");
+
+    ASSERT_TRUE(false);
+  }
+
+  ASSERT_EQ(rbx_val, (long)0xBBBBBBBBBBBBBBBB);
+  ASSERT_EQ(rdx_val, (long)0xDDDDDDDDDDDDDDDD);
+}
+
+void test_r8_r11() {
+  ucontext_t ctx;
+  static volatile int jumped = 0;
+
+  register long r8_val asm("r8") = 0x0808080808080808;
+  register long r9_val asm("r9") = 0x0909090909090909;
+  register long r10_val asm("r10") = 0x1010101010101010;
+  register long r11_val asm("r11") = 0x1111111111111111;
+
+  register void *rdi_val asm("rdi") = &ctx;
+
+  asm volatile("call *%[getcontext_ptr]"
+               : "+r"(rdi_val), "+r"(r8_val), "+r"(r9_val), "+r"(r10_val),
+                 "+r"(r11_val)
+               : [getcontext_ptr] "r"((void *)LIBC_NAMESPACE::getcontext)
+               : "memory", "rax", "rcx", "rdx", "rsi");
+
+  if (!jumped) {
+    jumped = 1;
+
+    asm volatile("movq $0, %%r8\n\t"
+                 "movq $0, %%r9\n\t"
+                 "movq $0, %%r10\n\t"
+                 "movq $0, %%r11\n\t" ::
+                     : "r8", "r9", "r10", "r11");
+
+    register const ucontext_t *rdi_set asm("rdi") = &ctx;
----------------
labath wrote:

Are you sure you need to redeclare the variable. The one from line 120 should still be in scope. It *may* be necessary to reassign it (see below).

https://github.com/llvm/llvm-project/pull/192343


More information about the libc-commits mailing list