summary refs log tree commit diff
path: root/elf/rtld.c
diff options
context:
space:
mode:
Diffstat (limited to 'elf/rtld.c')
-rw-r--r--elf/rtld.c207
1 files changed, 114 insertions, 93 deletions
diff --git a/elf/rtld.c b/elf/rtld.c
index 9ec250214b..85d8108813 100644
--- a/elf/rtld.c
+++ b/elf/rtld.c
@@ -130,9 +130,14 @@ _dl_start (void *arg)
 {
   struct link_map bootstrap_map;
   hp_timing_t start_time;
-#ifndef HAVE_BUILTIN_MEMSET
+#if !defined HAVE_BUILTIN_MEMSET || defined USE_TLS
   size_t cnt;
 #endif
+#ifdef USE_TLS
+  ElfW(Ehdr) *ehdr;
+  ElfW(Phdr) *phdr;
+  dtv_t initdtv[3];
+#endif
 
   /* This #define produces dynamic linking inline functions for
      bootstrap relocation instead of general-purpose relocation.  */
@@ -166,6 +171,97 @@ _dl_start (void *arg)
   bootstrap_map.l_ld = (void *) bootstrap_map.l_addr + elf_machine_dynamic ();
   elf_get_dynamic_info (&bootstrap_map);
 
+#if USE_TLS
+# ifndef HAVE___THREAD
+  /* Signal that we have not found TLS data so far.  */
+  bootstrap_map.l_tls_modid = 0;
+# endif
+
+  /* Get the dynamic linkers program header.  */
+  ehdr = (ElfW(Ehdr) *) bootstrap_map.l_addr;
+  phdr = (ElfW(Phdr) *) (bootstrap_map.l_addr + ehdr->e_phoff);
+  for (cnt = 0; cnt < ehdr->e_phnum; ++cnt)
+    if (phdr[cnt].p_type == PT_TLS)
+      {
+	void *tlsblock;
+	size_t max_align = MAX (TLS_INIT_TCB_ALIGN, phdr[cnt].p_align);
+
+	bootstrap_map.l_tls_blocksize = phdr[cnt].p_memsz;
+	bootstrap_map.l_tls_align = phdr[cnt].p_align;
+	assert (bootstrap_map.l_tls_blocksize != 0);
+	bootstrap_map.l_tls_initimage_size = phdr[cnt].p_filesz;
+	bootstrap_map.l_tls_initimage = (void *) (bootstrap_map.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 (bootstrap_map.l_tls_blocksize,
+				    TLS_INIT_TCB_ALIGN)
+			   + TLS_INIT_TCB_SIZE
+			   + max_align);
+# elif TLS_DTV_AT_TP
+	tlsblock = alloca (roundup (TLS_INIT_TCB_SIZE,
+				    bootstrap_map.l_tls_align)
+			   + bootstrap_map.l_tls_blocksize
+			   + max_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 + max_align - 1)
+			     & ~(max_align - 1));
+
+	/* Initialize the dtv.  [0] is the length, [1] the generation
+	   counter.  */
+	initdtv[0].counter = 1;
+	initdtv[1].counter = 0;
+
+	/* Initialize the TLS block.  */
+# if TLS_TCB_AT_TP
+	initdtv[2].pointer = tlsblock;
+# elif TLS_DTV_AT_TP
+	bootstrap_map.l_tls_offset = roundup (TLS_INIT_TCB_SIZE,
+					      bootstrap_map.l_tls_align);
+	initdtv[2].pointer = (char *) tlsblock + bootstrap_map.l_tls_offset;
+# else
+#  error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
+# endif
+	memset (__mempcpy (initdtv[2].pointer, bootstrap_map.l_tls_initimage,
+			   bootstrap_map.l_tls_initimage_size),
+		'\0', (bootstrap_map.l_tls_blocksize
+		       - bootstrap_map.l_tls_initimage_size));
+
+	/* Install the pointer to the dtv.  */
+
+	/* Initialize the thread pointer.  */
+# if TLS_TCB_AT_TP
+	bootstrap_map.l_tls_offset
+	  = roundup (bootstrap_map.l_tls_blocksize, TLS_INIT_TCB_ALIGN);
+
+	INSTALL_DTV ((char *) tlsblock + bootstrap_map.l_tls_offset,
+		     initdtv);
+
+	TLS_INIT_TP ((char *) tlsblock + bootstrap_map.l_tls_offset);
+# elif TLS_DTV_AT_TP
+	INSTALL_DTV (tlsblock, initdtv);
+	TLS_INIT_TP (tlsblock);
+# else
+#  error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
+# endif
+
+	/* So far this is module number one.  */
+	bootstrap_map.l_tls_modid = 1;
+
+	/* There can only be one PT_TLS entry.  */
+	break;
+      }
+#endif	/* use TLS */
+
 #ifdef ELF_MACHINE_BEFORE_RTLD_RELOC
   ELF_MACHINE_BEFORE_RTLD_RELOC (bootstrap_map.l_info);
 #endif
