about summary refs log tree commit diff
path: root/elf/rtld.c
diff options
context:
space:
mode:
authorUlrich Drepper <drepper@redhat.com>2002-02-05 00:57:29 +0000
committerUlrich Drepper <drepper@redhat.com>2002-02-05 00:57:29 +0000
commit535b764df5ca722066c2db615190e6a70688c6a6 (patch)
tree06f6ba9853ac4e8f698fc1e3b0b4cb80ffd06bae /elf/rtld.c
parent67ddea92542c12f2099a89dbc58a045a65bb7771 (diff)
downloadglibc-535b764df5ca722066c2db615190e6a70688c6a6.tar.gz
glibc-535b764df5ca722066c2db615190e6a70688c6a6.tar.xz
glibc-535b764df5ca722066c2db615190e6a70688c6a6.zip
Update.
	* elf/rtld.c (_dl_start_final): Allocate TLS and initialize
	thread-pointer as soon as possible.
	* sysdeps/generic/ldsodefs.h: Include <tls.h>.  Define first TLS
	elements in rtld_global.
	* sysdeps/generic/tls.h: New file.
	* elf/Makefile (distribute): Add tls.h.
	* sysdeps/i386/dl-machine.h (elf_machine_rel): Add support for TLS
	relocations.  Not complete yet.

	* resolv/resolv.h: Allow user to define __need_res_state and only
	define __res_start structure then.
	* include/resolv.h: Only declare functions if _RESOLV_H_ is defined.
Diffstat (limited to 'elf/rtld.c')
-rw-r--r--elf/rtld.c75
1 files changed, 75 insertions, 0 deletions
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)
     {