Index: uspace/lib/c/arch/ia32/include/libarch/tls.h
===================================================================
--- uspace/lib/c/arch/ia32/include/libarch/tls.h	(revision e2f260026920f1d43bed8d2b775564b1f64a6f6a)
+++ uspace/lib/c/arch/ia32/include/libarch/tls.h	(revision d2bb25e777311fb1c2e3cb09e66bab0c8b523a13)
@@ -43,4 +43,5 @@
 	void *self;
 	void *fibril_data;
+	void **dtv;
 } tcb_t;
 
Index: uspace/lib/c/arch/ia32/src/rtld/reloc.c
===================================================================
--- uspace/lib/c/arch/ia32/src/rtld/reloc.c	(revision e2f260026920f1d43bed8d2b775564b1f64a6f6a)
+++ uspace/lib/c/arch/ia32/src/rtld/reloc.c	(revision d2bb25e777311fb1c2e3cb09e66bab0c8b523a13)
@@ -101,9 +101,9 @@
 			sym_def = symbol_def_find(str_tab + sym->st_name,
 			    m, ssf_none, &dest);
-//			DPRINTF("dest name: '%s'\n", dest->dyn.soname);
+			DPRINTF("dest name: '%s'\n", dest->dyn.soname);
 //			DPRINTF("dest bias: 0x%x\n", dest->bias);
 			if (sym_def) {
 				sym_addr = (uint32_t)
-				    symbol_get_addr(sym_def, dest);
+				    symbol_get_addr(sym_def, dest, NULL);
 //				DPRINTF("symbol definition found, addr=0x%x\n", sym_addr);
 			} else {
@@ -154,5 +154,5 @@
 			if (sym_def) {
 				sym_addr = (uint32_t)
-				    symbol_get_addr(sym_def, dest);
+				    symbol_get_addr(sym_def, dest, NULL);
 			} else {
 				printf("Source definition of '%s' not found.\n",
Index: uspace/lib/c/arch/ia32/src/tls.c
===================================================================
--- uspace/lib/c/arch/ia32/src/tls.c	(revision e2f260026920f1d43bed8d2b775564b1f64a6f6a)
+++ uspace/lib/c/arch/ia32/src/tls.c	(revision d2bb25e777311fb1c2e3cb09e66bab0c8b523a13)
@@ -73,6 +73,6 @@
 #ifdef CONFIG_RTLD
 	if (runtime_env != NULL) {
-		return rtld_tls_get_addr(runtime_env, ti->ti_module,
-		    ti->ti_offset);
+		return rtld_tls_get_addr(runtime_env, __tcb_get(),
+		    ti->ti_module, ti->ti_offset);
 	}
 #endif
Index: uspace/lib/c/generic/dlfcn.c
===================================================================
--- uspace/lib/c/generic/dlfcn.c	(revision e2f260026920f1d43bed8d2b775564b1f64a6f6a)
+++ uspace/lib/c/generic/dlfcn.c	(revision d2bb25e777311fb1c2e3cb09e66bab0c8b523a13)
@@ -84,5 +84,5 @@
 	sd = symbol_bfs_find(sym_name, (module_t *) mod, &sm);
 	if (sd != NULL) {
-		return symbol_get_addr(sd, sm);
+		return symbol_get_addr(sd, sm, __tcb_get());
 	}
 
Index: uspace/lib/c/generic/rtld/rtld.c
===================================================================
--- uspace/lib/c/generic/rtld/rtld.c	(revision e2f260026920f1d43bed8d2b775564b1f64a6f6a)
+++ uspace/lib/c/generic/rtld/rtld.c	(revision d2bb25e777311fb1c2e3cb09e66bab0c8b523a13)
@@ -143,4 +143,7 @@
 	tcb_t *tcb;
 	size_t offset;
+	void **dtv;
+	size_t nmods;
+	size_t i;
 
 	tcb = tls_alloc_arch(&data, rtld->tls_size);
@@ -148,7 +151,21 @@
 		return NULL;
 
-	/*
-	 * Copy thread local data from the modules' initialization images.
-	 * Zero out thread-local uninitialized data.
+	/** Allocate dynamic thread vector */
+	nmods = list_count(&rtld->imodules);
+	dtv = malloc((nmods + 1) * sizeof(void *));
+	if (dtv == NULL) {
+		tls_free(tcb);
+		return NULL;
+	}
+
+	/*
+	 * We define generation number to be equal to vector length.
+	 * We start with a vector covering the initially loaded modules.
+	 */
+	DTV_GN(dtv) = nmods;
+
+	/*
+	 * Copy thread local data from the initialization images of initial
+	 * modules. Zero out thread-local uninitialized data.
 	 */
 
@@ -157,7 +174,9 @@
 	 * Ascending addresses
 	 */
-	offset = 0;
+	offset = 0; i = 1;
 	list_foreach(rtld->imodules, imodules_link, module_t, m) {
+		assert(i == m->id);
 		assert(offset + m->tdata_size + m->tbss_size <= rtld->tls_size);
+		dtv[i++] = data + offset;
 		memcpy(data + offset, m->tdata, m->tdata_size);
 		offset += m->tdata_size;
@@ -169,6 +188,7 @@
 	 * Descending addresses
 	 */
-	offset = 0;
+	offset = 0; i = 1;
 	list_foreach(rtld->imodules, imodules_link, module_t, m) {
+		assert(i == m->id);
 		assert(offset + m->tdata_size + m->tbss_size <= rtld->tls_size);
 		offset += m->tbss_size;
@@ -176,7 +196,9 @@
 		offset += m->tdata_size;
 		memcpy(data + rtld->tls_size - offset, m->tdata, m->tdata_size);
+		dtv[i++] = data + rtld->tls_size - offset;
 	}
 #endif
 
+	tcb->dtv = dtv;
 	return tcb;
 }
@@ -187,23 +209,23 @@
 }
 
-void *rtld_tls_get_addr(rtld_t *rtld, unsigned long mod_id,
+/** Get address of thread-local variable.
+ *
+ * @param rtld RTLD instance
+ * @param tcb TCB of the thread whose instance to return
+ * @param mod_id Module ID
+ * @param offset Offset within TLS block of the module
+ *
+ * @return Address of thread-local variable
+ */
+void *rtld_tls_get_addr(rtld_t *rtld, tcb_t *tcb, unsigned long mod_id,
     unsigned long offset)
 {
-	module_t *m;
-	uint8_t *tls;
-
-	m = module_by_id(rtld, mod_id);
-	assert(m != NULL);
-
-	if (!link_used(&m->imodules_link)) {
-		printf("module '%s' is not initial. aborting.\n",
-		    m->dyn.soname);
+	if (DTV_GN(tcb->dtv) < mod_id || tcb->dtv[mod_id] == NULL) {
+		printf("Module is not initial. aborting.\n");
 		abort();
 	}
 
-	tls = tls_get();
-	return tls + m->ioffs + offset;
-}
-
+	return (uint8_t *)(tcb->dtv[mod_id]) + offset;
+}
 
 /** @}
Index: uspace/lib/c/generic/rtld/symbol.c
===================================================================
--- uspace/lib/c/generic/rtld/symbol.c	(revision e2f260026920f1d43bed8d2b775564b1f64a6f6a)
+++ uspace/lib/c/generic/rtld/symbol.c	(revision d2bb25e777311fb1c2e3cb09e66bab0c8b523a13)
@@ -249,8 +249,20 @@
 }
 
-void *symbol_get_addr(elf_symbol_t *sym, module_t *m)
+/** Get symbol address.
+ *
+ * @param sym Symbol
+ * @param m Module contaning the symbol
+ * @param tcb TCB of the thread whose thread-local variable instance should
+ *            be returned. If @a tcb is @c NULL then @c NULL is returned for
+ *            thread-local variables.
+ *
+ * @return Symbol address
+ */
+void *symbol_get_addr(elf_symbol_t *sym, module_t *m, tcb_t *tcb)
 {
 	if (ELF_ST_TYPE(sym->st_info) == STT_TLS) {
-		return rtld_tls_get_addr(m->rtld, m->id, sym->st_value);
+		if (tcb == NULL)
+			return NULL;
+		return rtld_tls_get_addr(m->rtld, tcb, m->id, sym->st_value);
 	} else if (sym->st_shndx == SHN_ABS) {
 		/* Do not add bias to absolute symbols */
Index: uspace/lib/c/generic/tls.c
===================================================================
--- uspace/lib/c/generic/tls.c	(revision e2f260026920f1d43bed8d2b775564b1f64a6f6a)
+++ uspace/lib/c/generic/tls.c	(revision d2bb25e777311fb1c2e3cb09e66bab0c8b523a13)
@@ -97,4 +97,5 @@
 void tls_free(tcb_t *tcb)
 {
+	free(tcb->dtv);
 	tls_free_arch(tcb, tls_get_size());
 }
@@ -109,12 +110,13 @@
 tcb_t *tls_alloc_variant_1(void **data, size_t size)
 {
-	tcb_t *result;
+	tcb_t *tcb;
 
-	result = malloc(sizeof(tcb_t) + size);
-	if (!result)
+	tcb = malloc(sizeof(tcb_t) + size);
+	if (!tcb)
 		return NULL;
-	*data = ((void *)result) + sizeof(tcb_t);
+	*data = ((void *)tcb) + sizeof(tcb_t);
+	tcb->dtv = NULL;
 
-	return result;
+	return tcb;
 }
 
@@ -147,4 +149,5 @@
 	tcb = (tcb_t *) (*data + size);
 	tcb->self = tcb;
+	tcb->dtv = NULL;
 
 	return tcb;
Index: uspace/lib/c/include/rtld/rtld.h
===================================================================
--- uspace/lib/c/include/rtld/rtld.h	(revision e2f260026920f1d43bed8d2b775564b1f64a6f6a)
+++ uspace/lib/c/include/rtld/rtld.h	(revision d2bb25e777311fb1c2e3cb09e66bab0c8b523a13)
@@ -50,5 +50,5 @@
 extern tcb_t *rtld_tls_make(rtld_t *);
 extern unsigned long rtld_get_next_id(rtld_t *);
-extern void *rtld_tls_get_addr(rtld_t *, unsigned long, unsigned long);
+extern void *rtld_tls_get_addr(rtld_t *, tcb_t *, unsigned long, unsigned long);
 
 #endif
Index: uspace/lib/c/include/rtld/symbol.h
===================================================================
--- uspace/lib/c/include/rtld/symbol.h	(revision e2f260026920f1d43bed8d2b775564b1f64a6f6a)
+++ uspace/lib/c/include/rtld/symbol.h	(revision d2bb25e777311fb1c2e3cb09e66bab0c8b523a13)
@@ -38,4 +38,5 @@
 #include <elf/elf.h>
 #include <rtld/rtld.h>
+#include <tls.h>
 
 /** Symbol search flags */
@@ -50,5 +51,5 @@
 extern elf_symbol_t *symbol_def_find(const char *, module_t *,
     symbol_search_flags_t, module_t **);
-extern void *symbol_get_addr(elf_symbol_t *, module_t *);
+extern void *symbol_get_addr(elf_symbol_t *, module_t *, tcb_t *);
 
 #endif
Index: uspace/lib/c/include/tls.h
===================================================================
--- uspace/lib/c/include/tls.h	(revision e2f260026920f1d43bed8d2b775564b1f64a6f6a)
+++ uspace/lib/c/include/tls.h	(revision d2bb25e777311fb1c2e3cb09e66bab0c8b523a13)
@@ -39,4 +39,7 @@
 #include <sys/types.h>
 
+/** DTV Generation number - equals vector length */
+#define DTV_GN(dtv) (((uintptr_t *)(dtv))[0])
+
 /*
  * Symbols defined in the respective linker script.
