1/* 2 * Copyright 2020, Data61, CSIRO (ABN 41 687 119 230) 3 * 4 * SPDX-License-Identifier: GPL-2.0-only 5 */ 6 7#include <strops.h> 8#include <printf.h> 9#include <abort.h> 10 11/* Both memset and memcpy need a custom type that allows us to use a word 12 * that has the aliasing properties of a char. 13 */ 14#ifdef __GNUC__ 15#define HAS_MAY_ALIAS 16#elif defined(__clang__) 17#if __has_attribute(may_alias) 18#define HAS_MAY_ALIAS 19#endif 20#endif 21 22#ifdef HAS_MAY_ALIAS 23typedef word_t __attribute__((__may_alias__)) u_alias; 24#endif 25 26size_t strlen(const char *str) 27{ 28 const char *s; 29 for (s = str; *s; ++s); 30 return (s - str); 31} 32 33int strcmp(const char *a, const char *b) 34{ 35 while (1) { 36 if (*a != * b) { 37 return ((unsigned char) * a) - ((unsigned char) * b); 38 } 39 if (*a == 0) { 40 return 0; 41 } 42 a++; 43 b++; 44 } 45} 46 47int strncmp(const char *s1, const char *s2, size_t n) 48{ 49 word_t i; 50 int diff; 51 52 for (i = 0; i < n; i++) { 53 diff = ((unsigned char *)s1)[i] - ((unsigned char *)s2)[i]; 54 if (diff != 0 || s1[i] == '\0') { 55 return diff; 56 } 57 } 58 59 return 0; 60} 61 62void *memset(void *s, int c, size_t n) 63{ 64 char *mem = (char *)s; 65 66#ifdef HAS_MAY_ALIAS 67 /* fill byte by byte until word aligned */ 68 for (; (uintptr_t)mem % BYTE_PER_WORD != 0 && n > 0; mem++, n--) { 69 *mem = c; 70 } 71 /* construct word filler */ 72 u_alias fill = ((u_alias) - 1 / 255) * (unsigned char)c; 73 /* do as many word writes as we can */ 74 for (; n > BYTE_PER_WORD - 1; n -= BYTE_PER_WORD, mem += BYTE_PER_WORD) { 75 *(u_alias *)mem = fill; 76 } 77 /* fill byte by byte for any remainder */ 78 for (; n > 0; n--, mem++) { 79 *mem = c; 80 } 81#else 82 /* Without the __may__alias__ attribute we cannot safely do word writes 83 * so fallback to bytes */ 84 size_t i; 85 for (i = 0; i < n; i++) { 86 mem[i] = c; 87 } 88#endif 89 90 return s; 91} 92 93void *memmove(void *restrict dest, const void *restrict src, size_t n) 94{ 95 unsigned char *d = (unsigned char *)dest; 96 const unsigned char *s = (const unsigned char *)src; 97 98 /* no copying to do */ 99 if (d == s) { 100 return dest; 101 } 102 /* for non-overlapping regions, just use memcpy */ 103 else if (s + n <= d || d + n <= s) { 104 return memcpy(dest, src, n); 105 } 106 /* if copying from the start of s to the start of d, just use memcpy */ 107 else if (s > d) { 108 return memcpy(dest, src, n); 109 } 110 111 /* copy from end of 's' to end of 'd' */ 112 size_t i; 113 for (i = 1; i <= n; i++) { 114 d[n - i] = s[n - i]; 115 } 116 117 return dest; 118} 119 120void *memcpy(void *restrict dest, const void *restrict src, size_t n) 121{ 122 unsigned char *d = (unsigned char *)dest; 123 const unsigned char *s = (const unsigned char *)src; 124 125 /* For ARM, we also need to consider if src is aligned. * 126 * There are two cases: (1) If rs == 0 and rd == 0, dest * 127 * and src are copy_unit-aligned. (2) If (rs == rd && rs != 0), * 128 * src and dest can be made copy_unit-aligned by copying rs bytes * 129 * first. (1) is a special case of (2). */ 130 131 size_t copy_unit = BYTE_PER_WORD; 132 while (1) { 133 int rs = (uintptr_t)s % copy_unit; 134 int rd = (uintptr_t)d % copy_unit; 135 if (rs == rd) { 136 break; 137 } 138 if (copy_unit == 1) { 139 break; 140 } 141 copy_unit >>= 1; 142 } 143 144#ifdef HAS_MAY_ALIAS 145 /* copy byte by byte until copy-unit aligned */ 146 for (; (uintptr_t)d % copy_unit != 0 && n > 0; d++, s++, n--) { 147 *d = *s; 148 } 149 /* copy unit by unit as long as we can */ 150 for (; n > copy_unit - 1; n -= copy_unit, s += copy_unit, d += copy_unit) { 151 switch (copy_unit) { 152 case 8: 153 *(uint64_t *)d = *(const uint64_t *)s; 154 break; 155 case 4: 156 *(uint32_t *)d = *(const uint32_t *)s; 157 break; 158 case 2: 159 *(uint16_t *)d = *(const uint16_t *)s; 160 break; 161 case 1: 162 *(uint8_t *)d = *(const uint8_t *)s; 163 break; 164 default: 165 printf("Invalid copy unit %ld\n", copy_unit); 166 abort(); 167 } 168 } 169 /* copy any remainder byte by byte */ 170 for (; n > 0; d++, s++, n--) { 171 *d = *s; 172 } 173#else 174 size_t i; 175 for (i = 0; i < n; i++) { 176 d[i] = s[i]; 177 } 178#endif 179 180 return dest; 181} 182