@@ -220,12 +316,6 @@ _dl_start_final (void *arg, struct link_map *bootstrap_map_p,
   ElfW(Addr) *start_addr = alloca (sizeof (ElfW(Addr)));
   extern char _begin[] attribute_hidden;
   extern char _end[] attribute_hidden;
-#ifdef USE_TLS
-  ElfW(Ehdr) *ehdr;
-  ElfW(Phdr) *phdr;
-  size_t cnt;
-  dtv_t initdtv[3];
-#endif
 
   if (HP_TIMING_AVAIL)
     {
@@ -247,96 +337,27 @@ _dl_start_final (void *arg, struct link_map *bootstrap_map_p,
   GL(dl_rtld_map).l_mach = bootstrap_map_p->l_mach;
   GL(dl_rtld_map).l_map_start = (ElfW(Addr)) _begin;
   GL(dl_rtld_map).l_map_end = (ElfW(Addr)) _end;
-
-#if HP_TIMING_AVAIL
-  HP_TIMING_NOW (GL(dl_cpuclock_offset));
-#endif
-
+  /* Copy the TLS related data if necessary.  */
 #if USE_TLS
-  /* Get the dynamic linkers program header.  */
-  ehdr = (ElfW(Ehdr) *) GL(dl_rtld_map).l_map_start;
-  phdr = (ElfW(Phdr) *) (GL(dl_rtld_map).l_map_start + ehdr->e_phoff);
-  for (cnt = 0; cnt < ehdr->e_phnum; ++cnt)
-    if (phdr[cnt].p_type == PT_TLS)
-      {
-	void *tlsblock;
-	size_t max_align = MAX (TLS_INIT_TCB_ALIGN, phdr[cnt].p_align);
-
-	GL(dl_rtld_map).l_tls_blocksize = phdr[cnt].p_memsz;
-	GL(dl_rtld_map).l_tls_align = phdr[cnt].p_align;
-	assert (GL(dl_rtld_map).l_tls_blocksize != 0);
-	GL(dl_rtld_map).l_tls_initimage_size = phdr[cnt].p_filesz;
-	GL(dl_rtld_map).l_tls_initimage = (void *) (GL(dl_rtld_map).l_map_start
-						    + 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 (GL(dl_rtld_map).l_tls_blocksize,
-				    TLS_INIT_TCB_ALIGN)
-			   + TLS_INIT_TCB_SIZE
-			   + max_align);
-# elif TLS_DTV_AT_TP
-	tlsblock = alloca (roundup (TLS_INIT_TCB_SIZE,
-				    GL(dl_rtld_map).l_tls_align)
-			   + GL(dl_rtld_map).l_tls_blocksize
-			   + max_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 + max_align - 1)
-			     & ~(max_align - 1));
-
-	/* Initialize the dtv.  [0] is the length, [1] the generation
-	   counter.  */
-	initdtv[0].counter = 1;
-	initdtv[1].counter = 0;
-
-	/* Initialize the TLS block.  */
-# if TLS_TCB_AT_TP
-	initdtv[2].pointer = tlsblock;
-# elif TLS_DTV_AT_TP
-	GL(dl_rtld_map).l_tls_offset = roundup (TLS_INIT_TCB_SIZE,
-						GL(dl_rtld_map).l_tls_align);
-	initdtv[2].pointer = (char *) tlsblock + GL(dl_rtld_map).l_tls_offset;
-# else
-#  error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
-# endif
-	memset (__mempcpy (initdtv[1].pointer, GL(dl_rtld_map).l_tls_initimage,
-			   GL(dl_rtld_map).l_tls_initimage_size),
-		'\0', (GL(dl_rtld_map).l_tls_blocksize
-		       - GL(dl_rtld_map).l_tls_initimage_size));
-
-	/* Install the pointer to the dtv.  */
-
-	/* Initialize the thread pointer.  */
-# if TLS_TCB_AT_TP
-	GL(dl_rtld_map).l_tls_offset
-	  = roundup (GL(dl_rtld_map).l_tls_blocksize, TLS_INIT_TCB_ALIGN);
-
-	INSTALL_DTV ((char *) tlsblock + GL(dl_rtld_map).l_tls_offset,
-		     initdtv);
-
-	TLS_INIT_TP ((char *) tlsblock + GL(dl_rtld_map).l_tls_offset);
-# elif TLS_DTV_AT_TP
-	INSTALL_DTV (tlsblock, initdtv);
-	TLS_INIT_TP (tlsblock);
+# ifdef HAVE___THREAD
+  assert (bootstrap_map_p->l_tls_modid != 0);
 # else
-#  error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
+  if (bootstrap_map_p->l_tls_modid != 0)
 # endif
+    {
+      GL(dl_rtld_map).l_tls_blocksize = bootstrap_map_p->l_tls_blocksize;
+      GL(dl_rtld_map).l_tls_align = bootstrap_map_p->l_tls_align;
+      GL(dl_rtld_map).l_tls_initimage_size
+	= bootstrap_map_p->l_tls_initimage_size;
+      GL(dl_rtld_map).l_tls_initimage = bootstrap_map_p->l_tls_initimage;
+      GL(dl_rtld_map).l_tls_offset = bootstrap_map_p->l_tls_offset;
+      GL(dl_rtld_map).l_tls_modid = 1;
+    }
+#endif
 
-	/* So far this is module number one.  */
-	GL(dl_rtld_map).l_tls_modid = 1;
-
-	/* There can only be one PT_TLS entry.  */
-	break;
-      }
-#endif	/* use TLS */
+#if HP_TIMING_AVAIL
+  HP_TIMING_NOW (GL(dl_cpuclock_offset));
+#endif
 
   /* 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