1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * arch/arm/boot/compressed/string.c |
4 | * |
5 | * Small subset of simple string routines |
6 | */ |
7 | |
8 | #define __NO_FORTIFY |
9 | #include <linux/string.h> |
10 | |
11 | /* |
12 | * The decompressor is built without KASan but uses the same redirects as the |
13 | * rest of the kernel when CONFIG_KASAN is enabled, defining e.g. memcpy() |
14 | * to __memcpy() but since we are not linking with the main kernel string |
15 | * library in the decompressor, that will lead to link failures. |
16 | * |
17 | * Undefine KASan's versions, define the wrapped functions and alias them to |
18 | * the right names so that when e.g. __memcpy() appear in the code, it will |
19 | * still be linked to this local version of memcpy(). |
20 | */ |
21 | #ifdef CONFIG_KASAN |
22 | #undef memcpy |
23 | #undef memmove |
24 | #undef memset |
25 | void *__memcpy(void *__dest, __const void *__src, size_t __n) __alias(memcpy); |
26 | void *__memmove(void *__dest, __const void *__src, size_t count) __alias(memmove); |
27 | void *__memset(void *s, int c, size_t count) __alias(memset); |
28 | #endif |
29 | |
30 | void *memcpy(void *__dest, __const void *__src, size_t __n) |
31 | { |
32 | int i = 0; |
33 | unsigned char *d = (unsigned char *)__dest, *s = (unsigned char *)__src; |
34 | |
35 | for (i = __n >> 3; i > 0; i--) { |
36 | *d++ = *s++; |
37 | *d++ = *s++; |
38 | *d++ = *s++; |
39 | *d++ = *s++; |
40 | *d++ = *s++; |
41 | *d++ = *s++; |
42 | *d++ = *s++; |
43 | *d++ = *s++; |
44 | } |
45 | |
46 | if (__n & 1 << 2) { |
47 | *d++ = *s++; |
48 | *d++ = *s++; |
49 | *d++ = *s++; |
50 | *d++ = *s++; |
51 | } |
52 | |
53 | if (__n & 1 << 1) { |
54 | *d++ = *s++; |
55 | *d++ = *s++; |
56 | } |
57 | |
58 | if (__n & 1) |
59 | *d++ = *s++; |
60 | |
61 | return __dest; |
62 | } |
63 | |
64 | void *memmove(void *__dest, __const void *__src, size_t count) |
65 | { |
66 | unsigned char *d = __dest; |
67 | const unsigned char *s = __src; |
68 | |
69 | if (__dest == __src) |
70 | return __dest; |
71 | |
72 | if (__dest < __src) |
73 | return memcpy(__dest, __src, n: count); |
74 | |
75 | while (count--) |
76 | d[count] = s[count]; |
77 | return __dest; |
78 | } |
79 | |
80 | size_t strlen(const char *s) |
81 | { |
82 | const char *sc = s; |
83 | |
84 | while (*sc != '\0') |
85 | sc++; |
86 | return sc - s; |
87 | } |
88 | |
89 | size_t strnlen(const char *s, size_t count) |
90 | { |
91 | const char *sc; |
92 | |
93 | for (sc = s; count-- && *sc != '\0'; ++sc) |
94 | /* nothing */; |
95 | return sc - s; |
96 | } |
97 | |
98 | int memcmp(const void *cs, const void *ct, size_t count) |
99 | { |
100 | const unsigned char *su1 = cs, *su2 = ct, *end = su1 + count; |
101 | int res = 0; |
102 | |
103 | while (su1 < end) { |
104 | res = *su1++ - *su2++; |
105 | if (res) |
106 | break; |
107 | } |
108 | return res; |
109 | } |
110 | |
111 | int strcmp(const char *cs, const char *ct) |
112 | { |
113 | unsigned char c1, c2; |
114 | int res = 0; |
115 | |
116 | do { |
117 | c1 = *cs++; |
118 | c2 = *ct++; |
119 | res = c1 - c2; |
120 | if (res) |
121 | break; |
122 | } while (c1); |
123 | return res; |
124 | } |
125 | |
126 | void *memchr(const void *s, int c, size_t count) |
127 | { |
128 | const unsigned char *p = s; |
129 | |
130 | while (count--) |
131 | if ((unsigned char)c == *p++) |
132 | return (void *)(p - 1); |
133 | return NULL; |
134 | } |
135 | |
136 | char *strchr(const char *s, int c) |
137 | { |
138 | while (*s != (char)c) |
139 | if (*s++ == '\0') |
140 | return NULL; |
141 | return (char *)s; |
142 | } |
143 | |
144 | char *strrchr(const char *s, int c) |
145 | { |
146 | const char *last = NULL; |
147 | do { |
148 | if (*s == (char)c) |
149 | last = s; |
150 | } while (*s++); |
151 | return (char *)last; |
152 | } |
153 | |
154 | #undef memset |
155 | |
156 | void *memset(void *s, int c, size_t count) |
157 | { |
158 | char *xs = s; |
159 | while (count--) |
160 | *xs++ = c; |
161 | return s; |
162 | } |
163 | |