Esempio n. 1
0
int
internal_function
_dl_tls_setup (void)
{
  _dl_assert (_dl_tls_dtv_slotinfo_list == NULL);
  _dl_assert (_dl_tls_max_dtv_idx == 0);

  const size_t nelem = 2 + TLS_SLOTINFO_SURPLUS;

  _dl_tls_dtv_slotinfo_list
    = _dl_calloc (1, (sizeof (struct dtv_slotinfo_list)
		  + nelem * sizeof (struct dtv_slotinfo)));
  if (_dl_tls_dtv_slotinfo_list == NULL)
    return -1;

  _dl_tls_dtv_slotinfo_list->len = nelem;

  /* Number of elements in the static TLS block.  It can't be zero
     because of various assumptions.  The one element is null.  */
  _dl_tls_static_nelem = _dl_tls_max_dtv_idx = 1;

  /* This initializes more variables for us.  */
  _dl_determine_tlsoffset ();

  return 0;
}
Esempio n. 2
0
internal_function
allocate_dtv (void *result)
{
  dtv_t *dtv;
  size_t dtv_length;

  /* We allocate a few more elements in the dtv than are needed for the
     initial set of modules.  This should avoid in most cases expansions
     of the dtv.  */
  dtv_length = _dl_tls_max_dtv_idx + DTV_SURPLUS;
  dtv = _dl_calloc (dtv_length + 2, sizeof (dtv_t));
  if (dtv != NULL)
    {
      /* This is the initial length of the dtv.  */
      dtv[0].counter = dtv_length;

      /* The rest of the dtv (including the generation counter) is
	 Initialize with zero to indicate nothing there.  */

      /* Add the dtv to the thread data structures.  */
      INSTALL_DTV (result, dtv);
    }
  else
    result = NULL;

  return result;
}
Esempio n. 3
0
internal_function
init_tls (void)
{
	/* Number of elements in the static TLS block.  */
	_dl_tls_static_nelem = _dl_tls_max_dtv_idx;

	/* Do not do this twice.  The audit interface might have required
	   the DTV interfaces to be set up early.  */
	if (_dl_initial_dtv != NULL)
		return NULL;

	/* Allocate the array which contains the information about the
	   dtv slots.  We allocate a few entries more than needed to
	   avoid the need for reallocation.  */
	size_t nelem = _dl_tls_max_dtv_idx + 1 + TLS_SLOTINFO_SURPLUS;

	/* Allocate.  */
	_dl_assert (_dl_tls_dtv_slotinfo_list == NULL);
	_dl_tls_dtv_slotinfo_list = (struct dtv_slotinfo_list *)
		_dl_calloc (sizeof (struct dtv_slotinfo_list)
			+ nelem * sizeof (struct dtv_slotinfo), 1);
	/* No need to check the return value.  If memory allocation failed
	   the program would have been terminated.  */

	struct dtv_slotinfo *slotinfo = _dl_tls_dtv_slotinfo_list->slotinfo;
	_dl_tls_dtv_slotinfo_list->len = nelem;
	_dl_tls_dtv_slotinfo_list->next = NULL;

	/* Fill in the information from the loaded modules.  No namespace
	   but the base one can be filled at this time.  */
	int i = 0;
	struct link_map *l;
	for (l =  (struct link_map *) _dl_loaded_modules; l != NULL; l = l->l_next)
		if (l->l_tls_blocksize != 0)
		{
			/* This is a module with TLS data.  Store the map reference.
			   The generation counter is zero.  */

			/* Skeep slot[0]: it will be never used */
			slotinfo[++i].map = l;
		}
	_dl_assert (i == _dl_tls_max_dtv_idx);

	/* Compute the TLS offsets for the various blocks.  */
	_dl_determine_tlsoffset ();

	/* Construct the static TLS block and the dtv for the initial
	   thread.  For some platforms this will include allocating memory
	   for the thread descriptor.  The memory for the TLS block will
	   never be freed.  It should be allocated accordingly.  The dtv
	   array can be changed if dynamic loading requires it.  */
	void *tcbp = _dl_allocate_tls_storage ();
	if (tcbp == NULL) {
		_dl_debug_early("\ncannot allocate TLS data structures for initial thread");
		_dl_exit(30);
	}

	/* Store for detection of the special case by __tls_get_addr
	   so it knows not to pass this dtv to the normal realloc.  */
	_dl_initial_dtv = GET_DTV (tcbp);

	/* And finally install it for the main thread.  If ld.so itself uses
	   TLS we know the thread pointer was initialized earlier.  */
	const char *lossage = TLS_INIT_TP (tcbp, USE___THREAD);
	if(__builtin_expect (lossage != NULL, 0)) {
		_dl_debug_early("cannot set up thread-local storage: %s\n", lossage);
		_dl_exit(30);
	}
	tls_init_tp_called = true;

	return tcbp;
}
Esempio n. 4
0
/*
 * Initialize a new dynamic object.
 */
