]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - libexec/rtld-elf/aarch64/rtld_start.S
MFV r368607:
[FreeBSD/FreeBSD.git] / libexec / rtld-elf / aarch64 / rtld_start.S
1 /*-
2  * Copyright (c) 2014 The FreeBSD Foundation
3  * All rights reserved.
4  *
5  * This software was developed by Andrew Turner under
6  * sponsorship from the FreeBSD Foundation.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29
30 #include <machine/asm.h>
31 __FBSDID("$FreeBSD$");
32
33 ENTRY(.rtld_start)
34         mov     x19, x0         /* Put ps_strings in a callee-saved register */
35         mov     x20, sp         /* And the stack pointer */
36
37         sub     sp, sp, #16     /* Make room for obj_main & exit proc */
38
39         mov     x1, sp          /* exit_proc */
40         add     x2, x1, #8      /* obj_main */
41         bl      _rtld           /* Call the loader */
42         mov     x8, x0          /* Backup the entry point */
43
44         ldr     x2, [sp]        /* Load cleanup */
45         ldr     x1, [sp, #8]    /* Load obj_main */
46         mov     x0, x19         /* Restore ps_strings */
47         mov     sp, x20         /* Restore the stack pointer */
48         br      x8              /* Jump to the entry point */
49 END(.rtld_start)
50
51 /*
52  * sp + 0 = &GOT[x + 3]
53  * sp + 8 = RA
54  * x16 = &GOT[2]
55  * x17 = &_rtld_bind_start
56  */
57 ENTRY(_rtld_bind_start)
58         mov     x17, sp
59
60         /* Save frame pointer and SP */
61         stp     x29, x30, [sp, #-16]!
62         mov     x29, sp
63         .cfi_def_cfa x29, 16
64         .cfi_offset x30, -8
65         .cfi_offset x29, -16
66
67         /* Save the arguments */
68         stp     x0, x1, [sp, #-16]!
69         stp     x2, x3, [sp, #-16]!
70         stp     x4, x5, [sp, #-16]!
71         stp     x6, x7, [sp, #-16]!
72         stp     x8, xzr, [sp, #-16]!
73
74         /* Save any floating-point arguments */
75         stp     q0, q1, [sp, #-32]!
76         stp     q2, q3, [sp, #-32]!
77         stp     q4, q5, [sp, #-32]!
78         stp     q6, q7, [sp, #-32]!
79
80         /* Calculate reloff */
81         ldr     x2, [x17, #0]   /* Get the address of the entry */
82         sub     x1, x2, x16     /* Find its offset */
83         sub     x1, x1, #8      /* Adjust for x16 not being at offset 0 */
84         /* Each rela item has 3 entriesso we need reloff = 3 * index */
85         lsl     x3, x1, #1      /* x3 = 2 * offset */
86         add     x1, x1, x3      /* x1 = x3 + offset = 3 * offset */
87
88         /* Load obj */
89         ldr     x0, [x16, #-8]
90
91         /* Call into rtld */
92         bl      _rtld_bind
93
94         /* Backup the address to branch to */
95         mov     x16, x0
96
97         /* restore the arguments */
98         ldp     q6, q7, [sp], #32
99         ldp     q4, q5, [sp], #32
100         ldp     q2, q3, [sp], #32
101         ldp     q0, q1, [sp], #32
102         ldp     x8, xzr, [sp], #16
103         ldp     x6, x7, [sp], #16
104         ldp     x4, x5, [sp], #16
105         ldp     x2, x3, [sp], #16
106         ldp     x0, x1, [sp], #16
107
108         /* Restore frame pointer */
109         ldp     x29, xzr, [sp], #16
110
111          /* Restore link register saved by the plt code */
112         ldp     xzr, x30, [sp], #16
113
114         /* Call into the correct function */
115         br      x16
116 END(_rtld_bind_start)
117
118 /*
119  * struct rel_tlsdesc {
120  *  uint64_t resolver_fnc;
121  *  uint64_t resolver_arg;
122  *
123  *
124  * uint64_t _rtld_tlsdesc_static(struct rel_tlsdesc *);
125  *
126  * Resolver function for TLS symbols resolved at load time
127  */
128 ENTRY(_rtld_tlsdesc_static)
129         ldr     x0, [x0, #8]
130         ret
131 END(_rtld_tlsdesc_static)
132
133 /*
134  * uint64_t _rtld_tlsdesc_undef(void);
135  *
136  * Resolver function for weak and undefined TLS symbols
137  */
138 ENTRY(_rtld_tlsdesc_undef)
139         str     x1, [sp, #-16]!
140         .cfi_adjust_cfa_offset  16
141
142         mrs     x1, tpidr_el0
143         ldr     x0, [x0, #8]
144         sub     x0, x0, x1
145
146         ldr     x1, [sp], #16
147         .cfi_adjust_cfa_offset  -16
148         ret
149 END(_rtld_tlsdesc_undef)
150
151 /*
152  * uint64_t _rtld_tlsdesc_dynamic(struct rel_tlsdesc *);
153  *
154  * Resolver function for TLS symbols from dlopen()
155  */
156 ENTRY(_rtld_tlsdesc_dynamic)
157         /* Save registers used in fast path */
158         stp     x1,  x2, [sp, #(-2 * 16)]!
159         stp     x3,  x4, [sp, #(1 * 16)]
160         .cfi_adjust_cfa_offset  2 * 16
161         .cfi_rel_offset         x1, 0
162         .cfi_rel_offset         x2, 8
163         .cfi_rel_offset         x3, 16
164         .cfi_rel_offset         x4, 24
165
166         /* Test fastpath - inlined version of tls_get_addr_common(). */
167         ldr     x1, [x0, #8]            /* tlsdesc ptr */
168         mrs     x4, tpidr_el0
169         ldr     x0, [x4]                /* DTV pointer */
170         ldr     x2, [x0]                /* dtv[0] (generation count) */
171         ldr     x3, [x1]                /* tlsdec->dtv_gen */
172         cmp     x2, x3
173         b.ne    1f                      /* dtv[0] != tlsdec->dtv_gen */
174
175         ldr     w2, [x1, #8]            /* tlsdec->tls_index */
176         add     w2, w2, #1
177         ldr     x3, [x0, w2, sxtw #3]   /* dtv[tlsdesc->tls_index + 1] */
178         cbz     x3, 1f
179
180         /* Return (dtv[tlsdesc->tls_index + 1] + tlsdesc->tls_offs - tp) */
181         ldr     x2, [x1, #16]           /* tlsdec->tls_offs */
182         add     x2, x2, x3
183         sub     x0, x2, x4
184         /* Restore registers and return */
185         ldp      x3,  x4, [sp, #(1 * 16)]
186         ldp      x1,  x2, [sp], #(2 * 16)
187         .cfi_adjust_cfa_offset  -2 * 16
188         ret
189
190         /*
191          * Slow path
192           * return(
193          *    tls_get_addr_common(tp, tlsdesc->tls_index, tlsdesc->tls_offs));
194          *
195          */
196 1:
197         /* Save all interger registers */
198         stp     x29, x30, [sp, #-(8 * 16)]!
199         .cfi_adjust_cfa_offset  8 * 16
200         .cfi_rel_offset         x29, 0
201         .cfi_rel_offset         x30, 8
202
203         mov     x29, sp
204         stp     x5,   x6, [sp, #(1 * 16)]
205         stp     x7,   x8, [sp, #(2 * 16)]
206         stp     x9,  x10, [sp, #(3 * 16)]
207         stp     x11, x12, [sp, #(4 * 16)]
208         stp     x13, x14, [sp, #(5 * 16)]
209         stp     x15, x16, [sp, #(6 * 16)]
210         stp     x17, x18, [sp, #(7 * 16)]
211         .cfi_rel_offset          x5, 16
212         .cfi_rel_offset          x6, 24
213         .cfi_rel_offset          x7, 32
214         .cfi_rel_offset          x8, 40
215         .cfi_rel_offset          x9, 48
216         .cfi_rel_offset         x10, 56
217         .cfi_rel_offset         x11, 64
218         .cfi_rel_offset         x12, 72
219         .cfi_rel_offset         x13, 80
220         .cfi_rel_offset         x14, 88
221         .cfi_rel_offset         x15, 96
222         .cfi_rel_offset         x16, 104
223         .cfi_rel_offset         x17, 112
224         .cfi_rel_offset         x18, 120
225
226         /* Find the tls offset */
227         mov     x0, x4                  /* tp */
228         mov     x3, x1                  /* tlsdesc ptr */
229         ldr     w1, [x3, #8]            /* tlsdec->tls_index */
230         ldr     x2, [x3, #16]           /* tlsdec->tls_offs */
231         bl      tls_get_addr_common
232         mrs     x1, tpidr_el0
233         sub     x0, x0, x1
234
235         /* Restore slow patch registers */
236         ldp     x17, x18, [sp, #(7 * 16)]
237         ldp     x15, x16, [sp, #(6 * 16)]
238         ldp     x13, x14, [sp, #(5 * 16)]
239         ldp     x11, x12, [sp, #(4 * 16)]
240         ldp     x9, x10,  [sp, #(3 * 16)]
241         ldp     x7, x8,   [sp, #(2 * 16)]
242         ldp     x5, x6,   [sp, #(1 * 16)]
243         ldp     x29, x30, [sp], #(8 * 16)
244         .cfi_adjust_cfa_offset  -8 * 16
245         .cfi_restore            x29
246         .cfi_restore            x30
247
248         /* Restore fast path registers and return */
249         ldp      x3,  x4, [sp, #16]
250         ldp      x1,  x2, [sp], #(2 * 16)
251         .cfi_adjust_cfa_offset  -2 * 16
252         ret
253 END(_rtld_tlsdesc_dynamic)