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