blob: dba9e1535d4d6ee98c90dcc55d86844562294e40 [file] [log] [blame]
#include <endian.h>
#include <stdint.h>
#include <string.h>
#include "asan_impl.h"
#include "libc.h"
NO_ASAN void* memcpy(void* restrict dest, const void* restrict src, size_t n) {
unsigned char* d = dest;
const unsigned char* s = src;
#ifdef __GNUC__
#if __BYTE_ORDER == __LITTLE_ENDIAN
#define LS >>
#define RS <<
#else
#define LS <<
#define RS >>
#endif
typedef uint32_t __attribute__((__may_alias__)) u32;
uint32_t w, x;
for (; (uintptr_t)s % 4 && n; n--)
*d++ = *s++;
if ((uintptr_t)d % 4 == 0) {
for (; n >= 16; s += 16, d += 16, n -= 16) {
*(u32*)(d + 0) = *(u32*)(s + 0);
*(u32*)(d + 4) = *(u32*)(s + 4);
*(u32*)(d + 8) = *(u32*)(s + 8);
*(u32*)(d + 12) = *(u32*)(s + 12);
}
if (n & 8) {
*(u32*)(d + 0) = *(u32*)(s + 0);
*(u32*)(d + 4) = *(u32*)(s + 4);
d += 8;
s += 8;
}
if (n & 4) {
*(u32*)(d + 0) = *(u32*)(s + 0);
d += 4;
s += 4;
}
if (n & 2) {
*d++ = *s++;
*d++ = *s++;
}
if (n & 1) {
*d = *s;
}
return dest;
}
if (n >= 32)
switch ((uintptr_t)d % 4) {
case 1:
w = *(u32*)s;
*d++ = *s++;
*d++ = *s++;
*d++ = *s++;
n -= 3;
for (; n >= 17; s += 16, d += 16, n -= 16) {
x = *(u32*)(s + 1);
*(u32*)(d + 0) = (w LS 24) | (x RS 8);
w = *(u32*)(s + 5);
*(u32*)(d + 4) = (x LS 24) | (w RS 8);
x = *(u32*)(s + 9);
*(u32*)(d + 8) = (w LS 24) | (x RS 8);
w = *(u32*)(s + 13);
*(u32*)(d + 12) = (x LS 24) | (w RS 8);
}
break;
case 2:
w = *(u32*)s;
*d++ = *s++;
*d++ = *s++;
n -= 2;
for (; n >= 18; s += 16, d += 16, n -= 16) {
x = *(u32*)(s + 2);
*(u32*)(d + 0) = (w LS 16) | (x RS 16);
w = *(u32*)(s + 6);
*(u32*)(d + 4) = (x LS 16) | (w RS 16);
x = *(u32*)(s + 10);
*(u32*)(d + 8) = (w LS 16) | (x RS 16);
w = *(u32*)(s + 14);
*(u32*)(d + 12) = (x LS 16) | (w RS 16);
}
break;
case 3:
w = *(u32*)s;
*d++ = *s++;
n -= 1;
for (; n >= 19; s += 16, d += 16, n -= 16) {
x = *(u32*)(s + 3);
*(u32*)(d + 0) = (w LS 8) | (x RS 24);
w = *(u32*)(s + 7);
*(u32*)(d + 4) = (x LS 8) | (w RS 24);
x = *(u32*)(s + 11);
*(u32*)(d + 8) = (w LS 8) | (x RS 24);
w = *(u32*)(s + 15);
*(u32*)(d + 12) = (x LS 8) | (w RS 24);
}
break;
}
if (n & 16) {
*d++ = *s++;
*d++ = *s++;
*d++ = *s++;
*d++ = *s++;
*d++ = *s++;
*d++ = *s++;
*d++ = *s++;
*d++ = *s++;
*d++ = *s++;
*d++ = *s++;
*d++ = *s++;
*d++ = *s++;
*d++ = *s++;
*d++ = *s++;
*d++ = *s++;
*d++ = *s++;
}
if (n & 8) {
*d++ = *s++;
*d++ = *s++;
*d++ = *s++;
*d++ = *s++;
*d++ = *s++;
*d++ = *s++;
*d++ = *s++;
*d++ = *s++;
}
if (n & 4) {
*d++ = *s++;
*d++ = *s++;
*d++ = *s++;
*d++ = *s++;
}
if (n & 2) {
*d++ = *s++;
*d++ = *s++;
}
if (n & 1) {
*d = *s;
}
return dest;
#endif
for (; n; n--)
*d++ = *s++;
return dest;
}
__typeof(memcpy) __unsanitized_memcpy __attribute__((alias("memcpy")));
__asan_weak_alias(memcpy)