Index: uspace/lib/c/arch/ia32/_link.ld.in
===================================================================
--- uspace/lib/c/arch/ia32/_link.ld.in	(revision 5035ba05f0dcb66a61ad5e5722c225bf1d375437)
+++ uspace/lib/c/arch/ia32/_link.ld.in	(revision 32573ffe2f11f1f46237edf372866632f5d0f7f2)
@@ -12,4 +12,5 @@
 #endif
 	data PT_LOAD FLAGS(6);
+	tls PT_TLS;
 #if defined(SHLIB) || defined(DLEXE)
 	dynamic PT_DYNAMIC;
@@ -95,15 +96,25 @@
 #endif
 	
+	.tdata : {
 #ifndef DLEXE
-	.tdata : {
 		_tdata_start = .;
+#endif
 		*(.tdata);
 		*(.gnu.linkonce.tb.*);
+#ifndef DLEXE
 		_tdata_end = .;
+#endif
+	} :data :tls
+	.tbss : {
+#ifndef DLEXE
 		_tbss_start = .;
+#endif
 		*(.tbss);
+#ifndef DLEXE
 		_tbss_end = .;
-	} :data
+#endif
+	} :data :tls
 	
+#ifndef DLEXE
 	_tls_alignment = ALIGNOF(.tdata);
 #endif
Index: uspace/lib/c/arch/ia32/src/rtld/reloc.c
===================================================================
--- uspace/lib/c/arch/ia32/src/rtld/reloc.c	(revision 5035ba05f0dcb66a61ad5e5722c225bf1d375437)
+++ uspace/lib/c/arch/ia32/src/rtld/reloc.c	(revision 32573ffe2f11f1f46237edf372866632f5d0f7f2)
@@ -171,10 +171,10 @@
 			break;
 
+//		case R_386_TLS_DTPOFF32:
+//			*r_ptr = sym_def->st_value;
+//			break; 
+
 		case R_386_TLS_DTPMOD32:
-			/*
-			 * We can ignore this as long as the only module
-			 * with TLS variables is libc.so.
-			 */
-			DPRINTF("Ignoring R_386_TLS_DTPMOD32\n");
+			*r_ptr = dest->id;
 			break;
 
Index: uspace/lib/c/arch/ia32/src/tls.c
===================================================================
--- uspace/lib/c/arch/ia32/src/tls.c	(revision 5035ba05f0dcb66a61ad5e5722c225bf1d375437)
+++ uspace/lib/c/arch/ia32/src/tls.c	(revision 32573ffe2f11f1f46237edf372866632f5d0f7f2)
@@ -1,4 +1,5 @@
 /*
  * Copyright (c) 2006 Ondrej Palkovsky
+ * Copyright (c) 2016 Jiri Svoboda
  * All rights reserved.
  *
@@ -39,4 +40,8 @@
 #include <align.h>
 
+#ifdef CONFIG_RTLD
+#include <rtld/rtld.h>
+#endif
+
 tcb_t *tls_alloc_arch(void **data, size_t size)
 {
@@ -68,9 +73,15 @@
 
 	/* Calculate size of TLS block */
-	tls_size = ALIGN_UP(&_tbss_end - &_tdata_start, &_tls_alignment);
+	tls_size = tls_get_size();
 
 	/* The TLS block is just before TCB */
 	tls = (uint8_t *)__tcb_get() - tls_size;
 
+#ifdef CONFIG_RTLD
+	if (runtime_env != NULL) {
+		return rtld_tls_get_addr(runtime_env, tls, ti->ti_module,
+		    ti->ti_offset);
+	}
+#endif
 	return tls + ti->ti_offset;
 }
Index: uspace/lib/c/generic/elf/elf_mod.c
===================================================================
--- uspace/lib/c/generic/elf/elf_mod.c	(revision 5035ba05f0dcb66a61ad5e5722c225bf1d375437)
+++ uspace/lib/c/generic/elf/elf_mod.c	(revision 32573ffe2f11f1f46237edf372866632f5d0f7f2)
@@ -248,6 +248,21 @@
 }
 
+/** Process TLS program header.
+ *
+ * @param elf  Pointer to loader state buffer.
+ * @param hdr  TLS program header
+ * @param info Place to store TLS info
+ */
+static void tls_program_header(elf_ld_t *elf, elf_segment_header_t *hdr,
+    elf_tls_info_t *info)
+{
+	info->tdata = (void *)((uint8_t *)hdr->p_vaddr + elf->bias);
+	info->tdata_size = hdr->p_filesz;
+	info->tbss_size = hdr->p_memsz - hdr->p_filesz;
+}
+
 /** Process segment header.
  *
+ * @param elf   Pointer to loader state buffer.
  * @param entry	Segment header.
  *
@@ -277,4 +292,10 @@
 	case 0x70000000:
 		/* FIXME: MIPS reginfo */
