]> git.ipfire.org Git - thirdparty/glibc.git/commitdiff
elf: Iterate over loaded object list in _dl_determine_tlsoffset
authorFlorian Weimer <fweimer@redhat.com>
Thu, 16 Jan 2025 19:02:42 +0000 (20:02 +0100)
committerFlorian Weimer <fweimer@redhat.com>
Thu, 16 Jan 2025 19:02:42 +0000 (20:02 +0100)
The old code used the slotinfo array as a scratch area to pass the
list of TLS-using objects to _dl_determine_tlsoffset.  All array
entries are subsequently overwritten by _dl_add_to_slotinfo,
except the first one.  The link maps are usually not at their
right position for their module ID in the slotinfo array, so
the initial use of the slotinfo array would be incorrect if not
for scratch purposes only.

In _dl_tls_initial_modid_limit_setup, the old code relied that
some link map was written to the first slotinfo entry.  After the
change, this no longer happens because TLS module ID zero is unused.
It's also necessary to move the call after the real initialization
of the slotinfo array.

elf/dl-tls.c
elf/rtld.c

index 45ea0588c37811b846f84c16dccd1bf4ab0a67a6..647deaf6d0c16dc3ac71879f6c2d1b392559d835 100644 (file)
@@ -245,14 +245,6 @@ _dl_determine_tlsoffset (void)
   size_t freetop = 0;
   size_t freebottom = 0;
 
-  /* The first element of the dtv slot info list is allocated.  */
-  assert (GL(dl_tls_dtv_slotinfo_list) != NULL);
-  /* There is at this point only one element in the
-     dl_tls_dtv_slotinfo_list list.  */
-  assert (GL(dl_tls_dtv_slotinfo_list)->next == NULL);
-
-  struct dtv_slotinfo *slotinfo = GL(dl_tls_dtv_slotinfo_list)->slotinfo;
-
   /* Determining the offset of the various parts of the static TLS
      block has several dependencies.  In addition we have to work
      around bugs in some toolchains.
@@ -285,19 +277,21 @@ _dl_determine_tlsoffset (void)
   /* We simply start with zero.  */
   size_t offset = 0;
 
