158234Skato/* 258234Skato * Copyright 2020, Data61, CSIRO (ABN 41 687 119 230) 358234Skato * 458234Skato * SPDX-License-Identifier: GPL-2.0-only 558234Skato */ 658234Skato 758234Skato#include <strops.h> 858234Skato#include <printf.h> 958234Skato#include <abort.h> 1058234Skato 1158234Skato/* Both memset and memcpy need a custom type that allows us to use a word 1258234Skato * that has the aliasing properties of a char. 1358234Skato */ 1458234Skato#ifdef __GNUC__ 1558234Skato#define HAS_MAY_ALIAS 1658234Skato#elif defined(__clang__) 1758234Skato#if __has_attribute(may_alias) 1858234Skato#define HAS_MAY_ALIAS 1958234Skato#endif 2058234Skato#endif 2158234Skato 2258234Skato#ifdef HAS_MAY_ALIAS 2358234Skatotypedef word_t __attribute__((__may_alias__)) u_alias; 2458234Skato#endif 2558234Skato 2658234Skatosize_t strlen(const char *str) 27145748Snyan{ 28145748Snyan const char *s; 2958234Skato for (s = str; *s; ++s); 30106047Snyan return (s - str); 3158234Skato} 32104459Snyan 33106047Snyanint strcmp(const char *a, const char *b) 3458234Skato{ 35106047Snyan while (1) { 3658234Skato if (*a != * b) { 3758234Skato return ((unsigned char) * a) - ((unsigned char) * b); 3858234Skato } 3958234Skato if (*a == 0) { 40148062Snyan return 0; 4169793Sobrien } 42106047Snyan a++; 43106047Snyan b++; 4458234Skato } 4558234Skato} 4658234Skato 4758234Skatoint strncmp(const char *s1, const char *s2, size_t n) 4858234Skato{ 4958234Skato word_t i; 5058234Skato int diff; 5158234Skato 5258234Skato for (i = 0; i < n; i++) { 5358234Skato diff = ((unsigned char *)s1)[i] - ((unsigned char *)s2)[i]; 5458234Skato if (diff != 0 || s1[i] == '\0') { 5558234Skato return diff; 5658234Skato } 5758234Skato } 5858234Skato 5958234Skato return 0; 6058234Skato} 6158234Skato 6258234Skatovoid *memset(void *s, int c, size_t n) 6358234Skato{ 6458234Skato char *mem = (char *)s; 6558234Skato 6658234Skato#ifdef HAS_MAY_ALIAS 6758234Skato /* fill byte by byte until word aligned */ 6858234Skato for (; (uintptr_t)mem % BYTE_PER_WORD != 0 && n > 0; mem++, n--) { 6958234Skato *mem = c; 70106047Snyan } 7158234Skato /* construct word filler */ 72106047Snyan u_alias fill = ((u_alias) - 1 / 255) * (unsigned char)c; 7358234Skato /* do as many word writes as we can */ 74106047Snyan for (; n > BYTE_PER_WORD - 1; n -= BYTE_PER_WORD, mem += BYTE_PER_WORD) { 7558234Skato *(u_alias *)mem = fill; 76106047Snyan } 7758234Skato /* fill byte by byte for any remainder */ 7858234Skato for (; n > 0; n--, mem++) { 7958234Skato *mem = c; 80108650Snyan } 8158234Skato#else 8258234Skato /* Without the __may__alias__ attribute we cannot safely do word writes 8358234Skato * so fallback to bytes */ 84106047Snyan size_t i; 85148062Snyan for (i = 0; i < n; i++) { 86106047Snyan mem[i] = c; 87106047Snyan } 88106047Snyan#endif 89106047Snyan 90106047Snyan return s; 9158234Skato} 9258234Skato 9358234Skatovoid *memmove(void *restrict dest, const void *restrict src, size_t n) 9458234Skato{ 9558234Skato unsigned char *d = (unsigned char *)dest; 9658234Skato const unsigned char *s = (const unsigned char *)src; 9758234Skato 9858234Skato /* no copying to do */ 9958234Skato if (d == s) { 10058234Skato return dest; 10158234Skato } 10258234Skato /* for non-overlapping regions, just use memcpy */ 10358234Skato else if (s + n <= d || d + n <= s) { 104156020Simp return memcpy(dest, src, n); 10558234Skato } 10658234Skato /* if copying from the start of s to the start of d, just use memcpy */ 10758234Skato else if (s > d) { 10858234Skato return memcpy(dest, src, n); 109106047Snyan } 11058234Skato 11158234Skato /* copy from end of 's' to end of 'd' */ 11258234Skato size_t i; 113106047Snyan for (i = 1; i <= n; i++) { 11458234Skato d[n - i] = s[n - i]; 115106047Snyan } 116106047Snyan 117106047Snyan return dest; 11858234Skato} 11958234Skato 12058234Skatovoid *memcpy(void *restrict dest, const void *restrict src, size_t n) 12158234Skato{ 12258234Skato unsigned char *d = (unsigned char *)dest; 12358234Skato const unsigned char *s = (const unsigned char *)src; 12458234Skato 125102231Strhodes /* For ARM, we also need to consider if src is aligned. * 126102231Strhodes * There are two cases: (1) If rs == 0 and rd == 0, dest * 12758234Skato * and src are copy_unit-aligned. (2) If (rs == rd && rs != 0), * 12858234Skato * src and dest can be made copy_unit-aligned by copying rs bytes * 12958234Skato * first. (1) is a special case of (2). */ 13058234Skato 131102231Strhodes size_t copy_unit = BYTE_PER_WORD; 13258234Skato while (1) { 13358234Skato int rs = (uintptr_t)s % copy_unit; 13458234Skato int rd = (uintptr_t)d % copy_unit; 13558234Skato if (rs == rd) { 13658234Skato break; 13758234Skato } 13858234Skato if (copy_unit == 1) { 13958234Skato break; 14058234Skato } 14158234Skato copy_unit >>= 1; 14258234Skato } 14358234Skato 14458234Skato#ifdef HAS_MAY_ALIAS 14558234Skato /* copy byte by byte until copy-unit aligned */ 14658234Skato for (; (uintptr_t)d % copy_unit != 0 && n > 0; d++, s++, n--) { 14758234Skato *d = *s; 14858234Skato } 14958234Skato /* copy unit by unit as long as we can */ 15058234Skato for (; n > copy_unit - 1; n -= copy_unit, s += copy_unit, d += copy_unit) { 15158234Skato switch (copy_unit) { 15258234Skato case 8: 15358234Skato *(uint64_t *)d = *(const uint64_t *)s; 154168934Simp break; 155106047Snyan case 4: 15658234Skato *(uint32_t *)d = *(const uint32_t *)s; 157106047Snyan break; 158106047Snyan case 2: 159106047Snyan *(uint16_t *)d = *(const uint16_t *)s; 160145765Snyan break; 161106047Snyan case 1: 16258234Skato *(uint8_t *)d = *(const uint8_t *)s; 163148062Snyan break; 164106047Snyan default: 165106047Snyan printf("Invalid copy unit %ld\n", copy_unit); 166106047Snyan abort(); 167106047Snyan } 168106047Snyan } 169106047Snyan /* copy any remainder byte by byte */ 17058234Skato for (; n > 0; d++, s++, n--) { 171145765Snyan *d = *s; 172156020Simp } 17358234Skato#else 17458234Skato size_t i; 17558234Skato for (i = 0; i < n; i++) { 17658234Skato d[i] = s[i]; 177106047Snyan } 17858234Skato#endif 179106047Snyan 180108650Snyan return dest; 18158234Skato} 182156020Simp