diff libmpx/mpxwrap/mpx_wrappers.c @ 111:04ced10e8804

gcc 7
author kono
date Fri, 27 Oct 2017 22:46:09 +0900
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libmpx/mpxwrap/mpx_wrappers.c	Fri Oct 27 22:46:09 2017 +0900
@@ -0,0 +1,646 @@
+/* MPX Wrappers Library
+   Copyright (C) 2014 Free Software Foundation, Inc.
+   Contributed by Ilya Enkovich (ilya.enkovich@intel.com)
+
+   This file is part of GCC.
+
+   GCC is free software; you can redistribute it and/or modify it under
+   the terms of the GNU General Public License as published by the Free
+   Software Foundation; either version 3, or (at your option) any later
+   version.
+
+   GCC 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 General Public License
+   for more details.
+
+   Under Section 7 of GPL version 3, you are granted additional
+   permissions described in the GCC Runtime Library Exception, version
+   3.1, as published by the Free Software Foundation.
+
+   You should have received a copy of the GNU General Public License and
+   a copy of the GCC Runtime Library Exception along with this program;
+   see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include "stdlib.h"
+#include "string.h"
+#include <sys/mman.h>
+#include <stdint.h>
+#include <assert.h>
+#include "mpxrt/mpxrt.h"
+
+/* Since internal MPX wrapper calls must avoid PLT which will clear bound
+   registers, we make them static with an external alias.  */
+#define EXTERN_ALIAS(f) \
+  __typeof (f) __##f __attribute__((alias(#f)));
+
+static void *
+mpx_wrapper_malloc (size_t size)
+{
+  void *p = (void *)malloc (size);
+  if (!p) return __bnd_null_ptr_bounds (p);
+  return __bnd_set_ptr_bounds (p, size);
+}
+
+EXTERN_ALIAS (mpx_wrapper_malloc)
+
+void *
+__mpx_wrapper_mmap (void *addr, size_t length, int prot, int flags,
+		    int fd, off_t offset)
+{
+  void *p = mmap (addr, length, prot, flags, fd, offset);
+  if (!p) return __bnd_null_ptr_bounds (p);
+  return __bnd_set_ptr_bounds (p, length);
+}
+
+void *
+__mpx_wrapper_realloc (void *ptr, size_t n)
+{
+  if (!ptr)
+    return mpx_wrapper_malloc (n);
+
+  /* We don't kwnow how much data is copied by realloc
+     and therefore may check only lower bounds.  */
+  __bnd_chk_ptr_lbounds (ptr);
+  ptr = realloc (ptr, n);
+
+  if (!ptr)
+    return __bnd_null_ptr_bounds (ptr);
+
+  return __bnd_set_ptr_bounds (ptr, n);
+}
+
+void *
+__mpx_wrapper_calloc (size_t n_elements, size_t element_size)
+{
+  void *p = calloc (n_elements, element_size);
+  if (!p)
+    return __bnd_null_ptr_bounds (p);
+  return __bnd_set_ptr_bounds (p, n_elements * element_size);
+}
+
+static void *
+mpx_wrapper_memset (void *dstpp, int c, size_t len)
+{
+  if (len > 0)
+    {
+      __bnd_chk_ptr_bounds (dstpp, len);
+      memset (dstpp, c, len);
+    }
+  return dstpp;
+}
+
+EXTERN_ALIAS (mpx_wrapper_memset)
+
+void
+__mpx_wrapper_bzero (void *dst, size_t len)
+{
+  mpx_wrapper_memset (dst, 0, len);
+}
+
+/* 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
+{
+  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");
+}
+
+/* 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;
+}
+
+/* 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;
+}
+
+/* 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
+        {
+          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;
+        }
+      /* Go to previous table but beware of overflow.
+	 We should have copied all required element
+	 in case src_bd_index_end is 0.  */
+      if (src_bd_index_end)
+	src_bd_index_end--;
+      else
+	{
+	  assert (!elems_to_copy);
+	  return;
+	}
+      /* 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;
+}
+
+static 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);
+
+  /* When we copy exactly one pointer it is faster to
+     just use bndldx + bndstx.  */
+  if (n == sizeof (void *))
+    {
+      void *const *s = (void *const *) src;
+      void **d = (void **) dst;
+      *d = *s;
+      return dst;
+    }
+
+  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;
+}
+
+EXTERN_ALIAS (mpx_wrapper_memmove)
+
+static void *
+mpx_wrapper_memcpy (void *dst, const void *src, size_t n)
+{
+  return mpx_wrapper_memmove (dst, src, n);
+}
+
+EXTERN_ALIAS (mpx_wrapper_memcpy)
+
+void *
+__mpx_wrapper_mempcpy (void *dst, const void *src, size_t n)
+{
+  return (char *)mpx_wrapper_memcpy (dst, src, n) + n;
+}
+
+char *
+__mpx_wrapper_strncat (char *dst, const char *src, size_t n)
+{
+  size_t dst_size = strlen (dst);
+  size_t src_size = strnlen (src, n);
+
+  __bnd_chk_ptr_bounds (dst, dst_size + src_size + 1);
+  if (src_size < n)
+    __bnd_chk_ptr_bounds (src, src_size + 1);
+  else
+    __bnd_chk_ptr_bounds (src, src_size);
+
+  strncat (dst, src, n);
+
+  return dst;
+}
+
+char *
+__mpx_wrapper_strcat (char *dst, const char *src)
+{
+  size_t dst_size = strlen (dst);
+  size_t src_size = strlen (src);
+
+  __bnd_chk_ptr_bounds (dst, dst_size + src_size + 1);
+  __bnd_chk_ptr_bounds (src, src_size + 1);
+
+  strcat (dst, src);
+
+  return dst;
+}
+
+char *
+__mpx_wrapper_stpcpy (char *dst, const char *src)
+{
+  size_t src_size = strlen (src);
+
+  __bnd_chk_ptr_bounds (dst, src_size + 1);
+  __bnd_chk_ptr_bounds (src, src_size + 1);
+
+  memcpy (dst, src, src_size + 1);
+
+  return dst + src_size;
+}
+
+char *
+__mpx_wrapper_stpncpy (char *dst, const char *src, size_t n)
+{
+  size_t src_size = strnlen (src, n);
+  char *res;
+
+  __bnd_chk_ptr_bounds (dst, n);
+  if (src_size < n)
+    {
+      __bnd_chk_ptr_bounds (src, src_size + 1);
+      res = dst + src_size;
+    }
+  else
+    {
+      __bnd_chk_ptr_bounds (src, src_size);
+      res = dst + n;
+    }
+
+  memcpy (dst, src, src_size);
+  if (n > src_size)
+    memset (dst + src_size, 0, n - src_size);
+
+  return res;
+}
+
+char *
+__mpx_wrapper_strcpy (char *dst, const char *src)
+{
+  size_t src_size = strlen (src);
+
+  __bnd_chk_ptr_bounds (dst, src_size + 1);
+  __bnd_chk_ptr_bounds (src, src_size + 1);
+
+  memcpy (dst, src, src_size + 1);
+
+  return dst;
+}
+
+char *
+__mpx_wrapper_strncpy (char *dst, const char *src, size_t n)
+{
+  size_t src_size = strnlen (src, n);
+
+  __bnd_chk_ptr_bounds (dst, n);
+  if (src_size < n)
+    __bnd_chk_ptr_bounds (src, src_size + 1);
+  else
+    __bnd_chk_ptr_bounds (src, src_size);
+
+  memcpy (dst, src, src_size);
+  if (n > src_size)
+    memset (dst + src_size, 0, n - src_size);
+
+  return dst;
+}
+
+size_t
+__mpx_wrapper_strlen (const char *s)
+{
+  size_t length = strlen (s);
+  __bnd_chk_ptr_bounds (s, length + 1);
+  return length;
+}