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/>. */
31 #include "mpxrt/mpxrt.h"
34 __mpx_wrapper_malloc (size_t size
)
36 void *p
= (void *)malloc (size
);
37 if (!p
) return __bnd_null_ptr_bounds (p
);
38 return __bnd_set_ptr_bounds (p
, size
);
43 __mpx_wrapper_mmap (void *addr
, size_t length
, int prot
, int flags
,
46 void *p
= mmap (addr
, length
, prot
, flags
, fd
, offset
);
47 if (!p
) return __bnd_null_ptr_bounds (p
);
48 return __bnd_set_ptr_bounds (p
, length
);
52 __mpx_wrapper_realloc (void *ptr
, size_t n
)
55 return __mpx_wrapper_malloc (n
);
57 /* We don't kwnow how much data is copied by realloc
58 and therefore may check only lower bounds. */
59 __bnd_chk_ptr_lbounds (ptr
);
60 ptr
= realloc (ptr
, n
);
63 return __bnd_null_ptr_bounds (ptr
);
65 return __bnd_set_ptr_bounds (ptr
, n
);
69 __mpx_wrapper_calloc (size_t n_elements
, size_t element_size
)
71 void *p
= calloc (n_elements
, element_size
);
73 return __bnd_null_ptr_bounds (p
);
74 return __bnd_set_ptr_bounds (p
, n_elements
* element_size
);
78 __mpx_wrapper_memset (void *dstpp
, int c
, size_t len
)
82 __bnd_chk_ptr_bounds (dstpp
, len
);
83 memset (dstpp
, c
, len
);
89 __mpx_wrapper_bzero (void *dst
, size_t len
)
91 __mpx_wrapper_memset (dst
, 0, len
);
94 /* The mpx_pointer type is used for getting bits
95 for bt_index (index in bounds table) and
96 bd_index (index in bounds directory). */
101 unsigned long ignored
:NUM_IGN_BITS
;
102 unsigned long l2entry
:NUM_L2_BITS
;
103 unsigned long l1index
:NUM_L1_BITS
;
108 /* The mpx_bt_entry struct represents a cell in bounds table.
109 lb is the lower bound, ub is the upper bound,
110 p is the stored pointer. */
119 /* A special type for bd is needed because bt addresses can be modified. */
120 typedef struct mpx_bt_entry
* volatile * bd_type
;
122 /* Function alloc_bt is used for allocating bounds table
123 for the destination pointers if we don't have one.
124 We generate a bounds store for some pointer belonging
125 to that table and kernel allocates the table for us. */
126 static inline void __attribute__ ((bnd_legacy
))
129 __asm__
__volatile__ ("bndstx %%bnd0, (%0,%0)"::"r" (ptr
):"%bnd0");
132 /* get_bt returns address of bounds table that should
133 exist at BD[BD_INDEX]. If there is no address or the address is not valid,
134 we try to allocate a valid table.
135 If we succeed in getting bt, its address will be returned.
136 If we can't get a valid bt, NULL will be returned. */
137 __attribute__ ((bnd_legacy
)) static inline struct mpx_bt_entry
*
138 get_bt (unsigned bd_index
, bd_type bd
)
140 struct mpx_bt_entry
*bt
= (struct mpx_bt_entry
*) ((uintptr_t) bd
[bd_index
]
142 if (!(bt
) || !((uintptr_t) bd
[bd_index
] & MPX_L2_VALID_MASK
))
145 ptr
.l1index
= bd_index
;
146 /* If we don't have BT, allocate it. */
147 alloc_bt (ptr
.pointer
);
148 bt
= (struct mpx_bt_entry
*) ((uintptr_t) bd
[bd_index
]
150 if (!(bt
) || !((uintptr_t) bd
[bd_index
] & MPX_L2_VALID_MASK
))
156 /* Function copy_if_possible moves elements from *FROM to *TO.
157 If ELEMS is less then the ELEMS_TO_COPY (elements we can copy),
158 it copies ELEMS elements and returns 0.
159 Otherwise, it copies ELEMS_TO_COPY elements and returns 1. */
160 __attribute__ ((bnd_legacy
)) static inline int
161 copy_if_possible (int elems
, int elems_to_copy
, struct mpx_bt_entry
*from
,
162 struct mpx_bt_entry
*to
)
164 if (elems
< elems_to_copy
)
165 memmove (to
, from
, elems
* sizeof (struct mpx_bt_entry
));
168 memmove (to
, from
, elems_to_copy
* sizeof (struct mpx_bt_entry
));
174 /* Function copy_if_possible_from_end moves elements ending at *SRC_END
175 to the place where they will end at *DST_END.
176 If ELEMS is less then the ELEMS_TO_COPY (elements we can copy),
177 function copies ELEMS elements and returns 0.
178 Otherwise, it copies ELEMS_TO_COPY elements and returns 1. */
179 __attribute__ ((bnd_legacy
)) static inline int
180 copy_if_possible_from_end (int elems
, int elems_to_copy
, struct mpx_bt_entry
181 *src_end
, struct mpx_bt_entry
*dst_end
)
183 if (elems
< elems_to_copy
)
184 memmove (dst_end
- elems
, src_end
- elems
,
185 elems
* sizeof (struct mpx_bt_entry
));
188 memmove (dst_end
- elems_to_copy
,
189 src_end
- elems_to_copy
,
190 elems_to_copy
* sizeof (struct mpx_bt_entry
));
196 /* move_bounds function copies bounds for N bytes from bt of SRC to bt of DST.
197 It also copies bounds for all pointers inside.
198 There are 3 parts of the algorithm:
199 1) We copy everything till the end of the first bounds table of SRC
200 2) In loop we copy whole bound tables till the second-last one
201 3) Data in the last bounds table is copied separately, after the loop.
202 If one of bound tables in SRC doesn't exist,
203 we skip it because there are no pointers.
204 Depending on the arrangement of SRC and DST we copy from the beginning
206 __attribute__ ((bnd_legacy
)) static void
207 move_bounds (void *dst
, const void *src
, size_t n
)
209 bd_type bd
= (bd_type
)get_bd ();
213 /* We get indexes for all tables and number of elements for BT. */
214 unsigned long bt_num_of_elems
= (1UL << NUM_L2_BITS
);
215 mpx_pointer addr_src
, addr_dst
, addr_src_end
, addr_dst_end
;
216 addr_src
.pointer
= (char *) src
;
217 addr_dst
.pointer
= (char *) dst
;
218 addr_src_end
.pointer
= (char *) src
+ n
- 1;
219 addr_dst_end
.pointer
= (char *) dst
+ n
- 1;
220 unsigned dst_bd_index
= addr_dst
.l1index
;
221 unsigned src_bd_index
= addr_src
.l1index
;
222 unsigned dst_bt_index
= addr_dst
.l2entry
;
223 unsigned src_bt_index
= addr_src
.l2entry
;
225 unsigned dst_bd_index_end
= addr_dst_end
.l1index
;
226 unsigned src_bd_index_end
= addr_src_end
.l1index
;
227 unsigned dst_bt_index_end
= addr_dst_end
.l2entry
;
228 unsigned src_bt_index_end
= addr_src_end
.l2entry
;
230 int elems_to_copy
= src_bt_index_end
- src_bt_index
+ 1 + (src_bd_index_end
231 - src_bd_index
) * bt_num_of_elems
;
232 struct mpx_bt_entry
*bt_src
, *bt_dst
;
234 /* size1 and size2 will be used to find out what portions
235 can be used to copy data. */
236 int size1_elem
, size2_elem
, size1_bytes
, size2_bytes
;
238 /* Copy from the beginning. */
239 if (((char *) src
- (char *) dst
) > 0)
241 /* Copy everything till the end of the first bounds table (src) */
242 bt_src
= (struct mpx_bt_entry
*) ((uintptr_t) bd
[src_bd_index
]
244 bt_valid
= (uintptr_t) bd
[src_bd_index
] & MPX_L2_VALID_MASK
;
246 /* We can copy the whole preliminary piece of data. */
247 if (src_bt_index
> dst_bt_index
)
249 size1_elem
= src_bt_index
- dst_bt_index
;
250 size2_elem
= bt_num_of_elems
- size1_elem
;
251 size1_bytes
= size1_elem
* sizeof (struct mpx_bt_entry
);
252 size2_bytes
= size2_elem
* sizeof (struct mpx_bt_entry
);
254 /* Check we have bounds to copy. */
255 if (bt_src
&& bt_valid
)
257 bt_dst
= get_bt (dst_bd_index
, bd
);
260 if (copy_if_possible (bt_num_of_elems
- src_bt_index
,
261 elems_to_copy
, &(bt_src
[src_bt_index
]),
262 &(bt_dst
[dst_bt_index
])))
265 elems_to_copy
-= bt_num_of_elems
- src_bt_index
;
267 /* We have to copy preliminary data in two parts. */
270 size2_elem
= dst_bt_index
- src_bt_index
;
271 size1_elem
= bt_num_of_elems
- size2_elem
;
272 size1_bytes
= size1_elem
* sizeof (struct mpx_bt_entry
);
273 size2_bytes
= size2_elem
* sizeof (struct mpx_bt_entry
);
275 /* Check we have bounds to copy. */
276 if (bt_src
&& bt_valid
)
278 bt_dst
= get_bt (dst_bd_index
, bd
);
282 if (copy_if_possible (bt_num_of_elems
- dst_bt_index
,
283 elems_to_copy
, &(bt_src
[src_bt_index
]),
284 &(bt_dst
[dst_bt_index
])))
286 elems_to_copy
-= bt_num_of_elems
- dst_bt_index
;
290 bt_dst
= get_bt (dst_bd_index
, bd
);
293 if (copy_if_possible (size2_elem
, elems_to_copy
,
294 &(bt_src
[size1_elem
]), &(bt_dst
[0])))
296 elems_to_copy
-= size2_elem
;
299 elems_to_copy
-= bt_num_of_elems
- src_bt_index
;
303 /* For each bounds table check if it's valid and move it. */
304 for (; src_bd_index
< src_bd_index_end
; src_bd_index
++)
306 bt_src
= (struct mpx_bt_entry
*) ((uintptr_t) bd
[src_bd_index
]
308 bt_valid
= (uintptr_t) bd
[src_bd_index
] & MPX_L2_VALID_MASK
;
310 /* Check we have bounds to copy. */
311 if (!bt_src
|| !bt_valid
)
315 bt_dst
= get_bt (dst_bd_index
, bd
);
318 memmove (&(bt_dst
[size2_elem
]), &(bt_src
[0]), size1_bytes
);
320 bt_dst
= get_bt (dst_bd_index
, bd
);
323 memmove (&(bt_dst
[0]), &(bt_src
[size1_elem
]), size2_bytes
);
325 elems_to_copy
-= bt_num_of_elems
;
328 /* Now we have the last page that may be not full
329 we copy it separately. */
330 if (elems_to_copy
> 0)
332 bt_src
= (struct mpx_bt_entry
*) ((uintptr_t) bd
[src_bd_index
]
334 bt_valid
= (uintptr_t) bd
[src_bd_index
] & MPX_L2_VALID_MASK
;
336 /* Check we have bounds to copy. */
337 if (bt_src
&& bt_valid
)
339 bt_dst
= get_bt (dst_bd_index
, bd
);
343 if (copy_if_possible (size1_elem
, elems_to_copy
, &(bt_src
[0]),
344 &(bt_dst
[size2_elem
])))
347 elems_to_copy
-= size1_elem
;
349 bt_dst
= get_bt (dst_bd_index
, bd
);
352 memmove (&(bt_dst
[0]), &(bt_src
[size1_elem
]),
353 elems_to_copy
* sizeof (struct mpx_bt_entry
));
358 /* Copy from the end. */
361 /* Copy everything till the end of the first bounds table (src) */
362 bt_src
= (struct mpx_bt_entry
*) ((uintptr_t) bd
[src_bd_index_end
]
364 bt_valid
= (uintptr_t) bd
[src_bd_index_end
] & MPX_L2_VALID_MASK
;
366 if (src_bt_index_end
<= dst_bt_index_end
)
367 /* We can copy the whole preliminary piece of data. */
369 size2_elem
= dst_bt_index_end
- src_bt_index_end
;
370 size1_elem
= bt_num_of_elems
- size2_elem
;
371 size1_bytes
= size1_elem
* sizeof (struct mpx_bt_entry
);
372 size2_bytes
= size2_elem
* sizeof (struct mpx_bt_entry
);
374 /* Check we have bounds to copy. */
375 if (bt_src
&& bt_valid
)
377 bt_dst
= get_bt (dst_bd_index_end
, bd
);
381 if (copy_if_possible_from_end (src_bt_index_end
+ 1,
382 elems_to_copy
, &(bt_src
[src_bt_index_end
+ 1]),
383 &(bt_dst
[dst_bt_index_end
+ 1])))
386 elems_to_copy
-= src_bt_index_end
+ 1;
388 /* We have to copy preliminary data in two parts. */
391 size1_elem
= src_bt_index_end
- dst_bt_index_end
;
392 size2_elem
= bt_num_of_elems
- size1_elem
;
393 size1_bytes
= size1_elem
* sizeof (struct mpx_bt_entry
);
394 size2_bytes
= size2_elem
* sizeof (struct mpx_bt_entry
);
396 /* Check we have bounds to copy. */
397 if (bt_src
&& bt_valid
)
399 bt_dst
= get_bt (dst_bd_index_end
, bd
);
402 if (copy_if_possible_from_end (dst_bt_index_end
+ 1,
403 elems_to_copy
, &(bt_src
[src_bt_index_end
+ 1]),
404 &(bt_dst
[dst_bt_index_end
+ 1])))
406 elems_to_copy
-= dst_bt_index_end
+ 1;
410 bt_dst
= get_bt (dst_bd_index_end
, bd
);
413 if (copy_if_possible_from_end (size1_elem
, elems_to_copy
,
414 &(bt_src
[size1_elem
]), &(bt_dst
[bt_num_of_elems
])))
417 elems_to_copy
-= size1_elem
;
420 elems_to_copy
-= src_bt_index_end
+ 1;
422 /* Go to previous table but beware of overflow.
423 We should have copied all required element
424 in case src_bd_index_end is 0. */
425 if (src_bd_index_end
)
429 assert (!elems_to_copy
);
432 /* For each bounds table we check if there are valid pointers inside.
433 If there are some, we copy table in pre-counted portions. */
434 for (; src_bd_index_end
> src_bd_index
; src_bd_index_end
--)
436 bt_src
= (struct mpx_bt_entry
*) ((uintptr_t) bd
[src_bd_index_end
]
438 bt_valid
= (uintptr_t) bd
[src_bd_index_end
] & MPX_L2_VALID_MASK
;
439 /* Check we have bounds to copy. */
440 if (!bt_src
|| !bt_valid
)
444 bt_dst
= get_bt (dst_bd_index_end
, bd
);
447 memmove (&(bt_dst
[0]), &(bt_src
[size1_elem
]), size2_bytes
);
449 bt_dst
= get_bt (dst_bd_index_end
, bd
);
452 memmove (&(bt_dst
[size2_elem
]), &(bt_src
[0]), size1_bytes
);
454 elems_to_copy
-= bt_num_of_elems
;
457 /* Now we have the last page that may be not full
458 we copy it separately. */
459 if (elems_to_copy
> 0)
461 bt_src
= (struct mpx_bt_entry
*) ((uintptr_t) bd
[src_bd_index_end
]
463 bt_valid
= (uintptr_t) bd
[src_bd_index_end
] & MPX_L2_VALID_MASK
;
464 /* Check we have bounds to copy. */
465 if (bt_src
&& bt_valid
)
467 bt_dst
= get_bt (dst_bd_index_end
, bd
);
470 if (copy_if_possible_from_end (size2_elem
, elems_to_copy
,
471 &(bt_src
[bt_num_of_elems
]), &(bt_dst
[size2_elem
])))
474 elems_to_copy
-= size2_elem
;
476 bt_dst
= get_bt (dst_bd_index_end
, bd
);
479 memmove (&(bt_dst
[dst_bt_index
]), &(bt_src
[src_bt_index
]),
480 elems_to_copy
* sizeof (struct mpx_bt_entry
));
488 __mpx_wrapper_memmove (void *dst
, const void *src
, size_t n
)
493 __bnd_chk_ptr_bounds (dst
, n
);
494 __bnd_chk_ptr_bounds (src
, n
);
496 /* When we copy exactly one pointer it is faster to
497 just use bndldx + bndstx. */
498 if (n
== sizeof (void *))
500 void *const *s
= (void *const *) src
;
501 void **d
= (void **) dst
;
506 memmove (dst
, src
, n
);
508 /* Not necessary to copy bounds if size is less then size of pointer
510 if ((n
>= sizeof (void *)) && (src
!= dst
))
511 move_bounds (dst
, src
, n
);
518 __mpx_wrapper_memcpy (void *dst
, const void *src
, size_t n
)
520 return __mpx_wrapper_memmove (dst
, src
, n
);
524 __mpx_wrapper_mempcpy (void *dst
, const void *src
, size_t n
)
526 return (char *)__mpx_wrapper_memcpy (dst
, src
, n
) + n
;
530 __mpx_wrapper_strncat (char *dst
, const char *src
, size_t n
)
532 size_t dst_size
= strlen (dst
);
533 size_t src_size
= strnlen (src
, n
);
535 __bnd_chk_ptr_bounds (dst
, dst_size
+ src_size
+ 1);
537 __bnd_chk_ptr_bounds (src
, src_size
+ 1);
539 __bnd_chk_ptr_bounds (src
, src_size
);
541 strncat (dst
, src
, n
);
547 __mpx_wrapper_strcat (char *dst
, const char *src
)
549 size_t dst_size
= strlen (dst
);
550 size_t src_size
= strlen (src
);
552 __bnd_chk_ptr_bounds (dst
, dst_size
+ src_size
+ 1);
553 __bnd_chk_ptr_bounds (src
, src_size
+ 1);
561 __mpx_wrapper_stpcpy (char *dst
, const char *src
)
563 size_t src_size
= strlen (src
);
565 __bnd_chk_ptr_bounds (dst
, src_size
+ 1);
566 __bnd_chk_ptr_bounds (src
, src_size
+ 1);
568 memcpy (dst
, src
, src_size
+ 1);
570 return dst
+ src_size
;
574 __mpx_wrapper_stpncpy (char *dst
, const char *src
, size_t n
)
576 size_t src_size
= strnlen (src
, n
);
579 __bnd_chk_ptr_bounds (dst
, n
);
582 __bnd_chk_ptr_bounds (src
, src_size
+ 1);
583 res
= dst
+ src_size
;
587 __bnd_chk_ptr_bounds (src
, src_size
);
591 memcpy (dst
, src
, src_size
);
593 memset (dst
+ src_size
, 0, n
- src_size
);
599 __mpx_wrapper_strcpy (char *dst
, const char *src
)
601 size_t src_size
= strlen (src
);
603 __bnd_chk_ptr_bounds (dst
, src_size
+ 1);
604 __bnd_chk_ptr_bounds (src
, src_size
+ 1);
606 memcpy (dst
, src
, src_size
+ 1);
612 __mpx_wrapper_strncpy (char *dst
, const char *src
, size_t n
)
614 size_t src_size
= strnlen (src
, n
);
616 __bnd_chk_ptr_bounds (dst
, n
);
618 __bnd_chk_ptr_bounds (src
, src_size
+ 1);
620 __bnd_chk_ptr_bounds (src
, src_size
);
622 memcpy (dst
, src
, src_size
);
624 memset (dst
+ src_size
, 0, n
- src_size
);
630 __mpx_wrapper_strlen (const char *s
)
632 size_t length
= strlen (s
);
633 __bnd_chk_ptr_bounds (s
, length
+ 1);