1 // RUN: rm -rf %t
2 // RUN: mkdir %t
3 // RUN: %cheri_purecap_cc1 %s -emit-obj -o %t/libc-stubs.o -DLIBC_STUBS
4 // RUN: %cheri_purecap_cc1 %s -emit-obj -o %t/libc-exit.o -DLIBC_EXIT
5 // RUN: llvm-ar cq %t/libc.a %t/libc-stubs.o %t/libc-exit.o
6 // RUN: %cheri_purecap_cc1 %s -emit-obj -o %t/libthr-table.o -DLIBTHR_TABLE
7 // RUN: %cheri_purecap_cc1 %s -emit-obj -o %t/libthr-impls.o -DLIBTHR_IMPLS -O2
8 // RUN: llvm-ar cq %t/libthr.a %t/libthr-table.o %t/libthr-impls.o
9
10 // RUN: %cheri_purecap_cc1 %s -emit-obj -o %t/main.o -DEXE
11 // RUN: %cheri_purecap_cc1 %s -emit-obj -o %t/main.o -DEXE
12 // RUN: ld.lld --verbose -pie %t/main.o -o %t/thr-first.exe %t/libthr.a %t/libc.a
13 // RUN: ld.lld --verbose -pie %t/main.o -o %t/libc-first.exe %t/libc.a %t/libthr.a
14
15 // RUN: llvm-objdump -t %t/thr-first.exe | FileCheck %s --check-prefix USES-LIBTHR-SYMBOLS
16 // RUN: llvm-objdump -t %t/libc-first.exe | FileCheck %s --check-prefix USES-LIBC-SYMBOLS
17
18 // PTHREAD symbols are a single instruction in the libthr version:
19
20 // USES-LIBTHR-SYMBOLS: SYMBOL TABLE:
21 // USES-LIBTHR-SYMBOLS-DAG: w F .text 0000000000000004 pthread_exit
22 // USES-LIBTHR-SYMBOLS-DAG: g F .text 0000000000000004 _pthread_exit
23 // USES-LIBTHR-SYMBOLS-DAG: g F .text 0000000000000004 _pthread_join
24 // USES-LIBTHR-SYMBOLS-DAG: g F .text 0000000000000004 _pthread_kill
25 // USES-LIBTHR-SYMBOLS-DAG: g F .text 0000000000000004 _pthread_once
26 // USES-LIBTHR-SYMBOLS-DAG: w F .text 0000000000000004 pthread_join
27 // USES-LIBTHR-SYMBOLS-DAG: w F .text 0000000000000004 pthread_kill
28 // USES-LIBTHR-SYMBOLS-DAG: w F .text 0000000000000004 pthread_once
29
30 // Static linking of libc and libthr must be done in the right order otherwise we get infinite loops
31 // FIXME: can we warn about this?
32 // USES-LIBC-SYMBOLS: SYMBOL TABLE:
33 // USES-LIBC-SYMBOLS: l F .text 00000000000000{{50|54}} pthread_exit
34
35
36 #ifndef EXE
37 // namespace.h:
38 #define pthread_exit _pthread_exit
39 #define pthread_join _pthread_join
40 #define pthread_kill _pthread_kill
41 #define pthread_once _pthread_once
42 #endif
43
44 /*
45 * Indexes into the pthread jump table.
46 *
47 * Warning! If you change this type, you must also change the threads
48 * libraries that reference it (libc_r, libpthread).
49 */
50 typedef enum {
51 PJT_EXIT,
52 PJT_JOIN,
53 PJT_KILL,
54 PJT_ONCE,
55 PJT_MAX
56 } pjt_index_t;
57
58 #define __used __attribute__((used))
59 #define __CONCAT1(x,y) x ## y
60 #define __CONCAT(x,y) __CONCAT1(x,y)
61 #define __STRING(x) #x /* stringify without expanding x */
62 #define __XSTRING(x) __STRING(x) /* expand x, then stringify */
63 #ifdef __STDC__
64 #define __weak_reference(sym,alias) \
65 __asm__(".weak " #alias); \
66 __asm__(".equ " #alias ", " #sym)
67 #define __warn_references(sym,msg) \
68 __asm__(".section .gnu.warning." #sym); \
69 __asm__(".asciz \"" msg "\""); \
70 __asm__(".previous")
71 #define __sym_compat(sym,impl,verid) \
72 __asm__(".symver " #impl ", " #sym "@" #verid)
73 #define __sym_default(sym,impl,verid) \
74 __asm__(".symver " #impl ", " #sym "@@@" #verid)
75 #else
76 #define __weak_reference(sym,alias) \
77 __asm__(".weak alias"); \
78 __asm__(".equ alias, sym")
79 #define __warn_references(sym,msg) \
80 __asm__(".section .gnu.warning.sym"); \
81 __asm__(".asciz \"msg\""); \
82 __asm__(".previous")
83 #define __sym_compat(sym,impl,verid) \
84 __asm__(".symver impl, sym@verid")
85 #define __sym_default(impl,sym,verid) \
86 __asm__(".symver impl, sym@@@verid")
87 #endif /* __STDC__ */
88
89 #define NULL ((void*)0)
90 #define ENOSYS 44
91
92 typedef int (*pthread_func_t)(void);
93 typedef pthread_func_t pthread_func_entry_t[2];
94 typedef __UINT32_TYPE__ __uint32_t;
95
96 extern pthread_func_entry_t __thr_jtable[];
97
98 struct pthread; /* XXX */
99 typedef struct pthread *__pthread_t;
100 typedef __pthread_t pthread_t;
101 #define _SIG_WORDS 4
102 #define _SIG_MAXSIG 128
103 #define _SIG_IDX(sig) ((sig) - 1)
104 #define _SIG_WORD(sig) (_SIG_IDX(sig) >> 5)
105 #define _SIG_BIT(sig) (1 << (_SIG_IDX(sig) & 31))
106 #define _SIG_VALID(sig) ((sig) <= _SIG_MAXSIG && (sig) > 0)
107 typedef struct __sigset {
108 __uint32_t __bits[_SIG_WORDS];
109 } __sigset_t;
110 typedef __sigset_t sigset_t;
111
112
113 void pthread_exit(void *) __attribute__((noreturn));
114 int pthread_kill(__pthread_t, int);
115 int pthread_join(pthread_t, void **);
116 typedef struct pthread_once pthread_once_t;
117 int pthread_once(pthread_once_t *, void (*) (void));
118
119 int pthread_sigmask(int, const __sigset_t * __restrict,
120 __sigset_t * __restrict);
121
122 void exit(int status) __attribute__((noreturn));
123
124
125 #ifndef EXE
126 // un-namespace.h:
127 #undef pthread_exit
128 #undef pthread_join
129 #undef pthread_kill
130 #undef pthread_once
131 #endif
132
133 #ifdef LIBC_STUBS
134 /*
135 * Weak symbols: All libc internal usage of these functions should
136 * use the weak symbol versions (_pthread_XXX). If libpthread is
137 * linked, it will override these functions with (non-weak) routines.
138 * The _pthread_XXX functions are provided solely for internal libc
139 * usage to avoid unwanted cancellation points and to differentiate
140 * between application locks and libc locks (threads holding the
141 * latter can't be allowed to exit/terminate).
142 */
143
144 /* Define a null pthread structure just to satisfy _pthread_self. */
145 struct pthread {
146 };
147
148 static struct pthread main_thread;
149
150 static int stub_main(void);
151 static void *stub_null(void);
152 static struct pthread *stub_self(void);
153 static int stub_zero(void);
154 static int stub_fail(void);
155 static int stub_true(void);
156 static void stub_exit(void);
157
158 #define PJT_DUAL_ENTRY(entry) \
159 (pthread_func_t)entry, (pthread_func_t)entry
160
161 pthread_func_entry_t __thr_jtable[PJT_MAX] = {
162 {PJT_DUAL_ENTRY(stub_exit)}, /* PJT_EXIT */
163 {PJT_DUAL_ENTRY(stub_zero)}, /* PJT_JOIN */
164 {PJT_DUAL_ENTRY(stub_zero)}, /* PJT_KILL */
165 {PJT_DUAL_ENTRY(stub_fail)}, /* PJT_ONCE */
166 };
167
168 /*
169 * Weak aliases for exported (pthread_*) and internal (_pthread_*) routines.
170 */
171 #define WEAK_REF(sym, alias) __weak_reference(sym, alias)
172
173 #define FUNC_TYPE(name) __CONCAT(name, _func_t)
174 #define FUNC_INT(name) __CONCAT(name, _int)
175 #define FUNC_EXP(name) __CONCAT(name, _exp)
176
177 #define STUB_FUNC(name, idx, ret) \
178 static ret FUNC_EXP(name)(void) __used; \
179 static ret FUNC_INT(name)(void) __used; \
180 WEAK_REF(FUNC_EXP(name), name); \
181 WEAK_REF(FUNC_INT(name), __CONCAT(_, name)); \
182 typedef ret (*FUNC_TYPE(name))(void); \
183 static ret FUNC_EXP(name)(void) \
184 { \
185 FUNC_TYPE(name) func; \
186 func = (FUNC_TYPE(name))__thr_jtable[idx][0]; \
187 return (func()); \
188 } \
189 static ret FUNC_INT(name)(void) \
190 { \
191 FUNC_TYPE(name) func; \
192 func = (FUNC_TYPE(name))__thr_jtable[idx][1]; \
193 return (func()); \
194 }
195
196 #define STUB_FUNC1(name, idx, ret, p0_type) \
197 static ret FUNC_EXP(name)(p0_type) __used; \
198 static ret FUNC_INT(name)(p0_type) __used; \
199 WEAK_REF(FUNC_EXP(name), name); \
200 WEAK_REF(FUNC_INT(name), __CONCAT(_, name)); \
201 typedef ret (*FUNC_TYPE(name))(p0_type); \
202 static ret FUNC_EXP(name)(p0_type p0) \
203 { \
204 FUNC_TYPE(name) func; \
205 func = (FUNC_TYPE(name))__thr_jtable[idx][0]; \
206 return (func(p0)); \
207 } \
208 static ret FUNC_INT(name)(p0_type p0) \
209 { \
210 FUNC_TYPE(name) func; \
211 func = (FUNC_TYPE(name))__thr_jtable[idx][1]; \
212 return (func(p0)); \
213 }
214
215 #define STUB_FUNC2(name, idx, ret, p0_type, p1_type) \
216 static ret FUNC_EXP(name)(p0_type, p1_type) __used; \
217 static ret FUNC_INT(name)(p0_type, p1_type) __used; \
218 WEAK_REF(FUNC_EXP(name), name); \
219 WEAK_REF(FUNC_INT(name), __CONCAT(_, name)); \
220 typedef ret (*FUNC_TYPE(name))(p0_type, p1_type); \
221 static ret FUNC_EXP(name)(p0_type p0, p1_type p1) \
222 { \
223 FUNC_TYPE(name) func; \
224 func = (FUNC_TYPE(name))__thr_jtable[idx][0]; \
225 return (func(p0, p1)); \
226 } \
227 static ret FUNC_INT(name)(p0_type p0, p1_type p1) \
228 { \
229 FUNC_TYPE(name) func; \
230 func = (FUNC_TYPE(name))__thr_jtable[idx][1]; \
231 return (func(p0, p1)); \
232 }
233
234 #define STUB_FUNC3(name, idx, ret, p0_type, p1_type, p2_type) \
235 static ret FUNC_EXP(name)(p0_type, p1_type, p2_type) __used; \
236 static ret FUNC_INT(name)(p0_type, p1_type, p2_type) __used; \
237 WEAK_REF(FUNC_EXP(name), name); \
238 WEAK_REF(FUNC_INT(name), __CONCAT(_, name)); \
239 typedef ret (*FUNC_TYPE(name))(p0_type, p1_type, p2_type); \
240 static ret FUNC_EXP(name)(p0_type p0, p1_type p1, p2_type p2) \
241 { \
242 FUNC_TYPE(name) func; \
243 func = (FUNC_TYPE(name))__thr_jtable[idx][0]; \
244 return (func(p0, p1, p2)); \
245 } \
246 static ret FUNC_INT(name)(p0_type p0, p1_type p1, p2_type p2) \
247 { \
248 FUNC_TYPE(name) func; \
249 func = (FUNC_TYPE(name))__thr_jtable[idx][1]; \
250 return (func(p0, p1, p2)); \
251 }
STUB_FUNC2(pthread_once,PJT_ONCE,int,void *,void *)252 STUB_FUNC2(pthread_once, PJT_ONCE, int, void *, void *)
253 STUB_FUNC1(pthread_exit, PJT_EXIT, void, void *)
254 STUB_FUNC2(pthread_join, PJT_JOIN, int, void *, void *)
255 STUB_FUNC2(pthread_kill, PJT_KILL, int, void *, int)
256
257 static int
258 stub_zero(void)
259 {
260 return (0);
261 }
262
263 static void *
stub_null(void)264 stub_null(void)
265 {
266 return (NULL);
267 }
268
269 static struct pthread *
stub_self(void)270 stub_self(void)
271 {
272 return (&main_thread);
273 }
274
275 static int
stub_fail(void)276 stub_fail(void)
277 {
278 return (ENOSYS);
279 }
280
281 static int
stub_main(void)282 stub_main(void)
283 {
284 return (-1);
285 }
286
287 static int
stub_true(void)288 stub_true(void)
289 {
290 return (1);
291 }
292
293 static void
stub_exit(void)294 stub_exit(void)
295 {
296 exit(0);
297 }
298
299 int link_libc_table = 0;
300
301 #endif
302
303 #ifdef LIBC_EXIT
304 void
exit(int status)305 exit(int status)
306 {
307 /* Ensure that the auto-initialization routine is linked in: */
308 extern int _thread_autoinit_dummy_decl;
309
310 _thread_autoinit_dummy_decl = 1;
311
312 __builtin_trap();
313 }
314 #endif
315
316 #ifdef LIBTHR_TABLE
317 # define STATIC_LIB_REQUIRE(name) __asm (".globl " #name)
318 /*
319 * All weak references used within libc should be in this table.
320 * This is so that static libraries will work.
321 */
322 STATIC_LIB_REQUIRE(_thread_init_hack);
323
324 /*
325 * These are needed when linking statically. All references within
326 * libgcc (and in the future libc) to these routines are weak, but
327 * if they are not (strongly) referenced by the application or other
328 * libraries, then the actual functions will not be loaded.
329 */
330 STATIC_LIB_REQUIRE(_pthread_once);
331 STATIC_LIB_REQUIRE(_pthread_create);
332
333 extern typeof(_pthread_exit) libthr_pthread_exit;
334 extern typeof(_pthread_join) libthr_pthread_join;
335 extern typeof(_pthread_kill) libthr_pthread_kill;
336 extern typeof(_pthread_once) libthr_pthread_once;
337
338 #define DUAL_ENTRY(entry) \
339 (pthread_func_t)libthr##entry, (pthread_func_t)libthr##entry
340
341 // FIXME: this seems broken in lld -> it resolves to the weak alias stub functions!!!!
342 static pthread_func_t jmp_table[][2] = {
343 {DUAL_ENTRY(_pthread_exit)}, /* PJT_EXIT */
344 {DUAL_ENTRY(_pthread_join)}, /* PJT_JOIN */
345 {DUAL_ENTRY(_pthread_kill)}, /* PJT_KILL */
346 {DUAL_ENTRY(_pthread_once)}, /* PJT_ONCE */
347 };
348
349 static int init_once = 0;
350
351 /*
352 * For the shared version of the threads library, the above is sufficient.
353 * But for the archive version of the library, we need a little bit more.
354 * Namely, we must arrange for this particular module to be pulled in from
355 * the archive library at link time. To accomplish that, we define and
356 * initialize a variable, "_thread_autoinit_dummy_decl". This variable is
357 * referenced (as an extern) from libc/stdlib/exit.c. This will always
358 * create a need for this module, ensuring that it is present in the
359 * executable.
360 */
361 extern int _thread_autoinit_dummy_decl;
362 int _thread_autoinit_dummy_decl = 0;
363
364 void
_libpthread_init(struct pthread * curthread)365 _libpthread_init(struct pthread *curthread)
366 {
367 if (sizeof(jmp_table) != sizeof(pthread_func_t) * PJT_MAX * 2)
368 __builtin_trap();
369 __builtin_memcpy(__thr_jtable, jmp_table, sizeof(jmp_table));
370 // __thr_interpose_libc();
371 }
372
373 #endif
374
375
376 #ifdef LIBTHR_IMPLS
377 #define __strong_reference(sym,aliassym) \
378 extern __typeof (sym) aliassym __attribute__ ((__alias__ (#sym)))
379
380 __weak_reference(_pthread_exit, pthread_exit);
_pthread_exit(void * status)381 void _pthread_exit(void *status) { __asm__ volatile ("li $zero, 0x1234"); __builtin_unreachable(); }
382 __strong_reference(_pthread_exit, libthr_pthread_exit);
383
384 __weak_reference(_pthread_kill, pthread_kill);
_pthread_kill(pthread_t pthread,int sig)385 int _pthread_kill(pthread_t pthread, int sig) { __asm__ volatile ("li $zero, 0x1235"); __builtin_unreachable(); }
386 __strong_reference(_pthread_kill, libthr_pthread_kill);
387
388 __weak_reference(_pthread_once, pthread_once);
_pthread_once(pthread_once_t * once_control,void (* init_routine)(void))389 int _pthread_once(pthread_once_t *once_control, void (*init_routine) (void)) { __asm__ volatile ("li $zero, 0x1236"); __builtin_unreachable(); }
390 __strong_reference(_pthread_once, libthr_pthread_once);
391
392 __weak_reference(_pthread_join, pthread_join);
_pthread_join(pthread_t pthread,void ** thread_return)393 int _pthread_join(pthread_t pthread, void **thread_return) { __asm__ volatile ("li $zero, 0x1237"); __builtin_unreachable(); }
394 __strong_reference(_pthread_join, libthr_pthread_join);
395
396 #endif
397
398 #ifdef EXE
399
__start(void)400 void __start(void) {
401 int status;
402 extern int link_libc_table;
403 link_libc_table = 0;
404 pthread_exit(&status);
405 exit(1);
406
407 }
408 #endif
409