diff --git a/lib/libc/gen/tls.c b/lib/libc/gen/tls.c --- a/lib/libc/gen/tls.c +++ b/lib/libc/gen/tls.c @@ -81,20 +81,6 @@ #error TLS_TCB_ALIGN undefined for target architecture #endif -#if defined(__aarch64__) || defined(__arm__) || defined(__mips__) || \ - defined(__powerpc__) || defined(__riscv) -#define TLS_VARIANT_I -#endif -#if defined(__i386__) || defined(__amd64__) -#define TLS_VARIANT_II -#endif - -#if defined(__mips__) || defined(__powerpc__) || defined(__riscv) -#define DTV_OFFSET 0x8000 -#else -#define DTV_OFFSET 0 -#endif - #ifndef PIC static size_t libc_tls_static_space; @@ -297,7 +283,7 @@ /* Adjust the DTV. */ dtv = tcb[0]; - dtv[2] = (Elf_Addr)(tls + DTV_OFFSET); + dtv[2] = (Elf_Addr)(tls + TLS_DTV_OFFSET); } else { dtv = __je_bootstrap_malloc(3 * sizeof(Elf_Addr)); if (dtv == NULL) { @@ -308,7 +294,7 @@ tcb[0] = dtv; dtv[0] = 1; /* Generation. */ dtv[1] = 1; /* Segments count. */ - dtv[2] = (Elf_Addr)(tls + DTV_OFFSET); + dtv[2] = (Elf_Addr)(tls + TLS_DTV_OFFSET); if (libc_tls_init_size > 0) memcpy(tls, libc_tls_init, libc_tls_init_size); diff --git a/libexec/rtld-elf/aarch64/rtld_machdep.h b/libexec/rtld-elf/aarch64/rtld_machdep.h --- a/libexec/rtld-elf/aarch64/rtld_machdep.h +++ b/libexec/rtld-elf/aarch64/rtld_machdep.h @@ -76,7 +76,6 @@ round(16, align) #define calculate_tls_offset(prev_offset, prev_size, size, align, offset) \ round(prev_offset + prev_size, align) -#define calculate_tls_end(off, size) ((off) + (size)) #define calculate_tls_post_size(align) \ round(TLS_TCB_SIZE, align) - TLS_TCB_SIZE @@ -93,6 +92,7 @@ #define md_abi_variant_hook(x) +#define TLS_VARIANT_I 1 #define TLS_DTV_OFFSET 0 #endif diff --git a/libexec/rtld-elf/amd64/reloc.c b/libexec/rtld-elf/amd64/reloc.c --- a/libexec/rtld-elf/amd64/reloc.c +++ b/libexec/rtld-elf/amd64/reloc.c @@ -548,31 +548,22 @@ } size_t -calculate_first_tls_offset(size_t size, size_t align, size_t offset) +calculate_tls_offset(size_t prev_offset, size_t prev_size __unused, + size_t size, size_t align, size_t offset) { size_t res; - res = roundup(size, align); - offset &= align - 1; - if (offset != 0) - res += align - offset; - return (res); + /* + * res is the smallest integer satisfying res - prev_offset >= size + * and (-res) % p_align = p_vaddr % p_align (= p_offset % p_align). + */ + res = prev_offset + size + align - 1; + res -= (res + offset) & (align - 1); + return (res); } size_t -calculate_tls_offset(size_t prev_offset, size_t prev_size __unused, size_t size, - size_t align, size_t offset) -{ - size_t res; - - res = roundup(prev_offset + size, align); - offset &= align - 1; - if (offset != 0) - res += align - offset; - return (res); -} -size_t -calculate_tls_end(size_t off, size_t size __unused) +calculate_first_tls_offset(size_t size, size_t align, size_t offset) { - return (off); + return (calculate_tls_offset(0, 0, size, align, offset)); } diff --git a/libexec/rtld-elf/amd64/rtld_machdep.h b/libexec/rtld-elf/amd64/rtld_machdep.h --- a/libexec/rtld-elf/amd64/rtld_machdep.h +++ b/libexec/rtld-elf/amd64/rtld_machdep.h @@ -73,10 +73,10 @@ #define md_abi_variant_hook(x) +#define TLS_VARIANT_II 1 #define TLS_DTV_OFFSET 0 size_t calculate_first_tls_offset(size_t size, size_t align, size_t offset); size_t calculate_tls_offset(size_t prev_offset, size_t prev_size, size_t size, size_t align, size_t offset); -size_t calculate_tls_end(size_t off, size_t size); #endif diff --git a/libexec/rtld-elf/arm/rtld_machdep.h b/libexec/rtld-elf/arm/rtld_machdep.h --- a/libexec/rtld-elf/arm/rtld_machdep.h +++ b/libexec/rtld-elf/arm/rtld_machdep.h @@ -68,7 +68,6 @@ round(8, align) #define calculate_tls_offset(prev_offset, prev_size, size, align, offset) \ round(prev_offset + prev_size, align) -#define calculate_tls_end(off, size) ((off) + (size)) #define calculate_tls_post_size(align) \ round(TLS_TCB_SIZE, align) - TLS_TCB_SIZE @@ -86,6 +85,7 @@ #define md_abi_variant_hook(x) #endif +#define TLS_VARIANT_I 1 #define TLS_DTV_OFFSET 0 #endif diff --git a/libexec/rtld-elf/i386/reloc.c b/libexec/rtld-elf/i386/reloc.c --- a/libexec/rtld-elf/i386/reloc.c +++ b/libexec/rtld-elf/i386/reloc.c @@ -539,31 +539,22 @@ } size_t -calculate_first_tls_offset(size_t size, size_t align, size_t offset) +calculate_tls_offset(size_t prev_offset, size_t prev_size __unused, + size_t size, size_t align, size_t offset) { size_t res; - res = roundup(size, align); - offset &= align - 1; - if (offset != 0) - res += align - offset; - return (res); + /* + * res is the smallest integer satisfying res - prev_offset >= size + * and (-res) % p_align = p_vaddr % p_align (= p_offset % p_align). + */ + res = prev_offset + size + align - 1; + res -= (res + offset) & (align - 1); + return (res); } size_t -calculate_tls_offset(size_t prev_offset, size_t prev_size __unused, size_t size, - size_t align, size_t offset) -{ - size_t res; - - res = roundup(prev_offset + size, align); - offset &= align - 1; - if (offset != 0) - res += align - offset; - return (res); -} -size_t -calculate_tls_end(size_t off, size_t size __unused) +calculate_first_tls_offset(size_t size, size_t align, size_t offset) { - return (off); + return (calculate_tls_offset(0, 0, size, align, offset)); } diff --git a/libexec/rtld-elf/i386/rtld_machdep.h b/libexec/rtld-elf/i386/rtld_machdep.h --- a/libexec/rtld-elf/i386/rtld_machdep.h +++ b/libexec/rtld-elf/i386/rtld_machdep.h @@ -74,10 +74,10 @@ #define md_abi_variant_hook(x) +#define TLS_VARIANT_II 1 #define TLS_DTV_OFFSET 0 size_t calculate_first_tls_offset(size_t size, size_t align, size_t offset); size_t calculate_tls_offset(size_t prev_offset, size_t prev_size, size_t size, size_t align, size_t offset); -size_t calculate_tls_end(size_t off, size_t size); #endif diff --git a/libexec/rtld-elf/mips/rtld_machdep.h b/libexec/rtld-elf/mips/rtld_machdep.h --- a/libexec/rtld-elf/mips/rtld_machdep.h +++ b/libexec/rtld-elf/mips/rtld_machdep.h @@ -68,7 +68,6 @@ TLS_TCB_SIZE #define calculate_tls_offset(prev_offset, prev_size, size, align, offset) \ round(prev_offset + prev_size, align) -#define calculate_tls_end(off, size) ((off) + (size)) #define calculate_tls_post_size(align) 0 extern void *__tls_get_addr(tls_index *ti); @@ -78,6 +77,7 @@ #define md_abi_variant_hook(x) +#define TLS_VARIANT_I 1 #define TLS_DTV_OFFSET 0 #endif diff --git a/libexec/rtld-elf/powerpc/rtld_machdep.h b/libexec/rtld-elf/powerpc/rtld_machdep.h --- a/libexec/rtld-elf/powerpc/rtld_machdep.h +++ b/libexec/rtld-elf/powerpc/rtld_machdep.h @@ -73,6 +73,7 @@ * TLS */ +#define TLS_VARIANT_I 1 #define TLS_TP_OFFSET 0x7000 #define TLS_DTV_OFFSET 0x8000 #define TLS_TCB_SIZE 8 @@ -83,7 +84,6 @@ TLS_TCB_SIZE #define calculate_tls_offset(prev_offset, prev_size, size, align, offset) \ round(prev_offset + prev_size, align) -#define calculate_tls_end(off, size) ((off) + (size)) #define calculate_tls_post_size(align) 0 typedef struct { diff --git a/libexec/rtld-elf/powerpc64/rtld_machdep.h b/libexec/rtld-elf/powerpc64/rtld_machdep.h --- a/libexec/rtld-elf/powerpc64/rtld_machdep.h +++ b/libexec/rtld-elf/powerpc64/rtld_machdep.h @@ -65,6 +65,7 @@ * TLS */ +#define TLS_VARIANT_I 1 #define TLS_TP_OFFSET 0x7000 #define TLS_DTV_OFFSET 0x8000 #define TLS_TCB_SIZE 16 @@ -75,7 +76,6 @@ TLS_TCB_SIZE #define calculate_tls_offset(prev_offset, prev_size, size, align, offset) \ round(prev_offset + prev_size, align) -#define calculate_tls_end(off, size) ((off) + (size)) #define calculate_tls_post_size(align) 0 typedef struct { diff --git a/libexec/rtld-elf/riscv/rtld_machdep.h b/libexec/rtld-elf/riscv/rtld_machdep.h --- a/libexec/rtld-elf/riscv/rtld_machdep.h +++ b/libexec/rtld-elf/riscv/rtld_machdep.h @@ -82,6 +82,7 @@ /* * TLS */ +#define TLS_VARIANT_I 1 #define TLS_TP_OFFSET 0x0 #define TLS_DTV_OFFSET 0x800 #define TLS_TCB_SIZE 16 @@ -92,7 +93,6 @@ TLS_TCB_SIZE #define calculate_tls_offset(prev_offset, prev_size, size, align, offset) \ round(prev_offset + prev_size, align) -#define calculate_tls_end(off, size) ((off) + (size)) #define calculate_tls_post_size(align) 0 typedef struct { diff --git a/libexec/rtld-elf/rtld.c b/libexec/rtld-elf/rtld.c --- a/libexec/rtld-elf/rtld.c +++ b/libexec/rtld-elf/rtld.c @@ -4939,8 +4939,7 @@ return (tls_get_addr_slow(dtvp, index, offset, false)); } -#if defined(__aarch64__) || defined(__arm__) || defined(__mips__) || \ - defined(__powerpc__) || defined(__riscv) +#ifdef TLS_VARIANT_I /* * Return pointer to allocated TLS block @@ -5071,9 +5070,9 @@ free_aligned(get_tls_block_ptr(tcb, tcbsize)); } -#endif +#endif /* TLS_VARIANT_I */ -#if defined(__i386__) || defined(__amd64__) +#ifdef TLS_VARIANT_II /* * Allocate Static TLS using the Variant II method. @@ -5179,7 +5178,7 @@ free((void*) dtv); } -#endif +#endif /* TLS_VARIANT_II */ /* * Allocate TLS block for module with given index. @@ -5227,6 +5226,11 @@ off = calculate_tls_offset(tls_last_offset, tls_last_size, obj->tlssize, obj->tlsalign, obj->tlspoffset); + obj->tlsoffset = off; +#ifdef TLS_VARIANT_I + off += obj->tlssize; +#endif + /* * If we have already fixed the size of the static TLS block, we * must stay within that size. When allocating the static TLS, we @@ -5234,13 +5238,13 @@ * loading modules which use static TLS. */ if (tls_static_space != 0) { - if (calculate_tls_end(off, obj->tlssize) > tls_static_space) + if (off > 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; + tls_last_offset = off; tls_last_size = obj->tlssize; obj->tls_done = true; @@ -5257,8 +5261,11 @@ * simplistic workaround to allow libGL.so.1 to be loaded and * unloaded multiple times. */ - if (calculate_tls_end(obj->tlsoffset, obj->tlssize) - == calculate_tls_end(tls_last_offset, tls_last_size)) { + size_t off = obj->tlsoffset; +#ifdef TLS_VARIANT_I + off += obj->tlssize; +#endif + if (off == tls_last_offset) { tls_last_offset -= obj->tlssize; tls_last_size = 0; }