Update.
authorUlrich Drepper <drepper@redhat.com>
Tue, 5 Feb 2002 08:02:04 +0000 (08:02 +0000)
committerUlrich Drepper <drepper@redhat.com>
Tue, 5 Feb 2002 08:02:04 +0000 (08:02 +0000)
* elf/rtld.c (_dl_start): Fill TLS values in link map for rtld.
* include/link.h (struct link_map): Add various members for TLS
information.
* sysdeps/generic/ldsodefs.h (struct rtld_global): Remove
_rtld_tlsoffset, add _dl_initimage_list.
* sysdeps/i386/dl-lookupcfg.h: New file.
* sysdeps/i386/dl-machine.h (elf_machine_rel): Implement missing
TLS relocation.  When using TLS we now use RESOLVE_MAP.
(elf_machine_rela): Use RESOLVE_MAP instead of RESOLVE_MAP if TLS
is used.

* sysdeps/generic/dl-cache.c (_dl_cache_libcmp): Mark as possibly
unused.

ChangeLog
elf/rtld.c
include/link.h
sysdeps/generic/dl-cache.h
sysdeps/generic/ldsodefs.h
sysdeps/i386/dl-lookupcfg.h [new file with mode: 0644]
sysdeps/i386/dl-machine.h

index 4931ba5..d5078bd 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,19 @@
 2002-02-04  Ulrich Drepper  <drepper@redhat.com>
 
+       * elf/rtld.c (_dl_start): Fill TLS values in link map for rtld.
+       * include/link.h (struct link_map): Add various members for TLS
+       information.
+       * sysdeps/generic/ldsodefs.h (struct rtld_global): Remove
+       _rtld_tlsoffset, add _dl_initimage_list.
+       * sysdeps/i386/dl-lookupcfg.h: New file.
+       * sysdeps/i386/dl-machine.h (elf_machine_rel): Implement missing
+       TLS relocation.  When using TLS we now use RESOLVE_MAP.
+       (elf_machine_rela): Use RESOLVE_MAP instead of RESOLVE_MAP if TLS
+       is used.
+
+       * sysdeps/generic/dl-cache.c (_dl_cache_libcmp): Mark as possibly
+       unused.
+
        * 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
