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