[libc-commits] [libc] [libc] Implement getcontext and setcontext for x86_64 (PR #192343)
Jeff Bailey via libc-commits
libc-commits at lists.llvm.org
Thu Apr 16 12:51:28 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;
----------------
kaladron wrote:
I'm taking a different approach where I'm putting the register-mapped variables in smaller scopes so that the compiler isn't hanging onto those any longer than it needs to.
https://github.com/llvm/llvm-project/pull/192343
More information about the libc-commits
mailing list