diff options
-rw-r--r-- | ldso/ldso/dl-tls.c | 112 |
1 files changed, 77 insertions, 35 deletions
diff --git a/ldso/ldso/dl-tls.c b/ldso/ldso/dl-tls.c index eef164d51..502720e58 100644 --- a/ldso/ldso/dl-tls.c +++ b/ldso/ldso/dl-tls.c @@ -26,16 +26,6 @@ * SUCH DAMAGE. */ -/* - * The big TODO list: - * - * - Environment variables LD_TRACE_LOADED_OBJECTS and LD_PRELOAD - * need to be supported. - * - Config option LDSO_PRELOAD_FILE_SUPPORT needs to be supported. - * - Support TLS information for 'ldd' command. - * - */ - #include <tls.h> #include <dl-tls.h> #include <ldsodefs.h> @@ -46,6 +36,7 @@ void *(*_dl_memalign_function) (size_t __boundary, size_t __size) = NULL; void (*_dl_free_function) (void *__ptr) = NULL; void *_dl_memalign (size_t __boundary, size_t __size); +struct link_map *_dl_update_slotinfo (unsigned long int req_modid); void * _dl_calloc (size_t __nmemb, size_t __size) @@ -85,7 +76,9 @@ _dl_free (void *__ptr) if (_dl_free_function) (*_dl_free_function) (__ptr); - _dl_debug_early("Unable to free memory used for TLS\n"); +#if 0 + _dl_debug_early("NOT IMPLEMENTED PROPERLY!!!\n"); +#endif } @@ -122,13 +115,81 @@ _dl_free (void *__ptr) _dl_allocate_static_tls (sym_map); \ } while (0) -void +/* + * 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) { - _dl_dprintf(2, "_dl_allocate_static_tls NOT IMPLEMENTED!\n"); - _dl_exit(1); - return; + /* 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); + } + +# if 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; + + size_t offset = _dl_tls_static_used + (freebytes - n * map->l_tls_align + - map->l_tls_firstbyte_offset); + + map->l_tls_offset = _dl_tls_static_used = offset; +# elif TLS_DTV_AT_TP + size_t used; + size_t check; + + size_t offset = roundup (_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; } /* Initialize static TLS area and DTV for current (only) thread. @@ -150,7 +211,7 @@ _dl_nothread_init_static_tls (struct link_map *map) dtv_t *dtv = THREAD_DTV (); if (!(map->l_tls_modid <= dtv[-1].counter)) { _dl_dprintf(2, "map->l_tls_modid <= dtv[-1].counter FAILED!\n"); - _dl_exit(1); + _dl_exit(30); } dtv[map->l_tls_modid].pointer.val = dest; dtv[map->l_tls_modid].pointer.is_static = true; @@ -415,11 +476,7 @@ allocate_dtv (void *result) initial set of modules. This should avoid in most cases expansions of the dtv. */ dtv_length = _dl_tls_max_dtv_idx + DTV_SURPLUS; -#ifndef __UCLIBC__ - dtv = calloc (dtv_length + 2, sizeof (dtv_t)); -#else dtv = _dl_calloc (dtv_length + 2, sizeof (dtv_t)); -#endif if (dtv != NULL) { /* This is the initial length of the dtv. */ @@ -936,20 +993,6 @@ init_tls (void) /* Fill in the information from the loaded modules. No namespace but the base one can be filled at this time. */ -#ifndef __UCLIBC__ - _dl_assert (_dl_ns[LM_ID_BASE + 1]._ns_loaded == NULL); - int i = 0; - struct link_map *l; - for (l = _dl_ns[LM_ID_BASE]._ns_loaded; 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. */ - slotinfo[i].map = l; - /* slotinfo[i].gen = 0; */ - ++i; - } -#else int i = 0; struct link_map *l; for (l = (struct link_map *) _dl_loaded_modules; l != NULL; l = l->l_next) @@ -961,7 +1004,6 @@ init_tls (void) /* slotinfo[i].gen = 0; */ ++i; } -#endif _dl_assert (i == _dl_tls_max_dtv_idx); /* Compute the TLS offsets for the various blocks. */ |