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; }
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; }
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; }
/* * 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); }