+		break;
+	case PT_TLS:
+		/* Parse TLS program header */
+		tls_program_header(elf, entry, &elf->info->tls);
+		DPRINTF("TLS header found at %p\n",
+		    (void *)((uint8_t *)entry->p_vaddr + elf->bias));
 		break;
 	case PT_SHLIB:
Index: uspace/lib/c/generic/rtld/module.c
===================================================================
--- uspace/lib/c/generic/rtld/module.c	(revision 5035ba05f0dcb66a61ad5e5722c225bf1d375437)
+++ uspace/lib/c/generic/rtld/module.c	(revision 32573ffe2f11f1f46237edf372866632f5d0f7f2)
@@ -37,4 +37,5 @@
 #include <adt/list.h>
 #include <elf/elf_load.h>
+#include <errno.h>
 #include <fcntl.h>
 #include <loader/pcb.h>
@@ -135,5 +136,5 @@
 
 	m = calloc(1, sizeof(module_t));
-	if (!m) {
+	if (m == NULL) {
 		printf("malloc failed\n");
 		exit(1);
@@ -141,4 +142,6 @@
 
 	m->rtld = rtld;
+	m->id = rtld_get_next_id(rtld);
+
 	if ((flags & mlf_local) != 0)
 		m->local = true;
@@ -181,4 +184,12 @@
 	/* Insert into the list of loaded modules */
 	list_append(&m->modules_link, &rtld->modules);
+
+	/* Copy TLS info */
+	m->tdata = info.tls.tdata;
+	m->tdata_size = info.tls.tdata_size;
+	m->tbss_size = info.tls.tbss_size;
+
+	printf("tdata at %p size %zu, tbss size %zu\n",
+	    m->tdata, m->tdata_size, m->tbss_size);
 
 	return m;
@@ -243,4 +254,15 @@
 }
 
+/** Find module structure by ID. */
+module_t *module_by_id(rtld_t *rtld, unsigned long id)
+{
+	list_foreach(rtld->modules, modules_link, module_t, m) {
+		if (m->id == id)
+			return m;
+	}
+
+	return NULL;
+}
+
 /** Process relocations in modules.
  *
@@ -260,4 +282,12 @@
 }
 
+void modules_process_tls(rtld_t *rtld)
+{
+	list_foreach(rtld->modules, modules_link, module_t, m) {
+		m->ioffs = rtld->tls_size;
+		rtld->tls_size += m->tdata_size + m->tbss_size;
+	}
+}
+
 /** Clear BFS tags of all modules.
  */
Index: uspace/lib/c/generic/rtld/rtld.c
===================================================================
--- uspace/lib/c/generic/rtld/rtld.c	(revision 5035ba05f0dcb66a61ad5e5722c225bf1d375437)
+++ uspace/lib/c/generic/rtld/rtld.c	(revision 32573ffe2f11f1f46237edf372866632f5d0f7f2)
@@ -43,5 +43,4 @@
 rtld_t *runtime_env;
 static rtld_t rt_env_static;
-static module_t prog_mod;
 
 /** Initialize the runtime linker for use in a statically-linked executable. */
@@ -62,4 +61,5 @@
 {
 	rtld_t *env;
+	module_t *prog;
 
 	DPRINTF("Load dynamically linked program.\n");
@@ -70,4 +70,12 @@
 		return ENOMEM;
 
+	env->next_id = 1;
+
+	prog = calloc(1, sizeof(module_t));
+	if (prog == NULL) {
+		free(env);
+		return ENOMEM;
+	}
+
 	/*
 	 * First we need to process dynamic sections of the executable
@@ -76,17 +84,25 @@
 
 	DPRINTF("Parse program .dynamic section at %p\n", p_info->dynamic);
-	dynamic_parse(p_info->dynamic, 0, &prog_mod.dyn);
-	prog_mod.bias = 0;
-	prog_mod.dyn.soname = "[program]";
-	prog_mod.rtld = env;
-	prog_mod.exec = true;
-	prog_mod.local = false;
+	dynamic_parse(p_info->dynamic, 0, &prog->dyn);
+	prog->bias = 0;
+	prog->dyn.soname = "[program]";
+	prog->rtld = env;
+	prog->id = rtld_get_next_id(env);
+	prog->exec = true;
+	prog->local = false;
+
+	prog->tdata = p_info->tls.tdata;
+	prog->tdata_size = p_info->tls.tdata_size;
+	prog->tbss_size = p_info->tls.tbss_size;
+
+	printf("prog tdata at %p size %zu, tbss size %zu\n",
+	    prog->tdata, prog->tdata_size, prog->tbss_size);
 
 	/* Initialize list of loaded modules */
 	list_initialize(&env->modules);
-	list_append(&prog_mod.modules_link, &env->modules);
+	list_append(&prog->modules_link, &env->modules);
 
 	/* Pointer to program module. Used as root of the module graph. */
-	env->program = &prog_mod;
+	env->program = prog;
 
 	/* Work around non-existent memory space allocation. */
@@ -98,5 +114,5 @@
 
 	DPRINTF("Load all program dependencies\n");
-	module_load_deps(&prog_mod, 0);
+	module_load_deps(prog, 0);
 
 	/*
@@ -106,5 +122,7 @@
 	/* Process relocations in all modules */
 	DPRINTF("Relocate all modules\n");
-	modules_process_relocs(env, &prog_mod);
+	modules_process_relocs(env, prog);
+
+	modules_process_tls(env);
 
 	*rre = env;
@@ -112,4 +130,51 @@
 }
 
+/** Create TLS (Thread Local Storage) data structures.
+ *
+ * @return Pointer to TCB.
+ */
+tcb_t *rtld_tls_make(rtld_t *rtld)
+{
+	void *data;
+	tcb_t *tcb;
+	size_t offset;
+
+	tcb = tls_alloc_arch(&data, rtld->tls_size);
+	if (tcb == NULL)
+		return NULL;
+
+	/*
+	 * Copy thread local data from the modules' initialization images.
+	 * Zero out thread-local uninitialized data.
+	 */
+
+	offset = 0;
+	list_foreach(rtld->modules, modules_link, module_t, m) {
+		memcpy(data + offset, m->tdata, m->tdata_size);
+		offset += m->tdata_size;
+		memset(data + offset, 0, m->tbss_size);
+		offset += m->tbss_size;
+	}
+
+	return tcb;
+}
+
+unsigned long rtld_get_next_id(rtld_t *rtld)
+{
+	return rtld->next_id++;
+}
+
+void *rtld_tls_get_addr(rtld_t *rtld, void *tls, unsigned long mod_id,
+    unsigned long offset)
+{
+	module_t *m;
+
+	m = module_by_id(rtld, mod_id);
+	assert(m != NULL);
+
+	return tls + m->ioffs + offset;
+}
+
+
 /** @}
  */
Index: uspace/lib/c/generic/tls.c
===================================================================
--- uspace/lib/c/generic/tls.c	(revision 5035ba05f0dcb66a61ad5e5722c225bf1d375437)
+++ uspace/lib/c/generic/tls.c	(revision 32573ffe2f11f1f46237edf372866632f5d0f7f2)
@@ -34,18 +34,21 @@
  * Support for thread-local storage, as described in:
  * 	Drepper U.: ELF Handling For Thread-Local Storage, 2005
- *
- * Only static model is supported.
- */ 
+ */
 
 #include <tls.h>
 #include <malloc.h>
 #include <str.h>
-#include <align.h>
 #include <unistd.h>
 
+#ifdef CONFIG_RTLD
+#include <rtld/rtld.h>
+#endif
+
+size_t tls_get_size(void)
+{
+	return &_tbss_end - &_tdata_start;
+}
+
 /** Create TLS (Thread Local Storage) data structures.
- *
- * The code requires, that sections .tdata and .tbss are adjacent. It may be
- * changed in the future.
  *
  * @return Pointer to TCB.
@@ -56,9 +59,13 @@
 	tcb_t *tcb;
 	size_t tls_size = &_tbss_end - &_tdata_start;
-	
+
+#ifdef CONFIG_RTLD
+	if (runtime_env != NULL)
+		return rtld_tls_make(runtime_env);
+#endif
 	tcb = tls_alloc_arch(&data, tls_size);
 	if (!tcb)
 		return NULL;
-	
+
 	/*
 	 * Copy thread local data from the initialization image.
@@ -77,4 +84,9 @@
 {
 	size_t tls_size = &_tbss_end - &_tdata_start;
+
+#ifdef CONFIG_RTLD
+	if (runtime_env != NULL)
+		tls_size = runtime_env->tls_size;
+#endif
 	tls_free_arch(tcb, tls_size);
 }
@@ -121,8 +133,7 @@
 {
 	tcb_t *tcb;
-	
-	size = ALIGN_UP(size, &_tls_alignment);
-	*data = memalign((uintptr_t) &_tls_alignment, sizeof(tcb_t) + size);
-	if (!*data)
+
+	*data = malloc(sizeof(tcb_t) + size);
+	if (*data == NULL)
 		return NULL;
 	tcb = (tcb_t *) (*data + size);
@@ -139,5 +150,4 @@
 void tls_free_variant_2(tcb_t *tcb, size_t size)
 {
-	size = ALIGN_UP(size, &_tls_alignment);
 	void *start = ((void *) tcb) - size;
 	free(start);
Index: uspace/lib/c/include/elf/elf_mod.h
===================================================================
--- uspace/lib/c/include/elf/elf_mod.h	(revision 5035ba05f0dcb66a61ad5e5722c225bf1d375437)
+++ uspace/lib/c/include/elf/elf_mod.h	(revision 32573ffe2f11f1f46237edf372866632f5d0f7f2)
@@ -58,4 +58,14 @@
 } eld_flags_t;
 
+/** TLS info for a module */
+typedef struct {
+	/** tdata section image */
+	void *tdata;
+	/** Size of tdata section image in bytes */
+	size_t tdata_size;
+	/** Size of tbss section */
+	size_t tbss_size;
+} elf_tls_info_t;
+
 /**
  * Some data extracted from the headers are stored here
@@ -70,4 +80,7 @@
 	/** Pointer to the dynamic section */
 	void *dynamic;
+
+	/** TLS info */
+	elf_tls_info_t tls;
 } elf_finfo_t;
 
