/* Align the TCB offset to the maximum alignment, as _dl_allocate_tls_storage (in elf/dl-tls.c) does using __libc_memalign and dl_tls_static_align. */ tcb_offset = roundup (memsz + GLRO(dl_tls_static_surplus), max_align); tlsblock = __sbrk(tcb_offset + TLS_INIT_TCB_SIZE + max_align);
typedefstruct { void *tcb; /* Pointer to the TCB. Not necessarily the thread descriptor used by libpthread. */ dtv_t *dtv; void *self; /* Pointer to the thread descriptor. */ int multiple_threads; int gscope_flag; uintptr_t sysinfo; uintptr_t stack_guard; uintptr_t pointer_guard; unsignedlongint vgetcpu_cache[2]; # ifndef __ASSUME_PRIVATE_FUTEX int private_futex; # else int __glibc_reserved1; # endif int __glibc_unused1; /* Reservation of some values for the TM ABI. */ void *__private_tm[4]; /* GCC split stack support. */ void *__private_ss; longint __glibc_reserved2; /* Must be kept even if it is no longer used by glibc since programs, like AddressSanitizer, depend on the size of tcbhead_t. */ __128bits __glibc_unused2[8][4] __attribute__ ((aligned (32))); void *__padding[8]; } tcbhead_t;
structdtv_pointer { void *val; /* Pointer to data, or TLS_DTV_UNALLOCATED. */ void *to_free; /* Unaligned pointer, for deallocation. */ }; /* Type for the dtv. */ typedefuniondtv { size_t counter; structdtv_pointerpointer; } dtv_t; /* Number of additional entries in the slotinfo array of each slotinfo list element. A large number makes it almost certain take we never have to iterate beyond the first element in the slotinfo list. */ #define TLS_SLOTINFO_SURPLUS (62) dtv_t _dl_static_dtv[2 + TLS_SLOTINFO_SURPLUS]; /* Align the TLS block. */ tlsblock = (void *) (((uintptr_t) tlsblock + max_align - 1) & ~(max_align - 1)); /* Initialize the dtv. [0] is the length, [1] the generation counter. */ _dl_static_dtv[0].counter = (sizeof(_dl_static_dtv) / sizeof(_dl_static_dtv[0])) - 2; // _dl_static_dtv[1].counter = 0; would be needed if not already done /* Initialize the TLS block. */ _dl_static_dtv[2].pointer.val = ((char *) tlsblock + tcb_offset - roundup (memsz, align ?: 1)); _dl_static_dtv[2].pointer.to_free = NULL; /* sbrk gives us zero'd memory, so we don't need to clear the remainder. */ memcpy(_dl_static_dtv[2].pointer.val, initimage, filesz);
/* Install the dtv pointer. The pointer passed is to the element with index -1 which contain the length. */ # define INSTALL_DTV(descr, dtvp) ((tcbhead_t *) (descr))->dtv = (dtvp) + 1 staticvoid * 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 = GL(dl_tls_max_dtv_idx) + DTV_SURPLUS; dtv = 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; }
dtv[map->l_tls_modid].pointer.val = TLS_DTV_UNALLOCATED; dtv[map->l_tls_modid].pointer.to_free = NULL; if (map->l_tls_offset == NO_TLS_OFFSET || map->l_tls_offset == FORCED_DYNAMIC_TLS_OFFSET) continue; /* Set up the DTV entry. The simplified __tls_get_addr that some platforms use in static programs requires it. */ dtv[map->l_tls_modid].pointer.val = dest; /* Copy the initialization image and clear the BSS part. */ memset(__mempcpy (dest, map->l_tls_initimage, map->l_tls_initimage_size), '�', map->l_tls_blocksize - map->l_tls_initimage_size);