162306a36Sopenharmony_ci/* SPDX-License-Identifier: LGPL-2.1 OR MIT */ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * string function definitions for NOLIBC 462306a36Sopenharmony_ci * Copyright (C) 2017-2021 Willy Tarreau <w@1wt.eu> 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#ifndef _NOLIBC_STRING_H 862306a36Sopenharmony_ci#define _NOLIBC_STRING_H 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include "std.h" 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_cistatic void *malloc(size_t len); 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci/* 1562306a36Sopenharmony_ci * As much as possible, please keep functions alphabetically sorted. 1662306a36Sopenharmony_ci */ 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_cistatic __attribute__((unused)) 1962306a36Sopenharmony_ciint memcmp(const void *s1, const void *s2, size_t n) 2062306a36Sopenharmony_ci{ 2162306a36Sopenharmony_ci size_t ofs = 0; 2262306a36Sopenharmony_ci int c1 = 0; 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci while (ofs < n && !(c1 = ((unsigned char *)s1)[ofs] - ((unsigned char *)s2)[ofs])) { 2562306a36Sopenharmony_ci ofs++; 2662306a36Sopenharmony_ci } 2762306a36Sopenharmony_ci return c1; 2862306a36Sopenharmony_ci} 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_cistatic __attribute__((unused)) 3162306a36Sopenharmony_civoid *_nolibc_memcpy_up(void *dst, const void *src, size_t len) 3262306a36Sopenharmony_ci{ 3362306a36Sopenharmony_ci size_t pos = 0; 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci while (pos < len) { 3662306a36Sopenharmony_ci ((char *)dst)[pos] = ((const char *)src)[pos]; 3762306a36Sopenharmony_ci pos++; 3862306a36Sopenharmony_ci } 3962306a36Sopenharmony_ci return dst; 4062306a36Sopenharmony_ci} 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_cistatic __attribute__((unused)) 4362306a36Sopenharmony_civoid *_nolibc_memcpy_down(void *dst, const void *src, size_t len) 4462306a36Sopenharmony_ci{ 4562306a36Sopenharmony_ci while (len) { 4662306a36Sopenharmony_ci len--; 4762306a36Sopenharmony_ci ((char *)dst)[len] = ((const char *)src)[len]; 4862306a36Sopenharmony_ci } 4962306a36Sopenharmony_ci return dst; 5062306a36Sopenharmony_ci} 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci/* might be ignored by the compiler without -ffreestanding, then found as 5362306a36Sopenharmony_ci * missing. 5462306a36Sopenharmony_ci */ 5562306a36Sopenharmony_ci__attribute__((weak,unused,section(".text.nolibc_memmove"))) 5662306a36Sopenharmony_civoid *memmove(void *dst, const void *src, size_t len) 5762306a36Sopenharmony_ci{ 5862306a36Sopenharmony_ci size_t dir, pos; 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci pos = len; 6162306a36Sopenharmony_ci dir = -1; 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci if (dst < src) { 6462306a36Sopenharmony_ci pos = -1; 6562306a36Sopenharmony_ci dir = 1; 6662306a36Sopenharmony_ci } 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci while (len) { 6962306a36Sopenharmony_ci pos += dir; 7062306a36Sopenharmony_ci ((char *)dst)[pos] = ((const char *)src)[pos]; 7162306a36Sopenharmony_ci len--; 7262306a36Sopenharmony_ci } 7362306a36Sopenharmony_ci return dst; 7462306a36Sopenharmony_ci} 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci/* must be exported, as it's used by libgcc on ARM */ 7762306a36Sopenharmony_ci__attribute__((weak,unused,section(".text.nolibc_memcpy"))) 7862306a36Sopenharmony_civoid *memcpy(void *dst, const void *src, size_t len) 7962306a36Sopenharmony_ci{ 8062306a36Sopenharmony_ci return _nolibc_memcpy_up(dst, src, len); 8162306a36Sopenharmony_ci} 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci/* might be ignored by the compiler without -ffreestanding, then found as 8462306a36Sopenharmony_ci * missing. 8562306a36Sopenharmony_ci */ 8662306a36Sopenharmony_ci__attribute__((weak,unused,section(".text.nolibc_memset"))) 8762306a36Sopenharmony_civoid *memset(void *dst, int b, size_t len) 8862306a36Sopenharmony_ci{ 8962306a36Sopenharmony_ci char *p = dst; 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci while (len--) { 9262306a36Sopenharmony_ci /* prevent gcc from recognizing memset() here */ 9362306a36Sopenharmony_ci __asm__ volatile(""); 9462306a36Sopenharmony_ci *(p++) = b; 9562306a36Sopenharmony_ci } 9662306a36Sopenharmony_ci return dst; 9762306a36Sopenharmony_ci} 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_cistatic __attribute__((unused)) 10062306a36Sopenharmony_cichar *strchr(const char *s, int c) 10162306a36Sopenharmony_ci{ 10262306a36Sopenharmony_ci while (*s) { 10362306a36Sopenharmony_ci if (*s == (char)c) 10462306a36Sopenharmony_ci return (char *)s; 10562306a36Sopenharmony_ci s++; 10662306a36Sopenharmony_ci } 10762306a36Sopenharmony_ci return NULL; 10862306a36Sopenharmony_ci} 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_cistatic __attribute__((unused)) 11162306a36Sopenharmony_ciint strcmp(const char *a, const char *b) 11262306a36Sopenharmony_ci{ 11362306a36Sopenharmony_ci unsigned int c; 11462306a36Sopenharmony_ci int diff; 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci while (!(diff = (unsigned char)*a++ - (c = (unsigned char)*b++)) && c) 11762306a36Sopenharmony_ci ; 11862306a36Sopenharmony_ci return diff; 11962306a36Sopenharmony_ci} 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_cistatic __attribute__((unused)) 12262306a36Sopenharmony_cichar *strcpy(char *dst, const char *src) 12362306a36Sopenharmony_ci{ 12462306a36Sopenharmony_ci char *ret = dst; 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci while ((*dst++ = *src++)); 12762306a36Sopenharmony_ci return ret; 12862306a36Sopenharmony_ci} 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci/* this function is only used with arguments that are not constants or when 13162306a36Sopenharmony_ci * it's not known because optimizations are disabled. Note that gcc 12 13262306a36Sopenharmony_ci * recognizes an strlen() pattern and replaces it with a jump to strlen(), 13362306a36Sopenharmony_ci * thus itself, hence the asm() statement below that's meant to disable this 13462306a36Sopenharmony_ci * confusing practice. 13562306a36Sopenharmony_ci */ 13662306a36Sopenharmony_cistatic __attribute__((unused)) 13762306a36Sopenharmony_cisize_t strlen(const char *str) 13862306a36Sopenharmony_ci{ 13962306a36Sopenharmony_ci size_t len; 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci for (len = 0; str[len]; len++) 14262306a36Sopenharmony_ci __asm__(""); 14362306a36Sopenharmony_ci return len; 14462306a36Sopenharmony_ci} 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci/* do not trust __builtin_constant_p() at -O0, as clang will emit a test and 14762306a36Sopenharmony_ci * the two branches, then will rely on an external definition of strlen(). 14862306a36Sopenharmony_ci */ 14962306a36Sopenharmony_ci#if defined(__OPTIMIZE__) 15062306a36Sopenharmony_ci#define nolibc_strlen(x) strlen(x) 15162306a36Sopenharmony_ci#define strlen(str) ({ \ 15262306a36Sopenharmony_ci __builtin_constant_p((str)) ? \ 15362306a36Sopenharmony_ci __builtin_strlen((str)) : \ 15462306a36Sopenharmony_ci nolibc_strlen((str)); \ 15562306a36Sopenharmony_ci}) 15662306a36Sopenharmony_ci#endif 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_cistatic __attribute__((unused)) 15962306a36Sopenharmony_cisize_t strnlen(const char *str, size_t maxlen) 16062306a36Sopenharmony_ci{ 16162306a36Sopenharmony_ci size_t len; 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci for (len = 0; (len < maxlen) && str[len]; len++); 16462306a36Sopenharmony_ci return len; 16562306a36Sopenharmony_ci} 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_cistatic __attribute__((unused)) 16862306a36Sopenharmony_cichar *strdup(const char *str) 16962306a36Sopenharmony_ci{ 17062306a36Sopenharmony_ci size_t len; 17162306a36Sopenharmony_ci char *ret; 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci len = strlen(str); 17462306a36Sopenharmony_ci ret = malloc(len + 1); 17562306a36Sopenharmony_ci if (__builtin_expect(ret != NULL, 1)) 17662306a36Sopenharmony_ci memcpy(ret, str, len + 1); 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci return ret; 17962306a36Sopenharmony_ci} 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_cistatic __attribute__((unused)) 18262306a36Sopenharmony_cichar *strndup(const char *str, size_t maxlen) 18362306a36Sopenharmony_ci{ 18462306a36Sopenharmony_ci size_t len; 18562306a36Sopenharmony_ci char *ret; 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci len = strnlen(str, maxlen); 18862306a36Sopenharmony_ci ret = malloc(len + 1); 18962306a36Sopenharmony_ci if (__builtin_expect(ret != NULL, 1)) { 19062306a36Sopenharmony_ci memcpy(ret, str, len); 19162306a36Sopenharmony_ci ret[len] = '\0'; 19262306a36Sopenharmony_ci } 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci return ret; 19562306a36Sopenharmony_ci} 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_cistatic __attribute__((unused)) 19862306a36Sopenharmony_cisize_t strlcat(char *dst, const char *src, size_t size) 19962306a36Sopenharmony_ci{ 20062306a36Sopenharmony_ci size_t len; 20162306a36Sopenharmony_ci char c; 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci for (len = 0; dst[len]; len++) 20462306a36Sopenharmony_ci ; 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci for (;;) { 20762306a36Sopenharmony_ci c = *src; 20862306a36Sopenharmony_ci if (len < size) 20962306a36Sopenharmony_ci dst[len] = c; 21062306a36Sopenharmony_ci if (!c) 21162306a36Sopenharmony_ci break; 21262306a36Sopenharmony_ci len++; 21362306a36Sopenharmony_ci src++; 21462306a36Sopenharmony_ci } 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci return len; 21762306a36Sopenharmony_ci} 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_cistatic __attribute__((unused)) 22062306a36Sopenharmony_cisize_t strlcpy(char *dst, const char *src, size_t size) 22162306a36Sopenharmony_ci{ 22262306a36Sopenharmony_ci size_t len; 22362306a36Sopenharmony_ci char c; 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci for (len = 0;;) { 22662306a36Sopenharmony_ci c = src[len]; 22762306a36Sopenharmony_ci if (len < size) 22862306a36Sopenharmony_ci dst[len] = c; 22962306a36Sopenharmony_ci if (!c) 23062306a36Sopenharmony_ci break; 23162306a36Sopenharmony_ci len++; 23262306a36Sopenharmony_ci } 23362306a36Sopenharmony_ci return len; 23462306a36Sopenharmony_ci} 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_cistatic __attribute__((unused)) 23762306a36Sopenharmony_cichar *strncat(char *dst, const char *src, size_t size) 23862306a36Sopenharmony_ci{ 23962306a36Sopenharmony_ci char *orig = dst; 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci while (*dst) 24262306a36Sopenharmony_ci dst++; 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci while (size && (*dst = *src)) { 24562306a36Sopenharmony_ci src++; 24662306a36Sopenharmony_ci dst++; 24762306a36Sopenharmony_ci size--; 24862306a36Sopenharmony_ci } 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci *dst = 0; 25162306a36Sopenharmony_ci return orig; 25262306a36Sopenharmony_ci} 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_cistatic __attribute__((unused)) 25562306a36Sopenharmony_ciint strncmp(const char *a, const char *b, size_t size) 25662306a36Sopenharmony_ci{ 25762306a36Sopenharmony_ci unsigned int c; 25862306a36Sopenharmony_ci int diff = 0; 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci while (size-- && 26162306a36Sopenharmony_ci !(diff = (unsigned char)*a++ - (c = (unsigned char)*b++)) && c) 26262306a36Sopenharmony_ci ; 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci return diff; 26562306a36Sopenharmony_ci} 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_cistatic __attribute__((unused)) 26862306a36Sopenharmony_cichar *strncpy(char *dst, const char *src, size_t size) 26962306a36Sopenharmony_ci{ 27062306a36Sopenharmony_ci size_t len; 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci for (len = 0; len < size; len++) 27362306a36Sopenharmony_ci if ((dst[len] = *src)) 27462306a36Sopenharmony_ci src++; 27562306a36Sopenharmony_ci return dst; 27662306a36Sopenharmony_ci} 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_cistatic __attribute__((unused)) 27962306a36Sopenharmony_cichar *strrchr(const char *s, int c) 28062306a36Sopenharmony_ci{ 28162306a36Sopenharmony_ci const char *ret = NULL; 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci while (*s) { 28462306a36Sopenharmony_ci if (*s == (char)c) 28562306a36Sopenharmony_ci ret = s; 28662306a36Sopenharmony_ci s++; 28762306a36Sopenharmony_ci } 28862306a36Sopenharmony_ci return (char *)ret; 28962306a36Sopenharmony_ci} 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci/* make sure to include all global symbols */ 29262306a36Sopenharmony_ci#include "nolibc.h" 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci#endif /* _NOLIBC_STRING_H */ 295