[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 01:16:01 PDT 2026


================
@@ -0,0 +1,86 @@
+//===-- Implementation of setcontext for x86_64 ---------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/ucontext/setcontext.h"
+#include "include/llvm-libc-types/ucontext_t.h"
+#include "src/__support/common.h"
+#include "src/__support/macros/config.h"
+
+#include "hdr/types/size_t.h"
+#include <sys/syscall.h>
+
+namespace LIBC_NAMESPACE_DECL {
+
+__attribute__((naked)) LLVM_LIBC_FUNCTION(int, setcontext,
+                                          (const ucontext_t *ucp)) {
+  asm(R"(
+      # ucp is in rdi
+      
+      # Restore the signal mask using rt_sigprocmask syscall.
+      # rt_sigprocmask(SIG_SETMASK, &ucp->uc_sigmask, NULL, sizeof(sigset_t))
+      pushq %%rdi # Save ucp
+      leaq %c[sigmask](%%rdi), %%rsi # set = &ucp->uc_sigmask
+      xorq %%rdx, %%rdx # oldset = NULL
+      movq $%c[sigset_size], %%r10 # sigsetsize = sizeof(sigset_t)
+      movq $2, %%rdi # how = SIG_SETMASK
+      movq $%c[syscall_num], %%rax
+      syscall
+      popq %%rdi # Restore ucp
+
+      # Restore floating point state
+      fxrstorq %c[fpregs_mem](%%rdi)
+
+      # Restore other general purpose registers
+      mov %c[r8](%%rdi), %%r8
+      mov %c[r9](%%rdi), %%r9
+      mov %c[r10](%%rdi), %%r10
+      mov %c[r11](%%rdi), %%r11
+      mov %c[r12](%%rdi), %%r12
+      mov %c[r13](%%rdi), %%r13
+      mov %c[r14](%%rdi), %%r14
+      mov %c[r15](%%rdi), %%r15
+      mov %c[rbp](%%rdi), %%rbp
+      mov %c[rbx](%%rdi), %%rbx
+      mov %c[rdx](%%rdi), %%rdx
+      mov %c[rax](%%rdi), %%rax
+      mov %c[rcx](%%rdi), %%rcx
+
+      # Restore stack pointer and instruction pointer
+      mov %c[rsp](%%rdi), %%rsp
+      mov %c[rip](%%rdi), %%r11 # Use r11 as temp for rip
----------------
labath wrote:

I don't think that clobbering r11 is a problem, but it occurred to me this can be avoided by pushing the rip on the (new) stack, and then ending the function with a regular `ret`.

One nice property of this would be that it preserves the call/ret balance. I'm not particularly familiar with how this works on the CPU, but it feels like this could be less confusing to the return predictor (we are returning to a different place, but at least all of the subsequent returns will match up nicely).

Again, this is optional, and I don't think these functions will be hot enough for these optimizations to matter.

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


More information about the libc-commits mailing list