xref: /linux/tools/include/nolibc/string.h (revision 36ec807b627b4c0a0a382f0ae48eac7187d14b2b)
1c91eb033SWilly Tarreau /* SPDX-License-Identifier: LGPL-2.1 OR MIT */
2c91eb033SWilly Tarreau /*
3c91eb033SWilly Tarreau  * string function definitions for NOLIBC
4c91eb033SWilly Tarreau  * Copyright (C) 2017-2021 Willy Tarreau <w@1wt.eu>
5c91eb033SWilly Tarreau  */
6c91eb033SWilly Tarreau 
7c91eb033SWilly Tarreau #ifndef _NOLIBC_STRING_H
8c91eb033SWilly Tarreau #define _NOLIBC_STRING_H
9c91eb033SWilly Tarreau 
10c91eb033SWilly Tarreau #include "std.h"
11c91eb033SWilly Tarreau 
1211dbdaefSAmmar Faizi static void *malloc(size_t len);
1311dbdaefSAmmar Faizi 
14c91eb033SWilly Tarreau /*
15c91eb033SWilly Tarreau  * As much as possible, please keep functions alphabetically sorted.
16c91eb033SWilly Tarreau  */
17c91eb033SWilly Tarreau 
18c91eb033SWilly Tarreau static __attribute__((unused))
19c91eb033SWilly Tarreau int memcmp(const void *s1, const void *s2, size_t n)
20c91eb033SWilly Tarreau {
21c91eb033SWilly Tarreau 	size_t ofs = 0;
22b3f4f51eSRasmus Villemoes 	int c1 = 0;
23c91eb033SWilly Tarreau 
24b3f4f51eSRasmus Villemoes 	while (ofs < n && !(c1 = ((unsigned char *)s1)[ofs] - ((unsigned char *)s2)[ofs])) {
25c91eb033SWilly Tarreau 		ofs++;
26c91eb033SWilly Tarreau 	}
27c91eb033SWilly Tarreau 	return c1;
28c91eb033SWilly Tarreau }
29c91eb033SWilly Tarreau 
30553845eeSAmmar Faizi #ifndef NOLIBC_ARCH_HAS_MEMMOVE
318d304a37SWilly Tarreau /* might be ignored by the compiler without -ffreestanding, then found as
328d304a37SWilly Tarreau  * missing.
338d304a37SWilly Tarreau  */
348d304a37SWilly Tarreau __attribute__((weak,unused,section(".text.nolibc_memmove")))
35c91eb033SWilly Tarreau void *memmove(void *dst, const void *src, size_t len)
36c91eb033SWilly Tarreau {
37d76232ffSWilly Tarreau 	size_t dir, pos;
38c91eb033SWilly Tarreau 
39d76232ffSWilly Tarreau 	pos = len;
40d76232ffSWilly Tarreau 	dir = -1;
41d76232ffSWilly Tarreau 
42d76232ffSWilly Tarreau 	if (dst < src) {
43d76232ffSWilly Tarreau 		pos = -1;
44d76232ffSWilly Tarreau 		dir = 1;
45c91eb033SWilly Tarreau 	}
46d76232ffSWilly Tarreau 
47d76232ffSWilly Tarreau 	while (len) {
48d76232ffSWilly Tarreau 		pos += dir;
49d76232ffSWilly Tarreau 		((char *)dst)[pos] = ((const char *)src)[pos];
50d76232ffSWilly Tarreau 		len--;
51d76232ffSWilly Tarreau 	}
52d76232ffSWilly Tarreau 	return dst;
53c91eb033SWilly Tarreau }
54553845eeSAmmar Faizi #endif /* #ifndef NOLIBC_ARCH_HAS_MEMMOVE */
55c91eb033SWilly Tarreau 
56553845eeSAmmar Faizi #ifndef NOLIBC_ARCH_HAS_MEMCPY
57c91eb033SWilly Tarreau /* must be exported, as it's used by libgcc on ARM */
5807f47ea0SWilly Tarreau __attribute__((weak,unused,section(".text.nolibc_memcpy")))
59c91eb033SWilly Tarreau void *memcpy(void *dst, const void *src, size_t len)
60c91eb033SWilly Tarreau {
61bc61614dSAmmar Faizi 	size_t pos = 0;
62bc61614dSAmmar Faizi 
63bc61614dSAmmar Faizi 	while (pos < len) {
64bc61614dSAmmar Faizi 		((char *)dst)[pos] = ((const char *)src)[pos];
65bc61614dSAmmar Faizi 		pos++;
66bc61614dSAmmar Faizi 	}
67bc61614dSAmmar Faizi 	return dst;
68c91eb033SWilly Tarreau }
69553845eeSAmmar Faizi #endif /* #ifndef NOLIBC_ARCH_HAS_MEMCPY */
70c91eb033SWilly Tarreau 
7112108aa8SAmmar Faizi #ifndef NOLIBC_ARCH_HAS_MEMSET
728d304a37SWilly Tarreau /* might be ignored by the compiler without -ffreestanding, then found as
738d304a37SWilly Tarreau  * missing.
748d304a37SWilly Tarreau  */
758d304a37SWilly Tarreau __attribute__((weak,unused,section(".text.nolibc_memset")))
76c91eb033SWilly Tarreau void *memset(void *dst, int b, size_t len)
77c91eb033SWilly Tarreau {
78c91eb033SWilly Tarreau 	char *p = dst;
79c91eb033SWilly Tarreau 
801bfbe1f3SWilly Tarreau 	while (len--) {
811bfbe1f3SWilly Tarreau 		/* prevent gcc from recognizing memset() here */
827f291cfaSThomas Weißschuh 		__asm__ volatile("");
83c91eb033SWilly Tarreau 		*(p++) = b;
841bfbe1f3SWilly Tarreau 	}
85c91eb033SWilly Tarreau 	return dst;
86c91eb033SWilly Tarreau }
8712108aa8SAmmar Faizi #endif /* #ifndef NOLIBC_ARCH_HAS_MEMSET */
88c91eb033SWilly Tarreau 
89c91eb033SWilly Tarreau static __attribute__((unused))
90c91eb033SWilly Tarreau char *strchr(const char *s, int c)
91c91eb033SWilly Tarreau {
92c91eb033SWilly Tarreau 	while (*s) {
93c91eb033SWilly Tarreau 		if (*s == (char)c)
94c91eb033SWilly Tarreau 			return (char *)s;
95c91eb033SWilly Tarreau 		s++;
96c91eb033SWilly Tarreau 	}
97c91eb033SWilly Tarreau 	return NULL;
98c91eb033SWilly Tarreau }
99c91eb033SWilly Tarreau 
100c91eb033SWilly Tarreau static __attribute__((unused))
1010e7b4929SWilly Tarreau int strcmp(const char *a, const char *b)
1020e7b4929SWilly Tarreau {
1030e7b4929SWilly Tarreau 	unsigned int c;
1040e7b4929SWilly Tarreau 	int diff;
1050e7b4929SWilly Tarreau 
1060e7b4929SWilly Tarreau 	while (!(diff = (unsigned char)*a++ - (c = (unsigned char)*b++)) && c)
1070e7b4929SWilly Tarreau 		;
1080e7b4929SWilly Tarreau 	return diff;
1090e7b4929SWilly Tarreau }
1100e7b4929SWilly Tarreau 
1110e7b4929SWilly Tarreau static __attribute__((unused))
112c91eb033SWilly Tarreau char *strcpy(char *dst, const char *src)
113c91eb033SWilly Tarreau {
114c91eb033SWilly Tarreau 	char *ret = dst;
115c91eb033SWilly Tarreau 
116c91eb033SWilly Tarreau 	while ((*dst++ = *src++));
117c91eb033SWilly Tarreau 	return ret;
118c91eb033SWilly Tarreau }
119c91eb033SWilly Tarreau 
12096980b83SWilly Tarreau /* this function is only used with arguments that are not constants or when
121bfc3b0f0SWilly Tarreau  * it's not known because optimizations are disabled. Note that gcc 12
122bfc3b0f0SWilly Tarreau  * recognizes an strlen() pattern and replaces it with a jump to strlen(),
123bfc3b0f0SWilly Tarreau  * thus itself, hence the asm() statement below that's meant to disable this
124bfc3b0f0SWilly Tarreau  * confusing practice.
12596980b83SWilly Tarreau  */
126689230b6SRodrigo Campos __attribute__((weak,unused,section(".text.nolibc_strlen")))
127bfc3b0f0SWilly Tarreau size_t strlen(const char *str)
128c91eb033SWilly Tarreau {
129c91eb033SWilly Tarreau 	size_t len;
130c91eb033SWilly Tarreau 
131bfc3b0f0SWilly Tarreau 	for (len = 0; str[len]; len++)
1327f291cfaSThomas Weißschuh 		__asm__("");
133c91eb033SWilly Tarreau 	return len;
134c91eb033SWilly Tarreau }
135c91eb033SWilly Tarreau 
13696980b83SWilly Tarreau /* do not trust __builtin_constant_p() at -O0, as clang will emit a test and
13796980b83SWilly Tarreau  * the two branches, then will rely on an external definition of strlen().
13896980b83SWilly Tarreau  */
13996980b83SWilly Tarreau #if defined(__OPTIMIZE__)
140bfc3b0f0SWilly Tarreau #define nolibc_strlen(x) strlen(x)
141c91eb033SWilly Tarreau #define strlen(str) ({                          \
142c91eb033SWilly Tarreau 	__builtin_constant_p((str)) ?           \
143c91eb033SWilly Tarreau 		__builtin_strlen((str)) :       \
144c91eb033SWilly Tarreau 		nolibc_strlen((str));           \
145c91eb033SWilly Tarreau })
14696980b83SWilly Tarreau #endif
147c91eb033SWilly Tarreau 
148c91eb033SWilly Tarreau static __attribute__((unused))
149b26823c1SAmmar Faizi size_t strnlen(const char *str, size_t maxlen)
150b26823c1SAmmar Faizi {
151b26823c1SAmmar Faizi 	size_t len;
152b26823c1SAmmar Faizi 
153b26823c1SAmmar Faizi 	for (len = 0; (len < maxlen) && str[len]; len++);
154b26823c1SAmmar Faizi 	return len;
155b26823c1SAmmar Faizi }
156b26823c1SAmmar Faizi 
157b26823c1SAmmar Faizi static __attribute__((unused))
15811dbdaefSAmmar Faizi char *strdup(const char *str)
15911dbdaefSAmmar Faizi {
16011dbdaefSAmmar Faizi 	size_t len;
16111dbdaefSAmmar Faizi 	char *ret;
16211dbdaefSAmmar Faizi 
16311dbdaefSAmmar Faizi 	len = strlen(str);
16411dbdaefSAmmar Faizi 	ret = malloc(len + 1);
16511dbdaefSAmmar Faizi 	if (__builtin_expect(ret != NULL, 1))
16611dbdaefSAmmar Faizi 		memcpy(ret, str, len + 1);
16711dbdaefSAmmar Faizi 
16811dbdaefSAmmar Faizi 	return ret;
16911dbdaefSAmmar Faizi }
17011dbdaefSAmmar Faizi 
17111dbdaefSAmmar Faizi static __attribute__((unused))
17211dbdaefSAmmar Faizi char *strndup(const char *str, size_t maxlen)
17311dbdaefSAmmar Faizi {
17411dbdaefSAmmar Faizi 	size_t len;
17511dbdaefSAmmar Faizi 	char *ret;
17611dbdaefSAmmar Faizi 
17711dbdaefSAmmar Faizi 	len = strnlen(str, maxlen);
17811dbdaefSAmmar Faizi 	ret = malloc(len + 1);
17911dbdaefSAmmar Faizi 	if (__builtin_expect(ret != NULL, 1)) {
18011dbdaefSAmmar Faizi 		memcpy(ret, str, len);
18111dbdaefSAmmar Faizi 		ret[len] = '\0';
18211dbdaefSAmmar Faizi 	}
18311dbdaefSAmmar Faizi 
18411dbdaefSAmmar Faizi 	return ret;
18511dbdaefSAmmar Faizi }
18611dbdaefSAmmar Faizi 
18711dbdaefSAmmar Faizi static __attribute__((unused))
188d9390de6SWilly Tarreau size_t strlcat(char *dst, const char *src, size_t size)
189d9390de6SWilly Tarreau {
190*e93b912eSThomas Weißschuh 	size_t len = strnlen(dst, size);
191d9390de6SWilly Tarreau 
19234d232c3SRodrigo Campos 	/*
19334d232c3SRodrigo Campos 	 * We want len < size-1. But as size is unsigned and can wrap
19434d232c3SRodrigo Campos 	 * around, we use len + 1 instead.
19534d232c3SRodrigo Campos 	 */
19634d232c3SRodrigo Campos 	while (len + 1 < size) {
19734d232c3SRodrigo Campos 		dst[len] = *src;
19834d232c3SRodrigo Campos 		if (*src == '\0')
199d9390de6SWilly Tarreau 			break;
200d9390de6SWilly Tarreau 		len++;
201d9390de6SWilly Tarreau 		src++;
202d9390de6SWilly Tarreau 	}
203d9390de6SWilly Tarreau 
20434d232c3SRodrigo Campos 	if (len < size)
20534d232c3SRodrigo Campos 		dst[len] = '\0';
20634d232c3SRodrigo Campos 
20734d232c3SRodrigo Campos 	while (*src++)
20834d232c3SRodrigo Campos 		len++;
20934d232c3SRodrigo Campos 
210d9390de6SWilly Tarreau 	return len;
211d9390de6SWilly Tarreau }
212d9390de6SWilly Tarreau 
213d9390de6SWilly Tarreau static __attribute__((unused))
214b312eb0bSWilly Tarreau size_t strlcpy(char *dst, const char *src, size_t size)
215b312eb0bSWilly Tarreau {
216b312eb0bSWilly Tarreau 	size_t len;
217b312eb0bSWilly Tarreau 
218fbffce81SRodrigo Campos 	for (len = 0; len < size; len++) {
219fbffce81SRodrigo Campos 		dst[len] = src[len];
220fbffce81SRodrigo Campos 		if (!dst[len])
221fbffce81SRodrigo Campos 			return len;
222b312eb0bSWilly Tarreau 	}
223fbffce81SRodrigo Campos 	if (size)
224fbffce81SRodrigo Campos 		dst[size-1] = '\0';
225fbffce81SRodrigo Campos 
226fbffce81SRodrigo Campos 	while (src[len])
227fbffce81SRodrigo Campos 		len++;
228fbffce81SRodrigo Campos 
229b312eb0bSWilly Tarreau 	return len;
230b312eb0bSWilly Tarreau }
231b312eb0bSWilly Tarreau 
232b312eb0bSWilly Tarreau static __attribute__((unused))
233d9390de6SWilly Tarreau char *strncat(char *dst, const char *src, size_t size)
234d9390de6SWilly Tarreau {
235d9390de6SWilly Tarreau 	char *orig = dst;
236d9390de6SWilly Tarreau 
237d9390de6SWilly Tarreau 	while (*dst)
238d9390de6SWilly Tarreau 		dst++;
239d9390de6SWilly Tarreau 
240d9390de6SWilly Tarreau 	while (size && (*dst = *src)) {
241d9390de6SWilly Tarreau 		src++;
242d9390de6SWilly Tarreau 		dst++;
243d9390de6SWilly Tarreau 		size--;
244d9390de6SWilly Tarreau 	}
245d9390de6SWilly Tarreau 
246d9390de6SWilly Tarreau 	*dst = 0;
247d9390de6SWilly Tarreau 	return orig;
248d9390de6SWilly Tarreau }
249d9390de6SWilly Tarreau 
2500e7b4929SWilly Tarreau static __attribute__((unused))
2510e7b4929SWilly Tarreau int strncmp(const char *a, const char *b, size_t size)
2520e7b4929SWilly Tarreau {
2530e7b4929SWilly Tarreau 	unsigned int c;
2540e7b4929SWilly Tarreau 	int diff = 0;
2550e7b4929SWilly Tarreau 
2560e7b4929SWilly Tarreau 	while (size-- &&
2570e7b4929SWilly Tarreau 	       !(diff = (unsigned char)*a++ - (c = (unsigned char)*b++)) && c)
2580e7b4929SWilly Tarreau 		;
2590e7b4929SWilly Tarreau 
2600e7b4929SWilly Tarreau 	return diff;
2610e7b4929SWilly Tarreau }
262d9390de6SWilly Tarreau 
263d9390de6SWilly Tarreau static __attribute__((unused))
264b312eb0bSWilly Tarreau char *strncpy(char *dst, const char *src, size_t size)
265b312eb0bSWilly Tarreau {
266b312eb0bSWilly Tarreau 	size_t len;
267b312eb0bSWilly Tarreau 
268b312eb0bSWilly Tarreau 	for (len = 0; len < size; len++)
269b312eb0bSWilly Tarreau 		if ((dst[len] = *src))
270b312eb0bSWilly Tarreau 			src++;
271b312eb0bSWilly Tarreau 	return dst;
272b312eb0bSWilly Tarreau }
273b312eb0bSWilly Tarreau 
274b312eb0bSWilly Tarreau static __attribute__((unused))
275c91eb033SWilly Tarreau char *strrchr(const char *s, int c)
276c91eb033SWilly Tarreau {
277c91eb033SWilly Tarreau 	const char *ret = NULL;
278c91eb033SWilly Tarreau 
279c91eb033SWilly Tarreau 	while (*s) {
280c91eb033SWilly Tarreau 		if (*s == (char)c)
281c91eb033SWilly Tarreau 			ret = s;
282c91eb033SWilly Tarreau 		s++;
283c91eb033SWilly Tarreau 	}
284c91eb033SWilly Tarreau 	return (char *)ret;
285c91eb033SWilly Tarreau }
286c91eb033SWilly Tarreau 
28755abdd1fSWilly Tarreau /* make sure to include all global symbols */
28855abdd1fSWilly Tarreau #include "nolibc.h"
28955abdd1fSWilly Tarreau 
290c91eb033SWilly Tarreau #endif /* _NOLIBC_STRING_H */
291