summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ldso/ldso/dl-tls.c112
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. */