summaryrefslogtreecommitdiffstats
path: root/libexec
diff options
context:
space:
mode:
authorkib <kib@FreeBSD.org>2013-12-13 06:06:08 +0000
committerkib <kib@FreeBSD.org>2013-12-13 06:06:08 +0000
commitc4e5b24a258040ba4bc5343ad1fa02df5af9ccc7 (patch)
tree94df3eeedcd96a70e3154bc8a5d2e0cd9a4603e2 /libexec
parentd22cb2f95ea300443f067b7feec3432fed15cf65 (diff)
downloadFreeBSD-src-c4e5b24a258040ba4bc5343ad1fa02df5af9ccc7.zip
FreeBSD-src-c4e5b24a258040ba4bc5343ad1fa02df5af9ccc7.tar.gz
MFC r259044:
For variant II static TLS, properly align tls segments. MFC r259072: Cast Elf_Addr to void * to match the free_aligned() argument type.
Diffstat (limited to 'libexec')
-rw-r--r--libexec/rtld-elf/rtld.c35
1 files changed, 20 insertions, 15 deletions
diff --git a/libexec/rtld-elf/rtld.c b/libexec/rtld-elf/rtld.c
index fa6dc2a..ad37745 100644
--- a/libexec/rtld-elf/rtld.c
+++ b/libexec/rtld-elf/rtld.c
@@ -231,6 +231,7 @@ char **main_argv;
size_t tls_last_offset; /* Static TLS offset of last module */
size_t tls_last_size; /* Static TLS size of last module */
size_t tls_static_space; /* Static TLS space allocated */
+size_t tls_static_max_align;
int tls_dtv_generation = 1; /* Used to detect when dtv size changes */
int tls_max_index = 1; /* Largest module index allocated */
@@ -4276,19 +4277,22 @@ void *
allocate_tls(Obj_Entry *objs, void *oldtls, size_t tcbsize, size_t tcbalign)
{
Obj_Entry *obj;
- size_t size;
+ size_t size, ralign;
char *tls;
Elf_Addr *dtv, *olddtv;
Elf_Addr segbase, oldsegbase, addr;
int i;
- size = round(tls_static_space, tcbalign);
+ ralign = tcbalign;
+ if (tls_static_max_align > ralign)
+ ralign = tls_static_max_align;
+ size = round(tls_static_space, ralign) + round(tcbsize, ralign);
assert(tcbsize >= 2*sizeof(Elf_Addr));
- tls = xcalloc(1, size + tcbsize);
+ tls = malloc_aligned(size, ralign);
dtv = xcalloc(tls_max_index + 2, sizeof(Elf_Addr));
- segbase = (Elf_Addr)(tls + size);
+ segbase = (Elf_Addr)(tls + round(tls_static_space, ralign));
((Elf_Addr*)segbase)[0] = segbase;
((Elf_Addr*)segbase)[1] = (Elf_Addr) dtv;
@@ -4340,8 +4344,8 @@ allocate_tls(Obj_Entry *objs, void *oldtls, size_t tcbsize, size_t tcbalign)
void
free_tls(void *tls, size_t tcbsize, size_t tcbalign)
{
- size_t size;
Elf_Addr* dtv;
+ size_t size, ralign;
int dtvsize, i;
Elf_Addr tlsstart, tlsend;
@@ -4349,19 +4353,22 @@ free_tls(void *tls, size_t tcbsize, size_t tcbalign)
* Figure out the size of the initial TLS block so that we can
* find stuff which ___tls_get_addr() allocated dynamically.
*/
- size = round(tls_static_space, tcbalign);
+ ralign = tcbalign;
+ if (tls_static_max_align > ralign)
+ ralign = tls_static_max_align;
+ size = round(tls_static_space, ralign);
dtv = ((Elf_Addr**)tls)[1];
dtvsize = dtv[1];
tlsend = (Elf_Addr) tls;
tlsstart = tlsend - size;
for (i = 0; i < dtvsize; i++) {
- if (dtv[i+2] && (dtv[i+2] < tlsstart || dtv[i+2] > tlsend)) {
- free((void*) dtv[i+2]);
+ if (dtv[i + 2] != 0 && (dtv[i + 2] < tlsstart || dtv[i + 2] > tlsend)) {
+ free_aligned((void *)dtv[i + 2]);
}
}
- free((void*) tlsstart);
+ free_aligned((void *)tlsstart);
free((void*) dtv);
}
@@ -4385,11 +4392,7 @@ allocate_module_tls(int index)
die();
}
- p = malloc(obj->tlssize);
- if (p == NULL) {
- _rtld_error("Cannot allocate TLS block for index %d", index);
- die();
- }
+ p = malloc_aligned(obj->tlssize, obj->tlsalign);
memcpy(p, obj->tlsinit, obj->tlsinitsize);
memset(p + obj->tlsinitsize, 0, obj->tlssize - obj->tlsinitsize);
@@ -4421,9 +4424,11 @@ allocate_tls_offset(Obj_Entry *obj)
* leave a small amount of space spare to be used for dynamically
* loading modules which use static TLS.
*/
- if (tls_static_space) {
+ if (tls_static_space != 0) {
if (calculate_tls_end(off, obj->tlssize) > tls_static_space)
return false;
+ } else if (obj->tlsalign > tls_static_max_align) {
+ tls_static_max_align = obj->tlsalign;
}
tls_last_offset = obj->tlsoffset = off;
OpenPOWER on IntegriCloud