1/* 2 * Copyright (C) 2019 The Android Open Source Project 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * * Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in 12 * the documentation and/or other materials provided with the 13 * distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 16 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 17 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 18 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 19 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 22 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 25 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29#include <platform/bionic/tls_defines.h> 30#include <private/bionic_asm.h> 31 32.globl __tls_get_addr 33 34// These resolver functions must preserve every register except x0. They set x0 35// to the offset of the TLS symbol relative to the thread pointer. 36 37ENTRY_PRIVATE(tlsdesc_resolver_static) 38 ldr x0, [x0, #8] 39 ret 40END(tlsdesc_resolver_static) 41 42ENTRY_PRIVATE(tlsdesc_resolver_dynamic) 43 stp x19, x20, [sp, #-32]! 44 .cfi_def_cfa_offset 32 45 .cfi_rel_offset x19, 0 46 .cfi_rel_offset x20, 8 47 stp x21, x22, [sp, #16] 48 .cfi_rel_offset x21, 16 49 .cfi_rel_offset x22, 24 50 51 mrs x19, tpidr_el0 // __get_tls() 52 ldr x20, [x19, #(TLS_SLOT_DTV * 8)] 53 ldr x21, [x20] // TlsDtv::generation 54 55 ldr x0, [x0, #8] // TlsDynamicResolverArg* 56 ldr x22, [x0] // TlsDynamicResolverArg::generation 57 58 cmp x21, x22 59 b.lo L(fallback) 60 61 ldr x21, [x0, #8] // TlsIndex::module_id 62 ldr x22, [x0, #16] // TlsIndex::offset 63 ldr x21, [x20, x21, lsl #3] // TlsDtv::modules[module_id] 64 cbz x21, L(fallback) 65 add x0, x21, x22 66 sub x0, x0, x19 67 68 ldp x21, x22, [sp, #16] 69 .cfi_remember_state 70 .cfi_restore x21 71 .cfi_restore x22 72 ldp x19, x20, [sp], #32 73 .cfi_adjust_cfa_offset -32 74 .cfi_restore x19 75 .cfi_restore x20 76 ret 77 78L(fallback): 79 .cfi_restore_state 80 ldp x21, x22, [sp, #16] 81 .cfi_restore x21 82 .cfi_restore x22 83 ldp x19, x20, [sp], #32 84 .cfi_adjust_cfa_offset -32 85 .cfi_restore x19 86 .cfi_restore x20 87 b tlsdesc_resolver_dynamic_slow_path 88END(tlsdesc_resolver_dynamic) 89 90#define SAVE_REG(x, slot) \ 91 str x, [sp, #((slot) * 8)]; \ 92 .cfi_rel_offset x, (slot) * 8; \ 93 94#define SAVE_GPR_PAIR(x, y, slot) \ 95 stp x, y, [sp, #((slot) * 8)]; \ 96 .cfi_rel_offset x, (slot) * 8; \ 97 .cfi_rel_offset y, ((slot) + 1) * 8; \ 98 99#define SAVE_VEC_PAIR(x, y, slot) \ 100 stp x, y, [sp, #((slot) * 8)]; \ 101 .cfi_rel_offset x, (slot) * 8; \ 102 .cfi_rel_offset y, ((slot) + 2) * 8; \ 103 104#define RESTORE_REG(x, slot) \ 105 ldr x, [sp, #((slot) * 8)]; \ 106 .cfi_restore x; \ 107 108#define RESTORE_REG_PAIR(x, y, slot) \ 109 ldp x, y, [sp, #((slot) * 8)]; \ 110 .cfi_restore x; \ 111 .cfi_restore y; \ 112 113// On entry, x0 is the address of a TlsDynamicResolverArg object rather than 114// the TlsDescriptor address passed to the original resolver function. 115ENTRY_PRIVATE(tlsdesc_resolver_dynamic_slow_path) 116 sub sp, sp, #(8 * 84) 117 .cfi_def_cfa_offset (8 * 84) 118 SAVE_GPR_PAIR(x29, x30, 0) 119 mov x29, sp 120 121 // Avoid leaking the contents of the shadow call stack register (x18) into 122 // memory. x19 through x29 are callee-save registers, so we do not need to 123 // save them. 124 SAVE_GPR_PAIR(x1, x2, 2) 125 SAVE_GPR_PAIR(x3, x4, 4) 126 SAVE_GPR_PAIR(x5, x6, 6) 127 SAVE_GPR_PAIR(x7, x8, 8) 128 SAVE_GPR_PAIR(x9, x10, 10) 129 SAVE_GPR_PAIR(x11, x12, 12) 130 SAVE_GPR_PAIR(x13, x14, 14) 131 SAVE_GPR_PAIR(x15, x16, 16) 132 SAVE_REG(x17, 18) 133 134 SAVE_VEC_PAIR(q0, q1, 20) 135 SAVE_VEC_PAIR(q2, q3, 24) 136 SAVE_VEC_PAIR(q4, q5, 28) 137 SAVE_VEC_PAIR(q6, q7, 32) 138 SAVE_VEC_PAIR(q8, q9, 36) 139 SAVE_VEC_PAIR(q10, q11, 40) 140 SAVE_VEC_PAIR(q12, q13, 44) 141 SAVE_VEC_PAIR(q14, q15, 48) 142 SAVE_VEC_PAIR(q16, q17, 52) 143 SAVE_VEC_PAIR(q18, q19, 56) 144 SAVE_VEC_PAIR(q20, q21, 60) 145 SAVE_VEC_PAIR(q22, q23, 64) 146 SAVE_VEC_PAIR(q24, q25, 68) 147 SAVE_VEC_PAIR(q26, q27, 72) 148 SAVE_VEC_PAIR(q28, q29, 76) 149 SAVE_VEC_PAIR(q30, q31, 80) 150 151 add x0, x0, #8 152 bl __tls_get_addr 153 mrs x1, tpidr_el0 // __get_tls() 154 sub x0, x0, x1 155 156 RESTORE_REG_PAIR(q30, q31, 80) 157 RESTORE_REG_PAIR(q28, q29, 76) 158 RESTORE_REG_PAIR(q26, q27, 72) 159 RESTORE_REG_PAIR(q24, q25, 68) 160 RESTORE_REG_PAIR(q22, q23, 64) 161 RESTORE_REG_PAIR(q20, q21, 60) 162 RESTORE_REG_PAIR(q18, q19, 56) 163 RESTORE_REG_PAIR(q16, q17, 52) 164 RESTORE_REG_PAIR(q14, q15, 48) 165 RESTORE_REG_PAIR(q12, q13, 44) 166 RESTORE_REG_PAIR(q10, q11, 40) 167 RESTORE_REG_PAIR(q8, q9, 36) 168 RESTORE_REG_PAIR(q6, q7, 32) 169 RESTORE_REG_PAIR(q4, q5, 28) 170 RESTORE_REG_PAIR(q2, q3, 24) 171 RESTORE_REG_PAIR(q0, q1, 20) 172 173 RESTORE_REG(x17, 18) 174 RESTORE_REG_PAIR(x15, x16, 16) 175 RESTORE_REG_PAIR(x13, x14, 14) 176 RESTORE_REG_PAIR(x11, x12, 12) 177 RESTORE_REG_PAIR(x9, x10, 10) 178 RESTORE_REG_PAIR(x7, x8, 8) 179 RESTORE_REG_PAIR(x5, x6, 6) 180 RESTORE_REG_PAIR(x3, x4, 4) 181 RESTORE_REG_PAIR(x1, x2, 2) 182 183 RESTORE_REG_PAIR(x29, x30, 0) 184 add sp, sp, #(8 * 84) 185 .cfi_def_cfa_offset 0 186 ret 187END(tlsdesc_resolver_dynamic_slow_path) 188 189// The address of an unresolved weak TLS symbol evaluates to NULL with TLSDESC. 190// The value returned by this function is added to the thread pointer, so return 191// a negated thread pointer to cancel it out. 192ENTRY_PRIVATE(tlsdesc_resolver_unresolved_weak) 193 str x19, [sp, #-16]! 194 .cfi_def_cfa_offset 16 195 .cfi_rel_offset x19, 0 196 ldr x19, [x0, #8] 197 mrs x0, tpidr_el0 // __get_tls() 198 sub x0, x19, x0 199 ldr x19, [sp], #16 200 .cfi_def_cfa_offset 0 201 .cfi_restore x19 202 ret 203END(tlsdesc_resolver_unresolved_weak) 204