xref: /aosp_15_r20/bionic/linker/arch/riscv64/tlsdesc_resolver.S (revision 8d67ca893c1523eb926b9080dbe4e2ffd2a27ba1)
1*8d67ca89SAndroid Build Coastguard Worker/*
2*8d67ca89SAndroid Build Coastguard Worker * Copyright (C) 2024 The Android Open Source Project
3*8d67ca89SAndroid Build Coastguard Worker * All rights reserved.
4*8d67ca89SAndroid Build Coastguard Worker *
5*8d67ca89SAndroid Build Coastguard Worker * Redistribution and use in source and binary forms, with or without
6*8d67ca89SAndroid Build Coastguard Worker * modification, are permitted provided that the following conditions
7*8d67ca89SAndroid Build Coastguard Worker * are met:
8*8d67ca89SAndroid Build Coastguard Worker *  * Redistributions of source code must retain the above copyright
9*8d67ca89SAndroid Build Coastguard Worker *    notice, this list of conditions and the following disclaimer.
10*8d67ca89SAndroid Build Coastguard Worker *  * Redistributions in binary form must reproduce the above copyright
11*8d67ca89SAndroid Build Coastguard Worker *    notice, this list of conditions and the following disclaimer in
12*8d67ca89SAndroid Build Coastguard Worker *    the documentation and/or other materials provided with the
13*8d67ca89SAndroid Build Coastguard Worker *    distribution.
14*8d67ca89SAndroid Build Coastguard Worker *
15*8d67ca89SAndroid Build Coastguard Worker * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16*8d67ca89SAndroid Build Coastguard Worker * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17*8d67ca89SAndroid Build Coastguard Worker * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
18*8d67ca89SAndroid Build Coastguard Worker * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
19*8d67ca89SAndroid Build Coastguard Worker * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
20*8d67ca89SAndroid Build Coastguard Worker * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21*8d67ca89SAndroid Build Coastguard Worker * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
22*8d67ca89SAndroid Build Coastguard Worker * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23*8d67ca89SAndroid Build Coastguard Worker * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24*8d67ca89SAndroid Build Coastguard Worker * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
25*8d67ca89SAndroid Build Coastguard Worker * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26*8d67ca89SAndroid Build Coastguard Worker * SUCH DAMAGE.
27*8d67ca89SAndroid Build Coastguard Worker */
28*8d67ca89SAndroid Build Coastguard Worker
29*8d67ca89SAndroid Build Coastguard Worker#include <platform/bionic/tls_defines.h>
30*8d67ca89SAndroid Build Coastguard Worker#include <private/bionic_asm.h>
31*8d67ca89SAndroid Build Coastguard Worker#include <private/bionic_elf_dtv_offset.h>
32*8d67ca89SAndroid Build Coastguard Worker
33*8d67ca89SAndroid Build Coastguard Worker#ifndef TLS_DTV_OFFSET
34*8d67ca89SAndroid Build Coastguard Worker  #error "TLS_DTV_OFFSET not defined"
35*8d67ca89SAndroid Build Coastguard Worker#endif
36*8d67ca89SAndroid Build Coastguard Worker
37*8d67ca89SAndroid Build Coastguard Worker.globl __tls_get_addr
38*8d67ca89SAndroid Build Coastguard Worker
39*8d67ca89SAndroid Build Coastguard Worker// spill a register onto the stack
40*8d67ca89SAndroid Build Coastguard Worker.macro spill reg, idx, f=
41*8d67ca89SAndroid Build Coastguard Worker  \f\()sd \reg, \idx*8(sp)
42*8d67ca89SAndroid Build Coastguard Worker  .cfi_rel_offset \reg, (\idx)*8
43*8d67ca89SAndroid Build Coastguard Worker.endm
44*8d67ca89SAndroid Build Coastguard Worker
45*8d67ca89SAndroid Build Coastguard Worker// reload a value from the stack
46*8d67ca89SAndroid Build Coastguard Worker.macro reload reg, idx, f=
47*8d67ca89SAndroid Build Coastguard Worker  \f\()ld \reg, \idx*8(sp)
48*8d67ca89SAndroid Build Coastguard Worker  .cfi_same_value \reg
49*8d67ca89SAndroid Build Coastguard Worker.endm
50*8d67ca89SAndroid Build Coastguard Worker
51*8d67ca89SAndroid Build Coastguard Worker.macro spill_vector_regs
52*8d67ca89SAndroid Build Coastguard Worker  csrr a3, vlenb
53*8d67ca89SAndroid Build Coastguard Worker  slli a3, a3, 3
54*8d67ca89SAndroid Build Coastguard Worker  sub sp, sp, a3
55*8d67ca89SAndroid Build Coastguard Worker  vs8r.v v0, (sp)
56*8d67ca89SAndroid Build Coastguard Worker  sub sp, sp, a3
57*8d67ca89SAndroid Build Coastguard Worker  vs8r.v v8, (sp)
58*8d67ca89SAndroid Build Coastguard Worker  sub sp, sp, a3
59*8d67ca89SAndroid Build Coastguard Worker  vs8r.v v16, (sp)
60*8d67ca89SAndroid Build Coastguard Worker  sub sp, sp, a3
61*8d67ca89SAndroid Build Coastguard Worker  vs8r.v v24, (sp)
62*8d67ca89SAndroid Build Coastguard Worker.endm
63*8d67ca89SAndroid Build Coastguard Worker
64*8d67ca89SAndroid Build Coastguard Worker.macro reload_vector_regs
65*8d67ca89SAndroid Build Coastguard Worker  csrr a3, vlenb
66*8d67ca89SAndroid Build Coastguard Worker  slli a3, a3, 3
67*8d67ca89SAndroid Build Coastguard Worker  vl8r.v v24, (sp)
68*8d67ca89SAndroid Build Coastguard Worker  add sp, sp, a3
69*8d67ca89SAndroid Build Coastguard Worker  vl8r.v v16, (sp)
70*8d67ca89SAndroid Build Coastguard Worker  add sp, sp, a3
71*8d67ca89SAndroid Build Coastguard Worker  vl8r.v v8, (sp)
72*8d67ca89SAndroid Build Coastguard Worker  add sp, sp, a3
73*8d67ca89SAndroid Build Coastguard Worker  vl8r.v v0, (sp)
74*8d67ca89SAndroid Build Coastguard Worker  add sp, sp, a3
75*8d67ca89SAndroid Build Coastguard Worker.endm
76*8d67ca89SAndroid Build Coastguard Worker
77*8d67ca89SAndroid Build Coastguard Worker// We save a total of 35 registers
78*8d67ca89SAndroid Build Coastguard Worker.macro for_each_saved_reg op max
79*8d67ca89SAndroid Build Coastguard Worker  \op ra, 1
80*8d67ca89SAndroid Build Coastguard Worker  \op a1, 2
81*8d67ca89SAndroid Build Coastguard Worker  \op a2, 3
82*8d67ca89SAndroid Build Coastguard Worker  \op a3, 4
83*8d67ca89SAndroid Build Coastguard Worker  \op a4, 5
84*8d67ca89SAndroid Build Coastguard Worker  \op a5, 6
85*8d67ca89SAndroid Build Coastguard Worker  \op a6, 7
86*8d67ca89SAndroid Build Coastguard Worker  \op a7, 8
87*8d67ca89SAndroid Build Coastguard Worker  \op t0, 9
88*8d67ca89SAndroid Build Coastguard Worker  \op t1, 10
89*8d67ca89SAndroid Build Coastguard Worker  \op t2, 11
90*8d67ca89SAndroid Build Coastguard Worker  \op t3, 12
91*8d67ca89SAndroid Build Coastguard Worker  \op t4, 13
92*8d67ca89SAndroid Build Coastguard Worker  \op t5, 14
93*8d67ca89SAndroid Build Coastguard Worker  \op t6, 15
94*8d67ca89SAndroid Build Coastguard Worker  // save floating point regs
95*8d67ca89SAndroid Build Coastguard Worker  \op ft0, 16, f
96*8d67ca89SAndroid Build Coastguard Worker  \op ft1, 17, f
97*8d67ca89SAndroid Build Coastguard Worker  \op ft2, 18, f
98*8d67ca89SAndroid Build Coastguard Worker  \op ft3, 19, f
99*8d67ca89SAndroid Build Coastguard Worker  \op ft4, 20, f
100*8d67ca89SAndroid Build Coastguard Worker  \op ft5, 21, f
101*8d67ca89SAndroid Build Coastguard Worker  \op ft6, 22, f
102*8d67ca89SAndroid Build Coastguard Worker  \op ft7, 23, f
103*8d67ca89SAndroid Build Coastguard Worker  \op ft8, 24, f
104*8d67ca89SAndroid Build Coastguard Worker  \op ft9, 25, f
105*8d67ca89SAndroid Build Coastguard Worker  \op ft10, 26, f
106*8d67ca89SAndroid Build Coastguard Worker  \op ft11, 27, f
107*8d67ca89SAndroid Build Coastguard Worker  \op fa0, 28, f
108*8d67ca89SAndroid Build Coastguard Worker  \op fa1, 29, f
109*8d67ca89SAndroid Build Coastguard Worker  \op fa2, 30, f
110*8d67ca89SAndroid Build Coastguard Worker  \op fa3, 31, f
111*8d67ca89SAndroid Build Coastguard Worker  \op fa4, 32, f
112*8d67ca89SAndroid Build Coastguard Worker  \op fa5, 33, f
113*8d67ca89SAndroid Build Coastguard Worker  \op fa6, 34, f
114*8d67ca89SAndroid Build Coastguard Worker  \op fa7, 35, f
115*8d67ca89SAndroid Build Coastguard Worker.endm
116*8d67ca89SAndroid Build Coastguard Worker
117*8d67ca89SAndroid Build Coastguard Worker// These resolver functions must preserve every register except a0. They set a0
118*8d67ca89SAndroid Build Coastguard Worker// to the offset of the TLS symbol relative to the thread pointer.
119*8d67ca89SAndroid Build Coastguard Worker
120*8d67ca89SAndroid Build Coastguard WorkerENTRY_PRIVATE(tlsdesc_resolver_static)
121*8d67ca89SAndroid Build Coastguard Worker  ld a0, 8(a0)
122*8d67ca89SAndroid Build Coastguard Worker  jr t0
123*8d67ca89SAndroid Build Coastguard WorkerEND(tlsdesc_resolver_static)
124*8d67ca89SAndroid Build Coastguard Worker
125*8d67ca89SAndroid Build Coastguard WorkerENTRY_PRIVATE(tlsdesc_resolver_dynamic)
126*8d67ca89SAndroid Build Coastguard Worker  // We only need 3 stack slots, but still require a 4th slot for alignment
127*8d67ca89SAndroid Build Coastguard Worker  addi sp, sp, -4*8
128*8d67ca89SAndroid Build Coastguard Worker  .cfi_def_cfa_offset 4*8
129*8d67ca89SAndroid Build Coastguard Worker  spill a1, 1
130*8d67ca89SAndroid Build Coastguard Worker  spill a2, 2
131*8d67ca89SAndroid Build Coastguard Worker  spill a3, 3
132*8d67ca89SAndroid Build Coastguard Worker
133*8d67ca89SAndroid Build Coastguard Worker  ld a2, (TLS_SLOT_DTV * 8)(tp) // a2 = &DTV
134*8d67ca89SAndroid Build Coastguard Worker  ld a1, (a2)                   // a1 = TlsDtv::generation (DTV[0])
135*8d67ca89SAndroid Build Coastguard Worker
136*8d67ca89SAndroid Build Coastguard Worker  ld a0, 8(a0)                  // a0 = TlsDynamicResolverArg*
137*8d67ca89SAndroid Build Coastguard Worker  ld a3, (a0)                   // a3 = TlsDynamicResolverArg::generation
138*8d67ca89SAndroid Build Coastguard Worker
139*8d67ca89SAndroid Build Coastguard Worker  // Fallback if TlsDtv::generation < TlsDynamicResolverArg::generation
140*8d67ca89SAndroid Build Coastguard Worker  // since we need to call __tls_get_addr
141*8d67ca89SAndroid Build Coastguard Worker  blt a1, a3, L(fallback)
142*8d67ca89SAndroid Build Coastguard Worker
143*8d67ca89SAndroid Build Coastguard Worker  // We can't modify a0 yet, since tlsdesc_resolver_dynamic_slow_path requires
144*8d67ca89SAndroid Build Coastguard Worker  // a pointer to the TlsIndex, which is the second field of the
145*8d67ca89SAndroid Build Coastguard Worker  // TlsDynamicResolverArg. As a result, we can't modify a0 until we will no
146*8d67ca89SAndroid Build Coastguard Worker  // longer fallback.
147*8d67ca89SAndroid Build Coastguard Worker  ld a1, 8(a0)                  // a1 = TlsIndex::module_id
148*8d67ca89SAndroid Build Coastguard Worker  slli a1, a1, 3                // a1 = module_id*8 -- scale the idx
149*8d67ca89SAndroid Build Coastguard Worker  add a1, a2, a1                // a1 = &TlsDtv::modules[module_id]
150*8d67ca89SAndroid Build Coastguard Worker  ld a1, (a1)                   // a1 = TlsDtv::modules[module_id]
151*8d67ca89SAndroid Build Coastguard Worker  beqz a1, L(fallback)
152*8d67ca89SAndroid Build Coastguard Worker  ld a3, 16(a0)                 // a3 = TlsIndex::offset
153*8d67ca89SAndroid Build Coastguard Worker  add a0, a1, a3                // a0 = TlsDtv::modules[module_id] + offset
154*8d67ca89SAndroid Build Coastguard Worker  sub a0, a0, tp                // a0 = TlsDtv::modules[module_id] + offset - tp
155*8d67ca89SAndroid Build Coastguard Worker
156*8d67ca89SAndroid Build Coastguard Worker  .cfi_remember_state
157*8d67ca89SAndroid Build Coastguard Worker  reload a3, 3
158*8d67ca89SAndroid Build Coastguard Worker  reload a2, 2
159*8d67ca89SAndroid Build Coastguard Worker  reload a1, 1
160*8d67ca89SAndroid Build Coastguard Worker  addi sp, sp, 4*8
161*8d67ca89SAndroid Build Coastguard Worker  .cfi_adjust_cfa_offset -4*8
162*8d67ca89SAndroid Build Coastguard Worker  jr t0
163*8d67ca89SAndroid Build Coastguard Worker
164*8d67ca89SAndroid Build Coastguard WorkerL(fallback):
165*8d67ca89SAndroid Build Coastguard Worker  reload a3, 3
166*8d67ca89SAndroid Build Coastguard Worker  reload a2, 2
167*8d67ca89SAndroid Build Coastguard Worker  reload a1, 1
168*8d67ca89SAndroid Build Coastguard Worker  addi sp, sp, 4*8
169*8d67ca89SAndroid Build Coastguard Worker  .cfi_adjust_cfa_offset -4*8
170*8d67ca89SAndroid Build Coastguard Worker  j tlsdesc_resolver_dynamic_slow_path
171*8d67ca89SAndroid Build Coastguard WorkerEND(tlsdesc_resolver_dynamic)
172*8d67ca89SAndroid Build Coastguard Worker
173*8d67ca89SAndroid Build Coastguard Worker// On entry, a0 is the address of a TlsDynamicResolverArg object rather than
174*8d67ca89SAndroid Build Coastguard Worker// the TlsDescriptor address passed to the original resolver function.
175*8d67ca89SAndroid Build Coastguard WorkerENTRY_PRIVATE(tlsdesc_resolver_dynamic_slow_path)
176*8d67ca89SAndroid Build Coastguard Worker  // We save a total of 35 registers, but vector spills require an alignment
177*8d67ca89SAndroid Build Coastguard Worker  // of 16, so use an extra slot to align it correctly.
178*8d67ca89SAndroid Build Coastguard Worker  addi sp, sp, (-8*36)
179*8d67ca89SAndroid Build Coastguard Worker  .cfi_def_cfa_offset (8 * 36)
180*8d67ca89SAndroid Build Coastguard Worker  for_each_saved_reg spill, 36
181*8d67ca89SAndroid Build Coastguard Worker  spill_vector_regs
182*8d67ca89SAndroid Build Coastguard Worker
183*8d67ca89SAndroid Build Coastguard Worker  add a0, a0, 8
184*8d67ca89SAndroid Build Coastguard Worker  call __tls_get_addr
185*8d67ca89SAndroid Build Coastguard Worker  addi a0, a0, (-1 * TLS_DTV_OFFSET)  // Correct the address by TLS_DTV_OFFSET
186*8d67ca89SAndroid Build Coastguard Worker  sub a0, a0, tp
187*8d67ca89SAndroid Build Coastguard Worker
188*8d67ca89SAndroid Build Coastguard Worker  reload_vector_regs
189*8d67ca89SAndroid Build Coastguard Worker  for_each_saved_reg reload, 36
190*8d67ca89SAndroid Build Coastguard Worker  addi sp, sp, 8*36
191*8d67ca89SAndroid Build Coastguard Worker  .cfi_def_cfa_offset 0
192*8d67ca89SAndroid Build Coastguard Worker  jr t0
193*8d67ca89SAndroid Build Coastguard WorkerEND(tlsdesc_resolver_dynamic_slow_path)
194*8d67ca89SAndroid Build Coastguard Worker
195*8d67ca89SAndroid Build Coastguard Worker// The address of an unresolved weak TLS symbol evaluates to NULL with TLSDESC.
196*8d67ca89SAndroid Build Coastguard Worker// The value returned by this function is added to the thread pointer, so return
197*8d67ca89SAndroid Build Coastguard Worker// a negated thread pointer to cancel it out.
198*8d67ca89SAndroid Build Coastguard WorkerENTRY_PRIVATE(tlsdesc_resolver_unresolved_weak)
199*8d67ca89SAndroid Build Coastguard Worker  sub a0, zero, tp
200*8d67ca89SAndroid Build Coastguard Worker  jr t0
201*8d67ca89SAndroid Build Coastguard WorkerEND(tlsdesc_resolver_unresolved_weak)
202