1/* -----------------------------------------------------------------------
2   aix.S - Copyright (c) 2002, 2009 Free Software Foundation, Inc.
3   based on darwin.S by John Hornkvist
4
5   PowerPC Assembly glue.
6
7   Permission is hereby granted, free of charge, to any person obtaining
8   a copy of this software and associated documentation files (the
9   ``Software''), to deal in the Software without restriction, including
10   without limitation the rights to use, copy, modify, merge, publish,
11   distribute, sublicense, and/or sell copies of the Software, and to
12   permit persons to whom the Software is furnished to do so, subject to
13   the following conditions:
14
15   The above copyright notice and this permission notice shall be included
16   in all copies or substantial portions of the Software.
17
18   THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS
19   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
21   IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR
22   OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
23   ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
24   OTHER DEALINGS IN THE SOFTWARE.
25   ----------------------------------------------------------------------- */
26
27	.set r0,0
28	.set r1,1
29	.set r2,2
30	.set r3,3
31	.set r4,4
32	.set r5,5
33	.set r6,6
34	.set r7,7
35	.set r8,8
36	.set r9,9
37	.set r10,10
38	.set r11,11
39	.set r12,12
40	.set r13,13
41	.set r14,14
42	.set r15,15
43	.set r16,16
44	.set r17,17
45	.set r18,18
46	.set r19,19
47	.set r20,20
48	.set r21,21
49	.set r22,22
50	.set r23,23
51	.set r24,24
52	.set r25,25
53	.set r26,26
54	.set r27,27
55	.set r28,28
56	.set r29,29
57	.set r30,30
58	.set r31,31
59	.set f0,0
60	.set f1,1
61	.set f2,2
62	.set f3,3
63	.set f4,4
64	.set f5,5
65	.set f6,6
66	.set f7,7
67	.set f8,8
68	.set f9,9
69	.set f10,10
70	.set f11,11
71	.set f12,12
72	.set f13,13
73	.set f14,14
74	.set f15,15
75	.set f16,16
76	.set f17,17
77	.set f18,18
78	.set f19,19
79	.set f20,20
80	.set f21,21
81
82	.extern .ffi_prep_args
83
84#define LIBFFI_ASM
85#include <fficonfig.h>
86#include <ffi.h>
87#define JUMPTARGET(name) name
88#define L(x) x
89	.file "aix.S"
90	.toc
91
92	/* void ffi_call_AIX(extended_cif *ecif, unsigned long bytes,
93	 *		     unsigned int flags, unsigned int *rvalue,
94	 *		     void (*fn)(),
95	 *		     void (*prep_args)(extended_cif*, unsigned *const));
96	 * r3=ecif, r4=bytes, r5=flags, r6=rvalue, r7=fn, r8=prep_args
97	 */
98
99.csect .text[PR]
100	.align 2
101	.globl ffi_call_AIX
102	.globl .ffi_call_AIX
103.csect ffi_call_AIX[DS]
104ffi_call_AIX:
105#ifdef __64BIT__
106	.llong .ffi_call_AIX, TOC[tc0], 0
107	.csect .text[PR]
108.ffi_call_AIX:
109	.function .ffi_call_AIX,.ffi_call_AIX,16,044,LFE..0-LFB..0
110	.bf __LINE__
111	.line 1
112LFB..0:
113	/* Save registers we use.  */
114	mflr	r0
115
116	std	r28,-32(r1)
117	std	r29,-24(r1)
118	std	r30,-16(r1)
119	std	r31, -8(r1)
120
121	std	r0, 16(r1)
122LCFI..0:
123	mr	r28, r1		/* our AP.  */
124	stdux	r1, r1, r4
125LCFI..1:
126
127	/* Save arguments over call...  */
128	mr	r31, r5	/* flags, */
129	mr	r30, r6	/* rvalue, */
130	mr	r29, r7	/* function address.  */
131	std	r2, 40(r1)
132
133	/* Call ffi_prep_args.  */
134	mr	r4, r1
135	bl	.ffi_prep_args
136	nop
137
138	/* Now do the call.  */
139	ld	r0, 0(r29)
140	ld	r2, 8(r29)
141	ld	r11, 16(r29)
142	/* Set up cr1 with bits 4-7 of the flags.  */
143	mtcrf	0x40, r31
144	mtctr	r0
145	/* Load all those argument registers.  */
146	/* We have set up a nice stack frame, just load it into registers. */
147	ld	r3, 40+(1*8)(r1)
148	ld	r4, 40+(2*8)(r1)
149	ld	r5, 40+(3*8)(r1)
150	ld	r6, 40+(4*8)(r1)
151	nop
152	ld	r7, 40+(5*8)(r1)
153	ld	r8, 40+(6*8)(r1)
154	ld	r9, 40+(7*8)(r1)
155	ld	r10,40+(8*8)(r1)
156
157L1:
158	/* Load all the FP registers.  */
159	bf	6,L2 /* 2f + 0x18 */
160	lfd	f1,-32-(13*8)(r28)
161	lfd	f2,-32-(12*8)(r28)
162	lfd	f3,-32-(11*8)(r28)
163	lfd	f4,-32-(10*8)(r28)
164	nop
165	lfd	f5,-32-(9*8)(r28)
166	lfd	f6,-32-(8*8)(r28)
167	lfd	f7,-32-(7*8)(r28)
168	lfd	f8,-32-(6*8)(r28)
169	nop
170	lfd	f9,-32-(5*8)(r28)
171	lfd	f10,-32-(4*8)(r28)
172	lfd	f11,-32-(3*8)(r28)
173	lfd	f12,-32-(2*8)(r28)
174	nop
175	lfd	f13,-32-(1*8)(r28)
176
177L2:
178	/* Make the call.  */
179	bctrl
180	ld	r2, 40(r1)
181
182	/* Now, deal with the return value.  */
183	mtcrf	0x01, r31
184
185	bt	30, L(done_return_value)
186	bt	29, L(fp_return_value)
187	std	r3, 0(r30)
188
189	/* Fall through...  */
190
191L(done_return_value):
192	/* Restore the registers we used and return.  */
193	mr	r1, r28
194	ld	r0, 16(r28)
195	ld	r28, -32(r1)
196	mtlr	r0
197	ld	r29, -24(r1)
198	ld	r30, -16(r1)
199	ld	r31, -8(r1)
200	blr
201
202L(fp_return_value):
203	bf	28, L(float_return_value)
204	stfd	f1, 0(r30)
205	bf	31, L(done_return_value)
206	stfd	f2, 8(r30)
207	b	L(done_return_value)
208L(float_return_value):
209	stfs	f1, 0(r30)
210	b	L(done_return_value)
211LFE..0:
212#else /* ! __64BIT__ */
213
214	.long .ffi_call_AIX, TOC[tc0], 0
215	.csect .text[PR]
216.ffi_call_AIX:
217	.function .ffi_call_AIX,.ffi_call_AIX,16,044,LFE..0-LFB..0
218	.bf __LINE__
219	.line 1
220LFB..0:
221	/* Save registers we use.  */
222	mflr	r0
223
224	stw	r28,-16(r1)
225	stw	r29,-12(r1)
226	stw	r30, -8(r1)
227	stw	r31, -4(r1)
228
229	stw	r0, 8(r1)
230LCFI..0:
231	mr	r28, r1		/* out AP.  */
232	stwux	r1, r1, r4
233LCFI..1:
234
235	/* Save arguments over call...  */
236	mr	r31, r5	/* flags, */
237	mr	r30, r6	/* rvalue, */
238	mr	r29, r7	/* function address, */
239	stw	r2, 20(r1)
240
241	/* Call ffi_prep_args.  */
242	mr	r4, r1
243	bl	.ffi_prep_args
244	nop
245
246	/* Now do the call.  */
247	lwz	r0, 0(r29)
248	lwz	r2, 4(r29)
249	lwz	r11, 8(r29)
250	/* Set up cr1 with bits 4-7 of the flags.  */
251	mtcrf	0x40, r31
252	mtctr	r0
253	/* Load all those argument registers.  */
254	/* We have set up a nice stack frame, just load it into registers. */
255	lwz	r3, 20+(1*4)(r1)
256	lwz	r4, 20+(2*4)(r1)
257	lwz	r5, 20+(3*4)(r1)
258	lwz	r6, 20+(4*4)(r1)
259	nop
260	lwz	r7, 20+(5*4)(r1)
261	lwz	r8, 20+(6*4)(r1)
262	lwz	r9, 20+(7*4)(r1)
263	lwz	r10,20+(8*4)(r1)
264
265L1:
266	/* Load all the FP registers.  */
267	bf	6,L2 /* 2f + 0x18 */
268	lfd	f1,-16-(13*8)(r28)
269	lfd	f2,-16-(12*8)(r28)
270	lfd	f3,-16-(11*8)(r28)
271	lfd	f4,-16-(10*8)(r28)
272	nop
273	lfd	f5,-16-(9*8)(r28)
274	lfd	f6,-16-(8*8)(r28)
275	lfd	f7,-16-(7*8)(r28)
276	lfd	f8,-16-(6*8)(r28)
277	nop
278	lfd	f9,-16-(5*8)(r28)
279	lfd	f10,-16-(4*8)(r28)
280	lfd	f11,-16-(3*8)(r28)
281	lfd	f12,-16-(2*8)(r28)
282	nop
283	lfd	f13,-16-(1*8)(r28)
284
285L2:
286	/* Make the call.  */
287	bctrl
288	lwz	r2, 20(r1)
289
290	/* Now, deal with the return value.  */
291	mtcrf	0x01, r31
292
293	bt	30, L(done_return_value)
294	bt	29, L(fp_return_value)
295	stw	r3, 0(r30)
296	bf	28, L(done_return_value)
297	stw	r4, 4(r30)
298
299	/* Fall through...  */
300
301L(done_return_value):
302	/* Restore the registers we used and return.  */
303	mr	r1, r28
304	lwz	r0, 8(r28)
305	lwz	r28,-16(r1)
306	mtlr	r0
307	lwz	r29,-12(r1)
308	lwz	r30, -8(r1)
309	lwz	r31, -4(r1)
310	blr
311
312L(fp_return_value):
313	bf	28, L(float_return_value)
314	stfd	f1, 0(r30)
315	b	L(done_return_value)
316L(float_return_value):
317	stfs	f1, 0(r30)
318	b	L(done_return_value)
319LFE..0:
320#endif
321	.ef __LINE__
322	.long 0
323	.byte 0,0,0,1,128,4,0,0
324/* END(ffi_call_AIX) */
325
326	/* void ffi_call_go_AIX(extended_cif *ecif, unsigned long bytes,
327	 *		        unsigned int flags, unsigned int *rvalue,
328	 *		        void (*fn)(),
329	 *		        void (*prep_args)(extended_cif*, unsigned *const),
330	 *                      void *closure);
331	 * r3=ecif, r4=bytes, r5=flags, r6=rvalue, r7=fn, r8=prep_args, r9=closure
332	 */
333
334.csect .text[PR]
335	.align 2
336	.globl ffi_call_go_AIX
337	.globl .ffi_call_go_AIX
338.csect ffi_call_go_AIX[DS]
339ffi_call_go_AIX:
340#ifdef __64BIT__
341	.llong .ffi_call_go_AIX, TOC[tc0], 0
342	.csect .text[PR]
343.ffi_call_go_AIX:
344	.function .ffi_call_go_AIX,.ffi_call_go_AIX,16,044,LFE..1-LFB..1
345	.bf __LINE__
346	.line 1
347LFB..1:
348	/* Save registers we use.  */
349	mflr	r0
350
351	std	r28,-32(r1)
352	std	r29,-24(r1)
353	std	r30,-16(r1)
354	std	r31, -8(r1)
355
356	std	r9, 8(r1)	/* closure, saved in cr field. */
357	std	r0, 16(r1)
358LCFI..2:
359	mr	r28, r1		/* our AP.  */
360	stdux	r1, r1, r4
361LCFI..3:
362
363	/* Save arguments over call...  */
364	mr	r31, r5	/* flags, */
365	mr	r30, r6	/* rvalue, */
366	mr	r29, r7	/* function address,  */
367	std	r2, 40(r1)
368
369	/* Call ffi_prep_args.  */
370	mr	r4, r1
371	bl	.ffi_prep_args
372	nop
373
374	/* Now do the call.  */
375	ld	r0, 0(r29)
376	ld	r2, 8(r29)
377	ld      r11, 8(r28)	/* closure */
378	/* Set up cr1 with bits 4-7 of the flags.  */
379	mtcrf	0x40, r31
380	mtctr	r0
381	/* Load all those argument registers.  */
382	/* We have set up a nice stack frame, just load it into registers. */
383	ld	r3, 40+(1*8)(r1)
384	ld	r4, 40+(2*8)(r1)
385	ld	r5, 40+(3*8)(r1)
386	ld	r6, 40+(4*8)(r1)
387	nop
388	ld	r7, 40+(5*8)(r1)
389	ld	r8, 40+(6*8)(r1)
390	ld	r9, 40+(7*8)(r1)
391	ld	r10,40+(8*8)(r1)
392
393	b	L1
394LFE..1:
395#else /* ! __64BIT__ */
396
397	.long .ffi_call_go_AIX, TOC[tc0], 0
398	.csect .text[PR]
399.ffi_call_go_AIX:
400	.function .ffi_call_go_AIX,.ffi_call_go_AIX,16,044,LFE..1-LFB..1
401	.bf __LINE__
402	.line 1
403	/* Save registers we use.  */
404LFB..1:
405	mflr	r0
406
407	stw	r28,-16(r1)
408	stw	r29,-12(r1)
409	stw	r30, -8(r1)
410	stw	r31, -4(r1)
411
412	stw	r9, 4(r1)	/* closure, saved in cr field.  */
413	stw	r0, 8(r1)
414LCFI..2:
415	mr	r28, r1		/* out AP.  */
416	stwux	r1, r1, r4
417LCFI..3:
418
419	/* Save arguments over call...  */
420	mr	r31, r5	/* flags, */
421	mr	r30, r6	/* rvalue, */
422	mr	r29, r7	/* function address, */
423	stw	r2, 20(r1)
424
425	/* Call ffi_prep_args.  */
426	mr	r4, r1
427	bl	.ffi_prep_args
428	nop
429
430	/* Now do the call.  */
431	lwz	r0, 0(r29)
432	lwz	r2, 4(r29)
433	lwz	r11, 4(r28)	/* closure */
434	/* Set up cr1 with bits 4-7 of the flags.  */
435	mtcrf	0x40, r31
436	mtctr	r0
437	/* Load all those argument registers.  */
438	/* We have set up a nice stack frame, just load it into registers. */
439	lwz	r3, 20+(1*4)(r1)
440	lwz	r4, 20+(2*4)(r1)
441	lwz	r5, 20+(3*4)(r1)
442	lwz	r6, 20+(4*4)(r1)
443	nop
444	lwz	r7, 20+(5*4)(r1)
445	lwz	r8, 20+(6*4)(r1)
446	lwz	r9, 20+(7*4)(r1)
447	lwz	r10,20+(8*4)(r1)
448
449	b	L1
450LFE..1:
451#endif
452	.ef __LINE__
453	.long 0
454	.byte 0,0,0,1,128,4,0,0
455/* END(ffi_call_go_AIX) */
456
457.csect .text[PR]
458	.align 2
459	.globl ffi_call_DARWIN
460	.globl .ffi_call_DARWIN
461.csect ffi_call_DARWIN[DS]
462ffi_call_DARWIN:
463#ifdef __64BIT__
464	.llong .ffi_call_DARWIN, TOC[tc0], 0
465#else
466	.long .ffi_call_DARWIN, TOC[tc0], 0
467#endif
468	.csect .text[PR]
469.ffi_call_DARWIN:
470	blr
471	.long 0
472	.byte 0,0,0,0,0,0,0,0
473/* END(ffi_call_DARWIN) */
474
475/* EH frame stuff.  */
476
477#define LR_REGNO		0x41		/* Link Register (65), see rs6000.md */
478#ifdef __64BIT__
479#define PTRSIZE			8
480#define LOG2_PTRSIZE		3
481#define FDE_ENCODING		0x1c		/* DW_EH_PE_pcrel|DW_EH_PE_sdata8 */
482#define EH_DATA_ALIGN_FACT	0x78		/* LEB128 -8 */
483#else
484#define PTRSIZE			4
485#define LOG2_PTRSIZE		2
486#define FDE_ENCODING		0x1b		/* DW_EH_PE_pcrel|DW_EH_PE_sdata4 */
487#define EH_DATA_ALIGN_FACT	0x7c		/* LEB128 -4 */
488#endif
489	.csect	_unwind.ro_[RO],4
490	.align	LOG2_PTRSIZE
491	.globl	_GLOBAL__F_libffi_src_powerpc_aix
492_GLOBAL__F_libffi_src_powerpc_aix:
493Lframe..1:
494	.vbyte	4,LECIE..1-LSCIE..1	/* CIE Length */
495LSCIE..1:
496	.vbyte	4,0			/* CIE Identifier Tag */
497	.byte	0x3			/* CIE Version */
498	.byte	"zR"			/* CIE Augmentation */
499	.byte	0
500	.byte	0x1			/* uleb128 0x1; CIE Code Alignment Factor */
501	.byte	EH_DATA_ALIGN_FACT	/* leb128 -4/-8; CIE Data Alignment Factor */
502	.byte	0x41			/* CIE RA Column */
503	.byte	0x1			/* uleb128 0x1; Augmentation size */
504	.byte	FDE_ENCODING		/* FDE Encoding (pcrel|sdata4/8) */
505	.byte	0xc			/* DW_CFA_def_cfa */
506	.byte	0x1			/*     uleb128 0x1; Register r1 */
507	.byte	0			/*     uleb128 0x0; Offset 0 */
508	.align	LOG2_PTRSIZE
509LECIE..1:
510LSFDE..1:
511	.vbyte	4,LEFDE..1-LASFDE..1	/* FDE Length */
512LASFDE..1:
513	.vbyte	4,LASFDE..1-Lframe..1	/* FDE CIE offset */
514	.vbyte	PTRSIZE,LFB..0-$	/* FDE initial location */
515	.vbyte	PTRSIZE,LFE..0-LFB..0	/* FDE address range */
516	.byte   0			/* uleb128 0x0; Augmentation size */
517	.byte	0x4			/* DW_CFA_advance_loc4 */
518	.vbyte	4,LCFI..0-LFB..0
519	.byte	0x11			/* DW_CFA_def_offset_extended_sf */
520	.byte	LR_REGNO		/*     uleb128 LR_REGNO; Register LR */
521	.byte	0x7e			/*     leb128 -2; Offset -2 (8/16) */
522	.byte	0x9f			/* DW_CFA_offset Register r31 */
523	.byte	0x1			/*     uleb128 0x1; Offset 1 (-4/-8) */
524	.byte	0x9e			/* DW_CFA_offset Register r30 */
525	.byte	0x2			/*     uleb128 0x2; Offset 2 (-8/-16) */
526	.byte	0x9d			/* DW_CFA_offset Register r29 */
527	.byte	0x3			/*     uleb128 0x3; Offset 3 (-12/-24) */
528	.byte	0x9c			/* DW_CFA_offset Register r28 */
529	.byte	0x4			/*     uleb128 0x4; Offset 4 (-16/-32) */
530	.byte	0x4			/* DW_CFA_advance_loc4 */
531	.vbyte	4,LCFI..1-LCFI..0
532	.byte	0xd			/* DW_CFA_def_cfa_register */
533	.byte	0x1c			/*     uleb128 28; Register r28 */
534	.align	LOG2_PTRSIZE
535LEFDE..1:
536LSFDE..2:
537	.vbyte	4,LEFDE..2-LASFDE..2	/* FDE Length */
538LASFDE..2:
539	.vbyte	4,LASFDE..2-Lframe..1	/* FDE CIE offset */
540	.vbyte	PTRSIZE,LFB..1-$	/* FDE initial location */
541	.vbyte	PTRSIZE,LFE..1-LFB..1	/* FDE address range */
542	.byte   0			/* uleb128 0x0; Augmentation size */
543	.byte	0x4			/* DW_CFA_advance_loc4 */
544	.vbyte	4,LCFI..2-LFB..1
545	.byte	0x11			/* DW_CFA_def_offset_extended_sf */
546	.byte	LR_REGNO		/*     uleb128 LR_REGNO; Register LR */
547	.byte	0x7e			/*     leb128 -2; Offset -2 (8/16) */
548	.byte	0x9f			/* DW_CFA_offset Register r31 */
549	.byte	0x1			/*     uleb128 0x1; Offset 1 (-4/-8) */
550	.byte	0x9e			/* DW_CFA_offset Register r30 */
551	.byte	0x2			/*     uleb128 0x2; Offset 2 (-8/-16) */
552	.byte	0x9d			/* DW_CFA_offset Register r29 */
553	.byte	0x3			/*     uleb128 0x3; Offset 3 (-12/-24) */
554	.byte	0x9c			/* DW_CFA_offset Register r28 */
555	.byte	0x4			/*     uleb128 0x4; Offset 4 (-16/-32) */
556	.byte	0x4			/* DW_CFA_advance_loc4 */
557	.vbyte	4,LCFI..3-LCFI..2
558	.byte	0xd			/* DW_CFA_def_cfa_register */
559	.byte	0x1c			/*     uleb128 28; Register r28 */
560	.align	LOG2_PTRSIZE
561LEFDE..2:
562	.vbyte	4,0			/* End of FDEs */
563
564	.csect	.text[PR]
565	.ref	_GLOBAL__F_libffi_src_powerpc_aix	/* Prevents garbage collection by AIX linker */
566
567