diff --git a/gcc/testsuite/gcc.target/i386/mpx/memmove-1.c b/gcc/testsuite/gcc.target/i386/mpx/memmove-1.c
new file mode 100755
index 0000000..0efd030
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/mpx/memmove-1.c
@@ -0,0 +1,117 @@
+/* { dg-do run } */
+/* { dg-options "-fcheck-pointer-bounds -mmpx" } */
+
+
+#include <stdint.h>
+#include <string.h>
+#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/gcc/testsuite/gcc.target/i386/mpx/memmove-2.c b/gcc/testsuite/gcc.target/i386/mpx/memmove-2.c
new file mode 100755
index 0000000..e1d78fa
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/mpx/memmove-2.c
@@ -0,0 +1,40 @@
+/* { dg-do run } */
+/* { dg-options "-fcheck-pointer-bounds -mmpx" } */
+
+
+#include <stdint.h>
+#include <string.h>
+#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.
+   Check case with no BT allocated for data.  */
+
+int
+mpx_test (int argc, const char **argv)
+{
+  void **arr = 0;
+  posix_memalign ((void **) (&arr),
+           1UL << (MPX_NUM_L2_BITS + MPX_NUM_IGN_BITS),
+           2 * bt_num_of_elems * sizeof (void *));
+  void **src = arr, **dst = arr, **ptr = arr;
+  src += 10;
+  dst += 1;
+  ptr += bt_num_of_elems + 100;
+  ptr[0] = __bnd_set_ptr_bounds (arr + 1, sizeof (void *) + 1);
+  memmove (dst, src, 5 * sizeof (void *));
+  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 <sys/prctl.h>
 #include <cpuid.h>
 #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..ffa7e7e
--- a/libmpx/mpxwrap/mpx_wrappers.c
+++ b/libmpx/mpxwrap/mpx_wrappers.c
@@ -26,6 +26,8 @@
 #include "stdlib.h"
 #include "string.h"
 #include <sys/mman.h>
+#include <stdint.h>
+#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;
+}
 
-  /* 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);
+/* 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
     {
-      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;
-	}
+      memmove (dst_end - elems_to_copy,
+           src_end - elems_to_copy,
+           elems_to_copy * sizeof (struct mpx_bt_entry));
+      return 1;
+    }
+  return 0;
+}
+
+/* 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
+    {
+      /* 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;
 }
 
 
