Blame sysdeps/x86_64/tlsdesc.c

Packit Service 82fcde
/* Manage TLS descriptors.  x86_64 version.
Packit Service 82fcde
   Copyright (C) 2005-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 <link.h>
Packit Service 82fcde
#include <ldsodefs.h>
Packit Service 82fcde
#include <elf/dynamic-link.h>
Packit Service 82fcde
#include <tls.h>
Packit Service 82fcde
#include <dl-tlsdesc.h>
Packit Service 82fcde
#include <dl-unmap-segments.h>
Packit Service 82fcde
#include <tlsdeschtab.h>
Packit Service 82fcde
Packit Service 82fcde
/* The following 2 functions take a caller argument, that contains the
Packit Service 82fcde
   address expected to be in the TLS descriptor.  If it's changed, we
Packit Service 82fcde
   want to return immediately.  */
Packit Service 82fcde
Packit Service 82fcde
/* This function is used to lazily resolve TLS_DESC RELA relocations.
Packit Service 82fcde
   The argument location is used to hold a pointer to the relocation.  */
Packit Service 82fcde
Packit Service 82fcde
void
Packit Service 82fcde
attribute_hidden
Packit Service 82fcde
_dl_tlsdesc_resolve_rela_fixup (struct tlsdesc volatile *td,
Packit Service 82fcde
				struct link_map *l)
