diff options
Diffstat (limited to '0001-elf-dynamic-linker-load-shared-object-use-hugepage-a.patch')
-rw-r--r-- | 0001-elf-dynamic-linker-load-shared-object-use-hugepage-a.patch | 1206 |
1 files changed, 1206 insertions, 0 deletions
diff --git a/0001-elf-dynamic-linker-load-shared-object-use-hugepage-a.patch b/0001-elf-dynamic-linker-load-shared-object-use-hugepage-a.patch new file mode 100644 index 0000000..fdbdead --- /dev/null +++ b/0001-elf-dynamic-linker-load-shared-object-use-hugepage-a.patch @@ -0,0 +1,1206 @@ +From d3a58c218f2c1605499be11a4b3a21f8ef133180 Mon Sep 17 00:00:00 2001 +From: Lv Ying <lvying6@huawei.com> +Date: Mon, 7 Mar 2022 03:28:33 +0000 +Subject: [PATCH] elf: dynamic linker load shared object use hugepage as much + as possible + +This patch provides environment variables HUGEPAGE_PROBE and LD_HUGEPAGE_LIB +to enable load shared object use hugepage. + +When load shared object, ld.so first to map text PT_LOAD segment into 2MB +hugepage area. And then, load the neighbor PT_LOAD segment use 2MB hugepage +as much as possible. This means: +* PT_LOAD segment's mapstart_va is 2MB aligned, howerver its maplenth is + less than 2MB, fallback to 4KB page +* PT_LOAD segment's mapstart_va is 2MB aligned, and its maplenth is larger + than 2MB, the first 2MB aligned area use 2MB hugepage, the end area (if it exists) use 4KB area +* PT_LOAD segment's mapstart_va is not 2MB aligned, alignup this address + to 2MB aligned address mapstart_align, if its maplenth is less than + mapstart_align - mapstart_va, or maplenth - (mapstart_align - mapstart_va), fallback to 4KB hugepage +* PT_LOAD segment's mapstart_va is not 2MB aligned, maplenth - (mapstart_align - mapstart_va) + is still larger than 2MB, first map (mapstart_align - mapstart_va) as 4KB page + then map 2MB aligned area as hugepage, the end area (if it exists) use 4KB area +--- + config.h.in | 2 + + configure | 20 ++ + configure.ac | 11 + + elf/Makefile | 8 + + elf/dl-environ.c | 11 + + elf/dl-load.c | 38 +++ + elf/dl-load.h | 16 + + elf/dl-map-segments-hugepage.h | 593 +++++++++++++++++++++++++++++++++ + elf/dl-support.c | 4 + + elf/elf.h | 2 + + elf/hugepageedit.c | 169 ++++++++++ + elf/rtld.c | 63 ++++ + sysdeps/generic/ldsodefs.h | 11 +- + 13 files changed, 947 insertions(+), 1 deletion(-) + create mode 100644 elf/dl-map-segments-hugepage.h + create mode 100644 elf/hugepageedit.c + +diff --git a/config.h.in b/config.h.in +index db6402cd..13101496 100644 +--- a/config.h.in ++++ b/config.h.in +@@ -277,6 +277,8 @@ + /* Define if static PIE is supported. */ + #undef SUPPORT_STATIC_PIE + ++#undef HUGEPAGE_SHARED_LIB ++ + /* Define if static PIE is enabled. */ + #define ENABLE_STATIC_PIE 0 + +diff --git a/configure b/configure +index 7272fbf6..43993923 100755 +--- a/configure ++++ b/configure +@@ -670,6 +670,7 @@ stack_protector + libc_cv_ssp + libc_cv_with_fp + base_machine ++enable_hugepage_shared_library + have_tunables + build_pt_chown + build_nscd +@@ -791,6 +792,7 @@ enable_pt_chown + enable_tunables + enable_mathvec + enable_cet ++enable_hugepage_shared_library + enable_scv + with_cpu + ' +@@ -1464,6 +1466,9 @@ Optional Features: + depends on architecture] + --enable-cet enable Intel Control-flow Enforcement Technology + (CET), x86 only ++ --enable-hugepage-shared-library ++ enable shared library use huge page to decrease TLB ++ miss, x86_64 aarch64 only + --disable-scv syscalls will not use scv instruction, even if the + kernel supports it, powerpc only + +@@ -3830,6 +3835,21 @@ if test "$use_scv" != "no"; then : + + fi + ++# Check whether --enable-hugepage-shared-library was given. ++if test "${enable_hugepage_shared_library+set}" = set; then : ++ enableval=$enable_hugepage_shared_library; enable_hugepage_shared_library=$enableval ++else ++ enable_hugepage_shared_library=no ++fi ++ ++ ++config_vars="$config_vars ++enable-hugepage-shared-library = $enable_hugepage_shared_library" ++if test "$enable_hugepage_shared_library" = yes; then ++ $as_echo "#define HUGEPAGE_SHARED_LIB 1" >>confdefs.h ++ ++fi ++ + # We keep the original values in `$config_*' and never modify them, so we + # can write them unchanged into config.make. Everything else uses + # $machine, $vendor, and $os, and changes them whenever convenient. +diff --git a/configure.ac b/configure.ac +index af47cd51..27a48338 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -478,6 +478,17 @@ AC_ARG_ENABLE([scv], + + AS_IF([[test "$use_scv" != "no"]],[AC_DEFINE(USE_PPC_SCV)]) + ++AC_ARG_ENABLE([hugepage-shared-library], ++ AC_HELP_STRING([--enable-hugepage-shared-library], ++ [enable shared library use huge page to decrease TLB miss, x86_64 aarch64 only]), ++ [enable_hugepage_shared_library=$enableval], ++ [enable_hugepage_shared_library=no]) ++ ++LIBC_CONFIG_VAR([enable-hugepage-shared-library], [$enable_hugepage_shared_library]) ++if test "$enable_hugepage_shared_library" = yes; then ++ AC_DEFINE(HUGEPAGE_SHARED_LIB) ++fi ++ + # We keep the original values in `$config_*' and never modify them, so we + # can write them unchanged into config.make. Everything else uses + # $machine, $vendor, and $os, and changes them whenever convenient. +diff --git a/elf/Makefile b/elf/Makefile +index 6fd515ba..32aba7ac 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -207,6 +207,14 @@ others-extras = $(ldconfig-modules) + endif + endif + ++ifeq (yes,$(enable-hugepage-shared-library)) ++others += hugepageedit ++others-pie += hugepageedit ++install-bin += hugepageedit ++ ++$(objpfx)hugepageedit: $(objpfx)hugepageedit.o ++endif ++ + # To find xmalloc.c and xstrdup.c + vpath %.c ../locale/programs + +diff --git a/elf/dl-environ.c b/elf/dl-environ.c +index 31c1c09f..ac70c9ab 100644 +--- a/elf/dl-environ.c ++++ b/elf/dl-environ.c +@@ -31,6 +31,17 @@ _dl_next_ld_env_entry (char ***position) + + while (*current != NULL) + { ++#ifdef HUGEPAGE_SHARED_LIB ++ #define LEN_HUGEPAGE_PROBE (sizeof("HUGEPAGE_PROBE") - 1) ++ if (memcmp (*current, "HUGEPAGE_PROBE", LEN_HUGEPAGE_PROBE) == 0) ++ { ++ result = *current; ++ ++ /* Save current position for next visit. */ ++ *position = ++current; ++ break; ++ } ++#endif + if (__builtin_expect ((*current)[0] == 'L', 0) + && (*current)[1] == 'D' && (*current)[2] == '_') + { +diff --git a/elf/dl-load.c b/elf/dl-load.c +index 0976977f..f4b5c4a7 100644 +--- a/elf/dl-load.c ++++ b/elf/dl-load.c +@@ -73,6 +73,9 @@ struct filebuf + #include <dl-sysdep-open.h> + #include <dl-prop.h> + #include <not-cancel.h> ++#ifdef HUGEPAGE_SHARED_LIB ++#include <dl-map-segments-hugepage.h> ++#endif + + #include <endian.h> + #if BYTE_ORDER == BIG_ENDIAN +@@ -1131,6 +1134,9 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd, + size_t nloadcmds = 0; + bool has_holes = false; + bool empty_dynamic = false; ++#ifdef HUGEPAGE_SHARED_LIB ++ bool use_hugepage = false; ++#endif + + /* The struct is initialized to zero so this is not necessary: + l->l_ld = 0; +@@ -1188,6 +1194,11 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd, + if (nloadcmds > 1 && c[-1].mapend != c->mapstart) + has_holes = true; + ++#ifdef HUGEPAGE_SHARED_LIB ++ if (ph->p_flags & PF_HUGEPAGE) ++ use_hugepage = true; ++#endif ++ + /* Optimize a common case. */ + #if (PF_R | PF_W | PF_X) == 7 && (PROT_READ | PROT_WRITE | PROT_EXEC) == 7 + c->prot = (PF_TO_PROT +@@ -1278,12 +1289,39 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd, + /* Length of the sections to be loaded. */ + maplength = loadcmds[nloadcmds - 1].allocend - loadcmds[0].mapstart; + ++#ifdef HUGEPAGE_SHARED_LIB ++#define ERRSTRING_BUF_LEN 1024 ++ int hp_errcode = 0; ++ char hp_buf[ERRSTRING_BUF_LEN]; ++ if ((GLRO(dl_hugepage_mask) & DL_HUGEPAGE_LIB_LARGE_IN_FLAG) || ++ ((GLRO(dl_hugepage_mask) & DL_HUGEPAGE_PROBE_FLAG) && use_hugepage)) ++ { ++ errstring = _dl_map_segments_largein (l, fd, header, type, loadcmds, nloadcmds, ++ maplength, has_holes); ++ if (__glibc_unlikely (errstring != NULL)) ++ { ++ hp_errcode = errno; ++ /* __strerror_r will set hp_buf last character '\0', hp_buf will not overflow */ ++ if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_FILES)) ++ _dl_debug_printf ("_dl_map_segments_largein: %s, %s\n", errstring, ++ hp_errcode ? __strerror_r (hp_errcode, hp_buf, sizeof hp_buf) : ""); ++ goto fallback; ++ } ++ } ++ else ++ { ++ fallback: ++ errstring = _dl_map_segments (l, fd, header, type, loadcmds, nloadcmds, ++ maplength, has_holes, loader); ++ } ++#else + /* Now process the load commands and map segments into memory. + This is responsible for filling in: + l_map_start, l_map_end, l_addr, l_contiguous, l_text_end, l_phdr + */ + errstring = _dl_map_segments (l, fd, header, type, loadcmds, nloadcmds, + maplength, has_holes, loader); ++#endif + if (__glibc_unlikely (errstring != NULL)) + { + /* Mappings can be in an inconsistent state: avoid unmap. */ +diff --git a/elf/dl-load.h b/elf/dl-load.h +index e329d49a..d3f69466 100644 +--- a/elf/dl-load.h ++++ b/elf/dl-load.h +@@ -131,5 +131,21 @@ static const char *_dl_map_segments (struct link_map *l, int fd, + #define DL_MAP_SEGMENTS_ERROR_MAP_ZERO_FILL \ + N_("cannot map zero-fill pages") + ++#ifdef HUGEPAGE_SHARED_LIB ++#define DL_MAP_SEGMENTS_ERROR_TYPE \ ++ N_("cannot map Non shared object file in hugepage") ++#define DL_MAP_SEGMENTS_ERROR_READ_SEGMENT \ ++ N_("failed to read shared object file") ++#define DL_MAP_SEGMENTS_ERROR_ARRANGE \ ++ N_("shared object's PT_LOAD segment in wrong arrange") ++#define DL_MAP_SEGMENTS_ERROR_MAP_HOLE_FILL \ ++ N_("failed to mmap shared object's hole part of PT_LOAD") ++#define DL_MAP_RESERVED_HUGEPAGE_AREA_ERROR \ ++ N_("failed to map reserved 2MB contiguous hugepage va space") ++#define DL_FIND_EXEC_SEGMENT_ERROR \ ++ N_("fail to find exec prot segment") ++#define DL_MAP_SEGMENT_ERROR_EXTRA_SIZE \ ++ N_("wrong segment extra size") ++#endif + + #endif /* dl-load.h */ +diff --git a/elf/dl-map-segments-hugepage.h b/elf/dl-map-segments-hugepage.h +new file mode 100644 +index 00000000..cd7b6d79 +--- /dev/null ++++ b/elf/dl-map-segments-hugepage.h +@@ -0,0 +1,593 @@ ++/* Map a shared object's segments into hugepage. Generic version. ++ Copyright (C) 1995-2021 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 ++ <http://www.gnu.org/licenses/>. */ ++ ++#include <dl-load.h> ++ ++#define SHFIT_2MB 21 ++#define SIZE_2MB 0x200000 ++#define MASK_2MB 0x1FFFFF ++#define THRESHOLD 16 ++ ++/* ++ * Find the first PT_LOAD segment with execute permission ++ */ ++static __always_inline const struct loadcmd * ++_find_exec_segment(const struct loadcmd loadcmds[], size_t nloadcmds) ++{ ++ const struct loadcmd *c = loadcmds; ++ ++ while (c < &loadcmds[nloadcmds]) ++ { ++ if (c->prot & PROT_EXEC) ++ return c; ++ c++; ++ } ++ return NULL; ++} ++ ++static __always_inline void * ++__mmap_reserved_area(const struct loadcmd loadcmds[], size_t nloadcmds, ++ size_t *maparealen) ++{ ++ const struct loadcmd * c = loadcmds; ++ *maparealen = 0; ++ ++ while (c < &loadcmds[nloadcmds]) ++ { ++ *maparealen += ALIGN_UP((c->mapend > c->allocend ? c->mapend : c->allocend), SIZE_2MB) - ++ ALIGN_DOWN(c->mapstart, SIZE_2MB); ++ c++; ++ } ++ ++ /* ++ * Get 2MB aligned contiguous va space ++ * This va space can not be munmap in case of multi thread dlopen concurrently ++ */ ++ void *map_area_start = __mmap(0, *maparealen, PROT_NONE, ++ MAP_PRIVATE|MAP_ANONYMOUS|MAP_HUGETLB|(SHFIT_2MB << MAP_HUGE_SHIFT), -1, 0); ++ if (__glibc_unlikely (map_area_start == MAP_FAILED)) ++ return MAP_FAILED; ++ ++ /* ++ * Remap 2MB aligned contiguous va space into 4KB contiguous va space ++ * to avoid the tedious work of splitting hugepage into 4KB page ++ */ ++ if (__glibc_unlikely(__mmap(map_area_start, *maparealen, PROT_NONE, ++ MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED, -1, 0) ++ == MAP_FAILED)) ++ { ++ goto unmap_reserved_area; ++ } ++ return map_area_start; ++ ++unmap_reserved_area: ++ __munmap(map_area_start, *maparealen); ++ return MAP_FAILED; ++} ++ ++static __always_inline size_t ++_get_relro_len(struct link_map *l, const struct loadcmd *c) ++{ ++ size_t relro_len = 0; ++ if (c->mapstart == ALIGN_DOWN (l->l_relro_addr, GLRO(dl_pagesize))) ++ { ++ relro_len = ALIGN_DOWN(l->l_relro_addr + l->l_relro_size, GLRO(dl_pagesize)) - ++ ALIGN_DOWN(l->l_relro_addr, GLRO(dl_pagesize)); ++ } ++ return relro_len; ++} ++ ++/* ++ * the alignment stands for the size of page which is to be cleared to zero ++ */ ++static __always_inline const char * ++_zero_tail_page(const struct loadcmd *c, ElfW(Addr) zero, ElfW(Addr) zeropage, ++ size_t alignment) ++{ ++ if (__glibc_unlikely ((c->prot & PROT_WRITE) == 0)) ++ { ++ /* Dag nab it. */ ++ if (__mprotect ((caddr_t) ALIGN_DOWN(zero, alignment), alignment, ++ c->prot|PROT_WRITE) < 0) ++ return DL_MAP_SEGMENTS_ERROR_MPROTECT; ++ } ++ memset ((void *) zero, '\0', zeropage - zero); ++ if (__glibc_unlikely ((c->prot & PROT_WRITE) == 0)) ++ __mprotect ((caddr_t) ALIGN_DOWN(zero, alignment), alignment, c->prot); ++ return NULL; ++} ++ ++static __always_inline const char * ++_mmap_remain_zero_page(ElfW(Addr) zeropage, ElfW(Addr) zeroend, int prot) ++{ ++ ElfW(Addr) hp_start = ALIGN_UP(zeropage, SIZE_2MB); ++ size_t len = 0, mod = 0; ++ caddr_t mapat; ++ ++ if (zeroend > hp_start && zeroend - hp_start >= SIZE_2MB) ++ { ++ len = zeroend - hp_start; ++ mod = len % SIZE_2MB; ++ } ++ else ++ hp_start = 0; ++ ++ if (hp_start == 0) ++ { ++ mapat = __mmap((caddr_t) zeropage, zeroend - zeropage, prot, ++ MAP_ANON|MAP_PRIVATE|MAP_FIXED, -1, 0); ++ if (__glibc_unlikely (mapat == MAP_FAILED)) ++ return DL_MAP_SEGMENTS_ERROR_MAP_ZERO_FILL; ++ return NULL; ++ } ++ ++ if (hp_start - zeropage > 0) ++ { ++ mapat = __mmap((caddr_t) zeropage, hp_start - zeropage, ++ prot, MAP_ANON|MAP_PRIVATE|MAP_FIXED, -1, 0); ++ if (__glibc_unlikely (mapat == MAP_FAILED)) ++ return DL_MAP_SEGMENTS_ERROR_MAP_ZERO_FILL; ++ } ++ ++ if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_FILES)) ++ _dl_debug_printf("\t\t\t=> mmap anonymous hugepage: [%lx-%lx)\n", hp_start, hp_start + len - mod); ++ mapat = __mmap((caddr_t) hp_start, len - mod, prot, ++ MAP_FIXED|MAP_PRIVATE|MAP_ANONYMOUS|MAP_HUGETLB|(SHFIT_2MB << MAP_HUGE_SHIFT), ++ -1, 0); ++ if (__glibc_unlikely (mapat == MAP_FAILED)) ++ return DL_MAP_SEGMENTS_ERROR_MAP_ZERO_FILL; ++ ++ if (mod > 0) ++ { ++ mapat =__mmap((caddr_t)(hp_start + len - mod), mod, prot, ++ MAP_ANON|MAP_PRIVATE|MAP_FIXED, -1, 0); ++ if (__glibc_unlikely (mapat == MAP_FAILED)) ++ return DL_MAP_SEGMENTS_ERROR_MAP_ZERO_FILL; ++ } ++ ++ return NULL; ++} ++ ++/* ++ * memsz_len records the remain memsiz part ++ */ ++static __always_inline const char * ++_mmap_segment_memsz(struct link_map *l, const struct loadcmd * c, ++ ElfW(Addr) mapstart, size_t extra_len, size_t *memsz_len) ++{ ++ const char * errstring = NULL; ++ ++ /* Extra zero pages should appear at the end of this segment, ++ after the data mapped from the file. */ ++ ElfW(Addr) zero, zeroend, zeropage; ++ ++ zero = mapstart + c->dataend - c->mapstart; ++ zeroend = mapstart + c->allocend - c->mapstart; ++ zeropage = ALIGN_UP(zero, GLRO(dl_pagesize)); ++ size_t alignment = GLRO(dl_pagesize); ++ *memsz_len = 0; ++ ++ /* ++ * no matter what the extra space consists of: ++ * 1. all the extra space is initialized data area (MemSiz > FileSiz) ++ * 2. initialized data area and hole ++ * 3. all the extra space is hole (MemSiz == FileSiz) ++ * ++ * the extra space just needs to be set zero, for the initialized data area, it's ++ * initialized to zero; for the hole area, it's initialized to invalid instruction ++ */ ++ if (extra_len > 0) ++ { ++ if (__glibc_unlikely(zeropage == ALIGN_UP(zero, SIZE_2MB) || ++ zeropage + extra_len != ALIGN_UP(zero, SIZE_2MB))) ++ return DL_MAP_SEGMENT_ERROR_EXTRA_SIZE; ++ ++ zeropage = ALIGN_UP(zero, SIZE_2MB); ++ alignment = SIZE_2MB; ++ } ++ else ++ { ++ /* ++ * extra_len = 0, _mmap_segment_filesz just mmap segment's FileSiz part, ++ * here, it needs to zero tail page [FileSiz end, tail page end) part ++ */ ++ if (c->allocend <= c->dataend) ++ return NULL; ++ ++ if (ALIGN_UP(zero, GLRO(dl_pagesize)) == ALIGN_UP(zero, SIZE_2MB) && ++ (zeropage - (mapstart + _get_relro_len(l, c)) >= SIZE_2MB)) ++ { ++ alignment = SIZE_2MB; ++ } ++ ++ if (zeroend < zeropage) ++ zeropage = zeroend; ++ } ++ ++ if (zeropage > zero) ++ { ++ if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_FILES)) ++ _dl_debug_printf("\t\tzero tail page [%lx-%lx) which contains hole area length: 0x%lx\n", ++ zero, zeropage, zeropage > ALIGN_UP(zero, GLRO(dl_pagesize)) ? ++ zeropage - ALIGN_UP(zero, GLRO(dl_pagesize)) : 0); ++ errstring = _zero_tail_page(c, zero, zeropage, alignment); ++ if (errstring != NULL) ++ return errstring; ++ } ++ ++ if (zeroend > zeropage) ++ { ++ *memsz_len = ALIGN_UP(zeroend, GLRO(dl_pagesize)) - zeropage; ++ if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_FILES)) ++ _dl_debug_printf("\t\tzero remain page [%lx-%lx)\n", zeropage, zeroend); ++ errstring = _mmap_remain_zero_page(zeropage, zeroend, c->prot); ++ } ++ return errstring; ++} ++ ++/* ++ * mmap as fixed addr, if the middle part is 2MB aligned, ++ * this part should be mmaped in 2MB aligned, else in 4KB aligned ++ * 2MB hugepage area should be set with correct permissions, no need to remap ++ */ ++static __always_inline const char * ++_mmap_segment_filesz(struct link_map *l, const struct loadcmd *c, ElfW(Addr) mapstart, ++ size_t extra_len, int fd) ++{ ++ void *map_addr = 0; ++ ++ size_t relro_len = _get_relro_len(l, c); ++ if (relro_len > 0) ++ { ++ if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_FILES)) ++ _dl_debug_printf("\t\tmmap relro: [%lx-%lx)\n", mapstart, mapstart + relro_len); ++ /* ++ * relro part must be mapped as normal page size to avoid ++ * _dl_protect_relro failure ++ */ ++ map_addr = __mmap((void *)mapstart, relro_len, c->prot, ++ MAP_PRIVATE|MAP_FIXED|MAP_FILE, ++ fd, c->mapoff); ++ if (__glibc_unlikely (map_addr == MAP_FAILED)) ++ return DL_MAP_SEGMENTS_ERROR_MAP_SEGMENT; ++ ++ mapstart += relro_len; ++ } ++ ++ size_t prev_map_len = ALIGN_UP(mapstart, SIZE_2MB) - mapstart; ++ size_t len = (c->mapend + extra_len) - (c->mapstart + relro_len); ++ if (len <= prev_map_len || len - prev_map_len < SIZE_2MB) ++ { ++ if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_FILES)) ++ _dl_debug_printf("\t\tmmap all: [%lx-%lx), which includes prev_map_len(0x%lx)\n", ++ mapstart, mapstart + len, prev_map_len); ++ mapstart = (ElfW(Addr))__mmap((void *)mapstart, len, c->prot, ++ MAP_PRIVATE|MAP_FIXED|MAP_FILE, ++ fd, c->mapoff + relro_len); ++ if (__glibc_unlikely ((void *)mapstart == MAP_FAILED)) ++ return DL_MAP_SEGMENTS_ERROR_MAP_SEGMENT; ++ return NULL; ++ } ++ ++ if (prev_map_len > 0) ++ { ++ if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_FILES)) ++ _dl_debug_printf("\t\tmmap prev_map_len: [%lx-%lx)\n", ++ mapstart, mapstart + prev_map_len); ++ mapstart = (ElfW(Addr))__mmap((void *)mapstart, prev_map_len, c->prot, ++ MAP_PRIVATE|MAP_FIXED|MAP_FILE, ++ fd, c->mapoff + relro_len); ++ if (__glibc_unlikely ((void *)mapstart == MAP_FAILED)) ++ return DL_MAP_SEGMENTS_ERROR_MAP_SEGMENT; ++ ++ map_addr = map_addr == 0 ? (void *)mapstart : map_addr; ++ mapstart += prev_map_len; ++ len -= prev_map_len; ++ } ++ ++ size_t mod = len % SIZE_2MB; ++ if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_FILES)) ++ _dl_debug_printf("\t\tmmap hugepage: [%lx-%lx)\n", mapstart, mapstart + len - mod); ++ mapstart = (ElfW(Addr))__mmap((void *)mapstart, len - mod, c->prot, ++ MAP_FIXED|MAP_PRIVATE|MAP_ANONYMOUS|MAP_HUGETLB|(SHFIT_2MB << MAP_HUGE_SHIFT), ++ -1, 0); ++ if (__glibc_unlikely ((void *)mapstart == MAP_FAILED)) ++ return DL_MAP_SEGMENTS_ERROR_MAP_SEGMENT; ++ ++ if ((c->prot & PROT_WRITE) == 0 && __mprotect((void *)mapstart, len - mod, c->prot | PROT_WRITE) < 0) ++ { ++ return DL_MAP_SEGMENTS_ERROR_MPROTECT; ++ } ++ ++ /* Read the segment contents from the file. */ ++ size_t file_len = (size_t)(c->dataend - c->mapstart) <= prev_map_len + relro_len ? 0 : ++ (size_t)(c->dataend - c->mapstart) - prev_map_len - relro_len; ++ if (file_len > 0) ++ { ++ lseek(fd, c->mapoff + relro_len + prev_map_len, SEEK_SET); ++ if ( __read(fd, (void *)mapstart, file_len < len - mod ? file_len : len - mod) < 0) ++ return DL_MAP_SEGMENTS_ERROR_READ_SEGMENT; ++ } ++ ++ if ((c->prot & PROT_WRITE) == 0 && __mprotect((void *)mapstart, len - mod, c->prot) < 0) ++ { ++ return DL_MAP_SEGMENTS_ERROR_MPROTECT; ++ } ++ ++ map_addr = map_addr == 0 ? (void *)mapstart : map_addr; ++ mapstart += len - mod; ++ ++ if (__glibc_unlikely (extra_len > 0 && mod > 0)) ++ return DL_MAP_SEGMENT_ERROR_EXTRA_SIZE; ++ ++ if (mod > 0 && __glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_FILES)) ++ _dl_debug_printf("\t\tmmap tail part: [%lx-%lx)\n", mapstart, mapstart + mod); ++ if (mod > 0 && __mmap((void *)mapstart, mod, c->prot, ++ MAP_PRIVATE|MAP_FIXED|MAP_FILE, ++ fd, c->mapoff + relro_len + prev_map_len + len - mod) ++ == MAP_FAILED) ++ { ++ return DL_MAP_SEGMENTS_ERROR_MAP_SEGMENT; ++ } ++ return NULL; ++} ++ ++/* ++ * mmap segment filesz tail part only covers the very first part of hugepage, ++ * if the size of this tail part reach the threshold, map the tail part in hugepage ++ * ++ * The tail part must be calculated by mapend, because this is file mmaping, ++ * if tail part is calculated by allocend, it will mmap invalid data in file ++ * s: mapstart mp: mapend ac: allocend ++ * 1. [s, mp) can not cover the tail hugepage start, mp, s, ac are all in same hugepage, no extra space ++ * s mp ac ++ * | | | ++ * |--------|--------| ++ * ++ * 2. [s, mp) can not cover the tail hugepage start, ac is in the behind hugepage, no extra space ++ * s mp ac ++ * | | | ++ * |--------|--------|--------| ++ * ++ * 3. [s, mp) covers the tail hugepage start, mp and the ac in the same hugepage, ++ * if (ac - ALIGN_DOWN(mp, SIZE_2MB) < threshold, no extra space; else extra space ++ * [mp, ALIGN_UP(mp, SIZE_2MB) which contains initialized data area and hole ++ * if ac == mp, the extra space only contains hole ++ * s1 s2 mp ac ++ * | | | | ++ * |--------|--------|--------| ++ * ++ * 4. [s, mp) covers the tail hugepage start, ac is in the behind hugepage, ++ * the extra space is [mp, ALIGN_UP(mp, SIZE_2MB) which only contains initialized data area ++ * s1 s2 mp ac ++ * | | | | ++ * |--------|--------|--------|--------|--------| ++ * ++ * 5. if mp is 2MB aligned, no matter [s, mp) covers the tail hugepage start or not, ++ * no extra area ++ * s1 s2 s3 mp ac ++ * | | | | | ++ * |--------|--------|--------|--------|--------| ++ * ++ * there are a few points to note: ++ * 1. the extra part shold not overlap with the next segment ++ * 2. PT_LOAD segment which contains relro section should update mapstart ++ */ ++static __always_inline size_t ++_extra_mmap(struct link_map *l, const struct loadcmd loadcmds[], size_t nloadcmds, ++ const struct loadcmd *c, ElfW(Addr) mapstart) ++{ ++ ElfW(Addr) mapend = mapstart + (c->mapend - c->mapstart); ++ ElfW(Addr) hugepage = ALIGN_DOWN(mapend, SIZE_2MB); ++ size_t relro_len = _get_relro_len(l, c); ++ mapstart += relro_len; ++ ++ /* ++ * 1. mapend is 2MB aligned ++ * 2. [mapstart, mapend) does not cover the tail hugepage start ++ */ ++ if (mapend == ALIGN_UP(mapend, SIZE_2MB) || mapstart > hugepage) ++ return 0; ++ ++ /* the initialized data area end in the tail hugepage */ ++ ElfW(Addr) end = (mapstart - relro_len) + ALIGN_UP(c->allocend - c->mapstart, GLRO(dl_pagesize)) >= ++ ALIGN_UP(mapend, SIZE_2MB) ? ALIGN_UP(mapend, SIZE_2MB) : ++ (mapstart - relro_len) + ALIGN_UP(c->allocend - c->mapstart, GLRO(dl_pagesize)); ++ ++ size_t extra_len = ALIGN_UP(mapend, SIZE_2MB) - mapend; ++ if ((end - hugepage < THRESHOLD * GLRO(dl_pagesize)) || ((c < loadcmds + (nloadcmds - 1)) && ++ (ALIGN_UP(mapend, SIZE_2MB) > (mapstart - relro_len) + c[1].mapstart - c->mapstart))) ++ { ++ extra_len = 0; ++ } ++ ++ return extra_len; ++} ++ ++/* ++ * PT_LOAD segment is described by p_filesz and p_memsz. ++ * The bytes from the file are mapped to the beginning of the memory segment. ++ * If the segment’s memory size (p_memsz) is larger than the file size (p_filesz), ++ * the extra bytes are defined to hold the value 0 and to follow the segment’s ++ * initialized area ++ */ ++static __always_inline const char * ++_mmap_segment(struct link_map *l, const struct loadcmd loadcmds[], size_t nloadcmds, ++ const struct loadcmd *c, ElfW(Addr) mapstart, int fd, size_t *mapseglen) ++{ ++ const char * errstring = NULL; ++ size_t extra_len = _extra_mmap(l, loadcmds, nloadcmds, c, mapstart); ++ size_t memsz_len = 0; ++ if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_FILES)) ++ _dl_debug_printf("\t%s(0x%lx): extra_len = 0x%lx\n\t{\n", __func__, ++ (unsigned long)c, extra_len); ++ ++ errstring = _mmap_segment_filesz(l, c, mapstart, extra_len, fd); ++ if (__glibc_unlikely (errstring != NULL)) ++ return errstring; ++ errstring = _mmap_segment_memsz(l, c, mapstart, extra_len, &memsz_len); ++ if (__glibc_unlikely (errstring != NULL)) ++ return errstring; ++ ++ *mapseglen = c->mapend - c->mapstart + extra_len + memsz_len; ++ if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_FILES)) ++ _dl_debug_printf("\t} => mapseglen = 0x%lx, memsz_len = 0x%lx\n", *mapseglen, memsz_len); ++ return NULL; ++} ++ ++static __always_inline void * ++_mmap_hole(const struct loadcmd *current, const struct loadcmd *next, ++ ElfW(Addr) mapstart, size_t mapseglen, int fd) ++{ ++ if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_FILES)) ++ _dl_debug_printf("\tmmap hole area:[%lx-%lx)\n", mapstart + mapseglen, ++ mapstart + (next->mapstart - current->mapstart)); ++ return __mmap((void *)(mapstart + mapseglen), ++ next->mapstart - (current->mapstart + mapseglen), ++ PROT_NONE, MAP_FILE|MAP_PRIVATE|MAP_FIXED, ++ fd, current->mapoff + mapseglen); ++} ++ ++static __always_inline const char * ++_dl_map_segments_largein (struct link_map *l, int fd, ++ const ElfW(Ehdr) *header, int type, ++ const struct loadcmd loadcmds[], size_t nloadcmds, ++ const size_t maplength, bool has_holes) ++{ ++ if (__glibc_unlikely (type != ET_DYN)) ++ return DL_MAP_SEGMENTS_ERROR_TYPE; ++ ++ const char *errstring = NULL; ++ const struct loadcmd *text = _find_exec_segment(loadcmds, nloadcmds); ++ if (__glibc_unlikely (text == NULL)) ++ return DL_FIND_EXEC_SEGMENT_ERROR; ++ ++ size_t maparealen; ++ void *map_area_start = __mmap_reserved_area(loadcmds, nloadcmds, &maparealen); ++ if (__glibc_unlikely (map_area_start == MAP_FAILED)) ++ return DL_MAP_RESERVED_HUGEPAGE_AREA_ERROR; ++ if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_FILES)) ++ _dl_debug_printf("reserved area:[%lx-%lx)\n", ++ (unsigned long)map_area_start, (unsigned long)map_area_start + maparealen); ++ ++ /* First to mmap text segment */ ++ const struct loadcmd * c = loadcmds; ++ ElfW(Addr) text_addr = ALIGN_UP((ElfW(Addr))map_area_start + (text->mapstart - c->mapstart), SIZE_2MB); ++ size_t mapseglen; ++ errstring = _mmap_segment(l, loadcmds, nloadcmds, text, text_addr, fd, &mapseglen); ++ if (__glibc_unlikely(errstring != NULL)) ++ goto unmap_reserved_area; ++ ++ const struct loadcmd *prev = text; ++ c = text + 1; ++ ElfW(Addr) map_addr = text_addr; ++ while (c < &loadcmds[nloadcmds]) ++ { ++ if (prev->mapstart + mapseglen > c->mapstart || c->mapstart < prev->mapstart) ++ { ++ errstring = DL_MAP_SEGMENTS_ERROR_ARRANGE; ++ goto unmap_reserved_area; ++ } ++ ++ if (prev->mapstart + mapseglen < c->mapstart && ++ _mmap_hole(prev, c, map_addr, mapseglen, fd) == MAP_FAILED) ++ { ++ errstring = DL_MAP_SEGMENTS_ERROR_MAP_HOLE_FILL; ++ goto unmap_reserved_area; ++ } ++ ++ map_addr += c->mapstart - prev->mapstart; ++ errstring = _mmap_segment(l, loadcmds, nloadcmds, c, map_addr, fd, &mapseglen); ++ if (__glibc_unlikely(errstring != NULL)) ++ goto unmap_reserved_area; ++ prev = c; ++ ++c; ++ } ++ ElfW(Addr) l_map_end = map_addr + mapseglen; ++ ++ /* search for the first segment */ ++ prev = text; ++ c = text - 1; ++ map_addr = text_addr; ++ while (c >= loadcmds) ++ { ++ if (prev->mapstart < c->mapstart) ++ { ++ errstring = DL_MAP_SEGMENTS_ERROR_ARRANGE; ++ goto unmap_reserved_area; ++ } ++ ++ map_addr -= prev->mapstart - c->mapstart; ++ errstring = _mmap_segment(l, loadcmds, nloadcmds, c, map_addr, fd, &mapseglen); ++ if (__glibc_unlikely(errstring != NULL)) ++ goto unmap_reserved_area; ++ ++ if (c->mapstart + mapseglen > prev->mapstart) ++ { ++ errstring = DL_MAP_SEGMENTS_ERROR_ARRANGE; ++ goto unmap_reserved_area; ++ } ++ ++ if (c->mapstart + mapseglen < prev->mapstart && ++ _mmap_hole(c, prev, map_addr, mapseglen, fd) == MAP_FAILED) ++ { ++ errstring = DL_MAP_SEGMENTS_ERROR_MAP_HOLE_FILL; ++ goto unmap_reserved_area; ++ } ++ prev = c; ++ --c; ++ } ++ ++ ++c; ++ l->l_map_start = map_addr; ++ l->l_map_end = l->l_map_start + maplength; ++ l->l_addr = l->l_map_start - c->mapstart; ++ l->l_contiguous = 1; ++ ++ c = loadcmds; ++ while (c < &loadcmds[nloadcmds]) ++ { ++ _dl_postprocess_loadcmd (l, header, c); ++ ++c; ++ } ++ ++ if (l->l_map_start > (ElfW(Addr))map_area_start) ++ { ++ if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_FILES)) ++ _dl_debug_printf("__munmap [%lx-%lx)\n", (ElfW(Addr))map_area_start, l->l_map_start); ++ __munmap(map_area_start, l->l_map_start - (ElfW(Addr))map_area_start); ++ } ++ ++ /* ++ * l->l_map_end is caculated by maplength, l_map_end may end with extra space ++ * use l->l_map_end may munmap extra space part ++ */ ++ if ((ElfW(Addr))map_area_start + maparealen > l_map_end) ++ { ++ if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_FILES)) ++ _dl_debug_printf("__munmap [%lx-%lx)\n", l_map_end, (ElfW(Addr))map_area_start + maparealen); ++ __munmap((void *)l_map_end, (ElfW(Addr))map_area_start + maparealen - l_map_end); ++ } ++ ++ return NULL; ++ ++unmap_reserved_area: ++ __munmap(map_area_start, maparealen); ++ ++ return errstring; ++} +diff --git a/elf/dl-support.c b/elf/dl-support.c +index d8c06ba7..f6ab2627 100644 +--- a/elf/dl-support.c ++++ b/elf/dl-support.c +@@ -166,6 +166,10 @@ size_t _dl_phnum; + uint64_t _dl_hwcap; + uint64_t _dl_hwcap2; + ++#ifdef HUGEPAGE_SHARED_LIB ++int _dl_hugepage_mask; ++#endif ++ + /* The value of the FPU control word the kernel will preset in hardware. */ + fpu_control_t _dl_fpu_control = _FPU_DEFAULT; + +diff --git a/elf/elf.h b/elf/elf.h +index 4738dfa2..c5315d1b 100644 +--- a/elf/elf.h ++++ b/elf/elf.h +@@ -730,6 +730,8 @@ typedef struct + + /* Legal values for p_flags (segment flags). */ + ++/* libhugetlbfs's hugeedit use 0x00100000, here use another */ ++#define PF_HUGEPAGE (0x01000000) + #define PF_X (1 << 0) /* Segment is executable */ + #define PF_W (1 << 1) /* Segment is writable */ + #define PF_R (1 << 2) /* Segment is readable */ +diff --git a/elf/hugepageedit.c b/elf/hugepageedit.c +new file mode 100644 +index 00000000..14a91a4b +--- /dev/null ++++ b/elf/hugepageedit.c +@@ -0,0 +1,169 @@ ++/* Mark ELF object ELF header hugepage flag Generic version. ++ Copyright (C) 2021-2021 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 ++ <http://www.gnu.org/licenses/>. */ ++#include <stdio.h> ++#include <stdlib.h> ++#include <fcntl.h> ++#include <string.h> ++#include <unistd.h> ++#include <elf.h> ++#include <link.h> ++#include <sys/stat.h> ++#include <sys/mman.h> ++#include <sys/types.h> ++ ++/* reference kernel load_elf_phdrs program header table size constraint */ ++#define ELF_MIN_ALIGN 4096 ++#define TOOL_NAME "hugepageedit" ++ ++int check_ptr(void *ptr, void *start, size_t len) ++{ ++ if (ptr < start || ptr > start + len) ++ return -1; ++ return 0; ++} ++ ++void print_usage(void) ++{ ++ fprintf(stderr, "%s [-x] [-d] <ELF file>\n" \ ++ "\tdefault mark all PT_LOAD segment PF_HUGEPAGE flag\n" \ ++ "\t-x option only mark executable PT_LOAD segment PF_HUGEPAGE flag\n" \ ++ "\t-d option delete all the PT_LOAD segment PF_HUGEPAGE flag\n", TOOL_NAME); ++} ++ ++int main(int argc, char *argv[]) ++{ ++ int exit_status = -1; ++ int i, opt, delete = 0, exec_only = 0; ++ while ((opt = getopt(argc, argv, "dx")) != -1) ++ { ++ switch (opt) ++ { ++ case 'd': ++ delete = 1; ++ break; ++ case 'x': ++ exec_only = 1; ++ break; ++ default: ++ print_usage(); ++ return 0; ++ } ++ } ++ ++ if (delete && exec_only) ++ { ++ fprintf(stderr, "can not specify -x and -d option at the same time\n"); ++ return -1; ++ } ++ ++ if (optind >= argc) ++ { ++ fprintf(stderr, "Expected argument after options\n"); ++ return -1; ++ } ++ ++ int fd = open(argv[optind], O_RDWR); ++ if (fd < 0) ++ { ++ perror("open"); ++ return -1; ++ } ++ ++ struct stat statbuf; ++ if (fstat(fd, &statbuf) != 0) ++ { ++ perror("fstat"); ++ goto close_fd; ++ } ++ ++ /* this ensures file is large enough to hold ELF header */ ++ if (statbuf.st_size < sizeof (ElfW(Ehdr))) ++ { ++ fprintf(stderr, "file is not large enough to hold ELF header\n"); ++ goto close_fd; ++ } ++ ++ void *ehdr = mmap(NULL, statbuf.st_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); ++ if (ehdr == MAP_FAILED) ++ { ++ perror("mmap"); ++ goto close_fd; ++ } ++ ++ if (memcmp(((ElfW(Ehdr) *) ehdr)->e_ident, ELFMAG, SELFMAG) != 0) ++ { ++ fprintf(stderr, "file is not ELF format\n"); ++ goto unmap; ++ } ++ ++ if (((ElfW(Ehdr) *)ehdr)->e_phentsize != sizeof(ElfW(Phdr))) ++ { ++ fprintf(stderr, "ELF header's e_phentsize mismatch ElfW(Phdr) size\n"); ++ goto unmap; ++ } ++ ++ unsigned int size = ((ElfW(Ehdr) *)ehdr)->e_phnum * sizeof(ElfW(Phdr)); ++ if (size == 0 || size > ELF_MIN_ALIGN) ++ { ++ fprintf(stderr, "The program header table size specified by ELF header is abnormal: %u\n", size); ++ goto unmap; ++ } ++ ++ void *ephdr_s = ehdr + ((ElfW(Ehdr) *)ehdr)->e_phoff; ++ void *ephdr_e = ehdr + ((ElfW(Ehdr) *)ehdr)->e_phoff + size; ++ ++ if (check_ptr(ephdr_s, ehdr, statbuf.st_size) || ++ check_ptr(ephdr_e, ehdr, statbuf.st_size)) ++ { ++ fprintf(stderr, "ELF porgram header table is not fully mmaped\n"); ++ goto unmap; ++ } ++ ++ ElfW(Phdr) *phdr = (ElfW(Phdr) *)ephdr_s; ++ /* ++ * Here, mark hugepage flag in ELF header e_ident padding bytes won't work. ++ * elf/dl-load.c open_verify will check if shared object ELF header e_ident ++ * padding bytes match expected[EI_NIDENT] byte array which padding bytes ++ * should be zero. If it mismatches, ld.so will exit abnormally ++ */ ++ for (i = 0; i < ((ElfW(Ehdr) *)ehdr)->e_phnum; i++) ++ { ++ if (phdr[i].p_type == PT_LOAD) ++ { ++ if (delete) ++ { ++ phdr[i].p_flags &= ~PF_HUGEPAGE; ++ } ++ else ++ { ++ if (exec_only && !(phdr[i].p_flags & PF_X)) ++ continue; ++ phdr[i].p_flags |= PF_HUGEPAGE; ++ } ++ } ++ } ++ exit_status = 0; ++ ++unmap: ++ munmap(ehdr, statbuf.st_size); ++ ++close_fd: ++ close(fd); ++ ++ return exit_status; ++} +diff --git a/elf/rtld.c b/elf/rtld.c +index a8ae8b31..85596ee4 100644 +--- a/elf/rtld.c ++++ b/elf/rtld.c +@@ -2543,6 +2543,40 @@ dl_main (const ElfW(Phdr) *phdr, + /* Once we return, _dl_sysdep_start will invoke + the DT_INIT functions and then *USER_ENTRY. */ + } ++ ++#ifdef HUGEPAGE_SHARED_LIB ++/* prase the hugepage use strategy of loading shared object */ ++static void ++process_dl_hugepage (const char *dl_hugepage) ++{ ++ static const struct ++ { ++ uint64_t option; ++ int flag; ++ } hpopts[] = ++ { ++ {DL_HUGEPAGE_LARGE_IN, DL_HUGEPAGE_LIB_LARGE_IN_FLAG}, ++ }; ++#define nhpopts (sizeof (hpopts) / sizeof (hpopts[0])) ++ ++ if (dl_hugepage == NULL) ++ return; ++ ++ char *endptr; ++ uint64_t val = _dl_strtoul (dl_hugepage, &endptr); ++ /* Invalid digit in input string */ ++ if (*endptr != '\0') ++ return; ++ ++ for (size_t cnt = 0; cnt < nhpopts; ++cnt) ++ if (val == hpopts[cnt].option) ++ { ++ GLRO(dl_hugepage_mask) |= hpopts[cnt].flag; ++ break; ++ } ++} ++#endif ++ + + /* This is a little helper function for resolving symbols while + tracing the binary. */ +@@ -2678,6 +2712,9 @@ process_envvars (struct dl_main_state *state) + char **runp = _environ; + char *envline; + char *debug_output = NULL; ++#ifdef HUGEPAGE_SHARED_LIB ++ bool hugepage_lib_env = false; ++#endif + + /* This is the default place for profiling data file. */ + GLRO(dl_profile_output) +@@ -2790,6 +2827,15 @@ process_envvars (struct dl_main_state *state) + if (!__libc_enable_secure + && memcmp (envline, "DYNAMIC_WEAK", 12) == 0) + GLRO(dl_dynamic_weak) = 1; ++ ++#ifdef HUGEPAGE_SHARED_LIB ++ if (memcmp (envline, "HUGEPAGE_LIB", 12) == 0 && envline[13] != '\0') ++ { ++ hugepage_lib_env = true; ++ process_dl_hugepage(&envline[13]); ++ } ++#endif ++ + break; + + case 13: +@@ -2812,6 +2858,13 @@ process_envvars (struct dl_main_state *state) + && memcmp (envline, "PROFILE_OUTPUT", 14) == 0 + && envline[15] != '\0') + GLRO(dl_profile_output) = &envline[15]; ++ ++#ifdef HUGEPAGE_SHARED_LIB ++ if (memcmp (envline, "HUGEPAGE_PROBE", 14) == 0 && ++ envline[15] != '\0') ++ GLRO(dl_hugepage_mask) |= DL_HUGEPAGE_PROBE_FLAG; ++#endif ++ + break; + + case 16: +@@ -2841,6 +2894,16 @@ process_envvars (struct dl_main_state *state) + } + } + ++#ifdef HUGEPAGE_SHARED_LIB ++ /* LIB_HUGEPAGE_LIB and HUGEPAGE_PROBE are both set. use LIB_HUGEPAGE_LIB */ ++ if ((GLRO(dl_hugepage_mask) & DL_HUGEPAGE_PROBE_FLAG) && hugepage_lib_env) ++ { ++ GLRO(dl_hugepage_mask) &= ~DL_HUGEPAGE_PROBE_FLAG; ++ } ++ /* unsetenv LD_HUGEPAGE_LIB, child process should not get this env */ ++ unsetenv("LD_HUGEPAGE_LIB"); ++#endif ++ + /* Extra security for SUID binaries. Remove all dangerous environment + variables. */ + if (__builtin_expect (__libc_enable_secure, 0)) +diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h +index a1d70ce7..a9fffd66 100644 +--- a/sysdeps/generic/ldsodefs.h ++++ b/sysdeps/generic/ldsodefs.h +@@ -549,7 +549,11 @@ struct rtld_global_ro + /* These two are used only internally. */ + #define DL_DEBUG_HELP (1 << 10) + #define DL_DEBUG_PRELINK (1 << 11) +- ++#ifdef HUGEPAGE_SHARED_LIB ++#define DL_HUGEPAGE_PROBE_FLAG (1 << 31) ++#define DL_HUGEPAGE_LIB_LARGE_IN_FLAG (1 << 30) ++#define DL_HUGEPAGE_LARGE_IN 1 ++#endif + /* OS version. */ + EXTERN unsigned int _dl_osversion; + /* Platform name. */ +@@ -672,6 +676,11 @@ struct rtld_global_ro + platforms. */ + EXTERN uint64_t _dl_hwcap2; + ++#ifdef HUGEPAGE_SHARED_LIB ++ /* Mask for how to use hugepage */ ++ EXTERN int _dl_hugepage_mask; ++#endif ++ + #ifdef SHARED + /* We add a function table to _rtld_global which is then used to + call the function instead of going through the PLT. The result +-- +2.37.3 + |