| xf.li | bdd93d5 | 2023-05-12 07:10:14 -0700 | [diff] [blame] | 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. | 
|  | 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 | 
|  | 16 | License along with the GNU C Library.  If not, see | 
|  | 17 | <http://www.gnu.org/licenses/>.  */ | 
|  | 18 |  | 
|  | 19 | #include <sysdep.h> | 
|  | 20 | #include <arm-features.h> | 
|  | 21 | #include <tls.h> | 
|  | 22 | #include "tlsdesc.h" | 
|  | 23 |  | 
|  | 24 | .text | 
|  | 25 | @ emit debug information with cfi | 
|  | 26 | @ use arm-specific pseudos for unwinding itself | 
|  | 27 | CFI_SECTIONS | 
|  | 28 | .hidden _dl_tlsdesc_return | 
|  | 29 | .global	_dl_tlsdesc_return | 
|  | 30 | .type	_dl_tlsdesc_return,#function | 
|  | 31 | cfi_startproc | 
|  | 32 | eabi_fnstart | 
|  | 33 | .align 2 | 
|  | 34 | _dl_tlsdesc_return: | 
|  | 35 | sfi_breg r0, \ | 
|  | 36 | ldr	r0, [\B] | 
|  | 37 | BX	(lr) | 
|  | 38 | eabi_fnend | 
|  | 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 | 
|  | 46 | eabi_fnstart | 
|  | 47 | .align 2 | 
|  | 48 | _dl_tlsdesc_undefweak: | 
|  | 49 | GET_TLS (r1) | 
|  | 50 | rsb 	r0, r0, #0 | 
|  | 51 | BX	(lr) | 
|  | 52 | cfi_endproc | 
|  | 53 | eabi_fnend | 
|  | 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 | 
|  | 83 | eabi_fnstart | 
|  | 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 */ | 
|  | 88 | eabi_save ({r2,r3,r4,lr}) | 
|  | 89 | push	{r2,r3,r4,lr} | 
|  | 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) | 
|  | 95 | sfi_breg r0, \ | 
|  | 96 | ldr	r1, [\B] /* td */ | 
|  | 97 | GET_TLS (lr) | 
|  | 98 | mov	r4, r0 /* r4 = tp */ | 
|  | 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] | 
|  | 105 | cmp	r2, r3 | 
|  | 106 | bhi	1f | 
|  | 107 | sfi_breg r1, \ | 
|  | 108 | ldr	r3, [\B] | 
|  | 109 | #ifndef ARM_NO_INDEX_REGISTER | 
|  | 110 | ldr	r2, [r0, r3, lsl #3] | 
|  | 111 | #else | 
|  | 112 | add	lr, r0, r3, lsl #3 | 
|  | 113 | sfi_breg lr, \ | 
|  | 114 | ldr	r2, [\B] | 
|  | 115 | #endif | 
|  | 116 | cmn	r2, #1 | 
|  | 117 | ittt	ne | 
|  | 118 | sfi_breg r1, \ | 
|  | 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 | 
|  | 126 | 2: | 
|  | 127 | #if ((defined (__ARM_ARCH_4T__) && defined (__THUMB_INTERWORK__)) \ | 
|  | 128 | || defined (ARM_ALWAYS_BX)) | 
|  | 129 | pop	{r2,r3,r4, lr} | 
|  | 130 | cfi_adjust_cfa_offset (-16) | 
|  | 131 | cfi_restore (lr) | 
|  | 132 | cfi_restore (r4) | 
|  | 133 | cfi_restore (r3) | 
|  | 134 | cfi_restore (r2) | 
|  | 135 | bx	lr | 
|  | 136 | #else | 
|  | 137 | pop	{r2,r3,r4, pc} | 
|  | 138 | #endif | 
|  | 139 | eabi_fnend | 
|  | 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 | 
|  | 149 | eabi_fnstart | 
|  | 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.  */ | 
|  | 159 | eabi_save ({r2}) | 
|  | 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) | 
|  | 173 | cfi_restore (lr) | 
|  | 174 | cfi_restore (ip) | 
|  | 175 | cfi_restore (r3) | 
|  | 176 | cfi_restore (r1) | 
|  | 177 | cfi_restore (r0) | 
|  | 178 | pop	{r2} | 
|  | 179 | cfi_adjust_cfa_offset (-4) | 
|  | 180 | cfi_restore (r2) | 
|  | 181 | sfi_breg r0, \ | 
|  | 182 | ldr	r1, [\B, #4] | 
|  | 183 | BX	(r1) | 
|  | 184 | eabi_fnend | 
|  | 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. | 
|  | 189 |  | 
|  | 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 | 
|  | 195 | cfi_startproc | 
|  | 196 | eabi_fnstart | 
|  | 197 | .align 2 | 
|  | 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) | 
|  | 217 | cfi_restore (lr) | 
|  | 218 | cfi_restore (ip) | 
|  | 219 | cfi_restore (r3) | 
|  | 220 | cfi_restore (r2) | 
|  | 221 | cfi_restore (r1) | 
|  | 222 | cfi_restore (r0) | 
|  | 223 | sfi_breg r0, \ | 
|  | 224 | ldr     r1, [\B, #4] | 
|  | 225 | BX      (r1) | 
|  | 226 | eabi_fnend | 
|  | 227 | cfi_endproc | 
|  | 228 | .size	_dl_tlsdesc_resolve_hold, .-_dl_tlsdesc_resolve_hold |