554 lines · c
1/* SPDX-License-Identifier: LGPL-2.1 OR MIT */2/*3 * stdlib function definitions for NOLIBC4 * Copyright (C) 2017-2021 Willy Tarreau <w@1wt.eu>5 */6 7#ifndef _NOLIBC_STDLIB_H8#define _NOLIBC_STDLIB_H9 10#include "std.h"11#include "arch.h"12#include "types.h"13#include "sys.h"14#include "string.h"15#include <linux/auxvec.h>16 17struct nolibc_heap {18 size_t len;19 char user_p[] __attribute__((__aligned__));20};21 22/* Buffer used to store int-to-ASCII conversions. Will only be implemented if23 * any of the related functions is implemented. The area is large enough to24 * store "18446744073709551615" or "-9223372036854775808" and the final zero.25 */26static __attribute__((unused)) char itoa_buffer[21];27 28/*29 * As much as possible, please keep functions alphabetically sorted.30 */31 32/* must be exported, as it's used by libgcc for various divide functions */33__attribute__((weak,unused,noreturn,section(".text.nolibc_abort")))34void abort(void)35{36 sys_kill(sys_getpid(), SIGABRT);37 for (;;);38}39 40static __attribute__((unused))41long atol(const char *s)42{43 unsigned long ret = 0;44 unsigned long d;45 int neg = 0;46 47 if (*s == '-') {48 neg = 1;49 s++;50 }51 52 while (1) {53 d = (*s++) - '0';54 if (d > 9)55 break;56 ret *= 10;57 ret += d;58 }59 60 return neg ? -ret : ret;61}62 63static __attribute__((unused))64int atoi(const char *s)65{66 return atol(s);67}68 69static __attribute__((unused))70void free(void *ptr)71{72 struct nolibc_heap *heap;73 74 if (!ptr)75 return;76 77 heap = container_of(ptr, struct nolibc_heap, user_p);78 munmap(heap, heap->len);79}80 81/* getenv() tries to find the environment variable named <name> in the82 * environment array pointed to by global variable "environ" which must be83 * declared as a char **, and must be terminated by a NULL (it is recommended84 * to set this variable to the "envp" argument of main()). If the requested85 * environment variable exists its value is returned otherwise NULL is86 * returned.87 */88static __attribute__((unused))89char *getenv(const char *name)90{91 int idx, i;92 93 if (environ) {94 for (idx = 0; environ[idx]; idx++) {95 for (i = 0; name[i] && name[i] == environ[idx][i];)96 i++;97 if (!name[i] && environ[idx][i] == '=')98 return &environ[idx][i+1];99 }100 }101 return NULL;102}103 104static __attribute__((unused))105unsigned long getauxval(unsigned long type)106{107 const unsigned long *auxv = _auxv;108 unsigned long ret;109 110 if (!auxv)111 return 0;112 113 while (1) {114 if (!auxv[0] && !auxv[1]) {115 ret = 0;116 break;117 }118 119 if (auxv[0] == type) {120 ret = auxv[1];121 break;122 }123 124 auxv += 2;125 }126 127 return ret;128}129 130static __attribute__((unused))131void *malloc(size_t len)132{133 struct nolibc_heap *heap;134 135 /* Always allocate memory with size multiple of 4096. */136 len = sizeof(*heap) + len;137 len = (len + 4095UL) & -4096UL;138 heap = mmap(NULL, len, PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE,139 -1, 0);140 if (__builtin_expect(heap == MAP_FAILED, 0))141 return NULL;142 143 heap->len = len;144 return heap->user_p;145}146 147static __attribute__((unused))148void *calloc(size_t size, size_t nmemb)149{150 size_t x = size * nmemb;151 152 if (__builtin_expect(size && ((x / size) != nmemb), 0)) {153 SET_ERRNO(ENOMEM);154 return NULL;155 }156 157 /*158 * No need to zero the heap, the MAP_ANONYMOUS in malloc()159 * already does it.160 */161 return malloc(x);162}163 164static __attribute__((unused))165void *realloc(void *old_ptr, size_t new_size)166{167 struct nolibc_heap *heap;168 size_t user_p_len;169 void *ret;170 171 if (!old_ptr)172 return malloc(new_size);173 174 heap = container_of(old_ptr, struct nolibc_heap, user_p);175 user_p_len = heap->len - sizeof(*heap);176 /*177 * Don't realloc() if @user_p_len >= @new_size, this block of178 * memory is still enough to handle the @new_size. Just return179 * the same pointer.180 */181 if (user_p_len >= new_size)182 return old_ptr;183 184 ret = malloc(new_size);185 if (__builtin_expect(!ret, 0))186 return NULL;187 188 memcpy(ret, heap->user_p, user_p_len);189 munmap(heap, heap->len);190 return ret;191}192 193/* Converts the unsigned long integer <in> to its hex representation into194 * buffer <buffer>, which must be long enough to store the number and the195 * trailing zero (17 bytes for "ffffffffffffffff" or 9 for "ffffffff"). The196 * buffer is filled from the first byte, and the number of characters emitted197 * (not counting the trailing zero) is returned. The function is constructed198 * in a way to optimize the code size and avoid any divide that could add a199 * dependency on large external functions.200 */201static __attribute__((unused))202int utoh_r(unsigned long in, char *buffer)203{204 signed char pos = (~0UL > 0xfffffffful) ? 60 : 28;205 int digits = 0;206 int dig;207 208 do {209 dig = in >> pos;210 in -= (uint64_t)dig << pos;211 pos -= 4;212 if (dig || digits || pos < 0) {213 if (dig > 9)214 dig += 'a' - '0' - 10;215 buffer[digits++] = '0' + dig;216 }217 } while (pos >= 0);218 219 buffer[digits] = 0;220 return digits;221}222 223/* converts unsigned long <in> to an hex string using the static itoa_buffer224 * and returns the pointer to that string.225 */226static __inline__ __attribute__((unused))227char *utoh(unsigned long in)228{229 utoh_r(in, itoa_buffer);230 return itoa_buffer;231}232 233/* Converts the unsigned long integer <in> to its string representation into234 * buffer <buffer>, which must be long enough to store the number and the235 * trailing zero (21 bytes for 18446744073709551615 in 64-bit, 11 for236 * 4294967295 in 32-bit). The buffer is filled from the first byte, and the237 * number of characters emitted (not counting the trailing zero) is returned.238 * The function is constructed in a way to optimize the code size and avoid239 * any divide that could add a dependency on large external functions.240 */241static __attribute__((unused))242int utoa_r(unsigned long in, char *buffer)243{244 unsigned long lim;245 int digits = 0;246 int pos = (~0UL > 0xfffffffful) ? 19 : 9;247 int dig;248 249 do {250 for (dig = 0, lim = 1; dig < pos; dig++)251 lim *= 10;252 253 if (digits || in >= lim || !pos) {254 for (dig = 0; in >= lim; dig++)255 in -= lim;256 buffer[digits++] = '0' + dig;257 }258 } while (pos--);259 260 buffer[digits] = 0;261 return digits;262}263 264/* Converts the signed long integer <in> to its string representation into265 * buffer <buffer>, which must be long enough to store the number and the266 * trailing zero (21 bytes for -9223372036854775808 in 64-bit, 12 for267 * -2147483648 in 32-bit). The buffer is filled from the first byte, and the268 * number of characters emitted (not counting the trailing zero) is returned.269 */270static __attribute__((unused))271int itoa_r(long in, char *buffer)272{273 char *ptr = buffer;274 int len = 0;275 276 if (in < 0) {277 in = -in;278 *(ptr++) = '-';279 len++;280 }281 len += utoa_r(in, ptr);282 return len;283}284 285/* for historical compatibility, same as above but returns the pointer to the286 * buffer.287 */288static __inline__ __attribute__((unused))289char *ltoa_r(long in, char *buffer)290{291 itoa_r(in, buffer);292 return buffer;293}294 295/* converts long integer <in> to a string using the static itoa_buffer and296 * returns the pointer to that string.297 */298static __inline__ __attribute__((unused))299char *itoa(long in)300{301 itoa_r(in, itoa_buffer);302 return itoa_buffer;303}304 305/* converts long integer <in> to a string using the static itoa_buffer and306 * returns the pointer to that string. Same as above, for compatibility.307 */308static __inline__ __attribute__((unused))309char *ltoa(long in)310{311 itoa_r(in, itoa_buffer);312 return itoa_buffer;313}314 315/* converts unsigned long integer <in> to a string using the static itoa_buffer316 * and returns the pointer to that string.317 */318static __inline__ __attribute__((unused))319char *utoa(unsigned long in)320{321 utoa_r(in, itoa_buffer);322 return itoa_buffer;323}324 325/* Converts the unsigned 64-bit integer <in> to its hex representation into326 * buffer <buffer>, which must be long enough to store the number and the327 * trailing zero (17 bytes for "ffffffffffffffff"). The buffer is filled from328 * the first byte, and the number of characters emitted (not counting the329 * trailing zero) is returned. The function is constructed in a way to optimize330 * the code size and avoid any divide that could add a dependency on large331 * external functions.332 */333static __attribute__((unused))334int u64toh_r(uint64_t in, char *buffer)335{336 signed char pos = 60;337 int digits = 0;338 int dig;339 340 do {341 if (sizeof(long) >= 8) {342 dig = (in >> pos) & 0xF;343 } else {344 /* 32-bit platforms: avoid a 64-bit shift */345 uint32_t d = (pos >= 32) ? (in >> 32) : in;346 dig = (d >> (pos & 31)) & 0xF;347 }348 if (dig > 9)349 dig += 'a' - '0' - 10;350 pos -= 4;351 if (dig || digits || pos < 0)352 buffer[digits++] = '0' + dig;353 } while (pos >= 0);354 355 buffer[digits] = 0;356 return digits;357}358 359/* converts uint64_t <in> to an hex string using the static itoa_buffer and360 * returns the pointer to that string.361 */362static __inline__ __attribute__((unused))363char *u64toh(uint64_t in)364{365 u64toh_r(in, itoa_buffer);366 return itoa_buffer;367}368 369/* Converts the unsigned 64-bit integer <in> to its string representation into370 * buffer <buffer>, which must be long enough to store the number and the371 * trailing zero (21 bytes for 18446744073709551615). The buffer is filled from372 * the first byte, and the number of characters emitted (not counting the373 * trailing zero) is returned. The function is constructed in a way to optimize374 * the code size and avoid any divide that could add a dependency on large375 * external functions.376 */377static __attribute__((unused))378int u64toa_r(uint64_t in, char *buffer)379{380 unsigned long long lim;381 int digits = 0;382 int pos = 19; /* start with the highest possible digit */383 int dig;384 385 do {386 for (dig = 0, lim = 1; dig < pos; dig++)387 lim *= 10;388 389 if (digits || in >= lim || !pos) {390 for (dig = 0; in >= lim; dig++)391 in -= lim;392 buffer[digits++] = '0' + dig;393 }394 } while (pos--);395 396 buffer[digits] = 0;397 return digits;398}399 400/* Converts the signed 64-bit integer <in> to its string representation into401 * buffer <buffer>, which must be long enough to store the number and the402 * trailing zero (21 bytes for -9223372036854775808). The buffer is filled from403 * the first byte, and the number of characters emitted (not counting the404 * trailing zero) is returned.405 */406static __attribute__((unused))407int i64toa_r(int64_t in, char *buffer)408{409 char *ptr = buffer;410 int len = 0;411 412 if (in < 0) {413 in = -in;414 *(ptr++) = '-';415 len++;416 }417 len += u64toa_r(in, ptr);418 return len;419}420 421/* converts int64_t <in> to a string using the static itoa_buffer and returns422 * the pointer to that string.423 */424static __inline__ __attribute__((unused))425char *i64toa(int64_t in)426{427 i64toa_r(in, itoa_buffer);428 return itoa_buffer;429}430 431/* converts uint64_t <in> to a string using the static itoa_buffer and returns432 * the pointer to that string.433 */434static __inline__ __attribute__((unused))435char *u64toa(uint64_t in)436{437 u64toa_r(in, itoa_buffer);438 return itoa_buffer;439}440 441static __attribute__((unused))442uintmax_t __strtox(const char *nptr, char **endptr, int base, intmax_t lower_limit, uintmax_t upper_limit)443{444 const char signed_ = lower_limit != 0;445 unsigned char neg = 0, overflow = 0;446 uintmax_t val = 0, limit, old_val;447 char c;448 449 if (base < 0 || base > 36) {450 SET_ERRNO(EINVAL);451 goto out;452 }453 454 while (isspace(*nptr))455 nptr++;456 457 if (*nptr == '+') {458 nptr++;459 } else if (*nptr == '-') {460 neg = 1;461 nptr++;462 }463 464 if (signed_ && neg)465 limit = -(uintmax_t)lower_limit;466 else467 limit = upper_limit;468 469 if ((base == 0 || base == 16) &&470 (strncmp(nptr, "0x", 2) == 0 || strncmp(nptr, "0X", 2) == 0)) {471 base = 16;472 nptr += 2;473 } else if (base == 0 && strncmp(nptr, "0", 1) == 0) {474 base = 8;475 nptr += 1;476 } else if (base == 0) {477 base = 10;478 }479 480 while (*nptr) {481 c = *nptr;482 483 if (c >= '0' && c <= '9')484 c -= '0';485 else if (c >= 'a' && c <= 'z')486 c = c - 'a' + 10;487 else if (c >= 'A' && c <= 'Z')488 c = c - 'A' + 10;489 else490 goto out;491 492 if (c >= base)493 goto out;494 495 nptr++;496 old_val = val;497 val *= base;498 val += c;499 500 if (val > limit || val < old_val)501 overflow = 1;502 }503 504out:505 if (overflow) {506 SET_ERRNO(ERANGE);507 val = limit;508 }509 if (endptr)510 *endptr = (char *)nptr;511 return neg ? -val : val;512}513 514static __attribute__((unused))515long strtol(const char *nptr, char **endptr, int base)516{517 return __strtox(nptr, endptr, base, LONG_MIN, LONG_MAX);518}519 520static __attribute__((unused))521unsigned long strtoul(const char *nptr, char **endptr, int base)522{523 return __strtox(nptr, endptr, base, 0, ULONG_MAX);524}525 526static __attribute__((unused))527long long strtoll(const char *nptr, char **endptr, int base)528{529 return __strtox(nptr, endptr, base, LLONG_MIN, LLONG_MAX);530}531 532static __attribute__((unused))533unsigned long long strtoull(const char *nptr, char **endptr, int base)534{535 return __strtox(nptr, endptr, base, 0, ULLONG_MAX);536}537 538static __attribute__((unused))539intmax_t strtoimax(const char *nptr, char **endptr, int base)540{541 return __strtox(nptr, endptr, base, INTMAX_MIN, INTMAX_MAX);542}543 544static __attribute__((unused))545uintmax_t strtoumax(const char *nptr, char **endptr, int base)546{547 return __strtox(nptr, endptr, base, 0, UINTMAX_MAX);548}549 550/* make sure to include all global symbols */551#include "nolibc.h"552 553#endif /* _NOLIBC_STDLIB_H */554