diff options
author | kib <kib@FreeBSD.org> | 2013-12-06 21:39:45 +0000 |
---|---|---|
committer | kib <kib@FreeBSD.org> | 2013-12-06 21:39:45 +0000 |
commit | 6d8fd140de9a951610292310c58bf8cca007b64f (patch) | |
tree | 43c0cad2c1474653e2b93d3f7767dd25166c91cd /libexec | |
parent | 18ee9284073c6ab130b819f7a74bc50fbd018c60 (diff) | |
download | FreeBSD-src-6d8fd140de9a951610292310c58bf8cca007b64f.zip FreeBSD-src-6d8fd140de9a951610292310c58bf8cca007b64f.tar.gz |
For variant II static TLS, properly align tls segments. Pre-calculate
the max required alignment for the static tls segments, and honor it
when carving the pieces for next module, from the static space. Use
aligned allocator to get properly-aligned dynamic blocks.
Reported by: dt71@gmx.com
Reviewed by: kan
Sponsored by: The FreeBSD Foundation
MFC after: 1 week
Diffstat (limited to 'libexec')
-rw-r--r-- | libexec/rtld-elf/rtld.c | 35 |
1 files changed, 20 insertions, 15 deletions
diff --git a/libexec/rtld-elf/rtld.c b/libexec/rtld-elf/rtld.c index b55effa..c067a64 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 */ @@ -4281,19 +4282,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; @@ -4345,8 +4349,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; @@ -4354,19 +4358,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(dtv[i + 2]); } } - free((void*) tlsstart); + free_aligned(tlsstart); free((void*) dtv); } @@ -4390,11 +4397,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); @@ -4426,9 +4429,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; |