Patch Detail
get:
Show a patch.
patch:
Update a patch.
put:
Update a patch.
GET /api/1.1/patches/2225405/?format=api
{ "id": 2225405, "url": "http://patchwork.ozlabs.org/api/1.1/patches/2225405/?format=api", "web_url": "http://patchwork.ozlabs.org/project/glibc/patch/CAMe9rOpuLjOmaFDiXVf+LOx54H5Nss95RBziKk91LyceH4Dibg@mail.gmail.com/", "project": { "id": 41, "url": "http://patchwork.ozlabs.org/api/1.1/projects/41/?format=api", "name": "GNU C Library", "link_name": "glibc", "list_id": "libc-alpha.sourceware.org", "list_email": "libc-alpha@sourceware.org", "web_url": "", "scm_url": "", "webscm_url": "" }, "msgid": "<CAMe9rOpuLjOmaFDiXVf+LOx54H5Nss95RBziKk91LyceH4Dibg@mail.gmail.com>", "date": "2026-04-21T01:31:30", "name": "[v5] elf: Support THP segment load with madvise enabled THP", "commit_ref": null, "pull_url": null, "state": "new", "archived": false, "hash": "a5bbc158d796d0560209499413fd8969c8f85b68", "submitter": { "id": 4387, "url": "http://patchwork.ozlabs.org/api/1.1/people/4387/?format=api", "name": "H.J. Lu", "email": "hjl.tools@gmail.com" }, "delegate": null, "mbox": "http://patchwork.ozlabs.org/project/glibc/patch/CAMe9rOpuLjOmaFDiXVf+LOx54H5Nss95RBziKk91LyceH4Dibg@mail.gmail.com/mbox/", "series": [ { "id": 500701, "url": "http://patchwork.ozlabs.org/api/1.1/series/500701/?format=api", "web_url": "http://patchwork.ozlabs.org/project/glibc/list/?series=500701", "date": "2026-04-21T01:31:30", "name": "[v5] elf: Support THP segment load with madvise enabled THP", "version": 5, "mbox": "http://patchwork.ozlabs.org/series/500701/mbox/" } ], "comments": "http://patchwork.ozlabs.org/api/patches/2225405/comments/", "check": "pending", "checks": "http://patchwork.ozlabs.org/api/patches/2225405/checks/", "tags": {}, "headers": { "Return-Path": "<libc-alpha-bounces~incoming=patchwork.ozlabs.org@sourceware.org>", "X-Original-To": [ "incoming@patchwork.ozlabs.org", "libc-alpha@sourceware.org" ], "Delivered-To": [ "patchwork-incoming@legolas.ozlabs.org", "libc-alpha@sourceware.org" ], "Authentication-Results": [ "legolas.ozlabs.org;\n\tdkim=pass (2048-bit key;\n unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256\n header.s=20251104 header.b=CM2W800b;\n\tdkim-atps=neutral", "legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=sourceware.org\n (client-ip=2620:52:6:3111::32; helo=vm01.sourceware.org;\n envelope-from=libc-alpha-bounces~incoming=patchwork.ozlabs.org@sourceware.org;\n receiver=patchwork.ozlabs.org)", "sourceware.org;\n\tdkim=pass (2048-bit key,\n unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256\n header.s=20251104 header.b=CM2W800b", "sourceware.org;\n dmarc=pass (p=none dis=none) header.from=gmail.com", "sourceware.org; spf=pass smtp.mailfrom=gmail.com", "server2.sourceware.org;\n arc=pass smtp.remote-ip=2607:f8b0:4864:20::62f" ], "Received": [ "from vm01.sourceware.org (vm01.sourceware.org\n [IPv6:2620:52:6:3111::32])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange x25519 server-signature ECDSA (secp384r1) server-digest SHA384)\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4g04cF0PzHz1yCv\n\tfor <incoming@patchwork.ozlabs.org>; Tue, 21 Apr 2026 11:33:00 +1000 (AEST)", "from vm01.sourceware.org (localhost [127.0.0.1])\n\tby sourceware.org (Postfix) with ESMTP id 0D9F54A98F0C\n\tfor <incoming@patchwork.ozlabs.org>; Tue, 21 Apr 2026 01:32:59 +0000 (GMT)", "from mail-pl1-x62f.google.com (mail-pl1-x62f.google.com\n [IPv6:2607:f8b0:4864:20::62f])\n by sourceware.org (Postfix) with ESMTPS id 7AF824C515FA\n for <libc-alpha@sourceware.org>; Tue, 21 Apr 2026 01:32:09 +0000 (GMT)", "by mail-pl1-x62f.google.com with SMTP id\n d9443c01a7336-2aae4816912so23696675ad.2\n for <libc-alpha@sourceware.org>; Mon, 20 Apr 2026 18:32:09 -0700 (PDT)" ], "DKIM-Filter": [ "OpenDKIM Filter v2.11.0 sourceware.org 0D9F54A98F0C", "OpenDKIM Filter v2.11.0 sourceware.org 7AF824C515FA" ], "DMARC-Filter": "OpenDMARC Filter v1.4.2 sourceware.org 7AF824C515FA", "ARC-Filter": "OpenARC Filter v1.0.0 sourceware.org 7AF824C515FA", "ARC-Seal": [ "i=2; a=rsa-sha256; d=sourceware.org; s=key; t=1776735129; cv=pass;\n b=phkGGdtEzJM0fnx+53v0gX6RnasuVE7OhpSbXyEibVQYQtPhSFF9LClmcr1gfn/IxBWDzemMq1WPm42p2T3Qh+oyMOniPXqldViyI3Mvtx/jDq1LWnnngMQCD2mGBkiyKIz9qhpYvcououxSollX2bdezWuyv7aXUey9TEjG468=", "i=1; a=rsa-sha256; t=1776735128; cv=none;\n d=google.com; s=arc-20240605;\n b=it54hEWmJhJHLNWbtU8t6GbZgYrR3YXUllOlqCGJSJ9skEXtSouTyFN4q6F4P0qeHq\n 4CnL3mgtxoYD3m6ENTRcLVJhDhmCaDJN0U2aJU5ZjR5AdcWBwzFqMu0gqCiVOonUX7Vb\n cHTg1J1EY9nEQDd3mADrQx7YXRsmizuZaZrYM8QYN8mT7YZHwsMlcnCU//AyjJPSrAgu\n Qtx01fyfWJzOxQcUphOhGH/LcjIJqTgem45qd4LdACeWH6kqYRECwBZirDvuIxfruXU0\n BFKfyZVikJJP/jzViKBPP9dAKKs4rQ6IwpbC0TNEGQULes5qjYZREoHl0fuOUL7VXEBQ\n Bwmg==" ], "ARC-Message-Signature": [ "i=2; a=rsa-sha256; d=sourceware.org; s=key;\n t=1776735129; c=relaxed/simple;\n bh=HySlFuT/WXINKQMzXBxfLXl0CeUU5BoT0Ggn08Qz4XE=;\n h=DKIM-Signature:MIME-Version:From:Date:Message-ID:Subject:To;\n b=b4BjQvTYA9pLprZNOsfgsxi5eQBPCT/pLnje6vaFgsrJs/X0IuEEytPMCX6ySpWmQAlhl7aHsEquhTWYY+1F9wZP4ixo+F10y3+FcKSRH0jcl6sAzQI/dHNj4yIgYMfe/Xy/juEiopJdzrm6hxFZlcffPspAHDbPxiDJOL2vtx8=", "i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com;\n s=arc-20240605;\n h=to:subject:message-id:date:from:mime-version:dkim-signature;\n bh=TqLoguRZyCwxqgFWEBAyA+Q/cFG8Hrt+tSXYDzVV3W4=;\n fh=f/XnL5/RpIm509ZuvGPKrqEF2R6WYaOnQ8UOL8MF9ac=;\n b=WIeeirwH1p7CGzY9eRywNpk4gSKTXl4ckH4yQzNjupiLWkNDZm66IIEjfLQ6pIcGyn\n 8StqQvtEh0iOsXqpFGhVb/LdLCQxk8KlPBHx5x2zVhc2DRBhNWNRUW/EzZ6l3bdLwd2S\n aOtiG+MH6+mz8udYRhwgoswxts0zXzJ/tryUyvYZx4jBbYVTpiNHIo/sZ2yoQ0f/dvBM\n gUKe+Ia9xoEKlzAe+/FwTgRePB7TXLk3IVt8W/y3BCRPVb/F2ROwIZUNoZ1qP9AlRer2\n PRZmUhZpQmqjeeLUNeHg0jsT7dNXUTrxGVPs90yYoJF2Z+EM/uGNeqiX0G+Kgws4tBNf\n xMQg==; darn=sourceware.org" ], "ARC-Authentication-Results": [ "i=2; server2.sourceware.org", "i=1; mx.google.com; arc=none" ], "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=gmail.com; s=20251104; t=1776735128; x=1777339928; darn=sourceware.org;\n h=to:subject:message-id:date:from:mime-version:from:to:cc:subject\n :date:message-id:reply-to;\n bh=TqLoguRZyCwxqgFWEBAyA+Q/cFG8Hrt+tSXYDzVV3W4=;\n b=CM2W800b+G9gm339rmDj89E0Smy/hMCuz0xOfIuhBEtAcmtBCqiv6Yn9mcRJahNy9J\n /iCxfefn0Bpo0QGU0zmNrineJJr5L8ud1tZxn+xqN8XO3Njt+lp3kOAAKOZFNmUo+/JM\n JB1Jmw1uR6/UYMZYc+7OPAYqm6X/z8bAMTZ+VP4OjB90Nx1STAY6m3Gfnq4z5K+++/LB\n 8Fx2ddaF5mVDl87sKA+gdyKX47SQGpRqxMzizaDVkQfa70L27svm45W3BsRtUY+zHL45\n xI/yO+duFBD3grohLwwBfbRqQyxpg56PNm2KSnV67UvemxPkBnUPW4Yqy639ek0uHolw\n s1Zg==", "X-Google-DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=1e100.net; s=20251104; t=1776735128; x=1777339928;\n h=to:subject:message-id:date:from:mime-version:x-gm-gg\n :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to;\n bh=TqLoguRZyCwxqgFWEBAyA+Q/cFG8Hrt+tSXYDzVV3W4=;\n b=HQXtfEbBLB72k2cmDoucqlczQ5u483QWAYaEh9daRZONKKapzMsnN/1swJCgkkyIQ9\n AkpW7697Bzb186ekgieQzmgepupy9cvTLvTSG36+oHyf4GvE4qnOX6Y+7E1M5KTe3V7m\n 3jdcY9C3aHZRmKaXjqcA93AQU/c+7u/bJ87sZDB+w7Pz/DnwE3f2hJeKJt0LuMdQA1yS\n he2uPYIOGVANP7H59um2HC49TsVcvEhpJQV/pkgRMye+IM/RwpbpQSImY/My50V1erKZ\n Q1IUEsqwPEEFq0UoYcaNspMymTcBdZiPORVfVeZd91oSdNlPqVvhobqdp4Cdz/5ehFH+\n ieQQ==", "X-Gm-Message-State": "AOJu0YxL+qTHPlMpVwAruVs/pxs0+FxxLSS6TNc2/kk7iKwmjLx5inQu\n H0qHvCCbipAd9jT27bwBrEEuEZAywRhH0Gvg279+uO9vZDqkceXYqwI63GkbqWmtMsbmFOwejTX\n hdOsywNP2IE/6huMj5le3su2u00Y1Y9U6tyQ6tplxSA==", "X-Gm-Gg": "AeBDievjeweBOe94BrrTaUBLuajlkuHT12RmkqvsUOF7jhCICKtaRob7oQgvpMuzezH\n 9uNnhu6UwQSCMPmFlYzfPN01deKBv3ZAODz3n/l9O3RgkBFhD+Y4zMkTuiNIm0jzRN8Iuyut4BE\n M8hTo+iB9mdGpMoZEYKUAOXVo/eYIfbu2HZYFpWE3tb/GF2D1KVvjwnTHCf2CY0O4KrZtG/RbS/\n C0L5m1DvV28c9TJ7GDiLj9oNwMWLbMEX0GaFcFBcCC3UxbXbcCqkU/nhNQPW5v6CKnMnHU6NR49\n QlZC07SF3VlYZU6N6Hg=", "X-Received": "by 2002:a17:903:2c0f:b0:2b4:678c:5f25 with SMTP id\n d9443c01a7336-2b5f9d671bcmr154139375ad.0.1776735127830; Mon, 20 Apr 2026\n 18:32:07 -0700 (PDT)", "MIME-Version": "1.0", "From": "\"H.J. Lu\" <hjl.tools@gmail.com>", "Date": "Tue, 21 Apr 2026 09:31:30 +0800", "X-Gm-Features": "AQROBzBpityC_2ZftAMMoetzs9FgdyfxvzufKtXkBICf-fNHIsUVqBYIoib2Y9A", "Message-ID": "\n <CAMe9rOpuLjOmaFDiXVf+LOx54H5Nss95RBziKk91LyceH4Dibg@mail.gmail.com>", "Subject": "[PATCH v5] elf: Support THP segment load with madvise enabled THP", "To": "GNU C Library <libc-alpha@sourceware.org>, WANG Rui <wangrui@loongson.cn>,\n \"Carlos O'Donell\" <carlos@redhat.com>", "Content-Type": "multipart/mixed; boundary=\"00000000000027a367064fee62b2\"", "X-BeenThere": "libc-alpha@sourceware.org", "X-Mailman-Version": "2.1.30", "Precedence": "list", "List-Id": "Libc-alpha mailing list <libc-alpha.sourceware.org>", "List-Unsubscribe": "<https://sourceware.org/mailman/options/libc-alpha>,\n <mailto:libc-alpha-request@sourceware.org?subject=unsubscribe>", "List-Archive": "<https://sourceware.org/pipermail/libc-alpha/>", "List-Post": "<mailto:libc-alpha@sourceware.org>", "List-Help": "<mailto:libc-alpha-request@sourceware.org?subject=help>", "List-Subscribe": "<https://sourceware.org/mailman/listinfo/libc-alpha>,\n <mailto:libc-alpha-request@sourceware.org?subject=subscribe>", "Errors-To": "libc-alpha-bounces~incoming=patchwork.ozlabs.org@sourceware.org" }, "content": "Changes from v4:\n\n1. Rebase against e3e8f814e5 visories: Fix spelling mistake in\nGLIBC-SA-2026-0009.\n2. Drop the -z separate-code linker option check and use it unconditionally.\n3. Set the maximum page alignment on tst-thp-size-mod.so to THP page size.\n\nChanges from v3:\n\n1. Fold the -z separate-code linker option check.\n2. Move DL_MAP_DEFAULT_THP_PAGESIZE to <hugepages.h>\nand default it to 0.\n3. Don't run strace tests for cross-compiling.\n4. Remove return after FAIL_UNSUPPORTED in THP test.\n\nChanges from v2:\n\n1. Keep _dl_map_segment_align name.\n2. Pass size_t to _dl_map_segment_align.\n3. Enable THP if THP is always enabled in the kernel.\n4. Disable THP if THP page size > MAX_THP_PAGESIZE\n\nChanges from v1:\n\n1. Rebased against the v10 THP test patch from WANG Rui <wangrui@loongson.cn>.\n2. Keep DL_MAP_DEFAULT_THP_PAGESIZE.", "diff": "From 172e517e2f2bd0f33c6fb35ecd40538e55ef57b6 Mon Sep 17 00:00:00 2001\nFrom: \"H.J. Lu\" <hjl.tools@gmail.com>\nDate: Mon, 13 Apr 2026 08:23:05 +0800\nSubject: [PATCH v5] elf: Support THP segment load with madvise enabled THP\n\nThe current THP segment load approach works only when THP is enabled\nwith always in the kernel. If THP is enabled with madvise in the\nkernel, to enable THP segment load in an application, madvise should\nbe called with MADV_HUGEPAGE on all THP eligible PT_LOAD segments:\n\n1. Define DL_MAP_DEFAULT_THP_PAGESIZE in hugepages.h and default it to 0.\n2. Change _dl_map_segment_align to update alignments of PT_LOAD segments,\nwhich marks and aligns only THP eligible PT_LOAD segments to THP page size\nwhen loading an object. This fixes BZ #34079.\n3. Call _dl_executable_postprocess in rtld_setup_main_map for dynamic\nexecutables and in LIBC_START_MAIN for static executables, which calls\nmadvise with MADV_HUGEPAGE on all THP eligible PT_LOAD segments in\nexecutable. This fixes BZ #34080 for both dynamic and static executables.\n4. Call _dl_postprocess_loadcmd_extra in _dl_postprocess_loadcmd, which\ncalls madvise with MADV_HUGEPAGE on all THP eligible PT_LOAD segments\nwhen loading an object after they have been mapped in. This fixes\nBZ #34080 for shared objects.\n5. Set the maximum page alignment on THP tests to THP page size as the\ndefault maximum page alignment may be smaller than THP page size.\n6. Add tests to verify that large executable PT_LOAD segments in\nexecutables are mapped at addresses aligned to THP page size when the\nkernel is configured to use THP in \"always\" mode or \"madvise\" mode by\ninspecting /proc/self/maps to check that the mapping address is aligned\nto THP page size reported by the kernel. Also verify that madvise is\ncalled with MADV_HUGEPAGE when the glibc tunable glibc.elf.thp=1 is used\nand madvise isn't called with MADV_HUGEPAGE when the glibc tunable\nglibc.elf.thp=0 is used.\n\nSkip these tests if THP page size cannot be determined or if THP is not\nenabled in \"always\" mode nor \"madvise\" mode.\n\nQuote WANG Rui <wangrui@loongson.cn>:\n\nFrom benchmarking a clang build of the Linux kernel on x86_64 with\nyour patch in THP madvise mode, I observed that iTLB misses were\nreduced, similar to what we see in THP always mode.\n\nThe added THP tests pass on x86 and aarch64. Some of them failed on\narm:\n\nhttps://patchwork.sourceware.org/project/glibc/patch/CAMe9rOqKfFXMDY07GRuppudP3V9fsCDXoyxDesPMNQLDrRhzvg@mail.gmail.com/\n\nProduces 4 regressions:\n |\n | regressions.sum:\n | Running glibc:elf ...\n | FAIL: elf/tst-thp-1-no-s-code-pde\n | FAIL: elf/tst-thp-1-no-s-code-static\n | FAIL: elf/tst-thp-1-pde\n | FAIL: elf/tst-thp-1-static\n\nIt looks like PIE works, but PDE and static PIE don't work on arm. The\nLinaro report doesn't have useful information for these failures. My\narm glibc test binaries look like\n\n$ readelf -lW elf/tst-thp-1-pde\n\nElf file type is EXEC (Executable file)\nEntry point 0x2003dc\nThere are 11 program headers, starting at offset 52\n\nProgram Headers:\n Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align\n ARM_EXIDX 0x2400e24 0x02400e24 0x02400e24 0x000c8 0x000c8 R 0x4\n PHDR 0x000034 0x00000034 0x00000034 0x00160 0x00160 R 0x4\n INTERP 0x010194 0x00010194 0x00010194 0x00019 0x00019 R 0x1\n [Requesting program interpreter: /lib/ld-linux-armhf.so.3]\n LOAD 0x000000 0x00000000 0x00000000 0x11374 0x11374 R 0x200000\n LOAD 0x200000 0x00200000 0x00200000 0x20032d0 0x20032d0 R E 0x200000\n LOAD 0x2400000 0x02400000 0x02400000 0x00f10 0x00f10 R 0x200000\n LOAD 0x25ffebc 0x027ffebc 0x027ffebc 0x002a4 0x002c4 RW 0x200000\n DYNAMIC 0x25fff08 0x027fff08 0x027fff08 0x000f8 0x000f8 RW 0x4\n NOTE 0x2400ef0 0x02400ef0 0x02400ef0 0x00020 0x00020 R 0x4\n GNU_STACK 0x000000 0x00000000 0x00000000 0x00000 0x00000 RW 0x10\n GNU_RELRO 0x25ffebc 0x027ffebc 0x027ffebc 0x00144 0x00144 R 0x1\n\n Section to Segment mapping:\n Segment Sections...\n 00 .ARM.exidx\n 01\n 02 .interp\n 03 .interp .hash .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rel.dyn .rel.plt\n 04 .init .plt .text .fini\n 05 .rodata .ARM.extab .ARM.exidx .eh_frame .note.ABI-tag\n 06 .init_array .fini_array .data.rel.ro .dynamic .got .data .bss\n 07 .dynamic\n 08 .note.ABI-tag\n 09\n 10 .init_array .fini_array .data.rel.ro .dynamic\n$\n\nI can work with someone who has access to arm machine to get the bottom\nof these failures.\n\nSigned-off-by: H.J. Lu <hjl.tools@gmail.com>\n---\n csu/libc-start.c | 4 +\n elf/dl-load.c | 8 +-\n elf/dl-load.h | 5 +\n elf/dl-support.c | 6 +\n elf/rtld.c | 17 +--\n sysdeps/generic/dl-exec-post.h | 34 +++++\n sysdeps/generic/dl-load-post.h | 25 ++++\n sysdeps/generic/dl-map-segment-align.h | 9 +-\n sysdeps/generic/hugepages.h | 8 +-\n sysdeps/generic/ldsodefs.h | 12 ++\n sysdeps/unix/sysv/linux/Makefile | 125 +++++++++++++++++-\n sysdeps/unix/sysv/linux/dl-exec-post.h | 108 +++++++++++++++\n sysdeps/unix/sysv/linux/dl-load-post.h | 32 +++++\n .../unix/sysv/linux/dl-map-segment-align.c | 62 +++++----\n .../unix/sysv/linux/dl-map-segment-align.h | 8 +-\n sysdeps/unix/sysv/linux/ldsodefs.h | 3 +\n sysdeps/unix/sysv/linux/loongarch/Makefile | 3 +\n .../{dl-map-segment-align.h => hugepages.h} | 4 +-\n sysdeps/unix/sysv/linux/strace-tst-thp.sh | 56 ++++++++\n .../unix/sysv/linux/tst-thp-1-no-s-code-pde.c | 19 +++\n .../sysv/linux/tst-thp-1-no-s-code-static.c | 19 +++\n sysdeps/unix/sysv/linux/tst-thp-1-no-s-code.c | 19 +++\n sysdeps/unix/sysv/linux/tst-thp-1-pde.c | 19 +++\n sysdeps/unix/sysv/linux/tst-thp-1-static.c | 19 +++\n sysdeps/unix/sysv/linux/tst-thp-1.c | 28 ++++\n sysdeps/unix/sysv/linux/tst-thp-align-check.h | 124 +++++++++++++++++\n sysdeps/unix/sysv/linux/tst-thp-align.c | 123 +----------------\n sysdeps/unix/sysv/linux/x86/hugepages.h | 22 +++\n 28 files changed, 744 insertions(+), 177 deletions(-)\n create mode 100644 sysdeps/generic/dl-exec-post.h\n create mode 100644 sysdeps/generic/dl-load-post.h\n create mode 100644 sysdeps/unix/sysv/linux/dl-exec-post.h\n create mode 100644 sysdeps/unix/sysv/linux/dl-load-post.h\n rename sysdeps/unix/sysv/linux/loongarch/lp64/{dl-map-segment-align.h => hugepages.h} (90%)\n create mode 100644 sysdeps/unix/sysv/linux/strace-tst-thp.sh\n create mode 100644 sysdeps/unix/sysv/linux/tst-thp-1-no-s-code-pde.c\n create mode 100644 sysdeps/unix/sysv/linux/tst-thp-1-no-s-code-static.c\n create mode 100644 sysdeps/unix/sysv/linux/tst-thp-1-no-s-code.c\n create mode 100644 sysdeps/unix/sysv/linux/tst-thp-1-pde.c\n create mode 100644 sysdeps/unix/sysv/linux/tst-thp-1-static.c\n create mode 100644 sysdeps/unix/sysv/linux/tst-thp-1.c\n create mode 100644 sysdeps/unix/sysv/linux/tst-thp-align-check.h\n create mode 100644 sysdeps/unix/sysv/linux/x86/hugepages.h\n\ndiff --git a/csu/libc-start.c b/csu/libc-start.c\nindex 1c58561bce..be60831a42 100644\n--- a/csu/libc-start.c\n+++ b/csu/libc-start.c\n@@ -205,6 +205,7 @@ call_fini (void *unused)\n #endif /* !SHARED */\n \n #include <libc-start.h>\n+#include <dl-exec-post.h>\n \n STATIC int LIBC_START_MAIN (int (*main) (int, char **, char **\n \t\t\t\t\t MAIN_AUXVEC_DECL),\n@@ -305,6 +306,9 @@ LIBC_START_MAIN (int (*main) (int, char **, char ** MAIN_AUXVEC_DECL),\n __pointer_chk_guard_local = pointer_chk_guard;\n # endif\n \n+ struct link_map *main_map = _dl_get_dl_main_map ();\n+ _dl_executable_postprocess (main_map, GL(dl_phdr), GL(dl_phnum));\n+\n #endif /* !SHARED */\n \n /* Register the destructor of the dynamic linker if there is any. */\ndiff --git a/elf/dl-load.c b/elf/dl-load.c\nindex 48575fff06..ab2727e611 100644\n--- a/elf/dl-load.c\n+++ b/elf/dl-load.c\n@@ -1173,8 +1173,8 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd,\n \t /* Optimize a common case. */\n \t c->prot = pf_to_prot (ph->p_flags);\n \n-\t /* Architecture-specific adjustment of segment alignment. */\n-\t p_align_max = _dl_map_segment_align (c, p_align_max);\n+\t /* Initialize flags. */\n+\t c->flags = 0;\n \t break;\n \n \tcase PT_TLS:\n@@ -1229,9 +1229,7 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd,\n \tgoto lose;\n }\n \n- /* Align all PT_LOAD segments to the maximum p_align. */\n- for (size_t i = 0; i < nloadcmds; i++)\n- loadcmds[i].mapalign = p_align_max;\n+ _dl_map_segment_align (loadcmds, nloadcmds, p_align_max);\n \n /* dlopen of an executable is not valid because it is not possible\n to perform proper relocations, handle static TLS, or run the\ndiff --git a/elf/dl-load.h b/elf/dl-load.h\nindex 897c4034c5..55edf0323c 100644\n--- a/elf/dl-load.h\n+++ b/elf/dl-load.h\n@@ -78,8 +78,11 @@ struct loadcmd\n ElfW(Addr) mapstart, mapend, dataend, allocend, mapalign;\n ElfW(Off) mapoff;\n int prot; /* PROT_* bits. */\n+ /* May be used by _dl_postprocess_loadcmd_extra. */\n+ unsigned int flags;\n };\n \n+#include <dl-load-post.h>\n \n /* This is a subroutine of _dl_map_segments. It should be called for each\n load command, some time after L->l_addr has been set correctly. It is\n@@ -95,6 +98,8 @@ _dl_postprocess_loadcmd (struct link_map *l, const ElfW(Ehdr) *header,\n /* Found the program header in this segment. */\n l->l_phdr = (void *) (uintptr_t) (c->mapstart + header->e_phoff\n - c->mapoff);\n+\n+ _dl_postprocess_loadcmd_extra (l, c);\n }\n \n \ndiff --git a/elf/dl-support.c b/elf/dl-support.c\nindex 0508d6113b..a8114de003 100644\n--- a/elf/dl-support.c\n+++ b/elf/dl-support.c\n@@ -179,6 +179,12 @@ int _dl_stack_cache_lock;\n #endif\n struct dl_scope_free_list *_dl_scope_free_list;\n \n+#ifdef HAVE_THP\n+int _dl_elf_thp_control = -1;\n+enum thp_mode_t _dl_thp_mode;\n+size_t _dl_elf_thp_pagesize;\n+#endif\n+\n #ifdef NEED_DL_SYSINFO\n /* Needed for improved syscall handling on at least x86/Linux. NB: Don't\n initialize it here to avoid RELATIVE relocation in static PIE. */\ndiff --git a/elf/rtld.c b/elf/rtld.c\nindex e926ec73e4..68e5476189 100644\n--- a/elf/rtld.c\n+++ b/elf/rtld.c\n@@ -52,6 +52,7 @@\n #include <dl-find_object.h>\n #include <dl-audit-check.h>\n #include <dl-call_tls_init_tp.h>\n+#include <dl-exec-post.h>\n \n #include <assert.h>\n \n@@ -323,6 +324,9 @@ struct rtld_global _rtld_global =\n /* Generally the default presumption without further information is an\n * executable stack but this is not true for all platforms. */\n ._dl_stack_prot_flags = DEFAULT_STACK_PROT_PERMS,\n+#ifdef HAVE_THP\n+ ._dl_elf_thp_control = -1,\n+#endif\n #ifdef _LIBC_REENTRANT\n ._dl_load_lock = _RTLD_LOCK_RECURSIVE_INITIALIZER,\n ._dl_load_write_lock = _RTLD_LOCK_RECURSIVE_INITIALIZER,\n@@ -1209,14 +1213,8 @@ rtld_setup_main_map (struct link_map *main_map)\n \tmain_map->l_relro_size = ph->p_memsz;\n \tbreak;\n }\n- /* Process program headers again, but scan them backwards since\n- PT_GNU_PROPERTY is close to the end of program headers. */\n- for (const ElfW(Phdr) *ph = &phdr[phnum]; ph != phdr; --ph)\n- if (ph[-1].p_type == PT_GNU_PROPERTY)\n- {\n-\t_dl_process_pt_gnu_property (main_map, -1, &ph[-1]);\n-\tbreak;\n- }\n+\n+ _dl_executable_postprocess (main_map, phdr, phnum);\n \n /* Adjust the address of the TLS initialization image in case\n the executable is actually an ET_DYN object. */\n@@ -1589,6 +1587,9 @@ dl_main (const ElfW(Phdr) *phdr,\n \t{\n \t RTLD_TIMING_VAR (start);\n \t rtld_timer_start (&start);\n+#ifdef HAVE_THP\n+\t _dl_get_thp_config ();\n+#endif\n \t _dl_map_object (NULL, rtld_progname, lt_executable, 0,\n \t\t\t __RTLD_OPENEXEC, LM_ID_BASE);\n \t rtld_timer_stop (&load_time, start);\ndiff --git a/sysdeps/generic/dl-exec-post.h b/sysdeps/generic/dl-exec-post.h\nnew file mode 100644\nindex 0000000000..f5dcdc093a\n--- /dev/null\n+++ b/sysdeps/generic/dl-exec-post.h\n@@ -0,0 +1,34 @@\n+/* _dl_executable_postprocess. Generic version.\n+ Copyright (C) 2026 Free Software Foundation, Inc.\n+ Copyright The GNU Toolchain Authors.\n+ This file is part of the GNU C Library.\n+\n+ The GNU C Library is free software; you can redistribute it and/or\n+ modify it under the terms of the GNU Lesser General Public\n+ License as published by the Free Software Foundation; either\n+ version 2.1 of the License, or (at your option) any later version.\n+\n+ The GNU C Library is distributed in the hope that it will be useful,\n+ but WITHOUT ANY WARRANTY; without even the implied warranty of\n+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n+ Lesser General Public License for more details.\n+\n+ You should have received a copy of the GNU Lesser General Public\n+ License along with the GNU C Library; if not, see\n+ <https://www.gnu.org/licenses/>. */\n+\n+static inline void\n+_dl_executable_postprocess (struct link_map *main_map,\n+\t\t\t const ElfW(Phdr) *phdr, ElfW(Word) phnum)\n+{\n+#ifdef SHARED\n+ /* Process program headers again, but scan them backwards since\n+ PT_GNU_PROPERTY is close to the end of program headers. */\n+ for (const ElfW(Phdr) *ph = &phdr[phnum]; ph != phdr; --ph)\n+ if (ph[-1].p_type == PT_GNU_PROPERTY)\n+ {\n+\t_dl_process_pt_gnu_property (main_map, -1, &ph[-1]);\n+\tbreak;\n+ }\n+#endif\n+}\ndiff --git a/sysdeps/generic/dl-load-post.h b/sysdeps/generic/dl-load-post.h\nnew file mode 100644\nindex 0000000000..bfaad8ea7c\n--- /dev/null\n+++ b/sysdeps/generic/dl-load-post.h\n@@ -0,0 +1,25 @@\n+/* _dl_postprocess_loadcmd_extra. Generic version.\n+ Copyright (C) 2026 Free Software Foundation, Inc.\n+ Copyright The GNU Toolchain Authors.\n+ This file is part of the GNU C Library.\n+\n+ The GNU C Library is free software; you can redistribute it and/or\n+ modify it under the terms of the GNU Lesser General Public\n+ License as published by the Free Software Foundation; either\n+ version 2.1 of the License, or (at your option) any later version.\n+\n+ The GNU C Library is distributed in the hope that it will be useful,\n+ but WITHOUT ANY WARRANTY; without even the implied warranty of\n+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n+ Lesser General Public License for more details.\n+\n+ You should have received a copy of the GNU Lesser General Public\n+ License along with the GNU C Library; if not, see\n+ <https://www.gnu.org/licenses/>. */\n+\n+#include <dl-load.h>\n+\n+static inline void\n+_dl_postprocess_loadcmd_extra (struct link_map *l, const struct loadcmd *c)\n+{\n+}\ndiff --git a/sysdeps/generic/dl-map-segment-align.h b/sysdeps/generic/dl-map-segment-align.h\nindex f4a671f25f..1e08afdbc1 100644\n--- a/sysdeps/generic/dl-map-segment-align.h\n+++ b/sysdeps/generic/dl-map-segment-align.h\n@@ -19,8 +19,11 @@\n \n #include <dl-load.h>\n \n-static inline ElfW(Addr)\n-_dl_map_segment_align (const struct loadcmd *c, ElfW(Addr) p_align_max)\n+static inline void\n+_dl_map_segment_align (struct loadcmd *load_cmds, size_t n,\n+\t\t ElfW(Addr) p_align_max)\n {\n- return p_align_max;\n+ /* Align all PT_LOAD segments to the maximum p_align. */\n+ for (size_t i = 0; i < n; i++)\n+ load_cmds[i].mapalign = p_align_max;\n }\ndiff --git a/sysdeps/generic/hugepages.h b/sysdeps/generic/hugepages.h\nindex 5fc9b5c8de..f7f4957e79 100644\n--- a/sysdeps/generic/hugepages.h\n+++ b/sysdeps/generic/hugepages.h\n@@ -26,10 +26,10 @@ unsigned long int __get_thp_size (void) attribute_hidden;\n \n enum thp_mode_t\n {\n+ thp_mode_not_supported = 0,\n thp_mode_always,\n thp_mode_madvise,\n- thp_mode_never,\n- thp_mode_not_supported\n+ thp_mode_never\n };\n \n enum thp_mode_t __get_thp_mode (void) attribute_hidden;\n@@ -45,6 +45,10 @@ void __get_hugepage_config (size_t requested, size_t *pagesize, int *flags)\n # define MALLOC_DEFAULT_THP_PAGESIZE\t0\n #endif\n \n+#ifndef DL_MAP_DEFAULT_THP_PAGESIZE\n+# define DL_MAP_DEFAULT_THP_PAGESIZE\t0\n+#endif\n+\n #ifndef MAX_THP_PAGESIZE\n # define MAX_THP_PAGESIZE\t(32 * 1024 * 1024)\n #endif\ndiff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h\nindex 15c4659853..733b7d6727 100644\n--- a/sysdeps/generic/ldsodefs.h\n+++ b/sysdeps/generic/ldsodefs.h\n@@ -39,6 +39,7 @@\n #include <libc-lock.h>\n #include <hp-timing.h>\n #include <list_t.h>\n+#include <hugepages.h>\n \n __BEGIN_DECLS\n \n@@ -477,6 +478,17 @@ struct rtld_global\n EXTERN struct __pthread **_dl_pthread_threads;\n __mach_rwlock_define (EXTERN, _dl_pthread_threads_lock)\n #endif\n+#ifdef HAVE_THP\n+ /* The THP segment load control:\n+ > 0: Enabled by GLIBC_TUNABLES=glibc.elf.thp=1.\n+ 0: Disabled by GLIBC_TUNABLES=glibc.elf.thp=0.\n+ < 0: To be enabled or disabled by GLIBC_TUNABLES. */\n+ EXTERN int _dl_elf_thp_control;\n+ /* The kernel THP mode. */\n+ EXTERN enum thp_mode_t _dl_thp_mode;\n+ /* Page size used for THP segment load. */\n+ EXTERN size_t _dl_elf_thp_pagesize;\n+#endif\n #ifdef SHARED\n };\n # define __rtld_global_attribute__\ndiff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile\nindex 0d47e9af57..cc97182a95 100644\n--- a/sysdeps/unix/sysv/linux/Makefile\n+++ b/sysdeps/unix/sysv/linux/Makefile\n@@ -698,11 +698,15 @@ $(objpfx)pldd: $(objpfx)xmalloc.o\n tests += \\\n tst-rseq-tls-range \\\n tst-rseq-tls-range-4096 \\\n+ tst-thp-1 \\\n+ tst-thp-1-pde \\\n+ tst-thp-1-static \\\n tst-thp-align \\\n # tests\n tests-static += \\\n tst-rseq-tls-range-4096-static \\\n tst-rseq-tls-range-static \\\n+ tst-thp-1-static \\\n # tests-static\n modules-names += \\\n tst-rseq-tls-range-mod \\\n@@ -712,15 +716,12 @@ CFLAGS-tst-rseq-tls-range.c += -DMAIN_TLS_ALIGN=4\n CFLAGS-tst-rseq-tls-range-4096.c += -DMAIN_TLS_ALIGN=4096\n CFLAGS-tst-rseq-tls-range-static.c += -DMAIN_TLS_ALIGN=4\n CFLAGS-tst-rseq-tls-range-4096-static.c += -DMAIN_TLS_ALIGN=4096\n-LDFLAGS-tst-thp-size-mod.so += -Wl,-z,noseparate-code\n $(objpfx)tst-rseq-tls-range.out: $(objpfx)tst-rseq-tls-range-mod.so\n $(objpfx)tst-rseq-tls-range-4096.out: $(objpfx)tst-rseq-tls-range-mod.so\n $(objpfx)tst-rseq-tls-range-static.out: $(objpfx)tst-rseq-tls-range-mod.so\n $(objpfx)tst-rseq-tls-range-4096-static.out: $(objpfx)tst-rseq-tls-range-mod.so\n-$(objpfx)tst-thp-align.out: $(objpfx)tst-thp-size-mod.so\n tst-rseq-tls-range-static-ENV = LD_LIBRARY_PATH=$(objpfx):$(common-objpfx)\n tst-rseq-tls-range-4096-static-ENV = LD_LIBRARY_PATH=$(objpfx):$(common-objpfx)\n-tst-thp-align-ENV = GLIBC_TUNABLES=glibc.elf.thp=1\n \n test-internal-extras += tst-nolink-libc\n ifeq ($(run-built-tests),yes)\n@@ -729,6 +730,124 @@ tests-special += \\\n $(objpfx)tst-nolink-libc-2.out \\\n # tests-special\n endif\n+\n+ifndef THP-PAGE-SIZE\n+# Align PT_LOAD segments in THP tests to THP page size so that kernel will\n+# map PIE to the address aligned to THP page size. Default THP page size\n+# to 2MB which can be overridden in Makefile in subdirectories.\n+THP-PAGE-SIZE = 0x200000\n+endif\n+\n+THP-PAGE-SIZE-LDFLAGS = -Wl,-z,max-page-size=$(THP-PAGE-SIZE)\n+\n+LDFLAGS-tst-thp-size-mod.so = -Wl,-z,noseparate-code \\\n+\t\t\t $(THP-PAGE-SIZE-LDFLAGS)\n+tst-thp-align-ENV = GLIBC_TUNABLES=glibc.elf.thp=1\n+$(objpfx)tst-thp-align.out: $(objpfx)tst-thp-size-mod.so\n+\n+tests += \\\n+ tst-thp-1-no-s-code \\\n+ tst-thp-1-no-s-code-pde \\\n+ tst-thp-1-no-s-code-static \\\n+# tests\n+tests-static += \\\n+ tst-thp-1-no-s-code-static \\\n+# tests-static\n+\n+LDFLAGS-tst-thp-1 = -Wl,-z,separate-code $(THP-PAGE-SIZE-LDFLAGS)\n+LDFLAGS-tst-thp-1-pde = -Wl,-z,separate-code $(THP-PAGE-SIZE-LDFLAGS)\n+LDFLAGS-tst-thp-1-static = -Wl,-z,separate-code $(THP-PAGE-SIZE-LDFLAGS)\n+LDFLAGS-tst-thp-1-no-s-code = -Wl,-z,noseparate-code \\\n+\t\t\t $(THP-PAGE-SIZE-LDFLAGS)\n+LDFLAGS-tst-thp-1-no-s-code-pde = -Wl,-z,noseparate-code \\\n+\t\t\t\t $(THP-PAGE-SIZE-LDFLAGS)\n+LDFLAGS-tst-thp-1-no-s-code-static = -Wl,-z,noseparate-code \\\n+\t\t\t\t $(THP-PAGE-SIZE-LDFLAGS)\n+\n+$(objpfx)tst-thp-1-no-s-code: $(objpfx)tst-thp-size-mod.o\n+$(objpfx)tst-thp-1-no-s-code-pde: $(objpfx)tst-thp-size-mod.o\n+$(objpfx)tst-thp-1-no-s-code-static: $(objpfx)tst-thp-size-mod.o\n+\n+tst-thp-1-no-s-code-ENV = GLIBC_TUNABLES=glibc.elf.thp=1\n+tst-thp-1-no-s-code-pde-ENV = GLIBC_TUNABLES=glibc.elf.thp=1\n+tst-thp-1-no-s-code-static-ENV = GLIBC_TUNABLES=glibc.elf.thp=1\n+\n+tst-thp-1-no-s-code-pde-no-pie = yes\n+\n+tst-thp-1-ENV = GLIBC_TUNABLES=glibc.elf.thp=1\n+tst-thp-1-pde-ENV = GLIBC_TUNABLES=glibc.elf.thp=1\n+tst-thp-1-static-ENV = GLIBC_TUNABLES=glibc.elf.thp=1\n+\n+$(objpfx)tst-thp-1: $(objpfx)tst-thp-size-mod.o\n+$(objpfx)tst-thp-1-pde: $(objpfx)tst-thp-size-mod.o\n+$(objpfx)tst-thp-1-static: $(objpfx)tst-thp-size-mod.o\n+\n+tst-thp-1-pde-no-pie = yes\n+\n+# Don't run strace tests for cross-compiling.\n+ifeq (no,$(cross-compiling))\n+thp-kernel-status = $(shell grep madvise /sys/kernel/mm/transparent_hugepage/enabled)\n+# Verify that madvise is called with MADV_HUGEPAGE when THP is enabled\n+# under madvise THP kernel.\n+ifneq ($(findstring [madvise],$(thp-kernel-status)),)\n+tests-special += \\\n+ $(objpfx)strace-tst-thp-1-disabled.out \\\n+ $(objpfx)strace-tst-thp-1-enabled.out \\\n+ $(objpfx)strace-tst-thp-1-pde-disabled.out \\\n+ $(objpfx)strace-tst-thp-1-pde-enabled.out \\\n+ $(objpfx)strace-tst-thp-1-static-disabled.out \\\n+ $(objpfx)strace-tst-thp-1-static-enabled.out \\\n+# tests-special\n+\n+$(objpfx)strace-tst-thp-1-enabled.out: \\\n+ $(..)sysdeps/unix/sysv/linux/strace-tst-thp.sh $(objpfx)ld.so \\\n+ $(objpfx)tst-thp-1\n+\t$(SHELL) $< $(objpfx)ld.so '$(test-wrapper-env)' \\\n+\t\t'$(run-program-env) GLIBC_TUNABLES=glibc.elf.thp=1' \\\n+\t\t'$(rpath-link)' $(objpfx)tst-thp-1 > $@; \\\n+\t $(evaluate-test)\n+\n+$(objpfx)strace-tst-thp-1-disabled.out: \\\n+ $(..)sysdeps/unix/sysv/linux/strace-tst-thp.sh $(objpfx)ld.so \\\n+ $(objpfx)tst-thp-1\n+\t$(SHELL) $< $(objpfx)ld.so '$(test-wrapper-env)' \\\n+\t\t'$(run-program-env) GLIBC_TUNABLES=glibc.elf.thp=0' \\\n+\t\t'$(rpath-link)' $(objpfx)tst-thp-1 > $@; \\\n+\t $(evaluate-test)\n+\n+$(objpfx)strace-tst-thp-1-pde-enabled.out: \\\n+ $(..)sysdeps/unix/sysv/linux/strace-tst-thp.sh $(objpfx)ld.so \\\n+ $(objpfx)tst-thp-1-pde\n+\t$(SHELL) $< $(objpfx)ld.so '$(test-wrapper-env)' \\\n+\t\t'$(run-program-env) GLIBC_TUNABLES=glibc.elf.thp=1' \\\n+\t\t'$(rpath-link)' $(objpfx)tst-thp-1-pde > $@; \\\n+\t $(evaluate-test)\n+\n+$(objpfx)strace-tst-thp-1-pde-disabled.out: \\\n+ $(..)sysdeps/unix/sysv/linux/strace-tst-thp.sh $(objpfx)ld.so \\\n+ $(objpfx)tst-thp-1-pde\n+\t$(SHELL) $< $(objpfx)ld.so '$(test-wrapper-env)' \\\n+\t\t'$(run-program-env) GLIBC_TUNABLES=glibc.elf.thp=0' \\\n+\t\t'$(rpath-link)' $(objpfx)tst-thp-1-pde > $@; \\\n+\t $(evaluate-test)\n+\n+$(objpfx)strace-tst-thp-1-static-enabled.out: \\\n+ $(..)sysdeps/unix/sysv/linux/strace-tst-thp.sh $(objpfx)ld.so \\\n+ $(objpfx)tst-thp-1-static\n+\t$(SHELL) $< $(objpfx)ld.so '$(test-wrapper-env)' \\\n+\t\t'$(run-program-env) GLIBC_TUNABLES=glibc.elf.thp=1' \\\n+\t\t'$(rpath-link)' $(objpfx)tst-thp-1-static > $@; \\\n+\t $(evaluate-test)\n+\n+$(objpfx)strace-tst-thp-1-static-disabled.out: \\\n+ $(..)sysdeps/unix/sysv/linux/strace-tst-thp.sh $(objpfx)ld.so \\\n+ $(objpfx)tst-thp-1-static\n+\t$(SHELL) $< $(objpfx)ld.so '$(test-wrapper-env)' \\\n+\t\t'$(run-program-env) GLIBC_TUNABLES=glibc.elf.thp=0' \\\n+\t\t'$(rpath-link)' $(objpfx)tst-thp-1-static > $@; \\\n+\t $(evaluate-test)\n+endif # [madvise]\n+endif # $(cross-compiling)\n endif # $(subdir) == elf\n \n ifeq ($(subdir),rt)\ndiff --git a/sysdeps/unix/sysv/linux/dl-exec-post.h b/sysdeps/unix/sysv/linux/dl-exec-post.h\nnew file mode 100644\nindex 0000000000..367b20ae2a\n--- /dev/null\n+++ b/sysdeps/unix/sysv/linux/dl-exec-post.h\n@@ -0,0 +1,108 @@\n+/* _dl_executable_postprocess. Linux version.\n+ Copyright (C) 2026 Free Software Foundation, Inc.\n+ Copyright The GNU Toolchain Authors.\n+ This file is part of the GNU C Library.\n+\n+ The GNU C Library is free software; you can redistribute it and/or\n+ modify it under the terms of the GNU Lesser General Public\n+ License as published by the Free Software Foundation; either\n+ version 2.1 of the License, or (at your option) any later version.\n+\n+ The GNU C Library is distributed in the hope that it will be useful,\n+ but WITHOUT ANY WARRANTY; without even the implied warranty of\n+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n+ Lesser General Public License for more details.\n+\n+ You should have received a copy of the GNU Lesser General Public\n+ License along with the GNU C Library; if not, see\n+ <https://www.gnu.org/licenses/>. */\n+\n+static inline void\n+_dl_get_thp_config (void)\n+{\n+ /* Check if there is GLIBC_TUNABLES=glibc.elf.thp=[0|1]. */\n+ if (TUNABLE_IS_INITIALIZED_FULL (glibc, elf, thp))\n+ GL(dl_elf_thp_control) = TUNABLE_GET_FULL (glibc, elf, thp, int32_t,\n+\t\t\t\t\t NULL);\n+\n+ /* Return if THP is disabled by GLIBC_TUNABLES=glibc.elf.thp=0. */\n+ if (GL(dl_elf_thp_control) == 0)\n+ return;\n+\n+ _Static_assert (DL_MAP_DEFAULT_THP_PAGESIZE <= MAX_THP_PAGESIZE,\n+\t\t \"DL_MAP_DEFAULT_THP_PAGESIZE <= MAX_THP_PAGESIZE\");\n+\n+ /* NB: Accessing /sys/kernel/mm files is quite expensive and the file\n+ may not be accessible in containers. If DL_MAP_DEFAULT_THP_PAGESIZE\n+ is non-zero, assume THP mode is madvise and always call madvise.\n+ Since madvise is a fast systemcall, it adds only a small overhead\n+ compared to the cost of accessing /sys/kernel/mm files. */\n+ if (DL_MAP_DEFAULT_THP_PAGESIZE != 0)\n+ {\n+ GL(dl_elf_thp_pagesize) = DL_MAP_DEFAULT_THP_PAGESIZE;\n+ GL(dl_thp_mode) = thp_mode_madvise;\n+ }\n+ else\n+ {\n+ GL(dl_elf_thp_pagesize) = __get_thp_size ();\n+ GL(dl_thp_mode) = __get_thp_mode ();\n+ /* We cap the huge page size at MAX_THP_PAGESIZE to avoid\n+\t over-aligning on systems with very large normal pages\n+\t (like 64K pages with 512M huge pages). */\n+ if (GL(dl_elf_thp_pagesize) > MAX_THP_PAGESIZE)\n+\tGL(dl_elf_thp_control) = 0;\n+ /* NB: Enable THP if THP is always enabled in the kernel. */\n+ else if (GL(dl_thp_mode) == thp_mode_always)\n+\tGL(dl_elf_thp_control) = 1;\n+ }\n+}\n+\n+static inline void\n+_dl_executable_postprocess (struct link_map *main_map,\n+\t\t\t const ElfW(Phdr) *phdr, ElfW(Word) phnum)\n+{\n+ if (GL(dl_elf_thp_control) == -1)\n+ _dl_get_thp_config ();\n+\n+ /* NB: In static executable, PT_GNU_PROPERTY is processed in target\n+ libc-start.h if it is needed by target. When ld.so is used, if\n+ a target doesn't need PT_GNU_PROPERTY, _dl_process_pt_gnu_property\n+ is an empty function. */\n+#ifdef SHARED\n+ /* Process program headers again, but scan them backwards since\n+ PT_GNU_PROPERTY is close to the end of program headers. */\n+ for (const ElfW(Phdr) *ph = &phdr[phnum]; ph != phdr; --ph)\n+ if (ph[-1].p_type == PT_GNU_PROPERTY)\n+ {\n+\t_dl_process_pt_gnu_property (main_map, -1, &ph[-1]);\n+\tbreak;\n+ }\n+#endif\n+\n+ /* Return if THP segment load isn't enabled. */\n+ if (GL(dl_elf_thp_control) <= 0)\n+ return;\n+\n+ /* NB: If DL_MAP_DEFAULT_THP_PAGESIZE is non-zero, dl_thp_mode is set\n+ to thp_mode_madvise. */\n+ if (DL_MAP_DEFAULT_THP_PAGESIZE == 0\n+ && GL(dl_thp_mode) != thp_mode_madvise)\n+ return;\n+\n+ /* When we get here, the main executable have been mapped in. Call\n+ madvise with MADV_HUGEPAGE for all THP eligible PT_LOAD segments. */\n+\n+ const ElfW(Phdr) *ph;\n+\n+ size_t thp_pagesize = GL(dl_elf_thp_pagesize);\n+\n+ /* Call __madvise if offset and address of the PT_LOAD segment are\n+ aligned to THP page size and it is read-only. */\n+ for (ph = phdr; ph < &phdr[phnum]; ++ph)\n+ if (ph->p_type == PT_LOAD\n+\t&& ph->p_memsz >= thp_pagesize\n+\t&& ((ph->p_vaddr | ph->p_offset) & (thp_pagesize - 1)) == 0\n+\t&& (ph->p_flags & (PF_W | PF_R)) == PF_R)\n+ __madvise ((void *) (main_map->l_addr + ph->p_vaddr),\n+\t\t ph->p_memsz, MADV_HUGEPAGE);\n+}\ndiff --git a/sysdeps/unix/sysv/linux/dl-load-post.h b/sysdeps/unix/sysv/linux/dl-load-post.h\nnew file mode 100644\nindex 0000000000..b3c4e16bb7\n--- /dev/null\n+++ b/sysdeps/unix/sysv/linux/dl-load-post.h\n@@ -0,0 +1,32 @@\n+/* _dl_postprocess_loadcmd_extra. Linux version.\n+ Copyright (C) 2026 Free Software Foundation, Inc.\n+ Copyright The GNU Toolchain Authors.\n+ This file is part of the GNU C Library.\n+\n+ The GNU C Library is free software; you can redistribute it and/or\n+ modify it under the terms of the GNU Lesser General Public\n+ License as published by the Free Software Foundation; either\n+ version 2.1 of the License, or (at your option) any later version.\n+\n+ The GNU C Library is distributed in the hope that it will be useful,\n+ but WITHOUT ANY WARRANTY; without even the implied warranty of\n+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n+ Lesser General Public License for more details.\n+\n+ You should have received a copy of the GNU Lesser General Public\n+ License along with the GNU C Library; if not, see\n+ <https://www.gnu.org/licenses/>. */\n+\n+/* Bits in the flags field of struct loadcmd. */\n+#define LOADCMD_POST_MADVISE_THP\t\t(0x1 << 0)\n+\n+/* After L has been mapped in, call madvise with MADV_HUGEPAGE if L is\n+ THP eligible. */\n+\n+static inline void\n+_dl_postprocess_loadcmd_extra (struct link_map *l, const struct loadcmd *c)\n+{\n+ if ((c->flags & LOADCMD_POST_MADVISE_THP) != 0)\n+ __madvise ((void *) (l->l_addr + c->mapstart),\n+\t c->mapend - c->mapstart, MADV_HUGEPAGE);\n+}\ndiff --git a/sysdeps/unix/sysv/linux/dl-map-segment-align.c b/sysdeps/unix/sysv/linux/dl-map-segment-align.c\nindex a39e74d91b..84548394ae 100644\n--- a/sysdeps/unix/sysv/linux/dl-map-segment-align.c\n+++ b/sysdeps/unix/sysv/linux/dl-map-segment-align.c\n@@ -17,39 +17,47 @@\n License along with the GNU C Library; if not, see\n <https://www.gnu.org/licenses/>. */\n \n+#include <ldsodefs.h>\n #include <dl-map-segment-align.h>\n-#include <dl-tunables.h>\n-#include <hugepages.h>\n \n-ElfW (Addr)\n-_dl_map_segment_align (const struct loadcmd *c, ElfW (Addr) p_align_max)\n+/* Set the mapalign field in entries in LOAD_CMDS to align PT_LOAD\n+ segments for THP. P_ALIGN_MAX is the maximum p_align value in all\n+ PT_LOAD segments. */\n+\n+void\n+_dl_map_segment_align (struct loadcmd *load_cmds, size_t n,\n+\t\t ElfW(Addr) p_align_max)\n {\n- static enum thp_mode_t thp_mode = thp_mode_not_supported;\n- static unsigned long int thp_pagesize;\n+ size_t i;\n+ enum thp_mode_t thp_mode = GL(dl_thp_mode);\n+ size_t thp_pagesize = GL(dl_elf_thp_pagesize);\n+ struct loadcmd *c = load_cmds;\n \n- if (TUNABLE_GET (glibc, elf, thp, int32_t, NULL) == 0)\n- return p_align_max;\n+ if (n == 0)\n+ return;\n \n- if (__glibc_unlikely (thp_mode == thp_mode_not_supported\n- || thp_pagesize == 0))\n+ if (GL(dl_elf_thp_control) <= 0\n+ || p_align_max >= thp_pagesize\n+ || !(thp_mode == thp_mode_always || thp_mode == thp_mode_madvise))\n {\n- unsigned long int default_thp_pagesize = DL_MAP_DEFAULT_THP_PAGESIZE;\n- thp_mode = default_thp_pagesize ? thp_mode_always : __get_thp_mode ();\n- thp_pagesize = default_thp_pagesize ? : __get_thp_size ();\n+ for (i = 0; i < n; i++, c++)\n+\tc->mapalign = p_align_max;\n+ return;\n }\n \n- /* Aligning load segments that are large enough to the PMD size helps\n- improve THP eligibility and reduces TLB pressure.\n- We cap the huge page size at MAX_THP_PAGESIZE to avoid over-aligning\n- on systems with very large normal pages (like 64K pages with 512M\n- huge pages). */\n- if (thp_mode == thp_mode_always\n- && thp_pagesize <= MAX_THP_PAGESIZE\n- && ((c->mapstart | c->mapoff) & (thp_pagesize - 1)) == 0\n- && (c->mapend - c->mapstart) >= thp_pagesize\n- && p_align_max < thp_pagesize\n- && (c->prot & PROT_WRITE) == 0)\n- return thp_pagesize;\n-\n- return p_align_max;\n+ /* Set the mapalign field to THP page size only if offset and address\n+ of the segment are aligned to THP page size, it is read-only and\n+ its size >= THP page size. It helps improve THP eligibility and\n+ reduces TLB pressure. */\n+ for (i = 0; i < n; i++, c++)\n+ if (((c->mapstart | c->mapoff) & (thp_pagesize - 1)) == 0\n+\t&& (c->mapend - c->mapstart) >= thp_pagesize\n+\t&& (c->prot & PROT_WRITE) == 0)\n+ {\n+\tc->mapalign = thp_pagesize;\n+\tif (thp_mode == thp_mode_madvise)\n+\t c->flags = LOADCMD_POST_MADVISE_THP;\n+ }\n+ else\n+ c->mapalign = p_align_max;\n }\ndiff --git a/sysdeps/unix/sysv/linux/dl-map-segment-align.h b/sysdeps/unix/sysv/linux/dl-map-segment-align.h\nindex d9b05181b7..8c03c5cb58 100644\n--- a/sysdeps/unix/sysv/linux/dl-map-segment-align.h\n+++ b/sysdeps/unix/sysv/linux/dl-map-segment-align.h\n@@ -19,9 +19,5 @@\n \n #include <dl-load.h>\n \n-#ifndef DL_MAP_DEFAULT_THP_PAGESIZE\n-# define DL_MAP_DEFAULT_THP_PAGESIZE\t0\n-#endif\n-\n-extern ElfW (Addr) _dl_map_segment_align\n- (const struct loadcmd *, ElfW (Addr)) attribute_hidden;\n+extern void _dl_map_segment_align\n+ (struct loadcmd *, size_t, ElfW(Addr)) attribute_hidden;\ndiff --git a/sysdeps/unix/sysv/linux/ldsodefs.h b/sysdeps/unix/sysv/linux/ldsodefs.h\nindex c63b649432..e39d9afe34 100644\n--- a/sysdeps/unix/sysv/linux/ldsodefs.h\n+++ b/sysdeps/unix/sysv/linux/ldsodefs.h\n@@ -21,6 +21,9 @@\n /* We have the auxiliary vector. */\n #define HAVE_AUX_VECTOR\n \n+/* We have transparent huge page. */\n+#define HAVE_THP\n+\n /* Get the real definitions. */\n #include_next <ldsodefs.h>\n \ndiff --git a/sysdeps/unix/sysv/linux/loongarch/Makefile b/sysdeps/unix/sysv/linux/loongarch/Makefile\nindex 0d5f087862..d5beb62440 100644\n--- a/sysdeps/unix/sysv/linux/loongarch/Makefile\n+++ b/sysdeps/unix/sysv/linux/loongarch/Makefile\n@@ -12,3 +12,6 @@ abi-ilp32s-condition\t:= __WORDSIZE == 32 && defined __loongarch_soft_float\n abi-ilp32d-condition\t:= __WORDSIZE == 32 && defined __loongarch_double_float\n abi-lp64s-condition\t:= __WORDSIZE == 64 && defined __loongarch_soft_float\n abi-lp64d-condition\t:= __WORDSIZE == 64 && defined __loongarch_double_float\n+\n+# Align THP tests to 32MB.\n+THP-PAGE-SIZE = 0x2000000\ndiff --git a/sysdeps/unix/sysv/linux/loongarch/lp64/dl-map-segment-align.h b/sysdeps/unix/sysv/linux/loongarch/lp64/hugepages.h\nsimilarity index 90%\nrename from sysdeps/unix/sysv/linux/loongarch/lp64/dl-map-segment-align.h\nrename to sysdeps/unix/sysv/linux/loongarch/lp64/hugepages.h\nindex c51ee4ac47..30252a9b86 100644\n--- a/sysdeps/unix/sysv/linux/loongarch/lp64/dl-map-segment-align.h\n+++ b/sysdeps/unix/sysv/linux/loongarch/lp64/hugepages.h\n@@ -1,4 +1,4 @@\n-/* _dl_map_segment_align. LoongArch64 Linux version.\n+/* Huge Page support. LoongArch64 Linux version.\n Copyright (C) 2026 Free Software Foundation, Inc.\n Copyright The GNU Toolchain Authors.\n This file is part of the GNU C Library.\n@@ -19,4 +19,4 @@\n \n #define DL_MAP_DEFAULT_THP_PAGESIZE (32 * 1024 * 1024)\n \n-#include_next <dl-map-segment-align.h>\n+#include_next <hugepages.h>\ndiff --git a/sysdeps/unix/sysv/linux/strace-tst-thp.sh b/sysdeps/unix/sysv/linux/strace-tst-thp.sh\nnew file mode 100644\nindex 0000000000..8903717fd4\n--- /dev/null\n+++ b/sysdeps/unix/sysv/linux/strace-tst-thp.sh\n@@ -0,0 +1,56 @@\n+#!/bin/sh\n+# Run THP test under strace to verify control of the THP segment load.\n+# Copyright (C) 2026 Free Software Foundation, Inc.\n+# This file is part of the GNU C Library.\n+\n+# The GNU C Library is free software; you can redistribute it and/or\n+# modify it under the terms of the GNU Lesser General Public\n+# License as published by the Free Software Foundation; either\n+# version 2.1 of the License, or (at your option) any later version.\n+\n+# The GNU C Library is distributed in the hope that it will be useful,\n+# but WITHOUT ANY WARRANTY; without even the implied warranty of\n+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n+# Lesser General Public License for more details.\n+\n+# You should have received a copy of the GNU Lesser General Public\n+# License along with the GNU C Library; if not, see\n+# <https://www.gnu.org/licenses/>.\n+\n+set -e\n+\n+rtld=\"$1\"\n+test_wrapper_env=\"$2\"\n+run_program_env=\"$3\"\n+library_path=\"$4\"\n+test_prog=\"$5\"\n+\n+# Test whether strace is available in the test environment. If not, skip\n+# the test.\n+${test_wrapper_env} ${run_program_env} \\\n+ /bin/sh -c \"command -v strace\" || exit 77\n+\n+# Finally the actual test inside the test environment, using the just\n+# build ld.so and new libraries to run the THP test under strace.\n+if /bin/sh -c \\\n+ \"${test_wrapper_env} ${run_program_env} strace ${rtld} \\\n+ --library-path ${library_path} ${test_prog} 2>&1 \\\n+ | grep -E \\\"madvise(.*, MADV_HUGEPAGE)\\\"\"; then\n+ case x\"${run_program_env}\" in\n+ *glibc.elf.thp=1*)\n+ exit 0\n+ ;;\n+ *)\n+ exit 1\n+ ;;\n+ esac\n+else\n+ case x\"${run_program_env}\" in\n+ *glibc.elf.thp=0*)\n+ exit 0\n+ ;;\n+ *)\n+ exit 1\n+ ;;\n+ esac\n+fi\ndiff --git a/sysdeps/unix/sysv/linux/tst-thp-1-no-s-code-pde.c b/sysdeps/unix/sysv/linux/tst-thp-1-no-s-code-pde.c\nnew file mode 100644\nindex 0000000000..3fd01e9bfe\n--- /dev/null\n+++ b/sysdeps/unix/sysv/linux/tst-thp-1-no-s-code-pde.c\n@@ -0,0 +1,19 @@\n+/* Test PDE with THP segment load linked with -Wl,-z,noseparate-code.\n+ Copyright (C) 2026 Free Software Foundation, Inc.\n+ This file is part of the GNU C Library.\n+\n+ The GNU C Library is free software; you can redistribute it and/or\n+ modify it under the terms of the GNU Lesser General Public\n+ License as published by the Free Software Foundation; either\n+ version 2.1 of the License, or (at your option) any later version.\n+\n+ The GNU C Library is distributed in the hope that it will be useful,\n+ but WITHOUT ANY WARRANTY; without even the implied warranty of\n+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n+ Lesser General Public License for more details.\n+\n+ You should have received a copy of the GNU Lesser General Public\n+ License along with the GNU C Library; if not, see\n+ <http://www.gnu.org/licenses/>. */\n+\n+#include \"tst-thp-1.c\"\ndiff --git a/sysdeps/unix/sysv/linux/tst-thp-1-no-s-code-static.c b/sysdeps/unix/sysv/linux/tst-thp-1-no-s-code-static.c\nnew file mode 100644\nindex 0000000000..d0ae0f1ff0\n--- /dev/null\n+++ b/sysdeps/unix/sysv/linux/tst-thp-1-no-s-code-static.c\n@@ -0,0 +1,19 @@\n+/* Test static with THP segment load linked with -Wl,-z,noseparate-code.\n+ Copyright (C) 2026 Free Software Foundation, Inc.\n+ This file is part of the GNU C Library.\n+\n+ The GNU C Library is free software; you can redistribute it and/or\n+ modify it under the terms of the GNU Lesser General Public\n+ License as published by the Free Software Foundation; either\n+ version 2.1 of the License, or (at your option) any later version.\n+\n+ The GNU C Library is distributed in the hope that it will be useful,\n+ but WITHOUT ANY WARRANTY; without even the implied warranty of\n+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n+ Lesser General Public License for more details.\n+\n+ You should have received a copy of the GNU Lesser General Public\n+ License along with the GNU C Library; if not, see\n+ <http://www.gnu.org/licenses/>. */\n+\n+#include \"tst-thp-1.c\"\ndiff --git a/sysdeps/unix/sysv/linux/tst-thp-1-no-s-code.c b/sysdeps/unix/sysv/linux/tst-thp-1-no-s-code.c\nnew file mode 100644\nindex 0000000000..5eb1e005ed\n--- /dev/null\n+++ b/sysdeps/unix/sysv/linux/tst-thp-1-no-s-code.c\n@@ -0,0 +1,19 @@\n+/* Test THP segment load linked with -Wl,-z,noseparate-code.\n+ Copyright (C) 2026 Free Software Foundation, Inc.\n+ This file is part of the GNU C Library.\n+\n+ The GNU C Library is free software; you can redistribute it and/or\n+ modify it under the terms of the GNU Lesser General Public\n+ License as published by the Free Software Foundation; either\n+ version 2.1 of the License, or (at your option) any later version.\n+\n+ The GNU C Library is distributed in the hope that it will be useful,\n+ but WITHOUT ANY WARRANTY; without even the implied warranty of\n+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n+ Lesser General Public License for more details.\n+\n+ You should have received a copy of the GNU Lesser General Public\n+ License along with the GNU C Library; if not, see\n+ <http://www.gnu.org/licenses/>. */\n+\n+#include \"tst-thp-1.c\"\ndiff --git a/sysdeps/unix/sysv/linux/tst-thp-1-pde.c b/sysdeps/unix/sysv/linux/tst-thp-1-pde.c\nnew file mode 100644\nindex 0000000000..d854dd43da\n--- /dev/null\n+++ b/sysdeps/unix/sysv/linux/tst-thp-1-pde.c\n@@ -0,0 +1,19 @@\n+/* Test PDE with THP segment load linked with -Wl,-z,separate-code.\n+ Copyright (C) 2026 Free Software Foundation, Inc.\n+ This file is part of the GNU C Library.\n+\n+ The GNU C Library is free software; you can redistribute it and/or\n+ modify it under the terms of the GNU Lesser General Public\n+ License as published by the Free Software Foundation; either\n+ version 2.1 of the License, or (at your option) any later version.\n+\n+ The GNU C Library is distributed in the hope that it will be useful,\n+ but WITHOUT ANY WARRANTY; without even the implied warranty of\n+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n+ Lesser General Public License for more details.\n+\n+ You should have received a copy of the GNU Lesser General Public\n+ License along with the GNU C Library; if not, see\n+ <http://www.gnu.org/licenses/>. */\n+\n+#include \"tst-thp-1.c\"\ndiff --git a/sysdeps/unix/sysv/linux/tst-thp-1-static.c b/sysdeps/unix/sysv/linux/tst-thp-1-static.c\nnew file mode 100644\nindex 0000000000..66d7e12954\n--- /dev/null\n+++ b/sysdeps/unix/sysv/linux/tst-thp-1-static.c\n@@ -0,0 +1,19 @@\n+/* Test static with THP segment load linked with -Wl,-z,separate-code.\n+ Copyright (C) 2026 Free Software Foundation, Inc.\n+ This file is part of the GNU C Library.\n+\n+ The GNU C Library is free software; you can redistribute it and/or\n+ modify it under the terms of the GNU Lesser General Public\n+ License as published by the Free Software Foundation; either\n+ version 2.1 of the License, or (at your option) any later version.\n+\n+ The GNU C Library is distributed in the hope that it will be useful,\n+ but WITHOUT ANY WARRANTY; without even the implied warranty of\n+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n+ Lesser General Public License for more details.\n+\n+ You should have received a copy of the GNU Lesser General Public\n+ License along with the GNU C Library; if not, see\n+ <http://www.gnu.org/licenses/>. */\n+\n+#include \"tst-thp-1.c\"\ndiff --git a/sysdeps/unix/sysv/linux/tst-thp-1.c b/sysdeps/unix/sysv/linux/tst-thp-1.c\nnew file mode 100644\nindex 0000000000..49eea7069c\n--- /dev/null\n+++ b/sysdeps/unix/sysv/linux/tst-thp-1.c\n@@ -0,0 +1,28 @@\n+/* Test THP segment load linked with -Wl,-z,separate-code.\n+ Copyright (C) 2026 Free Software Foundation, Inc.\n+ This file is part of the GNU C Library.\n+\n+ The GNU C Library is free software; you can redistribute it and/or\n+ modify it under the terms of the GNU Lesser General Public\n+ License as published by the Free Software Foundation; either\n+ version 2.1 of the License, or (at your option) any later version.\n+\n+ The GNU C Library is distributed in the hope that it will be useful,\n+ but WITHOUT ANY WARRANTY; without even the implied warranty of\n+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n+ Lesser General Public License for more details.\n+\n+ You should have received a copy of the GNU Lesser General Public\n+ License along with the GNU C Library; if not, see\n+ <http://www.gnu.org/licenses/>. */\n+\n+#include \"tst-thp-align-check.h\"\n+\n+static int\n+do_test (void)\n+{\n+ check_align (\"tst-thp-1\");\n+ return 0;\n+}\n+\n+#include <support/test-driver.c>\ndiff --git a/sysdeps/unix/sysv/linux/tst-thp-align-check.h b/sysdeps/unix/sysv/linux/tst-thp-align-check.h\nnew file mode 100644\nindex 0000000000..8f1efc0ef1\n--- /dev/null\n+++ b/sysdeps/unix/sysv/linux/tst-thp-align-check.h\n@@ -0,0 +1,124 @@\n+/* Test the THP compatible alignment of PT_LOAD segments.\n+\n+ Copyright (C) 2026 Free Software Foundation, Inc.\n+\n+ The GNU C Library is free software; you can redistribute it and/or\n+ modify it under the terms of the GNU Lesser General Public\n+ License as published by the Free Software Foundation; either\n+ version 2.1 of the License, or (at your option) any later version.\n+\n+ The GNU C Library is distributed in the hope that it will be useful,\n+ but WITHOUT ANY WARRANTY; without even the implied warranty of\n+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n+ Lesser General Public License for more details.\n+\n+ You should have received a copy of the GNU Lesser General Public\n+ License along with the GNU C Library; if not, see\n+ <https://www.gnu.org/licenses/>. */\n+\n+#include <fcntl.h>\n+#include <stdint.h>\n+#include <stdlib.h>\n+#include <string.h>\n+#include <intprops.h>\n+#include <inttypes.h>\n+#include <support/check.h>\n+#include <support/xstdio.h>\n+#include <support/xunistd.h>\n+#undef attribute_hidden\n+#define attribute_hidden\n+#include <hugepages.h>\t/* For enum thp_mode_t and MAX_THP_PAGESIZE. */\n+#undef attribute_hidden\n+\n+static unsigned long int\n+get_thp_size (void)\n+{\n+ int fd = open (\"/sys/kernel/mm/transparent_hugepage/hpage_pmd_size\",\n+ O_RDONLY, 0);\n+ if (fd == -1)\n+ return 0;\n+\n+ char str[INT_BUFSIZE_BOUND (unsigned long int)];\n+ ssize_t s = read (fd, str, sizeof (str));\n+ close (fd);\n+ if (s < 0)\n+ return 0;\n+\n+ unsigned long int r = 0;\n+ for (ssize_t i = 0; i < s; i++)\n+ {\n+ if (str[i] == '\\n')\n+ break;\n+ r *= 10;\n+ r += str[i] - '0';\n+ }\n+ return r;\n+}\n+\n+static enum thp_mode_t\n+get_thp_mode (void)\n+{\n+ int fd = open (\"/sys/kernel/mm/transparent_hugepage/enabled\", O_RDONLY, 0);\n+ if (fd == -1)\n+ return thp_mode_not_supported;\n+\n+ static const char mode_always[] = \"[always] madvise never\\n\";\n+ static const char mode_madvise[] = \"always [madvise] never\\n\";\n+ static const char mode_never[] = \"always madvise [never]\\n\";\n+\n+ char str[sizeof(mode_always)];\n+ ssize_t s = read (fd, str, sizeof (str));\n+ if (s >= sizeof str || s < 0)\n+ return thp_mode_not_supported;\n+ str[s] = '\\0';\n+ close (fd);\n+\n+ if (s == sizeof (mode_always) - 1)\n+ {\n+ if (strcmp (str, mode_always) == 0)\n+ return thp_mode_always;\n+ else if (strcmp (str, mode_madvise) == 0)\n+ return thp_mode_madvise;\n+ else if (strcmp (str, mode_never) == 0)\n+ return thp_mode_never;\n+ }\n+ return thp_mode_not_supported;\n+}\n+\n+static void\n+check_align (const char *name)\n+{\n+ unsigned long int thp_size = get_thp_size ();\n+ enum thp_mode_t thp_mode = get_thp_mode ();\n+\n+ if (thp_size == 0)\n+ FAIL_UNSUPPORTED (\"unable to get THP size.\\n\");\n+\n+ if (thp_size > MAX_THP_PAGESIZE)\n+ FAIL_UNSUPPORTED (\"THP size exceeds MAX_THP_PAGESIZE.\\n\");\n+\n+ if (thp_mode != thp_mode_always && thp_mode != thp_mode_madvise)\n+ FAIL_UNSUPPORTED (\"THP mode is not always nor madvise.\\n\");\n+\n+ FILE *f = xfopen (\"/proc/self/maps\", \"r\");\n+ char *line = NULL;\n+ size_t len;\n+\n+ while (xgetline (&line, &len, f))\n+ {\n+ uintptr_t from, to;\n+ char *prot = NULL, *path = NULL;\n+ int r = sscanf (line, \"%\" SCNxPTR \"-%\" SCNxPTR \"%ms%*s%*s%*s%ms\",\n+ &from, &to, &prot, &path);\n+\n+ TEST_VERIFY (r == 3 || r == 4);\n+\n+ if (strstr (prot, \"x\") && strstr (path, name))\n+ TEST_COMPARE (from % thp_size, 0);\n+\n+ free (path);\n+ }\n+\n+ free (line);\n+ xfclose (f);\n+}\ndiff --git a/sysdeps/unix/sysv/linux/tst-thp-align.c b/sysdeps/unix/sysv/linux/tst-thp-align.c\nindex 0b3f18e000..2e44109ba6 100644\n--- a/sysdeps/unix/sysv/linux/tst-thp-align.c\n+++ b/sysdeps/unix/sysv/linux/tst-thp-align.c\n@@ -16,129 +16,10 @@\n License along with the GNU C Library; if not, see\n <https://www.gnu.org/licenses/>. */\n \n-#include <fcntl.h>\n-#include <stdint.h>\n-#include <stdlib.h>\n-#include <string.h>\n-#include <intprops.h>\n-#include <inttypes.h>\n-#include <support/check.h>\n #include <support/xdlfcn.h>\n-#include <support/xstdio.h>\n-#include <support/xunistd.h>\n+#include \"tst-thp-align-check.h\"\n \n #define THP_SIZE_MOD_NAME \"tst-thp-size-mod.so\"\n-#define MAX_THP_PAGESIZE (32 * 1024 * 1024)\n-\n-enum thp_mode_t\n-{\n- thp_mode_always,\n- thp_mode_madvise,\n- thp_mode_never,\n- thp_mode_not_supported\n-};\n-\n-static unsigned long int\n-get_thp_size (void)\n-{\n- int fd = open (\"/sys/kernel/mm/transparent_hugepage/hpage_pmd_size\",\n- O_RDONLY, 0);\n- if (fd == -1)\n- return 0;\n-\n- char str[INT_BUFSIZE_BOUND (unsigned long int)];\n- ssize_t s = read (fd, str, sizeof (str));\n- close (fd);\n- if (s < 0)\n- return 0;\n-\n- unsigned long int r = 0;\n- for (ssize_t i = 0; i < s; i++)\n- {\n- if (str[i] == '\\n')\n- break;\n- r *= 10;\n- r += str[i] - '0';\n- }\n- return r;\n-}\n-\n-static enum thp_mode_t\n-get_thp_mode (void)\n-{\n- int fd = open (\"/sys/kernel/mm/transparent_hugepage/enabled\", O_RDONLY, 0);\n- if (fd == -1)\n- return thp_mode_not_supported;\n-\n- static const char mode_always[] = \"[always] madvise never\\n\";\n- static const char mode_madvise[] = \"always [madvise] never\\n\";\n- static const char mode_never[] = \"always madvise [never]\\n\";\n-\n- char str[sizeof(mode_always)];\n- ssize_t s = read (fd, str, sizeof (str));\n- if (s >= sizeof str || s < 0)\n- return thp_mode_not_supported;\n- str[s] = '\\0';\n- close (fd);\n-\n- if (s == sizeof (mode_always) - 1)\n- {\n- if (strcmp (str, mode_always) == 0)\n- return thp_mode_always;\n- else if (strcmp (str, mode_madvise) == 0)\n- return thp_mode_madvise;\n- else if (strcmp (str, mode_never) == 0)\n- return thp_mode_never;\n- }\n- return thp_mode_not_supported;\n-}\n-\n-static void\n-check_align (void)\n-{\n- unsigned long int thp_size = get_thp_size ();\n- enum thp_mode_t thp_mode = get_thp_mode ();\n-\n- if (thp_size == 0)\n- {\n- FAIL_UNSUPPORTED (\"unable to get THP size.\\n\");\n- return;\n- }\n-\n- if (thp_size > MAX_THP_PAGESIZE)\n- {\n- FAIL_UNSUPPORTED (\"THP size exceeds MAX_THP_PAGESIZE.\\n\");\n- return;\n- }\n-\n- if (thp_mode != thp_mode_always)\n- {\n- FAIL_UNSUPPORTED (\"THP mode is not always.\\n\");\n- return;\n- }\n-\n- FILE *f = xfopen (\"/proc/self/maps\", \"r\");\n- char *line = NULL;\n- size_t len;\n-\n- while (xgetline (&line, &len, f))\n- {\n- uintptr_t from, to;\n- char *prot = NULL, *path = NULL;\n- int r = sscanf (line, \"%\" SCNxPTR \"-%\" SCNxPTR \"%ms%*s%*s%*s%ms\",\n- &from, &to, &prot, &path);\n-\n- TEST_VERIFY (r == 3 || r == 4);\n-\n- if (strstr (prot, \"x\") && strstr (path, THP_SIZE_MOD_NAME))\n- TEST_COMPARE (from % thp_size, 0);\n-\n- free (path);\n- }\n-\n- free (line);\n- xfclose (f);\n-}\n \n static int\n do_test (void)\n@@ -146,7 +27,7 @@ do_test (void)\n void *dl;\n \n dl = xdlopen (THP_SIZE_MOD_NAME, RTLD_NOW);\n- check_align ();\n+ check_align (THP_SIZE_MOD_NAME);\n xdlclose (dl);\n \n return 0;\ndiff --git a/sysdeps/unix/sysv/linux/x86/hugepages.h b/sysdeps/unix/sysv/linux/x86/hugepages.h\nnew file mode 100644\nindex 0000000000..1a8c370969\n--- /dev/null\n+++ b/sysdeps/unix/sysv/linux/x86/hugepages.h\n@@ -0,0 +1,22 @@\n+/* Huge Page support. Linux/x86 version.\n+ Copyright (C) 2026 Free Software Foundation, Inc.\n+ Copyright The GNU Toolchain Authors.\n+ This file is part of the GNU C Library.\n+\n+ The GNU C Library is free software; you can redistribute it and/or\n+ modify it under the terms of the GNU Lesser General Public\n+ License as published by the Free Software Foundation; either\n+ version 2.1 of the License, or (at your option) any later version.\n+\n+ The GNU C Library is distributed in the hope that it will be useful,\n+ but WITHOUT ANY WARRANTY; without even the implied warranty of\n+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n+ Lesser General Public License for more details.\n+\n+ You should have received a copy of the GNU Lesser General Public\n+ License along with the GNU C Library; if not, see\n+ <https://www.gnu.org/licenses/>. */\n+\n+#define DL_MAP_DEFAULT_THP_PAGESIZE (2 * 1024 * 1024)\n+\n+#include_next <hugepages.h>\n-- \n2.53.0\n\n", "prefixes": [ "v5" ] }