From owner-svn-src-head@freebsd.org Fri Nov 3 15:57:28 2017 Return-Path: Delivered-To: svn-src-head@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id E2C00E55434; Fri, 3 Nov 2017 15:57:28 +0000 (UTC) (envelope-from mmel@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id BB92F69B74; Fri, 3 Nov 2017 15:57:28 +0000 (UTC) (envelope-from mmel@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id vA3FvRoE022791; Fri, 3 Nov 2017 15:57:27 GMT (envelope-from mmel@FreeBSD.org) Received: (from mmel@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id vA3FvRiG022790; Fri, 3 Nov 2017 15:57:27 GMT (envelope-from mmel@FreeBSD.org) Message-Id: <201711031557.vA3FvRiG022790@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: mmel set sender to mmel@FreeBSD.org using -f From: Michal Meloun Date: Fri, 3 Nov 2017 15:57:27 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r325364 - head/lib/libc/gen X-SVN-Group: head X-SVN-Commit-Author: mmel X-SVN-Commit-Paths: head/lib/libc/gen X-SVN-Commit-Revision: 325364 X-SVN-Commit-Repository: base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 03 Nov 2017 15:57:29 -0000 Author: mmel Date: Fri Nov 3 15:57:27 2017 New Revision: 325364 URL: https://svnweb.freebsd.org/changeset/base/325364 Log: Add alignment support to __libc_allocate_tls(). For statically linked binaries, where all relocation are solved by static linker, the linker expect that offset to TLS section is aligned. Additionaly, to maintain absolute alignment, TLS TCB should by also aligned. Obtained from: CheriBSD (initial version) MFC after: 1 month Reviewed by: brooks (previous version), kib Differential Revision: https://reviews.freebsd.org/D12907 Modified: head/lib/libc/gen/tls.c Modified: head/lib/libc/gen/tls.c ============================================================================== --- head/lib/libc/gen/tls.c Fri Nov 3 15:07:36 2017 (r325363) +++ head/lib/libc/gen/tls.c Fri Nov 3 15:57:27 2017 (r325364) @@ -37,9 +37,15 @@ #include #include #include +#include #include "libc_private.h" +#define tls_assert(cond) ((cond) ? (void) 0 : \ + (tls_msg(#cond ": assert failed: " __FILE__ ":" \ + __XSTRING(__LINE__) "\n"), abort())) +#define tls_msg(s) write(STDOUT_FILENO, s, strlen(s)) + /* Provided by jemalloc to avoid bootstrapping issues. */ void *__je_bootstrap_malloc(size_t size); void *__je_bootstrap_calloc(size_t num, size_t size); @@ -85,6 +91,7 @@ void __libc_free_tls(void *tls, size_t tcbsize, size_t static size_t tls_static_space; static size_t tls_init_size; +static size_t tls_init_align; static void *tls_init; #endif @@ -109,6 +116,35 @@ __libc_tls_get_addr(void *ti __unused) #ifndef PIC +static void * +malloc_aligned(size_t size, size_t align) +{ + void *mem, *res; + + if (align < sizeof(void *)) + align = sizeof(void *); + + mem = __je_bootstrap_malloc(size + sizeof(void *) + align - 1); + res = (void *)roundup2((uintptr_t)mem + sizeof(void *), align); + *(void **)((uintptr_t)res - sizeof(void *)) = mem; + return (res); +} + +static void +free_aligned(void *ptr) +{ + void *mem; + uintptr_t x; + + if (ptr == NULL) + return; + + x = (uintptr_t)ptr; + x -= sizeof(void *); + mem = *(void **)x; + __je_bootstrap_free(mem); +} + #ifdef TLS_VARIANT_I #define TLS_TCB_SIZE (2 * sizeof(void *)) @@ -117,52 +153,63 @@ __libc_tls_get_addr(void *ti __unused) * Free Static TLS using the Variant I method. */ void -__libc_free_tls(void *tcb, size_t tcbsize, size_t tcbalign __unused) +__libc_free_tls(void *tcb, size_t tcbsize __unused, size_t tcbalign __unused) { Elf_Addr *dtv; Elf_Addr **tls; - tls = (Elf_Addr **)((Elf_Addr)tcb + tcbsize - TLS_TCB_SIZE); + tls = (Elf_Addr **)tcb; dtv = tls[0]; __je_bootstrap_free(dtv); - __je_bootstrap_free(tcb); + free_aligned(tls); } /* * Allocate Static TLS using the Variant I method. */ void * -__libc_allocate_tls(void *oldtcb, size_t tcbsize, size_t tcbalign __unused) +__libc_allocate_tls(void *oldtcb, size_t tcbsize, size_t tcbalign) { Elf_Addr *dtv; Elf_Addr **tls; - char *tcb; if (oldtcb != NULL && tcbsize == TLS_TCB_SIZE) return (oldtcb); - tcb = __je_bootstrap_calloc(1, tls_static_space + tcbsize - TLS_TCB_SIZE); - tls = (Elf_Addr **)(tcb + tcbsize - TLS_TCB_SIZE); + tls_assert(tcbalign >= TLS_TCB_ALIGN); + tls_assert(tcbsize == TLS_TCB_SIZE); + tcbsize = roundup2(tcbsize, tcbalign); + tls = malloc_aligned(tcbsize + tls_static_space, tcbalign); + if (tls == NULL) { + tls_msg("__libc_allocate_tls: Out of memory.\n"); + abort(); + } + memset(tls, 0, tcbsize + tls_static_space); + if (oldtcb != NULL) { - memcpy(tls, oldtcb, tls_static_space); + memcpy(tls, oldtcb, tcbsize + tls_static_space); __je_bootstrap_free(oldtcb); /* Adjust the DTV. */ dtv = tls[0]; - dtv[2] = (Elf_Addr)tls + TLS_TCB_SIZE; + dtv[2] = (Elf_Addr)tls + tcbsize; } else { dtv = __je_bootstrap_malloc(3 * sizeof(Elf_Addr)); + if (dtv == NULL) { + tls_msg("__libc_allocate_tls: Out of memory.\n"); + abort(); + } tls[0] = dtv; - dtv[0] = 1; - dtv[1] = 1; - dtv[2] = (Elf_Addr)tls + TLS_TCB_SIZE; + dtv[0] = 1; /* Generation. */ + dtv[1] = 1; /* Segments count. */ + dtv[2] = (Elf_Addr)tls + tcbsize; if (tls_init_size > 0) memcpy((void*)dtv[2], tls_init, tls_init_size); } - return(tcb); + return (tls); } #endif @@ -190,7 +237,7 @@ __libc_free_tls(void *tcb, size_t tcbsize __unused, si dtv = ((Elf_Addr**)tcb)[1]; tlsend = (Elf_Addr) tcb; tlsstart = tlsend - size; - __je_bootstrap_free((void*) tlsstart); + free_aligned((void*)tlsstart); __je_bootstrap_free(dtv); } @@ -209,8 +256,17 @@ __libc_allocate_tls(void *oldtls, size_t tcbsize, size if (tcbsize < 2 * sizeof(Elf_Addr)) tcbsize = 2 * sizeof(Elf_Addr); - tls = __je_bootstrap_calloc(1, size + tcbsize); + tls = malloc_aligned(size + tcbsize, tcbalign); + if (tls == NULL) { + tls_msg("__libc_allocate_tls: Out of memory.\n"); + abort(); + } + memset(tls, 0, size + tcbsize); dtv = __je_bootstrap_malloc(3 * sizeof(Elf_Addr)); + if (dtv == NULL) { + tls_msg("__libc_allocate_tls: Out of memory.\n"); + abort(); + } segbase = (Elf_Addr)(tls + size); ((Elf_Addr*)segbase)[0] = segbase; @@ -305,18 +361,14 @@ _init_tls(void) tls_static_space = roundup2(phdr[i].p_memsz, phdr[i].p_align); tls_init_size = phdr[i].p_filesz; + tls_init_align = phdr[i].p_align; tls_init = (void*) phdr[i].p_vaddr; + break; } } -#ifdef TLS_VARIANT_I - /* - * tls_static_space should include space for TLS structure - */ - tls_static_space += TLS_TCB_SIZE; -#endif - - tls = _rtld_allocate_tls(NULL, TLS_TCB_SIZE, TLS_TCB_ALIGN); + tls = _rtld_allocate_tls(NULL, TLS_TCB_SIZE, + MAX(TLS_TCB_ALIGN, tls_init_align)); _set_tp(tls); #endif