1 /* Thread-local storage handling in the ELF dynamic linker.  s390 version.
2    Copyright (C) 2003-2021 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    <https://www.gnu.org/licenses/>.  */
18 
19 
20 /* Type used for the representation of TLS information in the GOT.  */
21 typedef struct
22 {
23   unsigned long int ti_module;
24   unsigned long int ti_offset;
25 } tls_index;
26 
27 
28 #ifdef SHARED
29 
30 extern unsigned long __tls_get_offset (unsigned long got_offset);
31 
32 # if IS_IN (rtld)
33 
34 #  include <shlib-compat.h>
35 
36 /* dl-tls.c declares __tls_get_addr as an exported symbol if it is not defined
37    as a macro.  It seems suitable to do that in the generic code because all
38    architectures other than s390 export __tls_get_addr.  The declaration causes
39    problems in s390 though, so we define __tls_get_addr here to avoid declaring
40    __tls_get_addr again.  */
41 #  define __tls_get_addr __tls_get_addr
42 
43 extern void *__tls_get_addr (tls_index *ti) attribute_hidden;
44 /* Make a temporary alias of __tls_get_addr to remove the hidden
45    attribute.  Then export __tls_get_addr as __tls_get_addr_internal
46    for use from libc.  We do not want to export __tls_get_addr, but we
47    do need to use it from libc when looking up the address of a TLS
48    variable. We don't use __tls_get_offset because it requires r12 to
49    be setup and that might not always be true. Either way it's more
50    optimal to use __tls_get_addr directly (that's what
51    __tls_get_offset does anyways).  */
52 strong_alias (__tls_get_addr, __tls_get_addr_internal_tmp);
53 versioned_symbol (ld, __tls_get_addr_internal_tmp,
54 		  __tls_get_addr_internal, GLIBC_PRIVATE);
55 
56 /* The special thing about the s390 TLS ABI is that we do not have the
57    standard __tls_get_addr function but the __tls_get_offset function
58    which differs in two important aspects:
59    1) __tls_get_offset gets a got offset instead of a pointer to the
60       tls_index structure
61    2) __tls_get_offset returns the offset of the requested variable to
62       the thread descriptor instead of a pointer to the variable.
63  */
64 #  ifdef __s390x__
65 __asm__("\n\
66 	.text\n\
67 	.globl __tls_get_offset\n\
68 	.type __tls_get_offset, @function\n\
69 	.align 4\n\
70 __tls_get_offset:\n\
71 	la	%r2,0(%r2,%r12)\n\
72 	jg	__tls_get_addr\n\
73 ");
74 #  elif defined __s390__
75 __asm__("\n\
76 	.text\n\
77 	.globl __tls_get_offset\n\
78 	.type __tls_get_offset, @function\n\
79 	.align 4\n\
80 __tls_get_offset:\n\
81 	basr	%r3,0\n\
82 0:	la	%r2,0(%r2,%r12)\n\
83 	l	%r4,1f-0b(%r3)\n\
84 	b	0(%r4,%r3)\n\
85 1:	.long	__tls_get_addr - 0b\n\
86 ");
87 #  endif
88 # else /* IS_IN (rtld) */
89 extern void *__tls_get_addr_internal (tls_index *ti);
90 # endif /* !IS_IN (rtld) */
91 
92 # define GET_ADDR_OFFSET \
93   (ti->ti_offset - (unsigned long) __builtin_thread_pointer ())
94 
95 /* Use the privately exported __tls_get_addr_internal instead of
96    __tls_get_offset in order to avoid the __tls_get_offset special
97    linkage requiring the GOT pointer to be set up in r12.  The
98    compiler will take care of setting up r12 only if itself issued the
99    __tls_get_offset call.  */
100 # define __TLS_GET_ADDR(__ti)					\
101   ({ __tls_get_addr_internal (__ti)				\
102       + (unsigned long) __builtin_thread_pointer (); })
103 
104 #endif
105