[PATCH v10] elf: Add test for THP alignment of large load segments

H.J. Lu hjl.tools@gmail.com
Fri Apr 17 04:23:23 GMT 2026


On Fri, Apr 17, 2026 at 11:56 AM WANG Rui <wangrui@loongson.cn> wrote:
>
> Add a new test to verify that large executable PT_LOAD segments are
> mapped at addresses aligned to the THP size when the glibc tunable
> glibc.elf.thp=1 is enabled and the system is configured to use THP
> in "always" mode.
>
> The test loads a shared object with a sufficiently large executable
> segment via dlopen and inspects /proc/self/maps to check that the
> mapping address is aligned to the THP page size reported by the kernel.
>
> The test is skipped if the THP size cannot be determined or if THP is
> not enabled in "always" mode.
>
> Signed-off-by: WANG Rui <wangrui@loongson.cn>

I'd like to combine your test change with my patch to enable
THP segment load with madvise enabled THP:

https://patchwork.sourceware.org/project/glibc/list/?series=59892

Can you provide feedback on my patch?

Thanks.

> ---
> Changes since [v9]:
>   * Use FAIL_UNSUPPORTED instead of printf.
>   * Skip tests when THP size exceeds MAX_THP_PAGESIZE.
>   * Add dependency of tst-thp-align on tst-thp-size-mod.
>   * Rebase onto current master.
>
> [v9]: https://sourceware.org/pipermail/libc-alpha/2026-April/176598.html
> ---
>  sysdeps/unix/sysv/linux/Makefile           |   5 +
>  sysdeps/unix/sysv/linux/tst-thp-align.c    | 155 +++++++++++++++++++++
>  sysdeps/unix/sysv/linux/tst-thp-size-mod.S |  22 +++
>  3 files changed, 182 insertions(+)
>  create mode 100644 sysdeps/unix/sysv/linux/tst-thp-align.c
>  create mode 100644 sysdeps/unix/sysv/linux/tst-thp-size-mod.S
>
> diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile
> index b06afbdeaab..0d47e9af57e 100644
> --- a/sysdeps/unix/sysv/linux/Makefile
> +++ b/sysdeps/unix/sysv/linux/Makefile
> @@ -698,6 +698,7 @@ $(objpfx)pldd: $(objpfx)xmalloc.o
>  tests += \
>    tst-rseq-tls-range \
>    tst-rseq-tls-range-4096 \
> +  tst-thp-align \
>  # tests
>  tests-static += \
>    tst-rseq-tls-range-4096-static \
> @@ -705,17 +706,21 @@ tests-static += \
>  # tests-static
>  modules-names += \
>    tst-rseq-tls-range-mod \
> +  tst-thp-size-mod \
>  # modules-names
>  CFLAGS-tst-rseq-tls-range.c += -DMAIN_TLS_ALIGN=4
>  CFLAGS-tst-rseq-tls-range-4096.c += -DMAIN_TLS_ALIGN=4096
>  CFLAGS-tst-rseq-tls-range-static.c += -DMAIN_TLS_ALIGN=4
>  CFLAGS-tst-rseq-tls-range-4096-static.c += -DMAIN_TLS_ALIGN=4096
> +LDFLAGS-tst-thp-size-mod.so += -Wl,-z,noseparate-code
>  $(objpfx)tst-rseq-tls-range.out: $(objpfx)tst-rseq-tls-range-mod.so
>  $(objpfx)tst-rseq-tls-range-4096.out: $(objpfx)tst-rseq-tls-range-mod.so
>  $(objpfx)tst-rseq-tls-range-static.out: $(objpfx)tst-rseq-tls-range-mod.so
>  $(objpfx)tst-rseq-tls-range-4096-static.out: $(objpfx)tst-rseq-tls-range-mod.so
> +$(objpfx)tst-thp-align.out: $(objpfx)tst-thp-size-mod.so
>  tst-rseq-tls-range-static-ENV = LD_LIBRARY_PATH=$(objpfx):$(common-objpfx)
>  tst-rseq-tls-range-4096-static-ENV = LD_LIBRARY_PATH=$(objpfx):$(common-objpfx)
> +tst-thp-align-ENV = GLIBC_TUNABLES=glibc.elf.thp=1
>
>  test-internal-extras += tst-nolink-libc
>  ifeq ($(run-built-tests),yes)
> diff --git a/sysdeps/unix/sysv/linux/tst-thp-align.c b/sysdeps/unix/sysv/linux/tst-thp-align.c
> new file mode 100644
> index 00000000000..0b3f18e000f
> --- /dev/null
> +++ b/sysdeps/unix/sysv/linux/tst-thp-align.c
> @@ -0,0 +1,155 @@
> +/* Test the THP compatible alignment of PT_LOAD segments.
> +
> +   Copyright (C) 2026 Free Software Foundation, Inc.
> +
> +   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 <fcntl.h>
> +#include <stdint.h>
> +#include <stdlib.h>
> +#include <string.h>
> +#include <intprops.h>
> +#include <inttypes.h>
> +#include <support/check.h>
> +#include <support/xdlfcn.h>
> +#include <support/xstdio.h>
> +#include <support/xunistd.h>
> +
> +#define THP_SIZE_MOD_NAME "tst-thp-size-mod.so"
> +#define MAX_THP_PAGESIZE (32 * 1024 * 1024)
> +
> +enum thp_mode_t
> +{
> +  thp_mode_always,
> +  thp_mode_madvise,
> +  thp_mode_never,
> +  thp_mode_not_supported
> +};
> +
> +static unsigned long int
> +get_thp_size (void)
> +{
> +  int fd = open ("/sys/kernel/mm/transparent_hugepage/hpage_pmd_size",
> +                 O_RDONLY, 0);
> +  if (fd == -1)
> +    return 0;
> +
> +  char str[INT_BUFSIZE_BOUND (unsigned long int)];
> +  ssize_t s = read (fd, str, sizeof (str));
> +  close (fd);
> +  if (s < 0)
> +    return 0;
> +
> +  unsigned long int r = 0;
> +  for (ssize_t i = 0; i < s; i++)
> +    {
> +      if (str[i] == '\n')
> +    break;
> +      r *= 10;
> +      r += str[i] - '0';
> +    }
> +  return r;
> +}
> +
> +static enum thp_mode_t
> +get_thp_mode (void)
> +{
> +  int fd = open ("/sys/kernel/mm/transparent_hugepage/enabled", O_RDONLY, 0);
> +  if (fd == -1)
> +    return thp_mode_not_supported;
> +
> +  static const char mode_always[]  = "[always] madvise never\n";
> +  static const char mode_madvise[] = "always [madvise] never\n";
> +  static const char mode_never[]   = "always madvise [never]\n";
> +
> +  char str[sizeof(mode_always)];
> +  ssize_t s = read (fd, str, sizeof (str));
> +  if (s >= sizeof str || s < 0)
> +    return thp_mode_not_supported;
> +  str[s] = '\0';
> +  close (fd);
> +
> +  if (s == sizeof (mode_always) - 1)
> +    {
> +      if (strcmp (str, mode_always) == 0)
> +    return thp_mode_always;
> +      else if (strcmp (str, mode_madvise) == 0)
> +    return thp_mode_madvise;
> +      else if (strcmp (str, mode_never) == 0)
> +    return thp_mode_never;
> +    }
> +  return thp_mode_not_supported;
> +}
> +
> +static void
> +check_align (void)
> +{
> +  unsigned long int thp_size = get_thp_size ();
> +  enum thp_mode_t thp_mode = get_thp_mode ();
> +
> +  if (thp_size == 0)
> +    {
> +      FAIL_UNSUPPORTED ("unable to get THP size.\n");
> +      return;
> +    }
> +
> +  if (thp_size > MAX_THP_PAGESIZE)
> +    {
> +      FAIL_UNSUPPORTED ("THP size exceeds MAX_THP_PAGESIZE.\n");
> +      return;
> +    }
> +
> +  if (thp_mode != thp_mode_always)
> +    {
> +      FAIL_UNSUPPORTED ("THP mode is not always.\n");
> +      return;
> +    }
> +
> +  FILE *f = xfopen ("/proc/self/maps", "r");
> +  char *line = NULL;
> +  size_t len;
> +
> +  while (xgetline (&line, &len, f))
> +    {
> +      uintptr_t from, to;
> +      char *prot = NULL, *path = NULL;
> +      int r = sscanf (line, "%" SCNxPTR "-%" SCNxPTR "%ms%*s%*s%*s%ms",
> +                      &from, &to, &prot, &path);
> +
> +      TEST_VERIFY (r == 3 || r == 4);
> +
> +      if (strstr (prot, "x") && strstr (path, THP_SIZE_MOD_NAME))
> +        TEST_COMPARE (from % thp_size, 0);
> +
> +      free (path);
> +    }
> +
> +  free (line);
> +  xfclose (f);
> +}
> +
> +static int
> +do_test (void)
> +{
> +  void *dl;
> +
> +  dl = xdlopen (THP_SIZE_MOD_NAME, RTLD_NOW);
> +  check_align ();
> +  xdlclose (dl);
> +
> +  return 0;
> +}
> +
> +#include <support/test-driver.c>
> diff --git a/sysdeps/unix/sysv/linux/tst-thp-size-mod.S b/sysdeps/unix/sysv/linux/tst-thp-size-mod.S
> new file mode 100644
> index 00000000000..3084c2d0e2c
> --- /dev/null
> +++ b/sysdeps/unix/sysv/linux/tst-thp-size-mod.S
> @@ -0,0 +1,22 @@
> +/* A module that provides THP code size for testing.
> +
> +   Copyright (C) 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/>.  */
> +
> +    .globl thp_size
> +thp_size:
> +    .space 32 * 1024 * 1024
> --
> 2.53.0
>


-- 
H.J.


More information about the Libc-alpha mailing list