1/* Copyright (C) 2005-2021 Free Software Foundation, Inc.
2
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 License as
7   published by the Free Software Foundation; either version 2.1 of the
8   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 <libc-symbols.h>
21
22#include "dl-link.h"
23
24#define ip0 x16
25#define ip0l PTR_REG (16)
26#define ip1 x17
27#define lr  x30
28
29/* RELA relocatons are 3 pointers */
30#define RELA_SIZE (PTR_SIZE * 3)
31
32	.text
33	.globl _dl_runtime_resolve
34	.type _dl_runtime_resolve, #function
35	cfi_startproc
36	.align 2
37_dl_runtime_resolve:
38	BTI_C
39	/* AArch64 we get called with:
40	   ip0		&PLTGOT[2]
41	   ip1		temp(dl resolver entry point)
42	   [sp, #8]	lr
43	   [sp, #0]	&PLTGOT[n]
44	 */
45
46	cfi_rel_offset (lr, 8)
47
48	/* Save arguments.  */
49	stp	x8, x9, [sp, #-(80+8*16)]!
50	cfi_adjust_cfa_offset (80+8*16)
51	cfi_rel_offset (x8, 0)
52	cfi_rel_offset (x9, 8)
53
54	stp	x6, x7, [sp,  #16]
55	cfi_rel_offset (x6, 16)
56	cfi_rel_offset (x7, 24)
57
58	stp	x4, x5, [sp,  #32]
59	cfi_rel_offset (x4, 32)
60	cfi_rel_offset (x5, 40)
61
62	stp	x2, x3, [sp,  #48]
63	cfi_rel_offset (x2, 48)
64	cfi_rel_offset (x3, 56)
65
66	stp	x0, x1, [sp,  #64]
67	cfi_rel_offset (x0, 64)
68	cfi_rel_offset (x1, 72)
69
70	stp	q0, q1, [sp, #(80+0*16)]
71	cfi_rel_offset (q0, 80+0*16)
72	cfi_rel_offset (q1, 80+1*16)
73
74	stp	q2, q3, [sp, #(80+2*16)]
75	cfi_rel_offset (q0, 80+2*16)
76	cfi_rel_offset (q1, 80+3*16)
77
78	stp	q4, q5, [sp, #(80+4*16)]
79	cfi_rel_offset (q0, 80+4*16)
80	cfi_rel_offset (q1, 80+5*16)
81
82	stp	q6, q7, [sp, #(80+6*16)]
83	cfi_rel_offset (q0, 80+6*16)
84	cfi_rel_offset (q1, 80+7*16)
85
86	/* Get pointer to linker struct.  */
87	ldr	PTR_REG (0), [ip0, #-PTR_SIZE]
88
89	/* Prepare to call _dl_fixup().  */
90	ldr	x1, [sp, 80+8*16]	/* Recover &PLTGOT[n] */
91
92	sub     x1, x1, ip0
93	add     x1, x1, x1, lsl #1
94	lsl     x1, x1, #3
95	sub     x1, x1, #(RELA_SIZE<<3)
96	lsr     x1, x1, #3
97
98	/* Call fixup routine.  */
99	bl	_dl_fixup
100
101	/* Save the return.  */
102	mov	ip0, x0
103
104	/* Get arguments and return address back.  */
105	ldp	q0, q1, [sp, #(80+0*16)]
106	ldp	q2, q3, [sp, #(80+2*16)]
107	ldp	q4, q5, [sp, #(80+4*16)]
108	ldp	q6, q7, [sp, #(80+6*16)]
109	ldp	x0, x1, [sp, #64]
110	ldp	x2, x3, [sp, #48]
111	ldp	x4, x5, [sp, #32]
112	ldp	x6, x7, [sp, #16]
113	ldp	x8, x9, [sp], #(80+8*16)
114	cfi_adjust_cfa_offset (-(80+8*16))
115
116	ldp	ip1, lr, [sp], #16
117	cfi_adjust_cfa_offset (-16)
118
119	/* Jump to the newly found address.  */
120	br	ip0
121
122	cfi_endproc
123	.size _dl_runtime_resolve, .-_dl_runtime_resolve
124#ifndef PROF
125	.globl _dl_runtime_profile
126	.type _dl_runtime_profile, #function
127	cfi_startproc
128	.align 2
129_dl_runtime_profile:
130# if HAVE_AARCH64_PAC_RET
131	PACIASP
132	cfi_window_save
133# else
134	BTI_C
135# endif
136	/* AArch64 we get called with:
137	   ip0		&PLTGOT[2]
138	   ip1		temp(dl resolver entry point)
139	   [sp, #8]	lr
140	   [sp, #0]	&PLTGOT[n]
141
142	   Stack frame layout:
143	   [sp,   #...] lr
144	   [sp,   #...] &PLTGOT[n]
145	   [sp,    #96] La_aarch64_regs
146	   [sp,    #48] La_aarch64_retval
147	   [sp,    #40] frame size return from pltenter
148	   [sp,    #32] dl_profile_call saved x1
149	   [sp,    #24] dl_profile_call saved x0
150	   [sp,    #16] t1
151	   [sp,     #0] x29, lr   <- x29
152	 */
153
154# define OFFSET_T1		16
155# define OFFSET_SAVED_CALL_X0	OFFSET_T1 + 8
156# define OFFSET_FS		OFFSET_SAVED_CALL_X0 + 16
157# define OFFSET_RV		OFFSET_FS + 8
158# define OFFSET_RG		OFFSET_RV + DL_SIZEOF_RV
159
160# define SF_SIZE		OFFSET_RG + DL_SIZEOF_RG
161
162# define OFFSET_PLTGOTN		SF_SIZE
163# define OFFSET_LR		OFFSET_PLTGOTN + 8
164
165	/* Save arguments.  */
166	sub	sp, sp, #SF_SIZE
167	cfi_adjust_cfa_offset (SF_SIZE)
168	stp	x29, x30, [SP, #0]
169	mov	x29, sp
170	cfi_def_cfa_register (x29)
171	cfi_rel_offset (x29, 0)
172	cfi_rel_offset (lr, 8)
173
174	stp	x0, x1, [x29, #OFFSET_RG + DL_OFFSET_RG_X0 + 16*0]
175	cfi_rel_offset (x0, OFFSET_RG + DL_OFFSET_RG_X0 + 16*0 + 0)
176	cfi_rel_offset (x1, OFFSET_RG + DL_OFFSET_RG_X0 + 16*0 + 8)
177	stp	x2, x3, [x29, #OFFSET_RG + DL_OFFSET_RG_X0 + 16*1]
178	cfi_rel_offset (x2, OFFSET_RG + DL_OFFSET_RG_X0 + 16*1 + 0)
179	cfi_rel_offset (x3, OFFSET_RG + DL_OFFSET_RG_X0 + 16*1 + 8)
180	stp	x4, x5, [x29, #OFFSET_RG + DL_OFFSET_RG_X0 + 16*2]
181	cfi_rel_offset (x4, OFFSET_RG + DL_OFFSET_RG_X0 + 16*2 + 0)
182	cfi_rel_offset (x5, OFFSET_RG + DL_OFFSET_RG_X0 + 16*2 + 8)
183	stp	x6, x7, [x29, #OFFSET_RG + DL_OFFSET_RG_X0 + 16*3]
184	cfi_rel_offset (x6, OFFSET_RG + DL_OFFSET_RG_X0 + 16*3 + 0)
185	cfi_rel_offset (x7, OFFSET_RG + DL_OFFSET_RG_X0 + 16*3 + 8)
186
187	stp	d0, d1, [X29, #OFFSET_RG + DL_OFFSET_RG_D0 + 16*0]
188	cfi_rel_offset (d0, OFFSET_RG + DL_OFFSET_RG_D0 + 16*0)
189	cfi_rel_offset (d1, OFFSET_RG + DL_OFFSET_RG_D0 + 16*0 + 8)
190	stp	d2, d3, [X29, #OFFSET_RG+ DL_OFFSET_RG_D0 + 16*1]
191	cfi_rel_offset (d2, OFFSET_RG + DL_OFFSET_RG_D0 + 16*1 + 0)
192	cfi_rel_offset (d3, OFFSET_RG + DL_OFFSET_RG_D0 + 16*1 + 8)
193	stp	d4, d5, [X29, #OFFSET_RG + DL_OFFSET_RG_D0 + 16*2]
194	cfi_rel_offset (d4, OFFSET_RG + DL_OFFSET_RG_D0 + 16*2 + 0)
195	cfi_rel_offset (d5, OFFSET_RG + DL_OFFSET_RG_D0 + 16*2 + 8)
196	stp	d6, d7, [X29, #OFFSET_RG + DL_OFFSET_RG_D0 + 16*3]
197	cfi_rel_offset (d6, OFFSET_RG + DL_OFFSET_RG_D0 + 16*3 + 0)
198	cfi_rel_offset (d7, OFFSET_RG + DL_OFFSET_RG_D0 + 16*3 + 8)
199
200	add     x0, x29, #SF_SIZE + 16
201	ldr	x1, [x29, #OFFSET_LR]
202	stp	x0, x1, [x29, #OFFSET_RG + DL_OFFSET_RG_SP]
203
204	/* Get pointer to linker struct.  */
205	ldr	PTR_REG (0), [ip0, #-PTR_SIZE]
206
207	/* Prepare to call _dl_profile_fixup().  */
208	ldr	x1, [x29, OFFSET_PLTGOTN]	/* Recover &PLTGOT[n] */
209
210	sub     x1, x1, ip0
211	add     x1, x1, x1, lsl #1
212	lsl     x1, x1, #3
213	sub     x1, x1, #(RELA_SIZE<<3)
214	lsr     x1, x1, #3
215
216	stp	x0, x1, [x29, #OFFSET_SAVED_CALL_X0]
217
218	/* Set up extra args for _dl_profile_fixup */
219	ldr	x2, [x29, #OFFSET_LR]		/* load saved LR */
220	add	x3, x29, #OFFSET_RG		/* address of La_aarch64_reg */
221	add	x4, x29, #OFFSET_FS		/* address of framesize */
222	bl	_dl_profile_fixup
223
224	ldr	ip0l, [x29, #OFFSET_FS]		/* framesize == 0 */
225	cmp	ip0l, #0
226	bge	1f
227	cfi_remember_state
228
229	/* Save the return.  */
230	mov	ip0, x0
231
232	/* Get arguments and return address back.  */
233	ldp	x0, x1, [x29, #OFFSET_RG + DL_OFFSET_RG_X0 + 16*0]
234	ldp	x2, x3, [x29, #OFFSET_RG + DL_OFFSET_RG_X0 + 16*1]
235	ldp	x4, x5, [x29, #OFFSET_RG + DL_OFFSET_RG_X0 + 16*2]
236	ldp	x6, x7, [x29, #OFFSET_RG + DL_OFFSET_RG_X0 + 16*3]
237	ldp	d0, d1, [x29, #OFFSET_RG + DL_OFFSET_RG_D0 + 16*0]
238	ldp	d2, d3, [x29, #OFFSET_RG + DL_OFFSET_RG_D0 + 16*1]
239	ldp	d4, d5, [x29, #OFFSET_RG + DL_OFFSET_RG_D0 + 16*2]
240	ldp	d6, d7, [x29, #OFFSET_RG + DL_OFFSET_RG_D0 + 16*3]
241
242	cfi_def_cfa_register (sp)
243	ldp	x29, x30, [x29, #0]
244	cfi_restore(x29)
245	cfi_restore(x30)
246
247# if HAVE_AARCH64_PAC_RET
248	add	sp, sp, SF_SIZE
249	cfi_adjust_cfa_offset (-SF_SIZE)
250	AUTIASP
251	cfi_window_save
252	add	sp, sp, 16
253	cfi_adjust_cfa_offset (-16)
254# else
255	add	sp, sp, SF_SIZE + 16
256	cfi_adjust_cfa_offset (- SF_SIZE - 16)
257# endif
258
259	/* Jump to the newly found address.  */
260	br	ip0
261
262	cfi_restore_state
2631:
264	/* The new frame size is in ip0.  */
265
266	sub	PTR_REG (1), PTR_REG (29), ip0l
267	and	sp, x1, #0xfffffffffffffff0
268
269	str	x0, [x29, #OFFSET_T1]
270
271	mov	x0, sp
272	add	x1, x29, #SF_SIZE + 16
273	mov	x2, ip0
274	bl	memcpy
275
276	ldr	ip0, [x29, #OFFSET_T1]
277
278	/* Call the function.  */
279	ldp	x0, x1, [x29, #OFFSET_RG + DL_OFFSET_RG_X0 + 16*0]
280	ldp	x2, x3, [x29, #OFFSET_RG + DL_OFFSET_RG_X0 + 16*1]
281	ldp	x4, x5, [x29, #OFFSET_RG + DL_OFFSET_RG_X0 + 16*2]
282	ldp	x6, x7, [x29, #OFFSET_RG + DL_OFFSET_RG_X0 + 16*3]
283	ldp	d0, d1, [x29, #OFFSET_RG + DL_OFFSET_RG_D0 + 16*0]
284	ldp	d2, d3, [x29, #OFFSET_RG + DL_OFFSET_RG_D0 + 16*1]
285	ldp	d4, d5, [x29, #OFFSET_RG + DL_OFFSET_RG_D0 + 16*2]
286	ldp	d6, d7, [x29, #OFFSET_RG + DL_OFFSET_RG_D0 + 16*3]
287	blr	ip0
288	stp	x0, x1, [x29, #OFFSET_RV + DL_OFFSET_RV_X0]
289	stp	d0, d1, [x29, #OFFSET_RV + DL_OFFSET_RV_D0 + 16*0]
290	stp	d2, d3, [x29, #OFFSET_RV + DL_OFFSET_RV_D0 + 16*1]
291
292	/* Setup call to pltexit  */
293	ldp	x0, x1, [x29, #OFFSET_SAVED_CALL_X0]
294	add	x2, x29, #OFFSET_RG
295	add	x3, x29, #OFFSET_RV
296	bl	_dl_audit_pltexit
297
298	ldp	x0, x1, [x29, #OFFSET_RV + DL_OFFSET_RV_X0]
299	ldp	d0, d1, [x29, #OFFSET_RV + DL_OFFSET_RV_D0 + 16*0]
300	ldp	d2, d3, [x29, #OFFSET_RV + DL_OFFSET_RV_D0 + 16*1]
301	/* LR from within La_aarch64_reg */
302	ldr	lr, [x29, #OFFSET_RG + DL_OFFSET_RG_LR]
303	cfi_restore(lr)
304# if HAVE_AARCH64_PAC_RET
305	/* Note: LR restored from La_aarch64_reg has no PAC.  */
306	cfi_window_save
307# endif
308	mov	sp, x29
309	cfi_def_cfa_register (sp)
310	ldr	x29, [x29, #0]
311	cfi_restore(x29)
312	add	sp, sp, SF_SIZE + 16
313	cfi_adjust_cfa_offset (- SF_SIZE - 16)
314
315	br	lr
316
317	cfi_endproc
318	.size _dl_runtime_profile, .-_dl_runtime_profile
319#endif
320	.previous
321