[PATCH v5] elf: Support THP segment load with madvise enabled THP
H.J. Lu
hjl.tools@gmail.com
Wed Apr 22 22:28:27 GMT 2026
On Wed, Apr 22, 2026 at 10:41 PM Adhemerval Zanella Netto
<adhemerval.zanella@linaro.org> wrote:
>
>
>
> On 20/04/26 22:31, H.J. Lu wrote:
> >
> > The added THP tests pass on x86 and aarch64. Some of them failed on
> > arm:
> >
> > https://patchwork.sourceware.org/project/glibc/patch/CAMe9rOqKfFXMDY07GRuppudP3V9fsCDXoyxDesPMNQLDrRhzvg@mail.gmail.com/
> >
> > Produces 4 regressions:
> > |
> > | regressions.sum:
> > | Running glibc:elf ...
> > | FAIL: elf/tst-thp-1-no-s-code-pde
> > | FAIL: elf/tst-thp-1-no-s-code-static
> > | FAIL: elf/tst-thp-1-pde
> > | FAIL: elf/tst-thp-1-static
> >
> > It looks like PIE works, but PDE and static PIE don't work on arm. The
> > Linaro report doesn't have useful information for these failures. My
> > arm glibc test binaries look like
> >
>
> It seems to be a limitation of arm32 kABI. The strace of elf/tst-thp-1-static
> shows that execve failed to load the binary:
>
> $ strace -f elf/tst-thp-1-static --direct
> execve("elf/tst-thp-1-static", ["elf/tst-thp-1-static", "--direct"], 0xbeda8468 /* 31 vars */) = -1 EINVAL (Invalid argument)
> +++ killed by SIGSEGV +++
> Segmentation fault
>
> And tracing where kernel triggers and error shows:
>
> # echo function_graph > /sys/kernel/debug/tracing/current_tracer
> # echo vm_mmap > /sys/kernel/debug/tracing/set_graph_function
> # echo 0 > /sys/kernel/debug/tracing/tracing_on
>
> # Clear the buffer
> echo > /sys/kernel/debug/tracing/trace
>
> # Filter to just the shell's PID
> # echo $$ > /sys/kernel/debug/tracing/set_ftrace_pid
>
> # echo 1 > /sys/kernel/debug/tracing/tracing_on
> # elf/tst-thp-1-static --direct
> # echo 0 > /sys/kernel/debug/tracing/tracing_on
>
> # cat /sys/kernel/debug/tracing/trace
>
> The trace output shows:
>
> [...]
> 3) | do_mmap() {
> 3) 9.760 us | __get_unmapped_area();
> 3) + 32.176 us | }
> 3) 1.344 us | up_write();
> 3) 7.152 us | userfaultfd_unmap_complete();
> [...]
>
> The ARM defines a arch_mmap_check hook (arch/arm/include/uapi/asm/mman.h):
>
> #define arch_mmap_check(addr, len, flags) \
> (((flags) & MAP_FIXED && (addr) < FIRST_USER_ADDRESS) ? -EINVAL : 0)
>
> which is the first thing called by __get_unmapped_area. For MMU configuration,
> FIRST_USER_ADDRESS is 2 times the page size:
>
> arch/arm/include/asm/pgtable.h:
> /*
> * This is the lowest virtual address we can permit any user space
> * mapping to be mapped at. This is particularly important for
> * non-high vector CPUs.
> */
> #define FIRST_USER_ADDRESS (PAGE_SIZE * 2)
>
> The kernel issues arch_mmap_check(0x0, 0x1000, MAP_FIXED|...), since the file
> is ET_EXEC (and SUPPORT_STATIC_PIE is not currently defined for arm32):
>
> fs/binfmt_elf.c:
> 1066 } else if (elf_ex->e_type == ET_EXEC) {
> 1067 /*
> 1068 * This logic is run once for the first LOAD Program
> 1069 * Header for ET_EXEC binaries. No special handling
> 1070 * is needed.
> 1071 */
> 1072 elf_flags |= MAP_FIXED_NOREPLACE;
>
> Afaik the FIRST_USER_ADDRESS is a requirement to handle the exception vector table
> placement in ARMv4T/ARMv5 eras and with modern kernels on recent hardware all
> the required machinery is mapped on high addresses:
>
> $ cat /proc/self/maps
> [...]
> bed3d000-bed5e000 rw-p 00000000 00:00 0 [stack]
> beda9000-bedaa000 r-xp 00000000 00:00 0 [sigpage]
> bedaa000-bedae000 r--p 00000000 00:00 0 [vvar]
> bedae000-bedb0000 r-xp 00000000 00:00 0 [vdso]
> ffff0000-ffff1000 r-xp 00000000 00:00 0 [vectors]
>
> To test this, I removed the arch_mmap_check and process startup fails with a different
> error:
>
> $ strace -f elf/tst-thp-1-static --direct
> execve("elf/tst-thp-1-static", ["elf/tst-thp-1-static", "--direct"], 0xbeda8468 /* 31 vars */) = -1 EPERM (Operation not permitted)
> +++ killed by SIGSEGV +++
> Segmentation fault
>
> And this is due a missing capability:
>
> $ ./tst-thp-1-static
> Segmentation fault
> $ sudo setcap cap_sys_rawio+ep tst-thp-1-static
> $ ./tst-thp-1-static
> $
>
> This is the same issue for dynamic linked binaries:
>
> $ strace -f -e mmap ./elf/ld.so --library-path . elf/tst-thp-1-pde --direct
> [pid 1197551] mmap(NULL, 73728, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0) = -1 EPERM (Operation not permitted)
>
> So in theory it would be possible to run such binaries on arm32, but I do not
> know all the implications of allowing binaries mapping the low addresses
> (and requiring cap_sys_rawio+ep has other implications as well).
>
> It seems to be a ARM32 idiosyncrasy, so I think maybe we should enable this along
> with arch-specific knob as we for the static-pie (SUPPORT_STATIC_PIE).
I added:
diff --git a/sysdeps/unix/sysv/linux/arm/Makefile
b/sysdeps/unix/sysv/linux/arm/Makefile
index e73ce4f811..1ee8bec9b9 100644
--- a/sysdeps/unix/sysv/linux/arm/Makefile
+++ b/sysdeps/unix/sysv/linux/arm/Makefile
@@ -3,6 +3,13 @@ sysdep-rtld-routines += aeabi_read_tp libc-do-syscall
# The test uses INTERNAL_SYSCALL_CALL. In thumb mode, this uses
# an undefined reference to __libc_do_syscall.
CFLAGS-tst-nolink-libc.c += -marm
+
+# These tests fail on arm due to limitations of arm32 kABI:
+# https://sourceware.org/bugzilla/show_bug.cgi?id=34096
+test-xfail-tst-thp-1-no-s-code-pde = yes
+test-xfail-tst-thp-1-no-s-code-static = yes
+test-xfail-tst-thp-1-pde = yes
+test-xfail-tst-thp-1-static = yes
endif
to the v6 patch.
Thanks.
--
H.J.
More information about the Libc-alpha
mailing list