forked from nihui/valgrind-android
-
Notifications
You must be signed in to change notification settings - Fork 0
/
valgrind-3.16.1-ndk-r19-minimal_setjmp.patch
124 lines (120 loc) · 4.46 KB
/
valgrind-3.16.1-ndk-r19-minimal_setjmp.patch
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
commit cebc9a058d2048e8233ee3eeb510e19b8772909f
Author: Benoit Jacob <benoitjacob@google.com>
Date: Wed May 29 21:15:53 2019 -0400
Implement VG_MINIMAL_SETJMP in inline assembly on Android/arm64
because __builtin_setjmp is not implemented in current clang
toolchains in current Android NDK.
diff --git a/include/pub_tool_libcsetjmp.h b/include/pub_tool_libcsetjmp.h
index 681450cef..ccdf295df 100644
--- a/include/pub_tool_libcsetjmp.h
+++ b/include/pub_tool_libcsetjmp.h
@@ -126,6 +126,111 @@ UWord VG_MINIMAL_SETJMP(VG_MINIMAL_JMP_BUF(_env));
__attribute__((noreturn))
void VG_MINIMAL_LONGJMP(VG_MINIMAL_JMP_BUF(_env));
+#elif defined __aarch64__ && defined __ANDROID__
+
+// __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.
+
+
+#define VG_MINIMAL_JMP_BUF(_name) UWord _name [13]
+
+__attribute__((returns_twice))
+inline 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))
+inline 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();
+}
+
#else
/* The default implementation. */