]>
Commit | Line | Data |
---|---|---|
3447f0d7 | 1 | /* Thread-local storage handling in the ELF dynamic linker. ARM version. |
bfff8b1b | 2 | Copyright (C) 2006-2017 Free Software Foundation, Inc. |
3447f0d7 NS |
3 | This file is part of the GNU C Library. |
4 | ||
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. | |
9 | ||
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. | |
14 | ||
15 | You should have received a copy of the GNU Lesser General Public | |
ab84e3ff PE |
16 | License along with the GNU C Library. If not, see |
17 | <http://www.gnu.org/licenses/>. */ | |
3447f0d7 NS |
18 | |
19 | #include <sysdep.h> | |
6bcae146 | 20 | #include <arm-features.h> |
3447f0d7 NS |
21 | #include <tls.h> |
22 | #include "tlsdesc.h" | |
23 | ||
3447f0d7 NS |
24 | .text |
25 | @ emit debug information with cfi | |
26 | @ use arm-specific pseudos for unwinding itself | |
f4564ff0 | 27 | CFI_SECTIONS |
3447f0d7 NS |
28 | .hidden _dl_tlsdesc_return |
29 | .global _dl_tlsdesc_return | |
30 | .type _dl_tlsdesc_return,#function | |
31 | cfi_startproc | |
7214d558 | 32 | eabi_fnstart |
3447f0d7 NS |
33 | .align 2 |
34 | _dl_tlsdesc_return: | |
6bcae146 RM |
35 | sfi_breg r0, \ |
36 | ldr r0, [\B] | |
3447f0d7 | 37 | BX (lr) |
7214d558 | 38 | eabi_fnend |
3447f0d7 NS |
39 | cfi_endproc |
40 | .size _dl_tlsdesc_return, .-_dl_tlsdesc_return | |
41 | ||
42 | .hidden _dl_tlsdesc_undefweak | |
43 | .global _dl_tlsdesc_undefweak | |
44 | .type _dl_tlsdesc_undefweak,#function | |
45 | cfi_startproc | |
7214d558 | 46 | eabi_fnstart |
3447f0d7 NS |
47 | .align 2 |
48 | _dl_tlsdesc_undefweak: | |
5232b909 | 49 | GET_TLS (r1) |
3447f0d7 | 50 | rsb r0, r0, #0 |
3447f0d7 | 51 | BX (lr) |
3447f0d7 | 52 | cfi_endproc |
7214d558 | 53 | eabi_fnend |
3447f0d7 NS |
54 | .size _dl_tlsdesc_undefweak, .-_dl_tlsdesc_undefweak |
55 | ||
56 | #ifdef SHARED | |
57 | .hidden _dl_tlsdesc_dynamic | |
58 | .global _dl_tlsdesc_dynamic | |
59 | .type _dl_tlsdesc_dynamic,#function | |
60 | ||
61 | ||
62 | /* | |
63 | The assembly code that follows is a rendition of the following | |
64 | C code, hand-optimized a little bit. | |
65 | ||
66 | ptrdiff_t | |
67 | _dl_tlsdesc_dynamic(struct tlsdesc *tdp) | |
68 | { | |
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, | |
74 | 1)) | |
75 | return dtv[td->tlsinfo.ti_module].pointer.val + | |
76 | td->tlsinfo.ti_offset - __builtin_thread_pointer(); | |
77 | ||
78 | return __tls_get_addr (&td->tlsinfo) - __builtin_thread_pointer(); | |
79 | } | |
80 | ||
81 | */ | |
82 | cfi_startproc | |
7214d558 | 83 | eabi_fnstart |
3447f0d7 NS |
84 | .align 2 |
85 | _dl_tlsdesc_dynamic: | |
86 | /* Our calling convention is to clobber r0, r1 and the processor | |
87 | flags. All others that are modified must be saved */ | |
7214d558 | 88 | eabi_save ({r2,r3,r4,lr}) |
55668624 | 89 | push {r2,r3,r4,lr} |
3447f0d7 NS |
90 | cfi_adjust_cfa_offset (16) |
91 | cfi_rel_offset (r2,0) | |
92 | cfi_rel_offset (r3,4) | |
93 | cfi_rel_offset (r4,8) | |
94 | cfi_rel_offset (lr,12) | |
6bcae146 RM |
95 | sfi_breg r0, \ |
96 | ldr r1, [\B] /* td */ | |
5232b909 | 97 | GET_TLS (lr) |
3447f0d7 | 98 | mov r4, r0 /* r4 = tp */ |
6bcae146 RM |
99 | sfi_breg r0, \ |
100 | ldr r0, [\B] | |
101 | sfi_breg r1, \ | |
102 | ldr r2, [\B, #8] /* gen_count */ | |
103 | sfi_breg r0, \ | |
104 | ldr r3, [\B] | |
3447f0d7 NS |
105 | cmp r2, r3 |
106 | bhi 1f | |
6bcae146 RM |
107 | sfi_breg r1, \ |
108 | ldr r3, [\B] | |
109 | #ifndef ARM_NO_INDEX_REGISTER | |
3447f0d7 | 110 | ldr r2, [r0, r3, lsl #3] |
6bcae146 RM |
111 | #else |
112 | add lr, r0, r3, lsl #3 | |
113 | sfi_breg lr, \ | |
114 | ldr r2, [\B] | |
115 | #endif | |
3447f0d7 | 116 | cmn r2, #1 |
6ccd0107 | 117 | ittt ne |
12290c06 | 118 | sfi_breg r1, \ |
3447f0d7 NS |
119 | ldrne r3, [r1, #4] |
120 | addne r3, r2, r3 | |
121 | rsbne r0, r4, r3 | |
122 | bne 2f | |
123 | 1: mov r0, r1 | |
124 | bl __tls_get_addr | |
125 | rsb r0, r4, r0 | |
d137b6dc | 126 | 2: |
6bcae146 RM |
127 | #if ((defined (__ARM_ARCH_4T__) && defined (__THUMB_INTERWORK__)) \ |
128 | || defined (ARM_ALWAYS_BX)) | |
d137b6dc | 129 | pop {r2,r3,r4, lr} |
3447f0d7 NS |
130 | cfi_adjust_cfa_offset (-16) |
131 | cfi_restore (lr) | |
132 | cfi_restore (r4) | |
133 | cfi_restore (r3) | |
134 | cfi_restore (r2) | |
d137b6dc RH |
135 | bx lr |
136 | #else | |
137 | pop {r2,r3,r4, pc} | |
138 | #endif | |
7214d558 | 139 | eabi_fnend |
3447f0d7 NS |
140 | cfi_endproc |
141 | .size _dl_tlsdesc_dynamic, .-_dl_tlsdesc_dynamic | |
142 | #endif /* SHARED */ | |
143 | ||
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 | |
148 | cfi_startproc | |
7214d558 | 149 | eabi_fnstart |
3447f0d7 NS |
150 | .align 2 |
151 | _dl_tlsdesc_lazy_resolver: | |
152 | /* r0 points at the tlsdesc, | |
153 | r1 points at the GOT | |
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. */ | |
7214d558 | 159 | eabi_save ({r2}) |
3447f0d7 NS |
160 | cfi_adjust_cfa_offset (4) |
161 | cfi_rel_offset (r2, 0) | |
7214d558 | 162 | eabi_save ({r0,r1,r3,ip,lr}) |
55668624 | 163 | push {r0, r1, r3, ip, lr} |
3447f0d7 NS |
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 | |
55668624 | 171 | pop {r0, r1, r3, ip, lr} |
3447f0d7 NS |
172 | cfi_adjust_cfa_offset (-20) |
173 | cfi_restore (lr) | |
174 | cfi_restore (ip) | |
175 | cfi_restore (r3) | |
176 | cfi_restore (r1) | |
177 | cfi_restore (r0) | |
55668624 | 178 | pop {r2} |
3447f0d7 NS |
179 | cfi_adjust_cfa_offset (-4) |
180 | cfi_restore (r2) | |
6bcae146 RM |
181 | sfi_breg r0, \ |
182 | ldr r1, [\B, #4] | |
3447f0d7 | 183 | BX (r1) |
7214d558 | 184 | eabi_fnend |
3447f0d7 NS |
185 | cfi_endproc |
186 | .size _dl_tlsdesc_lazy_resolver, .-_dl_tlsdesc_lazy_resolver | |
187 | ||
188 | /* Holder for lazy tls descriptors being resolve in another thread. | |
36ffe739 WN |
189 | |
190 | Our calling convention is to clobber r0, r1 and the processor | |
191 | flags. All others that are modified must be saved */ | |
3447f0d7 NS |
192 | .hidden _dl_tlsdesc_resolve_hold |
193 | .global _dl_tlsdesc_resolve_hold | |
194 | .type _dl_tlsdesc_resolve_hold,#function | |
195 | cfi_startproc | |
7214d558 | 196 | eabi_fnstart |
3447f0d7 NS |
197 | .align 2 |
198 | _dl_tlsdesc_resolve_hold: | |
1fae5a68 SN |
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) | |
36ffe739 | 213 | adr r1, _dl_tlsdesc_resolve_hold |
3447f0d7 | 214 | bl _dl_tlsdesc_resolve_hold_fixup |
1fae5a68 SN |
215 | pop {r0, r1, r2, r3, ip, lr} |
216 | cfi_adjust_cfa_offset (-24) | |
3447f0d7 NS |
217 | cfi_restore (lr) |
218 | cfi_restore (ip) | |
219 | cfi_restore (r3) | |
3447f0d7 | 220 | cfi_restore (r2) |
1fae5a68 SN |
221 | cfi_restore (r1) |
222 | cfi_restore (r0) | |
6bcae146 RM |
223 | sfi_breg r0, \ |
224 | ldr r1, [\B, #4] | |
3447f0d7 | 225 | BX (r1) |
7214d558 | 226 | eabi_fnend |
3447f0d7 NS |
227 | cfi_endproc |
228 | .size _dl_tlsdesc_resolve_hold, .-_dl_tlsdesc_resolve_hold |