linuxkm/linuxkm_wc_port.h: improve my_memcpy(), my_memset(), and my_memmove() (CONFIG_FORTIFY_SOURCE workarounds) with copy-by-words codepaths.

This commit is contained in:
Daniel Pouzzner
2024-01-27 23:12:37 -06:00
parent 82d94dab68
commit 8ae031a5ed

View File

@ -146,7 +146,7 @@
const char *s_start = s; const char *s_start = s;
while (*s) while (*s)
++s; ++s;
return (size_t)s - (size_t)s_start; return (size_t)((uintptr_t)s - (uintptr_t)s_start);
} }
#include <linux/string.h> #include <linux/string.h>
@ -157,37 +157,75 @@
(sizeof(s) - 1) : strlen(s)) (sizeof(s) - 1) : strlen(s))
static inline void *my_memcpy(void *dest, const void *src, size_t n) { static inline void *my_memcpy(void *dest, const void *src, size_t n) {
u8 *src_bytes = (u8 *)src, if (! (((uintptr_t)dest | (uintptr_t)src | (uintptr_t)n) & (uintptr_t)(sizeof(uintptr_t) - 1))) {
*dest_bytes = (u8 *)dest, uintptr_t *src_longs = (uintptr_t *)src,
*endp = src_bytes + n; *dest_longs = (uintptr_t *)dest,
while (src_bytes < endp) *endp = (uintptr_t *)((u8 *)src + n);
*dest_bytes++ = *src_bytes++; while (src_longs < endp)
*dest_longs++ = *src_longs++;
} else {
u8 *src_bytes = (u8 *)src,
*dest_bytes = (u8 *)dest,
*endp = src_bytes + n;
while (src_bytes < endp)
*dest_bytes++ = *src_bytes++;
}
return dest; return dest;
} }
#undef memcpy #undef memcpy
#define memcpy my_memcpy #define memcpy my_memcpy
static inline void *my_memset(void *dest, int c, size_t n) { static inline void *my_memset(void *dest, int c, size_t n) {
u8 *dest_bytes = (u8 *)dest, *endp = dest_bytes + n; if (! (((uintptr_t)dest | (uintptr_t)n) & (uintptr_t)(sizeof(uintptr_t) - 1))) {
while (dest_bytes < endp) uintptr_t c_long = __builtin_choose_expr(
*dest_bytes++ = (u8)c; sizeof(uintptr_t) == 8,
(uintptr_t)(u8)c * 0x0101010101010101UL,
(uintptr_t)(u8)c * 0x01010101U
);
uintptr_t *dest_longs = (uintptr_t *)dest, *endp = (uintptr_t *)((u8 *)dest_longs + n);
while (dest_longs < endp)
*dest_longs++ = c_long;
} else {
u8 *dest_bytes = (u8 *)dest, *endp = dest_bytes + n;
while (dest_bytes < endp)
*dest_bytes++ = (u8)c;
}
return dest; return dest;
} }
#undef memset #undef memset
#define memset my_memset #define memset my_memset
static inline void *my_memmove(void *dest, const void *src, size_t n) { static inline void *my_memmove(void *dest, const void *src, size_t n) {
u8 *src_bytes = (u8 *)src, *dest_bytes = (u8 *)dest; if (! (((uintptr_t)dest | (uintptr_t)src | (uintptr_t)n) & (uintptr_t)(sizeof(uintptr_t) - 1))) {
if (src_bytes < dest_bytes) { uintptr_t *src_longs = (uintptr_t *)src, *dest_longs = (uintptr_t *)dest;
u8 *startp = src_bytes; n >>= __builtin_choose_expr(
src_bytes += n - 1; sizeof(uintptr_t) == 8,
dest_bytes += n - 1; 3U,
while (src_bytes >= startp) 2U);
*dest_bytes-- = *src_bytes--; if (src_longs < dest_longs) {
} else if (src_bytes > dest_bytes) { uintptr_t *startp = src_longs;
u8 *endp = src_bytes + n; src_longs += n - 1;
while (src_bytes < endp) dest_longs += n - 1;
*dest_bytes++ = *src_bytes++; while (src_longs >= startp)
*dest_longs-- = *src_longs--;
} else if (src_longs > dest_longs) {
uintptr_t *endp = src_longs + n;
while (src_longs < endp)
*dest_longs++ = *src_longs++;
}
} else {
u8 *src_bytes = (u8 *)src, *dest_bytes = (u8 *)dest;
if (src_bytes < dest_bytes) {
u8 *startp = src_bytes;
src_bytes += n - 1;
dest_bytes += n - 1;
while (src_bytes >= startp)
*dest_bytes-- = *src_bytes--;
} else if (src_bytes > dest_bytes) {
u8 *endp = src_bytes + n;
while (src_bytes < endp)
*dest_bytes++ = *src_bytes++;
}
} }
return dest; return dest;
} }