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