]> sourceware.org Git - valgrind.git/commitdiff
Bug 369723 - __builtin_longjmp not supported in clang/llvm on Android arm64 target
authorPaul Floyd <pjfloyd@wanadoo.fr>
Thu, 22 Feb 2024 15:56:22 +0000 (16:56 +0100)
committerPaul Floyd <pjfloyd@wanadoo.fr>
Thu, 22 Feb 2024 15:56:22 +0000 (16:56 +0100)
Made the functions out-of-line, more like other platforms.

NEWS
coregrind/m_libcsetjmp.c
include/pub_tool_libcsetjmp.h

diff --git a/NEWS b/NEWS
index f0ec723c2869ca41ebd6e314a5ca58dc91afe1d7..0aa3d0eb385b443dad0a5fa4bf4293102878fec8 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -26,6 +26,7 @@ are not entered into bugzilla tend to get forgotten about or ignored.
 
 283429  ARM leak checking needs CLEAR_CALLER_SAVED_REGS
 281059  Cannot connect to Oracle using valgrind
+369723  __builtin_longjmp not supported in clang/llvm on Android arm64 target
 390269  unhandled amd64-darwin syscall: unix:464 (openat_nocancel)
 401284  False positive "Source and destination overlap in strncat"
 428364  Signals inside io_uring_enter not handled
index f53a22352854afc54f500c2983cbc70c12402ed4..aa1749032dc26928fd69f19b941fe991d080c480 100644 (file)
@@ -781,6 +781,112 @@ __asm__(
 );
 #endif /* VGP_s390x_linux */
 
+#if defined(__clang__) && (defined(VGP_arm64_linux) || defined(VGP_arm64_freebsd))
+
+// __builtin_setjmp is not implemented by the standard C library
+// used on Android in current llvm-based toolchains as of NDK r19.
+//
+// Here is a custom implementation of Valgrind's "minimal" setjmp
+// interface. Per the comment at the top of this file, we only need
+// to save integer registers.
+//
+// Per the Procedure Call Standard for the ARM 64-bit Architecture
+// document,
+// http://infocenter.arm.com/help/topic/com.arm.doc.ihi0055b/IHI0055B_aapcs64.pdf
+// Section 5.1.1. General-purpose registers:
+// >
+// > A subroutine invocation must preserve the contents of the
+// > registers r19-r29 and SP."
+//
+// We also need to save and restore r30, the link register, i.e.
+// the default destination that a 'ret' instruction branches to.
+//
+// Note that this document is phrased in terms of 'r' registers
+// (e.g. "r30") because it aims to be agnostic as to A64 vs A32
+// instruction sets, but here we are targeting the A64 instruction
+// set, so we are dealing with 'x' registers.
+
+
+
+__attribute__((returns_twice))
+UWord VG_MINIMAL_SETJMP(VG_MINIMAL_JMP_BUF(_env))
+{
+   asm volatile(
+                 // x9 is the first of the regular temporary registers
+                 // per the above-mentioned Procedule Call Standard document.
+                 // Use it as temporary to hold the value of SP, since str does
+                 // not accept SP as operand.
+      "  mov x9, sp                     \n"
+      // Store the general-purpose registers that we need to save
+      // per the above discussion.
+      // Note that x30 is the link register.
+      "  stp x19, x20, [%[_env], 0]     \n"
+      "  stp x21, x22, [%[_env], 0x10]  \n"
+      "  stp x23, x24, [%[_env], 0x20]  \n"
+      "  stp x25, x26, [%[_env], 0x30]  \n"
+      "  stp x27, x28, [%[_env], 0x40]  \n"
+      "  stp x29, x30, [%[_env], 0x50]  \n"
+      // Store the value of SP.
+      "  str x9,       [%[_env], 0x60]  \n"
+      :
+      // No outputs
+      :
+      // Inputs
+      [_env]"r"(_env)
+      :
+      // Clobbers.
+      // We have used x9 as a temporary
+      "x9",
+      // We have written to memory locations
+      "memory");
+
+          // Direct invokation of setjmp always returns 0.
+          // The pseudo returning of the value 1 as a return from longjmp
+          // is implemented in longjmp.
+   return 0;
+}
+
+__attribute__((noreturn))
+void VG_MINIMAL_LONGJMP(VG_MINIMAL_JMP_BUF(_env))
+{
+   asm volatile(
+                 // Loads to match the stores in the above setjmp implementation.
+      "  ldp x19, x20, [%[_env], 0]     \n"
+      "  ldp x21, x22, [%[_env], 0x10]  \n"
+      "  ldp x23, x24, [%[_env], 0x20]  \n"
+      "  ldp x25, x26, [%[_env], 0x30]  \n"
+      "  ldp x27, x28, [%[_env], 0x40]  \n"
+      "  ldp x29, x30, [%[_env], 0x50]  \n"
+      "  ldr x9,       [%[_env], 0x60]  \n"
+      "  mov sp, x9                     \n"
+      // return as setjmp for the second time, returning 1.
+      // Since we have loaded the link register x30 from the saved buffer
+      // that was set by the above setjmp implementation, the 'ret' instruction
+      // here is going to return to where setjmp was called.
+      // Per the setjmp/longjmp contract, that pseudo second returning
+      // of setjmp should return the value 1.
+      // x0 is holds the integer return value.
+      "  mov x0, 1                      \n"
+      "  ret                            \n"
+      :
+      // No outputs
+      :
+      // Inputs
+      [_env]"r"(_env)
+      :
+      // Clobbers.
+      // We have used x9 as a temporary
+      "x9");
+
+          // This statement is unreachable because the above asm statement
+          // unconditionally does a 'ret' instruction. The purpose of this
+          // statement is to silence clang warnings about this function returning
+          // while having the 'noreturn' attribute.
+   __builtin_unreachable();
+}
+
+#endif
+
 /*--------------------------------------------------------------------*/
 /*--- end                                                          ---*/
 /*--------------------------------------------------------------------*/
index a3a386f806ad4b8db4b4919b4fe38d7dbb866844..ee9e1dc8be90df568b213c4b9187ae49b5ecbe63 100644 (file)
@@ -134,6 +134,14 @@ UWord VG_MINIMAL_SETJMP(VG_MINIMAL_JMP_BUF(_env));
 __attribute__((noreturn))
 void  VG_MINIMAL_LONGJMP(VG_MINIMAL_JMP_BUF(_env));
 
+#elif defined(__clang__) && (defined(VGP_arm64_linux) || defined(VGP_arm64_freebsd))
+
+#define VG_MINIMAL_JMP_BUF(_name)        UWord _name [13]
+__attribute__((returns_twice))
+UWord VG_MINIMAL_SETJMP(VG_MINIMAL_JMP_BUF(_env));
+__attribute__((noreturn))
+void VG_MINIMAL_LONGJMP(VG_MINIMAL_JMP_BUF(_env));
+
 #else
 
 /* The default implementation. */
This page took 0.041198 seconds and 5 git commands to generate.