Index: uspace/lib/c/include/rtld/module.h
===================================================================
--- uspace/lib/c/include/rtld/module.h	(revision 5035ba05f0dcb66a61ad5e5722c225bf1d375437)
+++ uspace/lib/c/include/rtld/module.h	(revision 32573ffe2f11f1f46237edf372866632f5d0f7f2)
@@ -46,6 +46,8 @@
 extern module_t *module_load(rtld_t *, const char *, mlflags_t);
 extern void module_load_deps(module_t *, mlflags_t);
+extern module_t *module_by_id(rtld_t *, unsigned long);
 
 extern void modules_process_relocs(rtld_t *, module_t *);
+extern void modules_process_tls(rtld_t *);
 extern void modules_untag(rtld_t *);
 
Index: uspace/lib/c/include/rtld/rtld.h
===================================================================
--- uspace/lib/c/include/rtld/rtld.h	(revision 5035ba05f0dcb66a61ad5e5722c225bf1d375437)
+++ uspace/lib/c/include/rtld/rtld.h	(revision 32573ffe2f11f1f46237edf372866632f5d0f7f2)
@@ -41,4 +41,5 @@
 
 #include <rtld/dynamic.h>
+#include <tls.h>
 #include <types/rtld/rtld.h>
 
@@ -47,4 +48,7 @@
 extern void rtld_init_static(void);
 extern int rtld_prog_process(elf_finfo_t *, rtld_t **);
