1/* libunwind - a platform-independent unwind library
2   Copyright (C) 2004-2005 Hewlett-Packard Co
3	Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
4
5This file is part of libunwind.
6
7Permission is hereby granted, free of charge, to any person obtaining
8a copy of this software and associated documentation files (the
9"Software"), to deal in the Software without restriction, including
10without limitation the rights to use, copy, modify, merge, publish,
11distribute, sublicense, and/or sell copies of the Software, and to
12permit persons to whom the Software is furnished to do so, subject to
13the following conditions:
14
15The above copyright notice and this permission notice shall be
16included in all copies or substantial portions of the Software.
17
18THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
22LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */
25
26	.text
27
28#define CALL_NEXT_PTR(gp_save_reg, arg0, arg1)				\
29	ld8 r2 = [arg0], 8;;	/* read the next function pointer */	\
30	ld8 r3 = [r2], 8;;	/* read the function's entry-point */	\
31	ld8 r2 = [r2];;		/* read the function's gp */		\
32	mov b6 = r3;							\
33	mov gp_save_reg = gp;						\
34	mov out0 = arg0;						\
35	mov out1 = arg1;						\
36	mov gp = r2;							\
37	br.call.sptk.many rp = b6;;					\
38	mov gp = gp_save_reg
39
40#define CALL_NEXT(gp_save_reg)	CALL_NEXT_PTR(gp_save_reg, in0, in1)
41
42#define LOAD_VAL(reg)				\
43	ld8 reg = [in1], 8;;			\
44	tbit.nz p15, p0 = reg, 0;;		\
45(p15)	ld8.s reg = [r0]
46
47
48	.global flushrs
49	.proc flushrs
50flushrs:
51	flushrs;;
52	br.ret.sptk.many rp
53	.endp flushrs
54
55	/* Save r4-r7 into stacked registers, load them up with the
56	   values passed via the pointer in in1 and then call the
57	   function passed via the pointer in in0.  */
58
59	.global save_static_to_stacked
60	.proc save_static_to_stacked
61save_static_to_stacked:
62	.prologue
63	.regstk 2, 7, 2, 0
64	.save ar.pfs, loc0
65	alloc loc0 = ar.pfs, 2, 7, 2, 0
66	.save rp, loc1
67	mov loc1 = rp
68	.spillreg r4, loc2
69	mov loc2 = r4
70	.spillreg r5, loc3
71	mov loc3 = r5
72	.spillreg r6, loc4
73	mov loc4 = r6
74	.spillreg r7, loc5
75	mov loc5 = r7
76	.body
77	LOAD_VAL(r4)
78	LOAD_VAL(r5)
79	LOAD_VAL(r6)
80	LOAD_VAL(r7)
81	CALL_NEXT(loc6)
82
83	mov r4 = loc2
84	mov r5 = loc3
85	mov r6 = loc4
86	mov r7 = loc5
87
88	mov ar.pfs = loc0
89	mov rp = loc1
90	br.ret.sptk.many rp
91	.endp save_static_to_stacked
92
93	/* Save f2 to the memory stack, save r4 to f2, then load
94	   r4 with the value passed via in1 and call the function
95	   passed via in0.  */
96
97	.global save_static_to_fr
98	.proc save_static_to_fr
99save_static_to_fr:
100	.prologue
101	.regstk 2, 3, 2, 0
102	.save ar.pfs, loc0
103	alloc loc0 = ar.pfs, 2, 3, 2, 0
104	.save rp, loc1
105	mov loc1 = rp
106	.fframe 16
107	.spillpsp f2, 0
108	stf.spill [sp] = f2, -16
109	.spillreg r4, f2
110	setf.sig f2 = r4
111
112	.body
113
114	ld8 r4 = [in1], 8;;
115	tbit.nz p6, p0 = r4, 0;;
116(p6)	ld8.s r4 = [r0]
117
118	CALL_NEXT(loc2)
119
120	getf.sig r4 = f2		// restore r4
121	.restore sp
122	add sp = 16, sp;;
123	ldf.fill f2 = [sp]		// restore r2
124
125	mov ar.pfs = loc0
126	mov rp = loc1
127	br.ret.sptk.many rp
128	.endp save_static_to_fr
129
130	/* If r4 is not a NaT, save b3 to a stacked register and
131	   then save r4 in b3.  The non-NaTness of r4 is saved in
132	   p1.  */
133
134	.global save_static_to_br
135	.proc save_static_to_br
136save_static_to_br:
137	.prologue
138	.regstk 2, 6, 2, 0
139	.save ar.pfs, loc0
140	alloc loc0 = ar.pfs, 2, 6, 2, 0
141	.save rp, loc1
142	mov loc1 = rp
143
144	.save pr, loc2
145	mov loc2 = pr			// save predicates
146
147	.spillreg b3, loc3
148	mov loc3 = b3
149
150	tnat.z p1, p2 = r4;;
151	.spillreg.p p1, r4, b3
152(p1)	mov b3 = r4
153	.spillreg.p p2, r4, loc4
154(p2)	mov loc4 = r4
155
156	.body
157
158	LOAD_VAL(r4)
159	CALL_NEXT(loc5)
160
161	.pred.rel.mutex p1, p2
162(p1)	mov r4 = b3			// restore r4
163(p2)	mov r4 = loc4
164
165	mov ar.pfs = loc0
166	mov rp = loc1
167	mov pr = loc2, -1
168	mov b3 = loc3			// restore b3
169	br.ret.sptk.many rp
170	.endp save_static_to_br
171
172	/* Spill r4 into memory and then save r5 in r4.  */
173
174	.global save_static_to_mem
175	.proc save_static_to_mem
176save_static_to_mem:
177	.prologue
178	.regstk 2, 4, 2, 0
179	.save ar.pfs, loc0
180	alloc loc0 = ar.pfs, 2, 4, 2, 0
181	.save rp, loc1
182	mov loc1 = rp
183	.save ar.unat, loc2
184	mov loc2 = ar.unat
185
186	.fframe 16
187	.spillpsp r4, 0
188	st8.spill [sp] = r4, -16
189
190	.spillreg r5, r4
191	mov r4 = r5
192
193	.body
194
195	LOAD_VAL(r5)
196	CALL_NEXT(loc3)
197
198	mov r5 = r4			// restore r5
199	.restore sp
200	add sp = 16, sp;;
201	ld8.fill r4 = [sp]		// restore r4
202
203	mov ar.pfs = loc0
204	mov rp = loc1
205	mov ar.unat = loc2		// restore ar.unat
206	br.ret.sptk.many rp
207	.endp save_static_to_mem
208
209	/* Spill r6 into memory and save primary ar.unat in a register.  */
210
211	.global save_static_to_mem2
212	.proc save_static_to_mem2
213save_static_to_mem2:
214	.prologue
215	.regstk 2, 5, 2, 0
216	.save ar.pfs, loc0
217	alloc loc0 = ar.pfs, 2, 5, 2, 0
218	.save rp, loc1
219	mov loc1 = rp
220	.save ar.unat, loc2
221	mov loc2 = ar.unat
222
223	.fframe 16
224	.spillpsp r6, 0
225	st8.spill [sp] = r6, -16;;
226	.save @priunat, loc3
227	mov loc3 = ar.unat
228	mov ar.unat = 0			// trash ar.unat
229
230	.body
231
232	LOAD_VAL(r6)
233	CALL_NEXT(loc4)
234
235	mov ar.unat = loc3		// restore primary UNaT
236	.restore sp
237	add sp = 16, sp;;
238	ld8.fill r6 = [sp]		// restore r6
239
240	mov ar.pfs = loc0
241	mov rp = loc1
242	mov ar.unat = loc2		// restore ar.unat
243	br.ret.sptk.many rp
244	.endp save_static_to_mem2
245
246	/* Spill r6 into memory and save primary ar.unat in memory.  */
247
248	.global save_static_to_mem3
249	.proc save_static_to_mem3
250save_static_to_mem3:
251	.prologue
252	.regstk 2, 5, 2, 0
253	.save ar.pfs, loc0
254	alloc loc0 = ar.pfs, 2, 5, 2, 0
255	.save rp, loc1
256	mov loc1 = rp
257	.save ar.unat, loc2
258	mov loc2 = ar.unat
259
260	add r2 = 8, sp
261	.fframe 16
262	.spillpsp r6, 0
263	st8.spill [sp] = r6, -16;;
264	mov r3 = ar.unat;;
265	.savepsp @priunat, -8
266	st8 [r2] = r3
267	mov ar.unat = 0			// trash ar.unat
268
269	.body
270
271	LOAD_VAL(r6)
272	CALL_NEXT(loc4)
273
274	add r2 = 24, sp;;
275	ld8 r3 = [r2];;
276	mov ar.unat = r3		// restore primary UNaT
277	.restore sp
278	add sp = 16, sp;;
279	ld8.fill r6 = [sp]		// restore r6
280
281	mov ar.pfs = loc0
282	mov rp = loc1
283	mov ar.unat = loc2		// restore ar.unat
284	br.ret.sptk.many rp
285	.endp save_static_to_mem3
286
287	/* Spill r6 into memory and save primary ar.unat in register,
288	   then in memory.  */
289
290	.global save_static_to_mem4
291	.proc save_static_to_mem4
292save_static_to_mem4:
293	.prologue
294	.regstk 2, 5, 2, 0
295	.save ar.pfs, loc0
296	alloc loc0 = ar.pfs, 2, 5, 2, 0
297	.save rp, loc1
298	mov loc1 = rp
299	.save ar.unat, loc2
300	mov loc2 = ar.unat
301
302	add r2 = 8, sp
303	.fframe 16
304	.spillpsp r6, 0
305	st8.spill [sp] = r6, -16;;
306	.save @priunat, r3
307	mov r3 = ar.unat;;
308	mov ar.unat = 0			// trash ar.unat
309	.savepsp @priunat, -8
310	st8 [r2] = r3
311	mov r3 = r0			// trash register pri UNaT location
312	.body
313
314	LOAD_VAL(r6)
315	CALL_NEXT(loc4)
316
317	add r2 = 24, sp;;
318	ld8 r3 = [r2];;
319	mov ar.unat = r3		// restore primary UNaT
320	.restore sp
321	add sp = 16, sp;;
322	ld8.fill r6 = [sp]		// restore r6
323
324	mov ar.pfs = loc0
325	mov rp = loc1
326	mov ar.unat = loc2		// restore ar.unat
327	br.ret.sptk.many rp
328	.endp save_static_to_mem4
329
330	/* Spill r6 into memory and save primary ar.unat in register,
331	   then in memory.  */
332
333	.global save_static_to_mem5
334	.proc save_static_to_mem5
335save_static_to_mem5:
336	.prologue
337	.regstk 2, 5, 2, 0
338	.save ar.pfs, loc0
339	alloc loc0 = ar.pfs, 2, 5, 2, 0
340	.save rp, loc1
341	mov loc1 = rp
342	.save ar.unat, loc2
343	mov loc2 = ar.unat
344
345	add r2 = 8, sp
346	.fframe 16
347	.spillpsp r6, 0
348	st8.spill [sp] = r6, -16;;
349	mov r3 = ar.unat;;
350	mov ar.unat = 0			// trash ar.unat
351	.savepsp @priunat, -8
352	st8 [r2] = r3
353	.save @priunat, loc3
354	mov loc3 = r3
355	st8 [r2] = r0			// trash memory pri UNaT location
356	.body
357
358	LOAD_VAL(r6)
359	CALL_NEXT(loc4)
360
361	add r2 = 24, sp;;
362	ld8 r3 = [r2];;
363	mov ar.unat = loc3		// restore primary UNaT
364	.restore sp
365	add sp = 16, sp;;
366	ld8.fill r6 = [sp]		// restore r6
367
368	mov ar.pfs = loc0
369	mov rp = loc1
370	mov ar.unat = loc2		// restore ar.unat
371	br.ret.sptk.many rp
372	.endp save_static_to_mem5
373
374	/* Save r4-r7 to various scratch registers, then trigger
375	   a segfault.  */
376
377	.global save_static_to_scratch
378	.proc save_static_to_scratch
379save_static_to_scratch:
380	.prologue
381
382	.spillreg r4, r16
383	mov r16 = r4			// save r4 in r16
384	tnat.nz p6, p7 = r5;;
385	.spillreg.p p6, r5, f31
386(p6)	setf.sig f31 = r5		// save r5 in f31 if it's a NaT
387	.spillreg.p p7, r5, b6
388(p7)	mov b6 = r5			//         in  b6 if it not
389	.spillreg r6, f32
390	setf.sig f32 = r6		// save r6 in f32 (fph partition)
391	.spillsp r7, 0
392	st8.spill [sp] = r7		// save r7 in the scratch stack space
393	.spillreg f4, f6
394	mov f6 = f4;;
395	.body
396
397	ld8 r2 = [in1]
398	;;
399	mov ar.ec = r2
400
401	LOAD_VAL(r4)
402	LOAD_VAL(r5)
403	LOAD_VAL(r6)
404	LOAD_VAL(r7)
405	setf.sig f4 = r4
406
407	/* Now force a SIGSEGV.  Make sure the ld8 is at the beginning of a
408	   bundle, so the signal-handler can skip over it simply by
409	   incrementing the IP.  */
410	{
411		.mmi
412		ld8 r2 = [r0]
413		nop.m 0
414		nop.i 0 ;;
415	}
416
417	mov f4 = f6
418	mov r4 = r16
419	.pred.rel.mutex p6, p7
420(p6)	getf.sig r5 = f31
421(p7)	mov r5 = b6
422	getf.sig r6 = f32
423	ld8.fill r7 = [sp]
424
425	br.ret.sptk.many rp
426	.endp save_static_to_scratch
427
428	/* Rotate registers a bit in a vain attempt to sow some confusion.
429	   Care must be taken not to write any rotating general register
430	   after rotation, because we keep the preserved state
431	   there... */
432
433	.global rotate_regs
434	.proc rotate_regs
435rotate_regs:
436	.prologue
437	.regstk 2, 14, 2, 16
438	.save ar.pfs, loc0
439	alloc loc0 = ar.pfs, 2, 14, 2, 16
440	.save rp, loc1
441	mov loc1 = rp
442	.save pr, loc2
443	mov loc2 = pr
444	.save ar.lc, loc3
445	mov loc3 = ar.lc
446	.spillreg r4, loc4
447	mov loc4 = r4
448
449	ld8 r2 = [in1], 8;;
450	mov pr = r2, -1
451
452	ld8 r2 = [in1], 8;;
453	mov r8 = in0
454	mov r9 = in1
455	and r2 = 127, r2;;
456	mov ar.ec = 0
457	mov ar.lc = r2;;
458
459	// use p6 to preserve p63 as it gets rotated into p16:
460(p16)	cmp.eq.unc p6,p0 = r0,r0;;
4611:
462(p6)	cmp.eq.unc p16,p0 = r0,r0
463(p63)	cmp.eq.unc p6,p0 = r0,r0
464	br.ctop.dptk.few 1b;;
465
466(p6)	cmp.eq.unc p63,p0 = r0,r0
467
468	CALL_NEXT_PTR(r4, r8, r9)
469
470	clrrrb
471
472	mov ar.pfs = loc0
473	mov rp = loc1
474	mov pr = loc2, -1
475	mov ar.lc = loc3
476	mov r4 = loc4
477	br.ret.sptk.many rp
478
479	.endp rotate_regs
480
481	.global save_pr
482	.proc save_pr
483save_pr:
484	.prologue
485	.regstk 2, 4, 2, 0
486	.save ar.pfs, loc0
487	alloc loc0 = ar.pfs, 2, 4, 2, 0
488	.save rp, loc1
489	mov loc1 = rp
490	.save pr, loc2
491	mov loc2 = pr
492
493	ld8 r2 = [in1], 8;;
494	mov pr = r2, -1
495
496	CALL_NEXT(loc3)
497
498	mov ar.pfs = loc0
499	mov rp = loc1
500	mov pr = loc2, -1
501	br.ret.sptk.many rp
502
503	.endp save_pr
504
505#ifdef __linux__
506        /* We do not need executable stack.  */
507        .section        .note.GNU-stack,"",@progbits
508#endif
509