[libc-commits] [libc] [libc][setjmp] make x86_64 longjmp naked (PR #112581)

Nick Desaulniers via libc-commits libc-commits at lists.llvm.org
Wed Oct 16 14:00:54 PDT 2024


https://github.com/nickdesaulniers updated https://github.com/llvm/llvm-project/pull/112581

>From 6ca41d94bed4c2f78495bbf40d602fd8c5ea7566 Mon Sep 17 00:00:00 2001
From: Nick Desaulniers <ndesaulniers at google.com>
Date: Wed, 16 Oct 2024 09:59:01 -0700
Subject: [PATCH 1/2] [libc][setjmp] make x86_64 longjmp naked

The generated asm for x86_64's longjmp has a function prolog and epilog. The
epilog in particular is unreachable. Convert longjmp to a naked function to
avoid these spurious instructions in longjmp.

Link: https://github.com/llvm/llvm-project/pull/112437/files#r1802085511
---
 libc/src/setjmp/longjmp.h          | 13 ++++++++
 libc/src/setjmp/x86_64/longjmp.cpp | 48 ++++++++++++++++--------------
 2 files changed, 38 insertions(+), 23 deletions(-)

diff --git a/libc/src/setjmp/longjmp.h b/libc/src/setjmp/longjmp.h
index 7cb12b3392ae16..9b7db29717216b 100644
--- a/libc/src/setjmp/longjmp.h
+++ b/libc/src/setjmp/longjmp.h
@@ -11,9 +11,22 @@
 
 #include "hdr/types/jmp_buf.h"
 #include "src/__support/macros/config.h"
+#include "src/__support/macros/properties/compiler.h"
 
 namespace LIBC_NAMESPACE_DECL {
 
+// TODO(https://github.com/llvm/llvm-project/issues/112427)
+// Some of the architecture-specific definitions are marked `naked`, which in
+// GCC implies `nothrow`.
+//
+// Right now, our aliases aren't marked `nothrow`, so we wind up in a situation
+// where clang will emit -Wmissing-exception-spec if we add `nothrow` here, but
+// GCC will emit -Wmissing-attributes here without `nothrow`. We need to update
+// LLVM_LIBC_FUNCTION to denote when a function throws or not.
+
+#ifdef LIBC_COMPILER_IS_GCC
+[[gnu::nothrow]]
+#endif
 void longjmp(jmp_buf buf, int val);
 
 } // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/setjmp/x86_64/longjmp.cpp b/libc/src/setjmp/x86_64/longjmp.cpp
index d4b55565cb2187..5d5da673348ede 100644
--- a/libc/src/setjmp/x86_64/longjmp.cpp
+++ b/libc/src/setjmp/x86_64/longjmp.cpp
@@ -7,6 +7,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "src/setjmp/longjmp.h"
+#include "include/llvm-libc-macros/offsetof-macro.h"
 #include "src/__support/common.h"
 #include "src/__support/macros/config.h"
 
@@ -16,30 +17,31 @@
 
 namespace LIBC_NAMESPACE_DECL {
 
-LLVM_LIBC_FUNCTION(void, longjmp, (jmp_buf buf, int val)) {
-  register __UINT64_TYPE__ rbx __asm__("rbx");
-  register __UINT64_TYPE__ rbp __asm__("rbp");
-  register __UINT64_TYPE__ r12 __asm__("r12");
-  register __UINT64_TYPE__ r13 __asm__("r13");
-  register __UINT64_TYPE__ r14 __asm__("r14");
-  register __UINT64_TYPE__ r15 __asm__("r15");
-  register __UINT64_TYPE__ rsp __asm__("rsp");
-  register __UINT64_TYPE__ rax __asm__("rax");
+[[gnu::naked]]
+LLVM_LIBC_FUNCTION(void, longjmp, (jmp_buf, int)) {
+  asm(R"(
+      cmpl $0x1, %%esi
+      adcl $0x0, %%esi
+      movq %%rsi, %%rax
 
-  // ABI requires that the return value should be stored in rax. So, we store
-  // |val| in rax. Note that this has to happen before we restore the registers
-  // from values in |buf|. Otherwise, once rsp and rbp are updated, we cannot
-  // read |val|.
-  val = val == 0 ? 1 : val;
-  LIBC_INLINE_ASM("mov %1, %0\n\t" : "=r"(rax) : "m"(val) :);
-  LIBC_INLINE_ASM("mov %1, %0\n\t" : "=r"(rbx) : "m"(buf->rbx) :);
-  LIBC_INLINE_ASM("mov %1, %0\n\t" : "=r"(rbp) : "m"(buf->rbp) :);
-  LIBC_INLINE_ASM("mov %1, %0\n\t" : "=r"(r12) : "m"(buf->r12) :);
-  LIBC_INLINE_ASM("mov %1, %0\n\t" : "=r"(r13) : "m"(buf->r13) :);
-  LIBC_INLINE_ASM("mov %1, %0\n\t" : "=r"(r14) : "m"(buf->r14) :);
-  LIBC_INLINE_ASM("mov %1, %0\n\t" : "=r"(r15) : "m"(buf->r15) :);
-  LIBC_INLINE_ASM("mov %1, %0\n\t" : "=r"(rsp) : "m"(buf->rsp) :);
-  LIBC_INLINE_ASM("jmp *%0\n\t" : : "m"(buf->rip));
+      movq %c[rbx](%%rdi), %%rbx
+      movq %c[rbp](%%rdi), %%rbp
+      movq %c[r12](%%rdi), %%r12
+      movq %c[r13](%%rdi), %%r13
+      movq %c[r14](%%rdi), %%r14
+      movq %c[r15](%%rdi), %%r15
+      movq %c[rsp](%%rdi), %%rsp
+      jmpq *%c[rip](%%rdi)
+      )" ::
+      [rbx] "i"(offsetof(__jmp_buf, rbx)),
+      [rbp] "i"(offsetof(__jmp_buf, rbp)),
+      [r12] "i"(offsetof(__jmp_buf, r12)),
+      [r13] "i"(offsetof(__jmp_buf, r13)),
+      [r14] "i"(offsetof(__jmp_buf, r14)),
+      [r15] "i"(offsetof(__jmp_buf, r15)),
+      [rsp] "i"(offsetof(__jmp_buf, rsp)),
+      [rip] "i"(offsetof(__jmp_buf, rip))
+);
 }
 
 } // namespace LIBC_NAMESPACE_DECL

>From 99080665ccac9d2425d100fb1a1bf182352ec306 Mon Sep 17 00:00:00 2001
From: Nick Desaulniers <ndesaulniers at google.com>
Date: Wed, 16 Oct 2024 14:00:41 -0700
Subject: [PATCH 2/2] reformat

---
 libc/src/setjmp/x86_64/longjmp.cpp | 15 +++++----------
 1 file changed, 5 insertions(+), 10 deletions(-)

diff --git a/libc/src/setjmp/x86_64/longjmp.cpp b/libc/src/setjmp/x86_64/longjmp.cpp
index 5d5da673348ede..c293c55a6f9fb2 100644
--- a/libc/src/setjmp/x86_64/longjmp.cpp
+++ b/libc/src/setjmp/x86_64/longjmp.cpp
@@ -32,16 +32,11 @@ LLVM_LIBC_FUNCTION(void, longjmp, (jmp_buf, int)) {
       movq %c[r15](%%rdi), %%r15
       movq %c[rsp](%%rdi), %%rsp
       jmpq *%c[rip](%%rdi)
-      )" ::
-      [rbx] "i"(offsetof(__jmp_buf, rbx)),
-      [rbp] "i"(offsetof(__jmp_buf, rbp)),
-      [r12] "i"(offsetof(__jmp_buf, r12)),
-      [r13] "i"(offsetof(__jmp_buf, r13)),
-      [r14] "i"(offsetof(__jmp_buf, r14)),
-      [r15] "i"(offsetof(__jmp_buf, r15)),
-      [rsp] "i"(offsetof(__jmp_buf, rsp)),
-      [rip] "i"(offsetof(__jmp_buf, rip))
-);
+      )" ::[rbx] "i"(offsetof(__jmp_buf, rbx)),
+      [rbp] "i"(offsetof(__jmp_buf, rbp)), [r12] "i"(offsetof(__jmp_buf, r12)),
+      [r13] "i"(offsetof(__jmp_buf, r13)), [r14] "i"(offsetof(__jmp_buf, r14)),
+      [r15] "i"(offsetof(__jmp_buf, r15)), [rsp] "i"(offsetof(__jmp_buf, rsp)),
+      [rip] "i"(offsetof(__jmp_buf, rip)));
 }
 
 } // namespace LIBC_NAMESPACE_DECL



More information about the libc-commits mailing list