1 | /* PLT trampolines. hppa 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 | |
21 | /* This code gets called via the .plt stub, and is used in |
22 | dl-runtime.c to call the `_dl_fixup' function and then redirect |
23 | to the address it returns. `_dl_fixup' takes two arguments, however |
24 | `_dl_profile_fixup' takes a number of parameters for use with |
25 | library auditing (LA). |
26 | |
27 | WARNING: This template is also used by gcc's __cffc, and expects |
28 | that the "bl" for _dl_runtime_resolve exist at a particular offset. |
29 | Do not change this template without changing gcc, while the prefix |
30 | "bl" should fix everything so gcc finds the right spot, it will |
31 | slow down __cffc when it attempts to call fixup to resolve function |
32 | descriptor references. Please refer to gcc/gcc/config/pa/fptr.c |
33 | |
34 | Enter with r19 = reloc offset, r20 = got-8, r21 = fixup ltp, r22 = fp. */ |
35 | |
36 | /* RELOCATION MARKER: bl to provide gcc's __cffc with fixup loc. */ |
37 | .text |
38 | /* THIS CODE DOES NOT EXECUTE */ |
39 | bl _dl_fixup, %r2 |
40 | .text |
41 | .global _dl_runtime_resolve |
42 | .type _dl_runtime_resolve,@function |
43 | cfi_startproc |
44 | .align 4 |
45 | _dl_runtime_resolve: |
46 | .PROC |
47 | .CALLINFO FRAME=128,CALLS,SAVE_RP,ENTRY_GR=3 |
48 | .ENTRY |
49 | /* SAVE_RP says we do */ |
50 | stw %rp, -20(%sp) |
51 | |
52 | /* Save static link register */ |
53 | stw %r29,-16(%sp) |
54 | /* Save argument registers */ |
55 | stw %r26,-36(%sp) |
56 | stw %r25,-40(%sp) |
57 | stw %r24,-44(%sp) |
58 | stw %r23,-48(%sp) |
59 | |
60 | /* Build a call frame, and save structure pointer. */ |
61 | copy %sp, %r1 /* Copy previous sp */ |
62 | /* Save function result address (on entry) */ |
63 | stwm %r28,128(%sp) |
64 | /* Fill in some frame info to follow ABI */ |
65 | stw %r1,-4(%sp) /* Previous sp */ |
66 | stw %r21,-32(%sp) /* PIC register value */ |
67 | |
68 | /* Save input floating point registers. This must be done |
69 | in the new frame since the previous frame doesn't have |
70 | enough space */ |
71 | ldo -64(%sp),%r1 |
72 | fstd,ma %fr4,-8(%r1) |
73 | fstd,ma %fr5,-8(%r1) |
74 | fstd,ma %fr6,-8(%r1) |
75 | |
76 | /* Test PA_GP_RELOC bit. */ |
77 | bb,>= %r19,31,2f /* branch if not reloc offset */ |
78 | fstd,ma %fr7,-8(%r1) |
79 | |
80 | /* Set up args to fixup func, needs only two arguments */ |
81 | ldw 8+4(%r20),%r26 /* (1) got[1] == struct link_map */ |
82 | copy %r19,%r25 /* (2) reloc offset */ |
83 | |
84 | /* Call the real address resolver. */ |
85 | 3: bl _dl_fixup,%rp |
86 | copy %r21,%r19 /* set fixup func ltp */ |
87 | |
88 | /* While the linker will set a function pointer to NULL when it |
89 | encounters an undefined weak function, we need to dynamically |
90 | detect removed weak functions. The issue arises because a weak |
91 | __gmon_start__ function was added to shared executables to work |
92 | around issues in _init that are now resolved. The presence of |
93 | __gmon_start__ in every shared library breaks the linker |
94 | `--as-needed' option. This __gmon_start__ function does nothing |
95 | but removal is tricky. Depending on the binding, removal can |
96 | cause an application using it to fault. The call to _dl_fixup |
97 | returns NULL when a function isn't resolved. In order to help |
98 | with __gmon_start__ removal, we return directly to the caller |
99 | when _dl_fixup returns NULL. This check could be removed when |
100 | BZ 19170 is fixed. */ |
101 | comib,= 0,%r28,1f |
102 | |
103 | /* Load up the returned func descriptor */ |
104 | copy %r28, %r22 |
105 | copy %r29, %r19 |
106 | |
107 | /* Reload arguments fp args */ |
108 | ldo -64(%sp),%r1 |
109 | fldd,ma -8(%r1),%fr4 |
110 | fldd,ma -8(%r1),%fr5 |
111 | fldd,ma -8(%r1),%fr6 |
112 | fldd,ma -8(%r1),%fr7 |
113 | |
114 | /* Adjust sp, and restore function result address*/ |
115 | ldwm -128(%sp),%r28 |
116 | |
117 | /* Reload static link register */ |
118 | ldw -16(%sp),%r29 |
119 | /* Reload general args */ |
120 | ldw -36(%sp),%r26 |
121 | ldw -40(%sp),%r25 |
122 | ldw -44(%sp),%r24 |
123 | ldw -48(%sp),%r23 |
124 | |
125 | /* Jump to new function, but return to previous function */ |
126 | bv %r0(%r22) |
127 | ldw -20(%sp),%rp |
128 | |
129 | 1: |
130 | /* Return to previous function */ |
131 | ldw -148(%sp),%rp |
132 | bv %r0(%rp) |
133 | ldo -128(%sp),%sp |
134 | |
135 | 2: |
136 | /* Set up args for _dl_fix_reloc_arg. */ |
137 | copy %r22,%r26 /* (1) function pointer */ |
138 | depi 0,31,2,%r26 /* clear least significant bits */ |
139 | ldw 8+4(%r20),%r25 /* (2) got[1] == struct link_map */ |
140 | |
141 | /* Save ltp and link map arg for _dl_fixup. */ |
142 | stw %r21,-56(%sp) /* ltp */ |
143 | stw %r25,-60(%sp) /* struct link map */ |
144 | |
145 | /* Find reloc offset. */ |
146 | bl _dl_fix_reloc_arg,%rp |
147 | copy %r21,%r19 /* set func ltp */ |
148 | |
149 | /* Set up args for _dl_fixup. */ |
150 | ldw -56(%sp),%r21 /* ltp */ |
151 | ldw -60(%sp),%r26 /* (1) struct link map */ |
152 | b 3b |
153 | copy %ret0,%r25 /* (2) reloc offset */ |
154 | .EXIT |
155 | .PROCEND |
156 | cfi_endproc |
157 | .size _dl_runtime_resolve, . - _dl_runtime_resolve |
158 | |
159 | .text |
160 | .global _dl_runtime_profile |
161 | .type _dl_runtime_profile,@function |
162 | cfi_startproc |
163 | .align 4 |
164 | _dl_runtime_profile: |
165 | .PROC |
166 | .CALLINFO FRAME=192,CALLS,SAVE_RP,ENTRY_GR=3 |
167 | .ENTRY |
168 | |
169 | /* SAVE_RP says we do */ |
170 | stw %rp, -20(%sp) |
171 | /* Save static link register */ |
172 | stw %r29,-16(%sp) |
173 | |
174 | /* Build a call frame, and save structure pointer. */ |
175 | copy %sp, %r1 /* Copy previous sp */ |
176 | /* Save function result address (on entry) */ |
177 | stwm %r28,192(%sp) |
178 | /* Fill in some frame info to follow ABI */ |
179 | stw %r1,-4(%sp) /* Previous sp */ |
180 | stw %r21,-32(%sp) /* PIC register value */ |
181 | |
182 | /* Create La_hppa_retval */ |
183 | /* -140, lrv_r28 |
184 | -136, lrv_r29 |
185 | -132, 4 byte pad |
186 | -128, lr_fr4 (8 bytes) */ |
187 | |
188 | /* Create save space for _dl_profile_fixup arguments |
189 | -120, Saved reloc offset |
190 | -116, Saved struct link_map |
191 | -112, *framesizep */ |
192 | |
193 | /* Create La_hppa_regs */ |
194 | /* 32-bit registers */ |
195 | stw %r26,-108(%sp) |
196 | stw %r25,-104(%sp) |
197 | stw %r24,-100(%sp) |
198 | stw %r23,-96(%sp) |
199 | /* -92, 4 byte pad */ |
200 | /* 64-bit floating point registers */ |
201 | ldo -88(%sp),%r1 |
202 | fstd,ma %fr4,8(%r1) |
203 | fstd,ma %fr5,8(%r1) |
204 | fstd,ma %fr6,8(%r1) |
205 | fstd,ma %fr7,8(%r1) |
206 | |
207 | /* Test PA_GP_RELOC bit. */ |
208 | bb,>= %r19,31,2f /* branch if not reloc offset */ |
209 | /* 32-bit stack pointer */ |
210 | stw %sp,-56(%sp) |
211 | |
212 | /* Set up args to fixup func, needs five arguments */ |
213 | ldw 8+4(%r20),%r26 /* (1) got[1] == struct link_map */ |
214 | stw %r26,-116(%sp) /* Save struct link_map */ |
215 | copy %r19,%r25 /* (2) reloc offset */ |
216 | stw %r25,-120(%sp) /* Save reloc offset */ |
217 | copy %rp,%r24 /* (3) profile_fixup needs rp */ |
218 | ldo -56(%sp),%r23 /* (4) La_hppa_regs */ |
219 | ldo -112(%sp), %r1 |
220 | stw %r1, -52(%sp) /* (5) long int *framesizep */ |
221 | |
222 | /* Call the real address resolver. */ |
223 | 3: bl _dl_profile_fixup,%rp |
224 | copy %r21,%r19 /* set fixup func ltp */ |
225 | |
226 | /* Load up the returned function descriptor */ |
227 | copy %r28, %r22 |
228 | copy %r29, %r19 |
229 | |
230 | /* Restore gr/fr/sp/rp */ |
231 | ldw -108(%sp),%r26 |
232 | ldw -104(%sp),%r25 |
233 | ldw -100(%sp),%r24 |
234 | ldw -96(%sp),%r23 |
235 | /* -92, 4 byte pad, skip */ |
236 | ldo -88(%sp),%r1 |
237 | fldd,ma 8(%r1),%fr4 |
238 | fldd,ma 8(%r1),%fr5 |
239 | fldd,ma 8(%r1),%fr6 |
240 | fldd,ma 8(%r1),%fr7 |
241 | |
242 | /* Reload rp register -(192+20) without adjusting stack */ |
243 | ldw -212(%sp),%rp |
244 | |
245 | /* Reload static link register -(192+16) without adjusting stack */ |
246 | ldw -208(%sp),%r29 |
247 | |
248 | /* *framesizep is >= 0 if we have to run pltexit */ |
249 | ldw -112(%sp),%r28 |
250 | cmpb,>>=,N %r0,%r28,L(cpe) |
251 | |
252 | /* Adjust sp, and restore function result address*/ |
253 | ldwm -192(%sp),%r28 |
254 | /* Jump to new function, but return to previous function */ |
255 | bv %r0(%r22) |
256 | ldw -20(%sp),%rp |
257 | /* NO RETURN */ |
258 | |
259 | L(nf): |
260 | /* Call the returned function descriptor */ |
261 | bv %r0(%r22) |
262 | nop |
263 | b,n L(cont) |
264 | |
265 | L(cpe): |
266 | /* We are going to call the resolved function, but we have a |
267 | stack frame in the middle. We use the value of framesize to |
268 | guess how much extra frame we need, and how much frame to |
269 | copy forward. */ |
270 | |
271 | /* Round to nearest multiple of 64 */ |
272 | addi 63, %r28, %r28 |
273 | depi 0, 27, 6, %r28 |
274 | |
275 | /* Calcualte start of stack copy */ |
276 | ldo -192(%sp),%r2 |
277 | |
278 | /* Increate the stack by *framesizep */ |
279 | copy %sp, %r1 |
280 | add %sp, %r28, %sp |
281 | /* Save stack pointer */ |
282 | stw %r1, -4(%sp) |
283 | |
284 | /* Single byte copy of prevous stack onto newly allocated stack */ |
285 | 1: ldb %r28(%r2), %r1 |
286 | add %r28, %sp, %r26 |
287 | stb %r1, 0(%r26) |
288 | addi,< -1,%r28,%r28 |
289 | b,n 1b |
290 | |
291 | /* Retore r28 and r27 and r2 already points at -192(%sp) */ |
292 | ldw 0(%r2),%r28 |
293 | ldw 84(%r2),%r26 |
294 | |
295 | /* Calculate address of L(cont) */ |
296 | b,l L(nf),%r2 |
297 | depwi 0,31,2,%r2 |
298 | L(cont): |
299 | /* Undo fake stack */ |
300 | ldw -4(%sp),%r1 |
301 | copy %r1, %sp |
302 | |
303 | /* Arguments to _dl_audit_pltexit */ |
304 | ldw -116(%sp), %r26 /* (1) got[1] == struct link_map */ |
305 | ldw -120(%sp), %r25 /* (2) reloc offsets */ |
306 | ldo -56(%sp), %r24 /* (3) *La_hppa_regs */ |
307 | ldo -124(%sp), %r23 /* (4) *La_hppa_retval */ |
308 | |
309 | /* Fill *La_hppa_retval */ |
310 | stw %r28,-140(%sp) |
311 | stw %r29,-136(%sp) |
312 | ldo -128(%sp), %r1 |
313 | fstd %fr4,0(%r1) |
314 | |
315 | /* Call _dl_audit_pltexit */ |
316 | bl _dl_audit_pltexit,%rp |
317 | nop |
318 | |
319 | /* Restore *La_hppa_retval */ |
320 | ldw -140(%sp), %r28 |
321 | ldw -136(%sp), %r29 |
322 | ldo -128(%sp), %r1 |
323 | fldd 0(%r1), %fr4 |
324 | |
325 | /* Unwind the stack */ |
326 | ldo 192(%sp),%sp |
327 | /* Retore callers rp */ |
328 | ldw -20(%sp),%rp |
329 | /* Return */ |
330 | bv,n 0(%r2) |
331 | |
332 | 2: |
333 | /* Set up args for _dl_fix_reloc_arg. */ |
334 | copy %r22,%r26 /* (1) function pointer */ |
335 | depi 0,31,2,%r26 /* clear least significant bits */ |
336 | ldw 8+4(%r20),%r25 /* (2) got[1] == struct link_map */ |
337 | |
338 | /* Save ltp and link map arg for _dl_fixup. */ |
339 | stw %r21,-92(%sp) /* ltp */ |
340 | stw %r25,-116(%sp) /* struct link map */ |
341 | |
342 | /* Find reloc offset. */ |
343 | bl _dl_fix_reloc_arg,%rp |
344 | copy %r21,%r19 /* set func ltp */ |
345 | |
346 | /* Restore fixup ltp. */ |
347 | ldw -92(%sp),%r21 /* ltp */ |
348 | |
349 | /* Set up args to fixup func, needs five arguments */ |
350 | ldw -116(%sp),%r26 /* (1) struct link map */ |
351 | copy %ret0,%r25 /* (2) reloc offset */ |
352 | stw %r25,-120(%sp) /* Save reloc offset */ |
353 | ldw -212(%sp),%r24 /* (3) profile_fixup needs rp */ |
354 | ldo -56(%sp),%r23 /* (4) La_hppa_regs */ |
355 | ldo -112(%sp), %r1 |
356 | b 3b |
357 | stw %r1, -52(%sp) /* (5) long int *framesizep */ |
358 | .EXIT |
359 | .PROCEND |
360 | cfi_endproc |
361 | .size _dl_runtime_profile, . - _dl_runtime_profile |
362 | |