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.
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;
volatile int startlock[2];
unsigned long sigmask[_NSIG/8/sizeof(long)];
void *stdio_locks;
+ void **dtv_copy;
};
struct __timer {
dtv[0] = (void *)tls_cnt;
if (!tls_cnt) {
td = (void *)(dtv+1);
- td->dtv = dtv;
+ td->dtv = td->dtv_copy = dtv;
return td;
}
memcpy(dtv[p->tls_id], p->tls_image, p->tls_len);
}
#endif
- td->dtv = dtv;
+ td->dtv = td->dtv_copy = dtv;
return td;
}
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 */