From patchwork Fri Dec 10 12:39:10 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Rongwei Wang X-Patchwork-Id: 48778 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 0E3F93858024 for ; Fri, 10 Dec 2021 12:41:03 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 0E3F93858024 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1639140063; bh=K0tLs8Nf2xx6sPxja9cjkPARM3AmNLPlqHX5J5rB3OU=; h=To:Subject:Date:In-Reply-To:References:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:Cc: From; b=Xn3leGsQXx2m5KJAsCzo/z9u3D7kbOSMy39GTSoamLK78FdDjrClHhdETayVZ7KGK Lm87mP/KF8sTxWT/F/4g0i9v9C/fqhtxbtoglAU9YHYPpodUPhb5BsORHlussbNX00 DkvlUmZMWuFVm9nYfmDlA777xcmQ5iJsoWVkN+jQ= X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from out30-131.freemail.mail.aliyun.com (out30-131.freemail.mail.aliyun.com [115.124.30.131]) by sourceware.org (Postfix) with ESMTPS id 1B81D385800E for ; Fri, 10 Dec 2021 12:39:19 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 1B81D385800E X-Alimail-AntiSpam: AC=PASS; BC=-1|-1; BR=01201311R361e4; CH=green; DM=||false|; DS=||; FP=0|-1|-1|-1|0|-1|-1|-1; HT=e01e04400; MF=rongwei.wang@linux.alibaba.com; NM=1; PH=DS; RN=5; SR=0; TI=SMTPD_---0V-9u4OF_1639139951; Received: from localhost.localdomain(mailfrom:rongwei.wang@linux.alibaba.com fp:SMTPD_---0V-9u4OF_1639139951) by smtp.aliyun-inc.com(127.0.0.1); Fri, 10 Dec 2021 20:39:13 +0800 To: libc-alpha@sourceware.org, hjl.tools@gmail.com, fweimer@redhat.com Subject: [PATCH v5 1/2] elf: Properly align PT_LOAD segments Date: Fri, 10 Dec 2021 20:39:10 +0800 Message-Id: <20211210123911.86568-2-rongwei.wang@linux.alibaba.com> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20211210123911.86568-1-rongwei.wang@linux.alibaba.com> References: <20211204045848.71105-1-rongwei.wang@linux.alibaba.com> <20211210123911.86568-1-rongwei.wang@linux.alibaba.com> MIME-Version: 1.0 X-Spam-Status: No, score=-20.3 required=5.0 tests=BAYES_00, ENV_AND_HDR_SPF_MATCH, GIT_PATCH_0, KAM_DMARC_STATUS, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP, UNPARSEABLE_RELAY, USER_IN_DEF_SPF_WL autolearn=ham autolearn_force=no version=3.4.4 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on server2.sourceware.org X-BeenThere: libc-alpha@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Libc-alpha mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Rongwei Wang via Libc-alpha From: Rongwei Wang Reply-To: Rongwei Wang Cc: xuyu@linux.alibaba.com, gavin.dg@linux.alibaba.com Errors-To: libc-alpha-bounces+patchwork=sourceware.org@sourceware.org Sender: "Libc-alpha" When PT_LOAD segment alignment > the page size, allocate enough space to ensure that the segment can be properly aligned. And this fix can help code segments use huge pages become simple and available. This fixes [BZ #28676]. Signed-off-by: Xu Yu Signed-off-by: Rongwei Wang Reviewed-by: H.J. Lu --- elf/dl-load.c | 1 + elf/dl-load.h | 2 +- elf/dl-map-segments.h | 49 +++++++++++++++++++++++++++++++++++++++---- 3 files changed, 47 insertions(+), 5 deletions(-) diff --git a/elf/dl-load.c b/elf/dl-load.c index bf8957e73c..9a23590bf4 100644 --- a/elf/dl-load.c +++ b/elf/dl-load.c @@ -1150,6 +1150,7 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd, c->mapend = ALIGN_UP (ph->p_vaddr + ph->p_filesz, GLRO(dl_pagesize)); c->dataend = ph->p_vaddr + ph->p_filesz; c->allocend = ph->p_vaddr + ph->p_memsz; + c->mapalign = ph->p_align; c->mapoff = ALIGN_DOWN (ph->p_offset, GLRO(dl_pagesize)); /* Determine whether there is a gap between the last segment diff --git a/elf/dl-load.h b/elf/dl-load.h index e329d49a81..c121e3456c 100644 --- a/elf/dl-load.h +++ b/elf/dl-load.h @@ -74,7 +74,7 @@ ELF_PREFERRED_ADDRESS_DATA; Its details have been expanded out and converted. */ struct loadcmd { - ElfW(Addr) mapstart, mapend, dataend, allocend; + ElfW(Addr) mapstart, mapend, dataend, allocend, mapalign; ElfW(Off) mapoff; int prot; /* PROT_* bits. */ }; diff --git a/elf/dl-map-segments.h b/elf/dl-map-segments.h index f9fb110ee3..74abf324ed 100644 --- a/elf/dl-map-segments.h +++ b/elf/dl-map-segments.h @@ -18,6 +18,50 @@ #include +/* Map a segment and align it properly. */ + +static __always_inline ElfW(Addr) +_dl_map_segment (const struct loadcmd *c, ElfW(Addr) mappref, + const size_t maplength, int fd) +{ + if (__glibc_likely (c->mapalign <= GLRO(dl_pagesize))) + return (ElfW(Addr)) __mmap ((void *) mappref, maplength, c->prot, + MAP_COPY|MAP_FILE, fd, c->mapoff); + + /* If the segment alignment > the page size, allocate enough space to + ensure that the segment can be properly aligned. */ + ElfW(Addr) maplen = (maplength >= c->mapalign + ? (maplength + c->mapalign) + : (2 * c->mapalign)); + ElfW(Addr) map_start = (ElfW(Addr)) __mmap ((void *) mappref, maplen, + PROT_NONE, + MAP_ANONYMOUS|MAP_PRIVATE, + -1, 0); + if (__glibc_unlikely ((void *) map_start == MAP_FAILED)) + return map_start; + + ElfW(Addr) map_start_aligned = ALIGN_UP (map_start, c->mapalign); + map_start_aligned = (ElfW(Addr)) __mmap ((void *) map_start_aligned, + maplength, c->prot, + MAP_COPY|MAP_FILE|MAP_FIXED, + fd, c->mapoff); + if (__glibc_unlikely ((void *) map_start_aligned == MAP_FAILED)) + __munmap ((void *) map_start, maplen); + else + { + /* Unmap the unused regions. */ + ElfW(Addr) delta = map_start_aligned - map_start; + if (delta) + __munmap ((void *) map_start, delta); + ElfW(Addr) map_end = map_start_aligned + maplength; + delta = map_start + maplen - map_end; + if (delta) + __munmap ((void *) map_end, delta); + } + + return map_start_aligned; +} + /* This implementation assumes (as does the corresponding implementation of _dl_unmap_segments, in dl-unmap-segments.h) that shared objects are always laid out with all segments contiguous (or with gaps @@ -53,10 +97,7 @@ _dl_map_segments (struct link_map *l, int fd, - MAP_BASE_ADDR (l)); /* Remember which part of the address space this object uses. */ - l->l_map_start = (ElfW(Addr)) __mmap ((void *) mappref, maplength, - c->prot, - MAP_COPY|MAP_FILE, - fd, c->mapoff); + l->l_map_start = _dl_map_segment (c, mappref, maplength, fd); if (__glibc_unlikely ((void *) l->l_map_start == MAP_FAILED)) return DL_MAP_SEGMENTS_ERROR_MAP_SEGMENT;