[v3,1/1] rtld: add glibc.rtld.optional_static_tls_alignment

Message ID 202609112221.68BMLlHb2750232@greed.delorie.com (mailing list archive)
State Under Review
Delegated to: Florian Weimer
Headers
Series [v3,1/1] rtld: add glibc.rtld.optional_static_tls_alignment |

Checks

Context Check Description
redhat-pt-bot/TryBot-apply_patch success Patch applied to master at the time it was sent
redhat-pt-bot/TryBot-32bit success Build for i686
linaro-tcwg-bot/tcwg_glibc_build--master-arm success Build passed
linaro-tcwg-bot/tcwg_glibc_build--master-aarch64 success Build passed
linaro-tcwg-bot/tcwg_glibc_check--master-aarch64 fail Test failed
linaro-tcwg-bot/tcwg_glibc_check--master-arm success Test passed

Commit Message

DJ Delorie Sept. 11, 2026, 10:19 p.m. UTC
  Add an alignment tunable to go along with glibc.rtld.optional_static_tls
to optimize loading audit modules with higher-than-default alignment
requirements.  Unlike the extra size, this is only used when creating
the TLS area so need not be stored in GLRO().
---
changes in v3:
  - renamed test
  - random style cleanups
  - comment optional_static_tls_alignment variable
  - ignore invalid alignments
  - make tdata1 volatile
  - tweak documentation
  - fix list-tunables test
changes in v2:
  - add the other tls case type for adding extra alignment

 elf/Makefile                        |  7 ++++
 elf/dl-tls.c                        | 15 +++++++++
 elf/dl-tunables.list                |  5 +++
 elf/tst-rtld-list-tunables.exp      |  1 +
 elf/tst-tlsalign-tunable-auditmod.c | 52 +++++++++++++++++++++++++++++
 elf/tst-tlsalign-tunable.c          | 39 ++++++++++++++++++++++
 manual/tunables.texi                |  7 ++++
 7 files changed, 126 insertions(+)
 create mode 100644 elf/tst-tlsalign-tunable-auditmod.c
 create mode 100644 elf/tst-tlsalign-tunable.c
  

Patch

diff --git a/elf/Makefile b/elf/Makefile
index b0f594f5b3..151ed6ed35 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -311,6 +311,7 @@  tests-container := \
   tst-dl-cache-old-format \
   tst-ldconfig-bad-aux-cache \
   tst-ldconfig-ld_so_conf-update \
+  tst-tlsalign-tunable \
   # tests-container
 
 ifeq (no,$(build-hardcoded-path-in-tests))
@@ -1093,6 +1094,7 @@  modules-names += \
   tst-tls22-mod2-gnu2 \
   tst-tls23-mod \
   tst-tlsalign-lib \
+  tst-tlsalign-tunable-auditmod \
   tst-tlsgap-mod0 \
   tst-tlsgap-mod1 \
   tst-tlsgap-mod2 \
@@ -1846,6 +1848,11 @@  $(objpfx)tst-nodelete-opened.out: $(objpfx)tst-nodelete-opened-lib.so
 $(objpfx)tst-tlsalign-extern: $(objpfx)tst-tlsalign-vars.o
 $(objpfx)tst-tlsalign-extern-static: $(objpfx)tst-tlsalign-vars.o
 
+tst-tlsalign-tunable-TUNABLES = glibc.rtld.optional_static_tls_alignment=0x1000
+tst-tlsalign-tunable-TUNABLES += glibc.rtld.optional_static_tls=0x3000
+tst-tlsalign-tunable-ENV = LD_AUDIT=$(objpfx)tst-tlsalign-tunable-auditmod.so
+$(objpfx)tst-tlsalign-tunable.out: $(objpfx)tst-tlsalign-tunable-auditmod.so
+
 # The resolver translation unit must always be compiled with
 # -fstack-protector-all so the canary code is emitted regardless of the
 # default.
diff --git a/elf/dl-tls.c b/elf/dl-tls.c
index f2a99e8edb..31b26fe8d3 100644
--- a/elf/dl-tls.c
+++ b/elf/dl-tls.c
@@ -126,6 +126,11 @@  tls_static_surplus (int nns, int opt_tls)
    backwards compatibility.  */
 #define LEGACY_TLS (1664 - tls_static_surplus (DEFAULT_NNS, OPTIONAL_TLS))
 
+/* This value is set from the glibc.rtld.optional_static_tls_alignment
+   tunable, and sets an additional minimum alignment on the TLS
+   data.  */
+static size_t optional_static_tls_alignment = 0;
+
 /* Calculate the size of the static TLS surplus, when the given
    number of audit modules are loaded.  Must be called after the
    number of audit modules is known and before static TLS allocation.  */
@@ -136,6 +141,10 @@  _dl_tls_static_surplus_init (size_t naudit)
 
   nns = TUNABLE_GET (nns, size_t, NULL);
   opt_tls = TUNABLE_GET (optional_static_tls, size_t, NULL);
+  optional_static_tls_alignment = TUNABLE_GET (optional_static_tls_alignment, size_t, NULL);
+  /* Ignore invalid requests.  */
+  if (! powerof2 (optional_static_tls_alignment))
+    optional_static_tls_alignment = 0;
   if (nns > DL_NNS)
     nns = DL_NNS;
   if (DL_NNS - nns < naudit)
