Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[libc][i386] setjmp/longjmp #112437

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

nickdesaulniers
Copy link
Member

Link: #93709

@llvmbot
Copy link
Collaborator

llvmbot commented Oct 15, 2024

@llvm/pr-subscribers-libc

Author: Nick Desaulniers (nickdesaulniers)

Changes

Link: #93709


Full diff: https://github.com/llvm/llvm-project/pull/112437.diff

4 Files Affected:

  • (modified) libc/include/llvm-libc-types/jmp_buf.h (+7)
  • (modified) libc/src/setjmp/longjmp.h (+1)
  • (modified) libc/src/setjmp/x86_64/longjmp.cpp (+31-2)
  • (modified) libc/src/setjmp/x86_64/setjmp.cpp (+30-1)
diff --git a/libc/include/llvm-libc-types/jmp_buf.h b/libc/include/llvm-libc-types/jmp_buf.h
index 60e033c6c65a95..f246e6491cf554 100644
--- a/libc/include/llvm-libc-types/jmp_buf.h
+++ b/libc/include/llvm-libc-types/jmp_buf.h
@@ -19,6 +19,13 @@ typedef struct {
   __UINT64_TYPE__ r15;
   __UINTPTR_TYPE__ rsp;
   __UINTPTR_TYPE__ rip;
+#elif defined(__i386__)
+  long ebx;
+  long esi;
+  long edi;
+  long ebp;
+  long esp;
+  long eip;
 #elif defined(__riscv)
   /* Program counter.  */
   long int __pc;
diff --git a/libc/src/setjmp/longjmp.h b/libc/src/setjmp/longjmp.h
index 7cb12b3392ae16..e8d6985f44ee4d 100644
--- a/libc/src/setjmp/longjmp.h
+++ b/libc/src/setjmp/longjmp.h
@@ -14,6 +14,7 @@
 
 namespace LIBC_NAMESPACE_DECL {
 
+[[noreturn]]
 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..f27e5f055d6f99 100644
--- a/libc/src/setjmp/x86_64/longjmp.cpp
+++ b/libc/src/setjmp/x86_64/longjmp.cpp
@@ -6,16 +6,44 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "src/setjmp/longjmp.h"
+#include "include/llvm-libc-macros/offsetof-macro.h"
 #include "src/__support/common.h"
 #include "src/__support/macros/config.h"
+#include "src/setjmp/longjmp.h"
 
-#if !defined(LIBC_TARGET_ARCH_IS_X86_64)
+#if !defined(LIBC_TARGET_ARCH_IS_X86)
 #error "Invalid file include"
 #endif
 
 namespace LIBC_NAMESPACE_DECL {
 
+#ifdef __i386__
+[[noreturn]]
+LLVM_LIBC_FUNCTION(void, longjmp, (jmp_buf, int val)) {
+  asm(R"(
+      mov 4(%%esp), %%edx
+
+      mov %c[ebx](%%edx), %%ebx
+      mov %c[esi](%%edx), %%esi
+      mov %c[edi](%%edx), %%edi
+      mov %c[ebp](%%edx), %%ebp
+      mov %c[esp](%%edx), %%esp
+
+      jmp *%c[eip](%%edx)
+      )"
+      ::
+      [ebx] "i"(offsetof(__jmp_buf, ebx)),
+      [esi] "i"(offsetof(__jmp_buf, esi)),
+      [edi] "i"(offsetof(__jmp_buf, edi)),
+      [ebp] "i"(offsetof(__jmp_buf, ebp)),
+      [esp] "i"(offsetof(__jmp_buf, esp)),
+      [eip] "i"(offsetof(__jmp_buf, eip)),
+      [val] "a"(val == 0 ? 1 : val) :
+      "edx");
+  __builtin_unreachable();
+}
+#else
+[[noreturn]]
 LLVM_LIBC_FUNCTION(void, longjmp, (jmp_buf buf, int val)) {
   register __UINT64_TYPE__ rbx __asm__("rbx");
   register __UINT64_TYPE__ rbp __asm__("rbp");
@@ -41,5 +69,6 @@ LLVM_LIBC_FUNCTION(void, longjmp, (jmp_buf buf, int val)) {
   LIBC_INLINE_ASM("mov %1, %0\n\t" : "=r"(rsp) : "m"(buf->rsp) :);
   LIBC_INLINE_ASM("jmp *%0\n\t" : : "m"(buf->rip));
 }
+#endif
 
 } // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/setjmp/x86_64/setjmp.cpp b/libc/src/setjmp/x86_64/setjmp.cpp
index f6e82642edd7da..90532c5654b33b 100644
--- a/libc/src/setjmp/x86_64/setjmp.cpp
+++ b/libc/src/setjmp/x86_64/setjmp.cpp
@@ -11,12 +11,40 @@
 #include "src/__support/macros/config.h"
 #include "src/setjmp/setjmp_impl.h"
 
-#if !defined(LIBC_TARGET_ARCH_IS_X86_64)
+#if !defined(LIBC_TARGET_ARCH_IS_X86)
 #error "Invalid file include"
 #endif
 
 namespace LIBC_NAMESPACE_DECL {
 
+#ifdef __i386__
+[[gnu::naked]]
+LLVM_LIBC_FUNCTION(int, setjmp, (jmp_buf buf)) {
+  asm(R"(
+      mov 4(%%esp), %%eax
+
+      mov %%ebx, %c[ebx](%%eax)
+      mov %%esi, %c[esi](%%eax)
+      mov %%edi, %c[edi](%%eax)
+      mov %%ebp, %c[ebp](%%eax)
+
+      lea 4(%%esp), %%ecx
+      mov %%ecx, %c[esp](%%eax)
+
+      mov (%%esp), %%ecx
+      mov %%ecx, %c[eip](%%eax)
+
+      xorl %%eax, %%eax
+      retl)" ::
+      [ebx] "i"(offsetof(__jmp_buf, ebx)),
+      [esi] "i"(offsetof(__jmp_buf, esi)),
+      [edi] "i"(offsetof(__jmp_buf, edi)),
+      [ebp] "i"(offsetof(__jmp_buf, ebp)),
+      [esp] "i"(offsetof(__jmp_buf, esp)),
+      [eip] "i"(offsetof(__jmp_buf, eip))
+      : "eax", "ecx");
+}
+#else
 [[gnu::naked]]
 LLVM_LIBC_FUNCTION(int, setjmp, (jmp_buf buf)) {
   asm(R"(
@@ -41,5 +69,6 @@ LLVM_LIBC_FUNCTION(int, setjmp, (jmp_buf buf)) {
       [rip] "i"(offsetof(__jmp_buf, rip))
       : "rax");
 }
+#endif
 
 } // namespace LIBC_NAMESPACE_DECL

Copy link

github-actions bot commented Oct 15, 2024

✅ With the latest revision this PR passed the C/C++ code formatter.

@nickdesaulniers
Copy link
Member Author

I'll land #112443 first, then revisit this in that style.

@nickdesaulniers nickdesaulniers marked this pull request as draft October 15, 2024 22:24
libc/src/setjmp/x86_64/longjmp.cpp Show resolved Hide resolved
libc/src/setjmp/x86_64/longjmp.cpp Outdated Show resolved Hide resolved
@nickdesaulniers nickdesaulniers marked this pull request as ready for review October 16, 2024 16:29
@nickdesaulniers
Copy link
Member Author

ok, I've converted longjmp to be a naked fn using offsetof. I'll send a patch to fix up x86_64 in a distinct PR. Ready for rereview.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants