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] |
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] |