This is the mail archive of the libc-hacker@sources.redhat.com mailing list for the glibc project.

Note that libc-hacker is a closed list. You may look at the archives of this list, but subscription and posting are not open.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

using pre-TCB padding for static TLS


On Feb  7, 2005, Alexandre Oliva <aoliva@redhat.com> wrote:

>> The other novelty is that the offset from the (biased) TLS pointer to
>> the TLS block for the main executable, if there is one, is fixed by
>> the ABI, which makes the Local Exec model extremely efficient.

> This last bit, in turn, required a change to the TLS offset assignment
> that can benefit other ports.  The existing TLS offset assignment code
> assigns all offsets starting at zero, with the maximum alignment
> required by the static TLS blocks.  Only then does it take
> TLS_PRE_TCB_SIZE into account, rounding it up to the alignment of the
> static TLS block, leaving whatever padding required by this operation
> unused.

> The change introduced to enable the offset from the TCB to the
> executable TLS block to be constant enabled the pre-tcb size and
> alignment requirements to be taken into account early, such that we
> can use whatever padding they might require for TLS blocks.  This is
> particularly useful in case some TLS segment has a very large
> alignment requirement.

> Also, if a TLS segment has alignment requirements no stricter than
> those of the TCB, and the pre-TCB block has wider alignment
> requirements than the TCB, the current code will not obtain the
> correct alignment for the pre-TCB block.  This actually hits in
> current code, because the TCB often has 16-byte alignment, and the
> pre-TCB block is declared as requiring 32-byte alignment.

> The change to implement this fix was implemented by adding an argument
> to a function exported by ld.so to libpthread.so.  I'm not sure this
> is regarded as an ABI break, since it's an internal function.  It
> would be simple enough to introduce a separate entry point to obtain
> the same information, or version the function so as to make
> incompatibilities explicit.  Opinions?

This patch has the changes described above.  It introduces two new
macros to control the behavior of dl-tls: TLS_PRE_TCB_ALIGN (that
should probably be set for all DTV_AT_TP ports) and
TLS_FIXED_EXEC_TCB_OFFSET_P (that is only used on FR-V).  I could
probably split these out into a separate patch, but they're so small
and entangled with the current patch that I didn't think it was worth
the trouble.

It also introduces TLS_STATIC_RESERVED_SIZE, defined as an alias to
TLS_PRE_TCB_SIZE unless TLS_FIXED_EXEC_TCB_OFFSET_P, in which case the
offset may have to vary, and is thus defined as a macro.

_dl_get_tls_static_info() gets a new argument that libc uses to
communicate the amount of space reserved for the pre-tcb block, such
that nptl can take it into account when allocating space for the TLS
block.  I have a few backward-compatibility concerns regarding this
change, but since it's an internal function, I thought this might be
ok.

Index: ChangeLog
2005-02-03  Alexandre Oliva  <aoliva@redhat.com>

	* sysdeps/generic/dl-tls.c (_dl_determine_tlsoffset): Update
	executable sanity check in fixed exec tcb offset mode.

2004-11-22  Alexandre Oliva  <aoliva@redhat.com>

	* sysdeps/generic/dl-tls.c (_dl_determine_tlsoffset): Handle
	executables with stricter alignment requirements than the TCB.
	(_dl_get_tls_static_info): Add reservedp argument.
	(_dl_allocate_tls_storage): Add total reserved space to the size.
	(_dl_deallocate_tls): Subtract it to get the original pointer.
	* sysdeps/generic/ldsodefs.h (_dl_tls_static_tcb_offset): New.
	(TLS_STATIC_RESERVED_SIZE): Define.
	(_dl_get_tls_static_info): Adjust prototype.
	* sysdeps/generic/libc-tls.c (_dl_tls_static_tcb_offset): Define.
	(__libc_setup_tls): Set it and use it.

2004-11-20  Alexandre Oliva  <aoliva@redhat.com>

	* sysdeps/generic/dl-tls.c (_dl_determine_tlsoffset): Fix typo and
	thinko in executable's TLS alignment check.

2004-11-10  Alexandre Oliva  <aoliva@redhat.com>

	* sysdeps/generic/dl-tls.c (_dl_determine_tlsoffset): Honor
	TLS_FIXED_EXEC_TCB_OFFSET.  Take TLS_PRE_TCB_SIZE into account for
	alignment.
	(_dl_allocate_tls_storage): Assume _dl_determine_tlsoffset took
	TLS_PRE_TCB_SIZE's alignment requirements into account.
	(_dl_deallocate_tls): Likewise.
	(_dl_allocate_tls_init): Fix typo in comment.

