commit b08b0728ae5e297d794a02297f01eb76aa8fb909
parent 435b2bf2a0f0dccb1665142c0e96791098bc56a2
Author: cowmonk <rekketstone@proton.me>
Date: Wed, 28 May 2025 18:58:30 -0700
cowos uses it's own cowlibc! big W
Diffstat:
18 files changed, 187 insertions(+), 3049 deletions(-)
diff --git a/Makefile b/Makefile
@@ -14,7 +14,7 @@ iso: kernel limine
kernel:
make -C ./kernel/ all
-limine:
+limine: kernel
git clone https://github.com/limine-bootloader/limine.git --branch=v9.x-binary --depth=1
make -C limine
@@ -26,3 +26,4 @@ limine:
clean:
rm cowos.iso
+ make -C ./kernel/ clean
diff --git a/README.md b/README.md
@@ -23,5 +23,4 @@ make
```
# Credits
-- [nolibc](https://github.com/wtarreau/nolibc): libc-less wrapper to make tiny static executables for simple programs.
- [Limine](https://github.com/limine-bootloader/limine): modern, advanced, portable, multiprotocol bootloader and boot manager.
diff --git a/kernel/include/klibc/arch.h b/kernel/include/klibc/arch.h
@@ -1,235 +0,0 @@
-/*
- * x86_64 specific definitions for NOLIBC
- * Copyright (C) 2017-2022 Willy Tarreau <w@1wt.eu>
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
- * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
- * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
- * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- */
-
-#ifndef _NOLIBC_ARCH_H
-#define _NOLIBC_ARCH_H
-
-/* O_* macros for fcntl/open are architecture-specific */
-#define O_RDONLY 0
-#define O_WRONLY 1
-#define O_RDWR 2
-#define O_CREAT 0x40
-#define O_EXCL 0x80
-#define O_NOCTTY 0x100
-#define O_TRUNC 0x200
-#define O_APPEND 0x400
-#define O_NONBLOCK 0x800
-#define O_DIRECTORY 0x10000
-
-/* The struct returned by the stat() syscall, equivalent to stat64(). The
- * syscall returns 116 bytes and stops in the middle of __unused.
- */
-struct sys_stat_struct {
- unsigned long st_dev;
- unsigned long st_ino;
- unsigned long st_nlink;
- unsigned int st_mode;
- unsigned int st_uid;
-
- unsigned int st_gid;
- unsigned int __pad0;
- unsigned long st_rdev;
- long st_size;
- long st_blksize;
-
- long st_blocks;
- unsigned long st_atime;
- unsigned long st_atime_nsec;
- unsigned long st_mtime;
-
- unsigned long st_mtime_nsec;
- unsigned long st_ctime;
- unsigned long st_ctime_nsec;
- long __unused[3];
-};
-
-/* Syscalls for x86_64 :
- * - registers are 64-bit
- * - syscall number is passed in rax
- * - arguments are in rdi, rsi, rdx, r10, r8, r9 respectively
- * - the system call is performed by calling the syscall instruction
- * - syscall return comes in rax
- * - rcx and r11 are clobbered, others are preserved.
- * - the arguments are cast to long and assigned into the target registers
- * which are then simply passed as registers to the asm code, so that we
- * don't have to experience issues with register constraints.
- * - the syscall number is always specified last in order to allow to force
- * some registers before (gcc refuses a %-register at the last position).
- * - see also x86-64 ABI section A.2 AMD64 Linux Kernel Conventions, A.2.1
- * Calling Conventions.
- *
- * Link x86-64 ABI: https://gitlab.com/x86-psABIs/x86-64-ABI/-/wikis/x86-64-psABI
- *
- */
-
-#define my_syscall0(num) \
-({ \
- long _ret; \
- register long _num asm("rax") = (num); \
- \
- asm volatile ( \
- "syscall\n" \
- : "=a"(_ret) \
- : "0"(_num) \
- : "rcx", "r11", "memory", "cc" \
- ); \
- _ret; \
-})
-
-#define my_syscall1(num, arg1) \
-({ \
- long _ret; \
- register long _num asm("rax") = (num); \
- register long _arg1 asm("rdi") = (long)(arg1); \
- \
- asm volatile ( \
- "syscall\n" \
- : "=a"(_ret) \
- : "r"(_arg1), \
- "0"(_num) \
- : "rcx", "r11", "memory", "cc" \
- ); \
- _ret; \
-})
-
-#define my_syscall2(num, arg1, arg2) \
-({ \
- long _ret; \
- register long _num asm("rax") = (num); \
- register long _arg1 asm("rdi") = (long)(arg1); \
- register long _arg2 asm("rsi") = (long)(arg2); \
- \
- asm volatile ( \
- "syscall\n" \
- : "=a"(_ret) \
- : "r"(_arg1), "r"(_arg2), \
- "0"(_num) \
- : "rcx", "r11", "memory", "cc" \
- ); \
- _ret; \
-})
-
-#define my_syscall3(num, arg1, arg2, arg3) \
-({ \
- long _ret; \
- register long _num asm("rax") = (num); \
- register long _arg1 asm("rdi") = (long)(arg1); \
- register long _arg2 asm("rsi") = (long)(arg2); \
- register long _arg3 asm("rdx") = (long)(arg3); \
- \
- asm volatile ( \
- "syscall\n" \
- : "=a"(_ret) \
- : "r"(_arg1), "r"(_arg2), "r"(_arg3), \
- "0"(_num) \
- : "rcx", "r11", "memory", "cc" \
- ); \
- _ret; \
-})
-
-#define my_syscall4(num, arg1, arg2, arg3, arg4) \
-({ \
- long _ret; \
- register long _num asm("rax") = (num); \
- register long _arg1 asm("rdi") = (long)(arg1); \
- register long _arg2 asm("rsi") = (long)(arg2); \
- register long _arg3 asm("rdx") = (long)(arg3); \
- register long _arg4 asm("r10") = (long)(arg4); \
- \
- asm volatile ( \
- "syscall\n" \
- : "=a"(_ret) \
- : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), \
- "0"(_num) \
- : "rcx", "r11", "memory", "cc" \
- ); \
- _ret; \
-})
-
-#define my_syscall5(num, arg1, arg2, arg3, arg4, arg5) \
-({ \
- long _ret; \
- register long _num asm("rax") = (num); \
- register long _arg1 asm("rdi") = (long)(arg1); \
- register long _arg2 asm("rsi") = (long)(arg2); \
- register long _arg3 asm("rdx") = (long)(arg3); \
- register long _arg4 asm("r10") = (long)(arg4); \
- register long _arg5 asm("r8") = (long)(arg5); \
- \
- asm volatile ( \
- "syscall\n" \
- : "=a"(_ret) \
- : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \
- "0"(_num) \
- : "rcx", "r11", "memory", "cc" \
- ); \
- _ret; \
-})
-
-#define my_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6) \
-({ \
- long _ret; \
- register long _num asm("rax") = (num); \
- register long _arg1 asm("rdi") = (long)(arg1); \
- register long _arg2 asm("rsi") = (long)(arg2); \
- register long _arg3 asm("rdx") = (long)(arg3); \
- register long _arg4 asm("r10") = (long)(arg4); \
- register long _arg5 asm("r8") = (long)(arg5); \
- register long _arg6 asm("r9") = (long)(arg6); \
- \
- asm volatile ( \
- "syscall\n" \
- : "=a"(_ret) \
- : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \
- "r"(_arg6), "0"(_num) \
- : "rcx", "r11", "memory", "cc" \
- ); \
- _ret; \
-})
-
-/* startup code */
-/*
- * x86-64 System V ABI mandates:
- * 1) %rsp must be 16-byte aligned right before the function call.
- * 2) The deepest stack frame should be zero (the %rbp).
- *
- */
-asm(".section .text\n"
- ".weak _start\n"
- ".global _start\n"
- "_start:\n"
- "pop %rdi\n" // argc (first arg, %rdi)
- "mov %rsp, %rsi\n" // argv[] (second arg, %rsi)
- "lea 8(%rsi,%rdi,8),%rdx\n" // then a NULL then envp (third arg, %rdx)
- "xor %ebp, %ebp\n" // zero the stack frame
- "and $-16, %rsp\n" // x86 ABI : esp must be 16-byte aligned before call
- "call main\n" // main() returns the status code, we'll exit with it.
- "mov %eax, %edi\n" // retrieve exit code (32 bit)
- "mov $60, %eax\n" // NR_exit == 60
- "syscall\n" // really exit
- "hlt\n" // ensure it does not return
- "");
-
-#endif // _NOLIBC_ARCH_H
diff --git a/kernel/include/klibc/ctype.h b/kernel/include/klibc/ctype.h
@@ -1,118 +0,0 @@
-/*
- * ctype function definitions for NOLIBC
- * Copyright (C) 2017-2021 Willy Tarreau <w@1wt.eu>
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
- * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
- * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
- * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- */
-
-#ifndef _NOLIBC_CTYPE_H
-#define _NOLIBC_CTYPE_H
-
-#include "std.h"
-
-/*
- * As much as possible, please keep functions alphabetically sorted.
- */
-
-static __attribute__((unused))
-int isascii(int c)
-{
- /* 0x00..0x7f */
- return (unsigned int)c <= 0x7f;
-}
-
-static __attribute__((unused))
-int isblank(int c)
-{
- return c == '\t' || c == ' ';
-}
-
-static __attribute__((unused))
-int iscntrl(int c)
-{
- /* 0x00..0x1f, 0x7f */
- return (unsigned int)c < 0x20 || c == 0x7f;
-}
-
-static __attribute__((unused))
-int isdigit(int c)
-{
- return (unsigned int)(c - '0') < 10;
-}
-
-static __attribute__((unused))
-int isgraph(int c)
-{
- /* 0x21..0x7e */
- return (unsigned int)(c - 0x21) < 0x5e;
-}
-
-static __attribute__((unused))
-int islower(int c)
-{
- return (unsigned int)(c - 'a') < 26;
-}
-
-static __attribute__((unused))
-int isprint(int c)
-{
- /* 0x20..0x7e */
- return (unsigned int)(c - 0x20) < 0x5f;
-}
-
-static __attribute__((unused))
-int isspace(int c)
-{
- /* \t is 0x9, \n is 0xA, \v is 0xB, \f is 0xC, \r is 0xD */
- return ((unsigned int)c == ' ') || (unsigned int)(c - 0x09) < 5;
-}
-
-static __attribute__((unused))
-int isupper(int c)
-{
- return (unsigned int)(c - 'A') < 26;
-}
-
-static __attribute__((unused))
-int isxdigit(int c)
-{
- return isdigit(c) || (unsigned int)(c - 'A') < 6 || (unsigned int)(c - 'a') < 6;
-}
-
-static __attribute__((unused))
-int isalpha(int c)
-{
- return islower(c) || isupper(c);
-}
-
-static __attribute__((unused))
-int isalnum(int c)
-{
- return isalpha(c) || isdigit(c);
-}
-
-static __attribute__((unused))
-int ispunct(int c)
-{
- return isgraph(c) && !isalnum(c);
-}
-
-#endif /* _NOLIBC_CTYPE_H */
diff --git a/kernel/include/klibc/errno.h b/kernel/include/klibc/errno.h
@@ -1,46 +0,0 @@
-/*
- * Minimal errno definitions for NOLIBC
- * Copyright (C) 2017-2022 Willy Tarreau <w@1wt.eu>
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
- * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
- * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
- * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- */
-
-#ifndef _NOLIBC_ERRNO_H
-#define _NOLIBC_ERRNO_H
-
-#include <asm/errno.h>
-
-/* 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
-
-#endif /* _NOLIBC_ERRNO_H */
diff --git a/kernel/include/klibc/nolibc.h b/kernel/include/klibc/nolibc.h
@@ -1,130 +0,0 @@
-/*
- * Copyright (C) 2017-2018 Willy Tarreau <w@1wt.eu>
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
- * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
- * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
- * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- */
-
-/*
- * 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_<name>() 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_<name>() 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.
- *
- * The nolibc.h file is only a convenient entry point which includes all other
- * files. It also defines the NOLIBC macro, 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.
- *
- * 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
- *
- * Simple programs meant to be reasonably portable to various libc and using
- * only a few common includes, may also be built by simply making the include
- * path point to the nolibc directory:
- * $ gcc -fno-asynchronous-unwind-tables -fno-ident -s -Os -nostdlib \
- * -I../nolibc -o hello hello.c -lgcc
- *
- * The available standard (but limited) include files are:
- * ctype.h, errno.h, signal.h, stdio.h, stdlib.h, string.h, time.h
- *
- * In addition, the following ones are expected to be provided by the compiler:
- * float.h, stdarg.h, stddef.h
- *
- * The following ones which are part to the C standard are not provided:
- * assert.h, locale.h, math.h, setjmp.h, limits.h
- *
- * 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/
- *
- */
-#ifndef _NOLIBC_H
-#define _NOLIBC_H
-
-#include "std.h"
-#include "arch.h"
-#include "types.h"
-#include "sys.h"
-#include "ctype.h"
-#include "signal.h"
-#include "stdio.h"
-#include "stdlib.h"
-#include "string.h"
-#include "time.h"
-#include "unistd.h"
-
-/* Used by programs to avoid std includes */
-#define NOLIBC
-
-#endif /* _NOLIBC_H */
diff --git a/kernel/include/klibc/signal.h b/kernel/include/klibc/signal.h
@@ -1,41 +0,0 @@
-/*
- * signal function definitions for NOLIBC
- * Copyright (C) 2017-2022 Willy Tarreau <w@1wt.eu>
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
- * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
- * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
- * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- */
-
-#ifndef _NOLIBC_SIGNAL_H
-#define _NOLIBC_SIGNAL_H
-
-#include "std.h"
-#include "arch.h"
-#include "types.h"
-#include "sys.h"
-
-/* This one is not marked static as it's needed by libgcc for divide by zero */
-__attribute__((weak,unused,section(".text.nolibc_raise")))
-int raise(int signal)
-{
- return sys_kill(sys_getpid(), signal);
-}
-
-#endif /* _NOLIBC_SIGNAL_H */
diff --git a/kernel/include/klibc/std.h b/kernel/include/klibc/std.h
@@ -1,68 +0,0 @@
-/*
- * Standard definitions and types for NOLIBC
- * Copyright (C) 2017-2021 Willy Tarreau <w@1wt.eu>
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
- * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
- * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
- * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- */
-
-#ifndef _NOLIBC_STD_H
-#define _NOLIBC_STD_H
-
-/* Declare a few quite common macros and types that usually are in stdlib.h,
- * stdint.h, ctype.h, unistd.h and a few other common locations. Please place
- * integer type definitions and generic macros here, but avoid OS-specific and
- * syscall-specific stuff, as this file is expected to be included very early.
- */
-
-/* note: may already be defined */
-#ifndef NULL
-#define NULL ((void *)0)
-#endif
-
-/* stdint types */
-typedef unsigned char uint8_t;
-typedef signed char int8_t;
-typedef unsigned short uint16_t;
-typedef signed short int16_t;
-typedef unsigned int uint32_t;
-typedef signed int int32_t;
-// typedef unsigned long long uint64_t;
-// typedef signed long long int64_t;
-typedef unsigned long size_t;
-typedef signed long ssize_t;
-typedef unsigned long uintptr_t;
-typedef signed long intptr_t;
-typedef signed long ptrdiff_t;
-
-/* those are commonly provided by sys/types.h */
-typedef unsigned int dev_t;
-typedef unsigned long ino_t;
-typedef unsigned int mode_t;
-typedef signed int pid_t;
-typedef unsigned int uid_t;
-typedef unsigned int gid_t;
-typedef unsigned long nlink_t;
-typedef signed long off_t;
-typedef signed long blksize_t;
-typedef signed long blkcnt_t;
-typedef signed long time_t;
-
-#endif /* _NOLIBC_STD_H */
diff --git a/kernel/include/klibc/stdio.h b/kernel/include/klibc/stdio.h
@@ -1,325 +1,13 @@
-/*
- * minimal stdio function definitions for NOLIBC
- * Copyright (C) 2017-2021 Willy Tarreau <w@1wt.eu>
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
- * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
- * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
- * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- */
+#ifndef _STDIO_H
+#define _STDIO_H 1
-#ifndef _NOLIBC_STDIO_H
-#define _NOLIBC_STDIO_H
+#include <klibc/sys/cdefs.h>
-#include <stdarg.h>
-
-#include "std.h"
-#include "arch.h"
-#include "errno.h"
-#include "types.h"
-#include "sys.h"
-#include "stdlib.h"
-#include "string.h"
-
-#ifndef EOF
#define EOF (-1)
-#endif
-
-/* just define FILE as a non-empty type */
-typedef struct FILE {
- char dummy[1];
-} FILE;
-
-/* We define the 3 common stdio files as constant invalid pointers that
- * are easily recognized.
- */
-static __attribute__((unused)) FILE* const stdin = (FILE*)-3;
-static __attribute__((unused)) FILE* const stdout = (FILE*)-2;
-static __attribute__((unused)) FILE* const stderr = (FILE*)-1;
-
-/* getc(), fgetc(), getchar() */
-
-#define getc(stream) fgetc(stream)
-
-static __attribute__((unused))
-int fgetc(FILE* stream)
-{
- unsigned char ch;
- int fd;
-
- if (stream < stdin || stream > stderr)
- return EOF;
-
- fd = 3 + (long)stream;
-
- if (read(fd, &ch, 1) <= 0)
- return EOF;
- return ch;
-}
-
-static __attribute__((unused))
-int getchar(void)
-{
- return fgetc(stdin);
-}
-
-
-/* putc(), fputc(), putchar() */
-
-#define putc(c, stream) fputc(c, stream)
-
-static __attribute__((unused))
-int fputc(int c, FILE* stream)
-{
- unsigned char ch = c;
- int fd;
-
- if (stream < stdin || stream > stderr)
- return EOF;
-
- fd = 3 + (long)stream;
-
- if (write(fd, &ch, 1) <= 0)
- return EOF;
- return ch;
-}
-
-static __attribute__((unused))
-int putchar(int c)
-{
- return fputc(c, stdout);
-}
-
-
-/* fwrite(), puts(), fputs(). Note that puts() emits '\n' but not fputs(). */
-
-/* internal fwrite()-like function which only takes a size and returns 0 on
- * success or EOF on error. It automatically retries on short writes.
- */
-static __attribute__((unused))
-int _fwrite(const void *buf, size_t size, FILE *stream)
-{
- ssize_t ret;
- int fd;
-
- if (stream < stdin || stream > stderr)
- return EOF;
- fd = 3 + (long)stream;
+int printf(const char* __restrict, ...);
+int putchar(int);
+int puts(const char*);
- while (size) {
- ret = write(fd, buf, size);
- if (ret <= 0)
- return EOF;
- size -= ret;
- buf += ret;
- }
- return 0;
-}
-
-static __attribute__((unused))
-size_t fwrite(const void *s, size_t size, size_t nmemb, FILE *stream)
-{
- size_t written;
-
- for (written = 0; written < nmemb; written++) {
- if (_fwrite(s, size, stream) != 0)
- break;
- s += size;
- }
- return written;
-}
-
-static __attribute__((unused))
-int fputs(const char *s, FILE *stream)
-{
- return _fwrite(s, strlen(s), stream);
-}
-
-static __attribute__((unused))
-int puts(const char *s)
-{
- if (fputs(s, stdout) == EOF)
- return EOF;
- return putchar('\n');
-}
-
-
-/* fgets() */
-static __attribute__((unused))
-char *fgets(char *s, int size, FILE *stream)
-{
- int ofs;
- int c;
-
- for (ofs = 0; ofs + 1 < size;) {
- c = fgetc(stream);
- if (c == EOF)
- break;
- s[ofs++] = c;
- if (c == '\n')
- break;
- }
- if (ofs < size)
- s[ofs] = 0;
- return ofs ? s : NULL;
-}
-
-
-/* minimal vfprintf(). It supports the following formats:
- * - %[l*]{d,u,c,x,p}
- * - %s
- * - unknown modifiers are ignored.
- */
-static __attribute__((unused))
-int vfprintf(FILE *stream, const char *fmt, va_list args)
-{
- char escape, lpref, c;
- unsigned long long v;
- unsigned int written;
- size_t len, ofs;
- char tmpbuf[21];
- const char *outstr;
-
- written = ofs = escape = lpref = 0;
- while (1) {
- c = fmt[ofs++];
-
- if (escape) {
- /* we're in an escape sequence, ofs == 1 */
- escape = 0;
- if (c == 'c' || c == 'd' || c == 'u' || c == 'x' || c == 'p') {
- char *out = tmpbuf;
-
- if (c == 'p')
- v = va_arg(args, unsigned long);
- else if (lpref) {
- if (lpref > 1)
- v = va_arg(args, unsigned long long);
- else
- v = va_arg(args, unsigned long);
- } else
- v = va_arg(args, unsigned int);
-
- if (c == 'd') {
- /* sign-extend the value */
- if (lpref == 0)
- v = (long long)(int)v;
- else if (lpref == 1)
- v = (long long)(long)v;
- }
-
- switch (c) {
- case 'c':
- out[0] = v;
- out[1] = 0;
- break;
- case 'd':
- i64toa_r(v, out);
- break;
- case 'u':
- u64toa_r(v, out);
- break;
- case 'p':
- *(out++) = '0';
- *(out++) = 'x';
- /* fall through */
- default: /* 'x' and 'p' above */
- u64toh_r(v, out);
- break;
- }
- outstr = tmpbuf;
- }
- else if (c == 's') {
- outstr = va_arg(args, char *);
- if (!outstr)
- outstr="(null)";
- }
- else if (c == '%') {
- /* queue it verbatim */
- continue;
- }
- else {
- /* modifiers or final 0 */
- if (c == 'l') {
- /* long format prefix, maintain the escape */
- lpref++;
- }
- escape = 1;
- goto do_escape;
- }
- len = strlen(outstr);
- goto flush_str;
- }
-
- /* not an escape sequence */
- if (c == 0 || c == '%') {
- /* flush pending data on escape or end */
- escape = 1;
- lpref = 0;
- outstr = fmt;
- len = ofs - 1;
- flush_str:
- if (_fwrite(outstr, len, stream) != 0)
- break;
-
- written += len;
- do_escape:
- if (c == 0)
- break;
- fmt += ofs;
- ofs = 0;
- continue;
- }
-
- /* literal char, just queue it */
- }
- return written;
-}
-
-static __attribute__((unused))
-int fprintf(FILE *stream, const char *fmt, ...)
-{
- va_list args;
- int ret;
-
- va_start(args, fmt);
- ret = vfprintf(stream, fmt, args);
- va_end(args);
- return ret;
-}
-
-static __attribute__((unused))
-int printf(const char *fmt, ...)
-{
- va_list args;
- int ret;
-
- va_start(args, fmt);
- ret = vfprintf(stdout, fmt, args);
- va_end(args);
- return ret;
-}
-
-static __attribute__((unused))
-void perror(const char *msg)
-{
- fprintf(stderr, "%s%serrno=%d\n", (msg && *msg) ? msg : "", (msg && *msg) ? ": " : "", errno);
-}
+#endif
-#endif /* _NOLIBC_STDIO_H */
diff --git a/kernel/include/klibc/stdlib.h b/kernel/include/klibc/stdlib.h
@@ -1,353 +0,0 @@
-/*
- * stdlib function definitions for NOLIBC
- * Copyright (C) 2017-2021 Willy Tarreau <w@1wt.eu>
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
- * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
- * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
- * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- */
-
-#ifndef _NOLIBC_STDLIB_H
-#define _NOLIBC_STDLIB_H
-
-#include "std.h"
-#include "arch.h"
-#include "types.h"
-#include "sys.h"
-
-
-/* Buffer used to store int-to-ASCII conversions. Will only be implemented if
- * any of the related functions is implemented. The area is large enough to
- * store "18446744073709551615" or "-9223372036854775808" and the final zero.
- */
-static __attribute__((unused)) char itoa_buffer[21];
-
-/*
- * As much as possible, please keep functions alphabetically sorted.
- */
-
-/* must be exported, as it's used by libgcc for various divide functions */
-__attribute__((weak,unused,noreturn,section(".text.nolibc_abort")))
-void abort(void)
-{
- sys_kill(sys_getpid(), SIGABRT);
- for (;;);
-}
-
-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);
-}
-
-/* Tries to find the environment variable named <name> in the environment array
- * pointed to by global variable "environ" which must be declared as a char **,
- * and must be terminated by a NULL (it is recommended to set this variable to
- * the "envp" argument of main()). If the requested environment variable exists
- * its value is returned otherwise NULL is returned.
- */
-static __attribute__((unused))
-char *getenv(const char *name)
-{
- extern char **environ;
- int idx, i;
-
- if (environ) {
- for (idx = 0; environ[idx]; idx++) {
- for (i = 0; name[i] && name[i] == environ[idx][i];)
- i++;
- if (!name[i] && environ[idx][i] == '=')
- return &environ[idx][i+1];
- }
- }
- return NULL;
-}
-
-/* Converts the unsigned long integer <in> to its hex representation into
- * buffer <buffer>, which must be long enough to store the number and the
- * trailing zero (17 bytes for "ffffffffffffffff" or 9 for "ffffffff"). The
- * buffer is filled from the first byte, and the number of characters emitted
- * (not counting the trailing zero) is returned. The function is constructed
- * in a way to optimize the code size and avoid any divide that could add a
- * dependency on large external functions.
- */
-static __attribute__((unused))
-int utoh_r(unsigned long in, char *buffer)
-{
- signed char pos = (~0UL > 0xfffffffful) ? 60 : 28;
- int digits = 0;
- int dig;
-
- do {
- dig = in >> pos;
- in -= (uint64_t)dig << pos;
- pos -= 4;
- if (dig || digits || pos < 0) {
- if (dig > 9)
- dig += 'a' - '0' - 10;
- buffer[digits++] = '0' + dig;
- }
- } while (pos >= 0);
-
- buffer[digits] = 0;
- return digits;
-}
-
-/* converts unsigned long <in> to an hex string using the static itoa_buffer
- * and returns the pointer to that string.
- */
-static inline __attribute__((unused))
-char *utoh(unsigned long in)
-{
- utoh_r(in, itoa_buffer);
- return itoa_buffer;
-}
-
-/* Converts the unsigned long integer <in> to its string representation into
- * buffer <buffer>, which must be long enough to store the number and the
- * trailing zero (21 bytes for 18446744073709551615 in 64-bit, 11 for
- * 4294967295 in 32-bit). The buffer is filled from the first byte, and the
- * number of characters emitted (not counting the trailing zero) is returned.
- * The function is constructed in a way to optimize the code size and avoid
- * any divide that could add a dependency on large external functions.
- */
-static __attribute__((unused))
-int utoa_r(unsigned long in, char *buffer)
-{
- unsigned long lim;
- int digits = 0;
- int pos = (~0UL > 0xfffffffful) ? 19 : 9;
- int dig;
-
- do {
- for (dig = 0, lim = 1; dig < pos; dig++)
- lim *= 10;
-
- if (digits || in >= lim || !pos) {
- for (dig = 0; in >= lim; dig++)
- in -= lim;
- buffer[digits++] = '0' + dig;
- }
- } while (pos--);
-
- buffer[digits] = 0;
- return digits;
-}
-
-/* Converts the signed long integer <in> to its string representation into
- * buffer <buffer>, which must be long enough to store the number and the
- * trailing zero (21 bytes for -9223372036854775808 in 64-bit, 12 for
- * -2147483648 in 32-bit). The buffer is filled from the first byte, and the
- * number of characters emitted (not counting the trailing zero) is returned.
- */
-static __attribute__((unused))
-int itoa_r(long in, char *buffer)
-{
- char *ptr = buffer;
- int len = 0;
-
- if (in < 0) {
- in = -in;
- *(ptr++) = '-';
- len++;
- }
- len += utoa_r(in, ptr);
- return len;
-}
-
-/* for historical compatibility, same as above but returns the pointer to the
- * buffer.
- */
-static inline __attribute__((unused))
-char *ltoa_r(long in, char *buffer)
-{
- itoa_r(in, buffer);
- return buffer;
-}
-
-/* converts long integer <in> to a string using the static itoa_buffer and
- * returns the pointer to that string.
- */
-static inline __attribute__((unused))
-char *itoa(long in)
-{
- itoa_r(in, itoa_buffer);
- return itoa_buffer;
-}
-
-/* converts long integer <in> to a string using the static itoa_buffer and
- * returns the pointer to that string. Same as above, for compatibility.
- */
-static inline __attribute__((unused))
-char *ltoa(long in)
-{
- itoa_r(in, itoa_buffer);
- return itoa_buffer;
-}
-
-/* converts unsigned long integer <in> to a string using the static itoa_buffer
- * and returns the pointer to that string.
- */
-static inline __attribute__((unused))
-char *utoa(unsigned long in)
-{
- utoa_r(in, itoa_buffer);
- return itoa_buffer;
-}
-
-/* Converts the unsigned 64-bit integer <in> to its hex representation into
- * buffer <buffer>, which must be long enough to store the number and the
- * trailing zero (17 bytes for "ffffffffffffffff"). The buffer is filled from
- * the first byte, and the number of characters emitted (not counting the
- * trailing zero) is returned. The function is constructed in a way to optimize
- * the code size and avoid any divide that could add a dependency on large
- * external functions.
- */
-static __attribute__((unused))
-int u64toh_r(uint64_t in, char *buffer)
-{
- signed char pos = 60;
- int digits = 0;
- int dig;
-
- do {
- if (sizeof(long) >= 8) {
- dig = (in >> pos) & 0xF;
- } else {
- /* 32-bit platforms: avoid a 64-bit shift */
- uint32_t d = (pos >= 32) ? (in >> 32) : in;
- dig = (d >> (pos & 31)) & 0xF;
- }
- if (dig > 9)
- dig += 'a' - '0' - 10;
- pos -= 4;
- if (dig || digits || pos < 0)
- buffer[digits++] = '0' + dig;
- } while (pos >= 0);
-
- buffer[digits] = 0;
- return digits;
-}
-
-/* converts uint64_t <in> to an hex string using the static itoa_buffer and
- * returns the pointer to that string.
- */
-static inline __attribute__((unused))
-char *u64toh(uint64_t in)
-{
- u64toh_r(in, itoa_buffer);
- return itoa_buffer;
-}
-
-/* Converts the unsigned 64-bit integer <in> to its string representation into
- * buffer <buffer>, which must be long enough to store the number and the
- * trailing zero (21 bytes for 18446744073709551615). The buffer is filled from
- * the first byte, and the number of characters emitted (not counting the
- * trailing zero) is returned. The function is constructed in a way to optimize
- * the code size and avoid any divide that could add a dependency on large
- * external functions.
- */
-static __attribute__((unused))
-int u64toa_r(uint64_t in, char *buffer)
-{
- unsigned long long lim;
- int digits = 0;
- int pos = 19; /* start with the highest possible digit */
- int dig;
-
- do {
- for (dig = 0, lim = 1; dig < pos; dig++)
- lim *= 10;
-
- if (digits || in >= lim || !pos) {
- for (dig = 0; in >= lim; dig++)
- in -= lim;
- buffer[digits++] = '0' + dig;
- }
- } while (pos--);
-
- buffer[digits] = 0;
- return digits;
-}
-
-/* Converts the signed 64-bit integer <in> to its string representation into
- * buffer <buffer>, which must be long enough to store the number and the
- * trailing zero (21 bytes for -9223372036854775808). The buffer is filled from
- * the first byte, and the number of characters emitted (not counting the
- * trailing zero) is returned.
- */
-static __attribute__((unused))
-int i64toa_r(int64_t in, char *buffer)
-{
- char *ptr = buffer;
- int len = 0;
-
- if (in < 0) {
- in = -in;
- *(ptr++) = '-';
- len++;
- }
- len += u64toa_r(in, ptr);
- return len;
-}
-
-/* converts int64_t <in> to a string using the static itoa_buffer and returns
- * the pointer to that string.
- */
-static inline __attribute__((unused))
-char *i64toa(int64_t in)
-{
- i64toa_r(in, itoa_buffer);
- return itoa_buffer;
-}
-
-/* converts uint64_t <in> to a string using the static itoa_buffer and returns
- * the pointer to that string.
- */
-static inline __attribute__((unused))
-char *u64toa(uint64_t in)
-{
- u64toa_r(in, itoa_buffer);
- return itoa_buffer;
-}
-
-#endif /* _NOLIBC_STDLIB_H */
diff --git a/kernel/include/klibc/string.h b/kernel/include/klibc/string.h
@@ -1,231 +1,14 @@
-/*
- * string function definitions for NOLIBC
- * Copyright (C) 2017-2021 Willy Tarreau <w@1wt.eu>
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
- * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
- * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
- * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- */
+#ifndef _STRING_H
+#define _STRING_H 1
-#ifndef _NOLIBC_STRING_H
-#define _NOLIBC_STRING_H
+#include <klibc/sys/cdefs.h>
-#include "std.h"
+#include <stddef.h>
-/*
- * As much as possible, please keep functions alphabetically sorted.
- */
+int memcmp(const void*, const void*, size_t);
+void* memcpy(void* __restrict, const void* __restrict, size_t);
+void* memmove(void*, const void*, size_t);
+void* memset(void*, int, size_t);
+size_t strlen(const char*);
-static __attribute__((unused))
-int memcmp(const void *s1, const void *s2, size_t n)
-{
- size_t ofs = 0;
- char c1 = 0;
-
- while (ofs < n && !(c1 = ((char *)s1)[ofs] - ((char *)s2)[ofs])) {
- ofs++;
- }
- return c1;
-}
-
-static __attribute__((unused))
-void *_nolibc_memcpy_up(void *dst, const void *src, size_t len)
-{
- size_t pos = 0;
-
- while (pos < len) {
- ((char *)dst)[pos] = ((const char *)src)[pos];
- pos++;
- }
- return dst;
-}
-
-static __attribute__((unused))
-void *_nolibc_memcpy_down(void *dst, const void *src, size_t len)
-{
- while (len) {
- len--;
- ((char *)dst)[len] = ((const char *)src)[len];
- }
- return dst;
-}
-
-/* might be ignored by the compiler without -ffreestanding, then found as
- * missing.
- */
-__attribute__((weak,unused,section(".text.nolibc_memmove")))
-void *memmove(void *dst, const void *src, size_t len)
-{
- size_t dir, pos;
-
- pos = len;
- dir = -1;
-
- if (dst < src) {
- pos = -1;
- dir = 1;
- }
-
- while (len) {
- pos += dir;
- ((char *)dst)[pos] = ((const char *)src)[pos];
- len--;
- }
- return dst;
-}
-
-/* must be exported, as it's used by libgcc on ARM */
-__attribute__((weak,unused,section(".text.nolibc_memcpy")))
-void *memcpy(void *dst, const void *src, size_t len)
-{
- return _nolibc_memcpy_up(dst, src, len);
-}
-
-/* might be ignored by the compiler without -ffreestanding, then found as
- * missing.
- */
-__attribute__((weak,unused,section(".text.nolibc_memset")))
-void *memset(void *dst, int b, size_t len)
-{
- char *p = dst;
-
- while (len--)
- *(p++) = b;
- return dst;
-}
-
-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 *strcpy(char *dst, const char *src)
-{
- char *ret = dst;
-
- while ((*dst++ = *src++));
- return ret;
-}
-
-/* this function is only used with arguments that are not constants */
-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))
-size_t strlcat(char *dst, const char *src, size_t size)
-{
- size_t len;
- char c;
-
- for (len = 0; dst[len]; len++)
- ;
-
- for (;;) {
- c = *src;
- if (len < size)
- dst[len] = c;
- if (!c)
- break;
- len++;
- src++;
- }
-
- return len;
-}
-
-static __attribute__((unused))
-size_t strlcpy(char *dst, const char *src, size_t size)
-{
- size_t len;
- char c;
-
- for (len = 0;;) {
- c = src[len];
- if (len < size)
- dst[len] = c;
- if (!c)
- break;
- len++;
- }
- return len;
-}
-
-static __attribute__((unused))
-char *strncat(char *dst, const char *src, size_t size)
-{
- char *orig = dst;
-
- while (*dst)
- dst++;
-
- while (size && (*dst = *src)) {
- src++;
- dst++;
- size--;
- }
-
- *dst = 0;
- return orig;
-}
-
-
-static __attribute__((unused))
-char *strncpy(char *dst, const char *src, size_t size)
-{
- size_t len;
-
- for (len = 0; len < size; len++)
- if ((dst[len] = *src))
- src++;
- return dst;
-}
-
-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;
-}
-
-#endif /* _NOLIBC_STRING_H */
+#endif
diff --git a/kernel/include/klibc/sys.h b/kernel/include/klibc/sys.h
@@ -1,1187 +0,0 @@
-/*
- * Syscall definitions for NOLIBC (those in man(2))
- * Copyright (C) 2017-2021 Willy Tarreau <w@1wt.eu>
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
- * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
- * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
- * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- */
-
-#ifndef _NOLIBC_SYS_H
-#define _NOLIBC_SYS_H
-
-#include <stdarg.h>
-#include "std.h"
-
-/* system includes */
-#include <asm/unistd.h>
-#include <asm/signal.h> // for SIGCHLD
-#include <asm/ioctls.h>
-#include <linux/fs.h>
-#include <linux/loop.h>
-#include <linux/time.h>
-
-#include "arch.h"
-#include "errno.h"
-#include "types.h"
-
-
-/* Functions in this file only describe syscalls. They're declared static so
- * that the compiler usually decides to inline them while still being allowed
- * to pass a pointer to one of their instances. Each syscall exists in two
- * versions:
- * - the "internal" ones, which matches the raw syscall interface at the
- * kernel level, which may sometimes slightly differ from the documented
- * libc-level ones. For example most of them return either a valid value
- * or -errno. All of these are prefixed with "sys_". They may be called
- * by non-portable applications if desired.
- *
- * - the "exported" ones, whose interface must closely match the one
- * documented in man(2), that applications are supposed to expect. These
- * ones rely on the internal ones, and set errno.
- *
- * Each syscall will be defined with the two functions, sorted in alphabetical
- * order applied to the exported names.
- *
- * In case of doubt about the relevance of a function here, only those which
- * set errno should be defined here. Wrappers like those appearing in man(3)
- * should not be placed here.
- */
-
-
-/*
- * int brk(void *addr);
- * void *sbrk(intptr_t inc)
- */
-
-static __attribute__((unused))
-void *sys_brk(void *addr)
-{
- return (void *)my_syscall1(__NR_brk, addr);
-}
-
-static __attribute__((unused))
-int brk(void *addr)
-{
- void *ret = sys_brk(addr);
-
- if (!ret) {
- SET_ERRNO(ENOMEM);
- return -1;
- }
- return 0;
-}
-
-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;
-}
-
-
-/*
- * int chdir(const char *path);
- */
-
-static __attribute__((unused))
-int sys_chdir(const char *path)
-{
- return my_syscall1(__NR_chdir, path);
-}
-
-static __attribute__((unused))
-int chdir(const char *path)
-{
- int ret = sys_chdir(path);
-
- if (ret < 0) {
- SET_ERRNO(-ret);
- ret = -1;
- }
- return ret;
-}
-
-
-/*
- * int chmod(const char *path, mode_t mode);
- */
-
-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 chmod(const char *path, mode_t mode)
-{
- int ret = sys_chmod(path, mode);
-
- if (ret < 0) {
- SET_ERRNO(-ret);
- ret = -1;
- }
- return ret;
-}
-
-
-/*
- * int chown(const char *path, uid_t owner, gid_t group);
- */
-
-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 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;
-}
-
-
-/*
- * int chroot(const char *path);
- */
-
-static __attribute__((unused))
-int sys_chroot(const char *path)
-{
- return my_syscall1(__NR_chroot, path);
-}
-
-static __attribute__((unused))
-int chroot(const char *path)
-{
- int ret = sys_chroot(path);
-
- if (ret < 0) {
- SET_ERRNO(-ret);
- ret = -1;
- }
- return ret;
-}
-
-
-/*
- * int close(int fd);
- */
-
-static __attribute__((unused))
-int sys_close(int fd)
-{
- return my_syscall1(__NR_close, fd);
-}
-
-static __attribute__((unused))
-int close(int fd)
-{
- int ret = sys_close(fd);
-
- if (ret < 0) {
- SET_ERRNO(-ret);
- ret = -1;
- }
- return ret;
-}
-
-
-/*
- * int dup(int fd);
- */
-
-static __attribute__((unused))
-int sys_dup(int fd)
-{
- return my_syscall1(__NR_dup, fd);
-}
-
-static __attribute__((unused))
-int dup(int fd)
-{
- int ret = sys_dup(fd);
-
- if (ret < 0) {
- SET_ERRNO(-ret);
- ret = -1;
- }
- return ret;
-}
-
-
-/*
- * int dup2(int old, int new);
- */
-
-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 dup2(int old, int new)
-{
- int ret = sys_dup2(old, new);
-
- if (ret < 0) {
- SET_ERRNO(-ret);
- ret = -1;
- }
- return ret;
-}
-
-
-/*
- * int dup3(int old, int new, int flags);
- */
-
-#ifdef __NR_dup3
-static __attribute__((unused))
-int sys_dup3(int old, int new, int flags)
-{
- return my_syscall3(__NR_dup3, old, new, flags);
-}
-
-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
-
-
-/*
- * int execve(const char *filename, char *const argv[], char *const envp[]);
- */
-
-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))
-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;
-}
-
-
-/*
- * void exit(int status);
- */
-
-static __attribute__((noreturn,unused))
-void sys_exit(int status)
-{
- my_syscall1(__NR_exit, status & 255);
- while(1); // shut the "noreturn" warnings.
-}
-
-static __attribute__((noreturn,unused))
-void exit(int status)
-{
- sys_exit(status);
-}
-
-
-/*
- * pid_t fork(void);
- */
-
-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))
-pid_t fork(void)
-{
- pid_t ret = sys_fork();
-
- if (ret < 0) {
- SET_ERRNO(-ret);
- ret = -1;
- }
- return ret;
-}
-
-
-/*
- * int fsync(int fd);
- */
-
-static __attribute__((unused))
-int sys_fsync(int fd)
-{
- return my_syscall1(__NR_fsync, fd);
-}
-
-static __attribute__((unused))
-int fsync(int fd)
-{
- int ret = sys_fsync(fd);
-
- if (ret < 0) {
- SET_ERRNO(-ret);
- ret = -1;
- }
- return ret;
-}
-
-
-/*
- * int getdents64(int fd, struct linux_dirent64 *dirp, int count);
- */
-
-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))
-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;
-}
-
-
-/*
- * pid_t getpgid(pid_t pid);
- */
-
-static __attribute__((unused))
-pid_t sys_getpgid(pid_t pid)
-{
- return my_syscall1(__NR_getpgid, pid);
-}
-
-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;
-}
-
-
-/*
- * pid_t getpgrp(void);
- */
-
-static __attribute__((unused))
-pid_t sys_getpgrp(void)
-{
- return sys_getpgid(0);
-}
-
-static __attribute__((unused))
-pid_t getpgrp(void)
-{
- return sys_getpgrp();
-}
-
-
-/*
- * pid_t getpid(void);
- */
-
-static __attribute__((unused))
-pid_t sys_getpid(void)
-{
- return my_syscall0(__NR_getpid);
-}
-
-static __attribute__((unused))
-pid_t getpid(void)
-{
- return sys_getpid();
-}
-
-
-/*
- * pid_t gettid(void);
- */
-
-static __attribute__((unused))
-pid_t sys_gettid(void)
-{
- return my_syscall0(__NR_gettid);
-}
-
-static __attribute__((unused))
-pid_t gettid(void)
-{
- return sys_gettid();
-}
-
-
-/*
- * int gettimeofday(struct timeval *tv, struct timezone *tz);
- */
-
-static __attribute__((unused))
-int sys_gettimeofday(struct timeval *tv, struct timezone *tz)
-{
- return my_syscall2(__NR_gettimeofday, tv, tz);
-}
-
-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;
-}
-
-
-/*
- * int ioctl(int fd, unsigned long req, void *value);
- */
-
-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 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;
-}
-
-/*
- * int kill(pid_t pid, int signal);
- */
-
-static __attribute__((unused))
-int sys_kill(pid_t pid, int signal)
-{
- return my_syscall2(__NR_kill, pid, signal);
-}
-
-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;
-}
-
-
-/*
- * int link(const char *old, const char *new);
- */
-
-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))
-int link(const char *old, const char *new)
-{
- int ret = sys_link(old, new);
-
- if (ret < 0) {
- SET_ERRNO(-ret);
- ret = -1;
- }
- return ret;
-}
-
-
-/*
- * off_t lseek(int fd, off_t offset, int whence);
- */
-
-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))
-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;
-}
-
-
-/*
- * int mkdir(const char *path, mode_t mode);
- */
-
-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))
-int mkdir(const char *path, mode_t mode)
-{
- int ret = sys_mkdir(path, mode);
-
- if (ret < 0) {
- SET_ERRNO(-ret);
- ret = -1;
- }
- return ret;
-}
-
-
-/*
- * int mknod(const char *path, mode_t mode, dev_t dev);
- */
-
-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 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;
-}
-
-
-/*
- * int mount(const char *source, const char *target,
- * const char *fstype, unsigned long flags,
- * const void *data);
- */
-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 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;
-}
-
-
-/*
- * int open(const char *path, int flags[, mode_t mode]);
- */
-
-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 open(const char *path, int flags, ...)
-{
- mode_t mode = 0;
- int ret;
-
- if (flags & O_CREAT) {
- va_list args;
-
- va_start(args, flags);
- mode = va_arg(args, mode_t);
- va_end(args);
- }
-
- ret = sys_open(path, flags, mode);
-
- if (ret < 0) {
- SET_ERRNO(-ret);
- ret = -1;
- }
- return ret;
-}
-
-
-/*
- * int pivot_root(const char *new, const char *old);
- */
-
-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 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;
-}
-
-
-/*
- * int poll(struct pollfd *fds, int nfds, int timeout);
- */
-
-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))
-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;
-}
-
-
-/*
- * ssize_t read(int fd, void *buf, size_t count);
- */
-
-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 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;
-}
-
-
-/*
- * int reboot(int cmd);
- * <cmd> is among LINUX_REBOOT_CMD_*
- */
-
-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 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;
-}
-
-
-/*
- * int sched_yield(void);
- */
-
-static __attribute__((unused))
-int sys_sched_yield(void)
-{
- return my_syscall0(__NR_sched_yield);
-}
-
-static __attribute__((unused))
-int sched_yield(void)
-{
- int ret = sys_sched_yield();
-
- if (ret < 0) {
- SET_ERRNO(-ret);
- ret = -1;
- }
- return ret;
-}
-
-
-/*
- * int select(int nfds, fd_set *read_fds, fd_set *write_fds,
- * fd_set *except_fds, struct timeval *timeout);
- */
-
-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 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;
-}
-
-
-/*
- * int setpgid(pid_t pid, pid_t pgid);
- */
-
-static __attribute__((unused))
-int sys_setpgid(pid_t pid, pid_t pgid)
-{
- return my_syscall2(__NR_setpgid, pid, pgid);
-}
-
-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;
-}
-
-
-/*
- * pid_t setsid(void);
- */
-
-static __attribute__((unused))
-pid_t sys_setsid(void)
-{
- return my_syscall0(__NR_setsid);
-}
-
-static __attribute__((unused))
-pid_t setsid(void)
-{
- pid_t ret = sys_setsid();
-
- if (ret < 0) {
- SET_ERRNO(-ret);
- ret = -1;
- }
- return ret;
-}
-
-
-/*
- * int stat(const char *path, struct stat *buf);
- * Warning: the struct stat's layout is arch-dependent.
- */
-
-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 stat(const char *path, struct stat *buf)
-{
- int ret = sys_stat(path, buf);
-
- if (ret < 0) {
- SET_ERRNO(-ret);
- ret = -1;
- }
- return ret;
-}
-
-
-/*
- * int symlink(const char *old, const char *new);
- */
-
-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))
-int symlink(const char *old, const char *new)
-{
- int ret = sys_symlink(old, new);
-
- if (ret < 0) {
- SET_ERRNO(-ret);
- ret = -1;
- }
- return ret;
-}
-
-
-/*
- * mode_t umask(mode_t mode);
- */
-
-static __attribute__((unused))
-mode_t sys_umask(mode_t mode)
-{
- return my_syscall1(__NR_umask, mode);
-}
-
-static __attribute__((unused))
-mode_t umask(mode_t mode)
-{
- return sys_umask(mode);
-}
-
-
-/*
- * int umount2(const char *path, int flags);
- */
-
-static __attribute__((unused))
-int sys_umount2(const char *path, int flags)
-{
- return my_syscall2(__NR_umount2, path, flags);
-}
-
-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;
-}
-
-
-/*
- * int unlink(const char *path);
- */
-
-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))
-int unlink(const char *path)
-{
- int ret = sys_unlink(path);
-
- if (ret < 0) {
- SET_ERRNO(-ret);
- ret = -1;
- }
- return ret;
-}
-
-
-/*
- * pid_t wait(int *status);
- * pid_t wait4(pid_t pid, int *status, int options, struct rusage *rusage);
- * pid_t waitpid(pid_t pid, int *status, int options);
- */
-
-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 wait(int *status)
-{
- pid_t ret = sys_wait4(-1, status, 0, NULL);
-
- 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_wait4(pid, status, options, NULL);
-
- if (ret < 0) {
- SET_ERRNO(-ret);
- ret = -1;
- }
- return ret;
-}
-
-
-/*
- * ssize_t write(int fd, const void *buf, size_t count);
- */
-
-static __attribute__((unused))
-ssize_t sys_write(int fd, const void *buf, size_t count)
-{
- return my_syscall3(__NR_write, fd, buf, count);
-}
-
-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;
-}
-
-
-#endif /* _NOLIBC_SYS_H */
diff --git a/kernel/include/klibc/sys/cdefs.h b/kernel/include/klibc/sys/cdefs.h
@@ -0,0 +1,6 @@
+#ifndef _SYS_CDEFS_H
+#define _SYS_CDEFS_H 1
+
+#define __cow_libc 1
+
+#endif
diff --git a/kernel/include/klibc/time.h b/kernel/include/klibc/time.h
@@ -1,47 +0,0 @@
-/*
- * time function definitions for NOLIBC
- * Copyright (C) 2017-2022 Willy Tarreau <w@1wt.eu>
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
- * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
- * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
- * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- */
-
-#ifndef _NOLIBC_TIME_H
-#define _NOLIBC_TIME_H
-
-#include "std.h"
-#include "arch.h"
-#include "types.h"
-#include "sys.h"
-
-static __attribute__((unused))
-time_t time(time_t *tptr)
-{
- struct timeval tv;
-
- /* note, cannot fail here */
- sys_gettimeofday(&tv, NULL);
-
- if (tptr)
- *tptr = tv.tv_sec;
- return tv.tv_sec;
-}
-
-#endif /* _NOLIBC_TIME_H */
diff --git a/kernel/include/klibc/types.h b/kernel/include/klibc/types.h
@@ -1,203 +0,0 @@
-/*
- * Special types used by various syscalls for NOLIBC
- * Copyright (C) 2017-2021 Willy Tarreau <w@1wt.eu>
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
- * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
- * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
- * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- */
-
-#ifndef _NOLIBC_TYPES_H
-#define _NOLIBC_TYPES_H
-
-#include "std.h"
-#include <linux/time.h>
-
-
-/* Only the generic macros and types may be defined here. The arch-specific
- * ones such as the O_RDONLY and related macros used by fcntl() and open(), or
- * the layout of sys_stat_struct must not be defined here.
- */
-
-/* stat flags (WARNING, octal here) */
-#define S_IFDIR 0040000
-#define S_IFCHR 0020000
-#define S_IFBLK 0060000
-#define S_IFREG 0100000
-#define S_IFIFO 0010000
-#define S_IFLNK 0120000
-#define S_IFSOCK 0140000
-#define S_IFMT 0170000
-
-#define S_ISDIR(mode) (((mode) & S_IFDIR) == S_IFDIR)
-#define S_ISCHR(mode) (((mode) & S_IFCHR) == S_IFCHR)
-#define S_ISBLK(mode) (((mode) & S_IFBLK) == S_IFBLK)
-#define S_ISREG(mode) (((mode) & S_IFREG) == S_IFREG)
-#define S_ISFIFO(mode) (((mode) & S_IFIFO) == S_IFIFO)
-#define S_ISLNK(mode) (((mode) & S_IFLNK) == S_IFLNK)
-#define S_ISSOCK(mode) (((mode) & S_IFSOCK) == S_IFSOCK)
-
-/* dirent types */
-#define DT_UNKNOWN 0x0
-#define DT_FIFO 0x1
-#define DT_CHR 0x2
-#define DT_DIR 0x4
-#define DT_BLK 0x6
-#define DT_REG 0x8
-#define DT_LNK 0xa
-#define DT_SOCK 0xc
-
-/* commonly an fd_set represents 256 FDs */
-#ifndef FD_SETSIZE
-#define FD_SETSIZE 256
-#endif
-
-/* PATH_MAX and MAXPATHLEN are often used and found with plenty of different
- * values.
- */
-#ifndef PATH_MAX
-#define PATH_MAX 4096
-#endif
-
-#ifndef MAXPATHLEN
-#define MAXPATHLEN (PATH_MAX)
-#endif
-
-/* Special FD used by all the *at functions */
-#ifndef AT_FDCWD
-#define AT_FDCWD (-100)
-#endif
-
-/* whence values for lseek() */
-#define SEEK_SET 0
-#define SEEK_CUR 1
-#define SEEK_END 2
-
-/* cmd for reboot() */
-#define LINUX_REBOOT_MAGIC1 0xfee1dead
-#define LINUX_REBOOT_MAGIC2 0x28121969
-#define LINUX_REBOOT_CMD_HALT 0xcdef0123
-#define LINUX_REBOOT_CMD_POWER_OFF 0x4321fedc
-#define LINUX_REBOOT_CMD_RESTART 0x01234567
-#define LINUX_REBOOT_CMD_SW_SUSPEND 0xd000fce2
-
-/* Macros used on waitpid()'s return status */
-#define WEXITSTATUS(status) (((status) & 0xff00) >> 8)
-#define WIFEXITED(status) (((status) & 0x7f) == 0)
-
-/* standard exit() codes */
-#define EXIT_SUCCESS 0
-#define EXIT_FAILURE 1
-
-/* for select() */
-typedef struct {
- uint32_t fd32[(FD_SETSIZE + 31) / 32];
-} fd_set;
-
-#define FD_CLR(fd, set) do { \
- fd_set *__set = (set); \
- int __fd = (fd); \
- if (__fd >= 0) \
- __set->fd32[__fd / 32] &= ~(1U << (__fd & 31)); \
- } while (0)
-
-#define FD_SET(fd, set) do { \
- fd_set *__set = (set); \
- int __fd = (fd); \
- if (__fd >= 0) \
- __set->fd32[__fd / 32] |= 1U << (__fd & 31); \
- } while (0)
-
-#define FD_ISSET(fd, set) ({ \
- fd_set *__set = (set); \
- int __fd = (fd); \
- int __r = 0; \
- if (__fd >= 0) \
- __r = !!(__set->fd32[__fd / 32] & 1U << (__fd & 31)); \
- __r; \
- })
-
-#define FD_ZERO(set) do { \
- fd_set *__set = (set); \
- int __idx; \
- for (__idx = 0; __idx < (FD_SETSIZE+31) / 32; __idx ++) \
- __set->fd32[__idx] = 0; \
- } while (0)
-
-/* for poll() */
-struct pollfd {
- int fd;
- short int events;
- short int revents;
-};
-
-/* for getdents64() */
-struct linux_dirent64 {
- uint64_t d_ino;
- int64_t d_off;
- unsigned short d_reclen;
- unsigned char d_type;
- char d_name[];
-};
-
-/* needed by wait4() */
-struct rusage {
- struct timeval ru_utime;
- struct timeval ru_stime;
- long ru_maxrss;
- long ru_ixrss;
- long ru_idrss;
- long ru_isrss;
- long ru_minflt;
- long ru_majflt;
- long ru_nswap;
- long ru_inblock;
- long ru_oublock;
- long ru_msgsnd;
- long ru_msgrcv;
- long ru_nsignals;
- long ru_nvcsw;
- long ru_nivcsw;
-};
-
-/* The format of the struct as returned by the libc to the application, which
- * significantly differs from the format returned by the stat() syscall flavours.
- */
-struct stat {
- dev_t st_dev; /* ID of device containing file */
- ino_t st_ino; /* inode number */
- mode_t st_mode; /* protection */
- nlink_t st_nlink; /* number of hard links */
- uid_t st_uid; /* user ID of owner */
- gid_t st_gid; /* group ID of owner */
- dev_t st_rdev; /* device ID (if special file) */
- off_t st_size; /* total size, in bytes */
- blksize_t st_blksize; /* blocksize for file system I/O */
- blkcnt_t st_blocks; /* number of 512B blocks allocated */
- time_t st_atime; /* time of last access */
- time_t st_mtime; /* time of last modification */
- time_t st_ctime; /* time of last status change */
-};
-
-/* WARNING, it only deals with the 4096 first majors and 256 first minors */
-#define makedev(major, minor) ((dev_t)((((major) & 0xfff) << 8) | ((minor) & 0xff)))
-#define major(dev) ((unsigned int)(((dev) >> 8) & 0xfff))
-#define minor(dev) ((unsigned int)(((dev) & 0xff))
-
-#endif /* _NOLIBC_TYPES_H */
diff --git a/kernel/include/klibc/unistd.h b/kernel/include/klibc/unistd.h
@@ -1,73 +0,0 @@
-/*
- * unistd function definitions for NOLIBC
- * Copyright (C) 2017-2022 Willy Tarreau <w@1wt.eu>
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
- * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
- * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
- * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- */
-
-#ifndef _NOLIBC_UNISTD_H
-#define _NOLIBC_UNISTD_H
-
-#include "std.h"
-#include "arch.h"
-#include "types.h"
-#include "sys.h"
-
-
-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))
-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 usleep(unsigned int usecs)
-{
- struct timeval my_timeval = { usecs / 1000000, usecs % 1000000 };
-
- return sys_select(0, 0, 0, 0, &my_timeval);
-}
-
-static __attribute__((unused))
-int tcsetpgrp(int fd, pid_t pid)
-{
- return ioctl(fd, TIOCSPGRP, &pid);
-}
-
-#endif /* _NOLIBC_UNISTD_H */
diff --git a/kernel/klibc/stdio.c b/kernel/klibc/stdio.c
@@ -0,0 +1,100 @@
+#include <limits.h>
+#include <stdarg.h>
+/* #include <tty.h> */
+#include <klibc/stdio.h>
+#include <klibc/string.h>
+
+/* returns 1 for true, adhering to suckless */
+static int
+print(const char* data, size_t length)
+{
+ const unsigned char* bytes = (const unsigned char*) data;
+ for (size_t i = 0; i < length; i++) {
+ if (putchar(bytes[i]) == EOF) {
+ return 0;
+ }
+ }
+ return 1;
+}
+
+/* todo: set errno to eoverflow for some cases in which errno should not be used */
+int
+printf(const char* restrict format, ...)
+{
+ va_list parameters;
+ va_start(parameters, format);
+
+ int written = 0;
+
+ while (*format != '\0') {
+ size_t maxrem = INT_MAX - written;
+
+ if (format[0] != '%' || format[1] == '%') {
+ if (format[0] == '%')
+ format++;
+ size_t amount = 1;
+ while (format[amount] && format[amount] != '%')
+ amount++;
+ if (maxrem < amount) {
+ return -1;
+ }
+ if (!print(format, amount))
+ return -1;
+ format += amount;
+ written += amount;
+ continue;
+ }
+
+ const char* format_begun_at = format++;
+
+ if (*format == 'c') {
+ format++;
+ char c = (char) va_arg(parameters, int /* char promotes to int */);
+ if (!maxrem) {
+ return -1;
+ }
+ if (!print(&c, sizeof(c))) {
+ return -1;
+ }
+ written++;
+ } else if (*format == 's') {
+ format++;
+ const char* str = va_arg(parameters, const char*);
+ size_t len = strlen(str);
+ if (maxrem < len) {
+ return -1;
+ }
+ if (!print(str, len)) {
+ return -1;
+ }
+ written += len;
+ } else {
+ format = format_begun_at;
+ size_t len = strlen(format);
+ if (maxrem < len) {
+ return -1;
+ }
+ if (!print(format, len)) {
+ return -1;
+ }
+ written += len;
+ format += len;
+ }
+ }
+
+ va_end(parameters);
+ return written;
+}
+
+/* todo: Implement stdio and the write system call. */
+int
+putchar(int ic)
+{
+ return ic;
+}
+
+int
+puts(const char* string)
+{
+ return printf("%s\n", string);
+}
diff --git a/kernel/klibc/string.c b/kernel/klibc/string.c
@@ -0,0 +1,62 @@
+#include <string.h>
+
+size_t
+strlen(const char* str)
+{
+ size_t len = 0;
+ while (str[len]) {
+ len++;
+ }
+ return len;
+}
+
+void*
+memset(void* bufptr, int value, size_t size)
+{
+ unsigned char* buf = (unsigned char*) bufptr;
+ for (size_t i = 0; i < size; i++) {
+ buf[i] = (unsigned char) value;
+ }
+ return bufptr;
+}
+
+void*
+memmove(void* dstptr, const void* srcptr, size_t size)
+{
+ unsigned char* dst = (unsigned char*) dstptr;
+ const unsigned char* src = (const unsigned char*) srcptr;
+ if (dst < src) {
+ for (size_t i = 0; i < size; i++)
+ dst[i] = src[i];
+ } else {
+ for (size_t i = size; i != 0; i--)
+ dst[i-1] = src[i-1];
+ }
+ return dstptr;
+}
+
+void*
+memcpy(void* restrict dstptr, const void* restrict srcptr, size_t size)
+{
+ unsigned char* dst = (unsigned char*) dstptr;
+ const unsigned char* src = (const unsigned char*) srcptr;
+ for (size_t i = 0; i < size; i++) {
+ dst[i] = src[i];
+ }
+ return dstptr;
+}
+
+int
+memcmp(const void* aptr, const void* bptr, size_t size)
+{
+ const unsigned char* a = (const unsigned char*) aptr;
+ const unsigned char* b = (const unsigned char*) bptr;
+ for (size_t i = 0; i < size; i++) {
+ if (a[i] < b[i]) {
+ return -1;
+ } else if (b[i] < a[i]) {
+ return 1;
+ }
+ }
+ return 0;
+}