Blame sysdeps/s390/dl-tls.h

Packit 6c4009
/* Thread-local storage handling in the ELF dynamic linker.  s390 version.
Packit 6c4009
   Copyright (C) 2003-2018 Free Software Foundation, Inc.
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
Packit 6c4009
/* Type used for the representation of TLS information in the GOT.  */
Packit 6c4009
typedef struct
Packit 6c4009
{
Packit 6c4009
  unsigned long int ti_module;
Packit 6c4009
  unsigned long int ti_offset;
Packit 6c4009
} tls_index;
Packit 6c4009
Packit 6c4009
Packit 6c4009
#ifdef SHARED
Packit 6c4009
Packit 6c4009
extern unsigned long __tls_get_offset (unsigned long got_offset);
Packit 6c4009
Packit 6c4009
# if IS_IN (rtld)
Packit 6c4009
Packit 6c4009
#  include <shlib-compat.h>
Packit 6c4009
Packit 6c4009
/* dl-tls.c declares __tls_get_addr as an exported symbol if it is not defined
Packit 6c4009
   as a macro.  It seems suitable to do that in the generic code because all
Packit 6c4009
   architectures other than s390 export __tls_get_addr.  The declaration causes
Packit 6c4009
   problems in s390 though, so we define __tls_get_addr here to avoid declaring
Packit 6c4009
   __tls_get_addr again.  */
Packit 6c4009
#  define __tls_get_addr __tls_get_addr
Packit 6c4009
Packit 6c4009
extern void *__tls_get_addr (tls_index *ti) attribute_hidden;
Packit 6c4009
/* Make a temporary alias of __tls_get_addr to remove the hidden
Packit 6c4009
   attribute.  Then export __tls_get_addr as __tls_get_addr_internal
Packit 6c4009
   for use from libc.  We do not want to export __tls_get_addr, but we
Packit 6c4009
   do need to use it from libc when looking up the address of a TLS
Packit 6c4009
   variable. We don't use __tls_get_offset because it requires r12 to
Packit 6c4009
   be setup and that might not always be true. Either way it's more
Packit 6c4009
   optimal to use __tls_get_addr directly (that's what
Packit 6c4009
   __tls_get_offset does anyways).  */
Packit 6c4009
strong_alias (__tls_get_addr, __tls_get_addr_internal_tmp);
Packit 6c4009
versioned_symbol (ld, __tls_get_addr_internal_tmp,
Packit 6c4009
		  __tls_get_addr_internal, GLIBC_PRIVATE);
Packit 6c4009
Packit 6c4009
/* The special thing about the s390 TLS ABI is that we do not have the
Packit 6c4009
   standard __tls_get_addr function but the __tls_get_offset function
Packit 6c4009
   which differs in two important aspects:
Packit 6c4009
   1) __tls_get_offset gets a got offset instead of a pointer to the
Packit 6c4009
      tls_index structure
Packit 6c4009
   2) __tls_get_offset returns the offset of the requested variable to
Packit 6c4009
      the thread descriptor instead of a pointer to the variable.
Packit 6c4009
 */
Packit 6c4009
#  ifdef __s390x__
Packit 6c4009
__asm__("\n\
Packit 6c4009
	.text\n\
Packit 6c4009
	.globl __tls_get_offset\n\
Packit 6c4009
	.type __tls_get_offset, @function\n\
Packit 6c4009
	.align 4\n\
Packit 6c4009
__tls_get_offset:\n\
Packit 6c4009
	la	%r2,0(%r2,%r12)\n\
Packit 6c4009
	jg	__tls_get_addr\n\
Packit 6c4009
");
Packit 6c4009
#  elif defined __s390__
Packit 6c4009
__asm__("\n\
Packit 6c4009
	.text\n\
Packit 6c4009
	.globl __tls_get_offset\n\
Packit 6c4009
	.type __tls_get_offset, @function\n\
Packit 6c4009
	.align 4\n\
Packit 6c4009
__tls_get_offset:\n\
Packit 6c4009
	basr	%r3,0\n\
Packit 6c4009
0:	la	%r2,0(%r2,%r12)\n\
Packit 6c4009
	l	%r4,1f-0b(%r3)\n\
Packit 6c4009
	b	0(%r4,%r3)\n\
Packit 6c4009
1:	.long	__tls_get_addr - 0b\n\
Packit 6c4009
");
Packit 6c4009
#  endif
Packit 6c4009
# else /* IS_IN (rtld) */
Packit 6c4009
extern void *__tls_get_addr_internal (tls_index *ti);
Packit 6c4009
# endif /* !IS_IN (rtld) */
Packit 6c4009
Packit 6c4009
# define GET_ADDR_OFFSET \
Packit 6c4009
  (ti->ti_offset - (unsigned long) __builtin_thread_pointer ())
Packit 6c4009
Packit 6c4009
/* Use the privately exported __tls_get_addr_internal instead of
Packit 6c4009
   __tls_get_offset in order to avoid the __tls_get_offset special
Packit 6c4009
   linkage requiring the GOT pointer to be set up in r12.  The
Packit 6c4009
   compiler will take care of setting up r12 only if itself issued the
Packit 6c4009
   __tls_get_offset call.  */
Packit 6c4009
# define __TLS_GET_ADDR(__ti)					\
Packit 6c4009
  ({ __tls_get_addr_internal (__ti)				\
Packit 6c4009
      + (unsigned long) __builtin_thread_pointer (); })
Packit 6c4009
Packit 6c4009
#endif