1/* 2 * Copyright (C) 2024 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#include <private/bionic_elf_dtv_offset.h> 32 33#ifndef TLS_DTV_OFFSET 34 #error "TLS_DTV_OFFSET not defined" 35#endif 36 37.globl __tls_get_addr 38 39// spill a register onto the stack 40.macro spill reg, idx, f= 41 \f\()sd \reg, \idx*8(sp) 42 .cfi_rel_offset \reg, (\idx)*8 43.endm 44 45// reload a value from the stack 46.macro reload reg, idx, f= 47 \f\()ld \reg, \idx*8(sp) 48 .cfi_same_value \reg 49.endm 50 51.macro spill_vector_regs 52 csrr a3, vlenb 53 slli a3, a3, 3 54 sub sp, sp, a3 55 vs8r.v v0, (sp) 56 sub sp, sp, a3 57 vs8r.v v8, (sp) 58 sub sp, sp, a3 59 vs8r.v v16, (sp) 60 sub sp, sp, a3 61 vs8r.v v24, (sp) 62.endm 63 64.macro reload_vector_regs 65 csrr a3, vlenb 66 slli a3, a3, 3 67 vl8r.v v24, (sp) 68 add sp, sp, a3 69 vl8r.v v16, (sp) 70 add sp, sp, a3 71 vl8r.v v8, (sp) 72 add sp, sp, a3 73 vl8r.v v0, (sp) 74 add sp, sp, a3 75.endm 76 77// We save a total of 35 registers 78.macro for_each_saved_reg op max 79 \op ra, 1 80 \op a1, 2 81 \op a2, 3 82 \op a3, 4 83 \op a4, 5 84 \op a5, 6 85 \op a6, 7 86 \op a7, 8 87 \op t0, 9 88 \op t1, 10 89 \op t2, 11 90 \op t3, 12 91 \op t4, 13 92 \op t5, 14 93 \op t6, 15 94 // save floating point regs 95 \op ft0, 16, f 96 \op ft1, 17, f 97 \op ft2, 18, f 98 \op ft3, 19, f 99 \op ft4, 20, f 100 \op ft5, 21, f 101 \op ft6, 22, f 102 \op ft7, 23, f 103 \op ft8, 24, f 104 \op ft9, 25, f 105 \op ft10, 26, f 106 \op ft11, 27, f 107 \op fa0, 28, f 108 \op fa1, 29, f 109 \op fa2, 30, f 110 \op fa3, 31, f 111 \op fa4, 32, f 112 \op fa5, 33, f 113 \op fa6, 34, f 114 \op fa7, 35, f 115.endm 116 117// These resolver functions must preserve every register except a0. They set a0 118// to the offset of the TLS symbol relative to the thread pointer. 119 120ENTRY_PRIVATE(tlsdesc_resolver_static) 121 ld a0, 8(a0) 122 jr t0 123END(tlsdesc_resolver_static) 124 125ENTRY_PRIVATE(tlsdesc_resolver_dynamic) 126 // We only need 3 stack slots, but still require a 4th slot for alignment 127 addi sp, sp, -4*8 128 .cfi_def_cfa_offset 4*8 129 spill a1, 1 130 spill a2, 2 131 spill a3, 3 132 133 ld a2, (TLS_SLOT_DTV * 8)(tp) // a2 = &DTV 134 ld a1, (a2) // a1 = TlsDtv::generation (DTV[0]) 135 136 ld a0, 8(a0) // a0 = TlsDynamicResolverArg* 137 ld a3, (a0) // a3 = TlsDynamicResolverArg::generation 138 139 // Fallback if TlsDtv::generation < TlsDynamicResolverArg::generation 140 // since we need to call __tls_get_addr 141 blt a1, a3, L(fallback) 142 143 // We can't modify a0 yet, since tlsdesc_resolver_dynamic_slow_path requires 144 // a pointer to the TlsIndex, which is the second field of the 145 // TlsDynamicResolverArg. As a result, we can't modify a0 until we will no 146 // longer fallback. 147 ld a1, 8(a0) // a1 = TlsIndex::module_id 148 slli a1, a1, 3 // a1 = module_id*8 -- scale the idx 149 add a1, a2, a1 // a1 = &TlsDtv::modules[module_id] 150 ld a1, (a1) // a1 = TlsDtv::modules[module_id] 151 beqz a1, L(fallback) 152 ld a3, 16(a0) // a3 = TlsIndex::offset 153 add a0, a1, a3 // a0 = TlsDtv::modules[module_id] + offset 154 sub a0, a0, tp // a0 = TlsDtv::modules[module_id] + offset - tp 155 156 .cfi_remember_state 157 reload a3, 3 158 reload a2, 2 159 reload a1, 1 160 addi sp, sp, 4*8 161 .cfi_adjust_cfa_offset -4*8 162 jr t0 163 164L(fallback): 165 reload a3, 3 166 reload a2, 2 167 reload a1, 1 168 addi sp, sp, 4*8 169 .cfi_adjust_cfa_offset -4*8 170 j tlsdesc_resolver_dynamic_slow_path 171END(tlsdesc_resolver_dynamic) 172 173// On entry, a0 is the address of a TlsDynamicResolverArg object rather than 174// the TlsDescriptor address passed to the original resolver function. 175ENTRY_PRIVATE(tlsdesc_resolver_dynamic_slow_path) 176 // We save a total of 35 registers, but vector spills require an alignment 177 // of 16, so use an extra slot to align it correctly. 178 addi sp, sp, (-8*36) 179 .cfi_def_cfa_offset (8 * 36) 180 for_each_saved_reg spill, 36 181 spill_vector_regs 182 183 add a0, a0, 8 184 call __tls_get_addr 185 addi a0, a0, (-1 * TLS_DTV_OFFSET) // Correct the address by TLS_DTV_OFFSET 186 sub a0, a0, tp 187 188 reload_vector_regs 189 for_each_saved_reg reload, 36 190 addi sp, sp, 8*36 191 .cfi_def_cfa_offset 0 192 jr t0 193END(tlsdesc_resolver_dynamic_slow_path) 194 195// The address of an unresolved weak TLS symbol evaluates to NULL with TLSDESC. 196// The value returned by this function is added to the thread pointer, so return 197// a negated thread pointer to cancel it out. 198ENTRY_PRIVATE(tlsdesc_resolver_unresolved_weak) 199 sub a0, zero, tp 200 jr t0 201END(tlsdesc_resolver_unresolved_weak) 202