From patchwork Sun Dec 6 19:41:51 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Aleksandra Tsvetkova X-Patchwork-Id: 553177 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id AF3F4140297 for ; Mon, 7 Dec 2015 06:42:07 +1100 (AEDT) Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b=HQQ0ooPs; dkim-atps=neutral DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender :mime-version:in-reply-to:references:date:message-id:subject :from:to:cc:content-type; q=dns; s=default; b=R1i885zP23N1Cuz0KZ schV9MPHa0mAF4t5qgI14akM32E5cvEWtCwkDRQlr51E/CO89QgJBZ28J3u40ZcI sZxhP1dz7Nk5QratpR4ZIsgzPy9vEDdiGF6xiVcmPO5+kSG7osV97wakWi5vWXr4 FSF/BxeU+Z9Ihr70paxUs6ZV8= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender :mime-version:in-reply-to:references:date:message-id:subject :from:to:cc:content-type; s=default; bh=dlzD7Iabgi+ltHqlQj2bAwzZ kDk=; b=HQQ0ooPsi5VkJhYl2nEvdqfN4z+itzFy0YkqMfgcVpFbdVAMsRNG978h uDOaO3ZCoRGevN8zEDtdS6ZlI6qq8izIRbhTq6swqP+nzI1v0CGc1ugShbw84Huf HufouEQpw6+iW+fou6Jr64r6pGjnOhenQeyFEwgcJgrqTVM3CG8= Received: (qmail 18338 invoked by alias); 6 Dec 2015 19:41:59 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 18327 invoked by uid 89); 6 Dec 2015 19:41:58 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=1.2 required=5.0 tests=AWL, BAYES_50, FREEMAIL_FROM, RCVD_IN_DNSWL_LOW, SPF_PASS autolearn=ham version=3.3.2 X-HELO: mail-lf0-f50.google.com Received: from mail-lf0-f50.google.com (HELO mail-lf0-f50.google.com) (209.85.215.50) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES128-GCM-SHA256 encrypted) ESMTPS; Sun, 06 Dec 2015 19:41:55 +0000 Received: by lffu14 with SMTP id u14so140278913lff.1 for ; Sun, 06 Dec 2015 11:41:51 -0800 (PST) MIME-Version: 1.0 X-Received: by 10.25.17.196 with SMTP id 65mr10156698lfr.137.1449430911264; Sun, 06 Dec 2015 11:41:51 -0800 (PST) Received: by 10.25.81.204 with HTTP; Sun, 6 Dec 2015 11:41:51 -0800 (PST) In-Reply-To: References: <20151125154058.GA53196@msticlxl57.ims.intel.com> Date: Sun, 6 Dec 2015 22:41:51 +0300 Message-ID: Subject: Re: [PATCH] New version of libmpx with new memmove wrapper From: Aleksandra Tsvetkova To: Ilya Enkovich Cc: gcc-patches Fixed all. Now there are no new fails on spec2000 diff --git a/gcc/testsuite/gcc.target/i386/mpx/memmove.c b/gcc/testsuite/gcc.target/i386/mpx/memmove.c new file mode 100755 index 0000000..57030a3 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/mpx/memmove.c @@ -0,0 +1,119 @@ +/* { dg-do run } */ +/* { dg-options "-fcheck-pointer-bounds -mmpx" } */ + + +#include +#include +#include +#include +#include "mpx-check.h" + +#ifdef __i386__ +/* i386 directory size is 4MB. */ +#define MPX_NUM_L2_BITS 10 +#define MPX_NUM_IGN_BITS 2 +#else /* __i386__ */ +/* x86_64 directory size is 2GB. */ +#define MPX_NUM_L2_BITS 17 +#define MPX_NUM_IGN_BITS 3 +#endif /* !__i386__ */ + + +/* bt_num_of_elems is the number of elements in bounds table. */ +unsigned long bt_num_of_elems = (1UL << MPX_NUM_L2_BITS); +/* Function to test MPX wrapper of memmove function. + src_bigger_dst determines which address is bigger, can be 0 or 1. + src_bt_index and dst_bt index are bt_indexes + from the beginning of the page. + bd_index_end is the bd index of the last element of src if we define + bd index of the first element as 0. + src_bt index_end is bt index of the last element of src. + pointers inside determines if array being copied includes pointers + src_align and dst_align are alignments of src and dst. + Arrays may contain unaligned pointers. */ +int +test (int src_bigger_dst, int src_bt_index, int dst_bt_index, + int bd_index_end, int src_bt_index_end, int pointers_inside, + int src_align, int dst_align) +{ + const int n = + src_bt_index_end - src_bt_index + bd_index_end * bt_num_of_elems; + if (n < 0) + { + return 0; + } + const int num_of_pointers = (bd_index_end + 2) * bt_num_of_elems; + void **arr = 0; + posix_memalign ((void **) (&arr), + 1UL << (MPX_NUM_L2_BITS + MPX_NUM_IGN_BITS), + num_of_pointers * sizeof (void *)); + void **src = arr, **dst = arr; + if ((src_bigger_dst) && (src_bt_index < dst_bt_index)) + src_bt_index += bt_num_of_elems; + if (!(src_bigger_dst) && (src_bt_index > dst_bt_index)) + dst_bt_index += bt_num_of_elems; + src += src_bt_index; + dst += dst_bt_index; + char *realign = (char *) src; + realign += src_align; + src = (void **) realign; + realign = (char *) dst; + realign += src_align; + dst = (void **) realign; + if (pointers_inside) + { + for (int i = 0; i < n; i++) + src[i] = __bnd_set_ptr_bounds (arr + i, i * sizeof (void *) + 1); + } + memmove (dst, src, n * sizeof (void *)); + if (pointers_inside) + { + for (int i = 0; i < n; i++) + { + if (dst[i] != arr + i) + abort (); + if (__bnd_get_ptr_lbound (dst[i]) != arr + i) + abort (); + if (__bnd_get_ptr_ubound (dst[i]) != arr + 2 * i) + abort (); + } + } + free (arr); + return 0; +} + +/* Call testall to test common cases of memmove for MPX. */ +void +testall () +{ + int align[3]; + align[0] = 0; + align[1] = 1; + align[2] = 7; + for (int pointers_inside = 0; pointers_inside < 2; pointers_inside++) + for (int src_bigger_dst = 0; src_bigger_dst < 2; src_bigger_dst++) + for (int src_align = 0; src_align < 3; src_align ++) + for (int dst_align = 0; dst_align < 3; dst_align ++) + for (int pages = 0; pages < 4; pages++) + { + test (src_bigger_dst, 1, 2, pages, 1, pointers_inside, + align[src_align], align[dst_align]); + test (src_bigger_dst, 1, 2, pages, 2, pointers_inside, + align[src_align], align[dst_align]); + test (src_bigger_dst, 2, 1, pages, 12, pointers_inside, + align[src_align], align[dst_align]); + test (src_bigger_dst, 2, 1, pages, 1, pointers_inside, + align[src_align], align[dst_align]); + test (src_bigger_dst, 2, 3, pages, 12, pointers_inside, + align[src_align], align[dst_align]); + test (src_bigger_dst, 1, bt_num_of_elems - 2, pages, 2, + pointers_inside, align[src_align], align[dst_align]); + } +}; + +int +mpx_test (int argc, const char **argv) +{ + testall (); + return 0; +} diff --git a/libmpx/Makefile.in b/libmpx/Makefile.in index ff36a7f..d644af3 100644 --- a/libmpx/Makefile.in +++ b/libmpx/Makefile.in @@ -228,7 +228,6 @@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ link_libmpx = @link_libmpx@ -link_mpx = @link_mpx@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ diff --git a/libmpx/mpxrt/Makefile.am b/libmpx/mpxrt/Makefile.am old mode 100644 new mode 100755 index a00a808..3280b62 --- a/libmpx/mpxrt/Makefile.am +++ b/libmpx/mpxrt/Makefile.am @@ -13,7 +13,8 @@ libmpx_la_SOURCES = mpxrt.c mpxrt-utils.c libmpx_la_CFLAGS = -fPIC libmpx_la_DEPENDENCIES = libmpx.map -libmpx_la_LDFLAGS = -Wl,--version-script=$(srcdir)/libmpx.map $(link_libmpx) +libmpx_la_LDFLAGS = -Wl,--version-script=$(srcdir)/libmpx.map $(link_libmpx) \ + -version-info `grep -v '^\#' $(srcdir)/libtool-version` mpxrt.lo: mpxrt-utils.h mpxrt-utils.lo: mpxrt-utils.h diff --git a/libmpx/mpxrt/Makefile.in b/libmpx/mpxrt/Makefile.in index 646f3a9..1fdb454 100644 --- a/libmpx/mpxrt/Makefile.in +++ b/libmpx/mpxrt/Makefile.in @@ -222,7 +222,6 @@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ link_libmpx = @link_libmpx@ -link_mpx = @link_mpx@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ @@ -257,7 +256,9 @@ ACLOCAL_AMFLAGS = -I $(top_srcdir) -I $(top_srcdir)/config @LIBMPX_SUPPORTED_TRUE@libmpx_la_SOURCES = mpxrt.c mpxrt-utils.c @LIBMPX_SUPPORTED_TRUE@libmpx_la_CFLAGS = -fPIC @LIBMPX_SUPPORTED_TRUE@libmpx_la_DEPENDENCIES = libmpx.map -@LIBMPX_SUPPORTED_TRUE@libmpx_la_LDFLAGS = -Wl,--version-script=$(srcdir)/libmpx.map $(link_libmpx) +@LIBMPX_SUPPORTED_TRUE@libmpx_la_LDFLAGS = -Wl,--version-script=$(srcdir)/libmpx.map $(link_libmpx) \ +@LIBMPX_SUPPORTED_TRUE@ -version-info `grep -v '^\#' $(srcdir)/libtool-version` + # Work around what appears to be a GNU make bug handling MAKEFLAGS # values defined in terms of make variables, as is the case for CC and diff --git a/libmpx/mpxrt/libmpx.map b/libmpx/mpxrt/libmpx.map index 90093b7..1f0fc2c 100644 --- a/libmpx/mpxrt/libmpx.map +++ b/libmpx/mpxrt/libmpx.map @@ -3,3 +3,8 @@ LIBMPX_1.0 local: *; }; +LIBMPX_2.0 +{ + global: + get_bd; +} LIBMPX_1.0; diff --git a/libmpx/mpxrt/libtool-version b/libmpx/mpxrt/libtool-version index 5aa6ed7..7d99255 100644 --- a/libmpx/mpxrt/libtool-version +++ b/libmpx/mpxrt/libtool-version @@ -3,4 +3,4 @@ # a separate file so that version updates don't involve re-running # automake. # CURRENT:REVISION:AGE -1:0:0 +2:0:0 diff --git a/libmpx/mpxrt/mpxrt.c b/libmpx/mpxrt/mpxrt.c old mode 100644 new mode 100755 index c29c5d9..bcdd3a6 --- a/libmpx/mpxrt/mpxrt.c +++ b/libmpx/mpxrt/mpxrt.c @@ -51,34 +51,11 @@ #include #include #include "mpxrt-utils.h" - -#ifdef __i386__ - -/* i386 directory size is 4MB */ -#define NUM_L1_BITS 20 - -#define REG_IP_IDX REG_EIP -#define REX_PREFIX - -#define XSAVE_OFFSET_IN_FPMEM sizeof (struct _libc_fpstate) - -#else /* __i386__ */ - -/* x86_64 directory size is 2GB */ -#define NUM_L1_BITS 28 - -#define REG_IP_IDX REG_RIP -#define REX_PREFIX "0x48, " - -#define XSAVE_OFFSET_IN_FPMEM 0 - -#endif /* !__i386__ */ +#include "mpxrt.h" #define MPX_ENABLE_BIT_NO 0 #define BNDPRESERVE_BIT_NO 1 -const size_t MPX_L1_SIZE = (1UL << NUM_L1_BITS) * sizeof (void *); - struct xsave_hdr_struct { uint64_t xstate_bv; @@ -508,3 +485,10 @@ mpxrt_cleanup (void) __mpxrt_utils_free (); process_specific_finish (); } + +/* Get address of bounds directory. */ +void * +get_bd () +{ + return l1base; +} diff --git a/libmpx/mpxrt/mpxrt.h b/libmpx/mpxrt/mpxrt.h new file mode 100755 index 0000000..e825d7d --- /dev/null +++ b/libmpx/mpxrt/mpxrt.h @@ -0,0 +1,75 @@ +/* mpxrt.h -*-C++-*- + * + ************************************************************************* + * + * @copyright + * Copyright (C) 2015, Intel Corporation + * All rights reserved. + * + * @copyright + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * @copyright + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************/ +#ifdef __i386__ + +/* i386 directory size is 4MB. */ +#define NUM_L1_BITS 20 +#define NUM_L2_BITS 10 +#define NUM_IGN_BITS 2 +#define MPX_L1_ADDR_MASK 0xfffff000UL +#define MPX_L2_ADDR_MASK 0xfffffffcUL +#define MPX_L2_VALID_MASK 0x00000001UL + +#define REG_IP_IDX REG_EIP +#define REX_PREFIX + +#define XSAVE_OFFSET_IN_FPMEM sizeof (struct _libc_fpstate) + +#else /* __i386__ */ + +/* x86_64 directory size is 2GB. */ +#define NUM_L1_BITS 28 +#define NUM_L2_BITS 17 +#define NUM_IGN_BITS 3 +#define MPX_L1_ADDR_MASK 0xfffffffffffff000ULL +#define MPX_L2_ADDR_MASK 0xfffffffffffffff8ULL +#define MPX_L2_VALID_MASK 0x0000000000000001ULL + +#define REG_IP_IDX REG_RIP +#define REX_PREFIX "0x48, " + +#define XSAVE_OFFSET_IN_FPMEM 0 + +#endif /* !__i386__ */ + +#define MPX_L1_SIZE ((1UL << NUM_L1_BITS) * sizeof (void *)) + +/* Get address of bounds directory. */ +void * +get_bd (); diff --git a/libmpx/mpxwrap/Makefile.am b/libmpx/mpxwrap/Makefile.am old mode 100644 new mode 100755 index 72abccf..f24cdc8 --- a/libmpx/mpxwrap/Makefile.am +++ b/libmpx/mpxwrap/Makefile.am @@ -1,4 +1,5 @@ ALCLOCAL_AMFLAGS = -I .. -I ../config +AM_CPPFLAGS = -I $(top_srcdir) # May be used by toolexeclibdir. gcc_version := $(shell cat $(top_srcdir)/../gcc/BASE-VER) @@ -6,7 +7,8 @@ gcc_version := $(shell cat $(top_srcdir)/../gcc/BASE-VER) libmpxwrappers_la_CFLAGS = -fcheck-pointer-bounds -mmpx -fno-chkp-check-read \ -fno-chkp-check-write -fno-chkp-use-wrappers -fPIC libmpxwrappers_la_DEPENDENCIES = libmpxwrappers.map -libmpxwrappers_la_LDFLAGS = -Wl,--version-script=$(srcdir)/libmpxwrappers.map +libmpxwrappers_la_LDFLAGS = -Wl,--version-script=$(srcdir)/libmpxwrappers.map \ + -version-info `grep -v '^\#' $(srcdir)/libtool-version` toolexeclib_LTLIBRARIES = libmpxwrappers.la diff --git a/libmpx/mpxwrap/Makefile.in b/libmpx/mpxwrap/Makefile.in index 1612ebf..df1a334 100644 --- a/libmpx/mpxwrap/Makefile.in +++ b/libmpx/mpxwrap/Makefile.in @@ -221,7 +221,6 @@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ link_libmpx = @link_libmpx@ -link_mpx = @link_mpx@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ @@ -247,6 +246,7 @@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ ALCLOCAL_AMFLAGS = -I .. -I ../config +AM_CPPFLAGS = -I $(top_srcdir) # May be used by toolexeclibdir. gcc_version := $(shell cat $(top_srcdir)/../gcc/BASE-VER) @@ -254,7 +254,9 @@ libmpxwrappers_la_CFLAGS = -fcheck-pointer-bounds -mmpx -fno-chkp-check-read \ -fno-chkp-check-write -fno-chkp-use-wrappers -fPIC libmpxwrappers_la_DEPENDENCIES = libmpxwrappers.map -libmpxwrappers_la_LDFLAGS = -Wl,--version-script=$(srcdir)/libmpxwrappers.map +libmpxwrappers_la_LDFLAGS = -Wl,--version-script=$(srcdir)/libmpxwrappers.map \ + -version-info `grep -v '^\#' $(srcdir)/libtool-version` + toolexeclib_LTLIBRARIES = libmpxwrappers.la libmpxwrappers_la_SOURCES = mpx_wrappers.c diff --git a/libmpx/mpxwrap/libtool-version b/libmpx/mpxwrap/libtool-version old mode 100644 new mode 100755 index bfe84c8..fab30fb --- a/libmpx/mpxwrap/libtool-version +++ b/libmpx/mpxwrap/libtool-version @@ -3,4 +3,4 @@ # a separate file so that version updates don't involve re-running # automake. # CURRENT:REVISION:AGE -1:0:0 +2:0:0 diff --git a/libmpx/mpxwrap/mpx_wrappers.c b/libmpx/mpxwrap/mpx_wrappers.c old mode 100644 new mode 100755 index 58670aa..7991f48 --- a/libmpx/mpxwrap/mpx_wrappers.c +++ b/libmpx/mpxwrap/mpx_wrappers.c @@ -26,6 +26,8 @@ #include "stdlib.h" #include "string.h" #include +#include +#include "mpxrt/mpxrt.h" void * __mpx_wrapper_malloc (size_t size) @@ -88,75 +90,406 @@ __mpx_wrapper_bzero (void *dst, size_t len) __mpx_wrapper_memset (dst, 0, len); } -void * -__mpx_wrapper_memmove (void *dst, const void *src, size_t n) +/* The mpx_pointer type is used for getting bits + for bt_index (index in bounds table) and + bd_index (index in bounds directory). */ +typedef union +{ + struct + { + unsigned long ignored:NUM_IGN_BITS; + unsigned long l2entry:NUM_L2_BITS; + unsigned long l1index:NUM_L1_BITS; + }; + void *pointer; +} mpx_pointer; + +/* The mpx_bt_entry struct represents a cell in bounds table. + lb is the lower bound, ub is the upper bound, + p is the stored pointer. */ +struct mpx_bt_entry { - const char *s = (const char*)src; - char *d = (char*)dst; - void *ret = dst; - size_t offset_src = ((size_t) s) & (sizeof (void *) - 1); - size_t offset_dst = ((size_t) d) & (sizeof (void *) - 1); + void *lb; + void *ub; + void *p; + void *reserved; +}; + +/* A special type for bd is needed because bt addresses can be modified. */ +typedef struct mpx_bt_entry * volatile * bd_type; + +/* Function alloc_bt is used for allocating bounds table + for the destination pointers if we don't have one. + We generate a bounds store for some pointer belonging + to that table and kernel allocates the table for us. */ +static inline void __attribute__ ((bnd_legacy)) +alloc_bt (void *ptr) +{ + __asm__ __volatile__ ("bndstx %%bnd0, (%0,%0)"::"r" (ptr):"%bnd0"); +} - if (n == 0) - return ret; +/* get_bt returns address of bounds table that should + exist at BD[BD_INDEX]. If there is no address or the address is not valid, + we try to allocate a valid table. + If we succeed in getting bt, its address will be returned. + If we can't get a valid bt, NULL will be returned. */ +__attribute__ ((bnd_legacy)) static inline struct mpx_bt_entry * +get_bt (unsigned bd_index, bd_type bd) +{ + struct mpx_bt_entry *bt = (struct mpx_bt_entry *) ((uintptr_t) bd[bd_index] + & MPX_L2_ADDR_MASK); + if (!(bt) || !((uintptr_t) bd[bd_index] & MPX_L2_VALID_MASK)) + { + mpx_pointer ptr; + ptr.l1index = bd_index; + /* If we don't have BT, allocate it. */ + alloc_bt (ptr.pointer); + bt = (struct mpx_bt_entry *) ((uintptr_t) bd[bd_index] + & MPX_L2_ADDR_MASK); + if (!(bt) || !((uintptr_t) bd[bd_index] & MPX_L2_VALID_MASK)) + return NULL; + } + return bt; +} - __bnd_chk_ptr_bounds (dst, n); - __bnd_chk_ptr_bounds (src, n); +/* Function copy_if_possible moves elements from *FROM to *TO. + If ELEMS is less then the ELEMS_TO_COPY (elements we can copy), + it copies ELEMS elements and returns 0. + Otherwise, it copies ELEMS_TO_COPY elements and returns 1. */ +__attribute__ ((bnd_legacy)) static inline int +copy_if_possible (int elems, int elems_to_copy, struct mpx_bt_entry *from, + struct mpx_bt_entry *to) +{ + if (elems < elems_to_copy) + memmove (to, from, elems * sizeof (struct mpx_bt_entry)); + else + { + memmove (to, from, elems_to_copy * sizeof (struct mpx_bt_entry)); + return 1; + } + return 0; +} + +/* Function copy_if_possible_from_end moves elements ending at *SRC_END + to the place where they will end at *DST_END. + If ELEMS is less then the ELEMS_TO_COPY (elements we can copy), + function copies ELEMS elements and returns 0. + Otherwise, it copies ELEMS_TO_COPY elements and returns 1. */ +__attribute__ ((bnd_legacy)) static inline int +copy_if_possible_from_end (int elems, int elems_to_copy, struct mpx_bt_entry + *src_end, struct mpx_bt_entry *dst_end) +{ + if (elems < elems_to_copy) + memmove (dst_end - elems, src_end - elems, + elems * sizeof (struct mpx_bt_entry)); + else + { + memmove (dst_end - elems_to_copy, + src_end - elems_to_copy, + elems_to_copy * sizeof (struct mpx_bt_entry)); + return 1; + } + return 0; +} - /* Different alignment means that even if - pointers exist in memory, we don't how - pointers are aligned and therefore cann't - copy bounds anyway. */ - if (offset_src != offset_dst) - memmove (dst, src, n); +/* move_bounds function copies bounds for N bytes from bt of SRC to bt of DST. + It also copies bounds for all pointers inside. + There are 3 parts of the algorithm: + 1) We copy everything till the end of the first bounds table of SRC + 2) In loop we copy whole bound tables till the second-last one + 3) Data in the last bounds table is copied separately, after the loop. + If one of bound tables in SRC doesn't exist, + we skip it because there are no pointers. + Depending on the arrangement of SRC and DST we copy from the beginning + or from the end. */ +__attribute__ ((bnd_legacy)) static void +move_bounds (void *dst, const void *src, size_t n) +{ + bd_type bd = (bd_type)get_bd (); + if (!(bd)) + return; + + /* We get indexes for all tables and number of elements for BT. */ + unsigned long bt_num_of_elems = (1UL << NUM_L2_BITS); + mpx_pointer addr_src, addr_dst, addr_src_end, addr_dst_end; + addr_src.pointer = (char *) src; + addr_dst.pointer = (char *) dst; + addr_src_end.pointer = (char *) src + n - 1; + addr_dst_end.pointer = (char *) dst + n - 1; + unsigned dst_bd_index = addr_dst.l1index; + unsigned src_bd_index = addr_src.l1index; + unsigned dst_bt_index = addr_dst.l2entry; + unsigned src_bt_index = addr_src.l2entry; + + unsigned dst_bd_index_end = addr_dst_end.l1index; + unsigned src_bd_index_end = addr_src_end.l1index; + unsigned dst_bt_index_end = addr_dst_end.l2entry; + unsigned src_bt_index_end = addr_src_end.l2entry; + + int elems_to_copy = src_bt_index_end - src_bt_index + 1 + (src_bd_index_end + - src_bd_index) * bt_num_of_elems; + struct mpx_bt_entry *bt_src, *bt_dst; + uintptr_t bt_valid; + /* size1 and size2 will be used to find out what portions + can be used to copy data. */ + int size1_elem, size2_elem, size1_bytes, size2_bytes; + + /* Copy from the beginning. */ + if (((char *) src - (char *) dst) > 0) + { + /* Copy everything till the end of the first bounds table (src) */ + bt_src = (struct mpx_bt_entry *) ((uintptr_t) bd[src_bd_index] + & MPX_L2_ADDR_MASK); + bt_valid = (uintptr_t) bd[src_bd_index] & MPX_L2_VALID_MASK; + + /* We can copy the whole preliminary piece of data. */ + if (src_bt_index > dst_bt_index) + { + size1_elem = src_bt_index - dst_bt_index; + size2_elem = bt_num_of_elems - size1_elem; + size1_bytes = size1_elem * sizeof (struct mpx_bt_entry); + size2_bytes = size2_elem * sizeof (struct mpx_bt_entry); + + /* Check we have bounds to copy. */ + if (bt_src && bt_valid) + { + bt_dst = get_bt (dst_bd_index, bd); + if (!bt_dst) + return; + if (copy_if_possible (bt_num_of_elems - src_bt_index, + elems_to_copy, &(bt_src[src_bt_index]), + &(bt_dst[dst_bt_index]))) + return; + } + elems_to_copy -= bt_num_of_elems - src_bt_index; + } + /* We have to copy preliminary data in two parts. */ + else + { + size2_elem = dst_bt_index - src_bt_index; + size1_elem = bt_num_of_elems - size2_elem; + size1_bytes = size1_elem * sizeof (struct mpx_bt_entry); + size2_bytes = size2_elem * sizeof (struct mpx_bt_entry); + + /* Check we have bounds to copy. */ + if (bt_src && bt_valid) + { + bt_dst = get_bt (dst_bd_index, bd); + if (!bt_dst) + return; + + if (copy_if_possible (bt_num_of_elems - dst_bt_index, + elems_to_copy, &(bt_src[src_bt_index]), + &(bt_dst[dst_bt_index]))) + return; + elems_to_copy -= bt_num_of_elems - dst_bt_index; + + dst_bd_index++; + + bt_dst = get_bt (dst_bd_index, bd); + if (!bt_dst) + return; + if (copy_if_possible (size2_elem, elems_to_copy, + &(bt_src[size1_elem]), &(bt_dst[0]))) + return; + elems_to_copy -= size2_elem; + } + else + elems_to_copy -= bt_num_of_elems - src_bt_index; + } + src_bd_index++; + + /* For each bounds table check if it’s valid and move it. */ + for (; src_bd_index < src_bd_index_end; src_bd_index++) + { + bt_src = (struct mpx_bt_entry *) ((uintptr_t) bd[src_bd_index] + & MPX_L2_ADDR_MASK); + bt_valid = (uintptr_t) bd[src_bd_index] & MPX_L2_VALID_MASK; + + /* Check we have bounds to copy. */ + if (!bt_src || !bt_valid) + dst_bd_index++; + else + { + bt_dst = get_bt (dst_bd_index, bd); + if (!bt_dst) + return; + memmove (&(bt_dst[size2_elem]), &(bt_src[0]), size1_bytes); + dst_bd_index++; + bt_dst = get_bt (dst_bd_index, bd); + if (!bt_dst) + return; + memmove (&(bt_dst[0]), &(bt_src[size1_elem]), size2_bytes); + } + elems_to_copy -= bt_num_of_elems; + } + + /* Now we have the last page that may be not full + we copy it separately. */ + if (elems_to_copy > 0) + { + bt_src = (struct mpx_bt_entry *) ((uintptr_t) bd[src_bd_index] + & MPX_L2_ADDR_MASK); + bt_valid = (uintptr_t) bd[src_bd_index] & MPX_L2_VALID_MASK; + + /* Check we have bounds to copy. */ + if (bt_src && bt_valid) + { + bt_dst = get_bt (dst_bd_index, bd); + if (!bt_dst) + return; + + if (copy_if_possible (size1_elem, elems_to_copy, &(bt_src[0]), + &(bt_dst[size2_elem]))) + return; + + elems_to_copy -= size1_elem; + dst_bd_index++; + bt_dst = get_bt (dst_bd_index, bd); + if (!bt_dst) + return; + memmove (&(bt_dst[0]), &(bt_src[size1_elem]), + elems_to_copy * sizeof (struct mpx_bt_entry)); + + } + } + } + /* Copy from the end. */ else { - if (s < d) - { - d += n; - s += n; - offset_src = (offset_src + n) & (sizeof (void *) -1); - while (n-- && offset_src--) - *--d = *--s; - n++; - if (!n) - return ret; - void **d1 = (void **)d; - void **s1 = (void **)s; - /* This loop will also copy bounds. */ - while (n >= sizeof (void *)) - { - n -= sizeof (void *); - *--d1 = *--s1; - } - s = (char *)s1; - d = (char *)d1; - while (n--) - *--d = *--s; - } + /* Copy everything till the end of the first bounds table (src) */ + bt_src = (struct mpx_bt_entry *) ((uintptr_t) bd[src_bd_index_end] + & MPX_L2_ADDR_MASK); + bt_valid = (uintptr_t) bd[src_bd_index_end] & MPX_L2_VALID_MASK; + + if (src_bt_index_end <= dst_bt_index_end) + /* We can copy the whole preliminary piece of data. */ + { + size2_elem = dst_bt_index_end - src_bt_index_end; + size1_elem = bt_num_of_elems - size2_elem; + size1_bytes = size1_elem * sizeof (struct mpx_bt_entry); + size2_bytes = size2_elem * sizeof (struct mpx_bt_entry); + + /* Check we have bounds to copy. */ + if (bt_src && bt_valid) + { + bt_dst = get_bt (dst_bd_index_end, bd); + if (!bt_dst) + return; + + if (copy_if_possible_from_end (src_bt_index_end + 1, + elems_to_copy, &(bt_src[src_bt_index_end + 1]), + &(bt_dst[dst_bt_index_end + 1]))) + return; + } + elems_to_copy -= src_bt_index_end + 1; + } + /* We have to copy preliminary data in two parts. */ else - { - offset_src = sizeof (void *) - offset_src; - while (n-- && offset_src--) - *d++ = *s++; - n++; - if (!n) - return ret; - void **d1 = (void **)d; - void **s1 = (void **)s; - /* This loop will also copy bounds. */ - while (n >= sizeof (void *)) - { - n -= sizeof (void *); - *d1++ = *s1++; - } - s = (char *)s1; - d = (char *)d1; - while (n--) - *d++ = *s++; - } + { + size1_elem = src_bt_index_end - dst_bt_index_end; + size2_elem = bt_num_of_elems - size1_elem; + size1_bytes = size1_elem * sizeof (struct mpx_bt_entry); + size2_bytes = size2_elem * sizeof (struct mpx_bt_entry); + + /* Check we have bounds to copy. */ + if (bt_src && bt_valid) + { + bt_dst = get_bt (dst_bd_index_end, bd); + if (!bt_dst) + return; + if (copy_if_possible_from_end (dst_bt_index_end + 1, + elems_to_copy, &(bt_src[src_bt_index_end + 1]), + &(bt_dst[dst_bt_index_end + 1]))) + return; + elems_to_copy -= dst_bt_index_end + 1; + + dst_bd_index_end--; + + bt_dst = get_bt (dst_bd_index_end, bd); + if (!bt_dst) + return; + if (copy_if_possible_from_end (size1_elem, elems_to_copy, + &(bt_src[size1_elem]), &(bt_dst[bt_num_of_elems]))) + return; + + elems_to_copy -= size1_elem; + } + else + elems_to_copy -= src_bt_index_end + 1; + } + src_bd_index_end--; + /* For each bounds table we check if there are valid pointers inside. + If there are some, we copy table in pre-counted portions. */ + for (; src_bd_index_end > src_bd_index; src_bd_index_end--) + { + bt_src = (struct mpx_bt_entry *) ((uintptr_t) bd[src_bd_index_end] + & MPX_L2_ADDR_MASK); + bt_valid = (uintptr_t) bd[src_bd_index_end] & MPX_L2_VALID_MASK; + /* Check we have bounds to copy. */ + if (!bt_src || !bt_valid) + dst_bd_index_end--; + else + { + bt_dst = get_bt (dst_bd_index_end, bd); + if (!bt_dst) + return; + memmove (&(bt_dst[0]), &(bt_src[size1_elem]), size2_bytes); + dst_bd_index_end--; + bt_dst = get_bt (dst_bd_index_end, bd); + if (!bt_dst) + return; + memmove (&(bt_dst[size2_elem]), &(bt_src[0]), size1_bytes); + } + elems_to_copy -= bt_num_of_elems; + } + + /* Now we have the last page that may be not full + we copy it separately. */ + if (elems_to_copy > 0) + { + bt_src = (struct mpx_bt_entry *) ((uintptr_t) bd[src_bd_index_end] + & MPX_L2_ADDR_MASK); + bt_valid = (uintptr_t) bd[src_bd_index_end] & MPX_L2_VALID_MASK; + /* Check we have bounds to copy. */ + if (bt_src && bt_valid) + { + bt_dst = get_bt (dst_bd_index_end, bd); + if (!bt_dst) + return; + if (copy_if_possible_from_end (size2_elem, elems_to_copy, + &(bt_src[bt_num_of_elems]), &(bt_dst[size2_elem]))) + return; + + elems_to_copy -= size2_elem; + dst_bd_index_end--; + bt_dst = get_bt (dst_bd_index_end, bd); + if (!bt_dst) + return; + memmove (&(bt_dst[dst_bt_index]), &(bt_src[src_bt_index]), + elems_to_copy * sizeof (struct mpx_bt_entry)); + } + } } - return ret; + return; +} + +void * +__mpx_wrapper_memmove (void *dst, const void *src, size_t n) +{ + if (n == 0) + return dst; + + __bnd_chk_ptr_bounds (dst, n); + __bnd_chk_ptr_bounds (src, n); + + memmove (dst, src, n); + /* Not necessary to copy bounds if size is less then size of pointer + or SRC=DST. */ + if ((n >= sizeof (void *)) || (src != dst)) + move_bounds (dst, src, n); + +return dst; }