1 /* SPDX-License-Identifier: LGPL-2.1 OR MIT */ 2 /* 3 * string function definitions for NOLIBC 4 * Copyright (C) 2017-2021 Willy Tarreau <w@1wt.eu> 5 */ 6 7 #ifndef _NOLIBC_STRING_H 8 #define _NOLIBC_STRING_H 9 10 #include "std.h" 11 12 static void *malloc(size_t len); 13 14 /* 15 * As much as possible, please keep functions alphabetically sorted. 16 */ 17 18 static __attribute__((unused)) 19 int memcmp(const void *s1, const void *s2, size_t n) 20 { 21 size_t ofs = 0; 22 int c1 = 0; 23 24 while (ofs < n && !(c1 = ((unsigned char *)s1)[ofs] - ((unsigned char *)s2)[ofs])) { 25 ofs++; 26 } 27 return c1; 28 } 29 30 static __attribute__((unused)) 31 void *_nolibc_memcpy_up(void *dst, const void *src, size_t len) 32 { 33 size_t pos = 0; 34 35 while (pos < len) { 36 ((char *)dst)[pos] = ((const char *)src)[pos]; 37 pos++; 38 } 39 return dst; 40 } 41 42 static __attribute__((unused)) 43 void *_nolibc_memcpy_down(void *dst, const void *src, size_t len) 44 { 45 while (len) { 46 len--; 47 ((char *)dst)[len] = ((const char *)src)[len]; 48 } 49 return dst; 50 } 51 52 /* might be ignored by the compiler without -ffreestanding, then found as 53 * missing. 54 */ 55 __attribute__((weak,unused,section(".text.nolibc_memmove"))) 56 void *memmove(void *dst, const void *src, size_t len) 57 { 58 size_t dir, pos; 59 60 pos = len; 61 dir = -1; 62 63 if (dst < src) { 64 pos = -1; 65 dir = 1; 66 } 67 68 while (len) { 69 pos += dir; 70 ((char *)dst)[pos] = ((const char *)src)[pos]; 71 len--; 72 } 73 return dst; 74 } 75 76 /* must be exported, as it's used by libgcc on ARM */ 77 __attribute__((weak,unused,section(".text.nolibc_memcpy"))) 78 void *memcpy(void *dst, const void *src, size_t len) 79 { 80 return _nolibc_memcpy_up(dst, src, len); 81 } 82 83 /* might be ignored by the compiler without -ffreestanding, then found as 84 * missing. 85 */ 86 __attribute__((weak,unused,section(".text.nolibc_memset"))) 87 void *memset(void *dst, int b, size_t len) 88 { 89 char *p = dst; 90 91 while (len--) 92 *(p++) = b; 93 return dst; 94 } 95 96 static __attribute__((unused)) 97 char *strchr(const char *s, int c) 98 { 99 while (*s) { 100 if (*s == (char)c) 101 return (char *)s; 102 s++; 103 } 104 return NULL; 105 } 106 107 static __attribute__((unused)) 108 int strcmp(const char *a, const char *b) 109 { 110 unsigned int c; 111 int diff; 112 113 while (!(diff = (unsigned char)*a++ - (c = (unsigned char)*b++)) && c) 114 ; 115 return diff; 116 } 117 118 static __attribute__((unused)) 119 char *strcpy(char *dst, const char *src) 120 { 121 char *ret = dst; 122 123 while ((*dst++ = *src++)); 124 return ret; 125 } 126 127 /* this function is only used with arguments that are not constants or when 128 * it's not known because optimizations are disabled. Note that gcc 12 129 * recognizes an strlen() pattern and replaces it with a jump to strlen(), 130 * thus itself, hence the asm() statement below that's meant to disable this 131 * confusing practice. 132 */ 133 static __attribute__((unused)) 134 size_t strlen(const char *str) 135 { 136 size_t len; 137 138 for (len = 0; str[len]; len++) 139 asm(""); 140 return len; 141 } 142 143 /* do not trust __builtin_constant_p() at -O0, as clang will emit a test and 144 * the two branches, then will rely on an external definition of strlen(). 145 */ 146 #if defined(__OPTIMIZE__) 147 #define nolibc_strlen(x) strlen(x) 148 #define strlen(str) ({ \ 149 __builtin_constant_p((str)) ? \ 150 __builtin_strlen((str)) : \ 151 nolibc_strlen((str)); \ 152 }) 153 #endif 154 155 static __attribute__((unused)) 156 size_t strnlen(const char *str, size_t maxlen) 157 { 158 size_t len; 159 160 for (len = 0; (len < maxlen) && str[len]; len++); 161 return len; 162 } 163 164 static __attribute__((unused)) 165 char *strdup(const char *str) 166 { 167 size_t len; 168 char *ret; 169 170 len = strlen(str); 171 ret = malloc(len + 1); 172 if (__builtin_expect(ret != NULL, 1)) 173 memcpy(ret, str, len + 1); 174 175 return ret; 176 } 177 178 static __attribute__((unused)) 179 char *strndup(const char *str, size_t maxlen) 180 { 181 size_t len; 182 char *ret; 183 184 len = strnlen(str, maxlen); 185 ret = malloc(len + 1); 186 if (__builtin_expect(ret != NULL, 1)) { 187 memcpy(ret, str, len); 188 ret[len] = '\0'; 189 } 190 191 return ret; 192 } 193 194 static __attribute__((unused)) 195 size_t strlcat(char *dst, const char *src, size_t size) 196 { 197 size_t len; 198 char c; 199 200 for (len = 0; dst[len]; len++) 201 ; 202 203 for (;;) { 204 c = *src; 205 if (len < size) 206 dst[len] = c; 207 if (!c) 208 break; 209 len++; 210 src++; 211 } 212 213 return len; 214 } 215 216 static __attribute__((unused)) 217 size_t strlcpy(char *dst, const char *src, size_t size) 218 { 219 size_t len; 220 char c; 221 222 for (len = 0;;) { 223 c = src[len]; 224 if (len < size) 225 dst[len] = c; 226 if (!c) 227 break; 228 len++; 229 } 230 return len; 231 } 232 233 static __attribute__((unused)) 234 char *strncat(char *dst, const char *src, size_t size) 235 { 236 char *orig = dst; 237 238 while (*dst) 239 dst++; 240 241 while (size && (*dst = *src)) { 242 src++; 243 dst++; 244 size--; 245 } 246 247 *dst = 0; 248 return orig; 249 } 250 251 static __attribute__((unused)) 252 int strncmp(const char *a, const char *b, size_t size) 253 { 254 unsigned int c; 255 int diff = 0; 256 257 while (size-- && 258 !(diff = (unsigned char)*a++ - (c = (unsigned char)*b++)) && c) 259 ; 260 261 return diff; 262 } 263 264 static __attribute__((unused)) 265 char *strncpy(char *dst, const char *src, size_t size) 266 { 267 size_t len; 268 269 for (len = 0; len < size; len++) 270 if ((dst[len] = *src)) 271 src++; 272 return dst; 273 } 274 275 static __attribute__((unused)) 276 char *strrchr(const char *s, int c) 277 { 278 const char *ret = NULL; 279 280 while (*s) { 281 if (*s == (char)c) 282 ret = s; 283 s++; 284 } 285 return (char *)ret; 286 } 287 288 #endif /* _NOLIBC_STRING_H */ 289