at v6.2-rc2 288 lines 5.2 kB view raw
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 12static void *malloc(size_t len); 13 14/* 15 * As much as possible, please keep functions alphabetically sorted. 16 */ 17 18static __attribute__((unused)) 19int 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 30static __attribute__((unused)) 31void *_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 42static __attribute__((unused)) 43void *_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"))) 56void *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"))) 78void *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"))) 87void *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 96static __attribute__((unused)) 97char *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 107static __attribute__((unused)) 108int 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 118static __attribute__((unused)) 119char *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 */ 133static __attribute__((unused)) 134size_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 155static __attribute__((unused)) 156size_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 164static __attribute__((unused)) 165char *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 178static __attribute__((unused)) 179char *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 194static __attribute__((unused)) 195size_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 216static __attribute__((unused)) 217size_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 233static __attribute__((unused)) 234char *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 251static __attribute__((unused)) 252int 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 264static __attribute__((unused)) 265char *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 275static __attribute__((unused)) 276char *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 */