+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 *, void *, unsigned long, unsigned long);
 
 #endif
Index: uspace/lib/c/include/tls.h
===================================================================
--- uspace/lib/c/include/tls.h	(revision 5035ba05f0dcb66a61ad5e5722c225bf1d375437)
+++ uspace/lib/c/include/tls.h	(revision 32573ffe2f11f1f46237edf372866632f5d0f7f2)
@@ -52,4 +52,5 @@
 extern void tls_free(tcb_t *);
 extern void tls_free_arch(tcb_t *, size_t);
+extern size_t tls_get_size(void);
 
 #ifdef CONFIG_TLS_VARIANT_1
Index: uspace/lib/c/include/types/rtld/module.h
===================================================================
--- uspace/lib/c/include/types/rtld/module.h	(revision 5035ba05f0dcb66a61ad5e5722c225bf1d375437)
+++ uspace/lib/c/include/types/rtld/module.h	(revision 32573ffe2f11f1f46237edf372866632f5d0f7f2)
@@ -46,6 +46,19 @@
 /** Dynamically linked module */
 typedef struct module {
+	/** Module ID */
+	unsigned long id;
+	/** Dynamic info for this module */
 	dyn_info_t dyn;
+	/** Load bias */
 	size_t bias;
+
+	/** tdata image start */
+	void *tdata;
+	/** tdata image size */
+	size_t tdata_size;
+	/** tbss size */
+	size_t tbss_size;
+
+	size_t ioffs;
 
 	/** Containing rtld */
Index: uspace/lib/c/include/types/rtld/rtld.h
===================================================================
--- uspace/lib/c/include/types/rtld/rtld.h	(revision 5035ba05f0dcb66a61ad5e5722c225bf1d375437)
+++ uspace/lib/c/include/types/rtld/rtld.h	(revision 32573ffe2f11f1f46237edf372866632f5d0f7f2)
@@ -48,4 +48,10 @@
 	module_t *program;
 
+	/** Next module ID */
+	unsigned long next_id;
+
+	/** Size of initial TLS tdata + tbss */
+	size_t tls_size;
+
 	/** List of all loaded modules including rtld and the program */
 	list_t modules;
