copy the dtv pointer to the end of the pthread struct for TLS_ABOVE_TP archs
authorSzabolcs Nagy <nsz@port70.net>
Wed, 11 Mar 2015 12:48:12 +0000 (12:48 +0000)
committerRich Felker <dalias@aerifal.cx>
Wed, 11 Mar 2015 22:53:48 +0000 (18:53 -0400)
There are two main abi variants for thread local storage layout:

 (1) TLS is above the thread pointer at a fixed offset and the pthread
 struct is below that. So the end of the struct is at known offset.

 (2) the thread pointer points to the pthread struct and TLS starts
 below it. So the start of the struct is at known (zero) offset.

Assembly code for the dynamic TLSDESC callback needs to access the
dynamic thread vector (dtv) pointer which is currently at the front
of the pthread struct. So in case of (1) the asm code needs to hard
code the offset from the end of the struct which can easily break if
the struct changes.

This commit adds a copy of the dtv at the end of the struct. New members
must not be added after dtv_copy, only before it. The size of the struct
is increased a bit, but there is opportunity for size optimizations.

src/env/__init_tls.c
src/internal/pthread_impl.h
src/ldso/dynlink.c

index b0dad42941059404667fd162ac107a9a00dbf5db..e651c7a78922a40703c18c8ef5f4b3de44db4e6a 100644 (file)
@@ -54,7 +54,7 @@ void *__copy_tls(unsigned char *mem)
        td = (pthread_t)mem;
        mem -= T.size;
 #endif
-       td->dtv = dtv;
+       td->dtv = td->dtv_copy = dtv;
        dtv[1] = mem;
        memcpy(mem, T.image, T.len);
        return td;
index 441b075f43f2a6d475d92d1c7c006d638127e417..7c352bc42c14df5efc600c1f1432022fcdfd7b34 100644 (file)
@@ -45,6 +45,7 @@ struct pthread {
        volatile int startlock[2];
        unsigned long sigmask[_NSIG/8/sizeof(long)];
        void *stdio_locks;
+       void **dtv_copy;
 };
 
 struct __timer {
index ca101993da5e16f2cbc9fc424682376088a66302..b0d5ff463a72118f6e3a5fd40d4f525b5c4ab818 100644 (file)
@@ -1015,7 +1015,7 @@ void *__copy_tls(unsigned char *mem)
        dtv[0] = (void *)tls_cnt;
        if (!tls_cnt) {
                td = (void *)(dtv+1);
-               td->dtv = dtv;
+               td->dtv = td->dtv_copy = dtv;
                return td;
        }
 
@@ -1041,7 +1041,7 @@ void *__copy_tls(unsigned char *mem)
                memcpy(dtv[p->tls_id], p->tls_image, p->tls_len);
        }
 #endif
-       td->dtv = dtv;
+       td->dtv = td->dtv_copy = dtv;
        return td;
 }
 
@@ -1071,7 +1071,7 @@ void *__tls_get_new(size_t *v)
                memcpy(newdtv, self->dtv,
                        ((size_t)self->dtv[0]+1) * sizeof(void *));
                newdtv[0] = (void *)v[0];
-               self->dtv = newdtv;
+               self->dtv = self->dtv_copy = newdtv;
        }
 
        /* Get new TLS memory from all new DSOs up to the requested one */