| xf.li | bdd93d5 | 2023-05-12 07:10:14 -0700 | [diff] [blame] | 1 | /* Thread-local storage handling in the ELF dynamic linker.  s390 version. | 
|  | 2 | Copyright (C) 2003-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 |  | 
|  | 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 |  | 
|  | 106 | /* Value used for dtv entries for which the allocation is delayed.  */ | 
|  | 107 | #define TLS_DTV_UNALLOCATED	((void *) -1l) |