@@ -346,6 +355,9 @@  _dl_determine_tlsoffset (void)
   size_t extra_tls_size = _dl_extra_tls_get_size ();
   size_t extra_tls_align = _dl_extra_tls_get_align ();
 
+  /* Apply any user-specified alignment, if larger.  */
+  extra_tls_align = MAX (extra_tls_align, optional_static_tls_alignment);
+
   /* Increase the maximum alignment with the extra TLS alignment requirements
      if necessary.  */
   max_align = MAX (max_align, extra_tls_align);
@@ -426,6 +438,9 @@  _dl_determine_tlsoffset (void)
   size_t extra_tls_size = _dl_extra_tls_get_size ();
   size_t extra_tls_align = _dl_extra_tls_get_align ();
 
+  /* Apply any user-specified alignment, if larger.  */
+  extra_tls_align = MAX (extra_tls_align, optional_static_tls_alignment);
+
   /* Increase the maximum alignment with the extra TLS alignment requirements
      if necessary.  */
   max_align = MAX (max_align, extra_tls_align);
diff --git a/elf/dl-tunables.list b/elf/dl-tunables.list
index 111649f145..4c78444542 100644
--- a/elf/dl-tunables.list
+++ b/elf/dl-tunables.list
@@ -101,6 +101,11 @@  glibc {
       minval: 0
       default: 512
     }
+    optional_static_tls_alignment {
+      type: SIZE_T
+      minval: 0
+      default: 0
+    }
     enable_secure {
       type: INT_32
       minval: 0
diff --git a/elf/tst-rtld-list-tunables.exp b/elf/tst-rtld-list-tunables.exp
index 9590021f3a..17520d6b31 100644
--- a/elf/tst-rtld-list-tunables.exp
+++ b/elf/tst-rtld-list-tunables.exp
@@ -15,3 +15,4 @@  glibc.rtld.enable_secure: 0 (min: 0, max: 1)
 glibc.rtld.execstack: 1 (min: 0, max: 2)
 glibc.rtld.nns: 0x4 (min: 0x1, max: 0x10)
 glibc.rtld.optional_static_tls: 0x200 (min: 0x0, max: 0x[f]+)
+glibc.rtld.optional_static_tls_alignment: 0x0 (min: 0x0, max: 0x[f]+)
diff --git a/elf/tst-tlsalign-tunable-auditmod.c b/elf/tst-tlsalign-tunable-auditmod.c
new file mode 100644
index 0000000000..e6f6c23652
--- /dev/null
+++ b/elf/tst-tlsalign-tunable-auditmod.c
@@ -0,0 +1,52 @@ 
+/* Test for large alignment in TLS blocks, BZ#1838, audit module.
+   Copyright (C) 2020-2026 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/>.  */
+
+#include <unistd.h>
+
+__thread int x;
+__thread int b[4]
+  __attribute__ ((tls_model("initial-exec")))
+  __attribute__ ((aligned(0x1000)));
+
+/* These exist just to make the above variables "used".  */
+int *
+func_x (void)
+{
+  return &x;
+}
+
+int *
+func_b (void)
+{
+  return b;
+}
+
+void __attribute__ ((constructor))
+la_ctor (void)
+{
+  write (1, "AUDITctor\n", 10);
+  /* We only care if the auditor got loaded.  It doesn't need to
+     run.  */
+  _exit (0);
+}
+
+unsigned int
+la_version (unsigned int version)
+{
+  return version;
+}
diff --git a/elf/tst-tlsalign-tunable.c b/elf/tst-tlsalign-tunable.c
new file mode 100644
index 0000000000..eb98e6e912
--- /dev/null
+++ b/elf/tst-tlsalign-tunable.c
@@ -0,0 +1,39 @@ 
+/* Test for large alignment in TLS blocks, BZ#18383.
+   Copyright (C) 2015-2026 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 specifically tests that the
+   glibc.rtld.optional_static_tls_alignment tunable works, by loading
+   an audit module that can't load without alignment help.  */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+static volatile __thread int tdata1 = 1;
+
+static int
+do_test (void)
+{
+  printf("tst-tlsalign-tunable!\n");
+  /* If the test passes, the auditor itself will call exit with a
+     value of 0.  If we get here, we've failed.  "Use" tdata1 here
+     too.  */
+  return tdata1 ? EXIT_FAILURE : 43;
+}
+
+#include <support/test-driver.c>
diff --git a/manual/tunables.texi b/manual/tunables.texi
index 9052c56d9b..845ff6d5db 100644
--- a/manual/tunables.texi
+++ b/manual/tunables.texi
@@ -422,6 +422,13 @@  changed once allocated at process startup.  The default allocation of
 optional static TLS is 512 bytes and is allocated in every thread.
 @end deftp
 
+@deftp Tunable glibc.rtld.optional_static_tls_alignment
+Sets a minimum alignment for the static TLS.  The loader normally uses
+the alignment requirements of shared objects, but this might be needed
+for (for example) audit modules that have a higher-than-default
+alignment requirement.
+@end deftp
+
 @deftp Tunable glibc.rtld.dynamic_sort
 Sets the algorithm to use for DSO sorting, valid values are @samp{1} and
 @samp{2}.  For value of @samp{1}, an older O(n^3) algorithm is used, which is