Blame csu/libc-tls.c

Packit Service 82fcde
/* Initialization code for TLS in statically linked application.
Packit Service 82fcde
   Copyright (C) 2002-2018 Free Software Foundation, Inc.
Packit Service 82fcde
   This file is part of the GNU C Library.
Packit Service 82fcde
Packit Service 82fcde
   The GNU C Library is free software; you can redistribute it and/or
Packit Service 82fcde
   modify it under the terms of the GNU Lesser General Public
Packit Service 82fcde
   License as published by the Free Software Foundation; either
Packit Service 82fcde
   version 2.1 of the License, or (at your option) any later version.
Packit Service 82fcde
Packit Service 82fcde
   The GNU C Library is distributed in the hope that it will be useful,
Packit Service 82fcde
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 82fcde
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit Service 82fcde
   Lesser General Public License for more details.
Packit Service 82fcde
Packit Service 82fcde
   You should have received a copy of the GNU Lesser General Public
Packit Service 82fcde
   License along with the GNU C Library; if not, see
Packit Service 82fcde
   <http://www.gnu.org/licenses/>.  */
Packit Service 82fcde
Packit Service 82fcde
#include <startup.h>
Packit Service 82fcde
#include <errno.h>
Packit Service 82fcde
#include <ldsodefs.h>
Packit Service 82fcde
#include <tls.h>
Packit Service 82fcde
#include <unistd.h>
Packit Service 82fcde
#include <stdio.h>
Packit Service 82fcde
#include <sys/param.h>
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
#ifdef SHARED
Packit Service 82fcde
 #error makefile bug, this file is for static only
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
dtv_t _dl_static_dtv[2 + TLS_SLOTINFO_SURPLUS];
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
static struct
Packit Service 82fcde
{
Packit Service 82fcde
  struct dtv_slotinfo_list si;
Packit Service 82fcde
  /* The dtv_slotinfo_list data structure does not include the actual
Packit Service 82fcde
     information since it is defined as an array of size zero.  We define
Packit Service 82fcde
     here the necessary entries.  Note that it is not important whether
Packit Service 82fcde
     there is padding or not since we will always access the information
Packit Service 82fcde
     through the 'si' element.  */
Packit Service 82fcde
  struct dtv_slotinfo info[2 + TLS_SLOTINFO_SURPLUS];
Packit Service 82fcde
} static_slotinfo;
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
/* Highest dtv index currently needed.  */
Packit Service 82fcde
size_t _dl_tls_max_dtv_idx;
Packit Service 82fcde
/* Flag signalling whether there are gaps in the module ID allocation.  */
Packit Service 82fcde
bool _dl_tls_dtv_gaps;
Packit Service 82fcde
/* Information about the dtv slots.  */
Packit Service 82fcde
struct dtv_slotinfo_list *_dl_tls_dtv_slotinfo_list;
Packit Service 82fcde
/* Number of modules in the static TLS block.  */
Packit Service 82fcde
size_t _dl_tls_static_nelem;
Packit Service 82fcde
/* Size of the static TLS block.  Giving this initialized value
Packit Service 82fcde
   preallocates some surplus bytes in the static TLS area.  */