Packit Service 82fcde
{
Packit Service 82fcde
  const ElfW(Rela) *reloc = td->arg;
Packit Service 82fcde
Packit Service 82fcde
  if (_dl_tlsdesc_resolve_early_return_p
Packit Service 82fcde
      (td, (void*)(D_PTR (l, l_info[ADDRIDX (DT_TLSDESC_PLT)]) + l->l_addr)))
Packit Service 82fcde
    return;
Packit Service 82fcde
Packit Service 82fcde
  /* The code below was borrowed from _dl_fixup().  */
Packit Service 82fcde
  const ElfW(Sym) *const symtab
Packit Service 82fcde
    = (const void *) D_PTR (l, l_info[DT_SYMTAB]);
Packit Service 82fcde
  const char *strtab = (const void *) D_PTR (l, l_info[DT_STRTAB]);
Packit Service 82fcde
  const ElfW(Sym) *sym = &symtab[ELFW(R_SYM) (reloc->r_info)];
Packit Service 82fcde
  lookup_t result;
Packit Service 82fcde
Packit Service 82fcde
   /* Look up the target symbol.  If the normal lookup rules are not
Packit Service 82fcde
      used don't look in the global scope.  */
Packit Service 82fcde
  if (ELFW(ST_BIND) (sym->st_info) != STB_LOCAL
Packit Service 82fcde
      && __builtin_expect (ELFW(ST_VISIBILITY) (sym->st_other), 0) == 0)
Packit Service 82fcde
    {
Packit Service 82fcde
      const struct r_found_version *version = NULL;
Packit Service 82fcde
Packit Service 82fcde
      if (l->l_info[VERSYMIDX (DT_VERSYM)] != NULL)
Packit Service 82fcde
	{
Packit Service 82fcde
	  const ElfW(Half) *vernum =
Packit Service 82fcde
	    (const void *) D_PTR (l, l_info[VERSYMIDX (DT_VERSYM)]);
Packit Service 82fcde
	  ElfW(Half) ndx = vernum[ELFW(R_SYM) (reloc->r_info)] & 0x7fff;
Packit Service 82fcde
	  version = &l->l_versions[ndx];
Packit Service 82fcde
	  if (version->hash == 0)
Packit Service 82fcde
	    version = NULL;
Packit Service 82fcde
	}
Packit Service 82fcde
Packit Service 82fcde
      result = _dl_lookup_symbol_x (strtab + sym->st_name, l, &sym,
Packit Service 82fcde
				    l->l_scope, version, ELF_RTYPE_CLASS_PLT,
Packit Service 82fcde
				    DL_LOOKUP_ADD_DEPENDENCY, NULL);
Packit Service 82fcde
    }
Packit Service 82fcde
  else
Packit Service 82fcde
    {
Packit Service 82fcde
      /* We already found the symbol.  The module (and therefore its load
Packit Service 82fcde
	 address) is also known.  */
Packit Service 82fcde
      result = l;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  if (! sym)
Packit Service 82fcde
    {
Packit Service 82fcde
      td->arg = (void*)reloc->r_addend;
Packit Service 82fcde
      td->entry = _dl_tlsdesc_undefweak;
Packit Service 82fcde
    }
Packit Service 82fcde
  else
Packit Service 82fcde
    {
Packit Service 82fcde
#  ifndef SHARED
Packit Service 82fcde
      CHECK_STATIC_TLS (l, result);
Packit Service 82fcde
#  else
Packit Service 82fcde
      if (!TRY_STATIC_TLS (l, result))
Packit Service 82fcde
	{
Packit Service 82fcde
	  td->arg = _dl_make_tlsdesc_dynamic (result, sym->st_value
Packit Service 82fcde
					      + reloc->r_addend);
Packit Service 82fcde
	  td->entry = _dl_tlsdesc_dynamic;
Packit Service 82fcde
	}
Packit Service 82fcde
      else
Packit Service 82fcde
#  endif
Packit Service 82fcde
	{
Packit Service 82fcde
	  td->arg = (void*)(sym->st_value - result->l_tls_offset
Packit Service 82fcde
			    + reloc->r_addend);
Packit Service 82fcde
	  td->entry = _dl_tlsdesc_return;
Packit Service 82fcde
	}
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  _dl_tlsdesc_wake_up_held_fixups ();
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
/* This function is used to avoid busy waiting for other threads to
Packit Service 82fcde
   complete the lazy relocation.  Once another thread wins the race to
Packit Service 82fcde
   relocate a TLS descriptor, it sets the descriptor up such that this
Packit Service 82fcde
   function is called to wait until the resolver releases the
Packit Service 82fcde
   lock.  */
Packit Service 82fcde
Packit Service 82fcde
void
Packit Service 82fcde
attribute_hidden
Packit Service 82fcde
_dl_tlsdesc_resolve_hold_fixup (struct tlsdesc volatile *td,
Packit Service 82fcde
				void *caller)
Packit Service 82fcde
{
Packit Service 82fcde
  /* Maybe we're lucky and can return early.  */
Packit Service 82fcde
  if (caller != td->entry)
Packit Service 82fcde
    return;
Packit Service 82fcde
Packit Service 82fcde
  /* Locking here will stop execution until the running resolver runs
Packit Service 82fcde
     _dl_tlsdesc_wake_up_held_fixups(), releasing the lock.
Packit Service 82fcde
Packit Service 82fcde
     FIXME: We'd be better off waiting on a condition variable, such
Packit Service 82fcde
     that we didn't have to hold the lock throughout the relocation
Packit Service 82fcde
     processing.  */
Packit Service 82fcde
  __rtld_lock_lock_recursive (GL(dl_load_lock));
Packit Service 82fcde
  __rtld_lock_unlock_recursive (GL(dl_load_lock));
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
/* Unmap the dynamic object, but also release its TLS descriptor table
Packit Service 82fcde
   if there is one.  */
Packit Service 82fcde
Packit Service 82fcde
void
Packit Service 82fcde
_dl_unmap (struct link_map *map)
Packit Service 82fcde
{
Packit Service 82fcde
  _dl_unmap_segments (map);
Packit Service 82fcde
Packit Service 82fcde
#ifdef SHARED
Packit Service 82fcde
  /* _dl_unmap is only called for dlopen()ed libraries, for which
Packit Service 82fcde
     calling free() is safe, or before we've completed the initial
Packit Service 82fcde
     relocation, in which case calling free() is probably pointless,
Packit Service 82fcde
     but still safe.  */
Packit Service 82fcde
  if (map->l_mach.tlsdesc_table)
Packit Service 82fcde
    htab_delete (map->l_mach.tlsdesc_table);
Packit Service 82fcde
#endif
Packit Service 82fcde
}