From patchwork Tue Jan 7 11:54:12 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Szabolcs Nagy X-Patchwork-Id: 37240 Received: (qmail 69094 invoked by alias); 7 Jan 2020 11:54:26 -0000 Mailing-List: contact libc-alpha-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: libc-alpha-owner@sourceware.org Delivered-To: mailing list libc-alpha@sourceware.org Received: (qmail 69085 invoked by uid 89); 7 Jan 2020 11:54:26 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-18.1 required=5.0 tests=AWL, BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, KAM_SHORT, RCVD_IN_DNSWL_NONE, SPF_HELO_PASS, SPF_PASS, UNPARSEABLE_RELAY autolearn=ham version=3.3.1 spammy=Forces X-HELO: EUR02-VE1-obe.outbound.protection.outlook.com DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=armh.onmicrosoft.com; s=selector2-armh-onmicrosoft-com; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=+G+5UyjUdDKWkjkz2nf+4782PO7rQEfXjGMBImYjGNY=; b=SrVpc1EgRPTjiqb0VA9MGpygU3El/92U80BKjsCF4a0fq7aIdVcVaS7ZgANOMQ/Y9u0sJI7Wynvzfc9kZGs7ddhLQSmccCKVeVXQurx3BYYDtsjybHwr8Dp9qBpHdrtCtLpXKk70YOH+X8wBIwbYiY1sQI225P2QfpTVklG14cE= Authentication-Results: spf=pass (sender IP is 63.35.35.123) smtp.mailfrom=arm.com; sourceware.org; dkim=pass (signature was verified) header.d=armh.onmicrosoft.com; sourceware.org; dmarc=bestguesspass action=none header.from=arm.com; Received-SPF: Pass (protection.outlook.com: domain of arm.com designates 63.35.35.123 as permitted sender) receiver=protection.outlook.com; client-ip=63.35.35.123; helo=64aa7808-outbound-1.mta.getcheckrecipient.com; X-CheckRecipientChecked: true X-CR-MTA-CID: 82310a43f2fab2b2 X-CR-MTA-TID: 64aa7808 ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=MukTpYMoug29yWXktjiywkCaUv55fNv9slgd/FzVvY7wR5lXykbPwOm+tp2ugdofUJ+yxRbJgI71wkEU5PQRRh8QxPjP4nfB8duq4EkRrxINEl1/B+IBnCryBWYXsfXoGGaqgY2Thnl41iD2hOGzVSYLjgeXey3PIe1XlqMa/1Fl3nrtQnPm4u/tnhL9/0VzMteraJ00OEUuHu5a2nZ58/uq8mGn6UYwIoMkPbrOm2Cvk+5t6CTAiHY7yCDmAxbKbEABbzOY60oK7R6P8BMwHdckS61ESpr+/cY1onIFG5CiuzkxoAWYqE+GhgHhBLrhvfkjgTTJl1IA9Ux+tnaB5g== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=+G+5UyjUdDKWkjkz2nf+4782PO7rQEfXjGMBImYjGNY=; b=BkhkQ3WKurrjbQFRzhhyj5fA9/A5kf6M/dQ1SYOfRJOxB39uFxOzUQjiaVlElfvdKnpEKk+4B6G2UQTNv0kXdVpS4tEKk0RdBsWEti0cHfgzqLnTzM3YgurVSJuzrsypB2j9tlII6Czs1NVT36DXIUsE69Qeq5ifJv1rrtrPt6Oa1J4lJuDWfw5SISl3Xrz8n1AcQmrKccuyPr5/kd5km0o1rDuKuc3kyzWrnGTx1SNl20osEggbCCHKQTQt9xk1E85HxZ5gGoS4C0r3yXFhMFmjlt13gssS+yKWfyePkNFTG5NtLVDXdG29UhYwdUuOtkQAJlHYK/B7pLNCbaHR0A== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=arm.com; dmarc=pass action=none header.from=arm.com; dkim=pass header.d=arm.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=armh.onmicrosoft.com; s=selector2-armh-onmicrosoft-com; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=+G+5UyjUdDKWkjkz2nf+4782PO7rQEfXjGMBImYjGNY=; b=SrVpc1EgRPTjiqb0VA9MGpygU3El/92U80BKjsCF4a0fq7aIdVcVaS7ZgANOMQ/Y9u0sJI7Wynvzfc9kZGs7ddhLQSmccCKVeVXQurx3BYYDtsjybHwr8Dp9qBpHdrtCtLpXKk70YOH+X8wBIwbYiY1sQI225P2QfpTVklG14cE= From: Szabolcs Nagy To: GNU C Library CC: nd Subject: [PATCH] Reserve static TLS for dynamically loaded initial-exec TLS only [BZ #25051] Date: Tue, 7 Jan 2020 11:54:12 +0000 Message-ID: <44eaccc2-f760-88c0-989a-e413e328b051@arm.com> user-agent: Mozilla/5.0 (X11; Linux aarch64; rv:60.0) Gecko/20100101 Thunderbird/60.9.0 Authentication-Results-Original: spf=none (sender IP is ) smtp.mailfrom=Szabolcs.Nagy@arm.com; x-checkrecipientrouted: true x-ms-oob-tlc-oobclassifiers: OLM:8882;OLM:8882; X-Forefront-Antispam-Report-Untrusted: SFV:NSPM; SFS:(10009020)(4636009)(39860400002)(396003)(346002)(376002)(136003)(366004)(189003)(199004)(5660300002)(8676002)(81156014)(8936002)(31686004)(52116002)(81166006)(26005)(4326008)(478600001)(64756008)(66556008)(66446008)(66476007)(316002)(2616005)(66946007)(66616009)(956004)(2906002)(16576012)(71200400001)(36756003)(558084003)(86362001)(31696002)(186003)(16526019)(44832011)(6916009)(6486002); DIR:OUT; SFP:1101; SCL:1; SRVR:AM0PR08MB4164; H:AM0PR08MB3281.eurprd08.prod.outlook.com; FPR:; SPF:None; LANG:en; PTR:InfoNoRecords; MX:1; A:1; received-spf: None (protection.outlook.com: arm.com does not designate permitted sender hosts) X-MS-Exchange-SenderADCheck: 1 X-Microsoft-Antispam-Untrusted: BCL:0; X-Microsoft-Antispam-Message-Info-Original: mr8+ZHtmrisG30FENe9JUj0gFhu1LBpaTBMtvjKSm7nKvLeeQruHbN5F/L8pVLIoeYzMk1HsazilcTUJY6e5yxdKwAlcE/caTax0Zfug6ujgOL7Gc4fX4kLwTr+3CXeJH1rm/UG/QO1G7/nHsOuGNnZYPPB05GAyFndtX33d+nSfhYiIqETzXlTuixAYP2sTxrqFs04NLCk+9CaeplbDKJwq9VE6mdqwXnma/pOUvfVggAii3nV80gXKWhdqc/41vFKE+LMHGwWgGd4YkC+vmHXHLFk8g4NqMA5fPLWMSHc+jPR5+5MkcUYj5gQZQpTexiyo109ydP7VioJGQLpTBPakhCtG1IzZA+ZGpNdcD8PPTCvXJ7ZatrWtUrpeP8w5ogfSakKL8BdXQUnB8K3hH0ubWjluCvkHbrOiqcUx8WHgKcwCOE0iOORu2Ik9rxuU x-ms-exchange-transport-forked: True MIME-Version: 1.0 Original-Authentication-Results: spf=none (sender IP is ) smtp.mailfrom=Szabolcs.Nagy@arm.com; Return-Path: Szabolcs.Nagy@arm.com X-MS-Exchange-Transport-CrossTenantHeadersStripped: DB5EUR03FT060.eop-EUR03.prod.protection.outlook.com X-MS-Office365-Filtering-Correlation-Id-Prvs: 8b64285b-2793-4cb4-f01d-08d793685003 i forgot about this, i guess it's too late for 2.31. please comment if you disagree with the approach. From c0ab4649026d19bda77818946e349369b12384ee Mon Sep 17 00:00:00 2001 From: Szabolcs Nagy Date: Tue, 31 Dec 2019 16:01:41 +0000 Subject: [PATCH] Reserve static TLS for dynamically loaded initial-exec TLS only [BZ #25051] On some targets static TLS surplus area can be used opportunistically for dynamically loaded modules such that the TLS access then becomes faster (TLSDESC and powerpc TLS optimization). However we don't want all surplus TLS to be used for this optimization because dynamically loaded modules with initial-exec TLS can only use surplus TLS. This patch reserves 128 bytes of the surplus TLS that is not used opportunistically. TLS_STATIC_SURPLUS is currently 1664, so this still allows 1536 bytes for opportunistic use. A new test is added to verify this ABI contract: dynamic loading of libraries with initial-exec TLS is supported up to 128 bytes in total on all targets. This should be enough for system libraries such as libgomp. Discussed at https://sourceware.org/ml/libc-alpha/2019-09/msg00533.html Tested on aarch64-linux-gnu and x86_64-linux-gnu. --- elf/Makefile | 17 +++++++- elf/dl-reloc.c | 17 ++++---- elf/dynamic-link.h | 10 ++++- elf/tst-tls-ie-mod.h | 40 ++++++++++++++++++ elf/tst-tls-ie-mod0.c | 4 ++ elf/tst-tls-ie-mod1.c | 4 ++ elf/tst-tls-ie-mod2.c | 4 ++ elf/tst-tls-ie-mod3.c | 4 ++ elf/tst-tls-ie-mod4.c | 4 ++ elf/tst-tls-ie-mod5.c | 4 ++ elf/tst-tls-ie.c | 98 +++++++++++++++++++++++++++++++++++++++++++ 11 files changed, 194 insertions(+), 12 deletions(-) create mode 100644 elf/tst-tls-ie-mod.h create mode 100644 elf/tst-tls-ie-mod0.c create mode 100644 elf/tst-tls-ie-mod1.c create mode 100644 elf/tst-tls-ie-mod2.c create mode 100644 elf/tst-tls-ie-mod3.c create mode 100644 elf/tst-tls-ie-mod4.c create mode 100644 elf/tst-tls-ie-mod5.c create mode 100644 elf/tst-tls-ie.c diff --git a/elf/Makefile b/elf/Makefile index f861126b2f..6ec23ac874 100644 --- a/elf/Makefile +++ b/elf/Makefile @@ -194,17 +194,18 @@ tests += restest1 preloadtest loadfail multiload origtest resolvfail \ tst-nodelete tst-dlopen-nodelete-reloc) \ tst-initorder tst-initorder2 tst-relsort1 tst-null-argv \ tst-tlsalign tst-tlsalign-extern tst-nodelete-opened \ tst-nodelete2 tst-audit11 tst-audit12 tst-dlsym-error tst-noload \ tst-latepthread tst-tls-manydynamic tst-nodelete-dlclose \ tst-debug1 tst-main1 tst-absolute-sym tst-absolute-zero tst-big-note \ tst-unwind-ctor tst-unwind-main tst-audit13 \ tst-sonamemove-link tst-sonamemove-dlopen tst-dlopen-tlsmodid \ - tst-dlopen-self tst-auditmany tst-initfinilazyfail tst-dlopenfail + tst-dlopen-self tst-auditmany tst-initfinilazyfail tst-dlopenfail \ + tst-tls-ie # reldep9 tests-internal += loadtest unload unload2 circleload1 \ neededtest neededtest2 neededtest3 neededtest4 \ tst-tls3 tst-tls6 tst-tls7 tst-tls8 tst-dlmopen2 \ tst-ptrguard1 tst-stackguard1 tst-libc_dlvsym \ tst-create_format1 tests-container += tst-pldd tst-dlopen-tlsmodid-container \ tst-dlopen-self-container @@ -304,17 +305,20 @@ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \ tst-main1mod tst-libc_dlvsym-dso tst-absolute-sym-lib \ tst-absolute-zero-lib tst-big-note-lib tst-unwind-ctor-lib \ tst-audit13mod1 tst-sonamemove-linkmod1 \ tst-sonamemove-runmod1 tst-sonamemove-runmod2 \ tst-auditmanymod1 tst-auditmanymod2 tst-auditmanymod3 \ tst-auditmanymod4 tst-auditmanymod5 tst-auditmanymod6 \ tst-auditmanymod7 tst-auditmanymod8 tst-auditmanymod9 \ tst-initlazyfailmod tst-finilazyfailmod \ - tst-dlopenfailmod1 tst-dlopenfaillinkmod tst-dlopenfailmod2 + tst-dlopenfailmod1 tst-dlopenfaillinkmod tst-dlopenfailmod2 \ + tst-tls-ie-mod0 tst-tls-ie-mod1 tst-tls-ie-mod2 \ + tst-tls-ie-mod3 tst-tls-ie-mod4 tst-tls-ie-mod5 + # Most modules build with _ISOMAC defined, but those filtered out # depend on internal headers. modules-names-tests = $(filter-out ifuncmod% tst-libc_dlvsym-dso tst-tlsmod%,\ $(modules-names)) ifeq (yes,$(have-mtls-dialect-gnu2)) tests += tst-gnu2-tls1 modules-names += tst-gnu2-tls1mod @@ -1683,8 +1687,17 @@ $(objpfx)tst-dlopen-nodelete-reloc-mod15.so: \ tst-dlopen-nodelete-reloc-mod16.so-no-z-defs = yes $(objpfx)tst-dlopen-nodelete-reloc-mod16.so: \ $(objpfx)tst-dlopen-nodelete-reloc-mod15.so LDFLAGS-tst-dlopen-nodelete-reloc-mod16.so = -Wl,--no-as-needed $(objpfx)tst-dlopen-nodelete-reloc-mod17.so: \ $(objpfx)tst-dlopen-nodelete-reloc-mod15.so \ $(objpfx)tst-dlopen-nodelete-reloc-mod16.so LDFLAGS-tst-dlopen-nodelete-reloc-mod17.so = -Wl,--no-as-needed + +$(objpfx)tst-tls-ie: $(libdl) $(shared-thread-library) +$(objpfx)tst-tls-ie.out: \ + $(objpfx)tst-tls-ie-mod0.so \ + $(objpfx)tst-tls-ie-mod1.so \ + $(objpfx)tst-tls-ie-mod2.so \ + $(objpfx)tst-tls-ie-mod3.so \ + $(objpfx)tst-tls-ie-mod4.so \ + $(objpfx)tst-tls-ie-mod5.so diff --git a/elf/dl-reloc.c b/elf/dl-reloc.c index 7f201fe184..fb284cc455 100644 --- a/elf/dl-reloc.c +++ b/elf/dl-reloc.c @@ -33,39 +33,39 @@ # define bump_num_cache_relocations() ++GL(dl_num_cache_relocations) #else # define bump_num_cache_relocations() ((void) 0) #endif /* We are trying to perform a static TLS relocation in MAP, but it was dynamically loaded. This can only work if there is enough surplus in - the static TLS area already allocated for each running thread. If this - object's TLS segment is too big to fit, we fail. If it fits, - we set MAP->l_tls_offset and return. + the static TLS area already allocated for each running thread. If this + object's TLS segment is too big to fit or less than RESERVED bytes + remain free, we fail. If it fits, we set MAP->l_tls_offset and return. This function intentionally does not return any value but signals error directly, as static TLS should be rare and code handling it should not be inlined as much as possible. */ int -_dl_try_allocate_static_tls (struct link_map *map) +_dl_try_allocate_static_tls (struct link_map *map, size_t reserved) { /* If we've already used the variable with dynamic access, or if the alignment requirements are too high, fail. */ if (map->l_tls_offset == FORCED_DYNAMIC_TLS_OFFSET || map->l_tls_align > GL(dl_tls_static_align)) { fail: return -1; } #if TLS_TCB_AT_TP size_t freebytes = GL(dl_tls_static_size) - GL(dl_tls_static_used); - if (freebytes < TLS_TCB_SIZE) + if (freebytes < TLS_TCB_SIZE + reserved) goto fail; - freebytes -= TLS_TCB_SIZE; + freebytes -= TLS_TCB_SIZE + reserved; size_t blsize = map->l_tls_blocksize + map->l_tls_firstbyte_offset; if (freebytes < blsize) goto fail; size_t n = (freebytes - blsize) / map->l_tls_align; size_t offset = GL(dl_tls_static_used) + (freebytes - n * map->l_tls_align @@ -75,17 +75,18 @@ _dl_try_allocate_static_tls (struct link_map *map) #elif TLS_DTV_AT_TP /* dl_tls_static_used includes the TCB at the beginning. */ size_t offset = (ALIGN_UP(GL(dl_tls_static_used) - map->l_tls_firstbyte_offset, map->l_tls_align) + map->l_tls_firstbyte_offset); size_t used = offset + map->l_tls_blocksize; - if (used > GL(dl_tls_static_size)) + if (GL(dl_tls_static_size) < reserved + || used > GL(dl_tls_static_size) - reserved) goto fail; map->l_tls_offset = offset; map->l_tls_firstbyte_offset = GL(dl_tls_static_used); GL(dl_tls_static_used) = used; #else # error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined" #endif @@ -110,17 +111,17 @@ _dl_try_allocate_static_tls (struct link_map *map) return 0; } void __attribute_noinline__ _dl_allocate_static_tls (struct link_map *map) { if (map->l_tls_offset == FORCED_DYNAMIC_TLS_OFFSET - || _dl_try_allocate_static_tls (map)) + || _dl_try_allocate_static_tls (map, 0)) { _dl_signal_error (0, map->l_name, NULL, N_("\ cannot allocate memory in static TLS block")); } } /* Initialize static TLS area and DTV for current (only) thread. libpthread implementations should provide their own hook diff --git a/elf/dynamic-link.h b/elf/dynamic-link.h index 5d9ef492ac..013a859ca3 100644 --- a/elf/dynamic-link.h +++ b/elf/dynamic-link.h @@ -35,19 +35,25 @@ if (!HAVE_STATIC_TLS (map, sym_map)) \ _dl_allocate_static_tls (sym_map); \ } while (0) #define TRY_STATIC_TLS(map, sym_map) \ (__builtin_expect ((sym_map)->l_tls_offset \ != FORCED_DYNAMIC_TLS_OFFSET, 1) \ && (__builtin_expect ((sym_map)->l_tls_offset != NO_TLS_OFFSET, 1) \ - || _dl_try_allocate_static_tls (sym_map) == 0)) + || _dl_try_allocate_static_tls (sym_map, TLS_RESERVED_FOR_IE) == 0)) -int _dl_try_allocate_static_tls (struct link_map *map) attribute_hidden; +/* When the static TLS surplus area is opportunistically used, e.g. by + TRY_STATIC_TLS, reserve at least this much for dynamically loaded + modules with initial-exec TLS which can only use the surplus TLS. */ +#define TLS_RESERVED_FOR_IE 128 + +int _dl_try_allocate_static_tls (struct link_map *map, size_t reserved) + attribute_hidden; #include #ifdef RESOLVE_MAP /* We pass reloc_addr as a pointer to void, as opposed to a pointer to ElfW(Addr), because not all architectures can assume that the relocated address is properly aligned, whereas the compiler is entitled to assume that a pointer to a type is properly aligned for diff --git a/elf/tst-tls-ie-mod.h b/elf/tst-tls-ie-mod.h new file mode 100644 index 0000000000..46b362a9b7 --- /dev/null +++ b/elf/tst-tls-ie-mod.h @@ -0,0 +1,40 @@ +/* Module with specified TLS size and model. + Copyright (C) 2020 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +/* This file is parameterized by macros N, SIZE and MODEL. */ + +#include +#include + +#define CONCATX(x, y) x ## y +#define CONCAT(x, y) CONCATX (x, y) +#define STRX(x) #x +#define STR(x) STRX (x) + +#define VAR CONCAT (var, N) + +__attribute__ ((aligned (8), tls_model (MODEL))) +__thread char VAR[SIZE]; + +void +CONCAT (access, N) (void) +{ + printf (STR (VAR) "[%d]:\t %p .. %p " MODEL "\n", SIZE, VAR, VAR + SIZE); + fflush (stdout); + memset (VAR, 1, SIZE); +} diff --git a/elf/tst-tls-ie-mod0.c b/elf/tst-tls-ie-mod0.c new file mode 100644 index 0000000000..a822af1b3c --- /dev/null +++ b/elf/tst-tls-ie-mod0.c @@ -0,0 +1,4 @@ +#define N 0 +#define SIZE 1520 +#define MODEL "global-dynamic" +#include "tst-tls-ie-mod.h" diff --git a/elf/tst-tls-ie-mod1.c b/elf/tst-tls-ie-mod1.c new file mode 100644 index 0000000000..849ff91e53 --- /dev/null +++ b/elf/tst-tls-ie-mod1.c @@ -0,0 +1,4 @@ +#define N 1 +#define SIZE 120 +#define MODEL "global-dynamic" +#include "tst-tls-ie-mod.h" diff --git a/elf/tst-tls-ie-mod2.c b/elf/tst-tls-ie-mod2.c new file mode 100644 index 0000000000..70f8e81e05 --- /dev/null +++ b/elf/tst-tls-ie-mod2.c @@ -0,0 +1,4 @@ +#define N 2 +#define SIZE 48 +#define MODEL "global-dynamic" +#include "tst-tls-ie-mod.h" diff --git a/elf/tst-tls-ie-mod3.c b/elf/tst-tls-ie-mod3.c new file mode 100644 index 0000000000..5395f844a5 --- /dev/null +++ b/elf/tst-tls-ie-mod3.c @@ -0,0 +1,4 @@ +#define N 3 +#define SIZE 16 +#define MODEL "global-dynamic" +#include "tst-tls-ie-mod.h" diff --git a/elf/tst-tls-ie-mod4.c b/elf/tst-tls-ie-mod4.c new file mode 100644 index 0000000000..d6a1998d6d --- /dev/null +++ b/elf/tst-tls-ie-mod4.c @@ -0,0 +1,4 @@ +#define N 4 +#define SIZE 120 +#define MODEL "initial-exec" +#include "tst-tls-ie-mod.h" diff --git a/elf/tst-tls-ie-mod5.c b/elf/tst-tls-ie-mod5.c new file mode 100644 index 0000000000..3bb4dbcbfb --- /dev/null +++ b/elf/tst-tls-ie-mod5.c @@ -0,0 +1,4 @@ +#define N 5 +#define SIZE 8 +#define MODEL "initial-exec" +#include "tst-tls-ie-mod.h" diff --git a/elf/tst-tls-ie.c b/elf/tst-tls-ie.c new file mode 100644 index 0000000000..d17f1fc59e --- /dev/null +++ b/elf/tst-tls-ie.c @@ -0,0 +1,98 @@ +/* Test dlopen of modules with initial-exec TLS. + Copyright (C) 2016-2020 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +/* This test tries to ensure that at least 128 byte surplus TLS is + available for dlopening modules with initial-exec TLS. */ + +#include +#include +#include +#include +#include + +static int do_test (void); +#include +#include +#include + +/* Have some big TLS in the main exe: should not use surplus TLS. */ +__thread char maintls[1000]; + +static pthread_barrier_t barrier; + +/* Forces multi-threaded behaviour. */ +static void * +blocked_thread_func (void *closure) +{ + xpthread_barrier_wait (&barrier); + /* TLS load and access tests run here in the main thread. */ + xpthread_barrier_wait (&barrier); + return NULL; +} + +static void * +load_and_access (const char *mod, const char *func) +{ + /* Load module with TLS. */ + void *p = xdlopen (mod, RTLD_NOW); + /* Access the TLS variable to ensure it is allocated. */ + void (*f) (void) = (void (*) (void))xdlsym (p, func); + f (); + return p; +} + +static int +do_test (void) +{ + void *mods[6]; + + { + int ret = pthread_barrier_init (&barrier, NULL, 2); + if (ret != 0) + { + errno = ret; + printf ("error: pthread_barrier_init: %m\n"); + exit (1); + } + } + + pthread_t blocked_thread = xpthread_create (NULL, blocked_thread_func, NULL); + xpthread_barrier_wait (&barrier); + + printf ("maintls[%zu]:\t %p .. %p\n", + sizeof maintls, maintls, maintls + sizeof maintls); + memset (maintls, 1, sizeof maintls); + + /* Load modules with dynamic TLS (may use surplus TLS opportunistically). */ + mods[0] = load_and_access ("tst-tls-ie-mod0.so", "access0"); + mods[1] = load_and_access ("tst-tls-ie-mod1.so", "access1"); + mods[2] = load_and_access ("tst-tls-ie-mod2.so", "access2"); + mods[3] = load_and_access ("tst-tls-ie-mod3.so", "access3"); + /* Load modules with initial-exec TLS (can only use surplus TLS). */ + mods[4] = load_and_access ("tst-tls-ie-mod4.so", "access4"); + mods[5] = load_and_access ("tst-tls-ie-mod5.so", "access5"); + + xpthread_barrier_wait (&barrier); + xpthread_join (blocked_thread); + + /* Close the modules. */ + for (int i = 0; i < 6; ++i) + xdlclose (mods[i]); + + return 0; +} -- 2.17.1