2002-08-04 Roland McGrath <roland@redhat.com>
authorRoland McGrath <roland@gnu.org>
Mon, 5 Aug 2002 01:20:52 +0000 (01:20 +0000)
committerRoland McGrath <roland@gnu.org>
Mon, 5 Aug 2002 01:20:52 +0000 (01:20 +0000)
* sysdeps/generic/dl-tls.c (_dl_allocate_tls_storage): New function,
split out of _dl_allocate_tls.
(_dl_allocate_tls_init): Likewise.
(_dl_allocate_tls): Call those.
* sysdeps/generic/ldsodefs.h: Declare them with attribute_hidden.
* elf/rtld.c (dl_main): Call them separately instead of calling
_dl_allocate_tls.  Delay _dl_allocate_tls_init until after relocation
is finished, so that the initializer data has been relocated before we
copy it into the main thread's TLS block.
* sysdeps/generic/dl-tls.c (_dl_allocate_tls): Fix off-by-one error in
loop conditions, prevented the last used module from being initialized.

sysdeps/generic/dl-tls.c

index 8877023..e4c36fb 100644 (file)
@@ -198,7 +198,7 @@ _dl_determine_tlsoffset (void)
 
 void *
 internal_function
-_dl_allocate_tls (void)
+_dl_allocate_tls_storage (void)
 {
   void *result;
   dtv_t *dtv;
@@ -225,10 +225,6 @@ _dl_allocate_tls (void)
   dtv = (dtv_t *) malloc ((dtv_length + 2) * sizeof (dtv_t));
   if (result != MAP_FAILED && dtv != NULL)
     {
-      struct dtv_slotinfo_list *listp;
-      bool first_block = true;
-      size_t total = 0;
-
 # if TLS_TCB_AT_TP
       /* The TCB follows the TLS blocks.  */
       result = (char *) result + GL(dl_tls_static_size) - TLS_TCB_SIZE;
@@ -242,75 +238,93 @@ _dl_allocate_tls (void)
         nothing there.  */
       memset (dtv + 2, '\0', dtv_length * sizeof (dtv_t));
 
-      /* We have to look prepare the dtv for all currently loaded
-        modules using TLS.  For those which are dynamically loaded we
-        add the values indicating deferred allocation.  */
-      listp = GL(dl_tls_dtv_slotinfo_list);
-      while (1)
-       {
-         size_t cnt;
+      /* Add the dtv to the thread data structures.  */
+      INSTALL_DTV (result, dtv);
+    }
+  else if (result != NULL)
+    {
+      free (result);
+      result = NULL;
+    }
 
-         for (cnt = first_block ? 1 : 0; cnt < listp->len; ++cnt)
-           {
-             struct link_map *map;
-             void *dest;
+  return result;
+}
+INTDEF(_dl_allocate_tls)
 
-             /* Check for the total number of used slots.  */
-             if (total + cnt >= GL(dl_tls_max_dtv_idx))
-               break;
+void *
+internal_function
+_dl_allocate_tls_init (void *result)
+{
+  dtv_t *dtv = GET_DTV (result);
+  struct dtv_slotinfo_list *listp;
+  bool first_block = true;
+  size_t total = 0;
+
+  /* We have to look prepare the dtv for all currently loaded
+     modules using TLS.  For those which are dynamically loaded we
+     add the values indicating deferred allocation.  */
+  listp = GL(dl_tls_dtv_slotinfo_list);
+  while (1)
+    {
+      size_t cnt;
 
-             map = listp->slotinfo[cnt].map;
-             if (map == NULL)
-               /* Unused entry.  */
-               continue;
+      for (cnt = first_block ? 1 : 0; cnt < listp->len; ++cnt)
+       {
+         struct link_map *map;
+         void *dest;
 
-             if (map->l_type == lt_loaded)
-               {
-                 /* For dynamically loaded modules we simply store
-                    the value indicating deferred allocation.  */
-                 dtv[1 + map->l_tls_modid].pointer = TLS_DTV_UNALLOCATED;
-                 continue;
-               }
+         /* Check for the total number of used slots.  */
+         if (total + cnt > GL(dl_tls_max_dtv_idx))
+           break;
+
+         map = listp->slotinfo[cnt].map;
+         if (map == NULL)
+           /* Unused entry.  */
+           continue;
+
+         if (map->l_type == lt_loaded)
+           {
+             /* For dynamically loaded modules we simply store
+                the value indicating deferred allocation.  */
+             dtv[map->l_tls_modid].pointer = TLS_DTV_UNALLOCATED;
+             continue;
+           }
 
-             assert (map->l_tls_modid == cnt);
-             assert (map->l_tls_blocksize >= map->l_tls_initimage_size);
+         assert (map->l_tls_modid == cnt);
+         assert (map->l_tls_blocksize >= map->l_tls_initimage_size);
 # if TLS_TCB_AT_TP
-             assert (map->l_tls_offset >= map->l_tls_blocksize);
-             dest = (char *) result - map->l_tls_offset;
+         assert (map->l_tls_offset >= map->l_tls_blocksize);
+         dest = (char *) result - map->l_tls_offset;
 # elif TLS_DTV_AT_TP
-             dest = (char *) result + map->l_tls_offset;
+         dest = (char *) result + map->l_tls_offset;
 # else
 #  error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
 # endif
 
-             /* We don't have to clear the BSS part of the TLS block
-                since mmap is used to allocate the memory which
-                guarantees it is initialized to zero.  */
-             dtv[1 + cnt].pointer = memcpy (dest, map->l_tls_initimage,
-                                            map->l_tls_initimage_size);
-           }
-
-         total += cnt;
-         if (total >= GL(dl_tls_max_dtv_idx))
-           break;
-
-         listp = listp->next;
-         assert (listp != NULL);
+         /* We don't have to clear the BSS part of the TLS block
+            since mmap is used to allocate the memory which
+            guarantees it is initialized to zero.  */
+         dtv[cnt].pointer = memcpy (dest, map->l_tls_initimage,
+                                    map->l_tls_initimage_size);
        }
 
-      /* Add the dtv to the thread data structures.  */
-      INSTALL_DTV (result, dtv);
-    }
-  else if (result != NULL)
-    {
-      free (result);
-      result = NULL;
+      total += cnt;
+      if (total > GL(dl_tls_max_dtv_idx))
+       break;
+
+      listp = listp->next;
+      assert (listp != NULL);
     }
 
   return result;
 }
-INTDEF(_dl_allocate_tls)
 
+void *
+internal_function
+_dl_allocate_tls (void)
+{
+  return _dl_allocate_tls_init (_dl_allocate_tls_storage ());
+}
 
 void
 internal_function