Packit Service 82fcde
size_t _dl_tls_static_size = 2048;
Packit Service 82fcde
/* Size actually allocated in the static TLS block.  */
Packit Service 82fcde
size_t _dl_tls_static_used;
Packit Service 82fcde
/* Alignment requirement of the static TLS block.  */
Packit Service 82fcde
size_t _dl_tls_static_align;
Packit Service 82fcde
Packit Service 82fcde
/* Generation counter for the dtv.  */
Packit Service 82fcde
size_t _dl_tls_generation;
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
/* Additional definitions needed by TLS initialization.  */
Packit Service 82fcde
#ifdef TLS_INIT_HELPER
Packit Service 82fcde
TLS_INIT_HELPER
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
static void
Packit Service 82fcde
init_slotinfo (void)
Packit Service 82fcde
{
Packit Service 82fcde
  /* Create the slotinfo list.  */
Packit Service 82fcde
  static_slotinfo.si.len = (((char *) (&static_slotinfo + 1)
Packit Service 82fcde
			     - (char *) &static_slotinfo.si.slotinfo[0])
Packit Service 82fcde
			    / sizeof static_slotinfo.si.slotinfo[0]);
Packit Service 82fcde
  // static_slotinfo.si.next = NULL;	already zero
Packit Service 82fcde
Packit Service 82fcde
  /* The slotinfo list.  Will be extended by the code doing dynamic
Packit Service 82fcde
     linking.  */
Packit Service 82fcde
  GL(dl_tls_max_dtv_idx) = 1;
Packit Service 82fcde
  GL(dl_tls_dtv_slotinfo_list) = &static_slotinfo.si;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
static void
Packit Service 82fcde
init_static_tls (size_t memsz, size_t align)
Packit Service 82fcde
{
Packit Service 82fcde
  /* That is the size of the TLS memory for this object.  The initialized
Packit Service 82fcde
     value of _dl_tls_static_size is provided by dl-open.c to request some
Packit Service 82fcde
     surplus that permits dynamic loading of modules with IE-model TLS.  */
Packit Service 82fcde
  GL(dl_tls_static_size) = roundup (memsz + GL(dl_tls_static_size),
Packit Service 82fcde
				    TLS_TCB_ALIGN);
Packit Service 82fcde
#if TLS_TCB_AT_TP
Packit Service 82fcde
  GL(dl_tls_static_size) += TLS_TCB_SIZE;
Packit Service 82fcde
#endif
Packit Service 82fcde
  GL(dl_tls_static_used) = memsz;
Packit Service 82fcde
  /* The alignment requirement for the static TLS block.  */
Packit Service 82fcde
  GL(dl_tls_static_align) = align;
Packit Service 82fcde
  /* Number of elements in the static TLS block.  */
Packit Service 82fcde
  GL(dl_tls_static_nelem) = GL(dl_tls_max_dtv_idx);
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
void
Packit Service 82fcde
__libc_setup_tls (void)
Packit Service 82fcde
{
Packit Service 82fcde
  void *tlsblock;
Packit Service 82fcde
  size_t memsz = 0;
Packit Service 82fcde
  size_t filesz = 0;
Packit Service 82fcde
  void *initimage = NULL;
Packit Service 82fcde
  size_t align = 0;
Packit Service 82fcde
  size_t max_align = TCB_ALIGNMENT;
Packit Service 82fcde
  size_t tcb_offset;
Packit Service 82fcde
  const ElfW(Phdr) *phdr;
Packit Service 82fcde
Packit Service 82fcde
  struct link_map *main_map = GL(dl_ns)[LM_ID_BASE]._ns_loaded;
Packit Service 82fcde
Packit Service 82fcde
  /* Look through the TLS segment if there is any.  */
Packit Service 82fcde
  if (_dl_phdr != NULL)
Packit Service 82fcde
    for (phdr = _dl_phdr; phdr < &_dl_phdr[_dl_phnum]; ++phdr)
Packit Service 82fcde
      if (phdr->p_type == PT_TLS)
Packit Service 82fcde
	{
Packit Service 82fcde
	  /* Remember the values we need.  */
Packit Service 82fcde
	  memsz = phdr->p_memsz;
Packit Service 82fcde
	  filesz = phdr->p_filesz;
Packit Service 82fcde
	  initimage = (void *) phdr->p_vaddr + main_map->l_addr;
Packit Service 82fcde
	  align = phdr->p_align;
Packit Service 82fcde
	  if (phdr->p_align > max_align)
Packit Service 82fcde
	    max_align = phdr->p_align;
Packit Service 82fcde
	  break;
Packit Service 82fcde
	}
Packit Service 82fcde
Packit Service 82fcde
  /* We have to set up the TCB block which also (possibly) contains
Packit Service 82fcde
     'errno'.  Therefore we avoid 'malloc' which might touch 'errno'.
Packit Service 82fcde
     Instead we use 'sbrk' which would only uses 'errno' if it fails.
Packit Service 82fcde
     In this case we are right away out of memory and the user gets
Packit Service 82fcde
     what she/he deserves.
Packit Service 82fcde
Packit Service 82fcde
     The initialized value of _dl_tls_static_size is provided by dl-open.c
Packit Service 82fcde
     to request some surplus that permits dynamic loading of modules with
Packit Service 82fcde
     IE-model TLS.  */
Packit Service 82fcde
#if TLS_TCB_AT_TP
Packit Service 82fcde
  /* Align the TCB offset to the maximum alignment, as
Packit Service 82fcde
     _dl_allocate_tls_storage (in elf/dl-tls.c) does using __libc_memalign
Packit Service 82fcde
     and dl_tls_static_align.  */
Packit Service 82fcde
  tcb_offset = roundup (memsz + GL(dl_tls_static_size), max_align);
Packit Service 82fcde
  tlsblock = __sbrk (tcb_offset + TLS_INIT_TCB_SIZE + max_align);
Packit Service 82fcde
#elif TLS_DTV_AT_TP
Packit Service 82fcde
  tcb_offset = roundup (TLS_INIT_TCB_SIZE, align ?: 1);
Packit Service 82fcde
  tlsblock = __sbrk (tcb_offset + memsz + max_align
Packit Service 82fcde
		     + TLS_PRE_TCB_SIZE + GL(dl_tls_static_size));
Packit Service 82fcde
  tlsblock += TLS_PRE_TCB_SIZE;
Packit Service 82fcde
#else
Packit Service 82fcde
  /* In case a model with a different layout for the TCB and DTV
Packit Service 82fcde
     is defined add another #elif here and in the following #ifs.  */
Packit Service 82fcde
# error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
  /* Align the TLS block.  */
Packit Service 82fcde
  tlsblock = (void *) (((uintptr_t) tlsblock + max_align - 1)
Packit Service 82fcde
		       & ~(max_align - 1));
Packit Service 82fcde
Packit Service 82fcde
  /* Initialize the dtv.  [0] is the length, [1] the generation counter.  */
Packit Service 82fcde
  _dl_static_dtv[0].counter = (sizeof (_dl_static_dtv) / sizeof (_dl_static_dtv[0])) - 2;
Packit Service 82fcde
  // _dl_static_dtv[1].counter = 0;		would be needed if not already done
Packit Service 82fcde
Packit Service 82fcde
  /* Initialize the TLS block.  */
Packit Service 82fcde
#if TLS_TCB_AT_TP
Packit Service 82fcde
  _dl_static_dtv[2].pointer.val = ((char *) tlsblock + tcb_offset
Packit Service 82fcde
			       - roundup (memsz, align ?: 1));
Packit Service 82fcde
  main_map->l_tls_offset = roundup (memsz, align ?: 1);
Packit Service 82fcde
#elif TLS_DTV_AT_TP
Packit Service 82fcde
  _dl_static_dtv[2].pointer.val = (char *) tlsblock + tcb_offset;
Packit Service 82fcde
  main_map->l_tls_offset = tcb_offset;
Packit Service 82fcde
#else
Packit Service 82fcde
# error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
Packit Service 82fcde
#endif
Packit Service 82fcde
  _dl_static_dtv[2].pointer.to_free = NULL;
Packit Service 82fcde
  /* sbrk gives us zero'd memory, so we don't need to clear the remainder.  */
Packit Service 82fcde
  memcpy (_dl_static_dtv[2].pointer.val, initimage, filesz);
Packit Service 82fcde
Packit Service 82fcde
  /* Install the pointer to the dtv.  */
Packit Service 82fcde
Packit Service 82fcde
  /* Initialize the thread pointer.  */
Packit Service 82fcde
#if TLS_TCB_AT_TP
Packit Service 82fcde
  INSTALL_DTV ((char *) tlsblock + tcb_offset, _dl_static_dtv);
Packit Service 82fcde
Packit Service 82fcde
  const char *lossage = TLS_INIT_TP ((char *) tlsblock + tcb_offset);
Packit Service 82fcde
#elif TLS_DTV_AT_TP
Packit Service 82fcde
  INSTALL_DTV (tlsblock, _dl_static_dtv);
Packit Service 82fcde
  const char *lossage = TLS_INIT_TP (tlsblock);
Packit Service 82fcde
#else
Packit Service 82fcde
# error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
Packit Service 82fcde
#endif
Packit Service 82fcde
  if (__builtin_expect (lossage != NULL, 0))
Packit Service 82fcde
    _startup_fatal (lossage);
Packit Service 82fcde
Packit Service 82fcde
  /* Update the executable's link map with enough information to make
Packit Service 82fcde
     the TLS routines happy.  */
Packit Service 82fcde
  main_map->l_tls_align = align;
Packit Service 82fcde
  main_map->l_tls_blocksize = memsz;
Packit Service 82fcde
  main_map->l_tls_initimage = initimage;
Packit Service 82fcde
  main_map->l_tls_initimage_size = filesz;
Packit Service 82fcde
  main_map->l_tls_modid = 1;
Packit Service 82fcde
Packit Service 82fcde
  init_slotinfo ();
Packit Service 82fcde
  // static_slotinfo.si.slotinfo[1].gen = 0; already zero
Packit Service 82fcde
  static_slotinfo.si.slotinfo[1].map = main_map;
Packit Service 82fcde
Packit Service 82fcde
  memsz = roundup (memsz, align ?: 1);
Packit Service 82fcde
Packit Service 82fcde
#if TLS_DTV_AT_TP
Packit Service 82fcde
  memsz += tcb_offset;
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
  init_static_tls (memsz, MAX (TLS_TCB_ALIGN, max_align));
Packit Service 82fcde
}