(root)/
glibc-2.38/
sysdeps/
s390/
dl-tls.h
       1  /* Thread-local storage handling in the ELF dynamic linker.  s390 version.
       2     Copyright (C) 2003-2023 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