Index: uspace/lib/c/generic/elf/elf_mod.c
===================================================================
--- uspace/lib/c/generic/elf/elf_mod.c	(revision dc0d8b52826b8cb72258c5c945e82004187e62ac)
+++ uspace/lib/c/generic/elf/elf_mod.c	(revision 6adb775f3673e07585ec14ce5919b69217752f6e)
@@ -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 dc0d8b52826b8cb72258c5c945e82004187e62ac)
+++ uspace/lib/c/generic/rtld/module.c	(revision 6adb775f3673e07585ec14ce5919b69217752f6e)
@@ -37,4 +37,5 @@
 #include <adt/list.h>
 #include <elf/elf_load.h>
+#include <errno.h>
 #include <fcntl.h>
 #include <loader/pcb.h>
@@ -129,6 +130,6 @@
 	int rc;
 	
-	m = malloc(sizeof(module_t));
-	if (!m) {
+	m = calloc(1, sizeof(module_t));
+	if (m == NULL) {
 		printf("malloc failed\n");
 		exit(1);
@@ -136,4 +137,5 @@
 
 	m->rtld = rtld;
+	m->id = rtld_get_next_id(rtld);
 
 	if (str_size(name) > NAME_BUF_SIZE - 2) {
@@ -174,4 +176,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;
@@ -236,4 +246,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.
  *
@@ -253,4 +274,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 dc0d8b52826b8cb72258c5c945e82004187e62ac)
+++ uspace/lib/c/generic/rtld/rtld.c	(revision 6adb775f3673e07585ec14ce5919b69217752f6e)
@@ -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,15 +84,23 @@
 
 	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;
+	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->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. */
@@ -96,5 +112,5 @@
 
 	DPRINTF("Load all program dependencies\n");
-	module_load_deps(&prog_mod);
+	module_load_deps(prog);
 
 	/*
@@ -104,5 +120,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;
@@ -110,4 +128,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 dc0d8b52826b8cb72258c5c945e82004187e62ac)
+++ uspace/lib/c/generic/tls.c	(revision 6adb775f3673e07585ec14ce5919b69217752f6e)
@@ -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);
