1/* PLT trampolines. hppa version.
2   Copyright (C) 2005-2021 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. */
853:	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
1291:
130	/* Return to previous function */
131	ldw	-148(%sp),%rp
132	bv	%r0(%rp)
133	ldo	-128(%sp),%sp
134
1352:
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. */
2233:	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
259L(nf):
260	/* Call the returned function descriptor */
261	bv	%r0(%r22)
262	nop
263	b,n	L(cont)
264
265L(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 */
2851:	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
298L(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
3322:
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