-  for (size_t cnt = 0; slotinfo[cnt].map != NULL; ++cnt)
+  for (struct link_map *l = GL(dl_ns)[LM_ID_BASE]._ns_loaded; l != NULL;
+       l = l->l_next)
     {
-      assert (cnt < GL(dl_tls_dtv_slotinfo_list)->len);
+      if (l->l_tls_blocksize == 0)
+       continue;
 
-      size_t firstbyte = (-slotinfo[cnt].map->l_tls_firstbyte_offset
-                         & (slotinfo[cnt].map->l_tls_align - 1));
+      size_t firstbyte = (-l->l_tls_firstbyte_offset
+                         & (l->l_tls_align - 1));
       size_t off;
-      max_align = MAX (max_align, slotinfo[cnt].map->l_tls_align);
+      max_align = MAX (max_align, l->l_tls_align);
 
-      if (freebottom - freetop >= slotinfo[cnt].map->l_tls_blocksize)
+      if (freebottom - freetop >= l->l_tls_blocksize)
        {
-         off = roundup (freetop + slotinfo[cnt].map->l_tls_blocksize
-                        - firstbyte, slotinfo[cnt].map->l_tls_align)
+         off = roundup (freetop + l->l_tls_blocksize
+                        - firstbyte, l->l_tls_align)
                + firstbyte;
          if (off <= freebottom)
            {
@@ -305,24 +299,24 @@ _dl_determine_tlsoffset (void)
 
              /* XXX For some architectures we perhaps should store the
                 negative offset.  */
-             slotinfo[cnt].map->l_tls_offset = off;
+             l->l_tls_offset = off;
              continue;
            }
        }
 
-      off = roundup (offset + slotinfo[cnt].map->l_tls_blocksize - firstbyte,
-                    slotinfo[cnt].map->l_tls_align) + firstbyte;
-      if (off > offset + slotinfo[cnt].map->l_tls_blocksize
+      off = roundup (offset + l->l_tls_blocksize - firstbyte,
+                    l->l_tls_align) + firstbyte;
+      if (off > offset + l->l_tls_blocksize
                + (freebottom - freetop))
        {
          freetop = offset;
-         freebottom = off - slotinfo[cnt].map->l_tls_blocksize;
+         freebottom = off - l->l_tls_blocksize;
        }
       offset = off;
 
       /* XXX For some architectures we perhaps should store the
         negative offset.  */
-      slotinfo[cnt].map->l_tls_offset = off;
+      l->l_tls_offset = off;
     }
 
   /* Insert the extra TLS block after the last TLS block.  */
@@ -366,41 +360,43 @@ _dl_determine_tlsoffset (void)
   /* The TLS blocks start right after the TCB.  */
   size_t offset = TLS_TCB_SIZE;
 
-  for (size_t cnt = 0; slotinfo[cnt].map != NULL; ++cnt)
+  for (struct link_map *l = GL(dl_ns)[LM_ID_BASE]._ns_loaded; l != NULL;
+       l = l->l_next)
     {
-      assert (cnt < GL(dl_tls_dtv_slotinfo_list)->len);
+      if (l->l_tls_blocksize == 0)
+       continue;
 
-      size_t firstbyte = (-slotinfo[cnt].map->l_tls_firstbyte_offset
-                         & (slotinfo[cnt].map->l_tls_align - 1));
+      size_t firstbyte = (-l->l_tls_firstbyte_offset
+                         & (l->l_tls_align - 1));
       size_t off;
-      max_align = MAX (max_align, slotinfo[cnt].map->l_tls_align);
+      max_align = MAX (max_align, l->l_tls_align);
 
-      if (slotinfo[cnt].map->l_tls_blocksize <= freetop - freebottom)
+      if (l->l_tls_blocksize <= freetop - freebottom)
        {
-         off = roundup (freebottom, slotinfo[cnt].map->l_tls_align);
+         off = roundup (freebottom, l->l_tls_align);
          if (off - freebottom < firstbyte)
-           off += slotinfo[cnt].map->l_tls_align;
-         if (off + slotinfo[cnt].map->l_tls_blocksize - firstbyte <= freetop)
+           off += l->l_tls_align;
+         if (off + l->l_tls_blocksize - firstbyte <= freetop)
            {
-             slotinfo[cnt].map->l_tls_offset = off - firstbyte;
-             freebottom = (off + slotinfo[cnt].map->l_tls_blocksize
+             l->l_tls_offset = off - firstbyte;
+             freebottom = (off + l->l_tls_blocksize
                            - firstbyte);
              continue;
            }
        }
 
-      off = roundup (offset, slotinfo[cnt].map->l_tls_align);
+      off = roundup (offset, l->l_tls_align);
       if (off - offset < firstbyte)
-       off += slotinfo[cnt].map->l_tls_align;
+       off += l->l_tls_align;
 
-      slotinfo[cnt].map->l_tls_offset = off - firstbyte;
+      l->l_tls_offset = off - firstbyte;
       if (off - firstbyte - offset > freetop - freebottom)
        {
          freebottom = offset;
          freetop = off - firstbyte;
        }
 
-      offset = off + slotinfo[cnt].map->l_tls_blocksize - firstbyte;
+      offset = off + l->l_tls_blocksize - firstbyte;
     }
 
   /* Insert the extra TLS block after the last TLS block.  */
@@ -1157,7 +1153,8 @@ _dl_tls_initial_modid_limit_setup (void)
 {
   struct dtv_slotinfo_list *listp = GL(dl_tls_dtv_slotinfo_list);
   size_t idx;
-  for (idx = 0; idx < listp->len; ++idx)
+  /* Start with 1 because TLS module ID zero is unused.  */
+  for (idx = 1; idx < listp->len; ++idx)
     {
       struct link_map *l = listp->slotinfo[idx].map;
       if (l == NULL
index f32058bba6a1165c362c7849e38c08dfe12a16f4..00bec1531638ea133f5a9c1445c81d18f5cdc8f1 100644 (file)
@@ -752,26 +752,9 @@ init_tls (size_t naudit)
   /* No need to check the return value.  If memory allocation failed
      the program would have been terminated.  */
 
-  struct dtv_slotinfo *slotinfo = GL(dl_tls_dtv_slotinfo_list)->slotinfo;
   GL(dl_tls_dtv_slotinfo_list)->len = nelem;
   GL(dl_tls_dtv_slotinfo_list)->next = NULL;
 
-  /* Fill in the information from the loaded modules.  No namespace
-     but the base one can be filled at this time.  */
-  assert (GL(dl_ns)[LM_ID_BASE + 1]._ns_loaded == NULL);
-  int i = 0;
-  for (struct link_map *l = GL(dl_ns)[LM_ID_BASE]._ns_loaded; l != NULL;
-       l = l->l_next)
-    if (l->l_tls_blocksize != 0)
-      {
-       /* This is a module with TLS data.  Store the map reference.
-          The generation counter is zero.  */
-       slotinfo[i].map = l;
-       /* slotinfo[i].gen = 0; */
-       ++i;
-      }
-  assert (i == GL(dl_tls_max_dtv_idx));
-
   /* Calculate the size of the static TLS surplus.  */
   _dl_tls_static_surplus_init (naudit);
 
@@ -788,8 +771,6 @@ init_tls (size_t naudit)
     _dl_fatal_printf ("\
 cannot allocate TLS data structures for initial thread\n");
 
-  _dl_tls_initial_modid_limit_setup ();
-
   /* Store for detection of the special case by __tls_get_addr
      so it knows not to pass this dtv to the normal realloc.  */
   GL(dl_initial_dtv) = GET_DTV (tcbp);
@@ -2293,6 +2274,10 @@ dl_main (const ElfW(Phdr) *phdr,
   }
   rtld_timer_stop (&relocate_time, start);
 
+  /* This call must come after the slotinfo array has been filled in
+     using _dl_add_to_slotinfo.  */
+  _dl_tls_initial_modid_limit_setup ();
+
   /* Now enable profiling if needed.  Like the previous call,
      this has to go here because the calls it makes should use the
      rtld versions of the functions (particularly calloc()), but it