string.h 5.3 KB

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