Index: nptl/ChangeLog
2004-11-22  Alexandre Oliva  <aoliva@redhat.com>

	* allocatestack.c: Assume __static_tls_size is sufficiently
	aligned.
	* init.c (__pthread_initialize_minimal_internal): Make it so,
	taking reserved space into account.

Index: sysdeps/generic/dl-tls.c
--- sysdeps/generic/dl-tls.c	2005-01-22 16:18:32.000000000 -0200
+++ sysdeps/generic/dl-tls.c	2005-02-03 11:14:16.000000000 -0200
@@ -124,6 +124,8 @@
   size_t max_align = TLS_TCB_ALIGN;
   size_t freetop = 0;
   size_t freebottom = 0;
+  size_t offset;
+  size_t reserved __attribute__ ((unused)) = 0;
 
   /* The first element of the dtv slot info list is allocated.  */
   assert (GL(dl_tls_dtv_slotinfo_list) != NULL);
@@ -163,7 +165,7 @@
 
 # if TLS_TCB_AT_TP
   /* We simply start with zero.  */
-  size_t offset = 0;
+  offset = 0;
 
   for (size_t cnt = 0; slotinfo[cnt].map != NULL; ++cnt)
     {
@@ -209,8 +211,15 @@
   GL(dl_tls_static_size) = (roundup (offset + TLS_STATIC_SURPLUS, max_align)
 			    + TLS_TCB_SIZE);
 # elif TLS_DTV_AT_TP
+  reserved = TLS_PRE_TCB_SIZE;
+
   /* The TLS blocks start right after the TCB.  */
-  size_t offset = TLS_TCB_SIZE;
+#  ifdef TLS_PRE_TCB_ALIGN
+  max_align = MAX (max_align, TLS_PRE_TCB_ALIGN);
+#  endif
+  offset = reserved + TLS_TCB_SIZE;
+  assert ((TLS_PRE_TCB_SIZE & (TLS_TCB_ALIGN - 1)) == 0);
+  assert ((offset & (max_align - 1)) == 0);
 
   for (size_t cnt = 0; slotinfo[cnt].map != NULL; ++cnt)
     {
@@ -218,9 +227,19 @@
 
       size_t firstbyte = (-slotinfo[cnt].map->l_tls_firstbyte_offset
 			  & (slotinfo[cnt].map->l_tls_align - 1));
+
       size_t off;
       max_align = MAX (max_align, slotinfo[cnt].map->l_tls_align);
 
+#  if TLS_FIXED_EXEC_TCB_OFFSET_P
+      if (slotinfo[cnt].map->l_type == lt_executable)
+	{
+	  assert (cnt == 0 && firstbyte == 0);
+	  reserved = roundup (offset, slotinfo[cnt].map->l_tls_align)
+	    - TLS_TCB_SIZE;
+	}
+#  endif
+
       if (slotinfo[cnt].map->l_tls_blocksize <= freetop - freebottom)
 	{
 	  off = roundup (freebottom, slotinfo[cnt].map->l_tls_align);
@@ -228,7 +247,8 @@
 	    off += slotinfo[cnt].map->l_tls_align;
 	  if (off + slotinfo[cnt].map->l_tls_blocksize - firstbyte <= freetop)
 	    {
-	      slotinfo[cnt].map->l_tls_offset = off - firstbyte;
+	      slotinfo[cnt].map->l_tls_offset = off - firstbyte
+		- reserved;
 	      freebottom = (off + slotinfo[cnt].map->l_tls_blocksize
 			    - firstbyte);
 	      continue;
@@ -239,7 +259,7 @@
       if (off - offset < firstbyte)
 	off += slotinfo[cnt].map->l_tls_align;
 
-      slotinfo[cnt].map->l_tls_offset = off - firstbyte;
+      slotinfo[cnt].map->l_tls_offset = off - firstbyte - reserved;
       if (off - firstbyte - offset > freetop - freebottom)
 	{
 	  freebottom = offset;
@@ -249,13 +269,17 @@
       offset = off + slotinfo[cnt].map->l_tls_blocksize - firstbyte;
     }
 
-  GL(dl_tls_static_used) = offset;
+  GL(dl_tls_static_used) = offset - reserved;
   GL(dl_tls_static_size) = roundup (offset + TLS_STATIC_SURPLUS,
-				    TLS_TCB_ALIGN);
+				    TLS_TCB_ALIGN) - reserved;
 # else
 #  error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
 # endif
 
+#  if TLS_FIXED_EXEC_TCB_OFFSET_P
+  GL(dl_tls_static_tcb_offset) = reserved;
+#  endif
+
   /* The alignment requirement for the static TLS block.  */
   GL(dl_tls_static_align) = max_align;
 }
@@ -326,10 +350,15 @@
 /* Get size and alignment requirements of the static TLS block.  */
 void
 internal_function
-_dl_get_tls_static_info (size_t *sizep, size_t *alignp)
+_dl_get_tls_static_info (size_t *sizep, size_t *alignp, size_t *reservedp)
 {
   *sizep = GL(dl_tls_static_size);
   *alignp = GL(dl_tls_static_align);
+#if TLS_DTV_AT_TP
+  *reservedp = TLS_STATIC_RESERVED_SIZE;
+#else
+  *reservedp = 0;
+#endif
 }
 
 
@@ -343,9 +372,10 @@
 # if TLS_DTV_AT_TP
   /* Memory layout is:
      [ TLS_PRE_TCB_SIZE ] [ TLS_TCB_SIZE ] [ TLS blocks ]
-			  ^ This should be returned.  */
-  size += (TLS_PRE_TCB_SIZE + GL(dl_tls_static_align) - 1)
-	  & ~(GL(dl_tls_static_align) - 1);
+			  ^ This should be returned.
+     size and alignment are already set up such that alignment is
+     satisfied if we just add TLS_PRE_TCB_SIZE.  */
+  size += TLS_STATIC_RESERVED_SIZE;
 # endif
 
   /* Allocate a correctly aligned chunk of memory.  */
@@ -499,8 +529,7 @@
       tcb -= GL(dl_tls_static_size) - TLS_TCB_SIZE;
 # elif TLS_DTV_AT_TP
       /* Back up the TLS_PRE_TCB_SIZE bytes.  */
-      tcb -= (TLS_PRE_TCB_SIZE + GL(dl_tls_static_align) - 1)
-	     & ~(GL(dl_tls_static_align) - 1);
+      tcb -= TLS_STATIC_RESERVED_SIZE;
 # endif
       free (tcb);
     }
@@ -670,7 +699,7 @@
 		 pool.  */
 	      if (! dtv[modid].pointer.is_static
 		  && dtv[modid].pointer.val != TLS_DTV_UNALLOCATED)
-		/* Note that free is called for NULL is well.  We
+		/* Note that free is called for NULL as well.  We
 		   deallocate even if it is this dtv entry we are
 		   supposed to load.  The reason is that we call
 		   memalign and not malloc.  */
Index: sysdeps/generic/ldsodefs.h
--- sysdeps/generic/ldsodefs.h	2005-02-01 02:58:10.000000000 -0200
+++ sysdeps/generic/ldsodefs.h	2005-01-31 05:03:10.000000000 -0200
@@ -448,6 +448,15 @@
   EXTERN size_t _dl_tls_static_used;
   /* Alignment requirement of the static TLS block.  */
   EXTERN size_t _dl_tls_static_align;
+#if TLS_FIXED_EXEC_TCB_OFFSET_P
+  /* The location of the TCB past a static_align-aligned address in
+     order for the TLS block of the executable to satisfy its
+     alignment requirements and be at a fixed offset from the TCB.  */
+  EXTERN size_t _dl_tls_static_tcb_offset;
+# define TLS_STATIC_RESERVED_SIZE GL(dl_tls_static_tcb_offset)
+#else
+# define TLS_STATIC_RESERVED_SIZE TLS_PRE_TCB_SIZE
+#endif
 
 /* Number of additional entries in the slotinfo array of each slotinfo
    list element.  A large number makes it almost certain take we never
@@ -988,7 +997,8 @@
 rtld_hidden_proto (_dl_allocate_tls)
 
 /* Get size and alignment requirements of the static TLS block.  */
-extern void _dl_get_tls_static_info (size_t *sizep, size_t *alignp)
+extern void _dl_get_tls_static_info (size_t *sizep, size_t *alignp,
+				     size_t *reservedp)
      internal_function;
 
 extern void _dl_allocate_static_tls (struct link_map *map)
Index: sysdeps/generic/libc-tls.c
--- sysdeps/generic/libc-tls.c	2005-01-22 16:18:32.000000000 -0200
+++ sysdeps/generic/libc-tls.c	2005-01-31 04:48:46.000000000 -0200
@@ -67,6 +67,12 @@
 size_t _dl_tls_static_used;
 /* Alignment requirement of the static TLS block.  */
 size_t _dl_tls_static_align;
+#if TLS_FIXED_EXEC_TCB_OFFSET_P
+/* Space reserved in a TLS block before the TCB.  Used for
+   TLS_PRE_TCB_SIZE plus any padding required to align the
+   executable's TLS block.  */
+size_t _dl_tls_static_tcb_offset;
+#endif
 
 /* Generation counter for the dtv.  */
 size_t _dl_tls_generation;
@@ -161,7 +167,11 @@
   tcb_offset = roundup (tcbsize, align ?: 1);
   tlsblock = __sbrk (tcb_offset + memsz + max_align
 		     + TLS_PRE_TCB_SIZE + GL(dl_tls_static_size));
-  tlsblock += TLS_PRE_TCB_SIZE;
+#  if TLS_FIXED_EXEC_TCB_OFFSET_P
+  GL(dl_tls_static_tcb_offset) = roundup (TLS_PRE_TCB_SIZE + TLS_TCB_SIZE,
+					  max_align) - TLS_TCB_SIZE;
+#  endif
+  tlsblock += TLS_STATIC_RESERVED_SIZE + TLS_TCB_SIZE;
 # 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.  */
@@ -182,8 +192,9 @@
 			       - roundup (memsz, align ?: 1));
   static_map.l_tls_offset = roundup (memsz, align ?: 1);
 # elif TLS_DTV_AT_TP
