[PR19826] fix non-LE TLS in static programs

An earlier fix for TLS dropped early initialization of DTV entries for
modules using static TLS, leaving it for __tls_get_addr to set them
up.  That worked on platforms that require the GD access model to be
relaxed to LE in the main executable, but it caused a regression on
platforms that allow GD in the main executable, particularly in
statically-linked programs: they use a custom __tls_get_addr that does
not update the DTV, which fails when the DTV early initialization is
not performed.

In static programs, __libc_setup_tls performs the DTV initialization
for the main thread, but the DTV of other threads is set up in
_dl_allocate_tls_init, so that's the fix that matters.

Restoring the initialization in the remaining functions modified by
this patch was just for uniformity.  It's not clear that it is ever
needed: even on platforms that allow GD in the main executable, the
dynamically-linked version of __tls_get_addr would set up the DTV
entries, even for static TLS modules, while updating the DTV counter.

for  ChangeLog

	[BZ #19826]
	* elf/dl-tls.c (_dl_allocate_tls_init): Restore DTV early
	initialization of static TLS entries.
	* elf/dl-reloc.c (_dl_nothread_init_static_tls): Likewise.
	* nptl/allocatestack.c (init_one_static_tls): Likewise.
This commit is contained in:
Alexandre Oliva 2016-09-21 22:01:16 -03:00
parent 444eacba82
commit 17af5da98c
4 changed files with 24 additions and 3 deletions

View File

@ -1,3 +1,11 @@
2016-09-21 Alexandre Oliva <aoliva@redhat.com>
[BZ #19826]
* elf/dl-tls.c (_dl_allocate_tls_init): Restore DTV early
initialization of static TLS entries.
* elf/dl-reloc.c (_dl_nothread_init_static_tls): Likewise.
* nptl/allocatestack.c (init_one_static_tls): Likewise.
2016-09-22 Samuel Thibault <samuel.thibault@ens-lyon.org>
* hurd/hurdmalloc.c (malloc_fork_prepare): Rename to

View File

@ -137,6 +137,12 @@ _dl_nothread_init_static_tls (struct link_map *map)
# error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
#endif
/* Fill in the DTV slot so that a later LD/GD access will find it. */
dtv_t *dtv = THREAD_DTV ();
assert (map->l_tls_modid <= dtv[-1].counter);
dtv[map->l_tls_modid].pointer.to_free = NULL;
dtv[map->l_tls_modid].pointer.val = dest;
/* Initialize the memory. */
memset (__mempcpy (dest, map->l_tls_initimage, map->l_tls_initimage_size),
'\0', map->l_tls_blocksize - map->l_tls_initimage_size);

View File

@ -538,6 +538,10 @@ _dl_allocate_tls_init (void *result)
# error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
#endif
/* Set up the DTV entry. The simplified __tls_get_addr that
some platforms use in static programs requires it. */
dtv[map->l_tls_modid].pointer.val = dest;
/* Copy the initialization image and clear the BSS part. */
memset (__mempcpy (dest, map->l_tls_initimage,
map->l_tls_initimage_size), '\0',

View File

@ -1207,9 +1207,12 @@ init_one_static_tls (struct pthread *curp, struct link_map *map)
# error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
# endif
/* We cannot delay the initialization of the Static TLS area, since
it can be accessed with LE or IE, but since the DTV is only used
by GD and LD, we can delay its update to avoid a race. */
/* Fill in the DTV slot so that a later LD/GD access will find it. */
dtv_t *dtv = GET_DTV (TLS_TPADJ (curp));
dtv[map->l_tls_modid].pointer.to_free = NULL;
dtv[map->l_tls_modid].pointer.val = dest;
/* Initialize the memory. */
memset (__mempcpy (dest, map->l_tls_initimage, map->l_tls_initimage_size),
'\0', map->l_tls_blocksize - map->l_tls_initimage_size);
}