mirror of
https://github.com/cowmonk/cowos.git
synced 2025-10-27 14:33:27 +00:00
cowos uses it's own cowlibc! big W
This commit is contained in:
parent
435b2bf2a0
commit
b08b0728ae
18 changed files with 188 additions and 3050 deletions
3
Makefile
3
Makefile
|
|
@ -14,7 +14,7 @@ iso: kernel limine
|
||||||
kernel:
|
kernel:
|
||||||
make -C ./kernel/ all
|
make -C ./kernel/ all
|
||||||
|
|
||||||
limine:
|
limine: kernel
|
||||||
git clone https://github.com/limine-bootloader/limine.git --branch=v9.x-binary --depth=1
|
git clone https://github.com/limine-bootloader/limine.git --branch=v9.x-binary --depth=1
|
||||||
make -C limine
|
make -C limine
|
||||||
|
|
||||||
|
|
@ -26,3 +26,4 @@ limine:
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm cowos.iso
|
rm cowos.iso
|
||||||
|
make -C ./kernel/ clean
|
||||||
|
|
|
||||||
|
|
@ -23,5 +23,4 @@ make
|
||||||
```
|
```
|
||||||
|
|
||||||
# Credits
|
# 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.
|
- [Limine](https://github.com/limine-bootloader/limine): modern, advanced, portable, multiprotocol bootloader and boot manager.
|
||||||
|
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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 */
|
|
||||||
|
|
@ -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 */
|
|
||||||
|
|
@ -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 */
|
|
||||||
|
|
@ -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 */
|
|
||||||
|
|
@ -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 */
|
|
||||||
|
|
@ -1,325 +1,13 @@
|
||||||
/*
|
#ifndef _STDIO_H
|
||||||
* minimal stdio function definitions for NOLIBC
|
#define _STDIO_H 1
|
||||||
* 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_STDIO_H
|
#include <klibc/sys/cdefs.h>
|
||||||
#define _NOLIBC_STDIO_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)
|
#define EOF (-1)
|
||||||
|
|
||||||
|
int printf(const char* __restrict, ...);
|
||||||
|
int putchar(int);
|
||||||
|
int puts(const char*);
|
||||||
|
|
||||||
#endif
|
#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;
|
|
||||||
|
|
||||||
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 /* _NOLIBC_STDIO_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 */
|
|
||||||
|
|
@ -1,231 +1,14 @@
|
||||||
/*
|
#ifndef _STRING_H
|
||||||
* string function definitions for NOLIBC
|
#define _STRING_H 1
|
||||||
* 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_STRING_H
|
#include <klibc/sys/cdefs.h>
|
||||||
#define _NOLIBC_STRING_H
|
|
||||||
|
|
||||||
#include "std.h"
|
#include <stddef.h>
|
||||||
|
|
||||||
/*
|
int memcmp(const void*, const void*, size_t);
|
||||||
* As much as possible, please keep functions alphabetically sorted.
|
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))
|
#endif
|
||||||
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 */
|
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
6
kernel/include/klibc/sys/cdefs.h
Normal file
6
kernel/include/klibc/sys/cdefs.h
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
#ifndef _SYS_CDEFS_H
|
||||||
|
#define _SYS_CDEFS_H 1
|
||||||
|
|
||||||
|
#define __cow_libc 1
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -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 */
|
|
||||||
|
|
@ -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 */
|
|
||||||
|
|
@ -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 */
|
|
||||||
100
kernel/klibc/stdio.c
Normal file
100
kernel/klibc/stdio.c
Normal file
|
|
@ -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);
|
||||||
|
}
|
||||||
62
kernel/klibc/string.c
Normal file
62
kernel/klibc/string.c
Normal file
|
|
@ -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;
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue