| // SPDX-License-Identifier: GPL-2.0 | |
| /* | |
| * arch/arm/boot/compressed/string.c | |
| * | |
| * Small subset of simple string routines | |
| */ | |
| #define __NO_FORTIFY | |
| #include <linux/string.h> | |
| /* | |
| * The decompressor is built without KASan but uses the same redirects as the | |
| * rest of the kernel when CONFIG_KASAN is enabled, defining e.g. memcpy() | |
| * to __memcpy() but since we are not linking with the main kernel string | |
| * library in the decompressor, that will lead to link failures. | |
| * | |
| * Undefine KASan's versions, define the wrapped functions and alias them to | |
| * the right names so that when e.g. __memcpy() appear in the code, it will | |
| * still be linked to this local version of memcpy(). | |
| */ | |
| #ifdef CONFIG_KASAN | |
| #undef memcpy | |
| #undef memmove | |
| #undef memset | |
| void *__memcpy(void *__dest, __const void *__src, size_t __n) __alias(memcpy); | |
| void *__memmove(void *__dest, __const void *__src, size_t count) __alias(memmove); | |
| void *__memset(void *s, int c, size_t count) __alias(memset); | |
| #endif | |
| void *memcpy(void *__dest, __const void *__src, size_t __n) | |
| { | |
| int i = 0; | |
| unsigned char *d = (unsigned char *)__dest, *s = (unsigned char *)__src; | |
| for (i = __n >> 3; i > 0; i--) { | |
| *d++ = *s++; | |
| *d++ = *s++; | |
| *d++ = *s++; | |
| *d++ = *s++; | |
| *d++ = *s++; | |
| *d++ = *s++; | |
| *d++ = *s++; | |
| *d++ = *s++; | |
| } | |
| if (__n & 1 << 2) { | |
| *d++ = *s++; | |
| *d++ = *s++; | |
| *d++ = *s++; | |
| *d++ = *s++; | |
| } | |
| if (__n & 1 << 1) { | |
| *d++ = *s++; | |
| *d++ = *s++; | |
| } | |
| if (__n & 1) | |
| *d++ = *s++; | |
| return __dest; | |
| } | |
| void *memmove(void *__dest, __const void *__src, size_t count) | |
| { | |
| unsigned char *d = __dest; | |
| const unsigned char *s = __src; | |
| if (__dest == __src) | |
| return __dest; | |
| if (__dest < __src) | |
| return memcpy(__dest, __src, count); | |
| while (count--) | |
| d[count] = s[count]; | |
| return __dest; | |
| } | |
| size_t strlen(const char *s) | |
| { | |
| const char *sc = s; | |
| while (*sc != '\0') | |
| sc++; | |
| return sc - s; | |
| } | |
| size_t strnlen(const char *s, size_t count) | |
| { | |
| const char *sc; | |
| for (sc = s; count-- && *sc != '\0'; ++sc) | |
| /* nothing */; | |
| return sc - s; | |
| } | |
| int memcmp(const void *cs, const void *ct, size_t count) | |
| { | |
| const unsigned char *su1 = cs, *su2 = ct, *end = su1 + count; | |
| int res = 0; | |
| while (su1 < end) { | |
| res = *su1++ - *su2++; | |
| if (res) | |
| break; | |
| } | |
| return res; | |
| } | |
| int strcmp(const char *cs, const char *ct) | |
| { | |
| unsigned char c1, c2; | |
| int res = 0; | |
| do { | |
| c1 = *cs++; | |
| c2 = *ct++; | |
| res = c1 - c2; | |
| if (res) | |
| break; | |
| } while (c1); | |
| return res; | |
| } | |
| void *memchr(const void *s, int c, size_t count) | |
| { | |
| const unsigned char *p = s; | |
| while (count--) | |
| if ((unsigned char)c == *p++) | |
| return (void *)(p - 1); | |
| return NULL; | |
| } | |
| char *strchr(const char *s, int c) | |
| { | |
| while (*s != (char)c) | |
| if (*s++ == '\0') | |
| return NULL; | |
| return (char *)s; | |
| } | |
| char *strrchr(const char *s, int c) | |
| { | |
| const char *last = NULL; | |
| do { | |
| if (*s == (char)c) | |
| last = s; | |
| } while (*s++); | |
| return (char *)last; | |
| } | |
| #undef memset | |
| void *memset(void *s, int c, size_t count) | |
| { | |
| char *xs = s; | |
| while (count--) | |
| *xs++ = c; | |
| return s; | |
| } |