about summary refs log tree commit diff
path: root/elf
diff options
context:
space:
mode:
Diffstat (limited to 'elf')
-rw-r--r--elf/Makefile2
-rw-r--r--elf/rtld.c75
2 files changed, 76 insertions, 1 deletions
diff --git a/elf/Makefile b/elf/Makefile
index 12277741c4..e84c6d15cc 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -67,7 +67,7 @@ distribute	:= $(rtld-routines:=.c) dynamic-link.h do-rel.h dl-machine.h \
 		   reldep6mod4.c reldep6mod3.c reldep6mod2.c reldep6mod1.c \
 		   reldep6mod0.c \
 		   unwind-dw2.c unwind-dw2-fde.c unwind.h unwind-pe.h \
-		   unwind-dw2-fde.h dwarf2.h dl-procinfo.c
+		   unwind-dw2-fde.h dwarf2.h dl-procinfo.c tls.h
 
 include ../Makeconfig
 
diff --git a/elf/rtld.c b/elf/rtld.c
index e2360e3ae1..b7439b2e7b 100644
--- a/elf/rtld.c
+++ b/elf/rtld.c
@@ -218,6 +218,16 @@ _dl_start_final (void *arg, struct link_map *bootstrap_map_p,
      which use `alloca'.  */
   ElfW(Addr) *start_addr = alloca (sizeof (ElfW(Addr)));
   extern char _begin[], _end[];
+#ifdef USE_TLS
+  ElfW(Ehdr) *ehdr;
+  ElfW(Phdr) *phdr;
+  size_t cnt;
+  size_t tlssize = 0;
+  size_t tlsimagesize = 0;
+  const void *tlsimage = NULL;
+  void *tlsblock = NULL;
+  dtv_t initdtv[2];
+#endif
 
   if (HP_TIMING_AVAIL)
     {
@@ -244,11 +254,76 @@ _dl_start_final (void *arg, struct link_map *bootstrap_map_p,
   HP_TIMING_NOW (GL(dl_cpuclock_offset));
 #endif
 
+#if USE_TLS
+  /* Get the dynamic linkers program header.  */
+  ehdr = (ElfW(Ehdr) *) bootstrap_map_p->l_addr;
+  phdr = (ElfW(Phdr) *) (bootstrap_map_p->l_addr + ehdr->e_phoff);
+  for (cnt = 0; cnt < ehdr->e_phnum; ++cnt)
+    if (phdr[cnt].p_type == PT_TLS)
+      {
+	size_t align = MAX (TLS_INIT_TCB_ALIGN,  phdr[cnt].p_align);
+
+	tlssize = phdr[cnt].p_memsz;
+	tlsimagesize = phdr[cnt].p_filesz;
+	tlsimage = (void *) (bootstrap_map_p->l_addr + phdr[cnt].p_offset);
+
+	/* We can now allocate the initial TLS block.  This can happen
+	   on the stack.  We'll get the final memory later when we
+	   know all about the various objects loaded at startup
+	   time.  */
+# if TLS_TCB_AT_TP
+	tlsblock = alloca (roundup (tlssize, TLS_INIT_TCB_ALIGN)
+			   + TLS_INIT_TCB_SIZE
+			   + align);
+# elif TLS_DTV_AT_TP
+	tlsblock = alloca (roundup (TLS_INIT_TCB_SIZE, phdr[cnt].p_align)
+			   + tlssize
+			   + align);
+# else
+	/* In case a model with a different layout for the TCB and DTV
+	   is defined add another #elif here and in the following #ifs.  */
+#  error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
+# endif
+	/* Align the TLS block.  */
+	tlsblock = (void *) (((uintptr_t) tlsblock + align - 1)
+			     & ~(align - 1));
+
+	/* Initialize the dtv.  */
+	initdtv[0].counter = 1;
+
+	/* Initialize the TLS block.  */
+# if TLS_TCB_AT_TP
+	initdtv[1].pointer = tlsblock;
+# elif TLS_DTV_AT_TP
+	GL(rtld_tlsoffset) = roundup (TLS_INIT_TCB_SIZE, phdr[cnt].p_align);
+	initdtv[1].pointer = (char *) tlsblock + GL(rtld_tlsoffset);
+# else
+#  error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
+# endif
+	memset (__mempcpy (initdtv[1].pointer, tlsimage, tlsimagesize),
+		'\0', tlssize - tlsimagesize);
+
+	/* Initialize the thread pointer.  */
+# if TLS_TCB_AT_TP
+	GL(rtld_tlsoffset) = roundup (tlssize, TLS_INIT_TCB_ALIGN);
+	TLS_INIT_TP ((char *) tlsblock + GL(rtld_tlsoffset), initdtv);
+# elif TLS_DTV_AT_TP
+	TLS_INIT_TP (tlsblock, intidtv);
+# else
+#  error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
+# endif
+
+	/* There can only be one PT_TLS entry.  */
+	break;
+      }
+#endif	/* use TLS */
+
   /* Call the OS-dependent function to set up life so we can do things like
      file access.  It will call `dl_main' (below) to do all the real work
      of the dynamic linker, and then unwind our frame and run the user
      entry point on the same stack we entered on.  */
   *start_addr =  _dl_sysdep_start (arg, &dl_main);
+
 #ifndef HP_TIMING_NONAVAIL
   if (HP_TIMING_AVAIL)
     {