at v6.13 5.4 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 "arch.h" 11#include "std.h" 12 13static void *malloc(size_t len); 14 15/* 16 * As much as possible, please keep functions alphabetically sorted. 17 */ 18 19static __attribute__((unused)) 20int 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"))) 36void *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"))) 60void *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"))) 77void *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 90static __attribute__((unused)) 91char *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 101static __attribute__((unused)) 102int 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 112static __attribute__((unused)) 113char *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"))) 128size_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 149static __attribute__((unused)) 150size_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 158static __attribute__((unused)) 159char *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 172static __attribute__((unused)) 173char *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 188static __attribute__((unused)) 189size_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 214static __attribute__((unused)) 215size_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 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/* make sure to include all global symbols */ 289#include "nolibc.h" 290 291#endif /* _NOLIBC_STRING_H */