|
Packit |
6c4009 |
/* Thread-local storage handling in the ELF dynamic linker.
|
|
Packit |
6c4009 |
AArch64 version.
|
|
Packit |
6c4009 |
Copyright (C) 2011-2018 Free Software Foundation, Inc.
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
This file is part of the GNU C Library.
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
The GNU C Library is free software; you can redistribute it and/or
|
|
Packit |
6c4009 |
modify it under the terms of the GNU Lesser General Public
|
|
Packit |
6c4009 |
License as published by the Free Software Foundation; either
|
|
Packit |
6c4009 |
version 2.1 of the License, or (at your option) any later version.
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
The GNU C Library is distributed in the hope that it will be useful,
|
|
Packit |
6c4009 |
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
6c4009 |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Packit |
6c4009 |
Lesser General Public License for more details.
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
You should have received a copy of the GNU Lesser General Public
|
|
Packit |
6c4009 |
License along with the GNU C Library; if not, see
|
|
Packit |
6c4009 |
<http://www.gnu.org/licenses/>. */
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
#include <sysdep.h>
|
|
Packit |
6c4009 |
#include <tls.h>
|
|
Packit |
6c4009 |
#include "tlsdesc.h"
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
#define NSAVEDQREGPAIRS 16
|
|
Packit |
6c4009 |
#define SAVE_Q_REGISTERS \
|
|
Packit |
6c4009 |
stp q0, q1, [sp, #-32*NSAVEDQREGPAIRS]!; \
|
|
Packit |
6c4009 |
cfi_adjust_cfa_offset (32*NSAVEDQREGPAIRS); \
|
|
Packit |
6c4009 |
stp q2, q3, [sp, #32*1]; \
|
|
Packit |
6c4009 |
stp q4, q5, [sp, #32*2]; \
|
|
Packit |
6c4009 |
stp q6, q7, [sp, #32*3]; \
|
|
Packit |
6c4009 |
stp q8, q9, [sp, #32*4]; \
|
|
Packit |
6c4009 |
stp q10, q11, [sp, #32*5]; \
|
|
Packit |
6c4009 |
stp q12, q13, [sp, #32*6]; \
|
|
Packit |
6c4009 |
stp q14, q15, [sp, #32*7]; \
|
|
Packit |
6c4009 |
stp q16, q17, [sp, #32*8]; \
|
|
Packit |
6c4009 |
stp q18, q19, [sp, #32*9]; \
|
|
Packit |
6c4009 |
stp q20, q21, [sp, #32*10]; \
|
|
Packit |
6c4009 |
stp q22, q23, [sp, #32*11]; \
|
|
Packit |
6c4009 |
stp q24, q25, [sp, #32*12]; \
|
|
Packit |
6c4009 |
stp q26, q27, [sp, #32*13]; \
|
|
Packit |
6c4009 |
stp q28, q29, [sp, #32*14]; \
|
|
Packit |
6c4009 |
stp q30, q31, [sp, #32*15];
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
#define RESTORE_Q_REGISTERS \
|
|
Packit |
6c4009 |
ldp q2, q3, [sp, #32*1]; \
|
|
Packit |
6c4009 |
ldp q4, q5, [sp, #32*2]; \
|
|
Packit |
6c4009 |
ldp q6, q7, [sp, #32*3]; \
|
|
Packit |
6c4009 |
ldp q8, q9, [sp, #32*4]; \
|
|
Packit |
6c4009 |
ldp q10, q11, [sp, #32*5]; \
|
|
Packit |
6c4009 |
ldp q12, q13, [sp, #32*6]; \
|
|
Packit |
6c4009 |
ldp q14, q15, [sp, #32*7]; \
|
|
Packit |
6c4009 |
ldp q16, q17, [sp, #32*8]; \
|
|
Packit |
6c4009 |
ldp q18, q19, [sp, #32*9]; \
|
|
Packit |
6c4009 |
ldp q20, q21, [sp, #32*10]; \
|
|
Packit |
6c4009 |
ldp q22, q23, [sp, #32*11]; \
|
|
Packit |
6c4009 |
ldp q24, q25, [sp, #32*12]; \
|
|
Packit |
6c4009 |
ldp q26, q27, [sp, #32*13]; \
|
|
Packit |
6c4009 |
ldp q28, q29, [sp, #32*14]; \
|
|
Packit |
6c4009 |
ldp q30, q31, [sp, #32*15]; \
|
|
Packit |
6c4009 |
ldp q0, q1, [sp], #32*NSAVEDQREGPAIRS; \
|
|
Packit |
6c4009 |
cfi_adjust_cfa_offset (-32*NSAVEDQREGPAIRS);
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
.text
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
/* Compute the thread pointer offset for symbols in the static
|
|
Packit |
6c4009 |
TLS block. The offset is the same for all threads.
|
|
Packit |
6c4009 |
Prototype:
|
|
Packit |
6c4009 |
_dl_tlsdesc_return (tlsdesc *) ;
|
|
Packit |
6c4009 |
*/
|
|
Packit |
6c4009 |
.hidden _dl_tlsdesc_return
|
|
Packit |
6c4009 |
.global _dl_tlsdesc_return
|
|
Packit |
6c4009 |
.type _dl_tlsdesc_return,%function
|
|
Packit |
6c4009 |
cfi_startproc
|
|
Packit |
6c4009 |
.align 2
|
|
Packit |
6c4009 |
_dl_tlsdesc_return:
|
|
Packit |
6c4009 |
DELOUSE (0)
|
|
Packit |
6c4009 |
ldr PTR_REG (0), [x0, #PTR_SIZE]
|
|
Packit |
6c4009 |
RET
|
|
Packit |
6c4009 |
cfi_endproc
|
|
Packit |
6c4009 |
.size _dl_tlsdesc_return, .-_dl_tlsdesc_return
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
/* Handler for undefined weak TLS symbols.
|
|
Packit |
6c4009 |
Prototype:
|
|
Packit |
6c4009 |
_dl_tlsdesc_undefweak (tlsdesc *);
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
The second word of the descriptor contains the addend.
|
|
Packit |
6c4009 |
Return the addend minus the thread pointer. This ensures
|
|
Packit |
6c4009 |
that when the caller adds on the thread pointer it gets back
|
|
Packit |
6c4009 |
the addend. */
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
.hidden _dl_tlsdesc_undefweak
|
|
Packit |
6c4009 |
.global _dl_tlsdesc_undefweak
|
|
Packit |
6c4009 |
.type _dl_tlsdesc_undefweak,%function
|
|
Packit |
6c4009 |
cfi_startproc
|
|
Packit |
6c4009 |
.align 2
|
|
Packit |
6c4009 |
_dl_tlsdesc_undefweak:
|
|
Packit |
6c4009 |
str x1, [sp, #-16]!
|
|
Packit |
6c4009 |
cfi_adjust_cfa_offset (16)
|
|
Packit |
6c4009 |
DELOUSE (0)
|
|
Packit |
6c4009 |
ldr PTR_REG (0), [x0, #PTR_SIZE]
|
|
Packit |
6c4009 |
mrs x1, tpidr_el0
|
|
Packit |
6c4009 |
sub PTR_REG (0), PTR_REG (0), PTR_REG (1)
|
|
Packit |
6c4009 |
ldr x1, [sp], #16
|
|
Packit |
6c4009 |
cfi_adjust_cfa_offset (-16)
|
|
Packit |
6c4009 |
RET
|
|
Packit |
6c4009 |
cfi_endproc
|
|
Packit |
6c4009 |
.size _dl_tlsdesc_undefweak, .-_dl_tlsdesc_undefweak
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
#ifdef SHARED
|
|
Packit |
6c4009 |
/* Handler for dynamic TLS symbols.
|
|
Packit |
6c4009 |
Prototype:
|
|
Packit |
6c4009 |
_dl_tlsdesc_dynamic (tlsdesc *) ;
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
The second word of the descriptor points to a
|
|
Packit |
6c4009 |
tlsdesc_dynamic_arg structure.
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
Returns the offset between the thread pointer and the
|
|
Packit |
6c4009 |
object referenced by the argument.
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
ptrdiff_t
|
|
Packit |
6c4009 |
__attribute__ ((__regparm__ (1)))
|
|
Packit |
6c4009 |
_dl_tlsdesc_dynamic (struct tlsdesc *tdp)
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
struct tlsdesc_dynamic_arg *td = tdp->arg;
|
|
Packit |
6c4009 |
dtv_t *dtv = *(dtv_t **)((char *)__thread_pointer + TCBHEAD_DTV);
|
|
Packit |
6c4009 |
if (__builtin_expect (td->gen_count <= dtv[0].counter
|
|
Packit |
6c4009 |
&& (dtv[td->tlsinfo.ti_module].pointer.val
|
|
Packit |
6c4009 |
!= TLS_DTV_UNALLOCATED),
|
|
Packit |
6c4009 |
1))
|
|
Packit |
6c4009 |
return dtv[td->tlsinfo.ti_module].pointer.val
|
|
Packit |
6c4009 |
+ td->tlsinfo.ti_offset
|
|
Packit |
6c4009 |
- __thread_pointer;
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
return ___tls_get_addr (&td->tlsinfo) - __thread_pointer;
|
|
Packit |
6c4009 |
}
|
|
Packit |
6c4009 |
*/
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
.hidden _dl_tlsdesc_dynamic
|
|
Packit |
6c4009 |
.global _dl_tlsdesc_dynamic
|
|
Packit |
6c4009 |
.type _dl_tlsdesc_dynamic,%function
|
|
Packit |
6c4009 |
cfi_startproc
|
|
Packit |
6c4009 |
.align 2
|
|
Packit |
6c4009 |
_dl_tlsdesc_dynamic:
|
|
Packit |
6c4009 |
DELOUSE (0)
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
/* Save just enough registers to support fast path, if we fall
|
|
Packit |
6c4009 |
into slow path we will save additional registers. */
|
|
Packit |
6c4009 |
stp x1, x2, [sp, #-32]!
|
|
Packit |
6c4009 |
stp x3, x4, [sp, #16]
|
|
Packit |
6c4009 |
cfi_adjust_cfa_offset (32)
|
|
Packit |
6c4009 |
cfi_rel_offset (x1, 0)
|
|
Packit |
6c4009 |
cfi_rel_offset (x2, 8)
|
|
Packit |
6c4009 |
cfi_rel_offset (x3, 16)
|
|
Packit |
6c4009 |
cfi_rel_offset (x4, 24)
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
mrs x4, tpidr_el0
|
|
Packit |
6c4009 |
ldr PTR_REG (1), [x0,#TLSDESC_ARG]
|
|
Packit |
6c4009 |
ldr PTR_REG (0), [x4,#TCBHEAD_DTV]
|
|
Packit |
6c4009 |
ldr PTR_REG (3), [x1,#TLSDESC_GEN_COUNT]
|
|
Packit |
6c4009 |
ldr PTR_REG (2), [x0,#DTV_COUNTER]
|
|
Packit |
6c4009 |
cmp PTR_REG (3), PTR_REG (2)
|
|
Packit |
6c4009 |
b.hi 2f
|
|
Packit |
6c4009 |
/* Load r2 = td->tlsinfo.ti_module and r3 = td->tlsinfo.ti_offset. */
|
|
Packit |
6c4009 |
ldp PTR_REG (2), PTR_REG (3), [x1,#TLSDESC_MODID]
|
|
Packit |
6c4009 |
add PTR_REG (0), PTR_REG (0), PTR_REG (2), lsl #(PTR_LOG_SIZE + 1)
|
|
Packit |
6c4009 |
ldr PTR_REG (0), [x0] /* Load val member of DTV entry. */
|
|
Packit |
6c4009 |
cmp PTR_REG (0), #TLS_DTV_UNALLOCATED
|
|
Packit |
6c4009 |
b.eq 2f
|
|
Packit |
6c4009 |
sub PTR_REG (3), PTR_REG (3), PTR_REG (4)
|
|
Packit |
6c4009 |
add PTR_REG (0), PTR_REG (0), PTR_REG (3)
|
|
Packit |
6c4009 |
1:
|
|
Packit |
6c4009 |
ldp x3, x4, [sp, #16]
|
|
Packit |
6c4009 |
ldp x1, x2, [sp], #32
|
|
Packit |
6c4009 |
cfi_adjust_cfa_offset (-32)
|
|
Packit |
6c4009 |
RET
|
|
Packit |
6c4009 |
2:
|
|
Packit |
6c4009 |
/* This is the slow path. We need to call __tls_get_addr() which
|
|
Packit |
6c4009 |
means we need to save and restore all the register that the
|
|
Packit |
6c4009 |
callee will trash. */
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
/* Save the remaining registers that we must treat as caller save. */
|
|
Packit |
6c4009 |
# define NSAVEXREGPAIRS 8
|
|
Packit |
6c4009 |
stp x29, x30, [sp,#-16*NSAVEXREGPAIRS]!
|
|
Packit |
6c4009 |
cfi_adjust_cfa_offset (16*NSAVEXREGPAIRS)
|
|
Packit |
6c4009 |
cfi_rel_offset (x29, 0)
|
|
Packit |
6c4009 |
cfi_rel_offset (x30, 8)
|
|
Packit |
6c4009 |
mov x29, sp
|
|
Packit |
6c4009 |
stp x5, x6, [sp, #16*1]
|
|
Packit |
6c4009 |
stp x7, x8, [sp, #16*2]
|
|
Packit |
6c4009 |
stp x9, x10, [sp, #16*3]
|
|
Packit |
6c4009 |
stp x11, x12, [sp, #16*4]
|
|
Packit |
6c4009 |
stp x13, x14, [sp, #16*5]
|
|
Packit |
6c4009 |
stp x15, x16, [sp, #16*6]
|
|
Packit |
6c4009 |
stp x17, x18, [sp, #16*7]
|
|
Packit |
6c4009 |
cfi_rel_offset (x5, 16*1)
|
|
Packit |
6c4009 |
cfi_rel_offset (x6, 16*1+8)
|
|
Packit |
6c4009 |
cfi_rel_offset (x7, 16*2)
|
|
Packit |
6c4009 |
cfi_rel_offset (x8, 16*2+8)
|
|
Packit |
6c4009 |
cfi_rel_offset (x9, 16*3)
|
|
Packit |
6c4009 |
cfi_rel_offset (x10, 16*3+8)
|
|
Packit |
6c4009 |
cfi_rel_offset (x11, 16*4)
|
|
Packit |
6c4009 |
cfi_rel_offset (x12, 16*4+8)
|
|
Packit |
6c4009 |
cfi_rel_offset (x13, 16*5)
|
|
Packit |
6c4009 |
cfi_rel_offset (x14, 16*5+8)
|
|
Packit |
6c4009 |
cfi_rel_offset (x15, 16*6)
|
|
Packit |
6c4009 |
cfi_rel_offset (x16, 16*6+8)
|
|
Packit |
6c4009 |
cfi_rel_offset (x17, 16*7)
|
|
Packit |
6c4009 |
cfi_rel_offset (x18, 16*7+8)
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
SAVE_Q_REGISTERS
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
mov x0, x1
|
|
Packit |
6c4009 |
bl __tls_get_addr
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
mrs x1, tpidr_el0
|
|
Packit |
6c4009 |
sub PTR_REG (0), PTR_REG (0), PTR_REG (1)
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
RESTORE_Q_REGISTERS
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
ldp x5, x6, [sp, #16*1]
|
|
Packit |
6c4009 |
ldp x7, x8, [sp, #16*2]
|
|
Packit |
6c4009 |
ldp x9, x10, [sp, #16*3]
|
|
Packit |
6c4009 |
ldp x11, x12, [sp, #16*4]
|
|
Packit |
6c4009 |
ldp x13, x14, [sp, #16*5]
|
|
Packit |
6c4009 |
ldp x15, x16, [sp, #16*6]
|
|
Packit |
6c4009 |
ldp x17, x18, [sp, #16*7]
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
ldp x29, x30, [sp], #16*NSAVEXREGPAIRS
|
|
Packit |
6c4009 |
cfi_adjust_cfa_offset (-16*NSAVEXREGPAIRS)
|
|
Packit |
6c4009 |
cfi_restore (x29)
|
|
Packit |
6c4009 |
cfi_restore (x30)
|
|
Packit |
6c4009 |
b 1b
|
|
Packit |
6c4009 |
cfi_endproc
|
|
Packit |
6c4009 |
.size _dl_tlsdesc_dynamic, .-_dl_tlsdesc_dynamic
|
|
Packit |
6c4009 |
# undef NSAVEXREGPAIRS
|
|
Packit |
6c4009 |
#endif
|