| // 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; |
| } |