From d2f795624b73f35159e68369cf9fef542a025ee6 Mon Sep 17 00:00:00 2001 From: Youjie Zheng Date: Mon, 4 Nov 2024 15:16:56 +0800 Subject: [PATCH] [chore] Add axlibc for Starry --- .gitignore | 3 +- tools/axlibc/.gitignore | 22 + tools/axlibc/Cargo.toml | 64 ++ tools/axlibc/build.rs | 73 ++ tools/axlibc/c/assert.c | 8 + tools/axlibc/c/ctype.c | 17 + tools/axlibc/c/dirent.c | 98 ++ tools/axlibc/c/dlfcn.c | 39 + tools/axlibc/c/env.c | 31 + tools/axlibc/c/fcntl.c | 56 + tools/axlibc/c/flock.c | 9 + tools/axlibc/c/fnmatch.c | 15 + tools/axlibc/c/glob.c | 329 ++++++ tools/axlibc/c/ioctl.c | 9 + tools/axlibc/c/libgen.c | 33 + tools/axlibc/c/libm.c | 17 + tools/axlibc/c/libm.h | 233 +++++ tools/axlibc/c/locale.c | 42 + tools/axlibc/c/log.c | 395 +++++++ tools/axlibc/c/math.c | 571 +++++++++++ tools/axlibc/c/mmap.c | 39 + tools/axlibc/c/network.c | 226 ++++ tools/axlibc/c/poll.c | 9 + tools/axlibc/c/pow.c | 815 +++++++++++++++ tools/axlibc/c/printf.c | 1482 +++++++++++++++++++++++++++ tools/axlibc/c/printf.h | 215 ++++ tools/axlibc/c/printf_config.h | 14 + tools/axlibc/c/pthread.c | 110 ++ tools/axlibc/c/pwd.c | 14 + tools/axlibc/c/resource.c | 10 + tools/axlibc/c/sched.c | 9 + tools/axlibc/c/select.c | 17 + tools/axlibc/c/signal.c | 87 ++ tools/axlibc/c/socket.c | 47 + tools/axlibc/c/stat.c | 38 + tools/axlibc/c/stdio.c | 412 ++++++++ tools/axlibc/c/stdlib.c | 385 +++++++ tools/axlibc/c/string.c | 478 +++++++++ tools/axlibc/c/syslog.c | 16 + tools/axlibc/c/time.c | 203 ++++ tools/axlibc/c/unistd.c | 174 ++++ tools/axlibc/c/utsname.c | 9 + tools/axlibc/c/wait.c | 17 + tools/axlibc/ctypes.h | 2 + tools/axlibc/include/arpa/inet.h | 14 + tools/axlibc/include/assert.h | 14 + tools/axlibc/include/ctype.h | 20 + tools/axlibc/include/dirent.h | 45 + tools/axlibc/include/dlfcn.h | 41 + tools/axlibc/include/endian.h | 68 ++ tools/axlibc/include/errno.h | 150 +++ tools/axlibc/include/fcntl.h | 123 +++ tools/axlibc/include/features.h | 11 + tools/axlibc/include/float.h | 99 ++ tools/axlibc/include/fnmatch.h | 24 + tools/axlibc/include/glob.h | 34 + tools/axlibc/include/inttypes.h | 10 + tools/axlibc/include/langinfo.h | 82 ++ tools/axlibc/include/libgen.h | 15 + tools/axlibc/include/limits.h | 35 + tools/axlibc/include/locale.h | 59 ++ tools/axlibc/include/math.h | 321 ++++++ tools/axlibc/include/memory.h | 6 + tools/axlibc/include/netdb.h | 85 ++ tools/axlibc/include/netinet/in.h | 129 +++ tools/axlibc/include/netinet/tcp.h | 45 + tools/axlibc/include/poll.h | 21 + tools/axlibc/include/pthread.h | 84 ++ tools/axlibc/include/pwd.h | 45 + tools/axlibc/include/regex.h | 4 + tools/axlibc/include/sched.h | 23 + tools/axlibc/include/setjmp.h | 23 + tools/axlibc/include/signal.h | 179 ++++ tools/axlibc/include/stdarg.h | 11 + tools/axlibc/include/stdbool.h | 11 + tools/axlibc/include/stddef.h | 27 + tools/axlibc/include/stdint.h | 66 ++ tools/axlibc/include/stdio.h | 116 +++ tools/axlibc/include/stdlib.h | 60 ++ tools/axlibc/include/string.h | 50 + tools/axlibc/include/strings.h | 4 + tools/axlibc/include/sys/epoll.h | 60 ++ tools/axlibc/include/sys/file.h | 23 + tools/axlibc/include/sys/ioctl.h | 65 ++ tools/axlibc/include/sys/mman.h | 52 + tools/axlibc/include/sys/param.h | 6 + tools/axlibc/include/sys/prctl.h | 4 + tools/axlibc/include/sys/resource.h | 63 ++ tools/axlibc/include/sys/select.h | 36 + tools/axlibc/include/sys/socket.h | 310 ++++++ tools/axlibc/include/sys/stat.h | 78 ++ tools/axlibc/include/sys/time.h | 41 + tools/axlibc/include/sys/types.h | 20 + tools/axlibc/include/sys/uio.h | 13 + tools/axlibc/include/sys/un.h | 11 + tools/axlibc/include/sys/utsname.h | 27 + tools/axlibc/include/sys/wait.h | 12 + tools/axlibc/include/syslog.h | 45 + tools/axlibc/include/termios.h | 8 + tools/axlibc/include/time.h | 43 + tools/axlibc/include/unistd.h | 240 +++++ tools/axlibc/src/errno.rs | 39 + tools/axlibc/src/fd_ops.rs | 54 + tools/axlibc/src/fs.rs | 67 ++ tools/axlibc/src/io.rs | 32 + tools/axlibc/src/io_mpx.rs | 54 + tools/axlibc/src/lib.rs | 127 +++ tools/axlibc/src/malloc.rs | 56 + tools/axlibc/src/mktime.rs | 58 ++ tools/axlibc/src/net.rs | 180 ++++ tools/axlibc/src/pipe.rs | 14 + tools/axlibc/src/pthread.rs | 59 ++ tools/axlibc/src/rand.rs | 30 + tools/axlibc/src/resource.rs | 17 + tools/axlibc/src/setjmp.rs | 221 ++++ tools/axlibc/src/strftime.rs | 254 +++++ tools/axlibc/src/strtod.rs | 131 +++ tools/axlibc/src/sys.rs | 10 + tools/axlibc/src/time.rs | 21 + tools/axlibc/src/unistd.rs | 20 + tools/axlibc/src/utils.rs | 10 + tools/axlibc/src/vfp_setjmp.S | 37 + 122 files changed, 11692 insertions(+), 2 deletions(-) create mode 100644 tools/axlibc/.gitignore create mode 100644 tools/axlibc/Cargo.toml create mode 100644 tools/axlibc/build.rs create mode 100644 tools/axlibc/c/assert.c create mode 100644 tools/axlibc/c/ctype.c create mode 100644 tools/axlibc/c/dirent.c create mode 100644 tools/axlibc/c/dlfcn.c create mode 100644 tools/axlibc/c/env.c create mode 100644 tools/axlibc/c/fcntl.c create mode 100644 tools/axlibc/c/flock.c create mode 100644 tools/axlibc/c/fnmatch.c create mode 100644 tools/axlibc/c/glob.c create mode 100644 tools/axlibc/c/ioctl.c create mode 100644 tools/axlibc/c/libgen.c create mode 100644 tools/axlibc/c/libm.c create mode 100644 tools/axlibc/c/libm.h create mode 100644 tools/axlibc/c/locale.c create mode 100644 tools/axlibc/c/log.c create mode 100644 tools/axlibc/c/math.c create mode 100644 tools/axlibc/c/mmap.c create mode 100644 tools/axlibc/c/network.c create mode 100644 tools/axlibc/c/poll.c create mode 100644 tools/axlibc/c/pow.c create mode 100644 tools/axlibc/c/printf.c create mode 100644 tools/axlibc/c/printf.h create mode 100644 tools/axlibc/c/printf_config.h create mode 100644 tools/axlibc/c/pthread.c create mode 100644 tools/axlibc/c/pwd.c create mode 100644 tools/axlibc/c/resource.c create mode 100644 tools/axlibc/c/sched.c create mode 100644 tools/axlibc/c/select.c create mode 100644 tools/axlibc/c/signal.c create mode 100644 tools/axlibc/c/socket.c create mode 100644 tools/axlibc/c/stat.c create mode 100644 tools/axlibc/c/stdio.c create mode 100644 tools/axlibc/c/stdlib.c create mode 100644 tools/axlibc/c/string.c create mode 100644 tools/axlibc/c/syslog.c create mode 100644 tools/axlibc/c/time.c create mode 100644 tools/axlibc/c/unistd.c create mode 100644 tools/axlibc/c/utsname.c create mode 100644 tools/axlibc/c/wait.c create mode 100644 tools/axlibc/ctypes.h create mode 100644 tools/axlibc/include/arpa/inet.h create mode 100644 tools/axlibc/include/assert.h create mode 100644 tools/axlibc/include/ctype.h create mode 100644 tools/axlibc/include/dirent.h create mode 100644 tools/axlibc/include/dlfcn.h create mode 100644 tools/axlibc/include/endian.h create mode 100644 tools/axlibc/include/errno.h create mode 100644 tools/axlibc/include/fcntl.h create mode 100644 tools/axlibc/include/features.h create mode 100644 tools/axlibc/include/float.h create mode 100644 tools/axlibc/include/fnmatch.h create mode 100644 tools/axlibc/include/glob.h create mode 100644 tools/axlibc/include/inttypes.h create mode 100644 tools/axlibc/include/langinfo.h create mode 100644 tools/axlibc/include/libgen.h create mode 100644 tools/axlibc/include/limits.h create mode 100644 tools/axlibc/include/locale.h create mode 100644 tools/axlibc/include/math.h create mode 100644 tools/axlibc/include/memory.h create mode 100644 tools/axlibc/include/netdb.h create mode 100644 tools/axlibc/include/netinet/in.h create mode 100644 tools/axlibc/include/netinet/tcp.h create mode 100644 tools/axlibc/include/poll.h create mode 100644 tools/axlibc/include/pthread.h create mode 100644 tools/axlibc/include/pwd.h create mode 100644 tools/axlibc/include/regex.h create mode 100644 tools/axlibc/include/sched.h create mode 100644 tools/axlibc/include/setjmp.h create mode 100644 tools/axlibc/include/signal.h create mode 100644 tools/axlibc/include/stdarg.h create mode 100644 tools/axlibc/include/stdbool.h create mode 100644 tools/axlibc/include/stddef.h create mode 100644 tools/axlibc/include/stdint.h create mode 100644 tools/axlibc/include/stdio.h create mode 100644 tools/axlibc/include/stdlib.h create mode 100644 tools/axlibc/include/string.h create mode 100644 tools/axlibc/include/strings.h create mode 100644 tools/axlibc/include/sys/epoll.h create mode 100644 tools/axlibc/include/sys/file.h create mode 100644 tools/axlibc/include/sys/ioctl.h create mode 100644 tools/axlibc/include/sys/mman.h create mode 100644 tools/axlibc/include/sys/param.h create mode 100644 tools/axlibc/include/sys/prctl.h create mode 100644 tools/axlibc/include/sys/resource.h create mode 100644 tools/axlibc/include/sys/select.h create mode 100644 tools/axlibc/include/sys/socket.h create mode 100644 tools/axlibc/include/sys/stat.h create mode 100644 tools/axlibc/include/sys/time.h create mode 100644 tools/axlibc/include/sys/types.h create mode 100644 tools/axlibc/include/sys/uio.h create mode 100644 tools/axlibc/include/sys/un.h create mode 100644 tools/axlibc/include/sys/utsname.h create mode 100644 tools/axlibc/include/sys/wait.h create mode 100644 tools/axlibc/include/syslog.h create mode 100644 tools/axlibc/include/termios.h create mode 100644 tools/axlibc/include/time.h create mode 100644 tools/axlibc/include/unistd.h create mode 100644 tools/axlibc/src/errno.rs create mode 100644 tools/axlibc/src/fd_ops.rs create mode 100644 tools/axlibc/src/fs.rs create mode 100644 tools/axlibc/src/io.rs create mode 100644 tools/axlibc/src/io_mpx.rs create mode 100644 tools/axlibc/src/lib.rs create mode 100644 tools/axlibc/src/malloc.rs create mode 100644 tools/axlibc/src/mktime.rs create mode 100644 tools/axlibc/src/net.rs create mode 100644 tools/axlibc/src/pipe.rs create mode 100644 tools/axlibc/src/pthread.rs create mode 100644 tools/axlibc/src/rand.rs create mode 100644 tools/axlibc/src/resource.rs create mode 100644 tools/axlibc/src/setjmp.rs create mode 100644 tools/axlibc/src/strftime.rs create mode 100644 tools/axlibc/src/strtod.rs create mode 100644 tools/axlibc/src/sys.rs create mode 100644 tools/axlibc/src/time.rs create mode 100644 tools/axlibc/src/unistd.rs create mode 100644 tools/axlibc/src/utils.rs create mode 100644 tools/axlibc/src/vfp_setjmp.S diff --git a/.gitignore b/.gitignore index ffb688c..5b5982a 100644 --- a/.gitignore +++ b/.gitignore @@ -14,5 +14,4 @@ arceos-fada.itb linker_* crates/ minicom_output.log -.errorviz* -tools/axlibc +.errorviz* \ No newline at end of file diff --git a/tools/axlibc/.gitignore b/tools/axlibc/.gitignore new file mode 100644 index 0000000..7861f4f --- /dev/null +++ b/tools/axlibc/.gitignore @@ -0,0 +1,22 @@ +# Generated by Cargo +# will have compiled files and executables +debug/ +target/ + +# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries +# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html +Cargo.lock + +# These are backup files generated by rustfmt +**/*.rs.bk + +# MSVC Windows builds of rustc generate these, which store debugging information +*.pdb + +src/libctypes_gen.rs + +include/ax_pthread_mutex.h + +build_* + +lwext4* \ No newline at end of file diff --git a/tools/axlibc/Cargo.toml b/tools/axlibc/Cargo.toml new file mode 100644 index 0000000..7f68981 --- /dev/null +++ b/tools/axlibc/Cargo.toml @@ -0,0 +1,64 @@ +[package] +name = "axlibc" +version = "0.1.0" +edition = "2021" +authors = [ + "Yuekai Jia ", + "yanjuguang ", + "wudashuai ", + "yfblock <321353225@qq.com>", + "scPointer ", + "Shiping Yuan ", +] +description = "ArceOS user program library for C apps" +license = "GPL-3.0-or-later OR Apache-2.0" +homepage = "https://github.com/rcore-os/arceos" +repository = "https://github.com/rcore-os/arceos/tree/main/ulib/axlibc" +documentation = "https://rcore-os.github.io/arceos/axlibc/index.html" + +[lib] +crate-type = ["lib", "staticlib"] + +[features] +default = [] + +irq = ["arceos_posix_api/irq", "arch_boot/irq"] + +# Multicore +smp = ["arceos_posix_api/smp", "arch_boot/smp"] + +# Floating point/SIMD +fp_simd = ["axfeat/fp_simd", "arch_boot/fp_simd"] + +# Memory +alloc = ["arceos_posix_api/alloc"] +tls = ["alloc", "axfeat/tls"] + +# Multi-task +multitask = ["arceos_posix_api/multitask"] + +# File system +fs = ["arceos_posix_api/fs", "fd"] + +# Networking +net = ["arceos_posix_api/net", "fd"] + +# Schedule policy +sched_rr = ["arch_boot/preempt", "axfeat/sched_rr"] +sched_cfs = ["arch_boot/preempt", "axfeat/sched_cfs"] + +# Libc features +fd = [] +pipe = ["arceos_posix_api/pipe"] +select = ["arceos_posix_api/select"] +epoll = ["arceos_posix_api/epoll"] + +[dependencies] +axfeat = { git = "https://github.com/Starry-OS/axfeat.git" } +arceos_posix_api = { git = "https://github.com/Starry-OS/arceos_posix_api.git" } +axio = { git = "https://github.com/Starry-OS/axio.git" } +axerrno = { git = "https://github.com/Starry-OS/axerrno.git" } +arch_boot = { git = "https://github.com/Starry-OS/arch_boot.git" } + +[build-dependencies] +bindgen ={ version = "0.69" } \ No newline at end of file diff --git a/tools/axlibc/build.rs b/tools/axlibc/build.rs new file mode 100644 index 0000000..40a6ff3 --- /dev/null +++ b/tools/axlibc/build.rs @@ -0,0 +1,73 @@ +use std::env; +use std::path::PathBuf; +use std::process::Command; + +fn main() { + fn gen_c_to_rust_bindings(in_file: &str, out_file: &str) { + println!("cargo:rerun-if-changed={in_file}"); + + let allow_types = ["tm", "jmp_buf"]; + let mut builder = bindgen::Builder::default() + .header(in_file) + .clang_arg("-I./include") + .derive_default(true) + .size_t_is_usize(false) + .use_core(); + for ty in allow_types { + builder = builder.allowlist_type(ty); + } + + builder + .generate() + .expect("Unable to generate c->rust bindings") + .write_to_file(out_file) + .expect("Couldn't write bindings!"); + } + + gen_c_to_rust_bindings("ctypes.h", "src/libctypes_gen.rs"); + + let arch = std::env::var("CARGO_CFG_TARGET_ARCH").unwrap(); + if arch == "aarch64" { + aarch64_vfp_compile(); + } +} + +fn aarch64_vfp_compile() { + // 获取当前 crate 输出目录 + let out_dir = env::var("OUT_DIR").unwrap(); + // 指定汇编文件路径 + let asm_file = PathBuf::from("src/vfp_setjmp.S"); + let asm_out_file = PathBuf::from(&out_dir).join("vfp_setjmp.o"); + + // 编译汇编文件,增加 target-feature 选项 + let status = Command::new("clang") + .args([ + "-c", + asm_file.to_str().unwrap(), + "-o", + asm_out_file.to_str().unwrap(), + "-target", + "aarch64-unknown-none", + "-mfpu=neon", + ]) + .status() + .expect("failed to execute clang"); + assert!(status.success(), "clang failed to compile assembly file"); + + // 打包对象文件为静态库 + let lib_out_file = PathBuf::from(&out_dir).join("libvfp_setjmp.a"); + let status = Command::new("ar") + .args([ + "crus", + lib_out_file.to_str().unwrap(), + asm_out_file.to_str().unwrap(), + ]) + .status() + .expect("failed to execute ar"); + assert!(status.success(), "ar failed to create static library"); + + // 指示 rustc 链接器链接汇编对象文件 + println!("cargo:rerun-if-changed=src/vfp_setjmp.S"); + println!("cargo:rustc-link-search={}", out_dir); + println!("cargo:rustc-link-lib=static=vfp_setjmp"); +} diff --git a/tools/axlibc/c/assert.c b/tools/axlibc/c/assert.c new file mode 100644 index 0000000..ee07167 --- /dev/null +++ b/tools/axlibc/c/assert.c @@ -0,0 +1,8 @@ +#include +#include + +_Noreturn void __assert_fail(const char *expr, const char *file, int line, const char *func) +{ + fprintf(stderr, "Assertion failed: %s (%s: %s: %d)\n", expr, file, func, line); + abort(); +} diff --git a/tools/axlibc/c/ctype.c b/tools/axlibc/c/ctype.c new file mode 100644 index 0000000..08e8e5e --- /dev/null +++ b/tools/axlibc/c/ctype.c @@ -0,0 +1,17 @@ +#include +#include +#include + +int tolower(int c) +{ + if (isupper(c)) + return c | 32; + return c; +} + +int toupper(int c) +{ + if (islower(c)) + return c & 0x5f; + return c; +} diff --git a/tools/axlibc/c/dirent.c b/tools/axlibc/c/dirent.c new file mode 100644 index 0000000..a69094a --- /dev/null +++ b/tools/axlibc/c/dirent.c @@ -0,0 +1,98 @@ +#ifdef AX_CONFIG_FS + +#include +#include +#include +#include +#include +#include +#include +#include + +int closedir(DIR *dir) +{ + int ret = close(dir->fd); + free(dir); + return ret; +} + +DIR *fdopendir(int fd) +{ + DIR *dir; + struct stat st; + + if (fstat(fd, &st) < 0) { + return 0; + } + if (fcntl(fd, F_GETFL) & O_PATH) { + errno = EBADF; + return 0; + } + if (!S_ISDIR(st.st_mode)) { + errno = ENOTDIR; + return 0; + } + if (!(dir = calloc(1, sizeof(*dir)))) { + return 0; + } + + fcntl(fd, F_SETFD, FD_CLOEXEC); + dir->fd = fd; + return dir; +} + +int dirfd(DIR *d) +{ + return d->fd; +} + +// TODO +DIR *opendir(const char *__name) +{ + unimplemented(); + return NULL; +} + +// TODO +struct dirent *readdir(DIR *__dirp) +{ + unimplemented(); + return NULL; +} + +// TODO +int readdir_r(DIR *restrict dir, struct dirent *restrict buf, struct dirent **restrict result) +{ + struct dirent *de; + int errno_save = errno; + int ret; + + // LOCK(dir->lock); + errno = 0; + de = readdir(dir); + if ((ret = errno)) { + // UNLOCK(dir->lock); + return ret; + } + errno = errno_save; + if (de) + memcpy(buf, de, de->d_reclen); + else + buf = NULL; + + // UNLOCK(dir->lock); + *result = buf; + return 0; +} + +// TODO +void rewinddir(DIR *dir) +{ + // LOCK(dir->lock); + lseek(dir->fd, 0, SEEK_SET); + dir->buf_pos = dir->buf_end = 0; + dir->tell = 0; + // UNLOCK(dir->lock); +} + +#endif // AX_CONFIG_FS diff --git a/tools/axlibc/c/dlfcn.c b/tools/axlibc/c/dlfcn.c new file mode 100644 index 0000000..a539e7d --- /dev/null +++ b/tools/axlibc/c/dlfcn.c @@ -0,0 +1,39 @@ +#include +#include +#include + +// TODO +int dladdr(const void *__address, Dl_info *__info) +{ + unimplemented(); + return 0; +} + +// TODO +void *dlopen(const char *__file, int __mode) +{ + unimplemented(); + return NULL; +} + +// TODO +char *dlerror() +{ + unimplemented(); + return NULL; +} + +// TODO +void *dlsym(void *__restrict__ __handle, const char *__restrict__ __name) +{ + + unimplemented(); + return NULL; +} + +// TODO +int dlclose(void *p) +{ + unimplemented(); + return 0; +} diff --git a/tools/axlibc/c/env.c b/tools/axlibc/c/env.c new file mode 100644 index 0000000..a0505a9 --- /dev/null +++ b/tools/axlibc/c/env.c @@ -0,0 +1,31 @@ +#include +#include +#include +#include + +char *environ_[2] = {"dummy", NULL}; +char **environ = (char **)environ_; + +char *getenv(const char *name) +{ + size_t l = strchrnul(name, '=') - name; + if (l && !name[l] && environ) + for (char **e = environ; *e; e++) + if (!strncmp(name, *e, l) && l[*e] == '=') + return *e + l + 1; + return 0; +} + +// TODO +int setenv(const char *__name, const char *__value, int __replace) +{ + unimplemented(); + return 0; +} + +// TODO +int unsetenv(const char *__name) +{ + unimplemented(); + return 0; +} diff --git a/tools/axlibc/c/fcntl.c b/tools/axlibc/c/fcntl.c new file mode 100644 index 0000000..fa90917 --- /dev/null +++ b/tools/axlibc/c/fcntl.c @@ -0,0 +1,56 @@ +#include +#include +#include + +#ifdef AX_CONFIG_FD + +// TODO: remove this function in future work +int ax_fcntl(int fd, int cmd, size_t arg); + +int fcntl(int fd, int cmd, ... /* arg */) +{ + unsigned long arg; + va_list ap; + va_start(ap, cmd); + arg = va_arg(ap, unsigned long); + va_end(ap); + + return ax_fcntl(fd, cmd, arg); +} + +#endif // AX_CONFIG_FD + +#ifdef AX_CONFIG_FS + +// TODO: remove this function in future work +int ax_open(const char *filename, int flags, mode_t mode); + +int open(const char *filename, int flags, ...) +{ + mode_t mode = 0; + + if ((flags & O_CREAT) || (flags & O_TMPFILE) == O_TMPFILE) { + va_list ap; + va_start(ap, flags); + mode = va_arg(ap, mode_t); + va_end(ap); + } + + return ax_open(filename, flags, mode); +} + +// TODO +int posix_fadvise(int __fd, unsigned long __offset, unsigned long __len, int __advise) +{ + unimplemented(); + return 0; +} + +// TODO +int sync_file_range(int fd, off_t pos, off_t len, unsigned flags) +{ + unimplemented(); + return 0; +} + +#endif // AX_CONFIG_FS diff --git a/tools/axlibc/c/flock.c b/tools/axlibc/c/flock.c new file mode 100644 index 0000000..8ac9bee --- /dev/null +++ b/tools/axlibc/c/flock.c @@ -0,0 +1,9 @@ +#include +#include + +// TODO +int flock(int __fd, int __operation) +{ + unimplemented(); + return 0; +} diff --git a/tools/axlibc/c/fnmatch.c b/tools/axlibc/c/fnmatch.c new file mode 100644 index 0000000..3895fa2 --- /dev/null +++ b/tools/axlibc/c/fnmatch.c @@ -0,0 +1,15 @@ +#include +#include + +#define END 0 +#define UNMATCHABLE -2 +#define BRACKET -3 +#define QUESTION -4 +#define STAR -5 + +// TODO +int fnmatch(const char *pat, const char *str, int flags) +{ + unimplemented(); + return 0; +} diff --git a/tools/axlibc/c/glob.c b/tools/axlibc/c/glob.c new file mode 100644 index 0000000..841a226 --- /dev/null +++ b/tools/axlibc/c/glob.c @@ -0,0 +1,329 @@ +#ifdef AX_CONFIG_FS + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct match { + struct match *next; + char name[]; +}; + +static int append(struct match **tail, const char *name, size_t len, int mark) +{ + struct match *new = malloc(sizeof(struct match) + len + 2); + if (!new) + return -1; + (*tail)->next = new; + new->next = NULL; + memcpy(new->name, name, len + 1); + if (mark && len && name[len - 1] != '/') { + new->name[len] = '/'; + new->name[len + 1] = 0; + } + *tail = new; + return 0; +} + +static int do_glob(char *buf, size_t pos, int type, char *pat, int flags, + int (*errfunc)(const char *path, int err), struct match **tail) +{ + /* If GLOB_MARK is unused, we don't care about type. */ + if (!type && !(flags & GLOB_MARK)) + type = DT_REG; + + /* Special-case the remaining pattern being all slashes, in + * which case we can use caller-passed type if it's a dir. */ + if (*pat && type != DT_DIR) + type = 0; + while (pos + 1 < PATH_MAX && *pat == '/') buf[pos++] = *pat++; + + /* Consume maximal [escaped-]literal prefix of pattern, copying + * and un-escaping it to the running buffer as we go. */ + long i = 0, j = 0; + int in_bracket = 0, overflow = 0; + for (; pat[i] != '*' && pat[i] != '?' && (!in_bracket || pat[i] != ']'); i++) { + if (!pat[i]) { + if (overflow) + return 0; + pat += i; + pos += j; + i = j = 0; + break; + } else if (pat[i] == '[') { + in_bracket = 1; + } else if (pat[i] == '\\' && !(flags & GLOB_NOESCAPE)) { + /* Backslashes inside a bracket are (at least by + * our interpretation) non-special, so if next + * char is ']' we have a complete expression. */ + if (in_bracket && pat[i + 1] == ']') + break; + /* Unpaired final backslash never matches. */ + if (!pat[i + 1]) + return 0; + i++; + } + if (pat[i] == '/') { + if (overflow) + return 0; + in_bracket = 0; + pat += i + 1; + i = -1; + pos += j + 1; + j = -1; + } + /* Only store a character if it fits in the buffer, but if + * a potential bracket expression is open, the overflow + * must be remembered and handled later only if the bracket + * is unterminated (and thereby a literal), so as not to + * disallow long bracket expressions with short matches. */ + if (pos + (j + 1) < PATH_MAX) { + buf[pos + j++] = pat[i]; + } else if (in_bracket) { + overflow = 1; + } else { + return 0; + } + /* If we consume any new components, the caller-passed type + * or dummy type from above is no longer valid. */ + type = 0; + } + buf[pos] = 0; + if (!*pat) { + /* If we consumed any components above, or if GLOB_MARK is + * requested and we don't yet know if the match is a dir, + * we must confirm the file exists and/or determine its type. + * + * If marking dirs, symlink type is inconclusive; we need the + * type for the symlink target, and therefore must try stat + * first unless type is known not to be a symlink. Otherwise, + * or if that fails, use lstat for determining existence to + * avoid false negatives in the case of broken symlinks. */ + struct stat st; + if ((flags & GLOB_MARK) && (!type || type == DT_LNK) && !stat(buf, &st)) { + if (S_ISDIR(st.st_mode)) + type = DT_DIR; + else + type = DT_REG; + } + if (!type && lstat(buf, &st)) { + if (errno != ENOENT && (errfunc(buf, errno) || (flags & GLOB_ERR))) + return GLOB_ABORTED; + return 0; + } + if (append(tail, buf, pos, (flags & GLOB_MARK) && type == DT_DIR)) + return GLOB_NOSPACE; + return 0; + } + char *p2 = strchr(pat, '/'), saved_sep = '/'; + /* Check if the '/' was escaped and, if so, remove the escape char + * so that it will not be unpaired when passed to fnmatch. */ + if (p2 && !(flags & GLOB_NOESCAPE)) { + char *p; + for (p = p2; p > pat && p[-1] == '\\'; p--) + ; + if ((p2 - p) % 2) { + p2--; + saved_sep = '\\'; + } + } + DIR *dir = opendir(pos ? buf : "."); + if (!dir) { + if (errfunc(buf, errno) || (flags & GLOB_ERR)) + return GLOB_ABORTED; + return 0; + } + int old_errno = errno; + struct dirent *de; + while (errno = 0, de = readdir(dir)) { + /* Quickly skip non-directories when there's pattern left. */ + if (p2 && de->d_type && de->d_type != DT_DIR && de->d_type != DT_LNK) + continue; + + size_t l = strlen(de->d_name); + if (l >= PATH_MAX - pos) + continue; + + if (p2) + *p2 = 0; + + int fnm_flags = ((flags & GLOB_NOESCAPE) ? FNM_NOESCAPE : 0) | + ((!(flags & GLOB_PERIOD)) ? FNM_PERIOD : 0); + + if (fnmatch(pat, de->d_name, fnm_flags)) + continue; + + /* With GLOB_PERIOD, don't allow matching . or .. unless + * fnmatch would match them with FNM_PERIOD rules in effect. */ + if (p2 && (flags & GLOB_PERIOD) && de->d_name[0] == '.' && + (!de->d_name[1] || (de->d_name[1] == '.' && !de->d_name[2])) && + fnmatch(pat, de->d_name, fnm_flags | FNM_PERIOD)) + continue; + + memcpy(buf + pos, de->d_name, l + 1); + if (p2) + *p2 = saved_sep; + int r = do_glob(buf, pos + l, de->d_type, p2 ? p2 : "", flags, errfunc, tail); + if (r) { + closedir(dir); + return r; + } + } + int readerr = errno; + if (p2) + *p2 = saved_sep; + closedir(dir); + if (readerr && (errfunc(buf, errno) || (flags & GLOB_ERR))) + return GLOB_ABORTED; + errno = old_errno; + return 0; +} + +static int ignore_err(const char *path, int err) +{ + return 0; +} + +static void freelist(struct match *head) +{ + struct match *match, *next; + for (match = head->next; match; match = next) { + next = match->next; + free(match); + } +} + +static int sort(const void *a, const void *b) +{ + return strcmp(*(const char **)a, *(const char **)b); +} + +static int expand_tilde(char **pat, char *buf, size_t *pos) +{ + char *p = *pat + 1; + size_t i = 0; + + char delim, *name_end = strchrnul(p, '/'); + if ((delim = *name_end)) + *name_end++ = 0; + *pat = name_end; + + char *home = *p ? NULL : getenv("HOME"); + if (!home) { + struct passwd pw, *res; + switch (*p ? getpwnam_r(p, &pw, buf, PATH_MAX, &res) + : getpwuid_r(getuid(), &pw, buf, PATH_MAX, &res)) { + case ENOMEM: + return GLOB_NOSPACE; + case 0: + if (!res) + default: + return GLOB_NOMATCH; + } + home = pw.pw_dir; + } + while (i < PATH_MAX - 2 && *home) buf[i++] = *home++; + if (*home) + return GLOB_NOMATCH; + if ((buf[i] = delim)) + buf[++i] = 0; + *pos = i; + return 0; +} + +int glob(const char *restrict pat, int flags, int (*errfunc)(const char *path, int err), + glob_t *restrict g) +{ + struct match head = {.next = NULL}, *tail = &head; + size_t cnt, i; + size_t offs = (flags & GLOB_DOOFFS) ? g->gl_offs : 0; + int error = 0; + char buf[PATH_MAX]; + + if (!errfunc) + errfunc = ignore_err; + + if (!(flags & GLOB_APPEND)) { + g->gl_offs = offs; + g->gl_pathc = 0; + g->gl_pathv = NULL; + } + + if (*pat) { + char *p = strdup(pat); + if (!p) + return GLOB_NOSPACE; + buf[0] = 0; + size_t pos = 0; + char *s = p; + if ((flags & (GLOB_TILDE | GLOB_TILDE_CHECK)) && *p == '~') + error = expand_tilde(&s, buf, &pos); + if (!error) + error = do_glob(buf, pos, 0, s, flags, errfunc, &tail); + free(p); + } + + if (error == GLOB_NOSPACE) { + freelist(&head); + return error; + } + + for (cnt = 0, tail = head.next; tail; tail = tail->next, cnt++) + ; + if (!cnt) { + if (flags & GLOB_NOCHECK) { + tail = &head; + if (append(&tail, pat, strlen(pat), 0)) + return GLOB_NOSPACE; + cnt++; + } else + return GLOB_NOMATCH; + } + + if (flags & GLOB_APPEND) { + char **pathv = realloc(g->gl_pathv, (offs + g->gl_pathc + cnt + 1) * sizeof(char *)); + if (!pathv) { + freelist(&head); + return GLOB_NOSPACE; + } + g->gl_pathv = pathv; + offs += g->gl_pathc; + } else { + g->gl_pathv = malloc((offs + cnt + 1) * sizeof(char *)); + if (!g->gl_pathv) { + freelist(&head); + return GLOB_NOSPACE; + } + for (i = 0; i < offs; i++) g->gl_pathv[i] = NULL; + } + for (i = 0, tail = head.next; i < cnt; tail = tail->next, i++) + g->gl_pathv[offs + i] = tail->name; + g->gl_pathv[offs + i] = NULL; + g->gl_pathc += cnt; + + if (!(flags & GLOB_NOSORT)) + qsort(g->gl_pathv + offs, cnt, sizeof(char *), sort); + + return error; +} + +void globfree(glob_t *g) +{ + size_t i; + for (i = 0; i < g->gl_pathc; i++) + free(g->gl_pathv[g->gl_offs + i] - offsetof(struct match, name)); + free(g->gl_pathv); + g->gl_pathc = 0; + g->gl_pathv = NULL; +} + +#endif // AX_CONFIG_FS diff --git a/tools/axlibc/c/ioctl.c b/tools/axlibc/c/ioctl.c new file mode 100644 index 0000000..df2aad1 --- /dev/null +++ b/tools/axlibc/c/ioctl.c @@ -0,0 +1,9 @@ +#include +#include + +// TODO +int ioctl(int __fd, int __request, ...) +{ + unimplemented(); + return 0; +} diff --git a/tools/axlibc/c/libgen.c b/tools/axlibc/c/libgen.c new file mode 100644 index 0000000..fbce881 --- /dev/null +++ b/tools/axlibc/c/libgen.c @@ -0,0 +1,33 @@ +#include +#include + +char *dirname(char *s) +{ + size_t i; + if (!s || !*s) + return "."; + i = strlen(s) - 1; + for (; s[i] == '/'; i--) + if (!i) + return "/"; + for (; s[i] != '/'; i--) + if (!i) + return "."; + for (; s[i] == '/'; i--) + if (!i) + return "/"; + s[i + 1] = 0; + return s; +} + +char *basename(char *s) +{ + size_t i; + if (!s || !*s) + return "."; + i = strlen(s) - 1; + for (; i && s[i] == '/'; i--) s[i] = 0; + for (; i && s[i - 1] != '/'; i--) + ; + return s + i; +} diff --git a/tools/axlibc/c/libm.c b/tools/axlibc/c/libm.c new file mode 100644 index 0000000..c842011 --- /dev/null +++ b/tools/axlibc/c/libm.c @@ -0,0 +1,17 @@ +#ifdef AX_CONFIG_FP_SIMD + +#include + +#include "libm.h" + +double __math_divzero(uint32_t sign) +{ + return fp_barrier(sign ? -1.0 : 1.0) / 0.0; +} + +double __math_invalid(double x) +{ + return (x - x) / (x - x); +} + +#endif // AX_CONFIG_FP_SIMD diff --git a/tools/axlibc/c/libm.h b/tools/axlibc/c/libm.h new file mode 100644 index 0000000..ac9130d --- /dev/null +++ b/tools/axlibc/c/libm.h @@ -0,0 +1,233 @@ +#ifndef _LIBM_H +#define _LIBM_H + +#if AX_CONFIG_FP_SIMD + +#include +#include +#include + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 && __BYTE_ORDER == __LITTLE_ENDIAN +union ldshape { + long double f; + struct { + uint64_t m; + uint16_t se; + } i; +}; +#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 && __BYTE_ORDER == __BIG_ENDIAN +/* This is the m68k variant of 80-bit long double, and this definition only works + * on archs where the alignment requirement of uint64_t is <= 4. */ +union ldshape { + long double f; + struct { + uint16_t se; + uint16_t pad; + uint64_t m; + } i; +}; +#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 && __BYTE_ORDER == __LITTLE_ENDIAN +union ldshape { + long double f; + struct { + uint64_t lo; + uint32_t mid; + uint16_t top; + uint16_t se; + } i; + struct { + uint64_t lo; + uint64_t hi; + } i2; +}; +#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 && __BYTE_ORDER == __BIG_ENDIAN +union ldshape { + long double f; + struct { + uint16_t se; + uint16_t top; + uint32_t mid; + uint64_t lo; + } i; + struct { + uint64_t hi; + uint64_t lo; + } i2; +}; +#else +#error Unsupported long double representation +#endif + +/* Support non-nearest rounding mode. */ +#define WANT_ROUNDING 1 +/* Support signaling NaNs. */ +#define WANT_SNAN 0 + +#if WANT_SNAN +#error SNaN is unsupported +#else +#define issignalingf_inline(x) 0 +#define issignaling_inline(x) 0 +#endif + +#ifndef TOINT_INTRINSICS +#define TOINT_INTRINSICS 0 +#endif + +#if TOINT_INTRINSICS +/* Round x to nearest int in all rounding modes, ties have to be rounded + consistently with converttoint so the results match. If the result + would be outside of [-2^31, 2^31-1] then the semantics is unspecified. */ +static double_t roundtoint(double_t); + +/* Convert x to nearest int in all rounding modes, ties have to be rounded + consistently with roundtoint. If the result is not representible in an + int32_t then the semantics is unspecified. */ +static int32_t converttoint(double_t); +#endif + +/* Helps static branch prediction so hot path can be better optimized. */ +#ifdef __GNUC__ +#define predict_true(x) __builtin_expect(!!(x), 1) +#define predict_false(x) __builtin_expect(x, 0) +#else +#define predict_true(x) (x) +#define predict_false(x) (x) +#endif + +/* Evaluate an expression as the specified type. With standard excess + precision handling a type cast or assignment is enough (with + -ffloat-store an assignment is required, in old compilers argument + passing and return statement may not drop excess precision). */ + +static inline float eval_as_float(float x) +{ + float y = x; + return y; +} + +static inline double eval_as_double(double x) +{ + double y = x; + return y; +} + +/* fp_barrier returns its input, but limits code transformations + as if it had a side-effect (e.g. observable io) and returned + an arbitrary value. */ + +#ifndef fp_barrierf +#define fp_barrierf fp_barrierf +static inline float fp_barrierf(float x) +{ + volatile float y = x; + return y; +} +#endif + +#ifndef fp_barrier +#define fp_barrier fp_barrier +static inline double fp_barrier(double x) +{ + volatile double y = x; + return y; +} +#endif + +#ifndef fp_barrierl +#define fp_barrierl fp_barrierl +static inline long double fp_barrierl(long double x) +{ + volatile long double y = x; + return y; +} +#endif + +/* fp_force_eval ensures that the input value is computed when that's + otherwise unused. To prevent the constant folding of the input + expression, an additional fp_barrier may be needed or a compilation + mode that does so (e.g. -frounding-math in gcc). Then it can be + used to evaluate an expression for its fenv side-effects only. */ + +#ifndef fp_force_evalf +#define fp_force_evalf fp_force_evalf +static inline void fp_force_evalf(float x) +{ + volatile float y; + y = x; +} +#endif + +#ifndef fp_force_eval +#define fp_force_eval fp_force_eval +static inline void fp_force_eval(double x) +{ + volatile double y; + y = x; +} +#endif + +#ifndef fp_force_evall +#define fp_force_evall fp_force_evall +static inline void fp_force_evall(long double x) +{ + volatile long double y; + y = x; +} +#endif + +#define FORCE_EVAL(x) \ + do { \ + if (sizeof(x) == sizeof(float)) { \ + fp_force_evalf(x); \ + } else if (sizeof(x) == sizeof(double)) { \ + fp_force_eval(x); \ + } else { \ + fp_force_evall(x); \ + } \ + } while (0) + +#define asuint(f) \ + ((union { \ + float _f; \ + uint32_t _i; \ + }){f}) \ + ._i +#define asfloat(i) \ + ((union { \ + uint32_t _i; \ + float _f; \ + }){i}) \ + ._f +#define asuint64(f) \ + ((union { \ + double _f; \ + uint64_t _i; \ + }){f}) \ + ._i +#define asdouble(i) \ + ((union { \ + uint64_t _i; \ + double _f; \ + }){i}) \ + ._f + +/* error handling functions */ +float __math_xflowf(uint32_t, float); +float __math_uflowf(uint32_t); +float __math_oflowf(uint32_t); +float __math_divzerof(uint32_t); +float __math_invalidf(float); +double __math_xflow(uint32_t, double); +double __math_uflow(uint32_t); +double __math_oflow(uint32_t); +double __math_divzero(uint32_t); +double __math_invalid(double); +#if LDBL_MANT_DIG != DBL_MANT_DIG +long double __math_invalidl(long double); +#endif + +#endif // AX_CONFIG_FP_SIMD + +#endif // _LIBM_H diff --git a/tools/axlibc/c/locale.c b/tools/axlibc/c/locale.c new file mode 100644 index 0000000..9c535ac --- /dev/null +++ b/tools/axlibc/c/locale.c @@ -0,0 +1,42 @@ +#include +#include +#include + +// TODO +char *setlocale(int __category, const char *__locale) +{ + unimplemented(); + return NULL; +} + +static const struct lconv posix_lconv = { + .decimal_point = ".", + .thousands_sep = "", + .grouping = "", + .int_curr_symbol = "", + .currency_symbol = "", + .mon_decimal_point = "", + .mon_thousands_sep = "", + .mon_grouping = "", + .positive_sign = "", + .negative_sign = "", + .int_frac_digits = CHAR_MAX, + .frac_digits = CHAR_MAX, + .p_cs_precedes = CHAR_MAX, + .p_sep_by_space = CHAR_MAX, + .n_cs_precedes = CHAR_MAX, + .n_sep_by_space = CHAR_MAX, + .p_sign_posn = CHAR_MAX, + .n_sign_posn = CHAR_MAX, + .int_p_cs_precedes = CHAR_MAX, + .int_p_sep_by_space = CHAR_MAX, + .int_n_cs_precedes = CHAR_MAX, + .int_n_sep_by_space = CHAR_MAX, + .int_p_sign_posn = CHAR_MAX, + .int_n_sign_posn = CHAR_MAX, +}; + +struct lconv *localeconv(void) +{ + return (void *)&posix_lconv; +} diff --git a/tools/axlibc/c/log.c b/tools/axlibc/c/log.c new file mode 100644 index 0000000..4e34aa0 --- /dev/null +++ b/tools/axlibc/c/log.c @@ -0,0 +1,395 @@ +#ifdef AX_CONFIG_FP_SIMD + +#include +#include +#include +#include + +#include "libm.h" + +struct log_data { + double ln2hi; + double ln2lo; + double poly[LOG_POLY_ORDER - 1]; + double poly1[LOG_POLY1_ORDER - 1]; + struct { + double invc, logc; + } tab[1 << LOG_TABLE_BITS]; +#if !__FP_FAST_FMA + struct { + double chi, clo; + } tab2[1 << LOG_TABLE_BITS]; +#endif +}; + +const struct log_data __log_data = { + .ln2hi = 0x1.62e42fefa3800p-1, + .ln2lo = 0x1.ef35793c76730p-45, + .poly1 = + { + -0x1p-1, + 0x1.5555555555577p-2, + -0x1.ffffffffffdcbp-3, + 0x1.999999995dd0cp-3, + -0x1.55555556745a7p-3, + 0x1.24924a344de3p-3, + -0x1.fffffa4423d65p-4, + 0x1.c7184282ad6cap-4, + -0x1.999eb43b068ffp-4, + 0x1.78182f7afd085p-4, + -0x1.5521375d145cdp-4, + }, + .poly = + { + -0x1.0000000000001p-1, + 0x1.555555551305bp-2, + -0x1.fffffffeb459p-3, + 0x1.999b324f10111p-3, + -0x1.55575e506c89fp-3, + }, + .tab = + { + {0x1.734f0c3e0de9fp+0, -0x1.7cc7f79e69000p-2}, + {0x1.713786a2ce91fp+0, -0x1.76feec20d0000p-2}, + {0x1.6f26008fab5a0p+0, -0x1.713e31351e000p-2}, + {0x1.6d1a61f138c7dp+0, -0x1.6b85b38287800p-2}, + {0x1.6b1490bc5b4d1p+0, -0x1.65d5590807800p-2}, + {0x1.69147332f0cbap+0, -0x1.602d076180000p-2}, + {0x1.6719f18224223p+0, -0x1.5a8ca86909000p-2}, + {0x1.6524f99a51ed9p+0, -0x1.54f4356035000p-2}, + {0x1.63356aa8f24c4p+0, -0x1.4f637c36b4000p-2}, + {0x1.614b36b9ddc14p+0, -0x1.49da7fda85000p-2}, + {0x1.5f66452c65c4cp+0, -0x1.445923989a800p-2}, + {0x1.5d867b5912c4fp+0, -0x1.3edf439b0b800p-2}, + {0x1.5babccb5b90dep+0, -0x1.396ce448f7000p-2}, + {0x1.59d61f2d91a78p+0, -0x1.3401e17bda000p-2}, + {0x1.5805612465687p+0, -0x1.2e9e2ef468000p-2}, + {0x1.56397cee76bd3p+0, -0x1.2941b3830e000p-2}, + {0x1.54725e2a77f93p+0, -0x1.23ec58cda8800p-2}, + {0x1.52aff42064583p+0, -0x1.1e9e129279000p-2}, + {0x1.50f22dbb2bddfp+0, -0x1.1956d2b48f800p-2}, + {0x1.4f38f4734ded7p+0, -0x1.141679ab9f800p-2}, + {0x1.4d843cfde2840p+0, -0x1.0edd094ef9800p-2}, + {0x1.4bd3ec078a3c8p+0, -0x1.09aa518db1000p-2}, + {0x1.4a27fc3e0258ap+0, -0x1.047e65263b800p-2}, + {0x1.4880524d48434p+0, -0x1.feb224586f000p-3}, + {0x1.46dce1b192d0bp+0, -0x1.f474a7517b000p-3}, + {0x1.453d9d3391854p+0, -0x1.ea4443d103000p-3}, + {0x1.43a2744b4845ap+0, -0x1.e020d44e9b000p-3}, + {0x1.420b54115f8fbp+0, -0x1.d60a22977f000p-3}, + {0x1.40782da3ef4b1p+0, -0x1.cc00104959000p-3}, + {0x1.3ee8f5d57fe8fp+0, -0x1.c202956891000p-3}, + {0x1.3d5d9a00b4ce9p+0, -0x1.b81178d811000p-3}, + {0x1.3bd60c010c12bp+0, -0x1.ae2c9ccd3d000p-3}, + {0x1.3a5242b75dab8p+0, -0x1.a45402e129000p-3}, + {0x1.38d22cd9fd002p+0, -0x1.9a877681df000p-3}, + {0x1.3755bc5847a1cp+0, -0x1.90c6d69483000p-3}, + {0x1.35dce49ad36e2p+0, -0x1.87120a645c000p-3}, + {0x1.34679984dd440p+0, -0x1.7d68fb4143000p-3}, + {0x1.32f5cceffcb24p+0, -0x1.73cb83c627000p-3}, + {0x1.3187775a10d49p+0, -0x1.6a39a9b376000p-3}, + {0x1.301c8373e3990p+0, -0x1.60b3154b7a000p-3}, + {0x1.2eb4ebb95f841p+0, -0x1.5737d76243000p-3}, + {0x1.2d50a0219a9d1p+0, -0x1.4dc7b8fc23000p-3}, + {0x1.2bef9a8b7fd2ap+0, -0x1.4462c51d20000p-3}, + {0x1.2a91c7a0c1babp+0, -0x1.3b08abc830000p-3}, + {0x1.293726014b530p+0, -0x1.31b996b490000p-3}, + {0x1.27dfa5757a1f5p+0, -0x1.2875490a44000p-3}, + {0x1.268b39b1d3bbfp+0, -0x1.1f3b9f879a000p-3}, + {0x1.2539d838ff5bdp+0, -0x1.160c8252ca000p-3}, + {0x1.23eb7aac9083bp+0, -0x1.0ce7f57f72000p-3}, + {0x1.22a012ba940b6p+0, -0x1.03cdc49fea000p-3}, + {0x1.2157996cc4132p+0, -0x1.f57bdbc4b8000p-4}, + {0x1.201201dd2fc9bp+0, -0x1.e370896404000p-4}, + {0x1.1ecf4494d480bp+0, -0x1.d17983ef94000p-4}, + {0x1.1d8f5528f6569p+0, -0x1.bf9674ed8a000p-4}, + {0x1.1c52311577e7cp+0, -0x1.adc79202f6000p-4}, + {0x1.1b17c74cb26e9p+0, -0x1.9c0c3e7288000p-4}, + {0x1.19e010c2c1ab6p+0, -0x1.8a646b372c000p-4}, + {0x1.18ab07bb670bdp+0, -0x1.78d01b3ac0000p-4}, + {0x1.1778a25efbcb6p+0, -0x1.674f145380000p-4}, + {0x1.1648d354c31dap+0, -0x1.55e0e6d878000p-4}, + {0x1.151b990275fddp+0, -0x1.4485cdea1e000p-4}, + {0x1.13f0ea432d24cp+0, -0x1.333d94d6aa000p-4}, + {0x1.12c8b7210f9dap+0, -0x1.22079f8c56000p-4}, + {0x1.11a3028ecb531p+0, -0x1.10e4698622000p-4}, + {0x1.107fbda8434afp+0, -0x1.ffa6c6ad20000p-5}, + {0x1.0f5ee0f4e6bb3p+0, -0x1.dda8d4a774000p-5}, + {0x1.0e4065d2a9fcep+0, -0x1.bbcece4850000p-5}, + {0x1.0d244632ca521p+0, -0x1.9a1894012c000p-5}, + {0x1.0c0a77ce2981ap+0, -0x1.788583302c000p-5}, + {0x1.0af2f83c636d1p+0, -0x1.5715e67d68000p-5}, + {0x1.09ddb98a01339p+0, -0x1.35c8a49658000p-5}, + {0x1.08cabaf52e7dfp+0, -0x1.149e364154000p-5}, + {0x1.07b9f2f4e28fbp+0, -0x1.e72c082eb8000p-6}, + {0x1.06ab58c358f19p+0, -0x1.a55f152528000p-6}, + {0x1.059eea5ecf92cp+0, -0x1.63d62cf818000p-6}, + {0x1.04949cdd12c90p+0, -0x1.228fb8caa0000p-6}, + {0x1.038c6c6f0ada9p+0, -0x1.c317b20f90000p-7}, + {0x1.02865137932a9p+0, -0x1.419355daa0000p-7}, + {0x1.0182427ea7348p+0, -0x1.81203c2ec0000p-8}, + {0x1.008040614b195p+0, -0x1.0040979240000p-9}, + {0x1.fe01ff726fa1ap-1, 0x1.feff384900000p-9}, + {0x1.fa11cc261ea74p-1, 0x1.7dc41353d0000p-7}, + {0x1.f6310b081992ep-1, 0x1.3cea3c4c28000p-6}, + {0x1.f25f63ceeadcdp-1, 0x1.b9fc114890000p-6}, + {0x1.ee9c8039113e7p-1, 0x1.1b0d8ce110000p-5}, + {0x1.eae8078cbb1abp-1, 0x1.58a5bd001c000p-5}, + {0x1.e741aa29d0c9bp-1, 0x1.95c8340d88000p-5}, + {0x1.e3a91830a99b5p-1, 0x1.d276aef578000p-5}, + {0x1.e01e009609a56p-1, 0x1.07598e598c000p-4}, + {0x1.dca01e577bb98p-1, 0x1.253f5e30d2000p-4}, + {0x1.d92f20b7c9103p-1, 0x1.42edd8b380000p-4}, + {0x1.d5cac66fb5ccep-1, 0x1.606598757c000p-4}, + {0x1.d272caa5ede9dp-1, 0x1.7da76356a0000p-4}, + {0x1.cf26e3e6b2ccdp-1, 0x1.9ab434e1c6000p-4}, + {0x1.cbe6da2a77902p-1, 0x1.b78c7bb0d6000p-4}, + {0x1.c8b266d37086dp-1, 0x1.d431332e72000p-4}, + {0x1.c5894bd5d5804p-1, 0x1.f0a3171de6000p-4}, + {0x1.c26b533bb9f8cp-1, 0x1.067152b914000p-3}, + {0x1.bf583eeece73fp-1, 0x1.147858292b000p-3}, + {0x1.bc4fd75db96c1p-1, 0x1.2266ecdca3000p-3}, + {0x1.b951e0c864a28p-1, 0x1.303d7a6c55000p-3}, + {0x1.b65e2c5ef3e2cp-1, 0x1.3dfc33c331000p-3}, + {0x1.b374867c9888bp-1, 0x1.4ba366b7a8000p-3}, + {0x1.b094b211d304ap-1, 0x1.5933928d1f000p-3}, + {0x1.adbe885f2ef7ep-1, 0x1.66acd2418f000p-3}, + {0x1.aaf1d31603da2p-1, 0x1.740f8ec669000p-3}, + {0x1.a82e63fd358a7p-1, 0x1.815c0f51af000p-3}, + {0x1.a5740ef09738bp-1, 0x1.8e92954f68000p-3}, + {0x1.a2c2a90ab4b27p-1, 0x1.9bb3602f84000p-3}, + {0x1.a01a01393f2d1p-1, 0x1.a8bed1c2c0000p-3}, + {0x1.9d79f24db3c1bp-1, 0x1.b5b515c01d000p-3}, + {0x1.9ae2505c7b190p-1, 0x1.c2967ccbcc000p-3}, + {0x1.9852ef297ce2fp-1, 0x1.cf635d5486000p-3}, + {0x1.95cbaeea44b75p-1, 0x1.dc1bd3446c000p-3}, + {0x1.934c69de74838p-1, 0x1.e8c01b8cfe000p-3}, + {0x1.90d4f2f6752e6p-1, 0x1.f5509c0179000p-3}, + {0x1.8e6528effd79dp-1, 0x1.00e6c121fb800p-2}, + {0x1.8bfce9fcc007cp-1, 0x1.071b80e93d000p-2}, + {0x1.899c0dabec30ep-1, 0x1.0d46b9e867000p-2}, + {0x1.87427aa2317fbp-1, 0x1.13687334bd000p-2}, + {0x1.84f00acb39a08p-1, 0x1.1980d67234800p-2}, + {0x1.82a49e8653e55p-1, 0x1.1f8ffe0cc8000p-2}, + {0x1.8060195f40260p-1, 0x1.2595fd7636800p-2}, + {0x1.7e22563e0a329p-1, 0x1.2b9300914a800p-2}, + {0x1.7beb377dcb5adp-1, 0x1.3187210436000p-2}, + {0x1.79baa679725c2p-1, 0x1.377266dec1800p-2}, + {0x1.77907f2170657p-1, 0x1.3d54ffbaf3000p-2}, + {0x1.756cadbd6130cp-1, 0x1.432eee32fe000p-2}, + }, +#if !__FP_FAST_FMA + .tab2 = + { + {0x1.61000014fb66bp-1, 0x1.e026c91425b3cp-56}, + {0x1.63000034db495p-1, 0x1.dbfea48005d41p-55}, + {0x1.650000d94d478p-1, 0x1.e7fa786d6a5b7p-55}, + {0x1.67000074e6fadp-1, 0x1.1fcea6b54254cp-57}, + {0x1.68ffffedf0faep-1, -0x1.c7e274c590efdp-56}, + {0x1.6b0000763c5bcp-1, -0x1.ac16848dcda01p-55}, + {0x1.6d0001e5cc1f6p-1, 0x1.33f1c9d499311p-55}, + {0x1.6efffeb05f63ep-1, -0x1.e80041ae22d53p-56}, + {0x1.710000e86978p-1, 0x1.bff6671097952p-56}, + {0x1.72ffffc67e912p-1, 0x1.c00e226bd8724p-55}, + {0x1.74fffdf81116ap-1, -0x1.e02916ef101d2p-57}, + {0x1.770000f679c9p-1, -0x1.7fc71cd549c74p-57}, + {0x1.78ffffa7ec835p-1, 0x1.1bec19ef50483p-55}, + {0x1.7affffe20c2e6p-1, -0x1.07e1729cc6465p-56}, + {0x1.7cfffed3fc9p-1, -0x1.08072087b8b1cp-55}, + {0x1.7efffe9261a76p-1, 0x1.dc0286d9df9aep-55}, + {0x1.81000049ca3e8p-1, 0x1.97fd251e54c33p-55}, + {0x1.8300017932c8fp-1, -0x1.afee9b630f381p-55}, + {0x1.850000633739cp-1, 0x1.9bfbf6b6535bcp-55}, + {0x1.87000204289c6p-1, -0x1.bbf65f3117b75p-55}, + {0x1.88fffebf57904p-1, -0x1.9006ea23dcb57p-55}, + {0x1.8b00022bc04dfp-1, -0x1.d00df38e04b0ap-56}, + {0x1.8cfffe50c1b8ap-1, -0x1.8007146ff9f05p-55}, + {0x1.8effffc918e43p-1, 0x1.3817bd07a7038p-55}, + {0x1.910001efa5fc7p-1, 0x1.93e9176dfb403p-55}, + {0x1.9300013467bb9p-1, 0x1.f804e4b980276p-56}, + {0x1.94fffe6ee076fp-1, -0x1.f7ef0d9ff622ep-55}, + {0x1.96fffde3c12d1p-1, -0x1.082aa962638bap-56}, + {0x1.98ffff4458a0dp-1, -0x1.7801b9164a8efp-55}, + {0x1.9afffdd982e3ep-1, -0x1.740e08a5a9337p-55}, + {0x1.9cfffed49fb66p-1, 0x1.fce08c19bep-60}, + {0x1.9f00020f19c51p-1, -0x1.a3faa27885b0ap-55}, + {0x1.a10001145b006p-1, 0x1.4ff489958da56p-56}, + {0x1.a300007bbf6fap-1, 0x1.cbeab8a2b6d18p-55}, + {0x1.a500010971d79p-1, 0x1.8fecadd78793p-55}, + {0x1.a70001df52e48p-1, -0x1.f41763dd8abdbp-55}, + {0x1.a90001c593352p-1, -0x1.ebf0284c27612p-55}, + {0x1.ab0002a4f3e4bp-1, -0x1.9fd043cff3f5fp-57}, + {0x1.acfffd7ae1ed1p-1, -0x1.23ee7129070b4p-55}, + {0x1.aefffee510478p-1, 0x1.a063ee00edea3p-57}, + {0x1.b0fffdb650d5bp-1, 0x1.a06c8381f0ab9p-58}, + {0x1.b2ffffeaaca57p-1, -0x1.9011e74233c1dp-56}, + {0x1.b4fffd995badcp-1, -0x1.9ff1068862a9fp-56}, + {0x1.b7000249e659cp-1, 0x1.aff45d0864f3ep-55}, + {0x1.b8ffff987164p-1, 0x1.cfe7796c2c3f9p-56}, + {0x1.bafffd204cb4fp-1, -0x1.3ff27eef22bc4p-57}, + {0x1.bcfffd2415c45p-1, -0x1.cffb7ee3bea21p-57}, + {0x1.beffff86309dfp-1, -0x1.14103972e0b5cp-55}, + {0x1.c0fffe1b57653p-1, 0x1.bc16494b76a19p-55}, + {0x1.c2ffff1fa57e3p-1, -0x1.4feef8d30c6edp-57}, + {0x1.c4fffdcbfe424p-1, -0x1.43f68bcec4775p-55}, + {0x1.c6fffed54b9f7p-1, 0x1.47ea3f053e0ecp-55}, + {0x1.c8fffeb998fd5p-1, 0x1.383068df992f1p-56}, + {0x1.cb0002125219ap-1, -0x1.8fd8e64180e04p-57}, + {0x1.ccfffdd94469cp-1, 0x1.e7ebe1cc7ea72p-55}, + {0x1.cefffeafdc476p-1, 0x1.ebe39ad9f88fep-55}, + {0x1.d1000169af82bp-1, 0x1.57d91a8b95a71p-56}, + {0x1.d30000d0ff71dp-1, 0x1.9c1906970c7dap-55}, + {0x1.d4fffea790fc4p-1, -0x1.80e37c558fe0cp-58}, + {0x1.d70002edc87e5p-1, -0x1.f80d64dc10f44p-56}, + {0x1.d900021dc82aap-1, -0x1.47c8f94fd5c5cp-56}, + {0x1.dafffd86b0283p-1, 0x1.c7f1dc521617ep-55}, + {0x1.dd000296c4739p-1, 0x1.8019eb2ffb153p-55}, + {0x1.defffe54490f5p-1, 0x1.e00d2c652cc89p-57}, + {0x1.e0fffcdabf694p-1, -0x1.f8340202d69d2p-56}, + {0x1.e2fffdb52c8ddp-1, 0x1.b00c1ca1b0864p-56}, + {0x1.e4ffff24216efp-1, 0x1.2ffa8b094ab51p-56}, + {0x1.e6fffe88a5e11p-1, -0x1.7f673b1efbe59p-58}, + {0x1.e9000119eff0dp-1, -0x1.4808d5e0bc801p-55}, + {0x1.eafffdfa51744p-1, 0x1.80006d54320b5p-56}, + {0x1.ed0001a127fa1p-1, -0x1.002f860565c92p-58}, + {0x1.ef00007babcc4p-1, -0x1.540445d35e611p-55}, + {0x1.f0ffff57a8d02p-1, -0x1.ffb3139ef9105p-59}, + {0x1.f30001ee58ac7p-1, 0x1.a81acf2731155p-55}, + {0x1.f4ffff5823494p-1, 0x1.a3f41d4d7c743p-55}, + {0x1.f6ffffca94c6bp-1, -0x1.202f41c987875p-57}, + {0x1.f8fffe1f9c441p-1, 0x1.77dd1f477e74bp-56}, + {0x1.fafffd2e0e37ep-1, -0x1.f01199a7ca331p-57}, + {0x1.fd0001c77e49ep-1, 0x1.181ee4bceacb1p-56}, + {0x1.feffff7e0c331p-1, -0x1.e05370170875ap-57}, + {0x1.00ffff465606ep+0, -0x1.a7ead491c0adap-55}, + {0x1.02ffff3867a58p+0, -0x1.77f69c3fcb2ep-54}, + {0x1.04ffffdfc0d17p+0, 0x1.7bffe34cb945bp-54}, + {0x1.0700003cd4d82p+0, 0x1.20083c0e456cbp-55}, + {0x1.08ffff9f2cbe8p+0, -0x1.dffdfbe37751ap-57}, + {0x1.0b000010cda65p+0, -0x1.13f7faee626ebp-54}, + {0x1.0d00001a4d338p+0, 0x1.07dfa79489ff7p-55}, + {0x1.0effffadafdfdp+0, -0x1.7040570d66bcp-56}, + {0x1.110000bbafd96p+0, 0x1.e80d4846d0b62p-55}, + {0x1.12ffffae5f45dp+0, 0x1.dbffa64fd36efp-54}, + {0x1.150000dd59ad9p+0, 0x1.a0077701250aep-54}, + {0x1.170000f21559ap+0, 0x1.dfdf9e2e3deeep-55}, + {0x1.18ffffc275426p+0, 0x1.10030dc3b7273p-54}, + {0x1.1b000123d3c59p+0, 0x1.97f7980030188p-54}, + {0x1.1cffff8299eb7p+0, -0x1.5f932ab9f8c67p-57}, + {0x1.1effff48ad4p+0, 0x1.37fbf9da75bebp-54}, + {0x1.210000c8b86a4p+0, 0x1.f806b91fd5b22p-54}, + {0x1.2300003854303p+0, 0x1.3ffc2eb9fbf33p-54}, + {0x1.24fffffbcf684p+0, 0x1.601e77e2e2e72p-56}, + {0x1.26ffff52921d9p+0, 0x1.ffcbb767f0c61p-56}, + {0x1.2900014933a3cp+0, -0x1.202ca3c02412bp-56}, + {0x1.2b00014556313p+0, -0x1.2808233f21f02p-54}, + {0x1.2cfffebfe523bp+0, -0x1.8ff7e384fdcf2p-55}, + {0x1.2f0000bb8ad96p+0, -0x1.5ff51503041c5p-55}, + {0x1.30ffffb7ae2afp+0, -0x1.10071885e289dp-55}, + {0x1.32ffffeac5f7fp+0, -0x1.1ff5d3fb7b715p-54}, + {0x1.350000ca66756p+0, 0x1.57f82228b82bdp-54}, + {0x1.3700011fbf721p+0, 0x1.000bac40dd5ccp-55}, + {0x1.38ffff9592fb9p+0, -0x1.43f9d2db2a751p-54}, + {0x1.3b00004ddd242p+0, 0x1.57f6b707638e1p-55}, + {0x1.3cffff5b2c957p+0, 0x1.a023a10bf1231p-56}, + {0x1.3efffeab0b418p+0, 0x1.87f6d66b152bp-54}, + {0x1.410001532aff4p+0, 0x1.7f8375f198524p-57}, + {0x1.4300017478b29p+0, 0x1.301e672dc5143p-55}, + {0x1.44fffe795b463p+0, 0x1.9ff69b8b2895ap-55}, + {0x1.46fffe80475ep+0, -0x1.5c0b19bc2f254p-54}, + {0x1.48fffef6fc1e7p+0, 0x1.b4009f23a2a72p-54}, + {0x1.4afffe5bea704p+0, -0x1.4ffb7bf0d7d45p-54}, + {0x1.4d000171027dep+0, -0x1.9c06471dc6a3dp-54}, + {0x1.4f0000ff03ee2p+0, 0x1.77f890b85531cp-54}, + {0x1.5100012dc4bd1p+0, 0x1.004657166a436p-57}, + {0x1.530001605277ap+0, -0x1.6bfcece233209p-54}, + {0x1.54fffecdb704cp+0, -0x1.902720505a1d7p-55}, + {0x1.56fffef5f54a9p+0, 0x1.bbfe60ec96412p-54}, + {0x1.5900017e61012p+0, 0x1.87ec581afef9p-55}, + {0x1.5b00003c93e92p+0, -0x1.f41080abf0ccp-54}, + {0x1.5d0001d4919bcp+0, -0x1.8812afb254729p-54}, + {0x1.5efffe7b87a89p+0, -0x1.47eb780ed6904p-54}, + }, +#endif +}; + +#define T __log_data.tab +#define T2 __log_data.tab2 +#define B __log_data.poly1 +#define A __log_data.poly +#define Ln2hi __log_data.ln2hi +#define Ln2lo __log_data.ln2lo +#define N (1 << LOG_TABLE_BITS) +#define OFF 0x3fe6000000000000 + +static inline uint32_t top16(double x) +{ + return asuint64(x) >> 48; +} + +double log(double x) +{ + double_t w, z, r, r2, r3, y, invc, logc, kd, hi, lo; + uint64_t ix, iz, tmp; + uint32_t top; + int k, i; + + ix = asuint64(x); + top = top16(x); +#define LO asuint64(1.0 - 0x1p-4) +#define HI asuint64(1.0 + 0x1.09p-4) + if (predict_false(ix - LO < HI - LO)) { + if (WANT_ROUNDING && predict_false(ix == asuint64(1.0))) + return 0; + r = x - 1.0; + r2 = r * r; + r3 = r * r2; + y = r3 * + (B[1] + r * B[2] + r2 * B[3] + + r3 * (B[4] + r * B[5] + r2 * B[6] + r3 * (B[7] + r * B[8] + r2 * B[9] + r3 * B[10]))); + w = r * 0x1p27; + double_t rhi = r + w - w; + double_t rlo = r - rhi; + w = rhi * rhi * B[0]; + hi = r + w; + lo = r - hi + w; + lo += B[0] * rlo * (rhi + r); + y += lo; + y += hi; + return eval_as_double(y); + } + if (predict_false(top - 0x0010 >= 0x7ff0 - 0x0010)) { + if (ix * 2 == 0) + return __math_divzero(1); + if (ix == asuint64(INFINITY)) + return x; + if ((top & 0x8000) || (top & 0x7ff0) == 0x7ff0) + return __math_invalid(x); + ix = asuint64(x * 0x1p52); + ix -= 52ULL << 52; + } + + tmp = ix - OFF; + i = (tmp >> (52 - LOG_TABLE_BITS)) % N; + k = (int64_t)tmp >> 52; + iz = ix - (tmp & 0xfffULL << 52); + invc = T[i].invc; + logc = T[i].logc; + z = asdouble(iz); + +#if __FP_FAST_FMA + r = __builtin_fma(z, invc, -1.0); +#else + r = (z - T2[i].chi - T2[i].clo) * invc; +#endif + + kd = (double_t)k; + w = kd * Ln2hi + logc; + hi = w + r; + lo = w - hi + r + kd * Ln2lo; + r2 = r * r; + y = lo + r2 * A[0] + r * r2 * (A[1] + r * A[2] + r2 * (A[3] + r * A[4])) + hi; + return eval_as_double(y); +} + +#endif // AX_CONFIG_FP_SIMD diff --git a/tools/axlibc/c/math.c b/tools/axlibc/c/math.c new file mode 100644 index 0000000..04ee1e7 --- /dev/null +++ b/tools/axlibc/c/math.c @@ -0,0 +1,571 @@ +#ifdef AX_CONFIG_FP_SIMD + +#include +#include +#include +#include + +#include "libm.h" + +int __fpclassify(double x) +{ + union { + double f; + uint64_t i; + } u = {x}; + int e = u.i >> 52 & 0x7ff; + if (!e) + return u.i << 1 ? FP_SUBNORMAL : FP_ZERO; + if (e == 0x7ff) + return u.i << 12 ? FP_NAN : FP_INFINITE; + return FP_NORMAL; +} + +int __fpclassifyf(float x) +{ + union { + float f; + uint32_t i; + } u = {x}; + int e = u.i >> 23 & 0xff; + if (!e) + return u.i << 1 ? FP_SUBNORMAL : FP_ZERO; + if (e == 0xff) + return u.i << 9 ? FP_NAN : FP_INFINITE; + return FP_NORMAL; +} + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +int __fpclassifyl(long double x) +{ + return __fpclassify(x); +} +#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 +int __fpclassifyl(long double x) +{ + union ldshape u = {x}; + int e = u.i.se & 0x7fff; + int msb = u.i.m >> 63; + if (!e && !msb) + return u.i.m ? FP_SUBNORMAL : FP_ZERO; + if (e == 0x7fff) { + /* The x86 variant of 80-bit extended precision only admits + * one representation of each infinity, with the mantissa msb + * necessarily set. The version with it clear is invalid/nan. + * The m68k variant, however, allows either, and tooling uses + * the version with it clear. */ + if (__BYTE_ORDER == __LITTLE_ENDIAN && !msb) + return FP_NAN; + return u.i.m << 1 ? FP_NAN : FP_INFINITE; + } + if (!msb) + return FP_NAN; + return FP_NORMAL; +} +#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 +int __fpclassifyl(long double x) +{ + union ldshape u = {x}; + int e = u.i.se & 0x7fff; + u.i.se = 0; + if (!e) + return u.i2.lo | u.i2.hi ? FP_SUBNORMAL : FP_ZERO; + if (e == 0x7fff) + return u.i2.lo | u.i2.hi ? FP_NAN : FP_INFINITE; + return FP_NORMAL; +} +#endif + +double fabs(double x) +{ + union { + double f; + uint64_t i; + } u = {x}; + u.i &= -1ULL / 2; + return u.f; +} + +static const double toint = 1 / DBL_EPSILON; + +double floor(double x) +{ + union { + double f; + uint64_t i; + } u = {x}; + int e = u.i >> 52 & 0x7ff; + double y; + + if (e >= 0x3ff + 52 || x == 0) + return x; + /* y = int(x) - x, where int(x) is an integer neighbor of x */ + if (u.i >> 63) + y = x - toint + toint - x; + else + y = x + toint - toint - x; + /* special case because of non-nearest rounding modes */ + if (e <= 0x3ff - 1) { + FORCE_EVAL(y); + return u.i >> 63 ? -1 : 0; + } + if (y > 0) + return x + y - 1; + return x + y; +} + +double rint(double x) +{ + unimplemented(); + return 0; +} + +long long llrint(double x) +{ + return rint(x); +} + +double sqrt(double x) +{ + unimplemented(); + return 0; +} + +double round(double x) +{ + unimplemented(); + return x; +} + +long double roundl(long double x) +{ + unimplemented(); + return x; +} + +long long llroundl(long double x) +{ + unimplemented(); + return x; +} + +double cos(double __x) +{ + unimplemented(); + return 0; +} + +double ceil(double x) +{ + union { + double f; + uint64_t i; + } u = {x}; + int e = u.i >> 52 & 0x7ff; + double_t y; + + if (e >= 0x3ff + 52 || x == 0) + return x; + if (u.i >> 63) + y = x - toint + toint - x; + else + y = x + toint - toint - x; + if (e <= 0x3ff - 1) { + FORCE_EVAL(y); + return u.i >> 63 ? -0.0 : 1; + } + if (y < 0) + return x + y + 1; + return x + y; +} + +// TODO +double sin(double __x) +{ + unimplemented(); + return 0; +} + +// TODO +double asin(double __x) +{ + unimplemented(); + return 0; +} + +long double ceill(long double x) +{ + unimplemented(); + return x; +} + +double acos(double x) +{ + unimplemented(); + return 0; +} + +// TODO +double atan(double x) +{ + unimplemented(); + return 0; +} + +// TODO +double atan2(double y, double x) +{ + unimplemented(); + return 0; +} + +double cosh(double x) +{ + unimplemented(); + return 0; +} + +// TODO +double exp(double x) +{ + unimplemented(); + return 0; +} + +// TODO +double frexp(double x, int *e) +{ + unimplemented(); + return 0; +} + +double ldexp(double x, int n) +{ + unimplemented(); + return 0; +} + +// TODO +double log10(double x) +{ + unimplemented(); + return 0; +} + +// TODO +double modf(double x, double *iptr) +{ + unimplemented(); + return 0; +} + +double sinh(double x) +{ + unimplemented(); + return 0; +} + +// TODO +double tan(double x) +{ + unimplemented(); + return 0; +} + +// TODO +double tanh(double x) +{ + unimplemented(); + return 0; +} + +double copysign(double x, double y) +{ + union { + double f; + uint64_t i; + } ux = {x}, uy = {y}; + ux.i &= -1ULL / 2; + ux.i |= uy.i & 1ULL << 63; + return ux.f; +} + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double copysignl(long double x, long double y) +{ + return copysign(x, y); +} +#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 +long double copysignl(long double x, long double y) +{ + union ldshape ux = {x}, uy = {y}; + ux.i.se &= 0x7fff; + ux.i.se |= uy.i.se & 0x8000; + return ux.f; +} +#endif + +double scalbn(double x, int n) +{ + union { + double f; + uint64_t i; + } u; + double_t y = x; + + if (n > 1023) { + y *= 0x1p1023; + n -= 1023; + if (n > 1023) { + y *= 0x1p1023; + n -= 1023; + if (n > 1023) + n = 1023; + } + } else if (n < -1022) { + /* make sure final n < -53 to avoid double + rounding in the subnormal range */ + y *= 0x1p-1022 * 0x1p53; + n += 1022 - 53; + if (n < -1022) { + y *= 0x1p-1022 * 0x1p53; + n += 1022 - 53; + if (n < -1022) + n = -1022; + } + } + u.i = (uint64_t)(0x3ff + n) << 52; + x = y * u.f; + return x; +} + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double scalbnl(long double x, int n) +{ + return scalbn(x, n); +} +#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 +long double scalbnl(long double x, int n) +{ + union ldshape u; + + if (n > 16383) { + x *= 0x1p16383L; + n -= 16383; + if (n > 16383) { + x *= 0x1p16383L; + n -= 16383; + if (n > 16383) + n = 16383; + } + } else if (n < -16382) { + x *= 0x1p-16382L * 0x1p113L; + n += 16382 - 113; + if (n < -16382) { + x *= 0x1p-16382L * 0x1p113L; + n += 16382 - 113; + if (n < -16382) + n = -16382; + } + } + u.f = 1.0; + u.i.se = 0x3fff + n; + return x * u.f; +} +#endif + +double fmod(double x, double y) +{ + union { + double f; + uint64_t i; + } ux = {x}, uy = {y}; + int ex = ux.i >> 52 & 0x7ff; + int ey = uy.i >> 52 & 0x7ff; + int sx = ux.i >> 63; + uint64_t i; + + /* in the followings uxi should be ux.i, but then gcc wrongly adds */ + /* float load/store to inner loops ruining performance and code size */ + uint64_t uxi = ux.i; + + if (uy.i << 1 == 0 || isnan(y) || ex == 0x7ff) + return (x * y) / (x * y); + if (uxi << 1 <= uy.i << 1) { + if (uxi << 1 == uy.i << 1) + return 0 * x; + return x; + } + + /* normalize x and y */ + if (!ex) { + for (i = uxi << 12; i >> 63 == 0; ex--, i <<= 1) + ; + uxi <<= -ex + 1; + } else { + uxi &= -1ULL >> 12; + uxi |= 1ULL << 52; + } + if (!ey) { + for (i = uy.i << 12; i >> 63 == 0; ey--, i <<= 1) + ; + uy.i <<= -ey + 1; + } else { + uy.i &= -1ULL >> 12; + uy.i |= 1ULL << 52; + } + + /* x mod y */ + for (; ex > ey; ex--) { + i = uxi - uy.i; + if (i >> 63 == 0) { + if (i == 0) + return 0 * x; + uxi = i; + } + uxi <<= 1; + } + i = uxi - uy.i; + if (i >> 63 == 0) { + if (i == 0) + return 0 * x; + uxi = i; + } + for (; uxi >> 52 == 0; uxi <<= 1, ex--) + ; + + /* scale result */ + if (ex > 0) { + uxi -= 1ULL << 52; + uxi |= (uint64_t)ex << 52; + } else { + uxi >>= -ex + 1; + } + uxi |= (uint64_t)sx << 63; + ux.i = uxi; + return ux.f; +} + +// x86_64 has specific implementation +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double fmodl(long double x, long double y) +{ + return fmod(x, y); +} +#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 +long double fmodl(long double x, long double y) +{ + union ldshape ux = {x}, uy = {y}; + int ex = ux.i.se & 0x7fff; + int ey = uy.i.se & 0x7fff; + int sx = ux.i.se & 0x8000; + + if (y == 0 || isnan(y) || ex == 0x7fff) + return (x * y) / (x * y); + ux.i.se = ex; + uy.i.se = ey; + if (ux.f <= uy.f) { + if (ux.f == uy.f) + return 0 * x; + return x; + } + + /* normalize x and y */ + if (!ex) { + ux.f *= 0x1p120f; + ex = ux.i.se - 120; + } + if (!ey) { + uy.f *= 0x1p120f; + ey = uy.i.se - 120; + } + + /* x mod y */ +#if LDBL_MANT_DIG == 64 + uint64_t i, mx, my; + mx = ux.i.m; + my = uy.i.m; + for (; ex > ey; ex--) { + i = mx - my; + if (mx >= my) { + if (i == 0) + return 0 * x; + mx = 2 * i; + } else if (2 * mx < mx) { + mx = 2 * mx - my; + } else { + mx = 2 * mx; + } + } + i = mx - my; + if (mx >= my) { + if (i == 0) + return 0 * x; + mx = i; + } + for (; mx >> 63 == 0; mx *= 2, ex--) + ; + ux.i.m = mx; +#elif LDBL_MANT_DIG == 113 + uint64_t hi, lo, xhi, xlo, yhi, ylo; + xhi = (ux.i2.hi & -1ULL >> 16) | 1ULL << 48; + yhi = (uy.i2.hi & -1ULL >> 16) | 1ULL << 48; + xlo = ux.i2.lo; + ylo = uy.i2.lo; + for (; ex > ey; ex--) { + hi = xhi - yhi; + lo = xlo - ylo; + if (xlo < ylo) + hi -= 1; + if (hi >> 63 == 0) { + if ((hi | lo) == 0) + return 0 * x; + xhi = 2 * hi + (lo >> 63); + xlo = 2 * lo; + } else { + xhi = 2 * xhi + (xlo >> 63); + xlo = 2 * xlo; + } + } + hi = xhi - yhi; + lo = xlo - ylo; + if (xlo < ylo) + hi -= 1; + if (hi >> 63 == 0) { + if ((hi | lo) == 0) + return 0 * x; + xhi = hi; + xlo = lo; + } + for (; xhi >> 48 == 0; xhi = 2 * xhi + (xlo >> 63), xlo = 2 * xlo, ex--) + ; + ux.i2.hi = xhi; + ux.i2.lo = xlo; +#endif + + /* scale result */ + if (ex <= 0) { + ux.i.se = (ex + 120) | sx; + ux.f *= 0x1p-120f; + } else + ux.i.se = ex | sx; + return ux.f; +} +#endif + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double fabsl(long double x) +{ + return fabs(x); +} +#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 +long double fabsl(long double x) +{ + union ldshape u = {x}; + + u.i.se &= 0x7fff; + return u.f; +} +#endif + +#endif // AX_CONFIG_FP_SIMD diff --git a/tools/axlibc/c/mmap.c b/tools/axlibc/c/mmap.c new file mode 100644 index 0000000..e3204d7 --- /dev/null +++ b/tools/axlibc/c/mmap.c @@ -0,0 +1,39 @@ +#include +#include +#include + +// TODO: +void *mmap(void *addr, size_t len, int prot, int flags, int fildes, off_t off) +{ + unimplemented(); + return MAP_FAILED; +} + +// TODO: +int munmap(void *addr, size_t length) +{ + unimplemented(); + return 0; +} + +// TODO: +void *mremap(void *old_address, size_t old_size, size_t new_size, int flags, + ... /* void *new_address */) +{ + unimplemented(); + return NULL; +} + +// TODO +int mprotect(void *addr, size_t len, int prot) +{ + unimplemented(); + return 0; +} + +// TODO +int madvise(void *addr, size_t len, int advice) +{ + unimplemented(); + return 0; +} diff --git a/tools/axlibc/c/network.c b/tools/axlibc/c/network.c new file mode 100644 index 0000000..4c6beb8 --- /dev/null +++ b/tools/axlibc/c/network.c @@ -0,0 +1,226 @@ +#ifdef AX_CONFIG_NET + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +int h_errno; + +static const char gai_msgs[] = "Invalid flags\0" + "Name does not resolve\0" + "Try again\0" + "Non-recoverable error\0" + "Unknown error\0" + "Unrecognized address family or invalid length\0" + "Unrecognized socket type\0" + "Unrecognized service\0" + "Unknown error\0" + "Out of memory\0" + "System error\0" + "Overflow\0" + "\0Unknown error"; + +const char *gai_strerror(int ecode) +{ + const char *s; + for (s = gai_msgs, ecode++; ecode && *s; ecode++, s++) + for (; *s; s++) + ; + if (!*s) + s++; + return s; +} + +static const char msgs[] = "Host not found\0" + "Try again\0" + "Non-recoverable error\0" + "Address not available\0" + "\0Unknown error"; + +const char *hstrerror(int ecode) +{ + const char *s; + for (s = msgs, ecode--; ecode && *s; ecode--, s++) + for (; *s; s++) + ; + if (!*s) + s++; + return s; +} + +static __inline uint16_t __bswap_16(uint16_t __x) +{ + return __x << 8 | __x >> 8; +} + +static __inline uint32_t __bswap_32(uint32_t __x) +{ + return __x >> 24 | (__x >> 8 & 0xff00) | (__x << 8 & 0xff0000) | __x << 24; +} + +uint32_t htonl(uint32_t n) +{ + union { + int i; + char c; + } u = {1}; + return u.c ? __bswap_32(n) : n; +} + +uint16_t htons(uint16_t n) +{ + union { + int i; + char c; + } u = {1}; + return u.c ? __bswap_16(n) : n; +} + +uint32_t ntohl(uint32_t n) +{ + union { + int i; + char c; + } u = {1}; + return u.c ? __bswap_32(n) : n; +} + +uint16_t ntohs(uint16_t n) +{ + union { + int i; + char c; + } u = {1}; + return u.c ? __bswap_16(n) : n; +} + +static int hexval(unsigned c) +{ + if (c - '0' < 10) + return c - '0'; + c |= 32; + if (c - 'a' < 6) + return c - 'a' + 10; + return -1; +} + +int inet_pton(int af, const char *__restrict s, void *__restrict a0) +{ + uint16_t ip[8]; + unsigned char *a = a0; + int i, j, v, d, brk = -1, need_v4 = 0; + + if (af == AF_INET) { + for (i = 0; i < 4; i++) { + for (v = j = 0; j < 3 && isdigit(s[j]); j++) v = 10 * v + s[j] - '0'; + if (j == 0 || (j > 1 && s[0] == '0') || v > 255) + return 0; + a[i] = v; + if (s[j] == 0 && i == 3) + return 1; + if (s[j] != '.') + return 0; + s += j + 1; + } + return 0; + } else if (af != AF_INET6) { + errno = EAFNOSUPPORT; + return -1; + } + + if (*s == ':' && *++s != ':') + return 0; + + for (i = 0;; i++) { + if (s[0] == ':' && brk < 0) { + brk = i; + ip[i & 7] = 0; + if (!*++s) + break; + if (i == 7) + return 0; + continue; + } + for (v = j = 0; j < 4 && (d = hexval(s[j])) >= 0; j++) v = 16 * v + d; + if (j == 0) + return 0; + ip[i & 7] = v; + if (!s[j] && (brk >= 0 || i == 7)) + break; + if (i == 7) + return 0; + if (s[j] != ':') { + if (s[j] != '.' || (i < 6 && brk < 0)) + return 0; + need_v4 = 1; + i++; + break; + } + s += j + 1; + } + if (brk >= 0) { + for (j = 0; j < 7 - i; j++) ip[brk + j] = 0; + memmove(ip + brk + 7 - i, ip + brk, 2 * (i + 1 - brk)); + } + for (j = 0; j < 8; j++) { + *a++ = ip[j] >> 8; + *a++ = ip[j]; + } + if (need_v4 && inet_pton(AF_INET, (void *)s, a - 4) <= 0) + return 0; + return 1; +} + +const char *inet_ntop(int af, const void *__restrict a0, char *__restrict s, socklen_t l) +{ + const unsigned char *a = a0; + int i, j, max, best; + char buf[100]; + + switch (af) { + case AF_INET: + if (snprintf(s, l, "%d.%d.%d.%d", a[0], a[1], a[2], a[3]) < l) + return s; + break; + case AF_INET6: + if (memcmp(a, "\0\0\0\0\0\0\0\0\0\0\377\377", 12)) + snprintf(buf, sizeof buf, "%x:%x:%x:%x:%x:%x:%x:%x", 256 * a[0] + a[1], + 256 * a[2] + a[3], 256 * a[4] + a[5], 256 * a[6] + a[7], 256 * a[8] + a[9], + 256 * a[10] + a[11], 256 * a[12] + a[13], 256 * a[14] + a[15]); + else + snprintf(buf, sizeof buf, "%x:%x:%x:%x:%x:%x:%d.%d.%d.%d", 256 * a[0] + a[1], + 256 * a[2] + a[3], 256 * a[4] + a[5], 256 * a[6] + a[7], 256 * a[8] + a[9], + 256 * a[10] + a[11], a[12], a[13], a[14], a[15]); + /* Replace longest /(^0|:)[:0]{2,}/ with "::" */ + for (i = best = 0, max = 2; buf[i]; i++) { + if (i && buf[i] != ':') + continue; + j = strspn(buf + i, ":0"); + if (j > max) + best = i, max = j; + } + if (max > 3) { + buf[best] = buf[best + 1] = ':'; + memmove(buf + best + 2, buf + best + max, i - best - max + 1); + } + if (strlen(buf) < l) { + strcpy(s, buf); + return s; + } + break; + default: + errno = EAFNOSUPPORT; + return 0; + } + errno = ENOSPC; + return 0; +} + +#endif // AX_CONFIG_NET diff --git a/tools/axlibc/c/poll.c b/tools/axlibc/c/poll.c new file mode 100644 index 0000000..5474246 --- /dev/null +++ b/tools/axlibc/c/poll.c @@ -0,0 +1,9 @@ +#include +#include + +// TODO +int poll(struct pollfd *__fds, nfds_t __nfds, int __timeout) +{ + unimplemented(); + return 0; +} diff --git a/tools/axlibc/c/pow.c b/tools/axlibc/c/pow.c new file mode 100644 index 0000000..2172011 --- /dev/null +++ b/tools/axlibc/c/pow.c @@ -0,0 +1,815 @@ +#if defined(AX_CONFIG_FP_SIMD) + +#include +#include +#include +#include +#include + +#include "libm.h" + +#define OFF 0x3fe6955500000000 + +#define POW_LOG_TABLE_BITS 7 +#define POW_LOG_POLY_ORDER 8 +#define N (1 << POW_LOG_TABLE_BITS) +struct pow_log_data { + double ln2hi; + double ln2lo; + double poly[POW_LOG_POLY_ORDER - 1]; /* First coefficient is 1. */ + /* Note: the pad field is unused, but allows slightly faster indexing. */ + struct { + double invc, pad, logc, logctail; + } tab[1 << POW_LOG_TABLE_BITS]; +}; + +const struct + pow_log_data + __pow_log_data = + { + .ln2hi = 0x1.62e42fefa3800p-1, + .ln2lo = 0x1.ef35793c76730p-45, + .poly = + { + -0x1p-1, + 0x1.555555555556p-2 * -2, + -0x1.0000000000006p-2 * -2, + 0x1.999999959554ep-3 * 4, + -0x1.555555529a47ap-3 * 4, + 0x1.2495b9b4845e9p-3 * -8, + -0x1.0002b8b263fc3p-3 * -8, + }, + .tab = + { +#define A(a, b, c) {a, 0, b, c}, + A(0x1.6a00000000000p+0, -0x1.62c82f2b9c800p-2, 0x1.ab42428375680p-48) + A(0x1.6800000000000p+0, -0x1.5d1bdbf580800p-2, -0x1.ca508d8e0f720p-46) + A(0x1.6600000000000p+0, -0x1.5767717455800p-2, + -0x1.362a4d5b6506dp-45) + A(0x1.6400000000000p+0, -0x1.51aad872df800p-2, + -0x1.684e49eb067d5p-49) A(0x1.6200000000000p+0, + -0x1.4be5f95777800p-2, + -0x1.41b6993293ee0p-47) A(0x1.6000000000000p+0, -0x1.4618bc21c6000p-2, 0x1.3d82f484c84ccp-46) A(0x1.5e00000000000p+0, -0x1.404308686a800p-2, 0x1.c42f3ed820b3ap-50) A(0x1.5c00000000000p+0, -0x1.3a64c55694800p-2, 0x1.0b1c686519460p-45) A(0x1.5a00000000000p+0, -0x1.347dd9a988000p-2, 0x1.5594dd4c58092p-45) A(0x1.5800000000000p+0, -0x1.2e8e2bae12000p-2, 0x1.67b1e99b72bd8p-45) A(0x1.5600000000000p+0, + -0x1.2895a13de8800p-2, 0x1.5ca14b6cfb03fp-46) A(0x1.5600000000000p+0, + -0x1.2895a13de8800p-2, 0x1.5ca14b6cfb03fp-46) A(0x1.5400000000000p+0, + -0x1.22941fbcf7800p-2, + -0x1.65a242853da76p-46) A(0x1.5200000000000p+0, + -0x1.1c898c1699800p-2, + -0x1.fafbc68e75404p-46) A(0x1.5000000000000p+0, + -0x1.1675cababa800p-2, 0x1.f1fc63382a8f0p-46) A(0x1.4e00000000000p+0, + -0x1.1058bf9ae4800p-2, + -0x1.6a8c4fd055a66p-45) A(0x1.4c00000000000p+0, + -0x1.0a324e2739000p-2, -0x1.c6bee7ef4030ep-47) A(0x1.4a00000000000p+0, + -0x1.0402594b4d000p-2, -0x1.036b89ef42d7fp-48) A(0x1.4a00000000000p+0, + -0x1.0402594b4d000p-2, -0x1.036b89ef42d7fp-48) A(0x1.4800000000000p+0, + -0x1.fb9186d5e4000p-3, + 0x1.d572aab993c87p-47) A(0x1.4600000000000p+0, + -0x1.ef0adcbdc6000p-3, + 0x1.b26b79c86af24p-45) A(0x1.4400000000000p+0, + -0x1.e27076e2af000p-3, -0x1.72f4f543fff10p-46) A(0x1.4200000000000p+0, + -0x1.d5c216b4fc000p-3, 0x1.1ba91bbca681bp-45) A(0x1.4000000000000p+0, -0x1.c8ff7c79aa000p-3, 0x1.7794f689f8434p-45) A(0x1.4000000000000p+0, -0x1.c8ff7c79aa000p-3, 0x1.7794f689f8434p-45) A(0x1.3e00000000000p+0, + -0x1.bc286742d9000p-3, 0x1.94eb0318bb78fp-46) A(0x1.3c00000000000p+0, + -0x1.af3c94e80c000p-3, 0x1.a4e633fcd9066p-52) A(0x1.3a00000000000p+0, + -0x1.a23bc1fe2b000p-3, + -0x1.58c64dc46c1eap-45) A(0x1.3a00000000000p+0, + -0x1.a23bc1fe2b000p-3, -0x1.58c64dc46c1eap-45) A(0x1.3800000000000p+0, + -0x1.9525a9cf45000p-3, -0x1.ad1d904c1d4e3p-45) A(0x1.3600000000000p+0, + -0x1.87fa06520d000p-3, 0x1.bbdbf7fdbfa09p-45) A(0x1.3400000000000p+0, + -0x1.7ab890210e000p-3, 0x1.bdb9072534a58p-45) A(0x1.3400000000000p+0, + -0x1.7ab890210e000p-3, 0x1.bdb9072534a58p-45) A(0x1.3200000000000p+0, -0x1.6d60fe719d000p-3, -0x1.0e46aa3b2e266p-46) A(0x1.3000000000000p+0, + -0x1.5ff3070a79000p-3, -0x1.e9e439f105039p-46) A(0x1.3000000000000p+0, + -0x1.5ff3070a79000p-3, -0x1.e9e439f105039p-46) A(0x1.2e00000000000p+0, + -0x1.526e5e3a1b000p-3, -0x1.0de8b90075b8fp-45) A(0x1.2c00000000000p+0, + -0x1.44d2b6ccb8000p-3, 0x1.70cc16135783cp-46) A(0x1.2c00000000000p+0, -0x1.44d2b6ccb8000p-3, 0x1.70cc16135783cp-46) A(0x1.2a00000000000p+0, + -0x1.371fc201e9000p-3, 0x1.178864d27543ap-48) A(0x1.2800000000000p+0, + -0x1.29552f81ff000p-3, -0x1.48d301771c408p-45) A(0x1.2600000000000p+0, -0x1.1b72ad52f6000p-3, -0x1.e80a41811a396p-45) A(0x1.2600000000000p+0, -0x1.1b72ad52f6000p-3, -0x1.e80a41811a396p-45) A(0x1.2400000000000p+0, + -0x1.0d77e7cd09000p-3, + 0x1.a699688e85bf4p-47) A(0x1.2400000000000p+0, -0x1.0d77e7cd09000p-3, 0x1.a699688e85bf4p-47) A(0x1.2200000000000p+0, -0x1.fec9131dbe000p-4, -0x1.575545ca333f2p-45) A(0x1.2000000000000p+0, + -0x1.e27076e2b0000p-4, 0x1.a342c2af0003cp-45) A(0x1.2000000000000p+0, -0x1.e27076e2b0000p-4, 0x1.a342c2af0003cp-45) A(0x1.1e00000000000p+0, -0x1.c5e548f5bc000p-4, -0x1.d0c57585fbe06p-46) A(0x1.1c00000000000p+0, + -0x1.a926d3a4ae000p-4, 0x1.53935e85baac8p-45) A(0x1.1c00000000000p+0, + -0x1.a926d3a4ae000p-4, 0x1.53935e85baac8p-45) A(0x1.1a00000000000p+0, -0x1.8c345d631a000p-4, 0x1.37c294d2f5668p-46) A(0x1.1a00000000000p+0, + -0x1.8c345d631a000p-4, + 0x1.37c294d2f5668p-46) A(0x1.1800000000000p+0, -0x1.6f0d28ae56000p-4, + -0x1.69737c93373dap-45) A(0x1.1600000000000p+0, + -0x1.51b073f062000p-4, 0x1.f025b61c65e57p-46) A(0x1.1600000000000p+0, + -0x1.51b073f062000p-4, 0x1.f025b61c65e57p-46) A(0x1.1400000000000p+0, -0x1.341d7961be000p-4, 0x1.c5edaccf913dfp-45) A(0x1.1400000000000p+0, + -0x1.341d7961be000p-4, 0x1.c5edaccf913dfp-45) A(0x1.1200000000000p+0, -0x1.16536eea38000p-4, 0x1.47c5e768fa309p-46) A(0x1.1000000000000p+0, + -0x1.f0a30c0118000p-5, 0x1.d599e83368e91p-45) A(0x1.1000000000000p+0, -0x1.f0a30c0118000p-5, + 0x1.d599e83368e91p-45) A(0x1.0e00000000000p+0, + -0x1.b42dd71198000p-5, 0x1.c827ae5d6704cp-46) A(0x1.0e00000000000p+0, + -0x1.b42dd71198000p-5, 0x1.c827ae5d6704cp-46) A(0x1.0c00000000000p+0, + -0x1.77458f632c000p-5, -0x1.cfc4634f2a1eep-45) A(0x1.0c00000000000p+0, -0x1.77458f632c000p-5, -0x1.cfc4634f2a1eep-45) A(0x1.0a00000000000p+0, -0x1.39e87b9fec000p-5, 0x1.502b7f526feaap-48) A(0x1.0a00000000000p+0, + -0x1.39e87b9fec000p-5, 0x1.502b7f526feaap-48) A(0x1.0800000000000p+0, -0x1.f829b0e780000p-6, -0x1.980267c7e09e4p-45) A(0x1.0800000000000p+0, -0x1.f829b0e780000p-6, -0x1.980267c7e09e4p-45) A(0x1.0600000000000p+0, + -0x1.7b91b07d58000p-6, -0x1.88d5493faa639p-45) A(0x1.0400000000000p+0, + -0x1.fc0a8b0fc0000p-7, -0x1.f1e7cf6d3a69cp-50) A(0x1.0400000000000p+0, -0x1.fc0a8b0fc0000p-7, -0x1.f1e7cf6d3a69cp-50) A(0x1.0200000000000p+0, -0x1.fe02a6b100000p-8, -0x1.9e23f0dda40e4p-46) A(0x1.0200000000000p+0, + -0x1.fe02a6b100000p-8, + -0x1.9e23f0dda40e4p-46) A(0x1.0000000000000p+0, + 0x0.0000000000000p+0, 0x0.0000000000000p+0) A(0x1.0000000000000p+0, + 0x0.0000000000000p+0, + 0x0.0000000000000p+0) A(0x1.fc00000000000p-1, + 0x1.0101575890000p-7, -0x1.0c76b999d2be8p-46) A(0x1.f800000000000p-1, + 0x1.0205658938000p-6, -0x1.3dc5b06e2f7d2p-45) A(0x1.f400000000000p-1, + 0x1.8492528c90000p-6, + -0x1.aa0ba325a0c34p-45) A(0x1.f000000000000p-1, + 0x1.0415d89e74000p-5, + 0x1.111c05cf1d753p-47) A(0x1.ec00000000000p-1, 0x1.466aed42e0000p-5, -0x1.c167375bdfd28p-45) A(0x1.e800000000000p-1, + 0x1.894aa149fc000p-5, + -0x1.97995d05a267dp-46) A(0x1.e400000000000p-1, + 0x1.ccb73cdddc000p-5, -0x1.a68f247d82807p-46) A(0x1.e200000000000p-1, + 0x1.eea31c006c000p-5, + -0x1.e113e4fc93b7bp-47) A(0x1.de00000000000p-1, + 0x1.1973bd1466000p-4, + -0x1.5325d560d9e9bp-45) A(0x1.da00000000000p-1, 0x1.3bdf5a7d1e000p-4, 0x1.cc85ea5db4ed7p-45) A(0x1.d600000000000p-1, 0x1.5e95a4d97a000p-4, -0x1.c69063c5d1d1ep-45) A(0x1.d400000000000p-1, 0x1.700d30aeac000p-4, 0x1.c1e8da99ded32p-49) A(0x1.d000000000000p-1, + 0x1.9335e5d594000p-4, + 0x1.3115c3abd47dap-45) A(0x1.cc00000000000p-1, + 0x1.b6ac88dad6000p-4, + -0x1.390802bf768e5p-46) A(0x1.ca00000000000p-1, + 0x1.c885801bc4000p-4, + 0x1.646d1c65aacd3p-45) A(0x1.c600000000000p-1, + 0x1.ec739830a2000p-4, + -0x1.dc068afe645e0p-45) A(0x1.c400000000000p-1, + 0x1.fe89139dbe000p-4, + -0x1.534d64fa10afdp-45) A(0x1.c000000000000p-1, 0x1.1178e8227e000p-3, 0x1.1ef78ce2d07f2p-45) A(0x1.be00000000000p-1, 0x1.1aa2b7e23f000p-3, 0x1.ca78e44389934p-45) A(0x1.ba00000000000p-1, 0x1.2d1610c868000p-3, 0x1.39d6ccb81b4a1p-47) A(0x1.b800000000000p-1, 0x1.365fcb0159000p-3, 0x1.62fa8234b7289p-51) A(0x1.b400000000000p-1, 0x1.4913d8333b000p-3, 0x1.5837954fdb678p-45) A(0x1.b200000000000p-1, 0x1.527e5e4a1b000p-3, + 0x1.633e8e5697dc7p-45) A(0x1.ae00000000000p-1, + 0x1.6574ebe8c1000p-3, + 0x1.9cf8b2c3c2e78p-46) A(0x1.ac00000000000p-1, + 0x1.6f0128b757000p-3, -0x1.5118de59c21e1p-45) A(0x1.aa00000000000p-1, 0x1.7898d85445000p-3, -0x1.c661070914305p-46) A(0x1.a600000000000p-1, + 0x1.8beafeb390000p-3, -0x1.73d54aae92cd1p-47) A(0x1.a400000000000p-1, 0x1.95a5adcf70000p-3, 0x1.7f22858a0ff6fp-47) A(0x1.a000000000000p-1, 0x1.a93ed3c8ae000p-3, -0x1.8724350562169p-45) A(0x1.9e00000000000p-1, 0x1.b31d8575bd000p-3, -0x1.c358d4eace1aap-47) A(0x1.9c00000000000p-1, 0x1.bd087383be000p-3, -0x1.d4bc4595412b6p-45) A(0x1.9a00000000000p-1, 0x1.c6ffbc6f01000p-3, -0x1.1ec72c5962bd2p-48) A(0x1.9600000000000p-1, 0x1.db13db0d49000p-3, -0x1.aff2af715b035p-45) A(0x1.9400000000000p-1, + 0x1.e530effe71000p-3, + 0x1.212276041f430p-51) A(0x1.9200000000000p-1, 0x1.ef5ade4dd0000p-3, -0x1.a211565bb8e11p-51) A(0x1.9000000000000p-1, 0x1.f991c6cb3b000p-3, 0x1.bcbecca0cdf30p-46) A(0x1.8c00000000000p-1, 0x1.07138604d5800p-2, 0x1.89cdb16ed4e91p-48) A(0x1.8a00000000000p-1, + 0x1.0c42d67616000p-2, + 0x1.7188b163ceae9p-45) A(0x1.8800000000000p-1, 0x1.1178e8227e800p-2, -0x1.c210e63a5f01cp-45) A(0x1.8600000000000p-1, + 0x1.16b5ccbacf800p-2, + 0x1.b9acdf7a51681p-45) A(0x1.8400000000000p-1, + 0x1.1bf99635a6800p-2, + 0x1.ca6ed5147bdb7p-45) A(0x1.8200000000000p-1, + 0x1.214456d0eb800p-2, + 0x1.a87deba46baeap-47) A(0x1.7e00000000000p-1, + 0x1.2bef07cdc9000p-2, 0x1.a9cfa4a5004f4p-45) A(0x1.7c00000000000p-1, 0x1.314f1e1d36000p-2, -0x1.8e27ad3213cb8p-45) A(0x1.7a00000000000p-1, 0x1.36b6776be1000p-2, 0x1.16ecdb0f177c8p-46) A(0x1.7800000000000p-1, + 0x1.3c25277333000p-2, + 0x1.83b54b606bd5cp-46) A(0x1.7600000000000p-1, + 0x1.419b423d5e800p-2, + 0x1.8e436ec90e09dp-47) A(0x1.7400000000000p-1, 0x1.4718dc271c800p-2, -0x1.f27ce0967d675p-45) A(0x1.7200000000000p-1, 0x1.4c9e09e173000p-2, -0x1.e20891b0ad8a4p-45) A(0x1.7000000000000p-1, + 0x1.522ae0738a000p-2, + 0x1.ebe708164c759p-45) A(0x1.6e00000000000p-1, 0x1.57bf753c8d000p-2, 0x1.fadedee5d40efp-46) A(0x1.6c00000000000p-1, + 0x1.5d5bddf596000p-2, + -0x1.a0b2a08a465dcp-47)}, +}; + +#define T __pow_log_data.tab +#undef A +#define A __pow_log_data.poly +#define Ln2hi __pow_log_data.ln2hi +#define Ln2lo __pow_log_data.ln2lo + +/* Top 12 bits of a double (sign and exponent bits). */ +static inline uint32_t top12(double x) +{ + return asuint64(x) >> 52; +} + +/* Compute y+TAIL = log(x) where the rounded result is y and TAIL has about + additional 15 bits precision. IX is the bit representation of x, but + normalized in the subnormal range using the sign bit for the exponent. */ +static inline double_t log_inline(uint64_t ix, double_t *tail) +{ + /* double_t for better performance on targets with FLT_EVAL_METHOD==2. */ + double_t z, r, y, invc, logc, logctail, kd, hi, t1, t2, lo, lo1, lo2, p; + uint64_t iz, tmp; + int k, i; + + /* x = 2^k z; where z is in range [OFF,2*OFF) and exact. + The range is split into N subintervals. + The ith subinterval contains z and c is near its center. */ + tmp = ix - OFF; + i = (tmp >> (52 - POW_LOG_TABLE_BITS)) % N; + k = (int64_t)tmp >> 52; /* arithmetic shift */ + iz = ix - (tmp & 0xfffULL << 52); + z = asdouble(iz); + kd = (double_t)k; + + /* log(x) = k*Ln2 + log(c) + log1p(z/c-1). */ + invc = T[i].invc; + logc = T[i].logc; + logctail = T[i].logctail; + + /* Note: 1/c is j/N or j/N/2 where j is an integer in [N,2N) and + |z/c - 1| < 1/N, so r = z/c - 1 is exactly representible. */ +#if __FP_FAST_FMA + r = __builtin_fma(z, invc, -1.0); +#else + /* Split z such that rhi, rlo and rhi*rhi are exact and |rlo| <= |r|. */ + double_t zhi = asdouble((iz + (1ULL << 31)) & (-1ULL << 32)); + double_t zlo = z - zhi; + double_t rhi = zhi * invc - 1.0; + double_t rlo = zlo * invc; + r = rhi + rlo; +#endif + + /* k*Ln2 + log(c) + r. */ + t1 = kd * Ln2hi + logc; + t2 = t1 + r; + lo1 = kd * Ln2lo + logctail; + lo2 = t1 - t2 + r; + + /* Evaluation is optimized assuming superscalar pipelined execution. */ + double_t ar, ar2, ar3, lo3, lo4; + ar = A[0] * r; /* A[0] = -0.5. */ + ar2 = r * ar; + ar3 = r * ar2; + /* k*Ln2 + log(c) + r + A[0]*r*r. */ +#if __FP_FAST_FMA + hi = t2 + ar2; + lo3 = __builtin_fma(ar, r, -ar2); + lo4 = t2 - hi + ar2; +#else + double_t arhi = A[0] * rhi; + double_t arhi2 = rhi * arhi; + hi = t2 + arhi2; + lo3 = rlo * (ar + arhi); + lo4 = t2 - hi + arhi2; +#endif + /* p = log1p(r) - r - A[0]*r*r. */ + p = (ar3 * (A[1] + r * A[2] + ar2 * (A[3] + r * A[4] + ar2 * (A[5] + r * A[6])))); + lo = lo1 + lo2 + lo3 + lo4 + p; + y = hi + lo; + *tail = hi - y + lo; + return y; +} + +#undef N +#undef T +#define EXP_TABLE_BITS 7 +#define EXP_POLY_ORDER 5 +#define EXP_USE_TOINT_NARROW 0 +#define EXP2_POLY_ORDER 5 +struct exp_data { + double invln2N; + double shift; + double negln2hiN; + double negln2loN; + double poly[4]; /* Last four coefficients. */ + double exp2_shift; + double exp2_poly[EXP2_POLY_ORDER]; + uint64_t tab[2 * (1 << EXP_TABLE_BITS)]; +}; +#define N (1 << EXP_TABLE_BITS) + +const struct exp_data __exp_data = { + // N/ln2 + .invln2N = 0x1.71547652b82fep0 * N, + // -ln2/N + .negln2hiN = -0x1.62e42fefa0000p-8, + .negln2loN = -0x1.cf79abc9e3b3ap-47, +// Used for rounding when !TOINT_INTRINSICS +#if EXP_USE_TOINT_NARROW + .shift = 0x1800000000.8p0, +#else + .shift = 0x1.8p52, +#endif + // exp polynomial coefficients. + .poly = + { + // abs error: 1.555*2^-66 + // ulp error: 0.509 (0.511 without fma) + // if |x| < ln2/256+eps + // abs error if |x| < ln2/256+0x1p-15: 1.09*2^-65 + // abs error if |x| < ln2/128: 1.7145*2^-56 + 0x1.ffffffffffdbdp-2, + 0x1.555555555543cp-3, + 0x1.55555cf172b91p-5, + 0x1.1111167a4d017p-7, + }, + .exp2_shift = 0x1.8p52 / N, + // exp2 polynomial coefficients. + .exp2_poly = + { + // abs error: 1.2195*2^-65 + // ulp error: 0.507 (0.511 without fma) + // if |x| < 1/256 + // abs error if |x| < 1/128: 1.9941*2^-56 + 0x1.62e42fefa39efp-1, + 0x1.ebfbdff82c424p-3, + 0x1.c6b08d70cf4b5p-5, + 0x1.3b2abd24650ccp-7, + 0x1.5d7e09b4e3a84p-10, + }, + // 2^(k/N) ~= H[k]*(1 + T[k]) for int k in [0,N) + // tab[2*k] = asuint64(T[k]) + // tab[2*k+1] = asuint64(H[k]) - (k << 52)/N + .tab = + { + 0x0, + 0x3ff0000000000000, + 0x3c9b3b4f1a88bf6e, + 0x3feff63da9fb3335, + 0xbc7160139cd8dc5d, + 0x3fefec9a3e778061, + 0xbc905e7a108766d1, + 0x3fefe315e86e7f85, + 0x3c8cd2523567f613, + 0x3fefd9b0d3158574, + 0xbc8bce8023f98efa, + 0x3fefd06b29ddf6de, + 0x3c60f74e61e6c861, + 0x3fefc74518759bc8, + 0x3c90a3e45b33d399, + 0x3fefbe3ecac6f383, + 0x3c979aa65d837b6d, + 0x3fefb5586cf9890f, + 0x3c8eb51a92fdeffc, + 0x3fefac922b7247f7, + 0x3c3ebe3d702f9cd1, + 0x3fefa3ec32d3d1a2, + 0xbc6a033489906e0b, + 0x3fef9b66affed31b, + 0xbc9556522a2fbd0e, + 0x3fef9301d0125b51, + 0xbc5080ef8c4eea55, + 0x3fef8abdc06c31cc, + 0xbc91c923b9d5f416, + 0x3fef829aaea92de0, + 0x3c80d3e3e95c55af, + 0x3fef7a98c8a58e51, + 0xbc801b15eaa59348, + 0x3fef72b83c7d517b, + 0xbc8f1ff055de323d, + 0x3fef6af9388c8dea, + 0x3c8b898c3f1353bf, + 0x3fef635beb6fcb75, + 0xbc96d99c7611eb26, + 0x3fef5be084045cd4, + 0x3c9aecf73e3a2f60, + 0x3fef54873168b9aa, + 0xbc8fe782cb86389d, + 0x3fef4d5022fcd91d, + 0x3c8a6f4144a6c38d, + 0x3fef463b88628cd6, + 0x3c807a05b0e4047d, + 0x3fef3f49917ddc96, + 0x3c968efde3a8a894, + 0x3fef387a6e756238, + 0x3c875e18f274487d, + 0x3fef31ce4fb2a63f, + 0x3c80472b981fe7f2, + 0x3fef2b4565e27cdd, + 0xbc96b87b3f71085e, + 0x3fef24dfe1f56381, + 0x3c82f7e16d09ab31, + 0x3fef1e9df51fdee1, + 0xbc3d219b1a6fbffa, + 0x3fef187fd0dad990, + 0x3c8b3782720c0ab4, + 0x3fef1285a6e4030b, + 0x3c6e149289cecb8f, + 0x3fef0cafa93e2f56, + 0x3c834d754db0abb6, + 0x3fef06fe0a31b715, + 0x3c864201e2ac744c, + 0x3fef0170fc4cd831, + 0x3c8fdd395dd3f84a, + 0x3feefc08b26416ff, + 0xbc86a3803b8e5b04, + 0x3feef6c55f929ff1, + 0xbc924aedcc4b5068, + 0x3feef1a7373aa9cb, + 0xbc9907f81b512d8e, + 0x3feeecae6d05d866, + 0xbc71d1e83e9436d2, + 0x3feee7db34e59ff7, + 0xbc991919b3ce1b15, + 0x3feee32dc313a8e5, + 0x3c859f48a72a4c6d, + 0x3feedea64c123422, + 0xbc9312607a28698a, + 0x3feeda4504ac801c, + 0xbc58a78f4817895b, + 0x3feed60a21f72e2a, + 0xbc7c2c9b67499a1b, + 0x3feed1f5d950a897, + 0x3c4363ed60c2ac11, + 0x3feece086061892d, + 0x3c9666093b0664ef, + 0x3feeca41ed1d0057, + 0x3c6ecce1daa10379, + 0x3feec6a2b5c13cd0, + 0x3c93ff8e3f0f1230, + 0x3feec32af0d7d3de, + 0x3c7690cebb7aafb0, + 0x3feebfdad5362a27, + 0x3c931dbdeb54e077, + 0x3feebcb299fddd0d, + 0xbc8f94340071a38e, + 0x3feeb9b2769d2ca7, + 0xbc87deccdc93a349, + 0x3feeb6daa2cf6642, + 0xbc78dec6bd0f385f, + 0x3feeb42b569d4f82, + 0xbc861246ec7b5cf6, + 0x3feeb1a4ca5d920f, + 0x3c93350518fdd78e, + 0x3feeaf4736b527da, + 0x3c7b98b72f8a9b05, + 0x3feead12d497c7fd, + 0x3c9063e1e21c5409, + 0x3feeab07dd485429, + 0x3c34c7855019c6ea, + 0x3feea9268a5946b7, + 0x3c9432e62b64c035, + 0x3feea76f15ad2148, + 0xbc8ce44a6199769f, + 0x3feea5e1b976dc09, + 0xbc8c33c53bef4da8, + 0x3feea47eb03a5585, + 0xbc845378892be9ae, + 0x3feea34634ccc320, + 0xbc93cedd78565858, + 0x3feea23882552225, + 0x3c5710aa807e1964, + 0x3feea155d44ca973, + 0xbc93b3efbf5e2228, + 0x3feea09e667f3bcd, + 0xbc6a12ad8734b982, + 0x3feea012750bdabf, + 0xbc6367efb86da9ee, + 0x3fee9fb23c651a2f, + 0xbc80dc3d54e08851, + 0x3fee9f7df9519484, + 0xbc781f647e5a3ecf, + 0x3fee9f75e8ec5f74, + 0xbc86ee4ac08b7db0, + 0x3fee9f9a48a58174, + 0xbc8619321e55e68a, + 0x3fee9feb564267c9, + 0x3c909ccb5e09d4d3, + 0x3feea0694fde5d3f, + 0xbc7b32dcb94da51d, + 0x3feea11473eb0187, + 0x3c94ecfd5467c06b, + 0x3feea1ed0130c132, + 0x3c65ebe1abd66c55, + 0x3feea2f336cf4e62, + 0xbc88a1c52fb3cf42, + 0x3feea427543e1a12, + 0xbc9369b6f13b3734, + 0x3feea589994cce13, + 0xbc805e843a19ff1e, + 0x3feea71a4623c7ad, + 0xbc94d450d872576e, + 0x3feea8d99b4492ed, + 0x3c90ad675b0e8a00, + 0x3feeaac7d98a6699, + 0x3c8db72fc1f0eab4, + 0x3feeace5422aa0db, + 0xbc65b6609cc5e7ff, + 0x3feeaf3216b5448c, + 0x3c7bf68359f35f44, + 0x3feeb1ae99157736, + 0xbc93091fa71e3d83, + 0x3feeb45b0b91ffc6, + 0xbc5da9b88b6c1e29, + 0x3feeb737b0cdc5e5, + 0xbc6c23f97c90b959, + 0x3feeba44cbc8520f, + 0xbc92434322f4f9aa, + 0x3feebd829fde4e50, + 0xbc85ca6cd7668e4b, + 0x3feec0f170ca07ba, + 0x3c71affc2b91ce27, + 0x3feec49182a3f090, + 0x3c6dd235e10a73bb, + 0x3feec86319e32323, + 0xbc87c50422622263, + 0x3feecc667b5de565, + 0x3c8b1c86e3e231d5, + 0x3feed09bec4a2d33, + 0xbc91bbd1d3bcbb15, + 0x3feed503b23e255d, + 0x3c90cc319cee31d2, + 0x3feed99e1330b358, + 0x3c8469846e735ab3, + 0x3feede6b5579fdbf, + 0xbc82dfcd978e9db4, + 0x3feee36bbfd3f37a, + 0x3c8c1a7792cb3387, + 0x3feee89f995ad3ad, + 0xbc907b8f4ad1d9fa, + 0x3feeee07298db666, + 0xbc55c3d956dcaeba, + 0x3feef3a2b84f15fb, + 0xbc90a40e3da6f640, + 0x3feef9728de5593a, + 0xbc68d6f438ad9334, + 0x3feeff76f2fb5e47, + 0xbc91eee26b588a35, + 0x3fef05b030a1064a, + 0x3c74ffd70a5fddcd, + 0x3fef0c1e904bc1d2, + 0xbc91bdfbfa9298ac, + 0x3fef12c25bd71e09, + 0x3c736eae30af0cb3, + 0x3fef199bdd85529c, + 0x3c8ee3325c9ffd94, + 0x3fef20ab5fffd07a, + 0x3c84e08fd10959ac, + 0x3fef27f12e57d14b, + 0x3c63cdaf384e1a67, + 0x3fef2f6d9406e7b5, + 0x3c676b2c6c921968, + 0x3fef3720dcef9069, + 0xbc808a1883ccb5d2, + 0x3fef3f0b555dc3fa, + 0xbc8fad5d3ffffa6f, + 0x3fef472d4a07897c, + 0xbc900dae3875a949, + 0x3fef4f87080d89f2, + 0x3c74a385a63d07a7, + 0x3fef5818dcfba487, + 0xbc82919e2040220f, + 0x3fef60e316c98398, + 0x3c8e5a50d5c192ac, + 0x3fef69e603db3285, + 0x3c843a59ac016b4b, + 0x3fef7321f301b460, + 0xbc82d52107b43e1f, + 0x3fef7c97337b9b5f, + 0xbc892ab93b470dc9, + 0x3fef864614f5a129, + 0x3c74b604603a88d3, + 0x3fef902ee78b3ff6, + 0x3c83c5ec519d7271, + 0x3fef9a51fbc74c83, + 0xbc8ff7128fd391f0, + 0x3fefa4afa2a490da, + 0xbc8dae98e223747d, + 0x3fefaf482d8e67f1, + 0x3c8ec3bc41aa2008, + 0x3fefba1bee615a27, + 0x3c842b94c3a9eb32, + 0x3fefc52b376bba97, + 0x3c8a64a931d185ee, + 0x3fefd0765b6e4540, + 0xbc8e37bae43be3ed, + 0x3fefdbfdad9cbe14, + 0x3c77893b4d91cd9d, + 0x3fefe7c1819e90d8, + 0x3c5305c14160cc89, + 0x3feff3c22b8f71f1, + }, +}; + +#define InvLn2N __exp_data.invln2N +#define NegLn2hiN __exp_data.negln2hiN +#define NegLn2loN __exp_data.negln2loN +#define Shift __exp_data.shift +#define T __exp_data.tab +#define C2 __exp_data.poly[5 - EXP_POLY_ORDER] +#define C3 __exp_data.poly[6 - EXP_POLY_ORDER] +#define C4 __exp_data.poly[7 - EXP_POLY_ORDER] +#define C5 __exp_data.poly[8 - EXP_POLY_ORDER] +#define C6 __exp_data.poly[9 - EXP_POLY_ORDER] + +static inline double specialcase(double_t tmp, uint64_t sbits, uint64_t ki) +{ + double_t scale, y; + + if ((ki & 0x80000000) == 0) { + /* k > 0, the exponent of scale might have overflowed by <= 460. */ + sbits -= 1009ull << 52; + scale = asdouble(sbits); + y = 0x1p1009 * (scale + scale * tmp); + return eval_as_double(y); + } + /* k < 0, need special care in the subnormal range. */ + sbits += 1022ull << 52; + /* Note: sbits is signed scale. */ + scale = asdouble(sbits); + y = scale + scale * tmp; + if (fabs(y) < 1.0) { + /* Round y to the right precision before scaling it into the subnormal + range to avoid double rounding that can cause 0.5+E/2 ulp error where + E is the worst-case ulp error outside the subnormal range. So this + is only useful if the goal is better than 1 ulp worst-case error. */ + double_t hi, lo, one = 1.0; + if (y < 0.0) + one = -1.0; + lo = scale - y + scale * tmp; + hi = one + y; + lo = one - hi + y + lo; + y = eval_as_double(hi + lo) - one; + /* Fix the sign of 0. */ + if (y == 0.0) + y = asdouble(sbits & 0x8000000000000000); + /* The underflow exception needs to be signaled explicitly. */ + fp_force_eval(fp_barrier(0x1p-1022) * 0x1p-1022); + } + y = 0x1p-1022 * y; + return eval_as_double(y); +} + +#define SIGN_BIAS (0x800 << EXP_TABLE_BITS) + +double __math_xflow(uint32_t sign, double y) +{ + return eval_as_double(fp_barrier(sign ? -y : y) * y); +} + +double __math_uflow(uint32_t sign) +{ + return __math_xflow(sign, 0x1p-767); +} + +double __math_oflow(uint32_t sign) +{ + return __math_xflow(sign, 0x1p769); +} + +/* Computes sign*exp(x+xtail) where |xtail| < 2^-8/N and |xtail| <= |x|. + The sign_bias argument is SIGN_BIAS or 0 and sets the sign to -1 or 1. */ +static inline double exp_inline(double_t x, double_t xtail, uint32_t sign_bias) +{ + uint32_t abstop; + uint64_t ki, idx, top, sbits; + /* double_t for better performance on targets with FLT_EVAL_METHOD==2. */ + double_t kd, z, r, r2, scale, tail, tmp; + + abstop = top12(x) & 0x7ff; + if (predict_false(abstop - top12(0x1p-54) >= top12(512.0) - top12(0x1p-54))) { + if (abstop - top12(0x1p-54) >= 0x80000000) { + /* Avoid spurious underflow for tiny x. */ + /* Note: 0 is common input. */ + double_t one = WANT_ROUNDING ? 1.0 + x : 1.0; + return sign_bias ? -one : one; + } + if (abstop >= top12(1024.0)) { + /* Note: inf and nan are already handled. */ + if (asuint64(x) >> 63) + return __math_uflow(sign_bias); + else + return __math_oflow(sign_bias); + } + /* Large x is special cased below. */ + abstop = 0; + } + + /* exp(x) = 2^(k/N) * exp(r), with exp(r) in [2^(-1/2N),2^(1/2N)]. */ + /* x = ln2/N*k + r, with int k and r in [-ln2/2N, ln2/2N]. */ + z = InvLn2N * x; +#if TOINT_INTRINSICS + kd = roundtoint(z); + ki = converttoint(z); +#elif EXP_USE_TOINT_NARROW + /* z - kd is in [-0.5-2^-16, 0.5] in all rounding modes. */ + kd = eval_as_double(z + Shift); + ki = asuint64(kd) >> 16; + kd = (double_t)(int32_t)ki; +#else + /* z - kd is in [-1, 1] in non-nearest rounding modes. */ + kd = eval_as_double(z + Shift); + ki = asuint64(kd); + kd -= Shift; +#endif + r = x + kd * NegLn2hiN + kd * NegLn2loN; + /* The code assumes 2^-200 < |xtail| < 2^-8/N. */ + r += xtail; + /* 2^(k/N) ~= scale * (1 + tail). */ + idx = 2 * (ki % N); + top = (ki + sign_bias) << (52 - EXP_TABLE_BITS); + tail = asdouble(T[idx]); + /* This is only a valid scale when -1023*N < k < 1024*N. */ + sbits = T[idx + 1] + top; + /* exp(x) = 2^(k/N) * exp(r) ~= scale + scale * (tail + exp(r) - 1). */ + /* Evaluation is optimized assuming superscalar pipelined execution. */ + r2 = r * r; + /* Without fma the worst case error is 0.25/N ulp larger. */ + /* Worst case error is less than 0.5+1.11/N+(abs poly error * 2^53) ulp. */ + tmp = tail + r + r2 * (C2 + r * C3) + r2 * r2 * (C4 + r * C5); + if (predict_false(abstop == 0)) + return specialcase(tmp, sbits, ki); + scale = asdouble(sbits); + /* Note: tmp == 0 or |tmp| > 2^-200 and scale > 2^-739, so there + is no spurious underflow here even without fma. */ + return eval_as_double(scale + scale * tmp); +} + +/* Returns 0 if not int, 1 if odd int, 2 if even int. The argument is + the bit representation of a non-zero finite floating-point value. */ +static inline int checkint(uint64_t iy) +{ + int e = iy >> 52 & 0x7ff; + if (e < 0x3ff) + return 0; + if (e > 0x3ff + 52) + return 2; + if (iy & ((1ULL << (0x3ff + 52 - e)) - 1)) + return 0; + if (iy & (1ULL << (0x3ff + 52 - e))) + return 1; + return 2; +} + +#if 100 * __GNUC__ + __GNUC_MINOR__ >= 303 +#define NAN __builtin_nanf("") +#define INFINITY __builtin_inff() +#else +#define NAN (0.0f / 0.0f) +#define INFINITY 1e5000f +#endif + +static inline int zeroinfnan(uint64_t i) +{ + return 2 * i - 1 >= 2 * asuint64(INFINITY) - 1; +} + +#if WANT_SNAN +#error SNaN is unsupported +#else +#define issignalingf_inline(x) 0 +#define issignaling_inline(x) 0 +#endif + +double pow(double x, double y) +{ + uint32_t sign_bias = 0; + uint64_t ix, iy; + uint32_t topx, topy; + + ix = asuint64(x); + iy = asuint64(y); + topx = top12(x); + topy = top12(y); + if (predict_false(topx - 0x001 >= 0x7ff - 0x001 || (topy & 0x7ff) - 0x3be >= 0x43e - 0x3be)) { + /* Note: if |y| > 1075 * ln2 * 2^53 ~= 0x1.749p62 then pow(x,y) = inf/0 + and if |y| < 2^-54 / 1075 ~= 0x1.e7b6p-65 then pow(x,y) = +-1. */ + /* Special cases: (x < 0x1p-126 or inf or nan) or + (|y| < 0x1p-65 or |y| >= 0x1p63 or nan). */ + if (predict_false(zeroinfnan(iy))) { + if (2 * iy == 0) + return issignaling_inline(x) ? x + y : 1.0; + if (ix == asuint64(1.0)) + return issignaling_inline(y) ? x + y : 1.0; + if (2 * ix > 2 * asuint64(INFINITY) || 2 * iy > 2 * asuint64(INFINITY)) + return x + y; + if (2 * ix == 2 * asuint64(1.0)) + return 1.0; + if ((2 * ix < 2 * asuint64(1.0)) == !(iy >> 63)) + return 0.0; /* |x|<1 && y==inf or |x|>1 && y==-inf. */ + return y * y; + } + if (predict_false(zeroinfnan(ix))) { + double_t x2 = x * x; + if (ix >> 63 && checkint(iy) == 1) + x2 = -x2; + /* Without the barrier some versions of clang hoist the 1/x2 and + thus division by zero exception can be signaled spuriously. */ + return iy >> 63 ? fp_barrier(1 / x2) : x2; + } + /* Here x and y are non-zero finite. */ + if (ix >> 63) { + /* Finite x < 0. */ + int yint = checkint(iy); + if (yint == 0) + return __math_invalid(x); + if (yint == 1) + sign_bias = SIGN_BIAS; + ix &= 0x7fffffffffffffff; + topx &= 0x7ff; + } + if ((topy & 0x7ff) - 0x3be >= 0x43e - 0x3be) { + /* Note: sign_bias == 0 here because y is not odd. */ + if (ix == asuint64(1.0)) + return 1.0; + if ((topy & 0x7ff) < 0x3be) { + /* |y| < 2^-65, x^y ~= 1 + y*log(x). */ + if (WANT_ROUNDING) + return ix > asuint64(1.0) ? 1.0 + y : 1.0 - y; + else + return 1.0; + } + return (ix > asuint64(1.0)) == (topy < 0x800) ? __math_oflow(0) : __math_uflow(0); + } + if (topx == 0) { + /* Normalize subnormal x so exponent becomes negative. */ + ix = asuint64(x * 0x1p52); + ix &= 0x7fffffffffffffff; + ix -= 52ULL << 52; + } + } + + double_t lo; + double_t hi = log_inline(ix, &lo); + double_t ehi, elo; +#if __FP_FAST_FMA + ehi = y * hi; + elo = y * lo + __builtin_fma(y, hi, -ehi); +#else + double_t yhi = asdouble(iy & -1ULL << 27); + double_t ylo = y - yhi; + double_t lhi = asdouble(asuint64(hi) & -1ULL << 27); + double_t llo = hi - lhi + lo; + ehi = yhi * lhi; + elo = ylo * lhi + y * llo; /* |elo| < |ehi| * 2^-25. */ +#endif + return exp_inline(ehi, elo, sign_bias); +} +#endif diff --git a/tools/axlibc/c/printf.c b/tools/axlibc/c/printf.c new file mode 100644 index 0000000..3657376 --- /dev/null +++ b/tools/axlibc/c/printf.c @@ -0,0 +1,1482 @@ +/** + * @author (c) Eyal Rozenberg + * 2021-2022, Haifa, Palestine/Israel + * @author (c) Marco Paland (info@paland.com) + * 2014-2019, PALANDesign Hannover, Germany + * + * @note Others have made smaller contributions to this file: see the + * contributors page at https://github.com/eyalroz/printf/graphs/contributors + * or ask one of the authors. The original code for exponential specifiers was + * contributed by Martijn Jasperse . + * + * @brief Small stand-alone implementation of the printf family of functions + * (`(v)printf`, `(v)s(n)printf` etc., geared towards use on embedded systems with + * a very limited resources. + * + * @note the implementations are thread-safe; re-entrant; use no functions from + * the standard library; and do not dynamically allocate any memory. + * + * @license The MIT License (MIT) + * + * 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. + */ + +// Define this globally (e.g. gcc -DPRINTF_INCLUDE_CONFIG_H=1 ...) to include the +// printf_config.h header file +#define PRINTF_INCLUDE_CONFIG_H 1 + +#if PRINTF_INCLUDE_CONFIG_H +#include "printf_config.h" +#endif + +#include "printf.h" + +#ifdef __cplusplus +#include +#include +#else +#include +#include +#include +#include +#endif // __cplusplus + +#if PRINTF_ALIAS_STANDARD_FUNCTION_NAMES +#define printf_ printf +#define sprintf_ sprintf +#define vsprintf_ vsprintf +#define snprintf_ snprintf +#define vsnprintf_ vsnprintf +#define vprintf_ vprintf +#endif + +// 'ntoa' conversion buffer size, this must be big enough to hold one converted +// numeric number including padded zeros (dynamically created on stack) +#ifndef PRINTF_INTEGER_BUFFER_SIZE +#define PRINTF_INTEGER_BUFFER_SIZE 32 +#endif + +// size of the fixed (on-stack) buffer for printing individual decimal numbers. +// this must be big enough to hold one converted floating-point value including +// padded zeros. +#ifndef PRINTF_DECIMAL_BUFFER_SIZE +#define PRINTF_DECIMAL_BUFFER_SIZE 32 +#endif + +// Support for the decimal notation floating point conversion specifiers (%f, %F) +#ifndef PRINTF_SUPPORT_DECIMAL_SPECIFIERS +#define PRINTF_SUPPORT_DECIMAL_SPECIFIERS 1 +#endif + +// Support for the exponential notation floating point conversion specifiers (%e, %g, %E, %G) +#ifndef PRINTF_SUPPORT_EXPONENTIAL_SPECIFIERS +#define PRINTF_SUPPORT_EXPONENTIAL_SPECIFIERS 1 +#endif + +// Support for the length write-back specifier (%n) +#ifndef PRINTF_SUPPORT_WRITEBACK_SPECIFIER +#define PRINTF_SUPPORT_WRITEBACK_SPECIFIER 1 +#endif + +// Default precision for the floating point conversion specifiers (the C standard sets this at 6) +#ifndef PRINTF_DEFAULT_FLOAT_PRECISION +#define PRINTF_DEFAULT_FLOAT_PRECISION 6 +#endif + +// According to the C languages standard, printf() and related functions must be able to print any +// integral number in floating-point notation, regardless of length, when using the %f specifier - +// possibly hundreds of characters, potentially overflowing your buffers. In this implementation, +// all values beyond this threshold are switched to exponential notation. +#ifndef PRINTF_MAX_INTEGRAL_DIGITS_FOR_DECIMAL +#define PRINTF_MAX_INTEGRAL_DIGITS_FOR_DECIMAL 9 +#endif + +// Support for the long long integral types (with the ll, z and t length modifiers for specifiers +// %d,%i,%o,%x,%X,%u, and with the %p specifier). Note: 'L' (long double) is not supported. +#ifndef PRINTF_SUPPORT_LONG_LONG +#define PRINTF_SUPPORT_LONG_LONG 1 +#endif + +// The number of terms in a Taylor series expansion of log_10(x) to +// use for approximation - including the power-zero term (i.e. the +// value at the point of expansion). +#ifndef PRINTF_LOG10_TAYLOR_TERMS +#define PRINTF_LOG10_TAYLOR_TERMS 4 +#endif + +#if PRINTF_LOG10_TAYLOR_TERMS <= 1 +#error "At least one non-constant Taylor expansion is necessary for the log10() calculation" +#endif + +// Be extra-safe, and don't assume format specifiers are completed correctly +// before the format string end. +#ifndef PRINTF_CHECK_FOR_NUL_IN_FORMAT_SPECIFIER +#define PRINTF_CHECK_FOR_NUL_IN_FORMAT_SPECIFIER 1 +#endif + +#define PRINTF_PREFER_DECIMAL false +#define PRINTF_PREFER_EXPONENTIAL true + +/////////////////////////////////////////////////////////////////////////////// + +// The following will convert the number-of-digits into an exponential-notation literal +#define PRINTF_CONCATENATE(s1, s2) s1##s2 +#define PRINTF_EXPAND_THEN_CONCATENATE(s1, s2) PRINTF_CONCATENATE(s1, s2) +#define PRINTF_FLOAT_NOTATION_THRESHOLD \ + PRINTF_EXPAND_THEN_CONCATENATE(1e, PRINTF_MAX_INTEGRAL_DIGITS_FOR_DECIMAL) + +// internal flag definitions +#define FLAGS_ZEROPAD (1U << 0U) +#define FLAGS_LEFT (1U << 1U) +#define FLAGS_PLUS (1U << 2U) +#define FLAGS_SPACE (1U << 3U) +#define FLAGS_HASH (1U << 4U) +#define FLAGS_UPPERCASE (1U << 5U) +#define FLAGS_CHAR (1U << 6U) +#define FLAGS_SHORT (1U << 7U) +#define FLAGS_INT (1U << 8U) +// Only used with PRINTF_SUPPORT_MSVC_STYLE_INTEGER_SPECIFIERS +#define FLAGS_LONG (1U << 9U) +#define FLAGS_LONG_LONG (1U << 10U) +#define FLAGS_PRECISION (1U << 11U) +#define FLAGS_ADAPT_EXP (1U << 12U) +#define FLAGS_POINTER (1U << 13U) +// Note: Similar, but not identical, effect as FLAGS_HASH +#define FLAGS_SIGNED (1U << 14U) +// Only used with PRINTF_SUPPORT_MSVC_STYLE_INTEGER_SPECIFIERS + +#ifdef PRINTF_SUPPORT_MSVC_STYLE_INTEGER_SPECIFIERS + +#define FLAGS_INT8 FLAGS_CHAR + +#if (SHRT_MAX == 32767LL) +#define FLAGS_INT16 FLAGS_SHORT +#elif (INT_MAX == 32767LL) +#define FLAGS_INT16 FLAGS_INT +#elif (LONG_MAX == 32767LL) +#define FLAGS_INT16 FLAGS_LONG +#elif (LLONG_MAX == 32767LL) +#define FLAGS_INT16 FLAGS_LONG_LONG +#else +#error "No basic integer type has a size of 16 bits exactly" +#endif + +#if (SHRT_MAX == 2147483647LL) +#define FLAGS_INT32 FLAGS_SHORT +#elif (INT_MAX == 2147483647LL) +#define FLAGS_INT32 FLAGS_INT +#elif (LONG_MAX == 2147483647LL) +#define FLAGS_INT32 FLAGS_LONG +#elif (LLONG_MAX == 2147483647LL) +#define FLAGS_INT32 FLAGS_LONG_LONG +#else +#error "No basic integer type has a size of 32 bits exactly" +#endif + +#if (SHRT_MAX == 9223372036854775807LL) +#define FLAGS_INT64 FLAGS_SHORT +#elif (INT_MAX == 9223372036854775807LL) +#define FLAGS_INT64 FLAGS_INT +#elif (LONG_MAX == 9223372036854775807LL) +#define FLAGS_INT64 FLAGS_LONG +#elif (LLONG_MAX == 9223372036854775807LL) +#define FLAGS_INT64 FLAGS_LONG_LONG +#else +#error "No basic integer type has a size of 64 bits exactly" +#endif + +#endif // PRINTF_SUPPORT_MSVC_STYLE_INTEGER_SPECIFIERS + +typedef unsigned int printf_flags_t; + +#define BASE_BINARY 2 +#define BASE_OCTAL 8 +#define BASE_DECIMAL 10 +#define BASE_HEX 16 + +typedef uint8_t numeric_base_t; + +#if PRINTF_SUPPORT_LONG_LONG +typedef unsigned long long printf_unsigned_value_t; +typedef long long printf_signed_value_t; +#else +typedef unsigned long printf_unsigned_value_t; +typedef long printf_signed_value_t; +#endif + +// The printf()-family functions return an `int`; it is therefore +// unnecessary/inappropriate to use size_t - often larger than int +// in practice - for non-negative related values, such as widths, +// precisions, offsets into buffers used for printing and the sizes +// of these buffers. instead, we use: +typedef unsigned int printf_size_t; +#define PRINTF_MAX_POSSIBLE_BUFFER_SIZE INT_MAX +// If we were to nitpick, this would actually be INT_MAX + 1, +// since INT_MAX is the maximum return value, which excludes the +// trailing '\0'. + +#if (PRINTF_SUPPORT_DECIMAL_SPECIFIERS || PRINTF_SUPPORT_EXPONENTIAL_SPECIFIERS) +#include +#if FLT_RADIX != 2 +#error "Non-binary-radix floating-point types are unsupported." +#endif + +#if DBL_MANT_DIG == 24 + +#define DOUBLE_SIZE_IN_BITS 32 +typedef uint32_t double_uint_t; +#define DOUBLE_EXPONENT_MASK 0xFFU +#define DOUBLE_BASE_EXPONENT 127 +#define DOUBLE_MAX_SUBNORMAL_EXPONENT_OF_10 -38 +#define DOUBLE_MAX_SUBNORMAL_POWER_OF_10 1e-38 + +#elif DBL_MANT_DIG == 53 + +#define DOUBLE_SIZE_IN_BITS 64 +typedef uint64_t double_uint_t; +#define DOUBLE_EXPONENT_MASK 0x7FFU +#define DOUBLE_BASE_EXPONENT 1023 +#define DOUBLE_MAX_SUBNORMAL_EXPONENT_OF_10 -308 +#define DOUBLE_MAX_SUBNORMAL_POWER_OF_10 1e-308 + +#else +#error "Unsupported double type configuration" +#endif +#define DOUBLE_STORED_MANTISSA_BITS (DBL_MANT_DIG - 1) + +typedef union { + double_uint_t U; + double F; +} double_with_bit_access; + +// This is unnecessary in C99, since compound initializers can be used, +// but: +// 1. Some compilers are finicky about this; +// 2. Some people may want to convert this to C89; +// 3. If you try to use it as C++, only C++20 supports compound literals +static inline double_with_bit_access get_bit_access(double x) +{ + double_with_bit_access dwba; + dwba.F = x; + return dwba; +} + +static inline int get_sign_bit(double x) +{ + // The sign is stored in the highest bit + return (int)(get_bit_access(x).U >> (DOUBLE_SIZE_IN_BITS - 1)); +} + +static inline int get_exp2(double_with_bit_access x) +{ + // The exponent in an IEEE-754 floating-point number occupies a contiguous + // sequence of bits (e.g. 52..62 for 64-bit doubles), but with a non-trivial representation: An + // unsigned offset from some negative value (with the extremal offset values reserved for + // special use). + return (int)((x.U >> DOUBLE_STORED_MANTISSA_BITS) & DOUBLE_EXPONENT_MASK) - + DOUBLE_BASE_EXPONENT; +} +#define PRINTF_ABS(_x) ((_x) > 0 ? (_x) : -(_x)) + +#endif // (PRINTF_SUPPORT_DECIMAL_SPECIFIERS || PRINTF_SUPPORT_EXPONENTIAL_SPECIFIERS) + +// Note in particular the behavior here on LONG_MIN or LLONG_MIN; it is valid +// and well-defined, but if you're not careful you can easily trigger undefined +// behavior with -LONG_MIN or -LLONG_MIN +#define ABS_FOR_PRINTING(_x) \ + ((printf_unsigned_value_t)((_x) > 0 ? (_x) : -((printf_signed_value_t)_x))) + +// wrapper (used as buffer) for output function type +// +// One of the following must hold: +// 1. max_chars is 0 +// 2. buffer is non-null +// 3. function is non-null +// +// ... otherwise bad things will happen. +typedef struct { + void (*function)(char c, void *extra_arg); + void *extra_function_arg; + char *buffer; + printf_size_t pos; + printf_size_t max_chars; +} output_gadget_t; + +// Note: This function currently assumes it is not passed a '\0' c, +// or alternatively, that '\0' can be passed to the function in the output +// gadget. The former assumption holds within the printf library. It also +// assumes that the output gadget has been properly initialized. +static inline void putchar_via_gadget(output_gadget_t *gadget, char c) +{ + printf_size_t write_pos = gadget->pos++; + // We're _always_ increasing pos, so as to count how may characters + // _would_ have been written if not for the max_chars limitation + if (write_pos >= gadget->max_chars) { + return; + } + if (gadget->function != NULL) { + // No check for c == '\0' . + gadget->function(c, gadget->extra_function_arg); + } else { + // it must be the case that gadget->buffer != NULL , due to the constraint + // on output_gadget_t ; and note we're relying on write_pos being non-negative. + gadget->buffer[write_pos] = c; + } +} + +// Possibly-write the string-terminating '\0' character +static inline void append_termination_with_gadget(output_gadget_t *gadget) +{ + if (gadget->function != NULL || gadget->max_chars == 0) { + return; + } + if (gadget->buffer == NULL) { + return; + } + printf_size_t null_char_pos = + gadget->pos < gadget->max_chars ? gadget->pos : gadget->max_chars - 1; + gadget->buffer[null_char_pos] = '\0'; +} + +// We can't use putchar_ as is, since our output gadget +// only takes pointers to functions with an extra argument +// static inline void putchar_wrapper(char c, void *unused) +// { +// (void)unused; +// putchar_(c); +// } + +static inline output_gadget_t discarding_gadget(void) +{ + output_gadget_t gadget; + gadget.function = NULL; + gadget.extra_function_arg = NULL; + gadget.buffer = NULL; + gadget.pos = 0; + gadget.max_chars = 0; + return gadget; +} + +static inline output_gadget_t buffer_gadget(char *buffer, size_t buffer_size) +{ + printf_size_t usable_buffer_size = (buffer_size > PRINTF_MAX_POSSIBLE_BUFFER_SIZE) + ? PRINTF_MAX_POSSIBLE_BUFFER_SIZE + : (printf_size_t)buffer_size; + output_gadget_t result = discarding_gadget(); + if (buffer != NULL) { + result.buffer = buffer; + result.max_chars = usable_buffer_size; + } + return result; +} + +static inline output_gadget_t function_gadget(void (*function)(char, void *), void *extra_arg) +{ + output_gadget_t result = discarding_gadget(); + result.function = function; + result.extra_function_arg = extra_arg; + result.max_chars = PRINTF_MAX_POSSIBLE_BUFFER_SIZE; + return result; +} + +// static inline output_gadget_t extern_putchar_gadget(void) +// { +// return function_gadget(putchar_wrapper, NULL); +// } + +// internal secure strlen +// @return The length of the string (excluding the terminating 0) limited by 'maxsize' +// @note strlen uses size_t, but wes only use this function with printf_size_t +// variables - hence the signature. +static inline printf_size_t strnlen_s_(const char *str, printf_size_t maxsize) +{ + const char *s; + for (s = str; *s && maxsize--; ++s) + ; + return (printf_size_t)(s - str); +} + +// internal test if char is a digit (0-9) +// @return true if char is a digit +static inline bool is_digit_(char ch) +{ + return (ch >= '0') && (ch <= '9'); +} + +// internal ASCII string to printf_size_t conversion +static printf_size_t atou_(const char **str) +{ + printf_size_t i = 0U; + while (is_digit_(**str)) { + i = i * 10U + (printf_size_t)(*((*str)++) - '0'); + } + return i; +} + +// output the specified string in reverse, taking care of any zero-padding +static void out_rev_(output_gadget_t *output, const char *buf, printf_size_t len, + printf_size_t width, printf_flags_t flags) +{ + const printf_size_t start_pos = output->pos; + + // pad spaces up to given width + if (!(flags & FLAGS_LEFT) && !(flags & FLAGS_ZEROPAD)) { + for (printf_size_t i = len; i < width; i++) { + putchar_via_gadget(output, ' '); + } + } + + // reverse string + while (len) { + putchar_via_gadget(output, buf[--len]); + } + + // append pad spaces up to given width + if (flags & FLAGS_LEFT) { + while (output->pos - start_pos < width) { + putchar_via_gadget(output, ' '); + } + } +} + +// Invoked by print_integer after the actual number has been printed, performing necessary +// work on the number's prefix (as the number is initially printed in reverse order) +static void print_integer_finalization(output_gadget_t *output, char *buf, printf_size_t len, + bool negative, numeric_base_t base, printf_size_t precision, + printf_size_t width, printf_flags_t flags) +{ + printf_size_t unpadded_len = len; + + // pad with leading zeros + { + if (!(flags & FLAGS_LEFT)) { + if (width && (flags & FLAGS_ZEROPAD) && + (negative || (flags & (FLAGS_PLUS | FLAGS_SPACE)))) { + width--; + } + while ((flags & FLAGS_ZEROPAD) && (len < width) && (len < PRINTF_INTEGER_BUFFER_SIZE)) { + buf[len++] = '0'; + } + } + + while ((len < precision) && (len < PRINTF_INTEGER_BUFFER_SIZE)) { + buf[len++] = '0'; + } + + if (base == BASE_OCTAL && (len > unpadded_len)) { + // Since we've written some zeros, we've satisfied the alternative format leading space + // requirement + flags &= ~FLAGS_HASH; + } + } + + // handle hash + if (flags & (FLAGS_HASH | FLAGS_POINTER)) { + if (!(flags & FLAGS_PRECISION) && len && ((len == precision) || (len == width))) { + // Let's take back some padding digits to fit in what will eventually + // be the format-specific prefix + if (unpadded_len < len) { + len--; // This should suffice for BASE_OCTAL + } + if (len && (base == BASE_HEX || base == BASE_BINARY) && (unpadded_len < len)) { + len--; // ... and an extra one for 0x or 0b + } + } + if ((base == BASE_HEX) && !(flags & FLAGS_UPPERCASE) && + (len < PRINTF_INTEGER_BUFFER_SIZE)) { + buf[len++] = 'x'; + } else if ((base == BASE_HEX) && (flags & FLAGS_UPPERCASE) && + (len < PRINTF_INTEGER_BUFFER_SIZE)) { + buf[len++] = 'X'; + } else if ((base == BASE_BINARY) && (len < PRINTF_INTEGER_BUFFER_SIZE)) { + buf[len++] = 'b'; + } + if (len < PRINTF_INTEGER_BUFFER_SIZE) { + buf[len++] = '0'; + } + } + + if (len < PRINTF_INTEGER_BUFFER_SIZE) { + if (negative) { + buf[len++] = '-'; + } else if (flags & FLAGS_PLUS) { + buf[len++] = '+'; // ignore the space if the '+' exists + } else if (flags & FLAGS_SPACE) { + buf[len++] = ' '; + } + } + + out_rev_(output, buf, len, width, flags); +} + +// An internal itoa-like function +static void print_integer(output_gadget_t *output, printf_unsigned_value_t value, bool negative, + numeric_base_t base, printf_size_t precision, printf_size_t width, + printf_flags_t flags) +{ + char buf[PRINTF_INTEGER_BUFFER_SIZE]; + printf_size_t len = 0U; + + if (!value) { + if (!(flags & FLAGS_PRECISION)) { + buf[len++] = '0'; + flags &= ~FLAGS_HASH; + // We drop this flag this since either the alternative and regular modes of the + // specifier don't differ on 0 values, or (in the case of octal) we've already provided + // the special handling for this mode. + } else if (base == BASE_HEX) { + flags &= ~FLAGS_HASH; + // We drop this flag this since either the alternative and regular modes of the + // specifier don't differ on 0 values + } + } else { + do { + const char digit = (char)(value % base); + buf[len++] = (char)(digit < 10 ? '0' + digit + : (flags & FLAGS_UPPERCASE ? 'A' : 'a') + digit - 10); + value /= base; + } while (value && (len < PRINTF_INTEGER_BUFFER_SIZE)); + } + + print_integer_finalization(output, buf, len, negative, base, precision, width, flags); +} + +#if (PRINTF_SUPPORT_DECIMAL_SPECIFIERS || PRINTF_SUPPORT_EXPONENTIAL_SPECIFIERS) + +// Stores a fixed-precision representation of a double relative +// to a fixed precision (which cannot be determined by examining this structure) +struct double_components { + int_fast64_t integral; + int_fast64_t fractional; + // ... truncation of the actual fractional part of the double value, scaled + // by the precision value + bool is_negative; +}; + +#define NUM_DECIMAL_DIGITS_IN_INT64_T 18 +#define PRINTF_MAX_PRECOMPUTED_POWER_OF_10 NUM_DECIMAL_DIGITS_IN_INT64_T +static const double powers_of_10[NUM_DECIMAL_DIGITS_IN_INT64_T] = { + 1e00, 1e01, 1e02, 1e03, 1e04, 1e05, 1e06, 1e07, 1e08, + 1e09, 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17}; + +#define PRINTF_MAX_SUPPORTED_PRECISION NUM_DECIMAL_DIGITS_IN_INT64_T - 1 + +// Break up a double number - which is known to be a finite non-negative number - +// into its base-10 parts: integral - before the decimal point, and fractional - after it. +// Taken the precision into account, but does not change it even internally. +static struct double_components get_components(double number, printf_size_t precision) +{ + struct double_components number_; + number_.is_negative = get_sign_bit(number); + double abs_number = (number_.is_negative) ? -number : number; + number_.integral = (int_fast64_t)abs_number; + double remainder = (abs_number - (double)number_.integral) * powers_of_10[precision]; + number_.fractional = (int_fast64_t)remainder; + + remainder -= (double)number_.fractional; + + if (remainder > 0.5) { + ++number_.fractional; + // handle rollover, e.g. case 0.99 with precision 1 is 1.0 + if ((double)number_.fractional >= powers_of_10[precision]) { + number_.fractional = 0; + ++number_.integral; + } + } else if ((remainder == 0.5) && ((number_.fractional == 0U) || (number_.fractional & 1U))) { + // if halfway, round up if odd OR if last digit is 0 + ++number_.fractional; + } + + if (precision == 0U) { + remainder = abs_number - (double)number_.integral; + if ((!(remainder < 0.5) || (remainder > 0.5)) && (number_.integral & 1)) { + // exactly 0.5 and ODD, then round up + // 1.5 -> 2, but 2.5 -> 2 + ++number_.integral; + } + } + return number_; +} + +#if PRINTF_SUPPORT_EXPONENTIAL_SPECIFIERS +struct scaling_factor { + double raw_factor; + bool multiply; // if true, need to multiply by raw_factor; otherwise need to divide by it +}; + +static double apply_scaling(double num, struct scaling_factor normalization) +{ + return normalization.multiply ? num * normalization.raw_factor : num / normalization.raw_factor; +} + +static double unapply_scaling(double normalized, struct scaling_factor normalization) +{ +#ifdef __GNUC__ +// accounting for a static analysis bug in GCC 6.x and earlier +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wmaybe-uninitialized" +#endif + return normalization.multiply ? normalized / normalization.raw_factor + : normalized * normalization.raw_factor; +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif +} + +static struct scaling_factor update_normalization(struct scaling_factor sf, + double extra_multiplicative_factor) +{ + struct scaling_factor result; + if (sf.multiply) { + result.multiply = true; + result.raw_factor = sf.raw_factor * extra_multiplicative_factor; + } else { + int factor_exp2 = get_exp2(get_bit_access(sf.raw_factor)); + int extra_factor_exp2 = get_exp2(get_bit_access(extra_multiplicative_factor)); + + // Divide the larger-exponent raw raw_factor by the smaller + if (PRINTF_ABS(factor_exp2) > PRINTF_ABS(extra_factor_exp2)) { + result.multiply = false; + result.raw_factor = sf.raw_factor / extra_multiplicative_factor; + } else { + result.multiply = true; + result.raw_factor = extra_multiplicative_factor / sf.raw_factor; + } + } + return result; +} + +static struct double_components get_normalized_components(bool negative, printf_size_t precision, + double non_normalized, + struct scaling_factor normalization, + int floored_exp10) +{ + struct double_components components; + components.is_negative = negative; + double scaled = apply_scaling(non_normalized, normalization); + + bool close_to_representation_extremum = + ((-floored_exp10 + (int)precision) >= DBL_MAX_10_EXP - 1); + if (close_to_representation_extremum) { + // We can't have a normalization factor which also accounts for the precision, i.e. moves + // some decimal digits into the mantissa, since it's unrepresentable, or nearly + // unrepresentable. So, we'll give up early on getting extra precision... + return get_components(negative ? -scaled : scaled, precision); + } + components.integral = (int_fast64_t)scaled; + double remainder = non_normalized - unapply_scaling((double)components.integral, normalization); + double prec_power_of_10 = powers_of_10[precision]; + struct scaling_factor account_for_precision = + update_normalization(normalization, prec_power_of_10); + double scaled_remainder = apply_scaling(remainder, account_for_precision); + double rounding_threshold = 0.5; + + components.fractional = + (int_fast64_t)scaled_remainder; // when precision == 0, the assigned value should be 0 + scaled_remainder -= + (double)components.fractional; // when precision == 0, this will not change scaled_remainder + + components.fractional += (scaled_remainder >= rounding_threshold); + if (scaled_remainder == rounding_threshold) { + // banker's rounding: Round towards the even number (making the mean error 0) + components.fractional &= ~((int_fast64_t)0x1); + } + // handle rollover, e.g. the case of 0.99 with precision 1 becoming (0,100), + // and must then be corrected into (1, 0). + // Note: for precision = 0, this will "translate" the rounding effect from + // the fractional part to the integral part where it should actually be + // felt (as prec_power_of_10 is 1) + if ((double)components.fractional >= prec_power_of_10) { + components.fractional = 0; + ++components.integral; + } + return components; +} +#endif // PRINTF_SUPPORT_EXPONENTIAL_SPECIFIERS + +static void print_broken_up_decimal(struct double_components number_, output_gadget_t *output, + printf_size_t precision, printf_size_t width, + printf_flags_t flags, char *buf, printf_size_t len) +{ + if (precision != 0U) { + // do fractional part, as an unsigned number + + printf_size_t count = precision; + + // %g/%G mandates we skip the trailing 0 digits... + if ((flags & FLAGS_ADAPT_EXP) && !(flags & FLAGS_HASH) && (number_.fractional > 0)) { + while (true) { + int_fast64_t digit = number_.fractional % 10U; + if (digit != 0) { + break; + } + --count; + number_.fractional /= 10U; + } + // ... and even the decimal point if there are no + // non-zero fractional part digits (see below) + } + + if (number_.fractional > 0 || !(flags & FLAGS_ADAPT_EXP) || (flags & FLAGS_HASH)) { + while (len < PRINTF_DECIMAL_BUFFER_SIZE) { + --count; + buf[len++] = (char)('0' + number_.fractional % 10U); + if (!(number_.fractional /= 10U)) { + break; + } + } + // add extra 0s + while ((len < PRINTF_DECIMAL_BUFFER_SIZE) && (count > 0U)) { + buf[len++] = '0'; + --count; + } + if (len < PRINTF_DECIMAL_BUFFER_SIZE) { + buf[len++] = '.'; + } + } + } else { + if ((flags & FLAGS_HASH) && (len < PRINTF_DECIMAL_BUFFER_SIZE)) { + buf[len++] = '.'; + } + } + + // Write the integer part of the number (it comes after the fractional + // since the character order is reversed) + while (len < PRINTF_DECIMAL_BUFFER_SIZE) { + buf[len++] = (char)('0' + (number_.integral % 10)); + if (!(number_.integral /= 10)) { + break; + } + } + + // pad leading zeros + if (!(flags & FLAGS_LEFT) && (flags & FLAGS_ZEROPAD)) { + if (width && (number_.is_negative || (flags & (FLAGS_PLUS | FLAGS_SPACE)))) { + width--; + } + while ((len < width) && (len < PRINTF_DECIMAL_BUFFER_SIZE)) { + buf[len++] = '0'; + } + } + + if (len < PRINTF_DECIMAL_BUFFER_SIZE) { + if (number_.is_negative) { + buf[len++] = '-'; + } else if (flags & FLAGS_PLUS) { + buf[len++] = '+'; // ignore the space if the '+' exists + } else if (flags & FLAGS_SPACE) { + buf[len++] = ' '; + } + } + + out_rev_(output, buf, len, width, flags); +} + +// internal ftoa for fixed decimal floating point +static void print_decimal_number(output_gadget_t *output, double number, printf_size_t precision, + printf_size_t width, printf_flags_t flags, char *buf, + printf_size_t len) +{ + struct double_components value_ = get_components(number, precision); + print_broken_up_decimal(value_, output, precision, width, flags, buf, len); +} + +#if PRINTF_SUPPORT_EXPONENTIAL_SPECIFIERS + +// A floor function - but one which only works for numbers whose +// floor value is representable by an int. +static int bastardized_floor(double x) +{ + if (x >= 0) { + return (int)x; + } + int n = (int)x; + return (((double)n) == x) ? n : n - 1; +} + +// Computes the base-10 logarithm of the input number - which must be an actual +// positive number (not infinity or NaN, nor a sub-normal) +static double log10_of_positive(double positive_number) +{ + // The implementation follows David Gay (https://www.ampl.com/netlib/fp/dtoa.c). + // + // Since log_10 ( M * 2^x ) = log_10(M) + x , we can separate the components of + // our input number, and need only solve log_10(M) for M between 1 and 2 (as + // the base-2 mantissa is always 1-point-something). In that limited range, a + // Taylor series expansion of log10(x) should serve us well enough; and we'll + // take the mid-point, 1.5, as the point of expansion. + + double_with_bit_access dwba = get_bit_access(positive_number); + // based on the algorithm by David Gay (https://www.ampl.com/netlib/fp/dtoa.c) + int exp2 = get_exp2(dwba); + // drop the exponent, so dwba.F comes into the range [1,2) + dwba.U = (dwba.U & (((double_uint_t)(1) << DOUBLE_STORED_MANTISSA_BITS) - 1U)) | + ((double_uint_t)DOUBLE_BASE_EXPONENT << DOUBLE_STORED_MANTISSA_BITS); + double z = (dwba.F - 1.5); + return ( + // Taylor expansion around 1.5: + 0.1760912590556812420 // Expansion term 0: ln(1.5) / ln(10) + + z * 0.2895296546021678851 // Expansion term 1: (M - 1.5) * 2/3 / ln(10) +#if PRINTF_LOG10_TAYLOR_TERMS > 2 + - z * z * 0.0965098848673892950 // Expansion term 2: (M - 1.5)^2 * 2/9 / ln(10) +#if PRINTF_LOG10_TAYLOR_TERMS > 3 + + z * z * z * 0.0428932821632841311 // Expansion term 2: (M - 1.5)^3 * 8/81 / ln(10) +#endif +#endif + // exact log_2 of the exponent x, with logarithm base change + + exp2 * 0.30102999566398119521 // = exp2 * log_10(2) = exp2 * ln(2)/ln(10) + ); +} + +static double pow10_of_int(int floored_exp10) +{ + // A crude hack for avoiding undesired behavior with barely-normal or slightly-subnormal values. + if (floored_exp10 == DOUBLE_MAX_SUBNORMAL_EXPONENT_OF_10) { + return DOUBLE_MAX_SUBNORMAL_POWER_OF_10; + } + // Compute 10^(floored_exp10) but (try to) make sure that doesn't overflow + double_with_bit_access dwba; + int exp2 = bastardized_floor(floored_exp10 * 3.321928094887362 + 0.5); + const double z = floored_exp10 * 2.302585092994046 - exp2 * 0.6931471805599453; + const double z2 = z * z; + dwba.U = ((double_uint_t)(exp2) + DOUBLE_BASE_EXPONENT) << DOUBLE_STORED_MANTISSA_BITS; + // compute exp(z) using continued fractions, + // see https://en.wikipedia.org/wiki/Exponential_function#Continued_fractions_for_ex + dwba.F *= 1 + 2 * z / (2 - z + (z2 / (6 + (z2 / (10 + z2 / 14))))); + return dwba.F; +} + +static void print_exponential_number(output_gadget_t *output, double number, + printf_size_t precision, printf_size_t width, + printf_flags_t flags, char *buf, printf_size_t len) +{ + const bool negative = get_sign_bit(number); + // This number will decrease gradually (by factors of 10) as we "extract" the exponent out of it + double abs_number = negative ? -number : number; + + int floored_exp10; + bool abs_exp10_covered_by_powers_table; + struct scaling_factor normalization; + + // Determine the decimal exponent + if (abs_number == 0.0) { + // TODO: This is a special-case for 0.0 (and -0.0); but proper handling is required for + // denormals more generally. + floored_exp10 = + 0; // ... and no need to set a normalization factor or check the powers table + } else { + double exp10 = log10_of_positive(abs_number); + floored_exp10 = bastardized_floor(exp10); + double p10 = pow10_of_int(floored_exp10); + // correct for rounding errors + if (abs_number < p10) { + floored_exp10--; + p10 /= 10; + } + abs_exp10_covered_by_powers_table = + PRINTF_ABS(floored_exp10) < PRINTF_MAX_PRECOMPUTED_POWER_OF_10; + normalization.raw_factor = + abs_exp10_covered_by_powers_table ? powers_of_10[PRINTF_ABS(floored_exp10)] : p10; + } + + // We now begin accounting for the widths of the two parts of our printed field: + // the decimal part after decimal exponent extraction, and the base-10 exponent part. + // For both of these, the value of 0 has a special meaning, but not the same one: + // a 0 exponent-part width means "don't print the exponent"; a 0 decimal-part width + // means "use as many characters as necessary". + + bool fall_back_to_decimal_only_mode = false; + if (flags & FLAGS_ADAPT_EXP) { + int required_significant_digits = (precision == 0) ? 1 : (int)precision; + // Should we want to fall-back to "%f" mode, and only print the decimal part? + fall_back_to_decimal_only_mode = + (floored_exp10 >= -4 && floored_exp10 < required_significant_digits); + // Now, let's adjust the precision + // This also decided how we adjust the precision value - as in "%g" mode, + // "precision" is the number of _significant digits_, and this is when we "translate" + // the precision value to an actual number of decimal digits. + int precision_ = + fall_back_to_decimal_only_mode + ? (int)precision - 1 - floored_exp10 + : (int)precision - 1; // the presence of the exponent ensures only one significant + // digit comes before the decimal point + precision = (precision_ > 0 ? (unsigned)precision_ : 0U); + flags |= FLAGS_PRECISION; // make sure print_broken_up_decimal respects our choice above + } + + normalization.multiply = (floored_exp10 < 0 && abs_exp10_covered_by_powers_table); + bool should_skip_normalization = (fall_back_to_decimal_only_mode || floored_exp10 == 0); + struct double_components decimal_part_components = + should_skip_normalization ? get_components(negative ? -abs_number : abs_number, precision) + : get_normalized_components(negative, precision, abs_number, + normalization, floored_exp10); + + // Account for roll-over, e.g. rounding from 9.99 to 100.0 - which effects + // the exponent and may require additional tweaking of the parts + if (fall_back_to_decimal_only_mode) { + if ((flags & FLAGS_ADAPT_EXP) && floored_exp10 >= -1 && + decimal_part_components.integral == powers_of_10[floored_exp10 + 1]) { + floored_exp10++; // Not strictly necessary, since floored_exp10 is no longer really used + precision--; + // ... and it should already be the case that decimal_part_components.fractional == 0 + } + // TODO: What about rollover strictly within the fractional part? + } else { + if (decimal_part_components.integral >= 10) { + floored_exp10++; + decimal_part_components.integral = 1; + decimal_part_components.fractional = 0; + } + } + + // the floored_exp10 format is "E%+03d" and largest possible floored_exp10 value for a 64-bit + // double is "307" (for 2^1023), so we set aside 4-5 characters overall + printf_size_t exp10_part_width = fall_back_to_decimal_only_mode ? 0U + : (PRINTF_ABS(floored_exp10) < 100) ? 4U + : 5U; + + printf_size_t decimal_part_width = + ((flags & FLAGS_LEFT) && exp10_part_width) + ? + // We're padding on the right, so the width constraint is the exponent part's + // problem, not the decimal part's, so we'll use as many characters as we need: + 0U + : + // We're padding on the left; so the width constraint is the decimal part's + // problem. Well, can both the decimal part and the exponent part fit within our overall + // width? + ((width > exp10_part_width) + ? + // Yes, so we limit our decimal part's width. + // (Note this is trivially valid even if we've fallen back to "%f" mode) + width - exp10_part_width + : + // No; we just give up on any restriction on the decimal part and use as many + // characters as we need + 0U); + + const printf_size_t printed_exponential_start_pos = output->pos; + print_broken_up_decimal(decimal_part_components, output, precision, decimal_part_width, flags, + buf, len); + + if (!fall_back_to_decimal_only_mode) { + putchar_via_gadget(output, (flags & FLAGS_UPPERCASE) ? 'E' : 'e'); + print_integer(output, ABS_FOR_PRINTING(floored_exp10), floored_exp10 < 0, 10, 0, + exp10_part_width - 1, FLAGS_ZEROPAD | FLAGS_PLUS); + if (flags & FLAGS_LEFT) { + // We need to right-pad with spaces to meet the width requirement + while (output->pos - printed_exponential_start_pos < width) { + putchar_via_gadget(output, ' '); + } + } + } +} +#endif // PRINTF_SUPPORT_EXPONENTIAL_SPECIFIERS + +static void print_floating_point(output_gadget_t *output, double value, printf_size_t precision, + printf_size_t width, printf_flags_t flags, bool prefer_exponential) +{ + char buf[PRINTF_DECIMAL_BUFFER_SIZE]; + printf_size_t len = 0U; + + // test for special values + if (value != value) { + out_rev_(output, "nan", 3, width, flags); + return; + } + if (value < -DBL_MAX) { + out_rev_(output, "fni-", 4, width, flags); + return; + } + if (value > DBL_MAX) { + out_rev_(output, (flags & FLAGS_PLUS) ? "fni+" : "fni", (flags & FLAGS_PLUS) ? 4U : 3U, + width, flags); + return; + } + + if (!prefer_exponential && + ((value > PRINTF_FLOAT_NOTATION_THRESHOLD) || (value < -PRINTF_FLOAT_NOTATION_THRESHOLD))) { + // The required behavior of standard printf is to print _every_ integral-part digit -- which + // could mean printing hundreds of characters, overflowing any fixed internal buffer and + // necessitating a more complicated implementation. +#if PRINTF_SUPPORT_EXPONENTIAL_SPECIFIERS + print_exponential_number(output, value, precision, width, flags, buf, len); +#endif + return; + } + + // set default precision, if not set explicitly + if (!(flags & FLAGS_PRECISION)) { + precision = PRINTF_DEFAULT_FLOAT_PRECISION; + } + + // limit precision so that our integer holding the fractional part does not overflow + while ((len < PRINTF_DECIMAL_BUFFER_SIZE) && (precision > PRINTF_MAX_SUPPORTED_PRECISION)) { + buf[len++] = '0'; // This respects the precision in terms of result length only + precision--; + } + +#if PRINTF_SUPPORT_EXPONENTIAL_SPECIFIERS + if (prefer_exponential) + print_exponential_number(output, value, precision, width, flags, buf, len); + else +#endif + print_decimal_number(output, value, precision, width, flags, buf, len); +} + +#endif // (PRINTF_SUPPORT_DECIMAL_SPECIFIERS || PRINTF_SUPPORT_EXPONENTIAL_SPECIFIERS) + +// Advances the format pointer past the flags, and returns the parsed flags +// due to the characters passed +static printf_flags_t parse_flags(const char **format) +{ + printf_flags_t flags = 0U; + do { + switch (**format) { + case '0': + flags |= FLAGS_ZEROPAD; + (*format)++; + break; + case '-': + flags |= FLAGS_LEFT; + (*format)++; + break; + case '+': + flags |= FLAGS_PLUS; + (*format)++; + break; + case ' ': + flags |= FLAGS_SPACE; + (*format)++; + break; + case '#': + flags |= FLAGS_HASH; + (*format)++; + break; + default: + return flags; + } + } while (true); +} + +static inline void format_string_loop(output_gadget_t *output, const char *format, va_list args) +{ +#if PRINTF_CHECK_FOR_NUL_IN_FORMAT_SPECIFIER +#define ADVANCE_IN_FORMAT_STRING(cptr_) \ + do { \ + (cptr_)++; \ + if (!*(cptr_)) \ + return; \ + } while (0) +#else +#define ADVANCE_IN_FORMAT_STRING(cptr_) (cptr_)++ +#endif + + while (*format) { + if (*format != '%') { + // A regular content character + putchar_via_gadget(output, *format); + format++; + continue; + } + // We're parsing a format specifier: %[flags][width][.precision][length] + ADVANCE_IN_FORMAT_STRING(format); + + printf_flags_t flags = parse_flags(&format); + + // evaluate width field + printf_size_t width = 0U; + if (is_digit_(*format)) { + width = (printf_size_t)atou_(&format); + } else if (*format == '*') { + const int w = va_arg(args, int); + if (w < 0) { + flags |= FLAGS_LEFT; // reverse padding + width = (printf_size_t)-w; + } else { + width = (printf_size_t)w; + } + ADVANCE_IN_FORMAT_STRING(format); + } + + // evaluate precision field + printf_size_t precision = 0U; + if (*format == '.') { + flags |= FLAGS_PRECISION; + ADVANCE_IN_FORMAT_STRING(format); + if (is_digit_(*format)) { + precision = (printf_size_t)atou_(&format); + } else if (*format == '*') { + const int precision_ = va_arg(args, int); + precision = precision_ > 0 ? (printf_size_t)precision_ : 0U; + ADVANCE_IN_FORMAT_STRING(format); + } + } + + // evaluate length field + switch (*format) { +#ifdef PRINTF_SUPPORT_MSVC_STYLE_INTEGER_SPECIFIERS + case 'I': { + ADVANCE_IN_FORMAT_STRING(format); + // Greedily parse for size in bits: 8, 16, 32 or 64 + switch (*format) { + case '8': + flags |= FLAGS_INT8; + ADVANCE_IN_FORMAT_STRING(format); + break; + case '1': + ADVANCE_IN_FORMAT_STRING(format); + if (*format == '6') { + format++; + flags |= FLAGS_INT16; + } + break; + case '3': + ADVANCE_IN_FORMAT_STRING(format); + if (*format == '2') { + ADVANCE_IN_FORMAT_STRING(format); + flags |= FLAGS_INT32; + } + break; + case '6': + ADVANCE_IN_FORMAT_STRING(format); + if (*format == '4') { + ADVANCE_IN_FORMAT_STRING(format); + flags |= FLAGS_INT64; + } + break; + default: + break; + } + break; + } +#endif + case 'l': + flags |= FLAGS_LONG; + ADVANCE_IN_FORMAT_STRING(format); + if (*format == 'l') { + flags |= FLAGS_LONG_LONG; + ADVANCE_IN_FORMAT_STRING(format); + } + break; + case 'h': + flags |= FLAGS_SHORT; + ADVANCE_IN_FORMAT_STRING(format); + if (*format == 'h') { + flags |= FLAGS_CHAR; + ADVANCE_IN_FORMAT_STRING(format); + } + break; + case 't': + flags |= (sizeof(ptrdiff_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG); + ADVANCE_IN_FORMAT_STRING(format); + break; + case 'j': + flags |= (sizeof(intmax_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG); + ADVANCE_IN_FORMAT_STRING(format); + break; + case 'z': + flags |= (sizeof(size_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG); + ADVANCE_IN_FORMAT_STRING(format); + break; + default: + break; + } + + // evaluate specifier + switch (*format) { + case 'd': + case 'i': + case 'u': + case 'x': + case 'X': + case 'o': + case 'b': { + + if (*format == 'd' || *format == 'i') { + flags |= FLAGS_SIGNED; + } + + numeric_base_t base; + if (*format == 'x' || *format == 'X') { + base = BASE_HEX; + } else if (*format == 'o') { + base = BASE_OCTAL; + } else if (*format == 'b') { + base = BASE_BINARY; + } else { + base = BASE_DECIMAL; + flags &= ~FLAGS_HASH; // decimal integers have no alternative presentation + } + + if (*format == 'X') { + flags |= FLAGS_UPPERCASE; + } + + format++; + // ignore '0' flag when precision is given + if (flags & FLAGS_PRECISION) { + flags &= ~FLAGS_ZEROPAD; + } + + if (flags & FLAGS_SIGNED) { + // A signed specifier: d, i or possibly I + bit size if enabled + + if (flags & FLAGS_LONG_LONG) { +#if PRINTF_SUPPORT_LONG_LONG + const long long value = va_arg(args, long long); + print_integer(output, ABS_FOR_PRINTING(value), value < 0, base, precision, + width, flags); +#endif + } else if (flags & FLAGS_LONG) { + const long value = va_arg(args, long); + print_integer(output, ABS_FOR_PRINTING(value), value < 0, base, precision, + width, flags); + } else { + // We never try to interpret the argument as something potentially-smaller than + // int, due to integer promotion rules: Even if the user passed a short int, + // short unsigned etc. - these will come in after promotion, as int's (or + // unsigned for the case of short unsigned when it has the same size as int) + const int value = (flags & FLAGS_CHAR) ? (signed char)va_arg(args, int) + : (flags & FLAGS_SHORT) ? (short int)va_arg(args, int) + : va_arg(args, int); + print_integer(output, ABS_FOR_PRINTING(value), value < 0, base, precision, + width, flags); + } + } else { + // An unsigned specifier: u, x, X, o, b + + flags &= ~(FLAGS_PLUS | FLAGS_SPACE); + + if (flags & FLAGS_LONG_LONG) { +#if PRINTF_SUPPORT_LONG_LONG + print_integer(output, (printf_unsigned_value_t)va_arg(args, unsigned long long), + false, base, precision, width, flags); +#endif + } else if (flags & FLAGS_LONG) { + print_integer(output, (printf_unsigned_value_t)va_arg(args, unsigned long), + false, base, precision, width, flags); + } else { + const unsigned int value = + (flags & FLAGS_CHAR) ? (unsigned char)va_arg(args, unsigned int) + : (flags & FLAGS_SHORT) ? (unsigned short int)va_arg(args, unsigned int) + : va_arg(args, unsigned int); + print_integer(output, (printf_unsigned_value_t)value, false, base, precision, + width, flags); + } + } + break; + } +#if PRINTF_SUPPORT_DECIMAL_SPECIFIERS + case 'f': + case 'F': + if (*format == 'F') + flags |= FLAGS_UPPERCASE; + print_floating_point(output, va_arg(args, double), precision, width, flags, + PRINTF_PREFER_DECIMAL); + format++; + break; +#endif +#if PRINTF_SUPPORT_EXPONENTIAL_SPECIFIERS + case 'e': + case 'E': + case 'g': + case 'G': + if ((*format == 'g') || (*format == 'G')) + flags |= FLAGS_ADAPT_EXP; + if ((*format == 'E') || (*format == 'G')) + flags |= FLAGS_UPPERCASE; + print_floating_point(output, va_arg(args, double), precision, width, flags, + PRINTF_PREFER_EXPONENTIAL); + format++; + break; +#endif // PRINTF_SUPPORT_EXPONENTIAL_SPECIFIERS + case 'c': { + printf_size_t l = 1U; + // pre padding + if (!(flags & FLAGS_LEFT)) { + while (l++ < width) { + putchar_via_gadget(output, ' '); + } + } + // char output + putchar_via_gadget(output, (char)va_arg(args, int)); + // post padding + if (flags & FLAGS_LEFT) { + while (l++ < width) { + putchar_via_gadget(output, ' '); + } + } + format++; + break; + } + + case 's': { + const char *p = va_arg(args, char *); + if (p == NULL) { + out_rev_(output, ")llun(", 6, width, flags); + } else { + printf_size_t l = + strnlen_s_(p, precision ? precision : PRINTF_MAX_POSSIBLE_BUFFER_SIZE); + // pre padding + if (flags & FLAGS_PRECISION) { + l = (l < precision ? l : precision); + } + if (!(flags & FLAGS_LEFT)) { + while (l++ < width) { + putchar_via_gadget(output, ' '); + } + } + // string output + while ((*p != 0) && (!(flags & FLAGS_PRECISION) || precision)) { + putchar_via_gadget(output, *(p++)); + --precision; + } + // post padding + if (flags & FLAGS_LEFT) { + while (l++ < width) { + putchar_via_gadget(output, ' '); + } + } + } + format++; + break; + } + + case 'p': { + width = sizeof(void *) * 2U + 2; // 2 hex chars per byte + the "0x" prefix + flags |= FLAGS_ZEROPAD | FLAGS_POINTER; + uintptr_t value = (uintptr_t)va_arg(args, void *); + (value == (uintptr_t)NULL) ? out_rev_(output, ")lin(", 5, width, flags) + : print_integer(output, (printf_unsigned_value_t)value, + false, BASE_HEX, precision, width, flags); + format++; + break; + } + + case '%': + putchar_via_gadget(output, '%'); + format++; + break; + + // Many people prefer to disable support for %n, as it lets the caller + // engineer a write to an arbitrary location, of a value the caller + // effectively controls - which could be a security concern in some cases. +#if PRINTF_SUPPORT_WRITEBACK_SPECIFIER + case 'n': { + if (flags & FLAGS_CHAR) + *(va_arg(args, char *)) = (char)output->pos; + else if (flags & FLAGS_SHORT) + *(va_arg(args, short *)) = (short)output->pos; + else if (flags & FLAGS_LONG) + *(va_arg(args, long *)) = (long)output->pos; +#if PRINTF_SUPPORT_LONG_LONG + else if (flags & FLAGS_LONG_LONG) + *(va_arg(args, long long *)) = (long long int)output->pos; +#endif // PRINTF_SUPPORT_LONG_LONG + else + *(va_arg(args, int *)) = (int)output->pos; + format++; + break; + } +#endif // PRINTF_SUPPORT_WRITEBACK_SPECIFIER + + default: + putchar_via_gadget(output, *format); + format++; + break; + } + } +} + +// internal vsnprintf - used for implementing _all library functions +static int vsnprintf_impl(output_gadget_t *output, const char *format, va_list args) +{ + // Note: The library only calls vsnprintf_impl() with output->pos being 0. However, it is + // possible to call this function with a non-zero pos value for some "remedial printing". + format_string_loop(output, format, args); + + // termination + append_termination_with_gadget(output); + + // return written chars without terminating \0 + return (int)output->pos; +} + +/////////////////////////////////////////////////////////////////////////////// + +// int vprintf_(const char *format, va_list arg) +// { +// output_gadget_t gadget = extern_putchar_gadget(); +// return vsnprintf_impl(&gadget, format, arg); +// } + +int vsnprintf_(char *s, size_t n, const char *format, va_list arg) +{ + output_gadget_t gadget = buffer_gadget(s, n); + return vsnprintf_impl(&gadget, format, arg); +} + +int vsprintf_(char *s, const char *format, va_list arg) +{ + return vsnprintf_(s, PRINTF_MAX_POSSIBLE_BUFFER_SIZE, format, arg); +} + +int vfctprintf(void (*out)(char c, void *extra_arg), void *extra_arg, const char *format, + va_list arg) +{ + output_gadget_t gadget = function_gadget(out, extra_arg); + return vsnprintf_impl(&gadget, format, arg); +} + +// int printf_(const char *format, ...) +// { +// va_list args; +// va_start(args, format); +// const int ret = vprintf_(format, args); +// va_end(args); +// return ret; +// } + +int sprintf_(char *s, const char *format, ...) +{ + va_list args; + va_start(args, format); + const int ret = vsprintf_(s, format, args); + va_end(args); + return ret; +} + +int snprintf_(char *s, size_t n, const char *format, ...) +{ + va_list args; + va_start(args, format); + const int ret = vsnprintf_(s, n, format, args); + va_end(args); + return ret; +} + +int fctprintf(void (*out)(char c, void *extra_arg), void *extra_arg, const char *format, ...) +{ + va_list args; + va_start(args, format); + const int ret = vfctprintf(out, extra_arg, format, args); + va_end(args); + return ret; +} diff --git a/tools/axlibc/c/printf.h b/tools/axlibc/c/printf.h new file mode 100644 index 0000000..c6484e5 --- /dev/null +++ b/tools/axlibc/c/printf.h @@ -0,0 +1,215 @@ +/** + * @author (c) Eyal Rozenberg + * 2021-2022, Haifa, Palestine/Israel + * @author (c) Marco Paland (info@paland.com) + * 2014-2019, PALANDesign Hannover, Germany + * + * @note Others have made smaller contributions to this file: see the + * contributors page at https://github.com/eyalroz/printf/graphs/contributors + * or ask one of the authors. + * + * @brief Small stand-alone implementation of the printf family of functions + * (`(v)printf`, `(v)s(n)printf` etc., geared towards use on embedded systems with + * a very limited resources. + * + * @note the implementations are thread-safe; re-entrant; use no functions from + * the standard library; and do not dynamically allocate any memory. + * + * @license The MIT License (MIT) + * + * 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 PRINTF_H_ +#define PRINTF_H_ + +#ifdef __cplusplus +#include +#include +extern "C" { +#else +#include +#include +#endif + +#ifdef __GNUC__ +#if ((__GNUC__ == 4 && __GNUC_MINOR__ >= 4) || __GNUC__ > 4) +#define ATTR_PRINTF(one_based_format_index, first_arg) \ + __attribute__((format(gnu_printf, (one_based_format_index), (first_arg)))) +#else +#define ATTR_PRINTF(one_based_format_index, first_arg) \ + __attribute__((format(printf, (one_based_format_index), (first_arg)))) +#endif +#define ATTR_VPRINTF(one_based_format_index) ATTR_PRINTF((one_based_format_index), 0) +#else +#define ATTR_PRINTF(one_based_format_index, first_arg) +#define ATTR_VPRINTF(one_based_format_index) +#endif + +#ifndef PRINTF_ALIAS_STANDARD_FUNCTION_NAMES +#define PRINTF_ALIAS_STANDARD_FUNCTION_NAMES 0 +#endif + +#if PRINTF_ALIAS_STANDARD_FUNCTION_NAMES_HARD +#define printf_ printf +#define sprintf_ sprintf +#define vsprintf_ vsprintf +#define snprintf_ snprintf +#define vsnprintf_ vsnprintf +#define vprintf_ vprintf +#endif + +// If you want to include this implementation file directly rather than +// link against, this will let you control the functions' visibility, +// e.g. make them static so as not to clash with other objects also +// using them. +#ifndef PRINTF_VISIBILITY +#define PRINTF_VISIBILITY +#endif + +/** + * Prints/send a single character to some opaque output entity + * + * @note This function is not implemented by the library, only declared; you must provide an + * implementation if you wish to use the @ref printf / @ref vprintf function (and possibly + * for linking against the library, if your toolchain does not support discarding unused functions) + * + * @note The output could be as simple as a wrapper for the `write()` system call on a Unix-like + * system, or even libc's @ref putchar , for replicating actual functionality of libc's @ref printf + * function; but on an embedded system it may involve interaction with a special output device, + * like a UART, etc. + * + * @note in libc's @ref putchar, the parameter type is an int; this was intended to support the + * representation of either a proper character or EOF in a variable - but this is really not + * meaningful to pass into @ref putchar and is discouraged today. See further discussion in: + * @link https://stackoverflow.com/q/17452847/1593077 + * + * @param c the single character to print + */ +// PRINTF_VISIBILITY +// void putchar_(char c); + +/** + * An implementation of the C standard's printf/vprintf + * + * @note you must implement a @ref putchar_ function for using this function - it invokes @ref + * putchar_ rather than directly performing any I/O (which insulates it from any dependence on the + * operating system and external libraries). + * + * @param format A string specifying the format of the output, with %-marked specifiers of how to + * interpret additional arguments. + * @param arg Additional arguments to the function, one for each %-specifier in @p format string + * @return The number of characters written into @p s, not counting the terminating null character + */ +///@{ +// PRINTF_VISIBILITY +// int printf_(const char* format, ...) ATTR_PRINTF(1, 2); +// PRINTF_VISIBILITY +// int vprintf_(const char* format, va_list arg) ATTR_VPRINTF(1); +///@} + +/** + * An implementation of the C standard's sprintf/vsprintf + * + * @note For security considerations (the potential for exceeding the buffer bounds), please + * consider using the size-constrained variant, @ref snprintf / @ref vsnprintf , instead. + * + * @param s An array in which to store the formatted string. It must be large enough to fit the + * formatted output! + * @param format A string specifying the format of the output, with %-marked specifiers of how to + * interpret additional arguments. + * @param arg Additional arguments to the function, one for each specifier in @p format + * @return The number of characters written into @p s, not counting the terminating null character + */ +///@{ +PRINTF_VISIBILITY +int sprintf_(char *s, const char *format, ...) ATTR_PRINTF(2, 3); +PRINTF_VISIBILITY +int vsprintf_(char *s, const char *format, va_list arg) ATTR_VPRINTF(2); +///@} + +/** + * An implementation of the C standard's snprintf/vsnprintf + * + * @param s An array in which to store the formatted string. It must be large enough to fit either + * the entire formatted output, or at least @p n characters. Alternatively, it can be NULL, in which + * case nothing will be printed, and only the number of characters which _could_ have been printed + * is tallied and returned. + * @param n The maximum number of characters to write to the array, including a terminating null + * character + * @param format A string specifying the format of the output, with %-marked specifiers of how to + * interpret additional arguments. + * @param arg Additional arguments to the function, one for each specifier in @p format + * @return The number of characters that COULD have been written into @p s, not counting the + * terminating null character. A value equal or larger than @p n indicates truncation. Only when the + * returned value is non-negative and less than @p n, the null-terminated string has been fully and + * successfully printed. + */ +///@{ +PRINTF_VISIBILITY +int snprintf_(char *s, size_t count, const char *format, ...) ATTR_PRINTF(3, 4); +PRINTF_VISIBILITY +int vsnprintf_(char *s, size_t count, const char *format, va_list arg) ATTR_VPRINTF(3); +///@} + +/** + * printf/vprintf with user-specified output function + * + * An alternative to @ref printf_, in which the output function is specified dynamically + * (rather than @ref putchar_ being used) + * + * @param out An output function which takes one character and a type-erased additional parameters + * @param extra_arg The type-erased argument to pass to the output function @p out with each call + * @param format A string specifying the format of the output, with %-marked specifiers of how to + * interpret additional arguments. + * @param arg Additional arguments to the function, one for each specifier in @p format + * @return The number of characters for which the output f unction was invoked, not counting the + * terminating null character + * + */ +PRINTF_VISIBILITY +int fctprintf(void (*out)(char c, void *extra_arg), void *extra_arg, const char *format, ...) + ATTR_PRINTF(3, 4); +PRINTF_VISIBILITY +int vfctprintf(void (*out)(char c, void *extra_arg), void *extra_arg, const char *format, + va_list arg) ATTR_VPRINTF(3); + +#ifdef __cplusplus +} // extern "C" +#endif + +#if PRINTF_ALIAS_STANDARD_FUNCTION_NAMES_HARD +#undef printf_ +#undef sprintf_ +#undef vsprintf_ +#undef snprintf_ +#undef vsnprintf_ +#undef vprintf_ +#else +#if PRINTF_ALIAS_STANDARD_FUNCTION_NAMES_SOFT +#define printf printf_ +#define sprintf sprintf_ +#define vsprintf vsprintf_ +#define snprintf snprintf_ +#define vsnprintf vsnprintf_ +#define vprintf vprintf_ +#endif +#endif + +#endif // PRINTF_H_ diff --git a/tools/axlibc/c/printf_config.h b/tools/axlibc/c/printf_config.h new file mode 100644 index 0000000..bd860a7 --- /dev/null +++ b/tools/axlibc/c/printf_config.h @@ -0,0 +1,14 @@ +#ifndef PRINTF_CONFIG_H +#define PRINTF_CONFIG_H + +#define PRINTF_ALIAS_STANDARD_FUNCTION_NAMES 1 + +#ifndef AX_CONFIG_FP_SIMD + +#define PRINTF_SUPPORT_DECIMAL_SPECIFIERS 0 + +#define PRINTF_SUPPORT_EXPONENTIAL_SPECIFIERS 0 + +#endif // AX_CONFIG_FP_SIMD + +#endif // PRINTF_CONFIG_H diff --git a/tools/axlibc/c/pthread.c b/tools/axlibc/c/pthread.c new file mode 100644 index 0000000..74fb1fa --- /dev/null +++ b/tools/axlibc/c/pthread.c @@ -0,0 +1,110 @@ +#ifdef AX_CONFIG_MULTITASK + +#include +#include +#include +#include +#include + +int pthread_setcancelstate(int new, int *old) +{ + unimplemented(); + return 0; +} + +int pthread_setcanceltype(int new, int *old) +{ + unimplemented(); + return 0; +} + +// TODO +void pthread_testcancel(void) +{ + unimplemented(); + return; +} + +// TODO +int pthread_cancel(pthread_t t) +{ + unimplemented(); + return 0; +} + +// TODO +int pthread_mutex_trylock(pthread_mutex_t *m) +{ + unimplemented(); + return 0; +} + +// TODO +int pthread_setname_np(pthread_t thread, const char *name) +{ + unimplemented(); + return 0; +} + +int pthread_cond_init(pthread_cond_t *restrict c, const pthread_condattr_t *restrict a) +{ + *c = (pthread_cond_t){0}; + if (a) { + c->_c_clock = a->__attr & 0x7fffffff; + if (a->__attr >> 31) + c->_c_shared = (void *)-1; + } + return 0; +} + +// TODO +int pthread_cond_signal(pthread_cond_t *__cond) +{ + unimplemented(); + return 0; +} + +// TODO +int pthread_cond_wait(pthread_cond_t *__restrict__ __cond, pthread_mutex_t *__restrict__ __mutex) +{ + unimplemented(); + return 0; +} + +// TODO +int pthread_cond_broadcast(pthread_cond_t *c) +{ + unimplemented(); + return 0; +} + +#define DEFAULT_STACK_SIZE 131072 +#define DEFAULT_GUARD_SIZE 8192 + +// TODO +int pthread_attr_init(pthread_attr_t *a) +{ + *a = (pthread_attr_t){0}; + // __acquire_ptc(); + a->_a_stacksize = DEFAULT_STACK_SIZE; + a->_a_guardsize = DEFAULT_GUARD_SIZE; + // __release_ptc(); + return 0; +} + +int pthread_attr_getstacksize(const pthread_attr_t *restrict a, size_t *restrict size) +{ + *size = a->_a_stacksize; + return 0; +} + +int pthread_attr_setstacksize(pthread_attr_t *a, size_t size) +{ + if (size - PTHREAD_STACK_MIN > SIZE_MAX / 4) + return EINVAL; + a->_a_stackaddr = 0; + a->_a_stacksize = size; + return 0; +} + +#endif // AX_CONFIG_MULTITASK diff --git a/tools/axlibc/c/pwd.c b/tools/axlibc/c/pwd.c new file mode 100644 index 0000000..61f32f4 --- /dev/null +++ b/tools/axlibc/c/pwd.c @@ -0,0 +1,14 @@ +#include +#include + +int getpwnam_r(const char *name, struct passwd *pw, char *buf, size_t size, struct passwd **res) +{ + unimplemented(); + return 0; +} + +int getpwuid_r(uid_t uid, struct passwd *pw, char *buf, size_t size, struct passwd **res) +{ + unimplemented(); + return 0; +} diff --git a/tools/axlibc/c/resource.c b/tools/axlibc/c/resource.c new file mode 100644 index 0000000..3e34624 --- /dev/null +++ b/tools/axlibc/c/resource.c @@ -0,0 +1,10 @@ +#include +#include +#include + +// TODO +int getrusage(int __who, struct rusage *__usage) +{ + unimplemented(); + return 0; +} diff --git a/tools/axlibc/c/sched.c b/tools/axlibc/c/sched.c new file mode 100644 index 0000000..21203c4 --- /dev/null +++ b/tools/axlibc/c/sched.c @@ -0,0 +1,9 @@ +#include +#include + +// TODO +int sched_setaffinity(pid_t __pid, size_t __cpusetsize, const cpu_set_t *__cpuset) +{ + unimplemented(); + return 0; +} diff --git a/tools/axlibc/c/select.c b/tools/axlibc/c/select.c new file mode 100644 index 0000000..d20d5f6 --- /dev/null +++ b/tools/axlibc/c/select.c @@ -0,0 +1,17 @@ +#ifdef AX_CONFIG_SELECT + +#include +#include +#include +#include +#include + +int pselect(int n, fd_set *restrict rfds, fd_set *restrict wfds, fd_set *restrict efds, + const struct timespec *restrict ts, const sigset_t *restrict mask) +{ + struct timeval tv = {ts->tv_sec, ts->tv_nsec / 1000}; + select(n, rfds, wfds, efds, &tv); + return 0; +} + +#endif // AX_CONFIG_SELECT diff --git a/tools/axlibc/c/signal.c b/tools/axlibc/c/signal.c new file mode 100644 index 0000000..de21647 --- /dev/null +++ b/tools/axlibc/c/signal.c @@ -0,0 +1,87 @@ +#include +#include +#include +#include + +int sigaction_helper(int signum, const struct sigaction *act, struct sigaction *oldact, + size_t sigsetsize) +{ + if (signum == SIGKILL || signum == SIGSTOP) + return -EINVAL; + + if (oldact) + *oldact = (struct sigaction){0}; + + return 0; +} + +void (*signal(int signum, void (*handler)(int)))(int) +{ + struct sigaction old; + struct sigaction act = { + .sa_handler = handler, .sa_flags = SA_RESTART, /* BSD signal semantics */ + }; + + if (sigaction_helper(signum, &act, &old, sizeof(sigset_t)) < 0) + return SIG_ERR; + + return (old.sa_flags & SA_SIGINFO) ? NULL : old.sa_handler; +} + +int sigaction(int sig, const struct sigaction *restrict act, struct sigaction *restrict oact) +{ + return sigaction_helper(sig, act, oact, sizeof(sigset_t)); +} + +// TODO +int kill(pid_t __pid, int __sig) +{ + unimplemented(); + return 0; +} + +int sigemptyset(sigset_t *set) +{ + set->__bits[0] = 0; + if (sizeof(long) == 4 || _NSIG > 65) + set->__bits[1] = 0; + if (sizeof(long) == 4 && _NSIG > 65) { + set->__bits[2] = 0; + set->__bits[3] = 0; + } + return 0; +} + +// TODO +int raise(int __sig) +{ + unimplemented(); + return 0; +} + +int sigaddset(sigset_t *set, int sig) +{ + unsigned s = sig - 1; + if (s >= _NSIG - 1 || sig - 32U < 3) { + errno = EINVAL; + return -1; + } + set->__bits[s / 8 / sizeof *set->__bits] |= 1UL << (s & (8 * sizeof *set->__bits - 1)); + return 0; +} + +// TODO +int pthread_sigmask(int __how, const sigset_t *restrict __newmask, sigset_t *restrict __oldmask) +{ + unimplemented(); + return 0; +} + +#ifdef AX_CONFIG_MULTITASK +// TODO +int pthread_kill(pthread_t t, int sig) +{ + unimplemented(); + return 0; +} +#endif diff --git a/tools/axlibc/c/socket.c b/tools/axlibc/c/socket.c new file mode 100644 index 0000000..677e431 --- /dev/null +++ b/tools/axlibc/c/socket.c @@ -0,0 +1,47 @@ +#ifdef AX_CONFIG_NET + +#include +#include +#include +#include +#include + +int accept4(int fd, struct sockaddr *restrict addr, socklen_t *restrict len, int flg) +{ + if (!flg) + return accept(fd, addr, len); + if (flg & ~(SOCK_CLOEXEC | SOCK_NONBLOCK)) { + errno = EINVAL; + return -1; + } + int ret = accept(fd, addr, len); + if (ret < 0) + return ret; + if (flg & SOCK_CLOEXEC) + fcntl(ret, F_SETFD, FD_CLOEXEC); + if (flg & SOCK_NONBLOCK) + fcntl(ret, F_SETFL, O_NONBLOCK); + return ret; +} + +int getsockopt(int fd, int level, int optname, void *restrict optval, socklen_t *restrict optlen) +{ + unimplemented(); + return -1; +} + +int setsockopt(int fd, int level, int optname, const void *optval, socklen_t optlen) +{ + unimplemented("fd: %d, level: %d, optname: %d, optval: %d, optlen: %d", fd, level, optname, + *(int *)optval, optlen); + return 0; +} + +// TODO +ssize_t sendmsg(int fd, const struct msghdr *msg, int flags) +{ + unimplemented(); + return 0; +} + +#endif // AX_CONFIG_NET diff --git a/tools/axlibc/c/stat.c b/tools/axlibc/c/stat.c new file mode 100644 index 0000000..27ff3d8 --- /dev/null +++ b/tools/axlibc/c/stat.c @@ -0,0 +1,38 @@ +#include +#include +#include + +// TODO: +int fchmod(int fd, mode_t mode) +{ + unimplemented(); + return 0; +} + +// TODO: +int mkdir(const char *path, mode_t mode) +{ + unimplemented(); + return 0; +} + +// TODO +int chmod(const char *path, mode_t mode) +{ + unimplemented(); + return 0; +} + +// TODO +mode_t umask(mode_t mask) +{ + unimplemented("mask: %d", mask); + return 0; +} + +// TODO +int fstatat(int fd, const char *restrict path, struct stat *restrict st, int flag) +{ + unimplemented(); + return 0; +} diff --git a/tools/axlibc/c/stdio.c b/tools/axlibc/c/stdio.c new file mode 100644 index 0000000..03ea75c --- /dev/null +++ b/tools/axlibc/c/stdio.c @@ -0,0 +1,412 @@ +#include "printf.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// LOCK used by `puts()` +#ifdef AX_CONFIG_MULTITASK +#include +static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; +#endif + +#define MAX(a, b) ((a) > (b) ? (a) : (b)) +#define MIN(a, b) ((a) < (b) ? (a) : (b)) + +FILE __stdin_FILE = {.fd = 0, .buffer_len = 0}; + +FILE __stdout_FILE = {.fd = 1, .buffer_len = 0}; + +FILE __stderr_FILE = {.fd = 2, .buffer_len = 0}; + +FILE *const stdin = &__stdin_FILE; +FILE *const stdout = &__stdout_FILE; +FILE *const stderr = &__stderr_FILE; + +// Returns: number of chars written, negative for failure +// Warn: buffer_len[f] will not be changed +static int __write_buffer(FILE *f) +{ + int r = 0; + if (f->buffer_len == 0) + return 0; + r = write(f->fd, f->buf, f->buffer_len); + return r; +} + +// Clear buffer_len[f] +static void __clear_buffer(FILE *f) +{ + f->buffer_len = 0; +} + +static int __fflush(FILE *f) +{ + int r = __write_buffer(f); + __clear_buffer(f); + return r >= 0 ? 0 : r; +} + +static int out(FILE *f, const char *s, size_t l) +{ + int ret = 0; + for (size_t i = 0; i < l; i++) { + char c = s[i]; + f->buf[f->buffer_len++] = c; + if (f->buffer_len == FILE_BUF_SIZE || c == '\n') { + int r = __write_buffer(f); + __clear_buffer(f); + if (r < 0) + return r; + if (r < f->buffer_len) + return ret + r; + ret += r; + } + } + return ret; +} + +int getchar(void) +{ + unimplemented(); + return 0; +} + +int fflush(FILE *f) +{ + return __fflush(f); +} + +static inline int do_putc(int c, FILE *f) +{ + char byte = c; + return out(f, &byte, 1); +} + +int fputc(int c, FILE *f) +{ + return do_putc(c, f); +} + +int putc(int c, FILE *f) +{ + return do_putc(c, f); +} + +int putchar(int c) +{ + return do_putc(c, stdout); +} + +int puts(const char *s) +{ +#ifdef AX_CONFIG_MULTITASK + pthread_mutex_lock(&lock); +#endif + + int r = write(1, (const void *)s, strlen(s)); + char brk[1] = {'\n'}; + write(1, (const void *)brk, 1); + +#ifdef AX_CONFIG_MULTITASK + pthread_mutex_unlock(&lock); +#endif + + return r; +} + +void perror(const char *msg) +{ + FILE *f = stderr; + char *errstr = strerror(errno); + + if (msg && *msg) { + out(f, msg, strlen(msg)); + out(f, ": ", 2); + } + out(f, errstr, strlen(errstr)); + out(f, "\n", 1); +} + +static void __out_wrapper(char c, void *arg) +{ + out(arg, &c, 1); +} + +int printf(const char *restrict fmt, ...) +{ + int ret; + va_list ap; + va_start(ap, fmt); + ret = vfprintf(stdout, fmt, ap); + va_end(ap); + return ret; +} + +int fprintf(FILE *restrict f, const char *restrict fmt, ...) +{ + int ret; + va_list ap; + va_start(ap, fmt); + ret = vfprintf(f, fmt, ap); + va_end(ap); + return ret; +} + +int vfprintf(FILE *restrict f, const char *restrict fmt, va_list ap) +{ + return vfctprintf(__out_wrapper, f, fmt, ap); +} + +// TODO +int sscanf(const char *restrict __s, const char *restrict __format, ...) +{ + unimplemented(); + return 0; +} + +#ifdef AX_CONFIG_FS + +int __fmodeflags(const char *mode) +{ + int flags; + if (strchr(mode, '+')) + flags = O_RDWR; + else if (*mode == 'r') + flags = O_RDONLY; + else + flags = O_WRONLY; + if (strchr(mode, 'x')) + flags |= O_EXCL; + if (strchr(mode, 'e')) + flags |= O_CLOEXEC; + if (*mode != 'r') + flags |= O_CREAT; + if (*mode == 'w') + flags |= O_TRUNC; + if (*mode == 'a') + flags |= O_APPEND; + return flags; +} + +FILE *fopen(const char *filename, const char *mode) +{ + FILE *f; + int flags; + + if (!strchr("rwa", *mode)) { + errno = EINVAL; + return 0; + } + + f = (FILE *)malloc(sizeof(FILE)); + + flags = __fmodeflags(mode); + // TODO: currently mode is unused in ax_open + int fd = open(filename, flags, 0666); + if (fd < 0) + return NULL; + f->fd = fd; + + return f; +} + +char *fgets(char *restrict s, int n, FILE *restrict f) +{ + if (n == 0) + return NULL; + if (n == 1) { + *s = '\0'; + return s; + } + + int cnt = 0; + while (cnt < n - 1) { + char c; + if (read(f->fd, (void *)&c, 1) > 0) { + if (c != '\n') + s[cnt++] = c; + else + break; + } else + break; + } + s[cnt] = '\0'; + return s; +} + +size_t fread(void *restrict destv, size_t size, size_t nmemb, FILE *restrict f) +{ + size_t total = size * nmemb; + size_t read_len = 0; + size_t len = 0; + do { + len = read(f->fd, destv + read_len, total - read_len); + if (len < 0) + break; + read_len += len; + } while (len > 0); + return read_len == size * nmemb ? nmemb : read_len / size; +} + +size_t fwrite(const void *restrict src, size_t size, size_t nmemb, FILE *restrict f) +{ + size_t total = size * nmemb; + size_t write_len = 0; + size_t len = 0; + do { + len = write(f->fd, src + write_len, total - write_len); + if (len < 0) + break; + write_len += len; + } while (len > 0); + return write_len == size * nmemb ? nmemb : write_len / size; +} + +int fputs(const char *restrict s, FILE *restrict f) +{ + size_t l = strlen(s); + return (fwrite(s, 1, l, f) == l) - 1; +} + +int fclose(FILE *f) +{ + return close(f->fd); +} + +int fileno(FILE *f) +{ + return f->fd; +} + +int feof(FILE *f) +{ + unimplemented(); + return 0; +} + +// TODO +int fseek(FILE *__stream, long __off, int __whence) +{ + unimplemented(); + return 0; +} + +// TODO +off_t ftello(FILE *__stream) +{ + unimplemented(); + return 0; +} + +// TODO +char *tmpnam(char *buf) +{ + unimplemented(); + return 0; +} + +// TODO +void clearerr(FILE *f) +{ + unimplemented(); +} + +// TODO +int ferror(FILE *f) +{ + unimplemented(); + return 0; +} + +// TODO +FILE *freopen(const char *restrict filename, const char *restrict mode, FILE *restrict f) +{ + unimplemented(); + return 0; +} + +// TODO +int fscanf(FILE *restrict f, const char *restrict fmt, ...) +{ + unimplemented(); + return 0; +} + +// TODO +long ftell(FILE *f) +{ + unimplemented(); + return 0; +} + +int getc(FILE *f) +{ + unimplemented(); + return 0; +} + +// TODO +int remove(const char *path) +{ + unimplemented(); + return 0; +} + +// TODO +int setvbuf(FILE *restrict f, char *restrict buf, int type, size_t size) +{ + unimplemented(); + return 0; +} + +// TODO +FILE *tmpfile(void) +{ + unimplemented(); + return NULL; +} + +int ungetc(int c, FILE *f) +{ + unimplemented(); + return 0; +} + +ssize_t getdelim(char **restrict s, size_t *restrict n, int delim, FILE *restrict f) +{ + unimplemented(); + return 0; +} + +ssize_t getline(char **restrict s, size_t *restrict n, FILE *restrict f) +{ + return getdelim(s, n, '\n', f); +} + +int __uflow(FILE *f) +{ + unimplemented(); + return 0; +} + +int getc_unlocked(FILE *f) +{ + unimplemented(); + return 0; +} + +FILE *fdopen(int fd, const char *mode) +{ + unimplemented(); + return NULL; +} + +#endif // AX_CONFIG_FS diff --git a/tools/axlibc/c/stdlib.c b/tools/axlibc/c/stdlib.c new file mode 100644 index 0000000..ef8a823 --- /dev/null +++ b/tools/axlibc/c/stdlib.c @@ -0,0 +1,385 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +char *program_invocation_short_name = "dummy"; +char *program_invocation_name = "dummy"; + +#define __DECONST(type, var) ((type)(uintptr_t)(const void *)(var)) + +void srandom(unsigned int s) +{ + srand(s); +} + +#ifdef AX_CONFIG_ALLOC + +void *calloc(size_t m, size_t n) +{ + void *mem = malloc(m * n); + + return memset(mem, 0, n * m); +} + +void *realloc(void *memblock, size_t size) +{ + if (!memblock) + return malloc(size); + + size_t o_size = *(size_t *)(memblock - 8); + + void *mem = malloc(size); + + for (int i = 0; i < (o_size < size ? o_size : size); i++) + ((char *)mem)[i] = ((char *)memblock)[i]; + + free(memblock); + return mem; +} + +#endif // AX_CONFIG_ALLOC + +long long llabs(long long a) +{ + return a > 0 ? a : -a; +} + +int abs(int a) +{ + return a > 0 ? a : -a; +} + +long long atoll(const char *s) +{ + long long n = 0; + int neg = 0; + while (isspace(*s)) s++; + switch (*s) { + case '-': + neg = 1; + case '+': + s++; + } + /* Compute n as a negative number to avoid overflow on LLONG_MIN */ + while (isdigit(*s)) n = 10 * n - (*s++ - '0'); + return neg ? n : -n; +} + +long strtol(const char *restrict nptr, char **restrict endptr, int base) +{ + const char *s; + unsigned long acc; + unsigned char c; + unsigned long qbase, cutoff; + int neg, any, cutlim; + + s = nptr; + if (base < 0 || base == 1 || base > 36) { + errno = EINVAL; + any = 0; + acc = 0; + goto exit; + } + + do { + c = *s++; + } while (isspace(c)); + if (c == '-') { + neg = 1; + c = *s++; + } else { + neg = 0; + if (c == '+') + c = *s++; + } + if ((base == 0 || base == 16) && c == '0' && (*s == 'x' || *s == 'X')) { + c = s[1]; + s += 2; + base = 16; + } + if (base == 0) + base = c == '0' ? 8 : 10; + + qbase = (unsigned int)base; + cutoff = neg ? (unsigned long)LONG_MAX - (unsigned long)(LONG_MIN + LONG_MAX) : LONG_MAX; + cutlim = cutoff % qbase; + cutoff /= qbase; + for (acc = 0, any = 0;; c = *s++) { + if (!isascii(c)) + break; + if (isdigit(c)) + c -= '0'; + else if (isalpha(c)) + c -= isupper(c) ? 'A' - 10 : 'a' - 10; + else + break; + if (c >= base) + break; + if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim)) + any = -1; + else { + any = 1; + acc *= qbase; + acc += c; + } + } + + if (any < 0) { + acc = neg ? LONG_MIN : LONG_MAX; + errno = ERANGE; + } else if (neg) + acc = -acc; + +exit: + if (endptr != 0) + *endptr = __DECONST(char *, any ? s - 1 : nptr); + return acc; +} + +unsigned long strtoul(const char *nptr, char **endptr, int base) +{ + const char *s = nptr; + unsigned long acc; + unsigned char c; + unsigned long cutoff; + int neg = 0, any, cutlim; + + if (base < 0 || base == 1 || base > 36) { + errno = EINVAL; + any = 0; + acc = 0; + goto exit; + } + + do { + c = *s++; + } while (isspace(c)); + if (c == '-') { + neg = 1; + c = *s++; + } else if (c == '+') + c = *s++; + if ((base == 0 || base == 16) && c == '0' && (*s == 'x' || *s == 'X')) { + c = s[1]; + s += 2; + base = 16; + } + if (base == 0) + base = c == '0' ? 8 : 10; + cutoff = (unsigned long)ULONG_MAX / (unsigned long)base; + cutlim = (unsigned long)ULONG_MAX % (unsigned long)base; + + for (acc = 0, any = 0;; c = *s++) { + if (!isascii(c)) + break; + if (isdigit(c)) + c -= '0'; + else if (isalpha(c)) + c -= isupper(c) ? 'A' - 10 : 'a' - 10; + else + break; + if (c >= base) + break; + if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim)) + any = -1; + else { + any = 1; + acc *= base; + acc += c; + } + } + if (any < 0) { + acc = ULONG_MAX; + errno = ERANGE; + } else if (neg) + acc = -acc; +exit: + if (endptr != 0) + *endptr = __DECONST(char *, any ? s - 1 : nptr); + return acc; +} + +long long strtoll(const char *nptr, char **endptr, int base) +{ + const char *s; + unsigned long long acc; + unsigned char c; + unsigned long long qbase, cutoff; + int neg, any, cutlim; + + s = nptr; + if (base < 0 || base == 1 || base > 36) { + errno = EINVAL; + any = 0; + acc = 0; + goto exit; + } + + do { + c = *s++; + } while (isspace(c)); + if (c == '-') { + neg = 1; + c = *s++; + } else { + neg = 0; + if (c == '+') + c = *s++; + } + if ((base == 0 || base == 16) && c == '0' && (*s == 'x' || *s == 'X')) { + c = s[1]; + s += 2; + base = 16; + } + if (base == 0) + base = c == '0' ? 8 : 10; + + qbase = (unsigned int)base; + cutoff = neg ? (unsigned long long)LLONG_MAX - (unsigned long long)(LLONG_MIN + LLONG_MAX) + : LLONG_MAX; + cutlim = cutoff % qbase; + cutoff /= qbase; + for (acc = 0, any = 0;; c = *s++) { + if (!isascii(c)) + break; + if (isdigit(c)) + c -= '0'; + else if (isalpha(c)) + c -= isupper(c) ? 'A' - 10 : 'a' - 10; + else + break; + if (c >= base) + break; + if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim)) + any = -1; + else { + any = 1; + acc *= qbase; + acc += c; + } + } + + if (any < 0) { + errno = ERANGE; + acc = neg ? LLONG_MIN : LLONG_MAX; + } else if (neg) + acc = -acc; + +exit: + if (endptr != 0) + *endptr = __DECONST(char *, any ? s - 1 : nptr); + return acc; +} + +unsigned long long strtoull(const char *nptr, char **endptr, int base) +{ + const char *s = nptr; + unsigned long long acc; + unsigned char c; + unsigned long long qbase, cutoff; + int neg, any, cutlim; + + if (base < 0 || base == 1 || base > 36) { + errno = EINVAL; + any = 0; + acc = 0; + goto exit; + } + + do { + c = *s++; + } while (isspace(c)); + if (c == '-') { + neg = 1; + c = *s++; + } else { + neg = 0; + if (c == '+') + c = *s++; + } + if ((base == 0 || base == 16) && c == '0' && (*s == 'x' || *s == 'X')) { + c = s[1]; + s += 2; + base = 16; + } + if (base == 0) + base = c == '0' ? 8 : 10; + + qbase = (unsigned int)base; + cutoff = (unsigned long long)ULLONG_MAX / qbase; + cutlim = (unsigned long long)ULLONG_MAX % qbase; + for (acc = 0, any = 0;; c = *s++) { + if (!isascii(c)) + break; + if (isdigit(c)) + c -= '0'; + else if (isalpha(c)) + c -= isupper(c) ? 'A' - 10 : 'a' - 10; + else + break; + if (c >= base) + break; + if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim)) + any = -1; + else { + any = 1; + acc *= qbase; + acc += c; + } + } + if (any < 0) { + errno = ERANGE; + acc = ULLONG_MAX; + } else if (neg) + acc = -acc; + +exit: + if (endptr != 0) + *endptr = __DECONST(char *, any ? s - 1 : nptr); + return acc; +} + +#ifdef AX_CONFIG_FP_SIMD + +// TODO: precision may not be enough +long double strtold(const char *restrict s, char **restrict p) +{ + return (long double)strtod(s, p); +} + +#endif // AX_CONFIG_FP_SIMD + +typedef int (*cmpfun)(const void *, const void *); + +// TODO +void qsort(void *base, size_t nel, size_t width, cmpfun cmp) +{ + unimplemented(); + return; +} + +// TODO +int mkstemp(char *__template) +{ + unimplemented(); + return 0; +} + +// TODO +int mkostemp(char *__template, int __flags) +{ + unimplemented(); + return 0; +} + +// TODO +int system(const char *cmd) +{ + unimplemented(); + return 0; +} diff --git a/tools/axlibc/c/string.c b/tools/axlibc/c/string.c new file mode 100644 index 0000000..2c56d7e --- /dev/null +++ b/tools/axlibc/c/string.c @@ -0,0 +1,478 @@ +#include +#include +#include +#include +#include +#include + +size_t strlen(const char *s) +{ + const char *a = s; + for (; *s; s++) + ; + return s - a; +} + +size_t strnlen(const char *s, size_t n) +{ + const char *p = memchr(s, 0, n); + return p ? p - s : n; +} + +int atoi(const char *s) +{ + int n = 0, neg = 0; + while (isspace(*s)) s++; + switch (*s) { + case '-': + neg = 1; + case '+': + s++; + } + /* Compute n as a negative number to avoid overflow on INT_MIN */ + while (isdigit(*s)) n = 10 * n - (*s++ - '0'); + return neg ? n : -n; +} + +void *memchr(const void *src, int c, size_t n) +{ + const unsigned char *s = src; + c = (unsigned char)c; + for (; n && *s != c; s++, n--) + ; + return n ? (void *)s : 0; +} + +void *memset(void *dest, int c, size_t n) +{ + unsigned char *s = dest; + size_t k; + + /* Fill head and tail with minimal branching. Each + * conditional ensures that all the subsequently used + * offsets are well-defined and in the dest region. */ + + if (!n) + return dest; + s[0] = c; + s[n - 1] = c; + if (n <= 2) + return dest; + s[1] = c; + s[2] = c; + s[n - 2] = c; + s[n - 3] = c; + if (n <= 6) + return dest; + s[3] = c; + s[n - 4] = c; + if (n <= 8) + return dest; + + /* Advance pointer to align it at a 4-byte boundary, + * and truncate n to a multiple of 4. The previous code + * already took care of any head/tail that get cut off + * by the alignment. */ + + k = -(uintptr_t)s & 3; + s += k; + n -= k; + n &= -4; + + /* Pure C fallback with no aliasing violations. */ + for (; n; n--, s++) *s = c; + + return dest; +} + +char *strcpy(char *restrict d, const char *restrict s) +{ + for (; (*d = *s); s++, d++) + ; + return d; +} + +char *strncpy(char *restrict d, const char *restrict s, size_t n) +{ + for (; n && (*d = *s); n--, s++, d++) + ; + return d; +} + +char *strcat(char *restrict d, const char *restrict s) +{ + strcpy(d + strlen(d), s); + return d; +} + +char *strncat(char *restrict d, const char *restrict s, size_t n) +{ + char *a = d; + d += strlen(d); + while (n && *s) n--, *d++ = *s++; + *d++ = 0; + return a; +} + +int strcmp(const char *l, const char *r) +{ + for (; *l == *r && *l; l++, r++) + ; + return *(unsigned char *)l - *(unsigned char *)r; +} + +int strncmp(const char *_l, const char *_r, size_t n) +{ + const unsigned char *l = (void *)_l, *r = (void *)_r; + if (!n--) + return 0; + for (; *l && *r && n && *l == *r; l++, r++, n--) + ; + return *l - *r; +} + +int strcoll(const char *l, const char *r) +{ + return strcmp(l, r); +} + +#define BITOP(a, b, op) \ + ((a)[(size_t)(b) / (8 * sizeof *(a))] op(size_t) 1 << ((size_t)(b) % (8 * sizeof *(a)))) +#define MAX(a, b) ((a) > (b) ? (a) : (b)) +#define MIN(a, b) ((a) < (b) ? (a) : (b)) + +size_t strcspn(const char *s1, const char *s2) +{ + const char *a = s1; + size_t byteset[32 / sizeof(size_t)]; + + if (!s2[0] || !s2[1]) { + for (; *s1 != *s2; s1++) return s1 - a; + } + memset(byteset, 0, sizeof byteset); + + for (; *s2 != '\0'; s2++) BITOP(byteset, *(unsigned char *)s2, |=); + for (; *s1 && !(BITOP(byteset, *(unsigned char *)s1, &)); s1++) + ; + + return s1 - a; +} + +size_t strspn(const char *s, const char *c) +{ + const char *a = s; + size_t byteset[32 / sizeof(size_t)] = {0}; + + if (!c[0]) + return 0; + if (!c[1]) { + for (; *s == *c; s++) + ; + return s - a; + } + + for (; *c && BITOP(byteset, *(unsigned char *)c, |=); c++) + ; + for (; *s && BITOP(byteset, *(unsigned char *)s, &); s++) + ; + return s - a; +} + +char *strpbrk(const char *s, const char *b) +{ + s += strcspn(s, b); + return *s ? (char *)s : 0; +} + +char *strchrnul(const char *s, int c) +{ + c = (unsigned char)c; + if (!c) + return (char *)s + strlen(s); + + for (; *s && *(unsigned char *)s != c; s++) + ; + return (char *)s; +} + +char *strchr(const char *s, int c) +{ + while (*s != c && *s != '\0') s++; + + if (*s == c) { + return (char *)s; + } else { + return NULL; + } +} + +char *strrchr(const char *s, int c) +{ + char *isCharFind = NULL; + if (s != NULL) { + do { + if (*s == (char)c) { + isCharFind = (char *)s; + } + } while (*s++); + } + return isCharFind; +} + +int strerror_r(int err, char *buf, size_t buflen) +{ + char *msg = strerror(err); + size_t l = strlen(msg); + if (l >= buflen) { + if (buflen) { + memcpy(buf, msg, buflen - 1); + buf[buflen - 1] = 0; + } + return ERANGE; + } + memcpy(buf, msg, l + 1); + return 0; +} + +void *memcpy(void *restrict dest, const void *restrict src, size_t n) +{ + unsigned char *d = dest; + const unsigned char *s = src; + for (; n; n--) *d++ = *s++; + return dest; +} + +void *memmove(void *dest, const void *src, size_t n) +{ + char *d = dest; + const char *s = src; + + if (d == s) + return d; + if ((uintptr_t)s - (uintptr_t)d - n <= -2 * n) + return memcpy(d, s, n); + + if (d < s) { + for (; n; n--) *d++ = *s++; + } else { + while (n) n--, d[n] = s[n]; + } + + return dest; +} + +int memcmp(const void *vl, const void *vr, size_t n) +{ + const unsigned char *l = vl, *r = vr; + for (; n && *l == *r; n--, l++, r++) + ; + return n ? *l - *r : 0; +} + +int strcasecmp(const char *_l, const char *_r) +{ + const unsigned char *l = (void *)_l, *r = (void *)_r; + for (; *l && *r && (*l == *r || tolower(*l) == tolower(*r)); l++, r++) + ; + return tolower(*l) - tolower(*r); +} + +int strncasecmp(const char *_l, const char *_r, size_t n) +{ + const unsigned char *l = (void *)_l, *r = (void *)_r; + if (!n--) + return 0; + for (; *l && *r && n && (*l == *r || tolower(*l) == tolower(*r)); l++, r++, n--) + ; + return tolower(*l) - tolower(*r); +} + +// `strstr` helper function +static char *twobyte_strstr(const unsigned char *h, const unsigned char *n) +{ + uint16_t nw = n[0] << 8 | n[1], hw = h[0] << 8 | h[1]; + for (h++; *h && hw != nw; hw = hw << 8 | *++h) + ; + return *h ? (char *)h - 1 : 0; +} + +// `strstr` helper function +static char *threebyte_strstr(const unsigned char *h, const unsigned char *n) +{ + uint32_t nw = (uint32_t)n[0] << 24 | n[1] << 16 | n[2] << 8; + uint32_t hw = (uint32_t)h[0] << 24 | h[1] << 16 | h[2] << 8; + for (h += 2; *h && hw != nw; hw = (hw | *++h) << 8) + ; + return *h ? (char *)h - 2 : 0; +} + +// `strstr` helper function +static char *fourbyte_strstr(const unsigned char *h, const unsigned char *n) +{ + uint32_t nw = (uint32_t)n[0] << 24 | n[1] << 16 | n[2] << 8 | n[3]; + uint32_t hw = (uint32_t)h[0] << 24 | h[1] << 16 | h[2] << 8 | h[3]; + for (h += 3; *h && hw != nw; hw = hw << 8 | *++h) + ; + return *h ? (char *)h - 3 : 0; +} + +// `strstr` helper function +static char *twoway_strstr(const unsigned char *h, const unsigned char *n) +{ + const unsigned char *z; + size_t l, ip, jp, k, p, ms, p0, mem, mem0; + size_t byteset[32 / sizeof(size_t)] = {0}; + size_t shift[256]; + + /* Computing length of needle and fill shift table */ + for (l = 0; n[l] && h[l]; l++) BITOP(byteset, n[l], |=), shift[n[l]] = l + 1; + if (n[l]) + return 0; /* hit the end of h */ + + /* Compute maximal suffix */ + ip = -1; + jp = 0; + k = p = 1; + while (jp + k < l) { + if (n[ip + k] == n[jp + k]) { + if (k == p) { + jp += p; + k = 1; + } else + k++; + } else if (n[ip + k] > n[jp + k]) { + jp += k; + k = 1; + p = jp - ip; + } else { + ip = jp++; + k = p = 1; + } + } + ms = ip; + p0 = p; + + /* And with the opposite comparison */ + ip = -1; + jp = 0; + k = p = 1; + while (jp + k < l) { + if (n[ip + k] == n[jp + k]) { + if (k == p) { + jp += p; + k = 1; + } else + k++; + } else if (n[ip + k] < n[jp + k]) { + jp += k; + k = 1; + p = jp - ip; + } else { + ip = jp++; + k = p = 1; + } + } + if (ip + 1 > ms + 1) + ms = ip; + else + p = p0; + + /* Periodic needle? */ + if (memcmp(n, n + p, ms + 1)) { + mem0 = 0; + p = MAX(ms, l - ms - 1) + 1; + } else + mem0 = l - p; + mem = 0; + + /* Initialize incremental end-of-haystack pointer */ + z = h; + + /* Search loop */ + for (;;) { + /* Update incremental end-of-haystack pointer */ + if (z - h < l) { + /* Fast estimate for MAX(l,63) */ + size_t grow = l | 63; + const unsigned char *z2 = memchr(z, 0, grow); + if (z2) { + z = z2; + if (z - h < l) + return 0; + } else + z += grow; + } + + /* Check last byte first; advance by shift on mismatch */ + if (BITOP(byteset, h[l - 1], &)) { + k = l - shift[h[l - 1]]; + if (k) { + if (k < mem) + k = mem; + h += k; + mem = 0; + continue; + } + } else { + h += l; + mem = 0; + continue; + } + + /* Compare right half */ + for (k = MAX(ms + 1, mem); n[k] && n[k] == h[k]; k++) + ; + if (n[k]) { + h += k - ms; + mem = 0; + continue; + } + /* Compare left half */ + for (k = ms + 1; k > mem && n[k - 1] == h[k - 1]; k--) + ; + if (k <= mem) + return (char *)h; + h += p; + mem = mem0; + } +} + +char *strstr(const char *h, const char *n) +{ + /* Return immediately on empty needle */ + if (!n[0]) + return (char *)h; + + /* Use faster algorithms for short needles */ + h = strchr(h, *n); + if (!h || !n[1]) + return (char *)h; + if (!h[1]) + return 0; + if (!n[2]) + return twobyte_strstr((void *)h, (void *)n); + if (!h[2]) + return 0; + if (!n[3]) + return threebyte_strstr((void *)h, (void *)n); + if (!h[3]) + return 0; + if (!n[4]) + return fourbyte_strstr((void *)h, (void *)n); + + return twoway_strstr((void *)h, (void *)n); +} + +#ifdef AX_CONFIG_ALLOC + +#include +char *strdup(const char *s) +{ + size_t l = strlen(s); + char *d = malloc(l + 1); + if (!d) + return NULL; + return memcpy(d, s, l + 1); +} + +#endif // AX_CONFIG_ALLOC diff --git a/tools/axlibc/c/syslog.c b/tools/axlibc/c/syslog.c new file mode 100644 index 0000000..eb0ea8a --- /dev/null +++ b/tools/axlibc/c/syslog.c @@ -0,0 +1,16 @@ +#include +#include + +// TODO +void syslog(int __pri, const char *__fmt, ...) +{ + unimplemented(); + return; +} + +// TODO +void openlog(const char *__ident, int __option, int __facility) +{ + unimplemented(); + return; +} diff --git a/tools/axlibc/c/time.c b/tools/axlibc/c/time.c new file mode 100644 index 0000000..9a2384a --- /dev/null +++ b/tools/axlibc/c/time.c @@ -0,0 +1,203 @@ +#include +#include +#include +#include +#include +#include + +long timezone = 0; +const char __utc[] = "UTC"; + +const int SEC_PER_MIN = 60; +const int SEC_PER_HOUR = 3600; +const int MIN_PER_HOUR = 60; +const int HOUR_PER_DAY = 24; + +/* 2000-03-01 (mod 400 year, immediately after feb29 */ +#define LEAPOCH (946684800LL + 86400 * (31 + 29)) +#define DAYS_PER_400Y (365 * 400 + 97) +#define DAYS_PER_100Y (365 * 100 + 24) +#define DAYS_PER_4Y (365 * 4 + 1) + +int __secs_to_tm(long long t, struct tm *tm) +{ + long long days, secs, years; + int remdays, remsecs, remyears; + int qc_cycles, c_cycles, q_cycles; + int months; + int wday, yday, leap; + static const char days_in_month[] = {31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 31, 29}; + + /* Reject time_t values whose year would overflow int */ + if (t < INT_MIN * 31622400LL || t > INT_MAX * 31622400LL) + return -1; + + secs = t - LEAPOCH; + days = secs / 86400; + remsecs = secs % 86400; + if (remsecs < 0) { + remsecs += 86400; + days--; + } + + wday = (3 + days) % 7; + if (wday < 0) + wday += 7; + + qc_cycles = days / DAYS_PER_400Y; + remdays = days % DAYS_PER_400Y; + if (remdays < 0) { + remdays += DAYS_PER_400Y; + qc_cycles--; + } + + c_cycles = remdays / DAYS_PER_100Y; + if (c_cycles == 4) + c_cycles--; + remdays -= c_cycles * DAYS_PER_100Y; + + q_cycles = remdays / DAYS_PER_4Y; + if (q_cycles == 25) + q_cycles--; + remdays -= q_cycles * DAYS_PER_4Y; + + remyears = remdays / 365; + if (remyears == 4) + remyears--; + remdays -= remyears * 365; + + leap = !remyears && (q_cycles || !c_cycles); + yday = remdays + 31 + 28 + leap; + if (yday >= 365 + leap) + yday -= 365 + leap; + + years = remyears + 4 * q_cycles + 100 * c_cycles + 400LL * qc_cycles; + + for (months = 0; days_in_month[months] <= remdays; months++) remdays -= days_in_month[months]; + + if (months >= 10) { + months -= 12; + years++; + } + + if (years + 100 > INT_MAX || years + 100 < INT_MIN) + return -1; + + tm->tm_year = years + 100; + tm->tm_mon = months + 2; + tm->tm_mday = remdays + 1; + tm->tm_wday = wday; + tm->tm_yday = yday; + + tm->tm_hour = remsecs / 3600; + tm->tm_min = remsecs / 60 % 60; + tm->tm_sec = remsecs % 60; + + return 0; +} + +struct tm *gmtime_r(const time_t *restrict t, struct tm *restrict tm) +{ + if (__secs_to_tm(*t, tm) < 0) { + errno = EOVERFLOW; + return 0; + } + tm->tm_isdst = 0; + tm->__tm_gmtoff = 0; + tm->__tm_zone = __utc; + return tm; +} + +struct tm *gmtime(const time_t *timer) +{ + static struct tm tm; + return gmtime_r(timer, &tm); +} + +struct tm *localtime_r(const time_t *restrict t, struct tm *restrict tm) +{ + if (*t < INT_MIN * 31622400LL || *t > INT_MAX * 31622400LL) { + errno = EOVERFLOW; + return 0; + } + + if (__secs_to_tm(*t, tm) < 0) { + errno = EOVERFLOW; + return 0; + } + + tm->tm_isdst = 0; + tm->__tm_gmtoff = 0; + tm->__tm_zone = __utc; + + return tm; +} + +struct tm *localtime(const time_t *timep) +{ + static struct tm tm; + return localtime_r(timep, &tm); +} + +time_t time(time_t *t) +{ + struct timespec ts; + clock_gettime(CLOCK_REALTIME, &ts); + time_t ret = ts.tv_sec; + if (t) + *t = ret; + return ret; +} + +int gettimeofday(struct timeval *tv, struct timezone *tz) +{ + struct timespec ts; + if (!tv) + return 0; + clock_gettime(CLOCK_REALTIME, &ts); + tv->tv_sec = ts.tv_sec; + tv->tv_usec = (int)ts.tv_nsec / 1000; + return 0; +} + +// TODO: +int utimes(const char *filename, const struct timeval times[2]) +{ + unimplemented(); + return 0; +} + +// TODO +void tzset() +{ + unimplemented(); + return; +} + +// TODO +int setitimer(int _which, const struct itimerval *restrict _new, struct itimerval *restrict _old) +{ + unimplemented(); + return 0; +} + +// TODO +char *ctime_r(const time_t *t, char *buf) +{ + unimplemented(); + return NULL; +} + +// TODO +clock_t clock(void) +{ + unimplemented(); + return 0; +} + +#ifdef AX_CONFIG_FP_SIMD +double difftime(time_t t1, time_t t0) +{ + return t1 - t0; +} +#endif diff --git a/tools/axlibc/c/unistd.c b/tools/axlibc/c/unistd.c new file mode 100644 index 0000000..eec49bf --- /dev/null +++ b/tools/axlibc/c/unistd.c @@ -0,0 +1,174 @@ +#include +#include +#include +#include +#include +#include +#include + +// TODO: +uid_t geteuid(void) +{ + unimplemented(); + return 0; +} + +// TODO +uid_t getuid(void) +{ + unimplemented(); + return 0; +} + +// TODO +pid_t setsid(void) +{ + unimplemented(); + return 0; +} + +// TODO +int isatty(int fd) +{ + unimplemented(); + return 0; +} + +unsigned int sleep(unsigned int seconds) +{ + struct timespec ts; + + ts.tv_sec = seconds; + ts.tv_nsec = 0; + if (nanosleep(&ts, &ts)) + return ts.tv_sec; + + return 0; +} + +int usleep(unsigned useconds) +{ + struct timespec tv = {.tv_sec = useconds / 1000000, .tv_nsec = (useconds % 1000000) * 1000}; + return nanosleep(&tv, &tv); +} + +#ifdef AX_CONFIG_FS + +// TODO: +int access(const char *pathname, int mode) +{ + unimplemented(); + return 0; +} + +// TODO: +ssize_t readlink(const char *path, char *buf, size_t bufsiz) +{ + unimplemented(); + return 0; +} + +// TODO: +int unlink(const char *pathname) +{ + unimplemented(); + return 0; +} + +// TODO: +int rmdir(const char *pathname) +{ + unimplemented(); + return 0; +} + +// TODO: +int fsync(int fd) +{ + unimplemented(); + return 0; +} + +// TODO +int fdatasync(int __fildes) +{ + unimplemented(); + return 0; +} + +// TODO: +int fchown(int fd, uid_t owner, gid_t group) +{ + unimplemented("owner: %x group: %x", owner, group); + return 0; +} + +// TODO: +int ftruncate(int fd, off_t length) +{ + unimplemented(); + return 0; +} + +// TODO +int chdir(const char *__path) +{ + unimplemented(); + return 0; +} + +// TODO +int truncate(const char *path, off_t length) +{ + unimplemented(); + return 0; +} + +#endif // AX_CONFIG_FS + +#ifdef AX_CONFIG_PIPE + +int pipe2(int fd[2], int flag) +{ + if (!flag) + return pipe(fd); + if (flag & ~(O_CLOEXEC | O_NONBLOCK)) + return -EINVAL; + + int res = pipe(fd); + if (res != 0) + return res; + + if (flag & O_CLOEXEC) { + fcntl(fd[0], F_SETFD, FD_CLOEXEC); + fcntl(fd[1], F_SETFD, FD_CLOEXEC); + } + if (flag & O_NONBLOCK) { + fcntl(fd[0], F_SETFL, O_NONBLOCK); + fcntl(fd[1], F_SETFL, O_NONBLOCK); + } + + return 0; +} + +#endif // AX_CONFIG_PIPE + +// TODO +_Noreturn void _exit(int status) +{ + exit(status); +} + +// TODO +int execve(const char *__path, char *const *__argv, char *const *__envp) +{ + unimplemented(); + return 0; +} + +// TODO +pid_t fork(void) +{ + unimplemented(); + return -1; +} diff --git a/tools/axlibc/c/utsname.c b/tools/axlibc/c/utsname.c new file mode 100644 index 0000000..14c35c8 --- /dev/null +++ b/tools/axlibc/c/utsname.c @@ -0,0 +1,9 @@ +#include +#include + +// TODO +int uname(struct utsname *a) +{ + unimplemented(); + return 0; +} diff --git a/tools/axlibc/c/wait.c b/tools/axlibc/c/wait.c new file mode 100644 index 0000000..a63fa27 --- /dev/null +++ b/tools/axlibc/c/wait.c @@ -0,0 +1,17 @@ +#include +#include +#include + +// TODO +pid_t waitpid(pid_t pid, int *status, int options) +{ + unimplemented(); + return 0; +} + +// TODO +pid_t wait3(int *status, int _options, struct rusage *usage) +{ + unimplemented(); + return 0; +} diff --git a/tools/axlibc/ctypes.h b/tools/axlibc/ctypes.h new file mode 100644 index 0000000..882ec69 --- /dev/null +++ b/tools/axlibc/ctypes.h @@ -0,0 +1,2 @@ +#include +#include diff --git a/tools/axlibc/include/arpa/inet.h b/tools/axlibc/include/arpa/inet.h new file mode 100644 index 0000000..88889f6 --- /dev/null +++ b/tools/axlibc/include/arpa/inet.h @@ -0,0 +1,14 @@ +#ifndef _ARPA_INET_H +#define _ARPA_INET_H + +#include + +uint32_t htonl(uint32_t); +uint16_t htons(uint16_t); +uint32_t ntohl(uint32_t); +uint16_t ntohs(uint16_t); + +int inet_pton(int, const char *__restrict, void *__restrict); +const char *inet_ntop(int, const void *__restrict, char *__restrict, socklen_t); + +#endif diff --git a/tools/axlibc/include/assert.h b/tools/axlibc/include/assert.h new file mode 100644 index 0000000..0385fa3 --- /dev/null +++ b/tools/axlibc/include/assert.h @@ -0,0 +1,14 @@ +#ifndef __ASSERT_H__ +#define __ASSERT_H__ + +#include + +#if __STDC_VERSION__ >= 201112L && !defined(__cplusplus) +#define static_assert _Static_assert +#endif + +#define assert(x) ((void)((x) || (__assert_fail(#x, __FILE__, __LINE__, __func__), 0))) + +_Noreturn void __assert_fail(const char *, const char *, int, const char *); + +#endif // __ASSERT_H__ diff --git a/tools/axlibc/include/ctype.h b/tools/axlibc/include/ctype.h new file mode 100644 index 0000000..a3ba95b --- /dev/null +++ b/tools/axlibc/include/ctype.h @@ -0,0 +1,20 @@ +#ifndef _CTYPE_H +#define _CTYPE_H + +int tolower(int __c); +int toupper(int __c); + +#define isalpha(a) ((((unsigned)(a) | 32) - 'a') < 26) +#define isdigit(a) (((unsigned)(a) - '0') < 10) +#define islower(a) (((unsigned)(a) - 'a') < 26) +#define isupper(a) (((unsigned)(a) - 'A') < 26) +#define isprint(a) (((unsigned)(a)-0x20) < 0x5f) +#define isgraph(a) (((unsigned)(a)-0x21) < 0x5e) +#define isalnum(a) ((isalpha(a) || isdigit(a))) +#define iscntrl(a) (((unsigned)a < 0x20 || a == 0x7f)) +#define ispunct(a) ((isgraph(a) && !isalnum(a))) +#define isxdigit(a) ((isdigit(a) || ((unsigned)a | 32) - 'a' < 6)) +#define isascii(a) ((!(a & ~0x7f))) +#define isspace(a) ((a == ' ' || (unsigned)a - '\t' < 5)) + +#endif diff --git a/tools/axlibc/include/dirent.h b/tools/axlibc/include/dirent.h new file mode 100644 index 0000000..4189751 --- /dev/null +++ b/tools/axlibc/include/dirent.h @@ -0,0 +1,45 @@ +#ifndef _DIRENT_H +#define _DIRENT_H + +#include + +struct __dirstream { + long long tell; + int fd; + int buf_pos; + int buf_end; + int lock[1]; + char buf[2048]; +}; + +typedef struct __dirstream DIR; + +struct dirent { + ino_t d_ino; + off_t d_off; + unsigned short d_reclen; + unsigned char d_type; + char d_name[256]; +}; + +int closedir(DIR *); +DIR *fdopendir(int); +DIR *opendir(const char *); +struct dirent *readdir(DIR *); +int readdir_r(DIR *__restrict, struct dirent *__restrict, struct dirent **__restrict); +void rewinddir(DIR *); +int dirfd(DIR *); + +#define DT_UNKNOWN 0 +#define DT_FIFO 1 +#define DT_CHR 2 +#define DT_DIR 4 +#define DT_BLK 6 +#define DT_REG 8 +#define DT_LNK 10 +#define DT_SOCK 12 +#define DT_WHT 14 +#define IFTODT(x) ((x) >> 12 & 017) +#define DTTOIF(x) ((x) << 12) + +#endif //_DIRENT_H diff --git a/tools/axlibc/include/dlfcn.h b/tools/axlibc/include/dlfcn.h new file mode 100644 index 0000000..a1caea9 --- /dev/null +++ b/tools/axlibc/include/dlfcn.h @@ -0,0 +1,41 @@ +#ifndef _DLFCN_H +#define _DLFCN_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#define RTLD_LAZY 1 +#define RTLD_NOW 2 +#define RTLD_NOLOAD 4 +#define RTLD_NODELETE 4096 +#define RTLD_GLOBAL 256 +#define RTLD_LOCAL 0 +#define RTLD_NEXT ((void *)-1) +#define RTLD_DEFAULT ((void *)0) +#define RTLD_DI_LINKMAP 2 + +typedef struct { + const char *dli_fname; + void *dli_fbase; + const char *dli_sname; + void *dli_saddr; +} Dl_info; + +int dladdr(const void *, Dl_info *); +int dlclose(void *); +char *dlerror(void); +void *dlopen(const char *, int); +void *dlsym(void *__restrict, const char *__restrict); + +#if _REDIR_TIME64 +__REDIR(dlsym, __dlsym_time64); +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/tools/axlibc/include/endian.h b/tools/axlibc/include/endian.h new file mode 100644 index 0000000..819a726 --- /dev/null +++ b/tools/axlibc/include/endian.h @@ -0,0 +1,68 @@ +#ifndef _ENDIAN_H +#define _ENDIAN_H + +#include + +#if defined(__aarch64__) +#if __AARCH64EB__ +#define __BYTE_ORDER 4321 +#else +#define __BYTE_ORDER 1234 +#endif +#else +#define __BYTE_ORDER 1234 +#endif + +#define __LITTLE_ENDIAN 1234 +#define __BIG_ENDIAN 4321 +#define __PDP_ENDIAN 3412 + +#define BIG_ENDIAN __BIG_ENDIAN +#define LITTLE_ENDIAN __LITTLE_ENDIAN +#define PDP_ENDIAN __PDP_ENDIAN +#define BYTE_ORDER __BYTE_ORDER + +static __inline uint16_t __bswap16(uint16_t __x) +{ + return __x << 8 | __x >> 8; +} + +static __inline uint32_t __bswap32(uint32_t __x) +{ + return __x >> 24 | (__x >> 8 & 0xff00) | (__x << 8 & 0xff0000) | __x << 24; +} + +static __inline uint64_t __bswap64(uint64_t __x) +{ + return (__bswap32(__x) + 0ULL) << 32 | __bswap32(__x >> 32); +} + +#if __BYTE_ORDER == __LITTLE_ENDIAN +#define htobe16(x) __bswap16(x) +#define be16toh(x) __bswap16(x) +#define htobe32(x) __bswap32(x) +#define be32toh(x) __bswap32(x) +#define htobe64(x) __bswap64(x) +#define be64toh(x) __bswap64(x) +#define htole16(x) (uint16_t)(x) +#define le16toh(x) (uint16_t)(x) +#define htole32(x) (uint32_t)(x) +#define le32toh(x) (uint32_t)(x) +#define htole64(x) (uint64_t)(x) +#define le64toh(x) (uint64_t)(x) +#else +#define htobe16(x) (uint16_t)(x) +#define be16toh(x) (uint16_t)(x) +#define htobe32(x) (uint32_t)(x) +#define be32toh(x) (uint32_t)(x) +#define htobe64(x) (uint64_t)(x) +#define be64toh(x) (uint64_t)(x) +#define htole16(x) __bswap16(x) +#define le16toh(x) __bswap16(x) +#define htole32(x) __bswap32(x) +#define le32toh(x) __bswap32(x) +#define htole64(x) __bswap64(x) +#define le64toh(x) __bswap64(x) +#endif + +#endif diff --git a/tools/axlibc/include/errno.h b/tools/axlibc/include/errno.h new file mode 100644 index 0000000..16ed78e --- /dev/null +++ b/tools/axlibc/include/errno.h @@ -0,0 +1,150 @@ +#ifndef __ERRNO_H__ +#define __ERRNO_H__ + +#define EPERM 1 /* Operation not permitted */ +#define ENOENT 2 /* No such file or directory */ +#define ESRCH 3 /* No such process */ +#define EINTR 4 /* Interrupted system call */ +#define EIO 5 /* I/O error */ +#define ENXIO 6 /* No such device or address */ +#define E2BIG 7 /* Argument list too long */ +#define ENOEXEC 8 /* Exec format error */ +#define EBADF 9 /* Bad file number */ +#define ECHILD 10 /* No child processes */ +#define EAGAIN 11 /* Try again */ +#define ENOMEM 12 /* Out of memory */ +#define EACCES 13 /* Permission denied */ +#define EFAULT 14 /* Bad address */ +#define ENOTBLK 15 /* Block device required */ +#define EBUSY 16 /* Device or resource busy */ +#define EEXIST 17 /* File exists */ +#define EXDEV 18 /* Cross-device link */ +#define ENODEV 19 /* No such device */ +#define ENOTDIR 20 /* Not a directory */ +#define EISDIR 21 /* Is a directory */ +#define EINVAL 22 /* Invalid argument */ +#define ENFILE 23 /* File table overflow */ +#define EMFILE 24 /* Too many open files */ +#define ENOTTY 25 /* Not a typewriter */ +#define ETXTBSY 26 /* Text file busy */ +#define EFBIG 27 /* File too large */ +#define ENOSPC 28 /* No space left on device */ +#define ESPIPE 29 /* Illegal seek */ +#define EROFS 30 /* Read-only file system */ +#define EMLINK 31 /* Too many links */ +#define EPIPE 32 /* Broken pipe */ +#define EDOM 33 /* Math argument out of domain of func */ +#define ERANGE 34 /* Math result not representable */ +#define EDEADLK 35 /* Resource deadlock would occur */ +#define ENAMETOOLONG 36 /* File name too long */ +#define ENOLCK 37 /* No record locks available */ +#define ENOSYS 38 /* Invalid system call number */ +#define ENOTEMPTY 39 /* Directory not empty */ +#define ELOOP 40 /* Too many symbolic links encountered */ +#define EWOULDBLOCK EAGAIN /* Operation would block */ +#define ENOMSG 42 /* No message of desired type */ +#define EIDRM 43 /* Identifier removed */ +#define ECHRNG 44 /* Channel number out of range */ +#define EL2NSYNC 45 /* Level 2 not synchronized */ +#define EL3HLT 46 /* Level 3 halted */ +#define EL3RST 47 /* Level 3 reset */ +#define ELNRNG 48 /* Link number out of range */ +#define EUNATCH 49 /* Protocol driver not attached */ +#define ENOCSI 50 /* No CSI structure available */ +#define EL2HLT 51 /* Level 2 halted */ +#define EBADE 52 /* Invalid exchange */ +#define EBADR 53 /* Invalid request descriptor */ +#define EXFULL 54 /* Exchange full */ +#define ENOANO 55 /* No anode */ +#define EBADRQC 56 /* Invalid request code */ +#define EBADSLT 57 /* Invalid slot */ +#define EDEADLOCK EDEADLK +#define EBFONT 59 /* Bad font file format */ +#define ENOSTR 60 /* Device not a stream */ +#define ENODATA 61 /* No data available */ +#define ETIME 62 /* Timer expired */ +#define ENOSR 63 /* Out of streams resources */ +#define ENONET 64 /* Machine is not on the network */ +#define ENOPKG 65 /* Package not installed */ +#define EREMOTE 66 /* Object is remote */ +#define ENOLINK 67 /* Link has been severed */ +#define EADV 68 /* Advertise error */ +#define ESRMNT 69 /* Srmount error */ +#define ECOMM 70 /* Communication error on send */ +#define EPROTO 71 /* Protocol error */ +#define EMULTIHOP 72 /* Multihop attempted */ +#define EDOTDOT 73 /* RFS specific error */ +#define EBADMSG 74 /* Not a data message */ +#define EOVERFLOW 75 /* Value too large for defined data type */ +#define ENOTUNIQ 76 /* Name not unique on network */ +#define EBADFD 77 /* File descriptor in bad state */ +#define EREMCHG 78 /* Remote address changed */ +#define ELIBACC 79 /* Can not access a needed shared library */ +#define ELIBBAD 80 /* Accessing a corrupted shared library */ +#define ELIBSCN 81 /* .lib section in a.out corrupted */ +#define ELIBMAX 82 /* Attempting to link in too many shared libraries */ +#define ELIBEXEC 83 /* Cannot exec a shared library directly */ +#define EILSEQ 84 /* Illegal byte sequence */ +#define ERESTART 85 /* Interrupted system call should be restarted */ +#define ESTRPIPE 86 /* Streams pipe error */ +#define EUSERS 87 /* Too many users */ +#define ENOTSOCK 88 /* Socket operation on non-socket */ +#define EDESTADDRREQ 89 /* Destination address required */ +#define EMSGSIZE 90 /* Message too long */ +#define EPROTOTYPE 91 /* Protocol wrong type for socket */ +#define ENOPROTOOPT 92 /* Protocol not available */ +#define EPROTONOSUPPORT 93 /* Protocol not supported */ +#define ESOCKTNOSUPPORT 94 /* Socket type not supported */ +#define EOPNOTSUPP 95 /* Operation not supported on transport endpoint */ +#define EPFNOSUPPORT 96 /* Protocol family not supported */ +#define EAFNOSUPPORT 97 /* Address family not supported by protocol */ +#define EADDRINUSE 98 /* Address already in use */ +#define EADDRNOTAVAIL 99 /* Cannot assign requested address */ +#define ENETDOWN 100 /* Network is down */ +#define ENETUNREACH 101 /* Network is unreachable */ +#define ENETRESET 102 /* Network dropped connection because of reset */ +#define ECONNABORTED 103 /* Software caused connection abort */ +#define ECONNRESET 104 /* Connection reset by peer */ +#define ENOBUFS 105 /* No buffer space available */ +#define EISCONN 106 /* Transport endpoint is already connected */ +#define ENOTCONN 107 /* Transport endpoint is not connected */ +#define ESHUTDOWN 108 /* Cannot send after transport endpoint shutdown */ +#define ETOOMANYREFS 109 /* Too many references: cannot splice */ +#define ETIMEDOUT 110 /* Connection timed out */ +#define ECONNREFUSED 111 /* Connection refused */ +#define EHOSTDOWN 112 /* Host is down */ +#define EHOSTUNREACH 113 /* No route to host */ +#define EALREADY 114 /* Operation already in progress */ +#define EINPROGRESS 115 /* Operation now in progress */ +#define ESTALE 116 /* Stale file handle */ +#define EUCLEAN 117 /* Structure needs cleaning */ +#define ENOTNAM 118 /* Not a XENIX named type file */ +#define ENAVAIL 119 /* No XENIX semaphores available */ +#define EISNAM 120 /* Is a named type file */ +#define EREMOTEIO 121 /* Remote I/O error */ +#define EDQUOT 122 /* Quota exceeded */ + +#define ENOMEDIUM 123 /* No medium found */ +#define EMEDIUMTYPE 124 /* Wrong medium type */ +#define ECANCELED 125 /* Operation Canceled */ +#define ENOKEY 126 /* Required key not available */ +#define EKEYEXPIRED 127 /* Key has expired */ +#define EKEYREVOKED 128 /* Key has been revoked */ +#define EKEYREJECTED 129 /* Key was rejected by service */ +#define EOWNERDEAD 130 /* Owner died */ +#define ENOTRECOVERABLE 131 /* State not recoverable */ +#define ERFKILL 132 /* Operation not possible due to RF-kill */ +#define EHWPOISON 133 /* Memory page has hardware error */ + +#ifndef ENOTSUP +#define ENOTSUP EOPNOTSUPP +#endif + +int *__errno_location(void); +#define errno (*__errno_location()) + +#ifdef _GNU_SOURCE +extern char *program_invocation_short_name, *program_invocation_name; +#endif + +#endif // __ERRNO_H__ diff --git a/tools/axlibc/include/fcntl.h b/tools/axlibc/include/fcntl.h new file mode 100644 index 0000000..48750af --- /dev/null +++ b/tools/axlibc/include/fcntl.h @@ -0,0 +1,123 @@ +#ifndef __FCNTL_H__ +#define __FCNTL_H__ + +#include + +#define O_CREAT 0100 +#define O_EXCL 0200 +#define O_NOCTTY 0400 +#define O_TRUNC 01000 +#define O_APPEND 02000 +#define O_NONBLOCK 04000 +#define O_DSYNC 010000 +#define O_SYNC 04010000 +#define O_RSYNC 04010000 +#define O_DIRECTORY 0200000 +#define O_NOFOLLOW 0400000 +#define O_CLOEXEC 02000000 + +#define O_ASYNC 020000 +#define O_DIRECT 040000 +#define O_LARGEFILE 0100000 +#define O_NOATIME 01000000 +#define O_PATH 010000000 +#define O_TMPFILE 020200000 +#define O_NDELAY O_NONBLOCK + +#define O_SEARCH O_PATH +#define O_EXEC O_PATH +#define O_TTY_INIT 0 + +#define O_ACCMODE (03 | O_SEARCH) +#define O_RDONLY 00 +#define O_WRONLY 01 +#define O_RDWR 02 + +#define F_DUPFD 0 +#define F_GETFD 1 +#define F_SETFD 2 +#define F_GETFL 3 +#define F_SETFL 4 + +#define F_SETOWN 8 +#define F_GETOWN 9 +#define F_SETSIG 10 +#define F_GETSIG 11 + +#if __LONG_MAX == 0x7fffffffL +#define F_GETLK 12 +#define F_SETLK 13 +#define F_SETLKW 14 +#else +#define F_GETLK 5 +#define F_SETLK 6 +#define F_SETLKW 7 +#endif + +#define FD_CLOEXEC 1 +#define F_DUPFD_CLOEXEC 1030 + +#define F_RDLCK 0 +#define F_WRLCK 1 +#define F_UNLCK 2 + +#define F_OK 0 +#define R_OK 4 +#define W_OK 2 +#define X_OK 1 +#define F_ULOCK 0 +#define F_LOCK 1 +#define F_TLOCK 2 +#define F_TEST 3 + +#ifndef S_IRUSR +#define S_ISUID 04000 +#define S_ISGID 02000 +#define S_ISVTX 01000 +#define S_IRUSR 0400 +#define S_IWUSR 0200 +#define S_IXUSR 0100 +#define S_IRWXU 0700 +#define S_IRGRP 0040 +#define S_IWGRP 0020 +#define S_IXGRP 0010 +#define S_IRWXG 0070 +#define S_IROTH 0004 +#define S_IWOTH 0002 +#define S_IXOTH 0001 +#define S_IRWXO 0007 +#endif + +#define POSIX_FADV_NORMAL 0 +#define POSIX_FADV_RANDOM 1 +#define POSIX_FADV_SEQUENTIAL 2 +#define POSIX_FADV_WILLNEED 3 +#ifndef POSIX_FADV_DONTNEED +#define POSIX_FADV_DONTNEED 4 +#define POSIX_FADV_NOREUSE 5 +#endif + +#define AT_FDCWD (-100) +#define AT_EMPTY_PATH 0x1000 + +#define SYNC_FILE_RANGE_WAIT_BEFORE 1 +#define SYNC_FILE_RANGE_WRITE 2 +#define SYNC_FILE_RANGE_WAIT_AFTER 4 + +#define loff_t off_t + +struct flock { + short l_type; + short l_whence; + off_t l_start; + off_t l_len; + pid_t l_pid; +}; + +int fcntl(int fd, int cmd, ... /* arg */); +int posix_fadvise(int __fd, unsigned long __offset, unsigned long __len, int __advise); +int sync_file_range(int, off_t, off_t, unsigned); + +int open(const char *filename, int flags, ...); + +#endif diff --git a/tools/axlibc/include/features.h b/tools/axlibc/include/features.h new file mode 100644 index 0000000..2801151 --- /dev/null +++ b/tools/axlibc/include/features.h @@ -0,0 +1,11 @@ +#ifndef _FEATURES_H +#define _FEATURES_H + +#if __STDC_VERSION__ >= 201112L +#elif defined(__GNUC__) +#define _Noreturn __attribute__((__noreturn__)) +#else +#define _Noreturn +#endif + +#endif diff --git a/tools/axlibc/include/float.h b/tools/axlibc/include/float.h new file mode 100644 index 0000000..32ac40a --- /dev/null +++ b/tools/axlibc/include/float.h @@ -0,0 +1,99 @@ +#ifndef _FLOAT_H +#define _FLOAT_H + +// int __flt_rounds(void); +#define FLT_ROUNDS (__flt_rounds()) + +#define FLT_RADIX 2 + +#define FLT_TRUE_MIN 1.40129846432481707092e-45F +#define FLT_MIN 1.17549435082228750797e-38F +#define FLT_MAX 3.40282346638528859812e+38F +#define FLT_EPSILON 1.1920928955078125e-07F + +#define FLT_MANT_DIG 24 +#define FLT_MIN_EXP (-125) +#define FLT_MAX_EXP 128 +#define FLT_HAS_SUBNORM 1 + +#define FLT_DIG 6 +#define FLT_DECIMAL_DIG 9 +#define FLT_MIN_10_EXP (-37) +#define FLT_MAX_10_EXP 38 + +#define DBL_TRUE_MIN 4.94065645841246544177e-324 +#define DBL_MIN 2.22507385850720138309e-308 +#define DBL_MAX 1.79769313486231570815e+308 +#define DBL_EPSILON 2.22044604925031308085e-16 + +#define DBL_MANT_DIG 53 +#define DBL_MIN_EXP (-1021) +#define DBL_MAX_EXP 1024 +#define DBL_HAS_SUBNORM 1 + +#define DBL_DIG 15 +#define DBL_DECIMAL_DIG 17 +#define DBL_MIN_10_EXP (-307) +#define DBL_MAX_10_EXP 308 + +#define LDBL_HAS_SUBNORM 1 +#define LDBL_DECIMAL_DIG DECIMAL_DIG + +#if defined(__aarch64__) +#define FLT_EVAL_METHOD 0 + +#define LDBL_TRUE_MIN 6.47517511943802511092443895822764655e-4966L +#define LDBL_MIN 3.36210314311209350626267781732175260e-4932L +#define LDBL_MAX 1.18973149535723176508575932662800702e+4932L +#define LDBL_EPSILON 1.92592994438723585305597794258492732e-34L + +#define LDBL_MANT_DIG 113 +#define LDBL_MIN_EXP (-16381) +#define LDBL_MAX_EXP 16384 + +#define LDBL_DIG 33 +#define LDBL_MIN_10_EXP (-4931) +#define LDBL_MAX_10_EXP 4932 + +#define DECIMAL_DIG 36 +#elif defined(__riscv__) || defined(__riscv) +#define FLT_EVAL_METHOD 0 + +#define LDBL_TRUE_MIN 6.47517511943802511092443895822764655e-4966L +#define LDBL_MIN 3.36210314311209350626267781732175260e-4932L +#define LDBL_MAX 1.18973149535723176508575932662800702e+4932L +#define LDBL_EPSILON 1.92592994438723585305597794258492732e-34L + +#define LDBL_MANT_DIG 113 +#define LDBL_MIN_EXP (-16381) +#define LDBL_MAX_EXP 16384 + +#define LDBL_DIG 33 +#define LDBL_MIN_10_EXP (-4931) +#define LDBL_MAX_10_EXP 4932 + +#define DECIMAL_DIG 36 +#elif defined(__x86_64__) +#ifdef __FLT_EVAL_METHOD__ +#define FLT_EVAL_METHOD __FLT_EVAL_METHOD__ +#else +#define FLT_EVAL_METHOD 0 +#endif + +#define LDBL_TRUE_MIN 3.6451995318824746025e-4951L +#define LDBL_MIN 3.3621031431120935063e-4932L +#define LDBL_MAX 1.1897314953572317650e+4932L +#define LDBL_EPSILON 1.0842021724855044340e-19L + +#define LDBL_MANT_DIG 64 +#define LDBL_MIN_EXP (-16381) +#define LDBL_MAX_EXP 16384 + +#define LDBL_DIG 18 +#define LDBL_MIN_10_EXP (-4931) +#define LDBL_MAX_10_EXP 4932 + +#define DECIMAL_DIG 21 +#endif + +#endif diff --git a/tools/axlibc/include/fnmatch.h b/tools/axlibc/include/fnmatch.h new file mode 100644 index 0000000..c387c5c --- /dev/null +++ b/tools/axlibc/include/fnmatch.h @@ -0,0 +1,24 @@ +#ifndef _FNMATCH_H +#define _FNMATCH_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define FNM_PATHNAME 0x1 +#define FNM_NOESCAPE 0x2 +#define FNM_PERIOD 0x4 +#define FNM_LEADING_DIR 0x8 +#define FNM_CASEFOLD 0x10 +#define FNM_FILE_NAME FNM_PATHNAME + +#define FNM_NOMATCH 1 +#define FNM_NOSYS (-1) + +int fnmatch(const char *, const char *, int); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/tools/axlibc/include/glob.h b/tools/axlibc/include/glob.h new file mode 100644 index 0000000..4dbd347 --- /dev/null +++ b/tools/axlibc/include/glob.h @@ -0,0 +1,34 @@ +#ifndef _GLOB_H +#define _GLOB_H + +#include + +#define GLOB_ERR 0x01 +#define GLOB_MARK 0x02 +#define GLOB_NOSORT 0x04 +#define GLOB_DOOFFS 0x08 +#define GLOB_NOCHECK 0x10 +#define GLOB_APPEND 0x20 +#define GLOB_NOESCAPE 0x40 +#define GLOB_PERIOD 0x80 + +#define GLOB_TILDE 0x1000 +#define GLOB_TILDE_CHECK 0x4000 + +#define GLOB_NOSPACE 1 +#define GLOB_ABORTED 2 +#define GLOB_NOMATCH 3 +#define GLOB_NOSYS 4 + +typedef struct { + size_t gl_pathc; + char **gl_pathv; + size_t gl_offs; + int __dummy1; + void *__dummy2[5]; +} glob_t; + +int glob(const char *__restrict, int, int (*)(const char *, int), glob_t *__restrict); +void globfree(glob_t *); + +#endif diff --git a/tools/axlibc/include/inttypes.h b/tools/axlibc/include/inttypes.h new file mode 100644 index 0000000..536fd3f --- /dev/null +++ b/tools/axlibc/include/inttypes.h @@ -0,0 +1,10 @@ +#ifndef _INTTYPES_H +#define _INTTYPES_H + +#include + +#define __PRI64 "l" + +#define PRIu64 __PRI64 "u" + +#endif diff --git a/tools/axlibc/include/langinfo.h b/tools/axlibc/include/langinfo.h new file mode 100644 index 0000000..9114fba --- /dev/null +++ b/tools/axlibc/include/langinfo.h @@ -0,0 +1,82 @@ +#ifndef _LANGINFO_H +#define _LANGINFO_H + +typedef int nl_item; + +#define ABDAY_1 0x20000 +#define ABDAY_2 0x20001 +#define ABDAY_3 0x20002 +#define ABDAY_4 0x20003 +#define ABDAY_5 0x20004 +#define ABDAY_6 0x20005 +#define ABDAY_7 0x20006 + +#define DAY_1 0x20007 +#define DAY_2 0x20008 +#define DAY_3 0x20009 +#define DAY_4 0x2000A +#define DAY_5 0x2000B +#define DAY_6 0x2000C +#define DAY_7 0x2000D + +#define ABMON_1 0x2000E +#define ABMON_2 0x2000F +#define ABMON_3 0x20010 +#define ABMON_4 0x20011 +#define ABMON_5 0x20012 +#define ABMON_6 0x20013 +#define ABMON_7 0x20014 +#define ABMON_8 0x20015 +#define ABMON_9 0x20016 +#define ABMON_10 0x20017 +#define ABMON_11 0x20018 +#define ABMON_12 0x20019 + +#define MON_1 0x2001A +#define MON_2 0x2001B +#define MON_3 0x2001C +#define MON_4 0x2001D +#define MON_5 0x2001E +#define MON_6 0x2001F +#define MON_7 0x20020 +#define MON_8 0x20021 +#define MON_9 0x20022 +#define MON_10 0x20023 +#define MON_11 0x20024 +#define MON_12 0x20025 + +#define AM_STR 0x20026 +#define PM_STR 0x20027 + +#define D_T_FMT 0x20028 +#define D_FMT 0x20029 +#define T_FMT 0x2002A +#define T_FMT_AMPM 0x2002B + +#define ERA 0x2002C +#define ERA_D_FMT 0x2002E +#define ALT_DIGITS 0x2002F +#define ERA_D_T_FMT 0x20030 +#define ERA_T_FMT 0x20031 + +#define CODESET 14 + +#define CRNCYSTR 0x4000F + +#define RADIXCHAR 0x10000 +#define THOUSEP 0x10001 +#define YESEXPR 0x50000 +#define NOEXPR 0x50001 + +#define _NL_LOCALE_NAME(cat) (((cat) << 16) | 0xffff) + +#if defined(_GNU_SOURCE) +#define NL_LOCALE_NAME(cat) _NL_LOCALE_NAME(cat) +#endif + +#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE) +#define YESSTR 0x50002 +#define NOSTR 0x50003 +#endif + +#endif diff --git a/tools/axlibc/include/libgen.h b/tools/axlibc/include/libgen.h new file mode 100644 index 0000000..7c7fd9c --- /dev/null +++ b/tools/axlibc/include/libgen.h @@ -0,0 +1,15 @@ +#ifndef _LIBGEN_H +#define _LIBGEN_H + +#ifdef __cplusplus +extern "C" { +#endif + +char *dirname(char *); +char *basename(char *); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/tools/axlibc/include/limits.h b/tools/axlibc/include/limits.h new file mode 100644 index 0000000..26b213a --- /dev/null +++ b/tools/axlibc/include/limits.h @@ -0,0 +1,35 @@ +#ifndef __LIMITS__ +#define __LIMITS__ + +#define __LONG_MAX 0x7fffffffffffffffL +#define CHAR_BIT 8 +#define SCHAR_MIN (-128) +#define SCHAR_MAX 127 +#define UCHAR_MAX 255 +#define SHRT_MIN (-1 - 0x7fff) +#define SHRT_MAX 0x7fff +#define USHRT_MAX 0xffff +#define INT_MIN (-1 - 0x7fffffff) +#define INT_MAX 0x7fffffff +#define UINT_MAX 0xffffffffU +#define LONG_MIN (-LONG_MAX - 1) +#define LONG_MAX __LONG_MAX +#define ULONG_MAX (2UL * LONG_MAX + 1) +#define LLONG_MIN (-LLONG_MAX - 1) +#define LLONG_MAX 0x7fffffffffffffffLL +#define ULLONG_MAX (2ULL * LLONG_MAX + 1) +#define IOV_MAX 1024 + +#define PTHREAD_STACK_MIN 2048 + +#define LOGIN_NAME_MAX 256 +#ifndef NAME_MAX +#define NAME_MAX 255 +#endif +#define TZNAME_MAX 6 + +#define PATH_MAX 4096 +#define SSIZE_MAX LONG_MAX +#define CHAR_MAX 127 + +#endif diff --git a/tools/axlibc/include/locale.h b/tools/axlibc/include/locale.h new file mode 100644 index 0000000..e33b137 --- /dev/null +++ b/tools/axlibc/include/locale.h @@ -0,0 +1,59 @@ +#ifndef _LOCALE_H +#define _LOCALE_H + +#define LC_CTYPE 0 +#define LC_NUMERIC 1 +#define LC_TIME 2 +#define LC_COLLATE 3 +#define LC_MONETARY 4 +#define LC_MESSAGES 5 +#define LC_ALL 6 +#define LOCALE_NAME_MAX 23 + +#include + +struct lconv { + char *decimal_point; + char *thousands_sep; + char *grouping; + + char *int_curr_symbol; + char *currency_symbol; + char *mon_decimal_point; + char *mon_thousands_sep; + char *mon_grouping; + char *positive_sign; + char *negative_sign; + char int_frac_digits; + char frac_digits; + char p_cs_precedes; + char p_sep_by_space; + char n_cs_precedes; + char n_sep_by_space; + char p_sign_posn; + char n_sign_posn; + char int_p_cs_precedes; + char int_p_sep_by_space; + char int_n_cs_precedes; + char int_n_sep_by_space; + char int_p_sign_posn; + char int_n_sign_posn; +}; + +struct __locale_map { + const void *map; + size_t map_size; + char name[LOCALE_NAME_MAX + 1]; + const struct __locale_map *next; +}; + +struct __locale_struct { + const struct __locale_map *cat[6]; +}; + +typedef struct __locale_struct *locale_t; + +char *setlocale(int, const char *); +struct lconv *localeconv(void); + +#endif // _LOCALE_H diff --git a/tools/axlibc/include/math.h b/tools/axlibc/include/math.h new file mode 100644 index 0000000..649b851 --- /dev/null +++ b/tools/axlibc/include/math.h @@ -0,0 +1,321 @@ +#ifndef _MATH_H +#define _MATH_H + +#ifdef AX_CONFIG_FP_SIMD + +typedef double double_t; + +#if 100 * __GNUC__ + __GNUC_MINOR__ >= 303 +#define NAN __builtin_nanf("") +#define INFINITY __builtin_inff() +#else +#define NAN (0.0f / 0.0f) +#define INFINITY 1e5000f +#endif + +#define M_PI 3.14159265358979323846 /* pi */ + +#define LOG_TABLE_BITS 7 +#define LOG_POLY_ORDER 6 +#define LOG_POLY1_ORDER 12 + +#define HUGE_VALF INFINITY +#define HUGE_VAL ((double)INFINITY) +#define HUGE_VALL ((long double)INFINITY) + +#define MATH_ERRNO 1 +#define MATH_ERREXCEPT 2 +#define math_errhandling 2 + +#define FP_ILOGBNAN (-1 - 0x7fffffff) +#define FP_ILOGB0 FP_ILOGBNAN + +#define LOG_TABLE_BITS 7 +#define LOG_POLY_ORDER 6 +#define LOG_POLY1_ORDER 12 + +#define FP_NAN 0 +#define FP_INFINITE 1 +#define FP_ZERO 2 +#define FP_SUBNORMAL 3 +#define FP_NORMAL 4 + +int __fpclassify(double); +int __fpclassifyf(float); +int __fpclassifyl(long double); + +static __inline unsigned __FLOAT_BITS(float __f) +{ + union { + float __f; + unsigned __i; + } __u; + __u.__f = __f; + return __u.__i; +} + +static __inline unsigned long long __DOUBLE_BITS(double __f) +{ + union { + double __f; + unsigned long long __i; + } __u; + __u.__f = __f; + return __u.__i; +} + +#define fpclassify(x) \ + (sizeof(x) == sizeof(float) ? __fpclassifyf(x) \ + : sizeof(x) == sizeof(double) ? __fpclassify(x) \ + : __fpclassifyl(x)) + +#define isnan(x) \ + (sizeof(x) == sizeof(float) ? (__FLOAT_BITS(x) & 0x7fffffff) > 0x7f800000 \ + : sizeof(x) == sizeof(double) ? (__DOUBLE_BITS(x) & -1ULL >> 1) > 0x7ffULL << 52 \ + : __fpclassifyl(x) == FP_NAN) + +#define isinf(x) \ + (sizeof(x) == sizeof(float) ? (__FLOAT_BITS(x) & 0x7fffffff) == 0x7f800000 \ + : sizeof(x) == sizeof(double) ? (__DOUBLE_BITS(x) & -1ULL >> 1) == 0x7ffULL << 52 \ + : __fpclassifyl(x) == FP_INFINITE) + +#define isfinite(x) \ + (sizeof(x) == sizeof(float) ? (__FLOAT_BITS(x) & 0x7fffffff) < 0x7f800000 \ + : sizeof(x) == sizeof(double) ? (__DOUBLE_BITS(x) & -1ULL >> 1) < 0x7ffULL << 52 \ + : __fpclassifyl(x) > FP_INFINITE) + +#define isnormal(x) \ + (sizeof(x) == sizeof(float) ? ((__FLOAT_BITS(x) + 0x00800000) & 0x7fffffff) >= 0x01000000 \ + : ((__DOUBLE_BITS(x) + (1ULL << 52)) & -1ULL >> 1) >= 1ULL << 53) + +double acos(double); +float acosf(float); +long double acosl(long double); + +double acosh(double); +float acoshf(float); +long double acoshl(long double); + +double asin(double); +float asinf(float); +long double asinl(long double); + +double asinh(double); +float asinhf(float); +long double asinhl(long double); + +double atan(double); +float atanf(float); +long double atanl(long double); + +double atan2(double, double); +float atan2f(float, float); +long double atan2l(long double, long double); + +double atanh(double); +float atanhf(float); +long double atanhl(long double); + +double cbrt(double); +float cbrtf(float); +long double cbrtl(long double); + +double ceil(double); +float ceilf(float); +long double ceill(long double); + +double copysign(double, double); +float copysignf(float, float); +long double copysignl(long double, long double); + +double cos(double); +float cosf(float); +long double cosl(long double); + +double cosh(double); +float coshf(float); +long double coshl(long double); + +double erf(double); +float erff(float); +long double erfl(long double); + +double erfc(double); +float erfcf(float); +long double erfcl(long double); + +double exp(double); +float expf(float); +long double expl(long double); + +double exp2(double); +float exp2f(float); +long double exp2l(long double); + +double expm1(double); +float expm1f(float); +long double expm1l(long double); + +double fabs(double); +float fabsf(float); +long double fabsl(long double); + +double fdim(double, double); +float fdimf(float, float); +long double fdiml(long double, long double); + +double floor(double); +float floorf(float); +long double floorl(long double); + +double fma(double, double, double); +float fmaf(float, float, float); +long double fmal(long double, long double, long double); + +double fmax(double, double); +float fmaxf(float, float); +long double fmaxl(long double, long double); + +double fmin(double, double); +float fminf(float, float); +long double fminl(long double, long double); + +double fmod(double, double); +float fmodf(float, float); +long double fmodl(long double, long double); + +double frexp(double, int *); +float frexpf(float, int *); +long double frexpl(long double, int *); + +double hypot(double, double); +float hypotf(float, float); +long double hypotl(long double, long double); + +int ilogb(double); +int ilogbf(float); +int ilogbl(long double); + +double ldexp(double, int); +float ldexpf(float, int); +long double ldexpl(long double, int); + +double lgamma(double); +float lgammaf(float); +long double lgammal(long double); + +long long llrint(double); +long long llrintf(float); +long long llrintl(long double); + +long long llround(double); +long long llroundf(float); +long long llroundl(long double); + +double log(double); +float logf(float); +long double logl(long double); + +double log10(double); +float log10f(float); +long double log10l(long double); + +double log1p(double); +float log1pf(float); +long double log1pl(long double); + +double log2(double); +float log2f(float); +long double log2l(long double); + +double logb(double); +float logbf(float); +long double logbl(long double); + +long lrint(double); +long lrintf(float); +long lrintl(long double); + +long lround(double); +long lroundf(float); +long lroundl(long double); + +double modf(double, double *); +float modff(float, float *); +long double modfl(long double, long double *); + +double nan(const char *); +float nanf(const char *); +long double nanl(const char *); + +double nearbyint(double); +float nearbyintf(float); +long double nearbyintl(long double); + +double nextafter(double, double); +float nextafterf(float, float); +long double nextafterl(long double, long double); + +double nexttoward(double, long double); +float nexttowardf(float, long double); +long double nexttowardl(long double, long double); + +double pow(double, double); +float powf(float, float); +long double powl(long double, long double); + +double remainder(double, double); +float remainderf(float, float); +long double remainderl(long double, long double); + +double remquo(double, double, int *); +float remquof(float, float, int *); +long double remquol(long double, long double, int *); + +double rint(double); +float rintf(float); +long double rintl(long double); + +double round(double); +float roundf(float); +long double roundl(long double); + +double scalbln(double, long); +float scalblnf(float, long); +long double scalblnl(long double, long); + +double scalbn(double, int); +float scalbnf(float, int); +long double scalbnl(long double, int); + +double sin(double); +float sinf(float); +long double sinl(long double); + +double sinh(double); +float sinhf(float); +long double sinhl(long double); + +double sqrt(double); +float sqrtf(float); +long double sqrtl(long double); + +double tan(double); +float tanf(float); +long double tanl(long double); + +double tanh(double); +float tanhf(float); +long double tanhl(long double); + +double tgamma(double); +float tgammaf(float); +long double tgammal(long double); + +double trunc(double); +float truncf(float); +long double truncl(long double); + +#endif // AX_CONFIG_FP_SIMD + +#endif // _MATH_H diff --git a/tools/axlibc/include/memory.h b/tools/axlibc/include/memory.h new file mode 100644 index 0000000..d51b932 --- /dev/null +++ b/tools/axlibc/include/memory.h @@ -0,0 +1,6 @@ +#ifndef __MEMORY_H__ +#define __MEMORY_H__ + +#include + +#endif // __MEMORY_H__ diff --git a/tools/axlibc/include/netdb.h b/tools/axlibc/include/netdb.h new file mode 100644 index 0000000..6272578 --- /dev/null +++ b/tools/axlibc/include/netdb.h @@ -0,0 +1,85 @@ +#ifndef _NETDB_H +#define _NETDB_H + +#include + +struct addrinfo { + int ai_flags; + int ai_family; + int ai_socktype; + int ai_protocol; + socklen_t ai_addrlen; + struct sockaddr *ai_addr; + char *ai_canonname; + struct addrinfo *ai_next; +}; + +struct aibuf { + struct addrinfo ai; + union sa { + struct sockaddr_in sin; + struct sockaddr_in6 sin6; + } sa; + volatile int lock[1]; + short slot, ref; +}; + +struct service { + uint16_t port; + unsigned char proto, socktype; +}; + +struct address { + int family; + unsigned scopeid; + uint8_t addr[16]; + int sortkey; +}; + +#define AI_PASSIVE 0x01 +#define AI_CANONNAME 0x02 +#define AI_NUMERICHOST 0x04 +#define AI_V4MAPPED 0x08 +#define AI_ALL 0x10 +#define AI_ADDRCONFIG 0x20 +#define AI_NUMERICSERV 0x400 + +#define NI_NUMERICHOST 0x01 +#define NI_NUMERICSERV 0x02 +#define NI_NOFQDN 0x04 +#define NI_NAMEREQD 0x08 +#define NI_DGRAM 0x10 +#define NI_NUMERICSCOPE 0x100 + +#define EAI_BADFLAGS -1 +#define EAI_NONAME -2 +#define EAI_AGAIN -3 +#define EAI_FAIL -4 +#define EAI_FAMILY -6 +#define EAI_SOCKTYPE -7 +#define EAI_SERVICE -8 +#define EAI_MEMORY -10 +#define EAI_SYSTEM -11 +#define EAI_OVERFLOW -12 + +#define HOST_NOT_FOUND 1 +#define TRY_AGAIN 2 +#define NO_RECOVERY 3 +#define NO_DATA 4 +#define NO_ADDRESS NO_DATA + +extern int h_errno; +const char *hstrerror(int ecode); + +#define MAXSERVS 2 +#define MAXADDRS 48 + +#ifdef AX_CONFIG_NET + +int getaddrinfo(const char *, const char *, const struct addrinfo *, struct addrinfo **); +void freeaddrinfo(struct addrinfo *); +const char *gai_strerror(int __ecode); + +#endif // AX_CONFIG_NET + +#endif // _NETDB_H diff --git a/tools/axlibc/include/netinet/in.h b/tools/axlibc/include/netinet/in.h new file mode 100644 index 0000000..370f3b1 --- /dev/null +++ b/tools/axlibc/include/netinet/in.h @@ -0,0 +1,129 @@ +#ifndef _NETINET_IN_H +#define _NETINET_IN_H + +#include + +#define INET_ADDRSTRLEN 16 +#define INET6_ADDRSTRLEN 46 + +uint32_t htonl(uint32_t); +uint16_t htons(uint16_t); +uint32_t ntohl(uint32_t); +uint16_t ntohs(uint16_t); + +#define IPPROTO_IP 0 +#define IPPROTO_HOPOPTS 0 +#define IPPROTO_ICMP 1 +#define IPPROTO_IGMP 2 +#define IPPROTO_IPIP 4 +#define IPPROTO_TCP 6 +#define IPPROTO_EGP 8 +#define IPPROTO_PUP 12 +#define IPPROTO_UDP 17 +#define IPPROTO_IDP 22 +#define IPPROTO_TP 29 +#define IPPROTO_DCCP 33 +#define IPPROTO_IPV6 41 +#define IPPROTO_ROUTING 43 +#define IPPROTO_FRAGMENT 44 +#define IPPROTO_RSVP 46 +#define IPPROTO_GRE 47 +#define IPPROTO_ESP 50 +#define IPPROTO_AH 51 +#define IPPROTO_ICMPV6 58 +#define IPPROTO_NONE 59 +#define IPPROTO_DSTOPTS 60 +#define IPPROTO_MTP 92 +#define IPPROTO_BEETPH 94 +#define IPPROTO_ENCAP 98 +#define IPPROTO_PIM 103 +#define IPPROTO_COMP 108 +#define IPPROTO_SCTP 132 +#define IPPROTO_MH 135 +#define IPPROTO_UDPLITE 136 +#define IPPROTO_MPLS 137 +#define IPPROTO_ETHERNET 143 +#define IPPROTO_RAW 255 +#define IPPROTO_MPTCP 262 +#define IPPROTO_MAX 263 + +#define IPV6_ADDRFORM 1 +#define IPV6_2292PKTINFO 2 +#define IPV6_2292HOPOPTS 3 +#define IPV6_2292DSTOPTS 4 +#define IPV6_2292RTHDR 5 +#define IPV6_2292PKTOPTIONS 6 +#define IPV6_CHECKSUM 7 +#define IPV6_2292HOPLIMIT 8 +#define IPV6_NEXTHOP 9 +#define IPV6_AUTHHDR 10 +#define IPV6_UNICAST_HOPS 16 +#define IPV6_MULTICAST_IF 17 +#define IPV6_MULTICAST_HOPS 18 +#define IPV6_MULTICAST_LOOP 19 +#define IPV6_JOIN_GROUP 20 +#define IPV6_LEAVE_GROUP 21 +#define IPV6_ROUTER_ALERT 22 +#define IPV6_MTU_DISCOVER 23 +#define IPV6_MTU 24 +#define IPV6_RECVERR 25 +#define IPV6_V6ONLY 26 +#define IPV6_JOIN_ANYCAST 27 +#define IPV6_LEAVE_ANYCAST 28 +#define IPV6_MULTICAST_ALL 29 +#define IPV6_ROUTER_ALERT_ISOLATE 30 +#define IPV6_IPSEC_POLICY 34 +#define IPV6_XFRM_POLICY 35 +#define IPV6_HDRINCL 36 + +#define IN6ADDR_ANY_INIT \ + { \ + { \ + { \ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 \ + } \ + } \ + } +#define IN6ADDR_LOOPBACK_INIT \ + { \ + { \ + { \ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 \ + } \ + } \ + } + +typedef uint16_t in_port_t; +typedef uint32_t in_addr_t; + +struct in_addr { + in_addr_t s_addr; +}; + +struct sockaddr_in { + sa_family_t sin_family; + in_port_t sin_port; + struct in_addr sin_addr; + uint8_t sin_zero[8]; +}; + +struct in6_addr { + union { + uint8_t __s6_addr[16]; + uint16_t __s6_addr16[8]; + uint32_t __s6_addr32[4]; + } __in6_union; +}; +#define s6_addr __in6_union.__s6_addr +#define s6_addr16 __in6_union.__s6_addr16 +#define s6_addr32 __in6_union.__s6_addr32 + +struct sockaddr_in6 { + sa_family_t sin6_family; + in_port_t sin6_port; + uint32_t sin6_flowinfo; + struct in6_addr sin6_addr; + uint32_t sin6_scope_id; +}; + +#endif // _NETINET_IN_H diff --git a/tools/axlibc/include/netinet/tcp.h b/tools/axlibc/include/netinet/tcp.h new file mode 100644 index 0000000..dfe65d1 --- /dev/null +++ b/tools/axlibc/include/netinet/tcp.h @@ -0,0 +1,45 @@ +#ifndef _NETINET_TCP_H +#define _NETINET_TCP_H + +#define TCP_NODELAY 1 +#define TCP_MAXSEG 2 +#define TCP_CORK 3 +#define TCP_KEEPIDLE 4 +#define TCP_KEEPINTVL 5 +#define TCP_KEEPCNT 6 +#define TCP_SYNCNT 7 +#define TCP_LINGER2 8 +#define TCP_DEFER_ACCEPT 9 +#define TCP_WINDOW_CLAMP 10 +#define TCP_INFO 11 +#define TCP_QUICKACK 12 +#define TCP_CONGESTION 13 +#define TCP_MD5SIG 14 +#define TCP_THIN_LINEAR_TIMEOUTS 16 +#define TCP_THIN_DUPACK 17 +#define TCP_USER_TIMEOUT 18 +#define TCP_REPAIR 19 +#define TCP_REPAIR_QUEUE 20 +#define TCP_QUEUE_SEQ 21 +#define TCP_REPAIR_OPTIONS 22 +#define TCP_FASTOPEN 23 +#define TCP_TIMESTAMP 24 +#define TCP_NOTSENT_LOWAT 25 +#define TCP_CC_INFO 26 +#define TCP_SAVE_SYN 27 +#define TCP_SAVED_SYN 28 +#define TCP_REPAIR_WINDOW 29 +#define TCP_FASTOPEN_CONNECT 30 +#define TCP_ULP 31 +#define TCP_MD5SIG_EXT 32 +#define TCP_FASTOPEN_KEY 33 +#define TCP_FASTOPEN_NO_COOKIE 34 +#define TCP_ZEROCOPY_RECEIVE 35 +#define TCP_INQ 36 +#define TCP_TX_DELAY 37 + +#define TCP_REPAIR_ON 1 +#define TCP_REPAIR_OFF 0 +#define TCP_REPAIR_OFF_NO_WP -1 + +#endif // _NETINET_TCP_H diff --git a/tools/axlibc/include/poll.h b/tools/axlibc/include/poll.h new file mode 100644 index 0000000..e5903f2 --- /dev/null +++ b/tools/axlibc/include/poll.h @@ -0,0 +1,21 @@ +#ifndef _POLL_H +#define _POLL_H + +struct pollfd { + int fd; + short events; + short revents; +}; + +#define POLLIN 0x001 +#define POLLPRI 0x002 +#define POLLOUT 0x004 +#define POLLERR 0x008 +#define POLLHUP 0x010 +#define POLLNVAL 0x020 + +typedef unsigned long nfds_t; + +int poll(struct pollfd *__fds, nfds_t __nfds, int __timeout); + +#endif // _POLL_H diff --git a/tools/axlibc/include/pthread.h b/tools/axlibc/include/pthread.h new file mode 100644 index 0000000..5f8cd98 --- /dev/null +++ b/tools/axlibc/include/pthread.h @@ -0,0 +1,84 @@ +#ifndef _PTHREAD_H +#define _PTHREAD_H + +#include +#include + +#define PTHREAD_CANCEL_ENABLE 0 +#define PTHREAD_CANCEL_DISABLE 1 +#define PTHREAD_CANCEL_MASKED 2 + +#define PTHREAD_CANCEL_DEFERRED 0 +#define PTHREAD_CANCEL_ASYNCHRONOUS 1 + +typedef struct { + unsigned __attr; +} pthread_condattr_t; + +#include + +typedef struct { + unsigned __attr; +} pthread_mutexattr_t; + +typedef struct { + union { + int __i[sizeof(long) == 8 ? 14 : 9]; + volatile int __vi[sizeof(long) == 8 ? 14 : 9]; + unsigned long __s[sizeof(long) == 8 ? 7 : 9]; + } __u; +} pthread_attr_t; +#define _a_stacksize __u.__s[0] +#define _a_guardsize __u.__s[1] +#define _a_stackaddr __u.__s[2] + +typedef struct { + union { + int __i[12]; + volatile int __vi[12]; + void *__p[12 * sizeof(int) / sizeof(void *)]; + } __u; +} pthread_cond_t; +#define _c_clock __u.__i[4] +#define _c_shared __u.__p[0] + +typedef void *pthread_t; + +#define PTHREAD_CANCELED ((void *)-1) +#define SIGCANCEL 33 + +#ifdef AX_CONFIG_MULTITASK + +_Noreturn void pthread_exit(void *); +pthread_t pthread_self(void); + +int pthread_create(pthread_t *__restrict, const pthread_attr_t *__restrict, void *(*)(void *), + void *__restrict); +int pthread_join(pthread_t t, void **res); + +int pthread_setcancelstate(int, int *); +int pthread_setcanceltype(int, int *); +void pthread_testcancel(void); +int pthread_cancel(pthread_t); + +int pthread_mutex_init(pthread_mutex_t *__restrict, const pthread_mutexattr_t *__restrict); +int pthread_mutex_lock(pthread_mutex_t *); +int pthread_mutex_unlock(pthread_mutex_t *); +int pthread_mutex_trylock(pthread_mutex_t *); + +int pthread_setname_np(pthread_t, const char *); + +int pthread_cond_init(pthread_cond_t *__restrict__ __cond, + const pthread_condattr_t *__restrict__ __cond_attr); +int pthread_cond_signal(pthread_cond_t *__cond); +int pthread_cond_wait(pthread_cond_t *__restrict__ __cond, pthread_mutex_t *__restrict__ __mutex); +int pthread_cond_broadcast(pthread_cond_t *); + +int pthread_attr_init(pthread_attr_t *__attr); +int pthread_attr_getstacksize(const pthread_attr_t *__restrict__ __attr, + size_t *__restrict__ __stacksize); +int pthread_attr_setstacksize(pthread_attr_t *__attr, size_t __stacksize); + +#endif // AX_CONFIG_MULTITASK + +#endif // _PTHREAD_H diff --git a/tools/axlibc/include/pwd.h b/tools/axlibc/include/pwd.h new file mode 100644 index 0000000..3548546 --- /dev/null +++ b/tools/axlibc/include/pwd.h @@ -0,0 +1,45 @@ +#ifndef _PWD_H +#define _PWD_H + +#include +#include +#include +#include + +#define NSCDVERSION 2 +#define GETPWBYNAME 0 +#define GETPWBYUID 1 +#define GETGRBYNAME 2 +#define GETGRBYGID 3 +#define GETINITGR 15 + +#define PWVERSION 0 +#define PWFOUND 1 +#define PWNAMELEN 2 +#define PWPASSWDLEN 3 +#define PWUID 4 +#define PWGID 5 +#define PWGECOSLEN 6 +#define PWDIRLEN 7 +#define PWSHELLLEN 8 +#define PW_LEN 9 + +#define REQVERSION 0 +#define REQTYPE 1 +#define REQKEYLEN 2 +#define REQ_LEN 3 + +struct passwd { + char *pw_name; + char *pw_passwd; + uid_t pw_uid; + gid_t pw_gid; + char *pw_gecos; + char *pw_dir; + char *pw_shell; +}; + +int getpwuid_r(uid_t, struct passwd *, char *, size_t, struct passwd **); +int getpwnam_r(const char *, struct passwd *, char *, size_t, struct passwd **); + +#endif // _PWD_H diff --git a/tools/axlibc/include/regex.h b/tools/axlibc/include/regex.h new file mode 100644 index 0000000..50b3828 --- /dev/null +++ b/tools/axlibc/include/regex.h @@ -0,0 +1,4 @@ +#ifndef _REGEX_H +#define _REGEX_H + +#endif // _REGEX_H diff --git a/tools/axlibc/include/sched.h b/tools/axlibc/include/sched.h new file mode 100644 index 0000000..ed201c5 --- /dev/null +++ b/tools/axlibc/include/sched.h @@ -0,0 +1,23 @@ +#ifndef _SCHED_H +#define _SCHED_H + +#include + +typedef struct cpu_set_t { + unsigned long __bits[128 / sizeof(long)]; +} cpu_set_t; + +#define __CPU_op_S(i, size, set, op) \ + ((i) / 8U >= (size) ? 0 \ + : (((unsigned long *)(set))[(i) / 8 / sizeof(long)] op( \ + 1UL << ((i) % (8 * sizeof(long)))))) + +#define CPU_SET_S(i, size, set) __CPU_op_S(i, size, set, |=) +#define CPU_ZERO_S(size, set) memset(set, 0, size) + +#define CPU_SET(i, set) CPU_SET_S(i, sizeof(cpu_set_t), set); +#define CPU_ZERO(set) CPU_ZERO_S(sizeof(cpu_set_t), set) + +int sched_setaffinity(pid_t, size_t, const cpu_set_t *); + +#endif // _SCHED_H diff --git a/tools/axlibc/include/setjmp.h b/tools/axlibc/include/setjmp.h new file mode 100644 index 0000000..70981df --- /dev/null +++ b/tools/axlibc/include/setjmp.h @@ -0,0 +1,23 @@ +#ifndef _SETJMP_H +#define _SETJMP_H + +#include + +#if defined(__aarch64__) +typedef unsigned long __jmp_buf[22]; +#elif defined(__riscv__) || defined(__riscv) +typedef unsigned long __jmp_buf[26]; +#elif defined(__x86_64__) +typedef unsigned long __jmp_buf[8]; +#endif + +typedef struct __jmp_buf_tag { + __jmp_buf __jb; + unsigned long __fl; + unsigned long __ss[128 / sizeof(long)]; +} jmp_buf[1]; + +int setjmp(jmp_buf); +_Noreturn void longjmp(jmp_buf, int); + +#endif diff --git a/tools/axlibc/include/signal.h b/tools/axlibc/include/signal.h new file mode 100644 index 0000000..52e21ce --- /dev/null +++ b/tools/axlibc/include/signal.h @@ -0,0 +1,179 @@ +#ifndef _SIGNAL_H +#define _SIGNAL_H + +#include +#include +#include + +typedef int sig_atomic_t; + +union sigval { + int sival_int; + void *sival_ptr; +}; + +typedef union sigval __sigval_t; + +#define SA_NOCLDSTOP 1 +#define SA_NOCLDWAIT 2 +#define SA_SIGINFO 4 +#define SA_ONSTACK 0x08000000 +#define SA_RESTART 0x10000000 +#define SA_NODEFER 0x40000000 +#define SA_RESETHAND 0x80000000 +#define SA_RESTORER 0x04000000 + +#define SIG_BLOCK 0 +#define SIG_UNBLOCK 1 +#define SIG_SETMASK 2 + +#define SI_ASYNCNL (-60) +#define SI_TKILL (-6) +#define SI_SIGIO (-5) +#define SI_ASYNCIO (-4) +#define SI_MESGQ (-3) +#define SI_TIMER (-2) +#define SI_QUEUE (-1) +#define SI_USER 0 +#define SI_KERNEL 128 + +typedef struct { + int si_signo, si_errno, si_code; + union { + char __pad[128 - 2 * sizeof(int) - sizeof(long)]; + struct { + union { + struct { + int si_pid; + unsigned int si_uid; + } __piduid; + struct { + int si_timerid; + int si_overrun; + } __timer; + } __first; + union { + union sigval si_value; + struct { + int si_status; + long si_utime, si_stime; + } __sigchld; + } __second; + } __si_common; + struct { + void *si_addr; + short si_addr_lsb; + union { + struct { + void *si_lower; + void *si_upper; + } __addr_bnd; + unsigned si_pkey; + } __first; + } __sigfault; + struct { + long si_band; + int si_fd; + } __sigpoll; + struct { + void *si_call_addr; + int si_syscall; + unsigned si_arch; + } __sigsys; + } __si_fields; +} siginfo_t; + +#define si_pid __si_fields.__si_common.__first.__piduid.si_pid +#define si_uid __si_fields.__si_common.__first.__piduid.si_uid +#define si_status __si_fields.__si_common.__second.__sigchld.si_status +#define si_utime __si_fields.__si_common.__second.__sigchld.si_utime +#define si_stime __si_fields.__si_common.__second.__sigchld.si_stime +#define si_value __si_fields.__si_common.__second.si_value +#define si_addr __si_fields.__sigfault.si_addr +#define si_addr_lsb __si_fields.__sigfault.si_addr_lsb +#define si_lower __si_fields.__sigfault.__first.__addr_bnd.si_lower +#define si_upper __si_fields.__sigfault.__first.__addr_bnd.si_upper +#define si_pkey __si_fields.__sigfault.__first.si_pkey +#define si_band __si_fields.__sigpoll.si_band +#define si_fd __si_fields.__sigpoll.si_fd +#define si_timerid __si_fields.__si_common.__first.__timer.si_timerid +#define si_overrun __si_fields.__si_common.__first.__timer.si_overrun +#define si_ptr si_value.sival_ptr +#define si_int si_value.sival_int +#define si_call_addr __si_fields.__sigsys.si_call_addr +#define si_syscall __si_fields.__sigsys.si_syscall +#define si_arch __si_fields.__sigsys.si_arch + +#define SIGHUP 1 +#define SIGINT 2 +#define SIGQUIT 3 +#define SIGILL 4 +#define SIGTRAP 5 +#define SIGABRT 6 +#define SIGIOT SIGABRT +#define SIGBUS 7 +#define SIGFPE 8 +#define SIGKILL 9 +#define SIGUSR1 10 +#define SIGSEGV 11 +#define SIGUSR2 12 +#define SIGPIPE 13 +#define SIGALRM 14 +#define SIGTERM 15 +#define SIGSTKFLT 16 +#define SIGCHLD 17 +#define SIGCONT 18 +#define SIGSTOP 19 +#define SIGTSTP 20 +#define SIGTTIN 21 +#define SIGTTOU 22 +#define SIGURG 23 +#define SIGXCPU 24 +#define SIGXFSZ 25 +#define SIGVTALRM 26 +#define SIGPROF 27 +#define SIGWINCH 28 +#define SIGIO 29 +#define SIGPOLL 29 +#define SIGPWR 30 +#define SIGSYS 31 +#define SIGUNUSED SIGSYS + +#define _NSIG 65 + +typedef void (*sighandler_t)(int); +#define SIG_ERR ((void (*)(int)) - 1) +#define SIG_DFL ((void (*)(int))0) +#define SIG_IGN ((void (*)(int))1) + +typedef struct __sigset_t { + unsigned long __bits[128 / sizeof(long)]; +} sigset_t; + +struct sigaction { + union { + void (*sa_handler)(int); + void (*sa_sigaction)(int, siginfo_t *, void *); + } __sa_handler; + sigset_t sa_mask; + int sa_flags; + void (*sa_restorer)(void); +}; + +#define sa_handler __sa_handler.sa_handler +#define sa_sigaction __sa_handler.sa_sigaction + +void (*signal(int, void (*)(int)))(int); +int sigaction(int, const struct sigaction *__restrict, struct sigaction *__restrict); +int sigemptyset(sigset_t *); +int raise(int); +int sigaddset(sigset_t *, int); +int pthread_sigmask(int, const sigset_t *__restrict, sigset_t *__restrict); + +int kill(pid_t, int); + +#ifdef AX_CONFIG_MULTITASK +int pthread_kill(pthread_t t, int sig); +#endif + +#endif // _SIGNAL_H diff --git a/tools/axlibc/include/stdarg.h b/tools/axlibc/include/stdarg.h new file mode 100644 index 0000000..3c23d61 --- /dev/null +++ b/tools/axlibc/include/stdarg.h @@ -0,0 +1,11 @@ +#ifndef __STDARG_H__ +#define __STDARG_H__ + +#define va_start(v, l) __builtin_va_start(v, l) +#define va_end(v) __builtin_va_end(v) +#define va_arg(v, l) __builtin_va_arg(v, l) +#define va_copy(d, s) __builtin_va_copy(d, s) + +typedef __builtin_va_list va_list; + +#endif // __STDARG_H__ diff --git a/tools/axlibc/include/stdbool.h b/tools/axlibc/include/stdbool.h new file mode 100644 index 0000000..e3325f2 --- /dev/null +++ b/tools/axlibc/include/stdbool.h @@ -0,0 +1,11 @@ +#ifndef __STDBOOL_H__ +#define __STDBOOL_H__ + +/* Represents true-or-false values */ +#ifndef __cplusplus +#define true 1 +#define false 0 +#define bool _Bool +#endif + +#endif // __STDBOOL_H__ diff --git a/tools/axlibc/include/stddef.h b/tools/axlibc/include/stddef.h new file mode 100644 index 0000000..faf08bd --- /dev/null +++ b/tools/axlibc/include/stddef.h @@ -0,0 +1,27 @@ +#ifndef __STDDEF_H__ +#define __STDDEF_H__ + +#include +#include + +/* size_t is used for memory object sizes */ +typedef uintptr_t size_t; +typedef intptr_t ssize_t; +typedef ssize_t ptrdiff_t; + +typedef long clock_t; +typedef int clockid_t; + +#ifdef __cplusplus +#define NULL 0L +#else +#define NULL ((void *)0) +#endif + +#if __GNUC__ > 3 +#define offsetof(type, member) __builtin_offsetof(type, member) +#else +#define offsetof(type, member) ((size_t)((char *)&(((type *)0)->member) - (char *)0)) +#endif + +#endif // __STDDEF_H__ diff --git a/tools/axlibc/include/stdint.h b/tools/axlibc/include/stdint.h new file mode 100644 index 0000000..3081bf0 --- /dev/null +++ b/tools/axlibc/include/stdint.h @@ -0,0 +1,66 @@ +#ifndef __STDINT_H__ +#define __STDINT_H__ + +/* Explicitly-sized versions of integer types */ +typedef char int8_t; +typedef unsigned char uint8_t; +typedef short int16_t; +typedef unsigned short uint16_t; +typedef int int32_t; +typedef unsigned int uint32_t; +typedef long long int64_t; +typedef unsigned long long uint64_t; + +typedef int64_t int_fast64_t; +typedef int64_t intmax_t; + +#define INT8_MIN (-1 - 0x7f) +#define INT16_MIN (-1 - 0x7fff) +#define INT32_MIN (-1 - 0x7fffffff) +#define INT64_MIN (-1 - 0x7fffffffffffffff) + +#define INT8_MAX (0x7f) +#define INT16_MAX (0x7fff) +#define INT32_MAX (0x7fffffff) +#define INT64_MAX (0x7fffffffffffffff) + +#define UINT8_MAX (0xff) +#define UINT16_MAX (0xffff) +#define UINT32_MAX (0xffffffffu) +#define UINT64_MAX (0xffffffffffffffffu) + +#define INTPTR_MIN INT64_MIN +#define INTPTR_MAX INT64_MAX +#define UINTPTR_MAX UINT64_MAX + +/* * + * Pointers and addresses are 32 bits long. + * We use pointer types to represent addresses, + * uintptr_t to represent the numerical values of addresses. + * */ +#if __riscv_xlen == 64 || defined(__x86_64__) || defined(__aarch64__) +typedef int64_t intptr_t; +typedef uint64_t uintptr_t; +#elif __riscv_xlen == 32 || defined(__i386__) +typedef int32_t intptr_t; +typedef uint32_t uintptr_t; +#endif + +typedef uint8_t uint_fast8_t; +typedef uint64_t uint_fast64_t; + +#if UINTPTR_MAX == UINT64_MAX +#define INT64_C(c) c##L +#define UINT64_C(c) c##UL +#define INTMAX_C(c) c##L +#define UINTMAX_C(c) c##UL +#else +#define INT64_C(c) c##LL +#define UINT64_C(c) c##ULL +#define INTMAX_C(c) c##LL +#define UINTMAX_C(c) c##ULL +#endif + +#define SIZE_MAX UINT64_MAX + +#endif // __STDINT_H__ diff --git a/tools/axlibc/include/stdio.h b/tools/axlibc/include/stdio.h new file mode 100644 index 0000000..12aca2a --- /dev/null +++ b/tools/axlibc/include/stdio.h @@ -0,0 +1,116 @@ +#ifndef __STDIO_H__ +#define __STDIO_H__ + +#include +#include + +#define _IOFBF 0 +#define _IOLBF 1 +#define _IONBF 2 + +#define FILE_BUF_SIZE 1024 +// TODO: complete this struct +struct IO_FILE { + int fd; + uint16_t buffer_len; + char buf[FILE_BUF_SIZE]; +}; + +typedef struct IO_FILE FILE; + +extern FILE *const stdin; +extern FILE *const stdout; +extern FILE *const stderr; + +#define stdin (stdin) +#define stdout (stdout) +#define stderr (stderr) + +#define EOF (-1) + +#if defined(AX_LOG_WARN) || defined(AX_LOG_INFO) || defined(AX_LOG_DEBUG) || defined(AX_LOG_TRACE) + +#define unimplemented(fmt, ...) \ + printf("\x1b[33m%s%s:\x1b[0m " fmt "\n", "WARN: no ax_call implementation for ", __func__, \ + ##__VA_ARGS__) +#else + +#define unimplemented(fmt, ...) \ + do { \ + } while (0) + +#endif + +#define SEEK_SET 0 +#define SEEK_CUR 1 +#define SEEK_END 2 + +#define F_EOF 16 +#define F_ERR 32 +#define F_SVB 64 +#define F_NORD 4 +#define UNGET 8 + +#define FILENAME_MAX 4096 +#define BUFSIZ 1024 +#define L_tmpnam 20 + +FILE *fopen(const char *filename, const char *mode); +FILE *freopen(const char *__restrict, const char *__restrict, FILE *__restrict); +int fclose(FILE *); + +int remove(const char *); +int rename(const char *, const char *); + +int feof(FILE *__stream); +int ferror(FILE *); +int fflush(FILE *); +void clearerr(FILE *); + +int fseek(FILE *__stream, long __off, int __whence); +long ftell(FILE *); + +size_t fread(void *__restrict, size_t, size_t, FILE *__restrict); +size_t fwrite(const void *__restrict, size_t, size_t, FILE *__restrict); + +int getc(FILE *); +int getchar(void); +int ungetc(int, FILE *); + +int fputc(int, FILE *); +int putc(int, FILE *); +int putchar(int); + +char *fgets(char *__restrict, int, FILE *__restrict); + +int fputs(const char *__restrict, FILE *__restrict); +int puts(const char *s); + +int printf(const char *__restrict, ...); +int fprintf(FILE *__restrict, const char *__restrict, ...); +int sprintf(char *__restrict, const char *__restrict, ...); +int snprintf(char *__restrict, size_t, const char *__restrict, ...); + +int vfprintf(FILE *__restrict, const char *__restrict, va_list); +int vsprintf(char *__restrict, const char *__restrict, va_list); +int vsnprintf(char *__restrict, size_t, const char *__restrict, va_list); + +int fscanf(FILE *__restrict, const char *__restrict, ...); +int sscanf(const char *__restrict, const char *__restrict, ...); + +void perror(const char *); + +int setvbuf(FILE *__restrict, char *__restrict, int, size_t); + +char *tmpnam(char *); +FILE *tmpfile(void); + +FILE *fdopen(int, const char *); +int fileno(FILE *); +off_t ftello(FILE *); + +int getc_unlocked(FILE *); +ssize_t getdelim(char **__restrict, size_t *__restrict, int, FILE *__restrict); +ssize_t getline(char **__restrict, size_t *__restrict, FILE *__restrict); + +#endif // __STDIO_H__ diff --git a/tools/axlibc/include/stdlib.h b/tools/axlibc/include/stdlib.h new file mode 100644 index 0000000..411ea48 --- /dev/null +++ b/tools/axlibc/include/stdlib.h @@ -0,0 +1,60 @@ +#ifndef __STDLIB_H__ +#define __STDLIB_H__ + +#include +#include + +#define RAND_MAX (0x7fffffff) + +#define WEXITSTATUS(s) (((s)&0xff00) >> 8) +#define WTERMSIG(s) ((s)&0x7f) +#define WIFEXITED(s) (!WTERMSIG(s)) +#define WIFSIGNALED(s) (((s)&0xffff) - 1U < 0xffu) + +#define EXIT_FAILURE 1 +#define EXIT_SUCCESS 0 + +long long atoll(const char *nptr); + +float strtof(const char *__restrict, char **__restrict); +double strtod(const char *__restrict, char **__restrict); + +long strtol(const char *__restrict, char **__restrict, int); +unsigned long strtoul(const char *nptr, char **endptr, int base); +long long strtoll(const char *nptr, char **endptr, int base); +unsigned long long strtoull(const char *nptr, char **endptr, int base); + +int rand(void); +void srand(unsigned); +long random(void); +void srandom(unsigned int); + +#ifdef AX_CONFIG_FP_SIMD +float strtof(const char *__restrict, char **__restrict); +double strtod(const char *__restrict, char **__restrict); +long double strtold(const char *__restrict, char **__restrict); +#endif + +void qsort(void *, size_t, size_t, int (*)(const void *, const void *)); + +void *malloc(size_t); +void *calloc(size_t, size_t); +void *realloc(void *, size_t); +void free(void *); + +_Noreturn void abort(void); +_Noreturn void exit(int); + +char *getenv(const char *); + +int abs(int); +long labs(long); +long long llabs(long long); + +int mkstemp(char *); +int mkostemp(char *, int); +int setenv(const char *, const char *, int); +int unsetenv(const char *); +int system(const char *); + +#endif //__STDLIB_H__ diff --git a/tools/axlibc/include/string.h b/tools/axlibc/include/string.h new file mode 100644 index 0000000..3160af4 --- /dev/null +++ b/tools/axlibc/include/string.h @@ -0,0 +1,50 @@ +#ifndef __STRING_H__ +#define __STRING_H__ + +#include + +int atoi(const char *s); + +void *memset(void *dest, int c, size_t n); +void *memchr(const void *src, int c, size_t n); + +size_t strlen(const char *s); +size_t strnlen(const char *s, size_t n); + +char *strcpy(char *restrict d, const char *restrict s); +char *strncpy(char *restrict d, const char *restrict s, size_t n); + +char *strcat(char *restrict d, const char *restrict s); +char *strncat(char *restrict d, const char *restrict s, size_t n); + +int strcmp(const char *l, const char *r); +int strncmp(const char *l, const char *r, size_t n); + +int strcoll(const char *, const char *); + +size_t strcspn(const char *s1, const char *s2); +size_t strspn(const char *s, const char *c); +char *strpbrk(const char *, const char *); + +char *strchrnul(const char *, int); + +char *strrchr(const char *str, int c); +char *strchr(const char *str, int c); + +int strcasecmp(const char *__s1, const char *__s2); +int strncasecmp(const char *__s1, const char *__s2, size_t __n); + +char *strstr(const char *h, const char *n); + +char *strerror(int e); +int strerror_r(int, char *, size_t); + +void *memcpy(void *restrict dest, const void *restrict src, size_t n); + +void *memmove(void *dest, const void *src, size_t n); + +int memcmp(const void *vl, const void *vr, size_t n); + +char *strdup(const char *__s); + +#endif // __STRING_H__ diff --git a/tools/axlibc/include/strings.h b/tools/axlibc/include/strings.h new file mode 100644 index 0000000..3616bae --- /dev/null +++ b/tools/axlibc/include/strings.h @@ -0,0 +1,4 @@ +#ifndef __STRINGS_H__ +#define __STRINGS_H__ + +#endif // __STRINGS_H__ diff --git a/tools/axlibc/include/sys/epoll.h b/tools/axlibc/include/sys/epoll.h new file mode 100644 index 0000000..bd23bcf --- /dev/null +++ b/tools/axlibc/include/sys/epoll.h @@ -0,0 +1,60 @@ +#ifndef _SYS_EPOLL_H +#define _SYS_EPOLL_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +#define EPOLL_CLOEXEC O_CLOEXEC +#define EPOLL_NONBLOCK O_NONBLOCK + +enum EPOLL_EVENTS { __EPOLL_DUMMY }; +#define EPOLLIN 0x001 +#define EPOLLPRI 0x002 +#define EPOLLOUT 0x004 +#define EPOLLRDNORM 0x040 +#define EPOLLNVAL 0x020 +#define EPOLLRDBAND 0x080 +#define EPOLLWRNORM 0x100 +#define EPOLLWRBAND 0x200 +#define EPOLLMSG 0x400 +#define EPOLLERR 0x008 +#define EPOLLHUP 0x010 +#define EPOLLRDHUP 0x2000 +#define EPOLLEXCLUSIVE (1U << 28) +#define EPOLLWAKEUP (1U << 29) +#define EPOLLONESHOT (1U << 30) +#define EPOLLET (1U << 31) + +#define EPOLL_CTL_ADD 1 +#define EPOLL_CTL_DEL 2 +#define EPOLL_CTL_MOD 3 + +typedef union epoll_data { + void *ptr; + int fd; + uint32_t u32; + uint64_t u64; +} epoll_data_t; + +struct epoll_event { + uint32_t events; + epoll_data_t data; +} +#ifdef __x86_64__ +__attribute__((__packed__)) +#endif +; + +int epoll_create(int __size); +int epoll_ctl(int, int, int, struct epoll_event *); +int epoll_wait(int, struct epoll_event *, int, int); + +#ifdef __cplusplus +} +#endif + +#endif //_SYS_EPOLL_H diff --git a/tools/axlibc/include/sys/file.h b/tools/axlibc/include/sys/file.h new file mode 100644 index 0000000..d5e15a6 --- /dev/null +++ b/tools/axlibc/include/sys/file.h @@ -0,0 +1,23 @@ +#ifndef _SYS_FILE_H +#define _SYS_FILE_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define LOCK_SH 1 +#define LOCK_EX 2 +#define LOCK_NB 4 +#define LOCK_UN 8 + +#define L_SET 0 +#define L_INCR 1 +#define L_XTND 2 + +int flock(int, int); + +#ifdef __cplusplus +} +#endif + +#endif // _SYS_FILE_H diff --git a/tools/axlibc/include/sys/ioctl.h b/tools/axlibc/include/sys/ioctl.h new file mode 100644 index 0000000..e43c510 --- /dev/null +++ b/tools/axlibc/include/sys/ioctl.h @@ -0,0 +1,65 @@ +#ifndef __SYS_IOCTL_H__ +#define __SYS_IOCTL_H__ + +#define TCGETS 0x5401 +#define TCSETS 0x5402 +#define TCSETSW 0x5403 +#define TCSETSF 0x5404 +#define TCGETA 0x5405 +#define TCSETA 0x5406 +#define TCSETAW 0x5407 +#define TCSETAF 0x5408 +#define TCSBRK 0x5409 +#define TCXONC 0x540A +#define TCFLSH 0x540B +#define TIOCEXCL 0x540C +#define TIOCNXCL 0x540D +#define TIOCSCTTY 0x540E +#define TIOCGPGRP 0x540F +#define TIOCSPGRP 0x5410 +#define TIOCOUTQ 0x5411 +#define TIOCSTI 0x5412 +#define TIOCGWINSZ 0x5413 +#define TIOCSWINSZ 0x5414 +#define TIOCMGET 0x5415 +#define TIOCMBIS 0x5416 +#define TIOCMBIC 0x5417 +#define TIOCMSET 0x5418 +#define TIOCGSOFTCAR 0x5419 +#define TIOCSSOFTCAR 0x541A +#define FIONREAD 0x541B +#define TIOCINQ FIONREAD +#define TIOCLINUX 0x541C +#define TIOCCONS 0x541D +#define TIOCGSERIAL 0x541E +#define TIOCSSERIAL 0x541F +#define TIOCPKT 0x5420 +#define FIONBIO 0x5421 +#define TIOCNOTTY 0x5422 +#define TIOCSETD 0x5423 +#define TIOCGETD 0x5424 +#define TCSBRKP 0x5425 +#define TIOCSBRK 0x5427 +#define TIOCCBRK 0x5428 +#define TIOCGSID 0x5429 +#define TIOCGRS485 0x542E +#define TIOCSRS485 0x542F +#define TIOCGPTN 0x80045430 +#define TIOCSPTLCK 0x40045431 +#define TIOCGDEV 0x80045432 +#define TCGETX 0x5432 +#define TCSETX 0x5433 +#define TCSETXF 0x5434 +#define TCSETXW 0x5435 +#define TIOCSIG 0x40045436 +#define TIOCVHANGUP 0x5437 +#define TIOCGPKT 0x80045438 +#define TIOCGPTLCK 0x80045439 +#define TIOCGEXCL 0x80045440 +#define TIOCGPTPEER 0x5441 +#define TIOCGISO7816 0x80285442 +#define TIOCSISO7816 0xc0285443 + +int ioctl(int, int, ...); + +#endif // __SYS_IOCTL_H__ diff --git a/tools/axlibc/include/sys/mman.h b/tools/axlibc/include/sys/mman.h new file mode 100644 index 0000000..3d35023 --- /dev/null +++ b/tools/axlibc/include/sys/mman.h @@ -0,0 +1,52 @@ +#ifndef __SYS_MMAN_H__ +#define __SYS_MMAN_H__ + +#include + +#define PROT_READ 0x1 /* Page can be read. */ +#define PROT_WRITE 0x2 /* Page can be written. */ +#define PROT_EXEC 0x4 /* Page can be executed. */ +#define PROT_NONE 0x0 /* Page can not be accessed. */ +#define PROT_GROWSDOWN \ + 0x01000000 /* Extend change to start of \ + growsdown vma (mprotect only). */ +#define PROT_GROWSUP \ + 0x02000000 /* Extend change to start of \ + growsup vma (mprotect only). */ + +/* Sharing types (must choose one and only one of these). */ +#define MAP_SHARED 0x01 /* Share changes. */ +#define MAP_PRIVATE 0x02 /* Changes are private. */ +#define MAP_SHARED_VALIDATE \ + 0x03 /* Share changes and validate \ + extension flags. */ +#define MAP_TYPE 0x0f /* Mask for type of mapping. */ + +/* Other flags. */ +#define MAP_FIXED 0x10 /* Interpret addr exactly. */ +#define MAP_FILE 0 +#ifdef __MAP_ANONYMOUS +#define MAP_ANONYMOUS __MAP_ANONYMOUS /* Don't use a file. */ +#else +#define MAP_ANONYMOUS 0x20 /* Don't use a file. */ +#endif +#define MAP_ANON MAP_ANONYMOUS +/* When MAP_HUGETLB is set bits [26:31] encode the log2 of the huge page size. */ +#define MAP_HUGE_SHIFT 26 +#define MAP_HUGE_MASK 0x3f + +#define MAP_FAILED ((void *)-1) + +/* Flags for mremap. */ +#define MREMAP_MAYMOVE 1 +#define MREMAP_FIXED 2 +#define MREMAP_DONTUNMAP 4 + +void *mmap(void *addr, size_t len, int prot, int flags, int fildes, off_t off); +int munmap(void *addr, size_t length); +void *mremap(void *old_address, size_t old_size, size_t new_size, int flags, + ... /* void *new_address */); +int mprotect(void *addr, size_t len, int prot); +int madvise(void *addr, size_t length, int advice); + +#endif diff --git a/tools/axlibc/include/sys/param.h b/tools/axlibc/include/sys/param.h new file mode 100644 index 0000000..bbb762f --- /dev/null +++ b/tools/axlibc/include/sys/param.h @@ -0,0 +1,6 @@ +#ifndef _SYS_PARAM_H +#define _SYS_PARAM_H + +#define MAXPATHLEN 4096 + +#endif // _SYS_PARAM_H diff --git a/tools/axlibc/include/sys/prctl.h b/tools/axlibc/include/sys/prctl.h new file mode 100644 index 0000000..1ed9cc1 --- /dev/null +++ b/tools/axlibc/include/sys/prctl.h @@ -0,0 +1,4 @@ +#ifndef _SYS_PRCTL_H +#define _SYS_PRCTL_H + +#endif // _SYS_PRCTL_H diff --git a/tools/axlibc/include/sys/resource.h b/tools/axlibc/include/sys/resource.h new file mode 100644 index 0000000..99c8bbc --- /dev/null +++ b/tools/axlibc/include/sys/resource.h @@ -0,0 +1,63 @@ +#ifndef _SYS_RESOURCE_H +#define _SYS_RESOURCE_H + +#include + +typedef unsigned long long rlim_t; + +struct rlimit { + rlim_t rlim_cur; + rlim_t rlim_max; +}; + +#define RLIMIT_CPU 0 +#define RLIMIT_FSIZE 1 +#define RLIMIT_DATA 2 +#define RLIMIT_STACK 3 +#define RLIMIT_CORE 4 +#ifndef RLIMIT_RSS +#define RLIMIT_RSS 5 +#define RLIMIT_NPROC 6 +#define RLIMIT_NOFILE 7 +#define RLIMIT_MEMLOCK 8 +#define RLIMIT_AS 9 +#endif +#define RLIMIT_LOCKS 10 +#define RLIMIT_SIGPENDING 11 +#define RLIMIT_MSGQUEUE 12 +#define RLIMIT_NICE 13 +#define RLIMIT_RTPRIO 14 +#define RLIMIT_RTTIME 15 +#define RLIMIT_NLIMITS 16 + +#define RUSAGE_SELF 0 +#define RUSAGE_CHILDREN -1 + +struct rusage { + struct timeval ru_utime; + struct timeval ru_stime; + /* linux extentions, but useful */ + 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; + /* room for more... */ + long __reserved[16]; +}; + +int setrlimit(int __resource, struct rlimit *__rlimits); +int getrlimit(int __resource, struct rlimit *__rlimits); + +int getrusage(int __who, struct rusage *__usage); + +#endif diff --git a/tools/axlibc/include/sys/select.h b/tools/axlibc/include/sys/select.h new file mode 100644 index 0000000..e8cc2c5 --- /dev/null +++ b/tools/axlibc/include/sys/select.h @@ -0,0 +1,36 @@ +#ifndef _SYS_SELECT_H +#define _SYS_SELECT_H + +#include +#include +#include + +#define FD_SETSIZE 1024 + +typedef unsigned long fd_mask; + +typedef struct { + unsigned long fds_bits[FD_SETSIZE / 8 / sizeof(long)]; +} fd_set; + +#define FD_ZERO(s) \ + do { \ + int __i; \ + unsigned long *__b = (s)->fds_bits; \ + for (__i = sizeof(fd_set) / sizeof(long); __i; __i--) *__b++ = 0; \ + } while (0) +#define FD_SET(d, s) \ + ((s)->fds_bits[(d) / (8 * sizeof(long))] |= (1UL << ((d) % (8 * sizeof(long))))) +#define FD_CLR(d, s) \ + ((s)->fds_bits[(d) / (8 * sizeof(long))] &= ~(1UL << ((d) % (8 * sizeof(long))))) +#define FD_ISSET(d, s) \ + !!((s)->fds_bits[(d) / (8 * sizeof(long))] & (1UL << ((d) % (8 * sizeof(long))))) + +int select(int n, fd_set *__restrict rfds, fd_set *__restrict wfds, fd_set *__restrict efds, + struct timeval *__restrict tv); +int pselect(int, fd_set *__restrict, fd_set *__restrict, fd_set *__restrict, + const struct timespec *__restrict, const sigset_t *__restrict); + +#define NFDBITS (8 * (int)sizeof(long)) + +#endif diff --git a/tools/axlibc/include/sys/socket.h b/tools/axlibc/include/sys/socket.h new file mode 100644 index 0000000..c89c5f1 --- /dev/null +++ b/tools/axlibc/include/sys/socket.h @@ -0,0 +1,310 @@ +#ifndef __SOCKET_H__ +#define __SOCKET_H__ + +#include +#include +#include + +typedef unsigned socklen_t; +typedef unsigned short sa_family_t; + +struct msghdr { + void *msg_name; + socklen_t msg_namelen; + struct iovec *msg_iov; +#if __LONG_MAX > 0x7fffffff && __BYTE_ORDER == __BIG_ENDIAN + int __pad1; +#endif + int msg_iovlen; +#if __LONG_MAX > 0x7fffffff && __BYTE_ORDER == __LITTLE_ENDIAN + int __pad1; +#endif + void *msg_control; +#if __LONG_MAX > 0x7fffffff && __BYTE_ORDER == __BIG_ENDIAN + int __pad2; +#endif + socklen_t msg_controllen; +#if __LONG_MAX > 0x7fffffff && __BYTE_ORDER == __LITTLE_ENDIAN + int __pad2; +#endif + int msg_flags; +}; + +struct cmsghdr { +#if __LONG_MAX > 0x7fffffff && __BYTE_ORDER == __BIG_ENDIAN + int __pad1; +#endif + socklen_t cmsg_len; +#if __LONG_MAX > 0x7fffffff && __BYTE_ORDER == __LITTLE_ENDIAN + int __pad1; +#endif + int cmsg_level; + int cmsg_type; +}; + +struct sockaddr { + sa_family_t sa_family; + char sa_data[14]; +}; + +struct sockaddr_storage { + sa_family_t ss_family; + char __ss_padding[128 - sizeof(long) - sizeof(sa_family_t)]; + unsigned long __ss_align; +}; + +int socket(int, int, int); +int shutdown(int, int); + +int bind(int, const struct sockaddr *, socklen_t); +int connect(int, const struct sockaddr *, socklen_t); +int listen(int, int); +int accept(int, struct sockaddr *__restrict, socklen_t *__restrict); +int accept4(int, struct sockaddr *__restrict, socklen_t *__restrict, int); + +ssize_t send(int, const void *, size_t, int); +ssize_t recv(int, void *, size_t, int); +ssize_t sendto(int, const void *, size_t, int, const struct sockaddr *, socklen_t); +ssize_t recvfrom(int, void *__restrict, size_t, int, struct sockaddr *__restrict, + socklen_t *__restrict); +ssize_t sendmsg(int, const struct msghdr *, int); + +int getsockopt(int, int, int, void *__restrict, socklen_t *__restrict); +int setsockopt(int, int, int, const void *, socklen_t); + +int getsockname(int sockfd, struct sockaddr *restrict addr, socklen_t *restrict addrlen); +int getpeername(int sockfd, struct sockaddr *restrict addr, socklen_t *restrict addrlen); + +#define SO_BINDTODEVICE 25 +#define SO_ATTACH_FILTER 26 +#define SO_DETACH_FILTER 27 +#define SO_GET_FILTER SO_ATTACH_FILTER +#define SO_PEERNAME 28 +#define SO_ACCEPTCONN 30 +#define SO_PEERSEC 31 +#define SO_PASSSEC 34 +#define SO_MARK 36 +#define SO_RXQ_OVFL 40 +#define SO_WIFI_STATUS 41 +#define SCM_WIFI_STATUS SO_WIFI_STATUS +#define SO_PEEK_OFF 42 +#define SO_NOFCS 43 +#define SO_LOCK_FILTER 44 +#define SO_SELECT_ERR_QUEUE 45 +#define SO_BUSY_POLL 46 +#define SO_MAX_PACING_RATE 47 +#define SO_BPF_EXTENSIONS 48 +#define SO_INCOMING_CPU 49 +#define SO_ATTACH_BPF 50 +#define SO_DETACH_BPF SO_DETACH_FILTER +#define SO_ATTACH_REUSEPORT_CBPF 51 +#define SO_ATTACH_REUSEPORT_EBPF 52 +#define SO_CNX_ADVICE 53 +#define SCM_TIMESTAMPING_OPT_STATS 54 +#define SO_MEMINFO 55 +#define SO_INCOMING_NAPI_ID 56 +#define SO_COOKIE 57 +#define SCM_TIMESTAMPING_PKTINFO 58 +#define SO_PEERGROUPS 59 +#define SO_ZEROCOPY 60 +#define SO_TXTIME 61 +#define SCM_TXTIME SO_TXTIME +#define SO_BINDTOIFINDEX 62 +#define SO_DETACH_REUSEPORT_BPF 68 +#define SO_PREFER_BUSY_POLL 69 +#define SO_BUSY_POLL_BUDGET 70 + +#define MSG_NOSIGNAL 0x4000 + +#define SHUT_RD 0 +#define SHUT_WR 1 +#define SHUT_RDWR 2 + +#ifndef SOCK_STREAM +#define SOCK_STREAM 1 +#define SOCK_DGRAM 2 +#endif + +#define SOCK_RAW 3 +#define SOCK_RDM 4 +#define SOCK_SEQPACKET 5 +#define SOCK_DCCP 6 +#define SOCK_PACKET 10 + +#ifndef SOCK_CLOEXEC +#define SOCK_CLOEXEC 02000000 +#define SOCK_NONBLOCK 04000 +#endif + +#define PF_UNSPEC 0 +#define PF_LOCAL 1 +#define PF_UNIX PF_LOCAL +#define PF_FILE PF_LOCAL +#define PF_INET 2 +#define PF_AX25 3 +#define PF_IPX 4 +#define PF_APPLETALK 5 +#define PF_NETROM 6 +#define PF_BRIDGE 7 +#define PF_ATMPVC 8 +#define PF_X25 9 +#define PF_INET6 10 +#define PF_ROSE 11 +#define PF_DECnet 12 +#define PF_NETBEUI 13 +#define PF_SECURITY 14 +#define PF_KEY 15 +#define PF_NETLINK 16 +#define PF_ROUTE PF_NETLINK +#define PF_PACKET 17 +#define PF_ASH 18 +#define PF_ECONET 19 +#define PF_ATMSVC 20 +#define PF_RDS 21 +#define PF_SNA 22 +#define PF_IRDA 23 +#define PF_PPPOX 24 +#define PF_WANPIPE 25 +#define PF_LLC 26 +#define PF_IB 27 +#define PF_MPLS 28 +#define PF_CAN 29 +#define PF_TIPC 30 +#define PF_BLUETOOTH 31 +#define PF_IUCV 32 +#define PF_RXRPC 33 +#define PF_ISDN 34 +#define PF_PHONET 35 +#define PF_IEEE802154 36 +#define PF_CAIF 37 +#define PF_ALG 38 +#define PF_NFC 39 +#define PF_VSOCK 40 +#define PF_KCM 41 +#define PF_QIPCRTR 42 +#define PF_SMC 43 +#define PF_XDP 44 +#define PF_MAX 45 + +#define AF_UNSPEC PF_UNSPEC +#define AF_LOCAL PF_LOCAL +#define AF_UNIX AF_LOCAL +#define AF_FILE AF_LOCAL +#define AF_INET PF_INET +#define AF_AX25 PF_AX25 +#define AF_IPX PF_IPX +#define AF_APPLETALK PF_APPLETALK +#define AF_NETROM PF_NETROM +#define AF_BRIDGE PF_BRIDGE +#define AF_ATMPVC PF_ATMPVC +#define AF_X25 PF_X25 +#define AF_INET6 PF_INET6 +#define AF_ROSE PF_ROSE +#define AF_DECnet PF_DECnet +#define AF_NETBEUI PF_NETBEUI +#define AF_SECURITY PF_SECURITY +#define AF_KEY PF_KEY +#define AF_NETLINK PF_NETLINK +#define AF_ROUTE PF_ROUTE +#define AF_PACKET PF_PACKET +#define AF_ASH PF_ASH +#define AF_ECONET PF_ECONET +#define AF_ATMSVC PF_ATMSVC +#define AF_RDS PF_RDS +#define AF_SNA PF_SNA +#define AF_IRDA PF_IRDA +#define AF_PPPOX PF_PPPOX +#define AF_WANPIPE PF_WANPIPE +#define AF_LLC PF_LLC +#define AF_IB PF_IB +#define AF_MPLS PF_MPLS +#define AF_CAN PF_CAN +#define AF_TIPC PF_TIPC +#define AF_BLUETOOTH PF_BLUETOOTH +#define AF_IUCV PF_IUCV +#define AF_RXRPC PF_RXRPC +#define AF_ISDN PF_ISDN +#define AF_PHONET PF_PHONET +#define AF_IEEE802154 PF_IEEE802154 +#define AF_CAIF PF_CAIF +#define AF_ALG PF_ALG +#define AF_NFC PF_NFC +#define AF_VSOCK PF_VSOCK +#define AF_KCM PF_KCM +#define AF_QIPCRTR PF_QIPCRTR +#define AF_SMC PF_SMC +#define AF_XDP PF_XDP +#define AF_MAX PF_MAX + +#define SO_DEBUG 1 +#define SO_REUSEADDR 2 +#define SO_TYPE 3 +#define SO_ERROR 4 +#define SO_DONTROUTE 5 +#define SO_BROADCAST 6 +#define SO_SNDBUF 7 +#define SO_RCVBUF 8 +#define SO_KEEPALIVE 9 +#define SO_OOBINLINE 10 +#define SO_NO_CHECK 11 +#define SO_PRIORITY 12 +#define SO_LINGER 13 +#define SO_BSDCOMPAT 14 +#define SO_REUSEPORT 15 +#define SO_PASSCRED 16 +#define SO_PEERCRED 17 +#define SO_RCVLOWAT 18 +#define SO_SNDLOWAT 19 +#define SO_ACCEPTCONN 30 +#define SO_PEERSEC 31 +#define SO_SNDBUFFORCE 32 +#define SO_RCVBUFFORCE 33 +#define SO_PROTOCOL 38 +#define SO_DOMAIN 39 + +#define SO_SECURITY_AUTHENTICATION 22 +#define SO_SECURITY_ENCRYPTION_TRANSPORT 23 +#define SO_SECURITY_ENCRYPTION_NETWORK 24 + +#define SOL_SOCKET 1 + +#define SOL_IP 0 +#define SOL_IPV6 41 +#define SOL_ICMPV6 58 + +#define SOL_RAW 255 +#define SOL_DECNET 261 +#define SOL_X25 262 +#define SOL_PACKET 263 +#define SOL_ATM 264 +#define SOL_AAL 265 +#define SOL_IRDA 266 +#define SOL_NETBEUI 267 +#define SOL_LLC 268 +#define SOL_DCCP 269 +#define SOL_NETLINK 270 +#define SOL_TIPC 271 +#define SOL_RXRPC 272 +#define SOL_PPPOL2TP 273 +#define SOL_BLUETOOTH 274 +#define SOL_PNPIPE 275 +#define SOL_RDS 276 +#define SOL_IUCV 277 +#define SOL_CAIF 278 +#define SOL_ALG 279 +#define SOL_NFC 280 +#define SOL_KCM 281 +#define SOL_TLS 282 +#define SOL_XDP 283 + +#ifndef SO_RCVTIMEO_OLD +#define SO_RCVTIMEO_OLD 20 +#endif +#ifndef SO_SNDTIMEO_OLD +#define SO_SNDTIMEO_OLD 21 +#endif + +#define SO_RCVTIMEO SO_RCVTIMEO_OLD +#define SO_SNDTIMEO SO_SNDTIMEO_OLD + +#endif // __SOCKET_H__ diff --git a/tools/axlibc/include/sys/stat.h b/tools/axlibc/include/sys/stat.h new file mode 100644 index 0000000..24806af --- /dev/null +++ b/tools/axlibc/include/sys/stat.h @@ -0,0 +1,78 @@ +#ifndef __SYS_STAT_H__ +#define __SYS_STAT_H__ + +#include +#include + +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 filesystem I/O*/ + blkcnt_t st_blocks; /* number of blocks allocated*/ + struct timespec st_atime; /* time of last access*/ + struct timespec st_mtime; /* time of last modification*/ + struct timespec st_ctime; /* time of last status change*/ +}; + +#define st_atime st_atim.tv_sec +#define st_mtime st_mtim.tv_sec +#define st_ctime st_ctim.tv_sec + +#define S_IFMT 0170000 + +#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_TYPEISMQ(buf) 0 +#define S_TYPEISSEM(buf) 0 +#define S_TYPEISSHM(buf) 0 +#define S_TYPEISTMO(buf) 0 + +#define S_ISDIR(mode) (((mode)&S_IFMT) == S_IFDIR) +#define S_ISCHR(mode) (((mode)&S_IFMT) == S_IFCHR) +#define S_ISBLK(mode) (((mode)&S_IFMT) == S_IFBLK) +#define S_ISREG(mode) (((mode)&S_IFMT) == S_IFREG) +#define S_ISFIFO(mode) (((mode)&S_IFMT) == S_IFIFO) +#define S_ISLNK(mode) (((mode)&S_IFMT) == S_IFLNK) +#define S_ISSOCK(mode) (((mode)&S_IFMT) == S_IFSOCK) + +#ifndef S_IRUSR +#define S_ISUID 04000 +#define S_ISGID 02000 +#define S_ISVTX 01000 +#define S_IRUSR 0400 +#define S_IWUSR 0200 +#define S_IXUSR 0100 +#define S_IRWXU 0700 +#define S_IRGRP 0040 +#define S_IWGRP 0020 +#define S_IXGRP 0010 +#define S_IRWXG 0070 +#define S_IROTH 0004 +#define S_IWOTH 0002 +#define S_IXOTH 0001 +#define S_IRWXO 0007 +#endif + +int stat(const char *path, struct stat *buf); +int fstat(int fd, struct stat *buf); +int lstat(const char *path, struct stat *buf); + +int fchmod(int fd, mode_t mode); +int chmod(const char *file, mode_t mode); +int mkdir(const char *pathname, mode_t mode); +mode_t umask(mode_t mask); +int fstatat(int, const char *__restrict, struct stat *__restrict, int); + +#endif diff --git a/tools/axlibc/include/sys/time.h b/tools/axlibc/include/sys/time.h new file mode 100644 index 0000000..5eeaf4c --- /dev/null +++ b/tools/axlibc/include/sys/time.h @@ -0,0 +1,41 @@ +#ifndef __SYS_TIME_H__ +#define __SYS_TIME_H__ + +#include + +#define ITIMER_REAL 0 +#define ITIMER_VIRTUAL 1 +#define ITIMER_PROF 2 + +extern long timezone; +typedef long long time_t; + +struct timeval { + time_t tv_sec; /* seconds */ + long tv_usec; /* microseconds */ +}; + +struct timespec { + time_t tv_sec; /* seconds */ + long tv_nsec; /* nanoseconds */ +}; + +typedef struct timespec timespec; + +struct timezone { + int tz_minuteswest; /* (minutes west of Greenwich) */ + int tz_dsttime; /* (type of DST correction) */ +}; + +struct itimerval { + struct timeval it_interval; + struct timeval it_value; +}; + +int gettimeofday(struct timeval *tv, struct timezone *tz); + +int getitimer(int, struct itimerval *); +int setitimer(int, const struct itimerval *__restrict, struct itimerval *__restrict); +int utimes(const char *filename, const struct timeval times[2]); + +#endif diff --git a/tools/axlibc/include/sys/types.h b/tools/axlibc/include/sys/types.h new file mode 100644 index 0000000..adb6c35 --- /dev/null +++ b/tools/axlibc/include/sys/types.h @@ -0,0 +1,20 @@ +#ifndef __SYS_TYPES_H__ +#define __SYS_TYPES_H__ + +#include + +typedef unsigned char u_char; + +typedef unsigned mode_t; +typedef uint32_t nlink_t; +typedef int64_t off_t; +typedef uint64_t ino_t; +typedef uint64_t dev_t; +typedef long blksize_t; +typedef int64_t blkcnt_t; + +typedef int pid_t; +typedef unsigned uid_t; +typedef unsigned gid_t; + +#endif // __SYS_TYPES_H__ diff --git a/tools/axlibc/include/sys/uio.h b/tools/axlibc/include/sys/uio.h new file mode 100644 index 0000000..d38b197 --- /dev/null +++ b/tools/axlibc/include/sys/uio.h @@ -0,0 +1,13 @@ +#ifndef _SYS_UIO_H +#define _SYS_UIO_H + +#include + +struct iovec { + void *iov_base; /* Pointer to data. */ + size_t iov_len; /* Length of data. */ +}; + +ssize_t writev(int, const struct iovec *, int); + +#endif diff --git a/tools/axlibc/include/sys/un.h b/tools/axlibc/include/sys/un.h new file mode 100644 index 0000000..85e43ea --- /dev/null +++ b/tools/axlibc/include/sys/un.h @@ -0,0 +1,11 @@ +#ifndef _SYS_UN_H +#define _SYS_UN_H + +#include + +struct sockaddr_un { + sa_family_t sun_family; + char sun_path[108]; +}; + +#endif // _SYS_UN_H diff --git a/tools/axlibc/include/sys/utsname.h b/tools/axlibc/include/sys/utsname.h new file mode 100644 index 0000000..fa708a1 --- /dev/null +++ b/tools/axlibc/include/sys/utsname.h @@ -0,0 +1,27 @@ +#ifndef _SYS_UTSNAME_H +#define _SYS_UTSNAME_H + +#ifdef __cplusplus +extern "C" { +#endif + +struct utsname { + char sysname[65]; + char nodename[65]; + char release[65]; + char version[65]; + char machine[65]; +#ifdef _GNU_SOURCE + char domainname[65]; +#else + char __domainname[65]; +#endif +}; + +int uname(struct utsname *); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/tools/axlibc/include/sys/wait.h b/tools/axlibc/include/sys/wait.h new file mode 100644 index 0000000..f5e3887 --- /dev/null +++ b/tools/axlibc/include/sys/wait.h @@ -0,0 +1,12 @@ +#ifndef _SYS_WAIT_H +#define _SYS_WAIT_H + +#include +#include + +#define WNOHANG 1 + +pid_t waitpid(pid_t pid, int *status, int options); +pid_t wait3(int *, int, struct rusage *); + +#endif diff --git a/tools/axlibc/include/syslog.h b/tools/axlibc/include/syslog.h new file mode 100644 index 0000000..f98d663 --- /dev/null +++ b/tools/axlibc/include/syslog.h @@ -0,0 +1,45 @@ +#ifndef _SYSLOG_H +#define _SYSLOG_H + +#define LOG_EMERG 0 +#define LOG_ALERT 1 +#define LOG_CRIT 2 +#define LOG_ERR 3 +#define LOG_WARNING 4 +#define LOG_NOTICE 5 +#define LOG_INFO 6 +#define LOG_DEBUG 7 + +#define LOG_PID 0x01 +#define LOG_CONS 0x02 +#define LOG_ODELAY 0x04 +#define LOG_NDELAY 0x08 +#define LOG_NOWAIT 0x10 +#define LOG_PERROR 0x20 + +#define LOG_KERN (0 << 3) +#define LOG_USER (1 << 3) +#define LOG_MAIL (2 << 3) +#define LOG_DAEMON (3 << 3) +#define LOG_AUTH (4 << 3) +#define LOG_SYSLOG (5 << 3) +#define LOG_LPR (6 << 3) +#define LOG_NEWS (7 << 3) +#define LOG_UUCP (8 << 3) +#define LOG_CRON (9 << 3) +#define LOG_AUTHPRIV (10 << 3) +#define LOG_FTP (11 << 3) + +#define LOG_LOCAL0 (16 << 3) +#define LOG_LOCAL1 (17 << 3) +#define LOG_LOCAL2 (18 << 3) +#define LOG_LOCAL3 (19 << 3) +#define LOG_LOCAL4 (20 << 3) +#define LOG_LOCAL5 (21 << 3) +#define LOG_LOCAL6 (22 << 3) +#define LOG_LOCAL7 (23 << 3) + +void syslog(int, const char *, ...); +void openlog(const char *, int, int); + +#endif diff --git a/tools/axlibc/include/termios.h b/tools/axlibc/include/termios.h new file mode 100644 index 0000000..d319c5b --- /dev/null +++ b/tools/axlibc/include/termios.h @@ -0,0 +1,8 @@ +#ifndef _TERMIOS_H +#define _TERMIOS_H + +struct winsize { + unsigned short ws_row, ws_col, ws_xpixel, ws_ypixel; +}; + +#endif // _TERMIOS_H diff --git a/tools/axlibc/include/time.h b/tools/axlibc/include/time.h new file mode 100644 index 0000000..356edf9 --- /dev/null +++ b/tools/axlibc/include/time.h @@ -0,0 +1,43 @@ +#ifndef __TIME_H__ +#define __TIME_H__ + +#include +#include + +#define CLOCK_REALTIME 0 +#define CLOCK_MONOTONIC 1 +#define CLOCKS_PER_SEC 1000000L + +struct tm { + int tm_sec; /* seconds of minute */ + int tm_min; /* minutes of hour */ + int tm_hour; /* hours of day */ + int tm_mday; /* day of month */ + int tm_mon; /* month of year, 0 is first month(January) */ + int tm_year; /* years, whose value equals the actual year minus 1900 */ + int tm_wday; /* day of week, 0 is sunday, 1 is monday, and so on */ + int tm_yday; /* day of year */ + int tm_isdst; /* daylight saving time flag */ + long int __tm_gmtoff; + const char *__tm_zone; +}; + +clock_t clock(void); +time_t time(time_t *); +double difftime(time_t, time_t); +time_t mktime(struct tm *); +size_t strftime(char *__restrict, size_t, const char *__restrict, const struct tm *__restrict); +struct tm *gmtime(const time_t *); +struct tm *localtime(const time_t *); + +struct tm *gmtime_r(const time_t *__restrict, struct tm *__restrict); +struct tm *localtime_r(const time_t *__restrict, struct tm *__restrict); +char *asctime_r(const struct tm *__restrict, char *__restrict); +char *ctime_r(const time_t *, char *); + +void tzset(void); + +int nanosleep(const struct timespec *requested_time, struct timespec *remaining); +int clock_gettime(clockid_t _clk, struct timespec *ts); + +#endif // __TIME_H__ diff --git a/tools/axlibc/include/unistd.h b/tools/axlibc/include/unistd.h new file mode 100644 index 0000000..46b580d --- /dev/null +++ b/tools/axlibc/include/unistd.h @@ -0,0 +1,240 @@ +#ifndef __UNISTD_H__ +#define __UNISTD_H__ + +#include +#include +#include + +#define STDIN_FILENO 0 +#define STDOUT_FILENO 1 +#define STDERR_FILENO 2 + +#define SEEK_SET 0 +#define SEEK_CUR 1 +#define SEEK_END 2 +#define SEEK_DATA 3 +#define SEEK_HOLE 4 + +int pipe(int[2]); +int pipe2(int[2], int); +int close(int); +int posix_close(int, int); +int dup(int); +int dup2(int, int); +int dup3(int, int, int); +off_t lseek(int, off_t, int); +int fsync(int); +int fdatasync(int); + +ssize_t read(int, void *, size_t); +ssize_t write(int, const void *, size_t); +ssize_t pread(int, void *, size_t, off_t); +ssize_t pwrite(int, const void *, size_t, off_t); + +int chown(const char *, uid_t, gid_t); +int fchown(int, uid_t, gid_t); +int lchown(const char *, uid_t, gid_t); +int fchownat(int, const char *, uid_t, gid_t, int); + +int link(const char *, const char *); +int linkat(int, const char *, int, const char *, int); +int symlink(const char *, const char *); +int symlinkat(const char *, int, const char *); +ssize_t readlink(const char *__restrict, char *__restrict, size_t); +ssize_t readlinkat(int, const char *__restrict, char *__restrict, size_t); +int unlink(const char *); +int unlinkat(int, const char *, int); +int rmdir(const char *); +int truncate(const char *, off_t); +int ftruncate(int, off_t); + +#define F_OK 0 +#define R_OK 4 +#define W_OK 2 +#define X_OK 1 + +int access(const char *, int); +int faccessat(int, const char *, int, int); + +int chdir(const char *); +int fchdir(int); +char *getcwd(char *, size_t); + +unsigned alarm(unsigned); +unsigned sleep(unsigned); +int pause(void); +int usleep(unsigned); + +pid_t fork(void); +int execve(const char *, char *const[], char *const[]); +_Noreturn void _exit(int); + +pid_t getpid(void); +pid_t getppid(void); +pid_t getpgrp(void); +pid_t getpgid(pid_t); +int setpgid(pid_t, pid_t); +pid_t setsid(void); +pid_t getsid(pid_t); +char *ttyname(int); +int ttyname_r(int, char *, size_t); +int isatty(int); +pid_t tcgetpgrp(int); +int tcsetpgrp(int, pid_t); + +uid_t getuid(void); +uid_t geteuid(void); +gid_t getgid(void); +gid_t getegid(void); +int getgroups(int, gid_t[]); +int setuid(uid_t); +int seteuid(uid_t); +int setgid(gid_t); +int setegid(gid_t); + +long sysconf(int); + +#define _SC_ARG_MAX 0 +#define _SC_CHILD_MAX 1 +#define _SC_CLK_TCK 2 +#define _SC_NGROUPS_MAX 3 +#define _SC_OPEN_MAX 4 +#define _SC_STREAM_MAX 5 +#define _SC_TZNAME_MAX 6 +#define _SC_JOB_CONTROL 7 +#define _SC_SAVED_IDS 8 +#define _SC_REALTIME_SIGNALS 9 +#define _SC_PRIORITY_SCHEDULING 10 +#define _SC_TIMERS 11 +#define _SC_ASYNCHRONOUS_IO 12 +#define _SC_PRIORITIZED_IO 13 +#define _SC_SYNCHRONIZED_IO 14 +#define _SC_FSYNC 15 +#define _SC_MAPPED_FILES 16 +#define _SC_MEMLOCK 17 +#define _SC_MEMLOCK_RANGE 18 +#define _SC_MEMORY_PROTECTION 19 +#define _SC_MESSAGE_PASSING 20 +#define _SC_SEMAPHORES 21 +#define _SC_SHARED_MEMORY_OBJECTS 22 +#define _SC_AIO_LISTIO_MAX 23 +#define _SC_AIO_MAX 24 +#define _SC_AIO_PRIO_DELTA_MAX 25 +#define _SC_DELAYTIMER_MAX 26 +#define _SC_MQ_OPEN_MAX 27 +#define _SC_MQ_PRIO_MAX 28 +#define _SC_VERSION 29 +#define _SC_PAGE_SIZE 30 +#define _SC_PAGESIZE 30 /* !! */ +#define _SC_RTSIG_MAX 31 +#define _SC_SEM_NSEMS_MAX 32 +#define _SC_SEM_VALUE_MAX 33 +#define _SC_SIGQUEUE_MAX 34 +#define _SC_TIMER_MAX 35 +#define _SC_BC_BASE_MAX 36 +#define _SC_BC_DIM_MAX 37 +#define _SC_BC_SCALE_MAX 38 +#define _SC_BC_STRING_MAX 39 +#define _SC_COLL_WEIGHTS_MAX 40 +#define _SC_EXPR_NEST_MAX 42 +#define _SC_LINE_MAX 43 +#define _SC_RE_DUP_MAX 44 +#define _SC_2_VERSION 46 +#define _SC_2_C_BIND 47 +#define _SC_2_C_DEV 48 +#define _SC_2_FORT_DEV 49 +#define _SC_2_FORT_RUN 50 +#define _SC_2_SW_DEV 51 +#define _SC_2_LOCALEDEF 52 +#define _SC_UIO_MAXIOV 60 /* !! */ +#define _SC_IOV_MAX 60 +#define _SC_THREADS 67 +#define _SC_THREAD_SAFE_FUNCTIONS 68 +#define _SC_GETGR_R_SIZE_MAX 69 +#define _SC_GETPW_R_SIZE_MAX 70 +#define _SC_LOGIN_NAME_MAX 71 +#define _SC_TTY_NAME_MAX 72 +#define _SC_THREAD_DESTRUCTOR_ITERATIONS 73 +#define _SC_THREAD_KEYS_MAX 74 +#define _SC_THREAD_STACK_MIN 75 +#define _SC_THREAD_THREADS_MAX 76 +#define _SC_THREAD_ATTR_STACKADDR 77 +#define _SC_THREAD_ATTR_STACKSIZE 78 +#define _SC_THREAD_PRIORITY_SCHEDULING 79 +#define _SC_THREAD_PRIO_INHERIT 80 +#define _SC_THREAD_PRIO_PROTECT 81 +#define _SC_THREAD_PROCESS_SHARED 82 +#define _SC_NPROCESSORS_CONF 83 +#define _SC_NPROCESSORS_ONLN 84 +#define _SC_PHYS_PAGES 85 +#define _SC_AVPHYS_PAGES 86 +#define _SC_ATEXIT_MAX 87 +#define _SC_PASS_MAX 88 +#define _SC_XOPEN_VERSION 89 +#define _SC_XOPEN_XCU_VERSION 90 +#define _SC_XOPEN_UNIX 91 +#define _SC_XOPEN_CRYPT 92 +#define _SC_XOPEN_ENH_I18N 93 +#define _SC_XOPEN_SHM 94 +#define _SC_2_CHAR_TERM 95 +#define _SC_2_UPE 97 +#define _SC_XOPEN_XPG2 98 +#define _SC_XOPEN_XPG3 99 +#define _SC_XOPEN_XPG4 100 +#define _SC_NZERO 109 +#define _SC_XBS5_ILP32_OFF32 125 +#define _SC_XBS5_ILP32_OFFBIG 126 +#define _SC_XBS5_LP64_OFF64 127 +#define _SC_XBS5_LPBIG_OFFBIG 128 +#define _SC_XOPEN_LEGACY 129 +#define _SC_XOPEN_REALTIME 130 +#define _SC_XOPEN_REALTIME_THREADS 131 +#define _SC_ADVISORY_INFO 132 +#define _SC_BARRIERS 133 +#define _SC_CLOCK_SELECTION 137 +#define _SC_CPUTIME 138 +#define _SC_THREAD_CPUTIME 139 +#define _SC_MONOTONIC_CLOCK 149 +#define _SC_READER_WRITER_LOCKS 153 +#define _SC_SPIN_LOCKS 154 +#define _SC_REGEXP 155 +#define _SC_SHELL 157 +#define _SC_SPAWN 159 +#define _SC_SPORADIC_SERVER 160 +#define _SC_THREAD_SPORADIC_SERVER 161 +#define _SC_TIMEOUTS 164 +#define _SC_TYPED_MEMORY_OBJECTS 165 +#define _SC_2_PBS 168 +#define _SC_2_PBS_ACCOUNTING 169 +#define _SC_2_PBS_LOCATE 170 +#define _SC_2_PBS_MESSAGE 171 +#define _SC_2_PBS_TRACK 172 +#define _SC_SYMLOOP_MAX 173 +#define _SC_STREAMS 174 +#define _SC_2_PBS_CHECKPOINT 175 +#define _SC_V6_ILP32_OFF32 176 +#define _SC_V6_ILP32_OFFBIG 177 +#define _SC_V6_LP64_OFF64 178 +#define _SC_V6_LPBIG_OFFBIG 179 +#define _SC_HOST_NAME_MAX 180 +#define _SC_TRACE 181 +#define _SC_TRACE_EVENT_FILTER 182 +#define _SC_TRACE_INHERIT 183 +#define _SC_TRACE_LOG 184 + +#define _SC_IPV6 235 +#define _SC_RAW_SOCKETS 236 +#define _SC_V7_ILP32_OFF32 237 +#define _SC_V7_ILP32_OFFBIG 238 +#define _SC_V7_LP64_OFF64 239 +#define _SC_V7_LPBIG_OFFBIG 240 +#define _SC_SS_REPL_MAX 241 +#define _SC_TRACE_EVENT_NAME_MAX 242 +#define _SC_TRACE_NAME_MAX 243 +#define _SC_TRACE_SYS_MAX 244 +#define _SC_TRACE_USER_EVENT_MAX 245 +#define _SC_XOPEN_STREAMS 246 +#define _SC_THREAD_ROBUST_PRIO_INHERIT 247 +#define _SC_THREAD_ROBUST_PRIO_PROTECT 248 + +#endif diff --git a/tools/axlibc/src/errno.rs b/tools/axlibc/src/errno.rs new file mode 100644 index 0000000..5f38bee --- /dev/null +++ b/tools/axlibc/src/errno.rs @@ -0,0 +1,39 @@ +use axerrno::LinuxError; +use core::ffi::{c_char, c_int}; + +/// The global errno variable. +#[cfg_attr(feature = "tls", thread_local)] +#[no_mangle] +#[allow(non_upper_case_globals)] +pub static mut errno: c_int = 0; + +pub fn set_errno(code: i32) { + unsafe { + errno = code; + } +} + +/// Returns a pointer to the global errno variable. +#[no_mangle] +pub unsafe extern "C" fn __errno_location() -> *mut c_int { + core::ptr::addr_of_mut!(errno) +} + +/// Returns a pointer to the string representation of the given error code. +#[no_mangle] +pub unsafe extern "C" fn strerror(e: c_int) -> *mut c_char { + #[allow(non_upper_case_globals)] + static mut strerror_buf: [u8; 256] = [0; 256]; // TODO: thread safe + + let err_str = if e == 0 { + "Success" + } else { + LinuxError::try_from(e) + .map(|e| e.as_str()) + .unwrap_or("Unknown error") + }; + unsafe { + strerror_buf[..err_str.len()].copy_from_slice(err_str.as_bytes()); + strerror_buf.as_mut_ptr() as *mut c_char + } +} diff --git a/tools/axlibc/src/fd_ops.rs b/tools/axlibc/src/fd_ops.rs new file mode 100644 index 0000000..1b1a9d0 --- /dev/null +++ b/tools/axlibc/src/fd_ops.rs @@ -0,0 +1,54 @@ +use crate::{ctypes, utils::e}; +use arceos_posix_api::{sys_close, sys_dup, sys_dup2, sys_fcntl}; +use axerrno::LinuxError; +use core::ffi::c_int; + +/// Close a file by `fd`. +#[no_mangle] +pub unsafe extern "C" fn close(fd: c_int) -> c_int { + e(sys_close(fd)) +} + +/// Duplicate a file descriptor. +#[no_mangle] +pub unsafe extern "C" fn dup(old_fd: c_int) -> c_int { + e(sys_dup(old_fd)) +} + +/// Duplicate a file descriptor, use file descriptor specified in `new_fd`. +#[no_mangle] +pub unsafe extern "C" fn dup2(old_fd: c_int, new_fd: c_int) -> c_int { + e(sys_dup2(old_fd, new_fd)) +} + +/// Duplicate a file descriptor, the caller can force the close-on-exec flag to +/// be set for the new file descriptor by specifying `O_CLOEXEC` in flags. +/// +/// If oldfd equals newfd, then `dup3()` fails with the error `EINVAL`. +#[no_mangle] +pub unsafe extern "C" fn dup3(old_fd: c_int, new_fd: c_int, flags: c_int) -> c_int { + if old_fd == new_fd { + return e((LinuxError::EINVAL as c_int).wrapping_neg()); + } + let r = e(sys_dup2(old_fd, new_fd)); + if r < 0 { + r + } else { + if flags as u32 & ctypes::O_CLOEXEC != 0 { + e(sys_fcntl( + new_fd, + ctypes::F_SETFD as c_int, + ctypes::FD_CLOEXEC as usize, + )); + } + new_fd + } +} + +/// Manipulate file descriptor. +/// +/// TODO: `SET/GET` command is ignored +#[no_mangle] +pub unsafe extern "C" fn ax_fcntl(fd: c_int, cmd: c_int, arg: usize) -> c_int { + e(sys_fcntl(fd, cmd, arg)) +} diff --git a/tools/axlibc/src/fs.rs b/tools/axlibc/src/fs.rs new file mode 100644 index 0000000..bd93f88 --- /dev/null +++ b/tools/axlibc/src/fs.rs @@ -0,0 +1,67 @@ +use core::ffi::{c_char, c_int}; + +use arceos_posix_api::{ + sys_fstat, sys_getcwd, sys_lseek, sys_lstat, sys_open, sys_rename, sys_stat, +}; + +use crate::{ctypes, utils::e}; + +/// Open a file by `filename` and insert it into the file descriptor table. +/// +/// Return its index in the file table (`fd`). Return `EMFILE` if it already +/// has the maximum number of files open. +#[no_mangle] +pub unsafe extern "C" fn ax_open( + filename: *const c_char, + flags: c_int, + mode: ctypes::mode_t, +) -> c_int { + e(sys_open(filename, flags, mode)) +} + +/// Set the position of the file indicated by `fd`. +/// +/// Return its position after seek. +#[no_mangle] +pub unsafe extern "C" fn lseek(fd: c_int, offset: ctypes::off_t, whence: c_int) -> ctypes::off_t { + e(sys_lseek(fd, offset, whence) as _) as _ +} + +/// Get the file metadata by `path` and write into `buf`. +/// +/// Return 0 if success. +#[no_mangle] +pub unsafe extern "C" fn stat(path: *const c_char, buf: *mut ctypes::stat) -> c_int { + e(sys_stat(path, buf)) +} + +/// Get file metadata by `fd` and write into `buf`. +/// +/// Return 0 if success. +#[no_mangle] +pub unsafe extern "C" fn fstat(fd: c_int, buf: *mut ctypes::stat) -> c_int { + e(sys_fstat(fd, buf)) +} + +/// Get the metadata of the symbolic link and write into `buf`. +/// +/// Return 0 if success. +#[no_mangle] +pub unsafe extern "C" fn lstat(path: *const c_char, buf: *mut ctypes::stat) -> c_int { + e(sys_lstat(path, buf) as _) +} + +/// Get the path of the current directory. +#[no_mangle] +pub unsafe extern "C" fn getcwd(buf: *mut c_char, size: usize) -> *mut c_char { + sys_getcwd(buf, size) +} + +/// Rename `old` to `new` +/// If new exists, it is first removed. +/// +/// Return 0 if the operation succeeds, otherwise return -1. +#[no_mangle] +pub unsafe extern "C" fn rename(old: *const c_char, new: *const c_char) -> c_int { + e(sys_rename(old, new)) +} diff --git a/tools/axlibc/src/io.rs b/tools/axlibc/src/io.rs new file mode 100644 index 0000000..ea6187b --- /dev/null +++ b/tools/axlibc/src/io.rs @@ -0,0 +1,32 @@ +use core::ffi::{c_int, c_void}; + +use arceos_posix_api::{sys_read, sys_write, sys_writev}; + +use crate::{ctypes, utils::e}; + +/// Read data from the file indicated by `fd`. +/// +/// Return the read size if success. +#[no_mangle] +pub unsafe extern "C" fn read(fd: c_int, buf: *mut c_void, count: usize) -> ctypes::ssize_t { + e(sys_read(fd, buf, count) as _) as _ +} + +/// Write data to the file indicated by `fd`. +/// +/// Return the written size if success. +#[no_mangle] +#[cfg(not(test))] +pub unsafe extern "C" fn write(fd: c_int, buf: *const c_void, count: usize) -> ctypes::ssize_t { + e(sys_write(fd, buf, count) as _) as _ +} + +/// Write a vector. +#[no_mangle] +pub unsafe extern "C" fn writev( + fd: c_int, + iov: *const ctypes::iovec, + iocnt: c_int, +) -> ctypes::ssize_t { + e(sys_writev(fd, iov, iocnt) as _) as _ +} diff --git a/tools/axlibc/src/io_mpx.rs b/tools/axlibc/src/io_mpx.rs new file mode 100644 index 0000000..2bcffc7 --- /dev/null +++ b/tools/axlibc/src/io_mpx.rs @@ -0,0 +1,54 @@ +use crate::{ctypes, utils::e}; + +use core::ffi::c_int; + +#[cfg(feature = "select")] +use arceos_posix_api::sys_select; +#[cfg(feature = "epoll")] +use arceos_posix_api::{sys_epoll_create, sys_epoll_ctl, sys_epoll_wait}; + +/// Creates a new epoll instance. +/// +/// It returns a file descriptor referring to the new epoll instance. +#[cfg(feature = "epoll")] +#[no_mangle] +pub unsafe extern "C" fn epoll_create(size: c_int) -> c_int { + e(sys_epoll_create(size)) +} + +/// Control interface for an epoll file descriptor +#[cfg(feature = "epoll")] +#[no_mangle] +pub unsafe extern "C" fn epoll_ctl( + epfd: c_int, + op: c_int, + fd: c_int, + event: *mut ctypes::epoll_event, +) -> c_int { + e(sys_epoll_ctl(epfd, op, fd, event)) +} + +/// Waits for events on the epoll instance referred to by the file descriptor epfd. +#[cfg(feature = "epoll")] +#[no_mangle] +pub unsafe extern "C" fn epoll_wait( + epfd: c_int, + events: *mut ctypes::epoll_event, + maxevents: c_int, + timeout: c_int, +) -> c_int { + e(sys_epoll_wait(epfd, events, maxevents, timeout)) +} + +/// Monitor multiple file descriptors, waiting until one or more of the file descriptors become "ready" for some class of I/O operation +#[cfg(feature = "select")] +#[no_mangle] +pub unsafe extern "C" fn select( + nfds: c_int, + readfds: *mut ctypes::fd_set, + writefds: *mut ctypes::fd_set, + exceptfds: *mut ctypes::fd_set, + timeout: *mut ctypes::timeval, +) -> c_int { + e(sys_select(nfds, readfds, writefds, exceptfds, timeout)) +} diff --git a/tools/axlibc/src/lib.rs b/tools/axlibc/src/lib.rs new file mode 100644 index 0000000..5a02207 --- /dev/null +++ b/tools/axlibc/src/lib.rs @@ -0,0 +1,127 @@ +//! [ArceOS] user program library for C apps. +//! +//! ## Cargo Features +//! +//! - CPU +//! - `smp`: Enable SMP (symmetric multiprocessing) support. +//! - `fp_simd`: Enable floating point and SIMD support. +//! - Interrupts: +//! - `irq`: Enable interrupt handling support. +//! - Memory +//! - `alloc`: Enable dynamic memory allocation. +//! - `tls`: Enable thread-local storage. +//! - Task management +//! - `multitask`: Enable multi-threading support. +//! - Upperlayer stacks +//! - `fs`: Enable file system support. +//! - `net`: Enable networking support. +//! - Lib C functions +//! - `fd`: Enable file descriptor table. +//! - `pipe`: Enable pipe support. +//! - `select`: Enable synchronous I/O multiplexing ([select]) support. +//! - `epoll`: Enable event polling ([epoll]) support. +//! +//! [ArceOS]: https://github.com/rcore-os/arceos +//! [select]: https://man7.org/linux/man-pages/man2/select.2.html +//! [epoll]: https://man7.org/linux/man-pages/man7/epoll.7.html + +#![cfg_attr(all(not(test), not(doc)), no_std)] +#![feature(doc_cfg)] +#![feature(doc_auto_cfg)] +#![feature(naked_functions)] +#![feature(thread_local)] +#![allow(clippy::missing_safety_doc)] + +#[cfg(feature = "alloc")] +extern crate alloc; + +extern crate arch_boot; + +#[path = "."] +mod ctypes { + #[rustfmt::skip] + #[path = "libctypes_gen.rs"] + #[allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals, clippy::upper_case_acronyms)] + mod libctypes; + + pub use arceos_posix_api::ctypes::*; + pub use libctypes::*; +} + +#[macro_use] +mod utils; + +#[cfg(feature = "fd")] +mod fd_ops; +#[cfg(feature = "fs")] +mod fs; +#[cfg(any(feature = "select", feature = "epoll"))] +mod io_mpx; +#[cfg(feature = "alloc")] +mod malloc; +#[cfg(feature = "net")] +mod net; +#[cfg(feature = "pipe")] +mod pipe; +#[cfg(feature = "multitask")] +mod pthread; +#[cfg(feature = "alloc")] +mod strftime; +#[cfg(feature = "fp_simd")] +mod strtod; + +mod errno; +mod io; +mod mktime; +mod rand; +mod resource; +mod setjmp; +mod sys; +mod time; +mod unistd; + +#[cfg(not(test))] +pub use self::io::write; +pub use self::io::{read, writev}; + +pub use self::errno::strerror; +pub use self::mktime::mktime; +pub use self::rand::{rand, random, srand}; +pub use self::resource::{getrlimit, setrlimit}; +pub use self::setjmp::{longjmp, setjmp}; +pub use self::sys::sysconf; +pub use self::time::{clock_gettime, nanosleep}; +pub use self::unistd::{abort, exit, getpid}; + +#[cfg(feature = "alloc")] +pub use self::malloc::{free, malloc}; +#[cfg(feature = "alloc")] +pub use self::strftime::strftime; + +#[cfg(feature = "fd")] +pub use self::fd_ops::{ax_fcntl, close, dup, dup2, dup3}; + +#[cfg(feature = "fs")] +pub use self::fs::{ax_open, fstat, getcwd, lseek, lstat, rename, stat}; + +#[cfg(feature = "net")] +pub use self::net::{ + accept, bind, connect, freeaddrinfo, getaddrinfo, getpeername, getsockname, listen, recv, + recvfrom, send, sendto, shutdown, socket, +}; + +#[cfg(feature = "multitask")] +pub use self::pthread::{pthread_create, pthread_exit, pthread_join, pthread_self}; +#[cfg(feature = "multitask")] +pub use self::pthread::{pthread_mutex_init, pthread_mutex_lock, pthread_mutex_unlock}; + +#[cfg(feature = "pipe")] +pub use self::pipe::pipe; + +#[cfg(feature = "select")] +pub use self::io_mpx::select; +#[cfg(feature = "epoll")] +pub use self::io_mpx::{epoll_create, epoll_ctl, epoll_wait}; + +#[cfg(feature = "fp_simd")] +pub use self::strtod::{strtod, strtof}; diff --git a/tools/axlibc/src/malloc.rs b/tools/axlibc/src/malloc.rs new file mode 100644 index 0000000..f635b7f --- /dev/null +++ b/tools/axlibc/src/malloc.rs @@ -0,0 +1,56 @@ +//! Provides the corresponding malloc(size_t) and free(size_t) when using the C user program. +//! +//! The normal malloc(size_t) and free(size_t) are provided by the library malloc.h, and +//! sys_brk is used internally to apply for memory from the kernel. But in a unikernel like +//! `ArceOS`, we noticed that the heap of the Rust user program is shared with the kernel. In +//! order to maintain consistency, C user programs also choose to share the kernel heap, +//! skipping the sys_brk step. + +use alloc::alloc::{alloc, dealloc}; +use core::alloc::Layout; +use core::ffi::c_void; + +use crate::ctypes; + +struct MemoryControlBlock { + size: usize, +} + +const CTRL_BLK_SIZE: usize = core::mem::size_of::(); + +/// Allocate memory and return the memory address. +/// +/// Returns 0 on failure (the current implementation does not trigger an exception) +#[no_mangle] +pub unsafe extern "C" fn malloc(size: ctypes::size_t) -> *mut c_void { + // Allocate `(actual length) + 8`. The lowest 8 Bytes are stored in the actual allocated space size. + // This is because free(uintptr_t) has only one parameter representing the address, + // So we need to save in advance to know the size of the memory space that needs to be released + let layout = Layout::from_size_align(size + CTRL_BLK_SIZE, 8).unwrap(); + unsafe { + let ptr = alloc(layout).cast::(); + assert!(!ptr.is_null(), "malloc failed"); + ptr.write(MemoryControlBlock { size }); + ptr.add(1).cast() + } +} + +/// Deallocate memory. +/// +/// (WARNING) If the address to be released does not match the allocated address, an error should +/// occur, but it will NOT be checked out. This is due to the global allocator `Buddy_system` +/// (currently used) does not check the validity of address to be released. +#[no_mangle] +pub unsafe extern "C" fn free(ptr: *mut c_void) { + if ptr.is_null() { + return; + } + let ptr = ptr.cast::(); + assert!(ptr as usize > CTRL_BLK_SIZE, "free a null pointer"); + unsafe { + let ptr = ptr.sub(1); + let size = ptr.read().size; + let layout = Layout::from_size_align(size + CTRL_BLK_SIZE, 8).unwrap(); + dealloc(ptr.cast(), layout) + } +} diff --git a/tools/axlibc/src/mktime.rs b/tools/axlibc/src/mktime.rs new file mode 100644 index 0000000..1caf332 --- /dev/null +++ b/tools/axlibc/src/mktime.rs @@ -0,0 +1,58 @@ +use core::ffi::c_int; + +use crate::ctypes; + +const MONTH_DAYS: [[c_int; 12]; 2] = [ + // Non-leap years: + [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31], + // Leap years: + [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31], +]; + +#[inline(always)] +fn leap_year(year: c_int) -> bool { + year % 4 == 0 && (year % 100 != 0 || year % 400 == 0) +} + +/// Convert broken-down time into time since the Epoch. +#[no_mangle] +pub unsafe extern "C" fn mktime(t: *mut ctypes::tm) -> ctypes::time_t { + let mut year = (*t).tm_year + 1900; + let mut month = (*t).tm_mon; + let mut day = (*t).tm_mday as i64 - 1; + + let leap = if leap_year(year) { 1 } else { 0 }; + + if year < 1970 { + day = MONTH_DAYS[if leap_year(year) { 1 } else { 0 }][(*t).tm_mon as usize] as i64 - day; + + while year < 1969 { + year += 1; + day += if leap_year(year) { 366 } else { 365 }; + } + + while month < 11 { + month += 1; + day += MONTH_DAYS[leap][month as usize] as i64; + } + + (-(day * (60 * 60 * 24) + - (((*t).tm_hour as i64) * (60 * 60) + ((*t).tm_min as i64) * 60 + (*t).tm_sec as i64))) + as ctypes::time_t + } else { + while year > 1970 { + year -= 1; + day += if leap_year(year) { 366 } else { 365 }; + } + + while month > 0 { + month -= 1; + day += MONTH_DAYS[leap][month as usize] as i64; + } + + (day * (60 * 60 * 24) + + ((*t).tm_hour as i64) * (60 * 60) + + ((*t).tm_min as i64) * 60 + + (*t).tm_sec as i64) as ctypes::time_t + } +} diff --git a/tools/axlibc/src/net.rs b/tools/axlibc/src/net.rs new file mode 100644 index 0000000..e092181 --- /dev/null +++ b/tools/axlibc/src/net.rs @@ -0,0 +1,180 @@ +use arceos_posix_api::{ + sys_accept, sys_bind, sys_connect, sys_freeaddrinfo, sys_getaddrinfo, sys_getpeername, + sys_getsockname, sys_listen, sys_recv, sys_recvfrom, sys_send, sys_sendto, sys_shutdown, + sys_socket, +}; +use core::ffi::{c_char, c_int, c_void}; + +use crate::{ctypes, utils::e}; + +/// Create an socket for communication. +/// +/// Return the socket file descriptor. +#[no_mangle] +pub unsafe extern "C" fn socket(domain: c_int, socktype: c_int, protocol: c_int) -> c_int { + e(sys_socket(domain, socktype, protocol)) +} + +/// Bind a address to a socket. +/// +/// Return 0 if success. +#[no_mangle] +pub unsafe extern "C" fn bind( + socket_fd: c_int, + socket_addr: *const ctypes::sockaddr, + addrlen: ctypes::socklen_t, +) -> c_int { + e(sys_bind(socket_fd, socket_addr, addrlen)) +} + +/// Connects the socket to the address specified. +/// +/// Return 0 if success. +#[no_mangle] +pub unsafe extern "C" fn connect( + socket_fd: c_int, + socket_addr: *const ctypes::sockaddr, + addrlen: ctypes::socklen_t, +) -> c_int { + e(sys_connect(socket_fd, socket_addr, addrlen)) +} + +/// Send a message on a socket to the address specified. +/// +/// Return the number of bytes sent if success. +#[no_mangle] +pub unsafe extern "C" fn sendto( + socket_fd: c_int, + buf_ptr: *const c_void, + len: ctypes::size_t, + flag: c_int, // currently not used + socket_addr: *const ctypes::sockaddr, + addrlen: ctypes::socklen_t, +) -> ctypes::ssize_t { + if socket_addr.is_null() && addrlen == 0 { + return e(sys_send(socket_fd, buf_ptr, len, flag) as _) as _; + } + e(sys_sendto(socket_fd, buf_ptr, len, flag, socket_addr, addrlen) as _) as _ +} + +/// Send a message on a socket to the address connected. +/// +/// Return the number of bytes sent if success. +#[no_mangle] +pub unsafe extern "C" fn send( + socket_fd: c_int, + buf_ptr: *const c_void, + len: ctypes::size_t, + flag: c_int, // currently not used +) -> ctypes::ssize_t { + e(sys_send(socket_fd, buf_ptr, len, flag) as _) as _ +} + +/// Receive a message on a socket and get its source address. +/// +/// Return the number of bytes received if success. +#[no_mangle] +pub unsafe extern "C" fn recvfrom( + socket_fd: c_int, + buf_ptr: *mut c_void, + len: ctypes::size_t, + flag: c_int, // currently not used + socket_addr: *mut ctypes::sockaddr, + addrlen: *mut ctypes::socklen_t, +) -> ctypes::ssize_t { + if socket_addr.is_null() { + return e(sys_recv(socket_fd, buf_ptr, len, flag) as _) as _; + } + e(sys_recvfrom(socket_fd, buf_ptr, len, flag, socket_addr, addrlen) as _) as _ +} + +/// Receive a message on a socket. +/// +/// Return the number of bytes received if success. +#[no_mangle] +pub unsafe extern "C" fn recv( + socket_fd: c_int, + buf_ptr: *mut c_void, + len: ctypes::size_t, + flag: c_int, // currently not used +) -> ctypes::ssize_t { + e(sys_recv(socket_fd, buf_ptr, len, flag) as _) as _ +} + +/// Listen for connections on a socket +/// +/// Return 0 if success. +#[no_mangle] +pub unsafe extern "C" fn listen( + socket_fd: c_int, + backlog: c_int, // currently not used +) -> c_int { + e(sys_listen(socket_fd, backlog)) +} + +/// Accept for connections on a socket +/// +/// Return file descriptor for the accepted socket if success. +#[no_mangle] +pub unsafe extern "C" fn accept( + socket_fd: c_int, + socket_addr: *mut ctypes::sockaddr, + socket_len: *mut ctypes::socklen_t, +) -> c_int { + e(sys_accept(socket_fd, socket_addr, socket_len)) +} + +/// Shut down a full-duplex connection. +/// +/// Return 0 if success. +#[no_mangle] +pub unsafe extern "C" fn shutdown( + socket_fd: c_int, + flag: c_int, // currently not used +) -> c_int { + e(sys_shutdown(socket_fd, flag)) +} + +/// Query addresses for a domain name. +/// +/// Return address number if success. +#[no_mangle] +pub unsafe extern "C" fn getaddrinfo( + nodename: *const c_char, + servname: *const c_char, + hints: *const ctypes::addrinfo, + res: *mut *mut ctypes::addrinfo, +) -> c_int { + let ret = e(sys_getaddrinfo(nodename, servname, hints, res)); + match ret { + r if r < 0 => ctypes::EAI_FAIL, + 0 => ctypes::EAI_NONAME, + _ => 0, + } +} + +/// Free queried `addrinfo` struct +#[no_mangle] +pub unsafe extern "C" fn freeaddrinfo(res: *mut ctypes::addrinfo) { + sys_freeaddrinfo(res); +} + +/// Get current address to which the socket sockfd is bound. +#[no_mangle] +pub unsafe extern "C" fn getsockname( + sock_fd: c_int, + addr: *mut ctypes::sockaddr, + addrlen: *mut ctypes::socklen_t, +) -> c_int { + e(sys_getsockname(sock_fd, addr, addrlen)) +} + +/// Get peer address to which the socket sockfd is connected. +#[no_mangle] +pub unsafe extern "C" fn getpeername( + sock_fd: c_int, + addr: *mut ctypes::sockaddr, + addrlen: *mut ctypes::socklen_t, +) -> c_int { + e(sys_getpeername(sock_fd, addr, addrlen)) +} diff --git a/tools/axlibc/src/pipe.rs b/tools/axlibc/src/pipe.rs new file mode 100644 index 0000000..2bed253 --- /dev/null +++ b/tools/axlibc/src/pipe.rs @@ -0,0 +1,14 @@ +use core::ffi::c_int; + +use arceos_posix_api::sys_pipe; + +use crate::utils::e; + +/// Create a pipe +/// +/// Return 0 if succeed +#[no_mangle] +pub unsafe extern "C" fn pipe(fd: *mut c_int) -> c_int { + let fds = unsafe { core::slice::from_raw_parts_mut(fd, 2) }; + e(sys_pipe(fds)) +} diff --git a/tools/axlibc/src/pthread.rs b/tools/axlibc/src/pthread.rs new file mode 100644 index 0000000..b170b8b --- /dev/null +++ b/tools/axlibc/src/pthread.rs @@ -0,0 +1,59 @@ +use crate::{ctypes, utils::e}; +use arceos_posix_api as api; +use core::ffi::{c_int, c_void}; + +/// Returns the `pthread` struct of current thread. +#[no_mangle] +pub unsafe extern "C" fn pthread_self() -> ctypes::pthread_t { + api::sys_pthread_self() +} + +/// Create a new thread with the given entry point and argument. +/// +/// If successful, it stores the pointer to the newly created `struct __pthread` +/// in `res` and returns 0. +#[no_mangle] +pub unsafe extern "C" fn pthread_create( + res: *mut ctypes::pthread_t, + attr: *const ctypes::pthread_attr_t, + start_routine: extern "C" fn(arg: *mut c_void) -> *mut c_void, + arg: *mut c_void, +) -> c_int { + e(api::sys_pthread_create(res, attr, start_routine, arg)) +} + +/// Exits the current thread. The value `retval` will be returned to the joiner. +#[no_mangle] +pub unsafe extern "C" fn pthread_exit(retval: *mut c_void) -> ! { + api::sys_pthread_exit(retval) +} + +/// Waits for the given thread to exit, and stores the return value in `retval`. +#[no_mangle] +pub unsafe extern "C" fn pthread_join( + thread: ctypes::pthread_t, + retval: *mut *mut c_void, +) -> c_int { + e(api::sys_pthread_join(thread, retval)) +} + +/// Initialize a mutex. +#[no_mangle] +pub unsafe extern "C" fn pthread_mutex_init( + mutex: *mut ctypes::pthread_mutex_t, + attr: *const ctypes::pthread_mutexattr_t, +) -> c_int { + e(api::sys_pthread_mutex_init(mutex, attr)) +} + +/// Lock the given mutex. +#[no_mangle] +pub unsafe extern "C" fn pthread_mutex_lock(mutex: *mut ctypes::pthread_mutex_t) -> c_int { + e(api::sys_pthread_mutex_lock(mutex)) +} + +/// Unlock the given mutex. +#[no_mangle] +pub unsafe extern "C" fn pthread_mutex_unlock(mutex: *mut ctypes::pthread_mutex_t) -> c_int { + e(api::sys_pthread_mutex_unlock(mutex)) +} diff --git a/tools/axlibc/src/rand.rs b/tools/axlibc/src/rand.rs new file mode 100644 index 0000000..682f423 --- /dev/null +++ b/tools/axlibc/src/rand.rs @@ -0,0 +1,30 @@ +//! Random number generator. + +use core::{ + ffi::{c_int, c_long, c_uint}, + sync::atomic::{AtomicU64, Ordering::SeqCst}, +}; + +static SEED: AtomicU64 = AtomicU64::new(0xa2ce_a2ce); + +/// Sets the seed for the random number generator. +#[no_mangle] +pub unsafe extern "C" fn srand(seed: c_uint) { + SEED.store(seed.wrapping_sub(1) as u64, SeqCst); +} + +/// Returns a 32-bit unsigned pseudo random interger. +#[no_mangle] +pub unsafe extern "C" fn rand() -> c_int { + let new_seed = SEED.load(SeqCst).wrapping_mul(6364136223846793005) + 1; + SEED.store(new_seed, SeqCst); + (new_seed >> 33) as c_int +} + +/// Returns a 64-bit unsigned pseudo random number. +#[no_mangle] +pub unsafe extern "C" fn random() -> c_long { + let new_seed = SEED.load(SeqCst).wrapping_mul(6364136223846793005) + 1; + SEED.store(new_seed, SeqCst); + new_seed as c_long +} diff --git a/tools/axlibc/src/resource.rs b/tools/axlibc/src/resource.rs new file mode 100644 index 0000000..20e013e --- /dev/null +++ b/tools/axlibc/src/resource.rs @@ -0,0 +1,17 @@ +use core::ffi::c_int; + +use arceos_posix_api::{sys_getrlimit, sys_setrlimit}; + +use crate::utils::e; + +/// Get resource limitations +#[no_mangle] +pub unsafe extern "C" fn getrlimit(resource: c_int, rlimits: *mut crate::ctypes::rlimit) -> c_int { + e(sys_getrlimit(resource, rlimits)) +} + +/// Set resource limitations +#[no_mangle] +pub unsafe extern "C" fn setrlimit(resource: c_int, rlimits: *mut crate::ctypes::rlimit) -> c_int { + e(sys_setrlimit(resource, rlimits)) +} diff --git a/tools/axlibc/src/setjmp.rs b/tools/axlibc/src/setjmp.rs new file mode 100644 index 0000000..9c8fe28 --- /dev/null +++ b/tools/axlibc/src/setjmp.rs @@ -0,0 +1,221 @@ +use core::ffi::c_int; + +use crate::ctypes; + +#[cfg(all(target_arch = "aarch64", feature = "fp_simd"))] +extern "C" { + fn vfp_setjmp(buf: *mut ctypes::__jmp_buf_tag); + fn vfp_longjmp(buf: *mut ctypes::__jmp_buf_tag, _val: c_int) -> !; +} + +#[cfg(all(target_arch = "aarch64", feature = "fp_simd"))] +#[no_mangle] +#[allow(missing_docs)] +pub unsafe extern "C" fn setjmp(_buf: *mut ctypes::__jmp_buf_tag) { + vfp_setjmp(_buf); +} + +#[cfg(not(all(target_arch = "aarch64", feature = "fp_simd")))] +#[naked] +#[allow(missing_docs)] +#[no_mangle] +pub unsafe extern "C" fn setjmp(_buf: *mut ctypes::__jmp_buf_tag) { + #[cfg(all(target_arch = "aarch64", not(feature = "fp_simd")))] + core::arch::asm!( + " + stp x19, x20, [x0,#0] + stp x21, x22, [x0,#16] + stp x23, x24, [x0,#32] + stp x25, x26, [x0,#48] + stp x27, x28, [x0,#64] + stp x29, x30, [x0,#80] + mov x2, sp + str x2, [x0,#104] + mov x0, #0 + ret", + options(noreturn), + ); + #[cfg(target_arch = "x86_64")] + core::arch::asm!( + "mov [rdi], rbx + mov [rdi + 8], rbp + mov [rdi + 16], r12 + mov [rdi + 24], r13 + mov [rdi + 32], r14 + mov [rdi + 40], r15 + lea rdx, [rsp + 8] + mov [rdi + 48], rdx + mov rdx, [rsp] + mov [rdi + 56], rdx + xor rax, rax + ret", + options(noreturn), + ); + #[cfg(all(target_arch = "riscv64", feature = "fp_simd"))] + core::arch::asm!( + "sd s0, 0(a0) + sd s1, 8(a0) + sd s2, 16(a0) + sd s3, 24(a0) + sd s4, 32(a0) + sd s5, 40(a0) + sd s6, 48(a0) + sd s7, 56(a0) + sd s8, 64(a0) + sd s9, 72(a0) + sd s10, 80(a0) + sd s11, 88(a0) + sd sp, 96(a0) + sd ra, 104(a0) + + fsd fs0, 112(a0) + fsd fs1, 120(a0) + fsd fs2, 128(a0) + fsd fs3, 136(a0) + fsd fs4, 144(a0) + fsd fs5, 152(a0) + fsd fs6, 160(a0) + fsd fs7, 168(a0) + fsd fs8, 176(a0) + fsd fs9, 184(a0) + fsd fs10, 192(a0) + fsd fs11, 200(a0) + + li a0, 0 + ret", + options(noreturn), + ); + #[cfg(all(target_arch = "riscv64", not(feature = "fp_simd")))] + core::arch::asm!( + "sd s0, 0(a0) + sd s1, 8(a0) + sd s2, 16(a0) + sd s3, 24(a0) + sd s4, 32(a0) + sd s5, 40(a0) + sd s6, 48(a0) + sd s7, 56(a0) + sd s8, 64(a0) + sd s9, 72(a0) + sd s10, 80(a0) + sd s11, 88(a0) + sd sp, 96(a0) + sd ra, 104(a0) + + li a0, 0 + ret", + options(noreturn), + ); + #[cfg(not(any( + target_arch = "aarch64", + target_arch = "x86_64", + target_arch = "riscv64" + )))] + core::arch::asm!("ret", options(noreturn)) +} + +#[cfg(all(target_arch = "aarch64", feature = "fp_simd"))] +#[no_mangle] +#[allow(missing_docs)] +pub unsafe extern "C" fn longjmp(_buf: *mut ctypes::__jmp_buf_tag, _val: c_int) { + vfp_longjmp(_buf, _val); +} + +#[cfg(not(all(target_arch = "aarch64", feature = "fp_simd")))] +#[allow(missing_docs)] +#[naked] +#[no_mangle] +pub unsafe extern "C" fn longjmp(_buf: *mut ctypes::__jmp_buf_tag, _val: c_int) -> ! { + #[cfg(all(target_arch = "aarch64", not(feature = "fp_simd")))] + core::arch::asm!( + "ldp x19, x20, [x0,#0] + ldp x21, x22, [x0,#16] + ldp x23, x24, [x0,#32] + ldp x25, x26, [x0,#48] + ldp x27, x28, [x0,#64] + ldp x29, x30, [x0,#80] + ldr x2, [x0,#104] + mov sp, x2 + + cmp w1, 0 + csinc w0, w1, wzr, ne + br x30", + options(noreturn), + ); + #[cfg(target_arch = "x86_64")] + core::arch::asm!( + "mov rax,rsi + test rax,rax + jnz 2f + inc rax + 2: + mov rbx, [rdi] + mov rbp, [rdi + 8] + mov r12, [rdi + 16] + mov r13, [rdi + 24] + mov r14, [rdi + 32] + mov r15, [rdi + 40] + mov rdx, [rdi + 48] + mov rsp, rdx + mov rdx, [rdi + 56] + jmp rdx", + options(noreturn), + ); + #[cfg(all(target_arch = "riscv64", feature = "fp_simd"))] + core::arch::asm!( + "ld s0, 0(a0) + ld s1, 8(a0) + ld s2, 16(a0) + ld s3, 24(a0) + ld s4, 32(a0) + ld s5, 40(a0) + ld s6, 48(a0) + ld s7, 56(a0) + ld s8, 64(a0) + ld s9, 72(a0) + ld s10, 80(a0) + ld s11, 88(a0) + ld sp, 96(a0) + ld ra, 104(a0) + + fld fs0, 112(a0) + fld fs1, 120(a0) + fld fs2, 128(a0) + fld fs3, 136(a0) + fld fs4, 144(a0) + fld fs5, 152(a0) + fld fs6, 160(a0) + fld fs7, 168(a0) + fld fs8, 176(a0) + fld fs9, 184(a0) + fld fs10, 192(a0) + fld fs11, 200(a0) + + seqz a0, a1 + add a0, a0, a1 + ret", + options(noreturn), + ); + #[cfg(all(target_arch = "riscv64", not(feature = "fp_simd")))] + core::arch::asm!( + "ld s0, 0(a0) + ld s1, 8(a0) + ld s2, 16(a0) + ld s3, 24(a0) + ld s4, 32(a0) + ld s5, 40(a0) + ld s6, 48(a0) + ld s7, 56(a0) + ld s8, 64(a0) + ld s9, 72(a0) + ld s10, 80(a0) + ld s11, 88(a0) + ld sp, 96(a0) + ld ra, 104(a0) + + seqz a0, a1 + add a0, a0, a1 + ret", + options(noreturn), + ); +} diff --git a/tools/axlibc/src/strftime.rs b/tools/axlibc/src/strftime.rs new file mode 100644 index 0000000..aa3c010 --- /dev/null +++ b/tools/axlibc/src/strftime.rs @@ -0,0 +1,254 @@ +use alloc::string::String; +use core::{ffi::c_char, fmt}; + +use axio::Write; + +use crate::ctypes; + +pub trait WriteByte: fmt::Write { + fn write_u8(&mut self, byte: u8) -> fmt::Result; +} + +struct StringWriter(pub *mut u8, pub usize); + +impl Write for StringWriter { + fn write(&mut self, buf: &[u8]) -> axerrno::AxResult { + if self.1 > 1 { + let copy_size = buf.len().min(self.1 - 1); + unsafe { + core::ptr::copy_nonoverlapping(buf.as_ptr(), self.0, copy_size); + self.1 -= copy_size; + + self.0 = self.0.add(copy_size); + *self.0 = 0; + } + } + Ok(buf.len()) + } + fn flush(&mut self) -> axerrno::AxResult { + Ok(()) + } +} + +impl fmt::Write for StringWriter { + fn write_str(&mut self, s: &str) -> fmt::Result { + // can't fail + self.write(s.as_bytes()).unwrap(); + Ok(()) + } +} + +impl WriteByte for StringWriter { + fn write_u8(&mut self, byte: u8) -> fmt::Result { + // can't fail + self.write(&[byte]).unwrap(); + Ok(()) + } +} + +struct CountingWriter { + pub inner: T, + pub written: usize, +} + +impl CountingWriter { + pub fn new(writer: T) -> Self { + Self { + inner: writer, + written: 0, + } + } +} + +impl fmt::Write for CountingWriter { + fn write_str(&mut self, s: &str) -> fmt::Result { + self.written += s.len(); + self.inner.write_str(s) + } +} + +impl WriteByte for CountingWriter { + fn write_u8(&mut self, byte: u8) -> fmt::Result { + self.written += 1; + self.inner.write_u8(byte) + } +} + +impl Write for CountingWriter { + fn write(&mut self, buf: &[u8]) -> axerrno::AxResult { + let res = self.inner.write(buf); + if let Ok(written) = res { + self.written += written; + } + res + } + + fn write_all(&mut self, buf: &[u8]) -> axerrno::AxResult { + match self.inner.write_all(buf) { + Ok(()) => (), + Err(err) => return Err(err), + } + self.written += buf.len(); + Ok(()) + } + + fn flush(&mut self) -> axerrno::AxResult { + self.inner.flush() + } +} + +unsafe fn strftime_inner( + w: W, + format: *const c_char, + t: *const ctypes::tm, +) -> ctypes::size_t { + pub unsafe fn inner_strftime( + w: &mut W, + mut format: *const c_char, + t: *const ctypes::tm, + ) -> bool { + macro_rules! w { + (byte $b:expr) => {{ + if w.write_u8($b).is_err() { + return false; + } + }}; + (char $chr:expr) => {{ + if w.write_char($chr).is_err() { + return false; + } + }}; + (recurse $fmt:expr) => {{ + let mut fmt = String::with_capacity($fmt.len() + 1); + fmt.push_str($fmt); + fmt.push('\0'); + + if !inner_strftime(w, fmt.as_ptr() as *mut c_char, t) { + return false; + } + }}; + ($str:expr) => {{ + if w.write_str($str).is_err() { + return false; + } + }}; + ($fmt:expr, $($args:expr),+) => {{ + // Would use write!() if I could get the length written + if write!(w, $fmt, $($args),+).is_err() { + return false; + } + }}; + } + const WDAYS: [&str; 7] = [ + "Sunday", + "Monday", + "Tuesday", + "Wednesday", + "Thursday", + "Friday", + "Saturday", + ]; + const MONTHS: [&str; 12] = [ + "January", + "Febuary", + "March", + "April", + "May", + "June", + "July", + "August", + "September", + "October", + "November", + "December", + ]; + + while *format != 0 { + if *format as u8 != b'%' { + w!(byte * format as u8); + format = format.offset(1); + continue; + } + + format = format.offset(1); + + if *format as u8 == b'E' || *format as u8 == b'O' { + // Ignore because these do nothing without locale + format = format.offset(1); + } + + match *format as u8 { + b'%' => w!(byte b'%'), + b'n' => w!(byte b'\n'), + b't' => w!(byte b'\t'), + b'a' => w!(&WDAYS[(*t).tm_wday as usize][..3]), + b'A' => w!(WDAYS[(*t).tm_wday as usize]), + b'b' | b'h' => w!(&MONTHS[(*t).tm_mon as usize][..3]), + b'B' => w!(MONTHS[(*t).tm_mon as usize]), + b'C' => { + let mut year = (*t).tm_year / 100; + // Round up + if (*t).tm_year % 100 != 0 { + year += 1; + } + w!("{:02}", year + 19); + } + b'd' => w!("{:02}", (*t).tm_mday), + b'D' => w!(recurse "%m/%d/%y"), + b'e' => w!("{:2}", (*t).tm_mday), + b'F' => w!(recurse "%Y-%m-%d"), + b'H' => w!("{:02}", (*t).tm_hour), + b'I' => w!("{:02}", ((*t).tm_hour + 12 - 1) % 12 + 1), + b'j' => w!("{:03}", (*t).tm_yday), + b'k' => w!("{:2}", (*t).tm_hour), + b'l' => w!("{:2}", ((*t).tm_hour + 12 - 1) % 12 + 1), + b'm' => w!("{:02}", (*t).tm_mon + 1), + b'M' => w!("{:02}", (*t).tm_min), + b'p' => w!(if (*t).tm_hour < 12 { "AM" } else { "PM" }), + b'P' => w!(if (*t).tm_hour < 12 { "am" } else { "pm" }), + b'r' => w!(recurse "%I:%M:%S %p"), + b'R' => w!(recurse "%H:%M"), + // Nothing is modified in mktime, but the C standard of course requires a mutable pointer ._. + b's' => w!("{}", super::mktime(t as *mut ctypes::tm)), + b'S' => w!("{:02}", (*t).tm_sec), + b'T' => w!(recurse "%H:%M:%S"), + b'u' => w!("{}", ((*t).tm_wday + 7 - 1) % 7 + 1), + b'U' => w!("{}", ((*t).tm_yday + 7 - (*t).tm_wday) / 7), + b'w' => w!("{}", (*t).tm_wday), + b'W' => w!("{}", ((*t).tm_yday + 7 - ((*t).tm_wday + 6) % 7) / 7), + b'y' => w!("{:02}", (*t).tm_year % 100), + b'Y' => w!("{}", (*t).tm_year + 1900), + b'z' => w!("+0000"), // TODO + b'Z' => w!("UTC"), // TODO + b'+' => w!(recurse "%a %b %d %T %Z %Y"), + _ => return false, + } + + format = format.offset(1); + } + true + } + + let mut w: CountingWriter = CountingWriter::new(w); + if !inner_strftime(&mut w, format, t) { + return 0; + } + + w.written +} + +/// Convert date and time to a string. +#[no_mangle] +pub unsafe extern "C" fn strftime( + buf: *mut c_char, + size: ctypes::size_t, + format: *const c_char, + timeptr: *const ctypes::tm, +) -> ctypes::size_t { + let ret = strftime_inner(StringWriter(buf as *mut u8, size), format, timeptr); + if ret < size { + ret + } else { + 0 + } +} diff --git a/tools/axlibc/src/strtod.rs b/tools/axlibc/src/strtod.rs new file mode 100644 index 0000000..d930878 --- /dev/null +++ b/tools/axlibc/src/strtod.rs @@ -0,0 +1,131 @@ +use core::ffi::{c_char, c_double, c_float, c_int}; + +macro_rules! strto_float_impl { + ($type:ident, $s:expr, $endptr:expr) => {{ + let mut s = $s; + let endptr = $endptr; + + // TODO: Handle named floats: NaN, Inf... + + while isspace(*s as c_int) { + s = s.offset(1); + } + + let mut result: $type = 0.0; + let mut radix = 10; + + let result_sign = match *s as u8 { + b'-' => { + s = s.offset(1); + -1.0 + } + b'+' => { + s = s.offset(1); + 1.0 + } + _ => 1.0, + }; + + if *s as u8 == b'0' && *s.offset(1) as u8 == b'x' { + s = s.offset(2); + radix = 16; + } + + while let Some(digit) = (*s as u8 as char).to_digit(radix) { + result *= radix as $type; + result += digit as $type; + s = s.offset(1); + } + + if *s as u8 == b'.' { + s = s.offset(1); + + let mut i = 1.0; + while let Some(digit) = (*s as u8 as char).to_digit(radix) { + i *= radix as $type; + result += digit as $type / i; + s = s.offset(1); + } + } + + let s_before_exponent = s; + + let exponent = match (*s as u8, radix) { + (b'e' | b'E', 10) | (b'p' | b'P', 16) => { + s = s.offset(1); + + let is_exponent_positive = match *s as u8 { + b'-' => { + s = s.offset(1); + false + } + b'+' => { + s = s.offset(1); + true + } + _ => true, + }; + + // Exponent digits are always in base 10. + if (*s as u8 as char).is_digit(10) { + let mut exponent_value = 0; + + while let Some(digit) = (*s as u8 as char).to_digit(10) { + exponent_value *= 10; + exponent_value += digit; + s = s.offset(1); + } + + let exponent_base = match radix { + 10 => 10u128, + 16 => 2u128, + _ => unreachable!(), + }; + + if is_exponent_positive { + Some(exponent_base.pow(exponent_value) as $type) + } else { + Some(1.0 / (exponent_base.pow(exponent_value) as $type)) + } + } else { + // Exponent had no valid digits after 'e'/'p' and '+'/'-', rollback + s = s_before_exponent; + None + } + } + _ => None, + }; + + // Return pointer should be *mut + if !endptr.is_null() { + *endptr = s as *mut _; + } + + if let Some(exponent) = exponent { + result_sign * result * exponent + } else { + result_sign * result + } + }}; +} + +fn isspace(c: c_int) -> bool { + c == c_int::from(b' ') + || c == c_int::from(b'\t') + || c == c_int::from(b'\n') + || c == c_int::from(b'\r') + || c == 0x0b + || c == 0x0c +} + +/// Convert a string to a double-precision number. +#[no_mangle] +pub unsafe extern "C" fn strtod(s: *const c_char, endptr: *mut *mut c_char) -> c_double { + strto_float_impl!(c_double, s, endptr) +} + +/// Convert a string to a float number. +#[no_mangle] +pub unsafe extern "C" fn strtof(s: *const c_char, endptr: *mut *mut c_char) -> c_float { + strto_float_impl!(c_float, s, endptr) +} diff --git a/tools/axlibc/src/sys.rs b/tools/axlibc/src/sys.rs new file mode 100644 index 0000000..253d76f --- /dev/null +++ b/tools/axlibc/src/sys.rs @@ -0,0 +1,10 @@ +use arceos_posix_api::sys_sysconf; +use core::ffi::{c_int, c_long}; + +/// Return system configuration infomation +/// +/// Notice: currently only support what unikraft covers +#[no_mangle] +pub unsafe extern "C" fn sysconf(name: c_int) -> c_long { + sys_sysconf(name) +} diff --git a/tools/axlibc/src/time.rs b/tools/axlibc/src/time.rs new file mode 100644 index 0000000..f478cd7 --- /dev/null +++ b/tools/axlibc/src/time.rs @@ -0,0 +1,21 @@ +use arceos_posix_api::{sys_clock_gettime, sys_nanosleep}; +use core::ffi::c_int; + +use crate::{ctypes, utils::e}; + +/// Get clock time since booting +#[no_mangle] +pub unsafe extern "C" fn clock_gettime(clk: ctypes::clockid_t, ts: *mut ctypes::timespec) -> c_int { + e(sys_clock_gettime(clk, ts)) +} + +/// Sleep some nanoseconds +/// +/// TODO: should be woken by signals, and set errno +#[no_mangle] +pub unsafe extern "C" fn nanosleep( + req: *const ctypes::timespec, + rem: *mut ctypes::timespec, +) -> c_int { + e(sys_nanosleep(req, rem)) +} diff --git a/tools/axlibc/src/unistd.rs b/tools/axlibc/src/unistd.rs new file mode 100644 index 0000000..46c81bd --- /dev/null +++ b/tools/axlibc/src/unistd.rs @@ -0,0 +1,20 @@ +use arceos_posix_api::{sys_exit, sys_getpid}; +use core::ffi::c_int; + +/// Get current thread ID. +#[no_mangle] +pub unsafe extern "C" fn getpid() -> c_int { + sys_getpid() +} + +/// Abort the current process. +#[no_mangle] +pub unsafe extern "C" fn abort() -> ! { + panic!() +} + +/// Exits the current thread. +#[no_mangle] +pub unsafe extern "C" fn exit(exit_code: c_int) -> ! { + sys_exit(exit_code) +} diff --git a/tools/axlibc/src/utils.rs b/tools/axlibc/src/utils.rs new file mode 100644 index 0000000..730f8c3 --- /dev/null +++ b/tools/axlibc/src/utils.rs @@ -0,0 +1,10 @@ +use core::ffi::c_int; + +pub fn e(ret: c_int) -> c_int { + if ret < 0 { + crate::errno::set_errno(ret.abs()); + -1 + } else { + ret as _ + } +} diff --git a/tools/axlibc/src/vfp_setjmp.S b/tools/axlibc/src/vfp_setjmp.S new file mode 100644 index 0000000..fe93b87 --- /dev/null +++ b/tools/axlibc/src/vfp_setjmp.S @@ -0,0 +1,37 @@ +.section .text +.global vfp_setjmp +vfp_setjmp: + stp x19, x20, [x0,#0] + stp x21, x22, [x0,#16] + stp x23, x24, [x0,#32] + stp x25, x26, [x0,#48] + stp x27, x28, [x0,#64] + stp x29, x30, [x0,#80] + mov x2, sp + str x2, [x0,#104] + stp d8, d9, [x0,#112] + stp d10, d11, [x0,#128] + stp d12, d13, [x0,#144] + stp d14, d15, [x0,#160] + mov x0, #0 + ret + +.section .text +.global vfp_longjmp +vfp_longjmp: + ldp x19, x20, [x0,#0] + ldp x21, x22, [x0,#16] + ldp x23, x24, [x0,#32] + ldp x25, x26, [x0,#48] + ldp x27, x28, [x0,#64] + ldp x29, x30, [x0,#80] + ldr x2, [x0,#104] + mov sp, x2 + ldp d8 , d9, [x0,#112] + ldp d10, d11, [x0,#128] + ldp d12, d13, [x0,#144] + ldp d14, d15, [x0,#160] + + cmp w1, 0 + csinc w0, w1, wzr, ne + br x30