xref: /openbmc/linux/tools/include/nolibc/nolibc.h (revision bd8c8fbb)
130ca2051SWilly Tarreau /* SPDX-License-Identifier: LGPL-2.1 OR MIT */
230ca2051SWilly Tarreau /* nolibc.h
330ca2051SWilly Tarreau  * Copyright (C) 2017-2018 Willy Tarreau <w@1wt.eu>
430ca2051SWilly Tarreau  */
530ca2051SWilly Tarreau 
630ca2051SWilly Tarreau /*
730ca2051SWilly Tarreau  * This file is designed to be used as a libc alternative for minimal programs
830ca2051SWilly Tarreau  * with very limited requirements. It consists of a small number of syscall and
930ca2051SWilly Tarreau  * type definitions, and the minimal startup code needed to call main().
1030ca2051SWilly Tarreau  * All syscalls are declared as static functions so that they can be optimized
1130ca2051SWilly Tarreau  * away by the compiler when not used.
1230ca2051SWilly Tarreau  *
1330ca2051SWilly Tarreau  * Syscalls are split into 3 levels:
1430ca2051SWilly Tarreau  *   - The lower level is the arch-specific syscall() definition, consisting in
1530ca2051SWilly Tarreau  *     assembly code in compound expressions. These are called my_syscall0() to
1630ca2051SWilly Tarreau  *     my_syscall6() depending on the number of arguments. The MIPS
1730ca2051SWilly Tarreau  *     implementation is limited to 5 arguments. All input arguments are cast
1830ca2051SWilly Tarreau  *     to a long stored in a register. These expressions always return the
1930ca2051SWilly Tarreau  *     syscall's return value as a signed long value which is often either a
2030ca2051SWilly Tarreau  *     pointer or the negated errno value.
2130ca2051SWilly Tarreau  *
2230ca2051SWilly Tarreau  *   - The second level is mostly architecture-independent. It is made of
2330ca2051SWilly Tarreau  *     static functions called sys_<name>() which rely on my_syscallN()
2430ca2051SWilly Tarreau  *     depending on the syscall definition. These functions are responsible
2530ca2051SWilly Tarreau  *     for exposing the appropriate types for the syscall arguments (int,
2630ca2051SWilly Tarreau  *     pointers, etc) and for setting the appropriate return type (often int).
2730ca2051SWilly Tarreau  *     A few of them are architecture-specific because the syscalls are not all
2830ca2051SWilly Tarreau  *     mapped exactly the same among architectures. For example, some archs do
2930ca2051SWilly Tarreau  *     not implement select() and need pselect6() instead, so the sys_select()
3030ca2051SWilly Tarreau  *     function will have to abstract this.
3130ca2051SWilly Tarreau  *
3230ca2051SWilly Tarreau  *   - The third level is the libc call definition. It exposes the lower raw
3330ca2051SWilly Tarreau  *     sys_<name>() calls in a way that looks like what a libc usually does,
3430ca2051SWilly Tarreau  *     takes care of specific input values, and of setting errno upon error.
3530ca2051SWilly Tarreau  *     There can be minor variations compared to standard libc calls. For
3630ca2051SWilly Tarreau  *     example the open() call always takes 3 args here.
3730ca2051SWilly Tarreau  *
3830ca2051SWilly Tarreau  * The errno variable is declared static and unused. This way it can be
3930ca2051SWilly Tarreau  * optimized away if not used. However this means that a program made of
4030ca2051SWilly Tarreau  * multiple C files may observe different errno values (one per C file). For
4130ca2051SWilly Tarreau  * the type of programs this project targets it usually is not a problem. The
4230ca2051SWilly Tarreau  * resulting program may even be reduced by defining the NOLIBC_IGNORE_ERRNO
4330ca2051SWilly Tarreau  * macro, in which case the errno value will never be assigned.
4430ca2051SWilly Tarreau  *
4530ca2051SWilly Tarreau  * Some stdint-like integer types are defined. These are valid on all currently
4630ca2051SWilly Tarreau  * supported architectures, because signs are enforced, ints are assumed to be
4730ca2051SWilly Tarreau  * 32 bits, longs the size of a pointer and long long 64 bits. If more
4830ca2051SWilly Tarreau  * architectures have to be supported, this may need to be adapted.
4930ca2051SWilly Tarreau  *
5030ca2051SWilly Tarreau  * Some macro definitions like the O_* values passed to open(), and some
5130ca2051SWilly Tarreau  * structures like the sys_stat struct depend on the architecture.
5230ca2051SWilly Tarreau  *
5330ca2051SWilly Tarreau  * The definitions start with the architecture-specific parts, which are picked
5430ca2051SWilly Tarreau  * based on what the compiler knows about the target architecture, and are
5530ca2051SWilly Tarreau  * completed with the generic code. Since it is the compiler which sets the
5630ca2051SWilly Tarreau  * target architecture, cross-compiling normally works out of the box without
5730ca2051SWilly Tarreau  * having to specify anything.
5830ca2051SWilly Tarreau  *
5930ca2051SWilly Tarreau  * Finally some very common libc-level functions are provided. It is the case
6030ca2051SWilly Tarreau  * for a few functions usually found in string.h, ctype.h, or stdlib.h. Nothing
6130ca2051SWilly Tarreau  * is currently provided regarding stdio emulation.
6230ca2051SWilly Tarreau  *
6330ca2051SWilly Tarreau  * The macro NOLIBC is always defined, so that it is possible for a program to
6430ca2051SWilly Tarreau  * check this macro to know if it is being built against and decide to disable
6530ca2051SWilly Tarreau  * some features or simply not to include some standard libc files.
6630ca2051SWilly Tarreau  *
6730ca2051SWilly Tarreau  * Ideally this file should be split in multiple files for easier long term
6830ca2051SWilly Tarreau  * maintenance, but provided as a single file as it is now, it's quite
6930ca2051SWilly Tarreau  * convenient to use. Maybe some variations involving a set of includes at the
7030ca2051SWilly Tarreau  * top could work.
7130ca2051SWilly Tarreau  *
7230ca2051SWilly Tarreau  * A simple static executable may be built this way :
7330ca2051SWilly Tarreau  *      $ gcc -fno-asynchronous-unwind-tables -fno-ident -s -Os -nostdlib \
743c6ce7a5SWilly Tarreau  *            -static -include nolibc.h -o hello hello.c -lgcc
7530ca2051SWilly Tarreau  *
7630ca2051SWilly Tarreau  * A very useful calling convention table may be found here :
7730ca2051SWilly Tarreau  *      http://man7.org/linux/man-pages/man2/syscall.2.html
7830ca2051SWilly Tarreau  *
7930ca2051SWilly Tarreau  * This doc is quite convenient though not necessarily up to date :
8030ca2051SWilly Tarreau  *      https://w3challs.com/syscalls/
8130ca2051SWilly Tarreau  *
8230ca2051SWilly Tarreau  */
83930c4accSWilly Tarreau #ifndef _NOLIBC_H
84930c4accSWilly Tarreau #define _NOLIBC_H
8530ca2051SWilly Tarreau 
86967cce19SWilly Tarreau #include "std.h"
87271661c1SWilly Tarreau #include "arch.h"
88cc7a492aSWilly Tarreau #include "types.h"
89*bd8c8fbbSWilly Tarreau #include "sys.h"
9030ca2051SWilly Tarreau 
91cc7a492aSWilly Tarreau /* Used by programs to avoid std includes */
9230ca2051SWilly Tarreau #define NOLIBC
9330ca2051SWilly Tarreau 
9430ca2051SWilly Tarreau static __attribute__((unused))
95*bd8c8fbbSWilly Tarreau int tcsetpgrp(int fd, pid_t pid)
9630ca2051SWilly Tarreau {
97*bd8c8fbbSWilly Tarreau 	return ioctl(fd, TIOCSPGRP, &pid);
9830ca2051SWilly Tarreau }
9930ca2051SWilly Tarreau 
10030ca2051SWilly Tarreau static __attribute__((unused))
10130ca2051SWilly Tarreau unsigned int sleep(unsigned int seconds)
10230ca2051SWilly Tarreau {
10330ca2051SWilly Tarreau 	struct timeval my_timeval = { seconds, 0 };
10430ca2051SWilly Tarreau 
10530ca2051SWilly Tarreau 	if (sys_select(0, 0, 0, 0, &my_timeval) < 0)
10630ca2051SWilly Tarreau 		return my_timeval.tv_sec + !!my_timeval.tv_usec;
10730ca2051SWilly Tarreau 	else
10830ca2051SWilly Tarreau 		return 0;
10930ca2051SWilly Tarreau }
11030ca2051SWilly Tarreau 
11130ca2051SWilly Tarreau static __attribute__((unused))
112f916d77eSMark Brown int msleep(unsigned int msecs)
113f916d77eSMark Brown {
114f916d77eSMark Brown 	struct timeval my_timeval = { msecs / 1000, (msecs % 1000) * 1000 };
115f916d77eSMark Brown 
116f916d77eSMark Brown 	if (sys_select(0, 0, 0, 0, &my_timeval) < 0)
117f916d77eSMark Brown 		return (my_timeval.tv_sec * 1000) +
118f916d77eSMark Brown 			(my_timeval.tv_usec / 1000) +
119f916d77eSMark Brown 			!!(my_timeval.tv_usec % 1000);
120f916d77eSMark Brown 	else
121f916d77eSMark Brown 		return 0;
122f916d77eSMark Brown }
123f916d77eSMark Brown 
12430ca2051SWilly Tarreau /* some size-optimized reimplementations of a few common str* and mem*
12530ca2051SWilly Tarreau  * functions. They're marked static, except memcpy() and raise() which are used
12630ca2051SWilly Tarreau  * by libgcc on ARM, so they are marked weak instead in order not to cause an
12730ca2051SWilly Tarreau  * error when building a program made of multiple files (not recommended).
12830ca2051SWilly Tarreau  */
12930ca2051SWilly Tarreau 
13030ca2051SWilly Tarreau static __attribute__((unused))
13130ca2051SWilly Tarreau void *memmove(void *dst, const void *src, size_t len)
13230ca2051SWilly Tarreau {
13330ca2051SWilly Tarreau 	ssize_t pos = (dst <= src) ? -1 : (long)len;
13430ca2051SWilly Tarreau 	void *ret = dst;
13530ca2051SWilly Tarreau 
13630ca2051SWilly Tarreau 	while (len--) {
13730ca2051SWilly Tarreau 		pos += (dst <= src) ? 1 : -1;
13830ca2051SWilly Tarreau 		((char *)dst)[pos] = ((char *)src)[pos];
13930ca2051SWilly Tarreau 	}
14030ca2051SWilly Tarreau 	return ret;
14130ca2051SWilly Tarreau }
14230ca2051SWilly Tarreau 
14330ca2051SWilly Tarreau static __attribute__((unused))
14430ca2051SWilly Tarreau void *memset(void *dst, int b, size_t len)
14530ca2051SWilly Tarreau {
14630ca2051SWilly Tarreau 	char *p = dst;
14730ca2051SWilly Tarreau 
14830ca2051SWilly Tarreau 	while (len--)
14930ca2051SWilly Tarreau 		*(p++) = b;
15030ca2051SWilly Tarreau 	return dst;
15130ca2051SWilly Tarreau }
15230ca2051SWilly Tarreau 
15330ca2051SWilly Tarreau static __attribute__((unused))
15430ca2051SWilly Tarreau int memcmp(const void *s1, const void *s2, size_t n)
15530ca2051SWilly Tarreau {
15630ca2051SWilly Tarreau 	size_t ofs = 0;
15730ca2051SWilly Tarreau 	char c1 = 0;
15830ca2051SWilly Tarreau 
15930ca2051SWilly Tarreau 	while (ofs < n && !(c1 = ((char *)s1)[ofs] - ((char *)s2)[ofs])) {
16030ca2051SWilly Tarreau 		ofs++;
16130ca2051SWilly Tarreau 	}
16230ca2051SWilly Tarreau 	return c1;
16330ca2051SWilly Tarreau }
16430ca2051SWilly Tarreau 
16530ca2051SWilly Tarreau static __attribute__((unused))
16630ca2051SWilly Tarreau char *strcpy(char *dst, const char *src)
16730ca2051SWilly Tarreau {
16830ca2051SWilly Tarreau 	char *ret = dst;
16930ca2051SWilly Tarreau 
17030ca2051SWilly Tarreau 	while ((*dst++ = *src++));
17130ca2051SWilly Tarreau 	return ret;
17230ca2051SWilly Tarreau }
17330ca2051SWilly Tarreau 
17430ca2051SWilly Tarreau static __attribute__((unused))
17530ca2051SWilly Tarreau char *strchr(const char *s, int c)
17630ca2051SWilly Tarreau {
17730ca2051SWilly Tarreau 	while (*s) {
17830ca2051SWilly Tarreau 		if (*s == (char)c)
17930ca2051SWilly Tarreau 			return (char *)s;
18030ca2051SWilly Tarreau 		s++;
18130ca2051SWilly Tarreau 	}
18230ca2051SWilly Tarreau 	return NULL;
18330ca2051SWilly Tarreau }
18430ca2051SWilly Tarreau 
18530ca2051SWilly Tarreau static __attribute__((unused))
18630ca2051SWilly Tarreau char *strrchr(const char *s, int c)
18730ca2051SWilly Tarreau {
18830ca2051SWilly Tarreau 	const char *ret = NULL;
18930ca2051SWilly Tarreau 
19030ca2051SWilly Tarreau 	while (*s) {
19130ca2051SWilly Tarreau 		if (*s == (char)c)
19230ca2051SWilly Tarreau 			ret = s;
19330ca2051SWilly Tarreau 		s++;
19430ca2051SWilly Tarreau 	}
19530ca2051SWilly Tarreau 	return (char *)ret;
19630ca2051SWilly Tarreau }
19730ca2051SWilly Tarreau 
19830ca2051SWilly Tarreau static __attribute__((unused))
19930ca2051SWilly Tarreau size_t nolibc_strlen(const char *str)
20030ca2051SWilly Tarreau {
20130ca2051SWilly Tarreau 	size_t len;
20230ca2051SWilly Tarreau 
20330ca2051SWilly Tarreau 	for (len = 0; str[len]; len++);
20430ca2051SWilly Tarreau 	return len;
20530ca2051SWilly Tarreau }
20630ca2051SWilly Tarreau 
20730ca2051SWilly Tarreau #define strlen(str) ({                          \
20830ca2051SWilly Tarreau 	__builtin_constant_p((str)) ?           \
20930ca2051SWilly Tarreau 		__builtin_strlen((str)) :       \
21030ca2051SWilly Tarreau 		nolibc_strlen((str));           \
21130ca2051SWilly Tarreau })
21230ca2051SWilly Tarreau 
21330ca2051SWilly Tarreau static __attribute__((unused))
21430ca2051SWilly Tarreau int isdigit(int c)
21530ca2051SWilly Tarreau {
21630ca2051SWilly Tarreau 	return (unsigned int)(c - '0') <= 9;
21730ca2051SWilly Tarreau }
21830ca2051SWilly Tarreau 
21930ca2051SWilly Tarreau static __attribute__((unused))
22030ca2051SWilly Tarreau long atol(const char *s)
22130ca2051SWilly Tarreau {
22230ca2051SWilly Tarreau 	unsigned long ret = 0;
22330ca2051SWilly Tarreau 	unsigned long d;
22430ca2051SWilly Tarreau 	int neg = 0;
22530ca2051SWilly Tarreau 
22630ca2051SWilly Tarreau 	if (*s == '-') {
22730ca2051SWilly Tarreau 		neg = 1;
22830ca2051SWilly Tarreau 		s++;
22930ca2051SWilly Tarreau 	}
23030ca2051SWilly Tarreau 
23130ca2051SWilly Tarreau 	while (1) {
23230ca2051SWilly Tarreau 		d = (*s++) - '0';
23330ca2051SWilly Tarreau 		if (d > 9)
23430ca2051SWilly Tarreau 			break;
23530ca2051SWilly Tarreau 		ret *= 10;
23630ca2051SWilly Tarreau 		ret += d;
23730ca2051SWilly Tarreau 	}
23830ca2051SWilly Tarreau 
23930ca2051SWilly Tarreau 	return neg ? -ret : ret;
24030ca2051SWilly Tarreau }
24130ca2051SWilly Tarreau 
24230ca2051SWilly Tarreau static __attribute__((unused))
24330ca2051SWilly Tarreau int atoi(const char *s)
24430ca2051SWilly Tarreau {
24530ca2051SWilly Tarreau 	return atol(s);
24630ca2051SWilly Tarreau }
24730ca2051SWilly Tarreau 
24830ca2051SWilly Tarreau static __attribute__((unused))
24930ca2051SWilly Tarreau const char *ltoa(long in)
25030ca2051SWilly Tarreau {
25130ca2051SWilly Tarreau 	/* large enough for -9223372036854775808 */
25230ca2051SWilly Tarreau 	static char buffer[21];
25330ca2051SWilly Tarreau 	char       *pos = buffer + sizeof(buffer) - 1;
25430ca2051SWilly Tarreau 	int         neg = in < 0;
25530ca2051SWilly Tarreau 	unsigned long n = neg ? -in : in;
25630ca2051SWilly Tarreau 
25730ca2051SWilly Tarreau 	*pos-- = '\0';
25830ca2051SWilly Tarreau 	do {
25930ca2051SWilly Tarreau 		*pos-- = '0' + n % 10;
26030ca2051SWilly Tarreau 		n /= 10;
26130ca2051SWilly Tarreau 		if (pos < buffer)
26230ca2051SWilly Tarreau 			return pos + 1;
26330ca2051SWilly Tarreau 	} while (n);
26430ca2051SWilly Tarreau 
26530ca2051SWilly Tarreau 	if (neg)
26630ca2051SWilly Tarreau 		*pos-- = '-';
26730ca2051SWilly Tarreau 	return pos + 1;
26830ca2051SWilly Tarreau }
26930ca2051SWilly Tarreau 
27030ca2051SWilly Tarreau __attribute__((weak,unused))
27130ca2051SWilly Tarreau void *memcpy(void *dst, const void *src, size_t len)
27230ca2051SWilly Tarreau {
27330ca2051SWilly Tarreau 	return memmove(dst, src, len);
27430ca2051SWilly Tarreau }
27530ca2051SWilly Tarreau 
27630ca2051SWilly Tarreau /* needed by libgcc for divide by zero */
27730ca2051SWilly Tarreau __attribute__((weak,unused))
27830ca2051SWilly Tarreau int raise(int signal)
27930ca2051SWilly Tarreau {
28030ca2051SWilly Tarreau 	return kill(getpid(), signal);
28130ca2051SWilly Tarreau }
28230ca2051SWilly Tarreau 
28330ca2051SWilly Tarreau /* Here come a few helper functions */
28430ca2051SWilly Tarreau 
28530ca2051SWilly Tarreau static __attribute__((unused))
28630ca2051SWilly Tarreau void FD_ZERO(fd_set *set)
28730ca2051SWilly Tarreau {
28830ca2051SWilly Tarreau 	memset(set, 0, sizeof(*set));
28930ca2051SWilly Tarreau }
29030ca2051SWilly Tarreau 
29130ca2051SWilly Tarreau static __attribute__((unused))
29230ca2051SWilly Tarreau void FD_SET(int fd, fd_set *set)
29330ca2051SWilly Tarreau {
29430ca2051SWilly Tarreau 	if (fd < 0 || fd >= FD_SETSIZE)
29530ca2051SWilly Tarreau 		return;
29630ca2051SWilly Tarreau 	set->fd32[fd / 32] |= 1 << (fd & 31);
29730ca2051SWilly Tarreau }
29830ca2051SWilly Tarreau 
29930ca2051SWilly Tarreau /* WARNING, it only deals with the 4096 first majors and 256 first minors */
30030ca2051SWilly Tarreau static __attribute__((unused))
30130ca2051SWilly Tarreau dev_t makedev(unsigned int major, unsigned int minor)
30230ca2051SWilly Tarreau {
30330ca2051SWilly Tarreau 	return ((major & 0xfff) << 8) | (minor & 0xff);
30430ca2051SWilly Tarreau }
305930c4accSWilly Tarreau 
306930c4accSWilly Tarreau #endif /* _NOLIBC_H */
307