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 |
37 | ENTRY (_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 |
80 | END(_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 |
200 | ENTRY (_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 |
266 | L(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 |
327 | L(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 | |
364 | L(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 |
390 | L(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 |
456 | L(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 |
496 | L(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 |
503 | END(_dl_profile_resolve) |
504 | #endif |
505 | |