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