xref: /netbsd-src/libexec/ld.elf_so/arch/aarch64/rtld_start.S (revision a8c74629f602faa0ccf8a463757d7baf858bbf3a)
1/* $NetBSD: rtld_start.S,v 1.4 2019/01/18 11:59:03 skrll Exp $ */
2
3/*-
4 * Copyright (c) 2014 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Matt Thomas of 3am Software Foundry.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32/*-
33 * Copyright (c) 2014 The FreeBSD Foundation
34 * All rights reserved.
35 *
36 * This software was developed by Andrew Turner under
37 * sponsorship from the FreeBSD Foundation.
38 *
39 * Redistribution and use in source and binary forms, with or without
40 * modification, are permitted provided that the following conditions
41 * are met:
42 * 1. Redistributions of source code must retain the above copyright
43 *    notice, this list of conditions and the following disclaimer.
44 * 2. Redistributions in binary form must reproduce the above copyright
45 *    notice, this list of conditions and the following disclaimer in the
46 *    documentation and/or other materials provided with the distribution.
47 *
48 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
49 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
50 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
51 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
52 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
53 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
54 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
55 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
56 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
57 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
58 * SUCH DAMAGE.
59 */
60
61#include <machine/asm.h>
62
63RCSID("$NetBSD: rtld_start.S,v 1.4 2019/01/18 11:59:03 skrll Exp $")
64
65/*
66 * void _rtld_start(void (*cleanup)(void), const Obj_Entry *obj,
67 *    struct ps_strings *ps_strings);
68 *
69 * X0		= NULL
70 * X1		= NULL
71 * X2		= ps_strings
72 * X30 (LR)	= 0
73 * X29 (FP)	= 0
74 */
75ENTRY_NP(_rtld_start)
76	mov	x24, x2			/* save ps_strings */
77
78	adrp	x1, :got:_DYNAMIC	/* load _DYNAMIC offset from GOT */
79	ldr	x1, [x1, #:got_lo12:_DYNAMIC]
80
81	adrp	x0, _DYNAMIC		/* get &_DYNAMIC */
82	add	x0, x0, #:lo12:_DYNAMIC
83
84	sub	x25, x0, x1		/* relocbase = &_DYNAMIC - GOT:_DYNAMIC */
85	mov	x1, x25			/* pass as 2nd argument */
86	bl	_C_LABEL(_rtld_relocate_nonplt_self)
87
88	sub	sp, sp, #16		/* reserve space for returns */
89	mov	x0, sp			/* pointer to reserved space */
90	mov	x1, x25			/* pass relocbase */
91	bl	_C_LABEL(_rtld)
92	mov	x17, x0			/* save entry point */
93
94	ldp	x0, x1, [sp], #16	/* pop cleanup & obj_main */
95	mov	x2, x24			/* restore ps_strings */
96
97	br	x17			/* call saved entry point */
98END(_rtld_start)
99
100/*
101 * Upon entry from plt0 entry:
102 *
103 * SP+0		= &PLTGOT[n + 3]
104 * SP+8		= return addr
105 * X16		= &PLTGOT[2]
106 */
107ENTRY_NP(_rtld_bind_start)
108	ldr	x9, [sp]		/* x9 = &PLTGOT[n+3] */
109
110	/* save x0-x8 for arguments */
111	stp	x0, x1, [sp, #-16]!
112	stp	x2, x3, [sp, #-16]!
113	stp	x4, x5, [sp, #-16]!
114	stp	x6, x7, [sp, #-16]!
115	stp	x8, xzr, [sp, #-16]!
116
117	/* save q0-q7 for arguments */
118	stp	q0, q1, [sp, #-32]!
119	stp	q2, q3, [sp, #-32]!
120	stp	q4, q5, [sp, #-32]!
121	stp	q6, q7, [sp, #-32]!
122
123	ldr	x0, [x16, #-8]	/* x0 = PLTGOT[1] */
124	sub	x1, x9, x16	/* x1 = &PLTGOT[n+3] - &PLTGOT[1] = offset+8 */
125	sub	x1, x1, #8	/* x1 = offset */
126	lsr	x1, x1, #3	/* x1 /= sizeof(void *) */
127
128	bl	_C_LABEL(_rtld_bind)
129	mov	x17, x0		/* save result */
130
131	/* restore q0-q7 for arguments */
132	ldp	q6, q7, [sp], #32
133	ldp	q4, q5, [sp], #32
134	ldp	q2, q3, [sp], #32
135	ldp	q0, q1, [sp], #32
136
137	/* restore x0-x8 for arguments */
138	ldp	x8, xzr, [sp], #16
139	ldp	x6, x7, [sp], #16
140	ldp	x4, x5, [sp], #16
141	ldp	x2, x3, [sp], #16
142	ldp	x0, x1, [sp], #16
143
144	ldp	xzr, lr, [sp], #16	/* restore original lr pushed by plt0 */
145	br	x17			/* call bound function */
146END(_rtld_bind_start)
147
148/*
149 * struct rel_tlsdesc {
150 *  uint64_t resolver_fnc;
151 *  uint64_t resolver_arg;
152 *
153 *
154 * uint64_t _rtld_tlsdesc_static(struct rel_tlsdesc *);
155 *
156 * Resolver function for TLS symbols resolved at load time
157 */
158ENTRY(_rtld_tlsdesc_static)
159	.cfi_startproc
160	ldr	x0, [x0, #8]
161	ret
162	.cfi_endproc
163END(_rtld_tlsdesc_static)
164
165/*
166 * uint64_t _rtld_tlsdesc_undef(void);
167 *
168 * Resolver function for weak and undefined TLS symbols
169 */
170ENTRY(_rtld_tlsdesc_undef)
171	.cfi_startproc
172	str	x1, [sp, #-16]!
173	.cfi_adjust_cfa_offset	16
174
175	mrs	x1, tpidr_el0
176	ldr	x0, [x0, #8]
177	sub	x0, x0, x1
178
179	ldr	x1, [sp], #16
180	.cfi_adjust_cfa_offset 	-16
181	.cfi_endproc
182	ret
183END(_rtld_tlsdesc_undef)
184
185/*
186 * uint64_t _rtld_tlsdesc_dynamic(struct rel_tlsdesc *);
187 *
188 * Resolver function for TLS symbols from dlopen()
189 */
190ENTRY(_rtld_tlsdesc_dynamic)
191	.cfi_startproc
192
193	/* Save registers used in fast path */
194	stp	x1,  x2, [sp, #(-2 * 16)]!
195	stp	x3,  x4, [sp, #(1 * 16)]
196	.cfi_adjust_cfa_offset	2 * 16
197	.cfi_rel_offset		x1, 0
198	.cfi_rel_offset		x2, 8
199	.cfi_rel_offset		x3, 16
200	.cfi_rel_offset		x4, 24
201
202	/* Test fastpath - inlined version of __tls_get_addr. */
203
204	ldr	x1, [x0, #8]		/* tlsdesc ptr */
205	mrs	x4, tpidr_el0
206	ldr	x0, [x4]		/* DTV pointer (tcb->tcb_dtv) */
207
208	ldr	x3, [x0, #-8]		/* DTV_MAX_INDEX(dtv) */
209	ldr	x2, [x1, #0]		/* tlsdesc->td_tlsindex */
210	cmp	x2, x3
211	b.lt	1f			/* Slow path */
212
213	ldr     x3, [x0, x2, lsl #3]	/* dtv[tlsdesc->td_tlsindex] */
214	cbz	x3, 1f
215
216	/* Return (dtv[tlsdesc->td_tlsindex] + tlsdesc->td_tlsoffs - tp) */
217	ldr	x2, [x1, #8]		/* tlsdesc->td_tlsoffs */
218	add 	x2, x2, x3
219	sub	x0, x2, x4
220
221	/* Restore registers and return */
222	ldp	 x3,  x4, [sp, #(1 * 16)]
223	ldp	 x1,  x2, [sp], #(2 * 16)
224	.cfi_adjust_cfa_offset 	-2 * 16
225	ret
226
227	/*
228	 * Slow path
229	 * return _rtld_tls_get_addr(tp, tlsdesc->td_tlsindex, tlsdesc->td_tlsoffs);
230	 *
231	 */
2321:
233	/* Save all interger registers */
234	stp	x29, x30, [sp, #-(8 * 16)]!
235	.cfi_adjust_cfa_offset	8 * 16
236	.cfi_rel_offset		x29, 0
237	.cfi_rel_offset		x30, 8
238
239	stp	x5,   x6, [sp, #(1 * 16)]
240	stp	x7,   x8, [sp, #(2 * 16)]
241	stp	x9,  x10, [sp, #(3 * 16)]
242	stp	x11, x12, [sp, #(4 * 16)]
243	stp	x13, x14, [sp, #(5 * 16)]
244	stp	x15, x16, [sp, #(6 * 16)]
245	stp	x17, x18, [sp, #(7 * 16)]
246	.cfi_rel_offset		 x5, 16
247	.cfi_rel_offset		 x6, 24
248	.cfi_rel_offset		 x7, 32
249	.cfi_rel_offset		 x8, 40
250	.cfi_rel_offset		 x9, 48
251	.cfi_rel_offset		x10, 56
252	.cfi_rel_offset		x11, 64
253	.cfi_rel_offset		x12, 72
254	.cfi_rel_offset		x13, 80
255	.cfi_rel_offset		x14, 88
256	.cfi_rel_offset		x15, 96
257	.cfi_rel_offset		x16, 104
258	.cfi_rel_offset		x17, 112
259	.cfi_rel_offset		x18, 120
260
261	/* Find the tls offset */
262	mov	x0, x4			/* tp */
263	mov	x3, x1			/* tlsdesc ptr */
264	ldr	x1, [x3, #0]		/* tlsdesc->td_tlsindex */
265	ldr	x2, [x3, #8]		/* tlsdesc->td_tlsoffs */
266	bl	_rtld_tls_get_addr
267	mrs	x1, tpidr_el0
268	sub	x0, x0, x1
269
270	/* Restore slow path registers */
271	ldp	x17, x18, [sp, #(7 * 16)]
272	ldp	x15, x16, [sp, #(6 * 16)]
273	ldp	x13, x14, [sp, #(5 * 16)]
274	ldp	x11, x12, [sp, #(4 * 16)]
275	ldp	x9, x10,  [sp, #(3 * 16)]
276	ldp	x7, x8,   [sp, #(2 * 16)]
277	ldp	x5, x6,   [sp, #(1 * 16)]
278	ldp	x29, x30, [sp], #(8 * 16)
279	.cfi_adjust_cfa_offset 	-8 * 16
280	.cfi_restore		x29
281	.cfi_restore		x30
282
283	/* Restore fast path registers and return */
284	ldp	 x3,  x4, [sp, #16]
285	ldp	 x1,  x2, [sp], #(2 * 16)
286	.cfi_adjust_cfa_offset	-2 * 16
287	.cfi_endproc
288	ret
289END(_rtld_tlsdesc_dynamic)
290