Mercurial > hg > CbC > CbC_gcc
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; +}