/* SPDX-License-Identifier: LGPL-2.1 OR MIT */ /* nolibc.h * Copyright (C) 2017-2018 Willy Tarreau */ /* * This file is designed to be used as a libc alternative for minimal programs * with very limited requirements. It consists of a small number of syscall and * type definitions, and the minimal startup code needed to call main(). * All syscalls are declared as static functions so that they can be optimized * away by the compiler when not used. * * Syscalls are split into 3 levels: * - The lower level is the arch-specific syscall() definition, consisting in * assembly code in compound expressions. These are called my_syscall0() to * my_syscall6() depending on the number of arguments. The MIPS * implementation is limited to 5 arguments. All input arguments are cast * to a long stored in a register. These expressions always return the * syscall's return value as a signed long value which is often either a * pointer or the negated errno value. * * - The second level is mostly architecture-independent. It is made of * static functions called sys_() which rely on my_syscallN() * depending on the syscall definition. These functions are responsible * for exposing the appropriate types for the syscall arguments (int, * pointers, etc) and for setting the appropriate return type (often int). * A few of them are architecture-specific because the syscalls are not all * mapped exactly the same among architectures. For example, some archs do * not implement select() and need pselect6() instead, so the sys_select() * function will have to abstract this. * * - The third level is the libc call definition. It exposes the lower raw * sys_() calls in a way that looks like what a libc usually does, * takes care of specific input values, and of setting errno upon error. * There can be minor variations compared to standard libc calls. For * example the open() call always takes 3 args here. * * The errno variable is declared static and unused. This way it can be * optimized away if not used. However this means that a program made of * multiple C files may observe different errno values (one per C file). For * the type of programs this project targets it usually is not a problem. The * resulting program may even be reduced by defining the NOLIBC_IGNORE_ERRNO * macro, in which case the errno value will never be assigned. * * Some stdint-like integer types are defined. These are valid on all currently * supported architectures, because signs are enforced, ints are assumed to be * 32 bits, longs the size of a pointer and long long 64 bits. If more * architectures have to be supported, this may need to be adapted. * * Some macro definitions like the O_* values passed to open(), and some * structures like the sys_stat struct depend on the architecture. * * The definitions start with the architecture-specific parts, which are picked * based on what the compiler knows about the target architecture, and are * completed with the generic code. Since it is the compiler which sets the * target architecture, cross-compiling normally works out of the box without * having to specify anything. * * Finally some very common libc-level functions are provided. It is the case * for a few functions usually found in string.h, ctype.h, or stdlib.h. Nothing * is currently provided regarding stdio emulation. * * The macro NOLIBC is always defined, so that it is possible for a program to * check this macro to know if it is being built against and decide to disable * some features or simply not to include some standard libc files. * * Ideally this file should be split in multiple files for easier long term * maintenance, but provided as a single file as it is now, it's quite * convenient to use. Maybe some variations involving a set of includes at the * top could work. * * A simple static executable may be built this way : * $ gcc -fno-asynchronous-unwind-tables -fno-ident -s -Os -nostdlib \ * -static -include nolibc.h -o hello hello.c -lgcc * * A very useful calling convention table may be found here : * http://man7.org/linux/man-pages/man2/syscall.2.html * * This doc is quite convenient though not necessarily up to date : * https://w3challs.com/syscalls/ * */ /* standard type definitions */ #include "std.h" /* system includes */ #include #include // for SIGCHLD #include #include #include #include #include #include "arch.h" #include "types.h" /* Used by programs to avoid std includes */ #define NOLIBC /* this way it will be removed if unused */ static int errno; #ifndef NOLIBC_IGNORE_ERRNO #define SET_ERRNO(v) do { errno = (v); } while (0) #else #define SET_ERRNO(v) do { } while (0) #endif /* errno codes all ensure that they will not conflict with a valid pointer * because they all correspond to the highest addressable memory page. */ #define MAX_ERRNO 4095 /* Below are the C functions used to declare the raw syscalls. They try to be * architecture-agnostic, and return either a success or -errno. Declaring them * static will lead to them being inlined in most cases, but it's still possible * to reference them by a pointer if needed. */ static __attribute__((unused)) void *sys_brk(void *addr) { return (void *)my_syscall1(__NR_brk, addr); } static __attribute__((noreturn,unused)) void sys_exit(int status) { my_syscall1(__NR_exit, status & 255); while(1); // shut the "noreturn" warnings. } static __attribute__((unused)) int sys_chdir(const char *path) { return my_syscall1(__NR_chdir, path); } static __attribute__((unused)) int sys_chmod(const char *path, mode_t mode) { #ifdef __NR_fchmodat return my_syscall4(__NR_fchmodat, AT_FDCWD, path, mode, 0); #elif defined(__NR_chmod) return my_syscall2(__NR_chmod, path, mode); #else #error Neither __NR_fchmodat nor __NR_chmod defined, cannot implement sys_chmod() #endif } static __attribute__((unused)) int sys_chown(const char *path, uid_t owner, gid_t group) { #ifdef __NR_fchownat return my_syscall5(__NR_fchownat, AT_FDCWD, path, owner, group, 0); #elif defined(__NR_chown) return my_syscall3(__NR_chown, path, owner, group); #else #error Neither __NR_fchownat nor __NR_chown defined, cannot implement sys_chown() #endif } static __attribute__((unused)) int sys_chroot(const char *path) { return my_syscall1(__NR_chroot, path); } static __attribute__((unused)) int sys_close(int fd) { return my_syscall1(__NR_close, fd); } static __attribute__((unused)) int sys_dup(int fd) { return my_syscall1(__NR_dup, fd); } #ifdef __NR_dup3 static __attribute__((unused)) int sys_dup3(int old, int new, int flags) { return my_syscall3(__NR_dup3, old, new, flags); } #endif static __attribute__((unused)) int sys_dup2(int old, int new) { #ifdef __NR_dup3 return my_syscall3(__NR_dup3, old, new, 0); #elif defined(__NR_dup2) return my_syscall2(__NR_dup2, old, new); #else #error Neither __NR_dup3 nor __NR_dup2 defined, cannot implement sys_dup2() #endif } static __attribute__((unused)) int sys_execve(const char *filename, char *const argv[], char *const envp[]) { return my_syscall3(__NR_execve, filename, argv, envp); } static __attribute__((unused)) pid_t sys_fork(void) { #ifdef __NR_clone /* note: some archs only have clone() and not fork(). Different archs * have a different API, but most archs have the flags on first arg and * will not use the rest with no other flag. */ return my_syscall5(__NR_clone, SIGCHLD, 0, 0, 0, 0); #elif defined(__NR_fork) return my_syscall0(__NR_fork); #else #error Neither __NR_clone nor __NR_fork defined, cannot implement sys_fork() #endif } static __attribute__((unused)) int sys_fsync(int fd) { return my_syscall1(__NR_fsync, fd); } static __attribute__((unused)) int sys_getdents64(int fd, struct linux_dirent64 *dirp, int count) { return my_syscall3(__NR_getdents64, fd, dirp, count); } static __attribute__((unused)) pid_t sys_getpgid(pid_t pid) { return my_syscall1(__NR_getpgid, pid); } static __attribute__((unused)) pid_t sys_getpgrp(void) { return sys_getpgid(0); } static __attribute__((unused)) pid_t sys_getpid(void) { return my_syscall0(__NR_getpid); } static __attribute__((unused)) int sys_gettimeofday(struct timeval *tv, struct timezone *tz) { return my_syscall2(__NR_gettimeofday, tv, tz); } static __attribute__((unused)) int sys_ioctl(int fd, unsigned long req, void *value) { return my_syscall3(__NR_ioctl, fd, req, value); } static __attribute__((unused)) int sys_kill(pid_t pid, int signal) { return my_syscall2(__NR_kill, pid, signal); } static __attribute__((unused)) int sys_link(const char *old, const char *new) { #ifdef __NR_linkat return my_syscall5(__NR_linkat, AT_FDCWD, old, AT_FDCWD, new, 0); #elif defined(__NR_link) return my_syscall2(__NR_link, old, new); #else #error Neither __NR_linkat nor __NR_link defined, cannot implement sys_link() #endif } static __attribute__((unused)) off_t sys_lseek(int fd, off_t offset, int whence) { return my_syscall3(__NR_lseek, fd, offset, whence); } static __attribute__((unused)) int sys_mkdir(const char *path, mode_t mode) { #ifdef __NR_mkdirat return my_syscall3(__NR_mkdirat, AT_FDCWD, path, mode); #elif defined(__NR_mkdir) return my_syscall2(__NR_mkdir, path, mode); #else #error Neither __NR_mkdirat nor __NR_mkdir defined, cannot implement sys_mkdir() #endif } static __attribute__((unused)) long sys_mknod(const char *path, mode_t mode, dev_t dev) { #ifdef __NR_mknodat return my_syscall4(__NR_mknodat, AT_FDCWD, path, mode, dev); #elif defined(__NR_mknod) return my_syscall3(__NR_mknod, path, mode, dev); #else #error Neither __NR_mknodat nor __NR_mknod defined, cannot implement sys_mknod() #endif } static __attribute__((unused)) int sys_mount(const char *src, const char *tgt, const char *fst, unsigned long flags, const void *data) { return my_syscall5(__NR_mount, src, tgt, fst, flags, data); } static __attribute__((unused)) int sys_open(const char *path, int flags, mode_t mode) { #ifdef __NR_openat return my_syscall4(__NR_openat, AT_FDCWD, path, flags, mode); #elif defined(__NR_open) return my_syscall3(__NR_open, path, flags, mode); #else #error Neither __NR_openat nor __NR_open defined, cannot implement sys_open() #endif } static __attribute__((unused)) int sys_pivot_root(const char *new, const char *old) { return my_syscall2(__NR_pivot_root, new, old); } static __attribute__((unused)) int sys_poll(struct pollfd *fds, int nfds, int timeout) { #if defined(__NR_ppoll) struct timespec t; if (timeout >= 0) { t.tv_sec = timeout / 1000; t.tv_nsec = (timeout % 1000) * 1000000; } return my_syscall4(__NR_ppoll, fds, nfds, (timeout >= 0) ? &t : NULL, NULL); #elif defined(__NR_poll) return my_syscall3(__NR_poll, fds, nfds, timeout); #else #error Neither __NR_ppoll nor __NR_poll defined, cannot implement sys_poll() #endif } static __attribute__((unused)) ssize_t sys_read(int fd, void *buf, size_t count) { return my_syscall3(__NR_read, fd, buf, count); } static __attribute__((unused)) ssize_t sys_reboot(int magic1, int magic2, int cmd, void *arg) { return my_syscall4(__NR_reboot, magic1, magic2, cmd, arg); } static __attribute__((unused)) int sys_sched_yield(void) { return my_syscall0(__NR_sched_yield); } static __attribute__((unused)) int sys_select(int nfds, fd_set *rfds, fd_set *wfds, fd_set *efds, struct timeval *timeout) { #if defined(__ARCH_WANT_SYS_OLD_SELECT) && !defined(__NR__newselect) struct sel_arg_struct { unsigned long n; fd_set *r, *w, *e; struct timeval *t; } arg = { .n = nfds, .r = rfds, .w = wfds, .e = efds, .t = timeout }; return my_syscall1(__NR_select, &arg); #elif defined(__ARCH_WANT_SYS_PSELECT6) && defined(__NR_pselect6) struct timespec t; if (timeout) { t.tv_sec = timeout->tv_sec; t.tv_nsec = timeout->tv_usec * 1000; } return my_syscall6(__NR_pselect6, nfds, rfds, wfds, efds, timeout ? &t : NULL, NULL); #elif defined(__NR__newselect) || defined(__NR_select) #ifndef __NR__newselect #define __NR__newselect __NR_select #endif return my_syscall5(__NR__newselect, nfds, rfds, wfds, efds, timeout); #else #error None of __NR_select, __NR_pselect6, nor __NR__newselect defined, cannot implement sys_select() #endif } static __attribute__((unused)) int sys_setpgid(pid_t pid, pid_t pgid) { return my_syscall2(__NR_setpgid, pid, pgid); } static __attribute__((unused)) pid_t sys_setsid(void) { return my_syscall0(__NR_setsid); } static __attribute__((unused)) int sys_stat(const char *path, struct stat *buf) { struct sys_stat_struct stat; long ret; #ifdef __NR_newfstatat /* only solution for arm64 */ ret = my_syscall4(__NR_newfstatat, AT_FDCWD, path, &stat, 0); #elif defined(__NR_stat) ret = my_syscall2(__NR_stat, path, &stat); #else #error Neither __NR_newfstatat nor __NR_stat defined, cannot implement sys_stat() #endif buf->st_dev = stat.st_dev; buf->st_ino = stat.st_ino; buf->st_mode = stat.st_mode; buf->st_nlink = stat.st_nlink; buf->st_uid = stat.st_uid; buf->st_gid = stat.st_gid; buf->st_rdev = stat.st_rdev; buf->st_size = stat.st_size; buf->st_blksize = stat.st_blksize; buf->st_blocks = stat.st_blocks; buf->st_atime = stat.st_atime; buf->st_mtime = stat.st_mtime; buf->st_ctime = stat.st_ctime; return ret; } static __attribute__((unused)) int sys_symlink(const char *old, const char *new) { #ifdef __NR_symlinkat return my_syscall3(__NR_symlinkat, old, AT_FDCWD, new); #elif defined(__NR_symlink) return my_syscall2(__NR_symlink, old, new); #else #error Neither __NR_symlinkat nor __NR_symlink defined, cannot implement sys_symlink() #endif } static __attribute__((unused)) mode_t sys_umask(mode_t mode) { return my_syscall1(__NR_umask, mode); } static __attribute__((unused)) int sys_umount2(const char *path, int flags) { return my_syscall2(__NR_umount2, path, flags); } static __attribute__((unused)) int sys_unlink(const char *path) { #ifdef __NR_unlinkat return my_syscall3(__NR_unlinkat, AT_FDCWD, path, 0); #elif defined(__NR_unlink) return my_syscall1(__NR_unlink, path); #else #error Neither __NR_unlinkat nor __NR_unlink defined, cannot implement sys_unlink() #endif } static __attribute__((unused)) pid_t sys_wait4(pid_t pid, int *status, int options, struct rusage *rusage) { return my_syscall4(__NR_wait4, pid, status, options, rusage); } static __attribute__((unused)) pid_t sys_waitpid(pid_t pid, int *status, int options) { return sys_wait4(pid, status, options, 0); } static __attribute__((unused)) pid_t sys_wait(int *status) { return sys_waitpid(-1, status, 0); } static __attribute__((unused)) ssize_t sys_write(int fd, const void *buf, size_t count) { return my_syscall3(__NR_write, fd, buf, count); } /* Below are the libc-compatible syscalls which return x or -1 and set errno. * They rely on the functions above. Similarly they're marked static so that it * is possible to assign pointers to them if needed. */ static __attribute__((unused)) int brk(void *addr) { void *ret = sys_brk(addr); if (!ret) { SET_ERRNO(ENOMEM); return -1; } return 0; } static __attribute__((noreturn,unused)) void exit(int status) { sys_exit(status); } static __attribute__((unused)) int chdir(const char *path) { int ret = sys_chdir(path); if (ret < 0) { SET_ERRNO(-ret); ret = -1; } return ret; } static __attribute__((unused)) int chmod(const char *path, mode_t mode) { int ret = sys_chmod(path, mode); if (ret < 0) { SET_ERRNO(-ret); ret = -1; } return ret; } static __attribute__((unused)) int chown(const char *path, uid_t owner, gid_t group) { int ret = sys_chown(path, owner, group); if (ret < 0) { SET_ERRNO(-ret); ret = -1; } return ret; } static __attribute__((unused)) int chroot(const char *path) { int ret = sys_chroot(path); if (ret < 0) { SET_ERRNO(-ret); ret = -1; } return ret; } static __attribute__((unused)) int close(int fd) { int ret = sys_close(fd); if (ret < 0) { SET_ERRNO(-ret); ret = -1; } return ret; } static __attribute__((unused)) int dup(int fd) { int ret = sys_dup(fd); if (ret < 0) { SET_ERRNO(-ret); ret = -1; } return ret; } static __attribute__((unused)) int dup2(int old, int new) { int ret = sys_dup2(old, new); if (ret < 0) { SET_ERRNO(-ret); ret = -1; } return ret; } #ifdef __NR_dup3 static __attribute__((unused)) int dup3(int old, int new, int flags) { int ret = sys_dup3(old, new, flags); if (ret < 0) { SET_ERRNO(-ret); ret = -1; } return ret; } #endif static __attribute__((unused)) int execve(const char *filename, char *const argv[], char *const envp[]) { int ret = sys_execve(filename, argv, envp); if (ret < 0) { SET_ERRNO(-ret); ret = -1; } return ret; } static __attribute__((unused)) pid_t fork(void) { pid_t ret = sys_fork(); if (ret < 0) { SET_ERRNO(-ret); ret = -1; } return ret; } static __attribute__((unused)) int fsync(int fd) { int ret = sys_fsync(fd); if (ret < 0) { SET_ERRNO(-ret); ret = -1; } return ret; } static __attribute__((unused)) int getdents64(int fd, struct linux_dirent64 *dirp, int count) { int ret = sys_getdents64(fd, dirp, count); if (ret < 0) { SET_ERRNO(-ret); ret = -1; } return ret; } static __attribute__((unused)) pid_t getpgid(pid_t pid) { pid_t ret = sys_getpgid(pid); if (ret < 0) { SET_ERRNO(-ret); ret = -1; } return ret; } static __attribute__((unused)) pid_t getpgrp(void) { pid_t ret = sys_getpgrp(); if (ret < 0) { SET_ERRNO(-ret); ret = -1; } return ret; } static __attribute__((unused)) pid_t getpid(void) { pid_t ret = sys_getpid(); if (ret < 0) { SET_ERRNO(-ret); ret = -1; } return ret; } static __attribute__((unused)) int gettimeofday(struct timeval *tv, struct timezone *tz) { int ret = sys_gettimeofday(tv, tz); if (ret < 0) { SET_ERRNO(-ret); ret = -1; } return ret; } static __attribute__((unused)) int ioctl(int fd, unsigned long req, void *value) { int ret = sys_ioctl(fd, req, value); if (ret < 0) { SET_ERRNO(-ret); ret = -1; } return ret; } static __attribute__((unused)) int kill(pid_t pid, int signal) { int ret = sys_kill(pid, signal); if (ret < 0) { SET_ERRNO(-ret); ret = -1; } return ret; } static __attribute__((unused)) int link(const char *old, const char *new) { int ret = sys_link(old, new); if (ret < 0) { SET_ERRNO(-ret); ret = -1; } return ret; } static __attribute__((unused)) off_t lseek(int fd, off_t offset, int whence) { off_t ret = sys_lseek(fd, offset, whence); if (ret < 0) { SET_ERRNO(-ret); ret = -1; } return ret; } static __attribute__((unused)) int mkdir(const char *path, mode_t mode) { int ret = sys_mkdir(path, mode); if (ret < 0) { SET_ERRNO(-ret); ret = -1; } return ret; } static __attribute__((unused)) int mknod(const char *path, mode_t mode, dev_t dev) { int ret = sys_mknod(path, mode, dev); if (ret < 0) { SET_ERRNO(-ret); ret = -1; } return ret; } static __attribute__((unused)) int mount(const char *src, const char *tgt, const char *fst, unsigned long flags, const void *data) { int ret = sys_mount(src, tgt, fst, flags, data); if (ret < 0) { SET_ERRNO(-ret); ret = -1; } return ret; } static __attribute__((unused)) int open(const char *path, int flags, mode_t mode) { int ret = sys_open(path, flags, mode); if (ret < 0) { SET_ERRNO(-ret); ret = -1; } return ret; } static __attribute__((unused)) int pivot_root(const char *new, const char *old) { int ret = sys_pivot_root(new, old); if (ret < 0) { SET_ERRNO(-ret); ret = -1; } return ret; } static __attribute__((unused)) int poll(struct pollfd *fds, int nfds, int timeout) { int ret = sys_poll(fds, nfds, timeout); if (ret < 0) { SET_ERRNO(-ret); ret = -1; } return ret; } static __attribute__((unused)) ssize_t read(int fd, void *buf, size_t count) { ssize_t ret = sys_read(fd, buf, count); if (ret < 0) { SET_ERRNO(-ret); ret = -1; } return ret; } static __attribute__((unused)) int reboot(int cmd) { int ret = sys_reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, cmd, 0); if (ret < 0) { SET_ERRNO(-ret); ret = -1; } return ret; } static __attribute__((unused)) void *sbrk(intptr_t inc) { void *ret; /* first call to find current end */ if ((ret = sys_brk(0)) && (sys_brk(ret + inc) == ret + inc)) return ret + inc; SET_ERRNO(ENOMEM); return (void *)-1; } static __attribute__((unused)) int sched_yield(void) { int ret = sys_sched_yield(); if (ret < 0) { SET_ERRNO(-ret); ret = -1; } return ret; } static __attribute__((unused)) int select(int nfds, fd_set *rfds, fd_set *wfds, fd_set *efds, struct timeval *timeout) { int ret = sys_select(nfds, rfds, wfds, efds, timeout); if (ret < 0) { SET_ERRNO(-ret); ret = -1; } return ret; } static __attribute__((unused)) int setpgid(pid_t pid, pid_t pgid) { int ret = sys_setpgid(pid, pgid); if (ret < 0) { SET_ERRNO(-ret); ret = -1; } return ret; } static __attribute__((unused)) pid_t setsid(void) { pid_t ret = sys_setsid(); if (ret < 0) { SET_ERRNO(-ret); ret = -1; } return ret; } static __attribute__((unused)) unsigned int sleep(unsigned int seconds) { struct timeval my_timeval = { seconds, 0 }; if (sys_select(0, 0, 0, 0, &my_timeval) < 0) return my_timeval.tv_sec + !!my_timeval.tv_usec; else return 0; } static __attribute__((unused)) int msleep(unsigned int msecs) { struct timeval my_timeval = { msecs / 1000, (msecs % 1000) * 1000 }; if (sys_select(0, 0, 0, 0, &my_timeval) < 0) return (my_timeval.tv_sec * 1000) + (my_timeval.tv_usec / 1000) + !!(my_timeval.tv_usec % 1000); else return 0; } static __attribute__((unused)) int stat(const char *path, struct stat *buf) { int ret = sys_stat(path, buf); if (ret < 0) { SET_ERRNO(-ret); ret = -1; } return ret; } static __attribute__((unused)) int symlink(const char *old, const char *new) { int ret = sys_symlink(old, new); if (ret < 0) { SET_ERRNO(-ret); ret = -1; } return ret; } static __attribute__((unused)) int tcsetpgrp(int fd, pid_t pid) { return ioctl(fd, TIOCSPGRP, &pid); } static __attribute__((unused)) mode_t umask(mode_t mode) { return sys_umask(mode); } static __attribute__((unused)) int umount2(const char *path, int flags) { int ret = sys_umount2(path, flags); if (ret < 0) { SET_ERRNO(-ret); ret = -1; } return ret; } static __attribute__((unused)) int unlink(const char *path) { int ret = sys_unlink(path); if (ret < 0) { SET_ERRNO(-ret); ret = -1; } return ret; } static __attribute__((unused)) pid_t wait4(pid_t pid, int *status, int options, struct rusage *rusage) { pid_t ret = sys_wait4(pid, status, options, rusage); if (ret < 0) { SET_ERRNO(-ret); ret = -1; } return ret; } static __attribute__((unused)) pid_t waitpid(pid_t pid, int *status, int options) { pid_t ret = sys_waitpid(pid, status, options); if (ret < 0) { SET_ERRNO(-ret); ret = -1; } return ret; } static __attribute__((unused)) pid_t wait(int *status) { pid_t ret = sys_wait(status); if (ret < 0) { SET_ERRNO(-ret); ret = -1; } return ret; } static __attribute__((unused)) ssize_t write(int fd, const void *buf, size_t count) { ssize_t ret = sys_write(fd, buf, count); if (ret < 0) { SET_ERRNO(-ret); ret = -1; } return ret; } /* some size-optimized reimplementations of a few common str* and mem* * functions. They're marked static, except memcpy() and raise() which are used * by libgcc on ARM, so they are marked weak instead in order not to cause an * error when building a program made of multiple files (not recommended). */ static __attribute__((unused)) void *memmove(void *dst, const void *src, size_t len) { ssize_t pos = (dst <= src) ? -1 : (long)len; void *ret = dst; while (len--) { pos += (dst <= src) ? 1 : -1; ((char *)dst)[pos] = ((char *)src)[pos]; } return ret; } static __attribute__((unused)) void *memset(void *dst, int b, size_t len) { char *p = dst; while (len--) *(p++) = b; return dst; } static __attribute__((unused)) int memcmp(const void *s1, const void *s2, size_t n) { size_t ofs = 0; int c1 = 0; while (ofs < n && !(c1 = ((unsigned char *)s1)[ofs] - ((unsigned char *)s2)[ofs])) { ofs++; } return c1; } static __attribute__((unused)) char *strcpy(char *dst, const char *src) { char *ret = dst; while ((*dst++ = *src++)); return ret; } static __attribute__((unused)) char *strchr(const char *s, int c) { while (*s) { if (*s == (char)c) return (char *)s; s++; } return NULL; } static __attribute__((unused)) char *strrchr(const char *s, int c) { const char *ret = NULL; while (*s) { if (*s == (char)c) ret = s; s++; } return (char *)ret; } static __attribute__((unused)) size_t nolibc_strlen(const char *str) { size_t len; for (len = 0; str[len]; len++); return len; } #define strlen(str) ({ \ __builtin_constant_p((str)) ? \ __builtin_strlen((str)) : \ nolibc_strlen((str)); \ }) static __attribute__((unused)) int isdigit(int c) { return (unsigned int)(c - '0') <= 9; } static __attribute__((unused)) long atol(const char *s) { unsigned long ret = 0; unsigned long d; int neg = 0; if (*s == '-') { neg = 1; s++; } while (1) { d = (*s++) - '0'; if (d > 9) break; ret *= 10; ret += d; } return neg ? -ret : ret; } static __attribute__((unused)) int atoi(const char *s) { return atol(s); } static __attribute__((unused)) const char *ltoa(long in) { /* large enough for -9223372036854775808 */ static char buffer[21]; char *pos = buffer + sizeof(buffer) - 1; int neg = in < 0; unsigned long n = neg ? -in : in; *pos-- = '\0'; do { *pos-- = '0' + n % 10; n /= 10; if (pos < buffer) return pos + 1; } while (n); if (neg) *pos-- = '-'; return pos + 1; } __attribute__((weak,unused)) void *memcpy(void *dst, const void *src, size_t len) { return memmove(dst, src, len); } /* needed by libgcc for divide by zero */ __attribute__((weak,unused)) int raise(int signal) { return kill(getpid(), signal); } /* Here come a few helper functions */ static __attribute__((unused)) void FD_ZERO(fd_set *set) { memset(set, 0, sizeof(*set)); } static __attribute__((unused)) void FD_SET(int fd, fd_set *set) { if (fd < 0 || fd >= FD_SETSIZE) return; set->fd32[fd / 32] |= 1 << (fd & 31); } /* WARNING, it only deals with the 4096 first majors and 256 first minors */ static __attribute__((unused)) dev_t makedev(unsigned int major, unsigned int minor) { return ((major & 0xfff) << 8) | (minor & 0xff); }