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 "arch.h" 11 #include "std.h" 12 13 static void *malloc(size_t len); 14 15 /* 16 * As much as possible, please keep functions alphabetically sorted. 17 */ 18 19 static __attribute__((unused)) 20 int memcmp(const void *s1, const void *s2, size_t n) 21 { 22 size_t ofs = 0; 23 int c1 = 0; 24 25 while (ofs < n && !(c1 = ((unsigned char *)s1)[ofs] - ((unsigned char *)s2)[ofs])) { 26 ofs++; 27 } 28 return c1; 29 } 30 31 #ifndef NOLIBC_ARCH_HAS_MEMMOVE 32 /* might be ignored by the compiler without -ffreestanding, then found as 33 * missing. 34 */ 35 __attribute__((weak,unused,section(".text.nolibc_memmove"))) 36 void *memmove(void *dst, const void *src, size_t len) 37 { 38 size_t dir, pos; 39 40 pos = len; 41 dir = -1; 42 43 if (dst < src) { 44 pos = -1; 45 dir = 1; 46 } 47 48 while (len) { 49 pos += dir; 50 ((char *)dst)[pos] = ((const char *)src)[pos]; 51 len--; 52 } 53 return dst; 54 } 55 #endif /* #ifndef NOLIBC_ARCH_HAS_MEMMOVE */ 56 57 #ifndef NOLIBC_ARCH_HAS_MEMCPY 58 /* must be exported, as it's used by libgcc on ARM */ 59 __attribute__((weak,unused,section(".text.nolibc_memcpy"))) 60 void *memcpy(void *dst, const void *src, size_t len) 61 { 62 size_t pos = 0; 63 64 while (pos < len) { 65 ((char *)dst)[pos] = ((const char *)src)[pos]; 66 pos++; 67 } 68 return dst; 69 } 70 #endif /* #ifndef NOLIBC_ARCH_HAS_MEMCPY */ 71 72 #ifndef NOLIBC_ARCH_HAS_MEMSET 73 /* might be ignored by the compiler without -ffreestanding, then found as 74 * missing. 75 */ 76 __attribute__((weak,unused,section(".text.nolibc_memset"))) 77 void *memset(void *dst, int b, size_t len) 78 { 79 char *p = dst; 80 81 while (len--) { 82 /* prevent gcc from recognizing memset() here */ 83 __asm__ volatile(""); 84 *(p++) = b; 85 } 86 return dst; 87 } 88 #endif /* #ifndef NOLIBC_ARCH_HAS_MEMSET */ 89 90 static __attribute__((unused)) 91 char *strchr(const char *s, int c) 92 { 93 while (*s) { 94 if (*s == (char)c) 95 return (char *)s; 96 s++; 97 } 98 return NULL; 99 } 100 101 static __attribute__((unused)) 102 int strcmp(const char *a, const char *b) 103 { 104 unsigned int c; 105 int diff; 106 107 while (!(diff = (unsigned char)*a++ - (c = (unsigned char)*b++)) && c) 108 ; 109 return diff; 110 } 111 112 static __attribute__((unused)) 113 char *strcpy(char *dst, const char *src) 114 { 115 char *ret = dst; 116 117 while ((*dst++ = *src++)); 118 return ret; 119 } 120 121 /* this function is only used with arguments that are not constants or when 122 * it's not known because optimizations are disabled. Note that gcc 12 123 * recognizes an strlen() pattern and replaces it with a jump to strlen(), 124 * thus itself, hence the asm() statement below that's meant to disable this 125 * confusing practice. 126 */ 127 __attribute__((weak,unused,section(".text.nolibc_strlen"))) 128 size_t strlen(const char *str) 129 { 130 size_t len; 131 132 for (len = 0; str[len]; len++) 133 __asm__(""); 134 return len; 135 } 136 137 /* do not trust __builtin_constant_p() at -O0, as clang will emit a test and 138 * the two branches, then will rely on an external definition of strlen(). 139 */ 140 #if defined(__OPTIMIZE__) 141 #define nolibc_strlen(x) strlen(x) 142 #define strlen(str) ({ \ 143 __builtin_constant_p((str)) ? \ 144 __builtin_strlen((str)) : \ 145 nolibc_strlen((str)); \ 146 }) 147 #endif 148 149 static __attribute__((unused)) 150 size_t strnlen(const char *str, size_t maxlen) 151 { 152 size_t len; 153 154 for (len = 0; (len < maxlen) && str[len]; len++); 155 return len; 156 } 157 158 static __attribute__((unused)) 159 char *strdup(const char *str) 160 { 161 size_t len; 162 char *ret; 163 164 len = strlen(str); 165 ret = malloc(len + 1); 166 if (__builtin_expect(ret != NULL, 1)) 167 memcpy(ret, str, len + 1); 168 169 return ret; 170 } 171 172 static __attribute__((unused)) 173 char *strndup(const char *str, size_t maxlen) 174 { 175 size_t len; 176 char *ret; 177 178 len = strnlen(str, maxlen); 179 ret = malloc(len + 1); 180 if (__builtin_expect(ret != NULL, 1)) { 181 memcpy(ret, str, len); 182 ret[len] = '\0'; 183 } 184 185 return ret; 186 } 187 188 static __attribute__((unused)) 189 size_t strlcat(char *dst, const char *src, size_t size) 190 { 191 size_t len = strnlen(dst, size); 192 193 /* 194 * We want len < size-1. But as size is unsigned and can wrap 195 * around, we use len + 1 instead. 196 */ 197 while (len + 1 < size) { 198 dst[len] = *src; 199 if (*src == '\0') 200 break; 201 len++; 202 src++; 203 } 204 205 if (len < size) 206 dst[len] = '\0'; 207 208 while (*src++) 209 len++; 210 211 return len; 212 } 213 214 static __attribute__((unused)) 215 size_t strlcpy(char *dst, const char *src, size_t size) 216 { 217 size_t len; 218 219 for (len = 0; len < size; len++) { 220 dst[len] = src[len]; 221 if (!dst[len]) 222 return len; 223 } 224 if (size) 225 dst[size-1] = '\0'; 226 227 while (src[len]) 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 /* make sure to include all global symbols */ 289 #include "nolibc.h" 290 291 #endif /* _NOLIBC_STRING_H */ 292
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.