1 /* Thread-local storage handling in the ELF dynamic linker. ARM version.
2 Copyright (C) 2006-2016 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
40 .size _dl_tlsdesc_return, .-_dl_tlsdesc_return
42 .hidden _dl_tlsdesc_undefweak
43 .global _dl_tlsdesc_undefweak
44 .type _dl_tlsdesc_undefweak,#function
48 _dl_tlsdesc_undefweak:
54 .size _dl_tlsdesc_undefweak, .-_dl_tlsdesc_undefweak
57 .hidden _dl_tlsdesc_dynamic
58 .global _dl_tlsdesc_dynamic
59 .type _dl_tlsdesc_dynamic,#function
63 The assembly code that follows is a rendition of the following
64 C code, hand-optimized a little bit.
67 _dl_tlsdesc_dynamic(struct tlsdesc *tdp)
69 struct tlsdesc_dynamic_arg *td = tdp->argument.pointer;
70 dtv_t *dtv = (dtv_t *)THREAD_DTV();
71 if (__builtin_expect (td->gen_count <= dtv[0].counter
72 && dtv[td->tlsinfo.ti_module].pointer.val
73 != TLS_DTV_UNALLOCATED,
75 return dtv[td->tlsinfo.ti_module].pointer.val +
76 td->tlsinfo.ti_offset - __builtin_thread_pointer();
78 return __tls_get_addr (&td->tlsinfo) - __builtin_thread_pointer();
86 /* Our calling convention is to clobber r0, r1 and the processor
87 flags. All others that are modified must be saved */
88 eabi_save ({r2,r3,r4,lr})
90 cfi_adjust_cfa_offset (16)
94 cfi_rel_offset (lr,12)
98 mov r4, r0 /* r4 = tp */
102 ldr r2, [\B, #8] /* gen_count */
109 #ifndef ARM_NO_INDEX_REGISTER
110 ldr r2, [r0, r3, lsl #3]
112 add lr, r0, r3, lsl #3
127 #if ((defined (__ARM_ARCH_4T__) && defined (__THUMB_INTERWORK__)) \
128 || defined (ARM_ALWAYS_BX))
130 cfi_adjust_cfa_offset (-16)
141 .size _dl_tlsdesc_dynamic, .-_dl_tlsdesc_dynamic
144 /* lazy resolved for tls descriptors. */
145 .hidden _dl_tlsdesc_lazy_resolver
146 .global _dl_tlsdesc_lazy_resolver
147 .type _dl_tlsdesc_lazy_resolver,#function
151 _dl_tlsdesc_lazy_resolver:
152 /* r0 points at the tlsdesc,
154 r2 was pushed by the trampoline and used as a temp,
155 we need to pop it here.
156 We push the remaining call-clobbered registers here, and also
157 R1 -- to keep the stack correctly aligned. */
158 /* Tell the unwinder that r2 has already been pushed. */
160 cfi_adjust_cfa_offset (4)
161 cfi_rel_offset (r2, 0)
162 eabi_save ({r0,r1,r3,ip,lr})
163 push {r0, r1, r3, ip, lr}
164 cfi_adjust_cfa_offset (20)
165 cfi_rel_offset (r0, 0)
166 cfi_rel_offset (r1, 4)
167 cfi_rel_offset (r3, 8)
168 cfi_rel_offset (ip, 12)
169 cfi_rel_offset (lr, 16)
170 bl _dl_tlsdesc_lazy_resolver_fixup
171 pop {r0, r1, r3, ip, lr}
172 cfi_adjust_cfa_offset (-20)
179 cfi_adjust_cfa_offset (-4)
186 .size _dl_tlsdesc_lazy_resolver, .-_dl_tlsdesc_lazy_resolver
188 /* Holder for lazy tls descriptors being resolve in another thread.
190 Our calling convention is to clobber r0, r1 and the processor
191 flags. All others that are modified must be saved */
192 .hidden _dl_tlsdesc_resolve_hold
193 .global _dl_tlsdesc_resolve_hold
194 .type _dl_tlsdesc_resolve_hold,#function
198 _dl_tlsdesc_resolve_hold:
199 /* r0 is saved so its original value can be used after the call and
200 r1 is saved only to keep the stack aligned. (r0 points to the tls
201 descriptor, it is passed to _dl_tlsdesc_resolve_hold_fixup which
202 is a void function that may clobber r0, later r0 is used to load
203 the new resolver.) */
204 eabi_save ({r0,r1,r2,r3,ip,lr})
205 push {r0, r1, r2, r3, ip, lr}
206 cfi_adjust_cfa_offset (24)
207 cfi_rel_offset (r0, 0)
208 cfi_rel_offset (r1, 4)
209 cfi_rel_offset (r2, 8)
210 cfi_rel_offset (r3, 12)
211 cfi_rel_offset (ip, 16)
212 cfi_rel_offset (lr, 20)
213 adr r1, _dl_tlsdesc_resolve_hold
214 bl _dl_tlsdesc_resolve_hold_fixup
215 pop {r0, r1, r2, r3, ip, lr}
216 cfi_adjust_cfa_offset (-24)
228 .size _dl_tlsdesc_resolve_hold, .-_dl_tlsdesc_resolve_hold