Example #1
0
/* The generic dynamic and local dynamic model cannot be used in
   statically linked applications.  */
void *
__tls_get_addr (GET_ADDR_ARGS)
{
  dtv_t *dtv = THREAD_DTV ();
  struct link_map *the_map = NULL;
  void *p;

  if (__builtin_expect (dtv[0].counter != _dl_tls_generation, 0))
    {
      the_map = _dl_update_slotinfo (GET_ADDR_MODULE);
      dtv = THREAD_DTV ();
    }

  p = dtv[GET_ADDR_MODULE].pointer.val;

  if (__builtin_expect (p == TLS_DTV_UNALLOCATED, 0))
    {
      /* The allocation was deferred.  Do it now.  */
      if (the_map == NULL)
	{
	  /* Find the link map for this module.  */
	  size_t idx = GET_ADDR_MODULE;
	  struct dtv_slotinfo_list *listp = _dl_tls_dtv_slotinfo_list;

	  while (idx >= listp->len)
	    {
	      idx -= listp->len;
	      listp = listp->next;
	    }

	  the_map = listp->slotinfo[idx].map;
	}

      p = dtv[GET_ADDR_MODULE].pointer.val = allocate_and_init (the_map);
      dtv[GET_ADDR_MODULE].pointer.is_static = false;
    }

  return (char *) p + GET_ADDR_OFFSET;
}
Example #2
0
/* We are trying to perform a static TLS relocation in MAP, but it was
   dynamically loaded.  This can only work if there is enough surplus in
   the static TLS area already allocated for each running thread.  If this
   object's TLS segment is too big to fit, we fail.  If it fits,
   we set MAP->l_tls_offset and return.
   This function intentionally does not return any value but signals error
   directly, as static TLS should be rare and code handling it should
   not be inlined as much as possible.  */
int
_dl_try_allocate_static_tls (struct link_map *map)
{
  /* If we've already used the variable with dynamic access, or if the
     alignment requirements are too high, fail.  */
  if (map->l_tls_offset == FORCED_DYNAMIC_TLS_OFFSET
      || map->l_tls_align > GL(dl_tls_static_align))
    {
    fail:
      return -1;
    }

#if TLS_TCB_AT_TP
  size_t freebytes = GL(dl_tls_static_size) - GL(dl_tls_static_used);
  if (freebytes < TLS_TCB_SIZE)
    goto fail;
  freebytes -= TLS_TCB_SIZE;

  size_t blsize = map->l_tls_blocksize + map->l_tls_firstbyte_offset;
  if (freebytes < blsize)
    goto fail;

  size_t n = (freebytes - blsize) / map->l_tls_align;

  size_t offset = GL(dl_tls_static_used) + (freebytes - n * map->l_tls_align
					    - map->l_tls_firstbyte_offset);

  map->l_tls_offset = GL(dl_tls_static_used) = offset;
#elif TLS_DTV_AT_TP
  /* dl_tls_static_used includes the TCB at the beginning.  */
  size_t offset = (ALIGN_UP(GL(dl_tls_static_used)
			    - map->l_tls_firstbyte_offset,
			    map->l_tls_align)
		   + map->l_tls_firstbyte_offset);
  size_t used = offset + map->l_tls_blocksize;

  if (used > GL(dl_tls_static_size))
    goto fail;

  map->l_tls_offset = offset;
  map->l_tls_firstbyte_offset = GL(dl_tls_static_used);
  GL(dl_tls_static_used) = used;
#else
# error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
#endif

  /* If the object is not yet relocated we cannot initialize the
     static TLS region.  Delay it.  */
  if (map->l_real->l_relocated)
    {
#ifdef SHARED
      if (__builtin_expect (THREAD_DTV()[0].counter != GL(dl_tls_generation),
			    0))
	/* Update the slot information data for at least the generation of
	   the DSO we are allocating data for.  */
	(void) _dl_update_slotinfo (map->l_tls_modid);
#endif

      GL(dl_init_static_tls) (map);
    }
  else
    map->l_need_tls_init = 1;

  return 0;
}
Example #3
0
/*
 * We are trying to perform a static TLS relocation in MAP, but it was
 * dynamically loaded.  This can only work if there is enough surplus in
 * the static TLS area already allocated for each running thread.  If this
 * object's TLS segment is too big to fit, we fail.  If it fits,
 * we set MAP->l_tls_offset and return.
 * This function intentionally does not return any value but signals error
 * directly, as static TLS should be rare and code handling it should
 * not be inlined as much as possible.
 */
void
internal_function __attribute_noinline__
_dl_allocate_static_tls (struct link_map *map)
{
	/* If the alignment requirements are too high fail.  */
	if (map->l_tls_align > _dl_tls_static_align)
	{
fail:
		_dl_dprintf(2, "cannot allocate memory in static TLS block");
		_dl_exit(30);
	}

# ifdef TLS_TCB_AT_TP
	size_t freebytes;
	size_t n;
	size_t blsize;

	freebytes = _dl_tls_static_size - _dl_tls_static_used - TLS_TCB_SIZE;

	blsize = map->l_tls_blocksize + map->l_tls_firstbyte_offset;
	if (freebytes < blsize)
		goto fail;

	n = (freebytes - blsize) & ~(map->l_tls_align - 1);

	size_t offset = _dl_tls_static_used + (freebytes - n
		- map->l_tls_firstbyte_offset);

	map->l_tls_offset = _dl_tls_static_used = offset;
# elif defined(TLS_DTV_AT_TP)
	size_t used;
	size_t check;

	size_t offset = roundup_pow2 (_dl_tls_static_used, map->l_tls_align);
	used = offset + map->l_tls_blocksize;
	check = used;

	/* dl_tls_static_used includes the TCB at the beginning. */
	if (check > _dl_tls_static_size)
		goto fail;

	map->l_tls_offset = offset;
	_dl_tls_static_used = used;
# else
#  error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
# endif

	/*
	 * If the object is not yet relocated we cannot initialize the
	 * static TLS region.  Delay it.
	 */
	if (((struct elf_resolve *) map)->init_flag & RELOCS_DONE)
    {
#ifdef SHARED
		/*
		 * Update the slot information data for at least the generation of
		 * the DSO we are allocating data for.
		 */
		if (__builtin_expect (THREAD_DTV()[0].counter != _dl_tls_generation, 0))
			(void) _dl_update_slotinfo (map->l_tls_modid);
#endif
		_dl_init_static_tls (map);
	}
	else
		map->l_need_tls_init = 1;
}