summaryrefslogtreecommitdiff
path: root/rtld-Avoid-using-up-static-TLS-surplus-for-optimizat.patch
diff options
context:
space:
mode:
Diffstat (limited to 'rtld-Avoid-using-up-static-TLS-surplus-for-optimizat.patch')
-rw-r--r--rtld-Avoid-using-up-static-TLS-surplus-for-optimizat.patch586
1 files changed, 586 insertions, 0 deletions
diff --git a/rtld-Avoid-using-up-static-TLS-surplus-for-optimizat.patch b/rtld-Avoid-using-up-static-TLS-surplus-for-optimizat.patch
new file mode 100644
index 0000000..d70be0b
--- /dev/null
+++ b/rtld-Avoid-using-up-static-TLS-surplus-for-optimizat.patch
@@ -0,0 +1,586 @@
+From ffb17e7ba3a5ba9632cee97330b325072fbe41dd Mon Sep 17 00:00:00 2001
+From: Szabolcs Nagy <szabolcs.nagy@arm.com>
+Date: Wed, 10 Jun 2020 13:40:40 +0100
+Subject: [PATCH] rtld: Avoid using up static TLS surplus for optimizations [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 model TLS can only use surplus TLS.
+
+The new contract for surplus static TLS use is:
+
+- libc.so can have up to 192 bytes of IE TLS,
+- other system libraries together can have up to 144 bytes of IE TLS.
+- Some "optional" static TLS is available for opportunistic use.
+
+The optional TLS is now tunable: rtld.optional_static_tls, so users
+can directly affect the allocated static TLS size. (Note that module
+unloading with dlclose does not reclaim static TLS. After the optional
+TLS runs out, TLS access is no longer optimized to use static TLS.)
+
+The default setting of rtld.optional_static_tls is 512 so the surplus
+TLS is 3*192 + 4*144 + 512 = 1664 by default, the same as before.
+
+Fixes BZ #25051.
+
+Tested on aarch64-linux-gnu and x86_64-linux-gnu.
+
+Reviewed-by: Carlos O'Donell <carlos@redhat.com>
+---
+ csu/libc-tls.c | 3 ++
+ elf/Makefile | 29 +++++++++++-
+ elf/dl-reloc.c | 37 +++++++++++----
+ elf/dl-tls.c | 9 ++--
+ elf/dl-tunables.list | 5 ++
+ elf/dynamic-link.h | 5 +-
+ elf/tst-tls-ie-dlmopen.c | 112 +++++++++++++++++++++++++++++++++++++++++++++
+ 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-mod6.c | 4 ++
+ elf/tst-tls-ie.c | 111 ++++++++++++++++++++++++++++++++++++++++++++
+ manual/tunables.texi | 17 +++++++
+ sysdeps/generic/ldsodefs.h | 3 ++
+ 18 files changed, 382 insertions(+), 17 deletions(-)
+ create mode 100644 elf/tst-tls-ie-dlmopen.c
+ 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-mod6.c
+ create mode 100644 elf/tst-tls-ie.c
+
+diff --git a/csu/libc-tls.c b/csu/libc-tls.c
+index 28a7944..1b68d71 100644
+--- a/csu/libc-tls.c
++++ b/csu/libc-tls.c
+@@ -59,6 +59,9 @@ size_t _dl_tls_static_size = 2048;
+ size_t _dl_tls_static_used;
+ /* Alignment requirement of the static TLS block. */
+ size_t _dl_tls_static_align;
++/* Remaining amount of static TLS that may be used for optimizing
++ dynamic TLS access (e.g. with TLSDESC). */
++size_t _dl_tls_static_optional = 512;
+
+ /* Generation counter for the dtv. */
+ size_t _dl_tls_generation;
+diff --git a/elf/Makefile b/elf/Makefile
+index 632a4d8..f440488 100644
+--- a/elf/Makefile
++++ b/elf/Makefile
+@@ -201,7 +201,8 @@ tests += restest1 preloadtest loadfail multiload origtest resolvfail \
+ 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-dlopenfail-2
++ tst-dlopenfail-2 \
++ tst-tls-ie tst-tls-ie-dlmopen
+ # reldep9
+ tests-internal += loadtest unload unload2 circleload1 \
+ neededtest neededtest2 neededtest3 neededtest4 \
+@@ -312,7 +313,10 @@ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \
+ tst-auditmanymod7 tst-auditmanymod8 tst-auditmanymod9 \
+ tst-initlazyfailmod tst-finilazyfailmod \
+ tst-dlopenfailmod1 tst-dlopenfaillinkmod tst-dlopenfailmod2 \
+- tst-dlopenfailmod3 tst-ldconfig-ld-mod
++ tst-dlopenfailmod3 tst-ldconfig-ld-mod \
++ tst-tls-ie-mod0 tst-tls-ie-mod1 tst-tls-ie-mod2 \
++ tst-tls-ie-mod3 tst-tls-ie-mod4 tst-tls-ie-mod5 \
++ tst-tls-ie-mod6
+ # 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%,\
+@@ -1699,3 +1703,23 @@ LDFLAGS-tst-dlopen-nodelete-reloc-mod17.so = -Wl,--no-as-needed
+
+ $(objpfx)tst-ldconfig-ld_so_conf-update.out: $(objpfx)tst-ldconfig-ld-mod.so
+ $(objpfx)tst-ldconfig-ld_so_conf-update: $(libdl)
++
++$(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 \
++ $(objpfx)tst-tls-ie-mod6.so
++
++$(objpfx)tst-tls-ie-dlmopen: $(libdl) $(shared-thread-library)
++$(objpfx)tst-tls-ie-dlmopen.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 \
++ $(objpfx)tst-tls-ie-mod6.so
+diff --git a/elf/dl-reloc.c b/elf/dl-reloc.c
+index ffcc84d..6d32e49 100644
+--- a/elf/dl-reloc.c
++++ b/elf/dl-reloc.c
+@@ -39,13 +39,16 @@
+ /* 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.
+- 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. */
++ object's TLS segment is too big to fit, we fail with -1. If it fits,
++ we set MAP->l_tls_offset and return 0.
++ A portion of the surplus static TLS can be optionally used to optimize
++ dynamic TLS access (with TLSDESC or powerpc TLS optimizations).
++ If OPTIONAL is true then TLS is allocated for such optimization and
++ the caller must have a fallback in case the optional portion of surplus
++ TLS runs out. If OPTIONAL is false then the entire surplus TLS area is
++ considered and the allocation only fails if that runs out. */
+ int
+-_dl_try_allocate_static_tls (struct link_map *map)
++_dl_try_allocate_static_tls (struct link_map *map, bool optional)
+ {
+ /* If we've already used the variable with dynamic access, or if the
+ alignment requirements are too high, fail. */
+@@ -68,8 +71,14 @@ _dl_try_allocate_static_tls (struct link_map *map)
+
+ size_t n = (freebytes - blsize) / map->l_tls_align;
+
+- size_t offset = GL(dl_tls_static_used) + (freebytes - n * map->l_tls_align
+- - map->l_tls_firstbyte_offset);
++ /* Account optional static TLS surplus usage. */
++ size_t use = freebytes - n * map->l_tls_align - map->l_tls_firstbyte_offset;
++ if (optional && use > GL(dl_tls_static_optional))
++ goto fail;
++ else if (optional)
++ GL(dl_tls_static_optional) -= use;
++
++ size_t offset = GL(dl_tls_static_used) + use;
+
+ map->l_tls_offset = GL(dl_tls_static_used) = offset;
+ #elif TLS_DTV_AT_TP
+@@ -83,6 +92,13 @@ _dl_try_allocate_static_tls (struct link_map *map)
+ if (used > GL(dl_tls_static_size))
+ goto fail;
+
++ /* Account optional static TLS surplus usage. */
++ size_t use = used - GL(dl_tls_static_used);
++ if (optional && use > GL(dl_tls_static_optional))
++ goto fail;
++ else if (optional)
++ GL(dl_tls_static_optional) -= use;
++
+ map->l_tls_offset = offset;
+ map->l_tls_firstbyte_offset = GL(dl_tls_static_used);
+ GL(dl_tls_static_used) = used;
+@@ -110,12 +126,15 @@ _dl_try_allocate_static_tls (struct link_map *map)
+ return 0;
+ }
+
++/* 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. */
+ 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, false))
+ {
+ _dl_signal_error (0, map->l_name, NULL, N_("\
+ cannot allocate memory in static TLS block"));
+diff --git a/elf/dynamic-link.h b/elf/dynamic-link.h
+index bb7a66f..6727233 100644
+--- a/elf/dynamic-link.h
++++ b/elf/dynamic-link.h
+@@ -40,9 +40,10 @@
+ (__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, true) == 0))
+
+-int _dl_try_allocate_static_tls (struct link_map *map) attribute_hidden;
++int _dl_try_allocate_static_tls (struct link_map *map, bool optional)
++ attribute_hidden;
+
+ #include <elf.h>
+
+diff --git a/elf/tst-tls-ie-dlmopen.c b/elf/tst-tls-ie-dlmopen.c
+new file mode 100644
+index 0000000..c7b5c68
+--- /dev/null
++++ b/elf/tst-tls-ie-dlmopen.c
+@@ -0,0 +1,112 @@
++/* Test dlopen of modules with initial-exec TLS after dlmopen.
++ 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
++ <https://www.gnu.org/licenses/>. */
++
++/* This test tries to check that surplus static TLS is not used up for
++ dynamic TLS optimizations and 4*144 = 576 bytes of static TLS is
++ still available for dlopening modules with initial-exec TLS after 3
++ new dlmopen namespaces are created. It depends on rtld.nns=4 and
++ rtld.optional_static_tls=512 tunable settings. */
++
++#include <errno.h>
++#include <pthread.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++
++static int do_test (void);
++#include <support/xthread.h>
++#include <support/xdlfcn.h>
++#include <support/check.h>
++#include <support/test-driver.c>
++
++/* 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 (Lmid_t lmid, const char *mod, const char *func)
++{
++ /* Load module with TLS. */
++ void *p = xdlmopen (lmid, 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[5];
++
++ {
++ 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 (use surplus static TLS for libc
++ in new namespaces and may be for TLS optimizations too). */
++ mods[0] = load_and_access (LM_ID_BASE, "tst-tls-ie-mod0.so", "access0");
++ mods[1] = load_and_access (LM_ID_NEWLM, "tst-tls-ie-mod1.so", "access1");
++ mods[2] = load_and_access (LM_ID_NEWLM, "tst-tls-ie-mod2.so", "access2");
++ mods[3] = load_and_access (LM_ID_NEWLM, "tst-tls-ie-mod3.so", "access3");
++ /* Load modules with initial-exec TLS (can only use surplus static TLS). */
++ mods[4] = load_and_access (LM_ID_BASE, "tst-tls-ie-mod6.so", "access6");
++
++ /* Here 576 bytes + 3 * libc use of surplus static TLS is in use so less
++ than 1024 bytes are available (exact number depends on TLS optimizations
++ and the libc TLS use). */
++ printf ("The next dlmopen should fail...\n");
++ void *p = dlmopen (LM_ID_BASE, "tst-tls-ie-mod4.so", RTLD_NOW);
++ if (p != NULL)
++ FAIL_EXIT1 ("error: expected dlmopen to fail because there is "
++ "not enough surplus static TLS.\n");
++ printf ("...OK failed with: %s.\n", dlerror ());
++
++ xpthread_barrier_wait (&barrier);
++ xpthread_join (blocked_thread);
++
++ /* Close the modules. */
++ for (int i = 0; i < 5; ++i)
++ xdlclose (mods[i]);
++
++ return 0;
++}
+diff --git a/elf/tst-tls-ie-mod.h b/elf/tst-tls-ie-mod.h
+new file mode 100644
+index 0000000..46b362a
+--- /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
++ <https://www.gnu.org/licenses/>. */
++
++/* This file is parameterized by macros N, SIZE and MODEL. */
++
++#include <stdio.h>
++#include <string.h>
++
++#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 0000000..2450686
+--- /dev/null
++++ b/elf/tst-tls-ie-mod0.c
+@@ -0,0 +1,4 @@
++#define N 0
++#define SIZE 480
++#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 0000000..849ff91
+--- /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 0000000..23915ab
+--- /dev/null
++++ b/elf/tst-tls-ie-mod2.c
+@@ -0,0 +1,4 @@
++#define N 2
++#define SIZE 24
++#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 0000000..5395f84
+--- /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 0000000..93ac2ea
+--- /dev/null
++++ b/elf/tst-tls-ie-mod4.c
+@@ -0,0 +1,4 @@
++#define N 4
++#define SIZE 1024
++#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 0000000..84b3fd2
+--- /dev/null
++++ b/elf/tst-tls-ie-mod5.c
+@@ -0,0 +1,4 @@
++#define N 5
++#define SIZE 128
++#define MODEL "initial-exec"
++#include "tst-tls-ie-mod.h"
+diff --git a/elf/tst-tls-ie-mod6.c b/elf/tst-tls-ie-mod6.c
+new file mode 100644
+index 0000000..c736bf0
+--- /dev/null
++++ b/elf/tst-tls-ie-mod6.c
+@@ -0,0 +1,4 @@
++#define N 6
++#define SIZE 576
++#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 0000000..2dc0894
+--- /dev/null
++++ b/elf/tst-tls-ie.c
+@@ -0,0 +1,111 @@
++/* 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
++ <https://www.gnu.org/licenses/>. */
++
++/* This test tries to check that surplus static TLS is not used up for
++ dynamic TLS optimizations and 3*192 + 4*144 = 1152 bytes of static
++ TLS is available for dlopening modules with initial-exec TLS. It
++ depends on rtld.nns=4 and rtld.optional_static_tls=512 tunable setting. */
++
++#include <errno.h>
++#include <pthread.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++
++static int do_test (void);
++#include <support/xthread.h>
++#include <support/xdlfcn.h>
++#include <support/check.h>
++#include <support/test-driver.c>
++
++/* 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 static 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 static TLS). */
++ mods[4] = load_and_access ("tst-tls-ie-mod4.so", "access4");
++ mods[5] = load_and_access ("tst-tls-ie-mod5.so", "access5");
++
++ /* Here 1152 bytes of surplus static TLS is in use and at most 512 bytes
++ are available (depending on TLS optimizations). */
++ printf ("The next dlopen should fail...\n");
++ void *p = dlopen ("tst-tls-ie-mod6.so", RTLD_NOW);
++ if (p != NULL)
++ FAIL_EXIT1 ("error: expected dlopen to fail because there is "
++ "not enough surplus static TLS.\n");
++ printf ("...OK failed with: %s.\n", dlerror ());
++
++ xpthread_barrier_wait (&barrier);
++ xpthread_join (blocked_thread);
++
++ /* Close the modules. */
++ for (int i = 0; i < 6; ++i)
++ xdlclose (mods[i]);
++
++ return 0;
++}
+diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h
+index eb3ef5b..ba114ab 100644
+--- a/sysdeps/generic/ldsodefs.h
++++ b/sysdeps/generic/ldsodefs.h
+@@ -442,6 +442,9 @@ struct rtld_global
+ EXTERN size_t _dl_tls_static_used;
+ /* Alignment requirement of the static TLS block. */
+ EXTERN size_t _dl_tls_static_align;
++ /* Remaining amount of static TLS that may be used for optimizing
++ dynamic TLS access (e.g. with TLSDESC). */
++ EXTERN size_t _dl_tls_static_optional;
+
+ /* Number of additional entries in the slotinfo array of each slotinfo
+ list element. A large number makes it almost certain take we never
+--
+1.8.3.1
+