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