1/* PLT trampolines.  PPC64 version.
2   Copyright (C) 2005-2022 Free Software Foundation, Inc.
3   This file is part of the GNU C Library.
4
5   The GNU C Library is free software; you can redistribute it and/or
6   modify it under the terms of the GNU Lesser General Public
7   License as published by the Free Software Foundation; either
8   version 2.1 of the License, or (at your option) any later version.
9
10   The GNU C Library is distributed in the hope that it will be useful,
11   but WITHOUT ANY WARRANTY; without even the implied warranty of
12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13   Lesser General Public License for more details.
14
15   You should have received a copy of the GNU Lesser General Public
16   License along with the GNU C Library; if not, see
17   <https://www.gnu.org/licenses/>.  */
18
19#include <sysdep.h>
20#include <rtld-global-offsets.h>
21
22
23	.section ".text"
24/* On entry r0 contains the index of the PLT entry we need to fixup
25   and r11 contains the link_map (from PLT0+16).  The link_map becomes
26   parm1 (r3) and the index (r0) need to be converted to an offset
27   (index * 24) in parm2 (r4).  */
28
29#define FRAME_SIZE (FRAME_MIN_SIZE+64)
30/* We need to save the registers used to pass parameters, ie. r3 thru
31   r10;  Use local var space rather than the parameter save area,
32   because gcc as of 2010/05 doesn't allocate a proper stack frame for
33   a function that makes no calls except for __tls_get_addr and we
34   might be here resolving the __tls_get_addr call.  */
35	.hidden _dl_runtime_resolve
36#define INT_PARMS FRAME_MIN_SIZE
37ENTRY (_dl_runtime_resolve, 4)
38	stdu	r1,-FRAME_SIZE(r1)
39	cfi_adjust_cfa_offset (FRAME_SIZE)
40	std	r3,INT_PARMS+0(r1)
41	mr	r3,r11
42	std	r4,INT_PARMS+8(r1)
43	sldi	r4,r0,1
44	std	r5,INT_PARMS+16(r1)
45	add	r4,r4,r0
46	std	r6,INT_PARMS+24(r1)
47	sldi	r4,r4,3
48	std	r7,INT_PARMS+32(r1)
49	mflr	r0
50	std	r8,INT_PARMS+40(r1)
51/* Store the LR in the LR Save area.  */
52	std	r0,FRAME_SIZE+FRAME_LR_SAVE(r1)
53	cfi_offset (lr, FRAME_LR_SAVE)
54	std	r9,INT_PARMS+48(r1)
55	std	r10,INT_PARMS+56(r1)
56	bl	JUMPTARGET(_dl_fixup)
57#ifndef SHARED
58	nop
59#endif
60/* Put the registers back.  */
61	ld	r0,FRAME_SIZE+FRAME_LR_SAVE(r1)
62	ld	r10,INT_PARMS+56(r1)
63	ld	r9,INT_PARMS+48(r1)
64	ld	r8,INT_PARMS+40(r1)
65	ld	r7,INT_PARMS+32(r1)
66	mtlr	r0
67	ld	r6,INT_PARMS+24(r1)
68	ld	r5,INT_PARMS+16(r1)
69	ld	r4,INT_PARMS+8(r1)
70/* Prepare for calling the function returned by fixup.  */
71	PPC64_LOAD_FUNCPTR r3
72	ld	r3,INT_PARMS+0(r1)
73#if _CALL_ELF == 2
74/* Restore the caller's TOC in case we jump to a local entry point.  */
75	ld	r2,FRAME_SIZE+FRAME_TOC_SAVE(r1)
76#endif
77/* Unwind the stack frame, and jump.  */
78	addi	r1,r1,FRAME_SIZE
79	bctr
80END(_dl_runtime_resolve)
81#undef FRAME_SIZE
82#undef INT_PARMS
83
84	/* Stack layout:		ELFv2 ABI.
85					+752   previous backchain
86					+744   spill_r31
87					+736   spill_r30
88					+720   v8
89					+704   v7
90					+688   v6
91					+672   v5
92					+656   v4
93					+640   v3
94					+624   v2
95					+608   v1
96					+600   fp10
97	  ELFv1 ABI			+592   fp9
98	  +592   previous backchain	+584   fp8
99	  +584   spill_r31		+576   fp7
100	  +576   spill_r30		+568   fp6
101	  +560   v1			+560   fp5
102	  +552   fp4			+552   fp4
103	  +544   fp3			+544   fp3
104	  +536   fp2			+536   fp2
105	  +528   fp1			+528   fp1
106	  +520   r4			+520   r4
107	  +512   r3			+512   r3
108	   return values
109          +504   free
110	  +496   stackframe
111	  +488   lr
112	  +480   r1
113	  +464   v13
114	  +448   v12
115	  +432   v11
116	  +416   v10
117	  +400   v9
118	  +384   v8
119	  +368   v7
120	  +352   v6
121	  +336   v5
122	  +320   v4
123	  +304   v3
124	  +288   v2
125	 * VMX Parms in V2-V13, V0-V1 are scratch
126	  +284   vrsave
127	  +280   free
128	  +272   fp13
129	  +264   fp12
130	  +256   fp11
131	  +248   fp10
132	  +240   fp9
133	  +232   fp8
134	  +224   fp7
135	  +216   fp6
136	  +208   fp5
137	  +200   fp4
138	  +192   fp3
139	  +184   fp2
140	  +176   fp1
141	 * FP Parms in FP1-FP13, FP0 is a scratch register
142	  +168   r10
143	  +160   r9
144	  +152   r8
145	  +144   r7
146	  +136   r6
147	  +128   r5
148	  +120   r4
149	  +112   r3
150	 * Integer parms in R3-R10, R0 is scratch, R1 SP, R2 is TOC
151	  +104   parm8
152	  +96    parm7
153	  +88    parm6
154	  +80    parm5
155	  +72    parm4
156	  +64    parm3
157	  +56    parm2
158	  +48    parm1
159	 * Parameter save area
160	 * (v1 ABI: Allocated by the call, at least 8 double words)
161	  +40    v1 ABI: TOC save area
162	  +32    v1 ABI: Reserved for linker
163	  +24    v1 ABI: Reserved for compiler / v2 ABI: TOC save area
164	  +16    LR save area
165	  +8     CR save area
166	r1+0     stack back chain
167	*/
168#if _CALL_ELF == 2
169# define FRAME_SIZE 752
170# define VR_RTN 608
171#else
172# define FRAME_SIZE 592
173# define VR_RTN 560
174#endif
175#define INT_RTN 512
176#define FPR_RTN 528
177#define STACK_FRAME 496
178#define CALLING_LR 488
179#define CALLING_SP 480
180#define INT_PARMS 112
181#define FPR_PARMS 176
182#define VR_PARMS 288
183#define VR_VRSAVE 284
184	.section	".toc","aw"
185.LC__dl_hwcap:
186# ifdef SHARED
187	.tc _rtld_local_ro[TC],_rtld_local_ro
188# else
189	.tc _dl_hwcap[TC],_dl_hwcap
190# endif
191	.section ".text"
192
193	.machine	"altivec"
194/* On entry r0 contains the index of the PLT entry we need to fixup
195   and r11 contains the link_map (from PLT0+16).  The link_map becomes
196   parm1 (r3) and the index (r0) needs to be converted to an offset
197   (index * 24) in parm2 (r4).  */
198#ifndef PROF
199	.hidden _dl_profile_resolve
200ENTRY (_dl_profile_resolve, 4)
201/* Spill r30, r31 to preserve the link_map* and reloc_addr, in case we
202   need to call _dl_audit_pltexit.  */
203	std	r31,-8(r1)
204	std	r30,-16(r1)
205/* We need to save the registers used to pass parameters, ie. r3 thru
206   r10; the registers are saved in a stack frame.  */
207	stdu	r1,-FRAME_SIZE(r1)
208	cfi_adjust_cfa_offset (FRAME_SIZE)
209	cfi_offset(r31,-8)
210	cfi_offset(r30,-16)
211	std	r3,INT_PARMS+0(r1)
212	mr	r3,r11
213	std	r4,INT_PARMS+8(r1)
214	sldi	r4,r0,1		/* index * 2 */
215	std	r5,INT_PARMS+16(r1)
216	add	r4,r4,r0	/* index * 3 */
217	std	r6,INT_PARMS+24(r1)
218	sldi	r4,r4,3		/* index * 24  == PLT offset */
219	mflr	r5
220	std	r7,INT_PARMS+32(r1)
221	std	r8,INT_PARMS+40(r1)
222/* Store the LR in the LR Save area.  */
223	la	r8,FRAME_SIZE(r1)
224	std	r5,FRAME_SIZE+FRAME_LR_SAVE(r1)
225	cfi_offset (lr, FRAME_LR_SAVE)
226	std	r5,CALLING_LR(r1)
227	std	r9,INT_PARMS+48(r1)
228	std	r10,INT_PARMS+56(r1)
229	std	r8,CALLING_SP(r1)
230	addis   r12,r2,.LC__dl_hwcap@toc@ha
231	ld	r12,.LC__dl_hwcap@toc@l(r12)
232#ifdef SHARED
233	/* Load _rtld_local_ro._dl_hwcap.  */
234	ld	r12,RTLD_GLOBAL_RO_DL_HWCAP_OFFSET(r12)
235#else
236	/* Load extern _dl_hwcap.  */
237	ld	r12,0(r12)
238#endif
239	andis.  r0,r12,(PPC_FEATURE_HAS_ALTIVEC >> 16)
240	beq	L(saveFP)
241	la	r10,(VR_PARMS+0)(r1)
242	la	r9,(VR_PARMS+16)(r1)
243	li	r11,32
244	li	r12,64
245	stvx	v2,0,r10
246	stvx	v3,0,r9
247
248	stvx	v4,r11,r10
249	stvx	v5,r11,r9
250	addi	r11,r11,64
251
252	stvx	v6,r12,r10
253	stvx	v7,r12,r9
254	addi	r12,r12,64
255
256	stvx	v8,r11,r10
257	stvx	v9,r11,r9
258	addi	r11,r11,64
259
260	stvx	v10,r12,r10
261	stvx	v11,r12,r9
262	mfspr	r0,VRSAVE
263
264	stvx	v12,r11,r10
265	stvx	v13,r11,r9
266L(saveFP):
267	stw	r0,VR_VRSAVE(r1)
268/* Save floating registers.  */
269	stfd	fp1,FPR_PARMS+0(r1)
270	stfd	fp2,FPR_PARMS+8(r1)
271	stfd	fp3,FPR_PARMS+16(r1)
272	stfd	fp4,FPR_PARMS+24(r1)
273	stfd	fp5,FPR_PARMS+32(r1)
274	stfd	fp6,FPR_PARMS+40(r1)
275	stfd	fp7,FPR_PARMS+48(r1)
276	stfd	fp8,FPR_PARMS+56(r1)
277	stfd	fp9,FPR_PARMS+64(r1)
278	stfd	fp10,FPR_PARMS+72(r1)
279	stfd	fp11,FPR_PARMS+80(r1)
280	li	r0,-1
281	stfd	fp12,FPR_PARMS+88(r1)
282	stfd	fp13,FPR_PARMS+96(r1)
283/* Load the extra parameters.  */
284	addi	r6,r1,INT_PARMS
285	addi	r7,r1,STACK_FRAME
286/* Save  link_map* and reloc_addr parms for later.  */
287	mr	r31,r3
288	mr	r30,r4
289	std	r0,0(r7)
290	bl	JUMPTARGET(_dl_profile_fixup)
291#ifndef SHARED
292	nop
293#endif
294/* Test *framesizep > 0 to see if need to do pltexit processing.  */
295	ld	r0,STACK_FRAME(r1)
296/* Put the registers back.  */
297	lwz	r12,VR_VRSAVE(r1)
298	cmpdi	cr1,r0,0
299	cmpdi	cr0,r12,0
300	bgt	cr1,L(do_pltexit)
301	la	r10,(VR_PARMS+0)(r1)
302	la	r9,(VR_PARMS+16)(r1)
303/* VRSAVE must be non-zero if VMX is present and VRs are in use. */
304	beq	L(restoreFXR)
305	li	r11,32
306	li	r12,64
307	lvx	v2,0,r10
308	lvx	v3,0,r9
309
310	lvx	v4,r11,r10
311	lvx	v5,r11,r9
312	addi	r11,r11,64
313
314	lvx	v6,r12,r10
315	lvx	v7,r12,r9
316	addi	r12,r12,64
317
318	lvx	v8,r11,r10
319	lvx	v9,r11,r9
320	addi	r11,r11,64
321
322	lvx	v10,r12,r10
323	lvx	v11,r12,r9
324
325	lvx	v12,r11,r10
326	lvx	v13,r11,r9
327L(restoreFXR):
328	ld	r0,FRAME_SIZE+FRAME_LR_SAVE(r1)
329	ld	r10,INT_PARMS+56(r1)
330	ld	r9,INT_PARMS+48(r1)
331	ld	r8,INT_PARMS+40(r1)
332	ld	r7,INT_PARMS+32(r1)
333	mtlr	r0
334	ld	r6,INT_PARMS+24(r1)
335	ld	r5,INT_PARMS+16(r1)
336	ld	r4,INT_PARMS+8(r1)
337/* Prepare for calling the function returned by fixup.  */
338	PPC64_LOAD_FUNCPTR r3
339	ld	r3,INT_PARMS+0(r1)
340#if _CALL_ELF == 2
341/* Restore the caller's TOC in case we jump to a local entry point.  */
342	ld	r2,FRAME_SIZE+FRAME_TOC_SAVE(r1)
343#endif
344/* Load the floating point registers.  */
345	lfd	fp1,FPR_PARMS+0(r1)
346	lfd	fp2,FPR_PARMS+8(r1)
347	lfd	fp3,FPR_PARMS+16(r1)
348	lfd	fp4,FPR_PARMS+24(r1)
349	lfd	fp5,FPR_PARMS+32(r1)
350	lfd	fp6,FPR_PARMS+40(r1)
351	lfd	fp7,FPR_PARMS+48(r1)
352	lfd	fp8,FPR_PARMS+56(r1)
353	lfd	fp9,FPR_PARMS+64(r1)
354	lfd	fp10,FPR_PARMS+72(r1)
355	lfd	fp11,FPR_PARMS+80(r1)
356	lfd	fp12,FPR_PARMS+88(r1)
357	lfd	fp13,FPR_PARMS+96(r1)
358/* Unwind the stack frame, and jump.  */
359	ld	r31,FRAME_SIZE-8(r1)
360	ld	r30,FRAME_SIZE-16(r1)
361	addi	r1,r1,FRAME_SIZE
362	bctr
363
364L(do_pltexit):
365	la	r10,(VR_PARMS+0)(r1)
366	la	r9,(VR_PARMS+16)(r1)
367	beq	L(restoreFXR2)
368	li	r11,32
369	li	r12,64
370	lvx	v2,0,r10
371	lvx	v3,0,r9
372
373	lvx	v4,r11,r10
374	lvx	v5,r11,r9
375	addi	r11,r11,64
376
377	lvx	v6,r12,r10
378	lvx	v7,r12,r9
379	addi	r12,r12,64
380
381	lvx	v8,r11,r10
382	lvx	v9,r11,r9
383	addi	r11,r11,64
384
385	lvx	v10,r12,r10
386	lvx	v11,r12,r9
387
388	lvx	v12,r11,r10
389	lvx	v13,r11,r9
390L(restoreFXR2):
391	ld	r0,FRAME_SIZE+FRAME_LR_SAVE(r1)
392	ld	r10,INT_PARMS+56(r1)
393	ld	r9,INT_PARMS+48(r1)
394	ld	r8,INT_PARMS+40(r1)
395	ld	r7,INT_PARMS+32(r1)
396	mtlr	r0
397	ld	r6,INT_PARMS+24(r1)
398	ld	r5,INT_PARMS+16(r1)
399	ld	r4,INT_PARMS+8(r1)
400/* Prepare for calling the function returned by fixup.  */
401	std	r2,FRAME_TOC_SAVE(r1)
402	PPC64_LOAD_FUNCPTR r3
403	ld	r3,INT_PARMS+0(r1)
404/* Load the floating point registers.  */
405	lfd	fp1,FPR_PARMS+0(r1)
406	lfd	fp2,FPR_PARMS+8(r1)
407	lfd	fp3,FPR_PARMS+16(r1)
408	lfd	fp4,FPR_PARMS+24(r1)
409	lfd	fp5,FPR_PARMS+32(r1)
410	lfd	fp6,FPR_PARMS+40(r1)
411	lfd	fp7,FPR_PARMS+48(r1)
412	lfd	fp8,FPR_PARMS+56(r1)
413	lfd	fp9,FPR_PARMS+64(r1)
414	lfd	fp10,FPR_PARMS+72(r1)
415	lfd	fp11,FPR_PARMS+80(r1)
416	lfd	fp12,FPR_PARMS+88(r1)
417	lfd	fp13,FPR_PARMS+96(r1)
418/* Call the target function.  */
419	bctrl
420	ld	r2,FRAME_TOC_SAVE(r1)
421	lwz	r12,VR_VRSAVE(r1)
422/* But return here and store the return values.  */
423	std	r3,INT_RTN(r1)
424	std	r4,INT_RTN+8(r1)
425	stfd	fp1,FPR_RTN+0(r1)
426	stfd	fp2,FPR_RTN+8(r1)
427	cmpdi	cr0,r12,0
428	la	r10,VR_RTN(r1)
429	stfd	fp3,FPR_RTN+16(r1)
430	stfd	fp4,FPR_RTN+24(r1)
431#if _CALL_ELF == 2
432	la	r12,VR_RTN+16(r1)
433	stfd	fp5,FPR_RTN+32(r1)
434	stfd	fp6,FPR_RTN+40(r1)
435	li	r5,32
436	li	r6,64
437	stfd	fp7,FPR_RTN+48(r1)
438	stfd	fp8,FPR_RTN+56(r1)
439	stfd	fp9,FPR_RTN+64(r1)
440	stfd	fp10,FPR_RTN+72(r1)
441#endif
442	mr	r3,r31
443	mr	r4,r30
444	beq	L(callpltexit)
445	stvx	v2,0,r10
446#if _CALL_ELF == 2
447	stvx	v3,0,r12
448	stvx	v4,r5,r10
449	stvx	v5,r5,r12
450	addi	r5,r5,64
451	stvx	v6,r6,r10
452	stvx	v7,r6,r12
453	stvx	v8,r5,r10
454	stvx	v9,r5,r12
455#endif
456L(callpltexit):
457	addi	r5,r1,INT_PARMS
458	addi	r6,r1,INT_RTN
459	bl	JUMPTARGET(_dl_audit_pltexit)
460#ifndef SHARED
461	nop
462#endif
463/* Restore the return values from target function.  */
464	lwz	r12,VR_VRSAVE(r1)
465	ld	r3,INT_RTN(r1)
466	ld	r4,INT_RTN+8(r1)
467	lfd	fp1,FPR_RTN+0(r1)
468	lfd	fp2,FPR_RTN+8(r1)
469	cmpdi	cr0,r12,0
470	la	r11,VR_RTN(r1)
471	lfd	fp3,FPR_RTN+16(r1)
472	lfd	fp4,FPR_RTN+24(r1)
473#if _CALL_ELF == 2
474	la	r12,VR_RTN+16(r1)
475	lfd	fp5,FPR_RTN+32(r1)
476	lfd	fp6,FPR_RTN+40(r1)
477	li	r30,32
478	li	r31,64
479	lfd	fp7,FPR_RTN+48(r1)
480	lfd	fp8,FPR_RTN+56(r1)
481	lfd	fp9,FPR_RTN+64(r1)
482	lfd	fp10,FPR_RTN+72(r1)
483#endif
484	beq	L(pltexitreturn)
485	lvx	v2,0,r11
486#if _CALL_ELF == 2
487	lvx	v3,0,r12
488	lvx	v4,r30,r11
489	lvx	v5,r30,r12
490	addi	r30,r30,64
491	lvx	v6,r31,r11
492	lvx	v7,r31,r12
493	lvx	v8,r30,r11
494	lvx	v9,r30,r12
495#endif
496L(pltexitreturn):
497	ld	r0,FRAME_SIZE+FRAME_LR_SAVE(r1)
498	ld	r31,FRAME_SIZE-8(r1)
499	ld	r30,FRAME_SIZE-16(r1)
500	mtlr	r0
501	ld	r1,0(r1)
502	blr
503END(_dl_profile_resolve)
504#endif
505