aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog2
-rw-r--r--elf/rtld.c138
2 files changed, 135 insertions, 5 deletions
diff --git a/ChangeLog b/ChangeLog
index 8ec914f..40660b8 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -5,8 +5,6 @@
* sysdeps/unix/sysv/linux/sparc/bits/socket.h (__cmsg_nxthdr):
Likewise.
- * elf/rtld.c: Remove use of USE___THREAD.
-
2011-09-11 Andreas Schwab <schwab@linux-m68k.org>
* elf/Makefile (gen-ldd): Prepend $(..) to $(ldd-rewrite-script)
diff --git a/elf/rtld.c b/elf/rtld.c
index 0af9325..b3959a3 100644
--- a/elf/rtld.c
+++ b/elf/rtld.c
@@ -306,9 +306,21 @@ _dl_start_final (void *arg, struct dl_start_final_info *info)
GL(dl_rtld_map).l_text_end = (ElfW(Addr)) _etext;
/* Copy the TLS related data if necessary. */
#ifndef DONT_USE_BOOTSTRAP_MAP
-# if NO_TLS_OFFSET != 0
+# if USE___THREAD
+ assert (info->l.l_tls_modid != 0);
+ GL(dl_rtld_map).l_tls_blocksize = info->l.l_tls_blocksize;
+ GL(dl_rtld_map).l_tls_align = info->l.l_tls_align;
+ GL(dl_rtld_map).l_tls_firstbyte_offset = info->l.l_tls_firstbyte_offset;
+ GL(dl_rtld_map).l_tls_initimage_size = info->l.l_tls_initimage_size;
+ GL(dl_rtld_map).l_tls_initimage = info->l.l_tls_initimage;
+ GL(dl_rtld_map).l_tls_offset = info->l.l_tls_offset;
+ GL(dl_rtld_map).l_tls_modid = 1;
+# else
+# if NO_TLS_OFFSET != 0
GL(dl_rtld_map).l_tls_offset = NO_TLS_OFFSET;
+# endif
# endif
+
#endif
#if HP_TIMING_AVAIL
@@ -390,6 +402,9 @@ _dl_start (void *arg)
++cnt)
bootstrap_map.l_info[cnt] = 0;
# endif
+# if USE___THREAD
+ bootstrap_map.l_tls_modid = 0;
+# endif
#endif
/* Figure out the run-time load address of the dynamic linker itself. */
@@ -403,6 +418,123 @@ _dl_start (void *arg)
bootstrap_map.l_tls_offset = NO_TLS_OFFSET;
#endif
+ /* Get the dynamic linker's own program header. First we need the ELF
+ file header. The `_begin' symbol created by the linker script points
+ to it. When we have something like GOTOFF relocs, we can use a plain
+ reference to find the runtime address. Without that, we have to rely
+ on the `l_addr' value, which is not the value we want when prelinked. */
+#if USE___THREAD
+ dtv_t initdtv[3];
+ ElfW(Ehdr) *ehdr
+# ifdef DONT_USE_BOOTSTRAP_MAP
+ = (ElfW(Ehdr) *) &_begin;
+# else
+# error This will not work with prelink.
+ = (ElfW(Ehdr) *) bootstrap_map.l_addr;
+# endif
+ ElfW(Phdr) *phdr = (ElfW(Phdr) *) ((void *) ehdr + ehdr->e_phoff);
+ size_t cnt = ehdr->e_phnum; /* PT_TLS is usually the last phdr. */
+ while (cnt-- > 0)
+ if (phdr[cnt].p_type == PT_TLS)
+ {
+ void *tlsblock;
+ size_t max_align = MAX (TLS_INIT_TCB_ALIGN, phdr[cnt].p_align);
+ char *p;
+
+ bootstrap_map.l_tls_blocksize = phdr[cnt].p_memsz;
+ bootstrap_map.l_tls_align = phdr[cnt].p_align;
+ if (phdr[cnt].p_align == 0)
+ bootstrap_map.l_tls_firstbyte_offset = 0;
+ else
+ bootstrap_map.l_tls_firstbyte_offset = (phdr[cnt].p_vaddr
+ & (phdr[cnt].p_align - 1));
+ 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_vaddr);
+
+ /* 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
+ p = __mempcpy (initdtv[2].pointer, bootstrap_map.l_tls_initimage,
+ bootstrap_map.l_tls_initimage_size);
+# ifdef HAVE_BUILTIN_MEMSET
+ __builtin_memset (p, '\0', (bootstrap_map.l_tls_blocksize
+ - bootstrap_map.l_tls_initimage_size));
+# else
+ {
+ size_t remaining = (bootstrap_map.l_tls_blocksize
+ - bootstrap_map.l_tls_initimage_size);
+ while (remaining-- > 0)
+ *p++ = '\0';
+ }
+# endif
+
+ /* 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);
+
+ const char *lossage = TLS_INIT_TP ((char *) tlsblock
+ + bootstrap_map.l_tls_offset, 0);
+# elif TLS_DTV_AT_TP
+ INSTALL_DTV (tlsblock, initdtv);
+ const char *lossage = TLS_INIT_TP (tlsblock, 0);
+# else
+# error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
+# endif
+ if (__builtin_expect (lossage != NULL, 0))
+ _dl_fatal_printf ("cannot set up thread-local storage: %s\n",
+ lossage);
+
+ /* So far this is module number one. */
+ bootstrap_map.l_tls_modid = 1;
+
+ /* There can only be one PT_TLS entry. */
+ break;
+ }
+#endif /* USE___THREAD */
+
#ifdef ELF_MACHINE_BEFORE_RTLD_RELOC
ELF_MACHINE_BEFORE_RTLD_RELOC (bootstrap_map.l_info);
#endif
@@ -647,7 +779,7 @@ cannot allocate TLS data structures for initial thread");
/* And finally install it for the main thread. If ld.so itself uses
TLS we know the thread pointer was initialized earlier. */
- const char *lossage = TLS_INIT_TP (tcbp, 0);
+ const char *lossage = TLS_INIT_TP (tcbp, USE___THREAD);
if (__builtin_expect (lossage != NULL, 0))
_dl_fatal_printf ("cannot set up thread-local storage: %s\n", lossage);
tls_init_tp_called = true;
@@ -2178,7 +2310,7 @@ ERROR: ld.so: object '%s' cannot be loaded as audit interface: %s; ignored.\n",
TLS we know the thread pointer was initialized earlier. */
if (! tls_init_tp_called)
{
- const char *lossage = TLS_INIT_TP (tcbp, 0);
+ const char *lossage = TLS_INIT_TP (tcbp, USE___THREAD);
if (__builtin_expect (lossage != NULL, 0))
_dl_fatal_printf ("cannot set up thread-local storage: %s\n",
lossage);