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 /* prevent gcc from recognizing memset() here */ 93 asm volatile(""); 94 *(p++) = b; 95 } 96 return dst; 97 } 98 99 static __attribute__((unused)) 100 char *strchr(const char *s, int c) 101 { 102 while (*s) { 103 if (*s == (char)c) 104 return (char *)s; 105 s++; 106 } 107 return NULL; 108 } 109 110 static __attribute__((unused)) 111 int strcmp(const char *a, const char *b) 112 { 113 unsigned int c; 114 int diff; 115 116 while (!(diff = (unsigned char)*a++ - (c = (unsigned char)*b++)) && c) 117 ; 118 return diff; 119 } 120 121 static __attribute__((unused)) 122 char *strcpy(char *dst, const char *src) 123 { 124 char *ret = dst; 125 126 while ((*dst++ = *src++)); 127 return ret; 128 } 129 130 /* this function is only used with arguments that are not constants or when 131 * it's not known because optimizations are disabled. Note that gcc 12 132 * recognizes an strlen() pattern and replaces it with a jump to strlen(), 133 * thus itself, hence the asm() statement below that's meant to disable this 134 * confusing practice. 135 */ 136 static __attribute__((unused)) 137 size_t strlen(const char *str) 138 { 139 size_t len; 140 141 for (len = 0; str[len]; len++) 142 asm(""); 143 return len; 144 } 145 146 /* do not trust __builtin_constant_p() at -O0, as clang will emit a test and 147 * the two branches, then will rely on an external definition of strlen(). 148 */ 149 #if defined(__OPTIMIZE__) 150 #define nolibc_strlen(x) strlen(x) 151 #define strlen(str) ({ \ 152 __builtin_constant_p((str)) ? \ 153 __builtin_strlen((str)) : \ 154 nolibc_strlen((str)); \ 155 }) 156 #endif 157 158 static __attribute__((unused)) 159 size_t strnlen(const char *str, size_t maxlen) 160 { 161 size_t len; 162 163 for (len = 0; (len < maxlen) && str[len]; len++); 164 return len; 165 } 166 167 static __attribute__((unused)) 168 char *strdup(const char *str) 169 { 170 size_t len; 171 char *ret; 172 173 len = strlen(str); 174 ret = malloc(len + 1); 175 if (__builtin_expect(ret != NULL, 1)) 176 memcpy(ret, str, len + 1); 177 178 return ret; 179 } 180 181 static __attribute__((unused)) 182 char *strndup(const char *str, size_t maxlen) 183 { 184 size_t len; 185 char *ret; 186 187 len = strnlen(str, maxlen); 188 ret = malloc(len + 1); 189 if (__builtin_expect(ret != NULL, 1)) { 190 memcpy(ret, str, len); 191 ret[len] = '\0'; 192 } 193 194 return ret; 195 } 196 197 static __attribute__((unused)) 198 size_t strlcat(char *dst, const char *src, size_t size) 199 { 200 size_t len; 201 char c; 202 203 for (len = 0; dst[len]; len++) 204 ; 205 206 for (;;) { 207 c = *src; 208 if (len < size) 209 dst[len] = c; 210 if (!c) 211 break; 212 len++; 213 src++; 214 } 215 216 return len; 217 } 218 219 static __attribute__((unused)) 220 size_t strlcpy(char *dst, const char *src, size_t size) 221 { 222 size_t len; 223 char c; 224 225 for (len = 0;;) { 226 c = src[len]; 227 if (len < size) 228 dst[len] = c; 229 if (!c) 230 break; 231 len++; 232 } 233 return len; 234 } 235 236 static __attribute__((unused)) 237 char *strncat(char *dst, const char *src, size_t size) 238 { 239 char *orig = dst; 240 241 while (*dst) 242 dst++; 243 244 while (size && (*dst = *src)) { 245 src++; 246 dst++; 247 size--; 248 } 249 250 *dst = 0; 251 return orig; 252 } 253 254 static __attribute__((unused)) 255 int strncmp(const char *a, const char *b, size_t size) 256 { 257 unsigned int c; 258 int diff = 0; 259 260 while (size-- && 261 !(diff = (unsigned char)*a++ - (c = (unsigned char)*b++)) && c) 262 ; 263 264 return diff; 265 } 266 267 static __attribute__((unused)) 268 char *strncpy(char *dst, const char *src, size_t size) 269 { 270 size_t len; 271 272 for (len = 0; len < size; len++) 273 if ((dst[len] = *src)) 274 src++; 275 return dst; 276 } 277 278 static __attribute__((unused)) 279 char *strrchr(const char *s, int c) 280 { 281 const char *ret = NULL; 282 283 while (*s) { 284 if (*s == (char)c) 285 ret = s; 286 s++; 287 } 288 return (char *)ret; 289 } 290 291 /* make sure to include all global symbols */ 292 #include "nolibc.h" 293 294 #endif /* _NOLIBC_STRING_H */ 295