index b7439b2..bdd12b4 100644 (file)
@@ -222,10 +222,6 @@ _dl_start_final (void *arg, struct link_map *bootstrap_map_p,
   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
 
@@ -261,23 +257,26 @@ _dl_start_final (void *arg, struct link_map *bootstrap_map_p,
   for (cnt = 0; cnt < ehdr->e_phnum; ++cnt)
     if (phdr[cnt].p_type == PT_TLS)
       {
+       void *tlsblock;
        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);
+       GL(dl_rtld_map).l_tls_blocksize = phdr[cnt].p_memsz;
+       GL(dl_rtld_map).l_tls_initimage_size = phdr[cnt].p_filesz;
+       GL(dl_rtld_map).l_tls_initimage = (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)
+       tlsblock = alloca (roundup (GL(dl_rtld_map).l_tls_blocksize,
+                                   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
+                          + GL(dl_rtld_map).l_tls_blocksize
                           + align);
 # else
        /* In case a model with a different layout for the TCB and DTV
@@ -295,24 +294,32 @@ _dl_start_final (void *arg, struct link_map *bootstrap_map_p,
 # 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);
+       GL(dl_rtld_map).l_tls_offset = roundup (TLS_INIT_TCB_SIZE,
+                                               phdr[cnt].p_align);
+       initdtv[1].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, tlsimage, tlsimagesize),
-               '\0', tlssize - tlsimagesize);
+       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));
 
        /* 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);
+       GL(dl_rtld_map).l_tls_offset
+         = roundup (GL(dl_rtld_map).l_tls_blocksize, TLS_INIT_TCB_ALIGN);
+       TLS_INIT_TP ((char *) tlsblock + GL(dl_rtld_map).l_tls_offset,
+                    initdtv);
 # elif TLS_DTV_AT_TP
-       TLS_INIT_TP (tlsblock, intidtv);
+       TLS_INIT_TP (tlsblock, initdtv);
 # else
 #  error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
 # 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;
       }
index 2442350..5502bbf 100644 (file)
@@ -1,6 +1,6 @@
 /* Data structure for communication from the run-time dynamic linker for
    loaded ELF shared objects.
-   Copyright (C) 1995-1999, 2000, 2001 Free Software Foundation, Inc.
+   Copyright (C) 1995-1999, 2000, 2001, 2002 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -21,9 +21,9 @@
 #ifndef        _LINK_H
 #define        _LINK_H 1
 
-#include <features.h>
 #include <elf.h>
 #include <dlfcn.h>
+#include <stddef.h>
 #include <sys/types.h>
 
 /* We use this macro to refer to ELF types independent of the native wordsize.
@@ -254,6 +254,21 @@ struct link_map
 #endif
       const ElfW(Sym) *ret;
     } l_lookup_cache;
+
+    /* Thread-local storage related info.  */
+
+    /* Next module in list of initialization images.  */
+    struct link_map *l_tls_nextimage;
+    /* Start of the initialization image.  */
+    void *l_tls_initimage;
+    /* Size of the initialization image.  */
+    size_t l_tls_initimage_size;
+    /* Size of the TLS block.  */
+    size_t l_tls_blocksize;
+    /* For objects present at startup time: offset in the static TLS block.  */
+    ptrdiff_t l_tls_offset;
+    /* Index of the module in the dtv array.  */
+    size_t l_tls_modid;
   };
 
 struct dl_phdr_info
index ad6b010..d02c173 100644 (file)
@@ -1,5 +1,5 @@
 /* Support for reading /etc/ld.so.cache files written by Linux ldconfig.
-   Copyright (C) 1999, 2000 Free Software Foundation, Inc.
+   Copyright (C) 1999, 2000, 2002 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -98,6 +98,7 @@ struct cache_file_new
  & (~(__alignof__ (struct cache_file_new) - 1)))
 
 static int
+__attribute__ ((__unused__))
 _dl_cache_libcmp (const char *p1, const char *p2)
 {
   while (*p1 != '\0')
index 08785a8..4e4fecf 100644 (file)
@@ -288,8 +288,10 @@ struct rtld_global
 #endif
 
 #ifdef USE_TLS
-  /* Offset of the TLS block for ld.so from the thread-pointer.  */
-  EXTERN size_t _rtld_tlsoffset;
+  /* Beginning of the list of link maps for objects which contain
+     thread-local storage sections.  This will be traversed to
+     initialize new TLS blocks.  */
+  EXTERN struct link_map *_dl_initimage_list;
 #endif
 
   /* Name of the shared object to be profiled (if any).  */
diff --git a/sysdeps/i386/dl-lookupcfg.h b/sysdeps/i386/dl-lookupcfg.h
new file mode 100644 (file)
index 0000000..8daf7a8
--- /dev/null
@@ -0,0 +1,28 @@
+/* Configuration of lookup functions.  i386 version.
+   Copyright (C) 2000, 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <tls.h>
+
+/* Some platforms need more information from the symbol lookup function
+   than just the address.  For x86 we need it when we support TLS.  */
+#ifdef USE_TLS
+# define DL_LOOKUP_RETURNS_MAP
+#else
+# undef DL_LOOKUP_RETURNS_MAP
+#endif
index f791fa3..3e47180 100644 (file)
@@ -342,20 +342,18 @@ elf_machine_rel (struct link_map *map, const Elf32_Rel *reloc,
   else
 #endif
     {
-#if defined RTLD_BOOTSTRAP && !defined USE_TLS
-      Elf32_Addr value;
-
-      assert (r_type == R_386_GLOB_DAT || r_type == R_386_JMP_SLOT);
-
-      value = RESOLVE (&sym, version, r_type);
-      *reloc_addr = value + sym->st_value;
-#else
       const Elf32_Sym *const refsym = sym;
+#if defined USE_TLS && !defined RTLD_BOOTSTRAP
+      struct link_map *sym_map = RESOLVE_MAP (&sym, version, r_type);
+      Elf32_Addr value = sym == NULL ? 0 : sym_map->l_addr + sym->st_value;
+#else
       Elf32_Addr value = RESOLVE (&sym, version, r_type);
+
 # ifndef RTLD_BOOTSTRAP
-      if (sym)
+      if (sym != NULL)
 # endif
        value += sym->st_value;
+#endif
 
       switch (r_type)
        {
@@ -366,6 +364,7 @@ elf_machine_rel (struct link_map *map, const Elf32_Rel *reloc,
 
          /* XXX Remove TLS relocations which are not needed.  */
 
+#ifdef USE_TLS
        case R_386_TLS_DTPMOD32:
 # ifdef RTLD_BOOTSTRAP
          /* During startup the dynamic linker is always the module
@@ -374,29 +373,36 @@ elf_machine_rel (struct link_map *map, const Elf32_Rel *reloc,
             call.  */
          *reloc_addr = 1;
 # else
-         /* XXX Implement.  RESOLVE must return the map from which we
-            get the module ID.  */
-         _exit (99);
+         /* Get the information from the link map returned by the
+            resolv function.  */
+         if (sym_map != NULL)
+           *reloc_addr = sym_map->l_tls_modid;
 # endif
          break;
        case R_386_TLS_DTPOFF32:
 # ifndef RTLD_BOOTSTRAP
          /* During relocation all TLS symbols are defined and used.
             Therefore the offset is already correct.  */
-         *reloc_addr = sym->st_value;
+         if (sym != NULL)
+           *reloc_addr = sym->st_value;
 # endif
          break;
        case R_386_TLS_TPOFF32:
          /* The offset is positive, backward from the thread pointer.  */
 # ifdef RTLD_BOOTSTRAP
-         *reloc_addr = GL(rtld_tlsoffset) - sym->st_value;
+         *reloc_addr = GL(dl_rtld_map).l_tls_offset - sym->st_value;
 # else
-         /* XXX Implement.  */
-         _exit (98);
+         /* We know the offset of object the symbol is contained is.
+            It is a positive value which will be subtracted from the
+            thread pointer.  To get the variable position in the TLS
+            block we subtract the offset from that of the TLS block.  */
+         if (sym_map != NULL && sym != NULL)
+           *reloc_addr = sym_map->l_tls_offset - sym->st_value;
 # endif
          break;
+#endif /* use TLS */
 
-# ifndef RTLD_BOOTSTRAP
+#ifndef RTLD_BOOTSTRAP
        case R_386_32:
          *reloc_addr += value;
          break;
@@ -426,9 +432,8 @@ elf_machine_rel (struct link_map *map, const Elf32_Rel *reloc,
        default:
          _dl_reloc_bad_type (map, r_type, 0);
          break;
-# endif
-       }
 #endif
+       }
     }
 }
 
@@ -438,13 +443,20 @@ elf_machine_rela (struct link_map *map, const Elf32_Rela *reloc,
                  const Elf32_Sym *sym, const struct r_found_version *version,
                  Elf32_Addr *const reloc_addr)
 {
+  const unsigned int r_type = ELF32_R_TYPE (reloc->r_info);
+
   if (ELF32_R_TYPE (reloc->r_info) == R_386_RELATIVE)
     *reloc_addr = map->l_addr + reloc->r_addend;
-  else if (ELF32_R_TYPE (reloc->r_info) != R_386_NONE)
+  else if (r_type != R_386_NONE)
     {
+# ifdef USE_TLS
+      struct link_map *sym_map = RESOLVE_MAP (&sym, version, r_type);
+      Elf32_Addr value = sym == NULL ? 0 : sym_map->l_addr + sym->st_value;
+# else
       Elf32_Addr value = RESOLVE (&sym, version, ELF32_R_TYPE (reloc->r_info));
-      if (sym)
+      if (sym != NULL)
        value += sym->st_value;
+#endif
 
       switch (ELF32_R_TYPE (reloc->r_info))
        {
@@ -456,10 +468,11 @@ elf_machine_rela (struct link_map *map, const Elf32_Rela *reloc,
        case R_386_PC32:
          *reloc_addr = (value + reloc->r_addend - (Elf32_Addr) reloc_addr);
          break;
+         /* XXX Do we have to handle the TLS relocation here?  */
        default:
          /* We add these checks in the version to relocate ld.so only
             if we are still debugging.  */
-         _dl_reloc_bad_type (map, ELFW(R_TYPE) (reloc->r_info), 0);
+         _dl_reloc_bad_type (map, r_type, 0);
          break;
        }
     }