brintos

brintos / linux-shallow public Read only

0
0
Text · 12.7 KiB · 75aa273 Raw
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