elf_object_t *
_dl_finalize_object(const char *objname, Elf_Dyn *dynp, Elf_Phdr *phdrp,
    int phdrc, const int objtype, const long lbase, const long obase)
{
	elf_object_t *object;
#if 0
	_dl_printf("objname [%s], dynp %p, objtype %x lbase %lx, obase %lx\n",
	    objname, dynp, objtype, lbase, obase);
#endif
	object = _dl_calloc(1, sizeof(elf_object_t));
	if (object == NULL)
		_dl_exit(7);
	object->prev = object->next = NULL;

	object->load_dyn = dynp;
	while (dynp->d_tag != DT_NULL) {
		if (dynp->d_tag < DT_NUM)
			object->Dyn.info[dynp->d_tag] = dynp->d_un.d_val;
		else if (dynp->d_tag >= DT_LOPROC &&
		    dynp->d_tag < DT_LOPROC + DT_PROCNUM)
			object->Dyn.info[dynp->d_tag + DT_NUM - DT_LOPROC] =
			    dynp->d_un.d_val;
		if (dynp->d_tag == DT_TEXTREL)
			object->dyn.textrel = 1;
		if (dynp->d_tag == DT_SYMBOLIC)
			object->dyn.symbolic = 1;
		if (dynp->d_tag == DT_BIND_NOW)
			object->obj_flags |= DF_1_NOW;
		if (dynp->d_tag == DT_FLAGS_1)
			object->obj_flags |= dynp->d_un.d_val;
		if (dynp->d_tag == DT_RELACOUNT)
			object->relacount = dynp->d_un.d_val;
		if (dynp->d_tag == DT_RELCOUNT)
			object->relcount = dynp->d_un.d_val;
		dynp++;
	}
	DL_DEB((" flags %s = 0x%x\n", objname, object->obj_flags ));
	object->obj_type = objtype;

	if (_dl_loading_object == NULL) {
		/*
		 * no loading object, object is the loading object,
		 * as it is either executable, or dlopened()
		 */
		_dl_loading_object = object;
	}

	if ((object->obj_flags & DF_1_NOOPEN) != 0 &&
	    _dl_loading_object->obj_type == OBJTYPE_DLO &&
	    _dl_traceld == NULL) {
		_dl_free(object);
		_dl_errno = DL_CANT_LOAD_OBJ;
		return(NULL);
	}

	/*
	 *  Now relocate all pointer to dynamic info, but only
	 *  the ones which have pointer values.
	 */
	if (object->Dyn.info[DT_PLTGOT])
		object->Dyn.info[DT_PLTGOT] += obase;
	if (object->Dyn.info[DT_HASH])
		object->Dyn.info[DT_HASH] += obase;
	if (object->Dyn.info[DT_STRTAB])
		object->Dyn.info[DT_STRTAB] += obase;
	if (object->Dyn.info[DT_SYMTAB])
		object->Dyn.info[DT_SYMTAB] += obase;
	if (object->Dyn.info[DT_RELA])
		object->Dyn.info[DT_RELA] += obase;
	if (object->Dyn.info[DT_SONAME])
		object->Dyn.info[DT_SONAME] += object->Dyn.info[DT_STRTAB];
	if (object->Dyn.info[DT_RPATH])
		object->Dyn.info[DT_RPATH] += object->Dyn.info[DT_STRTAB];
	if (object->Dyn.info[DT_REL])
		object->Dyn.info[DT_REL] += obase;
	if (object->Dyn.info[DT_INIT])
		object->Dyn.info[DT_INIT] += obase;
	if (object->Dyn.info[DT_FINI])
		object->Dyn.info[DT_FINI] += obase;
	if (object->Dyn.info[DT_JMPREL])
		object->Dyn.info[DT_JMPREL] += obase;

	if (object->Dyn.info[DT_HASH] != 0) {
		Elf_Word *hashtab = (Elf_Word *)object->Dyn.info[DT_HASH];

		object->nbuckets = hashtab[0];
		object->nchains = hashtab[1];
		object->buckets = hashtab + 2;
		object->chains = object->buckets + object->nbuckets;
	}

	object->phdrp = phdrp;
	object->phdrc = phdrc;
	object->load_base = lbase;
	object->obj_base = obase;
	object->load_name = _dl_strdup(objname);
	if (object->load_name == NULL)
		_dl_exit(7);
	object->load_object = _dl_loading_object;
	if (object->load_object == object)
		DL_DEB(("head %s\n", object->load_name));
	DL_DEB(("obj %s has %s as head\n", object->load_name,
	    _dl_loading_object->load_name ));
	object->refcount = 0;
	TAILQ_INIT(&object->child_list);
	object->opencount = 0;	/* # dlopen() & exe */
	object->grprefcount = 0;
	/* default dev, inode for dlopen-able objects. */
	object->dev = 0;
	object->inode = 0;
	object->grpsym_gen = 0;
	TAILQ_INIT(&object->grpsym_list);
	TAILQ_INIT(&object->grpref_list);

	if (object->dyn.rpath) {
		object->rpath = _dl_split_path(object->dyn.rpath);
		if ((object->obj_flags & DF_1_ORIGIN) && _dl_trust)
			_dl_origin_subst(object);
	}

	_dl_trace_object_setup(object);

	return (object);
}