1 /* Thread-local storage handling in the ELF dynamic linker. ARM version.
2 Copyright (C) 2006-2017 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library. If not, see
17 <http://www.gnu.org/licenses/>. */
20 #include <arm-features.h>
25 @ emit debug information with cfi
26 @ use arm-specific pseudos for unwinding itself
28 .hidden _dl_tlsdesc_return
29 .global _dl_tlsdesc_return
30 .type _dl_tlsdesc_return,#function
39 .size _dl_tlsdesc_return, .-_dl_tlsdesc_return
41 .hidden _dl_tlsdesc_undefweak
42 .global _dl_tlsdesc_undefweak
43 .type _dl_tlsdesc_undefweak,#function
47 _dl_tlsdesc_undefweak:
53 .size _dl_tlsdesc_undefweak, .-_dl_tlsdesc_undefweak
56 .hidden _dl_tlsdesc_dynamic
57 .global _dl_tlsdesc_dynamic
58 .type _dl_tlsdesc_dynamic,#function
62 The assembly code that follows is a rendition of the following
63 C code, hand-optimized a little bit.
66 _dl_tlsdesc_dynamic(struct tlsdesc *tdp)
68 struct tlsdesc_dynamic_arg *td = tdp->argument.pointer;
69 dtv_t *dtv = (dtv_t *)THREAD_DTV();
70 if (__builtin_expect (td->gen_count <= dtv[0].counter
71 && dtv[td->tlsinfo.ti_module].pointer.val
72 != TLS_DTV_UNALLOCATED,
74 return dtv[td->tlsinfo.ti_module].pointer.val +
75 td->tlsinfo.ti_offset - __builtin_thread_pointer();
77 return __tls_get_addr (&td->tlsinfo) - __builtin_thread_pointer();
85 /* Our calling convention is to clobber r0, r1 and the processor
86 flags. All others that are modified must be saved */
87 eabi_save ({r2,r3,r4,lr})
89 cfi_adjust_cfa_offset (16)
93 cfi_rel_offset (lr,12)
96 mov r4, r0 /* r4 = tp */
98 ldr r2, [r1, #8] /* gen_count */
103 #ifndef ARM_NO_INDEX_REGISTER
104 ldr r2, [r0, r3, lsl #3]
106 add lr, r0, r3, lsl #3
119 #if ((defined (__ARM_ARCH_4T__) && defined (__THUMB_INTERWORK__)) \
120 || defined (ARM_ALWAYS_BX))
122 cfi_adjust_cfa_offset (-16)
133 .size _dl_tlsdesc_dynamic, .-_dl_tlsdesc_dynamic
136 /* lazy resolved for tls descriptors. */
137 .hidden _dl_tlsdesc_lazy_resolver
138 .global _dl_tlsdesc_lazy_resolver
139 .type _dl_tlsdesc_lazy_resolver,#function
143 _dl_tlsdesc_lazy_resolver:
144 /* r0 points at the tlsdesc,
146 r2 was pushed by the trampoline and used as a temp,
147 we need to pop it here.
148 We push the remaining call-clobbered registers here, and also
149 R1 -- to keep the stack correctly aligned. */
150 /* Tell the unwinder that r2 has already been pushed. */
152 cfi_adjust_cfa_offset (4)
153 cfi_rel_offset (r2, 0)
154 eabi_save ({r0,r1,r3,ip,lr})
155 push {r0, r1, r3, ip, lr}
156 cfi_adjust_cfa_offset (20)
157 cfi_rel_offset (r0, 0)
158 cfi_rel_offset (r1, 4)
159 cfi_rel_offset (r3, 8)
160 cfi_rel_offset (ip, 12)
161 cfi_rel_offset (lr, 16)
162 bl _dl_tlsdesc_lazy_resolver_fixup
163 pop {r0, r1, r3, ip, lr}
164 cfi_adjust_cfa_offset (-20)
171 cfi_adjust_cfa_offset (-4)
177 .size _dl_tlsdesc_lazy_resolver, .-_dl_tlsdesc_lazy_resolver
179 /* Holder for lazy tls descriptors being resolve in another thread.
181 Our calling convention is to clobber r0, r1 and the processor
182 flags. All others that are modified must be saved */
183 .hidden _dl_tlsdesc_resolve_hold
184 .global _dl_tlsdesc_resolve_hold
185 .type _dl_tlsdesc_resolve_hold,#function
189 _dl_tlsdesc_resolve_hold:
190 /* r0 is saved so its original value can be used after the call and
191 r1 is saved only to keep the stack aligned. (r0 points to the tls
192 descriptor, it is passed to _dl_tlsdesc_resolve_hold_fixup which
193 is a void function that may clobber r0, later r0 is used to load
194 the new resolver.) */
195 eabi_save ({r0,r1,r2,r3,ip,lr})
196 push {r0, r1, r2, r3, ip, lr}
197 cfi_adjust_cfa_offset (24)
198 cfi_rel_offset (r0, 0)
199 cfi_rel_offset (r1, 4)
200 cfi_rel_offset (r2, 8)
201 cfi_rel_offset (r3, 12)
202 cfi_rel_offset (ip, 16)
203 cfi_rel_offset (lr, 20)
204 adr r1, _dl_tlsdesc_resolve_hold
205 bl _dl_tlsdesc_resolve_hold_fixup
206 pop {r0, r1, r2, r3, ip, lr}
207 cfi_adjust_cfa_offset (-24)
218 .size _dl_tlsdesc_resolve_hold, .-_dl_tlsdesc_resolve_hold