1/* PLT trampolines. PPC64 version.
2 Copyright (C) 2005-2024 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#if !defined PROF && defined SHARED
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

source code of glibc/sysdeps/powerpc/powerpc64/dl-trampoline.S