-  static_dtv[2].pointer.val = (char *) tlsblock + tcb_offset;
+  static_dtv[2].pointer.val = (char *) tlsblock;
   static_map.l_tls_offset = tcb_offset;
+  tlsblock -= tcb_offset;
 # else
 #  error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
 # endif
Index: nptl/allocatestack.c
--- nptl/allocatestack.c	2005-01-22 16:18:31.000000000 -0200
+++ nptl/allocatestack.c	2005-01-31 04:47:41.000000000 -0200
@@ -319,8 +319,8 @@
 	    & __static_tls_align_m1;
       assert (size > adj + TLS_TCB_SIZE);
 #elif TLS_DTV_AT_TP
-      adj = ((uintptr_t) attr->stackaddr - __static_tls_size)
-	    & __static_tls_align_m1;
+      adj = ((uintptr_t) attr->stackaddr
+	    & __static_tls_align_m1);
       assert (size > adj);
 #endif
 
@@ -469,9 +469,9 @@
 #if TLS_TCB_AT_TP
 	  pd = (struct pthread *) ((char *) mem + size - coloring) - 1;
 #elif TLS_DTV_AT_TP
-	  pd = (struct pthread *) ((((uintptr_t) mem + size - coloring
-				    - __static_tls_size)
+	  pd = (struct pthread *) ((((uintptr_t) mem + size - coloring)
 				    & ~__static_tls_align_m1)
+				   - __static_tls_size
 				   - TLS_PRE_TCB_SIZE);
 #endif
 
Index: nptl/init.c
--- nptl/init.c	2005-01-06 16:39:24.000000000 -0200
+++ nptl/init.c	2005-01-31 04:47:41.000000000 -0200
@@ -304,15 +304,17 @@
 
   /* Get the size of the static and alignment requirements for the TLS
      block.  */
-  size_t static_tls_align;
-  _dl_get_tls_static_info (&__static_tls_size, &static_tls_align);
+  size_t static_tls_align, static_tls_reserve = 0;
+  _dl_get_tls_static_info (&__static_tls_size, &static_tls_align,
+			   &static_tls_reserve);
 
   /* Make sure the size takes all the alignments into account.  */
   if (STACK_ALIGN > static_tls_align)
     static_tls_align = STACK_ALIGN;
   __static_tls_align_m1 = static_tls_align - 1;
 
-  __static_tls_size = roundup (__static_tls_size, static_tls_align);
+  __static_tls_size = roundup (__static_tls_size + static_tls_reserve,
+			       static_tls_align) - static_tls_reserve;
 
 #ifdef SHARED
   /* Transfer the old value from the dynamic linker's internal location.  */
-- 
Alexandre Oliva             http://www.ic.unicamp.br/~oliva/
Red Hat Compiler Engineer   aoliva@{redhat.com, gcc.gnu.org}
Free Software Evangelist  oliva@{lsd.ic.unicamp.br, gnu.org}

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]