summary refs log tree commit diff
path: root/elf
diff options
context:
space:
mode:
authorSzabolcs Nagy <szabolcs.nagy@arm.com>2020-06-09 09:57:28 +0100
committerSzabolcs Nagy <szabolcs.nagy@arm.com>2020-07-08 17:32:56 +0100
commit0c7b002fac12dcb2f53ba83ee56bb3b5d2439447 (patch)
treecc07f5e054d4aefa382ceeacd458c06fc4205169 /elf
parentae7a94e5e3edf78f4da562edc05ece229614c716 (diff)
downloadglibc-0c7b002fac12dcb2f53ba83ee56bb3b5d2439447.tar.gz
glibc-0c7b002fac12dcb2f53ba83ee56bb3b5d2439447.tar.xz
glibc-0c7b002fac12dcb2f53ba83ee56bb3b5d2439447.zip
rtld: Add rtld.nns tunable for the number of supported namespaces
TLS_STATIC_SURPLUS is 1664 bytes currently which is not enough to
support DL_NNS (== 16) number of dynamic link namespaces, if we
assume 192 bytes of TLS are reserved for libc use and 144 bytes
are reserved for other system libraries that use IE TLS.

A new tunable is introduced to control the number of supported
namespaces and to adjust the surplus static TLS size as follows:

surplus_tls = 192 * (rtld.nns-1) + 144 * rtld.nns + 512

The default is rtld.nns == 4 and then the surplus TLS size is the
same as before, so the behaviour is unchanged by default. If an
application creates more namespaces than the rtld.nns setting
allows, then it is not guaranteed to work, but the limit is not
checked. So existing usage will continue to work, but in the
future if an application creates more than 4 dynamic link
namespaces then the tunable will need to be set.

In this patch DL_NNS is a fixed value and provides a maximum to
the rtld.nns setting.

Static linking used fixed 2048 bytes surplus TLS, this is changed
so the same contract is used as for dynamic linking.  With static
linking DL_NNS == 1 so rtld.nns tunable is forced to 1, so by
default the surplus TLS is reduced to 144 + 512 = 656 bytes. This
change is not expected to cause problems.

Tested on aarch64-linux-gnu and x86_64-linux-gnu.

Reviewed-by: Carlos O'Donell <carlos@redhat.com>
Diffstat (limited to 'elf')
-rw-r--r--elf/dl-tls.c55
-rw-r--r--elf/dl-tunables.list9
-rw-r--r--elf/rtld.c3
3 files changed, 62 insertions, 5 deletions
diff --git a/elf/dl-tls.c b/elf/dl-tls.c
index ca13778ca9..924ee5d989 100644
--- a/elf/dl-tls.c
+++ b/elf/dl-tls.c
@@ -29,10 +29,54 @@
 #include <dl-tls.h>
 #include <ldsodefs.h>
 
-/* Amount of excess space to allocate in the static TLS area
-   to allow dynamic loading of modules defining IE-model TLS data.  */
-#define TLS_STATIC_SURPLUS	64 + DL_NNS * 176
+#define TUNABLE_NAMESPACE rtld
+#include <dl-tunables.h>
+
+/* Surplus static TLS, GLRO(dl_tls_static_surplus), is used for
+
+   - IE TLS in libc.so for all dlmopen namespaces except in the initial
+     one where libc.so is not loaded dynamically but at startup time,
+   - IE TLS in other libraries which may be dynamically loaded even in the
+     initial namespace,
+   - and optionally for optimizing dynamic TLS access.
+
+   The maximum number of namespaces is DL_NNS, but to support that many
+   namespaces correctly the static TLS allocation should be significantly
+   increased, which may cause problems with small thread stacks due to the
+   way static TLS is accounted (bug 11787).
+
+   So there is a rtld.nns tunable limit on the number of supported namespaces
+   that affects the size of the static TLS and by default it's small enough
+   not to cause problems with existing applications. The limit is not
+   enforced or checked: it is the user's responsibility to increase rtld.nns
+   if more dlmopen namespaces are used.  */
+
+/* Size of initial-exec TLS in libc.so.  */
+#define LIBC_IE_TLS 192
+/* Size of initial-exec TLS in libraries other than libc.so.
+   This should be large enough to cover runtime libraries of the
+   compiler such as libgomp and libraries in libc other than libc.so.  */
+#define OTHER_IE_TLS 144
+/* Size of additional surplus TLS, placeholder for TLS optimizations.  */
+#define OPT_SURPLUS_TLS 512
 
+void
+_dl_tls_static_surplus_init (void)
+{
+  size_t nns;
+
+#if HAVE_TUNABLES
+  nns = TUNABLE_GET (nns, size_t, NULL);
+#else
+  /* Default values of the tunables.  */
+  nns = 4;
+#endif
+  if (nns > DL_NNS)
+    nns = DL_NNS;
+  GLRO(dl_tls_static_surplus) = ((nns - 1) * LIBC_IE_TLS
+				 + nns * OTHER_IE_TLS
+				 + OPT_SURPLUS_TLS);
+}
 
 /* Out-of-memory handler.  */
 static void
@@ -224,7 +268,8 @@ _dl_determine_tlsoffset (void)
     }
 
   GL(dl_tls_static_used) = offset;
-  GL(dl_tls_static_size) = (roundup (offset + TLS_STATIC_SURPLUS, max_align)
+  GL(dl_tls_static_size) = (roundup (offset + GLRO(dl_tls_static_surplus),
+				     max_align)
 			    + TLS_TCB_SIZE);
 #elif TLS_DTV_AT_TP
   /* The TLS blocks start right after the TCB.  */
@@ -268,7 +313,7 @@ _dl_determine_tlsoffset (void)
     }
 
   GL(dl_tls_static_used) = offset;
-  GL(dl_tls_static_size) = roundup (offset + TLS_STATIC_SURPLUS,
+  GL(dl_tls_static_size) = roundup (offset + GLRO(dl_tls_static_surplus),
 				    TLS_TCB_ALIGN);
 #else
 # error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
diff --git a/elf/dl-tunables.list b/elf/dl-tunables.list
index 0d398dd251..b07742d7b3 100644
--- a/elf/dl-tunables.list
+++ b/elf/dl-tunables.list
@@ -126,4 +126,13 @@ glibc {
       default: 3
     }
   }
+
+  rtld {
+    nns {
+      type: SIZE_T
+      minval: 1
+      maxval: 16
+      default: 4
+    }
+  }
 }
diff --git a/elf/rtld.c b/elf/rtld.c
index f4c2602d65..f339f6894f 100644
--- a/elf/rtld.c
+++ b/elf/rtld.c
@@ -780,6 +780,9 @@ init_tls (void)
       }
   assert (i == GL(dl_tls_max_dtv_idx));
 
+  /* Calculate the size of the static TLS surplus.  */
+  _dl_tls_static_surplus_init ();
+
   /* Compute the TLS offsets for the various blocks.  */
   _dl_determine_tlsoffset ();