1 /* MPX Wrappers Library
2 Copyright (C) 2014 Free Software Foundation, Inc.
3 Contributed by Ilya Enkovich (ilya.enkovich@intel.com)
5 This file is part of GCC.
7 GCC is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 3, or (at your option) any later
12 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
17 Under Section 7 of GPL version 3, you are granted additional
18 permissions described in the GCC Runtime Library Exception, version
19 3.1, as published by the Free Software Foundation.
21 You should have received a copy of the GNU General Public License and
22 a copy of the GCC Runtime Library Exception along with this program;
23 see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
24 <http://www.gnu.org/licenses/>. */
30 #include "mpxrt/mpxrt.h"
33 __mpx_wrapper_malloc (size_t size
)
35 void *p
= (void *)malloc (size
);
36 if (!p
) return __bnd_null_ptr_bounds (p
);
37 return __bnd_set_ptr_bounds (p
, size
);
42 __mpx_wrapper_mmap (void *addr
, size_t length
, int prot
, int flags
,
45 void *p
= mmap (addr
, length
, prot
, flags
, fd
, offset
);
46 if (!p
) return __bnd_null_ptr_bounds (p
);
47 return __bnd_set_ptr_bounds (p
, length
);
51 __mpx_wrapper_realloc (void *ptr
, size_t n
)
54 return __mpx_wrapper_malloc (n
);
56 /* We don't kwnow how much data is copied by realloc
57 and therefore may check only lower bounds. */
58 __bnd_chk_ptr_lbounds (ptr
);
59 ptr
= realloc (ptr
, n
);
62 return __bnd_null_ptr_bounds (ptr
);
64 return __bnd_set_ptr_bounds (ptr
, n
);
68 __mpx_wrapper_calloc (size_t n_elements
, size_t element_size
)
70 void *p
= calloc (n_elements
, element_size
);
72 return __bnd_null_ptr_bounds (p
);
73 return __bnd_set_ptr_bounds (p
, n_elements
* element_size
);
77 __mpx_wrapper_memset (void *dstpp
, int c
, size_t len
)
81 __bnd_chk_ptr_bounds (dstpp
, len
);
82 memset (dstpp
, c
, len
);
88 __mpx_wrapper_bzero (void *dst
, size_t len
)
90 __mpx_wrapper_memset (dst
, 0, len
);
93 /* The mpx_pointer type is used for getting bits
94 for bt_index (index in bounds table) and
95 bd_index (index in bounds directory). */
100 unsigned long ignored
:NUM_IGN_BITS
;
101 unsigned long l2entry
:NUM_L2_BITS
;
102 unsigned long l1index
:NUM_L1_BITS
;
107 /* The mpx_bt_entry struct represents a cell in bounds table.
108 lb is the lower bound, ub is the upper bound,
109 p is the stored pointer. */
118 /* A special type for bd is needed because bt addresses can be modified. */
119 typedef struct mpx_bt_entry
* volatile * bd_type
;
121 /* Function alloc_bt is used for allocating bounds table
122 for the destination pointers if we don't have one.
123 We generate a bounds store for some pointer belonging
124 to that table and kernel allocates the table for us. */
125 static inline void __attribute__ ((bnd_legacy
))
128 __asm__
__volatile__ ("bndstx %%bnd0, (%0,%0)"::"r" (ptr
):"%bnd0");
131 /* get_bt returns address of bounds table that should
132 exist at BD[BD_INDEX]. If there is no address or the address is not valid,
133 we try to allocate a valid table.
134 If we succeed in getting bt, its address will be returned.
135 If we can't get a valid bt, NULL will be returned. */
136 __attribute__ ((bnd_legacy
)) static inline struct mpx_bt_entry
*
137 get_bt (unsigned bd_index
, bd_type bd
)
139 struct mpx_bt_entry
*bt
= (struct mpx_bt_entry
*) ((uintptr_t) bd
[bd_index
]
141 if (!(bt
) || !((uintptr_t) bd
[bd_index
] & MPX_L2_VALID_MASK
))
144 ptr
.l1index
= bd_index
;
145 /* If we don't have BT, allocate it. */
146 alloc_bt (ptr
.pointer
);
147 bt
= (struct mpx_bt_entry
*) ((uintptr_t) bd
[bd_index
]
149 if (!(bt
) || !((uintptr_t) bd
[bd_index
] & MPX_L2_VALID_MASK
))
155 /* Function copy_if_possible moves elements from *FROM to *TO.
156 If ELEMS is less then the ELEMS_TO_COPY (elements we can copy),
157 it copies ELEMS elements and returns 0.
158 Otherwise, it copies ELEMS_TO_COPY elements and returns 1. */
159 __attribute__ ((bnd_legacy
)) static inline int
160 copy_if_possible (int elems
, int elems_to_copy
, struct mpx_bt_entry
*from
,
161 struct mpx_bt_entry
*to
)
163 if (elems
< elems_to_copy
)
164 memmove (to
, from
, elems
* sizeof (struct mpx_bt_entry
));
167 memmove (to
, from
, elems_to_copy
* sizeof (struct mpx_bt_entry
));
173 /* Function copy_if_possible_from_end moves elements ending at *SRC_END
174 to the place where they will end at *DST_END.
175 If ELEMS is less then the ELEMS_TO_COPY (elements we can copy),
176 function copies ELEMS elements and returns 0.
177 Otherwise, it copies ELEMS_TO_COPY elements and returns 1. */
178 __attribute__ ((bnd_legacy
)) static inline int
179 copy_if_possible_from_end (int elems
, int elems_to_copy
, struct mpx_bt_entry
180 *src_end
, struct mpx_bt_entry
*dst_end
)
182 if (elems
< elems_to_copy
)
183 memmove (dst_end
- elems
, src_end
- elems
,
184 elems
* sizeof (struct mpx_bt_entry
));
187 memmove (dst_end
- elems_to_copy
,
188 src_end
- elems_to_copy
,
189 elems_to_copy
* sizeof (struct mpx_bt_entry
));
195 /* move_bounds function copies bounds for N bytes from bt of SRC to bt of DST.
196 It also copies bounds for all pointers inside.
197 There are 3 parts of the algorithm:
198 1) We copy everything till the end of the first bounds table of SRC
199 2) In loop we copy whole bound tables till the second-last one
200 3) Data in the last bounds table is copied separately, after the loop.
201 If one of bound tables in SRC doesn't exist,
202 we skip it because there are no pointers.
203 Depending on the arrangement of SRC and DST we copy from the beginning
205 __attribute__ ((bnd_legacy
)) static void
206 move_bounds (void *dst
, const void *src
, size_t n
)
208 bd_type bd
= (bd_type
)get_bd ();
212 /* We get indexes for all tables and number of elements for BT. */
213 unsigned long bt_num_of_elems
= (1UL << NUM_L2_BITS
);
214 mpx_pointer addr_src
, addr_dst
, addr_src_end
, addr_dst_end
;
215 addr_src
.pointer
= (char *) src
;
216 addr_dst
.pointer
= (char *) dst
;
217 addr_src_end
.pointer
= (char *) src
+ n
- 1;
218 addr_dst_end
.pointer
= (char *) dst
+ n
- 1;
219 unsigned dst_bd_index
= addr_dst
.l1index
;
220 unsigned src_bd_index
= addr_src
.l1index
;
221 unsigned dst_bt_index
= addr_dst
.l2entry
;
222 unsigned src_bt_index
= addr_src
.l2entry
;
224 unsigned dst_bd_index_end
= addr_dst_end
.l1index
;
225 unsigned src_bd_index_end
= addr_src_end
.l1index
;
226 unsigned dst_bt_index_end
= addr_dst_end
.l2entry
;
227 unsigned src_bt_index_end
= addr_src_end
.l2entry
;
229 int elems_to_copy
= src_bt_index_end
- src_bt_index
+ 1 + (src_bd_index_end
230 - src_bd_index
) * bt_num_of_elems
;
231 struct mpx_bt_entry
*bt_src
, *bt_dst
;
233 /* size1 and size2 will be used to find out what portions
234 can be used to copy data. */
235 int size1_elem
, size2_elem
, size1_bytes
, size2_bytes
;
237 /* Copy from the beginning. */
238 if (((char *) src
- (char *) dst
) > 0)
240 /* Copy everything till the end of the first bounds table (src) */
241 bt_src
= (struct mpx_bt_entry
*) ((uintptr_t) bd
[src_bd_index
]
243 bt_valid
= (uintptr_t) bd
[src_bd_index
] & MPX_L2_VALID_MASK
;
245 /* We can copy the whole preliminary piece of data. */
246 if (src_bt_index
> dst_bt_index
)
248 size1_elem
= src_bt_index
- dst_bt_index
;
249 size2_elem
= bt_num_of_elems
- size1_elem
;
250 size1_bytes
= size1_elem
* sizeof (struct mpx_bt_entry
);
251 size2_bytes
= size2_elem
* sizeof (struct mpx_bt_entry
);
253 /* Check we have bounds to copy. */
254 if (bt_src
&& bt_valid
)
256 bt_dst
= get_bt (dst_bd_index
, bd
);
259 if (copy_if_possible (bt_num_of_elems
- src_bt_index
,
260 elems_to_copy
, &(bt_src
[src_bt_index
]),
261 &(bt_dst
[dst_bt_index
])))
264 elems_to_copy
-= bt_num_of_elems
- src_bt_index
;
266 /* We have to copy preliminary data in two parts. */
269 size2_elem
= dst_bt_index
- src_bt_index
;
270 size1_elem
= bt_num_of_elems
- size2_elem
;
271 size1_bytes
= size1_elem
* sizeof (struct mpx_bt_entry
);
272 size2_bytes
= size2_elem
* sizeof (struct mpx_bt_entry
);
274 /* Check we have bounds to copy. */
275 if (bt_src
&& bt_valid
)
277 bt_dst
= get_bt (dst_bd_index
, bd
);
281 if (copy_if_possible (bt_num_of_elems
- dst_bt_index
,
282 elems_to_copy
, &(bt_src
[src_bt_index
]),
283 &(bt_dst
[dst_bt_index
])))
285 elems_to_copy
-= bt_num_of_elems
- dst_bt_index
;
289 bt_dst
= get_bt (dst_bd_index
, bd
);
292 if (copy_if_possible (size2_elem
, elems_to_copy
,
293 &(bt_src
[size1_elem
]), &(bt_dst
[0])))
295 elems_to_copy
-= size2_elem
;
298 elems_to_copy
-= bt_num_of_elems
- src_bt_index
;
302 /* For each bounds table check if it's valid and move it. */
303 for (; src_bd_index
< src_bd_index_end
; src_bd_index
++)
305 bt_src
= (struct mpx_bt_entry
*) ((uintptr_t) bd
[src_bd_index
]
307 bt_valid
= (uintptr_t) bd
[src_bd_index
] & MPX_L2_VALID_MASK
;
309 /* Check we have bounds to copy. */
310 if (!bt_src
|| !bt_valid
)
314 bt_dst
= get_bt (dst_bd_index
, bd
);
317 memmove (&(bt_dst
[size2_elem
]), &(bt_src
[0]), size1_bytes
);
319 bt_dst
= get_bt (dst_bd_index
, bd
);
322 memmove (&(bt_dst
[0]), &(bt_src
[size1_elem
]), size2_bytes
);
324 elems_to_copy
-= bt_num_of_elems
;
327 /* Now we have the last page that may be not full
328 we copy it separately. */
329 if (elems_to_copy
> 0)
331 bt_src
= (struct mpx_bt_entry
*) ((uintptr_t) bd
[src_bd_index
]
333 bt_valid
= (uintptr_t) bd
[src_bd_index
] & MPX_L2_VALID_MASK
;
335 /* Check we have bounds to copy. */
336 if (bt_src
&& bt_valid
)
338 bt_dst
= get_bt (dst_bd_index
, bd
);
342 if (copy_if_possible (size1_elem
, elems_to_copy
, &(bt_src
[0]),
343 &(bt_dst
[size2_elem
])))
346 elems_to_copy
-= size1_elem
;
348 bt_dst
= get_bt (dst_bd_index
, bd
);
351 memmove (&(bt_dst
[0]), &(bt_src
[size1_elem
]),
352 elems_to_copy
* sizeof (struct mpx_bt_entry
));
357 /* Copy from the end. */
360 /* Copy everything till the end of the first bounds table (src) */
361 bt_src
= (struct mpx_bt_entry
*) ((uintptr_t) bd
[src_bd_index_end
]
363 bt_valid
= (uintptr_t) bd
[src_bd_index_end
] & MPX_L2_VALID_MASK
;
365 if (src_bt_index_end
<= dst_bt_index_end
)
366 /* We can copy the whole preliminary piece of data. */
368 size2_elem
= dst_bt_index_end
- src_bt_index_end
;
369 size1_elem
= bt_num_of_elems
- size2_elem
;
370 size1_bytes
= size1_elem
* sizeof (struct mpx_bt_entry
);
371 size2_bytes
= size2_elem
* sizeof (struct mpx_bt_entry
);
373 /* Check we have bounds to copy. */
374 if (bt_src
&& bt_valid
)
376 bt_dst
= get_bt (dst_bd_index_end
, bd
);
380 if (copy_if_possible_from_end (src_bt_index_end
+ 1,
381 elems_to_copy
, &(bt_src
[src_bt_index_end
+ 1]),
382 &(bt_dst
[dst_bt_index_end
+ 1])))
385 elems_to_copy
-= src_bt_index_end
+ 1;
387 /* We have to copy preliminary data in two parts. */
390 size1_elem
= src_bt_index_end
- dst_bt_index_end
;
391 size2_elem
= bt_num_of_elems
- size1_elem
;
392 size1_bytes
= size1_elem
* sizeof (struct mpx_bt_entry
);
393 size2_bytes
= size2_elem
* sizeof (struct mpx_bt_entry
);
395 /* Check we have bounds to copy. */
396 if (bt_src
&& bt_valid
)
398 bt_dst
= get_bt (dst_bd_index_end
, bd
);
401 if (copy_if_possible_from_end (dst_bt_index_end
+ 1,
402 elems_to_copy
, &(bt_src
[src_bt_index_end
+ 1]),
403 &(bt_dst
[dst_bt_index_end
+ 1])))
405 elems_to_copy
-= dst_bt_index_end
+ 1;
409 bt_dst
= get_bt (dst_bd_index_end
, bd
);
412 if (copy_if_possible_from_end (size1_elem
, elems_to_copy
,
413 &(bt_src
[size1_elem
]), &(bt_dst
[bt_num_of_elems
])))
416 elems_to_copy
-= size1_elem
;
419 elems_to_copy
-= src_bt_index_end
+ 1;
422 /* For each bounds table we check if there are valid pointers inside.
423 If there are some, we copy table in pre-counted portions. */
424 for (; src_bd_index_end
> src_bd_index
; src_bd_index_end
--)
426 bt_src
= (struct mpx_bt_entry
*) ((uintptr_t) bd
[src_bd_index_end
]
428 bt_valid
= (uintptr_t) bd
[src_bd_index_end
] & MPX_L2_VALID_MASK
;
429 /* Check we have bounds to copy. */
430 if (!bt_src
|| !bt_valid
)
434 bt_dst
= get_bt (dst_bd_index_end
, bd
);
437 memmove (&(bt_dst
[0]), &(bt_src
[size1_elem
]), size2_bytes
);
439 bt_dst
= get_bt (dst_bd_index_end
, bd
);
442 memmove (&(bt_dst
[size2_elem
]), &(bt_src
[0]), size1_bytes
);
444 elems_to_copy
-= bt_num_of_elems
;
447 /* Now we have the last page that may be not full
448 we copy it separately. */
449 if (elems_to_copy
> 0)
451 bt_src
= (struct mpx_bt_entry
*) ((uintptr_t) bd
[src_bd_index_end
]
453 bt_valid
= (uintptr_t) bd
[src_bd_index_end
] & MPX_L2_VALID_MASK
;
454 /* Check we have bounds to copy. */
455 if (bt_src
&& bt_valid
)
457 bt_dst
= get_bt (dst_bd_index_end
, bd
);
460 if (copy_if_possible_from_end (size2_elem
, elems_to_copy
,
461 &(bt_src
[bt_num_of_elems
]), &(bt_dst
[size2_elem
])))
464 elems_to_copy
-= size2_elem
;
466 bt_dst
= get_bt (dst_bd_index_end
, bd
);
469 memmove (&(bt_dst
[dst_bt_index
]), &(bt_src
[src_bt_index
]),
470 elems_to_copy
* sizeof (struct mpx_bt_entry
));
478 __mpx_wrapper_memmove (void *dst
, const void *src
, size_t n
)
483 __bnd_chk_ptr_bounds (dst
, n
);
484 __bnd_chk_ptr_bounds (src
, n
);
486 /* When we copy exactly one pointer it is faster to
487 just use bndldx + bndstx. */
488 if (n
== sizeof (void *))
490 void *const *s
= (void *const *) src
;
491 void **d
= (void **) dst
;
496 memmove (dst
, src
, n
);
498 /* Not necessary to copy bounds if size is less then size of pointer
500 if ((n
>= sizeof (void *)) && (src
!= dst
))
501 move_bounds (dst
, src
, n
);
508 __mpx_wrapper_memcpy (void *dst
, const void *src
, size_t n
)
510 return __mpx_wrapper_memmove (dst
, src
, n
);
514 __mpx_wrapper_mempcpy (void *dst
, const void *src
, size_t n
)
516 return (char *)__mpx_wrapper_memcpy (dst
, src
, n
) + n
;
520 __mpx_wrapper_strncat (char *dst
, const char *src
, size_t n
)
522 size_t dst_size
= strlen (dst
);
523 size_t src_size
= strnlen (src
, n
);
525 __bnd_chk_ptr_bounds (dst
, dst_size
+ src_size
+ 1);
527 __bnd_chk_ptr_bounds (src
, src_size
+ 1);
529 __bnd_chk_ptr_bounds (src
, src_size
);
531 strncat (dst
, src
, n
);
537 __mpx_wrapper_strcat (char *dst
, const char *src
)
539 size_t dst_size
= strlen (dst
);
540 size_t src_size
= strlen (src
);
542 __bnd_chk_ptr_bounds (dst
, dst_size
+ src_size
+ 1);
543 __bnd_chk_ptr_bounds (src
, src_size
+ 1);
551 __mpx_wrapper_stpcpy (char *dst
, const char *src
)
553 size_t src_size
= strlen (src
);
555 __bnd_chk_ptr_bounds (dst
, src_size
+ 1);
556 __bnd_chk_ptr_bounds (src
, src_size
+ 1);
558 memcpy (dst
, src
, src_size
+ 1);
560 return dst
+ src_size
;
564 __mpx_wrapper_stpncpy (char *dst
, const char *src
, size_t n
)
566 size_t src_size
= strnlen (src
, n
);
569 __bnd_chk_ptr_bounds (dst
, n
);
572 __bnd_chk_ptr_bounds (src
, src_size
+ 1);
573 res
= dst
+ src_size
;
577 __bnd_chk_ptr_bounds (src
, src_size
);
581 memcpy (dst
, src
, src_size
);
583 memset (dst
+ src_size
, 0, n
- src_size
);
589 __mpx_wrapper_strcpy (char *dst
, const char *src
)
591 size_t src_size
= strlen (src
);
593 __bnd_chk_ptr_bounds (dst
, src_size
+ 1);
594 __bnd_chk_ptr_bounds (src
, src_size
+ 1);
596 memcpy (dst
, src
, src_size
+ 1);
602 __mpx_wrapper_strncpy (char *dst
, const char *src
, size_t n
)
604 size_t src_size
= strnlen (src
, n
);
606 __bnd_chk_ptr_bounds (dst
, n
);
608 __bnd_chk_ptr_bounds (src
, src_size
+ 1);
610 __bnd_chk_ptr_bounds (src
, src_size
);
612 memcpy (dst
, src
, src_size
);
614 memset (dst
+ src_size
, 0, n
- src_size
);
620 __mpx_wrapper_strlen (const char *s
)
622 size_t length
= strlen (s
);
623 __bnd_chk_ptr_bounds (s
, length
+ 1);