Repository navigation
Expand file tree
/
Copy pathsetjmp.h
More file actions
191 lines (164 loc) · 5.42 KB
/
Copy pathsetjmp.h
File metadata and controls
191 lines (164 loc) · 5.42 KB
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
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
/* Copyright (C) 2012 DJ Delorie, see COPYING.DJ for details */
/* Copyright (C) 2011 DJ Delorie, see COPYING.DJ for details */
/* Copyright (C) 2003 DJ Delorie, see COPYING.DJ for details */
/* Copyright (C) 2001 DJ Delorie, see COPYING.DJ for details */
/* Copyright (C) 1999 DJ Delorie, see COPYING.DJ for details */
/* Copyright (C) 1995 DJ Delorie, see COPYING.DJ for details */
#ifndef __dj_include_setjmp_h_
#define __dj_include_setjmp_h_
#ifdef __cplusplus
namespace std {
extern "C" {
#endif
#ifndef __dj_ENFORCE_ANSI_FREESTANDING
#if defined(__clang__) && defined(__aarch64__) && defined(__ANDROID__)
#define CUSTOM_SETJMP 1
#else
#define CUSTOM_SETJMP 0
#endif
#if CUSTOM_SETJMP
typedef unsigned long long int minimal_jmp_buf[14];
#else
typedef void *minimal_jmp_buf[5];
#endif
typedef struct __jmp_buf {
minimal_jmp_buf buf;
volatile int rc;
} jmp_buf[1];
#if CUSTOM_SETJMP
__attribute__((returns_twice,always_inline))
static inline int do_setjmp(minimal_jmp_buf _env)
{
long int ret;
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"
" adr x10, _out \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,PC.
" stp x9, x10, [%[_env], 0x60] \n"
" mov x0, 0 \n"
"_out: \n"
" mov %x[ret], x0 \n"
:
// Outputs
[ret]"=r"(ret)
:
// Inputs
[_env]"r"(_env)
:
// Clobbers.
// We have used x9 as a temporary
"x0","x1","x2","x3","x4","x5","x6","x7","x8","x9","x10",
"x11","x12","x13","x14","x15","x16","x17",
// 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 ret;
}
__attribute__((noreturn))
static inline void do_longjmp(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"
" ldp x9, x10, [%[_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"
" br x10 \n"
:
// No outputs
:
// Inputs
[_env]"r"(_env)
:
// Clobbers.
// We have used x9 as a temporary
"x0","x9","x10");
// 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
__attribute__((noreturn))
static inline void longjmp(jmp_buf env, int val)
{
env[0].rc = val;
#if CUSTOM_SETJMP
do_longjmp(env[0].buf);
#else
__builtin_longjmp(env[0].buf, 1);
#endif
}
#if CUSTOM_SETJMP
#define setjmp(env) ( \
{ \
int _rc = do_setjmp(env[0].buf); \
(_rc ? env[0].rc : 0); \
})
#else
#define setjmp(env) ( \
{ \
int _rc = __builtin_setjmp(env[0].buf); \
(_rc ? env[0].rc : 0); \
})
#endif
#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) \
|| !defined(__STRICT_ANSI__) || defined(__cplusplus)
#endif /* (__STDC_VERSION__ >= 199901L) || !__STRICT_ANSI__ */
#ifndef __STRICT_ANSI__
#if 0
typedef jmp_buf sigjmp_buf;
int sigsetjmp(sigjmp_buf env, int savemask);
void siglongjmp(sigjmp_buf env, int val) __attribute__((__noreturn__));
#endif
#ifndef _POSIX_SOURCE
#endif /* !_POSIX_SOURCE */
#endif /* !__STRICT_ANSI__ */
#endif /* !__dj_ENFORCE_ANSI_FREESTANDING */
#ifndef __dj_ENFORCE_FUNCTION_CALLS
#endif /* !__dj_ENFORCE_FUNCTION_CALLS */
#ifdef __cplusplus
}
}
#endif
#endif /* !__dj_include_setjmp_h_ */
#if defined(__cplusplus) && !defined(__dj_ENFORCE_ANSI_FREESTANDING)
using std::setjmp;
#ifndef __dj_via_cplusplus_header_
using std::longjmp;
using std::jmp_buf;
#ifndef __STRICT_ANSI__
using std::sigjmp_buf;
using std::sigsetjmp;
using std::siglongjmp;
#endif /* !__STRICT_ANSI__ */
#endif /* !__dj_via_cplusplus_header_ */
#endif /* __cplusplus && !__dj_ENFORCE_ANSI_FREESTANDING */