From bd5969fc876a10b18613302db7087ef3c40f18e1 Mon Sep 17 00:00:00 2001 From: Ian Moffett Date: Thu, 7 Mar 2024 17:28:00 -0500 Subject: lib: Add mlibc Signed-off-by: Ian Moffett --- lib/Makefile | 11 + lib/mlibc/.github/workflows/abidiff.yml | 158 ++ lib/mlibc/.github/workflows/ci.yml | 123 + lib/mlibc/.github/workflows/detect-bad-ifs.yml | 17 + .../workflows/detect-missing-mlibc-config.yml | 10 + lib/mlibc/.github/workflows/fixups.yml | 24 + lib/mlibc/.gitignore | 6 + lib/mlibc/ABI_BREAKS.md | 29 + lib/mlibc/LICENSE | 19 + lib/mlibc/README.md | 49 + lib/mlibc/RELEASE_PROCEDURE.md | 18 + lib/mlibc/abis/aero/auxv.h | 9 + lib/mlibc/abis/dripos/auxv.h | 8 + lib/mlibc/abis/dripos/errno.h | 149 + lib/mlibc/abis/hyra/auxv.h | 16 + lib/mlibc/abis/ironclad/access.h | 9 + lib/mlibc/abis/ironclad/auxv.h | 8 + lib/mlibc/abis/ironclad/blkcnt_t.h | 7 + lib/mlibc/abis/ironclad/blksize_t.h | 8 + lib/mlibc/abis/ironclad/clockid_t.h | 7 + lib/mlibc/abis/ironclad/dev_t.h | 6 + lib/mlibc/abis/ironclad/epoll.h | 6 + lib/mlibc/abis/ironclad/errno.h | 126 + lib/mlibc/abis/ironclad/fcntl.h | 79 + lib/mlibc/abis/ironclad/fsblkcnt_t.h | 8 + lib/mlibc/abis/ironclad/fsfilcnt_t.h | 8 + lib/mlibc/abis/ironclad/gid_t.h | 6 + lib/mlibc/abis/ironclad/in.h | 168 ++ lib/mlibc/abis/ironclad/ino_t.h | 7 + lib/mlibc/abis/ironclad/inotify.h | 7 + lib/mlibc/abis/ironclad/ioctls.h | 13 + lib/mlibc/abis/ironclad/limits.h | 14 + lib/mlibc/abis/ironclad/mode_t.h | 6 + lib/mlibc/abis/ironclad/mqueue.h | 20 + lib/mlibc/abis/ironclad/msg.h | 39 + lib/mlibc/abis/ironclad/nlink_t.h | 6 + lib/mlibc/abis/ironclad/packet.h | 6 + lib/mlibc/abis/ironclad/pid_t.h | 6 + lib/mlibc/abis/ironclad/poll.h | 16 + lib/mlibc/abis/ironclad/ptrace.h | 56 + lib/mlibc/abis/ironclad/reboot.h | 12 + lib/mlibc/abis/ironclad/resource.h | 53 + lib/mlibc/abis/ironclad/seek-whence.h | 8 + lib/mlibc/abis/ironclad/shm.h | 21 + lib/mlibc/abis/ironclad/signal.h | 192 ++ lib/mlibc/abis/ironclad/socket.h | 165 ++ lib/mlibc/abis/ironclad/socklen_t.h | 6 + lib/mlibc/abis/ironclad/stat.h | 69 + lib/mlibc/abis/ironclad/statfs.h | 28 + lib/mlibc/abis/ironclad/statvfs.h | 30 + lib/mlibc/abis/ironclad/suseconds_t.h | 8 + lib/mlibc/abis/ironclad/termios.h | 116 + lib/mlibc/abis/ironclad/time.h | 15 + lib/mlibc/abis/ironclad/uid_t.h | 6 + lib/mlibc/abis/ironclad/utsname.h | 12 + lib/mlibc/abis/ironclad/vm-flags.h | 46 + lib/mlibc/abis/ironclad/wait.h | 25 + lib/mlibc/abis/ironclad/xattr.h | 21 + lib/mlibc/abis/lemon/auxv.h | 9 + lib/mlibc/abis/linux/access.h | 9 + lib/mlibc/abis/linux/auxv.h | 13 + lib/mlibc/abis/linux/blkcnt_t.h | 8 + lib/mlibc/abis/linux/blksize_t.h | 8 + lib/mlibc/abis/linux/clockid_t.h | 7 + lib/mlibc/abis/linux/dev_t.h | 10 + lib/mlibc/abis/linux/epoll.h | 6 + lib/mlibc/abis/linux/errno.h | 143 + lib/mlibc/abis/linux/fcntl.h | 89 + lib/mlibc/abis/linux/fsblkcnt_t.h | 8 + lib/mlibc/abis/linux/fsfilcnt_t.h | 8 + lib/mlibc/abis/linux/gid_t.h | 8 + lib/mlibc/abis/linux/in.h | 217 ++ lib/mlibc/abis/linux/ino_t.h | 10 + lib/mlibc/abis/linux/inotify.h | 9 + lib/mlibc/abis/linux/ioctls.h | 15 + lib/mlibc/abis/linux/limits.h | 9 + lib/mlibc/abis/linux/mode_t.h | 8 + lib/mlibc/abis/linux/mqueue.h | 21 + lib/mlibc/abis/linux/msg.h | 39 + lib/mlibc/abis/linux/nlink_t.h | 8 + lib/mlibc/abis/linux/packet.h | 6 + lib/mlibc/abis/linux/pid_t.h | 8 + lib/mlibc/abis/linux/poll.h | 16 + lib/mlibc/abis/linux/ptrace.h | 59 + lib/mlibc/abis/linux/reboot.h | 12 + lib/mlibc/abis/linux/resource.h | 53 + lib/mlibc/abis/linux/seek-whence.h | 10 + lib/mlibc/abis/linux/shm.h | 25 + lib/mlibc/abis/linux/signal.h | 496 ++++ lib/mlibc/abis/linux/socket.h | 299 ++ lib/mlibc/abis/linux/socklen_t.h | 6 + lib/mlibc/abis/linux/stat.h | 123 + lib/mlibc/abis/linux/statfs.h | 28 + lib/mlibc/abis/linux/statvfs.h | 29 + lib/mlibc/abis/linux/suseconds_t.h | 8 + lib/mlibc/abis/linux/termios.h | 155 + lib/mlibc/abis/linux/time.h | 15 + lib/mlibc/abis/linux/uid_t.h | 8 + lib/mlibc/abis/linux/utsname.h | 13 + lib/mlibc/abis/linux/vm-flags.h | 70 + lib/mlibc/abis/linux/vt.h | 76 + lib/mlibc/abis/linux/wait.h | 28 + lib/mlibc/abis/linux/xattr.h | 21 + lib/mlibc/abis/lyre/statvfs.h | 35 + lib/mlibc/abis/managarm/auxv.h | 16 + lib/mlibc/abis/mlibc/access.h | 9 + lib/mlibc/abis/mlibc/blkcnt_t.h | 7 + lib/mlibc/abis/mlibc/blksize_t.h | 9 + lib/mlibc/abis/mlibc/clockid_t.h | 7 + lib/mlibc/abis/mlibc/dev_t.h | 8 + lib/mlibc/abis/mlibc/epoll.h | 6 + lib/mlibc/abis/mlibc/errno.h | 126 + lib/mlibc/abis/mlibc/fcntl.h | 76 + lib/mlibc/abis/mlibc/gid_t.h | 8 + lib/mlibc/abis/mlibc/in.h | 168 ++ lib/mlibc/abis/mlibc/ino_t.h | 9 + lib/mlibc/abis/mlibc/inotify.h | 7 + lib/mlibc/abis/mlibc/limits.h | 14 + lib/mlibc/abis/mlibc/mode_t.h | 8 + lib/mlibc/abis/mlibc/nlink_t.h | 8 + lib/mlibc/abis/mlibc/packet.h | 6 + lib/mlibc/abis/mlibc/pid_t.h | 8 + lib/mlibc/abis/mlibc/poll.h | 16 + lib/mlibc/abis/mlibc/ptrace.h | 56 + lib/mlibc/abis/mlibc/resource.h | 53 + lib/mlibc/abis/mlibc/seek-whence.h | 10 + lib/mlibc/abis/mlibc/signal.h | 195 ++ lib/mlibc/abis/mlibc/socket.h | 165 ++ lib/mlibc/abis/mlibc/stat.h | 69 + lib/mlibc/abis/mlibc/termios.h | 118 + lib/mlibc/abis/mlibc/time.h | 15 + lib/mlibc/abis/mlibc/uid_t.h | 8 + lib/mlibc/abis/mlibc/utsname.h | 17 + lib/mlibc/abis/mlibc/vm-flags.h | 46 + lib/mlibc/abis/mlibc/wait.h | 30 + lib/mlibc/ci/abidiff_suppress.ini | 2 + lib/mlibc/ci/aero.cross-file | 12 + lib/mlibc/ci/bootstrap.yml | 181 ++ lib/mlibc/ci/dripos.cross-file | 12 + lib/mlibc/ci/ironclad.cross-file | 12 + lib/mlibc/ci/keyronex.cross-file | 9 + lib/mlibc/ci/lemon.cross-file | 12 + lib/mlibc/ci/linux-aarch64.cross-file | 13 + lib/mlibc/ci/linux-riscv64.cross-file | 13 + lib/mlibc/ci/linux-x86.cross-file | 10 + lib/mlibc/ci/linux-x86_64.cross-file | 9 + lib/mlibc/ci/lyre.cross-file | 12 + lib/mlibc/ci/managarm.cross-file | 12 + lib/mlibc/cross_file.txt | 12 + lib/mlibc/crossbin | 1 + lib/mlibc/dummy-libs/libcrypt/src/dummy.cpp | 6 + lib/mlibc/dummy-libs/libdl/src/dummy.cpp | 6 + lib/mlibc/dummy-libs/libm/src/dummy.cpp | 6 + lib/mlibc/dummy-libs/libpthread/src/dummy.cpp | 6 + lib/mlibc/dummy-libs/libresolv/src/dummy.cpp | 6 + lib/mlibc/dummy-libs/librt/src/dummy.cpp | 6 + lib/mlibc/dummy-libs/libssp/src/dummy.cpp | 6 + .../dummy-libs/libssp_nonshared/src/dummy.cpp | 6 + lib/mlibc/dummy-libs/libutil/src/dummy.cpp | 6 + lib/mlibc/internal-config.h.in | 9 + lib/mlibc/meson.build | 528 ++++ lib/mlibc/meson_options.txt | 16 + lib/mlibc/mlibc-config.h.in | 14 + lib/mlibc/options/ansi/generic/assert-stubs.cpp | 13 + lib/mlibc/options/ansi/generic/complex-stubs.c | 9 + lib/mlibc/options/ansi/generic/complex/cabs.c | 53 + lib/mlibc/options/ansi/generic/complex/cabsf.c | 19 + lib/mlibc/options/ansi/generic/complex/cacos.c | 99 + lib/mlibc/options/ansi/generic/complex/cacosf.c | 46 + lib/mlibc/options/ansi/generic/complex/cacosh.c | 93 + lib/mlibc/options/ansi/generic/complex/cacoshf.c | 48 + lib/mlibc/options/ansi/generic/complex/carg.c | 59 + lib/mlibc/options/ansi/generic/complex/cargf.c | 19 + lib/mlibc/options/ansi/generic/complex/casin.c | 165 ++ lib/mlibc/options/ansi/generic/complex/casinf.c | 122 + lib/mlibc/options/ansi/generic/complex/casinh.c | 97 + lib/mlibc/options/ansi/generic/complex/casinhf.c | 44 + lib/mlibc/options/ansi/generic/complex/catan.c | 130 + lib/mlibc/options/ansi/generic/complex/catanf.c | 79 + lib/mlibc/options/ansi/generic/complex/catanh.c | 90 + lib/mlibc/options/ansi/generic/complex/catanhf.c | 44 + lib/mlibc/options/ansi/generic/complex/ccos.c | 81 + lib/mlibc/options/ansi/generic/complex/ccosf.c | 48 + lib/mlibc/options/ansi/generic/complex/ccosh.c | 81 + lib/mlibc/options/ansi/generic/complex/ccoshf.c | 48 + .../options/ansi/generic/complex/cephes_subr.c | 126 + .../options/ansi/generic/complex/cephes_subr.h | 9 + .../options/ansi/generic/complex/cephes_subrf.c | 125 + .../options/ansi/generic/complex/cephes_subrf.h | 9 + lib/mlibc/options/ansi/generic/complex/cexp.c | 82 + lib/mlibc/options/ansi/generic/complex/cexpf.c | 49 + lib/mlibc/options/ansi/generic/complex/cimag.c | 54 + lib/mlibc/options/ansi/generic/complex/cimagf.c | 21 + lib/mlibc/options/ansi/generic/complex/clog.c | 91 + lib/mlibc/options/ansi/generic/complex/clogf.c | 49 + lib/mlibc/options/ansi/generic/complex/conj.c | 56 + lib/mlibc/options/ansi/generic/complex/conjf.c | 23 + lib/mlibc/options/ansi/generic/complex/cpow.c | 101 + lib/mlibc/options/ansi/generic/complex/cpowf.c | 59 + lib/mlibc/options/ansi/generic/complex/cproj.c | 105 + lib/mlibc/options/ansi/generic/complex/cprojf.c | 67 + lib/mlibc/options/ansi/generic/complex/creal.c | 54 + lib/mlibc/options/ansi/generic/complex/crealf.c | 21 + lib/mlibc/options/ansi/generic/complex/csin.c | 81 + lib/mlibc/options/ansi/generic/complex/csinf.c | 48 + lib/mlibc/options/ansi/generic/complex/csinh.c | 80 + lib/mlibc/options/ansi/generic/complex/csinhf.c | 48 + lib/mlibc/options/ansi/generic/complex/csqrt.c | 137 + lib/mlibc/options/ansi/generic/complex/csqrtf.c | 102 + lib/mlibc/options/ansi/generic/complex/ctan.c | 91 + lib/mlibc/options/ansi/generic/complex/ctanf.c | 58 + lib/mlibc/options/ansi/generic/complex/ctanh.c | 83 + lib/mlibc/options/ansi/generic/complex/ctanhf.c | 50 + lib/mlibc/options/ansi/generic/complex/fdlibm.h | 17 + lib/mlibc/options/ansi/generic/ctype-stubs.cpp | 326 +++ lib/mlibc/options/ansi/generic/environment.cpp | 164 ++ lib/mlibc/options/ansi/generic/errno-stubs.cpp | 12 + lib/mlibc/options/ansi/generic/fenv-stubs.cpp | 43 + lib/mlibc/options/ansi/generic/file-io.cpp | 745 +++++ lib/mlibc/options/ansi/generic/inttypes-stubs.cpp | 100 + lib/mlibc/options/ansi/generic/locale-stubs.cpp | 195 ++ .../options/ansi/generic/math-stubs.ignored-cpp | 1831 ++++++++++++ lib/mlibc/options/ansi/generic/signal-stubs.cpp | 44 + lib/mlibc/options/ansi/generic/stdio-stubs.cpp | 1270 +++++++++ lib/mlibc/options/ansi/generic/stdlib-stubs.cpp | 511 ++++ lib/mlibc/options/ansi/generic/string-stubs.cpp | 542 ++++ lib/mlibc/options/ansi/generic/threads.cpp | 97 + lib/mlibc/options/ansi/generic/time-stubs.cpp | 729 +++++ lib/mlibc/options/ansi/generic/uchar.cpp | 23 + lib/mlibc/options/ansi/generic/wchar-stubs.cpp | 783 ++++++ lib/mlibc/options/ansi/generic/wctype.cpp | 9 + lib/mlibc/options/ansi/include/alloca.h | 8 + lib/mlibc/options/ansi/include/assert.h | 46 + lib/mlibc/options/ansi/include/bits/ansi/fenv.h | 54 + lib/mlibc/options/ansi/include/bits/ansi/time_t.h | 8 + .../options/ansi/include/bits/ansi/timespec.h | 13 + lib/mlibc/options/ansi/include/complex.h | 134 + lib/mlibc/options/ansi/include/ctype.h | 46 + lib/mlibc/options/ansi/include/errno.h | 31 + lib/mlibc/options/ansi/include/fenv.h | 44 + lib/mlibc/options/ansi/include/inttypes.h | 146 + lib/mlibc/options/ansi/include/limits.h | 117 + lib/mlibc/options/ansi/include/locale.h | 81 + lib/mlibc/options/ansi/include/math.h | 383 +++ .../options/ansi/include/mlibc/ansi-sysdeps.hpp | 71 + .../options/ansi/include/mlibc/environment.hpp | 10 + lib/mlibc/options/ansi/include/mlibc/file-io.hpp | 111 + lib/mlibc/options/ansi/include/setjmp.h | 48 + lib/mlibc/options/ansi/include/signal.h | 48 + lib/mlibc/options/ansi/include/stdc-predef.h | 6 + lib/mlibc/options/ansi/include/stdio.h | 229 ++ lib/mlibc/options/ansi/include/stdlib.h | 128 + lib/mlibc/options/ansi/include/string.h | 107 + lib/mlibc/options/ansi/include/threads.h | 61 + lib/mlibc/options/ansi/include/time.h | 154 + lib/mlibc/options/ansi/include/uchar.h | 29 + lib/mlibc/options/ansi/include/wchar.h | 128 + lib/mlibc/options/ansi/include/wctype.h | 52 + lib/mlibc/options/ansi/meson.build | 326 +++ lib/mlibc/options/ansi/musl-generic-math/__cos.c | 71 + lib/mlibc/options/ansi/musl-generic-math/__cosdf.c | 35 + lib/mlibc/options/ansi/musl-generic-math/__cosl.c | 96 + lib/mlibc/options/ansi/musl-generic-math/__expo2.c | 16 + .../options/ansi/musl-generic-math/__expo2f.c | 16 + .../options/ansi/musl-generic-math/__fpclassify.c | 11 + .../options/ansi/musl-generic-math/__fpclassifyf.c | 11 + .../options/ansi/musl-generic-math/__fpclassifyl.c | 34 + .../options/ansi/musl-generic-math/__invtrigl.c | 63 + .../options/ansi/musl-generic-math/__invtrigl.h | 11 + .../options/ansi/musl-generic-math/__polevll.c | 93 + .../options/ansi/musl-generic-math/__rem_pio2.c | 177 ++ .../ansi/musl-generic-math/__rem_pio2_large.c | 442 +++ .../options/ansi/musl-generic-math/__rem_pio2f.c | 75 + .../options/ansi/musl-generic-math/__rem_pio2l.c | 141 + .../options/ansi/musl-generic-math/__signbit.c | 13 + .../options/ansi/musl-generic-math/__signbitf.c | 11 + .../options/ansi/musl-generic-math/__signbitl.c | 14 + lib/mlibc/options/ansi/musl-generic-math/__sin.c | 64 + lib/mlibc/options/ansi/musl-generic-math/__sindf.c | 36 + lib/mlibc/options/ansi/musl-generic-math/__sinl.c | 78 + lib/mlibc/options/ansi/musl-generic-math/__tan.c | 110 + lib/mlibc/options/ansi/musl-generic-math/__tandf.c | 54 + lib/mlibc/options/ansi/musl-generic-math/__tanl.c | 143 + lib/mlibc/options/ansi/musl-generic-math/acos.c | 101 + lib/mlibc/options/ansi/musl-generic-math/acosf.c | 71 + lib/mlibc/options/ansi/musl-generic-math/acosh.c | 24 + lib/mlibc/options/ansi/musl-generic-math/acoshf.c | 26 + lib/mlibc/options/ansi/musl-generic-math/acoshl.c | 29 + lib/mlibc/options/ansi/musl-generic-math/acosl.c | 67 + lib/mlibc/options/ansi/musl-generic-math/asin.c | 107 + lib/mlibc/options/ansi/musl-generic-math/asinf.c | 61 + lib/mlibc/options/ansi/musl-generic-math/asinh.c | 28 + lib/mlibc/options/ansi/musl-generic-math/asinhf.c | 28 + lib/mlibc/options/ansi/musl-generic-math/asinhl.c | 41 + lib/mlibc/options/ansi/musl-generic-math/asinl.c | 71 + lib/mlibc/options/ansi/musl-generic-math/atan.c | 116 + lib/mlibc/options/ansi/musl-generic-math/atan2.c | 107 + lib/mlibc/options/ansi/musl-generic-math/atan2f.c | 83 + lib/mlibc/options/ansi/musl-generic-math/atan2l.c | 85 + lib/mlibc/options/ansi/musl-generic-math/atanf.c | 94 + lib/mlibc/options/ansi/musl-generic-math/atanh.c | 29 + lib/mlibc/options/ansi/musl-generic-math/atanhf.c | 28 + lib/mlibc/options/ansi/musl-generic-math/atanhl.c | 35 + lib/mlibc/options/ansi/musl-generic-math/atanl.c | 184 ++ lib/mlibc/options/ansi/musl-generic-math/cbrt.c | 103 + lib/mlibc/options/ansi/musl-generic-math/cbrtf.c | 66 + lib/mlibc/options/ansi/musl-generic-math/cbrtl.c | 124 + lib/mlibc/options/ansi/musl-generic-math/ceil.c | 31 + lib/mlibc/options/ansi/musl-generic-math/ceilf.c | 27 + lib/mlibc/options/ansi/musl-generic-math/ceill.c | 34 + .../options/ansi/musl-generic-math/copysign.c | 8 + .../options/ansi/musl-generic-math/copysignf.c | 10 + .../options/ansi/musl-generic-math/copysignl.c | 16 + lib/mlibc/options/ansi/musl-generic-math/cos.c | 77 + lib/mlibc/options/ansi/musl-generic-math/cosf.c | 78 + lib/mlibc/options/ansi/musl-generic-math/cosh.c | 40 + lib/mlibc/options/ansi/musl-generic-math/coshf.c | 33 + lib/mlibc/options/ansi/musl-generic-math/coshl.c | 47 + lib/mlibc/options/ansi/musl-generic-math/cosl.c | 39 + lib/mlibc/options/ansi/musl-generic-math/erf.c | 273 ++ lib/mlibc/options/ansi/musl-generic-math/erff.c | 183 ++ lib/mlibc/options/ansi/musl-generic-math/erfl.c | 353 +++ lib/mlibc/options/ansi/musl-generic-math/exp.c | 134 + lib/mlibc/options/ansi/musl-generic-math/exp10.c | 26 + lib/mlibc/options/ansi/musl-generic-math/exp10f.c | 24 + lib/mlibc/options/ansi/musl-generic-math/exp10l.c | 34 + lib/mlibc/options/ansi/musl-generic-math/exp2.c | 375 +++ lib/mlibc/options/ansi/musl-generic-math/exp2f.c | 126 + lib/mlibc/options/ansi/musl-generic-math/exp2l.c | 619 ++++ lib/mlibc/options/ansi/musl-generic-math/expf.c | 83 + lib/mlibc/options/ansi/musl-generic-math/expl.c | 128 + lib/mlibc/options/ansi/musl-generic-math/expm1.c | 201 ++ lib/mlibc/options/ansi/musl-generic-math/expm1f.c | 111 + lib/mlibc/options/ansi/musl-generic-math/expm1l.c | 123 + lib/mlibc/options/ansi/musl-generic-math/fabs.c | 9 + lib/mlibc/options/ansi/musl-generic-math/fabsf.c | 9 + lib/mlibc/options/ansi/musl-generic-math/fabsl.c | 15 + lib/mlibc/options/ansi/musl-generic-math/fdim.c | 10 + lib/mlibc/options/ansi/musl-generic-math/fdimf.c | 10 + lib/mlibc/options/ansi/musl-generic-math/fdiml.c | 18 + lib/mlibc/options/ansi/musl-generic-math/finite.c | 7 + lib/mlibc/options/ansi/musl-generic-math/finitef.c | 7 + lib/mlibc/options/ansi/musl-generic-math/floor.c | 31 + lib/mlibc/options/ansi/musl-generic-math/floorf.c | 27 + lib/mlibc/options/ansi/musl-generic-math/floorl.c | 34 + lib/mlibc/options/ansi/musl-generic-math/fma.c | 194 ++ lib/mlibc/options/ansi/musl-generic-math/fmaf.c | 93 + lib/mlibc/options/ansi/musl-generic-math/fmal.c | 293 ++ lib/mlibc/options/ansi/musl-generic-math/fmax.c | 13 + lib/mlibc/options/ansi/musl-generic-math/fmaxf.c | 13 + lib/mlibc/options/ansi/musl-generic-math/fmaxl.c | 21 + lib/mlibc/options/ansi/musl-generic-math/fmin.c | 13 + lib/mlibc/options/ansi/musl-generic-math/fminf.c | 13 + lib/mlibc/options/ansi/musl-generic-math/fminl.c | 21 + lib/mlibc/options/ansi/musl-generic-math/fmod.c | 68 + lib/mlibc/options/ansi/musl-generic-math/fmodf.c | 65 + lib/mlibc/options/ansi/musl-generic-math/fmodl.c | 105 + lib/mlibc/options/ansi/musl-generic-math/frexp.c | 23 + lib/mlibc/options/ansi/musl-generic-math/frexpf.c | 23 + lib/mlibc/options/ansi/musl-generic-math/frexpl.c | 29 + lib/mlibc/options/ansi/musl-generic-math/hypot.c | 67 + lib/mlibc/options/ansi/musl-generic-math/hypotf.c | 35 + lib/mlibc/options/ansi/musl-generic-math/hypotl.c | 66 + lib/mlibc/options/ansi/musl-generic-math/ilogb.c | 26 + lib/mlibc/options/ansi/musl-generic-math/ilogbf.c | 26 + lib/mlibc/options/ansi/musl-generic-math/ilogbl.c | 55 + lib/mlibc/options/ansi/musl-generic-math/j0.c | 375 +++ lib/mlibc/options/ansi/musl-generic-math/j0f.c | 314 +++ lib/mlibc/options/ansi/musl-generic-math/j1.c | 362 +++ lib/mlibc/options/ansi/musl-generic-math/j1f.c | 310 ++ lib/mlibc/options/ansi/musl-generic-math/jn.c | 280 ++ lib/mlibc/options/ansi/musl-generic-math/jnf.c | 202 ++ lib/mlibc/options/ansi/musl-generic-math/ldexp.c | 6 + lib/mlibc/options/ansi/musl-generic-math/ldexpf.c | 6 + lib/mlibc/options/ansi/musl-generic-math/ldexpl.c | 6 + lib/mlibc/options/ansi/musl-generic-math/lgamma.c | 9 + .../options/ansi/musl-generic-math/lgamma_r.c | 285 ++ lib/mlibc/options/ansi/musl-generic-math/lgammaf.c | 9 + .../options/ansi/musl-generic-math/lgammaf_r.c | 220 ++ lib/mlibc/options/ansi/musl-generic-math/lgammal.c | 361 +++ lib/mlibc/options/ansi/musl-generic-math/libm.h | 186 ++ lib/mlibc/options/ansi/musl-generic-math/llrint.c | 8 + lib/mlibc/options/ansi/musl-generic-math/llrintf.c | 8 + lib/mlibc/options/ansi/musl-generic-math/llrintl.c | 36 + lib/mlibc/options/ansi/musl-generic-math/llround.c | 6 + .../options/ansi/musl-generic-math/llroundf.c | 6 + .../options/ansi/musl-generic-math/llroundl.c | 6 + lib/mlibc/options/ansi/musl-generic-math/log.c | 118 + lib/mlibc/options/ansi/musl-generic-math/log10.c | 101 + lib/mlibc/options/ansi/musl-generic-math/log10f.c | 77 + lib/mlibc/options/ansi/musl-generic-math/log10l.c | 191 ++ lib/mlibc/options/ansi/musl-generic-math/log1p.c | 122 + lib/mlibc/options/ansi/musl-generic-math/log1pf.c | 77 + lib/mlibc/options/ansi/musl-generic-math/log1pl.c | 177 ++ lib/mlibc/options/ansi/musl-generic-math/log2.c | 122 + lib/mlibc/options/ansi/musl-generic-math/log2f.c | 74 + lib/mlibc/options/ansi/musl-generic-math/log2l.c | 182 ++ lib/mlibc/options/ansi/musl-generic-math/logb.c | 17 + lib/mlibc/options/ansi/musl-generic-math/logbf.c | 10 + lib/mlibc/options/ansi/musl-generic-math/logbl.c | 16 + lib/mlibc/options/ansi/musl-generic-math/logf.c | 69 + lib/mlibc/options/ansi/musl-generic-math/logl.c | 175 ++ lib/mlibc/options/ansi/musl-generic-math/lrint.c | 46 + lib/mlibc/options/ansi/musl-generic-math/lrintf.c | 8 + lib/mlibc/options/ansi/musl-generic-math/lrintl.c | 36 + lib/mlibc/options/ansi/musl-generic-math/lround.c | 6 + lib/mlibc/options/ansi/musl-generic-math/lroundf.c | 6 + lib/mlibc/options/ansi/musl-generic-math/lroundl.c | 6 + lib/mlibc/options/ansi/musl-generic-math/modf.c | 34 + lib/mlibc/options/ansi/musl-generic-math/modff.c | 34 + lib/mlibc/options/ansi/musl-generic-math/modfl.c | 53 + lib/mlibc/options/ansi/musl-generic-math/nan.c | 6 + lib/mlibc/options/ansi/musl-generic-math/nanf.c | 6 + lib/mlibc/options/ansi/musl-generic-math/nanl.c | 6 + .../options/ansi/musl-generic-math/nearbyint.c | 20 + .../options/ansi/musl-generic-math/nearbyintf.c | 18 + .../options/ansi/musl-generic-math/nearbyintl.c | 26 + .../options/ansi/musl-generic-math/nextafter.c | 31 + .../options/ansi/musl-generic-math/nextafterf.c | 30 + .../options/ansi/musl-generic-math/nextafterl.c | 75 + .../options/ansi/musl-generic-math/nexttoward.c | 42 + .../options/ansi/musl-generic-math/nexttowardf.c | 35 + .../options/ansi/musl-generic-math/nexttowardl.c | 6 + lib/mlibc/options/ansi/musl-generic-math/pow.c | 328 +++ lib/mlibc/options/ansi/musl-generic-math/powf.c | 259 ++ lib/mlibc/options/ansi/musl-generic-math/powl.c | 522 ++++ .../options/ansi/musl-generic-math/remainder.c | 11 + .../options/ansi/musl-generic-math/remainderf.c | 11 + .../options/ansi/musl-generic-math/remainderl.c | 15 + lib/mlibc/options/ansi/musl-generic-math/remquo.c | 82 + lib/mlibc/options/ansi/musl-generic-math/remquof.c | 82 + lib/mlibc/options/ansi/musl-generic-math/remquol.c | 124 + lib/mlibc/options/ansi/musl-generic-math/rint.c | 28 + lib/mlibc/options/ansi/musl-generic-math/rintf.c | 30 + lib/mlibc/options/ansi/musl-generic-math/rintl.c | 29 + lib/mlibc/options/ansi/musl-generic-math/round.c | 35 + lib/mlibc/options/ansi/musl-generic-math/roundf.c | 36 + lib/mlibc/options/ansi/musl-generic-math/roundl.c | 37 + lib/mlibc/options/ansi/musl-generic-math/scalb.c | 35 + lib/mlibc/options/ansi/musl-generic-math/scalbf.c | 32 + lib/mlibc/options/ansi/musl-generic-math/scalbln.c | 12 + .../options/ansi/musl-generic-math/scalblnf.c | 12 + .../options/ansi/musl-generic-math/scalblnl.c | 20 + lib/mlibc/options/ansi/musl-generic-math/scalbn.c | 33 + lib/mlibc/options/ansi/musl-generic-math/scalbnf.c | 31 + lib/mlibc/options/ansi/musl-generic-math/scalbnl.c | 36 + lib/mlibc/options/ansi/musl-generic-math/signgam.c | 5 + .../options/ansi/musl-generic-math/significand.c | 7 + .../options/ansi/musl-generic-math/significandf.c | 7 + lib/mlibc/options/ansi/musl-generic-math/sin.c | 78 + lib/mlibc/options/ansi/musl-generic-math/sincos.c | 69 + lib/mlibc/options/ansi/musl-generic-math/sincosf.c | 117 + lib/mlibc/options/ansi/musl-generic-math/sincosl.c | 60 + lib/mlibc/options/ansi/musl-generic-math/sinf.c | 76 + lib/mlibc/options/ansi/musl-generic-math/sinh.c | 39 + lib/mlibc/options/ansi/musl-generic-math/sinhf.c | 31 + lib/mlibc/options/ansi/musl-generic-math/sinhl.c | 43 + lib/mlibc/options/ansi/musl-generic-math/sinl.c | 41 + lib/mlibc/options/ansi/musl-generic-math/sqrt.c | 185 ++ lib/mlibc/options/ansi/musl-generic-math/sqrtf.c | 84 + lib/mlibc/options/ansi/musl-generic-math/sqrtl.c | 7 + lib/mlibc/options/ansi/musl-generic-math/tan.c | 70 + lib/mlibc/options/ansi/musl-generic-math/tanf.c | 64 + lib/mlibc/options/ansi/musl-generic-math/tanh.c | 45 + lib/mlibc/options/ansi/musl-generic-math/tanhf.c | 39 + lib/mlibc/options/ansi/musl-generic-math/tanhl.c | 48 + lib/mlibc/options/ansi/musl-generic-math/tanl.c | 29 + lib/mlibc/options/ansi/musl-generic-math/tgamma.c | 222 ++ lib/mlibc/options/ansi/musl-generic-math/tgammaf.c | 6 + lib/mlibc/options/ansi/musl-generic-math/tgammal.c | 281 ++ lib/mlibc/options/ansi/musl-generic-math/trunc.c | 19 + lib/mlibc/options/ansi/musl-generic-math/truncf.c | 19 + lib/mlibc/options/ansi/musl-generic-math/truncl.c | 34 + .../options/ansi/musl-generic-math/weak_alias.h | 7 + .../options/bsd/generic/arpa-nameser-stubs.cpp | 41 + lib/mlibc/options/bsd/generic/ether.cpp | 19 + lib/mlibc/options/bsd/generic/getopt.cpp | 8 + lib/mlibc/options/bsd/include/arpa/nameser.h | 266 ++ .../options/bsd/include/arpa/nameser_compat.h | 1 + .../options/bsd/include/bits/bsd/bsd_unistd.h | 20 + lib/mlibc/options/bsd/include/fstab.h | 23 + .../options/bsd/include/mlibc/bsd-sysdeps.hpp | 10 + lib/mlibc/options/bsd/include/netinet/ether.h | 23 + lib/mlibc/options/bsd/include/sys/queue.h | 574 ++++ lib/mlibc/options/bsd/meson.build | 32 + lib/mlibc/options/crypt/generic/crypt-stubs.cpp | 7 + lib/mlibc/options/crypt/include/crypt.h | 18 + lib/mlibc/options/crypt/meson.build | 13 + lib/mlibc/options/elf/generic/phdr.cpp | 10 + lib/mlibc/options/elf/generic/startup.cpp | 73 + lib/mlibc/options/elf/include/elf.h | 667 +++++ lib/mlibc/options/elf/include/link.h | 58 + lib/mlibc/options/elf/include/mlibc/elf/startup.h | 28 + lib/mlibc/options/elf/meson.build | 11 + lib/mlibc/options/glibc/generic/err.cpp | 64 + lib/mlibc/options/glibc/generic/error.cpp | 65 + lib/mlibc/options/glibc/generic/execinfo.cpp | 17 + lib/mlibc/options/glibc/generic/getopt-stubs.cpp | 253 ++ lib/mlibc/options/glibc/generic/glibc-assert.cpp | 14 + lib/mlibc/options/glibc/generic/glibc-signal.cpp | 14 + lib/mlibc/options/glibc/generic/gshadow.cpp | 7 + lib/mlibc/options/glibc/generic/malloc.cpp | 6 + lib/mlibc/options/glibc/generic/personality.cpp | 15 + lib/mlibc/options/glibc/generic/printf.cpp | 7 + lib/mlibc/options/glibc/generic/resolv-stubs.cpp | 36 + lib/mlibc/options/glibc/generic/shadow-stubs.cpp | 217 ++ .../options/glibc/generic/stdio_ext-stubs.cpp | 64 + lib/mlibc/options/glibc/generic/string.cpp | 32 + lib/mlibc/options/glibc/generic/sys-io.cpp | 25 + lib/mlibc/options/glibc/generic/sys-ioctl.cpp | 21 + lib/mlibc/options/glibc/generic/sys-timex.cpp | 17 + lib/mlibc/options/glibc/include/ar.h | 27 + .../glibc/include/bits/glibc/glibc_assert.h | 32 + .../options/glibc/include/bits/glibc/glibc_icmp6.h | 21 + .../glibc/include/bits/glibc/glibc_malloc.h | 17 + .../glibc/include/bits/glibc/glibc_signal.h | 24 + lib/mlibc/options/glibc/include/endian.h | 54 + lib/mlibc/options/glibc/include/err.h | 29 + lib/mlibc/options/glibc/include/error.h | 25 + lib/mlibc/options/glibc/include/execinfo.h | 20 + lib/mlibc/options/glibc/include/features.h | 6 + lib/mlibc/options/glibc/include/getopt.h | 44 + lib/mlibc/options/glibc/include/gshadow.h | 30 + lib/mlibc/options/glibc/include/memory.h | 6 + .../options/glibc/include/mlibc/glibc-sysdeps.hpp | 16 + lib/mlibc/options/glibc/include/net/ethernet.h | 42 + lib/mlibc/options/glibc/include/net/if_ppp.h | 23 + lib/mlibc/options/glibc/include/net/route.h | 35 + lib/mlibc/options/glibc/include/netax25/ax25.h | 51 + lib/mlibc/options/glibc/include/netinet/in_systm.h | 7 + lib/mlibc/options/glibc/include/netipx/ipx.h | 35 + lib/mlibc/options/glibc/include/netrom/netrom.h | 27 + lib/mlibc/options/glibc/include/paths.h | 41 + lib/mlibc/options/glibc/include/printf.h | 41 + lib/mlibc/options/glibc/include/resolv.h | 73 + lib/mlibc/options/glibc/include/shadow.h | 42 + lib/mlibc/options/glibc/include/stdio_ext.h | 41 + lib/mlibc/options/glibc/include/sys/dir.h | 8 + lib/mlibc/options/glibc/include/sys/endian.h | 0 lib/mlibc/options/glibc/include/sys/errno.h | 1 + lib/mlibc/options/glibc/include/sys/io.h | 108 + lib/mlibc/options/glibc/include/sys/ioctl.h | 44 + lib/mlibc/options/glibc/include/sys/kd.h | 17 + lib/mlibc/options/glibc/include/sys/mtio.h | 103 + lib/mlibc/options/glibc/include/sys/personality.h | 58 + lib/mlibc/options/glibc/include/sys/procfs.h | 54 + lib/mlibc/options/glibc/include/sys/reg.h | 36 + lib/mlibc/options/glibc/include/sys/signal.h | 1 + lib/mlibc/options/glibc/include/sys/timeb.h | 14 + lib/mlibc/options/glibc/include/sys/timex.h | 78 + lib/mlibc/options/glibc/include/sys/ucontext.h | 14 + lib/mlibc/options/glibc/include/sys/user.h | 49 + lib/mlibc/options/glibc/include/sysexits.h | 24 + lib/mlibc/options/glibc/meson.build | 90 + lib/mlibc/options/iconv/generic/iconv-stubs.cpp | 34 + lib/mlibc/options/iconv/include/iconv.h | 25 + lib/mlibc/options/iconv/meson.build | 12 + .../internal/aarch64-include/mlibc/arch-defs.hpp | 12 + .../internal/aarch64-include/mlibc/thread.hpp | 21 + lib/mlibc/options/internal/aarch64/fenv.S | 69 + .../options/internal/aarch64/mlibc_crtbegin.S | 29 + lib/mlibc/options/internal/aarch64/mlibc_crtend.S | 22 + lib/mlibc/options/internal/aarch64/setjmp.S | 63 + lib/mlibc/options/internal/gcc-extra/cxxabi.cpp | 20 + lib/mlibc/options/internal/gcc/guard-abi.cpp | 68 + lib/mlibc/options/internal/gcc/initfini.cpp | 23 + lib/mlibc/options/internal/gcc/stack_protector.cpp | 31 + lib/mlibc/options/internal/generic/allocator.cpp | 196 ++ lib/mlibc/options/internal/generic/charcode.cpp | 244 ++ lib/mlibc/options/internal/generic/charset.cpp | 144 + lib/mlibc/options/internal/generic/debug.cpp | 22 + lib/mlibc/options/internal/generic/ensure.cpp | 18 + lib/mlibc/options/internal/generic/essential.cpp | 217 ++ lib/mlibc/options/internal/generic/frigg.cpp | 14 + .../options/internal/generic/global-config.cpp | 27 + .../options/internal/generic/inline-emitter.cpp | 16 + lib/mlibc/options/internal/generic/locale.cpp | 87 + lib/mlibc/options/internal/generic/sigset.cpp | 37 + lib/mlibc/options/internal/generic/strings.cpp | 22 + lib/mlibc/options/internal/generic/threads.cpp | 342 +++ lib/mlibc/options/internal/generic/ubsan.cpp | 254 ++ lib/mlibc/options/internal/include/bits/cpu_set.h | 13 + lib/mlibc/options/internal/include/bits/ensure.h | 45 + .../options/internal/include/bits/ether_addr.h | 10 + .../internal/include/bits/inline-definition.h | 19 + lib/mlibc/options/internal/include/bits/machine.h | 86 + lib/mlibc/options/internal/include/bits/mbstate.h | 12 + lib/mlibc/options/internal/include/bits/nl_item.h | 82 + lib/mlibc/options/internal/include/bits/null.h | 16 + lib/mlibc/options/internal/include/bits/off_t.h | 8 + lib/mlibc/options/internal/include/bits/sigset_t.h | 25 + lib/mlibc/options/internal/include/bits/size_t.h | 6 + lib/mlibc/options/internal/include/bits/ssize_t.h | 15 + lib/mlibc/options/internal/include/bits/threads.h | 79 + lib/mlibc/options/internal/include/bits/types.h | 319 +++ lib/mlibc/options/internal/include/bits/wchar.h | 9 + lib/mlibc/options/internal/include/bits/wchar_t.h | 12 + lib/mlibc/options/internal/include/bits/winsize.h | 13 + lib/mlibc/options/internal/include/bits/wint_t.h | 6 + .../options/internal/include/mlibc/all-sysdeps.hpp | 33 + .../options/internal/include/mlibc/allocator.hpp | 37 + .../options/internal/include/mlibc/bitutil.hpp | 34 + .../options/internal/include/mlibc/charcode.hpp | 124 + .../options/internal/include/mlibc/charset.hpp | 40 + lib/mlibc/options/internal/include/mlibc/debug.hpp | 27 + .../options/internal/include/mlibc/file-window.hpp | 64 + .../options/internal/include/mlibc/fsfd_target.hpp | 15 + .../internal/include/mlibc/global-config.hpp | 19 + .../internal/include/mlibc/internal-sysdeps.hpp | 41 + .../options/internal/include/mlibc/locale.hpp | 12 + lib/mlibc/options/internal/include/mlibc/lock.hpp | 124 + .../internal/include/mlibc/stack_protector.hpp | 10 + .../options/internal/include/mlibc/strings.hpp | 12 + .../options/internal/include/mlibc/strtofp.hpp | 165 ++ .../options/internal/include/mlibc/strtol.hpp | 159 ++ lib/mlibc/options/internal/include/mlibc/tcb.hpp | 180 ++ .../options/internal/include/mlibc/threads.hpp | 27 + lib/mlibc/options/internal/include/mlibc/tid.hpp | 18 + lib/mlibc/options/internal/include/stdint.h | 150 + .../internal/riscv64-include/mlibc/arch-defs.hpp | 12 + .../internal/riscv64-include/mlibc/thread.hpp | 23 + lib/mlibc/options/internal/riscv64/fenv.S | 57 + .../options/internal/riscv64/mlibc_crtbegin.S | 29 + lib/mlibc/options/internal/riscv64/mlibc_crtend.S | 21 + lib/mlibc/options/internal/riscv64/setjmp.S | 71 + .../internal/x86-include/mlibc/arch-defs.hpp | 13 + .../options/internal/x86-include/mlibc/thread.hpp | 21 + lib/mlibc/options/internal/x86/fenv.S | 168 ++ lib/mlibc/options/internal/x86/mlibc_crtbegin.S | 29 + lib/mlibc/options/internal/x86/mlibc_crtend.S | 24 + lib/mlibc/options/internal/x86/setjmp.S | 53 + .../internal/x86_64-include/mlibc/arch-defs.hpp | 12 + .../internal/x86_64-include/mlibc/thread.hpp | 20 + lib/mlibc/options/internal/x86_64/fenv.S | 102 + lib/mlibc/options/internal/x86_64/mlibc_crtbegin.S | 29 + lib/mlibc/options/internal/x86_64/mlibc_crtend.S | 24 + lib/mlibc/options/internal/x86_64/setjmp.S | 54 + lib/mlibc/options/intl/generic/libintl-stubs.cpp | 73 + lib/mlibc/options/intl/include/libintl.h | 33 + lib/mlibc/options/intl/meson.build | 12 + lib/mlibc/options/linux/generic/capabilities.cpp | 19 + lib/mlibc/options/linux/generic/cpuset.cpp | 71 + lib/mlibc/options/linux/generic/ifaddrs.cpp | 15 + lib/mlibc/options/linux/generic/linux-unistd.cpp | 33 + lib/mlibc/options/linux/generic/malloc.cpp | 7 + lib/mlibc/options/linux/generic/mntent-stubs.cpp | 98 + lib/mlibc/options/linux/generic/module.cpp | 24 + lib/mlibc/options/linux/generic/pty-stubs.cpp | 101 + lib/mlibc/options/linux/generic/sched.cpp | 50 + lib/mlibc/options/linux/generic/sys-epoll.cpp | 58 + lib/mlibc/options/linux/generic/sys-eventfd.cpp | 45 + lib/mlibc/options/linux/generic/sys-fsuid.cpp | 12 + .../options/linux/generic/sys-inotify-stubs.cpp | 47 + lib/mlibc/options/linux/generic/sys-klog.cpp | 16 + lib/mlibc/options/linux/generic/sys-mount.cpp | 29 + .../options/linux/generic/sys-prctl-stubs.cpp | 25 + .../options/linux/generic/sys-ptrace-stubs.cpp | 36 + lib/mlibc/options/linux/generic/sys-quota.cpp | 7 + .../options/linux/generic/sys-random-stubs.cpp | 21 + lib/mlibc/options/linux/generic/sys-reboot.cpp | 13 + .../options/linux/generic/sys-sendfile-stubs.cpp | 9 + lib/mlibc/options/linux/generic/sys-signalfd.cpp | 17 + .../options/linux/generic/sys-statfs-stubs.cpp | 26 + lib/mlibc/options/linux/generic/sys-swap.cpp | 24 + lib/mlibc/options/linux/generic/sys-sysinfo.cpp | 15 + lib/mlibc/options/linux/generic/sys-timerfd.cpp | 33 + lib/mlibc/options/linux/generic/sys-xattr.cpp | 122 + lib/mlibc/options/linux/generic/utmp-stubs.cpp | 116 + lib/mlibc/options/linux/generic/utmpx.cpp | 45 + .../options/linux/include/bits/linux/cpu_set.h | 49 + .../options/linux/include/bits/linux/linux_sched.h | 59 + .../linux/include/bits/linux/linux_unistd.h | 21 + lib/mlibc/options/linux/include/ifaddrs.h | 35 + lib/mlibc/options/linux/include/lastlog.h | 2 + .../options/linux/include/linux/libc-compat.h | 61 + lib/mlibc/options/linux/include/malloc.h | 32 + lib/mlibc/options/linux/include/memory.h | 9 + .../options/linux/include/mlibc/linux-sysdeps.hpp | 82 + lib/mlibc/options/linux/include/mntent.h | 50 + lib/mlibc/options/linux/include/module.h | 25 + lib/mlibc/options/linux/include/netpacket/packet.h | 40 + lib/mlibc/options/linux/include/pty.h | 23 + lib/mlibc/options/linux/include/scsi/scsi.h | 18 + lib/mlibc/options/linux/include/scsi/scsi_ioctl.h | 6 + lib/mlibc/options/linux/include/scsi/sg.h | 77 + lib/mlibc/options/linux/include/sys/epoll.h | 66 + lib/mlibc/options/linux/include/sys/eventfd.h | 29 + lib/mlibc/options/linux/include/sys/fsuid.h | 22 + lib/mlibc/options/linux/include/sys/inotify.h | 63 + lib/mlibc/options/linux/include/sys/klog.h | 18 + lib/mlibc/options/linux/include/sys/mount.h | 90 + lib/mlibc/options/linux/include/sys/prctl.h | 128 + lib/mlibc/options/linux/include/sys/ptrace.h | 55 + lib/mlibc/options/linux/include/sys/quota.h | 24 + lib/mlibc/options/linux/include/sys/random.h | 26 + lib/mlibc/options/linux/include/sys/reboot.h | 20 + lib/mlibc/options/linux/include/sys/sendfile.h | 22 + lib/mlibc/options/linux/include/sys/signalfd.h | 48 + lib/mlibc/options/linux/include/sys/statfs.h | 22 + lib/mlibc/options/linux/include/sys/swap.h | 24 + lib/mlibc/options/linux/include/sys/sysinfo.h | 34 + lib/mlibc/options/linux/include/sys/sysmacros.h | 35 + lib/mlibc/options/linux/include/sys/timerfd.h | 32 + lib/mlibc/options/linux/include/sys/vfs.h | 16 + lib/mlibc/options/linux/include/sys/vt.h | 6 + lib/mlibc/options/linux/include/sys/xattr.h | 38 + lib/mlibc/options/linux/include/utmp.h | 84 + lib/mlibc/options/linux/include/utmpx.h | 68 + lib/mlibc/options/linux/include/values.h | 39 + lib/mlibc/options/linux/meson.build | 96 + lib/mlibc/options/lsb/generic/auxv.cpp | 59 + lib/mlibc/options/lsb/generic/dso_exit.cpp | 42 + lib/mlibc/options/lsb/generic/tls.cpp | 23 + lib/mlibc/options/lsb/include/sys/auxv.h | 26 + lib/mlibc/options/lsb/meson.build | 14 + .../options/posix/generic/arpa-inet-stubs.cpp | 220 ++ lib/mlibc/options/posix/generic/dirent-stubs.cpp | 180 ++ lib/mlibc/options/posix/generic/dlfcn-stubs.cpp | 64 + lib/mlibc/options/posix/generic/fcntl-stubs.cpp | 108 + lib/mlibc/options/posix/generic/ftw-stubs.cpp | 18 + lib/mlibc/options/posix/generic/grp-stubs.cpp | 316 +++ lib/mlibc/options/posix/generic/langinfo-stubs.cpp | 15 + lib/mlibc/options/posix/generic/libgen-stubs.cpp | 51 + lib/mlibc/options/posix/generic/lookup.cpp | 512 ++++ lib/mlibc/options/posix/generic/mqueue.cpp | 22 + lib/mlibc/options/posix/generic/net-if-stubs.cpp | 40 + lib/mlibc/options/posix/generic/netdb-stubs.cpp | 486 ++++ lib/mlibc/options/posix/generic/poll.cpp | 31 + lib/mlibc/options/posix/generic/posix-file-io.cpp | 275 ++ lib/mlibc/options/posix/generic/posix_ctype.cpp | 136 + lib/mlibc/options/posix/generic/posix_locale.cpp | 37 + lib/mlibc/options/posix/generic/posix_signal.cpp | 151 + lib/mlibc/options/posix/generic/posix_stdio.cpp | 209 ++ lib/mlibc/options/posix/generic/posix_stdlib.cpp | 513 ++++ lib/mlibc/options/posix/generic/posix_string.cpp | 174 ++ lib/mlibc/options/posix/generic/posix_time.cpp | 32 + lib/mlibc/options/posix/generic/pthread-stubs.cpp | 1426 ++++++++++ lib/mlibc/options/posix/generic/pwd-stubs.cpp | 284 ++ lib/mlibc/options/posix/generic/resolv_conf.cpp | 42 + lib/mlibc/options/posix/generic/sched-stubs.cpp | 50 + lib/mlibc/options/posix/generic/search.cpp | 151 + .../options/posix/generic/semaphore-stubs.cpp | 114 + lib/mlibc/options/posix/generic/services.cpp | 222 ++ lib/mlibc/options/posix/generic/spawn-stubs.cpp | 376 +++ lib/mlibc/options/posix/generic/strings-stubs.cpp | 107 + lib/mlibc/options/posix/generic/sys-file-stubs.cpp | 16 + lib/mlibc/options/posix/generic/sys-ipc.cpp | 8 + lib/mlibc/options/posix/generic/sys-mman-stubs.cpp | 177 ++ lib/mlibc/options/posix/generic/sys-msg.cpp | 23 + .../options/posix/generic/sys-resource-stubs.cpp | 57 + .../options/posix/generic/sys-select-stubs.cpp | 58 + lib/mlibc/options/posix/generic/sys-sem.cpp | 51 + lib/mlibc/options/posix/generic/sys-shm.cpp | 24 + .../options/posix/generic/sys-socket-stubs.cpp | 225 ++ lib/mlibc/options/posix/generic/sys-stat-stubs.cpp | 155 + .../options/posix/generic/sys-statvfs-stubs.cpp | 24 + lib/mlibc/options/posix/generic/sys-time-stubs.cpp | 107 + lib/mlibc/options/posix/generic/sys-times.cpp | 19 + lib/mlibc/options/posix/generic/sys-uio.cpp | 67 + lib/mlibc/options/posix/generic/sys-utsname.cpp | 24 + lib/mlibc/options/posix/generic/sys-wait-stubs.cpp | 52 + lib/mlibc/options/posix/generic/syslog-stubs.cpp | 152 + lib/mlibc/options/posix/generic/termios-stubs.cpp | 103 + lib/mlibc/options/posix/generic/time.cpp | 505 ++++ lib/mlibc/options/posix/generic/ucontext-stubs.cpp | 19 + lib/mlibc/options/posix/generic/unistd-stubs.cpp | 1227 ++++++++ lib/mlibc/options/posix/generic/utime-stubs.cpp | 31 + lib/mlibc/options/posix/generic/wordexp-stubs.cpp | 342 +++ lib/mlibc/options/posix/include/arpa/inet.h | 46 + .../options/posix/include/bits/posix/fd_set.h | 14 + lib/mlibc/options/posix/include/bits/posix/id_t.h | 6 + .../options/posix/include/bits/posix/in_addr_t.h | 8 + .../options/posix/include/bits/posix/in_port_t.h | 8 + lib/mlibc/options/posix/include/bits/posix/iovec.h | 11 + .../options/posix/include/bits/posix/locale_t.h | 14 + .../options/posix/include/bits/posix/posix_ctype.h | 36 + .../posix/include/bits/posix/posix_locale.h | 23 + .../posix/include/bits/posix/posix_signal.h | 111 + .../options/posix/include/bits/posix/posix_stdio.h | 72 + .../posix/include/bits/posix/posix_stdlib.h | 73 + .../posix/include/bits/posix/posix_string.h | 57 + .../options/posix/include/bits/posix/posix_time.h | 25 + .../posix/include/bits/posix/posix_wctype.h | 44 + .../options/posix/include/bits/posix/pthread_t.h | 8 + lib/mlibc/options/posix/include/bits/posix/stat.h | 24 + .../options/posix/include/bits/posix/timer_t.h | 6 + .../options/posix/include/bits/posix/timeval.h | 12 + lib/mlibc/options/posix/include/byteswap.h | 23 + lib/mlibc/options/posix/include/dirent.h | 76 + lib/mlibc/options/posix/include/dlfcn.h | 52 + lib/mlibc/options/posix/include/fcntl.h | 76 + lib/mlibc/options/posix/include/fnmatch.h | 33 + lib/mlibc/options/posix/include/ftw.h | 43 + lib/mlibc/options/posix/include/glob.h | 58 + lib/mlibc/options/posix/include/grp.h | 43 + lib/mlibc/options/posix/include/langinfo.h | 24 + lib/mlibc/options/posix/include/libgen.h | 28 + lib/mlibc/options/posix/include/mlibc/lookup.hpp | 58 + .../options/posix/include/mlibc/posix-file-io.hpp | 102 + .../options/posix/include/mlibc/posix-sysdeps.hpp | 240 ++ .../options/posix/include/mlibc/resolv_conf.hpp | 21 + lib/mlibc/options/posix/include/mlibc/services.hpp | 33 + lib/mlibc/options/posix/include/mqueue.h | 26 + lib/mlibc/options/posix/include/net/if.h | 118 + lib/mlibc/options/posix/include/net/if_arp.h | 103 + lib/mlibc/options/posix/include/netdb.h | 148 + lib/mlibc/options/posix/include/netinet/icmp6.h | 139 + lib/mlibc/options/posix/include/netinet/if_ether.h | 105 + lib/mlibc/options/posix/include/netinet/in.h | 118 + lib/mlibc/options/posix/include/netinet/ip.h | 75 + lib/mlibc/options/posix/include/netinet/ip6.h | 28 + lib/mlibc/options/posix/include/netinet/ip_icmp.h | 84 + lib/mlibc/options/posix/include/netinet/tcp.h | 37 + lib/mlibc/options/posix/include/netinet/udp.h | 31 + lib/mlibc/options/posix/include/nl_types.h | 6 + lib/mlibc/options/posix/include/poll.h | 6 + lib/mlibc/options/posix/include/pthread.h | 325 +++ lib/mlibc/options/posix/include/pwd.h | 45 + lib/mlibc/options/posix/include/regex.h | 66 + lib/mlibc/options/posix/include/sched.h | 49 + lib/mlibc/options/posix/include/search.h | 37 + lib/mlibc/options/posix/include/semaphore.h | 37 + lib/mlibc/options/posix/include/spawn.h | 82 + lib/mlibc/options/posix/include/strings.h | 32 + lib/mlibc/options/posix/include/sys/file.h | 25 + lib/mlibc/options/posix/include/sys/ipc.h | 53 + lib/mlibc/options/posix/include/sys/mman.h | 47 + lib/mlibc/options/posix/include/sys/msg.h | 27 + lib/mlibc/options/posix/include/sys/param.h | 36 + lib/mlibc/options/posix/include/sys/poll.h | 37 + lib/mlibc/options/posix/include/sys/resource.h | 52 + lib/mlibc/options/posix/include/sys/select.h | 49 + lib/mlibc/options/posix/include/sys/sem.h | 44 + lib/mlibc/options/posix/include/sys/shm.h | 83 + lib/mlibc/options/posix/include/sys/socket.h | 105 + lib/mlibc/options/posix/include/sys/stat.h | 37 + lib/mlibc/options/posix/include/sys/statvfs.h | 22 + lib/mlibc/options/posix/include/sys/syslog.h | 1 + lib/mlibc/options/posix/include/sys/termios.h | 6 + lib/mlibc/options/posix/include/sys/time.h | 68 + lib/mlibc/options/posix/include/sys/times.h | 28 + lib/mlibc/options/posix/include/sys/ttydefaults.h | 39 + lib/mlibc/options/posix/include/sys/types.h | 53 + lib/mlibc/options/posix/include/sys/uio.h | 31 + lib/mlibc/options/posix/include/sys/un.h | 24 + lib/mlibc/options/posix/include/sys/utsname.h | 22 + lib/mlibc/options/posix/include/sys/wait.h | 40 + lib/mlibc/options/posix/include/syslog.h | 75 + lib/mlibc/options/posix/include/termios.h | 100 + lib/mlibc/options/posix/include/ucontext.h | 23 + lib/mlibc/options/posix/include/unistd.h | 360 +++ lib/mlibc/options/posix/include/utime.h | 25 + lib/mlibc/options/posix/include/wordexp.h | 43 + lib/mlibc/options/posix/meson.build | 175 ++ .../options/posix/musl-generic-regex/fnmatch.c | 321 +++ lib/mlibc/options/posix/musl-generic-regex/glob.c | 311 +++ .../options/posix/musl-generic-regex/regcomp.c | 2953 ++++++++++++++++++++ .../options/posix/musl-generic-regex/regerror.c | 37 + .../options/posix/musl-generic-regex/regexec.c | 1028 +++++++ .../options/posix/musl-generic-regex/tre-mem.c | 158 ++ lib/mlibc/options/posix/musl-generic-regex/tre.h | 241 ++ lib/mlibc/options/rtdl/aarch64/elf.hpp | 37 + lib/mlibc/options/rtdl/aarch64/entry.S | 11 + lib/mlibc/options/rtdl/aarch64/runtime.S | 62 + lib/mlibc/options/rtdl/generic/linker.cpp | 1872 +++++++++++++ lib/mlibc/options/rtdl/generic/linker.hpp | 402 +++ lib/mlibc/options/rtdl/generic/main.cpp | 844 ++++++ lib/mlibc/options/rtdl/include/mlibc/rtdl-abi.hpp | 28 + .../options/rtdl/include/mlibc/rtdl-config.hpp | 24 + .../options/rtdl/include/mlibc/rtdl-sysdeps.hpp | 12 + lib/mlibc/options/rtdl/riscv64/elf.hpp | 37 + lib/mlibc/options/rtdl/riscv64/entry.S | 11 + lib/mlibc/options/rtdl/riscv64/runtime.S | 5 + lib/mlibc/options/rtdl/x86/elf.hpp | 37 + lib/mlibc/options/rtdl/x86/entry.S | 10 + lib/mlibc/options/rtdl/x86/runtime.S | 9 + lib/mlibc/options/rtdl/x86_64/elf.hpp | 37 + lib/mlibc/options/rtdl/x86_64/entry.S | 11 + lib/mlibc/options/rtdl/x86_64/runtime.S | 36 + lib/mlibc/scripts/abi-link.sh | 12 + lib/mlibc/scripts/check-options-header-include.sh | 18 + lib/mlibc/scripts/hdoc.toml.in | 15 + lib/mlibc/sysdeps/aero/crt-x86_64/crt0.S | 10 + lib/mlibc/sysdeps/aero/generic/aero.cpp | 360 +++ lib/mlibc/sysdeps/aero/generic/entry.cpp | 36 + lib/mlibc/sysdeps/aero/generic/filesystem.cpp | 472 ++++ lib/mlibc/sysdeps/aero/generic/signals.S | 9 + lib/mlibc/sysdeps/aero/generic/signals.cpp | 53 + lib/mlibc/sysdeps/aero/generic/sockets.cpp | 250 ++ lib/mlibc/sysdeps/aero/generic/thread.cpp | 55 + lib/mlibc/sysdeps/aero/generic/thread_entry.S | 10 + lib/mlibc/sysdeps/aero/generic/time.cpp | 25 + lib/mlibc/sysdeps/aero/include/abi-bits/access.h | 1 + lib/mlibc/sysdeps/aero/include/abi-bits/auxv.h | 1 + lib/mlibc/sysdeps/aero/include/abi-bits/blkcnt_t.h | 1 + .../sysdeps/aero/include/abi-bits/blksize_t.h | 1 + .../sysdeps/aero/include/abi-bits/clockid_t.h | 1 + lib/mlibc/sysdeps/aero/include/abi-bits/dev_t.h | 1 + lib/mlibc/sysdeps/aero/include/abi-bits/epoll.h | 1 + lib/mlibc/sysdeps/aero/include/abi-bits/errno.h | 1 + lib/mlibc/sysdeps/aero/include/abi-bits/fcntl.h | 1 + .../sysdeps/aero/include/abi-bits/fsblkcnt_t.h | 1 + .../sysdeps/aero/include/abi-bits/fsfilcnt_t.h | 1 + lib/mlibc/sysdeps/aero/include/abi-bits/gid_t.h | 1 + lib/mlibc/sysdeps/aero/include/abi-bits/in.h | 1 + lib/mlibc/sysdeps/aero/include/abi-bits/ino_t.h | 1 + lib/mlibc/sysdeps/aero/include/abi-bits/inotify.h | 1 + lib/mlibc/sysdeps/aero/include/abi-bits/ioctls.h | 1 + lib/mlibc/sysdeps/aero/include/abi-bits/limits.h | 1 + lib/mlibc/sysdeps/aero/include/abi-bits/mode_t.h | 1 + lib/mlibc/sysdeps/aero/include/abi-bits/mqueue.h | 1 + lib/mlibc/sysdeps/aero/include/abi-bits/msg.h | 1 + lib/mlibc/sysdeps/aero/include/abi-bits/nlink_t.h | 1 + lib/mlibc/sysdeps/aero/include/abi-bits/packet.h | 1 + lib/mlibc/sysdeps/aero/include/abi-bits/pid_t.h | 1 + lib/mlibc/sysdeps/aero/include/abi-bits/poll.h | 1 + lib/mlibc/sysdeps/aero/include/abi-bits/ptrace.h | 1 + lib/mlibc/sysdeps/aero/include/abi-bits/reboot.h | 1 + lib/mlibc/sysdeps/aero/include/abi-bits/resource.h | 1 + .../sysdeps/aero/include/abi-bits/seek-whence.h | 1 + lib/mlibc/sysdeps/aero/include/abi-bits/shm.h | 1 + lib/mlibc/sysdeps/aero/include/abi-bits/signal.h | 1 + lib/mlibc/sysdeps/aero/include/abi-bits/socket.h | 1 + .../sysdeps/aero/include/abi-bits/socklen_t.h | 1 + lib/mlibc/sysdeps/aero/include/abi-bits/stat.h | 1 + lib/mlibc/sysdeps/aero/include/abi-bits/statfs.h | 1 + lib/mlibc/sysdeps/aero/include/abi-bits/statvfs.h | 1 + .../sysdeps/aero/include/abi-bits/suseconds_t.h | 1 + lib/mlibc/sysdeps/aero/include/abi-bits/termios.h | 1 + lib/mlibc/sysdeps/aero/include/abi-bits/time.h | 1 + lib/mlibc/sysdeps/aero/include/abi-bits/uid_t.h | 1 + lib/mlibc/sysdeps/aero/include/abi-bits/utsname.h | 1 + lib/mlibc/sysdeps/aero/include/abi-bits/vm-flags.h | 1 + lib/mlibc/sysdeps/aero/include/abi-bits/wait.h | 1 + lib/mlibc/sysdeps/aero/include/abi-bits/xattr.h | 1 + lib/mlibc/sysdeps/aero/include/aero/syscall.h | 231 ++ .../sysdeps/aero/include/mlibc/thread-entry.hpp | 11 + lib/mlibc/sysdeps/aero/meson.build | 85 + lib/mlibc/sysdeps/dripos/crt-x86_64/crt1.S | 9 + lib/mlibc/sysdeps/dripos/generic/entry.cpp | 35 + lib/mlibc/sysdeps/dripos/generic/generic.cpp | 298 ++ lib/mlibc/sysdeps/dripos/generic/thread.cpp | 53 + lib/mlibc/sysdeps/dripos/generic/thread_entry.S | 11 + lib/mlibc/sysdeps/dripos/include/abi-bits/access.h | 1 + lib/mlibc/sysdeps/dripos/include/abi-bits/auxv.h | 1 + .../sysdeps/dripos/include/abi-bits/blkcnt_t.h | 1 + .../sysdeps/dripos/include/abi-bits/blksize_t.h | 1 + .../sysdeps/dripos/include/abi-bits/clockid_t.h | 1 + lib/mlibc/sysdeps/dripos/include/abi-bits/dev_t.h | 1 + lib/mlibc/sysdeps/dripos/include/abi-bits/epoll.h | 1 + lib/mlibc/sysdeps/dripos/include/abi-bits/errno.h | 1 + lib/mlibc/sysdeps/dripos/include/abi-bits/fcntl.h | 1 + .../sysdeps/dripos/include/abi-bits/fsblkcnt_t.h | 1 + .../sysdeps/dripos/include/abi-bits/fsfilcnt_t.h | 1 + lib/mlibc/sysdeps/dripos/include/abi-bits/gid_t.h | 1 + lib/mlibc/sysdeps/dripos/include/abi-bits/in.h | 1 + lib/mlibc/sysdeps/dripos/include/abi-bits/ino_t.h | 1 + .../sysdeps/dripos/include/abi-bits/inotify.h | 1 + lib/mlibc/sysdeps/dripos/include/abi-bits/ioctls.h | 1 + lib/mlibc/sysdeps/dripos/include/abi-bits/limits.h | 1 + lib/mlibc/sysdeps/dripos/include/abi-bits/mode_t.h | 1 + lib/mlibc/sysdeps/dripos/include/abi-bits/mqueue.h | 1 + lib/mlibc/sysdeps/dripos/include/abi-bits/msg.h | 1 + .../sysdeps/dripos/include/abi-bits/nlink_t.h | 1 + lib/mlibc/sysdeps/dripos/include/abi-bits/packet.h | 1 + lib/mlibc/sysdeps/dripos/include/abi-bits/pid_t.h | 1 + lib/mlibc/sysdeps/dripos/include/abi-bits/poll.h | 1 + lib/mlibc/sysdeps/dripos/include/abi-bits/ptrace.h | 1 + .../sysdeps/dripos/include/abi-bits/resource.h | 1 + .../sysdeps/dripos/include/abi-bits/seek-whence.h | 1 + lib/mlibc/sysdeps/dripos/include/abi-bits/shm.h | 1 + lib/mlibc/sysdeps/dripos/include/abi-bits/signal.h | 1 + lib/mlibc/sysdeps/dripos/include/abi-bits/socket.h | 1 + .../sysdeps/dripos/include/abi-bits/socklen_t.h | 1 + lib/mlibc/sysdeps/dripos/include/abi-bits/stat.h | 1 + lib/mlibc/sysdeps/dripos/include/abi-bits/statfs.h | 1 + .../sysdeps/dripos/include/abi-bits/statvfs.h | 1 + .../sysdeps/dripos/include/abi-bits/suseconds_t.h | 1 + .../sysdeps/dripos/include/abi-bits/termios.h | 1 + lib/mlibc/sysdeps/dripos/include/abi-bits/time.h | 1 + lib/mlibc/sysdeps/dripos/include/abi-bits/uid_t.h | 1 + .../sysdeps/dripos/include/abi-bits/utsname.h | 1 + .../sysdeps/dripos/include/abi-bits/vm-flags.h | 1 + lib/mlibc/sysdeps/dripos/include/abi-bits/wait.h | 1 + lib/mlibc/sysdeps/dripos/include/abi-bits/xattr.h | 1 + .../sysdeps/dripos/include/mlibc/thread-entry.hpp | 10 + lib/mlibc/sysdeps/dripos/meson.build | 71 + lib/mlibc/sysdeps/hyra/crt-x86_64/crt0.S | 9 + lib/mlibc/sysdeps/hyra/generic/entry.cpp | 35 + lib/mlibc/sysdeps/hyra/generic/hyra.cpp | 121 + lib/mlibc/sysdeps/hyra/include/abi-bits/access.h | 1 + lib/mlibc/sysdeps/hyra/include/abi-bits/auxv.h | 1 + lib/mlibc/sysdeps/hyra/include/abi-bits/blkcnt_t.h | 1 + .../sysdeps/hyra/include/abi-bits/blksize_t.h | 1 + .../sysdeps/hyra/include/abi-bits/clockid_t.h | 1 + lib/mlibc/sysdeps/hyra/include/abi-bits/dev_t.h | 1 + lib/mlibc/sysdeps/hyra/include/abi-bits/epoll.h | 1 + lib/mlibc/sysdeps/hyra/include/abi-bits/errno.h | 1 + lib/mlibc/sysdeps/hyra/include/abi-bits/fcntl.h | 1 + .../sysdeps/hyra/include/abi-bits/fsblkcnt_t.h | 1 + .../sysdeps/hyra/include/abi-bits/fsfilcnt_t.h | 1 + lib/mlibc/sysdeps/hyra/include/abi-bits/gid_t.h | 1 + lib/mlibc/sysdeps/hyra/include/abi-bits/in.h | 1 + lib/mlibc/sysdeps/hyra/include/abi-bits/ino_t.h | 1 + lib/mlibc/sysdeps/hyra/include/abi-bits/inotify.h | 1 + lib/mlibc/sysdeps/hyra/include/abi-bits/ioctls.h | 1 + lib/mlibc/sysdeps/hyra/include/abi-bits/limits.h | 1 + lib/mlibc/sysdeps/hyra/include/abi-bits/mode_t.h | 1 + lib/mlibc/sysdeps/hyra/include/abi-bits/mqueue.h | 1 + lib/mlibc/sysdeps/hyra/include/abi-bits/msg.h | 1 + lib/mlibc/sysdeps/hyra/include/abi-bits/nlink_t.h | 1 + lib/mlibc/sysdeps/hyra/include/abi-bits/packet.h | 1 + lib/mlibc/sysdeps/hyra/include/abi-bits/pid_t.h | 1 + lib/mlibc/sysdeps/hyra/include/abi-bits/poll.h | 1 + lib/mlibc/sysdeps/hyra/include/abi-bits/ptrace.h | 1 + lib/mlibc/sysdeps/hyra/include/abi-bits/reboot.h | 1 + lib/mlibc/sysdeps/hyra/include/abi-bits/resource.h | 1 + .../sysdeps/hyra/include/abi-bits/seek-whence.h | 1 + lib/mlibc/sysdeps/hyra/include/abi-bits/shm.h | 1 + lib/mlibc/sysdeps/hyra/include/abi-bits/signal.h | 1 + lib/mlibc/sysdeps/hyra/include/abi-bits/socket.h | 1 + .../sysdeps/hyra/include/abi-bits/socklen_t.h | 1 + lib/mlibc/sysdeps/hyra/include/abi-bits/stat.h | 1 + lib/mlibc/sysdeps/hyra/include/abi-bits/statfs.h | 1 + lib/mlibc/sysdeps/hyra/include/abi-bits/statvfs.h | 1 + .../sysdeps/hyra/include/abi-bits/suseconds_t.h | 1 + lib/mlibc/sysdeps/hyra/include/abi-bits/termios.h | 1 + lib/mlibc/sysdeps/hyra/include/abi-bits/time.h | 1 + lib/mlibc/sysdeps/hyra/include/abi-bits/uid_t.h | 1 + lib/mlibc/sysdeps/hyra/include/abi-bits/utsname.h | 1 + lib/mlibc/sysdeps/hyra/include/abi-bits/vm-flags.h | 1 + lib/mlibc/sysdeps/hyra/include/abi-bits/vt.h | 1 + lib/mlibc/sysdeps/hyra/include/abi-bits/wait.h | 1 + lib/mlibc/sysdeps/hyra/include/abi-bits/xattr.h | 1 + lib/mlibc/sysdeps/hyra/include/hyra/syscall.h | 55 + lib/mlibc/sysdeps/hyra/meson.build | 69 + lib/mlibc/sysdeps/ironclad/crt-x86_64/crt0.S | 9 + lib/mlibc/sysdeps/ironclad/crt-x86_64/crti.S | 11 + lib/mlibc/sysdeps/ironclad/crt-x86_64/crtn.S | 9 + lib/mlibc/sysdeps/ironclad/generic/entry.cpp | 35 + lib/mlibc/sysdeps/ironclad/generic/generic.cpp | 1266 +++++++++ lib/mlibc/sysdeps/ironclad/generic/mac.cpp | 32 + lib/mlibc/sysdeps/ironclad/generic/mntent.cpp | 97 + lib/mlibc/sysdeps/ironclad/generic/mount.cpp | 20 + lib/mlibc/sysdeps/ironclad/generic/ptrace.cpp | 9 + lib/mlibc/sysdeps/ironclad/generic/pty.cpp | 41 + lib/mlibc/sysdeps/ironclad/generic/reboot.cpp | 9 + lib/mlibc/sysdeps/ironclad/generic/sched2.cpp | 20 + lib/mlibc/sysdeps/ironclad/generic/thread.S | 9 + lib/mlibc/sysdeps/ironclad/generic/thread.cpp | 54 + lib/mlibc/sysdeps/ironclad/generic/utmpx.cpp | 76 + .../sysdeps/ironclad/include/abi-bits/access.h | 1 + lib/mlibc/sysdeps/ironclad/include/abi-bits/auxv.h | 1 + .../sysdeps/ironclad/include/abi-bits/blkcnt_t.h | 1 + .../sysdeps/ironclad/include/abi-bits/blksize_t.h | 1 + .../sysdeps/ironclad/include/abi-bits/clockid_t.h | 1 + .../sysdeps/ironclad/include/abi-bits/dev_t.h | 1 + .../sysdeps/ironclad/include/abi-bits/epoll.h | 1 + .../sysdeps/ironclad/include/abi-bits/errno.h | 1 + .../sysdeps/ironclad/include/abi-bits/fcntl.h | 1 + .../sysdeps/ironclad/include/abi-bits/fsblkcnt_t.h | 1 + .../sysdeps/ironclad/include/abi-bits/fsfilcnt_t.h | 1 + .../sysdeps/ironclad/include/abi-bits/gid_t.h | 1 + lib/mlibc/sysdeps/ironclad/include/abi-bits/in.h | 1 + .../sysdeps/ironclad/include/abi-bits/ino_t.h | 1 + .../sysdeps/ironclad/include/abi-bits/inotify.h | 1 + .../sysdeps/ironclad/include/abi-bits/ioctls.h | 1 + .../sysdeps/ironclad/include/abi-bits/limits.h | 1 + .../sysdeps/ironclad/include/abi-bits/mode_t.h | 1 + .../sysdeps/ironclad/include/abi-bits/mqueue.h | 1 + lib/mlibc/sysdeps/ironclad/include/abi-bits/msg.h | 1 + .../sysdeps/ironclad/include/abi-bits/nlink_t.h | 1 + .../sysdeps/ironclad/include/abi-bits/packet.h | 1 + .../sysdeps/ironclad/include/abi-bits/pid_t.h | 1 + lib/mlibc/sysdeps/ironclad/include/abi-bits/poll.h | 1 + .../sysdeps/ironclad/include/abi-bits/ptrace.h | 1 + .../sysdeps/ironclad/include/abi-bits/reboot.h | 1 + .../sysdeps/ironclad/include/abi-bits/resource.h | 1 + .../ironclad/include/abi-bits/seek-whence.h | 1 + lib/mlibc/sysdeps/ironclad/include/abi-bits/shm.h | 1 + .../sysdeps/ironclad/include/abi-bits/signal.h | 1 + .../sysdeps/ironclad/include/abi-bits/socket.h | 1 + .../sysdeps/ironclad/include/abi-bits/socklen_t.h | 1 + lib/mlibc/sysdeps/ironclad/include/abi-bits/stat.h | 1 + .../sysdeps/ironclad/include/abi-bits/statfs.h | 1 + .../sysdeps/ironclad/include/abi-bits/statvfs.h | 1 + .../ironclad/include/abi-bits/suseconds_t.h | 1 + .../sysdeps/ironclad/include/abi-bits/termios.h | 1 + lib/mlibc/sysdeps/ironclad/include/abi-bits/time.h | 1 + .../sysdeps/ironclad/include/abi-bits/uid_t.h | 1 + .../sysdeps/ironclad/include/abi-bits/utsname.h | 1 + .../sysdeps/ironclad/include/abi-bits/vm-flags.h | 1 + lib/mlibc/sysdeps/ironclad/include/abi-bits/wait.h | 1 + .../sysdeps/ironclad/include/abi-bits/xattr.h | 1 + lib/mlibc/sysdeps/ironclad/include/asm/ioctls.h | 102 + lib/mlibc/sysdeps/ironclad/include/linux/fb.h | 397 +++ lib/mlibc/sysdeps/ironclad/include/mntent.h | 46 + lib/mlibc/sysdeps/ironclad/include/pty.h | 16 + .../ironclad/include/sys/ironclad_devices.h | 44 + lib/mlibc/sysdeps/ironclad/include/sys/mac.h | 46 + lib/mlibc/sysdeps/ironclad/include/sys/mount.h | 24 + lib/mlibc/sysdeps/ironclad/include/sys/ptrace.h | 23 + lib/mlibc/sysdeps/ironclad/include/sys/reboot.h | 16 + lib/mlibc/sysdeps/ironclad/include/sys/sched2.h | 24 + lib/mlibc/sysdeps/ironclad/include/sys/syscall.h | 187 ++ lib/mlibc/sysdeps/ironclad/include/utmpx.h | 63 + lib/mlibc/sysdeps/ironclad/meson.build | 125 + lib/mlibc/sysdeps/keyronex/generic/entry.cpp | 108 + lib/mlibc/sysdeps/keyronex/generic/generic.cpp | 753 +++++ lib/mlibc/sysdeps/keyronex/generic/linux.cpp | 41 + lib/mlibc/sysdeps/keyronex/generic/signal.cpp | 66 + lib/mlibc/sysdeps/keyronex/generic/socket.cpp | 119 + lib/mlibc/sysdeps/keyronex/generic/thread.S | 9 + lib/mlibc/sysdeps/keyronex/generic/thread.cpp | 80 + .../sysdeps/keyronex/include/abi-bits/access.h | 1 + lib/mlibc/sysdeps/keyronex/include/abi-bits/auxv.h | 1 + .../sysdeps/keyronex/include/abi-bits/blkcnt_t.h | 1 + .../sysdeps/keyronex/include/abi-bits/blksize_t.h | 1 + .../sysdeps/keyronex/include/abi-bits/clockid_t.h | 1 + .../sysdeps/keyronex/include/abi-bits/dev_t.h | 1 + .../sysdeps/keyronex/include/abi-bits/epoll.h | 1 + .../sysdeps/keyronex/include/abi-bits/errno.h | 1 + .../sysdeps/keyronex/include/abi-bits/fcntl.h | 1 + .../sysdeps/keyronex/include/abi-bits/fsblkcnt_t.h | 1 + .../sysdeps/keyronex/include/abi-bits/fsfilcnt_t.h | 1 + .../sysdeps/keyronex/include/abi-bits/gid_t.h | 1 + lib/mlibc/sysdeps/keyronex/include/abi-bits/in.h | 1 + .../sysdeps/keyronex/include/abi-bits/ino_t.h | 1 + .../sysdeps/keyronex/include/abi-bits/inotify.h | 1 + .../sysdeps/keyronex/include/abi-bits/ioctls.h | 1 + .../sysdeps/keyronex/include/abi-bits/limits.h | 1 + .../sysdeps/keyronex/include/abi-bits/mode_t.h | 1 + .../sysdeps/keyronex/include/abi-bits/mqueue.h | 1 + lib/mlibc/sysdeps/keyronex/include/abi-bits/msg.h | 1 + .../sysdeps/keyronex/include/abi-bits/nlink_t.h | 1 + .../sysdeps/keyronex/include/abi-bits/packet.h | 1 + .../sysdeps/keyronex/include/abi-bits/pid_t.h | 1 + lib/mlibc/sysdeps/keyronex/include/abi-bits/poll.h | 1 + .../sysdeps/keyronex/include/abi-bits/ptrace.h | 1 + .../sysdeps/keyronex/include/abi-bits/reboot.h | 1 + .../sysdeps/keyronex/include/abi-bits/resource.h | 1 + .../keyronex/include/abi-bits/seek-whence.h | 1 + lib/mlibc/sysdeps/keyronex/include/abi-bits/shm.h | 1 + .../sysdeps/keyronex/include/abi-bits/signal.h | 1 + .../sysdeps/keyronex/include/abi-bits/socket.h | 1 + .../sysdeps/keyronex/include/abi-bits/socklen_t.h | 1 + lib/mlibc/sysdeps/keyronex/include/abi-bits/stat.h | 1 + .../sysdeps/keyronex/include/abi-bits/statfs.h | 1 + .../sysdeps/keyronex/include/abi-bits/statvfs.h | 1 + .../keyronex/include/abi-bits/suseconds_t.h | 1 + .../sysdeps/keyronex/include/abi-bits/termios.h | 1 + lib/mlibc/sysdeps/keyronex/include/abi-bits/time.h | 1 + .../sysdeps/keyronex/include/abi-bits/uid_t.h | 1 + .../sysdeps/keyronex/include/abi-bits/utsname.h | 1 + .../sysdeps/keyronex/include/abi-bits/vm-flags.h | 1 + lib/mlibc/sysdeps/keyronex/include/abi-bits/wait.h | 1 + .../sysdeps/keyronex/include/abi-bits/xattr.h | 1 + .../sysdeps/keyronex/include/keyronex/syscall.h | 213 ++ lib/mlibc/sysdeps/keyronex/meson.build | 98 + lib/mlibc/sysdeps/keyronex/x86_64/crt-src/crt0.S | 7 + lib/mlibc/sysdeps/keyronex/x86_64/crt-src/crti.S | 11 + lib/mlibc/sysdeps/keyronex/x86_64/crt-src/crtn.S | 9 + lib/mlibc/sysdeps/lemon/crt-x86_64/crt0.S | 10 + lib/mlibc/sysdeps/lemon/generic/entry.cpp | 33 + lib/mlibc/sysdeps/lemon/generic/filesystem.cpp | 406 +++ lib/mlibc/sysdeps/lemon/generic/lemon.cpp | 199 ++ lib/mlibc/sysdeps/lemon/generic/pty.cpp | 63 + lib/mlibc/sysdeps/lemon/generic/signals.cpp | 38 + lib/mlibc/sysdeps/lemon/generic/sockets.cpp | 132 + lib/mlibc/sysdeps/lemon/generic/thread.cpp | 53 + lib/mlibc/sysdeps/lemon/generic/thread_entry.S | 11 + lib/mlibc/sysdeps/lemon/include/abi-bits/access.h | 1 + lib/mlibc/sysdeps/lemon/include/abi-bits/auxv.h | 1 + .../sysdeps/lemon/include/abi-bits/blkcnt_t.h | 1 + .../sysdeps/lemon/include/abi-bits/blksize_t.h | 1 + .../sysdeps/lemon/include/abi-bits/clockid_t.h | 1 + lib/mlibc/sysdeps/lemon/include/abi-bits/dev_t.h | 1 + lib/mlibc/sysdeps/lemon/include/abi-bits/epoll.h | 1 + lib/mlibc/sysdeps/lemon/include/abi-bits/errno.h | 1 + lib/mlibc/sysdeps/lemon/include/abi-bits/fcntl.h | 1 + .../sysdeps/lemon/include/abi-bits/fsblkcnt_t.h | 1 + .../sysdeps/lemon/include/abi-bits/fsfilcnt_t.h | 1 + lib/mlibc/sysdeps/lemon/include/abi-bits/gid_t.h | 1 + lib/mlibc/sysdeps/lemon/include/abi-bits/in.h | 1 + lib/mlibc/sysdeps/lemon/include/abi-bits/ino_t.h | 1 + lib/mlibc/sysdeps/lemon/include/abi-bits/inotify.h | 1 + lib/mlibc/sysdeps/lemon/include/abi-bits/ioctls.h | 1 + lib/mlibc/sysdeps/lemon/include/abi-bits/limits.h | 1 + lib/mlibc/sysdeps/lemon/include/abi-bits/mode_t.h | 1 + lib/mlibc/sysdeps/lemon/include/abi-bits/mqueue.h | 1 + lib/mlibc/sysdeps/lemon/include/abi-bits/msg.h | 1 + lib/mlibc/sysdeps/lemon/include/abi-bits/nlink_t.h | 1 + lib/mlibc/sysdeps/lemon/include/abi-bits/packet.h | 1 + lib/mlibc/sysdeps/lemon/include/abi-bits/pid_t.h | 1 + lib/mlibc/sysdeps/lemon/include/abi-bits/poll.h | 1 + lib/mlibc/sysdeps/lemon/include/abi-bits/ptrace.h | 1 + lib/mlibc/sysdeps/lemon/include/abi-bits/reboot.h | 1 + .../sysdeps/lemon/include/abi-bits/resource.h | 1 + .../sysdeps/lemon/include/abi-bits/seek-whence.h | 1 + lib/mlibc/sysdeps/lemon/include/abi-bits/shm.h | 1 + lib/mlibc/sysdeps/lemon/include/abi-bits/signal.h | 1 + lib/mlibc/sysdeps/lemon/include/abi-bits/socket.h | 1 + .../sysdeps/lemon/include/abi-bits/socklen_t.h | 1 + lib/mlibc/sysdeps/lemon/include/abi-bits/stat.h | 1 + lib/mlibc/sysdeps/lemon/include/abi-bits/statfs.h | 1 + lib/mlibc/sysdeps/lemon/include/abi-bits/statvfs.h | 1 + .../sysdeps/lemon/include/abi-bits/suseconds_t.h | 1 + lib/mlibc/sysdeps/lemon/include/abi-bits/termios.h | 1 + lib/mlibc/sysdeps/lemon/include/abi-bits/time.h | 1 + lib/mlibc/sysdeps/lemon/include/abi-bits/uid_t.h | 1 + lib/mlibc/sysdeps/lemon/include/abi-bits/utsname.h | 1 + .../sysdeps/lemon/include/abi-bits/vm-flags.h | 1 + lib/mlibc/sysdeps/lemon/include/abi-bits/wait.h | 1 + lib/mlibc/sysdeps/lemon/include/abi-bits/xattr.h | 1 + lib/mlibc/sysdeps/lemon/include/lemon/syscall.h | 194 ++ .../sysdeps/lemon/include/mlibc/thread-entry.hpp | 10 + lib/mlibc/sysdeps/lemon/meson.build | 81 + lib/mlibc/sysdeps/linux/aarch64/arch-syscall.cpp | 117 + lib/mlibc/sysdeps/linux/aarch64/cp_syscall.S | 31 + lib/mlibc/sysdeps/linux/aarch64/crt-src/Scrt1.S | 11 + lib/mlibc/sysdeps/linux/aarch64/crt-src/crt1.S | 9 + lib/mlibc/sysdeps/linux/aarch64/crt-src/crti.S | 13 + lib/mlibc/sysdeps/linux/aarch64/crt-src/crtn.S | 9 + lib/mlibc/sysdeps/linux/aarch64/signals.S | 12 + lib/mlibc/sysdeps/linux/aarch64/syscallnos.h | 313 +++ lib/mlibc/sysdeps/linux/aarch64/thread_entry.S | 27 + lib/mlibc/sysdeps/linux/generic/cxx-syscall.hpp | 118 + lib/mlibc/sysdeps/linux/generic/entry.cpp | 38 + lib/mlibc/sysdeps/linux/generic/sysdeps.cpp | 2002 +++++++++++++ lib/mlibc/sysdeps/linux/generic/thread.cpp | 60 + .../sysdeps/linux/include-internal/linux/unistd.h | 2 + lib/mlibc/sysdeps/linux/include/abi-bits/access.h | 1 + lib/mlibc/sysdeps/linux/include/abi-bits/auxv.h | 1 + .../sysdeps/linux/include/abi-bits/blkcnt_t.h | 1 + .../sysdeps/linux/include/abi-bits/blksize_t.h | 1 + .../sysdeps/linux/include/abi-bits/clockid_t.h | 1 + lib/mlibc/sysdeps/linux/include/abi-bits/dev_t.h | 1 + lib/mlibc/sysdeps/linux/include/abi-bits/epoll.h | 1 + lib/mlibc/sysdeps/linux/include/abi-bits/errno.h | 1 + lib/mlibc/sysdeps/linux/include/abi-bits/fcntl.h | 1 + .../sysdeps/linux/include/abi-bits/fsblkcnt_t.h | 1 + .../sysdeps/linux/include/abi-bits/fsfilcnt_t.h | 1 + lib/mlibc/sysdeps/linux/include/abi-bits/gid_t.h | 1 + lib/mlibc/sysdeps/linux/include/abi-bits/in.h | 1 + lib/mlibc/sysdeps/linux/include/abi-bits/ino_t.h | 1 + lib/mlibc/sysdeps/linux/include/abi-bits/inotify.h | 1 + lib/mlibc/sysdeps/linux/include/abi-bits/ioctls.h | 1 + lib/mlibc/sysdeps/linux/include/abi-bits/limits.h | 1 + lib/mlibc/sysdeps/linux/include/abi-bits/mode_t.h | 1 + lib/mlibc/sysdeps/linux/include/abi-bits/mqueue.h | 1 + lib/mlibc/sysdeps/linux/include/abi-bits/msg.h | 1 + lib/mlibc/sysdeps/linux/include/abi-bits/nlink_t.h | 1 + lib/mlibc/sysdeps/linux/include/abi-bits/packet.h | 1 + lib/mlibc/sysdeps/linux/include/abi-bits/pid_t.h | 1 + lib/mlibc/sysdeps/linux/include/abi-bits/poll.h | 1 + lib/mlibc/sysdeps/linux/include/abi-bits/ptrace.h | 1 + lib/mlibc/sysdeps/linux/include/abi-bits/reboot.h | 1 + .../sysdeps/linux/include/abi-bits/resource.h | 1 + .../sysdeps/linux/include/abi-bits/seek-whence.h | 1 + lib/mlibc/sysdeps/linux/include/abi-bits/shm.h | 1 + lib/mlibc/sysdeps/linux/include/abi-bits/signal.h | 1 + lib/mlibc/sysdeps/linux/include/abi-bits/socket.h | 1 + .../sysdeps/linux/include/abi-bits/socklen_t.h | 1 + lib/mlibc/sysdeps/linux/include/abi-bits/stat.h | 1 + lib/mlibc/sysdeps/linux/include/abi-bits/statfs.h | 1 + lib/mlibc/sysdeps/linux/include/abi-bits/statvfs.h | 1 + .../sysdeps/linux/include/abi-bits/suseconds_t.h | 1 + lib/mlibc/sysdeps/linux/include/abi-bits/termios.h | 1 + lib/mlibc/sysdeps/linux/include/abi-bits/time.h | 1 + lib/mlibc/sysdeps/linux/include/abi-bits/uid_t.h | 1 + lib/mlibc/sysdeps/linux/include/abi-bits/utsname.h | 1 + .../sysdeps/linux/include/abi-bits/vm-flags.h | 1 + lib/mlibc/sysdeps/linux/include/abi-bits/vt.h | 1 + lib/mlibc/sysdeps/linux/include/abi-bits/wait.h | 1 + lib/mlibc/sysdeps/linux/include/abi-bits/xattr.h | 1 + lib/mlibc/sysdeps/linux/include/bits/syscall.h | 90 + .../sysdeps/linux/include/bits/syscall_aliases.h | 1823 ++++++++++++ .../sysdeps/linux/include/mlibc/thread-entry.hpp | 12 + lib/mlibc/sysdeps/linux/include/sys/syscall.h | 12 + lib/mlibc/sysdeps/linux/include/syscall.h | 1 + lib/mlibc/sysdeps/linux/meson.build | 143 + lib/mlibc/sysdeps/linux/mlibc-gcc.in | 2 + lib/mlibc/sysdeps/linux/mlibc-gcc.specs.in | 32 + lib/mlibc/sysdeps/linux/riscv64/arch-syscall.cpp | 117 + lib/mlibc/sysdeps/linux/riscv64/cp_syscall.S | 30 + lib/mlibc/sysdeps/linux/riscv64/crt-src/Scrt1.S | 18 + lib/mlibc/sysdeps/linux/riscv64/crt-src/crt1.S | 15 + lib/mlibc/sysdeps/linux/riscv64/crt-src/crti.S | 11 + lib/mlibc/sysdeps/linux/riscv64/crt-src/crtn.S | 7 + lib/mlibc/sysdeps/linux/riscv64/signals.S | 12 + lib/mlibc/sysdeps/linux/riscv64/syscallnos.h | 314 +++ lib/mlibc/sysdeps/linux/riscv64/thread_entry.S | 29 + lib/mlibc/sysdeps/linux/update-syscall-list.py | 332 +++ lib/mlibc/sysdeps/linux/x86/arch-syscall.cpp | 90 + lib/mlibc/sysdeps/linux/x86/cp_syscall.S | 42 + lib/mlibc/sysdeps/linux/x86/crt-src/Scrt1.S | 29 + lib/mlibc/sysdeps/linux/x86/crt-src/crt1.S | 18 + lib/mlibc/sysdeps/linux/x86/crt-src/crti.S | 11 + lib/mlibc/sysdeps/linux/x86/crt-src/crtn.S | 9 + lib/mlibc/sysdeps/linux/x86/signals.S | 18 + lib/mlibc/sysdeps/linux/x86/syscallnos.h | 433 +++ lib/mlibc/sysdeps/linux/x86/thread_entry.S | 61 + lib/mlibc/sysdeps/linux/x86_64/arch-syscall.cpp | 78 + lib/mlibc/sysdeps/linux/x86_64/cp_syscall.S | 29 + lib/mlibc/sysdeps/linux/x86_64/crt-src/Scrt1.S | 8 + lib/mlibc/sysdeps/linux/x86_64/crt-src/crt1.S | 8 + lib/mlibc/sysdeps/linux/x86_64/crt-src/crti.S | 11 + lib/mlibc/sysdeps/linux/x86_64/crt-src/crtn.S | 9 + lib/mlibc/sysdeps/linux/x86_64/signals.S | 14 + lib/mlibc/sysdeps/linux/x86_64/syscallnos.h | 362 +++ lib/mlibc/sysdeps/linux/x86_64/thread_entry.S | 23 + lib/mlibc/sysdeps/lyre/generic/entry.cpp | 120 + lib/mlibc/sysdeps/lyre/generic/generic.cpp | 860 ++++++ lib/mlibc/sysdeps/lyre/generic/mntent.cpp | 97 + lib/mlibc/sysdeps/lyre/generic/mount.cpp | 16 + lib/mlibc/sysdeps/lyre/generic/reboot.cpp | 7 + lib/mlibc/sysdeps/lyre/generic/thread.S | 9 + lib/mlibc/sysdeps/lyre/generic/thread.cpp | 58 + lib/mlibc/sysdeps/lyre/include/abi-bits/access.h | 1 + lib/mlibc/sysdeps/lyre/include/abi-bits/auxv.h | 1 + lib/mlibc/sysdeps/lyre/include/abi-bits/blkcnt_t.h | 1 + .../sysdeps/lyre/include/abi-bits/blksize_t.h | 1 + .../sysdeps/lyre/include/abi-bits/clockid_t.h | 1 + lib/mlibc/sysdeps/lyre/include/abi-bits/dev_t.h | 1 + lib/mlibc/sysdeps/lyre/include/abi-bits/epoll.h | 1 + lib/mlibc/sysdeps/lyre/include/abi-bits/errno.h | 1 + lib/mlibc/sysdeps/lyre/include/abi-bits/fcntl.h | 1 + .../sysdeps/lyre/include/abi-bits/fsblkcnt_t.h | 1 + .../sysdeps/lyre/include/abi-bits/fsfilcnt_t.h | 1 + lib/mlibc/sysdeps/lyre/include/abi-bits/gid_t.h | 1 + lib/mlibc/sysdeps/lyre/include/abi-bits/in.h | 1 + lib/mlibc/sysdeps/lyre/include/abi-bits/ino_t.h | 1 + lib/mlibc/sysdeps/lyre/include/abi-bits/inotify.h | 1 + lib/mlibc/sysdeps/lyre/include/abi-bits/ioctls.h | 1 + lib/mlibc/sysdeps/lyre/include/abi-bits/limits.h | 1 + lib/mlibc/sysdeps/lyre/include/abi-bits/mode_t.h | 1 + lib/mlibc/sysdeps/lyre/include/abi-bits/mqueue.h | 1 + lib/mlibc/sysdeps/lyre/include/abi-bits/msg.h | 1 + lib/mlibc/sysdeps/lyre/include/abi-bits/nlink_t.h | 1 + lib/mlibc/sysdeps/lyre/include/abi-bits/packet.h | 1 + lib/mlibc/sysdeps/lyre/include/abi-bits/pid_t.h | 1 + lib/mlibc/sysdeps/lyre/include/abi-bits/poll.h | 1 + lib/mlibc/sysdeps/lyre/include/abi-bits/ptrace.h | 1 + lib/mlibc/sysdeps/lyre/include/abi-bits/reboot.h | 1 + lib/mlibc/sysdeps/lyre/include/abi-bits/resource.h | 1 + .../sysdeps/lyre/include/abi-bits/seek-whence.h | 1 + lib/mlibc/sysdeps/lyre/include/abi-bits/shm.h | 1 + lib/mlibc/sysdeps/lyre/include/abi-bits/signal.h | 1 + lib/mlibc/sysdeps/lyre/include/abi-bits/socket.h | 1 + .../sysdeps/lyre/include/abi-bits/socklen_t.h | 1 + lib/mlibc/sysdeps/lyre/include/abi-bits/stat.h | 1 + lib/mlibc/sysdeps/lyre/include/abi-bits/statfs.h | 1 + lib/mlibc/sysdeps/lyre/include/abi-bits/statvfs.h | 1 + .../sysdeps/lyre/include/abi-bits/suseconds_t.h | 1 + lib/mlibc/sysdeps/lyre/include/abi-bits/termios.h | 1 + lib/mlibc/sysdeps/lyre/include/abi-bits/time.h | 1 + lib/mlibc/sysdeps/lyre/include/abi-bits/uid_t.h | 1 + lib/mlibc/sysdeps/lyre/include/abi-bits/utsname.h | 1 + lib/mlibc/sysdeps/lyre/include/abi-bits/vm-flags.h | 1 + lib/mlibc/sysdeps/lyre/include/abi-bits/wait.h | 1 + lib/mlibc/sysdeps/lyre/include/abi-bits/xattr.h | 1 + lib/mlibc/sysdeps/lyre/include/asm/ioctl.h | 105 + lib/mlibc/sysdeps/lyre/include/asm/ioctls.h | 121 + lib/mlibc/sysdeps/lyre/include/linux/fb.h | 400 +++ lib/mlibc/sysdeps/lyre/include/lyre/sockios.h | 25 + lib/mlibc/sysdeps/lyre/include/lyre/syscall.h | 113 + lib/mlibc/sysdeps/lyre/include/mntent.h | 50 + lib/mlibc/sysdeps/lyre/include/sys/mount.h | 54 + lib/mlibc/sysdeps/lyre/include/sys/reboot.h | 20 + lib/mlibc/sysdeps/lyre/include/sys/sysmacros.h | 33 + lib/mlibc/sysdeps/lyre/meson.build | 122 + lib/mlibc/sysdeps/lyre/x86_64/crt-src/crt0.S | 7 + lib/mlibc/sysdeps/lyre/x86_64/crt-src/crti.S | 11 + lib/mlibc/sysdeps/lyre/x86_64/crt-src/crtn.S | 9 + lib/mlibc/sysdeps/managarm/aarch64/crt-src/Scrt1.S | 10 + lib/mlibc/sysdeps/managarm/aarch64/crt-src/crt0.S | 11 + lib/mlibc/sysdeps/managarm/aarch64/crt-src/crti.S | 15 + lib/mlibc/sysdeps/managarm/aarch64/crt-src/crtn.S | 11 + lib/mlibc/sysdeps/managarm/aarch64/signals.S | 10 + lib/mlibc/sysdeps/managarm/aarch64/thread.cpp | 56 + lib/mlibc/sysdeps/managarm/aarch64/thread_entry.S | 11 + lib/mlibc/sysdeps/managarm/generic/drm.cpp | 1176 ++++++++ lib/mlibc/sysdeps/managarm/generic/ensure.cpp | 38 + lib/mlibc/sysdeps/managarm/generic/entry.cpp | 132 + lib/mlibc/sysdeps/managarm/generic/file.cpp | 2526 +++++++++++++++++ lib/mlibc/sysdeps/managarm/generic/fork-exec.cpp | 744 +++++ lib/mlibc/sysdeps/managarm/generic/ioctl.cpp | 708 +++++ lib/mlibc/sysdeps/managarm/generic/memory.cpp | 30 + lib/mlibc/sysdeps/managarm/generic/mount.cpp | 44 + lib/mlibc/sysdeps/managarm/generic/net.cpp | 57 + lib/mlibc/sysdeps/managarm/generic/sched.cpp | 102 + lib/mlibc/sysdeps/managarm/generic/signals.cpp | 139 + lib/mlibc/sysdeps/managarm/generic/socket.cpp | 423 +++ lib/mlibc/sysdeps/managarm/generic/time.cpp | 81 + .../sysdeps/managarm/include/abi-bits/access.h | 1 + lib/mlibc/sysdeps/managarm/include/abi-bits/auxv.h | 1 + .../sysdeps/managarm/include/abi-bits/blkcnt_t.h | 1 + .../sysdeps/managarm/include/abi-bits/blksize_t.h | 1 + .../sysdeps/managarm/include/abi-bits/clockid_t.h | 1 + .../sysdeps/managarm/include/abi-bits/dev_t.h | 1 + .../sysdeps/managarm/include/abi-bits/epoll.h | 1 + .../sysdeps/managarm/include/abi-bits/errno.h | 1 + .../sysdeps/managarm/include/abi-bits/fcntl.h | 1 + .../sysdeps/managarm/include/abi-bits/fsblkcnt_t.h | 1 + .../sysdeps/managarm/include/abi-bits/fsfilcnt_t.h | 1 + .../sysdeps/managarm/include/abi-bits/gid_t.h | 1 + lib/mlibc/sysdeps/managarm/include/abi-bits/in.h | 1 + .../sysdeps/managarm/include/abi-bits/ino_t.h | 1 + .../sysdeps/managarm/include/abi-bits/inotify.h | 1 + .../sysdeps/managarm/include/abi-bits/ioctls.h | 1 + .../sysdeps/managarm/include/abi-bits/limits.h | 1 + .../sysdeps/managarm/include/abi-bits/mode_t.h | 1 + .../sysdeps/managarm/include/abi-bits/mqueue.h | 1 + lib/mlibc/sysdeps/managarm/include/abi-bits/msg.h | 1 + .../sysdeps/managarm/include/abi-bits/nlink_t.h | 1 + .../sysdeps/managarm/include/abi-bits/packet.h | 1 + .../sysdeps/managarm/include/abi-bits/pid_t.h | 1 + lib/mlibc/sysdeps/managarm/include/abi-bits/poll.h | 1 + .../sysdeps/managarm/include/abi-bits/ptrace.h | 1 + .../sysdeps/managarm/include/abi-bits/reboot.h | 1 + .../sysdeps/managarm/include/abi-bits/resource.h | 1 + .../managarm/include/abi-bits/seek-whence.h | 1 + lib/mlibc/sysdeps/managarm/include/abi-bits/shm.h | 1 + .../sysdeps/managarm/include/abi-bits/signal.h | 1 + .../sysdeps/managarm/include/abi-bits/socket.h | 1 + .../sysdeps/managarm/include/abi-bits/socklen_t.h | 1 + lib/mlibc/sysdeps/managarm/include/abi-bits/stat.h | 1 + .../sysdeps/managarm/include/abi-bits/statfs.h | 1 + .../sysdeps/managarm/include/abi-bits/statvfs.h | 1 + .../managarm/include/abi-bits/suseconds_t.h | 1 + .../sysdeps/managarm/include/abi-bits/termios.h | 1 + lib/mlibc/sysdeps/managarm/include/abi-bits/time.h | 1 + .../sysdeps/managarm/include/abi-bits/uid_t.h | 1 + .../sysdeps/managarm/include/abi-bits/utsname.h | 1 + .../sysdeps/managarm/include/abi-bits/vm-flags.h | 1 + lib/mlibc/sysdeps/managarm/include/abi-bits/vt.h | 1 + lib/mlibc/sysdeps/managarm/include/abi-bits/wait.h | 1 + .../sysdeps/managarm/include/abi-bits/xattr.h | 1 + .../sysdeps/managarm/include/mlibc/posix-pipe.hpp | 300 ++ .../managarm/include/mlibc/thread-entry.hpp | 10 + lib/mlibc/sysdeps/managarm/meson.build | 145 + .../sysdeps/managarm/rtdl-generic/support.cpp | 444 +++ lib/mlibc/sysdeps/managarm/x86_64/crt-src/Scrt1.S | 8 + lib/mlibc/sysdeps/managarm/x86_64/crt-src/crt0.S | 10 + lib/mlibc/sysdeps/managarm/x86_64/crt-src/crti.S | 15 + lib/mlibc/sysdeps/managarm/x86_64/crt-src/crtn.S | 11 + lib/mlibc/sysdeps/managarm/x86_64/signals.S | 10 + lib/mlibc/sysdeps/managarm/x86_64/thread.cpp | 56 + lib/mlibc/sysdeps/managarm/x86_64/thread_entry.S | 11 + lib/mlibc/test.c | 7 + lib/mlibc/tests/ansi/abs.c | 16 + lib/mlibc/tests/ansi/alloc.c | 37 + lib/mlibc/tests/ansi/calloc.c | 20 + lib/mlibc/tests/ansi/creal-cimag.c | 37 + lib/mlibc/tests/ansi/fenv.c | 91 + lib/mlibc/tests/ansi/fopen.c | 59 + lib/mlibc/tests/ansi/freopen.c | 49 + lib/mlibc/tests/ansi/locale.c | 17 + lib/mlibc/tests/ansi/longjmp.c | 29 + lib/mlibc/tests/ansi/mbrtoc32.c | 53 + lib/mlibc/tests/ansi/memmem.c | 22 + lib/mlibc/tests/ansi/qsort.c | 31 + lib/mlibc/tests/ansi/snprintf.c | 23 + lib/mlibc/tests/ansi/sprintf.c | 191 ++ lib/mlibc/tests/ansi/sscanf.c | 143 + lib/mlibc/tests/ansi/strchr.c | 20 + lib/mlibc/tests/ansi/strftime.c | 48 + lib/mlibc/tests/ansi/strrchr.c | 11 + lib/mlibc/tests/ansi/strtof.c | 83 + lib/mlibc/tests/ansi/strtol.c | 140 + lib/mlibc/tests/ansi/strverscmp.c | 16 + lib/mlibc/tests/ansi/strxfrm.c | 14 + lib/mlibc/tests/ansi/timegm.c | 45 + lib/mlibc/tests/ansi/ungetc.c | 74 + lib/mlibc/tests/ansi/utf8.c | 63 + lib/mlibc/tests/ansi/wcsdup.c | 11 + lib/mlibc/tests/ansi/wcsncasecmp.c | 11 + lib/mlibc/tests/ansi/wcsrtombs.c | 12 + lib/mlibc/tests/ansi/wmemcmp.c | 19 + lib/mlibc/tests/bsd/ns_get_put.c | 21 + lib/mlibc/tests/bsd/reallocarray.c | 7 + lib/mlibc/tests/bsd/sbrk.c | 9 + lib/mlibc/tests/bsd/strl.c | 56 + lib/mlibc/tests/glibc/error.c | 6 + lib/mlibc/tests/glibc/error.py | 11 + lib/mlibc/tests/glibc/error_at_line.c | 6 + lib/mlibc/tests/glibc/error_at_line.py | 11 + lib/mlibc/tests/glibc/error_expect_fail.c | 6 + lib/mlibc/tests/glibc/error_message_count.c | 11 + lib/mlibc/tests/glibc/error_one_per_line.c | 13 + lib/mlibc/tests/glibc/error_print_progname.c | 19 + lib/mlibc/tests/glibc/ffsl-ffsll.c | 36 + lib/mlibc/tests/glibc/getopt.c | 288 ++ lib/mlibc/tests/glibc/gnu-basename.c | 13 + lib/mlibc/tests/glibc/linux-syscall.c | 14 + lib/mlibc/tests/linux/cpuset.c | 27 + lib/mlibc/tests/linux/malloc-usable-size.c | 13 + lib/mlibc/tests/linux/pthread_attr.c | 90 + lib/mlibc/tests/linux/pthread_setname_np.c | 33 + lib/mlibc/tests/linux/xattr.c | 80 + lib/mlibc/tests/meson.build | 261 ++ lib/mlibc/tests/posix/abort.c | 21 + lib/mlibc/tests/posix/accept4.c | 123 + lib/mlibc/tests/posix/access.c | 30 + lib/mlibc/tests/posix/alarm.c | 34 + lib/mlibc/tests/posix/basename.c | 17 + lib/mlibc/tests/posix/dprintf.c | 39 + lib/mlibc/tests/posix/fdopen.c | 37 + lib/mlibc/tests/posix/ffs.c | 18 + lib/mlibc/tests/posix/flockfile.c | 35 + lib/mlibc/tests/posix/fmemopen.c | 150 + lib/mlibc/tests/posix/fopencookie.c | 69 + lib/mlibc/tests/posix/getaddrinfo.c | 52 + lib/mlibc/tests/posix/getcwd.c | 22 + lib/mlibc/tests/posix/getdelim.c | 90 + lib/mlibc/tests/posix/getnameinfo.c | 22 + lib/mlibc/tests/posix/getservbyname.c | 27 + lib/mlibc/tests/posix/getservbyport.c | 28 + lib/mlibc/tests/posix/grp.c | 110 + lib/mlibc/tests/posix/if_indextoname.c | 11 + lib/mlibc/tests/posix/index.c | 20 + lib/mlibc/tests/posix/inet_ntop.c | 30 + lib/mlibc/tests/posix/inet_pton.c | 16 + lib/mlibc/tests/posix/memrchr.c | 25 + lib/mlibc/tests/posix/mkstemp.c | 70 + lib/mlibc/tests/posix/open_memstream.c | 65 + lib/mlibc/tests/posix/pause.c | 49 + lib/mlibc/tests/posix/popen.c | 42 + lib/mlibc/tests/posix/posix-timer.c | 47 + lib/mlibc/tests/posix/posix_memalign.c | 21 + lib/mlibc/tests/posix/posix_spawn.c | 38 + lib/mlibc/tests/posix/pthread_atfork.c | 54 + lib/mlibc/tests/posix/pthread_attr.c | 157 ++ lib/mlibc/tests/posix/pthread_barrier.c | 56 + lib/mlibc/tests/posix/pthread_cancel.c | 150 + lib/mlibc/tests/posix/pthread_cleanup.c | 42 + lib/mlibc/tests/posix/pthread_cond.c | 106 + lib/mlibc/tests/posix/pthread_create.c | 22 + lib/mlibc/tests/posix/pthread_key.c | 95 + lib/mlibc/tests/posix/pthread_kill.c | 46 + lib/mlibc/tests/posix/pthread_mutex.c | 101 + lib/mlibc/tests/posix/pthread_rwlock.c | 114 + lib/mlibc/tests/posix/pthread_schedparam.c | 32 + lib/mlibc/tests/posix/pthread_thread_local.c | 53 + lib/mlibc/tests/posix/pwd.c | 88 + lib/mlibc/tests/posix/readv-writev.c | 51 + lib/mlibc/tests/posix/realpath.c | 133 + lib/mlibc/tests/posix/regex.c | 30 + lib/mlibc/tests/posix/rindex.c | 11 + lib/mlibc/tests/posix/rlimits.c | 26 + lib/mlibc/tests/posix/search.c | 51 + lib/mlibc/tests/posix/setpriority.c | 27 + lib/mlibc/tests/posix/sigaltstack.c | 55 + lib/mlibc/tests/posix/sigsuspend.c | 53 + lib/mlibc/tests/posix/sigtimedwait.c | 91 + lib/mlibc/tests/posix/strdupa.c | 14 + lib/mlibc/tests/posix/string.c | 29 + lib/mlibc/tests/posix/system.c | 18 + lib/mlibc/tests/posix/time.c | 191 ++ lib/mlibc/tests/posix/timer.c | 25 + lib/mlibc/tests/posix/vfork.c | 28 + lib/mlibc/tests/posix/waitid.c | 20 + lib/mlibc/tests/posix/wcwidth.c | 67 + lib/mlibc/tests/posix/wordexp.c | 140 + lib/mlibc/tests/rtdl/dl_iterate_phdr/libbar.c | 3 + lib/mlibc/tests/rtdl/dl_iterate_phdr/libfoo.c | 1 + lib/mlibc/tests/rtdl/dl_iterate_phdr/meson.build | 7 + lib/mlibc/tests/rtdl/dl_iterate_phdr/test.c | 91 + lib/mlibc/tests/rtdl/dladdr_local/libfoo.c | 1 + lib/mlibc/tests/rtdl/dladdr_local/meson.build | 5 + lib/mlibc/tests/rtdl/dladdr_local/test.c | 21 + lib/mlibc/tests/rtdl/ld_library_path/libfoo.c | 1 + lib/mlibc/tests/rtdl/ld_library_path/meson.build | 19 + lib/mlibc/tests/rtdl/ld_library_path/test.c | 16 + lib/mlibc/tests/rtdl/meson.build | 56 + lib/mlibc/tests/rtdl/noload-promote/libfoo.c | 1 + lib/mlibc/tests/rtdl/noload-promote/meson.build | 5 + lib/mlibc/tests/rtdl/noload-promote/test.c | 22 + lib/mlibc/tests/rtdl/preinit/libfoo.c | 18 + lib/mlibc/tests/rtdl/preinit/meson.build | 18 + lib/mlibc/tests/rtdl/preinit/test.c | 44 + lib/mlibc/tests/rtdl/rtld_next/libbar.c | 16 + lib/mlibc/tests/rtdl/rtld_next/libfoo.c | 17 + lib/mlibc/tests/rtdl/rtld_next/meson.build | 25 + lib/mlibc/tests/rtdl/rtld_next/test.c | 26 + lib/mlibc/tests/rtdl/scope1/libbar.c | 14 + lib/mlibc/tests/rtdl/scope1/libfoo.c | 9 + lib/mlibc/tests/rtdl/scope1/meson.build | 7 + lib/mlibc/tests/rtdl/scope1/test.c | 90 + lib/mlibc/tests/rtdl/scope2/libbar.c | 5 + lib/mlibc/tests/rtdl/scope2/libbaz.c | 3 + lib/mlibc/tests/rtdl/scope2/libfoo.c | 3 + lib/mlibc/tests/rtdl/scope2/meson.build | 9 + lib/mlibc/tests/rtdl/scope2/test.c | 36 + lib/mlibc/tests/rtdl/scope3/libbar.c | 8 + lib/mlibc/tests/rtdl/scope3/libbaz.c | 7 + lib/mlibc/tests/rtdl/scope3/libfoo.c | 5 + lib/mlibc/tests/rtdl/scope3/meson.build | 9 + lib/mlibc/tests/rtdl/scope3/test.c | 39 + lib/mlibc/tests/rtdl/scope4/libbar.c | 3 + lib/mlibc/tests/rtdl/scope4/libbaz.c | 1 + lib/mlibc/tests/rtdl/scope4/libfoo.c | 3 + lib/mlibc/tests/rtdl/scope4/meson.build | 9 + lib/mlibc/tests/rtdl/scope4/test.c | 36 + lib/mlibc/tests/rtdl/scope5/libfoo.c | 1 + lib/mlibc/tests/rtdl/scope5/meson.build | 5 + lib/mlibc/tests/rtdl/scope5/test.c | 27 + lib/mlibc/tests/rtdl/soname/libbar.c | 1 + lib/mlibc/tests/rtdl/soname/libfoo.c | 1 + lib/mlibc/tests/rtdl/soname/meson.build | 17 + lib/mlibc/tests/rtdl/soname/test.c | 33 + lib/mlibc/tests/rtdl/tls_align/libbar.c | 1 + lib/mlibc/tests/rtdl/tls_align/libfoo.c | 1 + lib/mlibc/tests/rtdl/tls_align/meson.build | 7 + lib/mlibc/tests/rtdl/tls_align/test.c | 10 + 1615 files changed, 104200 insertions(+) create mode 100644 lib/Makefile create mode 100644 lib/mlibc/.github/workflows/abidiff.yml create mode 100644 lib/mlibc/.github/workflows/ci.yml create mode 100644 lib/mlibc/.github/workflows/detect-bad-ifs.yml create mode 100644 lib/mlibc/.github/workflows/detect-missing-mlibc-config.yml create mode 100644 lib/mlibc/.github/workflows/fixups.yml create mode 100644 lib/mlibc/.gitignore create mode 100644 lib/mlibc/ABI_BREAKS.md create mode 100644 lib/mlibc/LICENSE create mode 100644 lib/mlibc/README.md create mode 100644 lib/mlibc/RELEASE_PROCEDURE.md create mode 100644 lib/mlibc/abis/aero/auxv.h create mode 100644 lib/mlibc/abis/dripos/auxv.h create mode 100644 lib/mlibc/abis/dripos/errno.h create mode 100644 lib/mlibc/abis/hyra/auxv.h create mode 100644 lib/mlibc/abis/ironclad/access.h create mode 100644 lib/mlibc/abis/ironclad/auxv.h create mode 100644 lib/mlibc/abis/ironclad/blkcnt_t.h create mode 100644 lib/mlibc/abis/ironclad/blksize_t.h create mode 100644 lib/mlibc/abis/ironclad/clockid_t.h create mode 100644 lib/mlibc/abis/ironclad/dev_t.h create mode 100644 lib/mlibc/abis/ironclad/epoll.h create mode 100644 lib/mlibc/abis/ironclad/errno.h create mode 100644 lib/mlibc/abis/ironclad/fcntl.h create mode 100644 lib/mlibc/abis/ironclad/fsblkcnt_t.h create mode 100644 lib/mlibc/abis/ironclad/fsfilcnt_t.h create mode 100644 lib/mlibc/abis/ironclad/gid_t.h create mode 100644 lib/mlibc/abis/ironclad/in.h create mode 100644 lib/mlibc/abis/ironclad/ino_t.h create mode 100644 lib/mlibc/abis/ironclad/inotify.h create mode 100644 lib/mlibc/abis/ironclad/ioctls.h create mode 100644 lib/mlibc/abis/ironclad/limits.h create mode 100644 lib/mlibc/abis/ironclad/mode_t.h create mode 100644 lib/mlibc/abis/ironclad/mqueue.h create mode 100644 lib/mlibc/abis/ironclad/msg.h create mode 100644 lib/mlibc/abis/ironclad/nlink_t.h create mode 100644 lib/mlibc/abis/ironclad/packet.h create mode 100644 lib/mlibc/abis/ironclad/pid_t.h create mode 100644 lib/mlibc/abis/ironclad/poll.h create mode 100644 lib/mlibc/abis/ironclad/ptrace.h create mode 100644 lib/mlibc/abis/ironclad/reboot.h create mode 100644 lib/mlibc/abis/ironclad/resource.h create mode 100644 lib/mlibc/abis/ironclad/seek-whence.h create mode 100644 lib/mlibc/abis/ironclad/shm.h create mode 100644 lib/mlibc/abis/ironclad/signal.h create mode 100644 lib/mlibc/abis/ironclad/socket.h create mode 100644 lib/mlibc/abis/ironclad/socklen_t.h create mode 100644 lib/mlibc/abis/ironclad/stat.h create mode 100644 lib/mlibc/abis/ironclad/statfs.h create mode 100644 lib/mlibc/abis/ironclad/statvfs.h create mode 100644 lib/mlibc/abis/ironclad/suseconds_t.h create mode 100644 lib/mlibc/abis/ironclad/termios.h create mode 100644 lib/mlibc/abis/ironclad/time.h create mode 100644 lib/mlibc/abis/ironclad/uid_t.h create mode 100644 lib/mlibc/abis/ironclad/utsname.h create mode 100644 lib/mlibc/abis/ironclad/vm-flags.h create mode 100644 lib/mlibc/abis/ironclad/wait.h create mode 100644 lib/mlibc/abis/ironclad/xattr.h create mode 100644 lib/mlibc/abis/lemon/auxv.h create mode 100644 lib/mlibc/abis/linux/access.h create mode 100644 lib/mlibc/abis/linux/auxv.h create mode 100644 lib/mlibc/abis/linux/blkcnt_t.h create mode 100644 lib/mlibc/abis/linux/blksize_t.h create mode 100644 lib/mlibc/abis/linux/clockid_t.h create mode 100644 lib/mlibc/abis/linux/dev_t.h create mode 100644 lib/mlibc/abis/linux/epoll.h create mode 100644 lib/mlibc/abis/linux/errno.h create mode 100644 lib/mlibc/abis/linux/fcntl.h create mode 100644 lib/mlibc/abis/linux/fsblkcnt_t.h create mode 100644 lib/mlibc/abis/linux/fsfilcnt_t.h create mode 100644 lib/mlibc/abis/linux/gid_t.h create mode 100644 lib/mlibc/abis/linux/in.h create mode 100644 lib/mlibc/abis/linux/ino_t.h create mode 100644 lib/mlibc/abis/linux/inotify.h create mode 100644 lib/mlibc/abis/linux/ioctls.h create mode 100644 lib/mlibc/abis/linux/limits.h create mode 100644 lib/mlibc/abis/linux/mode_t.h create mode 100644 lib/mlibc/abis/linux/mqueue.h create mode 100644 lib/mlibc/abis/linux/msg.h create mode 100644 lib/mlibc/abis/linux/nlink_t.h create mode 100644 lib/mlibc/abis/linux/packet.h create mode 100644 lib/mlibc/abis/linux/pid_t.h create mode 100644 lib/mlibc/abis/linux/poll.h create mode 100644 lib/mlibc/abis/linux/ptrace.h create mode 100644 lib/mlibc/abis/linux/reboot.h create mode 100644 lib/mlibc/abis/linux/resource.h create mode 100644 lib/mlibc/abis/linux/seek-whence.h create mode 100644 lib/mlibc/abis/linux/shm.h create mode 100644 lib/mlibc/abis/linux/signal.h create mode 100644 lib/mlibc/abis/linux/socket.h create mode 100644 lib/mlibc/abis/linux/socklen_t.h create mode 100644 lib/mlibc/abis/linux/stat.h create mode 100644 lib/mlibc/abis/linux/statfs.h create mode 100644 lib/mlibc/abis/linux/statvfs.h create mode 100644 lib/mlibc/abis/linux/suseconds_t.h create mode 100644 lib/mlibc/abis/linux/termios.h create mode 100644 lib/mlibc/abis/linux/time.h create mode 100644 lib/mlibc/abis/linux/uid_t.h create mode 100644 lib/mlibc/abis/linux/utsname.h create mode 100644 lib/mlibc/abis/linux/vm-flags.h create mode 100644 lib/mlibc/abis/linux/vt.h create mode 100644 lib/mlibc/abis/linux/wait.h create mode 100644 lib/mlibc/abis/linux/xattr.h create mode 100644 lib/mlibc/abis/lyre/statvfs.h create mode 100644 lib/mlibc/abis/managarm/auxv.h create mode 100644 lib/mlibc/abis/mlibc/access.h create mode 100644 lib/mlibc/abis/mlibc/blkcnt_t.h create mode 100644 lib/mlibc/abis/mlibc/blksize_t.h create mode 100644 lib/mlibc/abis/mlibc/clockid_t.h create mode 100644 lib/mlibc/abis/mlibc/dev_t.h create mode 100644 lib/mlibc/abis/mlibc/epoll.h create mode 100644 lib/mlibc/abis/mlibc/errno.h create mode 100644 lib/mlibc/abis/mlibc/fcntl.h create mode 100644 lib/mlibc/abis/mlibc/gid_t.h create mode 100644 lib/mlibc/abis/mlibc/in.h create mode 100644 lib/mlibc/abis/mlibc/ino_t.h create mode 100644 lib/mlibc/abis/mlibc/inotify.h create mode 100644 lib/mlibc/abis/mlibc/limits.h create mode 100644 lib/mlibc/abis/mlibc/mode_t.h create mode 100644 lib/mlibc/abis/mlibc/nlink_t.h create mode 100644 lib/mlibc/abis/mlibc/packet.h create mode 100644 lib/mlibc/abis/mlibc/pid_t.h create mode 100644 lib/mlibc/abis/mlibc/poll.h create mode 100644 lib/mlibc/abis/mlibc/ptrace.h create mode 100644 lib/mlibc/abis/mlibc/resource.h create mode 100644 lib/mlibc/abis/mlibc/seek-whence.h create mode 100644 lib/mlibc/abis/mlibc/signal.h create mode 100644 lib/mlibc/abis/mlibc/socket.h create mode 100644 lib/mlibc/abis/mlibc/stat.h create mode 100644 lib/mlibc/abis/mlibc/termios.h create mode 100644 lib/mlibc/abis/mlibc/time.h create mode 100644 lib/mlibc/abis/mlibc/uid_t.h create mode 100644 lib/mlibc/abis/mlibc/utsname.h create mode 100644 lib/mlibc/abis/mlibc/vm-flags.h create mode 100644 lib/mlibc/abis/mlibc/wait.h create mode 100644 lib/mlibc/ci/abidiff_suppress.ini create mode 100644 lib/mlibc/ci/aero.cross-file create mode 100644 lib/mlibc/ci/bootstrap.yml create mode 100644 lib/mlibc/ci/dripos.cross-file create mode 100644 lib/mlibc/ci/ironclad.cross-file create mode 100644 lib/mlibc/ci/keyronex.cross-file create mode 100644 lib/mlibc/ci/lemon.cross-file create mode 100644 lib/mlibc/ci/linux-aarch64.cross-file create mode 100644 lib/mlibc/ci/linux-riscv64.cross-file create mode 100644 lib/mlibc/ci/linux-x86.cross-file create mode 100644 lib/mlibc/ci/linux-x86_64.cross-file create mode 100644 lib/mlibc/ci/lyre.cross-file create mode 100644 lib/mlibc/ci/managarm.cross-file create mode 100644 lib/mlibc/cross_file.txt create mode 120000 lib/mlibc/crossbin create mode 100644 lib/mlibc/dummy-libs/libcrypt/src/dummy.cpp create mode 100644 lib/mlibc/dummy-libs/libdl/src/dummy.cpp create mode 100644 lib/mlibc/dummy-libs/libm/src/dummy.cpp create mode 100644 lib/mlibc/dummy-libs/libpthread/src/dummy.cpp create mode 100644 lib/mlibc/dummy-libs/libresolv/src/dummy.cpp create mode 100644 lib/mlibc/dummy-libs/librt/src/dummy.cpp create mode 100644 lib/mlibc/dummy-libs/libssp/src/dummy.cpp create mode 100644 lib/mlibc/dummy-libs/libssp_nonshared/src/dummy.cpp create mode 100644 lib/mlibc/dummy-libs/libutil/src/dummy.cpp create mode 100644 lib/mlibc/internal-config.h.in create mode 100644 lib/mlibc/meson.build create mode 100644 lib/mlibc/meson_options.txt create mode 100644 lib/mlibc/mlibc-config.h.in create mode 100644 lib/mlibc/options/ansi/generic/assert-stubs.cpp create mode 100644 lib/mlibc/options/ansi/generic/complex-stubs.c create mode 100644 lib/mlibc/options/ansi/generic/complex/cabs.c create mode 100644 lib/mlibc/options/ansi/generic/complex/cabsf.c create mode 100644 lib/mlibc/options/ansi/generic/complex/cacos.c create mode 100644 lib/mlibc/options/ansi/generic/complex/cacosf.c create mode 100644 lib/mlibc/options/ansi/generic/complex/cacosh.c create mode 100644 lib/mlibc/options/ansi/generic/complex/cacoshf.c create mode 100644 lib/mlibc/options/ansi/generic/complex/carg.c create mode 100644 lib/mlibc/options/ansi/generic/complex/cargf.c create mode 100644 lib/mlibc/options/ansi/generic/complex/casin.c create mode 100644 lib/mlibc/options/ansi/generic/complex/casinf.c create mode 100644 lib/mlibc/options/ansi/generic/complex/casinh.c create mode 100644 lib/mlibc/options/ansi/generic/complex/casinhf.c create mode 100644 lib/mlibc/options/ansi/generic/complex/catan.c create mode 100644 lib/mlibc/options/ansi/generic/complex/catanf.c create mode 100644 lib/mlibc/options/ansi/generic/complex/catanh.c create mode 100644 lib/mlibc/options/ansi/generic/complex/catanhf.c create mode 100644 lib/mlibc/options/ansi/generic/complex/ccos.c create mode 100644 lib/mlibc/options/ansi/generic/complex/ccosf.c create mode 100644 lib/mlibc/options/ansi/generic/complex/ccosh.c create mode 100644 lib/mlibc/options/ansi/generic/complex/ccoshf.c create mode 100644 lib/mlibc/options/ansi/generic/complex/cephes_subr.c create mode 100644 lib/mlibc/options/ansi/generic/complex/cephes_subr.h create mode 100644 lib/mlibc/options/ansi/generic/complex/cephes_subrf.c create mode 100644 lib/mlibc/options/ansi/generic/complex/cephes_subrf.h create mode 100644 lib/mlibc/options/ansi/generic/complex/cexp.c create mode 100644 lib/mlibc/options/ansi/generic/complex/cexpf.c create mode 100644 lib/mlibc/options/ansi/generic/complex/cimag.c create mode 100644 lib/mlibc/options/ansi/generic/complex/cimagf.c create mode 100644 lib/mlibc/options/ansi/generic/complex/clog.c create mode 100644 lib/mlibc/options/ansi/generic/complex/clogf.c create mode 100644 lib/mlibc/options/ansi/generic/complex/conj.c create mode 100644 lib/mlibc/options/ansi/generic/complex/conjf.c create mode 100644 lib/mlibc/options/ansi/generic/complex/cpow.c create mode 100644 lib/mlibc/options/ansi/generic/complex/cpowf.c create mode 100644 lib/mlibc/options/ansi/generic/complex/cproj.c create mode 100644 lib/mlibc/options/ansi/generic/complex/cprojf.c create mode 100644 lib/mlibc/options/ansi/generic/complex/creal.c create mode 100644 lib/mlibc/options/ansi/generic/complex/crealf.c create mode 100644 lib/mlibc/options/ansi/generic/complex/csin.c create mode 100644 lib/mlibc/options/ansi/generic/complex/csinf.c create mode 100644 lib/mlibc/options/ansi/generic/complex/csinh.c create mode 100644 lib/mlibc/options/ansi/generic/complex/csinhf.c create mode 100644 lib/mlibc/options/ansi/generic/complex/csqrt.c create mode 100644 lib/mlibc/options/ansi/generic/complex/csqrtf.c create mode 100644 lib/mlibc/options/ansi/generic/complex/ctan.c create mode 100644 lib/mlibc/options/ansi/generic/complex/ctanf.c create mode 100644 lib/mlibc/options/ansi/generic/complex/ctanh.c create mode 100644 lib/mlibc/options/ansi/generic/complex/ctanhf.c create mode 100644 lib/mlibc/options/ansi/generic/complex/fdlibm.h create mode 100644 lib/mlibc/options/ansi/generic/ctype-stubs.cpp create mode 100644 lib/mlibc/options/ansi/generic/environment.cpp create mode 100644 lib/mlibc/options/ansi/generic/errno-stubs.cpp create mode 100644 lib/mlibc/options/ansi/generic/fenv-stubs.cpp create mode 100644 lib/mlibc/options/ansi/generic/file-io.cpp create mode 100644 lib/mlibc/options/ansi/generic/inttypes-stubs.cpp create mode 100644 lib/mlibc/options/ansi/generic/locale-stubs.cpp create mode 100644 lib/mlibc/options/ansi/generic/math-stubs.ignored-cpp create mode 100644 lib/mlibc/options/ansi/generic/signal-stubs.cpp create mode 100644 lib/mlibc/options/ansi/generic/stdio-stubs.cpp create mode 100644 lib/mlibc/options/ansi/generic/stdlib-stubs.cpp create mode 100644 lib/mlibc/options/ansi/generic/string-stubs.cpp create mode 100644 lib/mlibc/options/ansi/generic/threads.cpp create mode 100644 lib/mlibc/options/ansi/generic/time-stubs.cpp create mode 100644 lib/mlibc/options/ansi/generic/uchar.cpp create mode 100644 lib/mlibc/options/ansi/generic/wchar-stubs.cpp create mode 100644 lib/mlibc/options/ansi/generic/wctype.cpp create mode 100644 lib/mlibc/options/ansi/include/alloca.h create mode 100644 lib/mlibc/options/ansi/include/assert.h create mode 100644 lib/mlibc/options/ansi/include/bits/ansi/fenv.h create mode 100644 lib/mlibc/options/ansi/include/bits/ansi/time_t.h create mode 100644 lib/mlibc/options/ansi/include/bits/ansi/timespec.h create mode 100644 lib/mlibc/options/ansi/include/complex.h create mode 100644 lib/mlibc/options/ansi/include/ctype.h create mode 100644 lib/mlibc/options/ansi/include/errno.h create mode 100644 lib/mlibc/options/ansi/include/fenv.h create mode 100644 lib/mlibc/options/ansi/include/inttypes.h create mode 100644 lib/mlibc/options/ansi/include/limits.h create mode 100644 lib/mlibc/options/ansi/include/locale.h create mode 100644 lib/mlibc/options/ansi/include/math.h create mode 100644 lib/mlibc/options/ansi/include/mlibc/ansi-sysdeps.hpp create mode 100644 lib/mlibc/options/ansi/include/mlibc/environment.hpp create mode 100644 lib/mlibc/options/ansi/include/mlibc/file-io.hpp create mode 100644 lib/mlibc/options/ansi/include/setjmp.h create mode 100644 lib/mlibc/options/ansi/include/signal.h create mode 100644 lib/mlibc/options/ansi/include/stdc-predef.h create mode 100644 lib/mlibc/options/ansi/include/stdio.h create mode 100644 lib/mlibc/options/ansi/include/stdlib.h create mode 100644 lib/mlibc/options/ansi/include/string.h create mode 100644 lib/mlibc/options/ansi/include/threads.h create mode 100644 lib/mlibc/options/ansi/include/time.h create mode 100644 lib/mlibc/options/ansi/include/uchar.h create mode 100644 lib/mlibc/options/ansi/include/wchar.h create mode 100644 lib/mlibc/options/ansi/include/wctype.h create mode 100644 lib/mlibc/options/ansi/meson.build create mode 100644 lib/mlibc/options/ansi/musl-generic-math/__cos.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/__cosdf.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/__cosl.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/__expo2.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/__expo2f.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/__fpclassify.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/__fpclassifyf.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/__fpclassifyl.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/__invtrigl.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/__invtrigl.h create mode 100644 lib/mlibc/options/ansi/musl-generic-math/__polevll.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/__rem_pio2.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/__rem_pio2_large.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/__rem_pio2f.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/__rem_pio2l.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/__signbit.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/__signbitf.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/__signbitl.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/__sin.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/__sindf.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/__sinl.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/__tan.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/__tandf.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/__tanl.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/acos.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/acosf.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/acosh.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/acoshf.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/acoshl.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/acosl.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/asin.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/asinf.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/asinh.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/asinhf.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/asinhl.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/asinl.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/atan.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/atan2.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/atan2f.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/atan2l.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/atanf.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/atanh.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/atanhf.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/atanhl.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/atanl.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/cbrt.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/cbrtf.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/cbrtl.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/ceil.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/ceilf.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/ceill.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/copysign.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/copysignf.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/copysignl.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/cos.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/cosf.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/cosh.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/coshf.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/coshl.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/cosl.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/erf.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/erff.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/erfl.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/exp.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/exp10.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/exp10f.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/exp10l.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/exp2.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/exp2f.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/exp2l.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/expf.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/expl.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/expm1.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/expm1f.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/expm1l.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/fabs.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/fabsf.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/fabsl.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/fdim.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/fdimf.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/fdiml.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/finite.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/finitef.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/floor.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/floorf.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/floorl.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/fma.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/fmaf.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/fmal.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/fmax.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/fmaxf.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/fmaxl.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/fmin.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/fminf.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/fminl.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/fmod.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/fmodf.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/fmodl.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/frexp.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/frexpf.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/frexpl.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/hypot.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/hypotf.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/hypotl.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/ilogb.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/ilogbf.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/ilogbl.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/j0.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/j0f.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/j1.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/j1f.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/jn.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/jnf.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/ldexp.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/ldexpf.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/ldexpl.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/lgamma.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/lgamma_r.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/lgammaf.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/lgammaf_r.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/lgammal.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/libm.h create mode 100644 lib/mlibc/options/ansi/musl-generic-math/llrint.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/llrintf.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/llrintl.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/llround.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/llroundf.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/llroundl.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/log.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/log10.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/log10f.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/log10l.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/log1p.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/log1pf.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/log1pl.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/log2.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/log2f.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/log2l.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/logb.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/logbf.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/logbl.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/logf.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/logl.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/lrint.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/lrintf.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/lrintl.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/lround.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/lroundf.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/lroundl.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/modf.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/modff.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/modfl.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/nan.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/nanf.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/nanl.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/nearbyint.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/nearbyintf.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/nearbyintl.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/nextafter.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/nextafterf.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/nextafterl.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/nexttoward.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/nexttowardf.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/nexttowardl.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/pow.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/powf.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/powl.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/remainder.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/remainderf.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/remainderl.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/remquo.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/remquof.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/remquol.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/rint.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/rintf.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/rintl.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/round.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/roundf.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/roundl.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/scalb.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/scalbf.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/scalbln.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/scalblnf.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/scalblnl.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/scalbn.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/scalbnf.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/scalbnl.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/signgam.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/significand.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/significandf.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/sin.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/sincos.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/sincosf.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/sincosl.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/sinf.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/sinh.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/sinhf.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/sinhl.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/sinl.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/sqrt.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/sqrtf.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/sqrtl.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/tan.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/tanf.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/tanh.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/tanhf.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/tanhl.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/tanl.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/tgamma.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/tgammaf.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/tgammal.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/trunc.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/truncf.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/truncl.c create mode 100644 lib/mlibc/options/ansi/musl-generic-math/weak_alias.h create mode 100644 lib/mlibc/options/bsd/generic/arpa-nameser-stubs.cpp create mode 100644 lib/mlibc/options/bsd/generic/ether.cpp create mode 100644 lib/mlibc/options/bsd/generic/getopt.cpp create mode 100644 lib/mlibc/options/bsd/include/arpa/nameser.h create mode 100644 lib/mlibc/options/bsd/include/arpa/nameser_compat.h create mode 100644 lib/mlibc/options/bsd/include/bits/bsd/bsd_unistd.h create mode 100644 lib/mlibc/options/bsd/include/fstab.h create mode 100644 lib/mlibc/options/bsd/include/mlibc/bsd-sysdeps.hpp create mode 100644 lib/mlibc/options/bsd/include/netinet/ether.h create mode 100644 lib/mlibc/options/bsd/include/sys/queue.h create mode 100644 lib/mlibc/options/bsd/meson.build create mode 100644 lib/mlibc/options/crypt/generic/crypt-stubs.cpp create mode 100644 lib/mlibc/options/crypt/include/crypt.h create mode 100644 lib/mlibc/options/crypt/meson.build create mode 100644 lib/mlibc/options/elf/generic/phdr.cpp create mode 100644 lib/mlibc/options/elf/generic/startup.cpp create mode 100644 lib/mlibc/options/elf/include/elf.h create mode 100644 lib/mlibc/options/elf/include/link.h create mode 100644 lib/mlibc/options/elf/include/mlibc/elf/startup.h create mode 100644 lib/mlibc/options/elf/meson.build create mode 100644 lib/mlibc/options/glibc/generic/err.cpp create mode 100644 lib/mlibc/options/glibc/generic/error.cpp create mode 100644 lib/mlibc/options/glibc/generic/execinfo.cpp create mode 100644 lib/mlibc/options/glibc/generic/getopt-stubs.cpp create mode 100644 lib/mlibc/options/glibc/generic/glibc-assert.cpp create mode 100644 lib/mlibc/options/glibc/generic/glibc-signal.cpp create mode 100644 lib/mlibc/options/glibc/generic/gshadow.cpp create mode 100644 lib/mlibc/options/glibc/generic/malloc.cpp create mode 100644 lib/mlibc/options/glibc/generic/personality.cpp create mode 100644 lib/mlibc/options/glibc/generic/printf.cpp create mode 100644 lib/mlibc/options/glibc/generic/resolv-stubs.cpp create mode 100644 lib/mlibc/options/glibc/generic/shadow-stubs.cpp create mode 100644 lib/mlibc/options/glibc/generic/stdio_ext-stubs.cpp create mode 100644 lib/mlibc/options/glibc/generic/string.cpp create mode 100644 lib/mlibc/options/glibc/generic/sys-io.cpp create mode 100644 lib/mlibc/options/glibc/generic/sys-ioctl.cpp create mode 100644 lib/mlibc/options/glibc/generic/sys-timex.cpp create mode 100644 lib/mlibc/options/glibc/include/ar.h create mode 100644 lib/mlibc/options/glibc/include/bits/glibc/glibc_assert.h create mode 100644 lib/mlibc/options/glibc/include/bits/glibc/glibc_icmp6.h create mode 100644 lib/mlibc/options/glibc/include/bits/glibc/glibc_malloc.h create mode 100644 lib/mlibc/options/glibc/include/bits/glibc/glibc_signal.h create mode 100644 lib/mlibc/options/glibc/include/endian.h create mode 100644 lib/mlibc/options/glibc/include/err.h create mode 100644 lib/mlibc/options/glibc/include/error.h create mode 100644 lib/mlibc/options/glibc/include/execinfo.h create mode 100644 lib/mlibc/options/glibc/include/features.h create mode 100644 lib/mlibc/options/glibc/include/getopt.h create mode 100644 lib/mlibc/options/glibc/include/gshadow.h create mode 100644 lib/mlibc/options/glibc/include/memory.h create mode 100644 lib/mlibc/options/glibc/include/mlibc/glibc-sysdeps.hpp create mode 100644 lib/mlibc/options/glibc/include/net/ethernet.h create mode 100644 lib/mlibc/options/glibc/include/net/if_ppp.h create mode 100644 lib/mlibc/options/glibc/include/net/route.h create mode 100644 lib/mlibc/options/glibc/include/netax25/ax25.h create mode 100644 lib/mlibc/options/glibc/include/netinet/in_systm.h create mode 100644 lib/mlibc/options/glibc/include/netipx/ipx.h create mode 100644 lib/mlibc/options/glibc/include/netrom/netrom.h create mode 100644 lib/mlibc/options/glibc/include/paths.h create mode 100644 lib/mlibc/options/glibc/include/printf.h create mode 100644 lib/mlibc/options/glibc/include/resolv.h create mode 100644 lib/mlibc/options/glibc/include/shadow.h create mode 100644 lib/mlibc/options/glibc/include/stdio_ext.h create mode 100644 lib/mlibc/options/glibc/include/sys/dir.h create mode 100644 lib/mlibc/options/glibc/include/sys/endian.h create mode 100644 lib/mlibc/options/glibc/include/sys/errno.h create mode 100644 lib/mlibc/options/glibc/include/sys/io.h create mode 100644 lib/mlibc/options/glibc/include/sys/ioctl.h create mode 100644 lib/mlibc/options/glibc/include/sys/kd.h create mode 100644 lib/mlibc/options/glibc/include/sys/mtio.h create mode 100644 lib/mlibc/options/glibc/include/sys/personality.h create mode 100644 lib/mlibc/options/glibc/include/sys/procfs.h create mode 100644 lib/mlibc/options/glibc/include/sys/reg.h create mode 100644 lib/mlibc/options/glibc/include/sys/signal.h create mode 100644 lib/mlibc/options/glibc/include/sys/timeb.h create mode 100644 lib/mlibc/options/glibc/include/sys/timex.h create mode 100644 lib/mlibc/options/glibc/include/sys/ucontext.h create mode 100644 lib/mlibc/options/glibc/include/sys/user.h create mode 100644 lib/mlibc/options/glibc/include/sysexits.h create mode 100644 lib/mlibc/options/glibc/meson.build create mode 100644 lib/mlibc/options/iconv/generic/iconv-stubs.cpp create mode 100644 lib/mlibc/options/iconv/include/iconv.h create mode 100644 lib/mlibc/options/iconv/meson.build create mode 100644 lib/mlibc/options/internal/aarch64-include/mlibc/arch-defs.hpp create mode 100644 lib/mlibc/options/internal/aarch64-include/mlibc/thread.hpp create mode 100644 lib/mlibc/options/internal/aarch64/fenv.S create mode 100644 lib/mlibc/options/internal/aarch64/mlibc_crtbegin.S create mode 100644 lib/mlibc/options/internal/aarch64/mlibc_crtend.S create mode 100644 lib/mlibc/options/internal/aarch64/setjmp.S create mode 100644 lib/mlibc/options/internal/gcc-extra/cxxabi.cpp create mode 100644 lib/mlibc/options/internal/gcc/guard-abi.cpp create mode 100644 lib/mlibc/options/internal/gcc/initfini.cpp create mode 100644 lib/mlibc/options/internal/gcc/stack_protector.cpp create mode 100644 lib/mlibc/options/internal/generic/allocator.cpp create mode 100644 lib/mlibc/options/internal/generic/charcode.cpp create mode 100644 lib/mlibc/options/internal/generic/charset.cpp create mode 100644 lib/mlibc/options/internal/generic/debug.cpp create mode 100644 lib/mlibc/options/internal/generic/ensure.cpp create mode 100644 lib/mlibc/options/internal/generic/essential.cpp create mode 100644 lib/mlibc/options/internal/generic/frigg.cpp create mode 100644 lib/mlibc/options/internal/generic/global-config.cpp create mode 100644 lib/mlibc/options/internal/generic/inline-emitter.cpp create mode 100644 lib/mlibc/options/internal/generic/locale.cpp create mode 100644 lib/mlibc/options/internal/generic/sigset.cpp create mode 100644 lib/mlibc/options/internal/generic/strings.cpp create mode 100644 lib/mlibc/options/internal/generic/threads.cpp create mode 100644 lib/mlibc/options/internal/generic/ubsan.cpp create mode 100644 lib/mlibc/options/internal/include/bits/cpu_set.h create mode 100644 lib/mlibc/options/internal/include/bits/ensure.h create mode 100644 lib/mlibc/options/internal/include/bits/ether_addr.h create mode 100644 lib/mlibc/options/internal/include/bits/inline-definition.h create mode 100644 lib/mlibc/options/internal/include/bits/machine.h create mode 100644 lib/mlibc/options/internal/include/bits/mbstate.h create mode 100644 lib/mlibc/options/internal/include/bits/nl_item.h create mode 100644 lib/mlibc/options/internal/include/bits/null.h create mode 100644 lib/mlibc/options/internal/include/bits/off_t.h create mode 100644 lib/mlibc/options/internal/include/bits/sigset_t.h create mode 100644 lib/mlibc/options/internal/include/bits/size_t.h create mode 100644 lib/mlibc/options/internal/include/bits/ssize_t.h create mode 100644 lib/mlibc/options/internal/include/bits/threads.h create mode 100644 lib/mlibc/options/internal/include/bits/types.h create mode 100644 lib/mlibc/options/internal/include/bits/wchar.h create mode 100644 lib/mlibc/options/internal/include/bits/wchar_t.h create mode 100644 lib/mlibc/options/internal/include/bits/winsize.h create mode 100644 lib/mlibc/options/internal/include/bits/wint_t.h create mode 100644 lib/mlibc/options/internal/include/mlibc/all-sysdeps.hpp create mode 100644 lib/mlibc/options/internal/include/mlibc/allocator.hpp create mode 100644 lib/mlibc/options/internal/include/mlibc/bitutil.hpp create mode 100644 lib/mlibc/options/internal/include/mlibc/charcode.hpp create mode 100644 lib/mlibc/options/internal/include/mlibc/charset.hpp create mode 100644 lib/mlibc/options/internal/include/mlibc/debug.hpp create mode 100644 lib/mlibc/options/internal/include/mlibc/file-window.hpp create mode 100644 lib/mlibc/options/internal/include/mlibc/fsfd_target.hpp create mode 100644 lib/mlibc/options/internal/include/mlibc/global-config.hpp create mode 100644 lib/mlibc/options/internal/include/mlibc/internal-sysdeps.hpp create mode 100644 lib/mlibc/options/internal/include/mlibc/locale.hpp create mode 100644 lib/mlibc/options/internal/include/mlibc/lock.hpp create mode 100644 lib/mlibc/options/internal/include/mlibc/stack_protector.hpp create mode 100644 lib/mlibc/options/internal/include/mlibc/strings.hpp create mode 100644 lib/mlibc/options/internal/include/mlibc/strtofp.hpp create mode 100644 lib/mlibc/options/internal/include/mlibc/strtol.hpp create mode 100644 lib/mlibc/options/internal/include/mlibc/tcb.hpp create mode 100644 lib/mlibc/options/internal/include/mlibc/threads.hpp create mode 100644 lib/mlibc/options/internal/include/mlibc/tid.hpp create mode 100644 lib/mlibc/options/internal/include/stdint.h create mode 100644 lib/mlibc/options/internal/riscv64-include/mlibc/arch-defs.hpp create mode 100644 lib/mlibc/options/internal/riscv64-include/mlibc/thread.hpp create mode 100644 lib/mlibc/options/internal/riscv64/fenv.S create mode 100644 lib/mlibc/options/internal/riscv64/mlibc_crtbegin.S create mode 100644 lib/mlibc/options/internal/riscv64/mlibc_crtend.S create mode 100644 lib/mlibc/options/internal/riscv64/setjmp.S create mode 100755 lib/mlibc/options/internal/x86-include/mlibc/arch-defs.hpp create mode 100755 lib/mlibc/options/internal/x86-include/mlibc/thread.hpp create mode 100644 lib/mlibc/options/internal/x86/fenv.S create mode 100644 lib/mlibc/options/internal/x86/mlibc_crtbegin.S create mode 100644 lib/mlibc/options/internal/x86/mlibc_crtend.S create mode 100644 lib/mlibc/options/internal/x86/setjmp.S create mode 100644 lib/mlibc/options/internal/x86_64-include/mlibc/arch-defs.hpp create mode 100644 lib/mlibc/options/internal/x86_64-include/mlibc/thread.hpp create mode 100644 lib/mlibc/options/internal/x86_64/fenv.S create mode 100644 lib/mlibc/options/internal/x86_64/mlibc_crtbegin.S create mode 100644 lib/mlibc/options/internal/x86_64/mlibc_crtend.S create mode 100644 lib/mlibc/options/internal/x86_64/setjmp.S create mode 100644 lib/mlibc/options/intl/generic/libintl-stubs.cpp create mode 100644 lib/mlibc/options/intl/include/libintl.h create mode 100644 lib/mlibc/options/intl/meson.build create mode 100644 lib/mlibc/options/linux/generic/capabilities.cpp create mode 100644 lib/mlibc/options/linux/generic/cpuset.cpp create mode 100644 lib/mlibc/options/linux/generic/ifaddrs.cpp create mode 100644 lib/mlibc/options/linux/generic/linux-unistd.cpp create mode 100644 lib/mlibc/options/linux/generic/malloc.cpp create mode 100644 lib/mlibc/options/linux/generic/mntent-stubs.cpp create mode 100644 lib/mlibc/options/linux/generic/module.cpp create mode 100644 lib/mlibc/options/linux/generic/pty-stubs.cpp create mode 100644 lib/mlibc/options/linux/generic/sched.cpp create mode 100644 lib/mlibc/options/linux/generic/sys-epoll.cpp create mode 100644 lib/mlibc/options/linux/generic/sys-eventfd.cpp create mode 100644 lib/mlibc/options/linux/generic/sys-fsuid.cpp create mode 100644 lib/mlibc/options/linux/generic/sys-inotify-stubs.cpp create mode 100644 lib/mlibc/options/linux/generic/sys-klog.cpp create mode 100644 lib/mlibc/options/linux/generic/sys-mount.cpp create mode 100644 lib/mlibc/options/linux/generic/sys-prctl-stubs.cpp create mode 100644 lib/mlibc/options/linux/generic/sys-ptrace-stubs.cpp create mode 100644 lib/mlibc/options/linux/generic/sys-quota.cpp create mode 100644 lib/mlibc/options/linux/generic/sys-random-stubs.cpp create mode 100644 lib/mlibc/options/linux/generic/sys-reboot.cpp create mode 100644 lib/mlibc/options/linux/generic/sys-sendfile-stubs.cpp create mode 100644 lib/mlibc/options/linux/generic/sys-signalfd.cpp create mode 100644 lib/mlibc/options/linux/generic/sys-statfs-stubs.cpp create mode 100644 lib/mlibc/options/linux/generic/sys-swap.cpp create mode 100644 lib/mlibc/options/linux/generic/sys-sysinfo.cpp create mode 100644 lib/mlibc/options/linux/generic/sys-timerfd.cpp create mode 100644 lib/mlibc/options/linux/generic/sys-xattr.cpp create mode 100644 lib/mlibc/options/linux/generic/utmp-stubs.cpp create mode 100644 lib/mlibc/options/linux/generic/utmpx.cpp create mode 100644 lib/mlibc/options/linux/include/bits/linux/cpu_set.h create mode 100644 lib/mlibc/options/linux/include/bits/linux/linux_sched.h create mode 100644 lib/mlibc/options/linux/include/bits/linux/linux_unistd.h create mode 100644 lib/mlibc/options/linux/include/ifaddrs.h create mode 100644 lib/mlibc/options/linux/include/lastlog.h create mode 100644 lib/mlibc/options/linux/include/linux/libc-compat.h create mode 100644 lib/mlibc/options/linux/include/malloc.h create mode 100644 lib/mlibc/options/linux/include/memory.h create mode 100644 lib/mlibc/options/linux/include/mlibc/linux-sysdeps.hpp create mode 100644 lib/mlibc/options/linux/include/mntent.h create mode 100644 lib/mlibc/options/linux/include/module.h create mode 100644 lib/mlibc/options/linux/include/netpacket/packet.h create mode 100644 lib/mlibc/options/linux/include/pty.h create mode 100644 lib/mlibc/options/linux/include/scsi/scsi.h create mode 100644 lib/mlibc/options/linux/include/scsi/scsi_ioctl.h create mode 100644 lib/mlibc/options/linux/include/scsi/sg.h create mode 100644 lib/mlibc/options/linux/include/sys/epoll.h create mode 100644 lib/mlibc/options/linux/include/sys/eventfd.h create mode 100644 lib/mlibc/options/linux/include/sys/fsuid.h create mode 100644 lib/mlibc/options/linux/include/sys/inotify.h create mode 100644 lib/mlibc/options/linux/include/sys/klog.h create mode 100644 lib/mlibc/options/linux/include/sys/mount.h create mode 100644 lib/mlibc/options/linux/include/sys/prctl.h create mode 100644 lib/mlibc/options/linux/include/sys/ptrace.h create mode 100644 lib/mlibc/options/linux/include/sys/quota.h create mode 100644 lib/mlibc/options/linux/include/sys/random.h create mode 100644 lib/mlibc/options/linux/include/sys/reboot.h create mode 100644 lib/mlibc/options/linux/include/sys/sendfile.h create mode 100644 lib/mlibc/options/linux/include/sys/signalfd.h create mode 100644 lib/mlibc/options/linux/include/sys/statfs.h create mode 100644 lib/mlibc/options/linux/include/sys/swap.h create mode 100644 lib/mlibc/options/linux/include/sys/sysinfo.h create mode 100644 lib/mlibc/options/linux/include/sys/sysmacros.h create mode 100644 lib/mlibc/options/linux/include/sys/timerfd.h create mode 100644 lib/mlibc/options/linux/include/sys/vfs.h create mode 100644 lib/mlibc/options/linux/include/sys/vt.h create mode 100644 lib/mlibc/options/linux/include/sys/xattr.h create mode 100644 lib/mlibc/options/linux/include/utmp.h create mode 100644 lib/mlibc/options/linux/include/utmpx.h create mode 100644 lib/mlibc/options/linux/include/values.h create mode 100644 lib/mlibc/options/linux/meson.build create mode 100644 lib/mlibc/options/lsb/generic/auxv.cpp create mode 100644 lib/mlibc/options/lsb/generic/dso_exit.cpp create mode 100644 lib/mlibc/options/lsb/generic/tls.cpp create mode 100644 lib/mlibc/options/lsb/include/sys/auxv.h create mode 100644 lib/mlibc/options/lsb/meson.build create mode 100644 lib/mlibc/options/posix/generic/arpa-inet-stubs.cpp create mode 100644 lib/mlibc/options/posix/generic/dirent-stubs.cpp create mode 100644 lib/mlibc/options/posix/generic/dlfcn-stubs.cpp create mode 100644 lib/mlibc/options/posix/generic/fcntl-stubs.cpp create mode 100644 lib/mlibc/options/posix/generic/ftw-stubs.cpp create mode 100644 lib/mlibc/options/posix/generic/grp-stubs.cpp create mode 100644 lib/mlibc/options/posix/generic/langinfo-stubs.cpp create mode 100644 lib/mlibc/options/posix/generic/libgen-stubs.cpp create mode 100644 lib/mlibc/options/posix/generic/lookup.cpp create mode 100644 lib/mlibc/options/posix/generic/mqueue.cpp create mode 100644 lib/mlibc/options/posix/generic/net-if-stubs.cpp create mode 100644 lib/mlibc/options/posix/generic/netdb-stubs.cpp create mode 100644 lib/mlibc/options/posix/generic/poll.cpp create mode 100644 lib/mlibc/options/posix/generic/posix-file-io.cpp create mode 100644 lib/mlibc/options/posix/generic/posix_ctype.cpp create mode 100644 lib/mlibc/options/posix/generic/posix_locale.cpp create mode 100644 lib/mlibc/options/posix/generic/posix_signal.cpp create mode 100644 lib/mlibc/options/posix/generic/posix_stdio.cpp create mode 100644 lib/mlibc/options/posix/generic/posix_stdlib.cpp create mode 100644 lib/mlibc/options/posix/generic/posix_string.cpp create mode 100644 lib/mlibc/options/posix/generic/posix_time.cpp create mode 100644 lib/mlibc/options/posix/generic/pthread-stubs.cpp create mode 100644 lib/mlibc/options/posix/generic/pwd-stubs.cpp create mode 100644 lib/mlibc/options/posix/generic/resolv_conf.cpp create mode 100644 lib/mlibc/options/posix/generic/sched-stubs.cpp create mode 100644 lib/mlibc/options/posix/generic/search.cpp create mode 100644 lib/mlibc/options/posix/generic/semaphore-stubs.cpp create mode 100644 lib/mlibc/options/posix/generic/services.cpp create mode 100644 lib/mlibc/options/posix/generic/spawn-stubs.cpp create mode 100644 lib/mlibc/options/posix/generic/strings-stubs.cpp create mode 100644 lib/mlibc/options/posix/generic/sys-file-stubs.cpp create mode 100644 lib/mlibc/options/posix/generic/sys-ipc.cpp create mode 100644 lib/mlibc/options/posix/generic/sys-mman-stubs.cpp create mode 100644 lib/mlibc/options/posix/generic/sys-msg.cpp create mode 100644 lib/mlibc/options/posix/generic/sys-resource-stubs.cpp create mode 100644 lib/mlibc/options/posix/generic/sys-select-stubs.cpp create mode 100644 lib/mlibc/options/posix/generic/sys-sem.cpp create mode 100644 lib/mlibc/options/posix/generic/sys-shm.cpp create mode 100644 lib/mlibc/options/posix/generic/sys-socket-stubs.cpp create mode 100644 lib/mlibc/options/posix/generic/sys-stat-stubs.cpp create mode 100644 lib/mlibc/options/posix/generic/sys-statvfs-stubs.cpp create mode 100644 lib/mlibc/options/posix/generic/sys-time-stubs.cpp create mode 100644 lib/mlibc/options/posix/generic/sys-times.cpp create mode 100644 lib/mlibc/options/posix/generic/sys-uio.cpp create mode 100644 lib/mlibc/options/posix/generic/sys-utsname.cpp create mode 100644 lib/mlibc/options/posix/generic/sys-wait-stubs.cpp create mode 100644 lib/mlibc/options/posix/generic/syslog-stubs.cpp create mode 100644 lib/mlibc/options/posix/generic/termios-stubs.cpp create mode 100644 lib/mlibc/options/posix/generic/time.cpp create mode 100644 lib/mlibc/options/posix/generic/ucontext-stubs.cpp create mode 100644 lib/mlibc/options/posix/generic/unistd-stubs.cpp create mode 100644 lib/mlibc/options/posix/generic/utime-stubs.cpp create mode 100644 lib/mlibc/options/posix/generic/wordexp-stubs.cpp create mode 100644 lib/mlibc/options/posix/include/arpa/inet.h create mode 100644 lib/mlibc/options/posix/include/bits/posix/fd_set.h create mode 100644 lib/mlibc/options/posix/include/bits/posix/id_t.h create mode 100644 lib/mlibc/options/posix/include/bits/posix/in_addr_t.h create mode 100644 lib/mlibc/options/posix/include/bits/posix/in_port_t.h create mode 100644 lib/mlibc/options/posix/include/bits/posix/iovec.h create mode 100644 lib/mlibc/options/posix/include/bits/posix/locale_t.h create mode 100644 lib/mlibc/options/posix/include/bits/posix/posix_ctype.h create mode 100644 lib/mlibc/options/posix/include/bits/posix/posix_locale.h create mode 100644 lib/mlibc/options/posix/include/bits/posix/posix_signal.h create mode 100644 lib/mlibc/options/posix/include/bits/posix/posix_stdio.h create mode 100644 lib/mlibc/options/posix/include/bits/posix/posix_stdlib.h create mode 100644 lib/mlibc/options/posix/include/bits/posix/posix_string.h create mode 100644 lib/mlibc/options/posix/include/bits/posix/posix_time.h create mode 100644 lib/mlibc/options/posix/include/bits/posix/posix_wctype.h create mode 100644 lib/mlibc/options/posix/include/bits/posix/pthread_t.h create mode 100644 lib/mlibc/options/posix/include/bits/posix/stat.h create mode 100644 lib/mlibc/options/posix/include/bits/posix/timer_t.h create mode 100644 lib/mlibc/options/posix/include/bits/posix/timeval.h create mode 100644 lib/mlibc/options/posix/include/byteswap.h create mode 100644 lib/mlibc/options/posix/include/dirent.h create mode 100644 lib/mlibc/options/posix/include/dlfcn.h create mode 100644 lib/mlibc/options/posix/include/fcntl.h create mode 100644 lib/mlibc/options/posix/include/fnmatch.h create mode 100644 lib/mlibc/options/posix/include/ftw.h create mode 100644 lib/mlibc/options/posix/include/glob.h create mode 100644 lib/mlibc/options/posix/include/grp.h create mode 100644 lib/mlibc/options/posix/include/langinfo.h create mode 100644 lib/mlibc/options/posix/include/libgen.h create mode 100644 lib/mlibc/options/posix/include/mlibc/lookup.hpp create mode 100644 lib/mlibc/options/posix/include/mlibc/posix-file-io.hpp create mode 100644 lib/mlibc/options/posix/include/mlibc/posix-sysdeps.hpp create mode 100644 lib/mlibc/options/posix/include/mlibc/resolv_conf.hpp create mode 100644 lib/mlibc/options/posix/include/mlibc/services.hpp create mode 100644 lib/mlibc/options/posix/include/mqueue.h create mode 100644 lib/mlibc/options/posix/include/net/if.h create mode 100644 lib/mlibc/options/posix/include/net/if_arp.h create mode 100644 lib/mlibc/options/posix/include/netdb.h create mode 100644 lib/mlibc/options/posix/include/netinet/icmp6.h create mode 100644 lib/mlibc/options/posix/include/netinet/if_ether.h create mode 100644 lib/mlibc/options/posix/include/netinet/in.h create mode 100644 lib/mlibc/options/posix/include/netinet/ip.h create mode 100644 lib/mlibc/options/posix/include/netinet/ip6.h create mode 100644 lib/mlibc/options/posix/include/netinet/ip_icmp.h create mode 100644 lib/mlibc/options/posix/include/netinet/tcp.h create mode 100644 lib/mlibc/options/posix/include/netinet/udp.h create mode 100644 lib/mlibc/options/posix/include/nl_types.h create mode 100644 lib/mlibc/options/posix/include/poll.h create mode 100644 lib/mlibc/options/posix/include/pthread.h create mode 100644 lib/mlibc/options/posix/include/pwd.h create mode 100644 lib/mlibc/options/posix/include/regex.h create mode 100644 lib/mlibc/options/posix/include/sched.h create mode 100644 lib/mlibc/options/posix/include/search.h create mode 100644 lib/mlibc/options/posix/include/semaphore.h create mode 100644 lib/mlibc/options/posix/include/spawn.h create mode 100644 lib/mlibc/options/posix/include/strings.h create mode 100644 lib/mlibc/options/posix/include/sys/file.h create mode 100644 lib/mlibc/options/posix/include/sys/ipc.h create mode 100644 lib/mlibc/options/posix/include/sys/mman.h create mode 100644 lib/mlibc/options/posix/include/sys/msg.h create mode 100644 lib/mlibc/options/posix/include/sys/param.h create mode 100644 lib/mlibc/options/posix/include/sys/poll.h create mode 100644 lib/mlibc/options/posix/include/sys/resource.h create mode 100644 lib/mlibc/options/posix/include/sys/select.h create mode 100644 lib/mlibc/options/posix/include/sys/sem.h create mode 100644 lib/mlibc/options/posix/include/sys/shm.h create mode 100644 lib/mlibc/options/posix/include/sys/socket.h create mode 100644 lib/mlibc/options/posix/include/sys/stat.h create mode 100644 lib/mlibc/options/posix/include/sys/statvfs.h create mode 100644 lib/mlibc/options/posix/include/sys/syslog.h create mode 100644 lib/mlibc/options/posix/include/sys/termios.h create mode 100644 lib/mlibc/options/posix/include/sys/time.h create mode 100644 lib/mlibc/options/posix/include/sys/times.h create mode 100644 lib/mlibc/options/posix/include/sys/ttydefaults.h create mode 100644 lib/mlibc/options/posix/include/sys/types.h create mode 100644 lib/mlibc/options/posix/include/sys/uio.h create mode 100644 lib/mlibc/options/posix/include/sys/un.h create mode 100644 lib/mlibc/options/posix/include/sys/utsname.h create mode 100644 lib/mlibc/options/posix/include/sys/wait.h create mode 100644 lib/mlibc/options/posix/include/syslog.h create mode 100644 lib/mlibc/options/posix/include/termios.h create mode 100644 lib/mlibc/options/posix/include/ucontext.h create mode 100644 lib/mlibc/options/posix/include/unistd.h create mode 100644 lib/mlibc/options/posix/include/utime.h create mode 100644 lib/mlibc/options/posix/include/wordexp.h create mode 100644 lib/mlibc/options/posix/meson.build create mode 100644 lib/mlibc/options/posix/musl-generic-regex/fnmatch.c create mode 100644 lib/mlibc/options/posix/musl-generic-regex/glob.c create mode 100644 lib/mlibc/options/posix/musl-generic-regex/regcomp.c create mode 100644 lib/mlibc/options/posix/musl-generic-regex/regerror.c create mode 100644 lib/mlibc/options/posix/musl-generic-regex/regexec.c create mode 100644 lib/mlibc/options/posix/musl-generic-regex/tre-mem.c create mode 100644 lib/mlibc/options/posix/musl-generic-regex/tre.h create mode 100644 lib/mlibc/options/rtdl/aarch64/elf.hpp create mode 100644 lib/mlibc/options/rtdl/aarch64/entry.S create mode 100644 lib/mlibc/options/rtdl/aarch64/runtime.S create mode 100644 lib/mlibc/options/rtdl/generic/linker.cpp create mode 100644 lib/mlibc/options/rtdl/generic/linker.hpp create mode 100644 lib/mlibc/options/rtdl/generic/main.cpp create mode 100644 lib/mlibc/options/rtdl/include/mlibc/rtdl-abi.hpp create mode 100644 lib/mlibc/options/rtdl/include/mlibc/rtdl-config.hpp create mode 100644 lib/mlibc/options/rtdl/include/mlibc/rtdl-sysdeps.hpp create mode 100644 lib/mlibc/options/rtdl/riscv64/elf.hpp create mode 100644 lib/mlibc/options/rtdl/riscv64/entry.S create mode 100644 lib/mlibc/options/rtdl/riscv64/runtime.S create mode 100644 lib/mlibc/options/rtdl/x86/elf.hpp create mode 100644 lib/mlibc/options/rtdl/x86/entry.S create mode 100755 lib/mlibc/options/rtdl/x86/runtime.S create mode 100644 lib/mlibc/options/rtdl/x86_64/elf.hpp create mode 100644 lib/mlibc/options/rtdl/x86_64/entry.S create mode 100644 lib/mlibc/options/rtdl/x86_64/runtime.S create mode 100755 lib/mlibc/scripts/abi-link.sh create mode 100644 lib/mlibc/scripts/check-options-header-include.sh create mode 100644 lib/mlibc/scripts/hdoc.toml.in create mode 100644 lib/mlibc/sysdeps/aero/crt-x86_64/crt0.S create mode 100644 lib/mlibc/sysdeps/aero/generic/aero.cpp create mode 100644 lib/mlibc/sysdeps/aero/generic/entry.cpp create mode 100644 lib/mlibc/sysdeps/aero/generic/filesystem.cpp create mode 100644 lib/mlibc/sysdeps/aero/generic/signals.S create mode 100644 lib/mlibc/sysdeps/aero/generic/signals.cpp create mode 100644 lib/mlibc/sysdeps/aero/generic/sockets.cpp create mode 100644 lib/mlibc/sysdeps/aero/generic/thread.cpp create mode 100644 lib/mlibc/sysdeps/aero/generic/thread_entry.S create mode 100644 lib/mlibc/sysdeps/aero/generic/time.cpp create mode 120000 lib/mlibc/sysdeps/aero/include/abi-bits/access.h create mode 120000 lib/mlibc/sysdeps/aero/include/abi-bits/auxv.h create mode 120000 lib/mlibc/sysdeps/aero/include/abi-bits/blkcnt_t.h create mode 120000 lib/mlibc/sysdeps/aero/include/abi-bits/blksize_t.h create mode 120000 lib/mlibc/sysdeps/aero/include/abi-bits/clockid_t.h create mode 120000 lib/mlibc/sysdeps/aero/include/abi-bits/dev_t.h create mode 120000 lib/mlibc/sysdeps/aero/include/abi-bits/epoll.h create mode 120000 lib/mlibc/sysdeps/aero/include/abi-bits/errno.h create mode 120000 lib/mlibc/sysdeps/aero/include/abi-bits/fcntl.h create mode 120000 lib/mlibc/sysdeps/aero/include/abi-bits/fsblkcnt_t.h create mode 120000 lib/mlibc/sysdeps/aero/include/abi-bits/fsfilcnt_t.h create mode 120000 lib/mlibc/sysdeps/aero/include/abi-bits/gid_t.h create mode 120000 lib/mlibc/sysdeps/aero/include/abi-bits/in.h create mode 120000 lib/mlibc/sysdeps/aero/include/abi-bits/ino_t.h create mode 120000 lib/mlibc/sysdeps/aero/include/abi-bits/inotify.h create mode 120000 lib/mlibc/sysdeps/aero/include/abi-bits/ioctls.h create mode 120000 lib/mlibc/sysdeps/aero/include/abi-bits/limits.h create mode 120000 lib/mlibc/sysdeps/aero/include/abi-bits/mode_t.h create mode 120000 lib/mlibc/sysdeps/aero/include/abi-bits/mqueue.h create mode 120000 lib/mlibc/sysdeps/aero/include/abi-bits/msg.h create mode 120000 lib/mlibc/sysdeps/aero/include/abi-bits/nlink_t.h create mode 120000 lib/mlibc/sysdeps/aero/include/abi-bits/packet.h create mode 120000 lib/mlibc/sysdeps/aero/include/abi-bits/pid_t.h create mode 120000 lib/mlibc/sysdeps/aero/include/abi-bits/poll.h create mode 120000 lib/mlibc/sysdeps/aero/include/abi-bits/ptrace.h create mode 120000 lib/mlibc/sysdeps/aero/include/abi-bits/reboot.h create mode 120000 lib/mlibc/sysdeps/aero/include/abi-bits/resource.h create mode 120000 lib/mlibc/sysdeps/aero/include/abi-bits/seek-whence.h create mode 120000 lib/mlibc/sysdeps/aero/include/abi-bits/shm.h create mode 120000 lib/mlibc/sysdeps/aero/include/abi-bits/signal.h create mode 120000 lib/mlibc/sysdeps/aero/include/abi-bits/socket.h create mode 120000 lib/mlibc/sysdeps/aero/include/abi-bits/socklen_t.h create mode 120000 lib/mlibc/sysdeps/aero/include/abi-bits/stat.h create mode 120000 lib/mlibc/sysdeps/aero/include/abi-bits/statfs.h create mode 120000 lib/mlibc/sysdeps/aero/include/abi-bits/statvfs.h create mode 120000 lib/mlibc/sysdeps/aero/include/abi-bits/suseconds_t.h create mode 120000 lib/mlibc/sysdeps/aero/include/abi-bits/termios.h create mode 120000 lib/mlibc/sysdeps/aero/include/abi-bits/time.h create mode 120000 lib/mlibc/sysdeps/aero/include/abi-bits/uid_t.h create mode 120000 lib/mlibc/sysdeps/aero/include/abi-bits/utsname.h create mode 120000 lib/mlibc/sysdeps/aero/include/abi-bits/vm-flags.h create mode 120000 lib/mlibc/sysdeps/aero/include/abi-bits/wait.h create mode 120000 lib/mlibc/sysdeps/aero/include/abi-bits/xattr.h create mode 100644 lib/mlibc/sysdeps/aero/include/aero/syscall.h create mode 100644 lib/mlibc/sysdeps/aero/include/mlibc/thread-entry.hpp create mode 100644 lib/mlibc/sysdeps/aero/meson.build create mode 100644 lib/mlibc/sysdeps/dripos/crt-x86_64/crt1.S create mode 100644 lib/mlibc/sysdeps/dripos/generic/entry.cpp create mode 100644 lib/mlibc/sysdeps/dripos/generic/generic.cpp create mode 100644 lib/mlibc/sysdeps/dripos/generic/thread.cpp create mode 100644 lib/mlibc/sysdeps/dripos/generic/thread_entry.S create mode 120000 lib/mlibc/sysdeps/dripos/include/abi-bits/access.h create mode 120000 lib/mlibc/sysdeps/dripos/include/abi-bits/auxv.h create mode 120000 lib/mlibc/sysdeps/dripos/include/abi-bits/blkcnt_t.h create mode 120000 lib/mlibc/sysdeps/dripos/include/abi-bits/blksize_t.h create mode 120000 lib/mlibc/sysdeps/dripos/include/abi-bits/clockid_t.h create mode 120000 lib/mlibc/sysdeps/dripos/include/abi-bits/dev_t.h create mode 120000 lib/mlibc/sysdeps/dripos/include/abi-bits/epoll.h create mode 120000 lib/mlibc/sysdeps/dripos/include/abi-bits/errno.h create mode 120000 lib/mlibc/sysdeps/dripos/include/abi-bits/fcntl.h create mode 120000 lib/mlibc/sysdeps/dripos/include/abi-bits/fsblkcnt_t.h create mode 120000 lib/mlibc/sysdeps/dripos/include/abi-bits/fsfilcnt_t.h create mode 120000 lib/mlibc/sysdeps/dripos/include/abi-bits/gid_t.h create mode 120000 lib/mlibc/sysdeps/dripos/include/abi-bits/in.h create mode 120000 lib/mlibc/sysdeps/dripos/include/abi-bits/ino_t.h create mode 120000 lib/mlibc/sysdeps/dripos/include/abi-bits/inotify.h create mode 120000 lib/mlibc/sysdeps/dripos/include/abi-bits/ioctls.h create mode 120000 lib/mlibc/sysdeps/dripos/include/abi-bits/limits.h create mode 120000 lib/mlibc/sysdeps/dripos/include/abi-bits/mode_t.h create mode 120000 lib/mlibc/sysdeps/dripos/include/abi-bits/mqueue.h create mode 120000 lib/mlibc/sysdeps/dripos/include/abi-bits/msg.h create mode 120000 lib/mlibc/sysdeps/dripos/include/abi-bits/nlink_t.h create mode 120000 lib/mlibc/sysdeps/dripos/include/abi-bits/packet.h create mode 120000 lib/mlibc/sysdeps/dripos/include/abi-bits/pid_t.h create mode 120000 lib/mlibc/sysdeps/dripos/include/abi-bits/poll.h create mode 120000 lib/mlibc/sysdeps/dripos/include/abi-bits/ptrace.h create mode 120000 lib/mlibc/sysdeps/dripos/include/abi-bits/resource.h create mode 120000 lib/mlibc/sysdeps/dripos/include/abi-bits/seek-whence.h create mode 120000 lib/mlibc/sysdeps/dripos/include/abi-bits/shm.h create mode 120000 lib/mlibc/sysdeps/dripos/include/abi-bits/signal.h create mode 120000 lib/mlibc/sysdeps/dripos/include/abi-bits/socket.h create mode 120000 lib/mlibc/sysdeps/dripos/include/abi-bits/socklen_t.h create mode 120000 lib/mlibc/sysdeps/dripos/include/abi-bits/stat.h create mode 120000 lib/mlibc/sysdeps/dripos/include/abi-bits/statfs.h create mode 120000 lib/mlibc/sysdeps/dripos/include/abi-bits/statvfs.h create mode 120000 lib/mlibc/sysdeps/dripos/include/abi-bits/suseconds_t.h create mode 120000 lib/mlibc/sysdeps/dripos/include/abi-bits/termios.h create mode 120000 lib/mlibc/sysdeps/dripos/include/abi-bits/time.h create mode 120000 lib/mlibc/sysdeps/dripos/include/abi-bits/uid_t.h create mode 120000 lib/mlibc/sysdeps/dripos/include/abi-bits/utsname.h create mode 120000 lib/mlibc/sysdeps/dripos/include/abi-bits/vm-flags.h create mode 120000 lib/mlibc/sysdeps/dripos/include/abi-bits/wait.h create mode 120000 lib/mlibc/sysdeps/dripos/include/abi-bits/xattr.h create mode 100644 lib/mlibc/sysdeps/dripos/include/mlibc/thread-entry.hpp create mode 100644 lib/mlibc/sysdeps/dripos/meson.build create mode 100644 lib/mlibc/sysdeps/hyra/crt-x86_64/crt0.S create mode 100644 lib/mlibc/sysdeps/hyra/generic/entry.cpp create mode 100644 lib/mlibc/sysdeps/hyra/generic/hyra.cpp create mode 120000 lib/mlibc/sysdeps/hyra/include/abi-bits/access.h create mode 120000 lib/mlibc/sysdeps/hyra/include/abi-bits/auxv.h create mode 120000 lib/mlibc/sysdeps/hyra/include/abi-bits/blkcnt_t.h create mode 120000 lib/mlibc/sysdeps/hyra/include/abi-bits/blksize_t.h create mode 120000 lib/mlibc/sysdeps/hyra/include/abi-bits/clockid_t.h create mode 120000 lib/mlibc/sysdeps/hyra/include/abi-bits/dev_t.h create mode 120000 lib/mlibc/sysdeps/hyra/include/abi-bits/epoll.h create mode 120000 lib/mlibc/sysdeps/hyra/include/abi-bits/errno.h create mode 120000 lib/mlibc/sysdeps/hyra/include/abi-bits/fcntl.h create mode 120000 lib/mlibc/sysdeps/hyra/include/abi-bits/fsblkcnt_t.h create mode 120000 lib/mlibc/sysdeps/hyra/include/abi-bits/fsfilcnt_t.h create mode 120000 lib/mlibc/sysdeps/hyra/include/abi-bits/gid_t.h create mode 120000 lib/mlibc/sysdeps/hyra/include/abi-bits/in.h create mode 120000 lib/mlibc/sysdeps/hyra/include/abi-bits/ino_t.h create mode 120000 lib/mlibc/sysdeps/hyra/include/abi-bits/inotify.h create mode 120000 lib/mlibc/sysdeps/hyra/include/abi-bits/ioctls.h create mode 120000 lib/mlibc/sysdeps/hyra/include/abi-bits/limits.h create mode 120000 lib/mlibc/sysdeps/hyra/include/abi-bits/mode_t.h create mode 120000 lib/mlibc/sysdeps/hyra/include/abi-bits/mqueue.h create mode 120000 lib/mlibc/sysdeps/hyra/include/abi-bits/msg.h create mode 120000 lib/mlibc/sysdeps/hyra/include/abi-bits/nlink_t.h create mode 120000 lib/mlibc/sysdeps/hyra/include/abi-bits/packet.h create mode 120000 lib/mlibc/sysdeps/hyra/include/abi-bits/pid_t.h create mode 120000 lib/mlibc/sysdeps/hyra/include/abi-bits/poll.h create mode 120000 lib/mlibc/sysdeps/hyra/include/abi-bits/ptrace.h create mode 120000 lib/mlibc/sysdeps/hyra/include/abi-bits/reboot.h create mode 120000 lib/mlibc/sysdeps/hyra/include/abi-bits/resource.h create mode 120000 lib/mlibc/sysdeps/hyra/include/abi-bits/seek-whence.h create mode 120000 lib/mlibc/sysdeps/hyra/include/abi-bits/shm.h create mode 120000 lib/mlibc/sysdeps/hyra/include/abi-bits/signal.h create mode 120000 lib/mlibc/sysdeps/hyra/include/abi-bits/socket.h create mode 120000 lib/mlibc/sysdeps/hyra/include/abi-bits/socklen_t.h create mode 120000 lib/mlibc/sysdeps/hyra/include/abi-bits/stat.h create mode 120000 lib/mlibc/sysdeps/hyra/include/abi-bits/statfs.h create mode 120000 lib/mlibc/sysdeps/hyra/include/abi-bits/statvfs.h create mode 120000 lib/mlibc/sysdeps/hyra/include/abi-bits/suseconds_t.h create mode 120000 lib/mlibc/sysdeps/hyra/include/abi-bits/termios.h create mode 120000 lib/mlibc/sysdeps/hyra/include/abi-bits/time.h create mode 120000 lib/mlibc/sysdeps/hyra/include/abi-bits/uid_t.h create mode 120000 lib/mlibc/sysdeps/hyra/include/abi-bits/utsname.h create mode 120000 lib/mlibc/sysdeps/hyra/include/abi-bits/vm-flags.h create mode 120000 lib/mlibc/sysdeps/hyra/include/abi-bits/vt.h create mode 120000 lib/mlibc/sysdeps/hyra/include/abi-bits/wait.h create mode 120000 lib/mlibc/sysdeps/hyra/include/abi-bits/xattr.h create mode 100644 lib/mlibc/sysdeps/hyra/include/hyra/syscall.h create mode 100644 lib/mlibc/sysdeps/hyra/meson.build create mode 100644 lib/mlibc/sysdeps/ironclad/crt-x86_64/crt0.S create mode 100644 lib/mlibc/sysdeps/ironclad/crt-x86_64/crti.S create mode 100644 lib/mlibc/sysdeps/ironclad/crt-x86_64/crtn.S create mode 100644 lib/mlibc/sysdeps/ironclad/generic/entry.cpp create mode 100644 lib/mlibc/sysdeps/ironclad/generic/generic.cpp create mode 100644 lib/mlibc/sysdeps/ironclad/generic/mac.cpp create mode 100644 lib/mlibc/sysdeps/ironclad/generic/mntent.cpp create mode 100644 lib/mlibc/sysdeps/ironclad/generic/mount.cpp create mode 100644 lib/mlibc/sysdeps/ironclad/generic/ptrace.cpp create mode 100644 lib/mlibc/sysdeps/ironclad/generic/pty.cpp create mode 100644 lib/mlibc/sysdeps/ironclad/generic/reboot.cpp create mode 100644 lib/mlibc/sysdeps/ironclad/generic/sched2.cpp create mode 100644 lib/mlibc/sysdeps/ironclad/generic/thread.S create mode 100644 lib/mlibc/sysdeps/ironclad/generic/thread.cpp create mode 100644 lib/mlibc/sysdeps/ironclad/generic/utmpx.cpp create mode 120000 lib/mlibc/sysdeps/ironclad/include/abi-bits/access.h create mode 120000 lib/mlibc/sysdeps/ironclad/include/abi-bits/auxv.h create mode 120000 lib/mlibc/sysdeps/ironclad/include/abi-bits/blkcnt_t.h create mode 120000 lib/mlibc/sysdeps/ironclad/include/abi-bits/blksize_t.h create mode 120000 lib/mlibc/sysdeps/ironclad/include/abi-bits/clockid_t.h create mode 120000 lib/mlibc/sysdeps/ironclad/include/abi-bits/dev_t.h create mode 120000 lib/mlibc/sysdeps/ironclad/include/abi-bits/epoll.h create mode 120000 lib/mlibc/sysdeps/ironclad/include/abi-bits/errno.h create mode 120000 lib/mlibc/sysdeps/ironclad/include/abi-bits/fcntl.h create mode 120000 lib/mlibc/sysdeps/ironclad/include/abi-bits/fsblkcnt_t.h create mode 120000 lib/mlibc/sysdeps/ironclad/include/abi-bits/fsfilcnt_t.h create mode 120000 lib/mlibc/sysdeps/ironclad/include/abi-bits/gid_t.h create mode 120000 lib/mlibc/sysdeps/ironclad/include/abi-bits/in.h create mode 120000 lib/mlibc/sysdeps/ironclad/include/abi-bits/ino_t.h create mode 120000 lib/mlibc/sysdeps/ironclad/include/abi-bits/inotify.h create mode 120000 lib/mlibc/sysdeps/ironclad/include/abi-bits/ioctls.h create mode 120000 lib/mlibc/sysdeps/ironclad/include/abi-bits/limits.h create mode 120000 lib/mlibc/sysdeps/ironclad/include/abi-bits/mode_t.h create mode 120000 lib/mlibc/sysdeps/ironclad/include/abi-bits/mqueue.h create mode 120000 lib/mlibc/sysdeps/ironclad/include/abi-bits/msg.h create mode 120000 lib/mlibc/sysdeps/ironclad/include/abi-bits/nlink_t.h create mode 120000 lib/mlibc/sysdeps/ironclad/include/abi-bits/packet.h create mode 120000 lib/mlibc/sysdeps/ironclad/include/abi-bits/pid_t.h create mode 120000 lib/mlibc/sysdeps/ironclad/include/abi-bits/poll.h create mode 120000 lib/mlibc/sysdeps/ironclad/include/abi-bits/ptrace.h create mode 120000 lib/mlibc/sysdeps/ironclad/include/abi-bits/reboot.h create mode 120000 lib/mlibc/sysdeps/ironclad/include/abi-bits/resource.h create mode 120000 lib/mlibc/sysdeps/ironclad/include/abi-bits/seek-whence.h create mode 120000 lib/mlibc/sysdeps/ironclad/include/abi-bits/shm.h create mode 120000 lib/mlibc/sysdeps/ironclad/include/abi-bits/signal.h create mode 120000 lib/mlibc/sysdeps/ironclad/include/abi-bits/socket.h create mode 120000 lib/mlibc/sysdeps/ironclad/include/abi-bits/socklen_t.h create mode 120000 lib/mlibc/sysdeps/ironclad/include/abi-bits/stat.h create mode 120000 lib/mlibc/sysdeps/ironclad/include/abi-bits/statfs.h create mode 120000 lib/mlibc/sysdeps/ironclad/include/abi-bits/statvfs.h create mode 120000 lib/mlibc/sysdeps/ironclad/include/abi-bits/suseconds_t.h create mode 120000 lib/mlibc/sysdeps/ironclad/include/abi-bits/termios.h create mode 120000 lib/mlibc/sysdeps/ironclad/include/abi-bits/time.h create mode 120000 lib/mlibc/sysdeps/ironclad/include/abi-bits/uid_t.h create mode 120000 lib/mlibc/sysdeps/ironclad/include/abi-bits/utsname.h create mode 120000 lib/mlibc/sysdeps/ironclad/include/abi-bits/vm-flags.h create mode 120000 lib/mlibc/sysdeps/ironclad/include/abi-bits/wait.h create mode 120000 lib/mlibc/sysdeps/ironclad/include/abi-bits/xattr.h create mode 100644 lib/mlibc/sysdeps/ironclad/include/asm/ioctls.h create mode 100644 lib/mlibc/sysdeps/ironclad/include/linux/fb.h create mode 100644 lib/mlibc/sysdeps/ironclad/include/mntent.h create mode 100644 lib/mlibc/sysdeps/ironclad/include/pty.h create mode 100644 lib/mlibc/sysdeps/ironclad/include/sys/ironclad_devices.h create mode 100644 lib/mlibc/sysdeps/ironclad/include/sys/mac.h create mode 100644 lib/mlibc/sysdeps/ironclad/include/sys/mount.h create mode 100644 lib/mlibc/sysdeps/ironclad/include/sys/ptrace.h create mode 100644 lib/mlibc/sysdeps/ironclad/include/sys/reboot.h create mode 100644 lib/mlibc/sysdeps/ironclad/include/sys/sched2.h create mode 100644 lib/mlibc/sysdeps/ironclad/include/sys/syscall.h create mode 100644 lib/mlibc/sysdeps/ironclad/include/utmpx.h create mode 100644 lib/mlibc/sysdeps/ironclad/meson.build create mode 100644 lib/mlibc/sysdeps/keyronex/generic/entry.cpp create mode 100644 lib/mlibc/sysdeps/keyronex/generic/generic.cpp create mode 100644 lib/mlibc/sysdeps/keyronex/generic/linux.cpp create mode 100644 lib/mlibc/sysdeps/keyronex/generic/signal.cpp create mode 100644 lib/mlibc/sysdeps/keyronex/generic/socket.cpp create mode 100644 lib/mlibc/sysdeps/keyronex/generic/thread.S create mode 100644 lib/mlibc/sysdeps/keyronex/generic/thread.cpp create mode 120000 lib/mlibc/sysdeps/keyronex/include/abi-bits/access.h create mode 120000 lib/mlibc/sysdeps/keyronex/include/abi-bits/auxv.h create mode 120000 lib/mlibc/sysdeps/keyronex/include/abi-bits/blkcnt_t.h create mode 120000 lib/mlibc/sysdeps/keyronex/include/abi-bits/blksize_t.h create mode 120000 lib/mlibc/sysdeps/keyronex/include/abi-bits/clockid_t.h create mode 120000 lib/mlibc/sysdeps/keyronex/include/abi-bits/dev_t.h create mode 120000 lib/mlibc/sysdeps/keyronex/include/abi-bits/epoll.h create mode 120000 lib/mlibc/sysdeps/keyronex/include/abi-bits/errno.h create mode 120000 lib/mlibc/sysdeps/keyronex/include/abi-bits/fcntl.h create mode 120000 lib/mlibc/sysdeps/keyronex/include/abi-bits/fsblkcnt_t.h create mode 120000 lib/mlibc/sysdeps/keyronex/include/abi-bits/fsfilcnt_t.h create mode 120000 lib/mlibc/sysdeps/keyronex/include/abi-bits/gid_t.h create mode 120000 lib/mlibc/sysdeps/keyronex/include/abi-bits/in.h create mode 120000 lib/mlibc/sysdeps/keyronex/include/abi-bits/ino_t.h create mode 120000 lib/mlibc/sysdeps/keyronex/include/abi-bits/inotify.h create mode 120000 lib/mlibc/sysdeps/keyronex/include/abi-bits/ioctls.h create mode 120000 lib/mlibc/sysdeps/keyronex/include/abi-bits/limits.h create mode 120000 lib/mlibc/sysdeps/keyronex/include/abi-bits/mode_t.h create mode 120000 lib/mlibc/sysdeps/keyronex/include/abi-bits/mqueue.h create mode 120000 lib/mlibc/sysdeps/keyronex/include/abi-bits/msg.h create mode 120000 lib/mlibc/sysdeps/keyronex/include/abi-bits/nlink_t.h create mode 120000 lib/mlibc/sysdeps/keyronex/include/abi-bits/packet.h create mode 120000 lib/mlibc/sysdeps/keyronex/include/abi-bits/pid_t.h create mode 120000 lib/mlibc/sysdeps/keyronex/include/abi-bits/poll.h create mode 120000 lib/mlibc/sysdeps/keyronex/include/abi-bits/ptrace.h create mode 120000 lib/mlibc/sysdeps/keyronex/include/abi-bits/reboot.h create mode 120000 lib/mlibc/sysdeps/keyronex/include/abi-bits/resource.h create mode 120000 lib/mlibc/sysdeps/keyronex/include/abi-bits/seek-whence.h create mode 120000 lib/mlibc/sysdeps/keyronex/include/abi-bits/shm.h create mode 120000 lib/mlibc/sysdeps/keyronex/include/abi-bits/signal.h create mode 120000 lib/mlibc/sysdeps/keyronex/include/abi-bits/socket.h create mode 120000 lib/mlibc/sysdeps/keyronex/include/abi-bits/socklen_t.h create mode 120000 lib/mlibc/sysdeps/keyronex/include/abi-bits/stat.h create mode 120000 lib/mlibc/sysdeps/keyronex/include/abi-bits/statfs.h create mode 120000 lib/mlibc/sysdeps/keyronex/include/abi-bits/statvfs.h create mode 120000 lib/mlibc/sysdeps/keyronex/include/abi-bits/suseconds_t.h create mode 120000 lib/mlibc/sysdeps/keyronex/include/abi-bits/termios.h create mode 120000 lib/mlibc/sysdeps/keyronex/include/abi-bits/time.h create mode 120000 lib/mlibc/sysdeps/keyronex/include/abi-bits/uid_t.h create mode 120000 lib/mlibc/sysdeps/keyronex/include/abi-bits/utsname.h create mode 120000 lib/mlibc/sysdeps/keyronex/include/abi-bits/vm-flags.h create mode 120000 lib/mlibc/sysdeps/keyronex/include/abi-bits/wait.h create mode 120000 lib/mlibc/sysdeps/keyronex/include/abi-bits/xattr.h create mode 100644 lib/mlibc/sysdeps/keyronex/include/keyronex/syscall.h create mode 100644 lib/mlibc/sysdeps/keyronex/meson.build create mode 100644 lib/mlibc/sysdeps/keyronex/x86_64/crt-src/crt0.S create mode 100644 lib/mlibc/sysdeps/keyronex/x86_64/crt-src/crti.S create mode 100644 lib/mlibc/sysdeps/keyronex/x86_64/crt-src/crtn.S create mode 100755 lib/mlibc/sysdeps/lemon/crt-x86_64/crt0.S create mode 100644 lib/mlibc/sysdeps/lemon/generic/entry.cpp create mode 100755 lib/mlibc/sysdeps/lemon/generic/filesystem.cpp create mode 100644 lib/mlibc/sysdeps/lemon/generic/lemon.cpp create mode 100644 lib/mlibc/sysdeps/lemon/generic/pty.cpp create mode 100644 lib/mlibc/sysdeps/lemon/generic/signals.cpp create mode 100755 lib/mlibc/sysdeps/lemon/generic/sockets.cpp create mode 100644 lib/mlibc/sysdeps/lemon/generic/thread.cpp create mode 100644 lib/mlibc/sysdeps/lemon/generic/thread_entry.S create mode 120000 lib/mlibc/sysdeps/lemon/include/abi-bits/access.h create mode 120000 lib/mlibc/sysdeps/lemon/include/abi-bits/auxv.h create mode 120000 lib/mlibc/sysdeps/lemon/include/abi-bits/blkcnt_t.h create mode 120000 lib/mlibc/sysdeps/lemon/include/abi-bits/blksize_t.h create mode 120000 lib/mlibc/sysdeps/lemon/include/abi-bits/clockid_t.h create mode 120000 lib/mlibc/sysdeps/lemon/include/abi-bits/dev_t.h create mode 120000 lib/mlibc/sysdeps/lemon/include/abi-bits/epoll.h create mode 120000 lib/mlibc/sysdeps/lemon/include/abi-bits/errno.h create mode 120000 lib/mlibc/sysdeps/lemon/include/abi-bits/fcntl.h create mode 120000 lib/mlibc/sysdeps/lemon/include/abi-bits/fsblkcnt_t.h create mode 120000 lib/mlibc/sysdeps/lemon/include/abi-bits/fsfilcnt_t.h create mode 120000 lib/mlibc/sysdeps/lemon/include/abi-bits/gid_t.h create mode 120000 lib/mlibc/sysdeps/lemon/include/abi-bits/in.h create mode 120000 lib/mlibc/sysdeps/lemon/include/abi-bits/ino_t.h create mode 120000 lib/mlibc/sysdeps/lemon/include/abi-bits/inotify.h create mode 120000 lib/mlibc/sysdeps/lemon/include/abi-bits/ioctls.h create mode 120000 lib/mlibc/sysdeps/lemon/include/abi-bits/limits.h create mode 120000 lib/mlibc/sysdeps/lemon/include/abi-bits/mode_t.h create mode 120000 lib/mlibc/sysdeps/lemon/include/abi-bits/mqueue.h create mode 120000 lib/mlibc/sysdeps/lemon/include/abi-bits/msg.h create mode 120000 lib/mlibc/sysdeps/lemon/include/abi-bits/nlink_t.h create mode 120000 lib/mlibc/sysdeps/lemon/include/abi-bits/packet.h create mode 120000 lib/mlibc/sysdeps/lemon/include/abi-bits/pid_t.h create mode 120000 lib/mlibc/sysdeps/lemon/include/abi-bits/poll.h create mode 120000 lib/mlibc/sysdeps/lemon/include/abi-bits/ptrace.h create mode 120000 lib/mlibc/sysdeps/lemon/include/abi-bits/reboot.h create mode 120000 lib/mlibc/sysdeps/lemon/include/abi-bits/resource.h create mode 120000 lib/mlibc/sysdeps/lemon/include/abi-bits/seek-whence.h create mode 120000 lib/mlibc/sysdeps/lemon/include/abi-bits/shm.h create mode 120000 lib/mlibc/sysdeps/lemon/include/abi-bits/signal.h create mode 120000 lib/mlibc/sysdeps/lemon/include/abi-bits/socket.h create mode 120000 lib/mlibc/sysdeps/lemon/include/abi-bits/socklen_t.h create mode 120000 lib/mlibc/sysdeps/lemon/include/abi-bits/stat.h create mode 120000 lib/mlibc/sysdeps/lemon/include/abi-bits/statfs.h create mode 120000 lib/mlibc/sysdeps/lemon/include/abi-bits/statvfs.h create mode 120000 lib/mlibc/sysdeps/lemon/include/abi-bits/suseconds_t.h create mode 120000 lib/mlibc/sysdeps/lemon/include/abi-bits/termios.h create mode 120000 lib/mlibc/sysdeps/lemon/include/abi-bits/time.h create mode 120000 lib/mlibc/sysdeps/lemon/include/abi-bits/uid_t.h create mode 120000 lib/mlibc/sysdeps/lemon/include/abi-bits/utsname.h create mode 120000 lib/mlibc/sysdeps/lemon/include/abi-bits/vm-flags.h create mode 120000 lib/mlibc/sysdeps/lemon/include/abi-bits/wait.h create mode 120000 lib/mlibc/sysdeps/lemon/include/abi-bits/xattr.h create mode 100755 lib/mlibc/sysdeps/lemon/include/lemon/syscall.h create mode 100644 lib/mlibc/sysdeps/lemon/include/mlibc/thread-entry.hpp create mode 100644 lib/mlibc/sysdeps/lemon/meson.build create mode 100644 lib/mlibc/sysdeps/linux/aarch64/arch-syscall.cpp create mode 100644 lib/mlibc/sysdeps/linux/aarch64/cp_syscall.S create mode 100644 lib/mlibc/sysdeps/linux/aarch64/crt-src/Scrt1.S create mode 100644 lib/mlibc/sysdeps/linux/aarch64/crt-src/crt1.S create mode 100644 lib/mlibc/sysdeps/linux/aarch64/crt-src/crti.S create mode 100644 lib/mlibc/sysdeps/linux/aarch64/crt-src/crtn.S create mode 100644 lib/mlibc/sysdeps/linux/aarch64/signals.S create mode 100644 lib/mlibc/sysdeps/linux/aarch64/syscallnos.h create mode 100644 lib/mlibc/sysdeps/linux/aarch64/thread_entry.S create mode 100644 lib/mlibc/sysdeps/linux/generic/cxx-syscall.hpp create mode 100644 lib/mlibc/sysdeps/linux/generic/entry.cpp create mode 100644 lib/mlibc/sysdeps/linux/generic/sysdeps.cpp create mode 100644 lib/mlibc/sysdeps/linux/generic/thread.cpp create mode 100644 lib/mlibc/sysdeps/linux/include-internal/linux/unistd.h create mode 120000 lib/mlibc/sysdeps/linux/include/abi-bits/access.h create mode 120000 lib/mlibc/sysdeps/linux/include/abi-bits/auxv.h create mode 120000 lib/mlibc/sysdeps/linux/include/abi-bits/blkcnt_t.h create mode 120000 lib/mlibc/sysdeps/linux/include/abi-bits/blksize_t.h create mode 120000 lib/mlibc/sysdeps/linux/include/abi-bits/clockid_t.h create mode 120000 lib/mlibc/sysdeps/linux/include/abi-bits/dev_t.h create mode 120000 lib/mlibc/sysdeps/linux/include/abi-bits/epoll.h create mode 120000 lib/mlibc/sysdeps/linux/include/abi-bits/errno.h create mode 120000 lib/mlibc/sysdeps/linux/include/abi-bits/fcntl.h create mode 120000 lib/mlibc/sysdeps/linux/include/abi-bits/fsblkcnt_t.h create mode 120000 lib/mlibc/sysdeps/linux/include/abi-bits/fsfilcnt_t.h create mode 120000 lib/mlibc/sysdeps/linux/include/abi-bits/gid_t.h create mode 120000 lib/mlibc/sysdeps/linux/include/abi-bits/in.h create mode 120000 lib/mlibc/sysdeps/linux/include/abi-bits/ino_t.h create mode 120000 lib/mlibc/sysdeps/linux/include/abi-bits/inotify.h create mode 120000 lib/mlibc/sysdeps/linux/include/abi-bits/ioctls.h create mode 120000 lib/mlibc/sysdeps/linux/include/abi-bits/limits.h create mode 120000 lib/mlibc/sysdeps/linux/include/abi-bits/mode_t.h create mode 120000 lib/mlibc/sysdeps/linux/include/abi-bits/mqueue.h create mode 120000 lib/mlibc/sysdeps/linux/include/abi-bits/msg.h create mode 120000 lib/mlibc/sysdeps/linux/include/abi-bits/nlink_t.h create mode 120000 lib/mlibc/sysdeps/linux/include/abi-bits/packet.h create mode 120000 lib/mlibc/sysdeps/linux/include/abi-bits/pid_t.h create mode 120000 lib/mlibc/sysdeps/linux/include/abi-bits/poll.h create mode 120000 lib/mlibc/sysdeps/linux/include/abi-bits/ptrace.h create mode 120000 lib/mlibc/sysdeps/linux/include/abi-bits/reboot.h create mode 120000 lib/mlibc/sysdeps/linux/include/abi-bits/resource.h create mode 120000 lib/mlibc/sysdeps/linux/include/abi-bits/seek-whence.h create mode 120000 lib/mlibc/sysdeps/linux/include/abi-bits/shm.h create mode 120000 lib/mlibc/sysdeps/linux/include/abi-bits/signal.h create mode 120000 lib/mlibc/sysdeps/linux/include/abi-bits/socket.h create mode 120000 lib/mlibc/sysdeps/linux/include/abi-bits/socklen_t.h create mode 120000 lib/mlibc/sysdeps/linux/include/abi-bits/stat.h create mode 120000 lib/mlibc/sysdeps/linux/include/abi-bits/statfs.h create mode 120000 lib/mlibc/sysdeps/linux/include/abi-bits/statvfs.h create mode 120000 lib/mlibc/sysdeps/linux/include/abi-bits/suseconds_t.h create mode 120000 lib/mlibc/sysdeps/linux/include/abi-bits/termios.h create mode 120000 lib/mlibc/sysdeps/linux/include/abi-bits/time.h create mode 120000 lib/mlibc/sysdeps/linux/include/abi-bits/uid_t.h create mode 120000 lib/mlibc/sysdeps/linux/include/abi-bits/utsname.h create mode 120000 lib/mlibc/sysdeps/linux/include/abi-bits/vm-flags.h create mode 120000 lib/mlibc/sysdeps/linux/include/abi-bits/vt.h create mode 120000 lib/mlibc/sysdeps/linux/include/abi-bits/wait.h create mode 120000 lib/mlibc/sysdeps/linux/include/abi-bits/xattr.h create mode 100644 lib/mlibc/sysdeps/linux/include/bits/syscall.h create mode 100644 lib/mlibc/sysdeps/linux/include/bits/syscall_aliases.h create mode 100644 lib/mlibc/sysdeps/linux/include/mlibc/thread-entry.hpp create mode 100644 lib/mlibc/sysdeps/linux/include/sys/syscall.h create mode 100644 lib/mlibc/sysdeps/linux/include/syscall.h create mode 100644 lib/mlibc/sysdeps/linux/meson.build create mode 100755 lib/mlibc/sysdeps/linux/mlibc-gcc.in create mode 100644 lib/mlibc/sysdeps/linux/mlibc-gcc.specs.in create mode 100644 lib/mlibc/sysdeps/linux/riscv64/arch-syscall.cpp create mode 100644 lib/mlibc/sysdeps/linux/riscv64/cp_syscall.S create mode 100644 lib/mlibc/sysdeps/linux/riscv64/crt-src/Scrt1.S create mode 100644 lib/mlibc/sysdeps/linux/riscv64/crt-src/crt1.S create mode 100644 lib/mlibc/sysdeps/linux/riscv64/crt-src/crti.S create mode 100644 lib/mlibc/sysdeps/linux/riscv64/crt-src/crtn.S create mode 100644 lib/mlibc/sysdeps/linux/riscv64/signals.S create mode 100644 lib/mlibc/sysdeps/linux/riscv64/syscallnos.h create mode 100644 lib/mlibc/sysdeps/linux/riscv64/thread_entry.S create mode 100755 lib/mlibc/sysdeps/linux/update-syscall-list.py create mode 100644 lib/mlibc/sysdeps/linux/x86/arch-syscall.cpp create mode 100644 lib/mlibc/sysdeps/linux/x86/cp_syscall.S create mode 100644 lib/mlibc/sysdeps/linux/x86/crt-src/Scrt1.S create mode 100644 lib/mlibc/sysdeps/linux/x86/crt-src/crt1.S create mode 100644 lib/mlibc/sysdeps/linux/x86/crt-src/crti.S create mode 100644 lib/mlibc/sysdeps/linux/x86/crt-src/crtn.S create mode 100644 lib/mlibc/sysdeps/linux/x86/signals.S create mode 100644 lib/mlibc/sysdeps/linux/x86/syscallnos.h create mode 100644 lib/mlibc/sysdeps/linux/x86/thread_entry.S create mode 100644 lib/mlibc/sysdeps/linux/x86_64/arch-syscall.cpp create mode 100644 lib/mlibc/sysdeps/linux/x86_64/cp_syscall.S create mode 100644 lib/mlibc/sysdeps/linux/x86_64/crt-src/Scrt1.S create mode 100644 lib/mlibc/sysdeps/linux/x86_64/crt-src/crt1.S create mode 100644 lib/mlibc/sysdeps/linux/x86_64/crt-src/crti.S create mode 100644 lib/mlibc/sysdeps/linux/x86_64/crt-src/crtn.S create mode 100644 lib/mlibc/sysdeps/linux/x86_64/signals.S create mode 100644 lib/mlibc/sysdeps/linux/x86_64/syscallnos.h create mode 100644 lib/mlibc/sysdeps/linux/x86_64/thread_entry.S create mode 100644 lib/mlibc/sysdeps/lyre/generic/entry.cpp create mode 100644 lib/mlibc/sysdeps/lyre/generic/generic.cpp create mode 100644 lib/mlibc/sysdeps/lyre/generic/mntent.cpp create mode 100644 lib/mlibc/sysdeps/lyre/generic/mount.cpp create mode 100644 lib/mlibc/sysdeps/lyre/generic/reboot.cpp create mode 100644 lib/mlibc/sysdeps/lyre/generic/thread.S create mode 100644 lib/mlibc/sysdeps/lyre/generic/thread.cpp create mode 120000 lib/mlibc/sysdeps/lyre/include/abi-bits/access.h create mode 120000 lib/mlibc/sysdeps/lyre/include/abi-bits/auxv.h create mode 120000 lib/mlibc/sysdeps/lyre/include/abi-bits/blkcnt_t.h create mode 120000 lib/mlibc/sysdeps/lyre/include/abi-bits/blksize_t.h create mode 120000 lib/mlibc/sysdeps/lyre/include/abi-bits/clockid_t.h create mode 120000 lib/mlibc/sysdeps/lyre/include/abi-bits/dev_t.h create mode 120000 lib/mlibc/sysdeps/lyre/include/abi-bits/epoll.h create mode 120000 lib/mlibc/sysdeps/lyre/include/abi-bits/errno.h create mode 120000 lib/mlibc/sysdeps/lyre/include/abi-bits/fcntl.h create mode 120000 lib/mlibc/sysdeps/lyre/include/abi-bits/fsblkcnt_t.h create mode 120000 lib/mlibc/sysdeps/lyre/include/abi-bits/fsfilcnt_t.h create mode 120000 lib/mlibc/sysdeps/lyre/include/abi-bits/gid_t.h create mode 120000 lib/mlibc/sysdeps/lyre/include/abi-bits/in.h create mode 120000 lib/mlibc/sysdeps/lyre/include/abi-bits/ino_t.h create mode 120000 lib/mlibc/sysdeps/lyre/include/abi-bits/inotify.h create mode 120000 lib/mlibc/sysdeps/lyre/include/abi-bits/ioctls.h create mode 120000 lib/mlibc/sysdeps/lyre/include/abi-bits/limits.h create mode 120000 lib/mlibc/sysdeps/lyre/include/abi-bits/mode_t.h create mode 120000 lib/mlibc/sysdeps/lyre/include/abi-bits/mqueue.h create mode 120000 lib/mlibc/sysdeps/lyre/include/abi-bits/msg.h create mode 120000 lib/mlibc/sysdeps/lyre/include/abi-bits/nlink_t.h create mode 120000 lib/mlibc/sysdeps/lyre/include/abi-bits/packet.h create mode 120000 lib/mlibc/sysdeps/lyre/include/abi-bits/pid_t.h create mode 120000 lib/mlibc/sysdeps/lyre/include/abi-bits/poll.h create mode 120000 lib/mlibc/sysdeps/lyre/include/abi-bits/ptrace.h create mode 120000 lib/mlibc/sysdeps/lyre/include/abi-bits/reboot.h create mode 120000 lib/mlibc/sysdeps/lyre/include/abi-bits/resource.h create mode 120000 lib/mlibc/sysdeps/lyre/include/abi-bits/seek-whence.h create mode 120000 lib/mlibc/sysdeps/lyre/include/abi-bits/shm.h create mode 120000 lib/mlibc/sysdeps/lyre/include/abi-bits/signal.h create mode 120000 lib/mlibc/sysdeps/lyre/include/abi-bits/socket.h create mode 120000 lib/mlibc/sysdeps/lyre/include/abi-bits/socklen_t.h create mode 120000 lib/mlibc/sysdeps/lyre/include/abi-bits/stat.h create mode 120000 lib/mlibc/sysdeps/lyre/include/abi-bits/statfs.h create mode 120000 lib/mlibc/sysdeps/lyre/include/abi-bits/statvfs.h create mode 120000 lib/mlibc/sysdeps/lyre/include/abi-bits/suseconds_t.h create mode 120000 lib/mlibc/sysdeps/lyre/include/abi-bits/termios.h create mode 120000 lib/mlibc/sysdeps/lyre/include/abi-bits/time.h create mode 120000 lib/mlibc/sysdeps/lyre/include/abi-bits/uid_t.h create mode 120000 lib/mlibc/sysdeps/lyre/include/abi-bits/utsname.h create mode 120000 lib/mlibc/sysdeps/lyre/include/abi-bits/vm-flags.h create mode 120000 lib/mlibc/sysdeps/lyre/include/abi-bits/wait.h create mode 120000 lib/mlibc/sysdeps/lyre/include/abi-bits/xattr.h create mode 100644 lib/mlibc/sysdeps/lyre/include/asm/ioctl.h create mode 100644 lib/mlibc/sysdeps/lyre/include/asm/ioctls.h create mode 100644 lib/mlibc/sysdeps/lyre/include/linux/fb.h create mode 100644 lib/mlibc/sysdeps/lyre/include/lyre/sockios.h create mode 100644 lib/mlibc/sysdeps/lyre/include/lyre/syscall.h create mode 100644 lib/mlibc/sysdeps/lyre/include/mntent.h create mode 100644 lib/mlibc/sysdeps/lyre/include/sys/mount.h create mode 100644 lib/mlibc/sysdeps/lyre/include/sys/reboot.h create mode 100644 lib/mlibc/sysdeps/lyre/include/sys/sysmacros.h create mode 100644 lib/mlibc/sysdeps/lyre/meson.build create mode 100644 lib/mlibc/sysdeps/lyre/x86_64/crt-src/crt0.S create mode 100644 lib/mlibc/sysdeps/lyre/x86_64/crt-src/crti.S create mode 100644 lib/mlibc/sysdeps/lyre/x86_64/crt-src/crtn.S create mode 100644 lib/mlibc/sysdeps/managarm/aarch64/crt-src/Scrt1.S create mode 100644 lib/mlibc/sysdeps/managarm/aarch64/crt-src/crt0.S create mode 100644 lib/mlibc/sysdeps/managarm/aarch64/crt-src/crti.S create mode 100644 lib/mlibc/sysdeps/managarm/aarch64/crt-src/crtn.S create mode 100644 lib/mlibc/sysdeps/managarm/aarch64/signals.S create mode 100644 lib/mlibc/sysdeps/managarm/aarch64/thread.cpp create mode 100644 lib/mlibc/sysdeps/managarm/aarch64/thread_entry.S create mode 100644 lib/mlibc/sysdeps/managarm/generic/drm.cpp create mode 100644 lib/mlibc/sysdeps/managarm/generic/ensure.cpp create mode 100644 lib/mlibc/sysdeps/managarm/generic/entry.cpp create mode 100644 lib/mlibc/sysdeps/managarm/generic/file.cpp create mode 100644 lib/mlibc/sysdeps/managarm/generic/fork-exec.cpp create mode 100644 lib/mlibc/sysdeps/managarm/generic/ioctl.cpp create mode 100644 lib/mlibc/sysdeps/managarm/generic/memory.cpp create mode 100644 lib/mlibc/sysdeps/managarm/generic/mount.cpp create mode 100644 lib/mlibc/sysdeps/managarm/generic/net.cpp create mode 100644 lib/mlibc/sysdeps/managarm/generic/sched.cpp create mode 100644 lib/mlibc/sysdeps/managarm/generic/signals.cpp create mode 100644 lib/mlibc/sysdeps/managarm/generic/socket.cpp create mode 100644 lib/mlibc/sysdeps/managarm/generic/time.cpp create mode 120000 lib/mlibc/sysdeps/managarm/include/abi-bits/access.h create mode 120000 lib/mlibc/sysdeps/managarm/include/abi-bits/auxv.h create mode 120000 lib/mlibc/sysdeps/managarm/include/abi-bits/blkcnt_t.h create mode 120000 lib/mlibc/sysdeps/managarm/include/abi-bits/blksize_t.h create mode 120000 lib/mlibc/sysdeps/managarm/include/abi-bits/clockid_t.h create mode 120000 lib/mlibc/sysdeps/managarm/include/abi-bits/dev_t.h create mode 120000 lib/mlibc/sysdeps/managarm/include/abi-bits/epoll.h create mode 120000 lib/mlibc/sysdeps/managarm/include/abi-bits/errno.h create mode 120000 lib/mlibc/sysdeps/managarm/include/abi-bits/fcntl.h create mode 120000 lib/mlibc/sysdeps/managarm/include/abi-bits/fsblkcnt_t.h create mode 120000 lib/mlibc/sysdeps/managarm/include/abi-bits/fsfilcnt_t.h create mode 120000 lib/mlibc/sysdeps/managarm/include/abi-bits/gid_t.h create mode 120000 lib/mlibc/sysdeps/managarm/include/abi-bits/in.h create mode 120000 lib/mlibc/sysdeps/managarm/include/abi-bits/ino_t.h create mode 120000 lib/mlibc/sysdeps/managarm/include/abi-bits/inotify.h create mode 120000 lib/mlibc/sysdeps/managarm/include/abi-bits/ioctls.h create mode 120000 lib/mlibc/sysdeps/managarm/include/abi-bits/limits.h create mode 120000 lib/mlibc/sysdeps/managarm/include/abi-bits/mode_t.h create mode 120000 lib/mlibc/sysdeps/managarm/include/abi-bits/mqueue.h create mode 120000 lib/mlibc/sysdeps/managarm/include/abi-bits/msg.h create mode 120000 lib/mlibc/sysdeps/managarm/include/abi-bits/nlink_t.h create mode 120000 lib/mlibc/sysdeps/managarm/include/abi-bits/packet.h create mode 120000 lib/mlibc/sysdeps/managarm/include/abi-bits/pid_t.h create mode 120000 lib/mlibc/sysdeps/managarm/include/abi-bits/poll.h create mode 120000 lib/mlibc/sysdeps/managarm/include/abi-bits/ptrace.h create mode 120000 lib/mlibc/sysdeps/managarm/include/abi-bits/reboot.h create mode 120000 lib/mlibc/sysdeps/managarm/include/abi-bits/resource.h create mode 120000 lib/mlibc/sysdeps/managarm/include/abi-bits/seek-whence.h create mode 120000 lib/mlibc/sysdeps/managarm/include/abi-bits/shm.h create mode 120000 lib/mlibc/sysdeps/managarm/include/abi-bits/signal.h create mode 120000 lib/mlibc/sysdeps/managarm/include/abi-bits/socket.h create mode 120000 lib/mlibc/sysdeps/managarm/include/abi-bits/socklen_t.h create mode 120000 lib/mlibc/sysdeps/managarm/include/abi-bits/stat.h create mode 120000 lib/mlibc/sysdeps/managarm/include/abi-bits/statfs.h create mode 120000 lib/mlibc/sysdeps/managarm/include/abi-bits/statvfs.h create mode 120000 lib/mlibc/sysdeps/managarm/include/abi-bits/suseconds_t.h create mode 120000 lib/mlibc/sysdeps/managarm/include/abi-bits/termios.h create mode 120000 lib/mlibc/sysdeps/managarm/include/abi-bits/time.h create mode 120000 lib/mlibc/sysdeps/managarm/include/abi-bits/uid_t.h create mode 120000 lib/mlibc/sysdeps/managarm/include/abi-bits/utsname.h create mode 120000 lib/mlibc/sysdeps/managarm/include/abi-bits/vm-flags.h create mode 120000 lib/mlibc/sysdeps/managarm/include/abi-bits/vt.h create mode 120000 lib/mlibc/sysdeps/managarm/include/abi-bits/wait.h create mode 120000 lib/mlibc/sysdeps/managarm/include/abi-bits/xattr.h create mode 100644 lib/mlibc/sysdeps/managarm/include/mlibc/posix-pipe.hpp create mode 100644 lib/mlibc/sysdeps/managarm/include/mlibc/thread-entry.hpp create mode 100644 lib/mlibc/sysdeps/managarm/meson.build create mode 100644 lib/mlibc/sysdeps/managarm/rtdl-generic/support.cpp create mode 100644 lib/mlibc/sysdeps/managarm/x86_64/crt-src/Scrt1.S create mode 100644 lib/mlibc/sysdeps/managarm/x86_64/crt-src/crt0.S create mode 100644 lib/mlibc/sysdeps/managarm/x86_64/crt-src/crti.S create mode 100644 lib/mlibc/sysdeps/managarm/x86_64/crt-src/crtn.S create mode 100644 lib/mlibc/sysdeps/managarm/x86_64/signals.S create mode 100644 lib/mlibc/sysdeps/managarm/x86_64/thread.cpp create mode 100644 lib/mlibc/sysdeps/managarm/x86_64/thread_entry.S create mode 100644 lib/mlibc/test.c create mode 100644 lib/mlibc/tests/ansi/abs.c create mode 100644 lib/mlibc/tests/ansi/alloc.c create mode 100644 lib/mlibc/tests/ansi/calloc.c create mode 100644 lib/mlibc/tests/ansi/creal-cimag.c create mode 100644 lib/mlibc/tests/ansi/fenv.c create mode 100644 lib/mlibc/tests/ansi/fopen.c create mode 100644 lib/mlibc/tests/ansi/freopen.c create mode 100644 lib/mlibc/tests/ansi/locale.c create mode 100644 lib/mlibc/tests/ansi/longjmp.c create mode 100644 lib/mlibc/tests/ansi/mbrtoc32.c create mode 100644 lib/mlibc/tests/ansi/memmem.c create mode 100644 lib/mlibc/tests/ansi/qsort.c create mode 100644 lib/mlibc/tests/ansi/snprintf.c create mode 100644 lib/mlibc/tests/ansi/sprintf.c create mode 100644 lib/mlibc/tests/ansi/sscanf.c create mode 100644 lib/mlibc/tests/ansi/strchr.c create mode 100644 lib/mlibc/tests/ansi/strftime.c create mode 100644 lib/mlibc/tests/ansi/strrchr.c create mode 100644 lib/mlibc/tests/ansi/strtof.c create mode 100644 lib/mlibc/tests/ansi/strtol.c create mode 100644 lib/mlibc/tests/ansi/strverscmp.c create mode 100644 lib/mlibc/tests/ansi/strxfrm.c create mode 100644 lib/mlibc/tests/ansi/timegm.c create mode 100644 lib/mlibc/tests/ansi/ungetc.c create mode 100644 lib/mlibc/tests/ansi/utf8.c create mode 100644 lib/mlibc/tests/ansi/wcsdup.c create mode 100644 lib/mlibc/tests/ansi/wcsncasecmp.c create mode 100644 lib/mlibc/tests/ansi/wcsrtombs.c create mode 100644 lib/mlibc/tests/ansi/wmemcmp.c create mode 100644 lib/mlibc/tests/bsd/ns_get_put.c create mode 100644 lib/mlibc/tests/bsd/reallocarray.c create mode 100644 lib/mlibc/tests/bsd/sbrk.c create mode 100644 lib/mlibc/tests/bsd/strl.c create mode 100644 lib/mlibc/tests/glibc/error.c create mode 100644 lib/mlibc/tests/glibc/error.py create mode 100644 lib/mlibc/tests/glibc/error_at_line.c create mode 100644 lib/mlibc/tests/glibc/error_at_line.py create mode 100644 lib/mlibc/tests/glibc/error_expect_fail.c create mode 100644 lib/mlibc/tests/glibc/error_message_count.c create mode 100644 lib/mlibc/tests/glibc/error_one_per_line.c create mode 100644 lib/mlibc/tests/glibc/error_print_progname.c create mode 100644 lib/mlibc/tests/glibc/ffsl-ffsll.c create mode 100644 lib/mlibc/tests/glibc/getopt.c create mode 100644 lib/mlibc/tests/glibc/gnu-basename.c create mode 100644 lib/mlibc/tests/glibc/linux-syscall.c create mode 100644 lib/mlibc/tests/linux/cpuset.c create mode 100644 lib/mlibc/tests/linux/malloc-usable-size.c create mode 100644 lib/mlibc/tests/linux/pthread_attr.c create mode 100644 lib/mlibc/tests/linux/pthread_setname_np.c create mode 100644 lib/mlibc/tests/linux/xattr.c create mode 100644 lib/mlibc/tests/meson.build create mode 100644 lib/mlibc/tests/posix/abort.c create mode 100644 lib/mlibc/tests/posix/accept4.c create mode 100644 lib/mlibc/tests/posix/access.c create mode 100644 lib/mlibc/tests/posix/alarm.c create mode 100644 lib/mlibc/tests/posix/basename.c create mode 100644 lib/mlibc/tests/posix/dprintf.c create mode 100644 lib/mlibc/tests/posix/fdopen.c create mode 100644 lib/mlibc/tests/posix/ffs.c create mode 100644 lib/mlibc/tests/posix/flockfile.c create mode 100644 lib/mlibc/tests/posix/fmemopen.c create mode 100644 lib/mlibc/tests/posix/fopencookie.c create mode 100644 lib/mlibc/tests/posix/getaddrinfo.c create mode 100644 lib/mlibc/tests/posix/getcwd.c create mode 100644 lib/mlibc/tests/posix/getdelim.c create mode 100644 lib/mlibc/tests/posix/getnameinfo.c create mode 100644 lib/mlibc/tests/posix/getservbyname.c create mode 100644 lib/mlibc/tests/posix/getservbyport.c create mode 100644 lib/mlibc/tests/posix/grp.c create mode 100644 lib/mlibc/tests/posix/if_indextoname.c create mode 100644 lib/mlibc/tests/posix/index.c create mode 100644 lib/mlibc/tests/posix/inet_ntop.c create mode 100644 lib/mlibc/tests/posix/inet_pton.c create mode 100644 lib/mlibc/tests/posix/memrchr.c create mode 100644 lib/mlibc/tests/posix/mkstemp.c create mode 100644 lib/mlibc/tests/posix/open_memstream.c create mode 100644 lib/mlibc/tests/posix/pause.c create mode 100644 lib/mlibc/tests/posix/popen.c create mode 100644 lib/mlibc/tests/posix/posix-timer.c create mode 100644 lib/mlibc/tests/posix/posix_memalign.c create mode 100644 lib/mlibc/tests/posix/posix_spawn.c create mode 100644 lib/mlibc/tests/posix/pthread_atfork.c create mode 100644 lib/mlibc/tests/posix/pthread_attr.c create mode 100644 lib/mlibc/tests/posix/pthread_barrier.c create mode 100644 lib/mlibc/tests/posix/pthread_cancel.c create mode 100644 lib/mlibc/tests/posix/pthread_cleanup.c create mode 100644 lib/mlibc/tests/posix/pthread_cond.c create mode 100644 lib/mlibc/tests/posix/pthread_create.c create mode 100644 lib/mlibc/tests/posix/pthread_key.c create mode 100644 lib/mlibc/tests/posix/pthread_kill.c create mode 100644 lib/mlibc/tests/posix/pthread_mutex.c create mode 100644 lib/mlibc/tests/posix/pthread_rwlock.c create mode 100644 lib/mlibc/tests/posix/pthread_schedparam.c create mode 100644 lib/mlibc/tests/posix/pthread_thread_local.c create mode 100644 lib/mlibc/tests/posix/pwd.c create mode 100644 lib/mlibc/tests/posix/readv-writev.c create mode 100644 lib/mlibc/tests/posix/realpath.c create mode 100644 lib/mlibc/tests/posix/regex.c create mode 100644 lib/mlibc/tests/posix/rindex.c create mode 100644 lib/mlibc/tests/posix/rlimits.c create mode 100644 lib/mlibc/tests/posix/search.c create mode 100644 lib/mlibc/tests/posix/setpriority.c create mode 100644 lib/mlibc/tests/posix/sigaltstack.c create mode 100644 lib/mlibc/tests/posix/sigsuspend.c create mode 100644 lib/mlibc/tests/posix/sigtimedwait.c create mode 100644 lib/mlibc/tests/posix/strdupa.c create mode 100644 lib/mlibc/tests/posix/string.c create mode 100644 lib/mlibc/tests/posix/system.c create mode 100644 lib/mlibc/tests/posix/time.c create mode 100644 lib/mlibc/tests/posix/timer.c create mode 100644 lib/mlibc/tests/posix/vfork.c create mode 100644 lib/mlibc/tests/posix/waitid.c create mode 100644 lib/mlibc/tests/posix/wcwidth.c create mode 100644 lib/mlibc/tests/posix/wordexp.c create mode 100644 lib/mlibc/tests/rtdl/dl_iterate_phdr/libbar.c create mode 100644 lib/mlibc/tests/rtdl/dl_iterate_phdr/libfoo.c create mode 100644 lib/mlibc/tests/rtdl/dl_iterate_phdr/meson.build create mode 100644 lib/mlibc/tests/rtdl/dl_iterate_phdr/test.c create mode 100644 lib/mlibc/tests/rtdl/dladdr_local/libfoo.c create mode 100644 lib/mlibc/tests/rtdl/dladdr_local/meson.build create mode 100644 lib/mlibc/tests/rtdl/dladdr_local/test.c create mode 100644 lib/mlibc/tests/rtdl/ld_library_path/libfoo.c create mode 100644 lib/mlibc/tests/rtdl/ld_library_path/meson.build create mode 100644 lib/mlibc/tests/rtdl/ld_library_path/test.c create mode 100644 lib/mlibc/tests/rtdl/meson.build create mode 100644 lib/mlibc/tests/rtdl/noload-promote/libfoo.c create mode 100644 lib/mlibc/tests/rtdl/noload-promote/meson.build create mode 100644 lib/mlibc/tests/rtdl/noload-promote/test.c create mode 100644 lib/mlibc/tests/rtdl/preinit/libfoo.c create mode 100644 lib/mlibc/tests/rtdl/preinit/meson.build create mode 100644 lib/mlibc/tests/rtdl/preinit/test.c create mode 100644 lib/mlibc/tests/rtdl/rtld_next/libbar.c create mode 100644 lib/mlibc/tests/rtdl/rtld_next/libfoo.c create mode 100644 lib/mlibc/tests/rtdl/rtld_next/meson.build create mode 100644 lib/mlibc/tests/rtdl/rtld_next/test.c create mode 100644 lib/mlibc/tests/rtdl/scope1/libbar.c create mode 100644 lib/mlibc/tests/rtdl/scope1/libfoo.c create mode 100644 lib/mlibc/tests/rtdl/scope1/meson.build create mode 100644 lib/mlibc/tests/rtdl/scope1/test.c create mode 100644 lib/mlibc/tests/rtdl/scope2/libbar.c create mode 100644 lib/mlibc/tests/rtdl/scope2/libbaz.c create mode 100644 lib/mlibc/tests/rtdl/scope2/libfoo.c create mode 100644 lib/mlibc/tests/rtdl/scope2/meson.build create mode 100644 lib/mlibc/tests/rtdl/scope2/test.c create mode 100644 lib/mlibc/tests/rtdl/scope3/libbar.c create mode 100644 lib/mlibc/tests/rtdl/scope3/libbaz.c create mode 100644 lib/mlibc/tests/rtdl/scope3/libfoo.c create mode 100644 lib/mlibc/tests/rtdl/scope3/meson.build create mode 100644 lib/mlibc/tests/rtdl/scope3/test.c create mode 100644 lib/mlibc/tests/rtdl/scope4/libbar.c create mode 100644 lib/mlibc/tests/rtdl/scope4/libbaz.c create mode 100644 lib/mlibc/tests/rtdl/scope4/libfoo.c create mode 100644 lib/mlibc/tests/rtdl/scope4/meson.build create mode 100644 lib/mlibc/tests/rtdl/scope4/test.c create mode 100644 lib/mlibc/tests/rtdl/scope5/libfoo.c create mode 100644 lib/mlibc/tests/rtdl/scope5/meson.build create mode 100644 lib/mlibc/tests/rtdl/scope5/test.c create mode 100644 lib/mlibc/tests/rtdl/soname/libbar.c create mode 100644 lib/mlibc/tests/rtdl/soname/libfoo.c create mode 100644 lib/mlibc/tests/rtdl/soname/meson.build create mode 100644 lib/mlibc/tests/rtdl/soname/test.c create mode 100644 lib/mlibc/tests/rtdl/tls_align/libbar.c create mode 100644 lib/mlibc/tests/rtdl/tls_align/libfoo.c create mode 100644 lib/mlibc/tests/rtdl/tls_align/meson.build create mode 100644 lib/mlibc/tests/rtdl/tls_align/test.c (limited to 'lib') diff --git a/lib/Makefile b/lib/Makefile new file mode 100644 index 0000000..a4946e9 --- /dev/null +++ b/lib/Makefile @@ -0,0 +1,11 @@ +mlibc/build/: + cd mlibc; ln -s ../../cross/bin/ crossbin + cd mlibc; meson setup -Ddisable_crypt_option=true -Ddisable_iconv_option=true \ + -Ddisable_intl_option=true -Ddisable_libgcc_dependency=true \ + -Ddisable_linux_option=true -Ddisable_libgcc_dependency=false \ + -Dmlibc_no_headers=true \ + --cross-file=cross_file.txt build; cd build/; ninja + +.PHONY: clean +clean: + rm -rf mlibc/build; rm -f mlibc/crossbin diff --git a/lib/mlibc/.github/workflows/abidiff.yml b/lib/mlibc/.github/workflows/abidiff.yml new file mode 100644 index 0000000..036a7ec --- /dev/null +++ b/lib/mlibc/.github/workflows/abidiff.yml @@ -0,0 +1,158 @@ +name: Check for ABI breaks + +on: + push: + branches-ignore: + - abi-break + pull_request: + branches-ignore: + - abi-break + +jobs: + run-abidiff: + name: Compare ABIs + runs-on: ubuntu-22.04 + container: + image: ghcr.io/managarm/mlibc-crossers:latest + defaults: + run: + shell: bash + steps: + - name: Install prerequisites + run: | + apt-get update + apt-get install -y ninja-build qemu-user \ + python3-setuptools python3-jsonschema \ + python3-pip abigail-tools + pip install --break-system-packages -U xbstrap pyexpect meson + + - name: Checkout base branch + if: ${{ github.base_ref }} + uses: actions/checkout@v2 + with: + path: mlibc-base + ref: ${{ github.base_ref }} + submodules: true + fetch-depth: 4 + + - name: Checkout managarm/mlibc#master + if: ${{ github.base_ref == '' }} + uses: actions/checkout@v2 + with: + path: mlibc-base + repository: managarm/mlibc + submodules: true + ref: master + fetch-depth: 4 + + - name: Checkout branch + uses: actions/checkout@v2 + with: + path: mlibc-branch + submodules: true + + - name: Determine base ref + run: | + master_hash="$(git -C mlibc-base rev-parse HEAD)" + branch_hash="$(git -C mlibc-branch rev-parse HEAD)" + printf '%s\n' "$master_hash" "$branch_hash" + + if [ "$master_hash" = "$branch_hash" ]; then + git -C mlibc-base reset --hard HEAD^ + fi + + - name: Set up linux kernel headers + run: | + set -x + mkdir -p linux-headers-base/{src,build} + cp mlibc-base/ci/bootstrap.yml linux-headers-base/src/ + ( + cd linux-headers-base/build + xbstrap init ../src + xbstrap install linux-headers + ) + mkdir -p linux-headers-branch/{src,build} + cp mlibc-branch/ci/bootstrap.yml linux-headers-branch/src/ + ( + cd linux-headers-branch/build + xbstrap init ../src + xbstrap install linux-headers + ) + cat > linux-headers-base/build/bootstrap-site.yml << EOF + define_options: + arch: ${{matrix.arch}} + EOF + cp linux-headers-base/build/bootstrap-site.yml linux-headers-branch/build/bootstrap-site.yml + + - name: Build and install both copies + run: | + set -xe + mkdir root-base root-branch + cat > linux-x86_64.cross-file <<-EOF + [binaries] + c = ['x86_64-linux-mlibc-gcc'] + cpp = ['x86_64-linux-mlibc-g++'] + + [host_machine] + system = 'linux' + cpu_family = 'x86_64' + cpu = 'x86_64' + endian = 'little' + EOF + ( + cd mlibc-branch + meson setup \ + --cross-file=../linux-x86_64.cross-file \ + --buildtype=debugoptimized \ + -Dlinux_kernel_headers=$GITHUB_WORKSPACE/linux-headers-branch/build/packages/linux-headers/usr/include \ + build + ninja -C build + DESTDIR="$GITHUB_WORKSPACE/root-branch" ninja -C build install + ) + ( + cd mlibc-base + meson setup \ + --cross-file=../linux-x86_64.cross-file \ + --buildtype=debugoptimized \ + -Dlinux_kernel_headers=$GITHUB_WORKSPACE/linux-headers-branch/build/packages/linux-headers/usr/include \ + build + ninja -C build + DESTDIR="$GITHUB_WORKSPACE/root-base" ninja -C build install + ) + - name: Compare + run: | + # TODO(arsen): does this require handling for version suffixes? + set -e +x + exec 2>&1 # work around GHA foolishly decoupling stdout and stderr + + exitcode=0 + git -C mlibc-branch show -s --format=%s | grep -q abi-break || \ + exitcode=1 + + echo ==== RUNNING ABIDIFF... ==== + ( cd root-base; find . -type f -name '*.so'; ) | while read -r file + do + if ! file -- root-{base,branch}/"$file"; then + touch files-differ + continue + fi + abidiff \ + --no-added-syms \ + --suppr mlibc-branch/ci/abidiff_suppress.ini \ + --hd1 root-base/usr/local/include/ \ + --hd2 root-branch/usr/local/include/ \ + root-{base,branch}/"$file" \ + || touch files-differ + done + + echo ==== CHECKING FOR EXTRA FILES... ==== + ( cd root-branch; find . -type f -name '*.so'; ) | while read -r file + do + [ -e "root-base/$file" ] || file root-{base,branch}/"$file" \ + || touch files-differ + done + + if [ -e files-differ ]; then + echo SOME FILES/ABI DIFFER, SEE OUTPUT ABOVE + exit "$exitcode" + fi diff --git a/lib/mlibc/.github/workflows/ci.yml b/lib/mlibc/.github/workflows/ci.yml new file mode 100644 index 0000000..d8b0360 --- /dev/null +++ b/lib/mlibc/.github/workflows/ci.yml @@ -0,0 +1,123 @@ +name: Continuous Integration + +on: [push, pull_request] + +jobs: + build-mlibc: + strategy: + matrix: + arch: [x86_64, riscv64, aarch64, x86] + builds: [mlibc, mlibc-static, mlibc-shared, mlibc-ansi-only, mlibc-headers-only] + name: Build mlibc + runs-on: ubuntu-22.04 + container: + image: ghcr.io/managarm/mlibc-crossers:latest + steps: + - name: Install prerequisites + run: | + apt-get update + apt-get install -y ninja-build qemu-user \ + python3-setuptools python3-jsonschema \ + python3-pexpect python3-pip netbase + pip install --break-system-packages -U xbstrap pyexpect meson + - name: Prepare directories + run: | + mkdir src/ + mkdir src/mlibc/ + mkdir build/ + - name: Checkout + uses: actions/checkout@v2 + with: + path: src/mlibc/ + - name: Prepare src/ + run: | + cp mlibc/ci/bootstrap.yml . + touch mlibc/checkedout.xbstrap + working-directory: src/ + - name: Prepare build/ + run: | + cat > bootstrap-site.yml << EOF + define_options: + arch: ${{matrix.arch}} + EOF + xbstrap init ../src + working-directory: build/ + - name: Build mlibc + run: 'xbstrap install ${{matrix.builds}}' + working-directory: build/ + - name: Test mlibc + run: 'meson test -v -C pkg-builds/${{matrix.builds}}' + working-directory: build/ + + compile-sysdeps: + strategy: + matrix: + sysdeps: [dripos, lemon, aero, ironclad, lyre, keyronex, managarm] + name: Compile sysdeps + runs-on: ubuntu-22.04 + container: + image: ghcr.io/managarm/mlibc-crossers:latest + steps: + - name: Install prerequisites + run: | + apt-get update + apt-get install -y ninja-build qemu-user \ + python3-setuptools python3-jsonschema \ + python3-pip + pip install --break-system-packages -U xbstrap meson + - if: ${{ matrix.sysdeps == 'managarm' }} + name: Checkout bootstrap-managarm + uses: actions/checkout@v2 + with: + repository: 'managarm/bootstrap-managarm' + path: src/ + - name: Checkout + uses: actions/checkout@v2 + with: + path: src/mlibc/ + - if: ${{ matrix.sysdeps == 'managarm' }} + name: Set up managarm subprojects directory + run: | + mkdir -p src/mlibc/subprojects build + ( + cd build + xbstrap init ../src + xbstrap regenerate libdrm + ) + - if: ${{ matrix.sysdeps == 'managarm' }} + name: Clone managarm/managarm + uses: actions/checkout@v4 + with: + repository: 'managarm/managarm' + path: 'src/mlibc/subprojects/managarm' + - if: ${{ matrix.sysdeps == 'managarm' }} + name: Clone managarm/bragi + uses: actions/checkout@v4 + with: + repository: 'managarm/bragi' + path: 'src/mlibc/subprojects/bragi' + - if: ${{ matrix.sysdeps == 'managarm' }} + name: Install bragi + run: | + pip install --break-system-packages -U bragi + - name: Set up linux kernel headers + run: | + mkdir -p build/mlibc/ + cp src/mlibc/ci/bootstrap.yml src/ + ( + cd build + xbstrap init ../src + xbstrap install linux-headers + ) + - name: Compile sysdeps + run: | + meson setup \ + "-Dc_args=['-fno-stack-protector', '-U__linux__', '-Wno-error=maybe-uninitialized', '-D__${{matrix.sysdeps}}__']" \ + "-Dcpp_args=['-fno-stack-protector', '-U__linux__', '-Wno-error=maybe-uninitialized', '-D__${{matrix.sysdeps}}__']" \ + "-Dbuild_tests=true" \ + "-Db_sanitize=undefined" \ + "-Dlinux_kernel_headers=$(pwd)/packages/linux-headers/usr/include" \ + --cross-file ../src/mlibc/ci/${{matrix.sysdeps}}.cross-file compile-${{matrix.sysdeps}} \ + "../src/mlibc/" + ninja -C compile-${{matrix.sysdeps}} + working-directory: build/ diff --git a/lib/mlibc/.github/workflows/detect-bad-ifs.yml b/lib/mlibc/.github/workflows/detect-bad-ifs.yml new file mode 100644 index 0000000..c738d29 --- /dev/null +++ b/lib/mlibc/.github/workflows/detect-bad-ifs.yml @@ -0,0 +1,17 @@ +name: Detect ifdef/defined (mis)use + +on: [push, pull_request] + +jobs: + find-misuse: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - run: | + printf '(^#ifn?def[[:space:]]+|defined[[:space:]]*[(][[:space:]]*)((%s)([^_A-Za-z0-9]|$))\0' \ + "$(printf '%s' "$(awk '/#mesondefine/ { print $2 }' mlibc-config.h.in)" | tr '\n' '|')" \ + | { ! xargs -0I '{}' grep --color=always -PR '{}' \ + || { echo 'found misuse'; exit 1; }; } + + +# vim: set sw=2 : diff --git a/lib/mlibc/.github/workflows/detect-missing-mlibc-config.yml b/lib/mlibc/.github/workflows/detect-missing-mlibc-config.yml new file mode 100644 index 0000000..f396121 --- /dev/null +++ b/lib/mlibc/.github/workflows/detect-missing-mlibc-config.yml @@ -0,0 +1,10 @@ +name: Detect missing mlibc-config.h + +on: [push, pull_request] + +jobs: + find-misuse: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - run: chmod +x ./scripts/check-options-header-include.sh && ./scripts/check-options-header-include.sh diff --git a/lib/mlibc/.github/workflows/fixups.yml b/lib/mlibc/.github/workflows/fixups.yml new file mode 100644 index 0000000..08bdf93 --- /dev/null +++ b/lib/mlibc/.github/workflows/fixups.yml @@ -0,0 +1,24 @@ +name: Check if PR has fixups + +on: + pull_request: + +jobs: + find-fixups: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 + - run: | + set -e -o pipefail + + git rev-list 'HEAD^..HEAD' \ + | while read -r COMMIT; do + printf 'pondering commit %s\n' "$COMMIT" + git show -s "$COMMIT" + if git show -s --format='%s' "$COMMIT" | grep -q '^fixup! '; then + exit 1 + fi + done + printf 'ready to merge!\n' diff --git a/lib/mlibc/.gitignore b/lib/mlibc/.gitignore new file mode 100644 index 0000000..ed51de3 --- /dev/null +++ b/lib/mlibc/.gitignore @@ -0,0 +1,6 @@ +build/ +subprojects +!subprojects/*.wrap +*.xbstrap +# editor configs: +.vscode diff --git a/lib/mlibc/ABI_BREAKS.md b/lib/mlibc/ABI_BREAKS.md new file mode 100644 index 0000000..5e71bad --- /dev/null +++ b/lib/mlibc/ABI_BREAKS.md @@ -0,0 +1,29 @@ +# ABI Breaks + +This document lists the ABI breaks that were made in each mlibc major version. + +## Version 4 + +- [#814](https://github.com/managarm/mlibc/pull/814): `struct timex`'s `long int tai` changed to the correct `int tai`, and `int __padding[11]` got appended to the struct. +- [#816](https://github.com/managarm/mlibc/pull/816): `sys_wait4` on Linux now correctly returns a `pid_t`, not an `int` as previously. +- [#816](https://github.com/managarm/mlibc/pull/816): All `MS_*` macros of the `sys/mount.h` header were adjusted to match linux. +- [#816](https://github.com/managarm/mlibc/pull/816): `struct epoll_event` now gets correctly packed on `x86_64`. +- [#819](https://github.com/managarm/mlibc/pull/819): `str(n)dupa` is now defined as a pure macro, and not as a macro that points to a function. +- [#828](https://github.com/managarm/mlibc/pull/828): Linux-specific functions previously included in the posix option in `pthreads.h` and `sched.h` are not correctly guarded behind the linux option. +- [#828](https://github.com/managarm/mlibc/pull/828): The `CPU_*` macros of `sched.h` have been rewritten to resolve to internal mlibc implementations, and are now correctly guarded behind the linux option. +- [#735](https://github.com/managarm/mlibc/pull/735): `sched_getcpu` and `setns` were previously mistakenly C++-mangled and not declared, which has now been rectified. + +## Version 3 + +- [#728](https://github.com/managarm/mlibc/pull/728): + The macros `CMSG_{LEN,SPACE,DATA}` were not accounting for padding between + `struct cmsghdr` and it's respective data. This manifested itself as some + parts of control data being skipped on platforms where `struct cmsghdr` is + not divisible by `alignof(size_t)`. +- [#452](https://github.com/managarm/mlibc/pull/452): The functions `FD_{CLR,ISSET,SET,ZERO}` were renamed to `__FD_{CLR,ISSET,SET,ZERO}` and replaced by macros to match Wine's assumptions. +- [#511](https://github.com/managarm/mlibc/pull/511): Musl's regex engine was added, implementing `regcomp` and `regexec`. This required some changes to the `regex_t` struct. +- [#504](https://github.com/managarm/mlibc/pull/504): In the Linux ABI, a `domainname` member was added to `struct utsname`, which is a glibc extension. +- [#311](https://github.com/managarm/mlibc/pull/311): Added all necessary fields in `pthread_attr_t` required for implementing all `pthread_attr` functions. +- [#652](https://github.com/managarm/mlibc/pull/652): The ABI of `struct statfs` and `struct statvfs` was changed to match Linux. `socklen_t` was also changed from `unsigned long` to `unsigned int`. +- [#658](https://github.com/managarm/mlibc/pull/648): In the Linux ABI, `cc_t` was changed from an `unsigned int` to an `unsigned char`. +- [#679](https://github.com/managarm/mlibc/pull/679): The `struct glob_t` received some additional members to bring it up to par with glibc. diff --git a/lib/mlibc/LICENSE b/lib/mlibc/LICENSE new file mode 100644 index 0000000..39ea764 --- /dev/null +++ b/lib/mlibc/LICENSE @@ -0,0 +1,19 @@ +Copyright (C) 2015-2024 mlibc Contributors + +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. diff --git a/lib/mlibc/README.md b/lib/mlibc/README.md new file mode 100644 index 0000000..411c1f9 --- /dev/null +++ b/lib/mlibc/README.md @@ -0,0 +1,49 @@ +# mlibc is a C standard library + +![Continuous Integration](https://github.com/managarm/mlibc/workflows/Continuous%20Integration/badge.svg) + +**Official Discord server:** https://discord.gg/7WB6Ur3 + +**AUR package** (provides `mlibc-gcc`): https://aur.archlinux.org/packages/mlibc + +## Design of the library + +| Directory | Purpose | +| --- | --- | +| `options/` | (More or less) OS-independent headers and code.
`options/` is divided into subdirectories that can be enabled or disabled by ports.| +| `sysdeps/` | OS-specific headers and code.
`sysdeps/` is divded into per-port subdirectories. Exactly one of those subdirectories is enabled in each build.| +| `abis/` | OS-specific interface headers ("ABI headers"). Those contain the constants and structs of the OS interface. For example, the numerical values of `SEEK_SET` or `O_CREAT` live here, as well as structs like `struct stat`. ABI headers are _only_ allowed to contain constants, structs and unions but _no_ function declarations or logic.
`abis/` is divided into per-OS subdirectories but this division is for organizational purposes only. Ports can still mix headers from different `abis/` subdirectories.| + +## Porting mlibc to a new OS + +Ports to new OSes are welcome. To port mlibc to another OS, the following changes need to be made: +1. Add new `sysdeps/` subdirectory `sysdeps/some-new-os/` and a `meson.build` to compile it. Integreate `sysdeps/some-new-os/meson.build` into the toplevel `meson.build`. +2. Create ABI headers in `abis/some-new-os/`. Add symlinks in `sysdeps/some-new-os/include/abi-bits` to your ABI headers. Look at existing ports to figure out the ABI headers required for the options enabled by `sysdeps/some-new-os/meson.build`. +3. In `sysdeps/some-new-os/`, add code to implement (a subset of) the functions from `options/internal/include/mlibc/internal-sysdeps.hpp`. Which subset you need depends on the options that `sysdeps/some-new-os/meson.build` enables. + +We recommend that new ports do not build from `master` as we occasionally make internal changes that cause out-of-tree sysdeps to break. Instead we recommend you pin a specific release (or commit), or to upstream your changes to this repository so that we can build them on our CI and thus any breakages will be fixed by us in-tree. + +## Build Configuration + +The following custom meson options are accepted, in addition to the [built-in options](https://mesonbuild.com/Builtin-options.html). The options below are booleans which default to false (see `meson_options.txt`). + +- `headers_only`: Only install headers; don't build `libc.so` or `ld.so`. +- `mlibc_no_headers`: Don't install headers; only build `libc.so` and `ld.so`. +- `build_tests`: Build the test suite (see below). +- `disable_x_option`: Disable `x` component of mlibc functionality. See `meson_options.txt` for a full list of possible values for `x`. This may be used to e.g disable POSIX and glibc extensions. +- `linux_kernel_headers`: Allows for directing mlibc to installed linux headers. [These can be obtained easily](https://docs.kernel.org/kbuild/headers_install.html), placed in a directory and this option set to the corresponding path. This is required if the linux option is enabled, i.e. when the linux option is not disabled. + +The type of library to be built (static, shared, or both) is controlled by meson's `default_library` option. Passing `-Ddefault_library=static` effectively disables the dynamic linker. + +We also support building with `-Db_sanitize=undefined` to use UBSan inside mlibc. Note that this does not enable UBSan for external applications which link against `libc.so`, but it can be useful during development to detect internal bugs (e.g when adding new sysdeps). + +## Running Tests + +The `mlibc` test suite can be run under a Linux host. To do this, first run from the project root: +``` +meson -Dbuild_tests=true build +``` +This will create a `build` directory. Then, `cd build` and run the tests (showing output) with: +``` +meson test -v +``` diff --git a/lib/mlibc/RELEASE_PROCEDURE.md b/lib/mlibc/RELEASE_PROCEDURE.md new file mode 100644 index 0000000..6030205 --- /dev/null +++ b/lib/mlibc/RELEASE_PROCEDURE.md @@ -0,0 +1,18 @@ +# Versioning + +mlibc uses semantic versioning to denote releases. +A bump in the major version signals an ABI break. +A bump in the minor version signals a newly released set of features, while still maintaining ABI. +A bump in the patch signals a bug-fix, while not adding new features. + +# Release schedule + +A minor or major version will be released every two months (every even month). A release is turned into a major one +when there is a pending ABI break, given that the ABI hasn't been broken in the last 6 months. +A patch version will be released on-demand, as bugs are fixed. + +When a new minor or major version is to be released, first a release candiate ("rc") will +be released. This release candiate will become the definite release after a week. During +this time, end-users shall test the rc and determine if there are breaking changes. Several +rc's can be released (``rc-1``, ``rc-2``, etc.). Once the rc is confirmed to be in a stable +state, the final version is to be released. diff --git a/lib/mlibc/abis/aero/auxv.h b/lib/mlibc/abis/aero/auxv.h new file mode 100644 index 0000000..a196fb5 --- /dev/null +++ b/lib/mlibc/abis/aero/auxv.h @@ -0,0 +1,9 @@ +#ifndef _ABIBITS_AUXV_H +#define _ABIBITS_AUXV_H + +#define AT_EXECPATH 15 +#define AT_SECURE 23 +#define AT_RANDOM 25 +#define AT_EXECFN 31 + +#endif // _ABIBITS_AUXV_H diff --git a/lib/mlibc/abis/dripos/auxv.h b/lib/mlibc/abis/dripos/auxv.h new file mode 100644 index 0000000..4e93ed3 --- /dev/null +++ b/lib/mlibc/abis/dripos/auxv.h @@ -0,0 +1,8 @@ +#ifndef _ABIBITS_AUXV_H +#define _ABIBITS_AUXV_H + +#define AT_SECURE 23 +#define AT_RANDOM 25 +#define AT_EXECFN 31 + +#endif diff --git a/lib/mlibc/abis/dripos/errno.h b/lib/mlibc/abis/dripos/errno.h new file mode 100644 index 0000000..0375024 --- /dev/null +++ b/lib/mlibc/abis/dripos/errno.h @@ -0,0 +1,149 @@ +#ifndef _ABIBITS_ERRNO_H +#define _ABIBITS_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 /* Input/output error */ +#define ENXIO 6 /* Device not configured */ +#define E2BIG 7 /* Argument list too long */ +#define ENOEXEC 8 /* Exec format error */ +#define EBADF 9 /* Bad file descriptor */ +#define ECHILD 10 /* No child processes */ +#define EDEADLK 11 /* Resource deadlock avoided */ + /* 11 was EAGAIN */ + +#define ENOMEM 12 /* Cannot allocate memory */ +#define EACCES 13 /* Permission denied */ +#define EFAULT 14 /* Bad address */ + +#define ENOTBLK 15 /* Block device required */ +#define EBUSY 16 /* Device busy */ + +#define EEXIST 17 /* File exists */ +#define EXDEV 18 /* Cross-device link */ +#define ENODEV 19 /* Operation not supported by device */ +#define ENOTDIR 20 /* Not a directory */ +#define EISDIR 21 /* Is a directory */ +#define EINVAL 22 /* Invalid argument */ +#define ENFILE 23 /* Too many open files in system */ +#define EMFILE 24 /* Too many open files */ +#define ENOTTY 25 /* Inappropriate ioctl for device */ + +#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 */ + +/* math software */ +#define EDOM 33 /* Numerical argument out of domain */ +#define ERANGE 34 /* Result too large */ + +/* non-blocking and interrupt i/o */ +#define EAGAIN 35 /* Resource temporarily unavailable */ + +#define EWOULDBLOCK EAGAIN /* Operation would block */ +#define EINPROGRESS 36 /* Operation now in progress */ +#define EALREADY 37 /* Operation already in progress */ + +/* ipc/network software -- argument errors */ +#define ENOTSOCK 38 /* Socket operation on non-socket */ +#define EDESTADDRREQ 39 /* Destination address required */ +#define EMSGSIZE 40 /* Message too long */ +#define EPROTOTYPE 41 /* Protocol wrong type for socket */ +#define ENOPROTOOPT 42 /* Protocol not available */ +#define EPROTONOSUPPORT 43 /* Protocol not supported */ +#define ESOCKTNOSUPPORT 44 /* Socket type not supported */ +#define EOPNOTSUPP 45 /* Operation not supported on socket */ +#define EPFNOSUPPORT 46 /* Protocol family not supported */ +#define EAFNOSUPPORT 47 /* Address family not supported by protocol family */ +#define EADDRINUSE 48 /* Address already in use */ +#define EADDRNOTAVAIL 49 /* Can't assign requested address */ + +/* ipc/network software -- operational errors */ +#define ENETDOWN 50 /* Network is down */ +#define ENETUNREACH 51 /* Network is unreachable */ +#define ENETRESET 52 /* Network dropped connection on reset */ +#define ECONNABORTED 53 /* Software caused connection abort */ +#define ECONNRESET 54 /* Connection reset by peer */ +#define ENOBUFS 55 /* No buffer space available */ +#define EISCONN 56 /* Socket is already connected */ +#define ENOTCONN 57 /* Socket is not connected */ +#define ESHUTDOWN 58 /* Can't send after socket shutdown */ +#define ETOOMANYREFS 59 /* Too many references: can't splice */ +#define ETIMEDOUT 60 /* Connection timed out */ +#define ECONNREFUSED 61 /* Connection refused */ + +#define ELOOP 62 /* Too many levels of symbolic links */ + +#define ENAMETOOLONG 63 /* File name too long */ + +/* should be rearranged */ +#define EHOSTDOWN 64 /* Host is down */ +#define EHOSTUNREACH 65 /* No route to host */ +#define ENOTEMPTY 66 /* Directory not empty */ + +/* quotas & mush */ +#define EPROCLIM 67 /* Too many processes */ +#define EUSERS 68 /* Too many users */ +#define EDQUOT 69 /* Disc quota exceeded */ + +/* Network File System */ +#define ESTALE 70 /* Stale NFS file handle */ +#define EREMOTE 71 /* Too many levels of remote in path */ +#define EBADRPC 72 /* RPC struct is bad */ +#define ERPCMISMATCH 73 /* RPC version wrong */ +#define EPROGUNAVAIL 74 /* RPC prog. not avail */ +#define EPROGMISMATCH 75 /* Program version wrong */ +#define EPROCUNAVAIL 76 /* Bad procedure for program */ + + +#define ENOLCK 77 /* No locks available */ +#define ENOSYS 78 /* Function not implemented */ + +#define EFTYPE 79 /* Inappropriate file type or format */ +#define EOVERFLOW 80 +#define EILSEQ 81 + +#define EBADMSG 82 +#define ECANCELED 83 +#define EIDRM 84 +#define EMULTIHOP 85 +#define ENOLINK 86 +#define ENOMSG 87 +#define ENOTRECOVERABLE 88 +#define ENOTSUP 89 +#define EOWNERDEAD 90 +#define EPROTO 91 +#define ENODATA 92 +#define ETIME 93 +#define ENOKEY 94 +#define EBADFD 95 +#define ENOMEDIUM 96 +#define ENONET 97 +#define ESTRPIPE 98 +#define EREMOTEIO 99 +#define ERFKILL 100 +#define EBADR 101 +#define EUNATCH 102 +#define EMEDIUMTYPE 103 +#define EKEYREJECTED 104 +#define EUCLEAN 105 +#define EBADSLT 106 +#define ENOANO 107 +#define ENOCSI 108 +#define ENOSTR 109 +#define ENOPKG 110 +#define EKEYREVOKED 111 +#define EXFULL 112 +#define ELNRNG 113 +#define ENOTUNIQ 114 +#define ERESTART 115 +#define ENOTSUP 116 + +#endif diff --git a/lib/mlibc/abis/hyra/auxv.h b/lib/mlibc/abis/hyra/auxv.h new file mode 100644 index 0000000..92fa648 --- /dev/null +++ b/lib/mlibc/abis/hyra/auxv.h @@ -0,0 +1,16 @@ +#ifndef _ABIBITS_AUXV_H +#define _ABIBITS_AUXV_H + +#define AT_NULL 0 +#define AT_IGNORE 1 +#define AT_EXECFD 2 +#define AT_PHDR 3 +#define AT_PHENT 4 +#define AT_PHNUM 5 +#define AT_PAGESZ 6 +#define AT_BASE 7 +#define AT_FLAGS 8 +#define AT_ENTRY 9 +#define AT_SECURE 10 + +#endif // _ABIBITS_AUXV_H diff --git a/lib/mlibc/abis/ironclad/access.h b/lib/mlibc/abis/ironclad/access.h new file mode 100644 index 0000000..bc19728 --- /dev/null +++ b/lib/mlibc/abis/ironclad/access.h @@ -0,0 +1,9 @@ +#ifndef _ABIBITS_ACCESS_H +#define _ABIBITS_ACCESS_H + +#define F_OK 1 +#define R_OK 2 +#define W_OK 4 +#define X_OK 8 + +#endif // _ABIBITS_ACCESS_H diff --git a/lib/mlibc/abis/ironclad/auxv.h b/lib/mlibc/abis/ironclad/auxv.h new file mode 100644 index 0000000..4e93ed3 --- /dev/null +++ b/lib/mlibc/abis/ironclad/auxv.h @@ -0,0 +1,8 @@ +#ifndef _ABIBITS_AUXV_H +#define _ABIBITS_AUXV_H + +#define AT_SECURE 23 +#define AT_RANDOM 25 +#define AT_EXECFN 31 + +#endif diff --git a/lib/mlibc/abis/ironclad/blkcnt_t.h b/lib/mlibc/abis/ironclad/blkcnt_t.h new file mode 100644 index 0000000..51c1519 --- /dev/null +++ b/lib/mlibc/abis/ironclad/blkcnt_t.h @@ -0,0 +1,7 @@ +#ifndef _ABIBITS_BLKCNT_T_H +#define _ABIBITS_BLKCNT_T_H + +// TODO: use int64_t? +typedef long blkcnt_t; + +#endif // _ABIBITS_BLKCNT_T_H diff --git a/lib/mlibc/abis/ironclad/blksize_t.h b/lib/mlibc/abis/ironclad/blksize_t.h new file mode 100644 index 0000000..9f87294 --- /dev/null +++ b/lib/mlibc/abis/ironclad/blksize_t.h @@ -0,0 +1,8 @@ +#ifndef _ABIBITS_BLKSIZE_T_H +#define _ABIBITS_BLKSIZE_T_H + +// TODO: use int64_t? +typedef long blksize_t; + +#endif // _ABIBITS_BLKSIZE_T_H + diff --git a/lib/mlibc/abis/ironclad/clockid_t.h b/lib/mlibc/abis/ironclad/clockid_t.h new file mode 100644 index 0000000..c3932ef --- /dev/null +++ b/lib/mlibc/abis/ironclad/clockid_t.h @@ -0,0 +1,7 @@ +#ifndef _ABIBITS_CLOCKID_T_H +#define _ABIBITS_CLOCKID_T_H + +typedef long clockid_t; + +#endif /* _ABIBITS_CLOCKID_T_H */ + diff --git a/lib/mlibc/abis/ironclad/dev_t.h b/lib/mlibc/abis/ironclad/dev_t.h new file mode 100644 index 0000000..0b63fe5 --- /dev/null +++ b/lib/mlibc/abis/ironclad/dev_t.h @@ -0,0 +1,6 @@ +#ifndef _ABIBITS_DEV_T_H +#define _ABIBITS_DEV_T_H + +typedef unsigned long dev_t; + +#endif // _ABIBITS_DEV_T_H diff --git a/lib/mlibc/abis/ironclad/epoll.h b/lib/mlibc/abis/ironclad/epoll.h new file mode 100644 index 0000000..49969d5 --- /dev/null +++ b/lib/mlibc/abis/ironclad/epoll.h @@ -0,0 +1,6 @@ +#ifndef _ABIBITS_EPOLL_H +#define _ABIBITS_EPOLL_H + +#define EPOLL_CLOEXEC 1 + +#endif // _ABIBITS_EPOLL_H diff --git a/lib/mlibc/abis/ironclad/errno.h b/lib/mlibc/abis/ironclad/errno.h new file mode 100644 index 0000000..f8c7203 --- /dev/null +++ b/lib/mlibc/abis/ironclad/errno.h @@ -0,0 +1,126 @@ +#ifndef _ABIBITS_ERRNO_H +#define _ABIBITS_ERRNO_H + +#define EDOM 1 +#define EILSEQ 2 +#define ERANGE 3 + +#define E2BIG 1001 +#define EACCES 1002 +#define EADDRINUSE 1003 +#define EADDRNOTAVAIL 1004 +#define EAFNOSUPPORT 1005 +#define EAGAIN 1006 +#define EALREADY 1007 +#define EBADF 1008 +#define EBADMSG 1009 +#define EBUSY 1010 +#define ECANCELED 1011 +#define ECHILD 1012 +#define ECONNABORTED 1013 +#define ECONNREFUSED 1014 +#define ECONNRESET 1015 +#define EDEADLK 1016 +#define EDESTADDRREQ 1017 +#define EDQUOT 1018 +#define EEXIST 1019 +#define EFAULT 1020 +#define EFBIG 1021 +#define EHOSTUNREACH 1022 +#define EIDRM 1023 +#define EINPROGRESS 1024 +#define EINTR 1025 +#define EINVAL 1026 +#define EIO 1027 +#define EISCONN 1028 +#define EISDIR 1029 +#define ELOOP 1030 +#define EMFILE 1031 +#define EMLINK 1032 +#define EMSGSIZE 1034 +#define EMULTIHOP 1035 +#define ENAMETOOLONG 1036 +#define ENETDOWN 1037 +#define ENETRESET 1038 +#define ENETUNREACH 1039 +#define ENFILE 1040 +#define ENOBUFS 1041 +#define ENODEV 1042 +#define ENOENT 1043 +#define ENOEXEC 1044 +#define ENOLCK 1045 +#define ENOLINK 1046 +#define ENOMEM 1047 +#define ENOMSG 1048 +#define ENOPROTOOPT 1049 +#define ENOSPC 1050 +#define ENOSYS 1051 +#define ENOTCONN 1052 +#define ENOTDIR 1053 +#define ENOTEMPTY 1054 +#define ENOTRECOVERABLE 1055 +#define ENOTSOCK 1056 +#define ENOTSUP 1057 +#define ENOTTY 1058 +#define ENXIO 1059 +#define EOPNOTSUPP 1060 +#define EOVERFLOW 1061 +#define EOWNERDEAD 1062 +#define EPERM 1063 +#define EPIPE 1064 +#define EPROTO 1065 +#define EPROTONOSUPPORT 1066 +#define EPROTOTYPE 1067 +#define EROFS 1068 +#define ESPIPE 1069 +#define ESRCH 1070 +#define ESTALE 1071 +#define ETIMEDOUT 1072 +#define ETXTBSY 1073 +#define EWOULDBLOCK EAGAIN +#define EXDEV 1075 +#define ENODATA 1076 +#define ETIME 1077 +#define ENOKEY 1078 +#define ESHUTDOWN 1079 +#define EHOSTDOWN 1080 +#define EBADFD 1081 +#define ENOMEDIUM 1082 +#define ENOTBLK 1083 +#define ENONET 1084 +#define EPFNOSUPPORT 1085 +#define ESOCKTNOSUPPORT 1086 +#define ESTRPIPE 1087 +#define EREMOTEIO 1088 +#define ERFKILL 1089 +#define EBADR 1090 +#define EUNATCH 1091 +#define EMEDIUMTYPE 1092 +#define EREMOTE 1093 +#define EKEYREJECTED 1094 +#define EUCLEAN 1095 +#define EBADSLT 1096 +#define ENOANO 1097 +#define ENOCSI 1098 +#define ENOSTR 1099 +#define ETOOMANYREFS 1100 +#define ENOPKG 1101 +#define EKEYREVOKED 1102 +#define EXFULL 1103 +#define ELNRNG 1104 +#define ENOTUNIQ 1105 +#define ERESTART 1106 +#define EUSERS 1107 +#define ECHRNG 1108 +#define ELIBBAD 1109 +#define EL2HLT 1110 +#define EL3HLT 1111 +#define EKEYEXPIRED 1112 +#define ECOMM 1113 +#define EBADE 1114 +#define EHWPOISON 1115 +#define EBADRQC 1116 + +#define EIEIO 1524152434 + +#endif // _ABIBITS_ERRNO_H diff --git a/lib/mlibc/abis/ironclad/fcntl.h b/lib/mlibc/abis/ironclad/fcntl.h new file mode 100644 index 0000000..10188de --- /dev/null +++ b/lib/mlibc/abis/ironclad/fcntl.h @@ -0,0 +1,79 @@ +#ifndef _ABIBITS_FCNTL_H +#define _ABIBITS_FCNTL_H + +// Flags supported by the kernel. +#define O_ACCMODE 0b000011 +#define O_RDONLY 00000001 +#define O_WRONLY 0b000010 +#define O_RDWR 0b000011 +#define O_APPEND 0b000100 +#define O_CLOEXEC 0b001000 +#define O_NOFOLLOW 0b010000 +#define O_NONBLOCK 0b100000 + +// Flags emulated by userland, we just have to make sure they dont overlap with +// kernel flags. +#define O_CREAT 0b0010000000 +#define O_EXCL 0b0100000000 +#define O_TRUNC 0b1000000000 + +// Stubbed flags, the value really doesnt matter as long as they dont overlap +// with usable ones. +// Implemented here as some software needs them to compile. +#define O_SEARCH 0b000000000010000000000 +#define O_EXEC 0b000000000100000000000 +#define O_NOCTTY 0b000000001000000000000 +#define O_DSYNC 0b000000010000000000000 +#define O_RSYNC 0b000000100000000000000 +#define O_SYNC 0b000001000000000000000 +#define O_PATH 0b000010000000000000000 +#define O_DIRECTORY 0b000100000000000000000 +#define O_LARGEFILE 0b001000000000000000000 +#define O_NOATIME 0b010000000000000000000 +#define O_TMPFILE 0b100000000000000000000 + +// Fcntl flags. +#define FD_CLOEXEC 1 +#define F_DUPFD 1 +#define F_DUPFD_CLOEXEC 2 +#define F_GETFD 3 +#define F_SETFD 4 +#define F_GETFL 5 +#define F_SETFL 6 +#define F_GETPIPE_SZ 7 +#define F_SETPIPE_SZ 8 +#define F_GETLK 9 +#define F_SETLK 10 +#define F_SETLKW 11 + +#define F_RDLCK 1 +#define F_UNLCK 2 +#define F_WRLCK 3 + +// Stubbed fcntl flags. +#define F_GETOWN 10 +#define F_SETOWN 11 + +#define F_SEAL_SHRINK 0x0002 +#define F_SEAL_GROW 0x0004 +#define F_SEAL_WRITE 0x0008 +#define F_SEAL_SEAL 0x0010 +#define F_ADD_SEALS 1033 +#define F_GET_SEALS 1034 + +// At flags. +#define AT_REMOVEDIR 500 +#define AT_EACCESS 512 +#define AT_FDCWD 0x7FFFFFFF +#define AT_EMPTY_PATH 1 +#define AT_SYMLINK_FOLLOW 0 +#define AT_SYMLINK_NOFOLLOW 2 + +#define POSIX_FADV_NORMAL 1 +#define POSIX_FADV_SEQUENTIAL 2 +#define POSIX_FADV_NOREUSE 3 +#define POSIX_FADV_DONTNEED 4 +#define POSIX_FADV_WILLNEED 5 +#define POSIX_FADV_RANDOM 6 + +#endif // _ABIBITS_FCNTL_H diff --git a/lib/mlibc/abis/ironclad/fsblkcnt_t.h b/lib/mlibc/abis/ironclad/fsblkcnt_t.h new file mode 100644 index 0000000..0d74456 --- /dev/null +++ b/lib/mlibc/abis/ironclad/fsblkcnt_t.h @@ -0,0 +1,8 @@ +#ifndef _ABIBITS_FSBLKCNT_T_H +#define _ABIBITS_FSBLKCNT_T_H + +#include + +typedef __mlibc_uint64 fsblkcnt_t; + +#endif /* _ABIBITS_FSBLKCNT_T_H */ diff --git a/lib/mlibc/abis/ironclad/fsfilcnt_t.h b/lib/mlibc/abis/ironclad/fsfilcnt_t.h new file mode 100644 index 0000000..1abda9a --- /dev/null +++ b/lib/mlibc/abis/ironclad/fsfilcnt_t.h @@ -0,0 +1,8 @@ +#ifndef _ABIBITS_FSFILCNT_T_H +#define _ABIBITS_FSFILCNT_T_H + +#include + +typedef __mlibc_uint64 fsfilcnt_t; + +#endif /* _ABIBITS_FSFILCNT_T_H */ diff --git a/lib/mlibc/abis/ironclad/gid_t.h b/lib/mlibc/abis/ironclad/gid_t.h new file mode 100644 index 0000000..252321f --- /dev/null +++ b/lib/mlibc/abis/ironclad/gid_t.h @@ -0,0 +1,6 @@ +#ifndef _ABIBITS_GID_T_H +#define _ABIBITS_GID_T_H + +typedef unsigned int gid_t; + +#endif // _ABIBITS_GID_T_H diff --git a/lib/mlibc/abis/ironclad/in.h b/lib/mlibc/abis/ironclad/in.h new file mode 100644 index 0000000..3c736e3 --- /dev/null +++ b/lib/mlibc/abis/ironclad/in.h @@ -0,0 +1,168 @@ +#ifndef _ABIBITS_IN_H +#define _ABIBITS_IN_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +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 pad[8]; +}; +#define sin_zero pad /* for BSD Unix compatibility */ + +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 in6_pktinfo { + struct in6_addr ipi6_addr; + uint32_t ipi6_ifindex; +}; + +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; +}; + +struct ipv6_mreq { + struct in6_addr ipv6mr_multiaddr; + unsigned ipv6mr_interface; +}; + +struct ip_mreq { + struct in_addr imr_multiaddr; + struct in_addr imr_interface; +}; + +struct ip_mreq_source { + struct in_addr imr_multiaddr; + struct in_addr imr_interface; + struct in_addr imr_sourceaddr; +}; + +struct ip_mreqn { + struct in_addr imr_multiaddr; + struct in_addr imr_address; + int imr_ifindex; +}; + +struct in_pktinfo { + unsigned int ipi_ifindex; + struct in_addr ipi_spec_dst; + struct in_addr ipi_addr; +}; + +struct group_source_req { + uint32_t gsr_interface; + struct sockaddr_storage gsr_group; + struct sockaddr_storage gsr_source; +}; + +#ifdef __cplusplus +} +#endif + +#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 } } } + +#define IPPROTO_IP 1 +#define IPPROTO_IPV6 2 +#define IPPROTO_ICMP 3 +#define IPPROTO_RAW 4 +#define IPPROTO_TCP 5 +#define IPPROTO_UDP 6 +#define IPPROTO_IGMP 7 +#define IPPROTO_IPIP 8 +#define IPPROTO_DCCP 33 +#define IPPROTO_ROUTING 43 +#define IPPROTO_GRE 47 +#define IPPROTO_ESP 50 +#define IPPROTO_AH 51 +#define IPPROTO_ICMPV6 58 +#define IPPROTO_DSTOPTS 60 +#define IPPROTO_COMP 108 +#define IPPROTO_SCTP 132 +#define IPPROTO_UDPLITE 136 +#define IPPROTO_MAX 256 + +#define INADDR_ANY ((in_addr_t)0x00000000) +#define INADDR_BROADCAST ((in_addr_t)0xffffffff) +#define INADDR_LOOPBACK ((in_addr_t)0x7f000001) +#define INADDR_NONE ((in_addr_t)0xffffffff) + +#define INET_ADDRSTRLEN 16 + +#define INET6_ADDRSTRLEN 46 + +#define IPV6_JOIN_GROUP 1 +#define IPV6_LEAVE_GROUP 2 +#define IPV6_MULTICAST_HOPS 3 +#define IPV6_MULTICAST_IF 4 +#define IPV6_MULTICAST_LOOP 5 +#define IPV6_UNICAST_HOPS 6 +#define IPV6_V6ONLY 7 +#define IPV6_PMTUDISC_DONT 8 +#define IPV6_PMTUDISC_DO 9 +#define IPV6_MTU 10 +#define IPV6_2292PKTOPTIONS 11 +#define IPV6_MTU_DISCOVER 23 +#define IPV6_RECVERR 25 +#define IPV6_RECVPKTINFO 49 +#define IPV6_PKTINFO 50 +#define IPV6_RECVHOPLIMIT 51 +#define IPV6_HOPLIMIT 52 +#define IPV6_TCLASS 67 + +#define IP_TOS 1 +#define IP_TTL 2 +#define IP_OPTIONS 4 +#define IP_PMTUDISC_OMIT 5 +#define IP_PKTINFO 8 +#define IP_PKTOPTIONS 9 +#define IP_MTU_DISCOVER 10 +#define IP_RECVERR 11 +#define IP_RECVTTL 12 +#define IP_UNICAST_IF 13 +#define IP_MTU 14 + +#define IP_DEFAULT_MULTICAST_TTL 1 +#define IP_MULTICAST_IF 32 +#define IP_MULTICAST_TTL 33 +#define IP_MULTICAST_LOOP 34 +#define IP_ADD_MEMBERSHIP 35 +#define IP_DROP_MEMBERSHIP 36 +#define IP_UNBLOCK_SOURCE 37 +#define IP_BLOCK_SOURCE 38 +#define IP_ADD_SOURCE_MEMBERSHIP 39 +#define IP_DROP_SOURCE_MEMBERSHIP 40 +#define MCAST_JOIN_SOURCE_GROUP 46 +#define MCAST_LEAVE_SOURCE_GROUP 47 + +#define IP_PMTUDISC_DONT 0 +#define IP_PMTUDISC_DO 2 + +#define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP +#define IPV6_DROP_MEMBERSHIP IPV6_LEAVE_GROUP + +#endif // _ABIBITS_IN_H diff --git a/lib/mlibc/abis/ironclad/ino_t.h b/lib/mlibc/abis/ironclad/ino_t.h new file mode 100644 index 0000000..264d888 --- /dev/null +++ b/lib/mlibc/abis/ironclad/ino_t.h @@ -0,0 +1,7 @@ +#ifndef _ABIBITS_INO_T_H +#define _ABIBITS_INO_T_H + +// TODO: use (u)int64_t? +typedef long ino_t; + +#endif // _ABIBITS_INO_T_H diff --git a/lib/mlibc/abis/ironclad/inotify.h b/lib/mlibc/abis/ironclad/inotify.h new file mode 100644 index 0000000..38c9c77 --- /dev/null +++ b/lib/mlibc/abis/ironclad/inotify.h @@ -0,0 +1,7 @@ +#ifndef _ABIBITS_INOTIFY_H +#define _ABIBITS_INOTIFY_H + +#define IN_CLOEXEC 1 +#define IN_NONBLOCK 2 + +#endif // _ABIBITS_INOTIFY_H diff --git a/lib/mlibc/abis/ironclad/ioctls.h b/lib/mlibc/abis/ironclad/ioctls.h new file mode 100644 index 0000000..c39abb5 --- /dev/null +++ b/lib/mlibc/abis/ironclad/ioctls.h @@ -0,0 +1,13 @@ +#ifndef _ABIBITS_IOCTLS_H +#define _ABIBITS_IOCTLS_H + +#define SIOCPROTOPRIVATE 0x89E0 +#define SIOCGIFNAME 0x8910 +#define SIOCGIFCONF 0x8912 +#define SIOCGIFFLAGS 0x8913 +#define SIOCSIFFLAGS 0x8914 +#define SIOCGIFINDEX 0x8933 +#define SIOCATMARK 0x8905 +#define SIOCGIFHWADDR 0x8927 + +#endif /* _ABIBITS_IOCTLS_H */ diff --git a/lib/mlibc/abis/ironclad/limits.h b/lib/mlibc/abis/ironclad/limits.h new file mode 100644 index 0000000..6aac622 --- /dev/null +++ b/lib/mlibc/abis/ironclad/limits.h @@ -0,0 +1,14 @@ +#ifndef _ABIBITS_LIMITS_H +#define _ABIBITS_LIMITS_H + +#define IOV_MAX 1024 + +// Niceness related +#define NZERO 20 + +// Maximum hostname length, posix defines it as 255 +#define HOST_NAME_MAX 255 + +#define OPEN_MAX 256 + +#endif //_ABIBITS_LIMITS_H diff --git a/lib/mlibc/abis/ironclad/mode_t.h b/lib/mlibc/abis/ironclad/mode_t.h new file mode 100644 index 0000000..77f75a9 --- /dev/null +++ b/lib/mlibc/abis/ironclad/mode_t.h @@ -0,0 +1,6 @@ +#ifndef _ABIBITS_MODE_T_H +#define _ABIBITS_MODE_T_H + +typedef int mode_t; + +#endif // _ABIBITS_MODE_T_H diff --git a/lib/mlibc/abis/ironclad/mqueue.h b/lib/mlibc/abis/ironclad/mqueue.h new file mode 100644 index 0000000..f18210c --- /dev/null +++ b/lib/mlibc/abis/ironclad/mqueue.h @@ -0,0 +1,20 @@ +#ifndef _ABIBITS_MQUEUE_H +#define _ABIBITS_MQUEUE_H + +#ifdef __cplusplus +extern "C" { +#endif + +struct mq_attr { + long mq_flags; + long mq_maxmsg; + long mq_msgsize; + long mq_curmsgs; + long __pad[4]; +}; + +#ifdef __cplusplus +} +#endif + +#endif /* _ABIBITS_MQUEUE_H */ diff --git a/lib/mlibc/abis/ironclad/msg.h b/lib/mlibc/abis/ironclad/msg.h new file mode 100644 index 0000000..5e890c0 --- /dev/null +++ b/lib/mlibc/abis/ironclad/msg.h @@ -0,0 +1,39 @@ +#ifndef _ABIBITS_MSG_H +#define _ABIBITS_MSG_H + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(__i386__) +typedef __mlibc_uint64 msglen_t; +typedef __mlibc_uint64 msgqnum_t; +#else +typedef unsigned long msglen_t; +typedef unsigned long msgqnum_t; +#endif + +struct msqid_ds { + struct ipc_perm msg_perm; + time_t msg_stime; + time_t msg_rtime; + time_t msg_ctime; + unsigned long msg_cbytes; + msgqnum_t msg_qnum; + msglen_t msg_qbytes; + pid_t msg_lspid; + pid_t msg_lrpid; + unsigned long __unused[2]; +}; + +#ifdef __cplusplus +} +#endif + +#endif /* _ABIBITS_MSG_H */ + diff --git a/lib/mlibc/abis/ironclad/nlink_t.h b/lib/mlibc/abis/ironclad/nlink_t.h new file mode 100644 index 0000000..30e178c --- /dev/null +++ b/lib/mlibc/abis/ironclad/nlink_t.h @@ -0,0 +1,6 @@ +#ifndef _ABIBITS_NLINK_T_H +#define _ABIBITS_NLINK_T_H + +typedef int nlink_t; + +#endif // _ABIBITS_NLINK_T_H diff --git a/lib/mlibc/abis/ironclad/packet.h b/lib/mlibc/abis/ironclad/packet.h new file mode 100644 index 0000000..ee1a424 --- /dev/null +++ b/lib/mlibc/abis/ironclad/packet.h @@ -0,0 +1,6 @@ +#ifndef _ABIBITS_PACKET_H +#define _ABIBITS_PACKET_H + +#define PACKET_HOST 0 + +#endif // _ABIBITS_PACKET_H diff --git a/lib/mlibc/abis/ironclad/pid_t.h b/lib/mlibc/abis/ironclad/pid_t.h new file mode 100644 index 0000000..5ffbd06 --- /dev/null +++ b/lib/mlibc/abis/ironclad/pid_t.h @@ -0,0 +1,6 @@ +#ifndef _ABIBITS_PID_T_H +#define _ABIBITS_PID_T_H + +typedef int pid_t; + +#endif // _ABIBITS_PID_T_H diff --git a/lib/mlibc/abis/ironclad/poll.h b/lib/mlibc/abis/ironclad/poll.h new file mode 100644 index 0000000..e0fe1a5 --- /dev/null +++ b/lib/mlibc/abis/ironclad/poll.h @@ -0,0 +1,16 @@ +#ifndef _ABIBITS_POLL_H +#define _ABIBITS_POLL_H + +#define POLLIN 0x01 +#define POLLOUT 0x02 +#define POLLPRI 0x04 +#define POLLHUP 0x08 +#define POLLERR 0x10 +#define POLLRDHUP 0x20 +#define POLLNVAL 0x40 +#define POLLWRNORM 0x80 +#define POLLRDNORM 0x100 +#define POLLWRBAND 0x200 +#define POLLRDBAND 0x400 + +#endif // _ABIBITS_POLL_H diff --git a/lib/mlibc/abis/ironclad/ptrace.h b/lib/mlibc/abis/ironclad/ptrace.h new file mode 100644 index 0000000..6f35eac --- /dev/null +++ b/lib/mlibc/abis/ironclad/ptrace.h @@ -0,0 +1,56 @@ +#ifndef _ABIBITS_PTRACE_H +#define _ABIBITS_PTRACE_H + +#define PTRACE_PEEKTEXT 1 +#define PTRACE_PEEKDATA 2 +#define PTRACE_PEEKUSER 3 +#define PTRACE_POKETEXT 4 +#define PTRACE_POKEDATA 5 +#define PTRACE_CONT 7 +#define PTRACE_KILL 8 +#define PTRACE_SINGLESTEP 9 +#define PTRACE_GETREGS 14 +#define PTRACE_SETREGS 15 +#define PTRACE_ATTACH 16 +#define PTRACE_DETACH 17 +#define PTRACE_GETFPXREGS 18 +#define PTRACE_SETFPXREGS 19 +#define PTRACE_GETFPREGS 20 +#define PTRACE_SYSCALL 24 +#define PTRACE_SETOPTIONS 0x4200 +#define PTRACE_GETEVENTMSG 0x4201 +#define PTRACE_GETSIGINFO 0x4202 +#define PTRACE_SETSIGINFO 0x4203 +#define PTRACE_GETREGSET 0x4204 +#define PTRACE_SETREGSET 0x4205 +#define PTRACE_SEIZE 0x4206 +#define PTRACE_INTERRUPT 0x4207 +#define PTRACE_LISTEN 0x4208 +#define PTRACE_PEEKSIGINFO 0x4209 +#define PTRACE_GETSIGMASK 0x420A +#define PTRACE_SETSIGMASK 0x420B +#define PTRACE_SECCOMP_GET_FILTER 0x420C + +#define PTRACE_CE_O_TRACESYSGOOD 0x00000001 +#define PTRACE_O_TRACEFORK 0x00000002 +#define PTRACE_O_TRACEVFORK 0x00000004 +#define PTRACE_O_TRACECLONE 0x00000008 +#define PTRACE_O_TRACEEXEC 0x00000010 +#define PTRACE_O_TRACEVFORKDONE 0x00000020 +#define PTRACE_O_TRACEEXIT 0x00000040 +#define PTRACE_O_TRACESECCOMP 0x00000080 +#define PTRACE_O_EXITKILL 0x00100000 +#define PTRACE_O_SUSPEND_SECCOMP 0x00200000 +#define PTRACE_O_MASK 0x003000ff + +#define PTRACE_EVENT_FORK 1 +#define PTRACE_EVENT_VFORK 2 +#define PTRACE_EVENT_CLONE 3 +#define PTRACE_EVENT_EXEC 4 +#define PTRACE_EVENT_VFORK_DONE 5 +#define PTRACE_EVENT_EXIT 6 +#define PTRACE_EVENT_SECCOMP 7 + +#define PTRACE_PEEKSIGINFO_SHARED 1 + +#endif // _ABIBITS_PTRACE_H diff --git a/lib/mlibc/abis/ironclad/reboot.h b/lib/mlibc/abis/ironclad/reboot.h new file mode 100644 index 0000000..aadc18f --- /dev/null +++ b/lib/mlibc/abis/ironclad/reboot.h @@ -0,0 +1,12 @@ +#ifndef _ABIBITS_REBOOT_H +#define _ABIBITS_REBOOT_H + +#define RB_AUTOBOOT 0x01234567 +#define RB_HALT_SYSTEM 0xcdef0123 +#define RB_ENABLE_CAD 0x89abcdef +#define RB_DISABLE_CAD 0 +#define RB_POWER_OFF 0x4321fedc +#define RB_SW_SUSPEND 0xd000fce2 +#define RB_KEXEC 0x45584543 + +#endif // _ABIBITS_REBOOT_H diff --git a/lib/mlibc/abis/ironclad/resource.h b/lib/mlibc/abis/ironclad/resource.h new file mode 100644 index 0000000..927588b --- /dev/null +++ b/lib/mlibc/abis/ironclad/resource.h @@ -0,0 +1,53 @@ +#ifndef _ABIBITS_RESOURCE_H +#define _ABIBITS_RESOURCE_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#define RUSAGE_SELF 1 +#define RUSAGE_CHILDREN 2 + +#define RLIMIT_CORE 1 +#define RLIMIT_CPU 2 +#define RLIMIT_DATA 3 +#define RLIMIT_FSIZE 4 +#define RLIMIT_NOFILE 5 +#define RLIMIT_STACK 6 +#define RLIMIT_AS 7 +#define RLIMIT_MEMLOCK 8 +#define RLIMIT_RSS 9 +#define RLIMIT_NPROC 10 +#define RLIMIT_LOCKS 11 +#define RLIMIT_SIGPENDING 12 +#define RLIMIT_MSGQUEUE 13 +#define RLIMIT_NICE 14 +#define RLIMIT_RTPRIO 15 +#define RLIMIT_NLIMITS 16 + +struct rusage { + struct timeval ru_utime; + struct timeval ru_stime; + long int ru_maxrss; + long int ru_ixrss; + long int ru_idrss; + long int ru_isrss; + long int ru_minflt; + long int ru_majflt; + long int ru_nswap; + long int ru_inblock; + long int ru_oublock; + long int ru_msgsnd; + long int ru_msgrcv; + long int ru_nsignals; + long int ru_nvcsw; + long int ru_nivcsw; +}; + +#ifdef __cplusplus +} +#endif + +#endif // _ABIBITS_RESOURCE_H diff --git a/lib/mlibc/abis/ironclad/seek-whence.h b/lib/mlibc/abis/ironclad/seek-whence.h new file mode 100644 index 0000000..617b6f4 --- /dev/null +++ b/lib/mlibc/abis/ironclad/seek-whence.h @@ -0,0 +1,8 @@ +#ifndef _ABIBITS_SEEK_WHENCE_H +#define _ABIBITS_SEEK_WHENCE_H + +#define SEEK_SET 1 +#define SEEK_CUR 2 +#define SEEK_END 4 + +#endif // _ABIBITS_SEEK_WHENCE_H diff --git a/lib/mlibc/abis/ironclad/shm.h b/lib/mlibc/abis/ironclad/shm.h new file mode 100644 index 0000000..93fb01b --- /dev/null +++ b/lib/mlibc/abis/ironclad/shm.h @@ -0,0 +1,21 @@ +#ifndef _ABIBITS_SHM_H +#define _ABIBITS_SHM_H + +#ifdef __cplusplus +extern "C" { +#endif + +struct shm_info { + int used_ids; + unsigned long shm_tot; + unsigned long shm_rss; + unsigned long shm_swp; + unsigned long swap_attempts; + unsigned long swap_successes; +}; + +#ifdef __cplusplus +} +#endif + +#endif /* _ABIBITS_SHM_H */ diff --git a/lib/mlibc/abis/ironclad/signal.h b/lib/mlibc/abis/ironclad/signal.h new file mode 100644 index 0000000..2d20315 --- /dev/null +++ b/lib/mlibc/abis/ironclad/signal.h @@ -0,0 +1,192 @@ +#ifndef _ABIBITS_SIGNAL_H +#define _ABIBITS_SIGNAL_H + +#include +#include +#include + +union sigval { + int sival_int; + void *sival_ptr; +}; + +typedef struct { + int si_signo; + int si_code; + int si_errno; + pid_t si_pid; + uid_t si_uid; + void *si_addr; + int si_status; + union sigval si_value; +} siginfo_t; + +#ifdef __cplusplus +extern "C" { +#endif + +// Argument for signal() +typedef void (*__sighandler) (int); + +#define SIG_ERR ((__sighandler)(void *)(-1)) +#define SIG_DFL ((__sighandler)(void *)(-2)) +#define SIG_IGN ((__sighandler)(void *)(-3)) + +#define SIGHUP 1 +#define SIGINT 2 +#define SIGQUIT 3 +#define SIGILL 4 +#define SIGTRAP 5 +#define SIGABRT 6 +#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 SIGIO +#define SIGPWR 30 +#define SIGSYS 31 +#define SIGRTMIN 32 +#define SIGRTMAX 33 +#define SIGCANCEL SIGSYS + +// siginfo->si_info constants +// SIGBUS +#define BUS_ADRALN 1 +#define BUS_ADRERR 2 +#define BUS_OBJERR 3 + +// SIGILL +#define ILL_ILLOPC 1 +#define ILL_ILLOPN 2 +#define ILL_ILLADR 3 +#define ILL_ILLTRP 4 +#define ILL_PRVOPC 5 +#define ILL_PRVREG 6 +#define ILL_COPROC 7 +#define ILL_BADSTK 8 +#define ILL_BADIADDR 9 + +// SIGSEGV +#define SEGV_MAPERR 1 +#define SEGV_ACCERR 2 + +// TODO: replace this by uint64_t +typedef long sigset_t; + +#define SIGUNUSED SIGSYS + +// constants for sigprocmask() +#define SIG_BLOCK 1 +#define SIG_UNBLOCK 2 +#define SIG_SETMASK 3 + +#define SA_NOCLDSTOP (1 << 0) +#define SA_ONSTACK (1 << 1) +#define SA_RESETHAND (1 << 2) +#define SA_RESTART (1 << 3) +#define SA_SIGINFO (1 << 4) +#define SA_NOCLDWAIT (1 << 5) +#define SA_NODEFER (1 << 6) + +#define MINSIGSTKSZ 2048 +#define SIGSTKSZ 8192 +#define SS_ONSTACK 1 +#define SS_DISABLE 2 + +typedef struct __stack { + void *ss_sp; + size_t ss_size; + int ss_flags; +} stack_t; + +// constants for sigev_notify of struct sigevent +#define SIGEV_NONE 1 +#define SIGEV_SIGNAL 2 +#define SIGEV_THREAD 3 + +#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 + +#define NSIG 65 +#define _NSIG NSIG + +#define CLD_EXITED 1 +#define CLD_KILLED 2 +#define CLD_DUMPED 3 +#define CLD_TRAPPED 4 +#define CLD_STOPPED 5 +#define CLD_CONTINUED 6 + +struct sigevent { + int sigev_notify; + int sigev_signo; + union sigval sigev_value; + void (*sigev_notify_function)(union sigval); + // MISSING: sigev_notify_attributes +}; + +struct sigaction { + union { + void (*sa_handler)(int); + void (*sa_sigaction)(int, siginfo_t *, void *); + }; + sigset_t sa_mask; + int sa_flags; +}; + +#if defined(__x86_64__) || defined(__aarch64__) +// TODO: This is wrong for AArch64. + +typedef struct { + unsigned long oldmask; + unsigned long gregs[16]; + unsigned long pc, pr, sr; + unsigned long gbr, mach, macl; + unsigned long fpregs[16]; + unsigned long xfpregs[16]; + unsigned int fpscr, fpul, ownedfp; +} mcontext_t; + +typedef struct __ucontext { + unsigned long uc_flags; + struct __ucontext *uc_link; + stack_t uc_stack; + mcontext_t uc_mcontext; + sigset_t uc_sigmask; +} ucontext_t; + +#else +#error "Missing architecture specific code." +#endif + +#ifdef __cplusplus +} +#endif + +#endif // _ABIBITS_SIGNAL_H diff --git a/lib/mlibc/abis/ironclad/socket.h b/lib/mlibc/abis/ironclad/socket.h new file mode 100644 index 0000000..48b8178 --- /dev/null +++ b/lib/mlibc/abis/ironclad/socket.h @@ -0,0 +1,165 @@ +#ifndef _ABIBITS_SOCKET_H +#define _ABIBITS_SOCKET_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef unsigned int sa_family_t; + +struct msghdr { + void *msg_name; + socklen_t msg_namelen; + struct iovec *msg_iov; + int msg_iovlen; + void *msg_control; + socklen_t msg_controllen; + int msg_flags; +}; + +struct sockaddr_storage { + sa_family_t ss_family; + char __padding[128 - sizeof(sa_family_t)]; +}; + +struct mmsghdr { + struct msghdr msg_hdr; + unsigned int msg_len; +}; + +struct cmsghdr { + socklen_t cmsg_len; + int cmsg_level; + int cmsg_type; +}; + +#ifdef __cplusplus +} +#endif + +#define SCM_RIGHTS 1 +#define SCM_TIMESTAMP SO_TIMESTAMP +#define SCM_TIMESTAMPNS SO_TIMESTAMPNS + +//MISSING: CMSG_DATA, CMSG_NXTHDR, CMSG_FIRSTHDR + +#define SCM_CREDENTIALS 0x02 + +#define SOCK_DGRAM 1 +#define SOCK_RAW 2 +#define SOCK_SEQPACKET 3 +#define SOCK_STREAM 4 +#define SOCK_DCCP 5 +#define SOCK_NONBLOCK 0x10000 +#define SOCK_CLOEXEC 0x20000 +#define SOCK_RDM 0x40000 + +#define SOL_SOCKET 1 +#define SOL_IPV6 41 +#define SOL_PACKET 263 +#define SOL_NETLINK 270 + +#define SO_ACCEPTCONN 1 +#define SO_BROADCAST 2 +#define SO_DEBUG 3 +#define SO_DONTROUTE 4 +#define SO_ERROR 5 +#define SO_KEEPALIVE 6 +#define SO_LINGER 7 +#define SO_OOBINLINE 8 +#define SO_RCVBUF 9 +#define SO_RCVLOWAT 10 +#define SO_RCVTIMEO 11 +#define SO_REUSEADDR 12 +#define SO_SNDBUF 13 +#define SO_SNDLOWAT 14 +#define SO_SNDTIMEO 15 +#define SO_TYPE 16 +#define SO_SNDBUFFORCE 17 +#define SO_PEERCRED 18 +#define SO_ATTACH_FILTER 19 +#define SO_PASSCRED 20 +#define SO_RCVBUFFORCE 21 +#define SO_DETACH_FILTER 22 +#define SO_PROTOCOL 23 +#define SO_REUSEPORT 24 +#define SO_TIMESTAMP 25 +#define SO_PEERSEC 26 +#define SO_BINDTODEVICE 27 +#define SO_DOMAIN 28 +#define SO_PASSSEC 29 +#define SO_TIMESTAMPNS 30 +#define SO_PRIORITY 31 +#define SO_MARK 32 + +#define SOMAXCONN 1 + +#define MSG_CTRUNC 0x1 +#define MSG_DONTROUTE 0x2 +#define MSG_EOR 0x4 +#define MSG_OOB 0x8 +#define MSG_NOSIGNAL 0x10 +#define MSG_PEEK 0x20 +#define MSG_TRUNC 0x40 +#define MSG_WAITALL 0x80 +#define MSG_FIN 0x200 +#define MSG_CONFIRM 0x800 + +// Linux extensions. +#define MSG_DONTWAIT 0x1000 +#define MSG_CMSG_CLOEXEC 0x2000 +#define MSG_MORE 0x4000 +#define MSG_FASTOPEN 0x20000000 + +// GNU (?) extension: Protocol family constants. + +#define PF_INET 1 +#define PF_INET6 2 +#define PF_UNIX 3 +#define PF_LOCAL 3 +#define PF_UNSPEC 4 +#define PF_NETLINK 5 +#define PF_BRIDGE 6 +#define PF_APPLETALK 7 +#define PF_BLUETOOTH 8 +#define PF_DECnet 9 +#define PF_IPX 10 +#define PF_ISDN 11 +#define PF_SNA 12 +#define PF_PACKET 13 +#define PF_AX25 14 +#define PF_NETROM 15 +#define PF_ROSE 16 +#define PF_TIPC 30 +#define PF_ALG 38 +#define PF_MAX 46 + +#define AF_INET PF_INET +#define AF_INET6 PF_INET6 +#define AF_UNIX PF_UNIX +#define AF_LOCAL PF_LOCAL +#define AF_UNSPEC PF_UNSPEC +#define AF_NETLINK PF_NETLINK +#define AF_BRIDGE PF_BRIDGE +#define AF_APPLETALK PF_APPLETALK +#define AF_BLUETOOTH PF_BLUETOOTH +#define AF_DECnet PF_DECnet +#define AF_IPX PF_IPX +#define AF_ISDN PF_ISDN +#define AF_SNA PF_SNA +#define AF_PACKET PF_PACKET +#define AF_PACKET PF_PACKET +#define AF_AX25 PF_AX25 +#define AF_NETROM PF_NETROM +#define AF_ROSE PF_ROSE +#define AF_TIPC PF_TIPC +#define AF_ALG PF_ALG +#define AF_MAX PF_MAX + +#define SHUT_RD 1 +#define SHUT_RDWR 2 +#define SHUT_WR 3 +#endif diff --git a/lib/mlibc/abis/ironclad/socklen_t.h b/lib/mlibc/abis/ironclad/socklen_t.h new file mode 100644 index 0000000..190e5f9 --- /dev/null +++ b/lib/mlibc/abis/ironclad/socklen_t.h @@ -0,0 +1,6 @@ +#ifndef _ABIBITS_SOCKLEN_T_H +#define _ABIBITS_SOCKLEN_T_H + +typedef unsigned socklen_t; + +#endif /* _ABIBITS_SOCKLEN_T_H */ diff --git a/lib/mlibc/abis/ironclad/stat.h b/lib/mlibc/abis/ironclad/stat.h new file mode 100644 index 0000000..3f55970 --- /dev/null +++ b/lib/mlibc/abis/ironclad/stat.h @@ -0,0 +1,69 @@ +#ifndef _ABIBITS_STAT_H +#define _ABIBITS_STAT_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define S_IFMT 0x0F000 +#define S_IFBLK 0x06000 +#define S_IFCHR 0x02000 +#define S_IFIFO 0x01000 +#define S_IFREG 0x08000 +#define S_IFDIR 0x04000 +#define S_IFLNK 0x0A000 +#define S_IFSOCK 0x0C000 + +#define S_IRWXU 0700 +#define S_IRUSR 0400 +#define S_IWUSR 0200 +#define S_IXUSR 0100 +#define S_IRWXG 070 +#define S_IRGRP 040 +#define S_IWGRP 020 +#define S_IXGRP 010 +#define S_IRWXO 07 +#define S_IROTH 04 +#define S_IWOTH 02 +#define S_IXOTH 01 +#define S_ISUID 04000 +#define S_ISGID 02000 +#define S_ISVTX 01000 + +#define S_IREAD S_IRUSR +#define S_IWRITE S_IWUSR +#define S_IEXEC S_IXUSR + +#ifdef __cplusplus +extern "C" { +#endif + +struct stat { + dev_t st_dev; + ino_t st_ino; + mode_t st_mode; + nlink_t st_nlink; + uid_t st_uid; + gid_t st_gid; + dev_t st_rdev; + off_t st_size; + struct timespec st_atim; + struct timespec st_mtim; + struct timespec st_ctim; + blksize_t st_blksize; + blkcnt_t st_blocks; +}; + +#ifdef __cplusplus +} +#endif + +#endif // _ABIBITS_STAT_H diff --git a/lib/mlibc/abis/ironclad/statfs.h b/lib/mlibc/abis/ironclad/statfs.h new file mode 100644 index 0000000..60c977f --- /dev/null +++ b/lib/mlibc/abis/ironclad/statfs.h @@ -0,0 +1,28 @@ +#ifndef _ABIBITS_STATFS_H +#define _ABIBITS_STATFS_H + +#include +#include + +typedef struct __mlibc_fsid { + int __val[2]; +} fsid_t; + +struct statfs { + unsigned long f_type; + unsigned long f_bsize; + fsblkcnt_t f_blocks; + fsblkcnt_t f_bfree; + fsblkcnt_t f_bavail; + + fsfilcnt_t f_files; + fsfilcnt_t f_ffree; + fsid_t f_fsid; + unsigned long f_namelen; + unsigned long f_frsize; + unsigned long f_flags; + unsigned long __f_spare[4]; +}; + +#endif /* _ABIBITS_STATFS_H */ + diff --git a/lib/mlibc/abis/ironclad/statvfs.h b/lib/mlibc/abis/ironclad/statvfs.h new file mode 100644 index 0000000..d4fc416 --- /dev/null +++ b/lib/mlibc/abis/ironclad/statvfs.h @@ -0,0 +1,30 @@ +#ifndef _ABIBITS_STATVFS_H +#define _ABIBITS_STATVFS_H + +#include +#include + +#define ST_RDONLY 1 +#define ST_NOSUID 2 +#define ST_MANDLOCK 64 + +// On Linux, this struct is not directly used by the kernel. +struct statvfs { + unsigned long f_bsize; + unsigned long f_frsize; + fsblkcnt_t f_blocks; + fsblkcnt_t f_bfree; + fsblkcnt_t f_bavail; + + fsfilcnt_t f_files; + fsfilcnt_t f_ffree; + fsfilcnt_t f_favail; + + unsigned long f_fsid; + unsigned long f_flag; + unsigned long f_namemax; + char f_basetype[80]; +}; + +#endif /* _ABIBITS_STATVFS_H */ + diff --git a/lib/mlibc/abis/ironclad/suseconds_t.h b/lib/mlibc/abis/ironclad/suseconds_t.h new file mode 100644 index 0000000..723ddfa --- /dev/null +++ b/lib/mlibc/abis/ironclad/suseconds_t.h @@ -0,0 +1,8 @@ +#ifndef _ABIBITS_SUSECONDS_T_H +#define _ABIBITS_SUSECONDS_T_H + +#include + +typedef __mlibc_int64 suseconds_t; + +#endif /* _ABIBITS_SUSECONDS_T_H */ diff --git a/lib/mlibc/abis/ironclad/termios.h b/lib/mlibc/abis/ironclad/termios.h new file mode 100644 index 0000000..4dd5987 --- /dev/null +++ b/lib/mlibc/abis/ironclad/termios.h @@ -0,0 +1,116 @@ +#ifndef _ABIBITS_TERMIOS_H +#define _ABIBITS_TERMIOS_H + +typedef unsigned int cc_t; +typedef unsigned int speed_t; +typedef unsigned int tcflag_t; + +// indices for the c_cc array in struct termios +#define NCCS 11 +#define VEOF 0 +#define VEOL 1 +#define VERASE 2 +#define VINTR 3 +#define VKILL 4 +#define VMIN 5 +#define VQUIT 6 +#define VSTART 7 +#define VSTOP 8 +#define VSUSP 9 +#define VTIME 10 + +// bitwise flags for c_iflag in struct termios +#define BRKINT 0x0001 +#define ICRNL 0x0002 +#define IGNBRK 0x0004 +#define IGNCR 0x0008 +#define IGNPAR 0x0010 +#define INLCR 0x0020 +#define INPCK 0x0040 +#define ISTRIP 0x0080 +#define IXANY 0x0100 +#define IXOFF 0x0200 +#define IXON 0x0400 +#define PARMRK 0x0800 +#define ECHOCTL 0001000 +#define IMAXBEL 0020000 +#define ECHOKE 0004000 + +// bitwise flags for c_oflag in struct termios +#define OPOST 0x0001 +#define ONLCR 0x0002 +#define OCRNL 0x0004 +#define ONOCR 0x0008 +#define ONLRET 0x0010 +#define OFDEL 0x0020 +#define OFILL 0x0040 + +#define NLDLY 0x0080 +#define NL0 0x0000 +#define NL1 0x0080 + +#define CRDLY 0x0300 +#define CR0 0x0000 +#define CR1 0x0100 +#define CR2 0x0200 +#define CR3 0x0300 + +#define TABDLY 0x0C00 +#define TAB0 0x0000 +#define TAB1 0x0400 +#define TAB2 0x0800 +#define TAB3 0x0C00 + +#define BSDLY 0x1000 +#define BS0 0x0000 +#define BS1 0x1000 + +#define VTDLY 0x2000 +#define VT0 0x0000 +#define VT1 0x2000 + +#define FFDLY 0x4000 +#define FF0 0x0000 +#define FF1 0x4000 + +// bitwise constants for c_cflag in struct termios +#define CSIZE 0x0003 +#define CS5 0x0000 +#define CS6 0x0001 +#define CS7 0x0002 +#define CS8 0x0003 + +#define CSTOPB 0x0004 +#define CREAD 0x0008 +#define PARENB 0x0010 +#define PARODD 0x0020 +#define HUPCL 0x0040 +#define CLOCAL 0x0080 + +#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE) +#define CBAUD 0x100F +#endif + +// bitwise constants for c_lflag in struct termios +#define ECHO 0x0001 +#define ECHOE 0x0002 +#define ECHOK 0x0004 +#define ECHONL 0x0008 +#define ICANON 0x0010 +#define IEXTEN 0x0020 +#define ISIG 0x0040 +#define NOFLSH 0x0080 +#define TOSTOP 0x0100 +#define ECHOPRT 0x0200 + +struct termios { + tcflag_t c_iflag; + tcflag_t c_oflag; + tcflag_t c_cflag; + tcflag_t c_lflag; + cc_t c_cc[NCCS]; + speed_t ibaud; + speed_t obaud; +}; + +#endif diff --git a/lib/mlibc/abis/ironclad/time.h b/lib/mlibc/abis/ironclad/time.h new file mode 100644 index 0000000..3f49db3 --- /dev/null +++ b/lib/mlibc/abis/ironclad/time.h @@ -0,0 +1,15 @@ +#ifndef _ABIBITS_TIME_H +#define _ABIBITS_TIME_H + +#include + +struct itimerval { + struct timeval it_interval; /* Interval for periodic timer */ + struct timeval it_value; /* Time until next expiration */ +}; + +#define ITIMER_REAL 0 +#define ITIMER_VIRTUAL 1 +#define ITIMER_PROF 2 + +#endif // _ABIBITS_TIME_H diff --git a/lib/mlibc/abis/ironclad/uid_t.h b/lib/mlibc/abis/ironclad/uid_t.h new file mode 100644 index 0000000..1688d07 --- /dev/null +++ b/lib/mlibc/abis/ironclad/uid_t.h @@ -0,0 +1,6 @@ +#ifndef _ABIBITS_UID_T_H +#define _ABIBITS_UID_T_H + +typedef unsigned int uid_t; + +#endif // _ABIBITS_UID_T_H diff --git a/lib/mlibc/abis/ironclad/utsname.h b/lib/mlibc/abis/ironclad/utsname.h new file mode 100644 index 0000000..2cd2226 --- /dev/null +++ b/lib/mlibc/abis/ironclad/utsname.h @@ -0,0 +1,12 @@ +#ifndef _ABIBITS_UTSNAME_T_H +#define _ABIBITS_UTSNAME_T_H + +struct utsname { + char sysname[65]; + char nodename[65]; + char release[65]; + char version[65]; + char machine[65]; +}; + +#endif // _ABIBITS_UTSNAME_T_H diff --git a/lib/mlibc/abis/ironclad/vm-flags.h b/lib/mlibc/abis/ironclad/vm-flags.h new file mode 100644 index 0000000..a686cd3 --- /dev/null +++ b/lib/mlibc/abis/ironclad/vm-flags.h @@ -0,0 +1,46 @@ +#ifndef _ABIBITS_MMAP_FLAGS_H +#define _ABIBITS_MMAP_FLAGS_H + +#define PROT_NONE 0x00 +#define PROT_READ 0x01 +#define PROT_WRITE 0x02 +#define PROT_EXEC 0x04 + +#define MAP_FAILED ((void *)(-1)) +#define MAP_FILE 0x00 +#define MAP_PRIVATE 0x01 +#define MAP_SHARED 0x02 +#define MAP_FIXED 0x04 +#define MAP_ANON 0x08 +#define MAP_ANONYMOUS 0x08 +#define MAP_NORESERVE 0x10 +#define MAP_WC 0b10000 + +#define MS_ASYNC 0x01 +#define MS_SYNC 0x02 +#define MS_INVALIDATE 0x04 + +#define MCL_CURRENT 0x01 +#define MCL_FUTURE 0x02 + +#define POSIX_MADV_NORMAL 1 +#define POSIX_MADV_SEQUENTIAL 2 +#define POSIX_MADV_RANDOM 3 +#define POSIX_MADV_DONTNEED 4 +#define POSIX_MADV_WILLNEED 5 + +#define MADV_NORMAL 0 +#define MADV_RANDOM 1 +#define MADV_SEQUENTIAL 2 +#define MADV_WILLNEED 3 +#define MADV_DONTNEED 4 +#define MADV_FREE 8 + +// Linux extensions: +#define MREMAP_MAYMOVE 1 +#define MREMAP_FIXED 2 + +#define MFD_CLOEXEC 1U +#define MFD_ALLOW_SEALING 2U + +#endif // _ABIBITS_MMAP_FLAGS_H diff --git a/lib/mlibc/abis/ironclad/wait.h b/lib/mlibc/abis/ironclad/wait.h new file mode 100644 index 0000000..5aa6bb8 --- /dev/null +++ b/lib/mlibc/abis/ironclad/wait.h @@ -0,0 +1,25 @@ +#ifndef _ABIBITS_WAIT_H +#define _ABIBITS_WAIT_H + +#define WCONTINUED 1 +#define WNOHANG 2 +#define WUNTRACED 4 +#define WEXITED 8 +#define WNOWAIT 16 +#define WSTOPPED 32 + +#define __WALL 0x40000000 +#define __WCLONE 0x80000000 + +#define WCOREFLAG 0x80 + +#define WEXITSTATUS(x) ((x) & 0x000000FF) +#define WIFCONTINUED(x) ((x) & 0x00000100) +#define WIFEXITED(x) ((x) & 0x00000200) +#define WIFSIGNALED(x) ((x) & 0x00000400) +#define WIFSTOPPED(x) ((x) & 0x00000800) +#define WSTOPSIG(x) (((x) & 0x00FF0000) >> 16) +#define WTERMSIG(x) (((x) & 0xFF000000) >> 24) +#define WCOREDUMP(x) ((x) & WCOREFLAG) + +#endif //_ABIBITS_WAIT_H diff --git a/lib/mlibc/abis/ironclad/xattr.h b/lib/mlibc/abis/ironclad/xattr.h new file mode 100644 index 0000000..c0e7fbe --- /dev/null +++ b/lib/mlibc/abis/ironclad/xattr.h @@ -0,0 +1,21 @@ +#ifndef MLIBC_ABIS_LINUX_XATTR_H +#define MLIBC_ABIS_LINUX_XATTR_H + +/* __USE_KERNEL_XATTR_DEFS is exported when XATTR_* are emitted, and + * __UAPI_DEF_XATTR is used to determine the behaviour of the + * header (through ), if it's set + * to 1, the header exports xattr defines and __USE_KERNEL_XATTR_DEFS. + * This applies for pretty much all other defines in libc-compat.h + * AFAICT. + */ +#ifndef __USE_KERNEL_XATTR_DEFS +enum { + XATTR_CREATE = 1, +#define XATTR_CREATE XATTR_CREATE + XATTR_REPLACE = 2, +#define XATTR_REPLACE XATTR_REPLACE +}; +# define __UAPI_DEF_XATTR 0 +#endif + +#endif /* MLIBC_ABIS_LINUX_XATTR_H */ diff --git a/lib/mlibc/abis/lemon/auxv.h b/lib/mlibc/abis/lemon/auxv.h new file mode 100644 index 0000000..da7a438 --- /dev/null +++ b/lib/mlibc/abis/lemon/auxv.h @@ -0,0 +1,9 @@ +#ifndef _ABIBITS_AUXV_H +#define _ABIBITS_AUXV_H + +#define AT_EXECPATH 15 +#define AT_SECURE 23 +#define AT_RANDOM 25 +#define AT_EXECFN 31 + +#endif diff --git a/lib/mlibc/abis/linux/access.h b/lib/mlibc/abis/linux/access.h new file mode 100644 index 0000000..f76ca62 --- /dev/null +++ b/lib/mlibc/abis/linux/access.h @@ -0,0 +1,9 @@ +#ifndef _ABIBITS_ACCESS_H +#define _ABIBITS_ACCESS_H + +#define F_OK 0 +#define X_OK 1 +#define W_OK 2 +#define R_OK 4 + +#endif // _ABIBITS_ACCESS_H diff --git a/lib/mlibc/abis/linux/auxv.h b/lib/mlibc/abis/linux/auxv.h new file mode 100644 index 0000000..8eb8049 --- /dev/null +++ b/lib/mlibc/abis/linux/auxv.h @@ -0,0 +1,13 @@ +#ifndef _ABIBITS_AUXV_H +#define _ABIBITS_AUXV_H + +#define AT_PLATFORM 15 +#define AT_HWCAP 16 +#define AT_CLKTCK 17 +#define AT_FPUCW 18 +#define AT_SECURE 23 +#define AT_RANDOM 25 +#define AT_EXECFN 31 +#define AT_SYSINFO_EHDR 33 + +#endif // _ABIBITS_AUXV_H diff --git a/lib/mlibc/abis/linux/blkcnt_t.h b/lib/mlibc/abis/linux/blkcnt_t.h new file mode 100644 index 0000000..c4b4505 --- /dev/null +++ b/lib/mlibc/abis/linux/blkcnt_t.h @@ -0,0 +1,8 @@ +#ifndef _ABIBITS_BLKCNT_T_H +#define _ABIBITS_BLKCNT_T_H + +#include + +typedef __mlibc_int64 blkcnt_t; + +#endif // _ABIBITS_BLKCNT_T_H diff --git a/lib/mlibc/abis/linux/blksize_t.h b/lib/mlibc/abis/linux/blksize_t.h new file mode 100644 index 0000000..afabadb --- /dev/null +++ b/lib/mlibc/abis/linux/blksize_t.h @@ -0,0 +1,8 @@ + +#ifndef _ABIBITS_BLKSIZE_T_H +#define _ABIBITS_BLKSIZE_T_H + +typedef long blksize_t; + +#endif // _ABIBITS_BLKSIZE_T_H + diff --git a/lib/mlibc/abis/linux/clockid_t.h b/lib/mlibc/abis/linux/clockid_t.h new file mode 100644 index 0000000..8d92826 --- /dev/null +++ b/lib/mlibc/abis/linux/clockid_t.h @@ -0,0 +1,7 @@ +#ifndef _ABIBITS_CLOCKID_T_H +#define _ABIBITS_CLOCKID_T_H + +typedef int clockid_t; + +#endif /* _ABIBITS_CLOCKID_T_H */ + diff --git a/lib/mlibc/abis/linux/dev_t.h b/lib/mlibc/abis/linux/dev_t.h new file mode 100644 index 0000000..839a445 --- /dev/null +++ b/lib/mlibc/abis/linux/dev_t.h @@ -0,0 +1,10 @@ + +#ifndef _ABIBITS_DEV_T_H +#define _ABIBITS_DEV_T_H + +#include + +typedef __mlibc_uint64 dev_t; + +#endif // _ABIBITS_DEV_T_H + diff --git a/lib/mlibc/abis/linux/epoll.h b/lib/mlibc/abis/linux/epoll.h new file mode 100644 index 0000000..0b984b6 --- /dev/null +++ b/lib/mlibc/abis/linux/epoll.h @@ -0,0 +1,6 @@ +#ifndef _ABIBITS_EPOLL_H +#define _ABIBITS_EPOLL_H + +#define EPOLL_CLOEXEC 02000000 // Same as __MLIBC_O_CLOEXEC + +#endif // _ABIBITS_EPOLL_H diff --git a/lib/mlibc/abis/linux/errno.h b/lib/mlibc/abis/linux/errno.h new file mode 100644 index 0000000..b2680e3 --- /dev/null +++ b/lib/mlibc/abis/linux/errno.h @@ -0,0 +1,143 @@ +#ifndef _ABIBITS_ERRNO_H +#define _ABIBITS_ERRNO_H + +#define EPERM 1 +#define ENOENT 2 +#define ESRCH 3 +#define EINTR 4 +#define EIO 5 +#define ENXIO 6 +#define E2BIG 7 +#define ENOEXEC 8 +#define EBADF 9 +#define ECHILD 10 +#define EAGAIN 11 +#define ENOMEM 12 +#define EACCES 13 +#define EFAULT 14 +#define ENOTBLK 15 +#define EBUSY 16 +#define EEXIST 17 +#define EXDEV 18 +#define ENODEV 19 +#define ENOTDIR 20 +#define EISDIR 21 +#define EINVAL 22 +#define ENFILE 23 +#define EMFILE 24 +#define ENOTTY 25 +#define ETXTBSY 26 +#define EFBIG 27 +#define ENOSPC 28 +#define ESPIPE 29 +#define EROFS 30 +#define EMLINK 31 +#define EPIPE 32 +#define EDOM 33 +#define ERANGE 34 +#define EDEADLK 35 +#define ENAMETOOLONG 36 +#define ENOLCK 37 +#define ENOSYS 38 +#define ENOTEMPTY 39 +#define ELOOP 40 +#define EWOULDBLOCK EAGAIN +#define ENOMSG 42 +#define EIDRM 43 +#define ECHRNG 44 +#define EL2NSYNC 45 +#define EL3HLT 46 +#define EL3RST 47 +#define ELNRNG 48 +#define EUNATCH 49 +#define ENOCSI 50 +#define EL2HLT 51 +#define EBADE 52 +#define EBADR 53 +#define EXFULL 54 +#define ENOANO 55 +#define EBADRQC 56 +#define EBADSLT 57 +#define EDEADLOCK EDEADLK +#define EBFONT 59 +#define ENOSTR 60 +#define ENODATA 61 +#define ETIME 62 +#define ENOSR 63 +#define ENONET 64 +#define ENOPKG 65 +#define EREMOTE 66 +#define ENOLINK 67 +#define EADV 68 +#define ESRMNT 69 +#define ECOMM 70 +#define EPROTO 71 +#define EMULTIHOP 72 +#define EDOTDOT 73 +#define EBADMSG 74 +#define EOVERFLOW 75 +#define ENOTUNIQ 76 +#define EBADFD 77 +#define EREMCHG 78 +#define ELIBACC 79 +#define ELIBBAD 80 +#define ELIBSCN 81 +#define ELIBMAX 82 +#define ELIBEXEC 83 +#define EILSEQ 84 +#define ERESTART 85 +#define ESTRPIPE 86 +#define EUSERS 87 +#define ENOTSOCK 88 +#define EDESTADDRREQ 89 +#define EMSGSIZE 90 +#define EPROTOTYPE 91 +#define ENOPROTOOPT 92 +#define EPROTONOSUPPORT 93 +#define ESOCKTNOSUPPORT 94 +#define EOPNOTSUPP 95 +#define ENOTSUP EOPNOTSUPP +#define EPFNOSUPPORT 96 +#define EAFNOSUPPORT 97 +#define EADDRINUSE 98 +#define EADDRNOTAVAIL 99 +#define ENETDOWN 100 +#define ENETUNREACH 101 +#define ENETRESET 102 +#define ECONNABORTED 103 +#define ECONNRESET 104 +#define ENOBUFS 105 +#define EISCONN 106 +#define ENOTCONN 107 +#define ESHUTDOWN 108 +#define ETOOMANYREFS 109 +#define ETIMEDOUT 110 +#define ECONNREFUSED 111 +#define EHOSTDOWN 112 +#define EHOSTUNREACH 113 +#define EALREADY 114 +#define EINPROGRESS 115 +#define ESTALE 116 +#define EUCLEAN 117 +#define ENOTNAM 118 +#define ENAVAIL 119 +#define EISNAM 120 +#define EREMOTEIO 121 +#define EDQUOT 122 +#define ENOMEDIUM 123 +#define EMEDIUMTYPE 124 +#define ECANCELED 125 +#define ENOKEY 126 +#define EKEYEXPIRED 127 +#define EKEYREVOKED 128 +#define EKEYREJECTED 129 +#define EOWNERDEAD 130 +#define ENOTRECOVERABLE 131 +#define ERFKILL 132 +#define EHWPOISON 133 + + +// This is mlibc-specific. +#define EIEIO 4095 + +#endif // _ABIBITS_ERRNO_H diff --git a/lib/mlibc/abis/linux/fcntl.h b/lib/mlibc/abis/linux/fcntl.h new file mode 100644 index 0000000..35be979 --- /dev/null +++ b/lib/mlibc/abis/linux/fcntl.h @@ -0,0 +1,89 @@ +#ifndef _ABIBITS_FCNTL_H +#define _ABIBITS_FCNTL_H + +#include + +#define O_PATH 010000000 + +#define O_ACCMODE (03 | O_PATH) +#define O_RDONLY 00 +#define O_WRONLY 01 +#define O_RDWR 02 + +#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_ASYNC 020000 +#define O_DIRECT 040000 +#define O_DIRECTORY 0200000 +#define O_NOFOLLOW 0400000 +#define O_CLOEXEC 02000000 +#define O_SYNC 04010000 +#define O_RSYNC 04010000 +#define O_LARGEFILE 0100000 +#define O_NOATIME 01000000 +#define O_TMPFILE 020000000 + +#define O_EXEC O_PATH +#define O_SEARCH O_PATH + +#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 + +#define F_GETLK 5 +#define F_SETLK 6 +#define F_SETLKW 7 + +#define F_SETOWN_EX 15 +#define F_GETOWN_EX 16 + +#define F_GETOWNER_UIDS 17 + +#define F_DUPFD_CLOEXEC 1030 +#define F_ADD_SEALS 1033 +#define F_GET_SEALS 1034 + +#define F_SEAL_SEAL 0x0001 +#define F_SEAL_SHRINK 0x0002 +#define F_SEAL_GROW 0x0004 +#define F_SEAL_WRITE 0x0008 + +#define F_RDLCK 0 +#define F_WRLCK 1 +#define F_UNLCK 2 + +#define FD_CLOEXEC 1 + +#define AT_FDCWD -100 +#define AT_SYMLINK_NOFOLLOW 0x100 +#define AT_REMOVEDIR 0x200 +#define AT_SYMLINK_FOLLOW 0x400 +#define AT_EACCESS 0x200 +#define AT_EMPTY_PATH 0x1000 + + +struct f_owner_ex { + int type; + pid_t pid; +}; + +#define POSIX_FADV_NORMAL 0 +#define POSIX_FADV_RANDOM 1 +#define POSIX_FADV_SEQUENTIAL 2 +#define POSIX_FADV_WILLNEED 3 +#define POSIX_FADV_DONTNEED 4 +#define POSIX_FADV_NOREUSE 5 + +#endif // _ABIBITS_FCNTL_H diff --git a/lib/mlibc/abis/linux/fsblkcnt_t.h b/lib/mlibc/abis/linux/fsblkcnt_t.h new file mode 100644 index 0000000..0d74456 --- /dev/null +++ b/lib/mlibc/abis/linux/fsblkcnt_t.h @@ -0,0 +1,8 @@ +#ifndef _ABIBITS_FSBLKCNT_T_H +#define _ABIBITS_FSBLKCNT_T_H + +#include + +typedef __mlibc_uint64 fsblkcnt_t; + +#endif /* _ABIBITS_FSBLKCNT_T_H */ diff --git a/lib/mlibc/abis/linux/fsfilcnt_t.h b/lib/mlibc/abis/linux/fsfilcnt_t.h new file mode 100644 index 0000000..1abda9a --- /dev/null +++ b/lib/mlibc/abis/linux/fsfilcnt_t.h @@ -0,0 +1,8 @@ +#ifndef _ABIBITS_FSFILCNT_T_H +#define _ABIBITS_FSFILCNT_T_H + +#include + +typedef __mlibc_uint64 fsfilcnt_t; + +#endif /* _ABIBITS_FSFILCNT_T_H */ diff --git a/lib/mlibc/abis/linux/gid_t.h b/lib/mlibc/abis/linux/gid_t.h new file mode 100644 index 0000000..65afa40 --- /dev/null +++ b/lib/mlibc/abis/linux/gid_t.h @@ -0,0 +1,8 @@ + +#ifndef _ABIBITS_GID_T_H +#define _ABIBITS_GID_T_H + +typedef unsigned int gid_t; + +#endif // _ABIBITS_GID_T_H + diff --git a/lib/mlibc/abis/linux/in.h b/lib/mlibc/abis/linux/in.h new file mode 100644 index 0000000..eb7be7b --- /dev/null +++ b/lib/mlibc/abis/linux/in.h @@ -0,0 +1,217 @@ +#ifndef _ABIBITS_IN_H +#define _ABIBITS_IN_H + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +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; +}; + +#define MCAST_INCLUDE 1 + +struct ip_mreq { + struct in_addr imr_multiaddr; + struct in_addr imr_interface; +}; + +struct ip_mreq_source { + struct in_addr imr_multiaddr; + struct in_addr imr_interface; + struct in_addr imr_sourceaddr; +}; + +struct ip_mreqn { + struct in_addr imr_multiaddr; + struct in_addr imr_address; + int imr_ifindex; +}; + +struct ipv6_mreq { + struct in6_addr ipv6mr_multiaddr; + unsigned ipv6mr_interface; +}; + +struct in_pktinfo { + unsigned int ipi_ifindex; + struct in_addr ipi_spec_dst; + struct in_addr ipi_addr; +}; + +struct in6_pktinfo { + struct in6_addr ipi6_addr; + uint32_t ipi6_ifindex; +}; + +struct group_req { + uint32_t gr_interface; + struct sockaddr_storage gr_group; +}; + +struct group_source_req { + uint32_t gsr_interface; + struct sockaddr_storage gsr_group; + struct sockaddr_storage gsr_source; +}; + +#ifdef __cplusplus +} +#endif + +#define INADDR_ANY ((in_addr_t) 0x00000000) +#define INADDR_BROADCAST ((in_addr_t) 0xffffffff) +#define INADDR_NONE ((in_addr_t) 0xffffffff) +#define INADDR_LOOPBACK ((in_addr_t) 0x7f000001) + +#define INADDR_UNSPEC_GROUP ((in_addr_t) 0xe0000000) +#define INADDR_ALLHOSTS_GROUP ((in_addr_t) 0xe0000001) +#define INADDR_ALLRTRS_GROUP ((in_addr_t) 0xe0000002) +#define INADDR_ALLSNOOPERS_GROUP ((in_addr_t) 0xe000006a) +#define INADDR_MAX_LOCAL_GROUP ((in_addr_t) 0xe00000ff) + +#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 } } } + +#define INET_ADDRSTRLEN 16 +#define INET6_ADDRSTRLEN 46 + +#define IPPORT_RESERVED 1024 + +#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_RAW 255 +#define IPPROTO_MAX 256 + +#define IP_TOS 1 +#define IP_TTL 2 +#define IP_HDRINCL 3 +#define IP_OPTIONS 4 +#define IP_RECVOPTS 6 +#define IP_PKTINFO 8 +#define IP_PKTOPTIONS 9 +#define IP_MTU_DISCOVER 10 +#define IP_RECVERR 11 +#define IP_RECVTTL 12 +#define IP_MTU 14 +#define IP_MULTICAST_IF 32 +#define IP_MULTICAST_TTL 33 +#define IP_MULTICAST_LOOP 34 +#define IP_ADD_MEMBERSHIP 35 +#define IP_DROP_MEMBERSHIP 36 +#define IP_UNBLOCK_SOURCE 37 +#define IP_BLOCK_SOURCE 38 +#define IP_ADD_SOURCE_MEMBERSHIP 39 +#define IP_DROP_SOURCE_MEMBERSHIP 40 +#define IP_UNICAST_IF 50 + +#define IPV6_2292PKTOPTIONS 6 +#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_MTU 24 +#define IPV6_RECVERR 25 +#define IPV6_V6ONLY 26 +#define IPV6_RECVPKTINFO 49 +#define IPV6_PKTINFO 50 +#define IPV6_RECVHOPLIMIT 51 +#define IPV6_HOPLIMIT 52 + +#define IPV6_RECVTCLASS 66 +#define IPV6_TCLASS 67 + +#define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP +#define IPV6_DROP_MEMBERSHIP IPV6_LEAVE_GROUP + +#define IP_PMTUDISC_DONT 0 +#define IP_PMTUDISC_WANT 1 +#define IP_PMTUDISC_DO 2 +#define IP_PMTUDISC_PROBE 3 +#define IP_PMTUDISC_INTERFACE 4 +#define IP_PMTUDISC_OMIT 5 + +#define MCAST_BLOCK_SOURCE 43 +#define MCAST_UNBLOCK_SOURCE 44 +#define MCAST_JOIN_SOURCE_GROUP 46 +#define MCAST_LEAVE_SOURCE_GROUP 47 + +/* These defines are needed for compatibility with Linux kernel headers. */ +#define __UAPI_DEF_IN_ADDR 0 +#define __UAPI_DEF_IN_IPPROTO 0 +#define __UAPI_DEF_IN_PKTINFO 0 +#define __UAPI_DEF_IP_MREQ 0 +#define __UAPI_DEF_SOCKADDR_IN 0 +#define __UAPI_DEF_IN_CLASS 0 +#define __UAPI_DEF_IN6_ADDR 0 +#define __UAPI_DEF_IN6_ADDR_ALT 0 +#define __UAPI_DEF_SOCKADDR_IN6 0 +#define __UAPI_DEF_IPV6_MREQ 0 +#define __UAPI_DEF_IPPROTO_V6 0 +#define __UAPI_DEF_IPV6_OPTIONS 0 +#define __UAPI_DEF_IN6_PKTINFO 0 +#define __UAPI_DEF_IP6_MTUINFO 0 + +#endif // _ABITBITS_IN_H diff --git a/lib/mlibc/abis/linux/ino_t.h b/lib/mlibc/abis/linux/ino_t.h new file mode 100644 index 0000000..ba076f4 --- /dev/null +++ b/lib/mlibc/abis/linux/ino_t.h @@ -0,0 +1,10 @@ + +#ifndef _ABIBITS_INO_T_H +#define _ABIBITS_INO_T_H + +#include + +typedef __mlibc_uint64 ino_t; + +#endif // _ABIBITS_INO_T_H + diff --git a/lib/mlibc/abis/linux/inotify.h b/lib/mlibc/abis/linux/inotify.h new file mode 100644 index 0000000..4a0bd4c --- /dev/null +++ b/lib/mlibc/abis/linux/inotify.h @@ -0,0 +1,9 @@ +#ifndef _ABIBITS_INOTIFY_H +#define _ABIBITS_INOTIFY_H + +#include + +#define IN_CLOEXEC O_CLOEXEC +#define IN_NONBLOCK O_NONBLOCK + +#endif // _ABIBITS_INOTIFY_H diff --git a/lib/mlibc/abis/linux/ioctls.h b/lib/mlibc/abis/linux/ioctls.h new file mode 100644 index 0000000..3a957bf --- /dev/null +++ b/lib/mlibc/abis/linux/ioctls.h @@ -0,0 +1,15 @@ +#ifndef _ABIBITS_IOCTLS_H +#define _ABIBITS_IOCTLS_H + +#define SIOCPROTOPRIVATE 0x89E0 +#define SIOCGIFNAME 0x8910 +#define SIOCGIFCONF 0x8912 +#define SIOCGIFFLAGS 0x8913 +#define SIOCSIFFLAGS 0x8914 +#define SIOCGIFINDEX 0x8933 +#define SIOCATMARK 0x8905 +#define SIOCGIFHWADDR 0x8927 +#define SIOCGIFBRDADDR 0x8919 +#define SIOCGIFNETMASK 0x891B + +#endif /* _ABIBITS_IOCTLS_H */ diff --git a/lib/mlibc/abis/linux/limits.h b/lib/mlibc/abis/linux/limits.h new file mode 100644 index 0000000..091b14b --- /dev/null +++ b/lib/mlibc/abis/linux/limits.h @@ -0,0 +1,9 @@ +#ifndef _ABIBITS_LIMITS_H +#define _ABIBITS_LIMITS_H + +#define IOV_MAX 1024 +#define LOGIN_NAME_MAX 256 +#define NAME_MAX 255 +#define OPEN_MAX 256 + +#endif //_ABIBITS_LIMITS_H diff --git a/lib/mlibc/abis/linux/mode_t.h b/lib/mlibc/abis/linux/mode_t.h new file mode 100644 index 0000000..8374c12 --- /dev/null +++ b/lib/mlibc/abis/linux/mode_t.h @@ -0,0 +1,8 @@ + +#ifndef _ABIBITS_MODE_T_H +#define _ABIBITS_MODE_T_H + +typedef unsigned int mode_t; + +#endif // _ABIBITS_MODE_T_H + diff --git a/lib/mlibc/abis/linux/mqueue.h b/lib/mlibc/abis/linux/mqueue.h new file mode 100644 index 0000000..1e2d3eb --- /dev/null +++ b/lib/mlibc/abis/linux/mqueue.h @@ -0,0 +1,21 @@ +#ifndef _ABIBITS_MQUEUE_H +#define _ABIBITS_MQUEUE_H + +#ifdef __cplusplus +extern "C" { +#endif + +struct mq_attr { + long mq_flags; + long mq_maxmsg; + long mq_msgsize; + long mq_curmsgs; + long __pad[4]; +}; + +#ifdef __cplusplus +} +#endif + +#endif /* _ABIBITS_MQUEUE_H */ + diff --git a/lib/mlibc/abis/linux/msg.h b/lib/mlibc/abis/linux/msg.h new file mode 100644 index 0000000..5e890c0 --- /dev/null +++ b/lib/mlibc/abis/linux/msg.h @@ -0,0 +1,39 @@ +#ifndef _ABIBITS_MSG_H +#define _ABIBITS_MSG_H + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(__i386__) +typedef __mlibc_uint64 msglen_t; +typedef __mlibc_uint64 msgqnum_t; +#else +typedef unsigned long msglen_t; +typedef unsigned long msgqnum_t; +#endif + +struct msqid_ds { + struct ipc_perm msg_perm; + time_t msg_stime; + time_t msg_rtime; + time_t msg_ctime; + unsigned long msg_cbytes; + msgqnum_t msg_qnum; + msglen_t msg_qbytes; + pid_t msg_lspid; + pid_t msg_lrpid; + unsigned long __unused[2]; +}; + +#ifdef __cplusplus +} +#endif + +#endif /* _ABIBITS_MSG_H */ + diff --git a/lib/mlibc/abis/linux/nlink_t.h b/lib/mlibc/abis/linux/nlink_t.h new file mode 100644 index 0000000..e0d9322 --- /dev/null +++ b/lib/mlibc/abis/linux/nlink_t.h @@ -0,0 +1,8 @@ + +#ifndef _ABIBITS_NLINK_T_H +#define _ABIBITS_NLINK_T_H + +typedef unsigned long nlink_t; + +#endif // _ABIBITS_NLINK_T_H + diff --git a/lib/mlibc/abis/linux/packet.h b/lib/mlibc/abis/linux/packet.h new file mode 100644 index 0000000..ee1a424 --- /dev/null +++ b/lib/mlibc/abis/linux/packet.h @@ -0,0 +1,6 @@ +#ifndef _ABIBITS_PACKET_H +#define _ABIBITS_PACKET_H + +#define PACKET_HOST 0 + +#endif // _ABIBITS_PACKET_H diff --git a/lib/mlibc/abis/linux/pid_t.h b/lib/mlibc/abis/linux/pid_t.h new file mode 100644 index 0000000..323168e --- /dev/null +++ b/lib/mlibc/abis/linux/pid_t.h @@ -0,0 +1,8 @@ + +#ifndef _ABIBITS_PID_T_H +#define _ABIBITS_PID_T_H + +typedef int pid_t; + +#endif // _ABIBITS_PID_T_H + diff --git a/lib/mlibc/abis/linux/poll.h b/lib/mlibc/abis/linux/poll.h new file mode 100644 index 0000000..1585b46 --- /dev/null +++ b/lib/mlibc/abis/linux/poll.h @@ -0,0 +1,16 @@ +#ifndef _ABIBITS_POLL_H +#define _ABIBITS_POLL_H + +#define POLLIN 0x0001 +#define POLLPRI 0x0002 +#define POLLOUT 0x0004 +#define POLLERR 0x0008 +#define POLLHUP 0x0010 +#define POLLNVAL 0x0020 +#define POLLRDNORM 0x0040 +#define POLLRDBAND 0x0080 +#define POLLWRNORM 0x0100 +#define POLLWRBAND 0x0200 +#define POLLRDHUP 0x2000 + +#endif // _ABIBITS_POLL_H diff --git a/lib/mlibc/abis/linux/ptrace.h b/lib/mlibc/abis/linux/ptrace.h new file mode 100644 index 0000000..3d73aa1 --- /dev/null +++ b/lib/mlibc/abis/linux/ptrace.h @@ -0,0 +1,59 @@ +#ifndef _ABIBITS_PTRACE_H +#define _ABIBITS_PTRACE_H + +#define PTRACE_PEEKTEXT 1 +#define PTRACE_PEEKDATA 2 +#define PTRACE_PEEKUSER 3 +#define PTRACE_POKETEXT 4 +#define PTRACE_POKEDATA 5 +#define PTRACE_POKEUSER 6 +#define PTRACE_CONT 7 +#define PTRACE_KILL 8 +#define PTRACE_SINGLESTEP 9 +#define PTRACE_GETREGS 12 +#define PTRACE_SETREGS 13 +#define PTRACE_GETFPREGS 14 +#define PTRACE_SETFPREGS 15 +#define PTRACE_ATTACH 16 +#define PTRACE_DETACH 17 +#define PTRACE_GETFPXREGS 18 +#define PTRACE_SETFPXREGS 19 +#define PTRACE_SYSCALL 24 +#define PTRACE_SETOPTIONS 0x4200 +#define PTRACE_GETEVENTMSG 0x4201 +#define PTRACE_GETSIGINFO 0x4202 +#define PTRACE_SETSIGINFO 0x4203 +#define PTRACE_GETREGSET 0x4204 +#define PTRACE_SETREGSET 0x4205 +#define PTRACE_SEIZE 0x4206 +#define PTRACE_INTERRUPT 0x4207 +#define PTRACE_LISTEN 0x4208 +#define PTRACE_PEEKSIGINFO 0x4209 +#define PTRACE_GETSIGMASK 0x420A +#define PTRACE_SETSIGMASK 0x420B +#define PTRACE_SECCOMP_GET_FILTER 0x420C + +#define PTRACE_O_TRACESYSGOOD 0x00000001 +#define PTRACE_O_TRACEFORK 0x00000002 +#define PTRACE_O_TRACEVFORK 0x00000004 +#define PTRACE_O_TRACECLONE 0x00000008 +#define PTRACE_O_TRACEEXEC 0x00000010 +#define PTRACE_O_TRACEVFORKDONE 0x00000020 +#define PTRACE_O_TRACEEXIT 0x00000040 +#define PTRACE_O_TRACESECCOMP 0x00000080 +#define PTRACE_O_EXITKILL 0x00100000 +#define PTRACE_O_SUSPEND_SECCOMP 0x00200000 +#define PTRACE_O_MASK 0x003000ff + +#define PTRACE_EVENT_FORK 1 +#define PTRACE_EVENT_VFORK 2 +#define PTRACE_EVENT_CLONE 3 +#define PTRACE_EVENT_EXEC 4 +#define PTRACE_EVENT_VFORK_DONE 5 +#define PTRACE_EVENT_EXIT 6 +#define PTRACE_EVENT_SECCOMP 7 +#define PTRACE_EVENT_STOP 128 + +#define PTRACE_PEEKSIGINFO_SHARED 1 + +#endif // _ABIBITS_PTRACE_H diff --git a/lib/mlibc/abis/linux/reboot.h b/lib/mlibc/abis/linux/reboot.h new file mode 100644 index 0000000..aadc18f --- /dev/null +++ b/lib/mlibc/abis/linux/reboot.h @@ -0,0 +1,12 @@ +#ifndef _ABIBITS_REBOOT_H +#define _ABIBITS_REBOOT_H + +#define RB_AUTOBOOT 0x01234567 +#define RB_HALT_SYSTEM 0xcdef0123 +#define RB_ENABLE_CAD 0x89abcdef +#define RB_DISABLE_CAD 0 +#define RB_POWER_OFF 0x4321fedc +#define RB_SW_SUSPEND 0xd000fce2 +#define RB_KEXEC 0x45584543 + +#endif // _ABIBITS_REBOOT_H diff --git a/lib/mlibc/abis/linux/resource.h b/lib/mlibc/abis/linux/resource.h new file mode 100644 index 0000000..75e8120 --- /dev/null +++ b/lib/mlibc/abis/linux/resource.h @@ -0,0 +1,53 @@ +#ifndef _ABIBITS_RESOURCE_H +#define _ABIBITS_RESOURCE_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#define RUSAGE_SELF 0 +#define RUSAGE_CHILDREN -1 + +#define RLIMIT_CPU 0 +#define RLIMIT_FSIZE 1 +#define RLIMIT_DATA 2 +#define RLIMIT_STACK 3 +#define RLIMIT_CORE 4 +#define RLIMIT_RSS 5 +#define RLIMIT_NPROC 6 +#define RLIMIT_NOFILE 7 +#define RLIMIT_MEMLOCK 8 +#define RLIMIT_AS 9 +#define RLIMIT_LOCKS 10 +#define RLIMIT_SIGPENDING 11 +#define RLIMIT_MSGQUEUE 12 +#define RLIMIT_NICE 13 +#define RLIMIT_RTPRIO 14 +#define RLIMIT_NLIMITS 16 + +struct rusage { + struct timeval ru_utime; + struct timeval ru_stime; + long ru_maxrss; + long ru_ixrss; + long ru_idrss; + long ru_isrss; + long ru_minflt; + long ru_majflt; + long ru_nswap; + long ru_inblock; + long ru_oublock; + long ru_msgsnd; + long ru_msgrcv; + long ru_nsignals; + long ru_nvcsw; + long ru_nivcsw; +}; + +#ifdef __cplusplus +} +#endif + +#endif // _ABIBITS_RESOURCE_H diff --git a/lib/mlibc/abis/linux/seek-whence.h b/lib/mlibc/abis/linux/seek-whence.h new file mode 100644 index 0000000..47a5b0e --- /dev/null +++ b/lib/mlibc/abis/linux/seek-whence.h @@ -0,0 +1,10 @@ +#ifndef _ABIBITS_SEEK_WHENCE_H +#define _ABIBITS_SEEK_WHENCE_H + +#define SEEK_SET 0 +#define SEEK_CUR 1 +#define SEEK_END 2 +#define SEEK_DATA 3 +#define SEEK_HOLE 4 + +#endif // _ABIBITS_SEEK_WHENCE_H diff --git a/lib/mlibc/abis/linux/shm.h b/lib/mlibc/abis/linux/shm.h new file mode 100644 index 0000000..bf71c8c --- /dev/null +++ b/lib/mlibc/abis/linux/shm.h @@ -0,0 +1,25 @@ +#ifndef _ABIBITS_SHM_H +#define _ABIBITS_SHM_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +struct shm_info { + int used_ids; + unsigned long shm_tot; + unsigned long shm_rss; + unsigned long shm_swp; + unsigned long swap_attempts; + unsigned long swap_successes; +}; + +#define SHMLBA (getpagesize()) + +#ifdef __cplusplus +} +#endif + +#endif /* _ABIBITS_SHM_H */ diff --git a/lib/mlibc/abis/linux/signal.h b/lib/mlibc/abis/linux/signal.h new file mode 100644 index 0000000..d83b401 --- /dev/null +++ b/lib/mlibc/abis/linux/signal.h @@ -0,0 +1,496 @@ +#ifndef _ABIBITS_SIGNAL_H +#define _ABIBITS_SIGNAL_H + +#include +#include +#include +#include +#include + +#define POLL_IN 1 +#define POLL_OUT 2 +#define POLL_MSG 3 +#define POLL_ERR 4 +#define POLL_PRI 5 +#define POLL_HUP 6 + +union sigval { + int sival_int; + void *sival_ptr; +}; + +// struct taken from musl. + +typedef struct { + int si_signo, si_errno, si_code; + union { + char __pad[128 - 2*sizeof(int) - sizeof(long)]; + struct { + union { + struct { + pid_t si_pid; + uid_t si_uid; + } __piduid; + struct { + int si_timerid; + int si_overrun; + } __timer; + } __first; + union { + union sigval si_value; + struct { + int si_status; + clock_t 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 + +// Required for sys_sigaction sysdep. +#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 + +#ifdef __cplusplus +extern "C" { +#endif + +// Argument for signal() +typedef void (*__sighandler) (int); + +#define SIG_ERR ((__sighandler)(void *)(-1)) +#define SIG_DFL ((__sighandler)(void *)(0)) +#define SIG_IGN ((__sighandler)(void *)(1)) + +#define SIGABRT 6 +#define SIGFPE 8 +#define SIGILL 4 +#define SIGINT 2 +#define SIGSEGV 11 +#define SIGTERM 15 +#define SIGPROF 27 +#define SIGIO 29 +#define SIGPWR 30 +#define SIGRTMIN 35 +#define SIGRTMAX 64 + +typedef uint64_t sigset_t; + +// constants for sigprocmask() +#define SIG_BLOCK 0 +#define SIG_UNBLOCK 1 +#define SIG_SETMASK 2 + +#define SIGHUP 1 +#define SIGQUIT 3 +#define SIGTRAP 5 +#define SIGIOT SIGABRT +#define SIGBUS 7 +#define SIGKILL 9 +#define SIGUSR1 10 +#define SIGUSR2 12 +#define SIGPIPE 13 +#define SIGALRM 14 +#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 SIGWINCH 28 +#define SIGPOLL 29 +#define SIGSYS 31 +#define SIGUNUSED SIGSYS +#define SIGCANCEL 32 + +#define MINSIGSTKSZ 2048 +#define SIGSTKSZ 8192 +#define SS_ONSTACK 1 +#define SS_DISABLE 2 + +typedef struct __stack { + void *ss_sp; + int ss_flags; + size_t ss_size; +} stack_t; + +// constants for sigev_notify of struct sigevent +#define SIGEV_SIGNAL 0 +#define SIGEV_NONE 1 +#define SIGEV_THREAD 2 +#define SIGEV_THREAD_ID 4 + +#define SEGV_MAPERR 1 +#define SEGV_ACCERR 2 + +#define BUS_ADRALN 1 +#define BUS_ADRERR 2 +#define BUS_OBJERR 3 +#define BUS_MCEERR_AR 4 +#define BUS_MCEERR_AO 5 + +#define ILL_ILLOPC 1 +#define ILL_ILLOPN 2 +#define ILL_ILLADR 3 +#define ILL_ILLTRP 4 +#define ILL_PRVOPC 5 +#define ILL_PRVREG 6 +#define ILL_COPROC 7 +#define ILL_BADSTK 8 +#define ILL_BADIADDR 9 + +#define NSIG 65 + +#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 + +#if defined(__i386__) +#define REG_GS 0 +#define REG_FS 1 +#define REG_ES 2 +#define REG_DS 3 +#define REG_EDI 4 +#define REG_ESI 5 +#define REG_EBP 6 +#define REG_ESP 7 +#define REG_EBX 8 +#define REG_EDX 9 +#define REG_ECX 10 +#define REG_EAX 11 +#define REG_TRAPNO 12 +#define REG_ERR 13 +#define REG_EIP 14 +#define REG_CS 15 +#define REG_EFL 16 +#define REG_UESP 17 +#define REG_SS 18 +#define NGREG 19 +#elif defined(__x86_64__) +#define REG_R8 0 +#define REG_R9 1 +#define REG_R10 2 +#define REG_R11 3 +#define REG_R12 4 +#define REG_R13 5 +#define REG_R14 6 +#define REG_R15 7 +#define REG_RDI 8 +#define REG_RSI 9 +#define REG_RBP 10 +#define REG_RBX 11 +#define REG_RDX 12 +#define REG_RAX 13 +#define REG_RCX 14 +#define REG_RSP 15 +#define REG_RIP 16 +#define REG_EFL 17 +#define REG_CSGSFS 18 +#define REG_ERR 19 +#define REG_TRAPNO 20 +#define REG_OLDMASK 21 +#define REG_CR2 22 +#define NGREG 23 +#endif + +#include + +struct sigevent { + union sigval sigev_value; + int sigev_notify; + int sigev_signo; + void (*sigev_notify_function)(union sigval); + struct __mlibc_threadattr *sigev_notify_attributes; + pid_t sigev_notify_thread_id; +}; + +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 + +// Taken from the linux kernel headers + +#if defined(__x86_64__) || defined(__i386__) + +struct _fpreg { + unsigned short significand[4]; + unsigned short exponent; +}; + +struct _fpxreg { + unsigned short significand[4]; + unsigned short exponent; + unsigned short padding[3]; +}; + +struct _xmmreg { + uint32_t element[4]; +}; + +struct _fpstate { +#if defined(__x86_64__) + uint16_t cwd; + uint16_t swd; + uint16_t ftw; + uint16_t fop; + uint64_t rip; + uint64_t rdp; + uint32_t mxcsr; + uint32_t mxcr_mask; + struct _fpxreg _st[8]; + struct _xmmreg _xmm[16]; + uint32_t padding[24]; +#elif defined(__i386__) + uint32_t cw; + uint32_t sw; + uint32_t tag; + uint32_t ipoff; + uint32_t cssel; + uint32_t dataoff; + uint32_t datasel; + struct _fpreg _st[8]; + uint16_t status; + uint16_t magic; + + // FXSR FPU + + uint32_t _fxsr_env[6]; + uint32_t mxscr; + uint32_t reserved; + struct _fpxreg _fxsr_st[8]; + struct _xmmreg _xmm[8]; + + uint32_t padding2[56]; +#endif +}; + +typedef struct { + unsigned long gregs[NGREG]; + struct _fpstate *fpregs; + unsigned long __reserved1[8]; +} mcontext_t; + +typedef struct __ucontext { + unsigned long uc_flags; + struct __ucontext *uc_link; + stack_t uc_stack; + mcontext_t uc_mcontext; + sigset_t uc_sigmask; +} ucontext_t; + +#elif defined(__riscv) && __riscv_xlen == 64 +// Definitions from Linux kernel headers. + +#define NGREG 32 + +enum { + REG_PC = 0, +#define REG_PC REG_PC + REG_RA = 1, +#define REG_RA REG_RA + REG_SP = 2, +#define REG_SP REG_SP + REG_TP = 4, +#define REG_TP REG_TP + REG_S0 = 8, +#define REG_S0 REG_S0 + REG_A0 = 10, +#define REG_A0 REG_A0 +}; + +struct __riscv_f_ext_state { + uint32_t f[32]; + uint32_t fcsr; +}; + +struct __riscv_d_ext_state { + uint64_t f[32]; + uint32_t fcsr; +}; + +struct __riscv_q_ext_state { + uint64_t f[64] __attribute__((__aligned__(16))); + uint32_t fcsr; + uint32_t reserved[3]; +}; + +union __riscv_fp_state { + struct __riscv_f_ext_state f; + struct __riscv_d_ext_state d; + struct __riscv_q_ext_state q; +}; + +typedef unsigned long __riscv_mc_gp_state[NGREG]; + +typedef struct sigcontext { + __riscv_mc_gp_state gregs; + union __riscv_fp_state fpregs; +} mcontext_t; + +typedef struct __ucontext { + unsigned long uc_flags; + struct ucontext *uc_link; + stack_t uc_stack; + sigset_t uc_sigmask; + uint8_t __unused[1024 / 8 - sizeof(sigset_t)]; + mcontext_t uc_mcontext; +} ucontext_t; + +#elif defined (__aarch64__) + +#define NGREG 34 + +typedef struct sigcontext { + uint64_t fault_address; + uint64_t regs[31]; + uint64_t sp; + uint64_t pc; + uint64_t pstate; + uint8_t __reserved[4096]; +} mcontext_t; + +#define FPSIMD_MAGIC 0x46508001 +#define ESR_MAGIC 0x45535201 +#define EXTRA_MAGIC 0x45585401 +#define SVE_MAGIC 0x53564501 +struct _aarch64_ctx { + uint32_t magic; + uint32_t size; +}; +struct fpsimd_context { + struct _aarch64_ctx head; + uint32_t fpsr; + uint32_t fpcr; + __uint128_t vregs[32]; +}; +struct esr_context { + struct _aarch64_ctx head; + uint64_t esr; +}; +struct extra_context { + struct _aarch64_ctx head; + uint64_t datap; + uint32_t size; + uint32_t __reserved[3]; +}; +struct sve_context { + struct _aarch64_ctx head; + uint16_t vl; + uint16_t __reserved[3]; +}; +#define SVE_VQ_BYTES 16 +#define SVE_VQ_MIN 1 +#define SVE_VQ_MAX 512 +#define SVE_VL_MIN (SVE_VQ_MIN * SVE_VQ_BYTES) +#define SVE_VL_MAX (SVE_VQ_MAX * SVE_VQ_BYTES) +#define SVE_NUM_ZREGS 32 +#define SVE_NUM_PREGS 16 +#define sve_vl_valid(vl) \ + ((vl) % SVE_VQ_BYTES == 0 && (vl) >= SVE_VL_MIN && (vl) <= SVE_VL_MAX) +#define sve_vq_from_vl(vl) ((vl) / SVE_VQ_BYTES) +#define sve_vl_from_vq(vq) ((vq) * SVE_VQ_BYTES) +#define SVE_SIG_ZREG_SIZE(vq) ((unsigned)(vq) * SVE_VQ_BYTES) +#define SVE_SIG_PREG_SIZE(vq) ((unsigned)(vq) * (SVE_VQ_BYTES / 8)) +#define SVE_SIG_FFR_SIZE(vq) SVE_SIG_PREG_SIZE(vq) +#define SVE_SIG_REGS_OFFSET \ + ((sizeof(struct sve_context) + (SVE_VQ_BYTES - 1)) \ + / SVE_VQ_BYTES * SVE_VQ_BYTES) +#define SVE_SIG_ZREGS_OFFSET SVE_SIG_REGS_OFFSET +#define SVE_SIG_ZREG_OFFSET(vq, n) \ + (SVE_SIG_ZREGS_OFFSET + SVE_SIG_ZREG_SIZE(vq) * (n)) +#define SVE_SIG_ZREGS_SIZE(vq) \ + (SVE_SIG_ZREG_OFFSET(vq, SVE_NUM_ZREGS) - SVE_SIG_ZREGS_OFFSET) +#define SVE_SIG_PREGS_OFFSET(vq) \ + (SVE_SIG_ZREGS_OFFSET + SVE_SIG_ZREGS_SIZE(vq)) +#define SVE_SIG_PREG_OFFSET(vq, n) \ + (SVE_SIG_PREGS_OFFSET(vq) + SVE_SIG_PREG_SIZE(vq) * (n)) +#define SVE_SIG_PREGS_SIZE(vq) \ + (SVE_SIG_PREG_OFFSET(vq, SVE_NUM_PREGS) - SVE_SIG_PREGS_OFFSET(vq)) +#define SVE_SIG_FFR_OFFSET(vq) \ + (SVE_SIG_PREGS_OFFSET(vq) + SVE_SIG_PREGS_SIZE(vq)) +#define SVE_SIG_REGS_SIZE(vq) \ + (SVE_SIG_FFR_OFFSET(vq) + SVE_SIG_FFR_SIZE(vq) - SVE_SIG_REGS_OFFSET) +#define SVE_SIG_CONTEXT_SIZE(vq) (SVE_SIG_REGS_OFFSET + SVE_SIG_REGS_SIZE(vq)) + +typedef struct __ucontext { + unsigned long uc_flags; + struct __ucontext *uc_link; + stack_t uc_stack; + sigset_t uc_sigmask; + mcontext_t uc_mcontext; +} ucontext_t; + +#else +#error "Missing architecture specific code." +#endif + +#ifdef __cplusplus +} +#endif + +#endif // _ABIBITS_SIGNAL_H diff --git a/lib/mlibc/abis/linux/socket.h b/lib/mlibc/abis/linux/socket.h new file mode 100644 index 0000000..713d532 --- /dev/null +++ b/lib/mlibc/abis/linux/socket.h @@ -0,0 +1,299 @@ +#ifndef _ABIBITS_SOCKET_H +#define _ABIBITS_SOCKET_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef unsigned short sa_family_t; + +struct msghdr { + void *msg_name; + socklen_t msg_namelen; + struct iovec *msg_iov; + size_t msg_iovlen; /* int in POSIX */ + void *msg_control; + size_t msg_controllen; /* socklen_t in POSIX */ + int msg_flags; +}; + +struct sockaddr_storage { + sa_family_t ss_family; + char __padding[128 - sizeof(sa_family_t)]; +}; + +struct mmsghdr { + struct msghdr msg_hdr; + unsigned int msg_len; +}; + +struct cmsghdr { + size_t cmsg_len; /* socklen_t in POSIX */ + int cmsg_level; + int cmsg_type; +}; + +#ifdef __cplusplus +} +#endif + +#define SCM_RIGHTS 1 +#define SCM_CREDENTIALS 2 + +#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_RCVTIMEO 20 +#define SO_SNDTIMEO 21 + +#define SO_TIMESTAMP 29 +#define SO_TIMESTAMPNS 35 +#define SO_TIMESTAMPING 37 + +#define SO_SECURITY_AUTHENTICATION 22 +#define SO_SECURITY_ENCRYPTION_TRANSPORT 23 +#define SO_SECURITY_ENCRYPTION_NETWORK 24 + +#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 SCM_TIMESTAMP SO_TIMESTAMP +#define SO_PASSSEC 34 +#define SCM_TIMESTAMPNS SO_TIMESTAMPNS +#define SO_MARK 36 +#define SCM_TIMESTAMPING SO_TIMESTAMPING +#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 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 + +#define SOMAXCONN 128 + +#define MSG_OOB 0x0001 +#define MSG_PEEK 0x0002 +#define MSG_DONTROUTE 0x0004 +#define MSG_CTRUNC 0x0008 +#define MSG_PROXY 0x0010 +#define MSG_TRUNC 0x0020 +#define MSG_DONTWAIT 0x0040 +#define MSG_EOR 0x0080 +#define MSG_WAITALL 0x0100 +#define MSG_FIN 0x0200 +#define MSG_SYN 0x0400 +#define MSG_CONFIRM 0x0800 +#define MSG_RST 0x1000 +#define MSG_ERRQUEUE 0x2000 +#define MSG_NOSIGNAL 0x4000 +#define MSG_MORE 0x8000 +#define MSG_WAITFORONE 0x10000 +#define MSG_BATCH 0x40000 +#define MSG_ZEROCOPY 0x4000000 +#define MSG_FASTOPEN 0x20000000 +#define MSG_CMSG_CLOEXEC 0x40000000 + +#endif diff --git a/lib/mlibc/abis/linux/socklen_t.h b/lib/mlibc/abis/linux/socklen_t.h new file mode 100644 index 0000000..190e5f9 --- /dev/null +++ b/lib/mlibc/abis/linux/socklen_t.h @@ -0,0 +1,6 @@ +#ifndef _ABIBITS_SOCKLEN_T_H +#define _ABIBITS_SOCKLEN_T_H + +typedef unsigned socklen_t; + +#endif /* _ABIBITS_SOCKLEN_T_H */ diff --git a/lib/mlibc/abis/linux/stat.h b/lib/mlibc/abis/linux/stat.h new file mode 100644 index 0000000..5c55ba8 --- /dev/null +++ b/lib/mlibc/abis/linux/stat.h @@ -0,0 +1,123 @@ +#ifndef _ABIBITS_STAT_H +#define _ABIBITS_STAT_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define S_IFMT 0x0F000 +#define S_IFBLK 0x06000 +#define S_IFCHR 0x02000 +#define S_IFIFO 0x01000 +#define S_IFREG 0x08000 +#define S_IFDIR 0x04000 +#define S_IFLNK 0x0A000 +#define S_IFSOCK 0x0C000 + +#define S_IRWXU 0700 +#define S_IRUSR 0400 +#define S_IWUSR 0200 +#define S_IXUSR 0100 +#define S_IEXEC S_IXUSR +#define S_IRWXG 070 +#define S_IRGRP 040 +#define S_IWGRP 020 +#define S_IXGRP 010 +#define S_IRWXO 07 +#define S_IROTH 04 +#define S_IWOTH 02 +#define S_IXOTH 01 +#define S_ISUID 04000 +#define S_ISGID 02000 +#define S_ISVTX 01000 + +#define S_IREAD S_IRUSR +#define S_IWRITE S_IWUSR +#define S_IEXEC S_IXUSR + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(__x86_64__) + +struct stat { + dev_t st_dev; + ino_t st_ino; + nlink_t st_nlink; + mode_t st_mode; + uid_t st_uid; + gid_t st_gid; + unsigned int __pad0; + dev_t st_rdev; + off_t st_size; + blksize_t st_blksize; + blkcnt_t st_blocks; + struct timespec st_atim; + struct timespec st_mtim; + struct timespec st_ctim; + long __unused[3]; +}; + +#elif (defined(__riscv) && __riscv_xlen == 64) || defined (__aarch64__) + +struct stat { + dev_t st_dev; + ino_t st_ino; + mode_t st_mode; + nlink_t st_nlink; + uid_t st_uid; + gid_t st_gid; + dev_t st_rdev; + unsigned long __pad1; + off_t st_size; + blksize_t st_blksize; + int __pad2; + blkcnt_t st_blocks; + struct timespec st_atim; + struct timespec st_mtim; + struct timespec st_ctim; + unsigned int __unused4; + unsigned int __unused5; +}; + +#elif defined(__i386__) + +struct stat { + dev_t st_dev; + int __st_dev_padding; + long __st_ino_truncated; + mode_t st_mode; + nlink_t st_nlink; + uid_t st_uid; + gid_t st_gid; + dev_t st_rdev; + int __st_rdev_padding; + off_t st_size; + blksize_t st_blksize; + blkcnt_t st_blocks; + struct { + long tv_sec; + long tv_nsec; + } __st_atim32, __st_mtim32, __st_ctim32; + ino_t st_ino; + struct timespec st_atim; + struct timespec st_mtim; + struct timespec st_ctim; +}; + +#endif + +#ifdef __cplusplus +} +#endif + +#endif // _ABIBITS_STAT_H diff --git a/lib/mlibc/abis/linux/statfs.h b/lib/mlibc/abis/linux/statfs.h new file mode 100644 index 0000000..60c977f --- /dev/null +++ b/lib/mlibc/abis/linux/statfs.h @@ -0,0 +1,28 @@ +#ifndef _ABIBITS_STATFS_H +#define _ABIBITS_STATFS_H + +#include +#include + +typedef struct __mlibc_fsid { + int __val[2]; +} fsid_t; + +struct statfs { + unsigned long f_type; + unsigned long f_bsize; + fsblkcnt_t f_blocks; + fsblkcnt_t f_bfree; + fsblkcnt_t f_bavail; + + fsfilcnt_t f_files; + fsfilcnt_t f_ffree; + fsid_t f_fsid; + unsigned long f_namelen; + unsigned long f_frsize; + unsigned long f_flags; + unsigned long __f_spare[4]; +}; + +#endif /* _ABIBITS_STATFS_H */ + diff --git a/lib/mlibc/abis/linux/statvfs.h b/lib/mlibc/abis/linux/statvfs.h new file mode 100644 index 0000000..7a75d3a --- /dev/null +++ b/lib/mlibc/abis/linux/statvfs.h @@ -0,0 +1,29 @@ +#ifndef _ABIBITS_STATVFS_H +#define _ABIBITS_STATVFS_H + +#include +#include + +#define ST_RDONLY 1 +#define ST_NOSUID 2 +#define ST_MANDLOCK 64 + +// On Linux, this struct is not directly used by the kernel. +struct statvfs { + unsigned long f_bsize; + unsigned long f_frsize; + fsblkcnt_t f_blocks; + fsblkcnt_t f_bfree; + fsblkcnt_t f_bavail; + + fsfilcnt_t f_files; + fsfilcnt_t f_ffree; + fsfilcnt_t f_favail; + + unsigned long f_fsid; + unsigned long f_flag; + unsigned long f_namemax; +}; + +#endif /* _ABIBITS_STATVFS_H */ + diff --git a/lib/mlibc/abis/linux/suseconds_t.h b/lib/mlibc/abis/linux/suseconds_t.h new file mode 100644 index 0000000..1de1a7c --- /dev/null +++ b/lib/mlibc/abis/linux/suseconds_t.h @@ -0,0 +1,8 @@ +#ifndef _ABIBITS_SUSECONDS_T_H +#define _ABIBITS_SUSECONDS_T_H + +#include + +typedef long suseconds_t; + +#endif /* _ABIBITS_SUSECONDS_T_H */ diff --git a/lib/mlibc/abis/linux/termios.h b/lib/mlibc/abis/linux/termios.h new file mode 100644 index 0000000..3ee43d0 --- /dev/null +++ b/lib/mlibc/abis/linux/termios.h @@ -0,0 +1,155 @@ +#ifndef _ABIBITS_TERMIOS_H +#define _ABIBITS_TERMIOS_H + +typedef unsigned char cc_t; +typedef unsigned int speed_t; +typedef unsigned int tcflag_t; + +// indices for the c_cc array in struct termios +#define NCCS 32 +#define VINTR 0 +#define VQUIT 1 +#define VERASE 2 +#define VKILL 3 +#define VEOF 4 +#define VTIME 5 +#define VMIN 6 +#define VSWTC 7 +#define VSTART 8 +#define VSTOP 9 +#define VSUSP 10 +#define VEOL 11 +#define VREPRINT 12 +#define VDISCARD 13 +#define VWERASE 14 +#define VLNEXT 15 +#define VEOL2 16 + +// bitwise flags for c_iflag in struct termios +#define IGNBRK 0000001 +#define BRKINT 0000002 +#define IGNPAR 0000004 +#define PARMRK 0000010 +#define INPCK 0000020 +#define ISTRIP 0000040 +#define INLCR 0000100 +#define IGNCR 0000200 +#define ICRNL 0000400 +#define IUCLC 0001000 +#define IXON 0002000 +#define IXANY 0004000 +#define IXOFF 0010000 +#define IMAXBEL 0020000 +#define IUTF8 0040000 + +// bitwise flags for c_oflag in struct termios +#define OPOST 0000001 +#define OLCUC 0000002 +#define ONLCR 0000004 +#define OCRNL 0000010 +#define ONOCR 0000020 +#define ONLRET 0000040 +#define OFILL 0000100 +#define OFDEL 0000200 + +#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE) || defined(_XOPEN_SOURCE) + +#define NLDLY 0000400 +#define NL0 0000000 +#define NL1 0000400 + +#define CRDLY 0003000 +#define CR0 0000000 +#define CR1 0001000 +#define CR2 0002000 +#define CR3 0003000 + +#define TABDLY 0014000 +#define TAB0 0000000 +#define TAB1 0004000 +#define TAB2 0010000 +#define TAB3 0014000 + +#define BSDLY 0020000 +#define BS0 0000000 +#define BS1 0020000 + +#define FFDLY 0100000 +#define FF0 0000000 +#define FF1 0100000 + +#endif + +#define VTDLY 0040000 +#define VT0 0000000 +#define VT1 0040000 + +// bitwise constants for c_cflag in struct termios +#define CSIZE 0000060 +#define CS5 0000000 +#define CS6 0000020 +#define CS7 0000040 +#define CS8 0000060 + +#define CSTOPB 0000100 +#define CREAD 0000200 +#define PARENB 0000400 +#define PARODD 0001000 +#define HUPCL 0002000 +#define CLOCAL 0004000 + +// bitwise constants for c_lflag in struct termios +#define ISIG 0000001 +#define ICANON 0000002 +#define ECHO 0000010 +#define ECHOE 0000020 +#define ECHOK 0000040 +#define ECHONL 0000100 +#define NOFLSH 0000200 +#define TOSTOP 0000400 +#define IEXTEN 0100000 + +#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE) + +#define EXTA 0000016 +#define EXTB 0000017 +#define CBAUD 0010017 +#define CBAUDEX 0010000 +#define CIBAUD 002003600000 +#define CMSPAR 010000000000 +#define CRTSCTS 020000000000 + +#define XCASE 0000004 +#define ECHOCTL 0001000 +#define ECHOPRT 0002000 +#define ECHOKE 0004000 +#define FLUSHO 0010000 +#define PENDIN 0040000 +#define EXTPROC 0200000 + +#define XTABS 0014000 + +#endif + +struct termios { + tcflag_t c_iflag; + tcflag_t c_oflag; + tcflag_t c_cflag; + tcflag_t c_lflag; + cc_t c_line; + cc_t c_cc[NCCS]; + speed_t ibaud; + speed_t obaud; +}; + +#define NCC 8 +struct termio { + unsigned short c_iflag; + unsigned short c_oflag; + unsigned short c_cflag; + unsigned short c_lflag; + unsigned char c_line; + unsigned char c_cc[NCC]; +}; + +#endif diff --git a/lib/mlibc/abis/linux/time.h b/lib/mlibc/abis/linux/time.h new file mode 100644 index 0000000..3f49db3 --- /dev/null +++ b/lib/mlibc/abis/linux/time.h @@ -0,0 +1,15 @@ +#ifndef _ABIBITS_TIME_H +#define _ABIBITS_TIME_H + +#include + +struct itimerval { + struct timeval it_interval; /* Interval for periodic timer */ + struct timeval it_value; /* Time until next expiration */ +}; + +#define ITIMER_REAL 0 +#define ITIMER_VIRTUAL 1 +#define ITIMER_PROF 2 + +#endif // _ABIBITS_TIME_H diff --git a/lib/mlibc/abis/linux/uid_t.h b/lib/mlibc/abis/linux/uid_t.h new file mode 100644 index 0000000..5b53ca3 --- /dev/null +++ b/lib/mlibc/abis/linux/uid_t.h @@ -0,0 +1,8 @@ + +#ifndef _ABIBITS_UID_T_H +#define _ABIBITS_UID_T_H + +typedef unsigned int uid_t; + +#endif // _ABIBITS_UID_T_H + diff --git a/lib/mlibc/abis/linux/utsname.h b/lib/mlibc/abis/linux/utsname.h new file mode 100644 index 0000000..9875a46 --- /dev/null +++ b/lib/mlibc/abis/linux/utsname.h @@ -0,0 +1,13 @@ +#ifndef _ABIBITS_UTSNAME_T_H +#define _ABIBITS_UTSNAME_T_H + +struct utsname { + char sysname[65]; + char nodename[65]; + char release[65]; + char version[65]; + char machine[65]; + char domainname[65]; +}; + +#endif // _ABIBITS_UTSNAME_T_H diff --git a/lib/mlibc/abis/linux/vm-flags.h b/lib/mlibc/abis/linux/vm-flags.h new file mode 100644 index 0000000..3f8137c --- /dev/null +++ b/lib/mlibc/abis/linux/vm-flags.h @@ -0,0 +1,70 @@ +#ifndef _ABIBITS_VM_FLAGS_H +#define _ABIBITS_VM_FLAGS_H + +#define PROT_NONE 0x00 +#define PROT_READ 0x01 +#define PROT_WRITE 0x02 +#define PROT_EXEC 0x04 + +#define MAP_FAILED ((void *)(-1)) +#define MAP_FILE 0x00 +#define MAP_SHARED 0x01 +#define MAP_PRIVATE 0x02 +#define MAP_FIXED 0x10 +#define MAP_ANON 0x20 +#define MAP_ANONYMOUS 0x20 +#define MAP_GROWSDOWN 0x100 +#define MAP_DENYWRITE 0x800 +#define MAP_EXECUTABLE 0x1000 +#define MAP_LOCKED 0x2000 +#define MAP_NORESERVE 0x4000 +#define MAP_POPULATE 0x8000 +#define MAP_NONBLOCK 0x10000 +#define MAP_STACK 0x20000 +#define MAP_HUGETLB 0x40000 +#define MAP_SYNC 0x80000 +#define MAP_FIXED_NOREPLACE 0x100000 + +#define MS_ASYNC 0x01 +#define MS_INVALIDATE 0x02 +#define MS_SYNC 0x04 + +#define MCL_CURRENT 0x01 +#define MCL_FUTURE 0x02 + +#define POSIX_MADV_NORMAL 0 +#define POSIX_MADV_RANDOM 1 +#define POSIX_MADV_SEQUENTIAL 2 +#define POSIX_MADV_WILLNEED 3 +#define POSIX_MADV_DONTNEED 4 + +#define MADV_NORMAL 0 +#define MADV_RANDOM 1 +#define MADV_SEQUENTIAL 2 +#define MADV_WILLNEED 3 +#define MADV_DONTNEED 4 +#define MADV_FREE 8 +#define MADV_REMOVE 9 +#define MADV_DONTFORK 10 +#define MADV_DOFORK 11 +#define MADV_MERGEABLE 12 +#define MADV_UNMERGEABLE 13 +#define MADV_HUGEPAGE 14 +#define MADV_NOHUGEPAGE 15 +#define MADV_DONTDUMP 16 +#define MADV_DODUMP 17 +#define MADV_WIPEONFORK 18 +#define MADV_KEEPONFORK 19 +#define MADV_COLD 20 +#define MADV_PAGEOUT 21 +#define MADV_HWPOISON 100 +#define MADV_SOFT_OFFLINE 101 + +#define MREMAP_MAYMOVE 1 +#define MREMAP_FIXED 2 + +#define MFD_CLOEXEC 1U +#define MFD_ALLOW_SEALING 2U +#define MFD_HUGETLB 4U + +#endif // _ABIBITS_VM_FLAGS_H diff --git a/lib/mlibc/abis/linux/vt.h b/lib/mlibc/abis/linux/vt.h new file mode 100644 index 0000000..811933b --- /dev/null +++ b/lib/mlibc/abis/linux/vt.h @@ -0,0 +1,76 @@ +#ifndef _ABIBITS_VT_H +#define _ABIBITS_VT_H + +#define MIN_NR_CONSOLES 1 +#define MAX_NR_CONSOLES 63 + +#define VT_OPENQRY 0x5600 +#define VT_GETMODE 0x5601 +#define VT_SETMODE 0x5602 +#define VT_GETSTATE 0x5603 +#define VT_SENDSIG 0x5604 +#define VT_RELDISP 0x5605 +#define VT_ACTIVATE 0x5606 +#define VT_WAITACTIVE 0x5607 +#define VT_DISALLOCATE 0x5608 +#define VT_RESIZE 0x5609 +#define VT_RESIZEX 0x560A +#define VT_LOCKSWITCH 0x560B +#define VT_UNLOCKSWITCH 0x560C +#define VT_GETHIFONTMASK 0x560D +#define VT_WAITEVENT 0x560E +#define VT_SETACTIVATE 0x560F + +struct vt_mode { + char mode; + char waitv; + short relsig; + short acqsig; + short frsig; +}; + +#define VT_AUTO 0x00 +#define VT_PROCESS 0x01 +#define VT_ACKACQ 0x02 + +struct vt_stat { + unsigned short v_active; + unsigned short v_signal; + unsigned short v_state; +}; + +struct vt_sizes { + unsigned short v_rows; + unsigned short v_cols; + unsigned short v_scrollsize; +}; + +struct vt_consize { + unsigned short v_rows; + unsigned short v_cols; + unsigned short v_vlin; + unsigned short v_clin; + unsigned short v_vcol; + unsigned short v_ccol; +}; + +#define VT_EVENT_SWITCH 0x0001 +#define VT_EVENT_BLANK 0x0002 +#define VT_EVENT_UNBLANK 0x0004 +#define VT_EVENT_RESIZE 0x0008 +#define VT_MAX_EVENT 0x000F + +struct vt_event { + unsigned int event; + + unsigned int oldev; + unsigned int newev; + unsigned int pad[4]; +}; + +struct vt_setactivate { + unsigned int console; + struct vt_mode mode; +}; + +#endif // _ABIBITS_VT_H diff --git a/lib/mlibc/abis/linux/wait.h b/lib/mlibc/abis/linux/wait.h new file mode 100644 index 0000000..58d1462 --- /dev/null +++ b/lib/mlibc/abis/linux/wait.h @@ -0,0 +1,28 @@ +#ifndef _ABIBITS_WAIT_H +#define _ABIBITS_WAIT_H + +#define WNOHANG 1 +#define WUNTRACED 2 +#define WSTOPPED 2 +#define WEXITED 4 +#define WCONTINUED 8 +#define WNOWAIT 0x01000000 + +#define __WALL 0x40000000 +#define __WCLONE 0x80000000 + +#define WCOREFLAG 0x80 + +#define WEXITSTATUS(x) (((x) & 0xff00) >> 8) +#define WTERMSIG(x) ((x) & 0x7f) +#define WSTOPSIG(x) WEXITSTATUS(x) +#define WIFEXITED(x) (WTERMSIG(x) == 0) +#define WIFSIGNALED(x) (((signed char) (((x) & 0x7f) + 1) >> 1) > 0) +#define WIFSTOPPED(x) (((x) & 0xff) == 0x7f) +#define WIFCONTINUED(x) ((x) == 0xffff) +#define WCOREDUMP(x) ((x) & WCOREFLAG) + +/* glibc extension, but also useful for kernels */ +#define W_EXITCODE(ret, sig) (((ret) << 8) | (sig)) + +#endif //_ABIBITS_WAIT_H diff --git a/lib/mlibc/abis/linux/xattr.h b/lib/mlibc/abis/linux/xattr.h new file mode 100644 index 0000000..c0e7fbe --- /dev/null +++ b/lib/mlibc/abis/linux/xattr.h @@ -0,0 +1,21 @@ +#ifndef MLIBC_ABIS_LINUX_XATTR_H +#define MLIBC_ABIS_LINUX_XATTR_H + +/* __USE_KERNEL_XATTR_DEFS is exported when XATTR_* are emitted, and + * __UAPI_DEF_XATTR is used to determine the behaviour of the + * header (through ), if it's set + * to 1, the header exports xattr defines and __USE_KERNEL_XATTR_DEFS. + * This applies for pretty much all other defines in libc-compat.h + * AFAICT. + */ +#ifndef __USE_KERNEL_XATTR_DEFS +enum { + XATTR_CREATE = 1, +#define XATTR_CREATE XATTR_CREATE + XATTR_REPLACE = 2, +#define XATTR_REPLACE XATTR_REPLACE +}; +# define __UAPI_DEF_XATTR 0 +#endif + +#endif /* MLIBC_ABIS_LINUX_XATTR_H */ diff --git a/lib/mlibc/abis/lyre/statvfs.h b/lib/mlibc/abis/lyre/statvfs.h new file mode 100644 index 0000000..7f53fc0 --- /dev/null +++ b/lib/mlibc/abis/lyre/statvfs.h @@ -0,0 +1,35 @@ +#ifndef _ABIBITS_STATVFS_H +#define _ABIBITS_STATVFS_H + +#include +#include + +#define ST_RDONLY 1 +#define ST_NOSUID 2 +#define ST_MANDLOCK 64 + +#define FSTYPSZ 16 + +// On Linux, this struct is not directly used by the kernel. +struct statvfs { + unsigned long f_bsize; + unsigned long f_frsize; + fsblkcnt_t f_blocks; + fsblkcnt_t f_bfree; + fsblkcnt_t f_bavail; + + fsfilcnt_t f_files; + fsfilcnt_t f_ffree; + fsfilcnt_t f_favail; + + unsigned long f_fsid; + char f_basetype[FSTYPSZ]; + + unsigned long f_flag; + unsigned long f_namemax; + char f_fstr[32]; + unsigned long f_filler[16]; +}; + +#endif /* _ABIBITS_STATVFS_H */ + diff --git a/lib/mlibc/abis/managarm/auxv.h b/lib/mlibc/abis/managarm/auxv.h new file mode 100644 index 0000000..5db7f03 --- /dev/null +++ b/lib/mlibc/abis/managarm/auxv.h @@ -0,0 +1,16 @@ +#ifndef _ABIBITS_AUXV_H +#define _ABIBITS_AUXV_H + +#define AT_SECURE 23 +#define AT_RANDOM 25 +#define AT_EXECFN 31 +#define AT_SYSINFO_EHDR 33 + +// managarm specific auxvector entries. + +#define AT_XPIPE 0x1000 +#define AT_OPENFILES 0x1001 +#define AT_FS_SERVER 0x1102 +#define AT_MBUS_SERVER 0x1103 + +#endif // _ABIBITS_AUXV_H diff --git a/lib/mlibc/abis/mlibc/access.h b/lib/mlibc/abis/mlibc/access.h new file mode 100644 index 0000000..bc19728 --- /dev/null +++ b/lib/mlibc/abis/mlibc/access.h @@ -0,0 +1,9 @@ +#ifndef _ABIBITS_ACCESS_H +#define _ABIBITS_ACCESS_H + +#define F_OK 1 +#define R_OK 2 +#define W_OK 4 +#define X_OK 8 + +#endif // _ABIBITS_ACCESS_H diff --git a/lib/mlibc/abis/mlibc/blkcnt_t.h b/lib/mlibc/abis/mlibc/blkcnt_t.h new file mode 100644 index 0000000..51c1519 --- /dev/null +++ b/lib/mlibc/abis/mlibc/blkcnt_t.h @@ -0,0 +1,7 @@ +#ifndef _ABIBITS_BLKCNT_T_H +#define _ABIBITS_BLKCNT_T_H + +// TODO: use int64_t? +typedef long blkcnt_t; + +#endif // _ABIBITS_BLKCNT_T_H diff --git a/lib/mlibc/abis/mlibc/blksize_t.h b/lib/mlibc/abis/mlibc/blksize_t.h new file mode 100644 index 0000000..9363a50 --- /dev/null +++ b/lib/mlibc/abis/mlibc/blksize_t.h @@ -0,0 +1,9 @@ + +#ifndef _ABIBITS_BLKSIZE_T_H +#define _ABIBITS_BLKSIZE_T_H + +// TODO: use int64_t? +typedef long blksize_t; + +#endif // _ABIBITS_BLKSIZE_T_H + diff --git a/lib/mlibc/abis/mlibc/clockid_t.h b/lib/mlibc/abis/mlibc/clockid_t.h new file mode 100644 index 0000000..c3932ef --- /dev/null +++ b/lib/mlibc/abis/mlibc/clockid_t.h @@ -0,0 +1,7 @@ +#ifndef _ABIBITS_CLOCKID_T_H +#define _ABIBITS_CLOCKID_T_H + +typedef long clockid_t; + +#endif /* _ABIBITS_CLOCKID_T_H */ + diff --git a/lib/mlibc/abis/mlibc/dev_t.h b/lib/mlibc/abis/mlibc/dev_t.h new file mode 100644 index 0000000..2481af3 --- /dev/null +++ b/lib/mlibc/abis/mlibc/dev_t.h @@ -0,0 +1,8 @@ + +#ifndef _ABIBITS_DEV_T_H +#define _ABIBITS_DEV_T_H + +typedef unsigned long dev_t; + +#endif // _ABIBITS_DEV_T_H + diff --git a/lib/mlibc/abis/mlibc/epoll.h b/lib/mlibc/abis/mlibc/epoll.h new file mode 100644 index 0000000..49969d5 --- /dev/null +++ b/lib/mlibc/abis/mlibc/epoll.h @@ -0,0 +1,6 @@ +#ifndef _ABIBITS_EPOLL_H +#define _ABIBITS_EPOLL_H + +#define EPOLL_CLOEXEC 1 + +#endif // _ABIBITS_EPOLL_H diff --git a/lib/mlibc/abis/mlibc/errno.h b/lib/mlibc/abis/mlibc/errno.h new file mode 100644 index 0000000..f8c7203 --- /dev/null +++ b/lib/mlibc/abis/mlibc/errno.h @@ -0,0 +1,126 @@ +#ifndef _ABIBITS_ERRNO_H +#define _ABIBITS_ERRNO_H + +#define EDOM 1 +#define EILSEQ 2 +#define ERANGE 3 + +#define E2BIG 1001 +#define EACCES 1002 +#define EADDRINUSE 1003 +#define EADDRNOTAVAIL 1004 +#define EAFNOSUPPORT 1005 +#define EAGAIN 1006 +#define EALREADY 1007 +#define EBADF 1008 +#define EBADMSG 1009 +#define EBUSY 1010 +#define ECANCELED 1011 +#define ECHILD 1012 +#define ECONNABORTED 1013 +#define ECONNREFUSED 1014 +#define ECONNRESET 1015 +#define EDEADLK 1016 +#define EDESTADDRREQ 1017 +#define EDQUOT 1018 +#define EEXIST 1019 +#define EFAULT 1020 +#define EFBIG 1021 +#define EHOSTUNREACH 1022 +#define EIDRM 1023 +#define EINPROGRESS 1024 +#define EINTR 1025 +#define EINVAL 1026 +#define EIO 1027 +#define EISCONN 1028 +#define EISDIR 1029 +#define ELOOP 1030 +#define EMFILE 1031 +#define EMLINK 1032 +#define EMSGSIZE 1034 +#define EMULTIHOP 1035 +#define ENAMETOOLONG 1036 +#define ENETDOWN 1037 +#define ENETRESET 1038 +#define ENETUNREACH 1039 +#define ENFILE 1040 +#define ENOBUFS 1041 +#define ENODEV 1042 +#define ENOENT 1043 +#define ENOEXEC 1044 +#define ENOLCK 1045 +#define ENOLINK 1046 +#define ENOMEM 1047 +#define ENOMSG 1048 +#define ENOPROTOOPT 1049 +#define ENOSPC 1050 +#define ENOSYS 1051 +#define ENOTCONN 1052 +#define ENOTDIR 1053 +#define ENOTEMPTY 1054 +#define ENOTRECOVERABLE 1055 +#define ENOTSOCK 1056 +#define ENOTSUP 1057 +#define ENOTTY 1058 +#define ENXIO 1059 +#define EOPNOTSUPP 1060 +#define EOVERFLOW 1061 +#define EOWNERDEAD 1062 +#define EPERM 1063 +#define EPIPE 1064 +#define EPROTO 1065 +#define EPROTONOSUPPORT 1066 +#define EPROTOTYPE 1067 +#define EROFS 1068 +#define ESPIPE 1069 +#define ESRCH 1070 +#define ESTALE 1071 +#define ETIMEDOUT 1072 +#define ETXTBSY 1073 +#define EWOULDBLOCK EAGAIN +#define EXDEV 1075 +#define ENODATA 1076 +#define ETIME 1077 +#define ENOKEY 1078 +#define ESHUTDOWN 1079 +#define EHOSTDOWN 1080 +#define EBADFD 1081 +#define ENOMEDIUM 1082 +#define ENOTBLK 1083 +#define ENONET 1084 +#define EPFNOSUPPORT 1085 +#define ESOCKTNOSUPPORT 1086 +#define ESTRPIPE 1087 +#define EREMOTEIO 1088 +#define ERFKILL 1089 +#define EBADR 1090 +#define EUNATCH 1091 +#define EMEDIUMTYPE 1092 +#define EREMOTE 1093 +#define EKEYREJECTED 1094 +#define EUCLEAN 1095 +#define EBADSLT 1096 +#define ENOANO 1097 +#define ENOCSI 1098 +#define ENOSTR 1099 +#define ETOOMANYREFS 1100 +#define ENOPKG 1101 +#define EKEYREVOKED 1102 +#define EXFULL 1103 +#define ELNRNG 1104 +#define ENOTUNIQ 1105 +#define ERESTART 1106 +#define EUSERS 1107 +#define ECHRNG 1108 +#define ELIBBAD 1109 +#define EL2HLT 1110 +#define EL3HLT 1111 +#define EKEYEXPIRED 1112 +#define ECOMM 1113 +#define EBADE 1114 +#define EHWPOISON 1115 +#define EBADRQC 1116 + +#define EIEIO 1524152434 + +#endif // _ABIBITS_ERRNO_H diff --git a/lib/mlibc/abis/mlibc/fcntl.h b/lib/mlibc/abis/mlibc/fcntl.h new file mode 100644 index 0000000..8f773aa --- /dev/null +++ b/lib/mlibc/abis/mlibc/fcntl.h @@ -0,0 +1,76 @@ +#ifndef _ABIBITS_FCNTL_H +#define _ABIBITS_FCNTL_H + +// reserve 3 bits for the access mode +#define O_ACCMODE 0x0007 +#define O_EXEC 1 +#define O_RDONLY 2 +#define O_RDWR 3 +#define O_SEARCH 4 +#define O_WRONLY 5 + +// these flags get their own bit +#define O_APPEND 0x000008 +#define O_CREAT 0x000010 +#define O_DIRECTORY 0x000020 +#define O_EXCL 0x000040 +#define O_NOCTTY 0x000080 +#define O_NOFOLLOW 0x000100 +#define O_TRUNC 0x000200 +#define O_NONBLOCK 0x000400 +#define O_DSYNC 0x000800 +#define O_RSYNC 0x001000 +#define O_SYNC 0x002000 +#define O_CLOEXEC 0x004000 +#define O_PATH 0x008000 +#define O_LARGEFILE 0x010000 +#define O_NOATIME 0x020000 +#define O_ASYNC 0x040000 +#define O_TMPFILE 0x080000 +#define O_DIRECT 0x100000 + +// constants for fcntl()'s command argument +#define F_DUPFD 1 +#define F_DUPFD_CLOEXEC 2 +#define F_GETFD 3 +#define F_SETFD 4 +#define F_GETFL 5 +#define F_SETFL 6 +#define F_GETLK 7 +#define F_SETLK 8 +#define F_SETLKW 9 +#define F_GETOWN 10 +#define F_SETOWN 11 + +// constants for struct flock's l_type member +#define F_RDLCK 1 +#define F_UNLCK 2 +#define F_WRLCK 3 + +// constants for fcntl()'s additional argument of F_GETFD and F_SETFD +#define FD_CLOEXEC 1 + +// Used by mmap +#define F_SEAL_SHRINK 0x0002 +#define F_SEAL_GROW 0x0004 +#define F_SEAL_WRITE 0x0008 +#define F_SEAL_SEAL 0x0010 +#define F_ADD_SEALS 1033 +#define F_GET_SEALS 1034 + +#define AT_EMPTY_PATH 1 +#define AT_SYMLINK_FOLLOW 2 +#define AT_SYMLINK_NOFOLLOW 4 +#define AT_REMOVEDIR 8 +#define AT_EACCESS 512 + +#define AT_FDCWD -100 + +#define POSIX_FADV_NORMAL 1 +#define POSIX_FADV_SEQUENTIAL 2 +#define POSIX_FADV_NOREUSE 3 +#define POSIX_FADV_DONTNEED 4 +#define POSIX_FADV_WILLNEED 5 +#define POSIX_FADV_RANDOM 6 + +#endif // _ABITBITS_FCNTL_H diff --git a/lib/mlibc/abis/mlibc/gid_t.h b/lib/mlibc/abis/mlibc/gid_t.h new file mode 100644 index 0000000..65afa40 --- /dev/null +++ b/lib/mlibc/abis/mlibc/gid_t.h @@ -0,0 +1,8 @@ + +#ifndef _ABIBITS_GID_T_H +#define _ABIBITS_GID_T_H + +typedef unsigned int gid_t; + +#endif // _ABIBITS_GID_T_H + diff --git a/lib/mlibc/abis/mlibc/in.h b/lib/mlibc/abis/mlibc/in.h new file mode 100644 index 0000000..3c736e3 --- /dev/null +++ b/lib/mlibc/abis/mlibc/in.h @@ -0,0 +1,168 @@ +#ifndef _ABIBITS_IN_H +#define _ABIBITS_IN_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +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 pad[8]; +}; +#define sin_zero pad /* for BSD Unix compatibility */ + +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 in6_pktinfo { + struct in6_addr ipi6_addr; + uint32_t ipi6_ifindex; +}; + +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; +}; + +struct ipv6_mreq { + struct in6_addr ipv6mr_multiaddr; + unsigned ipv6mr_interface; +}; + +struct ip_mreq { + struct in_addr imr_multiaddr; + struct in_addr imr_interface; +}; + +struct ip_mreq_source { + struct in_addr imr_multiaddr; + struct in_addr imr_interface; + struct in_addr imr_sourceaddr; +}; + +struct ip_mreqn { + struct in_addr imr_multiaddr; + struct in_addr imr_address; + int imr_ifindex; +}; + +struct in_pktinfo { + unsigned int ipi_ifindex; + struct in_addr ipi_spec_dst; + struct in_addr ipi_addr; +}; + +struct group_source_req { + uint32_t gsr_interface; + struct sockaddr_storage gsr_group; + struct sockaddr_storage gsr_source; +}; + +#ifdef __cplusplus +} +#endif + +#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 } } } + +#define IPPROTO_IP 1 +#define IPPROTO_IPV6 2 +#define IPPROTO_ICMP 3 +#define IPPROTO_RAW 4 +#define IPPROTO_TCP 5 +#define IPPROTO_UDP 6 +#define IPPROTO_IGMP 7 +#define IPPROTO_IPIP 8 +#define IPPROTO_DCCP 33 +#define IPPROTO_ROUTING 43 +#define IPPROTO_GRE 47 +#define IPPROTO_ESP 50 +#define IPPROTO_AH 51 +#define IPPROTO_ICMPV6 58 +#define IPPROTO_DSTOPTS 60 +#define IPPROTO_COMP 108 +#define IPPROTO_SCTP 132 +#define IPPROTO_UDPLITE 136 +#define IPPROTO_MAX 256 + +#define INADDR_ANY ((in_addr_t)0x00000000) +#define INADDR_BROADCAST ((in_addr_t)0xffffffff) +#define INADDR_LOOPBACK ((in_addr_t)0x7f000001) +#define INADDR_NONE ((in_addr_t)0xffffffff) + +#define INET_ADDRSTRLEN 16 + +#define INET6_ADDRSTRLEN 46 + +#define IPV6_JOIN_GROUP 1 +#define IPV6_LEAVE_GROUP 2 +#define IPV6_MULTICAST_HOPS 3 +#define IPV6_MULTICAST_IF 4 +#define IPV6_MULTICAST_LOOP 5 +#define IPV6_UNICAST_HOPS 6 +#define IPV6_V6ONLY 7 +#define IPV6_PMTUDISC_DONT 8 +#define IPV6_PMTUDISC_DO 9 +#define IPV6_MTU 10 +#define IPV6_2292PKTOPTIONS 11 +#define IPV6_MTU_DISCOVER 23 +#define IPV6_RECVERR 25 +#define IPV6_RECVPKTINFO 49 +#define IPV6_PKTINFO 50 +#define IPV6_RECVHOPLIMIT 51 +#define IPV6_HOPLIMIT 52 +#define IPV6_TCLASS 67 + +#define IP_TOS 1 +#define IP_TTL 2 +#define IP_OPTIONS 4 +#define IP_PMTUDISC_OMIT 5 +#define IP_PKTINFO 8 +#define IP_PKTOPTIONS 9 +#define IP_MTU_DISCOVER 10 +#define IP_RECVERR 11 +#define IP_RECVTTL 12 +#define IP_UNICAST_IF 13 +#define IP_MTU 14 + +#define IP_DEFAULT_MULTICAST_TTL 1 +#define IP_MULTICAST_IF 32 +#define IP_MULTICAST_TTL 33 +#define IP_MULTICAST_LOOP 34 +#define IP_ADD_MEMBERSHIP 35 +#define IP_DROP_MEMBERSHIP 36 +#define IP_UNBLOCK_SOURCE 37 +#define IP_BLOCK_SOURCE 38 +#define IP_ADD_SOURCE_MEMBERSHIP 39 +#define IP_DROP_SOURCE_MEMBERSHIP 40 +#define MCAST_JOIN_SOURCE_GROUP 46 +#define MCAST_LEAVE_SOURCE_GROUP 47 + +#define IP_PMTUDISC_DONT 0 +#define IP_PMTUDISC_DO 2 + +#define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP +#define IPV6_DROP_MEMBERSHIP IPV6_LEAVE_GROUP + +#endif // _ABIBITS_IN_H diff --git a/lib/mlibc/abis/mlibc/ino_t.h b/lib/mlibc/abis/mlibc/ino_t.h new file mode 100644 index 0000000..a80249f --- /dev/null +++ b/lib/mlibc/abis/mlibc/ino_t.h @@ -0,0 +1,9 @@ + +#ifndef _ABIBITS_INO_T_H +#define _ABIBITS_INO_T_H + +// TODO: use (u)int64_t? +typedef long ino_t; + +#endif // _ABIBITS_INO_T_H + diff --git a/lib/mlibc/abis/mlibc/inotify.h b/lib/mlibc/abis/mlibc/inotify.h new file mode 100644 index 0000000..38c9c77 --- /dev/null +++ b/lib/mlibc/abis/mlibc/inotify.h @@ -0,0 +1,7 @@ +#ifndef _ABIBITS_INOTIFY_H +#define _ABIBITS_INOTIFY_H + +#define IN_CLOEXEC 1 +#define IN_NONBLOCK 2 + +#endif // _ABIBITS_INOTIFY_H diff --git a/lib/mlibc/abis/mlibc/limits.h b/lib/mlibc/abis/mlibc/limits.h new file mode 100644 index 0000000..6aac622 --- /dev/null +++ b/lib/mlibc/abis/mlibc/limits.h @@ -0,0 +1,14 @@ +#ifndef _ABIBITS_LIMITS_H +#define _ABIBITS_LIMITS_H + +#define IOV_MAX 1024 + +// Niceness related +#define NZERO 20 + +// Maximum hostname length, posix defines it as 255 +#define HOST_NAME_MAX 255 + +#define OPEN_MAX 256 + +#endif //_ABIBITS_LIMITS_H diff --git a/lib/mlibc/abis/mlibc/mode_t.h b/lib/mlibc/abis/mlibc/mode_t.h new file mode 100644 index 0000000..c833299 --- /dev/null +++ b/lib/mlibc/abis/mlibc/mode_t.h @@ -0,0 +1,8 @@ + +#ifndef _ABIBITS_MODE_T_H +#define _ABIBITS_MODE_T_H + +typedef int mode_t; + +#endif // _ABIBITS_MODE_T_H + diff --git a/lib/mlibc/abis/mlibc/nlink_t.h b/lib/mlibc/abis/mlibc/nlink_t.h new file mode 100644 index 0000000..cb1e76b --- /dev/null +++ b/lib/mlibc/abis/mlibc/nlink_t.h @@ -0,0 +1,8 @@ + +#ifndef _ABIBITS_NLINK_T_H +#define _ABIBITS_NLINK_T_H + +typedef int nlink_t; + +#endif // _ABIBITS_NLINK_T_H + diff --git a/lib/mlibc/abis/mlibc/packet.h b/lib/mlibc/abis/mlibc/packet.h new file mode 100644 index 0000000..ee1a424 --- /dev/null +++ b/lib/mlibc/abis/mlibc/packet.h @@ -0,0 +1,6 @@ +#ifndef _ABIBITS_PACKET_H +#define _ABIBITS_PACKET_H + +#define PACKET_HOST 0 + +#endif // _ABIBITS_PACKET_H diff --git a/lib/mlibc/abis/mlibc/pid_t.h b/lib/mlibc/abis/mlibc/pid_t.h new file mode 100644 index 0000000..323168e --- /dev/null +++ b/lib/mlibc/abis/mlibc/pid_t.h @@ -0,0 +1,8 @@ + +#ifndef _ABIBITS_PID_T_H +#define _ABIBITS_PID_T_H + +typedef int pid_t; + +#endif // _ABIBITS_PID_T_H + diff --git a/lib/mlibc/abis/mlibc/poll.h b/lib/mlibc/abis/mlibc/poll.h new file mode 100644 index 0000000..e0fe1a5 --- /dev/null +++ b/lib/mlibc/abis/mlibc/poll.h @@ -0,0 +1,16 @@ +#ifndef _ABIBITS_POLL_H +#define _ABIBITS_POLL_H + +#define POLLIN 0x01 +#define POLLOUT 0x02 +#define POLLPRI 0x04 +#define POLLHUP 0x08 +#define POLLERR 0x10 +#define POLLRDHUP 0x20 +#define POLLNVAL 0x40 +#define POLLWRNORM 0x80 +#define POLLRDNORM 0x100 +#define POLLWRBAND 0x200 +#define POLLRDBAND 0x400 + +#endif // _ABIBITS_POLL_H diff --git a/lib/mlibc/abis/mlibc/ptrace.h b/lib/mlibc/abis/mlibc/ptrace.h new file mode 100644 index 0000000..6f35eac --- /dev/null +++ b/lib/mlibc/abis/mlibc/ptrace.h @@ -0,0 +1,56 @@ +#ifndef _ABIBITS_PTRACE_H +#define _ABIBITS_PTRACE_H + +#define PTRACE_PEEKTEXT 1 +#define PTRACE_PEEKDATA 2 +#define PTRACE_PEEKUSER 3 +#define PTRACE_POKETEXT 4 +#define PTRACE_POKEDATA 5 +#define PTRACE_CONT 7 +#define PTRACE_KILL 8 +#define PTRACE_SINGLESTEP 9 +#define PTRACE_GETREGS 14 +#define PTRACE_SETREGS 15 +#define PTRACE_ATTACH 16 +#define PTRACE_DETACH 17 +#define PTRACE_GETFPXREGS 18 +#define PTRACE_SETFPXREGS 19 +#define PTRACE_GETFPREGS 20 +#define PTRACE_SYSCALL 24 +#define PTRACE_SETOPTIONS 0x4200 +#define PTRACE_GETEVENTMSG 0x4201 +#define PTRACE_GETSIGINFO 0x4202 +#define PTRACE_SETSIGINFO 0x4203 +#define PTRACE_GETREGSET 0x4204 +#define PTRACE_SETREGSET 0x4205 +#define PTRACE_SEIZE 0x4206 +#define PTRACE_INTERRUPT 0x4207 +#define PTRACE_LISTEN 0x4208 +#define PTRACE_PEEKSIGINFO 0x4209 +#define PTRACE_GETSIGMASK 0x420A +#define PTRACE_SETSIGMASK 0x420B +#define PTRACE_SECCOMP_GET_FILTER 0x420C + +#define PTRACE_CE_O_TRACESYSGOOD 0x00000001 +#define PTRACE_O_TRACEFORK 0x00000002 +#define PTRACE_O_TRACEVFORK 0x00000004 +#define PTRACE_O_TRACECLONE 0x00000008 +#define PTRACE_O_TRACEEXEC 0x00000010 +#define PTRACE_O_TRACEVFORKDONE 0x00000020 +#define PTRACE_O_TRACEEXIT 0x00000040 +#define PTRACE_O_TRACESECCOMP 0x00000080 +#define PTRACE_O_EXITKILL 0x00100000 +#define PTRACE_O_SUSPEND_SECCOMP 0x00200000 +#define PTRACE_O_MASK 0x003000ff + +#define PTRACE_EVENT_FORK 1 +#define PTRACE_EVENT_VFORK 2 +#define PTRACE_EVENT_CLONE 3 +#define PTRACE_EVENT_EXEC 4 +#define PTRACE_EVENT_VFORK_DONE 5 +#define PTRACE_EVENT_EXIT 6 +#define PTRACE_EVENT_SECCOMP 7 + +#define PTRACE_PEEKSIGINFO_SHARED 1 + +#endif // _ABIBITS_PTRACE_H diff --git a/lib/mlibc/abis/mlibc/resource.h b/lib/mlibc/abis/mlibc/resource.h new file mode 100644 index 0000000..927588b --- /dev/null +++ b/lib/mlibc/abis/mlibc/resource.h @@ -0,0 +1,53 @@ +#ifndef _ABIBITS_RESOURCE_H +#define _ABIBITS_RESOURCE_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#define RUSAGE_SELF 1 +#define RUSAGE_CHILDREN 2 + +#define RLIMIT_CORE 1 +#define RLIMIT_CPU 2 +#define RLIMIT_DATA 3 +#define RLIMIT_FSIZE 4 +#define RLIMIT_NOFILE 5 +#define RLIMIT_STACK 6 +#define RLIMIT_AS 7 +#define RLIMIT_MEMLOCK 8 +#define RLIMIT_RSS 9 +#define RLIMIT_NPROC 10 +#define RLIMIT_LOCKS 11 +#define RLIMIT_SIGPENDING 12 +#define RLIMIT_MSGQUEUE 13 +#define RLIMIT_NICE 14 +#define RLIMIT_RTPRIO 15 +#define RLIMIT_NLIMITS 16 + +struct rusage { + struct timeval ru_utime; + struct timeval ru_stime; + long int ru_maxrss; + long int ru_ixrss; + long int ru_idrss; + long int ru_isrss; + long int ru_minflt; + long int ru_majflt; + long int ru_nswap; + long int ru_inblock; + long int ru_oublock; + long int ru_msgsnd; + long int ru_msgrcv; + long int ru_nsignals; + long int ru_nvcsw; + long int ru_nivcsw; +}; + +#ifdef __cplusplus +} +#endif + +#endif // _ABIBITS_RESOURCE_H diff --git a/lib/mlibc/abis/mlibc/seek-whence.h b/lib/mlibc/abis/mlibc/seek-whence.h new file mode 100644 index 0000000..5af138b --- /dev/null +++ b/lib/mlibc/abis/mlibc/seek-whence.h @@ -0,0 +1,10 @@ +#ifndef _ABIBITS_SEEK_WHENCE_H +#define _ABIBITS_SEEK_WHENCE_H + +#define SEEK_CUR 1 +#define SEEK_END 2 +#define SEEK_SET 3 +#define SEEK_DATA 4 +#define SEEK_HOLE 5 + +#endif // _ABIBITS_SEEK_WHENCE_H diff --git a/lib/mlibc/abis/mlibc/signal.h b/lib/mlibc/abis/mlibc/signal.h new file mode 100644 index 0000000..320bea7 --- /dev/null +++ b/lib/mlibc/abis/mlibc/signal.h @@ -0,0 +1,195 @@ +#ifndef _ABIBITS_SIGNAL_H +#define _ABIBITS_SIGNAL_H + +#if __MLIBC_BUILDING_MLIBC +#warning abis/mlibc/signal.h is deprecated. We suggest to use abis/linux/signal.h instead. \ + Note that this will potentially require kernel changes. +#endif + +#include +#include +#include +#include + +union sigval { + int sival_int; + void *sival_ptr; +}; + +typedef struct { + int si_signo; + int si_code; + int si_errno; + pid_t si_pid; + uid_t si_uid; + void *si_addr; + int si_status; + union sigval si_value; +} siginfo_t; + +#ifdef __cplusplus +extern "C" { +#endif + +// Argument for signal() +typedef void (*__sighandler) (int); + +#define SIG_ERR ((__sighandler)(void *)(-1)) +#define SIG_DFL ((__sighandler)(void *)(-2)) +#define SIG_IGN ((__sighandler)(void *)(-3)) + +#define SIGHUP 1 +#define SIGINT 2 +#define SIGQUIT 3 +#define SIGILL 4 +#define SIGTRAP 5 +#define SIGABRT 6 +#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 SIGIO +#define SIGPWR 30 +#define SIGSYS 31 +#define SIGRTMIN 32 +#define SIGRTMAX 33 +#define SIGCANCEL 34 + +// siginfo->si_info constants +// SIGBUS +#define BUS_ADRALN 1 +#define BUS_ADRERR 2 +#define BUS_OBJERR 3 + +// SIGILL +#define ILL_ILLOPC 1 +#define ILL_ILLOPN 2 +#define ILL_ILLADR 3 +#define ILL_ILLTRP 4 +#define ILL_PRVOPC 5 +#define ILL_PRVREG 6 +#define ILL_COPROC 7 +#define ILL_BADSTK 8 +#define ILL_BADIADDR 9 + +// SIGSEGV +#define SEGV_MAPERR 1 +#define SEGV_ACCERR 2 + +typedef __mlibc_uint64 sigset_t; + +#define SIGUNUSED SIGSYS + +// constants for sigprocmask() +#define SIG_BLOCK 1 +#define SIG_UNBLOCK 2 +#define SIG_SETMASK 3 + +#define SA_NOCLDSTOP (1 << 0) +#define SA_ONSTACK (1 << 1) +#define SA_RESETHAND (1 << 2) +#define SA_RESTART (1 << 3) +#define SA_SIGINFO (1 << 4) +#define SA_NOCLDWAIT (1 << 5) +#define SA_NODEFER (1 << 6) + +#define MINSIGSTKSZ 2048 +#define SIGSTKSZ 8192 +#define SS_ONSTACK 1 +#define SS_DISABLE 2 + +typedef struct __stack { + void *ss_sp; + size_t ss_size; + int ss_flags; +} stack_t; + +// constants for sigev_notify of struct sigevent +#define SIGEV_NONE 1 +#define SIGEV_SIGNAL 2 +#define SIGEV_THREAD 3 + +#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 + +#define NSIG 65 +#define _NSIG NSIG + +#define CLD_EXITED 1 +#define CLD_KILLED 2 +#define CLD_DUMPED 3 +#define CLD_TRAPPED 4 +#define CLD_STOPPED 5 +#define CLD_CONTINUED 6 + +struct sigevent { + int sigev_notify; + int sigev_signo; + union sigval sigev_value; + void (*sigev_notify_function)(union sigval); + // MISSING: sigev_notify_attributes +}; + +struct sigaction { + void (*sa_handler)(int); + sigset_t sa_mask; + int sa_flags; + void (*sa_sigaction)(int, siginfo_t *, void *); +}; + +#if defined(__x86_64__) || defined(__i386__) || defined(__aarch64__) +// TODO: This is wrong for AArch64. + +typedef struct { + unsigned long oldmask; + unsigned long gregs[16]; + unsigned long pc, pr, sr; + unsigned long gbr, mach, macl; + unsigned long fpregs[16]; + unsigned long xfpregs[16]; + unsigned int fpscr, fpul, ownedfp; +} mcontext_t; + +typedef struct __ucontext { + unsigned long uc_flags; + struct __ucontext *uc_link; + stack_t uc_stack; + mcontext_t uc_mcontext; + sigset_t uc_sigmask; +} ucontext_t; + +#else +#error "Missing architecture specific code." +#endif + +#ifdef __cplusplus +} +#endif + +#endif // _ABIBITS_SIGNAL_H diff --git a/lib/mlibc/abis/mlibc/socket.h b/lib/mlibc/abis/mlibc/socket.h new file mode 100644 index 0000000..48b8178 --- /dev/null +++ b/lib/mlibc/abis/mlibc/socket.h @@ -0,0 +1,165 @@ +#ifndef _ABIBITS_SOCKET_H +#define _ABIBITS_SOCKET_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef unsigned int sa_family_t; + +struct msghdr { + void *msg_name; + socklen_t msg_namelen; + struct iovec *msg_iov; + int msg_iovlen; + void *msg_control; + socklen_t msg_controllen; + int msg_flags; +}; + +struct sockaddr_storage { + sa_family_t ss_family; + char __padding[128 - sizeof(sa_family_t)]; +}; + +struct mmsghdr { + struct msghdr msg_hdr; + unsigned int msg_len; +}; + +struct cmsghdr { + socklen_t cmsg_len; + int cmsg_level; + int cmsg_type; +}; + +#ifdef __cplusplus +} +#endif + +#define SCM_RIGHTS 1 +#define SCM_TIMESTAMP SO_TIMESTAMP +#define SCM_TIMESTAMPNS SO_TIMESTAMPNS + +//MISSING: CMSG_DATA, CMSG_NXTHDR, CMSG_FIRSTHDR + +#define SCM_CREDENTIALS 0x02 + +#define SOCK_DGRAM 1 +#define SOCK_RAW 2 +#define SOCK_SEQPACKET 3 +#define SOCK_STREAM 4 +#define SOCK_DCCP 5 +#define SOCK_NONBLOCK 0x10000 +#define SOCK_CLOEXEC 0x20000 +#define SOCK_RDM 0x40000 + +#define SOL_SOCKET 1 +#define SOL_IPV6 41 +#define SOL_PACKET 263 +#define SOL_NETLINK 270 + +#define SO_ACCEPTCONN 1 +#define SO_BROADCAST 2 +#define SO_DEBUG 3 +#define SO_DONTROUTE 4 +#define SO_ERROR 5 +#define SO_KEEPALIVE 6 +#define SO_LINGER 7 +#define SO_OOBINLINE 8 +#define SO_RCVBUF 9 +#define SO_RCVLOWAT 10 +#define SO_RCVTIMEO 11 +#define SO_REUSEADDR 12 +#define SO_SNDBUF 13 +#define SO_SNDLOWAT 14 +#define SO_SNDTIMEO 15 +#define SO_TYPE 16 +#define SO_SNDBUFFORCE 17 +#define SO_PEERCRED 18 +#define SO_ATTACH_FILTER 19 +#define SO_PASSCRED 20 +#define SO_RCVBUFFORCE 21 +#define SO_DETACH_FILTER 22 +#define SO_PROTOCOL 23 +#define SO_REUSEPORT 24 +#define SO_TIMESTAMP 25 +#define SO_PEERSEC 26 +#define SO_BINDTODEVICE 27 +#define SO_DOMAIN 28 +#define SO_PASSSEC 29 +#define SO_TIMESTAMPNS 30 +#define SO_PRIORITY 31 +#define SO_MARK 32 + +#define SOMAXCONN 1 + +#define MSG_CTRUNC 0x1 +#define MSG_DONTROUTE 0x2 +#define MSG_EOR 0x4 +#define MSG_OOB 0x8 +#define MSG_NOSIGNAL 0x10 +#define MSG_PEEK 0x20 +#define MSG_TRUNC 0x40 +#define MSG_WAITALL 0x80 +#define MSG_FIN 0x200 +#define MSG_CONFIRM 0x800 + +// Linux extensions. +#define MSG_DONTWAIT 0x1000 +#define MSG_CMSG_CLOEXEC 0x2000 +#define MSG_MORE 0x4000 +#define MSG_FASTOPEN 0x20000000 + +// GNU (?) extension: Protocol family constants. + +#define PF_INET 1 +#define PF_INET6 2 +#define PF_UNIX 3 +#define PF_LOCAL 3 +#define PF_UNSPEC 4 +#define PF_NETLINK 5 +#define PF_BRIDGE 6 +#define PF_APPLETALK 7 +#define PF_BLUETOOTH 8 +#define PF_DECnet 9 +#define PF_IPX 10 +#define PF_ISDN 11 +#define PF_SNA 12 +#define PF_PACKET 13 +#define PF_AX25 14 +#define PF_NETROM 15 +#define PF_ROSE 16 +#define PF_TIPC 30 +#define PF_ALG 38 +#define PF_MAX 46 + +#define AF_INET PF_INET +#define AF_INET6 PF_INET6 +#define AF_UNIX PF_UNIX +#define AF_LOCAL PF_LOCAL +#define AF_UNSPEC PF_UNSPEC +#define AF_NETLINK PF_NETLINK +#define AF_BRIDGE PF_BRIDGE +#define AF_APPLETALK PF_APPLETALK +#define AF_BLUETOOTH PF_BLUETOOTH +#define AF_DECnet PF_DECnet +#define AF_IPX PF_IPX +#define AF_ISDN PF_ISDN +#define AF_SNA PF_SNA +#define AF_PACKET PF_PACKET +#define AF_PACKET PF_PACKET +#define AF_AX25 PF_AX25 +#define AF_NETROM PF_NETROM +#define AF_ROSE PF_ROSE +#define AF_TIPC PF_TIPC +#define AF_ALG PF_ALG +#define AF_MAX PF_MAX + +#define SHUT_RD 1 +#define SHUT_RDWR 2 +#define SHUT_WR 3 +#endif diff --git a/lib/mlibc/abis/mlibc/stat.h b/lib/mlibc/abis/mlibc/stat.h new file mode 100644 index 0000000..3f55970 --- /dev/null +++ b/lib/mlibc/abis/mlibc/stat.h @@ -0,0 +1,69 @@ +#ifndef _ABIBITS_STAT_H +#define _ABIBITS_STAT_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define S_IFMT 0x0F000 +#define S_IFBLK 0x06000 +#define S_IFCHR 0x02000 +#define S_IFIFO 0x01000 +#define S_IFREG 0x08000 +#define S_IFDIR 0x04000 +#define S_IFLNK 0x0A000 +#define S_IFSOCK 0x0C000 + +#define S_IRWXU 0700 +#define S_IRUSR 0400 +#define S_IWUSR 0200 +#define S_IXUSR 0100 +#define S_IRWXG 070 +#define S_IRGRP 040 +#define S_IWGRP 020 +#define S_IXGRP 010 +#define S_IRWXO 07 +#define S_IROTH 04 +#define S_IWOTH 02 +#define S_IXOTH 01 +#define S_ISUID 04000 +#define S_ISGID 02000 +#define S_ISVTX 01000 + +#define S_IREAD S_IRUSR +#define S_IWRITE S_IWUSR +#define S_IEXEC S_IXUSR + +#ifdef __cplusplus +extern "C" { +#endif + +struct stat { + dev_t st_dev; + ino_t st_ino; + mode_t st_mode; + nlink_t st_nlink; + uid_t st_uid; + gid_t st_gid; + dev_t st_rdev; + off_t st_size; + struct timespec st_atim; + struct timespec st_mtim; + struct timespec st_ctim; + blksize_t st_blksize; + blkcnt_t st_blocks; +}; + +#ifdef __cplusplus +} +#endif + +#endif // _ABIBITS_STAT_H diff --git a/lib/mlibc/abis/mlibc/termios.h b/lib/mlibc/abis/mlibc/termios.h new file mode 100644 index 0000000..49af908 --- /dev/null +++ b/lib/mlibc/abis/mlibc/termios.h @@ -0,0 +1,118 @@ +#ifndef _ABIBITS_TERMIOS_H +#define _ABIBITS_TERMIOS_H + +#if __MLIBC_BUILDING_MLIBC +#warning abis/mlibc/termios.h is deprecated. We suggest to use abis/linux/termios.h instead. \ + Note that this will potentially require kernel changes. +#endif + +typedef unsigned int cc_t; +typedef unsigned int speed_t; +typedef unsigned int tcflag_t; + +// indices for the c_cc array in struct termios +#define NCCS 11 +#define VEOF 0 +#define VEOL 1 +#define VERASE 2 +#define VINTR 3 +#define VKILL 4 +#define VMIN 5 +#define VQUIT 6 +#define VSTART 7 +#define VSTOP 8 +#define VSUSP 9 +#define VTIME 10 + +// bitwise flags for c_iflag in struct termios +#define BRKINT 0x0001 +#define ICRNL 0x0002 +#define IGNBRK 0x0004 +#define IGNCR 0x0008 +#define IGNPAR 0x0010 +#define INLCR 0x0020 +#define INPCK 0x0040 +#define ISTRIP 0x0080 +#define IXANY 0x0100 +#define IXOFF 0x0200 +#define IXON 0x0400 +#define PARMRK 0x0800 + +// bitwise flags for c_oflag in struct termios +#define OPOST 0x0001 +#define ONLCR 0x0002 +#define OCRNL 0x0004 +#define ONOCR 0x0008 +#define ONLRET 0x0010 +#define OFDEL 0x0020 +#define OFILL 0x0040 + +#define NLDLY 0x0080 +#define NL0 0x0000 +#define NL1 0x0080 + +#define CRDLY 0x0300 +#define CR0 0x0000 +#define CR1 0x0100 +#define CR2 0x0200 +#define CR3 0x0300 + +#define TABDLY 0x0C00 +#define TAB0 0x0000 +#define TAB1 0x0400 +#define TAB2 0x0800 +#define TAB3 0x0C00 + +#define BSDLY 0x1000 +#define BS0 0x0000 +#define BS1 0x1000 + +#define VTDLY 0x2000 +#define VT0 0x0000 +#define VT1 0x2000 + +#define FFDLY 0x4000 +#define FF0 0x0000 +#define FF1 0x4000 + +// bitwise constants for c_cflag in struct termios +#define CSIZE 0x0003 +#define CS5 0x0000 +#define CS6 0x0001 +#define CS7 0x0002 +#define CS8 0x0003 + +#define CSTOPB 0x0004 +#define CREAD 0x0008 +#define PARENB 0x0010 +#define PARODD 0x0020 +#define HUPCL 0x0040 +#define CLOCAL 0x0080 + +#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE) +#define CBAUD 0x100F +#endif + +// bitwise constants for c_lflag in struct termios +#define ECHO 0x0001 +#define ECHOE 0x0002 +#define ECHOK 0x0004 +#define ECHONL 0x0008 +#define ICANON 0x0010 +#define IEXTEN 0x0020 +#define ISIG 0x0040 +#define NOFLSH 0x0080 +#define TOSTOP 0x0100 +#define ECHOPRT 0x0200 + +struct termios { + tcflag_t c_iflag; + tcflag_t c_oflag; + tcflag_t c_cflag; + tcflag_t c_lflag; + cc_t c_cc[NCCS]; + speed_t ibaud; + speed_t obaud; +}; + +#endif diff --git a/lib/mlibc/abis/mlibc/time.h b/lib/mlibc/abis/mlibc/time.h new file mode 100644 index 0000000..3f49db3 --- /dev/null +++ b/lib/mlibc/abis/mlibc/time.h @@ -0,0 +1,15 @@ +#ifndef _ABIBITS_TIME_H +#define _ABIBITS_TIME_H + +#include + +struct itimerval { + struct timeval it_interval; /* Interval for periodic timer */ + struct timeval it_value; /* Time until next expiration */ +}; + +#define ITIMER_REAL 0 +#define ITIMER_VIRTUAL 1 +#define ITIMER_PROF 2 + +#endif // _ABIBITS_TIME_H diff --git a/lib/mlibc/abis/mlibc/uid_t.h b/lib/mlibc/abis/mlibc/uid_t.h new file mode 100644 index 0000000..5b53ca3 --- /dev/null +++ b/lib/mlibc/abis/mlibc/uid_t.h @@ -0,0 +1,8 @@ + +#ifndef _ABIBITS_UID_T_H +#define _ABIBITS_UID_T_H + +typedef unsigned int uid_t; + +#endif // _ABIBITS_UID_T_H + diff --git a/lib/mlibc/abis/mlibc/utsname.h b/lib/mlibc/abis/mlibc/utsname.h new file mode 100644 index 0000000..4e212b3 --- /dev/null +++ b/lib/mlibc/abis/mlibc/utsname.h @@ -0,0 +1,17 @@ +#ifndef _ABIBITS_UTSNAME_T_H +#define _ABIBITS_UTSNAME_T_H + +#if __MLIBC_BUILDING_MLIBC +#warning abis/mlibc/utsname.h is deprecated. We suggest to use abis/linux/utsname.h instead. \ + Note that this will potentially require kernel changes. +#endif + +struct utsname { + char sysname[65]; + char nodename[65]; + char release[65]; + char version[65]; + char machine[65]; +}; + +#endif // _ABIBITS_UTSNAME_T_H diff --git a/lib/mlibc/abis/mlibc/vm-flags.h b/lib/mlibc/abis/mlibc/vm-flags.h new file mode 100644 index 0000000..700d745 --- /dev/null +++ b/lib/mlibc/abis/mlibc/vm-flags.h @@ -0,0 +1,46 @@ +#ifndef _ABIBITS_MMAP_FLAGS_H +#define _ABIBITS_MMAP_FLAGS_H + +#define PROT_NONE 0x00 +#define PROT_READ 0x01 +#define PROT_WRITE 0x02 +#define PROT_EXEC 0x04 + +#define MAP_FAILED ((void *)(-1)) +#define MAP_FILE 0x00 +#define MAP_PRIVATE 0x01 +#define MAP_SHARED 0x02 +#define MAP_FIXED 0x04 +#define MAP_ANON 0x08 +#define MAP_ANONYMOUS 0x08 +#define MAP_NORESERVE 0x10 +#define MAP_FIXED_NOREPLACE 0x20 + +#define MS_ASYNC 0x01 +#define MS_SYNC 0x02 +#define MS_INVALIDATE 0x04 + +#define MCL_CURRENT 0x01 +#define MCL_FUTURE 0x02 + +#define POSIX_MADV_NORMAL 1 +#define POSIX_MADV_SEQUENTIAL 2 +#define POSIX_MADV_RANDOM 3 +#define POSIX_MADV_DONTNEED 4 +#define POSIX_MADV_WILLNEED 5 + +#define MADV_NORMAL 0 +#define MADV_RANDOM 1 +#define MADV_SEQUENTIAL 2 +#define MADV_WILLNEED 3 +#define MADV_DONTNEED 4 +#define MADV_FREE 8 + +// Linux extensions: +#define MREMAP_MAYMOVE 1 +#define MREMAP_FIXED 2 + +#define MFD_CLOEXEC 1U +#define MFD_ALLOW_SEALING 2U + +#endif // _ABIBITS_MMAP_FLAGS_H diff --git a/lib/mlibc/abis/mlibc/wait.h b/lib/mlibc/abis/mlibc/wait.h new file mode 100644 index 0000000..ebc7ee6 --- /dev/null +++ b/lib/mlibc/abis/mlibc/wait.h @@ -0,0 +1,30 @@ +#ifndef _ABIBITS_WAIT_H +#define _ABIBITS_WAIT_H + +#if __MLIBC_BUILDING_MLIBC +#warning abis/mlibc/wait.h is deprecated. We suggest to use abis/linux/wait.h instead. \ + Note that this will potentially require kernel changes. +#endif + +#define WCONTINUED 1 +#define WNOHANG 2 +#define WUNTRACED 4 +#define WEXITED 8 +#define WNOWAIT 16 +#define WSTOPPED 32 + +#define __WALL 0x40000000 +#define __WCLONE 0x80000000 + +#define WCOREFLAG 0x80 + +#define WEXITSTATUS(x) ((x) & 0x000000FF) +#define WIFCONTINUED(x) ((x) & 0x00000100) +#define WIFEXITED(x) ((x) & 0x00000200) +#define WIFSIGNALED(x) ((x) & 0x00000400) +#define WIFSTOPPED(x) ((x) & 0x00000800) +#define WSTOPSIG(x) (((x) & 0x00FF0000) >> 16) +#define WTERMSIG(x) (((x) & 0xFF000000) >> 24) +#define WCOREDUMP(x) ((x) & WCOREFLAG) + +#endif //_ABIBITS_WAIT_H diff --git a/lib/mlibc/ci/abidiff_suppress.ini b/lib/mlibc/ci/abidiff_suppress.ini new file mode 100644 index 0000000..0f68976 --- /dev/null +++ b/lib/mlibc/ci/abidiff_suppress.ini @@ -0,0 +1,2 @@ +[suppress_function] +name_regexp = ^(mlibc|frg|std)::.* diff --git a/lib/mlibc/ci/aero.cross-file b/lib/mlibc/ci/aero.cross-file new file mode 100644 index 0000000..48772eb --- /dev/null +++ b/lib/mlibc/ci/aero.cross-file @@ -0,0 +1,12 @@ +[binaries] +c = 'x86_64-linux-mlibc-gcc' +cpp = 'x86_64-linux-mlibc-g++' + +[properties] +needs_exe_wrapper = true + +[host_machine] +system = 'aero' +cpu_family = 'x86_64' +cpu = 'x86_64' +endian = 'little' diff --git a/lib/mlibc/ci/bootstrap.yml b/lib/mlibc/ci/bootstrap.yml new file mode 100644 index 0000000..f166bcc --- /dev/null +++ b/lib/mlibc/ci/bootstrap.yml @@ -0,0 +1,181 @@ +declare_options: + - name: arch + default: x86_64 + +sources: + - name: mlibc + git: 'https://github.com/managarm/mlibc.git' + branch: 'master' + + - name: linux + url: 'https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-6.1.8.tar.xz' + extract_path: 'linux-6.1.8' + format: 'tar.xz' + version: '6.1.8' + +tools: + +packages: + - name: mlibc + architecture: '@OPTION:arch@' + from_source: mlibc + pkgs_required: + - linux-headers + configure: + - args: + - 'meson' + - 'setup' + - '--prefix=/usr' + - '--libdir=lib' + - '--buildtype=debugoptimized' + - "-Dc_args=['-Wno-error=maybe-uninitialized']" + - "-Dcpp_args=['-Wno-error=maybe-uninitialized']" + - "-Dbuild_tests=true" + - "-Db_sanitize=undefined" + - "-Ddefault_library=both" + - "-Dwerror=true" + - '-Dlinux_kernel_headers=@BUILD_ROOT@/packages/linux-headers/usr/include' + - "--cross-file=@THIS_SOURCE_DIR@/ci/linux-@OPTION:arch@.cross-file" + - '@THIS_SOURCE_DIR@' + environ: + CFLAGS: '-Wno-error=maybe-uninitialized' + CXXFLAGS: '-Wno-error=maybe-uninitialized' + build: + - args: ['ninja'] + - args: ['ninja', 'install'] + environ: + DESTDIR: '@THIS_COLLECT_DIR@' + quiet: true + + - name: mlibc-static + architecture: '@OPTION:arch@' + from_source: mlibc + pkgs_required: + - linux-headers + configure: + - args: + - 'meson' + - 'setup' + - '--prefix=/usr' + - '--libdir=lib' + - '--buildtype=debugoptimized' + - "-Dc_args=['-Wno-error=maybe-uninitialized']" + - "-Dcpp_args=['-Wno-error=maybe-uninitialized']" + - "-Dbuild_tests=true" + - "-Db_sanitize=undefined" + - "-Ddefault_library=static" + - "-Dwerror=true" + - '-Dlinux_kernel_headers=@BUILD_ROOT@/packages/linux-headers/usr/include' + - "--cross-file=@THIS_SOURCE_DIR@/ci/linux-@OPTION:arch@.cross-file" + - '@THIS_SOURCE_DIR@' + build: + - args: ['ninja'] + - args: ['ninja', 'install'] + environ: + DESTDIR: '@THIS_COLLECT_DIR@' + quiet: true + + - name: mlibc-shared + from_source: mlibc + pkgs_required: + - linux-headers + configure: + - args: + - 'meson' + - 'setup' + - '--prefix=/usr' + - '--libdir=lib' + - '--buildtype=debugoptimized' + - "-Dc_args=['-Wno-error=maybe-uninitialized']" + - "-Dcpp_args=['-Wno-error=maybe-uninitialized']" + - "-Dbuild_tests=true" + - "-Db_sanitize=undefined" + - "-Ddefault_library=shared" + - "-Dwerror=true" + - '-Dlinux_kernel_headers=@BUILD_ROOT@/packages/linux-headers/usr/include' + - "--cross-file=@THIS_SOURCE_DIR@/ci/linux-@OPTION:arch@.cross-file" + - '@THIS_SOURCE_DIR@' + build: + - args: ['ninja'] + - args: ['ninja', 'install'] + environ: + DESTDIR: '@THIS_COLLECT_DIR@' + quiet: true + + - name: mlibc-ansi-only + architecture: '@OPTION:arch@' + from_source: mlibc + pkgs_required: + - linux-headers + configure: + - args: + - 'meson' + - 'setup' + - '--prefix=/usr' + - '--libdir=lib' + - '--buildtype=debugoptimized' + - "-Dc_args=['-Wno-error=maybe-uninitialized']" + - "-Dcpp_args=['-Wno-error=maybe-uninitialized']" + - "-Dbuild_tests=true" + - "-Db_sanitize=undefined" + - "-Ddefault_library=both" + - "-Dwerror=true" + - "-Ddisable_posix_option=true" + - "-Ddisable_linux_option=true" + - "-Ddisable_glibc_option=true" + - "-Ddisable_bsd_option=true" + - '-Dlinux_kernel_headers=@BUILD_ROOT@/packages/linux-headers/usr/include' + - "--cross-file=@THIS_SOURCE_DIR@/ci/linux-@OPTION:arch@.cross-file" + - '@THIS_SOURCE_DIR@' + build: + - args: ['ninja'] + - args: ['ninja', 'install'] + environ: + DESTDIR: '@THIS_COLLECT_DIR@' + quiet: true + + - name: mlibc-headers-only + architecture: '@OPTION:arch@' + from_source: mlibc + pkgs_required: + - linux-headers + configure: + - args: + - 'meson' + - 'setup' + - '--prefix=/usr' + - '--libdir=lib' + - '--buildtype=debugoptimized' + - "-Dc_args=['-Wno-error=maybe-uninitialized']" + - "-Dcpp_args=['-Wno-error=maybe-uninitialized']" + - "-Db_sanitize=undefined" + - "-Dwerror=true" + - "-Dheaders_only=true" + - '-Dlinux_kernel_headers=@BUILD_ROOT@/packages/linux-headers/usr/include' + - "--cross-file=@THIS_SOURCE_DIR@/ci/linux-@OPTION:arch@.cross-file" + - '@THIS_SOURCE_DIR@' + build: + - args: ['ninja'] + - args: ['ninja', 'install'] + environ: + DESTDIR: '@THIS_COLLECT_DIR@' + quiet: true + + - name: linux-headers + architecture: '@OPTION:arch@' + from_source: linux + configure: + # custom build system requires in tree-ish builds + - args: ['cp', '-Tr', '@THIS_SOURCE_DIR@/', '.'] + build: + - args: | + LINUX_ARCH="@OPTION:arch@" + case "$LINUX_ARCH" in + "aarch64") + LINUX_ARCH="arm64" + ;; + "riscv64") + LINUX_ARCH="riscv" + ;; + esac + make O=@THIS_COLLECT_DIR@ ARCH="$LINUX_ARCH" headers_install diff --git a/lib/mlibc/ci/dripos.cross-file b/lib/mlibc/ci/dripos.cross-file new file mode 100644 index 0000000..6a79be9 --- /dev/null +++ b/lib/mlibc/ci/dripos.cross-file @@ -0,0 +1,12 @@ +[binaries] +c = 'x86_64-linux-mlibc-gcc' +cpp = 'x86_64-linux-mlibc-g++' + +[properties] +needs_exe_wrapper = true + +[host_machine] +system = 'dripos' +cpu_family = 'x86_64' +cpu = 'x86_64' +endian = 'little' diff --git a/lib/mlibc/ci/ironclad.cross-file b/lib/mlibc/ci/ironclad.cross-file new file mode 100644 index 0000000..f016592 --- /dev/null +++ b/lib/mlibc/ci/ironclad.cross-file @@ -0,0 +1,12 @@ +[binaries] +c = 'x86_64-linux-mlibc-gcc' +cpp = 'x86_64-linux-mlibc-g++' + +[properties] +needs_exe_wrapper = true + +[host_machine] +system = 'ironclad' +cpu_family = 'x86_64' +cpu = 'x86_64' +endian = 'little' diff --git a/lib/mlibc/ci/keyronex.cross-file b/lib/mlibc/ci/keyronex.cross-file new file mode 100644 index 0000000..d77a540 --- /dev/null +++ b/lib/mlibc/ci/keyronex.cross-file @@ -0,0 +1,9 @@ +[binaries] +c = ['x86_64-linux-mlibc-gcc'] +cpp = ['x86_64-linux-mlibc-g++'] + +[host_machine] +system = 'keyronex' +cpu_family = 'x86_64' +cpu = 'x86_64' +endian = 'little' diff --git a/lib/mlibc/ci/lemon.cross-file b/lib/mlibc/ci/lemon.cross-file new file mode 100644 index 0000000..23dcf7e --- /dev/null +++ b/lib/mlibc/ci/lemon.cross-file @@ -0,0 +1,12 @@ +[binaries] +c = 'x86_64-linux-mlibc-gcc' +cpp = 'x86_64-linux-mlibc-g++' + +[properties] +needs_exe_wrapper = true + +[host_machine] +system = 'lemon' +cpu_family = 'x86_64' +cpu = 'x86_64' +endian = 'little' diff --git a/lib/mlibc/ci/linux-aarch64.cross-file b/lib/mlibc/ci/linux-aarch64.cross-file new file mode 100644 index 0000000..f1843ae --- /dev/null +++ b/lib/mlibc/ci/linux-aarch64.cross-file @@ -0,0 +1,13 @@ +[properties] +skip_sanity_check = true + +[binaries] +c = ['aarch64-linux-mlibc-gcc'] +cpp = ['aarch64-linux-mlibc-g++'] +exe_wrapper = 'qemu-aarch64' + +[host_machine] +system = 'linux' +cpu_family = 'aarch64' +cpu = 'unknown' +endian = 'little' diff --git a/lib/mlibc/ci/linux-riscv64.cross-file b/lib/mlibc/ci/linux-riscv64.cross-file new file mode 100644 index 0000000..283eaf2 --- /dev/null +++ b/lib/mlibc/ci/linux-riscv64.cross-file @@ -0,0 +1,13 @@ +[properties] +skip_sanity_check = true + +[binaries] +c = ['riscv64-linux-mlibc-gcc'] +cpp = ['riscv64-linux-mlibc-g++'] +exe_wrapper = 'qemu-riscv64' + +[host_machine] +system = 'linux' +cpu_family = 'riscv64' +cpu = 'unknown' +endian = 'little' diff --git a/lib/mlibc/ci/linux-x86.cross-file b/lib/mlibc/ci/linux-x86.cross-file new file mode 100644 index 0000000..edad985 --- /dev/null +++ b/lib/mlibc/ci/linux-x86.cross-file @@ -0,0 +1,10 @@ +[binaries] +c = 'i686-linux-mlibc-gcc' +cpp = 'i686-linux-mlibc-g++' +exe_wrapper = 'qemu-i386' + +[host_machine] +system = 'linux' +cpu_family = 'x86' +cpu = 'i386' +endian = 'little' diff --git a/lib/mlibc/ci/linux-x86_64.cross-file b/lib/mlibc/ci/linux-x86_64.cross-file new file mode 100644 index 0000000..fdf2b2d --- /dev/null +++ b/lib/mlibc/ci/linux-x86_64.cross-file @@ -0,0 +1,9 @@ +[binaries] +c = ['x86_64-linux-mlibc-gcc'] +cpp = ['x86_64-linux-mlibc-g++'] + +[host_machine] +system = 'linux' +cpu_family = 'x86_64' +cpu = 'x86_64' +endian = 'little' diff --git a/lib/mlibc/ci/lyre.cross-file b/lib/mlibc/ci/lyre.cross-file new file mode 100644 index 0000000..1d4cd70 --- /dev/null +++ b/lib/mlibc/ci/lyre.cross-file @@ -0,0 +1,12 @@ +[binaries] +c = 'x86_64-linux-mlibc-gcc' +cpp = 'x86_64-linux-mlibc-g++' + +[properties] +needs_exe_wrapper = true + +[host_machine] +system = 'lyre' +cpu_family = 'x86_64' +cpu = 'x86_64' +endian = 'little' diff --git a/lib/mlibc/ci/managarm.cross-file b/lib/mlibc/ci/managarm.cross-file new file mode 100644 index 0000000..0e1d48f --- /dev/null +++ b/lib/mlibc/ci/managarm.cross-file @@ -0,0 +1,12 @@ +[binaries] +c = 'x86_64-linux-mlibc-gcc' +cpp = 'x86_64-linux-mlibc-g++' + +[properties] +needs_exe_wrapper = true + +[host_machine] +system = 'managarm' +cpu_family = 'x86_64' +cpu = 'x86_64' +endian = 'little' diff --git a/lib/mlibc/cross_file.txt b/lib/mlibc/cross_file.txt new file mode 100644 index 0000000..68ae81e --- /dev/null +++ b/lib/mlibc/cross_file.txt @@ -0,0 +1,12 @@ +[binaries] +c = '@DIRNAME@/crossbin/x86_64-hyra-gcc' +cpp = '@DIRNAME@/crossbin/x86_64-hyra-g++' +ar = '@DIRNAME@/crossbin/x86_64-hyra-ar' +strip = '@DIRNAME@/crossbin/x86_64-hyra-strip' +pkg-config = 'pkg-config' + +[host_machine] +system = 'hyra' +cpu_family = 'x86_64' +cpu = 'x86_64' +endian = 'little' diff --git a/lib/mlibc/crossbin b/lib/mlibc/crossbin new file mode 120000 index 0000000..d0ddc89 --- /dev/null +++ b/lib/mlibc/crossbin @@ -0,0 +1 @@ +../../cross/bin/ \ No newline at end of file diff --git a/lib/mlibc/dummy-libs/libcrypt/src/dummy.cpp b/lib/mlibc/dummy-libs/libcrypt/src/dummy.cpp new file mode 100644 index 0000000..6c3a4c2 --- /dev/null +++ b/lib/mlibc/dummy-libs/libcrypt/src/dummy.cpp @@ -0,0 +1,6 @@ + +// We build an empty libcrypt because shadow expects -lcrypt +// The actual crypt functions reside inside libc + +extern "C" void __mlibc_libcrypt_dummy(void) { } + diff --git a/lib/mlibc/dummy-libs/libdl/src/dummy.cpp b/lib/mlibc/dummy-libs/libdl/src/dummy.cpp new file mode 100644 index 0000000..c9d4287 --- /dev/null +++ b/lib/mlibc/dummy-libs/libdl/src/dummy.cpp @@ -0,0 +1,6 @@ + +// We build an empty libdl because g++ always links with -ldl +// The actual functions reside inside libc + +extern "C" void __mlibc_libdl_dummy(void) { } + diff --git a/lib/mlibc/dummy-libs/libm/src/dummy.cpp b/lib/mlibc/dummy-libs/libm/src/dummy.cpp new file mode 100644 index 0000000..eed43ca --- /dev/null +++ b/lib/mlibc/dummy-libs/libm/src/dummy.cpp @@ -0,0 +1,6 @@ + +// We build an empty libm because g++ always links with -lm +// The actual math functions reside inside libc + +extern "C" void __mlibc_libm_dummy(void) { } + diff --git a/lib/mlibc/dummy-libs/libpthread/src/dummy.cpp b/lib/mlibc/dummy-libs/libpthread/src/dummy.cpp new file mode 100644 index 0000000..3f8c51a --- /dev/null +++ b/lib/mlibc/dummy-libs/libpthread/src/dummy.cpp @@ -0,0 +1,6 @@ + +// We build an empty libpthread because g++ always links with -lpthread +// The actual functions reside inside libc + +extern "C" void __mlibc_libpthread_dummy(void) { } + diff --git a/lib/mlibc/dummy-libs/libresolv/src/dummy.cpp b/lib/mlibc/dummy-libs/libresolv/src/dummy.cpp new file mode 100644 index 0000000..5feb1c3 --- /dev/null +++ b/lib/mlibc/dummy-libs/libresolv/src/dummy.cpp @@ -0,0 +1,6 @@ + +// We build an empty libresolv because some programs always links with -lresolv +// The actual functions reside inside libc + +extern "C" void __mlibc_libresolv_dummy(void) { } + diff --git a/lib/mlibc/dummy-libs/librt/src/dummy.cpp b/lib/mlibc/dummy-libs/librt/src/dummy.cpp new file mode 100644 index 0000000..35c3852 --- /dev/null +++ b/lib/mlibc/dummy-libs/librt/src/dummy.cpp @@ -0,0 +1,6 @@ + +// We build an empty librt because g++ always links with -lrt +// The actual functions reside inside libc + +extern "C" void __mlibc_librt_dummy(void) { } + diff --git a/lib/mlibc/dummy-libs/libssp/src/dummy.cpp b/lib/mlibc/dummy-libs/libssp/src/dummy.cpp new file mode 100644 index 0000000..43286c1 --- /dev/null +++ b/lib/mlibc/dummy-libs/libssp/src/dummy.cpp @@ -0,0 +1,6 @@ + +// We build an empty libsso because some packages expect -lssp +// The actual ssp functions are provided by libc. + +extern "C" void __mlibc_libssp_dummy(void) { } + diff --git a/lib/mlibc/dummy-libs/libssp_nonshared/src/dummy.cpp b/lib/mlibc/dummy-libs/libssp_nonshared/src/dummy.cpp new file mode 100644 index 0000000..dcd8e90 --- /dev/null +++ b/lib/mlibc/dummy-libs/libssp_nonshared/src/dummy.cpp @@ -0,0 +1,6 @@ + +// We build an empty libsso because some packages expect -lssp_nonshared +// The actual ssp functions are provided by libc. + +extern "C" void __mlibc_libssp_nonshared_dummy(void) { } + diff --git a/lib/mlibc/dummy-libs/libutil/src/dummy.cpp b/lib/mlibc/dummy-libs/libutil/src/dummy.cpp new file mode 100644 index 0000000..c295ee5 --- /dev/null +++ b/lib/mlibc/dummy-libs/libutil/src/dummy.cpp @@ -0,0 +1,6 @@ + +// We build an empty libutil because g++ always links with -lutil +// The actual functions reside inside libc + +extern "C" void __mlibc_libutil_dummy(void) { } + diff --git a/lib/mlibc/internal-config.h.in b/lib/mlibc/internal-config.h.in new file mode 100644 index 0000000..2a23e15 --- /dev/null +++ b/lib/mlibc/internal-config.h.in @@ -0,0 +1,9 @@ +#pragma once + +#mesondefine MLIBC_SYSTEM_NAME +#mesondefine MLIBC_MAP_DSO_SEGMENTS +#mesondefine MLIBC_MMAP_ALLOCATE_DSO +#mesondefine MLIBC_MAP_FILE_WINDOWS +#mesondefine MLIBC_STATIC_BUILD +#mesondefine MLIBC_DEBUG_ALLOCATOR + diff --git a/lib/mlibc/meson.build b/lib/mlibc/meson.build new file mode 100644 index 0000000..7e0956d --- /dev/null +++ b/lib/mlibc/meson.build @@ -0,0 +1,528 @@ +project('mlibc', default_options: ['warning_level=2', 'cpp_std=c++20']) + +fs = import('fs') + +rtdl_include_dirs = [ + include_directories('options/internal/include'), + include_directories('options/internal' / host_machine.cpu_family() + '-include'), + include_directories('options/rtdl' / host_machine.cpu_family()), + include_directories('options/rtdl/include'), +] +libc_include_dirs = [ + include_directories('options/internal/include'), + include_directories('options/elf/include'), + include_directories('options/lsb/include'), + include_directories('options/rtdl/include'), + include_directories('options/rtdl' / host_machine.cpu_family()), + include_directories('options/internal' / host_machine.cpu_family() + '-include') +] + +rtdl_sources = [ ] +rtdl_dso_sources = [ ] +libc_sources = [ ] +libc_sublibs = [ ] + +libc_deps = [ ] +rtdl_deps = [ ] + +headers_only = get_option('headers_only') +no_headers = get_option('mlibc_no_headers') +library_type = get_option('default_library') +build_tests = get_option('build_tests') +build_tests_host_libc = get_option('build_tests_host_libc') +disable_ansi_option = get_option('disable_ansi_option') +disable_posix_option = get_option('disable_posix_option') +disable_linux_option = get_option('disable_linux_option') +disable_iconv_option = get_option('disable_iconv_option') +disable_intl_option = get_option('disable_intl_option') +disable_glibc_option = get_option('disable_glibc_option') +disable_crypt_option = get_option('disable_crypt_option') +disable_bsd_option = get_option('disable_bsd_option') +disable_libgcc_dependency = get_option('disable_libgcc_dependency') +internal_conf = configuration_data() +mlibc_conf = configuration_data() + +if not headers_only + cshim_dep = dependency('cshim', + required: false, + fallback: ['cshim', 'cshim_dep']) + libc_deps += cshim_dep + rtdl_deps += cshim_dep + + cxxshim_dep = dependency('cxxshim', + required: false, + fallback: ['cxxshim', 'cxxshim_dep']) + libc_deps += cxxshim_dep + rtdl_deps += cxxshim_dep + + frigg_dep = dependency( + 'frigg', + default_options: ['frigg_no_install=true'], + fallback: ['frigg', 'frigg_dep'], + ) + libc_deps += frigg_dep + rtdl_deps += frigg_dep + + add_languages('c', 'cpp') + c_compiler = meson.get_compiler('c') + cpp_compiler = meson.get_compiler('cpp') + + add_project_arguments('-Wno-unused-function', '-D__MLIBC_BUILDING_MLIBC', language: ['c', 'cpp']) + add_project_arguments('-nostdinc', '-fno-builtin', '-ffreestanding', language: ['c', 'cpp']) + add_project_arguments('-Werror=misleading-indentation', language: ['c', 'cpp']) + add_project_arguments('-fno-rtti', '-fno-exceptions', language: 'cpp') + add_project_link_arguments('-nostdlib', language: ['c', 'cpp']) + + if not cshim_dep.found() + searchdirs = run_command(c_compiler.cmd_array(), '-print-search-dirs', + check: true).stdout() + searchdirs_arr = searchdirs.split('\n') + searchline = 'install: ' + ccdir = '' + if c_compiler.get_id() == 'clang' + searchline = 'libraries: =' + endif + + foreach line : searchdirs_arr + if line.startswith(searchline) + ccdir = line.strip(searchline) + ccdir = ccdir.split(':')[0] + break + endif + endforeach + + if ccdir == '' + error('could not find compiler-specific header directory') + endif + + if c_compiler.get_id() == 'gcc' and fs.exists(ccdir / 'include-fixed') + rtdl_include_dirs += include_directories(ccdir / 'include-fixed') + libc_include_dirs += include_directories(ccdir / 'include-fixed') + endif + + rtdl_include_dirs += include_directories(ccdir / 'include') + libc_include_dirs += include_directories(ccdir / 'include') + endif + + if not cxxshim_dep.found() + cplusplus_include_path = [] + + c_output = run_command(c_compiler.cmd_array(), '-E', '-v', '-x', 'c', + '/dev/null', '-o', '-', + capture: true, + check: true).stderr().split('\n') + + cpp_output = run_command(cpp_compiler.cmd_array(), '-E', '-v', '-x', + 'c++', '/dev/null', '-o', '-', + capture: true, + check: true).stderr().split('\n') + + c_relevant_lines = [] + + relevantmarker = '#include <...>' + relevant_started = false + + foreach line : c_output + if relevant_started + if not line.startswith(' ') + break + endif + c_relevant_lines += line.strip() + elif line.startswith(relevantmarker) + relevant_started = true + endif + endforeach + + relevant_started = false + + foreach line : cpp_output + if relevant_started + if not line.startswith(' ') + break + endif + debug('maybe relevant', line) + stripped = line.strip() + if stripped in c_relevant_lines + debug('not relevant (is C)', line) + continue + endif + cplusplus_include_path += include_directories(stripped) + elif line.startswith(relevantmarker) + relevant_started = true + endif + endforeach + + rtdl_include_dirs += cplusplus_include_path + libc_include_dirs += cplusplus_include_path + endif +endif + +internal_conf.set_quoted('MLIBC_SYSTEM_NAME', host_machine.system()) +internal_conf.set10('MLIBC_MAP_DSO_SEGMENTS', false) +internal_conf.set10('MLIBC_MMAP_ALLOCATE_DSO', false) +internal_conf.set10('MLIBC_MAP_FILE_WINDOWS', false) +internal_conf.set10('MLIBC_DEBUG_ALLOCATOR', get_option('debug_allocator')) + +#---------------------------------------------------------------------------------------- +# Configuration based on sysdeps. +#---------------------------------------------------------------------------------------- + +# Process sysdeps first, as sysdeps might want to disable unsupported options. +provides_bits_syscall_h = false +if host_machine.system() == 'linux' + provides_bits_syscall_h = true + rtdl_include_dirs += include_directories('sysdeps/linux/include') + libc_include_dirs += include_directories('sysdeps/linux/include') + + if not headers_only + if get_option('linux_kernel_headers') == '' + error('linux_kernel_headers is not set') + endif + + if not import('fs').is_dir(get_option('linux_kernel_headers')) + error('linux_kernel_headers is not set to a valid path') + endif + + rtdl_include_dirs += include_directories(get_option('linux_kernel_headers')) + libc_include_dirs += include_directories(get_option('linux_kernel_headers')) + endif + + internal_conf.set10('MLIBC_MAP_DSO_SEGMENTS', true) + internal_conf.set10('MLIBC_MMAP_ALLOCATE_DSO', true) + subdir('sysdeps/linux') +elif host_machine.system() == 'aero' + rtdl_include_dirs += include_directories('sysdeps/aero/include') + libc_include_dirs += include_directories('sysdeps/aero/include') + internal_conf.set10('MLIBC_MAP_DSO_SEGMENTS', true) + internal_conf.set10('MLIBC_MAP_FILE_WINDOWS', true) + subdir('sysdeps/aero') +elif host_machine.system() == 'hyra' + rtdl_include_dirs += include_directories('sysdeps/hyra/include') + libc_include_dirs += include_directories('sysdeps/hyra/include') + internal_conf.set10('MLIBC_MAP_DSO_SEGMENTS', true) + internal_conf.set10('MLIBC_MAP_FILE_WINDOWS', true) + subdir('sysdeps/hyra') +elif host_machine.system() == 'managarm' + # TODO: Adopt the include_directories() commands from the managarm meson.build. + rtdl_include_dirs += include_directories('sysdeps/managarm/include') + libc_include_dirs += include_directories('sysdeps/managarm/include') + internal_conf.set10('MLIBC_MAP_DSO_SEGMENTS', true) + internal_conf.set10('MLIBC_MMAP_ALLOCATE_DSO', true) + internal_conf.set10('MLIBC_MAP_FILE_WINDOWS', true) + subdir('sysdeps/managarm') +elif host_machine.system() == 'ironclad' + disable_linux_option = true + rtdl_include_dirs += include_directories('sysdeps/ironclad/include') + libc_include_dirs += include_directories('sysdeps/ironclad/include') + subdir('sysdeps/ironclad') +elif host_machine.system() == 'keyronex' + rtdl_include_dirs += include_directories('sysdeps/keyronex/include') + libc_include_dirs += include_directories('sysdeps/keyronex/include') + internal_conf.set10('MLIBC_MAP_DSO_SEGMENTS', true) + internal_conf.set10('MLIBC_MAP_FILE_WINDOWS', true) + subdir('sysdeps/keyronex') +elif host_machine.system() == 'lyre' + disable_linux_option = true + rtdl_include_dirs += include_directories('sysdeps/lyre/include') + libc_include_dirs += include_directories('sysdeps/lyre/include') + subdir('sysdeps/lyre') +elif host_machine.system() == 'lemon' + rtdl_include_dirs += include_directories('sysdeps/lemon/include') + libc_include_dirs += include_directories('sysdeps/lemon/include') + subdir('sysdeps/lemon') +elif host_machine.system() == 'dripos' + disable_linux_option = true + rtdl_include_dirs += include_directories('sysdeps/dripos/include') + libc_include_dirs += include_directories('sysdeps/dripos/include') + subdir('sysdeps/dripos') +else + error('No sysdeps defined for OS: ' + host_machine.system()) +endif + +#---------------------------------------------------------------------------------------- +# Configuration based on enabled options. +#---------------------------------------------------------------------------------------- + +mlibc_conf.set10('__MLIBC_ANSI_OPTION', not disable_ansi_option) +mlibc_conf.set10('__MLIBC_POSIX_OPTION', not disable_posix_option) +mlibc_conf.set10('__MLIBC_LINUX_OPTION', not disable_linux_option) +mlibc_conf.set10('__MLIBC_INTL_OPTION', not disable_intl_option) +mlibc_conf.set10('__MLIBC_ICONV_OPTION', not disable_iconv_option) +mlibc_conf.set10('__MLIBC_GLIBC_OPTION', not disable_glibc_option) +mlibc_conf.set10('__MLIBC_CRYPT_OPTION', not disable_crypt_option) +mlibc_conf.set10('__MLIBC_BSD_OPTION', not disable_bsd_option) +mlibc_conf.set10('__MLIBC_SYSDEP_HAS_BITS_SYSCALL_H', provides_bits_syscall_h) + +if not disable_ansi_option + rtdl_include_dirs += include_directories('options/ansi/include') + libc_include_dirs += include_directories('options/ansi/include') +endif + +if not disable_posix_option + rtdl_include_dirs += include_directories('options/posix/include') + libc_include_dirs += include_directories('options/posix/include') +endif + +if not disable_iconv_option + rtdl_include_dirs += include_directories('options/iconv/include') + libc_include_dirs += include_directories('options/iconv/include') +endif + +if not disable_intl_option + libc_include_dirs += include_directories('options/intl/include') +endif + +if not disable_linux_option + if not headers_only + if get_option('linux_kernel_headers') == '' + error('linux_kernel_headers is not set') + endif + + if not import('fs').is_dir(get_option('linux_kernel_headers')) + error('linux_kernel_headers is not set to a valid path') + endif + endif + + rtdl_include_dirs += include_directories('options/linux/include') + libc_include_dirs += include_directories('options/linux/include') + rtdl_include_dirs += include_directories(get_option('linux_kernel_headers')) + libc_include_dirs += include_directories(get_option('linux_kernel_headers')) +endif + +if not disable_glibc_option + rtdl_include_dirs += include_directories('options/glibc/include') + libc_include_dirs += include_directories('options/glibc/include') +endif + +if not disable_crypt_option + libc_include_dirs += include_directories('options/crypt/include') +endif + +if not disable_bsd_option + rtdl_include_dirs += include_directories('options/bsd/include') + libc_include_dirs += include_directories('options/bsd/include') +endif + +rtdl_include_dirs += include_directories('options/elf/include') +libc_include_dirs += include_directories('options/elf/include') +libc_include_dirs += include_directories('.') + +#---------------------------------------------------------------------------------------- + +configure_file(input: 'internal-config.h.in', + output: 'internal-config.h', + configuration: internal_conf) + +configure_file(input: 'mlibc-config.h.in', + output: 'mlibc-config.h', + configuration: mlibc_conf, + install: not no_headers, + install_dir: get_option('includedir')) + +internal_sources = [ + 'options/internal/generic/allocator.cpp', + 'options/internal/generic/charcode.cpp', + 'options/internal/generic/charset.cpp', + 'options/internal/generic/debug.cpp', + 'options/internal/generic/ensure.cpp', + 'options/internal/generic/essential.cpp', + 'options/internal/generic/frigg.cpp', + 'options/internal/generic/global-config.cpp', + 'options/internal/generic/inline-emitter.cpp', + 'options/internal/generic/locale.cpp', + 'options/internal/generic/sigset.cpp', + 'options/internal/generic/strings.cpp', + 'options/internal/generic/ubsan.cpp', + 'options/internal/generic/threads.cpp', + 'options/internal/gcc/stack_protector.cpp', + 'options/internal/gcc/guard-abi.cpp', + 'options/internal/gcc/initfini.cpp', + 'options/internal/gcc-extra/cxxabi.cpp', + 'options/internal' / host_machine.cpu_family() / 'setjmp.S', + 'options/internal' / host_machine.cpu_family() / 'fenv.S', +] + +internal_dso_sources = [ + 'options/internal' / host_machine.cpu_family() / 'mlibc_crtbegin.S', + 'options/internal' / host_machine.cpu_family() / 'mlibc_crtend.S', +] + +if not no_headers + install_headers( + 'options/internal/include/stdint.h' + ) + install_headers( + 'options/internal/include/bits/wchar_t.h', + 'options/internal/include/bits/wchar.h', + 'options/internal/include/bits/wint_t.h', + 'options/internal/include/bits/size_t.h', + 'options/internal/include/bits/types.h', + 'options/internal/include/bits/ensure.h', + 'options/internal/include/bits/machine.h', + 'options/internal/include/bits/mbstate.h', + 'options/internal/include/bits/nl_item.h', + 'options/internal/include/bits/null.h', + 'options/internal/include/bits/off_t.h', + 'options/internal/include/bits/ssize_t.h', + 'options/internal/include/bits/sigset_t.h', + 'options/internal/include/bits/inline-definition.h', + 'options/internal/include/bits/ether_addr.h', + 'options/internal/include/bits/cpu_set.h', + 'options/internal/include/bits/threads.h', + 'options/internal/include/bits/winsize.h', + subdir: 'bits' + ) +endif + +rtdl_sources += [ + 'options/internal/gcc/stack_protector.cpp', + 'options/internal/gcc/guard-abi.cpp', + 'options/internal/generic/allocator.cpp', + 'options/internal/generic/debug.cpp', + 'options/internal/generic/ensure.cpp', + 'options/internal/generic/essential.cpp', + 'options/internal/generic/inline-emitter.cpp', + 'options/internal/generic/frigg.cpp', + 'options/internal/generic/ubsan.cpp', + 'options/rtdl/generic/main.cpp', + 'options/rtdl/generic/linker.cpp', + 'options/rtdl' / host_machine.cpu_family() / 'runtime.S' +] + +rtdl_dso_sources += ['options/rtdl' / host_machine.cpu_family() / 'entry.S'] + +subdir('options/elf') +subdir('options/ansi') +subdir('options/posix') +subdir('options/lsb') +subdir('options/glibc') +subdir('options/linux') +subdir('options/iconv') +subdir('options/intl') +subdir('options/crypt') +subdir('options/bsd') + +rtlib_deps = [] + +if not headers_only + if not disable_libgcc_dependency + libgcc = meson.get_compiler('c').find_library('gcc', required: false) + + compiler_rt_name = 'libclang_rt.builtins-' + host_machine.cpu_family() + compiler_rt = meson.get_compiler('c').find_library(compiler_rt_name, required: false) + + if not compiler_rt.found() + compiler_rt_name = 'libclang_rt.builtins' + compiler_rt = meson.get_compiler('c').find_library(compiler_rt_name, required: false) + endif + + if libgcc.found() + rtlib_deps += libgcc + elif compiler_rt.found() + rtlib_deps += compiler_rt + else + error('neither libgcc nor ' + compiler_rt_name + ' was found') + endif + endif + + ld_cpp_args = [ + '-fvisibility=hidden', + '-fvisibility-inlines-hidden', + '-fno-stack-protector', + '-DMLIBC_BUILDING_RTDL' + ] + + libc_all_sources = [ + libc_sources, + internal_sources, + ansi_sources, + lsb_sources, + ] + + # Our library have different behaviour when built as static and shared libraries. + # Hence we need to rebuild the object files with a different define for each mode. + if library_type in ['static', 'both'] + static_cpp_args = [ + '-DMLIBC_STATIC_BUILD', + '-DFRIGG_HAVE_LIBC', + ] + ld_static_lib = static_library('ld', rtdl_sources, + name_prefix: '', + cpp_args: ld_cpp_args + static_cpp_args, + include_directories: rtdl_include_dirs, + dependencies: rtdl_deps + rtlib_deps, + install: false + ) + libc_static = static_library('c', libc_all_sources, + cpp_args: static_cpp_args + ['-fno-stack-protector'], + include_directories: libc_include_dirs, + dependencies: libc_deps + rtlib_deps, + link_with: [ld_static_lib], + link_whole: [libc_sublibs, ld_static_lib], + install: true + ) + endif + if library_type in ['shared', 'both'] + ld_shared_lib = shared_library('ld', rtdl_sources + rtdl_dso_sources, + name_prefix: '', + cpp_args: ld_cpp_args, + include_directories: rtdl_include_dirs, + dependencies: rtdl_deps + rtlib_deps, + install: true + ) + libc_shared = shared_library('c', libc_all_sources + internal_dso_sources, + include_directories: libc_include_dirs, + dependencies: libc_deps + rtlib_deps, + link_with: [ld_shared_lib], + link_whole: libc_sublibs, + install: true + ) + endif + + library('pthread', 'dummy-libs/libpthread/src/dummy.cpp', install: true) + library('rt', 'dummy-libs/librt/src/dummy.cpp', install: true) + library('util', 'dummy-libs/libutil/src/dummy.cpp', install: true) + library('m', 'dummy-libs/libm/src/dummy.cpp', install: true) + if not disable_crypt_option + library('crypt', 'dummy-libs/libcrypt/src/dummy.cpp', install: true) + endif + library('resolv', 'dummy-libs/libresolv/src/dummy.cpp', install: true) + library('dl', 'dummy-libs/libdl/src/dummy.cpp', install: true) + library('ssp', 'dummy-libs/libssp/src/dummy.cpp', install: true) + library('ssp_nonshared', 'dummy-libs/libssp_nonshared/src/dummy.cpp', install: true) +endif + +summary_info = {} +summary_info += {'Build tests': build_tests} +summary_info += {'Build host-libc tests': build_tests_host_libc} +summary(summary_info, bool_yn: true, section: 'tests') + +summary_info = {} +summary_info += {'headers-only': headers_only} +summary_info += {'ANSI option': not disable_ansi_option} +summary_info += {'crypt option': not disable_crypt_option} +summary_info += {'POSIX option': not disable_posix_option} +summary_info += {'Linux option': not disable_linux_option} +summary_info += {'iconv option': not disable_iconv_option} +summary_info += {'intl option': not disable_intl_option} +summary_info += {'glibc option': not disable_glibc_option} +summary_info += {'BSD option': not disable_bsd_option} +summary_info += {'debug allocator': get_option('debug_allocator')} +summary_info += {'libgcc dependency': not disable_libgcc_dependency} +summary(summary_info, bool_yn: true, section: 'mlibc options') + +if build_tests + subdir('tests/') +endif + +hdoc = find_program('hdoc', required: false) + +conf_data = configuration_data() +conf_data.set('source_root', meson.source_root()) +conf_data.set('build_root', meson.build_root()) +configure_file(input: 'scripts/hdoc.toml.in', + output: '.hdoc.toml', configuration: conf_data) + +if hdoc.found() + run_target('hdoc', command : [hdoc.full_path(), '--verbose']) +endif diff --git a/lib/mlibc/meson_options.txt b/lib/mlibc/meson_options.txt new file mode 100644 index 0000000..461b9a6 --- /dev/null +++ b/lib/mlibc/meson_options.txt @@ -0,0 +1,16 @@ +option('headers_only', type : 'boolean', value : false) +option('mlibc_no_headers', type : 'boolean', value : false) +option('build_tests', type: 'boolean', value : false) +option('build_tests_host_libc', type: 'boolean', value : true) +option('disable_ansi_option', type: 'boolean', value : false) +option('disable_crypt_option', type: 'boolean', value : false) +option('disable_posix_option', type: 'boolean', value : false) +option('disable_linux_option', type: 'boolean', value : false) +option('disable_iconv_option', type: 'boolean', value : false) +option('disable_intl_option', type: 'boolean', value : false) +option('disable_glibc_option', type: 'boolean', value : false) +option('disable_bsd_option', type: 'boolean', value : false) +option('disable_libgcc_dependency', type : 'boolean', value : false) +option('linux_kernel_headers', type: 'string', value : '') +option('debug_allocator', type : 'boolean', value : false, + description : 'Enable the debug allocator, which uses mmap for every allocation and adds guard pages for each allocation') diff --git a/lib/mlibc/mlibc-config.h.in b/lib/mlibc/mlibc-config.h.in new file mode 100644 index 0000000..cd3c08a --- /dev/null +++ b/lib/mlibc/mlibc-config.h.in @@ -0,0 +1,14 @@ +#ifndef _MLIBC_CONFIG_H +#define _MLIBC_CONFIG_H + +#mesondefine __MLIBC_ANSI_OPTION +#mesondefine __MLIBC_BSD_OPTION +#mesondefine __MLIBC_POSIX_OPTION +#mesondefine __MLIBC_LINUX_OPTION +#mesondefine __MLIBC_INTL_OPTION +#mesondefine __MLIBC_ICONV_OPTION +#mesondefine __MLIBC_GLIBC_OPTION +#mesondefine __MLIBC_CRYPT_OPTION +#mesondefine __MLIBC_SYSDEP_HAS_BITS_SYSCALL_H + +#endif // _MLIBC_CONFIG_H diff --git a/lib/mlibc/options/ansi/generic/assert-stubs.cpp b/lib/mlibc/options/ansi/generic/assert-stubs.cpp new file mode 100644 index 0000000..6ebb6ed --- /dev/null +++ b/lib/mlibc/options/ansi/generic/assert-stubs.cpp @@ -0,0 +1,13 @@ + +#include +#include +#include + +#include + +[[gnu::noreturn]] void __assert_fail(const char *assertion, const char *file, unsigned int line, + const char *function) { + fprintf(stderr, "In function %s, file %s:%d: Assertion '%s' failed!\n", + function, file, line, assertion); + abort(); +} diff --git a/lib/mlibc/options/ansi/generic/complex-stubs.c b/lib/mlibc/options/ansi/generic/complex-stubs.c new file mode 100644 index 0000000..069626b --- /dev/null +++ b/lib/mlibc/options/ansi/generic/complex-stubs.c @@ -0,0 +1,9 @@ +#include + +long double cimagl(long double complex z) { + return __imag__(z); +} + +long double creall(long double complex z) { + return __real__(z); +} diff --git a/lib/mlibc/options/ansi/generic/complex/cabs.c b/lib/mlibc/options/ansi/generic/complex/cabs.c new file mode 100644 index 0000000..2750fab --- /dev/null +++ b/lib/mlibc/options/ansi/generic/complex/cabs.c @@ -0,0 +1,53 @@ +/* $NetBSD: cabs.c,v 1.1 2007/08/20 16:01:30 drochner Exp $ */ + +/* + * Written by Matthias Drochner . + * Public domain. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +/* +FUNCTION + <>, <>---complex absolute-value + +INDEX + cabs +INDEX + cabsf + +ANSI_SYNOPSIS + #include + double cabs(double complex <[z]>); + float cabsf(float complex <[z]>); + + +DESCRIPTION + These functions compute compute the complex absolute value + (also called norm, modulus, or magnitude) of <[z]>. + + <> is identical to <>, except that it performs + its calculations on <>. + +RETURNS + The cabs functions return the complex absolute value. + +PORTABILITY + <> and <> are ISO C99 + +QUICKREF + <> and <> are ISO C99 + +*/ + + +#include +#include + +double +cabs(double complex z) +{ + + return hypot( creal(z), cimag(z) ); +} diff --git a/lib/mlibc/options/ansi/generic/complex/cabsf.c b/lib/mlibc/options/ansi/generic/complex/cabsf.c new file mode 100644 index 0000000..635e23e --- /dev/null +++ b/lib/mlibc/options/ansi/generic/complex/cabsf.c @@ -0,0 +1,19 @@ +/* $NetBSD: cabsf.c,v 1.1 2007/08/20 16:01:30 drochner Exp $ */ + +/* + * Written by Matthias Drochner . + * Public domain. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +#include +#include + +float +cabsf(float complex z) +{ + + return hypotf( crealf(z), cimagf(z) ); +} diff --git a/lib/mlibc/options/ansi/generic/complex/cacos.c b/lib/mlibc/options/ansi/generic/complex/cacos.c new file mode 100644 index 0000000..86e1198 --- /dev/null +++ b/lib/mlibc/options/ansi/generic/complex/cacos.c @@ -0,0 +1,99 @@ +/* $NetBSD: cacos.c,v 1.1 2007/08/20 16:01:30 drochner Exp $ */ + +/*- + * Copyright (c) 2007 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software written by Stephen L. Moshier. + * It is redistributed by the NetBSD Foundation by permission of the author. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +/* +FUNCTION + <>, <>---complex arc cosine + +INDEX + cacos +INDEX + cacosf + +ANSI_SYNOPSIS + #include + double complex cacos(double complex <[z]>); + float complex cacosf(float complex <[z]>); + + +DESCRIPTION + These functions compute the complex arc cosine of <[z]>, + with branch cuts outside the interval [-1, +1] along the real axis. + + <> is identical to <>, except that it performs + its calculations on <>. + +RETURNS + @ifnottex + These functions return the complex arc cosine value, in the range + of a strip mathematically unbounded along the imaginary axis + and in the interval [0, pi] along the real axis. + @end ifnottex + @tex + These functions return the complex arc cosine value, in the range + of a strip mathematically unbounded along the imaginary axis + and in the interval [<<0>>, $\pi$] along the real axis. + @end tex + +PORTABILITY + <> and <> are ISO C99 + +QUICKREF + <> and <> are ISO C99 + +*/ + +#include +#include + +double complex +cacos(double complex z) +{ + double complex w; + + /* FIXME: The original NetBSD code results in an ICE when trying to + build this function on ARM/Thumb using gcc 4.5.1. For now we use + a hopefully temporary workaround. */ +#if 0 + w = casin(z); + w = (M_PI_2 - creal(w)) - cimag(w) * I; +#else + double complex tmp0, tmp1; + + tmp0 = casin(z); + tmp1 = M_PI_2 - creal(tmp0); + w = tmp1 - (cimag(tmp0) * I); +#endif + return w; +} diff --git a/lib/mlibc/options/ansi/generic/complex/cacosf.c b/lib/mlibc/options/ansi/generic/complex/cacosf.c new file mode 100644 index 0000000..3874dd5 --- /dev/null +++ b/lib/mlibc/options/ansi/generic/complex/cacosf.c @@ -0,0 +1,46 @@ +/* $NetBSD: cacosf.c,v 1.1 2007/08/20 16:01:30 drochner Exp $ */ + +/*- + * Copyright (c) 2007 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software written by Stephen L. Moshier. + * It is redistributed by the NetBSD Foundation by permission of the author. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +#include +#include + +float complex +cacosf(float complex z) +{ + float complex w; + + w = casinf(z); + w = ((float)M_PI_2 - crealf(w)) - cimagf(w) * I; + return w; +} diff --git a/lib/mlibc/options/ansi/generic/complex/cacosh.c b/lib/mlibc/options/ansi/generic/complex/cacosh.c new file mode 100644 index 0000000..3d42c40 --- /dev/null +++ b/lib/mlibc/options/ansi/generic/complex/cacosh.c @@ -0,0 +1,93 @@ +/* $NetBSD: cacosh.c,v 1.2 2009/08/03 19:41:32 drochner Exp $ */ + +/*- + * Copyright (c) 2007 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software written by Stephen L. Moshier. + * It is redistributed by the NetBSD Foundation by permission of the author. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +/* +FUNCTION + <>, <>---complex arc hyperbolic cosine + +INDEX + cacosh +INDEX + cacoshf + +ANSI_SYNOPSIS + #include + double complex cacosh(double complex <[z]>); + float complex cacoshf(float complex <[z]>); + + +DESCRIPTION + These functions compute the complex arc hyperbolic cosine of <[z]>, + with a branch cut at values less than 1 along the real axis. + + <> is identical to <>, except that it performs + its calculations on <>. + +RETURNS + @ifnottex + These functions return the complex arc hyperbolic cosine value, + in the range of a half-strip of non-negative values along the + real axis and in the interval [-i * pi, +i * pi] along the + imaginary axis. + @end ifnottex + @tex + These functions return the complex arc hyperbolic cosine value, + in the range of a half-strip of non-negative values along the + real axis and in the interval [$-i\pi$, $+i\pi$] along the + imaginary axis. + @end tex + +PORTABILITY + <> and <> are ISO C99 + +QUICKREF + <> and <> are ISO C99 + +*/ + + +#include + +double complex +cacosh(double complex z) +{ + double complex w; + +#if 0 /* does not give the principal value */ + w = I * cacos(z); +#else + w = clog(z + csqrt(z + 1) * csqrt(z - 1)); +#endif + return w; +} diff --git a/lib/mlibc/options/ansi/generic/complex/cacoshf.c b/lib/mlibc/options/ansi/generic/complex/cacoshf.c new file mode 100644 index 0000000..41a557a --- /dev/null +++ b/lib/mlibc/options/ansi/generic/complex/cacoshf.c @@ -0,0 +1,48 @@ +/* $NetBSD: cacoshf.c,v 1.2 2009/08/03 19:41:32 drochner Exp $ */ + +/*- + * Copyright (c) 2007 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software written by Stephen L. Moshier. + * It is redistributed by the NetBSD Foundation by permission of the author. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +#include + +float complex +cacoshf(float complex z) +{ + float complex w; + +#if 0 /* does not give the principal value */ + w = I * cacosf(z); +#else + w = clogf(z + csqrtf(z + 1) * csqrtf(z - 1)); +#endif + return w; +} diff --git a/lib/mlibc/options/ansi/generic/complex/carg.c b/lib/mlibc/options/ansi/generic/complex/carg.c new file mode 100644 index 0000000..0447420 --- /dev/null +++ b/lib/mlibc/options/ansi/generic/complex/carg.c @@ -0,0 +1,59 @@ +/* $NetBSD: carg.c,v 1.1 2007/08/20 16:01:31 drochner Exp $ */ + +/* + * Written by Matthias Drochner . + * Public domain. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +/* +FUNCTION + <>, <>---argument (phase angle) + +INDEX + carg +INDEX + cargf + +ANSI_SYNOPSIS + #include + double carg(double complex <[z]>); + float cargf(float complex <[z]>); + + +DESCRIPTION + These functions compute the argument (also called phase angle) + of <[z]>, with a branch cut along the negative real axis. + + <> is identical to <>, except that it performs + its calculations on <>. + +RETURNS + @ifnottex + The carg functions return the value of the argument in the + interval [-pi, +pi] + @end ifnottex + @tex + The carg functions return the value of the argument in the + interval [$-\pi$, $+\pi$] + @end tex + +PORTABILITY + <> and <> are ISO C99 + +QUICKREF + <> and <> are ISO C99 + +*/ + +#include +#include + +double +carg(double complex z) +{ + + return atan2( cimag(z) , creal(z) ); +} diff --git a/lib/mlibc/options/ansi/generic/complex/cargf.c b/lib/mlibc/options/ansi/generic/complex/cargf.c new file mode 100644 index 0000000..1683d21 --- /dev/null +++ b/lib/mlibc/options/ansi/generic/complex/cargf.c @@ -0,0 +1,19 @@ +/* $NetBSD: cargf.c,v 1.1 2007/08/20 16:01:31 drochner Exp $ */ + +/* + * Written by Matthias Drochner . + * Public domain. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +#include +#include + +float +cargf(float complex z) +{ + + return atan2f( cimagf(z), crealf(z) ); +} diff --git a/lib/mlibc/options/ansi/generic/complex/casin.c b/lib/mlibc/options/ansi/generic/complex/casin.c new file mode 100644 index 0000000..5019fd8 --- /dev/null +++ b/lib/mlibc/options/ansi/generic/complex/casin.c @@ -0,0 +1,165 @@ +/* $NetBSD: casin.c,v 1.1 2007/08/20 16:01:31 drochner Exp $ */ + +/*- + * Copyright (c) 2007 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software written by Stephen L. Moshier. + * It is redistributed by the NetBSD Foundation by permission of the author. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +/* +FUNCTION + <>, <>---complex arc sine + +INDEX + casin +INDEX + casinf + +ANSI_SYNOPSIS + #include + double complex casin(double complex <[z]>); + float complex casinf(float complex <[z]>); + + +DESCRIPTION + These functions compute the complex arc sine of <[z]>, + with branch cuts outside the interval [-1, +1] along the real axis. + + <> is identical to <>, except that it performs + its calculations on <>. + +RETURNS + @ifnottex + These functions return the complex arc sine value, in the range + of a strip mathematically unbounded along the imaginary axis + and in the interval [-pi/2, +pi/2] along the real axis. + @end ifnottex + @tex + These functions return the complex arc sine value, in the range + of a strip mathematically unbounded along the imaginary axis + and in the interval [$-\pi/2$, $+\pi/2$] along the real axis. + @end tex + +PORTABILITY + <> and <> are ISO C99 + +QUICKREF + <> and <> are ISO C99 + +*/ + + +#include +#include + +#ifdef __weak_alias +__weak_alias(casin, _casin) +#endif + +double complex +casin(double complex z) +{ + double complex w; + double complex ca, ct, zz, z2; + double x, y; + + x = creal(z); + y = cimag(z); + +#if 0 /* MD: test is incorrect, casin(>1) is defined */ + if (y == 0.0) { + if (fabs(x) > 1.0) { + w = M_PI_2 + 0.0 * I; +#if 0 + mtherr ("casin", DOMAIN); +#endif + } else { + w = asin(x) + 0.0 * I; + } + return w; + } +#endif + +/* Power series expansion */ +/* +b = cabs(z); +if( b < 0.125 ) +{ +z2.r = (x - y) * (x + y); +z2.i = 2.0 * x * y; + +cn = 1.0; +n = 1.0; +ca.r = x; +ca.i = y; +sum.r = x; +sum.i = y; +do + { + ct.r = z2.r * ca.r - z2.i * ca.i; + ct.i = z2.r * ca.i + z2.i * ca.r; + ca.r = ct.r; + ca.i = ct.i; + + cn *= n; + n += 1.0; + cn /= n; + n += 1.0; + b = cn/n; + + ct.r *= b; + ct.i *= b; + sum.r += ct.r; + sum.i += ct.i; + b = fabs(ct.r) + fabs(ct.i); + } +while( b > MACHEP ); +w->r = sum.r; +w->i = sum.i; +return; +} +*/ + + + ca = x + y * I; + ct = ca * I; + /* sqrt( 1 - z*z) */ + /* cmul( &ca, &ca, &zz ) */ + /*x * x - y * y */ + zz = (x - y) * (x + y) + (2.0 * x * y) * I; + + zz = 1.0 - creal(zz) - cimag(zz) * I; + z2 = csqrt(zz); + + zz = ct + z2; + zz = clog(zz); + /* multiply by 1/i = -i */ + w = zz * (-1.0 * I); + return w; +} diff --git a/lib/mlibc/options/ansi/generic/complex/casinf.c b/lib/mlibc/options/ansi/generic/complex/casinf.c new file mode 100644 index 0000000..9a9f759 --- /dev/null +++ b/lib/mlibc/options/ansi/generic/complex/casinf.c @@ -0,0 +1,122 @@ +/* $NetBSD: casinf.c,v 1.1 2007/08/20 16:01:31 drochner Exp $ */ + +/*- + * Copyright (c) 2007 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software written by Stephen L. Moshier. + * It is redistributed by the NetBSD Foundation by permission of the author. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +#include +#include + +#ifdef __weak_alias +__weak_alias(casinf, _casinf) +#endif + +float complex +casinf(float complex z) +{ + float complex w; + float complex ca, ct, zz, z2; + float x, y; + + x = crealf(z); + y = cimagf(z); + +#if 0 /* MD: test is incorrect, casin(>1) is defined */ + if (y == 0.0f) { + if (fabsf(x) > 1.0) { + w = M_PI_2 + 0.0f * I; +#if 0 + mtherr ("casin", DOMAIN); +#endif + } else { + w = asinf(x) + 0.0f * I; + } + return w; + } +#endif + +/* Power series expansion */ +/* +b = cabsf(z); +if( b < 0.125 ) +{ +z2.r = (x - y) * (x + y); +z2.i = 2.0 * x * y; + +cn = 1.0; +n = 1.0; +ca.r = x; +ca.i = y; +sum.r = x; +sum.i = y; +do + { + ct.r = z2.r * ca.r - z2.i * ca.i; + ct.i = z2.r * ca.i + z2.i * ca.r; + ca.r = ct.r; + ca.i = ct.i; + + cn *= n; + n += 1.0; + cn /= n; + n += 1.0; + b = cn/n; + + ct.r *= b; + ct.i *= b; + sum.r += ct.r; + sum.i += ct.i; + b = fabsf(ct.r) + fabsf(ct.i); + } +while( b > MACHEP ); +w->r = sum.r; +w->i = sum.i; +return; +} +*/ + + + ca = x + y * I; + ct = ca * I; + /* sqrt( 1 - z*z) */ + /* cmul( &ca, &ca, &zz ) */ + /*x * x - y * y */ + zz = (x - y) * (x + y) + (2.0f * x * y) * I; + + zz = 1.0f - crealf(zz) - cimagf(zz) * I; + z2 = csqrtf(zz); + + zz = ct + z2; + zz = clogf(zz); + /* multiply by 1/i = -i */ + w = zz * (-1.0f * I); + return w; +} diff --git a/lib/mlibc/options/ansi/generic/complex/casinh.c b/lib/mlibc/options/ansi/generic/complex/casinh.c new file mode 100644 index 0000000..16238a6 --- /dev/null +++ b/lib/mlibc/options/ansi/generic/complex/casinh.c @@ -0,0 +1,97 @@ +/* $NetBSD: casinh.c,v 1.1 2007/08/20 16:01:31 drochner Exp $ */ + +/*- + * Copyright (c) 2007 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software written by Stephen L. Moshier. + * It is redistributed by the NetBSD Foundation by permission of the author. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +/* +FUNCTION + <>, <>---complex arc hyperbolic sine + +INDEX + casinh +INDEX + casinhf + +ANSI_SYNOPSIS + #include + double complex casinh(double complex <[z]>); + float complex casinhf(float complex <[z]>); + + +DESCRIPTION + @ifnottex + These functions compute the complex arc hyperbolic sine of <[z]>, + with branch cuts outside the interval [-i, +i] along the + imaginary axis. + @end ifnottex + @tex + These functions compute the complex arc hyperbolic sine of <[z]>, + with branch cuts outside the interval [$-i$, $+i$] along the + imaginary axis. + @end tex + + <> is identical to <>, except that it performs + its calculations on <>. + +RETURNS + @ifnottex + These functions return the complex arc hyperbolic sine value, + in the range of a strip mathematically unbounded along the + real axis and in the interval [-i*p/2, +i*p/2] along the + imaginary axis. + @end ifnottex + @tex + These functions return the complex arc hyperbolic sine value, + in the range of a strip mathematically unbounded along the + real axis and in the interval [$-i\pi/2$, $+i\pi/2$] along the + imaginary axis. + @end tex + +PORTABILITY + <> and <> are ISO C99 + +QUICKREF + <> and <> are ISO C99 + +*/ + + +#include + +double complex +casinh(double complex z) +{ + double complex w; + + w = -1.0 * I * casin(z * I); + return w; +} diff --git a/lib/mlibc/options/ansi/generic/complex/casinhf.c b/lib/mlibc/options/ansi/generic/complex/casinhf.c new file mode 100644 index 0000000..0db55a0 --- /dev/null +++ b/lib/mlibc/options/ansi/generic/complex/casinhf.c @@ -0,0 +1,44 @@ +/* $NetBSD: casinhf.c,v 1.1 2007/08/20 16:01:32 drochner Exp $ */ + +/*- + * Copyright (c) 2007 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software written by Stephen L. Moshier. + * It is redistributed by the NetBSD Foundation by permission of the author. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +#include + +float complex +casinhf(float complex z) +{ + float complex w; + + w = -1.0f * I * casinf(z * I); + return w; +} diff --git a/lib/mlibc/options/ansi/generic/complex/catan.c b/lib/mlibc/options/ansi/generic/complex/catan.c new file mode 100644 index 0000000..0cf4739 --- /dev/null +++ b/lib/mlibc/options/ansi/generic/complex/catan.c @@ -0,0 +1,130 @@ +/* $NetBSD: catan.c,v 1.1 2007/08/20 16:01:32 drochner Exp $ */ + +/*- + * Copyright (c) 2007 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software written by Stephen L. Moshier. + * It is redistributed by the NetBSD Foundation by permission of the author. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +/* +FUNCTION + <>, <>---complex arc tangent + +INDEX + catan +INDEX + catanf + +ANSI_SYNOPSIS + #include + double complex catan(double complex <[z]>); + float complex catanf(float complex <[z]>); + + +DESCRIPTION + @ifnottex + These functions compute the complex arc tangent of <[z]>, + with branch cuts outside the interval [-i, +i] along the + imaginary axis. + @end ifnottex + @tex + These functions compute the complex arc tangent of <[z]>, + with branch cuts outside the interval [$-i$, $+i$] along the + imaginary axis. + @end tex + + <> is identical to <>, except that it performs + its calculations on <>. + +RETURNS + @ifnottex + These functions return the complex arc tangent value, in the range + of a strip mathematically unbounded along the imaginary axis + and in the interval [-pi/2, +pi/2] along the real axis. + @end ifnottex + @tex + These functions return the complex arc tangent, in the range + of a strip mathematically unbounded along the imaginary axis + and in the interval [$-\pi/2$, $+\pi/2$] along the real axis. + @end tex + +PORTABILITY + <> and <> are ISO C99 + +QUICKREF + <> and <> are ISO C99 + +*/ + + +#include +#include +#include "cephes_subr.h" + +#ifdef __weak_alias +__weak_alias(catan, _catan) +#endif + +double complex +catan(double complex z) +{ + double complex w; + double a, t, x, x2, y; + + x = creal(z); + y = cimag(z); + + if ((x == 0.0) && (y > 1.0)) + goto ovrf; + + x2 = x * x; + a = 1.0 - x2 - (y * y); + if (a == 0.0) + goto ovrf; + + t = 0.5 * atan2(2.0 * x, a); + w = __mlibc_redupi(t); + + t = y - 1.0; + a = x2 + (t * t); + if (a == 0.0) + goto ovrf; + + t = y + 1.0; + a = (x2 + (t * t))/a; + w = w + (0.25 * log(a)) * I; + return w; + +ovrf: +#if 0 + mtherr ("catan", OVERFLOW); +#endif + w = HUGE_VAL + HUGE_VAL * I; + return w; +} diff --git a/lib/mlibc/options/ansi/generic/complex/catanf.c b/lib/mlibc/options/ansi/generic/complex/catanf.c new file mode 100644 index 0000000..33c47df --- /dev/null +++ b/lib/mlibc/options/ansi/generic/complex/catanf.c @@ -0,0 +1,79 @@ +/* $NetBSD: catanf.c,v 1.1 2007/08/20 16:01:32 drochner Exp $ */ + +/*- + * Copyright (c) 2007 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software written by Stephen L. Moshier. + * It is redistributed by the NetBSD Foundation by permission of the author. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +#include +#include +#include "cephes_subrf.h" + +#ifdef __weak_alias +__weak_alias(catanf, _catanf) +#endif + +float complex +catanf(float complex z) +{ + float complex w; + float a, t, x, x2, y; + + x = crealf(z); + y = cimagf(z); + + if ((x == 0.0f) && (y > 1.0f)) + goto ovrf; + + x2 = x * x; + a = 1.0f - x2 - (y * y); + if (a == 0.0f) + goto ovrf; + + t = 0.5f * atan2f(2.0f * x, a); + w = __mlibc_redupif(t); + + t = y - 1.0f; + a = x2 + (t * t); + if (a == 0.0f) + goto ovrf; + + t = y + 1.0f; + a = (x2 + (t * t))/a; + w = w + (0.25f * logf(a)) * I; + return w; + +ovrf: +#if 0 + mtherr ("catan", OVERFLOW); +#endif + w = HUGE_VALF + HUGE_VALF * I; + return w; +} diff --git a/lib/mlibc/options/ansi/generic/complex/catanh.c b/lib/mlibc/options/ansi/generic/complex/catanh.c new file mode 100644 index 0000000..2b9ef9e --- /dev/null +++ b/lib/mlibc/options/ansi/generic/complex/catanh.c @@ -0,0 +1,90 @@ +/* $NetBSD: catanh.c,v 1.1 2007/08/20 16:01:32 drochner Exp $ */ + +/*- + * Copyright (c) 2007 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software written by Stephen L. Moshier. + * It is redistributed by the NetBSD Foundation by permission of the author. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +/* +FUNCTION + <>, <>---complex arc hyperbolic tangent + +INDEX + catanh +INDEX + catanhf + +ANSI_SYNOPSIS + #include + double complex catanh(double complex <[z]>); + float complex catanhf(float complex <[z]>); + + +DESCRIPTION + These functions compute the complex arc hyperbolic tan of <[z]>, + with branch cuts outside the interval [-1, +1] along the + real axis. + + <> is identical to <>, except that it performs + its calculations on <>. + +RETURNS + @ifnottex + These functions return the complex arc hyperbolic tangent value, + in the range of a strip mathematically unbounded along the + real axis and in the interval [-i*p/2, +i*p/2] along the + imaginary axis. + @end ifnottex + @tex + These functions return the complex arc hyperbolic tangent value, + in the range of a strip mathematically unbounded along the + real axis and in the interval [$-i\pi/2$, $+i\pi/2$] along the + imaginary axis. + @end tex + +PORTABILITY + <> and <> are ISO C99 + +QUICKREF + <> and <> are ISO C99 + +*/ + + +#include + +double complex +catanh(double complex z) +{ + double complex w; + + w = -1.0 * I * catan(z * I); + return w; +} diff --git a/lib/mlibc/options/ansi/generic/complex/catanhf.c b/lib/mlibc/options/ansi/generic/complex/catanhf.c new file mode 100644 index 0000000..fe6127a --- /dev/null +++ b/lib/mlibc/options/ansi/generic/complex/catanhf.c @@ -0,0 +1,44 @@ +/* $NetBSD: catanhf.c,v 1.1 2007/08/20 16:01:32 drochner Exp $ */ + +/*- + * Copyright (c) 2007 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software written by Stephen L. Moshier. + * It is redistributed by the NetBSD Foundation by permission of the author. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +#include + +float complex +catanhf(float complex z) +{ + float complex w; + + w = -1.0f * I * catanf(z * I); + return w; +} diff --git a/lib/mlibc/options/ansi/generic/complex/ccos.c b/lib/mlibc/options/ansi/generic/complex/ccos.c new file mode 100644 index 0000000..ebb52bf --- /dev/null +++ b/lib/mlibc/options/ansi/generic/complex/ccos.c @@ -0,0 +1,81 @@ +/* $NetBSD: ccos.c,v 1.1 2007/08/20 16:01:32 drochner Exp $ */ + +/*- + * Copyright (c) 2007 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software written by Stephen L. Moshier. + * It is redistributed by the NetBSD Foundation by permission of the author. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +/* +FUNCTION + <>, <>---complex cosine + +INDEX + ccos +INDEX + ccosf + +ANSI_SYNOPSIS + #include + double complex ccos(double complex <[z]>); + float complex ccosf(float complex <[z]>); + + +DESCRIPTION + These functions compute the complex cosine of <[z]>. + + <> is identical to <>, except that it performs + its calculations on <>. + +RETURNS + These functions return the complex cosine value. + +PORTABILITY + <> and <> are ISO C99 + +QUICKREF + <> and <> are ISO C99 + +*/ + + +#include +#include +#include "cephes_subr.h" + +double complex +ccos(double complex z) +{ + double complex w; + double ch, sh; + + __mlibc_cchsh(cimag(z), &ch, &sh); + w = cos(creal(z)) * ch - (sin(creal(z)) * sh) * I; + return w; +} diff --git a/lib/mlibc/options/ansi/generic/complex/ccosf.c b/lib/mlibc/options/ansi/generic/complex/ccosf.c new file mode 100644 index 0000000..db7fab3 --- /dev/null +++ b/lib/mlibc/options/ansi/generic/complex/ccosf.c @@ -0,0 +1,48 @@ +/* $NetBSD: ccosf.c,v 1.1 2007/08/20 16:01:33 drochner Exp $ */ + +/*- + * Copyright (c) 2007 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software written by Stephen L. Moshier. + * It is redistributed by the NetBSD Foundation by permission of the author. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +#include +#include +#include "cephes_subrf.h" + +float complex +ccosf(float complex z) +{ + float complex w; + float ch, sh; + + __mlibc_cchshf(cimagf(z), &ch, &sh); + w = cosf(crealf(z)) * ch - (sinf(crealf(z)) * sh) * I; + return w; +} diff --git a/lib/mlibc/options/ansi/generic/complex/ccosh.c b/lib/mlibc/options/ansi/generic/complex/ccosh.c new file mode 100644 index 0000000..223a5ed --- /dev/null +++ b/lib/mlibc/options/ansi/generic/complex/ccosh.c @@ -0,0 +1,81 @@ +/* $NetBSD: ccosh.c,v 1.1 2007/08/20 16:01:33 drochner Exp $ */ + +/*- + * Copyright (c) 2007 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software written by Stephen L. Moshier. + * It is redistributed by the NetBSD Foundation by permission of the author. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +/* +FUNCTION + <>, <>---complex hyperbolic cosine + +INDEX + ccosh +INDEX + ccoshf + +ANSI_SYNOPSIS + #include + double complex ccosh(double complex <[z]>); + float complex ccoshf(float complex <[z]>); + + +DESCRIPTION + These functions compute the complex hyperbolic cosine of <[z]>. + + <> is identical to <>, except that it performs + its calculations on <>. + +RETURNS + These functions return the complex hyperbolic cosine value. + +PORTABILITY + <> and <> are ISO C99 + +QUICKREF + <> and <> are ISO C99 + +*/ + + +#include +#include + +double complex +ccosh(double complex z) +{ + double complex w; + double x, y; + + x = creal(z); + y = cimag(z); + w = cosh(x) * cos(y) + (sinh(x) * sin(y)) * I; + return w; +} diff --git a/lib/mlibc/options/ansi/generic/complex/ccoshf.c b/lib/mlibc/options/ansi/generic/complex/ccoshf.c new file mode 100644 index 0000000..af11353 --- /dev/null +++ b/lib/mlibc/options/ansi/generic/complex/ccoshf.c @@ -0,0 +1,48 @@ +/* $NetBSD: ccoshf.c,v 1.1 2007/08/20 16:01:33 drochner Exp $ */ + +/*- + * Copyright (c) 2007 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software written by Stephen L. Moshier. + * It is redistributed by the NetBSD Foundation by permission of the author. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +#include +#include + +float complex +ccoshf(float complex z) +{ + float complex w; + float x, y; + + x = crealf(z); + y = cimagf(z); + w = coshf(x) * cosf(y) + (sinhf(x) * sinf(y)) * I; + return w; +} diff --git a/lib/mlibc/options/ansi/generic/complex/cephes_subr.c b/lib/mlibc/options/ansi/generic/complex/cephes_subr.c new file mode 100644 index 0000000..fe08b42 --- /dev/null +++ b/lib/mlibc/options/ansi/generic/complex/cephes_subr.c @@ -0,0 +1,126 @@ +/* $NetBSD: cephes_subr.c,v 1.1 2007/08/20 16:01:33 drochner Exp $ */ + +/*- + * Copyright (c) 2007 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software written by Stephen L. Moshier. + * It is redistributed by the NetBSD Foundation by permission of the author. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +#include +#include +#include "cephes_subr.h" + +/* calculate cosh and sinh */ + +void +__mlibc_cchsh(double x, double *c, double *s) +{ + double e, ei; + + if (fabs(x) <= 0.5) { + *c = cosh(x); + *s = sinh(x); + } else { + e = exp(x); + ei = 0.5 / e; + e = 0.5 * e; + *s = e - ei; + *c = e + ei; + } +} + +/* Program to subtract nearest integer multiple of PI */ + +/* extended precision value of PI: */ +static const double DP1 = 3.14159265160560607910E0; +static const double DP2 = 1.98418714791870343106E-9; +static const double DP3 = 1.14423774522196636802E-17; +#define MACHEP 1.1e-16 + +double +__mlibc_redupi(double x) +{ + double t; + long i; + + t = x / M_PI; + if (t >= 0.0) + t += 0.5; + else + t -= 0.5; + + i = t; /* the multiple */ + t = i; + t = ((x - t * DP1) - t * DP2) - t * DP3; + return t; +} + +/* Taylor series expansion for cosh(2y) - cos(2x) */ + +double +__mlibc_ctans(double complex z) +{ + double f, x, x2, y, y2, rn, t; + double d; + + x = fabs(2.0 * creal(z)); + y = fabs(2.0 * cimag(z)); + + x = __mlibc_redupi(x); + + x = x * x; + y = y * y; + x2 = 1.0; + y2 = 1.0; + f = 1.0; + rn = 0.0; + d = 0.0; + do { + rn += 1.0; + f *= rn; + rn += 1.0; + f *= rn; + x2 *= x; + y2 *= y; + t = y2 + x2; + t /= f; + d += t; + + rn += 1.0; + f *= rn; + rn += 1.0; + f *= rn; + x2 *= x; + y2 *= y; + t = y2 - x2; + t /= f; + d += t; + } while (fabs(t/d) > MACHEP); + return d; +} diff --git a/lib/mlibc/options/ansi/generic/complex/cephes_subr.h b/lib/mlibc/options/ansi/generic/complex/cephes_subr.h new file mode 100644 index 0000000..719075e --- /dev/null +++ b/lib/mlibc/options/ansi/generic/complex/cephes_subr.h @@ -0,0 +1,9 @@ +/* $NetBSD: cephes_subr.h,v 1.1 2007/08/20 16:01:33 drochner Exp $ */ + +#ifndef __MLIBC_ABI_ONLY + +void __mlibc_cchsh(double, double *, double *); +double __mlibc_redupi(double); +double __mlibc_ctans(double complex); + +#endif /* !__MLIBC_ABI_ONLY */ diff --git a/lib/mlibc/options/ansi/generic/complex/cephes_subrf.c b/lib/mlibc/options/ansi/generic/complex/cephes_subrf.c new file mode 100644 index 0000000..1ce18e5 --- /dev/null +++ b/lib/mlibc/options/ansi/generic/complex/cephes_subrf.c @@ -0,0 +1,125 @@ +/* $NetBSD: cephes_subrf.c,v 1.1 2007/08/20 16:01:34 drochner Exp $ */ + +/*- + * Copyright (c) 2007 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software written by Stephen L. Moshier. + * It is redistributed by the NetBSD Foundation by permission of the author. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +#include +#include +#include "cephes_subrf.h" + +/* calculate cosh and sinh */ + +void +__mlibc_cchshf(float x, float *c, float *s) +{ + float e, ei; + + if (fabsf(x) <= 0.5f) { + *c = coshf(x); + *s = sinhf(x); + } else { + e = expf(x); + ei = 0.5f / e; + e = 0.5f * e; + *s = e - ei; + *c = e + ei; + } +} + +/* Program to subtract nearest integer multiple of PI */ + +/* extended precision value of PI: */ +static const double DP1 = 3.140625; +static const double DP2 = 9.67502593994140625E-4; +static const double DP3 = 1.509957990978376432E-7; +#define MACHEPF 3.0e-8 + +float +__mlibc_redupif(float x) +{ + float t; + long i; + + t = x / (float)M_PI; + if (t >= 0.0f) + t += 0.5f; + else + t -= 0.5f; + + i = t; /* the multiple */ + t = i; + t = ((x - t * DP1) - t * DP2) - t * DP3; + return t; +} + +/* Taylor series expansion for cosh(2y) - cos(2x) */ + +float +__mlibc_ctansf(float complex z) +{ + float f, x, x2, y, y2, rn, t, d; + + x = fabsf(2.0f * crealf(z)); + y = fabsf(2.0f * cimagf(z)); + + x = __mlibc_redupif(x); + + x = x * x; + y = y * y; + x2 = 1.0f; + y2 = 1.0f; + f = 1.0f; + rn = 0.0f; + d = 0.0f; + do { + rn += 1.0f; + f *= rn; + rn += 1.0f; + f *= rn; + x2 *= x; + y2 *= y; + t = y2 + x2; + t /= f; + d += t; + + rn += 1.0f; + f *= rn; + rn += 1.0f; + f *= rn; + x2 *= x; + y2 *= y; + t = y2 - x2; + t /= f; + d += t; + } while (fabsf(t/d) > MACHEPF); + return d; +} diff --git a/lib/mlibc/options/ansi/generic/complex/cephes_subrf.h b/lib/mlibc/options/ansi/generic/complex/cephes_subrf.h new file mode 100644 index 0000000..84cdd82 --- /dev/null +++ b/lib/mlibc/options/ansi/generic/complex/cephes_subrf.h @@ -0,0 +1,9 @@ +/* $NetBSD: cephes_subrf.h,v 1.1 2007/08/20 16:01:34 drochner Exp $ */ + +#ifndef __MLIBC_ABI_ONLY + +void __mlibc_cchshf(float, float *, float *); +float __mlibc_redupif(float); +float __mlibc_ctansf(float complex); + +#endif /* !__MLIBC_ABI_ONLY */ diff --git a/lib/mlibc/options/ansi/generic/complex/cexp.c b/lib/mlibc/options/ansi/generic/complex/cexp.c new file mode 100644 index 0000000..b9a3fd0 --- /dev/null +++ b/lib/mlibc/options/ansi/generic/complex/cexp.c @@ -0,0 +1,82 @@ +/* $NetBSD: cexp.c,v 1.1 2007/08/20 16:01:34 drochner Exp $ */ + +/*- + * Copyright (c) 2007 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software written by Stephen L. Moshier. + * It is redistributed by the NetBSD Foundation by permission of the author. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +/* +FUNCTION + <>, <>---complex base-e exponential + +INDEX + cexp +INDEX + cexpf + +ANSI_SYNOPSIS + #include + double complex cexp(double complex <[z]>); + float complex cexpf(float complex <[z]>); + + +DESCRIPTION + These functions compute the complex base-<[e]> exponential of <[z]>. + + <> is identical to <>, except that it performs + its calculations on <>. + +RETURNS + The cexp functions return the complex base-<[e]> exponential value. + +PORTABILITY + <> and <> are ISO C99 + +QUICKREF + <> and <> are ISO C99 + +*/ + + +#include +#include + +double complex +cexp(double complex z) +{ + double complex w; + double r, x, y; + + x = creal(z); + y = cimag(z); + r = exp(x); + w = r * cos(y) + r * sin(y) * I; + return w; +} diff --git a/lib/mlibc/options/ansi/generic/complex/cexpf.c b/lib/mlibc/options/ansi/generic/complex/cexpf.c new file mode 100644 index 0000000..07fab1f --- /dev/null +++ b/lib/mlibc/options/ansi/generic/complex/cexpf.c @@ -0,0 +1,49 @@ +/* $NetBSD: cexpf.c,v 1.1 2007/08/20 16:01:34 drochner Exp $ */ + +/*- + * Copyright (c) 2007 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software written by Stephen L. Moshier. + * It is redistributed by the NetBSD Foundation by permission of the author. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +#include +#include + +float complex +cexpf(float complex z) +{ + float complex w; + float r, x, y; + + x = crealf(z); + y = cimagf(z); + r = expf(x); + w = r * cosf(y) + r * sinf(y) * I; + return w; +} diff --git a/lib/mlibc/options/ansi/generic/complex/cimag.c b/lib/mlibc/options/ansi/generic/complex/cimag.c new file mode 100644 index 0000000..24619f0 --- /dev/null +++ b/lib/mlibc/options/ansi/generic/complex/cimag.c @@ -0,0 +1,54 @@ +/* $NetBSD: cimag.c,v 1.2 2010/09/15 16:11:29 christos Exp $ */ + +/* + * Written by Matthias Drochner . + * Public domain. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +/* +FUNCTION + <>, <>---imaginary part + +INDEX + cimag +INDEX + cimagf + +ANSI_SYNOPSIS + #include + double cimag(double complex <[z]>); + float cimagf(float complex <[z]>); + + +DESCRIPTION + These functions compute the imaginary part of <[z]>. + + <> is identical to <>, except that it performs + its calculations on <>. + +RETURNS + The cimag functions return the imaginary part value (as a real). + +PORTABILITY + <> and <> are ISO C99 + +QUICKREF + <> and <> are ISO C99 + +*/ + + +#include + +#include "fdlibm.h" + +double +cimag(double complex z) +{ + double_complex w = { .z = z }; + + return (IMAG_PART(w)); +} diff --git a/lib/mlibc/options/ansi/generic/complex/cimagf.c b/lib/mlibc/options/ansi/generic/complex/cimagf.c new file mode 100644 index 0000000..28ed81c --- /dev/null +++ b/lib/mlibc/options/ansi/generic/complex/cimagf.c @@ -0,0 +1,21 @@ +/* $NetBSD: cimagf.c,v 1.2 2010/09/15 16:11:29 christos Exp $ */ + +/* + * Written by Matthias Drochner . + * Public domain. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +#include + +#include "fdlibm.h" + +float +cimagf(float complex z) +{ + float_complex w = { .z = z }; + + return (IMAG_PART(w)); +} diff --git a/lib/mlibc/options/ansi/generic/complex/clog.c b/lib/mlibc/options/ansi/generic/complex/clog.c new file mode 100644 index 0000000..f7ad3d2 --- /dev/null +++ b/lib/mlibc/options/ansi/generic/complex/clog.c @@ -0,0 +1,91 @@ +/* $NetBSD: clog.c,v 1.1 2007/08/20 16:01:35 drochner Exp $ */ + +/*- + * Copyright (c) 2007 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software written by Stephen L. Moshier. + * It is redistributed by the NetBSD Foundation by permission of the author. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +/* +FUNCTION + <>, <>---complex base-e logarithm + +INDEX + clog +INDEX + clogf + +ANSI_SYNOPSIS + #include + double complex clog(double complex <[z]>); + float complex clogf(float complex <[z]>); + + +DESCRIPTION + These functions compute the complex natural (base-<[e]>) logarithm + of <[z]>, with a branch cut along the negative real axis. + + <> is identical to <>, except that it performs + its calculations on <>. + +RETURNS + @ifnottex + The clog functions return the complex natural logarithm value, in + the range of a strip mathematically unbounded along the real axis + and in the interval [-i*pi , +i*pi] along the imaginary axis. + @end ifnottex + @tex + The clog functions return the complex natural logarithm value, in + the range of a strip mathematically unbounded along the real axis + and in the interval [$-i\pi$, $+i\pi$] along the imaginary axis. + @end tex + +PORTABILITY + <> and <> are ISO C99 + +QUICKREF + <> and <> are ISO C99 + +*/ + +#include +#include + +double complex +clog(double complex z) +{ + double complex w; + double p, rr; + + rr = cabs(z); + p = log(rr); + rr = atan2(cimag(z), creal(z)); + w = p + rr * I; + return w; +} diff --git a/lib/mlibc/options/ansi/generic/complex/clogf.c b/lib/mlibc/options/ansi/generic/complex/clogf.c new file mode 100644 index 0000000..078cea5 --- /dev/null +++ b/lib/mlibc/options/ansi/generic/complex/clogf.c @@ -0,0 +1,49 @@ +/* $NetBSD: clogf.c,v 1.1 2007/08/20 16:01:35 drochner Exp $ */ + +/*- + * Copyright (c) 2007 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software written by Stephen L. Moshier. + * It is redistributed by the NetBSD Foundation by permission of the author. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +#include +#include + +float complex +clogf(float complex z) +{ + float complex w; + float p, rr; + + rr = cabsf(z); + p = logf(rr); + rr = atan2f(cimagf(z), crealf(z)); + w = p + rr * I; + return w; +} diff --git a/lib/mlibc/options/ansi/generic/complex/conj.c b/lib/mlibc/options/ansi/generic/complex/conj.c new file mode 100644 index 0000000..a761b5a --- /dev/null +++ b/lib/mlibc/options/ansi/generic/complex/conj.c @@ -0,0 +1,56 @@ +/* $NetBSD: conj.c,v 1.2 2010/09/15 16:11:29 christos Exp $ */ + +/* + * Written by Matthias Drochner . + * Public domain. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +/* +FUNCTION + <>, <>---complex conjugate + +INDEX + conj +INDEX + conjf + +ANSI_SYNOPSIS + #include + double complex conj(double complex <[z]>); + float complex conjf(float complex <[z]>); + + +DESCRIPTION + These functions compute the complex conjugate of <[z]>, + by reversing the sign of its imaginary part. + + <> is identical to <>, except that it performs + its calculations on <>. + +RETURNS + The conj functions return the complex conjugate value. + +PORTABILITY + <> and <> are ISO C99 + +QUICKREF + <> and <> are ISO C99 + +*/ + +#include + +#include "fdlibm.h" + +double complex +conj(double complex z) +{ + double_complex w = { .z = z }; + + IMAG_PART(w) = -IMAG_PART(w); + + return (w.z); +} diff --git a/lib/mlibc/options/ansi/generic/complex/conjf.c b/lib/mlibc/options/ansi/generic/complex/conjf.c new file mode 100644 index 0000000..0ca71ef --- /dev/null +++ b/lib/mlibc/options/ansi/generic/complex/conjf.c @@ -0,0 +1,23 @@ +/* $NetBSD: conjf.c,v 1.2 2010/09/15 16:11:29 christos Exp $ */ + +/* + * Written by Matthias Drochner . + * Public domain. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +#include + +#include "fdlibm.h" + +float complex +conjf(float complex z) +{ + float_complex w = { .z = z }; + + IMAG_PART(w) = -IMAG_PART(w); + + return (w.z); +} diff --git a/lib/mlibc/options/ansi/generic/complex/cpow.c b/lib/mlibc/options/ansi/generic/complex/cpow.c new file mode 100644 index 0000000..b60f7be --- /dev/null +++ b/lib/mlibc/options/ansi/generic/complex/cpow.c @@ -0,0 +1,101 @@ +/* $NetBSD: cpow.c,v 1.1 2007/08/20 16:01:35 drochner Exp $ */ + +/*- + * Copyright (c) 2007 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software written by Stephen L. Moshier. + * It is redistributed by the NetBSD Foundation by permission of the author. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +/* +FUNCTION + <>, <>---complex power + +INDEX + cpow +INDEX + cpowf + +ANSI_SYNOPSIS + #include + double complex cpow(double complex <[x]>, double complex <[y]>); + float complex cpowf(float complex <[x]>, float complex <[y]>); + + +DESCRIPTION + @ifnottex + The cpow functions compute the complex power function x^y + power, with a branch cut for the first parameter along the + negative real axis. + @end ifnottex + @tex + The cpow functions compute the complex power function $x^y$ + power, with a branch cut for the first parameter along the + negative real axis. + @end tex + + <> is identical to <>, except that it performs + its calculations on <>. + +RETURNS + The cpow functions return the complex power function value. + +PORTABILITY + <> and <> are ISO C99 + +QUICKREF + <> and <> are ISO C99 + +*/ + + +#include +#include + +double complex +cpow(double complex a, double complex z) +{ + double complex w; + double x, y, r, theta, absa, arga; + + x = creal(z); + y = cimag(z); + absa = cabs(a); + if (absa == 0.0) { + return (0.0 + 0.0 * I); + } + arga = carg(a); + r = pow(absa, x); + theta = x * arga; + if (y != 0.0) { + r = r * exp(-y * arga); + theta = theta + y * log(absa); + } + w = r * cos(theta) + (r * sin(theta)) * I; + return w; +} diff --git a/lib/mlibc/options/ansi/generic/complex/cpowf.c b/lib/mlibc/options/ansi/generic/complex/cpowf.c new file mode 100644 index 0000000..1e736af --- /dev/null +++ b/lib/mlibc/options/ansi/generic/complex/cpowf.c @@ -0,0 +1,59 @@ +/* $NetBSD: cpowf.c,v 1.1 2007/08/20 16:01:36 drochner Exp $ */ + +/*- + * Copyright (c) 2007 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software written by Stephen L. Moshier. + * It is redistributed by the NetBSD Foundation by permission of the author. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +#include +#include + +float complex +cpowf(float complex a, float complex z) +{ + float complex w; + float x, y, r, theta, absa, arga; + + x = crealf(z); + y = cimagf(z); + absa = cabsf(a); + if (absa == 0.0f) { + return (0.0f + 0.0f * I); + } + arga = cargf(a); + r = powf(absa, x); + theta = x * arga; + if (y != 0.0f) { + r = r * expf(-y * arga); + theta = theta + y * logf(absa); + } + w = r * cosf(theta) + (r * sinf(theta)) * I; + return w; +} diff --git a/lib/mlibc/options/ansi/generic/complex/cproj.c b/lib/mlibc/options/ansi/generic/complex/cproj.c new file mode 100644 index 0000000..0ed50f2 --- /dev/null +++ b/lib/mlibc/options/ansi/generic/complex/cproj.c @@ -0,0 +1,105 @@ +/* $NetBSD: cproj.c,v 1.3 2010/09/20 17:51:38 christos Exp $ */ + +/*- + * Copyright (c) 2010 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +/* +FUNCTION + <>, <>--- Riemann sphere projection + +INDEX + cproj +INDEX + cprojf + +ANSI_SYNOPSIS + #include + double complex cproj(double complex <[z]>); + float complex cprojf(float complex <[z]>); + + +DESCRIPTION + These functions compute a projection of <[z]> onto the Riemann + sphere: <[z]> projects to <[z]> except that all complex infinities + (even those with one infinite part and one NaN part) project + to positive infinity on the real axis. If <[z]> has an infinite part, + then <>(<[z]>) is equivalent to + + INFINITY + I * copysign(0.0, cimag(z)) + + <> is identical to <>, except that it performs + its calculations on <>. + +RETURNS + The cproj functions return the value of the projection onto + the Riemann sphere. + +PORTABILITY + <> and <> are ISO C99 + +QUICKREF + <> and <> are ISO C99 + +*/ + +/*__RCSID("$NetBSD: cproj.c,v 1.3 2010/09/20 17:51:38 christos Exp $"); */ + +#include +#include + +#include "fdlibm.h" + +/* + * cproj(double complex z) + * + * These functions return the value of the projection (not stereographic!) + * onto the Riemann sphere. + * + * z projects to z, except that all complex infinities (even those with one + * infinite part and one NaN part) project to positive infinity on the real axis. + * If z has an infinite part, then cproj(z) shall be equivalent to: + * + * INFINITY + I * copysign(0.0, cimag(z)) + */ +double complex +cproj(double complex z) +{ + double_complex w = { .z = z }; + + if (isinf(creal(z)) || isinf(cimag(z))) { +#ifdef __INFINITY + REAL_PART(w) = __INFINITY; +#else + REAL_PART(w) = INFINITY; +#endif + IMAG_PART(w) = copysign(0.0, cimag(z)); + } + + return (w.z); +} diff --git a/lib/mlibc/options/ansi/generic/complex/cprojf.c b/lib/mlibc/options/ansi/generic/complex/cprojf.c new file mode 100644 index 0000000..76c3d8a --- /dev/null +++ b/lib/mlibc/options/ansi/generic/complex/cprojf.c @@ -0,0 +1,67 @@ +/* $NetBSD: cprojf.c,v 1.3 2010/09/20 17:51:38 christos Exp $ */ + +/*- + * Copyright (c) 2010 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +/*__RCSID("$NetBSD: cprojf.c,v 1.3 2010/09/20 17:51:38 christos Exp $"); */ + +#include +#include + +#include "fdlibm.h" + +/* + * cprojf(float complex z) + * + * These functions return the value of the projection (not stereographic!) + * onto the Riemann sphere. + * + * z projects to z, except that all complex infinities (even those with one + * infinite part and one NaN part) project to positive infinity on the real axis. + * If z has an infinite part, then cproj(z) shall be equivalent to: + * + * INFINITY + I * copysign(0.0, cimag(z)) + */ + +float complex +cprojf(float complex z) +{ + float_complex w = { .z = z }; + + if (isinf(crealf(z)) || isinf(cimagf(z))) { +#ifdef __INFINITY + REAL_PART(w) = __INFINITY; +#else + REAL_PART(w) = INFINITY; +#endif + IMAG_PART(w) = copysignf(0.0, cimagf(z)); + } + + return (w.z); +} diff --git a/lib/mlibc/options/ansi/generic/complex/creal.c b/lib/mlibc/options/ansi/generic/complex/creal.c new file mode 100644 index 0000000..07bf96f --- /dev/null +++ b/lib/mlibc/options/ansi/generic/complex/creal.c @@ -0,0 +1,54 @@ +/* $NetBSD: creal.c,v 1.2 2010/09/15 16:11:29 christos Exp $ */ + +/* + * Written by Matthias Drochner . + * Public domain. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +/* +FUNCTION + <>, <>---real part + +INDEX + creal +INDEX + crealf + +ANSI_SYNOPSIS + #include + double creal(double complex <[z]>); + float crealf(float complex <[z]>); + + +DESCRIPTION + These functions compute the real part of <[z]>. + + <> is identical to <>, except that it performs + its calculations on <>. + +RETURNS + The creal functions return the real part value. + +PORTABILITY + <> and <> are ISO C99 + +QUICKREF + <> and <> are ISO C99 + +*/ + + +#include + +#include "fdlibm.h" + +double +creal(double complex z) +{ + double_complex w = { .z = z }; + + return (REAL_PART(w)); +} diff --git a/lib/mlibc/options/ansi/generic/complex/crealf.c b/lib/mlibc/options/ansi/generic/complex/crealf.c new file mode 100644 index 0000000..245986d --- /dev/null +++ b/lib/mlibc/options/ansi/generic/complex/crealf.c @@ -0,0 +1,21 @@ +/* $NetBSD: crealf.c,v 1.2 2010/09/15 16:11:29 christos Exp $ */ + +/* + * Written by Matthias Drochner . + * Public domain. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +#include + +#include "fdlibm.h" + +float +crealf(float complex z) +{ + float_complex w = { .z = z }; + + return (REAL_PART(w)); +} diff --git a/lib/mlibc/options/ansi/generic/complex/csin.c b/lib/mlibc/options/ansi/generic/complex/csin.c new file mode 100644 index 0000000..b32d057 --- /dev/null +++ b/lib/mlibc/options/ansi/generic/complex/csin.c @@ -0,0 +1,81 @@ +/* $NetBSD: csin.c,v 1.1 2007/08/20 16:01:36 drochner Exp $ */ + +/*- + * Copyright (c) 2007 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software written by Stephen L. Moshier. + * It is redistributed by the NetBSD Foundation by permission of the author. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +/* +FUNCTION + <>, <>---complex sine + +INDEX + csin +INDEX + csinf + +ANSI_SYNOPSIS + #include + double complex csin(double complex <[z]>); + float complex csinf(float complex <[z]>); + + +DESCRIPTION + These functions compute the complex sine of <[z]>. + + <> is identical to <>, except that it performs + its calculations on <>. + +RETURNS + These functions return the complex sine value. + +PORTABILITY + <> and <> are ISO C99 + +QUICKREF + <> and <> are ISO C99 + +*/ + + +#include +#include +#include "cephes_subr.h" + +double complex +csin(double complex z) +{ + double complex w; + double ch, sh; + + __mlibc_cchsh(cimag(z), &ch, &sh); + w = sin(creal(z)) * ch + (cos(creal(z)) * sh) * I; + return w; +} diff --git a/lib/mlibc/options/ansi/generic/complex/csinf.c b/lib/mlibc/options/ansi/generic/complex/csinf.c new file mode 100644 index 0000000..0d81d41 --- /dev/null +++ b/lib/mlibc/options/ansi/generic/complex/csinf.c @@ -0,0 +1,48 @@ +/* $NetBSD: csinf.c,v 1.1 2007/08/20 16:01:36 drochner Exp $ */ + +/*- + * Copyright (c) 2007 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software written by Stephen L. Moshier. + * It is redistributed by the NetBSD Foundation by permission of the author. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +#include +#include +#include "cephes_subrf.h" + +float complex +csinf(float complex z) +{ + float complex w; + float ch, sh; + + __mlibc_cchshf(cimagf(z), &ch, &sh); + w = sinf(crealf(z)) * ch + (cosf(crealf(z)) * sh) * I; + return w; +} diff --git a/lib/mlibc/options/ansi/generic/complex/csinh.c b/lib/mlibc/options/ansi/generic/complex/csinh.c new file mode 100644 index 0000000..f117162 --- /dev/null +++ b/lib/mlibc/options/ansi/generic/complex/csinh.c @@ -0,0 +1,80 @@ +/* $NetBSD: csinh.c,v 1.1 2007/08/20 16:01:36 drochner Exp $ */ + +/*- + * Copyright (c) 2007 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software written by Stephen L. Moshier. + * It is redistributed by the NetBSD Foundation by permission of the author. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +/* +FUNCTION + <>, <>---complex hyperbolic sine + +INDEX + csinh +INDEX + csinhf + +ANSI_SYNOPSIS + #include + double complex csinh(double complex <[z]>); + float complex csinhf(float complex <[z]>); + + +DESCRIPTION + These functions compute the complex hyperbolic sine of <[z]>. + + <> is identical to <>, except that it performs + its calculations on <>. + +RETURNS + These functions return the complex hyperbolic sine value. + +PORTABILITY + <> and <> are ISO C99 + +QUICKREF + <> and <> are ISO C99 + +*/ + +#include +#include + +double complex +csinh(double complex z) +{ + double complex w; + double x, y; + + x = creal(z); + y = cimag(z); + w = sinh(x) * cos(y) + (cosh(x) * sin(y)) * I; + return w; +} diff --git a/lib/mlibc/options/ansi/generic/complex/csinhf.c b/lib/mlibc/options/ansi/generic/complex/csinhf.c new file mode 100644 index 0000000..3cd6ba7 --- /dev/null +++ b/lib/mlibc/options/ansi/generic/complex/csinhf.c @@ -0,0 +1,48 @@ +/* $NetBSD: csinhf.c,v 1.1 2007/08/20 16:01:37 drochner Exp $ */ + +/*- + * Copyright (c) 2007 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software written by Stephen L. Moshier. + * It is redistributed by the NetBSD Foundation by permission of the author. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +#include +#include + +float complex +csinhf(float complex z) +{ + float complex w; + float x, y; + + x = crealf(z); + y = cimagf(z); + w = sinhf(x) * cosf(y) + (coshf(x) * sinf(y)) * I; + return w; +} diff --git a/lib/mlibc/options/ansi/generic/complex/csqrt.c b/lib/mlibc/options/ansi/generic/complex/csqrt.c new file mode 100644 index 0000000..b144b7c --- /dev/null +++ b/lib/mlibc/options/ansi/generic/complex/csqrt.c @@ -0,0 +1,137 @@ +/* $NetBSD: csqrt.c,v 1.1 2007/08/20 16:01:37 drochner Exp $ */ + +/*- + * Copyright (c) 2007 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software written by Stephen L. Moshier. + * It is redistributed by the NetBSD Foundation by permission of the author. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +/* +FUNCTION + <>, <>---complex square root + +INDEX + csqrt +INDEX + csqrtf + +ANSI_SYNOPSIS + #include + double complex csqrt(double complex <[z]>); + float complex csqrtf(float complex <[z]>); + + +DESCRIPTION + These functions compute the complex square root of <[z]>, with + a branch cut along the negative real axis. + + <> is identical to <>, except that it performs + its calculations on <>. + +RETURNS + The csqrt functions return the complex square root value, in + the range of the right halfplane (including the imaginary axis). + +PORTABILITY + <> and <> are ISO C99 + +QUICKREF + <> and <> are ISO C99 + +*/ + + +#include +#include + +double complex +csqrt(double complex z) +{ + double complex w; + double x, y, r, t, scale; + + x = creal (z); + y = cimag (z); + + if (y == 0.0) { + if (x == 0.0) { + w = 0.0 + y * I; + } else { + r = fabs(x); + r = sqrt(r); + if (x < 0.0) { + w = 0.0 + r * I; + } else { + w = r + y * I; + } + } + return w; + } + if (x == 0.0) { + r = fabs(y); + r = sqrt(0.5 * r); + if (y > 0) + w = r + r * I; + else + w = r - r * I; + return w; + } + /* Rescale to avoid internal overflow or underflow. */ + if ((fabs(x) > 4.0) || (fabs(y) > 4.0)) { + x *= 0.25; + y *= 0.25; + scale = 2.0; + } else { +#if 1 + x *= 1.8014398509481984e16; /* 2^54 */ + y *= 1.8014398509481984e16; + scale = 7.450580596923828125e-9; /* 2^-27 */ +#else + x *= 4.0; + y *= 4.0; + scale = 0.5; +#endif + } + w = x + y * I; + r = cabs(w); + if (x > 0) { + t = sqrt(0.5 * r + 0.5 * x); + r = scale * fabs((0.5 * y) / t ); + t *= scale; + } else { + r = sqrt(0.5 * r - 0.5 * x); + t = scale * fabs((0.5 * y) / r); + r *= scale; + } + if (y < 0) + w = t - r * I; + else + w = t + r * I; + return w; +} diff --git a/lib/mlibc/options/ansi/generic/complex/csqrtf.c b/lib/mlibc/options/ansi/generic/complex/csqrtf.c new file mode 100644 index 0000000..13451fa --- /dev/null +++ b/lib/mlibc/options/ansi/generic/complex/csqrtf.c @@ -0,0 +1,102 @@ +/* $NetBSD: csqrtf.c,v 1.1 2007/08/20 16:01:37 drochner Exp $ */ + +/*- + * Copyright (c) 2007 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software written by Stephen L. Moshier. + * It is redistributed by the NetBSD Foundation by permission of the author. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +#include +#include + +float complex +csqrtf(float complex z) +{ + float complex w; + float x, y, r, t, scale; + + x = crealf (z); + y = cimagf (z); + + if (y == 0.0f) { + if (x < 0.0f) { + w = 0.0f + sqrtf(-x) * I; + return w; + } else if (x == 0.0f) { + return (0.0f + y * I); + } else { + w = sqrtf(x) + y * I; + return w; + } + } + + if (x == 0.0f) { + r = fabsf(y); + r = sqrtf(0.5f * r); + if (y > 0) + w = r + r * I; + else + w = r - r * I; + return w; + } + + /* Rescale to avoid internal overflow or underflow. */ + if ((fabsf(x) > 4.0f) || (fabsf(y) > 4.0f)) { + x *= 0.25f; + y *= 0.25f; + scale = 2.0f; + } else { +#if 1 + x *= 6.7108864e7f; /* 2^26 */ + y *= 6.7108864e7f; + scale = 1.220703125e-4f; /* 2^-13 */ +#else + x *= 4.0f; + y *= 4.0f; + scale = 0.5f; +#endif + } + w = x + y * I; + r = cabsf(w); + if( x > 0 ) { + t = sqrtf(0.5f * r + 0.5f * x); + r = scale * fabsf((0.5f * y) / t); + t *= scale; + } else { + r = sqrtf(0.5f * r - 0.5f * x); + t = scale * fabsf((0.5f * y) / r); + r *= scale; + } + + if (y < 0) + w = t - r * I; + else + w = t + r * I; + return w; +} diff --git a/lib/mlibc/options/ansi/generic/complex/ctan.c b/lib/mlibc/options/ansi/generic/complex/ctan.c new file mode 100644 index 0000000..600989d --- /dev/null +++ b/lib/mlibc/options/ansi/generic/complex/ctan.c @@ -0,0 +1,91 @@ +/* $NetBSD: ctan.c,v 1.1 2007/08/20 16:01:37 drochner Exp $ */ + +/*- + * Copyright (c) 2007 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software written by Stephen L. Moshier. + * It is redistributed by the NetBSD Foundation by permission of the author. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +/* +FUNCTION + <>, <>---complex tangent + +INDEX + ctan +INDEX + ctanf + +ANSI_SYNOPSIS + #include + double complex ctan(double complex <[z]>); + float complex ctanf(float complex <[z]>); + + +DESCRIPTION + These functions compute the complex tangent of <[z]>. + + <> is identical to <>, except that it performs + its calculations on <>. + +RETURNS + These functions return the complex tangent value. + +PORTABILITY + <> and <> are ISO C99 + +QUICKREF + <> and <> are ISO C99 + +*/ + + +#include +#include +#include "cephes_subr.h" + +double complex +ctan(double complex z) +{ + double complex w; + double d; + + d = cos(2.0 * creal(z)) + cosh(2.0 * cimag(z)); + + if (fabs(d) < 0.25) + d = __mlibc_ctans(z); + + if (d == 0.0) { + /* mtherr ("ctan", OVERFLOW); */ + w = HUGE_VAL + HUGE_VAL * I; + return w; + } + + w = sin(2.0 * creal(z)) / d + (sinh(2.0 * cimag(z)) / d) * I; + return w; +} diff --git a/lib/mlibc/options/ansi/generic/complex/ctanf.c b/lib/mlibc/options/ansi/generic/complex/ctanf.c new file mode 100644 index 0000000..52360e0 --- /dev/null +++ b/lib/mlibc/options/ansi/generic/complex/ctanf.c @@ -0,0 +1,58 @@ +/* $NetBSD: ctanf.c,v 1.1 2007/08/20 16:01:38 drochner Exp $ */ + +/*- + * Copyright (c) 2007 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software written by Stephen L. Moshier. + * It is redistributed by the NetBSD Foundation by permission of the author. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +#include +#include +#include "cephes_subrf.h" + +float complex +ctanf(float complex z) +{ + float complex w; + float d; + + d = cosf(2.0f * crealf(z)) + coshf(2.0f * cimagf(z)); + + if (fabsf(d) < 0.25f) + d = __mlibc_ctansf(z); + + if (d == 0.0f) { + /* mtherr ("ctan", OVERFLOW); */ + w = HUGE_VALF + HUGE_VALF * I; + return w; + } + + w = sinf(2.0f * crealf(z)) / d + (sinhf(2.0f * cimagf(z)) / d) * I; + return w; +} diff --git a/lib/mlibc/options/ansi/generic/complex/ctanh.c b/lib/mlibc/options/ansi/generic/complex/ctanh.c new file mode 100644 index 0000000..db27e5b --- /dev/null +++ b/lib/mlibc/options/ansi/generic/complex/ctanh.c @@ -0,0 +1,83 @@ +/* $NetBSD: ctanh.c,v 1.1 2007/08/20 16:01:38 drochner Exp $ */ + +/*- + * Copyright (c) 2007 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software written by Stephen L. Moshier. + * It is redistributed by the NetBSD Foundation by permission of the author. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +/* +FUNCTION + <>, <>---complex hyperbolic tangent + +INDEX + ctanh +INDEX + ctanhf + +ANSI_SYNOPSIS + #include + double complex ctanh(double complex <[z]>); + float complex ctanhf(float complex <[z]>); + + +DESCRIPTION + These functions compute the complex hyperbolic tangent of <[z]>. + + <> is identical to <>, except that it performs + its calculations on <>. + +RETURNS + These functions return the complex hyperbolic tangent value. + +PORTABILITY + <> and <> are ISO C99 + +QUICKREF + <> and <> are ISO C99 + +*/ + + +#include +#include + +double complex +ctanh(double complex z) +{ + double complex w; + double x, y, d; + + x = creal(z); + y = cimag(z); + d = cosh(2.0 * x) + cos(2.0 * y); + w = sinh(2.0 * x) / d + (sin(2.0 * y) / d) * I; + + return w; +} diff --git a/lib/mlibc/options/ansi/generic/complex/ctanhf.c b/lib/mlibc/options/ansi/generic/complex/ctanhf.c new file mode 100644 index 0000000..6aaf20f --- /dev/null +++ b/lib/mlibc/options/ansi/generic/complex/ctanhf.c @@ -0,0 +1,50 @@ +/* $NetBSD: ctanhf.c,v 1.1 2007/08/20 16:01:38 drochner Exp $ */ + +/*- + * Copyright (c) 2007 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software written by Stephen L. Moshier. + * It is redistributed by the NetBSD Foundation by permission of the author. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * imported and modified include for newlib 2010/10/03 + * Marco Atzeri + */ + +#include +#include + +float complex +ctanhf(float complex z) +{ + float complex w; + float x, y, d; + + x = crealf(z); + y = cimagf(z); + d = coshf(2.0f * x) + cosf(2.0f * y); + w = sinhf(2.0f * x) / d + (sinf(2.0f * y) / d) * I; + + return w; +} diff --git a/lib/mlibc/options/ansi/generic/complex/fdlibm.h b/lib/mlibc/options/ansi/generic/complex/fdlibm.h new file mode 100644 index 0000000..75cdd2a --- /dev/null +++ b/lib/mlibc/options/ansi/generic/complex/fdlibm.h @@ -0,0 +1,17 @@ +#ifndef __MLIBC_FDLIBM_H +#define __MLIBC_FDLIBM_H + +#define REAL_PART(z) ((z).parts[0]) +#define IMAG_PART(z) ((z).parts[1]) + +typedef union { + float complex z; + float parts[2]; +} float_complex; + +typedef union { + double complex z; + double parts[2]; +} double_complex; + +#endif diff --git a/lib/mlibc/options/ansi/generic/ctype-stubs.cpp b/lib/mlibc/options/ansi/generic/ctype-stubs.cpp new file mode 100644 index 0000000..3ce76e9 --- /dev/null +++ b/lib/mlibc/options/ansi/generic/ctype-stubs.cpp @@ -0,0 +1,326 @@ + +#include +#include + +#include +#include + +// -------------------------------------------------------------------------------------- +// char ctype functions. +// -------------------------------------------------------------------------------------- + +int isalpha(int nc) { + auto cc = mlibc::current_charcode(); + mlibc::codepoint cp; + if(auto e = cc->promote(nc, cp); e != mlibc::charcode_error::null) + return 0; + return mlibc::current_charset()->is_alpha(cp); +} + +int isdigit(int nc) { + auto cc = mlibc::current_charcode(); + mlibc::codepoint cp; + if(auto e = cc->promote(nc, cp); e != mlibc::charcode_error::null) + return 0; + return mlibc::current_charset()->is_digit(cp); +} + +int isxdigit(int nc) { + auto cc = mlibc::current_charcode(); + mlibc::codepoint cp; + if(auto e = cc->promote(nc, cp); e != mlibc::charcode_error::null) + return 0; + return mlibc::current_charset()->is_xdigit(cp); +} + +int isalnum(int nc) { + auto cc = mlibc::current_charcode(); + mlibc::codepoint cp; + if(auto e = cc->promote(nc, cp); e != mlibc::charcode_error::null) + return 0; + return mlibc::current_charset()->is_alnum(cp); +} + +int ispunct(int nc) { + auto cc = mlibc::current_charcode(); + mlibc::codepoint cp; + if(auto e = cc->promote(nc, cp); e != mlibc::charcode_error::null) + return 0; + return mlibc::current_charset()->is_punct(cp); +} + +int isgraph(int nc) { + auto cc = mlibc::current_charcode(); + mlibc::codepoint cp; + if(auto e = cc->promote(nc, cp); e != mlibc::charcode_error::null) + return 0; + return mlibc::current_charset()->is_graph(cp); +} + +int isblank(int nc) { + auto cc = mlibc::current_charcode(); + mlibc::codepoint cp; + if(auto e = cc->promote(nc, cp); e != mlibc::charcode_error::null) + return 0; + return mlibc::current_charset()->is_blank(cp); +} + +int isspace(int nc) { + auto cc = mlibc::current_charcode(); + mlibc::codepoint cp; + if(auto e = cc->promote(nc, cp); e != mlibc::charcode_error::null) + return 0; + return mlibc::current_charset()->is_space(cp); +} + +int isprint(int nc) { + auto cc = mlibc::current_charcode(); + mlibc::codepoint cp; + if(auto e = cc->promote(nc, cp); e != mlibc::charcode_error::null) + return 0; + return mlibc::current_charset()->is_print(cp); +} + +int islower(int nc) { + auto cc = mlibc::current_charcode(); + mlibc::codepoint cp; + if(auto e = cc->promote(nc, cp); e != mlibc::charcode_error::null) + return 0; + return mlibc::current_charset()->is_lower(cp); +} + +int isupper(int nc) { + auto cc = mlibc::current_charcode(); + mlibc::codepoint cp; + if(auto e = cc->promote(nc, cp); e != mlibc::charcode_error::null) + return 0; + return mlibc::current_charset()->is_upper(cp); +} + +int iscntrl(int nc) { + auto cc = mlibc::current_charcode(); + mlibc::codepoint cp; + if(auto e = cc->promote(nc, cp); e != mlibc::charcode_error::null) + return 0; + return mlibc::generic_is_control(cp); +} + +int isascii(int nc) { + auto cc = mlibc::current_charcode(); + mlibc::codepoint cp; + if(auto e = cc->promote(nc, cp); e != mlibc::charcode_error::null) + return 0; + return cp <= 0x7F; +} + +// -------------------------------------------------------------------------------------- +// wchar_t ctype functions. +// -------------------------------------------------------------------------------------- + +int iswalpha(wint_t nc) { + auto cc = mlibc::platform_wide_charcode(); + mlibc::codepoint cp; + if(auto e = cc->promote(nc, cp); e != mlibc::charcode_error::null) + return 0; + return mlibc::current_charset()->is_alpha(cp); +} + +int iswdigit(wint_t nc) { + auto cc = mlibc::platform_wide_charcode(); + mlibc::codepoint cp; + if(auto e = cc->promote(nc, cp); e != mlibc::charcode_error::null) + return 0; + return mlibc::current_charset()->is_digit(cp); +} + +int iswxdigit(wint_t nc) { + auto cc = mlibc::platform_wide_charcode(); + mlibc::codepoint cp; + if(auto e = cc->promote(nc, cp); e != mlibc::charcode_error::null) + return 0; + return mlibc::current_charset()->is_xdigit(cp); +} + +int iswalnum(wint_t nc) { + auto cc = mlibc::platform_wide_charcode(); + mlibc::codepoint cp; + if(auto e = cc->promote(nc, cp); e != mlibc::charcode_error::null) + return 0; + return mlibc::current_charset()->is_alnum(cp); +} + +int iswpunct(wint_t nc) { + auto cc = mlibc::platform_wide_charcode(); + mlibc::codepoint cp; + if(auto e = cc->promote(nc, cp); e != mlibc::charcode_error::null) + return 0; + return mlibc::current_charset()->is_punct(cp); +} + +int iswgraph(wint_t nc) { + auto cc = mlibc::platform_wide_charcode(); + mlibc::codepoint cp; + if(auto e = cc->promote(nc, cp); e != mlibc::charcode_error::null) + return 0; + return mlibc::current_charset()->is_graph(cp); +} + +int iswblank(wint_t nc) { + auto cc = mlibc::platform_wide_charcode(); + mlibc::codepoint cp; + if(auto e = cc->promote(nc, cp); e != mlibc::charcode_error::null) + return 0; + return mlibc::current_charset()->is_blank(cp); +} + +int iswspace(wint_t nc) { + auto cc = mlibc::platform_wide_charcode(); + mlibc::codepoint cp; + if(auto e = cc->promote(nc, cp); e != mlibc::charcode_error::null) + return 0; + return mlibc::current_charset()->is_space(cp); +} + +int iswprint(wint_t nc) { + auto cc = mlibc::platform_wide_charcode(); + mlibc::codepoint cp; + if(auto e = cc->promote(nc, cp); e != mlibc::charcode_error::null) + return 0; + return mlibc::current_charset()->is_print(cp); +} + +int iswlower(wint_t nc) { + auto cc = mlibc::platform_wide_charcode(); + mlibc::codepoint cp; + if(auto e = cc->promote(nc, cp); e != mlibc::charcode_error::null) + return 0; + return mlibc::current_charset()->is_lower(cp); +} + +int iswupper(wint_t nc) { + auto cc = mlibc::platform_wide_charcode(); + mlibc::codepoint cp; + if(auto e = cc->promote(nc, cp); e != mlibc::charcode_error::null) + return 0; + return mlibc::current_charset()->is_upper(cp); +} + +int iswcntrl(wint_t nc) { + auto cc = mlibc::platform_wide_charcode(); + mlibc::codepoint cp; + if(auto e = cc->promote(nc, cp); e != mlibc::charcode_error::null) + return 0; + return mlibc::generic_is_control(cp); +} + +// -------------------------------------------------------------------------------------- +// iswctype functions. +// -------------------------------------------------------------------------------------- + +namespace { + enum { + ct_null, + ct_alnum, + ct_alpha, + ct_blank, + ct_cntrl, + ct_digit, + ct_graph, + ct_lower, + ct_print, + ct_punct, + ct_space, + ct_upper, + ct_xdigit, + ct_count + }; +} + +wctype_t wctype(const char *cs) { + frg::string_view s{cs}; + if(s == "alnum") return ct_alnum; + if(s == "alpha") return ct_alpha; + if(s == "blank") return ct_blank; + if(s == "cntrl") return ct_cntrl; + if(s == "digit") return ct_digit; + if(s == "graph") return ct_graph; + if(s == "lower") return ct_lower; + if(s == "print") return ct_print; + if(s == "punct") return ct_punct; + if(s == "space") return ct_space; + if(s == "upper") return ct_upper; + if(s == "xdigit") return ct_xdigit; + mlibc::infoLogger() << "mlibc: wctype(\"" << cs << "\") is not supported" << frg::endlog; + return ct_null; +} + +int iswctype(wint_t wc, wctype_t type) { + switch (type) { + case ct_alnum: + return iswalnum(wc); + case ct_alpha: + return iswalpha(wc); + case ct_blank: + return iswblank(wc); + case ct_cntrl: + return iswcntrl(wc); + case ct_digit: + return iswdigit(wc); + case ct_graph: + return iswgraph(wc); + case ct_lower: + return iswlower(wc); + case ct_print: + return iswprint(wc); + case ct_punct: + return iswpunct(wc); + case ct_space: + return iswspace(wc); + case ct_upper: + return iswupper(wc); + case ct_xdigit: + return iswxdigit(wc); + } + return 0; +} + +// -------------------------------------------------------------------------------------- +// char conversion functions. +// -------------------------------------------------------------------------------------- + +int tolower(int nc) { + auto cc = mlibc::current_charcode(); + mlibc::codepoint cp; + if(auto e = cc->promote(nc, cp); e != mlibc::charcode_error::null) + return nc; + return mlibc::current_charset()->to_lower(cp); +} + +int toupper(int nc) { + auto cc = mlibc::current_charcode(); + mlibc::codepoint cp; + if(auto e = cc->promote(nc, cp); e != mlibc::charcode_error::null) + return nc; + return mlibc::current_charset()->to_upper(cp); +} + +// -------------------------------------------------------------------------------------- +// wchar_t conversion functions. +// -------------------------------------------------------------------------------------- + +wint_t towlower(wint_t wc) { + auto cc = mlibc::platform_wide_charcode(); + mlibc::codepoint cp; + if(auto e = cc->promote(wc, cp); e != mlibc::charcode_error::null) + return wc; + return mlibc::current_charset()->to_lower(cp); +} + +wint_t towupper(wint_t wc) { + auto cc = mlibc::platform_wide_charcode(); + mlibc::codepoint cp; + if(auto e = cc->promote(wc, cp); e != mlibc::charcode_error::null) + return wc; + return mlibc::current_charset()->to_upper(cp); +} + diff --git a/lib/mlibc/options/ansi/generic/environment.cpp b/lib/mlibc/options/ansi/generic/environment.cpp new file mode 100644 index 0000000..5625592 --- /dev/null +++ b/lib/mlibc/options/ansi/generic/environment.cpp @@ -0,0 +1,164 @@ +#include +#include +#include + +#include +#include +#include + +#include +#include + +namespace { + char *empty_environment[] = { nullptr }; +} + +char **environ = empty_environment; + +namespace { + +size_t find_environ_index(frg::string_view name) { + for(size_t i = 0; environ[i]; i++) { + frg::string_view view{environ[i]}; + size_t s = view.find_first('='); + if(s == size_t(-1)) { + mlibc::infoLogger() << "mlibc: environment string \"" + << frg::escape_fmt{view.data(), view.size()} + << "\" does not contain an equals sign (=)" << frg::endlog; + continue; + } + if(view.sub_string(0, s) == name) + return i; + } + + return -1; +} + +// Environment vector that is mutated by putenv() and setenv(). +// Cannot be global as it is accessed during library initialization. +frg::vector &get_vector() { + static frg::vector vector{getAllocator()}; + return vector; +} + +void update_vector() { + auto &vector = get_vector(); + if(environ == vector.data()) + return; + + // If the environ variable was changed, we copy the environment. + // Note that we must only copy the pointers but not the strings themselves! + vector.clear(); + for(size_t i = 0; environ[i]; i++) + vector.push(environ[i]); + vector.push(nullptr); + + environ = vector.data(); +} + +void assign_variable(frg::string_view name, const char *string, bool overwrite) { + auto &vector = get_vector(); + __ensure(environ == vector.data()); + + auto k = find_environ_index(name); + if(k != size_t(-1)) { + if(overwrite) + vector[k] = const_cast(string); + }else{ + // Last pointer of environ must always be a null delimiter. + __ensure(!vector.back()); + vector.back() = const_cast(string); + vector.push(nullptr); + } + + // push() might have re-allocated the vector. + environ = vector.data(); +} + +void unassign_variable(frg::string_view name) { + auto &vector = get_vector(); + __ensure(environ == vector.data()); + + auto k = find_environ_index(name); + if(k == size_t(-1)) + return; + + // Last pointer of environ must always be a null delimiter. + __ensure(vector.size() >= 2 && !vector.back()); + std::swap(vector[k], vector[vector.size() - 2]); + vector.pop(); + vector.back() = nullptr; + + // pop() might have re-allocated the vector. + environ = vector.data(); +} + +} // anonymous namespace + +char *getenv(const char *name) { + auto k = find_environ_index(name); + if(k == size_t(-1)) + return nullptr; + + frg::string_view view{environ[k]}; + size_t s = view.find_first('='); + __ensure(s != size_t(-1)); + return const_cast(view.data() + s + 1); +} + +namespace mlibc { + +int putenv(char *string) { + frg::string_view view{string}; + size_t s = view.find_first('='); + if(s == size_t(-1)) + __ensure(!"Environment strings need to contain an equals sign"); + + update_vector(); + assign_variable(view.sub_string(0, s), string, true); + return 0; +} + +} // namespace mlibc + +#if __MLIBC_POSIX_OPTION + +int putenv(char *string) { + return mlibc::putenv(string); +} + +int setenv(const char *name, const char *value, int overwrite) { + frg::string_view view{name}; + size_t s = view.find_first('='); + if(s != size_t(-1)) { + mlibc::infoLogger() << "mlibc: environment variable \"" + << frg::escape_fmt{view.data(), view.size()} << "\" contains an equals sign" + << frg::endlog; + errno = EINVAL; + return -1; + } + + // We never free strings here. TODO: Reuse them? + char *string; + __ensure(asprintf(&string, "%s=%s", name, value) > 0); + __ensure(string); + + update_vector(); + assign_variable(name, string, overwrite); + return 0; +} + +int unsetenv(const char *name) { + update_vector(); + unassign_variable(name); + return 0; +} + +int clearenv(void) { + auto vector = get_vector(); + vector.clear(); + update_vector(); + return 0; +} + +#endif /* __MLIBC_POSIX_OPTION */ diff --git a/lib/mlibc/options/ansi/generic/errno-stubs.cpp b/lib/mlibc/options/ansi/generic/errno-stubs.cpp new file mode 100644 index 0000000..8229a9a --- /dev/null +++ b/lib/mlibc/options/ansi/generic/errno-stubs.cpp @@ -0,0 +1,12 @@ +#include + +int __thread __mlibc_errno; + +char *program_invocation_name = nullptr; +char *program_invocation_short_name = nullptr; +extern char *__progname __attribute__((__weak__, __alias__("program_invocation_short_name"))); +extern char *__progname_full __attribute__((__weak__, __alias__("program_invocation_name"))); + +int *__errno_location() { + return &__mlibc_errno; +} diff --git a/lib/mlibc/options/ansi/generic/fenv-stubs.cpp b/lib/mlibc/options/ansi/generic/fenv-stubs.cpp new file mode 100644 index 0000000..7153844 --- /dev/null +++ b/lib/mlibc/options/ansi/generic/fenv-stubs.cpp @@ -0,0 +1,43 @@ + +#include +#include + +// The functions that are not in this file but are defined in the header +// are implemented like musl does in assembly. +extern "C" __attribute__((__visibility__("hidden"))) int __fesetround(int); + +int fegetexceptflag(fexcept_t *, int) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +int feholdexcept(fenv_t *) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +int fesetexceptflag(const fexcept_t *, int) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +int fesetround(int r) { + if (r != FE_TONEAREST +#ifdef FE_DOWNWARD + && r != FE_DOWNWARD +#endif +#ifdef FE_UPWARD + && r != FE_UPWARD +#endif +#ifdef FE_TOWARDZERO + && r != FE_TOWARDZERO +#endif + ) + return -1; + return __fesetround(r); +} + +int feupdateenv(const fenv_t *) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} diff --git a/lib/mlibc/options/ansi/generic/file-io.cpp b/lib/mlibc/options/ansi/generic/file-io.cpp new file mode 100644 index 0000000..e59b109 --- /dev/null +++ b/lib/mlibc/options/ansi/generic/file-io.cpp @@ -0,0 +1,745 @@ + +#include +#include +#include +#include +#include +#if __MLIBC_GLIBC_OPTION +#include +#endif + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +namespace mlibc { + +// -------------------------------------------------------------------------------------- +// abstract_file implementation. +// -------------------------------------------------------------------------------------- + +namespace { + using file_list = frg::intrusive_list< + abstract_file, + frg::locate_member< + abstract_file, + frg::default_list_hook, + &abstract_file::_list_hook + > + >; + + // Useful when debugging the FILE implementation. + constexpr bool globallyDisableBuffering = false; + + // The maximum number of characters we permit the user to ungetc. + constexpr size_t ungetBufferSize = 8; + + // List of files that will be flushed before exit(). + file_list &global_file_list() { + static frg::eternal list; + return list.get(); + }; +} + +// For pipe-like streams (seek returns ESPIPE), we need to make sure +// that the buffer only ever contains all-dirty or all-clean data. +// Regarding _type and _bufmode: +// As we might construct FILE objects for FDs that are not actually +// open (e.g. for std{in,out,err}), we defer the type determination and cache the result. + +abstract_file::abstract_file(void (*do_dispose)(abstract_file *)) +: _type{stream_type::unknown}, _bufmode{buffer_mode::unknown}, _do_dispose{do_dispose} { + // TODO: For __fwriting to work correctly, set the __io_mode to 1 if the write is write-only. + __buffer_ptr = nullptr; + __unget_ptr = nullptr; + __buffer_size = 4096; + __offset = 0; + __io_offset = 0; + __valid_limit = 0; + __dirty_begin = 0; + __dirty_end = 0; + __io_mode = 0; + __status_bits = 0; + + global_file_list().push_back(this); +} + +abstract_file::~abstract_file() { + if(__dirty_begin != __dirty_end) + mlibc::infoLogger() << "mlibc warning: File is not flushed before destruction" + << frg::endlog; + + if(__buffer_ptr) + getAllocator().free(__buffer_ptr - ungetBufferSize); + + auto it = global_file_list().iterator_to(this); + global_file_list().erase(it); +} + +void abstract_file::dispose() { + if(!_do_dispose) + return; + _do_dispose(this); +} + +// Note that read() and write() are asymmetric: +// While read() can trigger a write-back, write() can never trigger a read-ahead(). +// This peculiarity is reflected in their code. + +int abstract_file::read(char *buffer, size_t max_size, size_t *actual_size) { + __ensure(max_size); + + if(_init_bufmode()) + return -1; + + size_t unget_length = 0; + if (__unget_ptr != __buffer_ptr) { + unget_length = frg::min(max_size, (size_t)(__buffer_ptr - __unget_ptr)); + memcpy(buffer, __unget_ptr, unget_length); + + __unget_ptr += unget_length; + buffer += unget_length; + max_size -= unget_length; + + if (max_size == 0) { + *actual_size = unget_length; + return 0; + } + } + + if(globallyDisableBuffering || _bufmode == buffer_mode::no_buffer) { + size_t io_size; + if(int e = io_read(buffer, max_size, &io_size); e) { + __status_bits |= __MLIBC_ERROR_BIT; + return e; + } + if(!io_size) + __status_bits |= __MLIBC_EOF_BIT; + *actual_size = io_size + unget_length; + return 0; + } + + // Ensure correct buffer type for pipe-like streams. + // TODO: In order to support pipe-like streams we need to write-back the buffer. + if(__io_mode && __valid_limit) + mlibc::panicLogger() << "mlibc: Cannot read-write to same pipe-like stream" + << frg::endlog; + __io_mode = 0; + + // Clear the buffer, then buffer new data. + if(__offset == __valid_limit) { + // TODO: We only have to write-back/reset if __valid_limit reaches the buffer end. + if(int e = _write_back(); e) + return e; + if(int e = _reset(); e) + return e; + + // Perform a read-ahead. + _ensure_allocation(); + size_t io_size; + if(int e = io_read(__buffer_ptr, __buffer_size, &io_size); e) { + __status_bits |= __MLIBC_ERROR_BIT; + return e; + } + if(!io_size) { + __status_bits |= __MLIBC_EOF_BIT; + *actual_size = 0; + return 0; + } + + __io_offset = io_size; + __valid_limit = io_size; + } + + // Return data from the buffer. + __ensure(__offset < __valid_limit); + + auto chunk = frg::min(size_t(__valid_limit - __offset), max_size); + memcpy(buffer, __buffer_ptr + __offset, chunk); + __offset += chunk; + + *actual_size = chunk + unget_length; + return 0; +} + +int abstract_file::write(const char *buffer, size_t max_size, size_t *actual_size) { + __ensure(max_size); + + if(_init_bufmode()) + return -1; + if(globallyDisableBuffering || _bufmode == buffer_mode::no_buffer) { + // As we do not buffer, nothing can be dirty. + __ensure(__dirty_begin == __dirty_end); + size_t io_size; + if(int e = io_write(buffer, max_size, &io_size); e) { + __status_bits |= __MLIBC_ERROR_BIT; + return e; + } + *actual_size = io_size; + return 0; + } + + // Flush the buffer if necessary. + if(__offset == __buffer_size) { + if(int e = _write_back(); e) + return e; + if(int e = _reset(); e) + return e; + } + + // Ensure correct buffer type for pipe-like streams. + // TODO: We could full support pipe-like files + // by ungetc()ing all data before a write happens, + // however, for now we just report an error. + if(!__io_mode && __valid_limit) // TODO: Only check this for pipe-like streams. + mlibc::panicLogger() << "mlibc: Cannot read-write to same pipe-like stream" + << frg::endlog; + __io_mode = 1; + + __ensure(__offset < __buffer_size); + auto chunk = frg::min(__buffer_size - __offset, max_size); + + // Line-buffered streams perform I/O on full lines. + bool flush_line = false; + if(_bufmode == buffer_mode::line_buffer) { + auto nl = reinterpret_cast(memchr(buffer, '\n', chunk)); + if(nl) { + chunk = nl + 1 - buffer; + flush_line = true; + } + } + __ensure(chunk); + + // Buffer data (without necessarily performing I/O). + _ensure_allocation(); + memcpy(__buffer_ptr + __offset, buffer, chunk); + + if(__dirty_begin != __dirty_end) { + __dirty_begin = frg::min(__dirty_begin, __offset); + __dirty_end = frg::max(__dirty_end, __offset + chunk); + }else{ + __dirty_begin = __offset; + __dirty_end = __offset + chunk; + } + __valid_limit = frg::max(__offset + chunk, __valid_limit); + __offset += chunk; + + // Flush line-buffered streams. + if(flush_line) { + if(_write_back()) + return -1; + } + + *actual_size = chunk; + return 0; +} + +int abstract_file::unget(char c) { + if (!__unget_ptr) { + // This can happen if the file is unbuffered, but we still need + // a space to store ungetc'd data. + __ensure(!__buffer_ptr); + _ensure_allocation(); + __ensure(__unget_ptr); + } + + if ((size_t)(__buffer_ptr - __unget_ptr) + 1 > ungetBufferSize) + return EOF; + else { + *(--__unget_ptr) = c; + return c; + } +} + +int abstract_file::update_bufmode(buffer_mode mode) { + // setvbuf() has undefined behavior if I/O has been performed. + __ensure(__dirty_begin == __dirty_end + && "update_bufmode() must only be called before performing I/O"); + _bufmode = mode; + return 0; +} + +void abstract_file::purge() { + __offset = 0; + __io_offset = 0; + __valid_limit = 0; + __dirty_end = __dirty_begin; + __unget_ptr = __buffer_ptr; +} + +int abstract_file::flush() { + if (__dirty_end != __dirty_begin) { + if (int e = _write_back(); e) + return e; + } + + if (int e = _save_pos(); e) + return e; + purge(); + return 0; +} + +int abstract_file::tell(off_t *current_offset) { + off_t seek_offset; + if(int e = io_seek(0, SEEK_CUR, &seek_offset); e) + return e; + + *current_offset = seek_offset + (off_t(__offset) - off_t(__io_offset)); + return 0; +} + +int abstract_file::seek(off_t offset, int whence) { + if(int e = _write_back(); e) + return e; + + off_t new_offset; + if(whence == SEEK_CUR) { + auto seek_offset = offset + (off_t(__offset) - off_t(__io_offset)); + if(int e = io_seek(seek_offset, whence, &new_offset); e) { + __status_bits |= __MLIBC_ERROR_BIT; + return e; + } + }else{ + __ensure(whence == SEEK_SET || whence == SEEK_END); + if(int e = io_seek(offset, whence, &new_offset); e) { + __status_bits |= __MLIBC_ERROR_BIT; + return e; + } + } + + // We just forget the current buffer. + // TODO: If the seek is "small", we can just modify our internal offset. + purge(); + + return 0; +} + +int abstract_file::_init_type() { + if(_type != stream_type::unknown) + return 0; + + if(int e = determine_type(&_type); e) + return e; + __ensure(_type != stream_type::unknown); + return 0; +} + +int abstract_file::_init_bufmode() { + if(_bufmode != buffer_mode::unknown) + return 0; + + if(determine_bufmode(&_bufmode)) + return -1; + __ensure(_bufmode != buffer_mode::unknown); + return 0; +} + +int abstract_file::_write_back() { + if(int e = _init_type(); e) + return e; + + if(__dirty_begin == __dirty_end) + return 0; + + // For non-pipe streams, first do a seek to reset the + // I/O position to zero, then do a write(). + if(_type == stream_type::file_like) { + if(__io_offset != __dirty_begin) { + __ensure(__dirty_begin - __io_offset > 0); + off_t new_offset; + if(int e = io_seek(off_t(__dirty_begin) - off_t(__io_offset), SEEK_CUR, &new_offset); e) + return e; + __io_offset = __dirty_begin; + } + }else{ + __ensure(_type == stream_type::pipe_like); + __ensure(__io_offset == __dirty_begin); + } + + // Now, we are in the correct position to write-back everything. + while(__io_offset < __dirty_end) { + size_t io_size; + if(int e = io_write(__buffer_ptr + __io_offset, __dirty_end - __io_offset, &io_size); e) { + __status_bits |= __MLIBC_ERROR_BIT; + return e; + } + __ensure(io_size > 0 && "io_write() is expected to always write at least one byte"); + __io_offset += io_size; + __dirty_begin += io_size; + } + + return 0; +} + +int abstract_file::_save_pos() { + if (int e = _init_type(); e) + return e; + if (int e = _init_bufmode(); e) + return e; + + if (_type == stream_type::file_like && _bufmode != buffer_mode::no_buffer) { + off_t new_offset; + auto seek_offset = (off_t(__offset) - off_t(__io_offset)); + if (int e = io_seek(seek_offset, SEEK_CUR, &new_offset); e) { + __status_bits |= __MLIBC_ERROR_BIT; + mlibc::infoLogger() << "hit io_seek() error " << e << frg::endlog; + return e; + } + return 0; + } + return 0; // nothing to do for the rest +} + +int abstract_file::_reset() { + if(int e = _init_type(); e) + return e; + + // For pipe-like files, we must not forget already read data. + // TODO: Report this error to the user. + if(_type == stream_type::pipe_like) + __ensure(__offset == __valid_limit); + + __ensure(__dirty_begin == __dirty_end); + __offset = 0; + __io_offset = 0; + __valid_limit = 0; + + return 0; +} + +// This may still be called when buffering is disabled, for ungetc. +void abstract_file::_ensure_allocation() { + if(__buffer_ptr) + return; + + auto ptr = getAllocator().allocate(__buffer_size + ungetBufferSize); + __buffer_ptr = reinterpret_cast(ptr) + ungetBufferSize; + __unget_ptr = __buffer_ptr; +} + +// -------------------------------------------------------------------------------------- +// fd_file implementation. +// -------------------------------------------------------------------------------------- + +fd_file::fd_file(int fd, void (*do_dispose)(abstract_file *), bool force_unbuffered) +: abstract_file{do_dispose}, _fd{fd}, _force_unbuffered{force_unbuffered} { } + +int fd_file::fd() { + return _fd; +} + +int fd_file::close() { + if(__dirty_begin != __dirty_end) + mlibc::infoLogger() << "mlibc warning: File is not flushed before closing" + << frg::endlog; + if(int e = mlibc::sys_close(_fd); e) + return e; + return 0; +} + +int fd_file::reopen(const char *path, const char *mode) { + int mode_flags = parse_modestring(mode); + + int fd; + if(int e = sys_open(path, mode_flags, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH, &fd); e) { + return e; + } + + flush(); + close(); + getAllocator().deallocate(__buffer_ptr, __buffer_size + ungetBufferSize); + + __buffer_ptr = nullptr; + __unget_ptr = nullptr; + __buffer_size = 4096; + _reset(); + _fd = fd; + + if(mode_flags & O_APPEND) { + seek(0, SEEK_END); + } + + return 0; +} + +int fd_file::determine_type(stream_type *type) { + off_t offset; + int e = mlibc::sys_seek(_fd, 0, SEEK_CUR, &offset); + if(!e) { + *type = stream_type::file_like; + return 0; + }else if(e == ESPIPE) { + *type = stream_type::pipe_like; + return 0; + }else{ + return e; + } +} + +int fd_file::determine_bufmode(buffer_mode *mode) { + // When isatty() is not implemented, we fall back to the safest default (no buffering). + if(!mlibc::sys_isatty) { + MLIBC_MISSING_SYSDEP(); + *mode = buffer_mode::no_buffer; + return 0; + } + if(_force_unbuffered) { + *mode = buffer_mode::no_buffer; + return 0; + } + + if(int e = mlibc::sys_isatty(_fd); !e) { + *mode = buffer_mode::line_buffer; + return 0; + }else if(e == ENOTTY) { + *mode = buffer_mode::full_buffer; + return 0; + }else{ + mlibc::infoLogger() << "mlibc: sys_isatty() failed while determining whether" + " stream is interactive" << frg::endlog; + return -1; + } +} + +int fd_file::io_read(char *buffer, size_t max_size, size_t *actual_size) { + ssize_t s; + if(int e = mlibc::sys_read(_fd, buffer, max_size, &s); e) + return e; + *actual_size = s; + return 0; +} + +int fd_file::io_write(const char *buffer, size_t max_size, size_t *actual_size) { + ssize_t s; + if(int e = mlibc::sys_write(_fd, buffer, max_size, &s); e) + return e; + *actual_size = s; + return 0; +} + +int fd_file::io_seek(off_t offset, int whence, off_t *new_offset) { + if(int e = mlibc::sys_seek(_fd, offset, whence, new_offset); e) + return e; + return 0; +} + +int fd_file::parse_modestring(const char *mode) { + // Consume the first char; this must be 'r', 'w' or 'a'. + int flags = 0; + bool has_plus = strchr(mode, '+'); + if(*mode == 'r') { + if(has_plus) { + flags = O_RDWR; + }else{ + flags = O_RDONLY; + } + }else if(*mode == 'w') { + if(has_plus) { + flags = O_RDWR; + }else{ + flags = O_WRONLY; + } + flags |= O_CREAT | O_TRUNC; + }else if(*mode == 'a') { + if(has_plus) { + flags = O_APPEND | O_RDWR; + }else{ + flags = O_APPEND | O_WRONLY; + } + flags |= O_CREAT; + }else{ + mlibc::infoLogger() << "Illegal fopen() mode '" << *mode << "'" << frg::endlog; + } + mode += 1; + + // Consume additional flags. + while(*mode) { + if(*mode == '+') { + mode++; // This is already handled above. + }else if(*mode == 'b') { + mode++; // mlibc assumes that there is no distinction between text and binary. + }else if(*mode == 'e') { + flags |= O_CLOEXEC; + mode++; + }else{ + mlibc::infoLogger() << "Illegal fopen() flag '" << mode << "'" << frg::endlog; + mode++; + } + } + + return flags; +} + +} // namespace mlibc + +namespace { + mlibc::fd_file stdin_file{0}; + mlibc::fd_file stdout_file{1}; + mlibc::fd_file stderr_file{2, nullptr, true}; + + struct stdio_guard { + stdio_guard() { } + + ~stdio_guard() { + // Only flush the files but do not close them. + for(auto it : mlibc::global_file_list()) { + if(int e = it->flush(); e) + mlibc::infoLogger() << "mlibc warning: Failed to flush file before exit()" + << frg::endlog; + } + } + } global_stdio_guard; +} + +FILE *stderr = &stderr_file; +FILE *stdin = &stdin_file; +FILE *stdout = &stdout_file; + +int fileno_unlocked(FILE *file_base) { + auto file = static_cast(file_base); + return file->fd(); +} + +int fileno(FILE *file_base) { + auto file = static_cast(file_base); + frg::unique_lock lock(file->_lock); + return fileno_unlocked(file_base); +} + +FILE *fopen(const char *path, const char *mode) { + int flags = mlibc::fd_file::parse_modestring(mode); + + int fd; + if(int e = mlibc::sys_open(path, flags, 0666, &fd); e) { + errno = e; + return nullptr; + } + + return frg::construct(getAllocator(), fd, + mlibc::file_dispose_cb); +} + +int fclose(FILE *file_base) { + auto file = static_cast(file_base); + int e = 0; + if(file->flush()) + e = EOF; + if(file->close()) + e = EOF; + file->dispose(); + return e; +} + +int fseek(FILE *file_base, long offset, int whence) { + auto file = static_cast(file_base); + frg::unique_lock lock(file->_lock); + if(int e = file->seek(offset, whence); e) { + errno = e; + return -1; + } + return 0; +} + +long ftell(FILE *file_base) { + auto file = static_cast(file_base); + frg::unique_lock lock(file->_lock); + off_t current_offset; + if(int e = file->tell(¤t_offset); e) { + errno = e; + return -1; + } + return current_offset; +} + +int fflush_unlocked(FILE *file_base) { + if(file_base == NULL) { + // Only flush the files but do not close them. + for(auto it : mlibc::global_file_list()) { + if(int e = it->flush(); e) + mlibc::infoLogger() << "mlibc warning: Failed to flush file" + << frg::endlog; + } + return 0; + } + auto file = static_cast(file_base); + if(file->flush()) + return EOF; + return 0; +} +int fflush(FILE *file_base) { + if(file_base == NULL) { + // Only flush the files but do not close them. + for(auto it : mlibc::global_file_list()) { + frg::unique_lock lock(it->_lock); + if(int e = it->flush(); e) + mlibc::infoLogger() << "mlibc warning: Failed to flush file" + << frg::endlog; + } + return 0; + } + + auto file = static_cast(file_base); + frg::unique_lock lock(file->_lock); + if (file->flush()) + return EOF; + return 0; +} + +int setvbuf(FILE *file_base, char *, int mode, size_t) { + // TODO: We could also honor the buffer, but for now use just set the mode. + auto file = static_cast(file_base); + if(mode == _IONBF) { + if(int e = file->update_bufmode(mlibc::buffer_mode::no_buffer); e) { + errno = e; + return -1; + } + }else if(mode == _IOLBF) { + if(int e = file->update_bufmode(mlibc::buffer_mode::line_buffer); e) { + errno = e; + return -1; + } + }else if(mode == _IOFBF) { + if(int e = file->update_bufmode(mlibc::buffer_mode::full_buffer); e) { + errno = e; + return -1; + } + }else{ + errno = EINVAL; + return -1; + } + + return 0; +} + +void rewind(FILE *file_base) { + auto file = static_cast(file_base); + frg::unique_lock lock(file->_lock); + file->seek(0, SEEK_SET); + file_base->__status_bits &= ~(__MLIBC_EOF_BIT | __MLIBC_ERROR_BIT); +} + +int ungetc(int c, FILE *file_base) { + if (c == EOF) + return EOF; + + auto file = static_cast(file_base); + frg::unique_lock lock(file->_lock); + return file->unget(c); +} + +#if __MLIBC_GLIBC_OPTION +void __fpurge(FILE *file_base) { + auto file = static_cast(file_base); + frg::unique_lock lock(file->_lock); + file->purge(); +} +#endif + diff --git a/lib/mlibc/options/ansi/generic/inttypes-stubs.cpp b/lib/mlibc/options/ansi/generic/inttypes-stubs.cpp new file mode 100644 index 0000000..ae0f9e7 --- /dev/null +++ b/lib/mlibc/options/ansi/generic/inttypes-stubs.cpp @@ -0,0 +1,100 @@ + +#include +#include +#include + +#include +#include + +static const char *__mlibc_digits = "0123456789abcdefghijklmnopqrstuvwxyz"; + +intmax_t imaxabs(intmax_t num) { + return num < 0 ? -num : num; +} +imaxdiv_t imaxdiv(intmax_t number, intmax_t denom) { + imaxdiv_t r; + r.quot = number / denom; + r.rem = number % denom; + return r; +} + +template T strtoxmax(const char *it, char **out, int base) { + T v = 0; + bool negate = false; + const unsigned char *s = (const unsigned char *)it; + int c; + + if(std::is_signed::value) { + if(*s == '+') { + s++; + }else if(*s == '-') { + negate = true; + s++; + } + } + + do { + c = *s++; + } while (isspace(c)); + 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; + + if(base == 8) { + if(*it != 0) + goto parse_digits; + it++; + }else if(base == 16) { + if(*it != 0) + goto parse_digits; + it++; + if(*it != 'x' && *it != 'X') + goto parse_digits; + it++; + } + +parse_digits: + while(*it) { + if(isspace(*it)) { + it++; + continue; + } + + __ensure(base <= 10); // TODO: For base > 10 we need to implement tolower(). + //auto c = strchr(__mlibc_digits, tolower(*it)); + auto c = strchr(__mlibc_digits, *it); + if(!c || (c - __mlibc_digits) >= base) + break; + v = v * base + (c - __mlibc_digits); + it++; + } + + if(std::is_signed::value) { + if(negate) + v = -v; + } + + if(out) + *out = const_cast(it); + return v; +} + +intmax_t strtoimax(const char *it, char **out, int base) { + // TODO: This function has to check for overflow! + return strtoxmax(it, out, base); +} +uintmax_t strtoumax(const char *it, char **out, int base) { + return strtoxmax(it, out, base); +} +intmax_t wcstoimax(const wchar_t *__restrict, wchar_t **__restrict, int) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +uintmax_t wcstoumax(const wchar_t *__restrict, wchar_t **__restrict, int) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} diff --git a/lib/mlibc/options/ansi/generic/locale-stubs.cpp b/lib/mlibc/options/ansi/generic/locale-stubs.cpp new file mode 100644 index 0000000..38f5859 --- /dev/null +++ b/lib/mlibc/options/ansi/generic/locale-stubs.cpp @@ -0,0 +1,195 @@ + +#include +#include +#include + +#include + +#include +#include + +namespace { + // Values of the C locale are defined by the C standard. + constexpr lconv c_lconv = { + const_cast("."), // decimal_point + const_cast(""), // thousands_sep + const_cast(""), // grouping + const_cast(""), // mon_decimal_point + const_cast(""), // mon_thousands_sep + const_cast(""), // mon_grouping + const_cast(""), // positive_sign + const_cast(""), // negative_sign + const_cast(""), // currency_symbol + CHAR_MAX, // frac_digits + CHAR_MAX, // p_cs_precedes + CHAR_MAX, // n_cs_precedes + CHAR_MAX, // p_sep_by_space + CHAR_MAX, // n_sep_by_space + CHAR_MAX, // p_sign_posn + CHAR_MAX, // n_sign_posn + const_cast(""), // int_curr_symbol + CHAR_MAX, // int_frac_digits + CHAR_MAX, // int_p_cs_precedes + CHAR_MAX, // int_n_cs_precedes + CHAR_MAX, // int_p_sep_by_space + CHAR_MAX, // int_n_sep_by_space + CHAR_MAX, // int_p_sign_posn + CHAR_MAX // int_n_sign_posn + }; +} + +namespace mlibc { + struct locale_description { + // Identifier of this locale. used in setlocale(). + const char *name; + lconv lc; + }; + + constinit const locale_description c_locale{ + .name = "C", + .lc = c_lconv + }; + + constinit const locale_description posix_locale{ + .name = "POSIX", + .lc = c_lconv + }; + + const locale_description *query_locale_description(const char *name) { + if(!strcmp(name, "C")) + return &c_locale; + if(!strcmp(name, "POSIX")) + return &posix_locale; + return nullptr; + } + + const locale_description *collate_facet; + const locale_description *ctype_facet; + const locale_description *monetary_facet; + const locale_description *numeric_facet; + const locale_description *time_facet; + const locale_description *messages_facet; +} + +void __mlibc_initLocale() { + mlibc::collate_facet = &mlibc::c_locale; + mlibc::ctype_facet = &mlibc::c_locale; + mlibc::monetary_facet = &mlibc::c_locale; + mlibc::numeric_facet = &mlibc::c_locale; + mlibc::time_facet = &mlibc::c_locale; + mlibc::messages_facet = &mlibc::c_locale; +} + +char *setlocale(int category, const char *name) { + if(category == LC_ALL) { + // ´TODO: Implement correct return value when categories differ. + auto current_desc = mlibc::collate_facet; + __ensure(current_desc == mlibc::ctype_facet); + __ensure(current_desc == mlibc::monetary_facet); + __ensure(current_desc == mlibc::numeric_facet); + __ensure(current_desc == mlibc::time_facet); + __ensure(current_desc == mlibc::messages_facet); + + if(name) { + // Our default C locale is the C locale. + if(!strlen(name)) + name = "C"; + + auto new_desc = mlibc::query_locale_description(name); + if(!new_desc) { + mlibc::infoLogger() << "mlibc: Locale " << name + << " is not supported" << frg::endlog; + return nullptr; + } + + mlibc::collate_facet = new_desc; + mlibc::ctype_facet = new_desc; + mlibc::monetary_facet = new_desc; + mlibc::numeric_facet = new_desc; + mlibc::time_facet = new_desc; + mlibc::messages_facet = new_desc; + } + return const_cast(current_desc->name); + }else{ + const mlibc::locale_description **facet_ptr; + switch(category) { + case LC_COLLATE: + facet_ptr = &mlibc::collate_facet; + break; + case LC_CTYPE: + facet_ptr = &mlibc::ctype_facet; + break; + case LC_MONETARY: + facet_ptr = &mlibc::monetary_facet; + break; + case LC_NUMERIC: + facet_ptr = &mlibc::numeric_facet; + break; + case LC_TIME: + facet_ptr = &mlibc::time_facet; + break; + case LC_MESSAGES: + facet_ptr = &mlibc::messages_facet; + break; + default: + mlibc::infoLogger() << "mlibc: Unexpected value " << category + << " for category in setlocale()" << frg::endlog; + return nullptr; + } + + auto current_desc = *facet_ptr; + if(name) { + // Our default C locale is the C locale. + if(!strlen(name)) + name = "C"; + + auto new_desc = mlibc::query_locale_description(name); + if(!new_desc) { + mlibc::infoLogger() << "mlibc: Locale " << name + << " is not supported" << frg::endlog; + return nullptr; + } + + *facet_ptr = new_desc; + } + return const_cast(current_desc->name); + } +} + +namespace { + lconv effective_lc; +} + +struct lconv *localeconv(void) { + // Numeric locale. + const auto &numeric_lc = mlibc::numeric_facet->lc; + effective_lc.decimal_point = numeric_lc.decimal_point; + effective_lc.thousands_sep = numeric_lc.thousands_sep; + effective_lc.grouping = numeric_lc.grouping; + + // Monetary locale. + const auto &monetary_lc = mlibc::monetary_facet->lc; + effective_lc.mon_decimal_point = monetary_lc.mon_decimal_point; + effective_lc.mon_thousands_sep = monetary_lc.mon_thousands_sep; + effective_lc.mon_grouping = monetary_lc.mon_grouping; + effective_lc.positive_sign = monetary_lc.positive_sign; + effective_lc.negative_sign = monetary_lc.negative_sign; + effective_lc.currency_symbol = monetary_lc.currency_symbol; + effective_lc.frac_digits = monetary_lc.frac_digits; + effective_lc.p_cs_precedes = monetary_lc.p_cs_precedes; + effective_lc.n_cs_precedes = monetary_lc.n_cs_precedes; + effective_lc.p_sep_by_space = monetary_lc.p_sep_by_space; + effective_lc.n_sep_by_space = monetary_lc.n_sep_by_space; + effective_lc.p_sign_posn = monetary_lc.p_sign_posn; + effective_lc.n_sign_posn = monetary_lc.n_sign_posn; + effective_lc.int_curr_symbol = monetary_lc.int_curr_symbol; + effective_lc.int_frac_digits = monetary_lc.int_frac_digits; + effective_lc.int_p_cs_precedes = monetary_lc.int_p_cs_precedes; + effective_lc.int_n_cs_precedes = monetary_lc.int_n_cs_precedes; + effective_lc.int_p_sep_by_space = monetary_lc.int_p_sep_by_space; + effective_lc.int_n_sep_by_space = monetary_lc.int_n_sep_by_space; + effective_lc.int_p_sign_posn = monetary_lc.int_p_sign_posn; + effective_lc.int_n_sign_posn = monetary_lc.int_n_sign_posn; + + return &effective_lc; +} diff --git a/lib/mlibc/options/ansi/generic/math-stubs.ignored-cpp b/lib/mlibc/options/ansi/generic/math-stubs.ignored-cpp new file mode 100644 index 0000000..9be985f --- /dev/null +++ b/lib/mlibc/options/ansi/generic/math-stubs.ignored-cpp @@ -0,0 +1,1831 @@ + +#include +#include + +#include + +#include + +#include + +// Taken from musl. See musl for the license/copyright! +#define FORCE_EVAL(x) do { \ + if (sizeof(x) == sizeof(float)) { \ + volatile float __x; \ + __x = (x); \ + } else if (sizeof(x) == sizeof(double)) { \ + volatile double __x; \ + __x = (x); \ + } else { \ + volatile long double __x; \ + __x = (x); \ + } \ +} while(0) + +namespace ieee754 { + +struct SoftDouble { + typedef uint64_t Bits; + typedef uint64_t Mantissa; + typedef int16_t Exp; + + static constexpr int kMantissaBits = 52; + static constexpr int kExpBits = 11; + static constexpr int kBias = 1023; + + // this exponent represents zeros (when mantissa = 0) and subnormals (when mantissa != 0) + static constexpr Exp kSubExp = -kBias; + // this exponent represents infinities (when mantissa = 0) and NaNs (when mantissa != 0) + static constexpr Exp kInfExp = ((Exp(1) << kExpBits) - 1) - kBias; + + static constexpr Bits kMantissaMask = (Bits(1) << kMantissaBits) - 1; + static constexpr Bits kExpMask = ((Bits(1) << kExpBits) - 1) << kMantissaBits; + static constexpr Bits kSignMask = Bits(1) << (kMantissaBits + kExpBits); + + SoftDouble(bool negative, Mantissa mantissa, Exp exp) + : negative(negative), mantissa(mantissa), exp(exp) { +// mlibc::infoLogger.log() << "(" << (int)negative << ", " << (void *)mantissa +// << ", " << exp << ")" << frg::end_log; + __ensure(mantissa < (Mantissa(1) << kMantissaBits)); + __ensure((exp + kBias) >= 0); + __ensure((exp + kBias) < (Exp(1) << kExpBits)); + } + + const bool negative; + const Mantissa mantissa; + const Exp exp; +}; + +template +using Bits = typename F::Bits; + +template +using Mantissa = typename F::Mantissa; + +template +using Exp = typename F::Exp; + +template +bool isZero(F x) { + return x.exp == F::kSubExp && x.mantissa == 0; +} + +template +bool isFinite(F x) { + return x.exp != F::kInfExp; +} + +// -------------------------------------------------------- +// Soft float operations +// -------------------------------------------------------- + +template +F constZero(bool negative) { + return F(negative, 0, F::kSubExp); +} + +template +F constOne(bool negative) { + return F(negative, 0, 0); +} + +template +F floor(F x) { + if(!isFinite(x) || isZero(x)) // TODO: need exception for the not-finite case? + return x; + + if(x.exp > F::kMantissaBits) + return x; // x is already integral + + if(x.exp < 0) { + // TODO: raise inexact + // return -1 or +0 + return x.negative ? constOne(true) : constZero(false); + } + + Mantissa mask = F::kMantissaMask >> x.exp; + if(!(x.mantissa & mask)) + return x; // x is already integral + + // TODO: raise inexact + Mantissa integral_position = (Mantissa(1) << F::kMantissaBits) >> x.exp; + if(x.negative) + return F(true, (x.mantissa + integral_position) & (~mask), x.exp); + return F(false, x.mantissa & (~mask), x.exp); +} + +template +F ceil(F x) { + if(!isFinite(x) || isZero(x)) // TODO: need exception for the not-finite case? + return x; + + if(x.exp > F::kMantissaBits) + return x; // x is already integral + + if(x.exp < 0) { + // TODO: raise inexact + // return -0 or +1 + return x.negative ? constZero(true) : constOne(false); + } + + Mantissa mask = F::kMantissaMask >> x.exp; + if(!(x.mantissa & mask)) + return x; // x is already integral + + // TODO: raise inexact + Mantissa integral_position = (Mantissa(1) << F::kMantissaBits) >> x.exp; + if(x.negative) + return F(true, x.mantissa & (~mask), x.exp); + return F(false, (x.mantissa + integral_position) & (~mask), x.exp); +} + +// -------------------------------------------------------- +// Soft float <-> bit string conversion functions +// -------------------------------------------------------- + +template +uint64_t compileBits(F soft) { + auto bits = Bits(soft.mantissa) | ((Bits(soft.exp) + F::kBias) << soft.kMantissaBits); + return soft.negative ? (F::kSignMask | bits) : bits; +} + +SoftDouble extractBits(uint64_t bits) { + return SoftDouble(bits & SoftDouble::kSignMask, bits & SoftDouble::kMantissaMask, + ((bits & SoftDouble::kExpMask) >> SoftDouble::kMantissaBits) - SoftDouble::kBias); +} + +// -------------------------------------------------------- +// Soft float -> native float conversion functions +// -------------------------------------------------------- + +union DoubleBits { + double fp; + uint64_t bits; +}; + +double compileNative(SoftDouble soft) { + DoubleBits word; + word.bits = compileBits(soft); + return word.fp; +} + +SoftDouble extractNative(double native) { + DoubleBits word; + word.fp = native; + return extractBits(word.bits); +} + +} // namespace ieee754 + +int __mlibc_fpclassify(double x) { + return __builtin_fpclassify(FP_NAN, FP_INFINITE, FP_NORMAL, FP_SUBNORMAL, FP_ZERO, x); +} +int __mlibc_fpclassifyf(float x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +int __mlibc_fpclassifyl(long double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +double acos(double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +float acosf(float x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +long double acosl(long double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +double asin(double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +float asinf(float x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +long double asinl(long double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +double atan(double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +float atanf(float x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +long double atanl(long double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +double atan2(double x, double y) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +float atan2f(float x, float y) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +long double atan2l(long double x, long double y) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +// Taken from musl. See musl for the license/copyright! +float __sindf(double x) { + /* |sin(x)/x - s(x)| < 2**-37.5 (~[-4.89e-12, 4.824e-12]). */ + static const double S1 = -0x15555554cbac77.0p-55, /* -0.166666666416265235595 */ + S2 = 0x111110896efbb2.0p-59, /* 0.0083333293858894631756 */ + S3 = -0x1a00f9e2cae774.0p-65, /* -0.000198393348360966317347 */ + S4 = 0x16cd878c3b46a7.0p-71; /* 0.0000027183114939898219064 */ + + double r, s, w, z; + + /* Try to optimize for parallel evaluation as in __tandf.c. */ + z = x*x; + w = z*z; + r = S3 + z*S4; + s = z*x; + return (x + s*(S1 + z*S2)) + s*w*r; +} + +// Taken from musl. See musl for the license/copyright! +float __cosdf(double x) { + /* |cos(x) - c(x)| < 2**-34.1 (~[-5.37e-11, 5.295e-11]). */ + static const double C0 = -0x1ffffffd0c5e81.0p-54, /* -0.499999997251031003120 */ + C1 = 0x155553e1053a42.0p-57, /* 0.0416666233237390631894 */ + C2 = -0x16c087e80f1e27.0p-62, /* -0.00138867637746099294692 */ + C3 = 0x199342e0ee5069.0p-68; /* 0.0000243904487962774090654 */ + + double r, w, z; + + /* Try to optimize for parallel evaluation as in __tandf.c. */ + z = x*x; + w = z*z; + r = C2+z*C3; + return ((1.0+z*C0) + w*C1) + (w*z)*r; +} + +float __tandf(double x, int odd) { + /* |tan(x)/x - t(x)| < 2**-25.5 (~[-2e-08, 2e-08]). */ + static const double T[] = { + 0x15554d3418c99f.0p-54, /* 0.333331395030791399758 */ + 0x1112fd38999f72.0p-55, /* 0.133392002712976742718 */ + 0x1b54c91d865afe.0p-57, /* 0.0533812378445670393523 */ + 0x191df3908c33ce.0p-58, /* 0.0245283181166547278873 */ + 0x185dadfcecf44e.0p-61, /* 0.00297435743359967304927 */ + 0x1362b9bf971bcd.0p-59, /* 0.00946564784943673166728 */ + }; + + double z,r,w,s,t,u; + + z = x*x; + /* + * Split up the polynomial into small independent terms to give + * opportunities for parallel evaluation. The chosen splitting is + * micro-optimized for Athlons (XP, X64). It costs 2 multiplications + * relative to Horner's method on sequential machines. + * + * We add the small terms from lowest degree up for efficiency on + * non-sequential machines (the lowest degree terms tend to be ready + * earlier). Apart from this, we don't care about order of + * operations, and don't need to to care since we have precision to + * spare. However, the chosen splitting is good for accuracy too, + * and would give results as accurate as Horner's method if the + * small terms were added from highest degree down. + */ + r = T[4] + z*T[5]; + t = T[2] + z*T[3]; + w = z*z; + s = z*x; + u = T[0] + z*T[1]; + r = (x + s*u) + (s*w)*(t + w*r); + return odd ? -1.0/r : r; +} + +#define DBL_EPSILON 2.22044604925031308085e-16 +#define EPS DBL_EPSILON + +/* Get a 32 bit int from a float. */ +#define GET_FLOAT_WORD(w,d) \ +do { \ + union {float f; uint32_t i;} __u; \ + __u.f = (d); \ + (w) = __u.i; \ +} while (0) + +/* Get the more significant 32 bit int from a double. */ +#define GET_HIGH_WORD(hi,d) \ +do { \ + union {double f; uint64_t i;} __u; \ + __u.f = (d); \ + (hi) = __u.i >> 32; \ +} while (0) + +/* Get the less significant 32 bit int from a double. */ +#define GET_LOW_WORD(lo,d) \ +do { \ + union {double f; uint64_t i;} __u; \ + __u.f = (d); \ + (lo) = (uint32_t)__u.i; \ +} while (0) + +// Taken from musl. See musl for the license/copyright! +int __rem_pio2_large(double *x, double *y, int e0, int nx, int prec) +{ + static const int init_jk[] = {3,4,4,6}; /* initial value for jk */ + + /* + * Table of constants for 2/pi, 396 Hex digits (476 decimal) of 2/pi + * + * integer array, contains the (24*i)-th to (24*i+23)-th + * bit of 2/pi after binary point. The corresponding + * floating value is + * + * ipio2[i] * 2^(-24(i+1)). + * + * NB: This table must have at least (e0-3)/24 + jk terms. + * For quad precision (e0 <= 16360, jk = 6), this is 686. + */ + static const int32_t ipio2[] = { + 0xA2F983, 0x6E4E44, 0x1529FC, 0x2757D1, 0xF534DD, 0xC0DB62, + 0x95993C, 0x439041, 0xFE5163, 0xABDEBB, 0xC561B7, 0x246E3A, + 0x424DD2, 0xE00649, 0x2EEA09, 0xD1921C, 0xFE1DEB, 0x1CB129, + 0xA73EE8, 0x8235F5, 0x2EBB44, 0x84E99C, 0x7026B4, 0x5F7E41, + 0x3991D6, 0x398353, 0x39F49C, 0x845F8B, 0xBDF928, 0x3B1FF8, + 0x97FFDE, 0x05980F, 0xEF2F11, 0x8B5A0A, 0x6D1F6D, 0x367ECF, + 0x27CB09, 0xB74F46, 0x3F669E, 0x5FEA2D, 0x7527BA, 0xC7EBE5, + 0xF17B3D, 0x0739F7, 0x8A5292, 0xEA6BFB, 0x5FB11F, 0x8D5D08, + 0x560330, 0x46FC7B, 0x6BABF0, 0xCFBC20, 0x9AF436, 0x1DA9E3, + 0x91615E, 0xE61B08, 0x659985, 0x5F14A0, 0x68408D, 0xFFD880, + 0x4D7327, 0x310606, 0x1556CA, 0x73A8C9, 0x60E27B, 0xC08C6B, + + #if LDBL_MAX_EXP > 1024 + 0x47C419, 0xC367CD, 0xDCE809, 0x2A8359, 0xC4768B, 0x961CA6, + 0xDDAF44, 0xD15719, 0x053EA5, 0xFF0705, 0x3F7E33, 0xE832C2, + 0xDE4F98, 0x327DBB, 0xC33D26, 0xEF6B1E, 0x5EF89F, 0x3A1F35, + 0xCAF27F, 0x1D87F1, 0x21907C, 0x7C246A, 0xFA6ED5, 0x772D30, + 0x433B15, 0xC614B5, 0x9D19C3, 0xC2C4AD, 0x414D2C, 0x5D000C, + 0x467D86, 0x2D71E3, 0x9AC69B, 0x006233, 0x7CD2B4, 0x97A7B4, + 0xD55537, 0xF63ED7, 0x1810A3, 0xFC764D, 0x2A9D64, 0xABD770, + 0xF87C63, 0x57B07A, 0xE71517, 0x5649C0, 0xD9D63B, 0x3884A7, + 0xCB2324, 0x778AD6, 0x23545A, 0xB91F00, 0x1B0AF1, 0xDFCE19, + 0xFF319F, 0x6A1E66, 0x615799, 0x47FBAC, 0xD87F7E, 0xB76522, + 0x89E832, 0x60BFE6, 0xCDC4EF, 0x09366C, 0xD43F5D, 0xD7DE16, + 0xDE3B58, 0x929BDE, 0x2822D2, 0xE88628, 0x4D58E2, 0x32CAC6, + 0x16E308, 0xCB7DE0, 0x50C017, 0xA71DF3, 0x5BE018, 0x34132E, + 0x621283, 0x014883, 0x5B8EF5, 0x7FB0AD, 0xF2E91E, 0x434A48, + 0xD36710, 0xD8DDAA, 0x425FAE, 0xCE616A, 0xA4280A, 0xB499D3, + 0xF2A606, 0x7F775C, 0x83C2A3, 0x883C61, 0x78738A, 0x5A8CAF, + 0xBDD76F, 0x63A62D, 0xCBBFF4, 0xEF818D, 0x67C126, 0x45CA55, + 0x36D9CA, 0xD2A828, 0x8D61C2, 0x77C912, 0x142604, 0x9B4612, + 0xC459C4, 0x44C5C8, 0x91B24D, 0xF31700, 0xAD43D4, 0xE54929, + 0x10D5FD, 0xFCBE00, 0xCC941E, 0xEECE70, 0xF53E13, 0x80F1EC, + 0xC3E7B3, 0x28F8C7, 0x940593, 0x3E71C1, 0xB3092E, 0xF3450B, + 0x9C1288, 0x7B20AB, 0x9FB52E, 0xC29247, 0x2F327B, 0x6D550C, + 0x90A772, 0x1FE76B, 0x96CB31, 0x4A1679, 0xE27941, 0x89DFF4, + 0x9794E8, 0x84E6E2, 0x973199, 0x6BED88, 0x365F5F, 0x0EFDBB, + 0xB49A48, 0x6CA467, 0x427271, 0x325D8D, 0xB8159F, 0x09E5BC, + 0x25318D, 0x3974F7, 0x1C0530, 0x010C0D, 0x68084B, 0x58EE2C, + 0x90AA47, 0x02E774, 0x24D6BD, 0xA67DF7, 0x72486E, 0xEF169F, + 0xA6948E, 0xF691B4, 0x5153D1, 0xF20ACF, 0x339820, 0x7E4BF5, + 0x6863B2, 0x5F3EDD, 0x035D40, 0x7F8985, 0x295255, 0xC06437, + 0x10D86D, 0x324832, 0x754C5B, 0xD4714E, 0x6E5445, 0xC1090B, + 0x69F52A, 0xD56614, 0x9D0727, 0x50045D, 0xDB3BB4, 0xC576EA, + 0x17F987, 0x7D6B49, 0xBA271D, 0x296996, 0xACCCC6, 0x5414AD, + 0x6AE290, 0x89D988, 0x50722C, 0xBEA404, 0x940777, 0x7030F3, + 0x27FC00, 0xA871EA, 0x49C266, 0x3DE064, 0x83DD97, 0x973FA3, + 0xFD9443, 0x8C860D, 0xDE4131, 0x9D3992, 0x8C70DD, 0xE7B717, + 0x3BDF08, 0x2B3715, 0xA0805C, 0x93805A, 0x921110, 0xD8E80F, + 0xAF806C, 0x4BFFDB, 0x0F9038, 0x761859, 0x15A562, 0xBBCB61, + 0xB989C7, 0xBD4010, 0x04F2D2, 0x277549, 0xF6B6EB, 0xBB22DB, + 0xAA140A, 0x2F2689, 0x768364, 0x333B09, 0x1A940E, 0xAA3A51, + 0xC2A31D, 0xAEEDAF, 0x12265C, 0x4DC26D, 0x9C7A2D, 0x9756C0, + 0x833F03, 0xF6F009, 0x8C402B, 0x99316D, 0x07B439, 0x15200C, + 0x5BC3D8, 0xC492F5, 0x4BADC6, 0xA5CA4E, 0xCD37A7, 0x36A9E6, + 0x9492AB, 0x6842DD, 0xDE6319, 0xEF8C76, 0x528B68, 0x37DBFC, + 0xABA1AE, 0x3115DF, 0xA1AE00, 0xDAFB0C, 0x664D64, 0xB705ED, + 0x306529, 0xBF5657, 0x3AFF47, 0xB9F96A, 0xF3BE75, 0xDF9328, + 0x3080AB, 0xF68C66, 0x15CB04, 0x0622FA, 0x1DE4D9, 0xA4B33D, + 0x8F1B57, 0x09CD36, 0xE9424E, 0xA4BE13, 0xB52333, 0x1AAAF0, + 0xA8654F, 0xA5C1D2, 0x0F3F0B, 0xCD785B, 0x76F923, 0x048B7B, + 0x721789, 0x53A6C6, 0xE26E6F, 0x00EBEF, 0x584A9B, 0xB7DAC4, + 0xBA66AA, 0xCFCF76, 0x1D02D1, 0x2DF1B1, 0xC1998C, 0x77ADC3, + 0xDA4886, 0xA05DF7, 0xF480C6, 0x2FF0AC, 0x9AECDD, 0xBC5C3F, + 0x6DDED0, 0x1FC790, 0xB6DB2A, 0x3A25A3, 0x9AAF00, 0x9353AD, + 0x0457B6, 0xB42D29, 0x7E804B, 0xA707DA, 0x0EAA76, 0xA1597B, + 0x2A1216, 0x2DB7DC, 0xFDE5FA, 0xFEDB89, 0xFDBE89, 0x6C76E4, + 0xFCA906, 0x70803E, 0x156E85, 0xFF87FD, 0x073E28, 0x336761, + 0x86182A, 0xEABD4D, 0xAFE7B3, 0x6E6D8F, 0x396795, 0x5BBF31, + 0x48D784, 0x16DF30, 0x432DC7, 0x356125, 0xCE70C9, 0xB8CB30, + 0xFD6CBF, 0xA200A4, 0xE46C05, 0xA0DD5A, 0x476F21, 0xD21262, + 0x845CB9, 0x496170, 0xE0566B, 0x015299, 0x375550, 0xB7D51E, + 0xC4F133, 0x5F6E13, 0xE4305D, 0xA92E85, 0xC3B21D, 0x3632A1, + 0xA4B708, 0xD4B1EA, 0x21F716, 0xE4698F, 0x77FF27, 0x80030C, + 0x2D408D, 0xA0CD4F, 0x99A520, 0xD3A2B3, 0x0A5D2F, 0x42F9B4, + 0xCBDA11, 0xD0BE7D, 0xC1DB9B, 0xBD17AB, 0x81A2CA, 0x5C6A08, + 0x17552E, 0x550027, 0xF0147F, 0x8607E1, 0x640B14, 0x8D4196, + 0xDEBE87, 0x2AFDDA, 0xB6256B, 0x34897B, 0xFEF305, 0x9EBFB9, + 0x4F6A68, 0xA82A4A, 0x5AC44F, 0xBCF82D, 0x985AD7, 0x95C7F4, + 0x8D4D0D, 0xA63A20, 0x5F57A4, 0xB13F14, 0x953880, 0x0120CC, + 0x86DD71, 0xB6DEC9, 0xF560BF, 0x11654D, 0x6B0701, 0xACB08C, + 0xD0C0B2, 0x485551, 0x0EFB1E, 0xC37295, 0x3B06A3, 0x3540C0, + 0x7BDC06, 0xCC45E0, 0xFA294E, 0xC8CAD6, 0x41F3E8, 0xDE647C, + 0xD8649B, 0x31BED9, 0xC397A4, 0xD45877, 0xC5E369, 0x13DAF0, + 0x3C3ABA, 0x461846, 0x5F7555, 0xF5BDD2, 0xC6926E, 0x5D2EAC, + 0xED440E, 0x423E1C, 0x87C461, 0xE9FD29, 0xF3D6E7, 0xCA7C22, + 0x35916F, 0xC5E008, 0x8DD7FF, 0xE26A6E, 0xC6FDB0, 0xC10893, + 0x745D7C, 0xB2AD6B, 0x9D6ECD, 0x7B723E, 0x6A11C6, 0xA9CFF7, + 0xDF7329, 0xBAC9B5, 0x5100B7, 0x0DB2E2, 0x24BA74, 0x607DE5, + 0x8AD874, 0x2C150D, 0x0C1881, 0x94667E, 0x162901, 0x767A9F, + 0xBEFDFD, 0xEF4556, 0x367ED9, 0x13D9EC, 0xB9BA8B, 0xFC97C4, + 0x27A831, 0xC36EF1, 0x36C594, 0x56A8D8, 0xB5A8B4, 0x0ECCCF, + 0x2D8912, 0x34576F, 0x89562C, 0xE3CE99, 0xB920D6, 0xAA5E6B, + 0x9C2A3E, 0xCC5F11, 0x4A0BFD, 0xFBF4E1, 0x6D3B8E, 0x2C86E2, + 0x84D4E9, 0xA9B4FC, 0xD1EEEF, 0xC9352E, 0x61392F, 0x442138, + 0xC8D91B, 0x0AFC81, 0x6A4AFB, 0xD81C2F, 0x84B453, 0x8C994E, + 0xCC2254, 0xDC552A, 0xD6C6C0, 0x96190B, 0xB8701A, 0x649569, + 0x605A26, 0xEE523F, 0x0F117F, 0x11B5F4, 0xF5CBFC, 0x2DBC34, + 0xEEBC34, 0xCC5DE8, 0x605EDD, 0x9B8E67, 0xEF3392, 0xB817C9, + 0x9B5861, 0xBC57E1, 0xC68351, 0x103ED8, 0x4871DD, 0xDD1C2D, + 0xA118AF, 0x462C21, 0xD7F359, 0x987AD9, 0xC0549E, 0xFA864F, + 0xFC0656, 0xAE79E5, 0x362289, 0x22AD38, 0xDC9367, 0xAAE855, + 0x382682, 0x9BE7CA, 0xA40D51, 0xB13399, 0x0ED7A9, 0x480569, + 0xF0B265, 0xA7887F, 0x974C88, 0x36D1F9, 0xB39221, 0x4A827B, + 0x21CF98, 0xDC9F40, 0x5547DC, 0x3A74E1, 0x42EB67, 0xDF9DFE, + 0x5FD45E, 0xA4677B, 0x7AACBA, 0xA2F655, 0x23882B, 0x55BA41, + 0x086E59, 0x862A21, 0x834739, 0xE6E389, 0xD49EE5, 0x40FB49, + 0xE956FF, 0xCA0F1C, 0x8A59C5, 0x2BFA94, 0xC5C1D3, 0xCFC50F, + 0xAE5ADB, 0x86C547, 0x624385, 0x3B8621, 0x94792C, 0x876110, + 0x7B4C2A, 0x1A2C80, 0x12BF43, 0x902688, 0x893C78, 0xE4C4A8, + 0x7BDBE5, 0xC23AC4, 0xEAF426, 0x8A67F7, 0xBF920D, 0x2BA365, + 0xB1933D, 0x0B7CBD, 0xDC51A4, 0x63DD27, 0xDDE169, 0x19949A, + 0x9529A8, 0x28CE68, 0xB4ED09, 0x209F44, 0xCA984E, 0x638270, + 0x237C7E, 0x32B90F, 0x8EF5A7, 0xE75614, 0x08F121, 0x2A9DB5, + 0x4D7E6F, 0x5119A5, 0xABF9B5, 0xD6DF82, 0x61DD96, 0x023616, + 0x9F3AC4, 0xA1A283, 0x6DED72, 0x7A8D39, 0xA9B882, 0x5C326B, + 0x5B2746, 0xED3400, 0x7700D2, 0x55F4FC, 0x4D5901, 0x8071E0, + #endif + }; + + static const double PIo2[] = { + 1.57079625129699707031e+00, /* 0x3FF921FB, 0x40000000 */ + 7.54978941586159635335e-08, /* 0x3E74442D, 0x00000000 */ + 5.39030252995776476554e-15, /* 0x3CF84698, 0x80000000 */ + 3.28200341580791294123e-22, /* 0x3B78CC51, 0x60000000 */ + 1.27065575308067607349e-29, /* 0x39F01B83, 0x80000000 */ + 1.22933308981111328932e-36, /* 0x387A2520, 0x40000000 */ + 2.73370053816464559624e-44, /* 0x36E38222, 0x80000000 */ + 2.16741683877804819444e-51, /* 0x3569F31D, 0x00000000 */ + }; + + int32_t jz,jx,jv,jp,jk,carry,n,iq[20],i,j,k,m,q0,ih; + double z,fw,f[20],fq[20],q[20]; + + /* initialize jk*/ + jk = init_jk[prec]; + jp = jk; + + /* determine jx,jv,q0, note that 3>q0 */ + jx = nx-1; + jv = (e0-3)/24; if(jv<0) jv=0; + q0 = e0-24*(jv+1); + + /* set up f[0] to f[jx+jk] where f[jx+jk] = ipio2[jv+jk] */ + j = jv-jx; m = jx+jk; + for (i=0; i<=m; i++,j++) + f[i] = j<0 ? 0.0 : (double)ipio2[j]; + + /* compute q[0],q[1],...q[jk] */ + for (i=0; i<=jk; i++) { + for (j=0,fw=0.0; j<=jx; j++) + fw += x[j]*f[jx+i-j]; + q[i] = fw; + } + + jz = jk; +recompute: + /* distill q[] into iq[] reversingly */ + for (i=0,j=jz,z=q[jz]; j>0; i++,j--) { + fw = (double)(int32_t)(0x1p-24*z); + iq[i] = (int32_t)(z - 0x1p24*fw); + z = q[j-1]+fw; + } + + /* compute n */ + z = scalbn(z,q0); /* actual value of z */ + z -= 8.0*floor(z*0.125); /* trim off integer >= 8 */ + n = (int32_t)z; + z -= (double)n; + ih = 0; + if (q0 > 0) { /* need iq[jz-1] to determine n */ + i = iq[jz-1]>>(24-q0); n += i; + iq[jz-1] -= i<<(24-q0); + ih = iq[jz-1]>>(23-q0); + } + else if (q0 == 0) ih = iq[jz-1]>>23; + else if (z >= 0.5) ih = 2; + + if (ih > 0) { /* q > 0.5 */ + n += 1; carry = 0; + for (i=0; i 0) { /* rare case: chance is 1 in 12 */ + switch(q0) { + case 1: + iq[jz-1] &= 0x7fffff; break; + case 2: + iq[jz-1] &= 0x3fffff; break; + } + } + if (ih == 2) { + z = 1.0 - z; + if (carry != 0) + z -= scalbn(1.0,q0); + } + } + + /* check if recomputation is needed */ + if (z == 0.0) { + j = 0; + for (i=jz-1; i>=jk; i--) j |= iq[i]; + if (j == 0) { /* need recomputation */ + for (k=1; iq[jk-k]==0; k++); /* k = no. of terms needed */ + + for (i=jz+1; i<=jz+k; i++) { /* add q[jz+1] to q[jz+k] */ + f[jx+i] = (double)ipio2[jv+i]; + for (j=0,fw=0.0; j<=jx; j++) + fw += x[j]*f[jx+i-j]; + q[i] = fw; + } + jz += k; + goto recompute; + } + } + + /* chop off zero terms */ + if (z == 0.0) { + jz -= 1; + q0 -= 24; + while (iq[jz] == 0) { + jz--; + q0 -= 24; + } + } else { /* break z into 24-bit if necessary */ + z = scalbn(z,-q0); + if (z >= 0x1p24) { + fw = (double)(int32_t)(0x1p-24*z); + iq[jz] = (int32_t)(z - 0x1p24*fw); + jz += 1; + q0 += 24; + iq[jz] = (int32_t)fw; + } else + iq[jz] = (int32_t)z; + } + + /* convert integer "bit" chunk to floating-point value */ + fw = scalbn(1.0,q0); + for (i=jz; i>=0; i--) { + q[i] = fw*(double)iq[i]; + fw *= 0x1p-24; + } + + /* compute PIo2[0,...,jp]*q[jz,...,0] */ + for(i=jz; i>=0; i--) { + for (fw=0.0,k=0; k<=jp && k<=jz-i; k++) + fw += PIo2[k]*q[i+k]; + fq[jz-i] = fw; + } + + /* compress fq[] into y[] */ + switch(prec) { + case 0: + fw = 0.0; + for (i=jz; i>=0; i--) + fw += fq[i]; + y[0] = ih==0 ? fw : -fw; + break; + case 1: + case 2: + fw = 0.0; + for (i=jz; i>=0; i--) + fw += fq[i]; + // TODO: drop excess precision here once double_t is used + fw = (double)fw; + y[0] = ih==0 ? fw : -fw; + fw = fq[0]-fw; + for (i=1; i<=jz; i++) + fw += fq[i]; + y[1] = ih==0 ? fw : -fw; + break; + case 3: /* painful */ + for (i=jz; i>0; i--) { + fw = fq[i-1]+fq[i]; + fq[i] += fq[i-1]-fw; + fq[i-1] = fw; + } + for (i=jz; i>1; i--) { + fw = fq[i-1]+fq[i]; + fq[i] += fq[i-1]-fw; + fq[i-1] = fw; + } + for (fw=0.0,i=jz; i>=2; i--) + fw += fq[i]; + if (ih==0) { + y[0] = fq[0]; y[1] = fq[1]; y[2] = fw; + } else { + y[0] = -fq[0]; y[1] = -fq[1]; y[2] = -fw; + } + } + return n&7; +} + +int __rem_pio2f(float x, double *y) { + /* + * invpio2: 53 bits of 2/pi + * pio2_1: first 25 bits of pi/2 + * pio2_1t: pi/2 - pio2_1 + */ + static const double toint = 1.5/EPS, + invpio2 = 6.36619772367581382433e-01, /* 0x3FE45F30, 0x6DC9C883 */ + pio2_1 = 1.57079631090164184570e+00, /* 0x3FF921FB, 0x50000000 */ + pio2_1t = 1.58932547735281966916e-08; /* 0x3E5110b4, 0x611A6263 */ + + union {float f; uint32_t i;} u = {x}; + double tx[1],ty[1]; + double fn; + uint32_t ix; + int n, sign, e0; + + ix = u.i & 0x7fffffff; + /* 25+53 bit pi is good enough for medium size */ + if (ix < 0x4dc90fdb) { /* |x| ~< 2^28*(pi/2), medium size */ + /* Use a specialized rint() to get fn. Assume round-to-nearest. */ + fn = (double)x*invpio2 + toint - toint; + n = (int32_t)fn; + *y = x - fn*pio2_1 - fn*pio2_1t; + return n; + } + if(ix>=0x7f800000) { /* x is inf or NaN */ + *y = x-x; + return 0; + } + /* scale x into [2^23, 2^24-1] */ + sign = u.i>>31; + e0 = (ix>>23) - (0x7f+23); /* e0 = ilogb(|x|)-23, positive */ + u.i = ix - (e0<<23); + tx[0] = u.f; + n = __rem_pio2_large(tx,ty,e0,1,0); + if (sign) { + *y = -ty[0]; + return -n; + } + *y = ty[0]; + return n; +} + +double cos(double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +// Taken from musl. See musl for the license/copyright! +float cosf(float x) { + /* Small multiples of pi/2 rounded to double precision. */ + static const double c1pio2 = 1*M_PI_2, /* 0x3FF921FB, 0x54442D18 */ + c2pio2 = 2*M_PI_2, /* 0x400921FB, 0x54442D18 */ + c3pio2 = 3*M_PI_2, /* 0x4012D97C, 0x7F3321D2 */ + c4pio2 = 4*M_PI_2; /* 0x401921FB, 0x54442D18 */ + + double y; + uint32_t ix; + unsigned n, sign; + + GET_FLOAT_WORD(ix, x); + sign = ix >> 31; + ix &= 0x7fffffff; + + if (ix <= 0x3f490fda) { /* |x| ~<= pi/4 */ + if (ix < 0x39800000) { /* |x| < 2**-12 */ + /* raise inexact if x != 0 */ + FORCE_EVAL(x + 0x1p120f); + return 1.0f; + } + return __cosdf(x); + } + if (ix <= 0x407b53d1) { /* |x| ~<= 5*pi/4 */ + if (ix > 0x4016cbe3) /* |x| ~> 3*pi/4 */ + return -__cosdf(sign ? x+c2pio2 : x-c2pio2); + else { + if (sign) + return __sindf(x + c1pio2); + else + return __sindf(c1pio2 - x); + } + } + if (ix <= 0x40e231d5) { /* |x| ~<= 9*pi/4 */ + if (ix > 0x40afeddf) /* |x| ~> 7*pi/4 */ + return __cosdf(sign ? x+c4pio2 : x-c4pio2); + else { + if (sign) + return __sindf(-x - c3pio2); + else + return __sindf(x - c3pio2); + } + } + + /* cos(Inf or NaN) is NaN */ + if (ix >= 0x7f800000) + return x-x; + + /* general argument reduction needed */ + n = __rem_pio2f(x,&y); + switch (n&3) { + case 0: return __cosdf(y); + case 1: return __sindf(-y); + case 2: return -__cosdf(y); + default: + return __sindf(y); + } +} +long double cosl(long double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +double sin(double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +// Taken from musl. See musl for the license/copyright! +float sinf(float x) { + /* Small multiples of pi/2 rounded to double precision. */ + static const double s1pio2 = 1*M_PI_2, /* 0x3FF921FB, 0x54442D18 */ + s2pio2 = 2*M_PI_2, /* 0x400921FB, 0x54442D18 */ + s3pio2 = 3*M_PI_2, /* 0x4012D97C, 0x7F3321D2 */ + s4pio2 = 4*M_PI_2; /* 0x401921FB, 0x54442D18 */ + + double y; + uint32_t ix; + int n, sign; + + GET_FLOAT_WORD(ix, x); + sign = ix >> 31; + ix &= 0x7fffffff; + + if (ix <= 0x3f490fda) { /* |x| ~<= pi/4 */ + if (ix < 0x39800000) { /* |x| < 2**-12 */ + /* raise inexact if x!=0 and underflow if subnormal */ + FORCE_EVAL(ix < 0x00800000 ? x/0x1p120f : x+0x1p120f); + return x; + } + return __sindf(x); + } + if (ix <= 0x407b53d1) { /* |x| ~<= 5*pi/4 */ + if (ix <= 0x4016cbe3) { /* |x| ~<= 3pi/4 */ + if (sign) + return -__cosdf(x + s1pio2); + else + return __cosdf(x - s1pio2); + } + return __sindf(sign ? -(x + s2pio2) : -(x - s2pio2)); + } + if (ix <= 0x40e231d5) { /* |x| ~<= 9*pi/4 */ + if (ix <= 0x40afeddf) { /* |x| ~<= 7*pi/4 */ + if (sign) + return __cosdf(x + s3pio2); + else + return -__cosdf(x - s3pio2); + } + return __sindf(sign ? x + s4pio2 : x - s4pio2); + } + + /* sin(Inf or NaN) is NaN */ + if (ix >= 0x7f800000) + return x - x; + + /* general argument reduction needed */ + n = __rem_pio2f(x, &y); + switch (n&3) { + case 0: return __sindf(y); + case 1: return __cosdf(y); + case 2: return __sindf(-y); + default: + return -__cosdf(y); + } +} +long double sinl(long double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +double tan(double x) { + mlibc::infoLogger() << "mlibc: tan() is not precise" << frg::endlog; + return tanf(x); +} +// Taken from musl. See musl for the license/copyright! +float tanf(float x) { + /* Small multiples of pi/2 rounded to double precision. */ + static const double t1pio2 = 1*M_PI_2, /* 0x3FF921FB, 0x54442D18 */ + t2pio2 = 2*M_PI_2, /* 0x400921FB, 0x54442D18 */ + t3pio2 = 3*M_PI_2, /* 0x4012D97C, 0x7F3321D2 */ + t4pio2 = 4*M_PI_2; /* 0x401921FB, 0x54442D18 */ + + double y; + uint32_t ix; + unsigned n, sign; + + GET_FLOAT_WORD(ix, x); + sign = ix >> 31; + ix &= 0x7fffffff; + + if (ix <= 0x3f490fda) { /* |x| ~<= pi/4 */ + if (ix < 0x39800000) { /* |x| < 2**-12 */ + /* raise inexact if x!=0 and underflow if subnormal */ + FORCE_EVAL(ix < 0x00800000 ? x/0x1p120f : x+0x1p120f); + return x; + } + return __tandf(x, 0); + } + if (ix <= 0x407b53d1) { /* |x| ~<= 5*pi/4 */ + if (ix <= 0x4016cbe3) /* |x| ~<= 3pi/4 */ + return __tandf((sign ? x+t1pio2 : x-t1pio2), 1); + else + return __tandf((sign ? x+t2pio2 : x-t2pio2), 0); + } + if (ix <= 0x40e231d5) { /* |x| ~<= 9*pi/4 */ + if (ix <= 0x40afeddf) /* |x| ~<= 7*pi/4 */ + return __tandf((sign ? x+t3pio2 : x-t3pio2), 1); + else + return __tandf((sign ? x+t4pio2 : x-t4pio2), 0); + } + + /* tan(Inf or NaN) is NaN */ + if (ix >= 0x7f800000) + return x - x; + + /* argument reduction */ + n = __rem_pio2f(x, &y); + return __tandf(y, n&1); +} +long double tanl(long double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +double acosh(double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +float acoshf(float x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +long double acoshl(long double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +double asinh(double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +float asinhf(float x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +long double asinhl(long double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +double atanh(double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +float atanhf(float x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +long double atanhl(long double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +double cosh(double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +float coshf(float x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +long double coshl(long double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +double sinh(double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +float sinhf(float x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +long double sinhl(long double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +double tanh(double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +float tanhf(float x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +long double tanhl(long double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +double exp(double x) { + static const double half[2] = {0.5,-0.5}, + ln2hi = 6.93147180369123816490e-01, /* 0x3fe62e42, 0xfee00000 */ + ln2lo = 1.90821492927058770002e-10, /* 0x3dea39ef, 0x35793c76 */ + invln2 = 1.44269504088896338700e+00, /* 0x3ff71547, 0x652b82fe */ + P1 = 1.66666666666666019037e-01, /* 0x3FC55555, 0x5555553E */ + P2 = -2.77777777770155933842e-03, /* 0xBF66C16C, 0x16BEBD93 */ + P3 = 6.61375632143793436117e-05, /* 0x3F11566A, 0xAF25DE2C */ + P4 = -1.65339022054652515390e-06, /* 0xBEBBBD41, 0xC5D26BF1 */ + P5 = 4.13813679705723846039e-08; /* 0x3E663769, 0x72BEA4D0 */ + + double hi, lo, c, xx, y; + int k, sign; + uint32_t hx; + + GET_HIGH_WORD(hx, x); + sign = hx>>31; + hx &= 0x7fffffff; /* high word of |x| */ + + /* special cases */ + if (hx >= 0x4086232b) { /* if |x| >= 708.39... */ + if (isnan(x)) + return x; + if (x > 709.782712893383973096) { + /* overflow if x!=inf */ + x *= 0x1p1023; + return x; + } + if (x < -708.39641853226410622) { + /* underflow if x!=-inf */ + FORCE_EVAL((float)(-0x1p-149/x)); + if (x < -745.13321910194110842) + return 0; + } + } + + /* argument reduction */ + if (hx > 0x3fd62e42) { /* if |x| > 0.5 ln2 */ + if (hx >= 0x3ff0a2b2) /* if |x| >= 1.5 ln2 */ + k = (int)(invln2*x + half[sign]); + else + k = 1 - sign - sign; + hi = x - k*ln2hi; /* k*ln2hi is exact here */ + lo = k*ln2lo; + x = hi - lo; + } else if (hx > 0x3e300000) { /* if |x| > 2**-28 */ + k = 0; + hi = x; + lo = 0; + } else { + /* inexact if x!=0 */ + FORCE_EVAL(0x1p1023 + x); + return 1 + x; + } + + /* x is now in primary range */ + xx = x*x; + c = x - xx*(P1+xx*(P2+xx*(P3+xx*(P4+xx*P5)))); + y = 1 + (x*c/(2-c) - lo + hi); + if (k == 0) + return y; + return scalbn(y, k); +} +float expf(float x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +long double expl(long double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +double exp2(double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +// Taken from musl. See musl for the license/copyright! +float exp2f(float x) { + constexpr int TBLSIZE = 16; + + constexpr float redux = 0x1.8p23f / TBLSIZE; + constexpr float P1 = 0x1.62e430p-1f; + constexpr float P2 = 0x1.ebfbe0p-3f; + constexpr float P3 = 0x1.c6b348p-5f; + constexpr float P4 = 0x1.3b2c9cp-7f; + + constexpr double exp2ft[TBLSIZE] = { + 0x1.6a09e667f3bcdp-1, + 0x1.7a11473eb0187p-1, + 0x1.8ace5422aa0dbp-1, + 0x1.9c49182a3f090p-1, + 0x1.ae89f995ad3adp-1, + 0x1.c199bdd85529cp-1, + 0x1.d5818dcfba487p-1, + 0x1.ea4afa2a490dap-1, + 0x1.0000000000000p+0, + 0x1.0b5586cf9890fp+0, + 0x1.172b83c7d517bp+0, + 0x1.2387a6e756238p+0, + 0x1.306fe0a31b715p+0, + 0x1.3dea64c123422p+0, + 0x1.4bfdad5362a27p+0, + 0x1.5ab07dd485429p+0, + }; + + double t, r, z; + union {float f; uint32_t i;} u = {x}; + union {double f; uint64_t i;} uk; + uint32_t ix, i0, k; + + /* Filter out exceptional cases. */ + ix = u.i & 0x7fffffff; + if (ix > 0x42fc0000) { /* |x| > 126 */ + if (ix > 0x7f800000) /* NaN */ + return x; + if (u.i >= 0x43000000 && u.i < 0x80000000) { /* x >= 128 */ + x *= 0x1p127f; + return x; + } + if (u.i >= 0x80000000) { /* x < -126 */ + if (u.i >= 0xc3160000 || (u.i & 0x0000ffff)) + FORCE_EVAL(-0x1p-149f/x); + if (u.i >= 0xc3160000) /* x <= -150 */ + return 0; + } + } else if (ix <= 0x33000000) { /* |x| <= 0x1p-25 */ + return 1.0f + x; + } + + /* Reduce x, computing z, i0, and k. */ + u.f = x + redux; + i0 = u.i; + i0 += TBLSIZE / 2; + k = i0 / TBLSIZE; + uk.i = (uint64_t)(0x3ff + k)<<52; + i0 &= TBLSIZE - 1; + u.f -= redux; + z = x - u.f; + /* Compute r = exp2(y) = exp2ft[i0] * p(z). */ + r = exp2ft[i0]; + t = r * z; + r = r + t * (P1 + z * P2) + t * (z * z) * (P3 + z * P4); + + /* Scale by 2**k */ + return r * uk.f; +} +long double exp2l(long double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +double expm1(double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +float expm1f(float x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +long double expm1l(long double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +double frexp(double x, int *power) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +float frexpf(float x, int *power) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +long double frexpl(long double x, int *power) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +double ilogb(double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +float ilogbf(float x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +long double ilogbl(long double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +double ldexp(double x, int power) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +float ldexpf(float x, int power) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +long double ldexpl(long double x, int power) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +double log(double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +float logf(float x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +long double logl(long double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +double log10(double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +float log10f(float x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +long double log10l(long double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +double log1p(double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +float log1pf(float x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +long double log1pl(long double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +// Taken from musl. See musl for the license/copyright! +double log2(double x) { + static const double + ivln2hi = 1.44269504072144627571e+00, /* 0x3ff71547, 0x65200000 */ + ivln2lo = 1.67517131648865118353e-10, /* 0x3de705fc, 0x2eefa200 */ + Lg1 = 6.666666666666735130e-01, /* 3FE55555 55555593 */ + Lg2 = 3.999999999940941908e-01, /* 3FD99999 9997FA04 */ + Lg3 = 2.857142874366239149e-01, /* 3FD24924 94229359 */ + Lg4 = 2.222219843214978396e-01, /* 3FCC71C5 1D8E78AF */ + Lg5 = 1.818357216161805012e-01, /* 3FC74664 96CB03DE */ + Lg6 = 1.531383769920937332e-01, /* 3FC39A09 D078C69F */ + Lg7 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */ + + union {double f; uint64_t i;} u = {x}; + double hfsq,f,s,z,R,w,t1,t2,y,hi,lo,val_hi,val_lo; + uint32_t hx; + int k; + + hx = u.i>>32; + k = 0; + if (hx < 0x00100000 || hx>>31) { + if (u.i<<1 == 0) + return -1/(x*x); /* log(+-0)=-inf */ + if (hx>>31) + return (x-x)/0.0; /* log(-#) = NaN */ + /* subnormal number, scale x up */ + k -= 54; + x *= 0x1p54; + u.f = x; + hx = u.i>>32; + } else if (hx >= 0x7ff00000) { + return x; + } else if (hx == 0x3ff00000 && u.i<<32 == 0) + return 0; + + /* reduce x into [sqrt(2)/2, sqrt(2)] */ + hx += 0x3ff00000 - 0x3fe6a09e; + k += (int)(hx>>20) - 0x3ff; + hx = (hx&0x000fffff) + 0x3fe6a09e; + u.i = (uint64_t)hx<<32 | (u.i&0xffffffff); + x = u.f; + + f = x - 1.0; + hfsq = 0.5*f*f; + s = f/(2.0+f); + z = s*s; + w = z*z; + t1 = w*(Lg2+w*(Lg4+w*Lg6)); + t2 = z*(Lg1+w*(Lg3+w*(Lg5+w*Lg7))); + R = t2 + t1; + + /* + * f-hfsq must (for args near 1) be evaluated in extra precision + * to avoid a large cancellation when x is near sqrt(2) or 1/sqrt(2). + * This is fairly efficient since f-hfsq only depends on f, so can + * be evaluated in parallel with R. Not combining hfsq with R also + * keeps R small (though not as small as a true `lo' term would be), + * so that extra precision is not needed for terms involving R. + * + * Compiler bugs involving extra precision used to break Dekker's + * theorem for spitting f-hfsq as hi+lo, unless double_t was used + * or the multi-precision calculations were avoided when double_t + * has extra precision. These problems are now automatically + * avoided as a side effect of the optimization of combining the + * Dekker splitting step with the clear-low-bits step. + * + * y must (for args near sqrt(2) and 1/sqrt(2)) be added in extra + * precision to avoid a very large cancellation when x is very near + * these values. Unlike the above cancellations, this problem is + * specific to base 2. It is strange that adding +-1 is so much + * harder than adding +-ln2 or +-log10_2. + * + * This uses Dekker's theorem to normalize y+val_hi, so the + * compiler bugs are back in some configurations, sigh. And I + * don't want to used double_t to avoid them, since that gives a + * pessimization and the support for avoiding the pessimization + * is not yet available. + * + * The multi-precision calculations for the multiplications are + * routine. + */ + + /* hi+lo = f - hfsq + s*(hfsq+R) ~ log(1+f) */ + hi = f - hfsq; + u.f = hi; + u.i &= (uint64_t)-1<<32; + hi = u.f; + lo = f - hi - hfsq + s*(hfsq+R); + + val_hi = hi*ivln2hi; + val_lo = (lo+hi)*ivln2lo + lo*ivln2hi; + + /* spadd(val_hi, val_lo, y), except for not using double_t: */ + y = k; + w = y + val_hi; + val_lo += (y - w) + val_hi; + val_hi = w; + + return val_lo + val_hi; +} +float log2f(float x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +long double log2l(long double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +double logb(double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +float logbf(float x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +long double logbl(long double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +double modf(double x, double *integral) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +float modff(float x, float *integral) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +long double modfl(long double x, long double *integral) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +double scalbn(double x, int n) { + union {double f; uint64_t i;} u; + double 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; +} +float scalbnf(float x, int power) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +long double scalbnl(long double x, int power) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +double scalbln(double x, long power) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +float scalblnf(float x, long power) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +long double scalblnl(long double x, long power) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +double cbrt(double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +float cbrtf(float x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +long double cbrtl(long double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +double fabs(double x) { + return signbit(x) ? -x : x; +} +float fabsf(float x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +long double fabsl(long double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +double hypot(double x, double y) { + __ensure(isfinite(x)); + __ensure(isfinite(y)); + // TODO: fix exception handling + double u = fabs(x); + double v = fabs(y); + if(u > v) + return u * sqrt(1 + (v / u) * (v / u)); + return v * sqrt(1 + (u / v) * (u / v)); +} +float hypotf(float x, float y) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +long double hypotl(long double x, long double y) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +double pow(double x, double y) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +float powf(float x, float y) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +long double powl(long double x, long double y) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +double sqrt(double x) { + auto sse_x = _mm_set_sd(x); + return _mm_cvtsd_f64(_mm_sqrt_sd(sse_x, sse_x)); +} +float sqrtf(float x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +long double sqrtl(long double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +double erf(double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +float erff(float x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +long double erfl(long double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +double erfc(double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +float erfcf(float x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +long double erfcl(long double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +double lgamma(double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +float lgammaf(float x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +long double lgammal(long double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +double tgamma(double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +float tgammaf(float x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +long double tgammal(long double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +double ceil(double x) { + auto soft_x = ieee754::extractNative(x); + auto result = ieee754::ceil(soft_x); + return ieee754::compileNative(result); +} +float ceilf(float x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +long double ceill(long double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +double floor(double x) { + auto soft_x = ieee754::extractNative(x); + auto result = ieee754::floor(soft_x); + return ieee754::compileNative(result); +} +float floorf(float x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +long double floorl(long double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +double nearbyint(double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +float nearbyintf(float x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +long double nearbyintl(long double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +double rint(double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +float rintf(float x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +long double rintl(long double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +long lrint(double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +long lrintf(float x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +long lrintl(long double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +long long llrint(double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +long long llrintf(float x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +long long llrintl(long double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +double round(double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +float roundf(float x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +long double roundl(long double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +long lround(double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +long lroundf(float x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +long lroundl(long double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +long long llround(double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +long long llroundf(float x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +long long llroundl(long double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +double trunc(double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +float truncf(float x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +long double truncl(long double x) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +double fmod(double x, double y) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +float fmodf(float x, float y) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +long double fmodl(long double x, long double y) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +double remainder(double x, double y) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +float remainderf(float x, float y) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +long double remainderl(long double x, long double y) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +double remquo(double x, double y, int *quotient) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +float remquof(float x, float y, int *quotient) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +long double remquol(long double x, long double y, int *quotient) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +double copysign(double x, double sign) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +float copysignf(float x, float sign) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +long double copysignl(long double x, long double sign) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +double nan(const char *tag) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +float nanf(const char *tag) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +long double nanl(const char *tag) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +double nextafter(double x, double dir) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +float nextafterf(float x, float dir) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +long double nextafterl(long double x, long double dir) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +double nexttoward(double x, long double dir) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +float nexttowardf(float x, long double dir) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +long double nexttowardl(long double x, long double dir) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +double fdim(double x, double y) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +float fdimf(float x, float y) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +long double fdiml(long double x, long double y) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +double fmax(double x, double y) { + __ensure(isfinite(x) && isfinite(y)); + return x < y ? y : x; +} +float fmaxf(float x, float y) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +long double fmaxl(long double x, long double y) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +double fmin(double x, double y) { + __ensure(isfinite(x) && isfinite(y)); + return x < y ? x : y; +} +float fminf(float x, float y) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +long double fminl(long double x, long double y) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +//gnu extension + +void sincos(double x, double *sx, double *cx) { + mlibc::infoLogger() << "mlibc: sincos() is not precise" << frg::endlog; + float sxf; + float cxf; + sincosf(x, &sxf, &cxf); + *sx = sxf; + *cx = cxf; +} + +void sincosf(float x, float *sx, float *cx) { + // This is a lazy implementation. + __ensure(sx); + __ensure(cx); + *sx = sinf(x); + *cx = cosf(x); +} +void sincosl(long double, long double *, long double *) { + __ensure(!"sincosl() not implemented"); + __builtin_unreachable(); +} + +double exp10(double) { + __ensure(!"exp10() not implemented"); + __builtin_unreachable(); +} +float exp10f(float) { + __ensure(!"exp10f() not implemented"); + __builtin_unreachable(); +} +long double exp10l(long double) { + __ensure(!"exp10l() not implemented"); + __builtin_unreachable(); +} + +double pow10(double) { + __ensure(!"pow10() not implemented"); + __builtin_unreachable(); +} +float pow10f(float) { + __ensure(!"pow10f() not implemented"); + __builtin_unreachable(); +} +long double pow10l(long double) { + __ensure(!"pow10l() not implemented"); + __builtin_unreachable(); +} + diff --git a/lib/mlibc/options/ansi/generic/signal-stubs.cpp b/lib/mlibc/options/ansi/generic/signal-stubs.cpp new file mode 100644 index 0000000..6da9dc1 --- /dev/null +++ b/lib/mlibc/options/ansi/generic/signal-stubs.cpp @@ -0,0 +1,44 @@ + +#include +#include +#include + +#include +#include + +__sighandler signal(int sn, __sighandler handler) { + struct sigaction sa; + sa.sa_handler = handler; + sa.sa_flags = 0; + sa.sa_mask = 0; + struct sigaction old; + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_sigaction, SIG_ERR); + if(int e = mlibc::sys_sigaction(sn, &sa, &old)){ + errno = e; + return SIG_ERR; + } + return old.sa_handler; +} + +int raise(int sig) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_getpid && mlibc::sys_kill, -1); + pid_t pid = mlibc::sys_getpid(); + + if (int e = mlibc::sys_kill(pid, sig)) { + errno = e; + return -1; + } + + return 0; +} + +// This is a POSIX extension, but we have it in here for sigsetjmp +int sigprocmask(int how, const sigset_t *__restrict set, sigset_t *__restrict retrieve) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_sigprocmask, -1); + if(int e = mlibc::sys_sigprocmask(how, set, retrieve); e) { + errno = e; + return -1; + } + return 0; +} + diff --git a/lib/mlibc/options/ansi/generic/stdio-stubs.cpp b/lib/mlibc/options/ansi/generic/stdio-stubs.cpp new file mode 100644 index 0000000..479a655 --- /dev/null +++ b/lib/mlibc/options/ansi/generic/stdio-stubs.cpp @@ -0,0 +1,1270 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +template +struct PrintfAgent { + PrintfAgent(F *formatter, frg::va_struct *vsp) + : _formatter{formatter}, _vsp{vsp} { } + + frg::expected operator() (char c) { + _formatter->append(c); + return {}; + } + frg::expected operator() (const char *c, size_t n) { + _formatter->append(c, n); + return {}; + } + + frg::expected operator() (char t, frg::format_options opts, + frg::printf_size_mod szmod) { + switch(t) { + case 'c': + if (szmod == frg::printf_size_mod::long_size) { + char c_buf[sizeof(wchar_t)]; + auto c = static_cast(va_arg(_vsp->args, wint_t)); + mbstate_t shift_state = {}; + if (wcrtomb(c_buf, c, &shift_state) == size_t(-1)) + return frg::format_error::agent_error; + _formatter->append(c_buf); + break; + } + frg::do_printf_chars(*_formatter, t, opts, szmod, _vsp); + break; + case 'p': case 's': + frg::do_printf_chars(*_formatter, t, opts, szmod, _vsp); + break; + case 'd': case 'i': case 'o': case 'x': case 'X': case 'u': + frg::do_printf_ints(*_formatter, t, opts, szmod, _vsp); + break; + case 'f': case 'F': case 'g': case 'G': case 'e': case 'E': + frg::do_printf_floats(*_formatter, t, opts, szmod, _vsp); + break; + case 'm': + __ensure(!opts.fill_zeros); + __ensure(!opts.left_justify); + __ensure(!opts.alt_conversion); + __ensure(opts.minimum_width == 0); + __ensure(szmod == frg::printf_size_mod::default_size); + __ensure(!opts.precision); + _formatter->append(strerror(errno)); + break; + case 'n': { + __ensure(szmod == frg::printf_size_mod::default_size); + auto p = va_arg(_vsp->args, int *); + *p = _formatter->count; + break; + } + default: + mlibc::infoLogger() << "\e[31mmlibc: Unknown printf terminator '" + << t << "'\e[39m" << frg::endlog; + __ensure(!"Illegal printf terminator"); + } + + return {}; + } + +private: + F *_formatter; + frg::va_struct *_vsp; +}; + +struct StreamPrinter { + StreamPrinter(FILE *stream) + : stream(stream), count(0) { } + + void append(char c) { + fwrite_unlocked(&c, 1, 1, stream); + count++; + } + + void append(const char *str) { + fwrite_unlocked(str, strlen(str), 1, stream); + count += strlen(str); + } + + void append(const char *str, size_t n) { + fwrite_unlocked(str, n, 1, stream); + count += n; + } + + FILE *stream; + size_t count; +}; + +struct BufferPrinter { + BufferPrinter(char *buffer) + : buffer(buffer), count(0) { } + + void append(char c) { + buffer[count] = c; + count++; + } + + void append(const char *str) { + // TODO: use strcat + for(size_t i = 0; str[i]; i++) { + buffer[count] = str[i]; + count++; + } + } + + void append(const char *str, size_t n) { + // TODO: use strcat + for(size_t i = 0; i < n; i++) { + buffer[count] = str[i]; + count++; + } + } + + char *buffer; + size_t count; +}; + +struct LimitedPrinter { + LimitedPrinter(char *buffer, size_t limit) + : buffer(buffer), limit(limit), count(0) { } + + void append(char c) { + if(count < limit) + buffer[count] = c; + count++; + } + + void append(const char *str) { + // TODO: use strcat + for(size_t i = 0; str[i]; i++) + append(str[i]); + } + + void append(const char *str, size_t n) { + // TODO: use strcat + for(size_t i = 0; i < n; i++) + append(str[i]); + } + + char *buffer; + size_t limit; + size_t count; +}; + +struct ResizePrinter { + ResizePrinter() + : buffer(nullptr), limit(0), count(0) { } + + void expand() { + if(count == limit) { + auto new_limit = frg::max(2 * limit, size_t(16)); + auto new_buffer = reinterpret_cast(malloc(new_limit)); + __ensure(new_buffer); + memcpy(new_buffer, buffer, count); + free(buffer); + buffer = new_buffer; + limit = new_limit; + } + __ensure(count < limit); + } + + void append(char c) { + expand(); + buffer[count] = c; + count++; + } + + void append(const char *str) { + for(size_t i = 0; str[i]; i++) + append(str[i]); + } + + void append(const char *str, size_t n) { + for(size_t i = 0; i < n; i++) + append(str[i]); + } + + char *buffer; + size_t limit; + size_t count; +}; + +int remove(const char *filename) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_rmdir, -1); + if(int e = mlibc::sys_rmdir(filename); e) { + if (e == ENOTDIR) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_unlinkat, -1); + if(e = mlibc::sys_unlinkat(AT_FDCWD, filename, 0); e) { + errno = e; + return -1; + } + + return 0; + } + return -1; + } + + return 0; +} + +int rename(const char *path, const char *new_path) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_rename, -1); + if(int e = mlibc::sys_rename(path, new_path); e) { + errno = e; + return -1; + } + return 0; +} + +int renameat(int olddirfd, const char *old_path, int newdirfd, const char *new_path) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_renameat, -1); + if(int e = mlibc::sys_renameat(olddirfd, old_path, newdirfd, new_path); e) { + errno = e; + return -1; + } + return 0; +} + +FILE *tmpfile(void) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +char *tmpnam(char *) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +// fflush() is provided by the POSIX sublibrary +// fopen() is provided by the POSIX sublibrary +FILE *freopen(const char *__restrict path, const char *__restrict mode, FILE *__restrict f) { + auto file = static_cast(f); + frg::unique_lock lock(file->_lock); + + if(file->reopen(path, mode) == -1) { + errno = EINVAL; + return nullptr; + } + + return f; +} + +void setbuf(FILE *__restrict stream, char *__restrict buffer) { + setvbuf(stream, buffer, buffer ? _IOFBF : _IONBF, BUFSIZ); +} +// setvbuf() is provided by the POSIX sublibrary + +void setlinebuf(FILE *stream) { + setvbuf(stream, NULL, _IOLBF, 0); +} + +void setbuffer(FILE *f, char *buf, size_t size) { + setvbuf(f, buf, buf ? _IOFBF : _IONBF, size); +} + +int fprintf(FILE *__restrict stream, const char *__restrict format, ...) { + va_list args; + va_start(args, format); + int result = vfprintf(stream, format, args); + va_end(args); + return result; +} + +int fscanf(FILE *__restrict stream, const char *__restrict format, ...) { + va_list args; + va_start(args, format); + int result = vfscanf(stream, format, args); + va_end(args); + return result; +} + +int printf(const char *__restrict format, ...) { + va_list args; + va_start(args, format); + int result = vfprintf(stdout, format, args); + va_end(args); + return result; +} + +namespace { + enum { + SCANF_TYPE_CHAR, + SCANF_TYPE_SHORT, + SCANF_TYPE_INTMAX, + SCANF_TYPE_L, + SCANF_TYPE_LL, + SCANF_TYPE_PTRDIFF, + SCANF_TYPE_SIZE_T, + SCANF_TYPE_INT + }; +} + +static void store_int(void *dest, unsigned int size, unsigned long long i) { + switch (size) { + case SCANF_TYPE_CHAR: + *(char *)dest = i; + break; + case SCANF_TYPE_SHORT: + *(short *)dest = i; + break; + case SCANF_TYPE_INTMAX: + *(intmax_t *)dest = i; + break; + case SCANF_TYPE_L: + *(long *)dest = i; + break; + case SCANF_TYPE_LL: + *(long long *)dest = i; + break; + case SCANF_TYPE_PTRDIFF: + *(ptrdiff_t *)dest = i; + break; + case SCANF_TYPE_SIZE_T: + *(size_t *)dest = i; + break; + /* fallthrough */ + case SCANF_TYPE_INT: + default: + *(int *)dest = i; + break; + } +} + +template +static int do_scanf(H &handler, const char *fmt, __builtin_va_list args) { + int match_count = 0; + for (; *fmt; fmt++) { + + if (isspace(*fmt)) { + while (isspace(fmt[1])) fmt++; + while (isspace(handler.look_ahead())) + handler.consume(); + continue; + } + + if (*fmt != '%' || fmt[1] == '%') { + if (*fmt == '%') + fmt++; + char c = handler.consume(); + if (c != *fmt) + break; + continue; + } + + void *dest = NULL; + /* %n$ format */ + if (isdigit(*fmt) && fmt[1] == '$') { + /* TODO: dest = get_arg_at_pos(args, *fmt -'0'); */ + fmt += 3; + } else { + if (fmt[1] != '*') { + dest = va_arg(args, void*); + } + fmt++; + } + + int width = 0; + if (*fmt == '*') { + fmt++; + } else if (*fmt == '\'') { + /* TODO: numeric seperators locale stuff */ + mlibc::infoLogger() << "do_scanf: \' not implemented!" << frg::endlog; + fmt++; + continue; + } else if (*fmt == 'm') { + /* TODO: allocate buffer for them */ + mlibc::infoLogger() << "do_scanf: m not implemented!" << frg::endlog; + fmt++; + continue; + } else if (*fmt >= '0' && *fmt <= '9') { + /* read in width specifier */ + width = 0; + while (*fmt >= '0' && *fmt <= '9') { + width = width * 10 + (*fmt - '0'); + fmt++; + continue; + } + } + + /* type modifiers */ + unsigned int type = SCANF_TYPE_INT; + unsigned int base = 10; + switch (*fmt) { + case 'h': { + if (fmt[1] == 'h') { + type = SCANF_TYPE_CHAR; + fmt += 2; + break; + } + type = SCANF_TYPE_SHORT; + fmt++; + break; + } + case 'j': { + type = SCANF_TYPE_INTMAX; + fmt++; + break; + } + case 'l': { + if (fmt[1] == 'l') { + type = SCANF_TYPE_LL; + fmt += 2; + break; + } + type = SCANF_TYPE_L; + fmt++; + break; + } + case 'L': { + type = SCANF_TYPE_LL; + fmt++; + break; + } + case 'q': { + type = SCANF_TYPE_LL; + fmt++; + break; + } + case 't': { + type = SCANF_TYPE_PTRDIFF; + fmt++; + break; + } + case 'z': { + type = SCANF_TYPE_SIZE_T; + fmt++; + break; + } + } + + // Leading whitespace is skipped for most conversions except these. + if (*fmt != 'c' && *fmt != '[' && *fmt != 'n') { + while (isspace(handler.look_ahead())) + handler.consume(); + } + + switch (*fmt) { + case 'd': + case 'u': + base = 10; + [[fallthrough]]; + case 'i': { + bool is_negative = false; + unsigned long long res = 0; + + if((*fmt == 'i' || *fmt == 'd') && handler.look_ahead() == '-') { + handler.consume(); + is_negative = true; + } + + if(*fmt == 'i' && handler.look_ahead() == '0') { + handler.consume(); + if(handler.look_ahead() == 'x') { + handler.consume(); + base = 16; + } else { + base = 8; + } + } + + char c = handler.look_ahead(); + switch (base) { + case 10: + if(!isdigit(c)) + return match_count; + while (c >= '0' && c <= '9') { + handler.consume(); + res = res * 10 + (c - '0'); + c = handler.look_ahead(); + } + break; + case 16: + if (c == '0') { + handler.consume(); + c = handler.look_ahead(); + if (c == 'x') { + handler.consume(); + c = handler.look_ahead(); + } + } + while (true) { + if (c >= '0' && c <= '9') { + handler.consume(); + res = res * 16 + (c - '0'); + } else if (c >= 'a' && c <= 'f') { + handler.consume(); + res = res * 16 + (c - 'a' + 10); + } else if (c >= 'A' && c <= 'F') { + handler.consume(); + res = res * 16 + (c - 'A' + 10); + } else { + break; + } + c = handler.look_ahead(); + } + break; + case 8: + while (c >= '0' && c <= '7') { + handler.consume(); + res = res * 8 + (c - '0'); + c = handler.look_ahead(); + } + break; + } + if (dest) { + if(is_negative) + store_int(dest, type, -res); + else + store_int(dest, type, res); + } + break; + } + case 'o': { + unsigned long long res = 0; + char c = handler.look_ahead(); + while (c >= '0' && c <= '7') { + handler.consume(); + res = res * 8 + (c - '0'); + c = handler.look_ahead(); + } + if (dest) + store_int(dest, type, res); + break; + } + case 'x': + case 'X': { + unsigned long long res = 0; + char c = handler.look_ahead(); + if (c == '0') { + handler.consume(); + c = handler.look_ahead(); + if (c == 'x') { + handler.consume(); + c = handler.look_ahead(); + } + } + while (true) { + if (c >= '0' && c <= '9') { + handler.consume(); + res = res * 16 + (c - '0'); + } else if (c >= 'a' && c <= 'f') { + handler.consume(); + res = res * 16 + (c - 'a' + 10); + } else if (c >= 'A' && c <= 'F') { + handler.consume(); + res = res * 16 + (c - 'A' + 10); + } else { + break; + } + c = handler.look_ahead(); + } + if (dest) + store_int(dest, type, res); + break; + } + case 's': { + char *typed_dest = (char *)dest; + char c = handler.look_ahead(); + int count = 0; + while (c && !isspace(c)) { + handler.consume(); + if (typed_dest) + typed_dest[count] = c; + c = handler.look_ahead(); + count++; + if (width && count >= width) + break; + } + if (typed_dest) + typed_dest[count] = '\0'; + break; + } + case 'c': { + char *typed_dest = (char *)dest; + char c = handler.look_ahead(); + int count = 0; + if (!width) + width = 1; + while (c && count < width) { + handler.consume(); + if (typed_dest) + typed_dest[count] = c; + c = handler.look_ahead(); + count++; + } + break; + } + case '[': { + fmt++; + int invert = 0; + if (*fmt == '^') { + invert = 1; + fmt++; + } + + char scanset[257]; + memset(&scanset[0], invert, sizeof(char) * 257); + scanset[0] = '\0'; + + if (*fmt == '-') { + fmt++; + scanset[1+'-'] = 1 - invert; + } else if (*fmt == ']') { + fmt++; + scanset[1+']'] = 1 - invert; + } + + for (; *fmt != ']'; fmt++) { + if (!*fmt) return EOF; + if (*fmt == '-' && *fmt != ']') { + fmt++; + for (char c = *(fmt - 2); c < *fmt; c++) + scanset[1 + c] = 1 - invert; + } + scanset[1 + *fmt] = 1 - invert; + } + + char *typed_dest = (char *)dest; + int count = 0; + char c = handler.look_ahead(); + while (c && (!width || count < width)) { + handler.consume(); + if (!scanset[1 + c]) + break; + if (typed_dest) + typed_dest[count] = c; + c = handler.look_ahead(); + count++; + } + if (typed_dest) + typed_dest[count] = '\0'; + break; + } + case 'p': { + unsigned long long res = 0; + char c = handler.look_ahead(); + if (c == '0') { + handler.consume(); + c = handler.look_ahead(); + if (c == 'x') { + handler.consume(); + c = handler.look_ahead(); + } + } + while (true) { + if (c >= '0' && c <= '9') { + handler.consume(); + res = res * 16 + (c - '0'); + } else if (c >= 'a' && c <= 'f') { + handler.consume(); + res = res * 16 + (c - 'a'); + } else if (c >= 'A' && c <= 'F') { + handler.consume(); + res = res * 16 + (c - 'A'); + } else { + break; + } + c = handler.look_ahead(); + } + void **typed_dest = (void **)dest; + *typed_dest = (void *)(uintptr_t)res; + break; + } + case 'n': { + int *typed_dest = (int *)dest; + if (typed_dest) + *typed_dest = handler.num_consumed; + continue; + } + } + if (dest) match_count++; + } + return match_count; +} + +int scanf(const char *__restrict format, ...) { + va_list args; + va_start(args, format); + int result = vfscanf(stdin, format, args); + va_end(args); + return result; +} + +int snprintf(char *__restrict buffer, size_t max_size, const char *__restrict format, ...) { + va_list args; + va_start(args, format); + int result = vsnprintf(buffer, max_size, format, args); + va_end(args); + return result; +} + +int sprintf(char *__restrict buffer, const char *__restrict format, ...) { + va_list args; + va_start(args, format); + int result = vsprintf(buffer, format, args); + va_end(args); + return result; +} + +int sscanf(const char *__restrict buffer, const char *__restrict format, ...) { + va_list args; + va_start(args, format); + + int result = vsscanf(buffer, format, args); + + va_end(args); + return result; +} + +int vfprintf(FILE *__restrict stream, const char *__restrict format, __builtin_va_list args) { + frg::va_struct vs; + frg::arg arg_list[NL_ARGMAX + 1]; + vs.arg_list = arg_list; + va_copy(vs.args, args); + auto file = static_cast(stream); + frg::unique_lock lock(file->_lock); + StreamPrinter p{stream}; +// mlibc::infoLogger() << "printf(" << format << ")" << frg::endlog; + auto res = frg::printf_format(PrintfAgent{&p, &vs}, format, &vs); + if (!res) + return -static_cast(res.error()); + + return p.count; +} + +int vfscanf(FILE *__restrict stream, const char *__restrict format, __builtin_va_list args) { + auto file = static_cast(stream); + frg::unique_lock lock(file->_lock); + + struct { + char look_ahead() { + char c; + size_t actual_size; + file->read(&c, 1, &actual_size); + if (actual_size) + file->unget(c); + return actual_size ? c : 0; + } + + char consume() { + char c; + size_t actual_size; + file->read(&c, 1, &actual_size); + if (actual_size) + num_consumed++; + return actual_size ? c : 0; + } + + mlibc::abstract_file *file; + int num_consumed; + } handler = {file, 0}; + + return do_scanf(handler, format, args); +} + +int vprintf(const char *__restrict format, __builtin_va_list args){ + return vfprintf(stdout, format, args); +} + +int vscanf(const char *__restrict, __builtin_va_list) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +int vsnprintf(char *__restrict buffer, size_t max_size, + const char *__restrict format, __builtin_va_list args) { + frg::va_struct vs; + frg::arg arg_list[NL_ARGMAX + 1]; + vs.arg_list = arg_list; + va_copy(vs.args, args); + LimitedPrinter p{buffer, max_size ? max_size - 1 : 0}; +// mlibc::infoLogger() << "printf(" << format << ")" << frg::endlog; + auto res = frg::printf_format(PrintfAgent{&p, &vs}, format, &vs); + if (!res) + return -static_cast(res.error()); + if (max_size) + p.buffer[frg::min(max_size - 1, p.count)] = 0; + return p.count; +} + +int vsprintf(char *__restrict buffer, const char *__restrict format, __builtin_va_list args) { + frg::va_struct vs; + frg::arg arg_list[NL_ARGMAX + 1]; + vs.arg_list = arg_list; + va_copy(vs.args, args); + BufferPrinter p(buffer); +// mlibc::infoLogger() << "printf(" << format << ")" << frg::endlog; + auto res = frg::printf_format(PrintfAgent{&p, &vs}, format, &vs); + if (!res) + return -static_cast(res.error()); + p.buffer[p.count] = 0; + return p.count; +} + +int vsscanf(const char *__restrict buffer, const char *__restrict format, __builtin_va_list args) { + struct { + char look_ahead() { + return *buffer; + } + + char consume() { + num_consumed++; + return *buffer++; + } + + const char *buffer; + int num_consumed; + } handler = {buffer, 0}; + + int result = do_scanf(handler, format, args); + + return result; +} + +int fwprintf(FILE *__restrict, const wchar_t *__restrict, ...) MLIBC_STUB_BODY +int fwscanf(FILE *__restrict, const wchar_t *__restrict, ...) MLIBC_STUB_BODY +int vfwprintf(FILE *__restrict, const wchar_t *__restrict, __builtin_va_list) MLIBC_STUB_BODY +int vfwscanf(FILE *__restrict, const wchar_t *__restrict, __builtin_va_list) MLIBC_STUB_BODY + +int swprintf(wchar_t *__restrict, size_t, const wchar_t *__restrict, ...) MLIBC_STUB_BODY +int swscanf(wchar_t *__restrict, size_t, const wchar_t *__restrict, ...) MLIBC_STUB_BODY +int vswprintf(wchar_t *__restrict, size_t, const wchar_t *__restrict, __builtin_va_list) MLIBC_STUB_BODY +int vswscanf(wchar_t *__restrict, size_t, const wchar_t *__restrict, __builtin_va_list) MLIBC_STUB_BODY + +int wprintf(const wchar_t *__restrict, ...) MLIBC_STUB_BODY +int wscanf(const wchar_t *__restrict, ...) MLIBC_STUB_BODY +int vwprintf(const wchar_t *__restrict, __builtin_va_list) MLIBC_STUB_BODY +int vwscanf(const wchar_t *__restrict, __builtin_va_list) MLIBC_STUB_BODY + +int fgetc(FILE *stream) { + char c; + auto bytes_read = fread(&c, 1, 1, stream); + if(bytes_read != 1) + return EOF; + return c; +} + +char *fgets(char *__restrict buffer, size_t max_size, FILE *__restrict stream) { + auto file = static_cast(stream); + frg::unique_lock lock(file->_lock); + return fgets_unlocked(buffer, max_size, stream); +} + +int fputc_unlocked(int c, FILE *stream) { + char d = c; + if(fwrite_unlocked(&d, 1, 1, stream) != 1) + return EOF; + return 1; +} + +int fputc(int c, FILE *stream) { + auto file = static_cast(stream); + frg::unique_lock lock(file->_lock); + return fputc_unlocked(c, stream); +} + +int fputs_unlocked(const char *__restrict string, FILE *__restrict stream) { + if(fwrite_unlocked(string, strlen(string), 1, stream) != 1) + return EOF; + return 1; +} + +int fputs(const char *__restrict string, FILE *__restrict stream) { + auto file = static_cast(stream); + frg::unique_lock lock(file->_lock); + return fputs_unlocked(string, stream); +} + +int getc_unlocked(FILE *stream) { + return fgetc_unlocked(stream); +} + +int getc(FILE *stream) { + return fgetc(stream); +} + +int getchar_unlocked(void) { + return fgetc_unlocked(stdin); +} + +int getchar(void) { + return fgetc(stdin); +} + +char *gets(char *s){ + return fgets(s, SIZE_MAX, stdin); +} + +int putc_unlocked(int c, FILE *stream) { + char d = c; + if(fwrite_unlocked(&d, 1, 1, stream) != 1) + return EOF; + return c; +} + +int putc(int c, FILE *stream) { + auto file = static_cast(stream); + frg::unique_lock lock(file->_lock); + return putc_unlocked(c, stream); +} + +int putchar_unlocked(int c) { + return putc_unlocked(c, stdout); +} + +int putchar(int c) { + auto file = static_cast(stdout); + frg::unique_lock lock(file->_lock); + return putchar_unlocked(c); +} + +int puts(const char *string) { + auto file = static_cast(stdout); + frg::unique_lock lock(file->_lock); + + size_t progress = 0; + size_t len = strlen(string); + while(progress < len) { + size_t chunk; + if(file->write(string + progress, + len - progress, &chunk)) { + return EOF; + }else if(!chunk) { + return EOF; + } + + progress += chunk; + } + + size_t unused; + if (!file->write("\n", 1, &unused)) { + return EOF; + } + + return 1; +} + +wint_t fgetwc(FILE *) MLIBC_STUB_BODY +wchar_t *fgetws(wchar_t *__restrict, int, FILE *__restrict) MLIBC_STUB_BODY +wint_t fputwc(wchar_t, FILE *) MLIBC_STUB_BODY +int fputws(const wchar_t *__restrict, FILE *__restrict) MLIBC_STUB_BODY +int fwide(FILE *, int) MLIBC_STUB_BODY +wint_t getwc(FILE *) MLIBC_STUB_BODY +wint_t getwchar(void) MLIBC_STUB_BODY +wint_t putwc(wchar_t, FILE *) MLIBC_STUB_BODY +wint_t putwchar(wchar_t) MLIBC_STUB_BODY +wint_t ungetwc(wint_t, FILE *) MLIBC_STUB_BODY + +size_t fread(void *buffer, size_t size, size_t count, FILE *file_base) { + auto file = static_cast(file_base); + frg::unique_lock lock(file->_lock); + return fread_unlocked(buffer, size, count, file_base); +} + +size_t fwrite(const void *buffer, size_t size , size_t count, FILE *file_base) { + auto file = static_cast(file_base); + frg::unique_lock lock(file->_lock); + return fwrite_unlocked(buffer, size, count, file_base); +} + +int fgetpos(FILE *__restrict, fpos_t *__restrict) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +// fseek() is provided by the POSIX sublibrary +int fsetpos(FILE *, const fpos_t *) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +// ftell() is provided by the POSIX sublibrary + +void clearerr(FILE *file_base) { + file_base->__status_bits = 0; +} + +int feof(FILE *file_base) { + return file_base->__status_bits & __MLIBC_EOF_BIT; +} + +int ferror(FILE *file_base) { + return file_base->__status_bits & __MLIBC_ERROR_BIT; +} + +void perror(const char *string) { + int error = errno; + if (string && *string) { + fprintf(stderr, "%s: ", string); + } + fprintf(stderr, "%s\n", strerror(error)); +} + +// POSIX extensions. + +ssize_t getline(char **line, size_t *n, FILE *stream) { + return getdelim(line, n, '\n', stream); +} + +ssize_t getdelim(char **line, size_t *n, int delim, FILE *stream) { + // Otherwise, we cannot store the buffer / size. + if(!line || !n) { + errno = EINVAL; + return -1; + } + + char *buffer = *line; + /* set the starting capacity to 512 if buffer = NULL */ + size_t capacity = (!buffer) ? 512 : *n; + size_t nwritten = 0; + + auto file = static_cast(stream); + frg::unique_lock lock(file->_lock); + + // Avoid allocating if we've already hit the end + auto c = fgetc_unlocked(stream); + if (c == EOF || ferror(stream)) { + return -1; + } else { + file->unget(c); + } + + while (true) { + // Fill the buffer + while (buffer && capacity > 0 && nwritten < capacity - 1) { + auto c = fgetc_unlocked(stream); + if (ferror(stream)) { + return -1; + } else if (c == EOF) { + buffer[nwritten] = 0; + return nwritten; + } + + buffer[nwritten++] = c; + + if (c == delim) { + buffer[nwritten] = 0; + return nwritten; + } + } + + // Double the size of the buffer (but make sure it's at least 1024) + capacity = (capacity >= 1024) ? capacity * 2 : 1024; + buffer = reinterpret_cast(getAllocator().reallocate(*line, capacity)); + if (!buffer) { + errno = ENOMEM; + return -1; + } + + *line = buffer; + *n = capacity; + } +} + +// GLIBC extensions. + +int asprintf(char **out, const char *format, ...) { + va_list args; + va_start(args, format); + int result = vasprintf(out, format, args); + va_end(args); + return result; +} + +int vasprintf(char **out, const char *format, __builtin_va_list args) { + frg::va_struct vs; + frg::arg arg_list[NL_ARGMAX + 1]; + vs.arg_list = arg_list; + va_copy(vs.args, args); + ResizePrinter p; +// mlibc::infoLogger() << "printf(" << format << ")" << frg::endlog; + auto res = frg::printf_format(PrintfAgent{&p, &vs}, format, &vs); + if (!res) + return -static_cast(res.error()); + p.expand(); + p.buffer[p.count] = 0; + *out = p.buffer; + return p.count; +} + +// Linux unlocked I/O extensions. + +void flockfile(FILE *file_base) { + static_cast(file_base)->_lock.lock(); +} + +void funlockfile(FILE *file_base) { + static_cast(file_base)->_lock.unlock(); +} + +int ftrylockfile(FILE *file_base) { + static_cast(file_base)->_lock.try_lock(); + return 0; +} + +void clearerr_unlocked(FILE *file_base) { + file_base->__status_bits = 0; +} + +int feof_unlocked(FILE *file_base) { + return file_base->__status_bits & __MLIBC_EOF_BIT; +} + +int ferror_unlocked(FILE *file_base) { + return file_base->__status_bits & __MLIBC_ERROR_BIT; +} + +int fgetc_unlocked(FILE *stream) { + unsigned char d; + if(fread_unlocked(&d, 1, 1, stream) != 1) + return EOF; + return (int)d; +} + +size_t fread_unlocked(void *buffer, size_t size, size_t count, FILE *file_base) { + auto file = static_cast(file_base); + if(!size || !count) + return 0; + + // Distinguish two cases here: If the object size is one, we perform byte-wise reads. + // Otherwise, we try to read each object individually. + if(size == 1) { + size_t progress = 0; + while(progress < count) { + size_t chunk; + if(int e = file->read((char *)buffer + progress, + count - progress, &chunk)) { + errno = e; + return 0; + }else if(!chunk) { + // TODO: Handle eof. + break; + } + + progress += chunk; + } + + return progress; + }else{ + for(size_t i = 0; i < count; i++) { + size_t progress = 0; + while(progress < size) { + size_t chunk; + if(int e = file->read((char *)buffer + i * size + progress, + size - progress, &chunk)) { + errno = e; + return 0; + }else if(!chunk) { + // TODO: Handle eof. + break; + } + + progress += chunk; + } + + if(progress < size) + return i; + } + + return count; + } +} + +size_t fwrite_unlocked(const void *buffer, size_t size, size_t count, FILE *file_base) { + auto file = static_cast(file_base); + if(!size || !count) + return 0; + + // Distinguish two cases here: If the object size is one, we perform byte-wise writes. + // Otherwise, we try to write each object individually. + if(size == 1) { + size_t progress = 0; + while(progress < count) { + size_t chunk; + if(file->write((const char *)buffer + progress, + count - progress, &chunk)) { + // TODO: Handle I/O errors. + mlibc::infoLogger() << "mlibc: fwrite() I/O errors are not handled" + << frg::endlog; + break; + }else if(!chunk) { + // TODO: Handle eof. + break; + } + + progress += chunk; + } + + return progress; + }else{ + for(size_t i = 0; i < count; i++) { + size_t progress = 0; + while(progress < size) { + size_t chunk; + if(file->write((const char *)buffer + i * size + progress, + size - progress, &chunk)) { + // TODO: Handle I/O errors. + mlibc::infoLogger() << "mlibc: fwrite() I/O errors are not handled" + << frg::endlog; + break; + }else if(!chunk) { + // TODO: Handle eof. + break; + } + + progress += chunk; + } + + if(progress < size) + return i; + } + + return count; + } +} + +char *fgets_unlocked(char *__restrict buffer, int max_size, FILE *stream) { + __ensure(max_size > 0); + for(int i = 0; ; i++) { + if(i == max_size - 1) { + buffer[i] = 0; + return buffer; + } + + auto c = fgetc_unlocked(stream); + + // If fgetc() fails, there is either an EOF or an I/O error. + if(c == EOF) { + if(i) { + buffer[i] = 0; + return buffer; + } else { + // In this case, the buffer is not changed. + return nullptr; + } + } else { + buffer[i] = c; + } + + if(c == '\n') { + buffer[i + 1] = 0; + return buffer; + } + } +} diff --git a/lib/mlibc/options/ansi/generic/stdlib-stubs.cpp b/lib/mlibc/options/ansi/generic/stdlib-stubs.cpp new file mode 100644 index 0000000..86b8a9a --- /dev/null +++ b/lib/mlibc/options/ansi/generic/stdlib-stubs.cpp @@ -0,0 +1,511 @@ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#if __MLIBC_POSIX_OPTION +#include +#endif // __MLIBC_POSIX_OPTION + +extern "C" int __cxa_atexit(void (*function)(void *), void *argument, void *dso_tag); +void __mlibc_do_finalize(); + +namespace { + // According to the first paragraph of [C11 7.22.7], + // mblen(), mbtowc() and wctomb() have an internal state. + // The string functions mbstowcs() and wcstombs() do *not* have this state. + thread_local __mlibc_mbstate mblen_state = __MLIBC_MBSTATE_INITIALIZER; + thread_local __mlibc_mbstate mbtowc_state = __MLIBC_MBSTATE_INITIALIZER; +} + +double atof(const char *string) { + return strtod(string, NULL); +} +int atoi(const char *string) { + return strtol(string, nullptr, 10); +} +long atol(const char *string) { + return strtol(string, nullptr, 10); +} +long long atoll(const char *string) { + return strtoll(string, nullptr, 10); +} + +// POSIX extensions but are here for simplicities sake. Forward declaration is here +// to avoid exporting sigprocmask when posix is disabled. +int sigprocmask(int, const sigset_t *__restrict, sigset_t *__restrict); +extern "C" { + __attribute__((__returns_twice__)) int __sigsetjmp(sigjmp_buf buffer, int savesigs) { + buffer[0].savesigs = savesigs; + if (savesigs) + sigprocmask(0, NULL, &buffer[0].sigset); + return 0; + } +} + +__attribute__((__noreturn__)) void siglongjmp(sigjmp_buf buffer, int value) { + if (buffer[0].savesigs) + sigprocmask(SIG_SETMASK, &buffer[0].sigset, NULL); + jmp_buf b; + b[0].reg_state = buffer[0].reg_state; + longjmp(b, value); +} + +double strtod(const char *__restrict string, char **__restrict end) { + return mlibc::strtofp(string, end); +} +float strtof(const char *__restrict string, char **__restrict end) { + return mlibc::strtofp(string, end); +} +long double strtold(const char *__restrict string, char **__restrict end) { + return mlibc::strtofp(string, end); +} + +long strtol(const char *__restrict string, char **__restrict end, int base) { + return mlibc::stringToInteger(string, end, base); +} +long long strtoll(const char *__restrict string, char **__restrict end, int base) { + return mlibc::stringToInteger(string, end, base); +} +unsigned long strtoul(const char *__restrict string, char **__restrict end, int base) { + return mlibc::stringToInteger(string, end, base); +} +unsigned long long strtoull(const char *__restrict string, char **__restrict end, int base) { + return mlibc::stringToInteger(string, end, base); +} + +frg::mt19937 __mlibc_rand_engine; + +int rand() { + // rand() is specified to return a positive number so we discard the MSB. + return static_cast(__mlibc_rand_engine() & 0x7FFFFFFF); +} + +static unsigned temper(unsigned x) { + x ^= x >> 11; + x ^= x << 7 & 0x9D2C5680; + x ^= x << 15 & 0xEFC60000; + x ^= x >> 18; + return x; +} + +int rand_r(unsigned *seed) { + return temper(*seed = *seed * 1103515245 + 12345) / 2; +} + +void srand(unsigned int s) { + __mlibc_rand_engine.seed(s); +} + +void *aligned_alloc(size_t alignment, size_t size) { + void *ptr; + + // alignment must be a power of two, and size % alignment must be 0 + if (alignment & (alignment - 1) || size & (alignment - 1)) { + errno = EINVAL; + return nullptr; + } + + // posix_memalign requires that the alignment is a multiple of sizeof(void *) + if (alignment < sizeof(void *)) + alignment = sizeof(void *); + + int ret = posix_memalign(&ptr, alignment, size); + if (ret) { + errno = ret; + return nullptr; + } + return ptr; + +} +void *calloc(size_t count, size_t size) { + // we want to ensure that count*size > SIZE_MAX doesn't happen + // to prevent overflowing, we divide both sides of the inequality by size and check with that + if(size && count > (SIZE_MAX / size)) { + errno = EINVAL; + return NULL; + } + + // TODO: this could be done more efficient if the OS gives us already zero'd pages + void *ptr = malloc(count * size); + if(!ptr) + return nullptr; + memset(ptr, 0, count * size); + return ptr; +} +// free() is provided by the platform +// malloc() is provided by the platform +// realloc() is provided by the platform + +void abort(void) { + sigset_t set; + sigemptyset(&set); + sigaddset(&set, SIGABRT); + if (mlibc::sys_sigprocmask) { + mlibc::sys_sigprocmask(SIG_UNBLOCK, &set, nullptr); + } + + raise(SIGABRT); + + sigfillset(&set); + sigdelset(&set, SIGABRT); + if (mlibc::sys_sigprocmask) { + mlibc::sys_sigprocmask(SIG_SETMASK, &set, nullptr); + } + + struct sigaction sa; + sa.sa_handler = SIG_DFL; + sa.sa_flags = 0; + sigemptyset(&sa.sa_mask); + + if (mlibc::sys_sigaction(SIGABRT, &sa, nullptr)) + mlibc::panicLogger() << "mlibc: sigaction failed in abort" << frg::endlog; + + if (raise(SIGABRT)) + mlibc::panicLogger() << "mlibc: raise failed in abort" << frg::endlog; + + __builtin_trap(); +} + +int atexit(void (*func)(void)) { + // TODO: the function pointer types are not compatible; + // the conversion here is undefined behavior. its fine to do + // this on the x86_64 abi though. + __cxa_atexit((void (*) (void *))func, nullptr, nullptr); + return 0; +} +int at_quick_exit(void (*func)(void)) { + (void)func; + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +void exit(int status) { + __mlibc_do_finalize(); + mlibc::sys_exit(status); +} + +void _Exit(int status) { + mlibc::sys_exit(status); +} + +// getenv() is provided by POSIX +void quick_exit(int) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +extern char **environ; + +int system(const char *command) { + int status = -1; + pid_t child; + + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_fork && mlibc::sys_waitpid && + mlibc::sys_execve && mlibc::sys_sigprocmask && mlibc::sys_sigaction, -1); + +#if __MLIBC_POSIX_OPTION + pthread_testcancel(); +#endif // __MLIBC_POSIX_OPTION + + if (!command) { + return 1; + } + + struct sigaction new_sa, old_int, old_quit; + sigset_t new_mask, old_mask; + + new_sa.sa_handler = SIG_IGN; + new_sa.sa_flags = 0; + sigemptyset(&new_sa.sa_mask); + mlibc::sys_sigaction(SIGINT, &new_sa, &old_int); + mlibc::sys_sigaction(SIGQUIT, &new_sa, &old_quit); + + sigemptyset(&new_mask); + sigaddset(&new_mask, SIGCHLD); + mlibc::sys_sigprocmask(SIG_BLOCK, &new_mask, &old_mask); + + if (int e = mlibc::sys_fork(&child)) { + errno = e; + } else if (!child) { + mlibc::sys_sigaction(SIGINT, &old_int, nullptr); + mlibc::sys_sigaction(SIGQUIT, &old_quit, nullptr); + mlibc::sys_sigprocmask(SIG_SETMASK, &old_mask, nullptr); + + const char *args[] = { + "sh", "-c", command, nullptr + }; + + mlibc::sys_execve("/bin/sh", const_cast(args), environ); + _Exit(127); + } else { + int err; + pid_t unused; + + while ((err = mlibc::sys_waitpid(child, &status, 0, NULL, &unused)) < 0) { + if (err == EINTR) + continue; + + errno = err; + status = -1; + } + } + + mlibc::sys_sigaction(SIGINT, &old_int, nullptr); + mlibc::sys_sigaction(SIGQUIT, &old_quit, nullptr); + mlibc::sys_sigprocmask(SIG_SETMASK, &old_mask, nullptr); + + return status; +} + +char *mktemp(char *) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +void *bsearch(const void *key, const void *base, size_t count, size_t size, + int (*compare)(const void *, const void *)) { + // Invariant: Element is in the interval [i, j). + size_t i = 0; + size_t j = count; + + while(i < j) { + size_t k = (j - i) / 2; + auto element = reinterpret_cast(base) + (i + k) * size; + auto res = compare(key, element); + if(res < 0) { + j = i + k; + }else if(res > 0) { + i = i + k + 1; + }else{ + return const_cast(element); + } + } + __ensure(i == j); + + return nullptr; +} + +static int qsort_callback(const void *a, const void *b, void *arg) { + auto compare = reinterpret_cast(arg); + + return compare(a, b); +} + +void qsort(void *base, size_t count, size_t size, + int (*compare)(const void *, const void *)) { + return qsort_r(base, count, size, qsort_callback, (void *) compare); +} + +void qsort_r(void *base, size_t count, size_t size, + int (*compare)(const void *, const void *, void *), + void *arg) { + // TODO: implement a faster sort + for(size_t i = 0; i < count; i++) { + void *u = (void *)((uintptr_t)base + i * size); + for(size_t j = i + 1; j < count; j++) { + void *v = (void *)((uintptr_t)base + j * size); + if(compare(u, v, arg) <= 0) + continue; + + // swap u and v + char *u_bytes = (char *)u; + char *v_bytes = (char *)v; + for(size_t k = 0; k < size; k++) { + char temp = u_bytes[k]; + u_bytes[k] = v_bytes[k]; + v_bytes[k] = temp; + } + } + } +} + +int abs(int num) { + return num < 0 ? -num : num; +} + +long labs(long num) { + return num < 0 ? -num : num; +} + +long long llabs(long long num) { + return num < 0 ? -num : num; +} + +div_t div(int number, int denom) { + div_t r; + r.quot = number / denom; + r.rem = number % denom; + return r; +} + +ldiv_t ldiv(long number, long denom) { + ldiv_t r; + r.quot = number / denom; + r.rem = number % denom; + return r; +} + +lldiv_t lldiv(long long number, long long denom) { + lldiv_t r; + r.quot = number / denom; + r.rem = number % denom; + return r; +} + +int mblen(const char *mbs, size_t mb_limit) { + auto cc = mlibc::current_charcode(); + wchar_t wc; + mlibc::code_seq nseq{mbs, mbs + mb_limit}; + mlibc::code_seq wseq{&wc, &wc + 1}; + + if(!mbs) { + mblen_state = __MLIBC_MBSTATE_INITIALIZER; + return cc->has_shift_states; + } + + if(auto e = cc->decode_wtranscode(nseq, wseq, mblen_state); e != mlibc::charcode_error::null) + __ensure(!"decode_wtranscode() errors are not handled"); + return nseq.it - mbs; +} + +int mbtowc(wchar_t *__restrict wc, const char *__restrict mb, size_t max_size) { + auto cc = mlibc::current_charcode(); + __ensure(max_size); + + // If wc is NULL, decode into a single local character which we discard + // to obtain the length. + wchar_t tmp_wc; + if (!wc) + wc = &tmp_wc; + + if (mb) { + if (*mb) { + mlibc::code_seq wseq{wc, wc + 1}; + mlibc::code_seq nseq{mb, mb + max_size}; + auto e = cc->decode_wtranscode(nseq, wseq, mbtowc_state); + switch(e) { + // We keep the state, so we can simply return here. + case mlibc::charcode_error::input_underflow: + case mlibc::charcode_error::null: { + return nseq.it - mb; + } + case mlibc::charcode_error::illegal_input: { + errno = -EILSEQ; + return -1; + } + case mlibc::charcode_error::dirty: { + mlibc::panicLogger() << "decode_wtranscode() charcode_error::dirty errors are not handled" << frg::endlog; + break; + } + case mlibc::charcode_error::output_overflow: { + mlibc::panicLogger() << "decode_wtranscode() charcode_error::output_overflow errors are not handled" << frg::endlog; + break; + } + } + __builtin_unreachable(); + } else { + *wc = L'\0'; + return 0; // When mbs is a null byte, return 0 + } + } else { + mblen_state = __MLIBC_MBSTATE_INITIALIZER; + return cc->has_shift_states; + } +} + +int wctomb(char *, wchar_t) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +size_t mbstowcs(wchar_t *wcs, const char *mbs, size_t wc_limit) { + auto cc = mlibc::current_charcode(); + __mlibc_mbstate st = __MLIBC_MBSTATE_INITIALIZER; + mlibc::code_seq nseq{mbs, nullptr}; + mlibc::code_seq wseq{wcs, wcs + wc_limit}; + + if(!wcs) { + size_t size; + if(auto e = cc->decode_wtranscode_length(nseq, &size, st); e != mlibc::charcode_error::null) + __ensure(!"decode_wtranscode() errors are not handled"); + return size; + } + + if(auto e = cc->decode_wtranscode(nseq, wseq, st); e != mlibc::charcode_error::null) { + __ensure(!"decode_wtranscode() errors are not handled"); + __builtin_unreachable(); + }else{ + size_t n = wseq.it - wcs; + if(n < wc_limit) // Null-terminate resulting wide string. + wcs[n] = 0; + return n; + } +} + +size_t wcstombs(char *mb_string, const wchar_t *wc_string, size_t max_size) { + return wcsrtombs(mb_string, &wc_string, max_size, 0); +} + +void free(void *ptr) { + // TODO: Print PID only if POSIX option is enabled. + if (mlibc::globalConfig().debugMalloc) { + mlibc::infoLogger() << "mlibc (PID ?): free() on " + << ptr << frg::endlog; + if((uintptr_t)ptr & 1) + mlibc::infoLogger() << __builtin_return_address(0) << frg::endlog; + } + getAllocator().free(ptr); +} + +void *malloc(size_t size) { + auto nptr = getAllocator().allocate(size); + // TODO: Print PID only if POSIX option is enabled. + if (mlibc::globalConfig().debugMalloc) + mlibc::infoLogger() << "mlibc (PID ?): malloc() returns " + << nptr << frg::endlog; + return nptr; +} + +void *realloc(void *ptr, size_t size) { + auto nptr = getAllocator().reallocate(ptr, size); + // TODO: Print PID only if POSIX option is enabled. + if (mlibc::globalConfig().debugMalloc) + mlibc::infoLogger() << "mlibc (PID ?): realloc() on " + << ptr << " returns " << nptr << frg::endlog; + return nptr; +} + +int posix_memalign(void **out, size_t align, size_t size) { + if(align < sizeof(void *)) + return EINVAL; + if(align & (align - 1)) // Make sure that align is a power of two. + return EINVAL; + auto p = getAllocator().allocate(frg::max(align, size)); + if(!p) + return ENOMEM; + // Hope that the alignment was respected. This works on the current allocator. + // TODO: Make the allocator alignment-aware. + __ensure(!(reinterpret_cast(p) & (align - 1))); + *out = p; + return 0; +} diff --git a/lib/mlibc/options/ansi/generic/string-stubs.cpp b/lib/mlibc/options/ansi/generic/string-stubs.cpp new file mode 100644 index 0000000..8defd0e --- /dev/null +++ b/lib/mlibc/options/ansi/generic/string-stubs.cpp @@ -0,0 +1,542 @@ +#include +#include +#include +#include + +#include +#include + +// memset() is defined in options/internals. +// memcpy() is defined in options/internals. +// memmove() is defined in options/internals. +// strlen() is defined in options/internals. + +char *strcpy(char *__restrict dest, const char *src) { + char *dest_bytes = (char *)dest; + char *src_bytes = (char *)src; + while(*src_bytes) + *(dest_bytes++) = *(src_bytes++); + *dest_bytes = 0; + return dest; +} +char *strncpy(char *__restrict dest, const char *src, size_t max_size) { + auto dest_bytes = static_cast(dest); + auto src_bytes = static_cast(src); + size_t i = 0; + while(*src_bytes && i < max_size) { + *(dest_bytes++) = *(src_bytes++); + i++; + } + while(i < max_size) { + *(dest_bytes++) = 0; + i++; + } + return dest; +} + +char *strcat(char *__restrict dest, const char *__restrict src) { + strcpy(dest + strlen(dest), src); + return dest; +} +char *strncat(char *__restrict dest, const char *__restrict src, size_t max_size) { + auto dest_bytes = static_cast(dest); + auto src_bytes = static_cast(src); + dest_bytes += strlen(dest); + size_t i = 0; + while(*src_bytes && i < max_size) { + *(dest_bytes++) = *(src_bytes++); + i++; + } + *dest_bytes = 0; + return dest; +} + +int memcmp(const void *a, const void *b, size_t size) { + for(size_t i = 0; i < size; i++) { + auto a_byte = static_cast(a)[i]; + auto b_byte = static_cast(b)[i]; + if(a_byte < b_byte) + return -1; + if(a_byte > b_byte) + return 1; + } + return 0; +} +int strcmp(const char *a, const char *b) { + size_t i = 0; + while(true) { + unsigned char a_byte = a[i]; + unsigned char b_byte = b[i]; + if(!a_byte && !b_byte) + return 0; + // If only one char is null, one of the following cases applies. + if(a_byte < b_byte) + return -1; + if(a_byte > b_byte) + return 1; + i++; + } +} + +int strcoll(const char *a, const char *b) { + // TODO: strcoll should take "LC_COLLATE" into account. + return strcmp(a, b); +} + +int strncmp(const char *a, const char *b, size_t max_size) { + size_t i = 0; + while(true) { + if(!(i < max_size)) + return 0; + unsigned char a_byte = a[i]; + unsigned char b_byte = b[i]; + if(!a_byte && !b_byte) + return 0; + // If only one char is null, one of the following cases applies. + if(a_byte < b_byte) + return -1; + if(a_byte > b_byte) + return 1; + i++; + } +} + +size_t strxfrm(char *__restrict dest, const char *__restrict src, size_t n) { + // NOTE: This might not work for non ANSI charsets. + size_t l = strlen(src); + + // man page: If the value returned is n or more, the contents of dest are indeterminate. + if(n > l) + strncpy(dest, src, n); + + return l; +} + +void *memchr(const void *s, int c, size_t size) { + auto s_bytes = static_cast(s); + for(size_t i = 0; i < size; i++) + if(s_bytes[i] == static_cast(c)) + return const_cast(s_bytes + i); + return nullptr; +} +char *strchr(const char *s, int c) { + size_t i = 0; + while(s[i]) { + if(s[i] == c) + return const_cast(&s[i]); + i++; + } + if(c == 0) + return const_cast(&s[i]); + return nullptr; +} +size_t strcspn(const char *s, const char *chrs) { + size_t n = 0; + while(true) { + if(!s[n] || strchr(chrs, s[n])) + return n; + n++; + } +} +char *strpbrk(const char *s, const char *chrs) { + size_t n = 0; + while(s[n]) { + if(strchr(chrs, s[n])) + return const_cast(s + n); + n++; + } + return nullptr; +} +char *strrchr(const char *s, int c) { + // The null-terminator is considered to be part of the string. + size_t length = strlen(s); + for(size_t i = 0; i <= length; i++) { + if(s[length - i] == c) + return const_cast(s + (length - i)); + } + return nullptr; +} +size_t strspn(const char *s, const char *chrs) { + size_t n = 0; + while(true) { + if(!s[n] || !strchr(chrs, s[n])) + return n; + n++; + } +} +char *strstr(const char *s, const char *pattern) { + for(size_t i = 0; s[i]; i++) { + bool found = true; + for(size_t j = 0; pattern[j]; j++) { + if(!pattern[j] || s[i + j] == pattern[j]) + continue; + + found = false; + break; + } + + if(found) + return const_cast(&s[i]); + } + + return nullptr; +} +char *strtok_r(char *__restrict s, const char *__restrict del, char **__restrict m) { + __ensure(m); + + // We use *m = null to memorize that the entire string was consumed. + char *tok; + if(s) { + tok = s; + }else if(*m) { + tok = *m; + }else { + return nullptr; + } + + // Skip initial delimiters. + // After this loop: *tok is non-null iff we return a token. + while(*tok && strchr(del, *tok)) + tok++; + + // Replace the following delimiter by a null-terminator. + // After this loop: *p is null iff we reached the end of the string. + auto p = tok; + while(*p && !strchr(del, *p)) + p++; + + if(*p) { + *p = 0; + *m = p + 1; + }else{ + *m = nullptr; + } + if(p == tok) + return nullptr; + return tok; +} +char *strtok(char *__restrict s, const char *__restrict delimiter) { + static char *saved; + return strtok_r(s, delimiter, &saved); +} + +// This is a GNU extension. +char *strchrnul(const char *s, int c) { + size_t i = 0; + while(s[i]) { + if(s[i] == c) + return const_cast(s + i); + i++; + } + return const_cast(s + i); +} + +double wcstod(const wchar_t *__restrict, wchar_t **__restrict) MLIBC_STUB_BODY +float wcstof(const wchar_t *__restrict, wchar_t **__restrict) MLIBC_STUB_BODY +long double wcstold(const wchar_t *__restrict, wchar_t **__restrict) MLIBC_STUB_BODY + +long wcstol(const wchar_t *__restrict nptr, wchar_t **__restrict endptr, int base) { + return mlibc::stringToInteger(nptr, endptr, base); +} +unsigned long wcstoul(const wchar_t *__restrict nptr, wchar_t **__restrict endptr, int base) { + return mlibc::stringToInteger(nptr, endptr, base); +} +long long wcstoll(const wchar_t *__restrict nptr, wchar_t **__restrict endptr, int base) { + return mlibc::stringToInteger(nptr, endptr, base); +} +unsigned long long wcstoull(const wchar_t *__restrict nptr, wchar_t **__restrict endptr, int base) { + return mlibc::stringToInteger(nptr, endptr, base); +} + +wchar_t *wcscpy(wchar_t *__restrict dest, const wchar_t *__restrict src) { + wchar_t *a = dest; + while((*dest++ = *src++)); + return a; +} + +wchar_t *wcsncpy(wchar_t *__restrict dest, const wchar_t *__restrict src, size_t n) { + wchar_t *a = dest; + while(n && *src) + n--, *dest++ = *src++; + wmemset(dest, 0, n); + return a; +} + +wchar_t *wmemcpy(wchar_t *__restrict dest, const wchar_t *__restrict src, size_t n) { + memcpy(dest, src, n * sizeof(wchar_t)); + return dest; +} + +wchar_t *wmemmove(wchar_t *dest, const wchar_t *src, size_t n) { + memmove(dest, src, n * sizeof(wchar_t)); + return dest; +} + +wchar_t *wcscat(wchar_t *__restrict dest, const wchar_t *__restrict src) { + wcscpy(dest + wcslen(dest), src); + return dest; +} + +wchar_t *wcsncat(wchar_t *__restrict, const wchar_t *__restrict, size_t) MLIBC_STUB_BODY + +int wcscmp(const wchar_t *l, const wchar_t *r) { + for(; *l == *r && *l && *r; l++, r++); + return *l - *r; +} + +int wcscoll(const wchar_t *, const wchar_t *) MLIBC_STUB_BODY +int wcsncmp(const wchar_t *, const wchar_t *, size_t) MLIBC_STUB_BODY +int wcsxfrm(wchar_t *__restrict, const wchar_t *__restrict, size_t) MLIBC_STUB_BODY + +int wmemcmp(const wchar_t *a, const wchar_t *b, size_t size) { + for(size_t i = 0; i < size; i++) { + auto a_byte = a[i]; + auto b_byte = b[i]; + if(a_byte < b_byte) + return -1; + if(a_byte > b_byte) + return 1; + } + return 0; +} + +wchar_t *wcschr(const wchar_t *s, wchar_t c) { + if(!c) + return (wchar_t *)s + wcslen(s); + for(; *s && *s != c; s++); + return *s ? (wchar_t *)s : 0; +} + +size_t wcscspn(const wchar_t *, const wchar_t *) MLIBC_STUB_BODY +wchar_t *wcspbrk(const wchar_t *, const wchar_t *) MLIBC_STUB_BODY + +wchar_t *wcsrchr(const wchar_t *s, wchar_t c) { + const wchar_t *p; + for(p = s + wcslen(s); p >= s && *p != c; p--); + return p >= s ? (wchar_t *)p : 0; +} + +size_t wcsspn(const wchar_t *, const wchar_t *) MLIBC_STUB_BODY +wchar_t *wcsstr(const wchar_t *, const wchar_t *) MLIBC_STUB_BODY +wchar_t *wcstok(wchar_t *__restrict, const wchar_t *__restrict, wchar_t **__restrict) MLIBC_STUB_BODY + +wchar_t *wmemchr(const wchar_t *s, wchar_t c, size_t size) { + auto s_bytes = s; + for(size_t i = 0; i < size; i++) + if(s_bytes[i] == c) + return const_cast(s_bytes + i); + return nullptr; +} + +size_t wcslen(const wchar_t *s) { + const wchar_t *a; + for(a = s; *s; s++); + return s-a; +} + +wchar_t *wmemset(wchar_t *d, wchar_t c, size_t n) { + wchar_t *ret = d; + while(n--) + *d++ = c; + return ret; +} + +char *strerror(int e) { + const char *s; + switch(e) { + case EAGAIN: s = "Operation would block (EAGAIN)"; break; + case EACCES: s = "Access denied (EACCESS)"; break; + case EBADF: s = "Bad file descriptor (EBADF)"; break; + case EEXIST: s = "File exists already (EEXIST)"; break; + case EFAULT: s = "Access violation (EFAULT)"; break; + case EINTR: s = "Operation interrupted (EINTR)"; break; + case EINVAL: s = "Invalid argument (EINVAL)"; break; + case EIO: s = "I/O error (EIO)"; break; + case EISDIR: s = "Resource is directory (EISDIR)"; break; + case ENOENT: s = "No such file or directory (ENOENT)"; break; + case ENOMEM: s = "Out of memory (ENOMEM)"; break; + case ENOTDIR: s = "Expected directory instead of file (ENOTDIR)"; break; + case ENOSYS: s = "Operation not implemented (ENOSYS)"; break; + case EPERM: s = "Operation not permitted (EPERM)"; break; + case EPIPE: s = "Broken pipe (EPIPE)"; break; + case ESPIPE: s = "Seek not possible (ESPIPE)"; break; + case ENXIO: s = "No such device or address (ENXIO)"; break; + case ENOEXEC: s = "Exec format error (ENOEXEC)"; break; + case ENOSPC: s = "No space left on device (ENOSPC)"; break; + case ENOTSOCK: s = "Socket operation on non-socket (ENOTSOCK)"; break; + case ENOTCONN: s = "Transport endpoint is not connected (ENOTCONN)"; break; + case EDOM: s = "Numerical argument out of domain (EDOM)"; break; + case EILSEQ: s = "Invalid or incomplete multibyte or wide character (EILSEQ)"; break; + case ERANGE: s = "Numerical result out of range (ERANGE)"; break; + case E2BIG: s = "Argument list too long (E2BIG)"; break; + case EADDRINUSE: s = "Address already in use (EADDRINUSE)"; break; + case EADDRNOTAVAIL: s = "Cannot assign requested address (EADDRNOTAVAIL)"; break; + case EAFNOSUPPORT: s = "Address family not supported by protocol (EAFNOSUPPORT)"; break; + case EALREADY: s = "Operation already in progress (EALREADY)"; break; + case EBADMSG: s = "Bad message (EBADMSG)"; break; + case EBUSY: s = "Device or resource busy (EBUSY)"; break; + case ECANCELED: s = "Operation canceled (ECANCELED)"; break; + case ECHILD: s = "No child processes (ECHILD)"; break; + case ECONNABORTED: s = "Software caused connection abort (ECONNABORTED)"; break; + case ECONNREFUSED: s = "Connection refused (ECONNREFUSED)"; break; + case ECONNRESET: s = "Connection reset by peer (ECONNRESET)"; break; + case EDEADLK: s = "Resource deadlock avoided (EDEADLK)"; break; + case EDESTADDRREQ: s = "Destination address required (EDESTADDRREQ)"; break; + case EDQUOT: s = "Disk quota exceeded (EDQUOT)"; break; + case EFBIG: s = "File too large (EFBIG)"; break; + case EHOSTUNREACH: s = "No route to host (EHOSTUNREACH)"; break; + case EIDRM: s = "Identifier removed (EIDRM)"; break; + case EINPROGRESS: s = "Operation now in progress (EINPROGRESS)"; break; + case EISCONN: s = "Transport endpoint is already connected (EISCONN)"; break; + case ELOOP: s = "Too many levels of symbolic links (ELOOP)"; break; + case EMFILE: s = "Too many open files (EMFILE)"; break; + case EMLINK: s = "Too many links (EMLINK)"; break; + case EMSGSIZE: s = "Message too long (EMSGSIZE)"; break; + case EMULTIHOP: s = "Multihop attempted (EMULTIHOP)"; break; + case ENAMETOOLONG: s = "File name too long (ENAMETOOLONG)"; break; + case ENETDOWN: s = "Network is down (ENETDOWN)"; break; + case ENETRESET: s = "Network dropped connection on reset (ENETRESET)"; break; + case ENETUNREACH: s = "Network is unreachable (ENETUNREACH)"; break; + case ENFILE: s = "Too many open files in system (ENFILE)"; break; + case ENOBUFS: s = "No buffer space available (ENOBUFS)"; break; + case ENODEV: s = "No such device (ENODEV)"; break; + case ENOLCK: s = "No locks available (ENOLCK)"; break; + case ENOLINK: s = "Link has been severed (ENOLINK)"; break; + case ENOMSG: s = "No message of desired type (ENOMSG)"; break; + case ENOPROTOOPT: s = "Protocol not available (ENOPROTOOPT)"; break; + case ENOTEMPTY: s = "Directory not empty (ENOTEMPTY)"; break; + case ENOTRECOVERABLE: s = "Sate not recoverable (ENOTRECOVERABLE)"; break; + case ENOTSUP: s = "Operation not supported (ENOTSUP)"; break; + case ENOTTY: s = "Inappropriate ioctl for device (ENOTTY)"; break; + case EOVERFLOW: s = "Value too large for defined datatype (EOVERFLOW)"; break; +#if EOPNOTSUPP != ENOTSUP + /* these are aliases on the mlibc abi */ + case EOPNOTSUPP: s = "Operation not supported (EOPNOTSUP)"; break; +#endif + case EOWNERDEAD: s = "Owner died (EOWNERDEAD)"; break; + case EPROTO: s = "Protocol error (EPROTO)"; break; + case EPROTONOSUPPORT: s = "Protocol not supported (EPROTONOSUPPORT)"; break; + case EPROTOTYPE: s = "Protocol wrong type for socket (EPROTOTYPE)"; break; + case EROFS: s = "Read-only file system (EROFS)"; break; + case ESRCH: s = "No such process (ESRCH)"; break; + case ESTALE: s = "Stale file handle (ESTALE)"; break; + case ETIMEDOUT: s = "Connection timed out (ETIMEDOUT)"; break; + case ETXTBSY: s = "Text file busy (ETXTBSY)"; break; + case EXDEV: s = "Invalid cross-device link (EXDEV)"; break; + case ENODATA: s = "No data available (ENODATA)"; break; + case ETIME: s = "Timer expired (ETIME)"; break; + case ENOKEY: s = "Required key not available (ENOKEY)"; break; + case ESHUTDOWN: s = "Cannot send after transport endpoint shutdown (ESHUTDOWN)"; break; + case EHOSTDOWN: s = "Host is down (EHOSTDOWN)"; break; + case EBADFD: s = "File descriptor in bad state (EBADFD)"; break; + case ENOMEDIUM: s = "No medium found (ENOMEDIUM)"; break; + case ENOTBLK: s = "Block device required (ENOTBLK)"; break; + case ENONET: s = "Machine is not on the network (ENONET)"; break; + case EPFNOSUPPORT: s = "Protocol family not supported (EPFNOSUPPORT)"; break; + case ESOCKTNOSUPPORT: s = "Socket type not supported (ESOCKTNOSUPPORT)"; break; + case ESTRPIPE: s = "Streams pipe error (ESTRPIPE)"; break; + case EREMOTEIO: s = "Remote I/O error (EREMOTEIO)"; break; + case ERFKILL: s = "Operation not possible due to RF-kill (ERFKILL)"; break; + case EBADR: s = "Invalid request descriptor (EBADR)"; break; + case EUNATCH: s = "Protocol driver not attached (EUNATCH)"; break; + case EMEDIUMTYPE: s = "Wrong medium type (EMEDIUMTYPE)"; break; + case EREMOTE: s = "Object is remote (EREMOTE)"; break; + case EKEYREJECTED: s = "Key was rejected by service (EKEYREJECTED)"; break; + case EUCLEAN: s = "Structure needs cleaning (EUCLEAN)"; break; + case EBADSLT: s = "Invalid slot (EBADSLT)"; break; + case ENOANO: s = "No anode (ENOANO)"; break; + case ENOCSI: s = "No CSI structure available (ENOCSI)"; break; + case ENOSTR: s = "Device not a stream (ENOSTR)"; break; + case ETOOMANYREFS: s = "Too many references: cannot splice (ETOOMANYREFS)"; break; + case ENOPKG: s = "Package not installed (ENOPKG)"; break; + case EKEYREVOKED: s = "Key has been revoked (EKEYREVOKED)"; break; + case EXFULL: s = "Exchange full (EXFULL)"; break; + case ELNRNG: s = "Link number out of range (ELNRNG)"; break; + case ENOTUNIQ: s = "Name not unique on network (ENOTUNIQ)"; break; + case ERESTART: s = "Interrupted system call should be restarted (ERESTART)"; break; + case EUSERS: s = "Too many users (EUSERS)"; break; + +#ifdef EIEIO + case EIEIO: s = "Computer bought the farm; OS internal error (EIEIO)"; break; +#endif + + default: + s = "Unknown error code (?)"; + } + return const_cast(s); +} +// strlen() is defined in options/internals. + +// POSIX extensions. + +int strerror_r(int e, char *buffer, size_t bufsz) { + auto s = strerror(e); + strncpy(buffer, s, bufsz); + // Note that strerror_r does not set errno on error! + if(strlen(s) >= bufsz) + return ERANGE; + return 0; +} + +void *mempcpy(void *dest, const void *src, size_t len) { + return (char *)memcpy(dest, src, len) + len; +} + +// GNU extensions. +// Taken from musl. +int strverscmp(const char *l0, const char *r0) { + const unsigned char *l = (const unsigned char *)l0; + const unsigned char *r = (const unsigned char *)r0; + size_t i, dp, j; + int z = 1; + + /* Find maximal matching prefix and track its maximal digit + * suffix and whether those digits are all zeros. */ + for(dp = i = 0; l[i] == r[i]; i++) { + int c = l[i]; + if(!c) + return 0; + if(!isdigit(c)) + dp = i + 1, z = 1; + else if(c != '0') + z = 0; + } + + if(l[dp] != '0' && r[dp] != '0') { + /* If we're not looking at a digit sequence that began + * with a zero, longest digit string is greater. */ + for(j = i; isdigit(l[j]); j++) { + if(!isdigit(r[j])) + return 1; + } + if(isdigit(r[j])) + return -1; + } else if(z && dp < i && (isdigit(l[i]) || isdigit(r[i]))) { + /* Otherwise, if common prefix of digit sequence is + * all zeros, digits order less than non-digits. */ + return (unsigned char)(l[i] - '0') - (unsigned char)(r[i] - '0'); + } + + return l[i] - r[i]; +} + +void *memmem(const void *hs, size_t haystackLen, const void *nd, size_t needleLen) { + const char *haystack = static_cast(hs); + const char *needle = static_cast(nd); + + for (size_t i = 0; i < haystackLen; i++) { + bool found = true; + + for (size_t j = 0; j < needleLen; j++) { + if (i + j >= haystackLen || haystack[i + j] != needle[j]) { + found = false; + break; + } + } + + if(found) + return const_cast(&haystack[i]); + } + + return nullptr; +} diff --git a/lib/mlibc/options/ansi/generic/threads.cpp b/lib/mlibc/options/ansi/generic/threads.cpp new file mode 100644 index 0000000..70fa055 --- /dev/null +++ b/lib/mlibc/options/ansi/generic/threads.cpp @@ -0,0 +1,97 @@ +#include +#include +#include +#include +#include +#include + +int thrd_create(thrd_t *thr, thrd_start_t func, void *arg) { + int res = mlibc::thread_create(thr, 0, reinterpret_cast(func), arg, true); + + if(!res) { + return thrd_success; + } + + return (res == ENOMEM) ? thrd_nomem : thrd_error; +} + +int thrd_equal(thrd_t t1, thrd_t t2) { + if(t1 == t2) { + return 1; + } + return 0; +} + +thrd_t thrd_current(void) { + return reinterpret_cast(mlibc::get_current_tcb()); +} + +int thrd_sleep(const struct timespec *, struct timespec *) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +void thrd_yield(void) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +int thrd_detach(thrd_t) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +int thrd_join(thrd_t thr, int *res) { + if(mlibc::thread_join(thr, res) != 0) { + return thrd_error; + } + + return thrd_success; +} + +__attribute__((__noreturn__)) void thrd_exit(int) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +int mtx_init(mtx_t *mtx, int type) { + struct __mlibc_mutexattr attr; + mlibc::thread_mutexattr_init(&attr); + + if(type & mtx_recursive) { + mlibc::thread_mutexattr_settype(&attr, __MLIBC_THREAD_MUTEX_RECURSIVE); + } + + int res = mlibc::thread_mutex_init(mtx, &attr) == 0 ? thrd_success : thrd_error; + mlibc::thread_mutexattr_destroy(&attr); + + return res; +} + +void mtx_destroy(mtx_t *mtx) { + mlibc::thread_mutex_destroy(mtx); +} + +int mtx_lock(mtx_t *mtx) { + return mlibc::thread_mutex_lock(mtx) == 0 ? thrd_success : thrd_error; +} + +int mtx_unlock(mtx_t *mtx) { + return mlibc::thread_mutex_unlock(mtx) == 0 ? thrd_success : thrd_error; +} + +int cnd_init(cnd_t *cond) { + return mlibc::thread_cond_init(cond, 0) == 0 ? thrd_success : thrd_error; +} + +void cnd_destroy(cnd_t *cond) { + mlibc::thread_cond_destroy(cond); +} + +int cnd_broadcast(cnd_t *cond) { + return mlibc::thread_cond_broadcast(cond) == 0 ? thrd_success : thrd_error; +} + +int cnd_wait(cnd_t *cond, mtx_t *mtx) { + return mlibc::thread_cond_timedwait(cond, mtx, nullptr) == 0 ? thrd_success : thrd_error; +} diff --git a/lib/mlibc/options/ansi/generic/time-stubs.cpp b/lib/mlibc/options/ansi/generic/time-stubs.cpp new file mode 100644 index 0000000..b8c7cf5 --- /dev/null +++ b/lib/mlibc/options/ansi/generic/time-stubs.cpp @@ -0,0 +1,729 @@ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +const char __utc[] = "UTC"; + +// Variables defined by POSIX. +int daylight; +long timezone; +char *tzname[2]; + +static FutexLock __time_lock; +static file_window *get_localtime_window() { + static file_window window{"/etc/localtime"}; + return &window; +} + +// Function taken from musl +clock_t clock(void) { + struct timespec ts; + + if(clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts)) + return -1; + + if(ts.tv_sec > LONG_MAX / 1000000 || ts.tv_nsec / 1000 > LONG_MAX - 1000000 * ts.tv_sec) + return -1; + + return ts.tv_sec * 1000000 + ts.tv_nsec / 1000; +} + +double difftime(time_t a, time_t b) { + return a - b; +} + +time_t mktime(struct tm *tm) { + return timegm(tm); +} + +/* There is no other implemented value than TIME_UTC; all other values + * are considered erroneous. */ +// Function taken from musl +int timespec_get(struct timespec *ts, int base) { + if(base != TIME_UTC) + return 0; + int ret = clock_gettime(CLOCK_REALTIME, ts); + return ret < 0 ? 0 : base; +} + +char *asctime(const struct tm *ptr) { + static char buf[26]; + return asctime_r(ptr, buf); +} + +char *ctime(const time_t *timer) { + struct tm *tm = localtime(timer); + if(!tm) { + return 0; + } + return asctime(tm); +} + +struct tm *gmtime(const time_t *unix_gmt) { + static thread_local struct tm per_thread_tm; + return gmtime_r(unix_gmt, &per_thread_tm); +} + +struct tm *localtime(const time_t *unix_gmt) { + tzset(); + static thread_local struct tm per_thread_tm; + return localtime_r(unix_gmt, &per_thread_tm); +} + +size_t strftime(char *__restrict dest, size_t max_size, + const char *__restrict format, const struct tm *__restrict tm) { + auto c = format; + auto p = dest; + + while(*c) { + int chunk; + auto space = (dest + max_size) - p; + __ensure(space >= 0); + + if(*c != '%') { + if(!space) + return 0; + *p = *c; + c++; + p++; + continue; + } + + switch(*++c) { + case 'Y': { + chunk = snprintf(p, space, "%d", 1900 + tm->tm_year); + if(chunk >= space) + return 0; + p += chunk; + c++; + break; + } + case 'm': { + chunk = snprintf(p, space, "%.2d", tm->tm_mon + 1); + if(chunk >= space) + return 0; + p += chunk; + c++; + break; + } + case 'd': { + chunk = snprintf(p, space, "%.2d", tm->tm_mday); + if(chunk >= space) + return 0; + p += chunk; + c++; + break; + } + case 'Z': { + chunk = snprintf(p, space, "%s", "GMT"); + if(chunk >= space) + return 0; + p += chunk; + c++; + break; + } + case 'H': { + chunk = snprintf(p, space, "%.2i", tm->tm_hour); + if(chunk >= space) + return 0; + p += chunk; + c++; + break; + } + case 'M': { + chunk = snprintf(p, space, "%.2i", tm->tm_min); + if(chunk >= space) + return 0; + p += chunk; + c++; + break; + } + case 'S': { + chunk = snprintf(p, space, "%.2d", tm->tm_sec); + if(chunk >= space) + return 0; + p += chunk; + c++; + break; + } + case 'R': { + chunk = snprintf(p, space, "%.2i:%.2i", tm->tm_hour, tm->tm_min); + if(chunk >= space) + return 0; + p += chunk; + c++; + break; + } + case 'T': { + chunk = snprintf(p, space, "%.2i:%.2i:%.2i", tm->tm_hour, tm->tm_min, tm->tm_sec); + if(chunk >= space) + return 0; + p += chunk; + c++; + break; + } + case 'F': { + chunk = snprintf(p, space, "%d-%.2d-%.2d", 1900 + tm->tm_year, tm->tm_mon + 1, + tm->tm_mday); + if(chunk >= space) + return 0; + p += chunk; + c++; + break; + } + case 'D': { + chunk = snprintf(p, space, "%.2d/%.2d/%.2d", tm->tm_mon + 1, tm->tm_mday, tm->tm_year % 100); + if(chunk >= space) + return 0; + p += chunk; + c++; + break; + } + case 'a': { + int day = tm->tm_wday; + if(day < 0 || day > 6) + __ensure(!"Day not in bounds."); + + chunk = snprintf(p, space, "%s", mlibc::nl_langinfo(ABDAY_1 + day)); + if(chunk >= space) + return 0; + p += chunk; + c++; + break; + } + case 'b': + case 'B': + case 'h': { + int mon = tm->tm_mon; + if(mon < 0 || mon > 11) + __ensure(!"Month not in bounds."); + + nl_item item = (*c == 'B') ? MON_1 : ABMON_1; + + chunk = snprintf(p, space, "%s", mlibc::nl_langinfo(item + mon)); + if(chunk >= space) + return 0; + p += chunk; + c++; + break; + } + case 'c': { + chunk = snprintf(p, space, "%d/%.2d/%.2d %.2d:%.2d:%.2d", 1900 + tm->tm_year, + tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec); + if(chunk >= space) + return 0; + p += chunk; + c++; + break; + } + case 'e': { + chunk = snprintf(p, space, "%2d", tm->tm_mday); + if(chunk >= space) + return 0; + p += chunk; + c++; + break; + } + case 'l': { + int hour = tm->tm_hour; + if(!hour) + hour = 12; + if(hour > 12) + hour -= 12; + chunk = snprintf(p, space, "%2d", hour); + if(chunk >= space) + return 0; + p += chunk; + c++; + break; + } + case 'I': { + int hour = tm->tm_hour; + if(!hour) + hour = 12; + if(hour > 12) + hour -= 12; + chunk = snprintf(p, space, "%.2d", hour); + if(chunk >= space) + return 0; + p += chunk; + c++; + break; + } + case 'p': { + chunk = snprintf(p, space, "%s", mlibc::nl_langinfo((tm->tm_hour < 12) ? AM_STR : PM_STR)); + if(chunk >= space) + return 0; + p += chunk; + c++; + break; + } + case 'C': { + chunk = snprintf(p, space, "%.2d", (1900 + tm->tm_year) / 100); + if(chunk >= space) + return 0; + p += chunk; + c++; + break; + } + case 'y': { + chunk = snprintf(p, space, "%.2d", (1900 + tm->tm_year) % 100); + if(chunk >= space) + return 0; + p += chunk; + c++; + break; + } + case 'j': { + chunk = snprintf(p, space, "%.3d", tm->tm_yday + 1); + if(chunk >= space) + return 0; + p += chunk; + c++; + break; + } + case 'A': { + chunk = snprintf(p, space, "%s", mlibc::nl_langinfo(DAY_1 + tm->tm_wday)); + if(chunk >= space) + return 0; + p += chunk; + c++; + break; + } + case 'r': { + int hour = tm->tm_hour; + if(!hour) + hour = 12; + if(hour > 12) + hour -= 12; + chunk = snprintf(p, space, "%.2i:%.2i:%.2i %s", hour, tm->tm_min, tm->tm_sec, + mlibc::nl_langinfo((tm->tm_hour < 12) ? AM_STR : PM_STR)); + if(chunk >= space) + return 0; + p += chunk; + c++; + break; + } + case '%': { + chunk = snprintf(p, space, "%%"); + if(chunk >= space) + return 0; + p += chunk; + c++; + break; + } + case 't': { + chunk = snprintf(p, space, "\t"); + if(chunk >= space) + return 0; + p += chunk; + c++; + break; + } + case 'x': { + return strftime(dest, max_size, mlibc::nl_langinfo(D_FMT), tm); + } + case 'X': { + return strftime(dest, max_size, mlibc::nl_langinfo(T_FMT), tm); + } + case '\0': { + chunk = snprintf(p, space, "%%"); + if(chunk >= space) + return 0; + p += chunk; + break; + } + default: + mlibc::panicLogger() << "mlibc: strftime unknown format type: " << c << frg::endlog; + } + } + + auto space = (dest + max_size) - p; + if(!space) + return 0; + + *p = '\0'; + return (p - dest); +} + +size_t wcsftime(wchar_t *__restrict, size_t, const wchar_t *__restrict, + const struct tm *__restrict) { + mlibc::infoLogger() << "mlibc: wcsftime is a stub" << frg::endlog; + return 0; +} + +namespace { + +struct tzfile { + uint8_t magic[4]; + uint8_t version; + uint8_t reserved[15]; + uint32_t tzh_ttisgmtcnt; + uint32_t tzh_ttisstdcnt; + uint32_t tzh_leapcnt; + uint32_t tzh_timecnt; + uint32_t tzh_typecnt; + uint32_t tzh_charcnt; +}; + +struct[[gnu::packed]] ttinfo { + int32_t tt_gmtoff; + unsigned char tt_isdst; + unsigned char tt_abbrind; +}; + +} + +// TODO(geert): this function doesn't parse the TZ environment variable +// or properly handle the case where information might be missing from /etc/localtime +// also we should probably unify the code for this and unix_local_from_gmt() +void tzset(void) { + frg::unique_lock lock(__time_lock); + // TODO(geert): we can probably cache this somehow + tzfile tzfile_time; + memcpy(&tzfile_time, reinterpret_cast(get_localtime_window()->get()), sizeof(tzfile)); + tzfile_time.tzh_ttisgmtcnt = mlibc::bit_util::byteswap(tzfile_time.tzh_ttisgmtcnt); + tzfile_time.tzh_ttisstdcnt = mlibc::bit_util::byteswap(tzfile_time.tzh_ttisstdcnt); + tzfile_time.tzh_leapcnt = mlibc::bit_util::byteswap(tzfile_time.tzh_leapcnt); + tzfile_time.tzh_timecnt = mlibc::bit_util::byteswap(tzfile_time.tzh_timecnt); + tzfile_time.tzh_typecnt = mlibc::bit_util::byteswap(tzfile_time.tzh_typecnt); + tzfile_time.tzh_charcnt = mlibc::bit_util::byteswap(tzfile_time.tzh_charcnt); + + if(tzfile_time.magic[0] != 'T' || tzfile_time.magic[1] != 'Z' || tzfile_time.magic[2] != 'i' + || tzfile_time.magic[3] != 'f') { + mlibc::infoLogger() << "mlibc: /etc/localtime is not a valid TZinfo file" << frg::endlog; + return; + } + + if(tzfile_time.version != '\0' && tzfile_time.version != '2' && tzfile_time.version != '3') { + mlibc::infoLogger() << "mlibc: /etc/localtime has an invalid TZinfo version" + << frg::endlog; + return; + } + + // There should be at least one entry in the ttinfo table. + // TODO: If there is not, we might want to fall back to UTC, no DST (?). + __ensure(tzfile_time.tzh_typecnt); + + char *abbrevs = reinterpret_cast(get_localtime_window()->get()) + sizeof(tzfile) + + tzfile_time.tzh_timecnt * sizeof(int32_t) + + tzfile_time.tzh_timecnt * sizeof(uint8_t) + + tzfile_time.tzh_typecnt * sizeof(struct ttinfo); + // start from the last ttinfo entry, this matches the behaviour of glibc and musl + for (int i = tzfile_time.tzh_typecnt; i > 0; i--) { + ttinfo time_info; + memcpy(&time_info, reinterpret_cast(get_localtime_window()->get()) + sizeof(tzfile) + + tzfile_time.tzh_timecnt * sizeof(int32_t) + + tzfile_time.tzh_timecnt * sizeof(uint8_t) + + i * sizeof(ttinfo), sizeof(ttinfo)); + time_info.tt_gmtoff = mlibc::bit_util::byteswap(time_info.tt_gmtoff); + if (!time_info.tt_isdst && !tzname[0]) { + tzname[0] = abbrevs + time_info.tt_abbrind; + timezone = -time_info.tt_gmtoff; + } + if (time_info.tt_isdst && !tzname[1]) { + tzname[1] = abbrevs + time_info.tt_abbrind; + timezone = -time_info.tt_gmtoff; + daylight = 1; + } + } +} + +// POSIX extensions. + +int nanosleep(const struct timespec *req, struct timespec *) { + if (req->tv_sec < 0 || req->tv_nsec > 999999999 || req->tv_nsec < 0) { + errno = EINVAL; + return -1; + } + + if(!mlibc::sys_sleep) { + MLIBC_MISSING_SYSDEP(); + __ensure(!"Cannot continue without sys_sleep()"); + } + + struct timespec tmp = *req; + + int e = mlibc::sys_sleep(&tmp.tv_sec, &tmp.tv_nsec); + if (!e) { + return 0; + } else { + errno = e; + return -1; + } +} + +int clock_getres(clockid_t clockid, struct timespec *res) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_clock_getres, -1); + if(int e = mlibc::sys_clock_getres(clockid, &res->tv_sec, &res->tv_nsec); e) { + errno = e; + return -1; + } + return 0; +} + +int clock_gettime(clockid_t clock, struct timespec *time) { + if(int e = mlibc::sys_clock_get(clock, &time->tv_sec, &time->tv_nsec); e) { + errno = e; + return -1; + } + return 0; +} + +int clock_nanosleep(clockid_t clockid, int, const struct timespec *req, struct timespec *) { + mlibc::infoLogger() << "clock_nanosleep is implemented as nanosleep!" << frg::endlog; + __ensure(clockid == CLOCK_REALTIME || clockid == CLOCK_MONOTONIC); + return nanosleep(req, nullptr); +} + +int clock_settime(clockid_t, const struct timespec *) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +time_t time(time_t *out) { + time_t secs; + long nanos; + if(int e = mlibc::sys_clock_get(CLOCK_REALTIME, &secs, &nanos); e) { + errno = e; + return (time_t)-1; + } + if(out) + *out = secs; + return secs; +} + +namespace { + +void civil_from_days(time_t days_since_epoch, int *year, unsigned int *month, unsigned int *day) { + time_t time = days_since_epoch + 719468; + int era = (time >= 0 ? time : time - 146096) / 146097; + unsigned int doe = static_cast(time - era * 146097); + unsigned int yoe = (doe - doe/1460 + doe/36524 - doe/146096) / 365; + int y = static_cast(yoe) + era * 400; + unsigned int doy = doe - (365*yoe + yoe/4 - yoe/100); + unsigned int mp = (5*doy + 2)/153; + unsigned int d = doy - (153*mp+2)/5 + 1; + unsigned int m = mp + (mp < 10 ? 3 : -9); + + *year = y + (m <= 2); + *month = m; + *day = d; +} + +void weekday_from_days(time_t days_since_epoch, unsigned int *weekday) { + *weekday = static_cast(days_since_epoch >= -4 ? + (days_since_epoch+4) % 7 : (days_since_epoch+5) % 7 + 6); +} + +void yearday_from_date(unsigned int year, unsigned int month, unsigned int day, unsigned int *yday) { + unsigned int n1 = 275 * month / 9; + unsigned int n2 = (month + 9) / 12; + unsigned int n3 = (1 + (year - 4 * year / 4 + 2) / 3); + *yday = n1 - (n2 * n3) + day - 30; +} + +// Looks up the local time rules for a given +// UNIX GMT timestamp (seconds since 1970 GMT, ignoring leap seconds). +// This function assumes the __time_lock has been taken +// TODO(geert): if /etc/localtime isn't available this will fail... In that case +// we should call tzset() and use the variables to compute the variables from +// the tzset() global variables. Look at the musl code for how to do that +int unix_local_from_gmt(time_t unix_gmt, time_t *offset, bool *dst, char **tm_zone) { + tzfile tzfile_time; + memcpy(&tzfile_time, reinterpret_cast(get_localtime_window()->get()), sizeof(tzfile)); + tzfile_time.tzh_ttisgmtcnt = mlibc::bit_util::byteswap(tzfile_time.tzh_ttisgmtcnt); + tzfile_time.tzh_ttisstdcnt = mlibc::bit_util::byteswap(tzfile_time.tzh_ttisstdcnt); + tzfile_time.tzh_leapcnt = mlibc::bit_util::byteswap(tzfile_time.tzh_leapcnt); + tzfile_time.tzh_timecnt = mlibc::bit_util::byteswap(tzfile_time.tzh_timecnt); + tzfile_time.tzh_typecnt = mlibc::bit_util::byteswap(tzfile_time.tzh_typecnt); + tzfile_time.tzh_charcnt = mlibc::bit_util::byteswap(tzfile_time.tzh_charcnt); + + if(tzfile_time.magic[0] != 'T' || tzfile_time.magic[1] != 'Z' || tzfile_time.magic[2] != 'i' + || tzfile_time.magic[3] != 'f') { + mlibc::infoLogger() << "mlibc: /etc/localtime is not a valid TZinfo file" << frg::endlog; + return -1; + } + + if(tzfile_time.version != '\0' && tzfile_time.version != '2' && tzfile_time.version != '3') { + mlibc::infoLogger() << "mlibc: /etc/localtime has an invalid TZinfo version" + << frg::endlog; + return -1; + } + + int index = -1; + for(size_t i = 0; i < tzfile_time.tzh_timecnt; i++) { + int32_t ttime; + memcpy(&ttime, reinterpret_cast(get_localtime_window()->get()) + sizeof(tzfile) + + i * sizeof(int32_t), sizeof(int32_t)); + ttime = mlibc::bit_util::byteswap(ttime); + // If we are before the first transition, the format dicates that + // the first ttinfo entry should be used (and not the ttinfo entry pointed + // to by the first transition time). + if(i && ttime > unix_gmt) { + index = i - 1; + break; + } + } + + // The format dictates that if no transition is applicable, + // the first entry in the file is chosen. + uint8_t ttinfo_index = 0; + if(index >= 0) { + memcpy(&ttinfo_index, reinterpret_cast(get_localtime_window()->get()) + sizeof(tzfile) + + tzfile_time.tzh_timecnt * sizeof(int32_t) + + index * sizeof(uint8_t), sizeof(uint8_t)); + } + + // There should be at least one entry in the ttinfo table. + // TODO: If there is not, we might want to fall back to UTC, no DST (?). + __ensure(tzfile_time.tzh_typecnt); + + ttinfo time_info; + memcpy(&time_info, reinterpret_cast(get_localtime_window()->get()) + sizeof(tzfile) + + tzfile_time.tzh_timecnt * sizeof(int32_t) + + tzfile_time.tzh_timecnt * sizeof(uint8_t) + + ttinfo_index * sizeof(ttinfo), sizeof(ttinfo)); + time_info.tt_gmtoff = mlibc::bit_util::byteswap(time_info.tt_gmtoff); + + char *abbrevs = reinterpret_cast(get_localtime_window()->get()) + sizeof(tzfile) + + tzfile_time.tzh_timecnt * sizeof(int32_t) + + tzfile_time.tzh_timecnt * sizeof(uint8_t) + + tzfile_time.tzh_typecnt * sizeof(struct ttinfo); + + *offset = time_info.tt_gmtoff; + *dst = time_info.tt_isdst; + *tm_zone = abbrevs + time_info.tt_abbrind; + return 0; +} + +} //anonymous namespace + +struct tm *gmtime_r(const time_t *unix_gmt, struct tm *res) { + int year; + unsigned int month; + unsigned int day; + unsigned int weekday; + unsigned int yday; + + time_t unix_local = *unix_gmt; + + int days_since_epoch = unix_local / (60*60*24); + civil_from_days(days_since_epoch, &year, &month, &day); + weekday_from_days(days_since_epoch, &weekday); + yearday_from_date(year, month, day, &yday); + + res->tm_sec = unix_local % 60; + res->tm_min = (unix_local / 60) % 60; + res->tm_hour = (unix_local / (60*60)) % 24; + res->tm_mday = day; + res->tm_mon = month - 1; + res->tm_year = year - 1900; + res->tm_wday = weekday; + res->tm_yday = yday - 1; + res->tm_isdst = -1; + res->tm_zone = __utc; + res->tm_gmtoff = 0; + + return res; +} + +struct tm *localtime_r(const time_t *unix_gmt, struct tm *res) { + int year; + unsigned int month; + unsigned int day; + unsigned int weekday; + unsigned int yday; + + time_t offset = 0; + bool dst; + char *tm_zone; + frg::unique_lock lock(__time_lock); + // TODO: Set errno if the conversion fails. + if(unix_local_from_gmt(*unix_gmt, &offset, &dst, &tm_zone)) { + __ensure(!"Error parsing /etc/localtime"); + __builtin_unreachable(); + } + time_t unix_local = *unix_gmt + offset; + + int days_since_epoch = unix_local / (60*60*24); + civil_from_days(days_since_epoch, &year, &month, &day); + weekday_from_days(days_since_epoch, &weekday); + yearday_from_date(year, month, day, &yday); + + res->tm_sec = unix_local % 60; + res->tm_min = (unix_local / 60) % 60; + res->tm_hour = (unix_local / (60*60)) % 24; + res->tm_mday = day; + res->tm_mon = month - 1; + res->tm_year = year - 1900; + res->tm_wday = weekday; + res->tm_yday = yday - 1; + res->tm_isdst = dst; + res->tm_zone = tm_zone; + res->tm_gmtoff = offset; + + return res; +} + +// This implementation of asctime_r is taken from sortix +char *asctime_r(const struct tm *tm, char *buf) { + static char weekday_names[7][4] = + { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" }; + static char month_names[12][4] = + { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", + "Nov", "Dec" }; + sprintf(buf, "%.3s %.3s%3d %.2d:%.2d%.2d %d\n", + weekday_names[tm->tm_wday], + month_names[tm->tm_mon], + tm->tm_mday, + tm->tm_hour, + tm->tm_min, + tm->tm_sec, + tm->tm_year + 1900); + return buf; +} + +char *ctime_r(const time_t *clock, char *buf) { + return asctime_r(localtime(clock), buf); +} + +time_t timelocal(struct tm *) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +constexpr static int days_from_civil(int y, unsigned m, unsigned d) noexcept { + y -= m <= 2; + const int era = (y >= 0 ? y : y - 399) / 400; + const unsigned yoe = static_cast(y - era * 400); // [0, 399] + const unsigned doy = (153 * (m > 2 ? m - 3 : m + 9) + 2) / 5 + d - 1; // [0, 365] + const unsigned doe = yoe * 365 + yoe / 4 - yoe / 100 + doy; // [0, 146096] + return era * 146097 + static_cast(doe) - 719468; +} + +time_t timegm(struct tm *tm) { + time_t year = tm->tm_year + 1900; + time_t month = tm->tm_mon + 1; + time_t days = days_from_civil(year, month, tm->tm_mday); + time_t secs = (days * 86400) + (tm->tm_hour * 60 * 60) + (tm->tm_min * 60) + tm->tm_sec; + return secs; +} diff --git a/lib/mlibc/options/ansi/generic/uchar.cpp b/lib/mlibc/options/ansi/generic/uchar.cpp new file mode 100644 index 0000000..cb13c12 --- /dev/null +++ b/lib/mlibc/options/ansi/generic/uchar.cpp @@ -0,0 +1,23 @@ +#include +#include +#include + +size_t c32rtomb(char *, char32_t, mbstate_t *) MLIBC_STUB_BODY + +size_t mbrtoc32(char32_t *__restrict pc32, const char *__restrict pmb, size_t max, mbstate_t *__restrict ps) { + static mbstate_t internal_state; + + if(!ps) + ps = &internal_state; + + if(!pmb) + return mbrtoc32(0, "", 1, ps); + + wchar_t wc; + size_t ret = mbrtowc(&wc, pmb, max, ps); + + if (ret <= 4 && pc32) + *pc32 = wc; + + return ret; +} diff --git a/lib/mlibc/options/ansi/generic/wchar-stubs.cpp b/lib/mlibc/options/ansi/generic/wchar-stubs.cpp new file mode 100644 index 0000000..d9f6598 --- /dev/null +++ b/lib/mlibc/options/ansi/generic/wchar-stubs.cpp @@ -0,0 +1,783 @@ + +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace { + // All conversion functions mbrlen(), mbrtowc(), wcrtomb(), + // mbsrtowcs() and wcsrtombs() have an internal state. + __mlibc_mbstate mbrlen_state = __MLIBC_MBSTATE_INITIALIZER; + __mlibc_mbstate mbrtowc_state = __MLIBC_MBSTATE_INITIALIZER; + __mlibc_mbstate mbsrtowcs_state = __MLIBC_MBSTATE_INITIALIZER; + __mlibc_mbstate wcsrtombs_state = __MLIBC_MBSTATE_INITIALIZER; +} + +wint_t btowc(int c) { + if(c == EOF) + return WEOF; + + char nc = c; + auto cc = mlibc::current_charcode(); + wchar_t wc; + if(auto e = cc->promote_wtranscode(nc, wc); e != mlibc::charcode_error::null) + return WEOF; + return wc; +} + +int wctob(wint_t wc) { + // TODO: Revisit this once we have character encoding functions. + return wc; +} + +int mbsinit(const mbstate_t *stp) { + if(!stp) + return -1; + return !stp->__progress && !stp->__shift; +} + +size_t mbrlen(const char *mbs, size_t mb_limit, mbstate_t *stp) { + auto cc = mlibc::current_charcode(); + wchar_t wc; + + if(!stp) + stp = &mbrlen_state; + if(!mbs) { + *stp = __MLIBC_MBSTATE_INITIALIZER; + return 0; + } + + mlibc::code_seq nseq{mbs, mbs + mb_limit}; + mlibc::code_seq wseq{&wc, &wc + 1}; + if(auto e = cc->decode_wtranscode(nseq, wseq, *stp); e != mlibc::charcode_error::null) + __ensure(!"decode_wtranscode() errors are not handled"); + return nseq.it - mbs; +} + +size_t mbrtowc(wchar_t *wcp, const char *mbs, size_t mb_limit, mbstate_t *stp) { + auto cc = mlibc::current_charcode(); + + if(!stp) + stp = &mbrtowc_state; + if(!mbs) { + *stp = __MLIBC_MBSTATE_INITIALIZER; + return 0; + } + + wchar_t temp = 0; + if(!wcp) + wcp = &temp; + + mlibc::code_seq nseq{mbs, mbs + mb_limit}; + mlibc::code_seq wseq{wcp, wcp + 1}; + if(auto e = cc->decode_wtranscode(nseq, wseq, *stp); e != mlibc::charcode_error::null) { + if(e == mlibc::charcode_error::input_underflow) + return static_cast(-2); + __ensure(e == mlibc::charcode_error::illegal_input); + errno = EILSEQ; + return static_cast(-1); + }else{ + if (*mbs) { + return nseq.it - mbs; + } else { + *stp = __MLIBC_MBSTATE_INITIALIZER; + *wcp = 0; + return 0; + } + } +} + +size_t wcrtomb(char *mbs, wchar_t wc, mbstate_t *stp) { + auto cc = mlibc::current_charcode(); + + // wcrtomb() always takes a mbstate_t. + __ensure(stp); + + // TODO: Implement the following case: + __ensure(mbs); + + mlibc::code_seq wseq{&wc, &wc + 1}; + mlibc::code_seq nseq{mbs, mbs + 4}; // TODO: Replace 4 by some named constant. + if(auto e = cc->encode_wtranscode(nseq, wseq, *stp); e != mlibc::charcode_error::null) { + __ensure(!"encode_wtranscode() errors are not handled"); + __builtin_unreachable(); + }else{ + size_t n = nseq.it - mbs; + if(!n) // Null-terminate resulting wide string. + *mbs = 0; + return n; + } +} + +size_t mbsrtowcs(wchar_t *wcs, const char **mbsp, size_t wc_limit, mbstate_t *stp) { + __ensure(mbsp); + + auto cc = mlibc::current_charcode(); + __mlibc_mbstate st = __MLIBC_MBSTATE_INITIALIZER; + mlibc::code_seq nseq{*mbsp, nullptr}; + mlibc::code_seq wseq{wcs, wcs + wc_limit}; + + if(!stp) + stp = &mbsrtowcs_state; + + if(!wcs) { + size_t size; + if(auto e = cc->decode_wtranscode_length(nseq, &size, st); e != mlibc::charcode_error::null) + __ensure(!"decode_wtranscode() errors are not handled"); + return size; + } + + if(auto e = cc->decode_wtranscode(nseq, wseq, st); e != mlibc::charcode_error::null) { + __ensure(!"decode_wtranscode() errors are not handled"); + __builtin_unreachable(); + }else{ + size_t n = wseq.it - wcs; + if(n < wc_limit) // Null-terminate resulting wide string. + wcs[n] = 0; + *mbsp = nullptr; + return n; + } +} + +size_t mbsnrtowcs(wchar_t *wcs, const char **mbsp, size_t mb_limit, size_t wc_limit, mbstate_t *stp) { + __ensure(mbsp); + + auto cc = mlibc::current_charcode(); + __mlibc_mbstate st = __MLIBC_MBSTATE_INITIALIZER; + mlibc::code_seq nseq{*mbsp, (*mbsp) + mb_limit}; + mlibc::code_seq wseq{wcs, wcs + wc_limit}; + + if(!stp) + stp = &mbsrtowcs_state; + + if(!wcs) { + size_t size; + if(auto e = cc->decode_wtranscode_length(nseq, &size, st); e != mlibc::charcode_error::null) + __ensure(!"decode_wtranscode() errors are not handled"); + return size; + } + + if(auto e = cc->decode_wtranscode(nseq, wseq, st); e != mlibc::charcode_error::null) { + __ensure(!"decode_wtranscode() errors are not handled"); + __builtin_unreachable(); + }else{ + size_t n = wseq.it - wcs; + if(n < wc_limit) // Null-terminate resulting wide string. + wcs[n] = 0; + *mbsp = nullptr; + return n; + } +} + +size_t wcsrtombs(char *mbs, const wchar_t **wcsp, size_t mb_limit, mbstate_t *stp) { + __ensure(wcsp && "wcsrtombs() with null input"); + auto cc = mlibc::current_charcode(); + mlibc::code_seq nseq{mbs, mbs + mb_limit}; + mlibc::code_seq wseq{*wcsp, nullptr}; + + if(!stp) + stp = &wcsrtombs_state; + + if(!mbs) { + size_t size; + if(auto e = cc->encode_wtranscode_length(wseq, &size, *stp); e != mlibc::charcode_error::null) + __ensure(!"decode_wtranscode() errors are not handled"); + return size; + } + + if(auto e = cc->encode_wtranscode(nseq, wseq, *stp); e != mlibc::charcode_error::null) { + __ensure(!"encode_wtranscode() errors are not handled"); + __builtin_unreachable(); + }else{ + *wcsp = wseq.it; + size_t n = nseq.it - mbs; + if(n < mb_limit) // Null-terminate resulting narrow string. + mbs[n] = 0; + return n; + } +} + +size_t wcsnrtombs(char *mbs, const wchar_t **wcsp, size_t wc_limit, size_t mb_limit, mbstate_t *stp) { + __ensure(wcsp && "wcsrtombs() with null input"); + auto cc = mlibc::current_charcode(); + mlibc::code_seq nseq{mbs, mbs + mb_limit}; + mlibc::code_seq wseq{*wcsp, (*wcsp) + wc_limit}; + + if(!stp) + stp = &wcsrtombs_state; + + if(!mbs) { + size_t size; + if(auto e = cc->encode_wtranscode_length(wseq, &size, *stp); e != mlibc::charcode_error::null) + __ensure(!"decode_wtranscode() errors are not handled"); + return size; + } + + if(auto e = cc->encode_wtranscode(nseq, wseq, *stp); e != mlibc::charcode_error::null) { + __ensure(!"encode_wtranscode() errors are not handled"); + __builtin_unreachable(); + }else{ + *wcsp = wseq.it; + size_t n = nseq.it - mbs; + if(n < mb_limit) // Null-terminate resulting narrow string. + mbs[n] = 0; + return n; + } +} + +/* + * The code in this anonymous namespace and the wcwidth function below + * are taken from https://github.com/termux/wcwidth/, under the following license: + * + * Copyright (C) Fredrik Fornwall 2016. + * Distributed under the MIT License. + * + * Implementation of wcwidth(3) as a C port of: + * https://github.com/jquast/wcwidth + * + * Report issues at: + * https://github.com/termux/wcwidth + */ + +namespace { + +struct width_interval { + int start; + int end; +}; + +// From https://github.com/jquast/wcwidth/blob/master/wcwidth/table_zero.py +// at commit b29897e5a1b403a0e36f7fc991614981cbc42475 (2020-07-14): +struct width_interval ZERO_WIDTH[] = { + {0x00300, 0x0036f}, // Combining Grave Accent ..Combining Latin Small Le + {0x00483, 0x00489}, // Combining Cyrillic Titlo..Combining Cyrillic Milli + {0x00591, 0x005bd}, // Hebrew Accent Etnahta ..Hebrew Point Meteg + {0x005bf, 0x005bf}, // Hebrew Point Rafe ..Hebrew Point Rafe + {0x005c1, 0x005c2}, // Hebrew Point Shin Dot ..Hebrew Point Sin Dot + {0x005c4, 0x005c5}, // Hebrew Mark Upper Dot ..Hebrew Mark Lower Dot + {0x005c7, 0x005c7}, // Hebrew Point Qamats Qata..Hebrew Point Qamats Qata + {0x00610, 0x0061a}, // Arabic Sign Sallallahou ..Arabic Small Kasra + {0x0064b, 0x0065f}, // Arabic Fathatan ..Arabic Wavy Hamza Below + {0x00670, 0x00670}, // Arabic Letter Superscrip..Arabic Letter Superscrip + {0x006d6, 0x006dc}, // Arabic Small High Ligatu..Arabic Small High Seen + {0x006df, 0x006e4}, // Arabic Small High Rounde..Arabic Small High Madda + {0x006e7, 0x006e8}, // Arabic Small High Yeh ..Arabic Small High Noon + {0x006ea, 0x006ed}, // Arabic Empty Centre Low ..Arabic Small Low Meem + {0x00711, 0x00711}, // Syriac Letter Superscrip..Syriac Letter Superscrip + {0x00730, 0x0074a}, // Syriac Pthaha Above ..Syriac Barrekh + {0x007a6, 0x007b0}, // Thaana Abafili ..Thaana Sukun + {0x007eb, 0x007f3}, // Nko Combining Short High..Nko Combining Double Dot + {0x007fd, 0x007fd}, // Nko Dantayalan ..Nko Dantayalan + {0x00816, 0x00819}, // Samaritan Mark In ..Samaritan Mark Dagesh + {0x0081b, 0x00823}, // Samaritan Mark Epentheti..Samaritan Vowel Sign A + {0x00825, 0x00827}, // Samaritan Vowel Sign Sho..Samaritan Vowel Sign U + {0x00829, 0x0082d}, // Samaritan Vowel Sign Lon..Samaritan Mark Nequdaa + {0x00859, 0x0085b}, // Mandaic Affrication Mark..Mandaic Gemination Mark + {0x008d3, 0x008e1}, // Arabic Small Low Waw ..Arabic Small High Sign S + {0x008e3, 0x00902}, // Arabic Turned Damma Belo..Devanagari Sign Anusvara + {0x0093a, 0x0093a}, // Devanagari Vowel Sign Oe..Devanagari Vowel Sign Oe + {0x0093c, 0x0093c}, // Devanagari Sign Nukta ..Devanagari Sign Nukta + {0x00941, 0x00948}, // Devanagari Vowel Sign U ..Devanagari Vowel Sign Ai + {0x0094d, 0x0094d}, // Devanagari Sign Virama ..Devanagari Sign Virama + {0x00951, 0x00957}, // Devanagari Stress Sign U..Devanagari Vowel Sign Uu + {0x00962, 0x00963}, // Devanagari Vowel Sign Vo..Devanagari Vowel Sign Vo + {0x00981, 0x00981}, // Bengali Sign Candrabindu..Bengali Sign Candrabindu + {0x009bc, 0x009bc}, // Bengali Sign Nukta ..Bengali Sign Nukta + {0x009c1, 0x009c4}, // Bengali Vowel Sign U ..Bengali Vowel Sign Vocal + {0x009cd, 0x009cd}, // Bengali Sign Virama ..Bengali Sign Virama + {0x009e2, 0x009e3}, // Bengali Vowel Sign Vocal..Bengali Vowel Sign Vocal + {0x009fe, 0x009fe}, // Bengali Sandhi Mark ..Bengali Sandhi Mark + {0x00a01, 0x00a02}, // Gurmukhi Sign Adak Bindi..Gurmukhi Sign Bindi + {0x00a3c, 0x00a3c}, // Gurmukhi Sign Nukta ..Gurmukhi Sign Nukta + {0x00a41, 0x00a42}, // Gurmukhi Vowel Sign U ..Gurmukhi Vowel Sign Uu + {0x00a47, 0x00a48}, // Gurmukhi Vowel Sign Ee ..Gurmukhi Vowel Sign Ai + {0x00a4b, 0x00a4d}, // Gurmukhi Vowel Sign Oo ..Gurmukhi Sign Virama + {0x00a51, 0x00a51}, // Gurmukhi Sign Udaat ..Gurmukhi Sign Udaat + {0x00a70, 0x00a71}, // Gurmukhi Tippi ..Gurmukhi Addak + {0x00a75, 0x00a75}, // Gurmukhi Sign Yakash ..Gurmukhi Sign Yakash + {0x00a81, 0x00a82}, // Gujarati Sign Candrabind..Gujarati Sign Anusvara + {0x00abc, 0x00abc}, // Gujarati Sign Nukta ..Gujarati Sign Nukta + {0x00ac1, 0x00ac5}, // Gujarati Vowel Sign U ..Gujarati Vowel Sign Cand + {0x00ac7, 0x00ac8}, // Gujarati Vowel Sign E ..Gujarati Vowel Sign Ai + {0x00acd, 0x00acd}, // Gujarati Sign Virama ..Gujarati Sign Virama + {0x00ae2, 0x00ae3}, // Gujarati Vowel Sign Voca..Gujarati Vowel Sign Voca + {0x00afa, 0x00aff}, // Gujarati Sign Sukun ..Gujarati Sign Two-circle + {0x00b01, 0x00b01}, // Oriya Sign Candrabindu ..Oriya Sign Candrabindu + {0x00b3c, 0x00b3c}, // Oriya Sign Nukta ..Oriya Sign Nukta + {0x00b3f, 0x00b3f}, // Oriya Vowel Sign I ..Oriya Vowel Sign I + {0x00b41, 0x00b44}, // Oriya Vowel Sign U ..Oriya Vowel Sign Vocalic + {0x00b4d, 0x00b4d}, // Oriya Sign Virama ..Oriya Sign Virama + {0x00b55, 0x00b56}, // (nil) ..Oriya Ai Length Mark + {0x00b62, 0x00b63}, // Oriya Vowel Sign Vocalic..Oriya Vowel Sign Vocalic + {0x00b82, 0x00b82}, // Tamil Sign Anusvara ..Tamil Sign Anusvara + {0x00bc0, 0x00bc0}, // Tamil Vowel Sign Ii ..Tamil Vowel Sign Ii + {0x00bcd, 0x00bcd}, // Tamil Sign Virama ..Tamil Sign Virama + {0x00c00, 0x00c00}, // Telugu Sign Combining Ca..Telugu Sign Combining Ca + {0x00c04, 0x00c04}, // Telugu Sign Combining An..Telugu Sign Combining An + {0x00c3e, 0x00c40}, // Telugu Vowel Sign Aa ..Telugu Vowel Sign Ii + {0x00c46, 0x00c48}, // Telugu Vowel Sign E ..Telugu Vowel Sign Ai + {0x00c4a, 0x00c4d}, // Telugu Vowel Sign O ..Telugu Sign Virama + {0x00c55, 0x00c56}, // Telugu Length Mark ..Telugu Ai Length Mark + {0x00c62, 0x00c63}, // Telugu Vowel Sign Vocali..Telugu Vowel Sign Vocali + {0x00c81, 0x00c81}, // Kannada Sign Candrabindu..Kannada Sign Candrabindu + {0x00cbc, 0x00cbc}, // Kannada Sign Nukta ..Kannada Sign Nukta + {0x00cbf, 0x00cbf}, // Kannada Vowel Sign I ..Kannada Vowel Sign I + {0x00cc6, 0x00cc6}, // Kannada Vowel Sign E ..Kannada Vowel Sign E + {0x00ccc, 0x00ccd}, // Kannada Vowel Sign Au ..Kannada Sign Virama + {0x00ce2, 0x00ce3}, // Kannada Vowel Sign Vocal..Kannada Vowel Sign Vocal + {0x00d00, 0x00d01}, // Malayalam Sign Combining..Malayalam Sign Candrabin + {0x00d3b, 0x00d3c}, // Malayalam Sign Vertical ..Malayalam Sign Circular + {0x00d41, 0x00d44}, // Malayalam Vowel Sign U ..Malayalam Vowel Sign Voc + {0x00d4d, 0x00d4d}, // Malayalam Sign Virama ..Malayalam Sign Virama + {0x00d62, 0x00d63}, // Malayalam Vowel Sign Voc..Malayalam Vowel Sign Voc + {0x00d81, 0x00d81}, // (nil) ..(nil) + {0x00dca, 0x00dca}, // Sinhala Sign Al-lakuna ..Sinhala Sign Al-lakuna + {0x00dd2, 0x00dd4}, // Sinhala Vowel Sign Ketti..Sinhala Vowel Sign Ketti + {0x00dd6, 0x00dd6}, // Sinhala Vowel Sign Diga ..Sinhala Vowel Sign Diga + {0x00e31, 0x00e31}, // Thai Character Mai Han-a..Thai Character Mai Han-a + {0x00e34, 0x00e3a}, // Thai Character Sara I ..Thai Character Phinthu + {0x00e47, 0x00e4e}, // Thai Character Maitaikhu..Thai Character Yamakkan + {0x00eb1, 0x00eb1}, // Lao Vowel Sign Mai Kan ..Lao Vowel Sign Mai Kan + {0x00eb4, 0x00ebc}, // Lao Vowel Sign I ..Lao Semivowel Sign Lo + {0x00ec8, 0x00ecd}, // Lao Tone Mai Ek ..Lao Niggahita + {0x00f18, 0x00f19}, // Tibetan Astrological Sig..Tibetan Astrological Sig + {0x00f35, 0x00f35}, // Tibetan Mark Ngas Bzung ..Tibetan Mark Ngas Bzung + {0x00f37, 0x00f37}, // Tibetan Mark Ngas Bzung ..Tibetan Mark Ngas Bzung + {0x00f39, 0x00f39}, // Tibetan Mark Tsa -phru ..Tibetan Mark Tsa -phru + {0x00f71, 0x00f7e}, // Tibetan Vowel Sign Aa ..Tibetan Sign Rjes Su Nga + {0x00f80, 0x00f84}, // Tibetan Vowel Sign Rever..Tibetan Mark Halanta + {0x00f86, 0x00f87}, // Tibetan Sign Lci Rtags ..Tibetan Sign Yang Rtags + {0x00f8d, 0x00f97}, // Tibetan Subjoined Sign L..Tibetan Subjoined Letter + {0x00f99, 0x00fbc}, // Tibetan Subjoined Letter..Tibetan Subjoined Letter + {0x00fc6, 0x00fc6}, // Tibetan Symbol Padma Gda..Tibetan Symbol Padma Gda + {0x0102d, 0x01030}, // Myanmar Vowel Sign I ..Myanmar Vowel Sign Uu + {0x01032, 0x01037}, // Myanmar Vowel Sign Ai ..Myanmar Sign Dot Below + {0x01039, 0x0103a}, // Myanmar Sign Virama ..Myanmar Sign Asat + {0x0103d, 0x0103e}, // Myanmar Consonant Sign M..Myanmar Consonant Sign M + {0x01058, 0x01059}, // Myanmar Vowel Sign Vocal..Myanmar Vowel Sign Vocal + {0x0105e, 0x01060}, // Myanmar Consonant Sign M..Myanmar Consonant Sign M + {0x01071, 0x01074}, // Myanmar Vowel Sign Geba ..Myanmar Vowel Sign Kayah + {0x01082, 0x01082}, // Myanmar Consonant Sign S..Myanmar Consonant Sign S + {0x01085, 0x01086}, // Myanmar Vowel Sign Shan ..Myanmar Vowel Sign Shan + {0x0108d, 0x0108d}, // Myanmar Sign Shan Counci..Myanmar Sign Shan Counci + {0x0109d, 0x0109d}, // Myanmar Vowel Sign Aiton..Myanmar Vowel Sign Aiton + {0x0135d, 0x0135f}, // Ethiopic Combining Gemin..Ethiopic Combining Gemin + {0x01712, 0x01714}, // Tagalog Vowel Sign I ..Tagalog Sign Virama + {0x01732, 0x01734}, // Hanunoo Vowel Sign I ..Hanunoo Sign Pamudpod + {0x01752, 0x01753}, // Buhid Vowel Sign I ..Buhid Vowel Sign U + {0x01772, 0x01773}, // Tagbanwa Vowel Sign I ..Tagbanwa Vowel Sign U + {0x017b4, 0x017b5}, // Khmer Vowel Inherent Aq ..Khmer Vowel Inherent Aa + {0x017b7, 0x017bd}, // Khmer Vowel Sign I ..Khmer Vowel Sign Ua + {0x017c6, 0x017c6}, // Khmer Sign Nikahit ..Khmer Sign Nikahit + {0x017c9, 0x017d3}, // Khmer Sign Muusikatoan ..Khmer Sign Bathamasat + {0x017dd, 0x017dd}, // Khmer Sign Atthacan ..Khmer Sign Atthacan + {0x0180b, 0x0180d}, // Mongolian Free Variation..Mongolian Free Variation + {0x01885, 0x01886}, // Mongolian Letter Ali Gal..Mongolian Letter Ali Gal + {0x018a9, 0x018a9}, // Mongolian Letter Ali Gal..Mongolian Letter Ali Gal + {0x01920, 0x01922}, // Limbu Vowel Sign A ..Limbu Vowel Sign U + {0x01927, 0x01928}, // Limbu Vowel Sign E ..Limbu Vowel Sign O + {0x01932, 0x01932}, // Limbu Small Letter Anusv..Limbu Small Letter Anusv + {0x01939, 0x0193b}, // Limbu Sign Mukphreng ..Limbu Sign Sa-i + {0x01a17, 0x01a18}, // Buginese Vowel Sign I ..Buginese Vowel Sign U + {0x01a1b, 0x01a1b}, // Buginese Vowel Sign Ae ..Buginese Vowel Sign Ae + {0x01a56, 0x01a56}, // Tai Tham Consonant Sign ..Tai Tham Consonant Sign + {0x01a58, 0x01a5e}, // Tai Tham Sign Mai Kang L..Tai Tham Consonant Sign + {0x01a60, 0x01a60}, // Tai Tham Sign Sakot ..Tai Tham Sign Sakot + {0x01a62, 0x01a62}, // Tai Tham Vowel Sign Mai ..Tai Tham Vowel Sign Mai + {0x01a65, 0x01a6c}, // Tai Tham Vowel Sign I ..Tai Tham Vowel Sign Oa B + {0x01a73, 0x01a7c}, // Tai Tham Vowel Sign Oa A..Tai Tham Sign Khuen-lue + {0x01a7f, 0x01a7f}, // Tai Tham Combining Crypt..Tai Tham Combining Crypt + {0x01ab0, 0x01ac0}, // Combining Doubled Circum..(nil) + {0x01b00, 0x01b03}, // Balinese Sign Ulu Ricem ..Balinese Sign Surang + {0x01b34, 0x01b34}, // Balinese Sign Rerekan ..Balinese Sign Rerekan + {0x01b36, 0x01b3a}, // Balinese Vowel Sign Ulu ..Balinese Vowel Sign Ra R + {0x01b3c, 0x01b3c}, // Balinese Vowel Sign La L..Balinese Vowel Sign La L + {0x01b42, 0x01b42}, // Balinese Vowel Sign Pepe..Balinese Vowel Sign Pepe + {0x01b6b, 0x01b73}, // Balinese Musical Symbol ..Balinese Musical Symbol + {0x01b80, 0x01b81}, // Sundanese Sign Panyecek ..Sundanese Sign Panglayar + {0x01ba2, 0x01ba5}, // Sundanese Consonant Sign..Sundanese Vowel Sign Pan + {0x01ba8, 0x01ba9}, // Sundanese Vowel Sign Pam..Sundanese Vowel Sign Pan + {0x01bab, 0x01bad}, // Sundanese Sign Virama ..Sundanese Consonant Sign + {0x01be6, 0x01be6}, // Batak Sign Tompi ..Batak Sign Tompi + {0x01be8, 0x01be9}, // Batak Vowel Sign Pakpak ..Batak Vowel Sign Ee + {0x01bed, 0x01bed}, // Batak Vowel Sign Karo O ..Batak Vowel Sign Karo O + {0x01bef, 0x01bf1}, // Batak Vowel Sign U For S..Batak Consonant Sign H + {0x01c2c, 0x01c33}, // Lepcha Vowel Sign E ..Lepcha Consonant Sign T + {0x01c36, 0x01c37}, // Lepcha Sign Ran ..Lepcha Sign Nukta + {0x01cd0, 0x01cd2}, // Vedic Tone Karshana ..Vedic Tone Prenkha + {0x01cd4, 0x01ce0}, // Vedic Sign Yajurvedic Mi..Vedic Tone Rigvedic Kash + {0x01ce2, 0x01ce8}, // Vedic Sign Visarga Svari..Vedic Sign Visarga Anuda + {0x01ced, 0x01ced}, // Vedic Sign Tiryak ..Vedic Sign Tiryak + {0x01cf4, 0x01cf4}, // Vedic Tone Candra Above ..Vedic Tone Candra Above + {0x01cf8, 0x01cf9}, // Vedic Tone Ring Above ..Vedic Tone Double Ring A + {0x01dc0, 0x01df9}, // Combining Dotted Grave A..Combining Wide Inverted + {0x01dfb, 0x01dff}, // Combining Deletion Mark ..Combining Right Arrowhea + {0x020d0, 0x020f0}, // Combining Left Harpoon A..Combining Asterisk Above + {0x02cef, 0x02cf1}, // Coptic Combining Ni Abov..Coptic Combining Spiritu + {0x02d7f, 0x02d7f}, // Tifinagh Consonant Joine..Tifinagh Consonant Joine + {0x02de0, 0x02dff}, // Combining Cyrillic Lette..Combining Cyrillic Lette + {0x0302a, 0x0302d}, // Ideographic Level Tone M..Ideographic Entering Ton + {0x03099, 0x0309a}, // Combining Katakana-hirag..Combining Katakana-hirag + {0x0a66f, 0x0a672}, // Combining Cyrillic Vzmet..Combining Cyrillic Thous + {0x0a674, 0x0a67d}, // Combining Cyrillic Lette..Combining Cyrillic Payer + {0x0a69e, 0x0a69f}, // Combining Cyrillic Lette..Combining Cyrillic Lette + {0x0a6f0, 0x0a6f1}, // Bamum Combining Mark Koq..Bamum Combining Mark Tuk + {0x0a802, 0x0a802}, // Syloti Nagri Sign Dvisva..Syloti Nagri Sign Dvisva + {0x0a806, 0x0a806}, // Syloti Nagri Sign Hasant..Syloti Nagri Sign Hasant + {0x0a80b, 0x0a80b}, // Syloti Nagri Sign Anusva..Syloti Nagri Sign Anusva + {0x0a825, 0x0a826}, // Syloti Nagri Vowel Sign ..Syloti Nagri Vowel Sign + {0x0a82c, 0x0a82c}, // (nil) ..(nil) + {0x0a8c4, 0x0a8c5}, // Saurashtra Sign Virama ..Saurashtra Sign Candrabi + {0x0a8e0, 0x0a8f1}, // Combining Devanagari Dig..Combining Devanagari Sig + {0x0a8ff, 0x0a8ff}, // Devanagari Vowel Sign Ay..Devanagari Vowel Sign Ay + {0x0a926, 0x0a92d}, // Kayah Li Vowel Ue ..Kayah Li Tone Calya Plop + {0x0a947, 0x0a951}, // Rejang Vowel Sign I ..Rejang Consonant Sign R + {0x0a980, 0x0a982}, // Javanese Sign Panyangga ..Javanese Sign Layar + {0x0a9b3, 0x0a9b3}, // Javanese Sign Cecak Telu..Javanese Sign Cecak Telu + {0x0a9b6, 0x0a9b9}, // Javanese Vowel Sign Wulu..Javanese Vowel Sign Suku + {0x0a9bc, 0x0a9bd}, // Javanese Vowel Sign Pepe..Javanese Consonant Sign + {0x0a9e5, 0x0a9e5}, // Myanmar Sign Shan Saw ..Myanmar Sign Shan Saw + {0x0aa29, 0x0aa2e}, // Cham Vowel Sign Aa ..Cham Vowel Sign Oe + {0x0aa31, 0x0aa32}, // Cham Vowel Sign Au ..Cham Vowel Sign Ue + {0x0aa35, 0x0aa36}, // Cham Consonant Sign La ..Cham Consonant Sign Wa + {0x0aa43, 0x0aa43}, // Cham Consonant Sign Fina..Cham Consonant Sign Fina + {0x0aa4c, 0x0aa4c}, // Cham Consonant Sign Fina..Cham Consonant Sign Fina + {0x0aa7c, 0x0aa7c}, // Myanmar Sign Tai Laing T..Myanmar Sign Tai Laing T + {0x0aab0, 0x0aab0}, // Tai Viet Mai Kang ..Tai Viet Mai Kang + {0x0aab2, 0x0aab4}, // Tai Viet Vowel I ..Tai Viet Vowel U + {0x0aab7, 0x0aab8}, // Tai Viet Mai Khit ..Tai Viet Vowel Ia + {0x0aabe, 0x0aabf}, // Tai Viet Vowel Am ..Tai Viet Tone Mai Ek + {0x0aac1, 0x0aac1}, // Tai Viet Tone Mai Tho ..Tai Viet Tone Mai Tho + {0x0aaec, 0x0aaed}, // Meetei Mayek Vowel Sign ..Meetei Mayek Vowel Sign + {0x0aaf6, 0x0aaf6}, // Meetei Mayek Virama ..Meetei Mayek Virama + {0x0abe5, 0x0abe5}, // Meetei Mayek Vowel Sign ..Meetei Mayek Vowel Sign + {0x0abe8, 0x0abe8}, // Meetei Mayek Vowel Sign ..Meetei Mayek Vowel Sign + {0x0abed, 0x0abed}, // Meetei Mayek Apun Iyek ..Meetei Mayek Apun Iyek + {0x0fb1e, 0x0fb1e}, // Hebrew Point Judeo-spani..Hebrew Point Judeo-spani + {0x0fe00, 0x0fe0f}, // Variation Selector-1 ..Variation Selector-16 + {0x0fe20, 0x0fe2f}, // Combining Ligature Left ..Combining Cyrillic Titlo + {0x101fd, 0x101fd}, // Phaistos Disc Sign Combi..Phaistos Disc Sign Combi + {0x102e0, 0x102e0}, // Coptic Epact Thousands M..Coptic Epact Thousands M + {0x10376, 0x1037a}, // Combining Old Permic Let..Combining Old Permic Let + {0x10a01, 0x10a03}, // Kharoshthi Vowel Sign I ..Kharoshthi Vowel Sign Vo + {0x10a05, 0x10a06}, // Kharoshthi Vowel Sign E ..Kharoshthi Vowel Sign O + {0x10a0c, 0x10a0f}, // Kharoshthi Vowel Length ..Kharoshthi Sign Visarga + {0x10a38, 0x10a3a}, // Kharoshthi Sign Bar Abov..Kharoshthi Sign Dot Belo + {0x10a3f, 0x10a3f}, // Kharoshthi Virama ..Kharoshthi Virama + {0x10ae5, 0x10ae6}, // Manichaean Abbreviation ..Manichaean Abbreviation + {0x10d24, 0x10d27}, // Hanifi Rohingya Sign Har..Hanifi Rohingya Sign Tas + {0x10eab, 0x10eac}, // (nil) ..(nil) + {0x10f46, 0x10f50}, // Sogdian Combining Dot Be..Sogdian Combining Stroke + {0x11001, 0x11001}, // Brahmi Sign Anusvara ..Brahmi Sign Anusvara + {0x11038, 0x11046}, // Brahmi Vowel Sign Aa ..Brahmi Virama + {0x1107f, 0x11081}, // Brahmi Number Joiner ..Kaithi Sign Anusvara + {0x110b3, 0x110b6}, // Kaithi Vowel Sign U ..Kaithi Vowel Sign Ai + {0x110b9, 0x110ba}, // Kaithi Sign Virama ..Kaithi Sign Nukta + {0x11100, 0x11102}, // Chakma Sign Candrabindu ..Chakma Sign Visarga + {0x11127, 0x1112b}, // Chakma Vowel Sign A ..Chakma Vowel Sign Uu + {0x1112d, 0x11134}, // Chakma Vowel Sign Ai ..Chakma Maayyaa + {0x11173, 0x11173}, // Mahajani Sign Nukta ..Mahajani Sign Nukta + {0x11180, 0x11181}, // Sharada Sign Candrabindu..Sharada Sign Anusvara + {0x111b6, 0x111be}, // Sharada Vowel Sign U ..Sharada Vowel Sign O + {0x111c9, 0x111cc}, // Sharada Sandhi Mark ..Sharada Extra Short Vowe + {0x111cf, 0x111cf}, // (nil) ..(nil) + {0x1122f, 0x11231}, // Khojki Vowel Sign U ..Khojki Vowel Sign Ai + {0x11234, 0x11234}, // Khojki Sign Anusvara ..Khojki Sign Anusvara + {0x11236, 0x11237}, // Khojki Sign Nukta ..Khojki Sign Shadda + {0x1123e, 0x1123e}, // Khojki Sign Sukun ..Khojki Sign Sukun + {0x112df, 0x112df}, // Khudawadi Sign Anusvara ..Khudawadi Sign Anusvara + {0x112e3, 0x112ea}, // Khudawadi Vowel Sign U ..Khudawadi Sign Virama + {0x11300, 0x11301}, // Grantha Sign Combining A..Grantha Sign Candrabindu + {0x1133b, 0x1133c}, // Combining Bindu Below ..Grantha Sign Nukta + {0x11340, 0x11340}, // Grantha Vowel Sign Ii ..Grantha Vowel Sign Ii + {0x11366, 0x1136c}, // Combining Grantha Digit ..Combining Grantha Digit + {0x11370, 0x11374}, // Combining Grantha Letter..Combining Grantha Letter + {0x11438, 0x1143f}, // Newa Vowel Sign U ..Newa Vowel Sign Ai + {0x11442, 0x11444}, // Newa Sign Virama ..Newa Sign Anusvara + {0x11446, 0x11446}, // Newa Sign Nukta ..Newa Sign Nukta + {0x1145e, 0x1145e}, // Newa Sandhi Mark ..Newa Sandhi Mark + {0x114b3, 0x114b8}, // Tirhuta Vowel Sign U ..Tirhuta Vowel Sign Vocal + {0x114ba, 0x114ba}, // Tirhuta Vowel Sign Short..Tirhuta Vowel Sign Short + {0x114bf, 0x114c0}, // Tirhuta Sign Candrabindu..Tirhuta Sign Anusvara + {0x114c2, 0x114c3}, // Tirhuta Sign Virama ..Tirhuta Sign Nukta + {0x115b2, 0x115b5}, // Siddham Vowel Sign U ..Siddham Vowel Sign Vocal + {0x115bc, 0x115bd}, // Siddham Sign Candrabindu..Siddham Sign Anusvara + {0x115bf, 0x115c0}, // Siddham Sign Virama ..Siddham Sign Nukta + {0x115dc, 0x115dd}, // Siddham Vowel Sign Alter..Siddham Vowel Sign Alter + {0x11633, 0x1163a}, // Modi Vowel Sign U ..Modi Vowel Sign Ai + {0x1163d, 0x1163d}, // Modi Sign Anusvara ..Modi Sign Anusvara + {0x1163f, 0x11640}, // Modi Sign Virama ..Modi Sign Ardhacandra + {0x116ab, 0x116ab}, // Takri Sign Anusvara ..Takri Sign Anusvara + {0x116ad, 0x116ad}, // Takri Vowel Sign Aa ..Takri Vowel Sign Aa + {0x116b0, 0x116b5}, // Takri Vowel Sign U ..Takri Vowel Sign Au + {0x116b7, 0x116b7}, // Takri Sign Nukta ..Takri Sign Nukta + {0x1171d, 0x1171f}, // Ahom Consonant Sign Medi..Ahom Consonant Sign Medi + {0x11722, 0x11725}, // Ahom Vowel Sign I ..Ahom Vowel Sign Uu + {0x11727, 0x1172b}, // Ahom Vowel Sign Aw ..Ahom Sign Killer + {0x1182f, 0x11837}, // Dogra Vowel Sign U ..Dogra Sign Anusvara + {0x11839, 0x1183a}, // Dogra Sign Virama ..Dogra Sign Nukta + {0x1193b, 0x1193c}, // (nil) ..(nil) + {0x1193e, 0x1193e}, // (nil) ..(nil) + {0x11943, 0x11943}, // (nil) ..(nil) + {0x119d4, 0x119d7}, // Nandinagari Vowel Sign U..Nandinagari Vowel Sign V + {0x119da, 0x119db}, // Nandinagari Vowel Sign E..Nandinagari Vowel Sign A + {0x119e0, 0x119e0}, // Nandinagari Sign Virama ..Nandinagari Sign Virama + {0x11a01, 0x11a0a}, // Zanabazar Square Vowel S..Zanabazar Square Vowel L + {0x11a33, 0x11a38}, // Zanabazar Square Final C..Zanabazar Square Sign An + {0x11a3b, 0x11a3e}, // Zanabazar Square Cluster..Zanabazar Square Cluster + {0x11a47, 0x11a47}, // Zanabazar Square Subjoin..Zanabazar Square Subjoin + {0x11a51, 0x11a56}, // Soyombo Vowel Sign I ..Soyombo Vowel Sign Oe + {0x11a59, 0x11a5b}, // Soyombo Vowel Sign Vocal..Soyombo Vowel Length Mar + {0x11a8a, 0x11a96}, // Soyombo Final Consonant ..Soyombo Sign Anusvara + {0x11a98, 0x11a99}, // Soyombo Gemination Mark ..Soyombo Subjoiner + {0x11c30, 0x11c36}, // Bhaiksuki Vowel Sign I ..Bhaiksuki Vowel Sign Voc + {0x11c38, 0x11c3d}, // Bhaiksuki Vowel Sign E ..Bhaiksuki Sign Anusvara + {0x11c3f, 0x11c3f}, // Bhaiksuki Sign Virama ..Bhaiksuki Sign Virama + {0x11c92, 0x11ca7}, // Marchen Subjoined Letter..Marchen Subjoined Letter + {0x11caa, 0x11cb0}, // Marchen Subjoined Letter..Marchen Vowel Sign Aa + {0x11cb2, 0x11cb3}, // Marchen Vowel Sign U ..Marchen Vowel Sign E + {0x11cb5, 0x11cb6}, // Marchen Sign Anusvara ..Marchen Sign Candrabindu + {0x11d31, 0x11d36}, // Masaram Gondi Vowel Sign..Masaram Gondi Vowel Sign + {0x11d3a, 0x11d3a}, // Masaram Gondi Vowel Sign..Masaram Gondi Vowel Sign + {0x11d3c, 0x11d3d}, // Masaram Gondi Vowel Sign..Masaram Gondi Vowel Sign + {0x11d3f, 0x11d45}, // Masaram Gondi Vowel Sign..Masaram Gondi Virama + {0x11d47, 0x11d47}, // Masaram Gondi Ra-kara ..Masaram Gondi Ra-kara + {0x11d90, 0x11d91}, // Gunjala Gondi Vowel Sign..Gunjala Gondi Vowel Sign + {0x11d95, 0x11d95}, // Gunjala Gondi Sign Anusv..Gunjala Gondi Sign Anusv + {0x11d97, 0x11d97}, // Gunjala Gondi Virama ..Gunjala Gondi Virama + {0x11ef3, 0x11ef4}, // Makasar Vowel Sign I ..Makasar Vowel Sign U + {0x16af0, 0x16af4}, // Bassa Vah Combining High..Bassa Vah Combining High + {0x16b30, 0x16b36}, // Pahawh Hmong Mark Cim Tu..Pahawh Hmong Mark Cim Ta + {0x16f4f, 0x16f4f}, // Miao Sign Consonant Modi..Miao Sign Consonant Modi + {0x16f8f, 0x16f92}, // Miao Tone Right ..Miao Tone Below + {0x16fe4, 0x16fe4}, // (nil) ..(nil) + {0x1bc9d, 0x1bc9e}, // Duployan Thick Letter Se..Duployan Double Mark + {0x1d167, 0x1d169}, // Musical Symbol Combining..Musical Symbol Combining + {0x1d17b, 0x1d182}, // Musical Symbol Combining..Musical Symbol Combining + {0x1d185, 0x1d18b}, // Musical Symbol Combining..Musical Symbol Combining + {0x1d1aa, 0x1d1ad}, // Musical Symbol Combining..Musical Symbol Combining + {0x1d242, 0x1d244}, // Combining Greek Musical ..Combining Greek Musical + {0x1da00, 0x1da36}, // Signwriting Head Rim ..Signwriting Air Sucking + {0x1da3b, 0x1da6c}, // Signwriting Mouth Closed..Signwriting Excitement + {0x1da75, 0x1da75}, // Signwriting Upper Body T..Signwriting Upper Body T + {0x1da84, 0x1da84}, // Signwriting Location Hea..Signwriting Location Hea + {0x1da9b, 0x1da9f}, // Signwriting Fill Modifie..Signwriting Fill Modifie + {0x1daa1, 0x1daaf}, // Signwriting Rotation Mod..Signwriting Rotation Mod + {0x1e000, 0x1e006}, // Combining Glagolitic Let..Combining Glagolitic Let + {0x1e008, 0x1e018}, // Combining Glagolitic Let..Combining Glagolitic Let + {0x1e01b, 0x1e021}, // Combining Glagolitic Let..Combining Glagolitic Let + {0x1e023, 0x1e024}, // Combining Glagolitic Let..Combining Glagolitic Let + {0x1e026, 0x1e02a}, // Combining Glagolitic Let..Combining Glagolitic Let + {0x1e130, 0x1e136}, // Nyiakeng Puachue Hmong T..Nyiakeng Puachue Hmong T + {0x1e2ec, 0x1e2ef}, // Wancho Tone Tup ..Wancho Tone Koini + {0x1e8d0, 0x1e8d6}, // Mende Kikakui Combining ..Mende Kikakui Combining + {0x1e944, 0x1e94a}, // Adlam Alif Lengthener ..Adlam Nukta + {0xe0100, 0xe01ef}, // Variation Selector-17 ..Variation Selector-256 +}; + +// https://github.com/jquast/wcwidth/blob/master/wcwidth/table_wide.py +// at commit b29897e5a1b403a0e36f7fc991614981cbc42475 (2020-07-14): +struct width_interval WIDE_EASTASIAN[] = { + {0x01100, 0x0115f}, // Hangul Choseong Kiyeok ..Hangul Choseong Filler + {0x0231a, 0x0231b}, // Watch ..Hourglass + {0x02329, 0x0232a}, // Left-pointing Angle Brac..Right-pointing Angle Bra + {0x023e9, 0x023ec}, // Black Right-pointing Dou..Black Down-pointing Doub + {0x023f0, 0x023f0}, // Alarm Clock ..Alarm Clock + {0x023f3, 0x023f3}, // Hourglass With Flowing S..Hourglass With Flowing S + {0x025fd, 0x025fe}, // White Medium Small Squar..Black Medium Small Squar + {0x02614, 0x02615}, // Umbrella With Rain Drops..Hot Beverage + {0x02648, 0x02653}, // Aries ..Pisces + {0x0267f, 0x0267f}, // Wheelchair Symbol ..Wheelchair Symbol + {0x02693, 0x02693}, // Anchor ..Anchor + {0x026a1, 0x026a1}, // High Voltage Sign ..High Voltage Sign + {0x026aa, 0x026ab}, // Medium White Circle ..Medium Black Circle + {0x026bd, 0x026be}, // Soccer Ball ..Baseball + {0x026c4, 0x026c5}, // Snowman Without Snow ..Sun Behind Cloud + {0x026ce, 0x026ce}, // Ophiuchus ..Ophiuchus + {0x026d4, 0x026d4}, // No Entry ..No Entry + {0x026ea, 0x026ea}, // Church ..Church + {0x026f2, 0x026f3}, // Fountain ..Flag In Hole + {0x026f5, 0x026f5}, // Sailboat ..Sailboat + {0x026fa, 0x026fa}, // Tent ..Tent + {0x026fd, 0x026fd}, // Fuel Pump ..Fuel Pump + {0x02705, 0x02705}, // White Heavy Check Mark ..White Heavy Check Mark + {0x0270a, 0x0270b}, // Raised Fist ..Raised Hand + {0x02728, 0x02728}, // Sparkles ..Sparkles + {0x0274c, 0x0274c}, // Cross Mark ..Cross Mark + {0x0274e, 0x0274e}, // Negative Squared Cross M..Negative Squared Cross M + {0x02753, 0x02755}, // Black Question Mark Orna..White Exclamation Mark O + {0x02757, 0x02757}, // Heavy Exclamation Mark S..Heavy Exclamation Mark S + {0x02795, 0x02797}, // Heavy Plus Sign ..Heavy Division Sign + {0x027b0, 0x027b0}, // Curly Loop ..Curly Loop + {0x027bf, 0x027bf}, // Double Curly Loop ..Double Curly Loop + {0x02b1b, 0x02b1c}, // Black Large Square ..White Large Square + {0x02b50, 0x02b50}, // White Medium Star ..White Medium Star + {0x02b55, 0x02b55}, // Heavy Large Circle ..Heavy Large Circle + {0x02e80, 0x02e99}, // Cjk Radical Repeat ..Cjk Radical Rap + {0x02e9b, 0x02ef3}, // Cjk Radical Choke ..Cjk Radical C-simplified + {0x02f00, 0x02fd5}, // Kangxi Radical One ..Kangxi Radical Flute + {0x02ff0, 0x02ffb}, // Ideographic Description ..Ideographic Description + {0x03000, 0x0303e}, // Ideographic Space ..Ideographic Variation In + {0x03041, 0x03096}, // Hiragana Letter Small A ..Hiragana Letter Small Ke + {0x03099, 0x030ff}, // Combining Katakana-hirag..Katakana Digraph Koto + {0x03105, 0x0312f}, // Bopomofo Letter B ..Bopomofo Letter Nn + {0x03131, 0x0318e}, // Hangul Letter Kiyeok ..Hangul Letter Araeae + {0x03190, 0x031e3}, // Ideographic Annotation L..Cjk Stroke Q + {0x031f0, 0x0321e}, // Katakana Letter Small Ku..Parenthesized Korean Cha + {0x03220, 0x03247}, // Parenthesized Ideograph ..Circled Ideograph Koto + {0x03250, 0x04dbf}, // Partnership Sign ..(nil) + {0x04e00, 0x0a48c}, // Cjk Unified Ideograph-4e..Yi Syllable Yyr + {0x0a490, 0x0a4c6}, // Yi Radical Qot ..Yi Radical Ke + {0x0a960, 0x0a97c}, // Hangul Choseong Tikeut-m..Hangul Choseong Ssangyeo + {0x0ac00, 0x0d7a3}, // Hangul Syllable Ga ..Hangul Syllable Hih + {0x0f900, 0x0faff}, // Cjk Compatibility Ideogr..(nil) + {0x0fe10, 0x0fe19}, // Presentation Form For Ve..Presentation Form For Ve + {0x0fe30, 0x0fe52}, // Presentation Form For Ve..Small Full Stop + {0x0fe54, 0x0fe66}, // Small Semicolon ..Small Equals Sign + {0x0fe68, 0x0fe6b}, // Small Reverse Solidus ..Small Commercial At + {0x0ff01, 0x0ff60}, // Fullwidth Exclamation Ma..Fullwidth Right White Pa + {0x0ffe0, 0x0ffe6}, // Fullwidth Cent Sign ..Fullwidth Won Sign + {0x16fe0, 0x16fe4}, // Tangut Iteration Mark ..(nil) + {0x16ff0, 0x16ff1}, // (nil) ..(nil) + {0x17000, 0x187f7}, // (nil) ..(nil) + {0x18800, 0x18cd5}, // Tangut Component-001 ..(nil) + {0x18d00, 0x18d08}, // (nil) ..(nil) + {0x1b000, 0x1b11e}, // Katakana Letter Archaic ..Hentaigana Letter N-mu-m + {0x1b150, 0x1b152}, // Hiragana Letter Small Wi..Hiragana Letter Small Wo + {0x1b164, 0x1b167}, // Katakana Letter Small Wi..Katakana Letter Small N + {0x1b170, 0x1b2fb}, // Nushu Character-1b170 ..Nushu Character-1b2fb + {0x1f004, 0x1f004}, // Mahjong Tile Red Dragon ..Mahjong Tile Red Dragon + {0x1f0cf, 0x1f0cf}, // Playing Card Black Joker..Playing Card Black Joker + {0x1f18e, 0x1f18e}, // Negative Squared Ab ..Negative Squared Ab + {0x1f191, 0x1f19a}, // Squared Cl ..Squared Vs + {0x1f200, 0x1f202}, // Square Hiragana Hoka ..Squared Katakana Sa + {0x1f210, 0x1f23b}, // Squared Cjk Unified Ideo..Squared Cjk Unified Ideo + {0x1f240, 0x1f248}, // Tortoise Shell Bracketed..Tortoise Shell Bracketed + {0x1f250, 0x1f251}, // Circled Ideograph Advant..Circled Ideograph Accept + {0x1f260, 0x1f265}, // Rounded Symbol For Fu ..Rounded Symbol For Cai + {0x1f300, 0x1f320}, // Cyclone ..Shooting Star + {0x1f32d, 0x1f335}, // Hot Dog ..Cactus + {0x1f337, 0x1f37c}, // Tulip ..Baby Bottle + {0x1f37e, 0x1f393}, // Bottle With Popping Cork..Graduation Cap + {0x1f3a0, 0x1f3ca}, // Carousel Horse ..Swimmer + {0x1f3cf, 0x1f3d3}, // Cricket Bat And Ball ..Table Tennis Paddle And + {0x1f3e0, 0x1f3f0}, // House Building ..European Castle + {0x1f3f4, 0x1f3f4}, // Waving Black Flag ..Waving Black Flag + {0x1f3f8, 0x1f43e}, // Badminton Racquet And Sh..Paw Prints + {0x1f440, 0x1f440}, // Eyes ..Eyes + {0x1f442, 0x1f4fc}, // Ear ..Videocassette + {0x1f4ff, 0x1f53d}, // Prayer Beads ..Down-pointing Small Red + {0x1f54b, 0x1f54e}, // Kaaba ..Menorah With Nine Branch + {0x1f550, 0x1f567}, // Clock Face One Oclock ..Clock Face Twelve-thirty + {0x1f57a, 0x1f57a}, // Man Dancing ..Man Dancing + {0x1f595, 0x1f596}, // Reversed Hand With Middl..Raised Hand With Part Be + {0x1f5a4, 0x1f5a4}, // Black Heart ..Black Heart + {0x1f5fb, 0x1f64f}, // Mount Fuji ..Person With Folded Hands + {0x1f680, 0x1f6c5}, // Rocket ..Left Luggage + {0x1f6cc, 0x1f6cc}, // Sleeping Accommodation ..Sleeping Accommodation + {0x1f6d0, 0x1f6d2}, // Place Of Worship ..Shopping Trolley + {0x1f6d5, 0x1f6d7}, // Hindu Temple ..(nil) + {0x1f6eb, 0x1f6ec}, // Airplane Departure ..Airplane Arriving + {0x1f6f4, 0x1f6fc}, // Scooter ..(nil) + {0x1f7e0, 0x1f7eb}, // Large Orange Circle ..Large Brown Square + {0x1f90c, 0x1f93a}, // (nil) ..Fencer + {0x1f93c, 0x1f945}, // Wrestlers ..Goal Net + {0x1f947, 0x1f978}, // First Place Medal ..(nil) + {0x1f97a, 0x1f9cb}, // Face With Pleading Eyes ..(nil) + {0x1f9cd, 0x1f9ff}, // Standing Person ..Nazar Amulet + {0x1fa70, 0x1fa74}, // Ballet Shoes ..(nil) + {0x1fa78, 0x1fa7a}, // Drop Of Blood ..Stethoscope + {0x1fa80, 0x1fa86}, // Yo-yo ..(nil) + {0x1fa90, 0x1faa8}, // Ringed Planet ..(nil) + {0x1fab0, 0x1fab6}, // (nil) ..(nil) + {0x1fac0, 0x1fac2}, // (nil) ..(nil) + {0x1fad0, 0x1fad6}, // (nil) ..(nil) + {0x20000, 0x2fffd}, // Cjk Unified Ideograph-20..(nil) + {0x30000, 0x3fffd}, // (nil) ..(nil) +}; + +bool intable(struct width_interval* table, int table_length, int c) { + // First quick check for Latin1 etc. characters. + if (c < table[0].start) return false; + + // Binary search in table. + int bot = 0; + int top = table_length - 1; + while (top >= bot) { + int mid = (bot + top) / 2; + if (table[mid].end < c) { + bot = mid + 1; + } else if (table[mid].start > c) { + top = mid - 1; + } else { + return true; + } + } + return false; +} + +} + +int wcwidth(wchar_t ucs) { + // NOTE: created by hand, there isn't anything identifiable other than + // general Cf category code to identify these, and some characters in Cf + // category code are of non-zero width. + if (ucs == 0 || ucs == 0x034F || (0x200B <= ucs && ucs <= 0x200F) || + ucs == 0x2028 || ucs == 0x2029 || (0x202A <= ucs && ucs <= 0x202E) || + (0x2060 <= ucs && ucs <= 0x2063)) { + return 0; + } + + // C0/C1 control characters. + if (ucs < 32 || (0x07F <= ucs && ucs < 0x0A0)) return -1; + + // Combining characters with zero width. + if (intable(ZERO_WIDTH, sizeof(ZERO_WIDTH) / sizeof(struct width_interval), ucs)) return 0; + + return intable(WIDE_EASTASIAN, sizeof(WIDE_EASTASIAN) / sizeof(struct width_interval), ucs) ? 2 : 1; +} + +int wcswidth(const wchar_t *wcs, size_t n) { + int ret = 0; + for(size_t i = 0; i < n && wcs[i]; i++) { + int cols = wcwidth(wcs[i]); + if (cols < 0) + return -1; + ret += cols; + } + + return ret; +} + +wchar_t *wcsdup(const wchar_t *s) { + size_t len = wcslen(s); + wchar_t *ret = (wchar_t *) malloc(sizeof(wchar_t) * (len + 1)); + if(!ret) + return NULL; + wmemcpy(ret, s, len + 1); + return ret; +} + +int wcsncasecmp(const wchar_t* s1, const wchar_t* s2, size_t n) { + for(size_t i = 0; i < n; i++) { + wint_t c1 = towlower(s1[i]); + wint_t c2 = towlower(s2[i]); + if(c1 == L'\0' && c2 == L'\0') + return 0; + if(c1 < c2) + return -1; + if(c1 > c2) + return 1; + } + return 0; +} + +int wcscasecmp(const wchar_t *, const wchar_t *) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} diff --git a/lib/mlibc/options/ansi/generic/wctype.cpp b/lib/mlibc/options/ansi/generic/wctype.cpp new file mode 100644 index 0000000..57dcbc9 --- /dev/null +++ b/lib/mlibc/options/ansi/generic/wctype.cpp @@ -0,0 +1,9 @@ + +#include +#include +#include +#include + +wctrans_t wctrans(const char *) MLIBC_STUB_BODY +wint_t towctrans(wint_t, wctrans_t) MLIBC_STUB_BODY + diff --git a/lib/mlibc/options/ansi/include/alloca.h b/lib/mlibc/options/ansi/include/alloca.h new file mode 100644 index 0000000..0cc6bcb --- /dev/null +++ b/lib/mlibc/options/ansi/include/alloca.h @@ -0,0 +1,8 @@ + +#ifndef _ALLOCA_H +#define _ALLOCA_H + +#define alloca __builtin_alloca + +#endif // _ALLOCA_H + diff --git a/lib/mlibc/options/ansi/include/assert.h b/lib/mlibc/options/ansi/include/assert.h new file mode 100644 index 0000000..7eccae0 --- /dev/null +++ b/lib/mlibc/options/ansi/include/assert.h @@ -0,0 +1,46 @@ + +#ifndef _ASSERT_H +#define _ASSERT_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +// NOTE: This is not ISO C. Declared in LSB +__attribute__ ((__noreturn__)) void __assert_fail(const char *assertion, const char *file, unsigned int line, + const char *function); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif // _ASSERT_H + +#include + +#if __MLIBC_GLIBC_OPTION +# include +#endif + +// NOTE: [7.2] requires this be outside the include guard +#ifdef NDEBUG + +#undef assert +#define assert(ignore) ((void)0) + +#else // NDEBUG + +#undef assert +#define assert(assertion) ((void)((assertion) \ + || (__assert_fail(#assertion, __FILE__, __LINE__, __func__), 0))) + +#endif // NDEBUG + +#ifndef __cplusplus +#undef static_assert +#define static_assert _Static_assert +#endif diff --git a/lib/mlibc/options/ansi/include/bits/ansi/fenv.h b/lib/mlibc/options/ansi/include/bits/ansi/fenv.h new file mode 100644 index 0000000..677ddaa --- /dev/null +++ b/lib/mlibc/options/ansi/include/bits/ansi/fenv.h @@ -0,0 +1,54 @@ +#ifndef MLIBC_FENV_H +#define MLIBC_FENV_H + +#if defined(__x86_64__) || defined(__i386__) + +#define FE_DENORMAL 2 +#define FE_DIVBYZERO 4 +#define FE_INEXACT 32 +#define FE_INVALID 1 +#define FE_OVERFLOW 8 +#define FE_UNDERFLOW 16 + +#define FE_ALL_EXCEPT (FE_DENORMAL | FE_DIVBYZERO | FE_INEXACT | FE_INVALID | FE_OVERFLOW | FE_UNDERFLOW) + +#define FE_TONEAREST 0 +#define FE_DOWNWARD 0x400 +#define FE_UPWARD 0x800 +#define FE_TOWARDZERO 0xC00 + +#elif defined(__aarch64__) + +#define FE_INVALID 1 +#define FE_DIVBYZERO 2 +#define FE_OVERFLOW 4 +#define FE_UNDERFLOW 8 +#define FE_INEXACT 16 + +#define FE_ALL_EXCEPT 31 + +#define FE_TONEAREST 0 +#define FE_UPWARD 0x400000 +#define FE_DOWNWARD 0x800000 +#define FE_TOWARDZERO 0xC00000 + +#elif defined(__riscv) && __riscv_xlen == 64 + +#define FE_INEXACT 1 +#define FE_UNDERFLOW 2 +#define FE_OVERFLOW 4 +#define FE_DIVBYZERO 8 +#define FE_INVALID 16 + +#define FE_ALL_EXCEPT 31 + +#define FE_TONEAREST 0 +#define FE_TOWARDZERO 1 +#define FE_DOWNWARD 2 +#define FE_UPWARD 3 + +#else +#error Unknown architecture +#endif + +#endif // MLIBC_FENV_H diff --git a/lib/mlibc/options/ansi/include/bits/ansi/time_t.h b/lib/mlibc/options/ansi/include/bits/ansi/time_t.h new file mode 100644 index 0000000..1c29fa0 --- /dev/null +++ b/lib/mlibc/options/ansi/include/bits/ansi/time_t.h @@ -0,0 +1,8 @@ + +#ifndef MLIBC_TIME_T +#define MLIBC_TIME_T + +typedef long time_t; + +#endif + diff --git a/lib/mlibc/options/ansi/include/bits/ansi/timespec.h b/lib/mlibc/options/ansi/include/bits/ansi/timespec.h new file mode 100644 index 0000000..d34aa64 --- /dev/null +++ b/lib/mlibc/options/ansi/include/bits/ansi/timespec.h @@ -0,0 +1,13 @@ + +#ifndef MLIBC_TIMESPEC_H +#define MLIBC_TIMESPEC_H + +#include + +struct timespec { + time_t tv_sec; + long tv_nsec; +}; + +#endif // MLIBC_TIMESPEC_H + diff --git a/lib/mlibc/options/ansi/include/complex.h b/lib/mlibc/options/ansi/include/complex.h new file mode 100644 index 0000000..6191f28 --- /dev/null +++ b/lib/mlibc/options/ansi/include/complex.h @@ -0,0 +1,134 @@ +/* $NetBSD: complex.h,v 1.3 2010/09/15 16:11:30 christos Exp $ */ + +/* + * Written by Matthias Drochner. + * Public domain. + */ + +#ifndef _COMPLEX_H +#define _COMPLEX_H + +#define complex _Complex +#define _Complex_I 1.0fi +#define I _Complex_I + +#define CMPLX(x, y) ((double complex)__builtin_complex((double)(x), (double)(y))) +#define CMPLXF(x, y) ((float complex)__builtin_complex((float)(x), (float)(y))) +#define CMPLXL(x, y) ((long double complex)__builtin_complex((long double)(x), (long double)(y))) + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +/* 7.3.5 Trigonometric functions */ +/* 7.3.5.1 The cacos functions */ +double complex cacos(double complex); +float complex cacosf(float complex); + +/* 7.3.5.2 The casin functions */ +double complex casin(double complex); +float complex casinf(float complex); + +/* 7.3.5.1 The catan functions */ +double complex catan(double complex); +float complex catanf(float complex); + +/* 7.3.5.1 The ccos functions */ +double complex ccos(double complex); +float complex ccosf(float complex); + +/* 7.3.5.1 The csin functions */ +double complex csin(double complex); +float complex csinf(float complex); + +/* 7.3.5.1 The ctan functions */ +double complex ctan(double complex); +float complex ctanf(float complex); + +/* 7.3.6 Hyperbolic functions */ +/* 7.3.6.1 The cacosh functions */ +double complex cacosh(double complex); +float complex cacoshf(float complex); + +/* 7.3.6.2 The casinh functions */ +double complex casinh(double complex); +float complex casinhf(float complex); + +/* 7.3.6.3 The catanh functions */ +double complex catanh(double complex); +float complex catanhf(float complex); + +/* 7.3.6.4 The ccosh functions */ +double complex ccosh(double complex); +float complex ccoshf(float complex); + +/* 7.3.6.5 The csinh functions */ +double complex csinh(double complex); +float complex csinhf(float complex); + +/* 7.3.6.6 The ctanh functions */ +double complex ctanh(double complex); +float complex ctanhf(float complex); + +/* 7.3.7 Exponential and logarithmic functions */ +/* 7.3.7.1 The cexp functions */ +double complex cexp(double complex); +float complex cexpf(float complex); + +/* 7.3.7.2 The clog functions */ +double complex clog(double complex); +float complex clogf(float complex); + +/* 7.3.8 Power and absolute-value functions */ +/* 7.3.8.1 The cabs functions */ +/*#ifndef __LIBM0_SOURCE__ */ +/* avoid conflict with historical cabs(struct complex) */ +/* double cabs(double complex) __RENAME(__c99_cabs); + float cabsf(float complex) __RENAME(__c99_cabsf); + #endif +*/ +double cabs(double complex) ; +float cabsf(float complex) ; + +/* 7.3.8.2 The cpow functions */ +double complex cpow(double complex, double complex); +float complex cpowf(float complex, float complex); + +/* 7.3.8.3 The csqrt functions */ +double complex csqrt(double complex); +float complex csqrtf(float complex); + +/* 7.3.9 Manipulation functions */ +/* 7.3.9.1 The carg functions */ +double carg(double complex); +float cargf(float complex); + +/* 7.3.9.2 The cimag functions */ +double cimag(double complex); +float cimagf(float complex); +long double cimagl(long double complex); + +/* 7.3.9.3 The conj functions */ +double complex conj(double complex); +float complex conjf(float complex); +/*long double complex conjl(long double complex); */ + +/* 7.3.9.4 The cproj functions */ +double complex cproj(double complex); +float complex cprojf(float complex); +/*long double complex cprojl(long double complex); */ + +/* 7.3.9.5 The creal functions */ +double creal(double complex); +float crealf(float complex); +long double creall(long double complex); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* ! _COMPLEX_H */ diff --git a/lib/mlibc/options/ansi/include/ctype.h b/lib/mlibc/options/ansi/include/ctype.h new file mode 100644 index 0000000..7cd1ec8 --- /dev/null +++ b/lib/mlibc/options/ansi/include/ctype.h @@ -0,0 +1,46 @@ +#ifndef _CTYPE_H +#define _CTYPE_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +// Character classification function [7.4.1] +int isalnum(int c); +int isalpha(int c); +int isblank(int c); +int iscntrl(int c); +int isdigit(int c); +int isgraph(int c); +int islower(int c); +int isprint(int c); +int ispunct(int c); +int isspace(int c); +int isupper(int c); +int isxdigit(int c); + +// glibc extensions. +int isascii(int c); + +// Character case mapping functions [7.4.2] +int tolower(int c); +int toupper(int c); + +#endif /* !__MLIBC_ABI_ONLY */ + +// Borrowed from glibc +#define toascii(c) ((c) & 0x7f) + +#ifdef __cplusplus +} +#endif + +#if __MLIBC_POSIX_OPTION +# include +#endif + +#endif // _CTYPE_H diff --git a/lib/mlibc/options/ansi/include/errno.h b/lib/mlibc/options/ansi/include/errno.h new file mode 100644 index 0000000..7730b16 --- /dev/null +++ b/lib/mlibc/options/ansi/include/errno.h @@ -0,0 +1,31 @@ +#ifndef _ERRNO_H +#define _ERRNO_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +// Some programs define their own errno as an "extern int" if it is not a macro. +#define errno __mlibc_errno +extern __thread int __mlibc_errno; + +int *__errno_location(void); + +// Linux extensions. + +extern char *program_invocation_name; +extern char *program_invocation_short_name; +extern char *__progname; +extern char *__progname_full; + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif // _ERRNO_H diff --git a/lib/mlibc/options/ansi/include/fenv.h b/lib/mlibc/options/ansi/include/fenv.h new file mode 100644 index 0000000..11e38f3 --- /dev/null +++ b/lib/mlibc/options/ansi/include/fenv.h @@ -0,0 +1,44 @@ + +#ifndef _FENV_H +#define _FENV_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + __mlibc_uint32 __control_word; + __mlibc_uint32 __status_word; + __mlibc_uint32 __unused[5]; + __mlibc_uint32 __mxcsr; +} fenv_t; + +typedef __mlibc_uint16 fexcept_t; + +#ifndef __MLIBC_ABI_ONLY + +int feclearexcept(int); +int fegetenv(fenv_t *); +int fegetexceptflag(fexcept_t *, int); +int fegetround(void); +int feholdexcept(fenv_t *); +int feraiseexcept(int); +int fesetenv(const fenv_t *); +int fesetexceptflag(const fexcept_t *, int); +int fesetround(int); +int fetestexcept(int); +int feupdateenv(const fenv_t *); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#define FE_DFL_ENV ((const fenv_t *) -1) + +#endif // _FENV_H + diff --git a/lib/mlibc/options/ansi/include/inttypes.h b/lib/mlibc/options/ansi/include/inttypes.h new file mode 100644 index 0000000..5495440 --- /dev/null +++ b/lib/mlibc/options/ansi/include/inttypes.h @@ -0,0 +1,146 @@ +#ifndef _STDINT_H +#define _STDINT_H + +#include + +/* Even though this is not strictly not-ABI, it is mlibc-printf specific therefore */ +/* gate behind !__MLIBC_ABI_ONLY */ +#ifndef __MLIBC_ABI_ONLY + +#if UINTPTR_MAX == UINT64_MAX +# define __PRI64 "l" +# define __PRIPTR "l" +#else +# define __PRI64 "ll" +# define __PRIPTR "" +#endif + +// TODO: This is extremly unelegant and fragile. +#define PRId8 "d" +#define PRIi8 "i" +#define PRIdLEAST8 "d" +#define PRIiLEAST8 "i" +#define PRIdFAST8 "d" +#define PRIiFAST8 "i" +#define PRId16 "d" +#define PRIi16 "i" +#define PRIdLEAST16 "d" +#define PRIiLEAST16 "i" +#define PRIdFAST16 "ld" +#define PRIiFAST16 "li" +#define PRId32 "d" +#define PRIi32 "i" +#define PRIdLEAST32 "d" +#define PRIiLEAST32 "i" +#define PRIdFAST32 "ld" +#define PRIiFAST32 "li" +#define PRId64 __PRI64 "d" +#define PRIi64 __PRI64 "i" +#define PRIdLEAST64 __PRI64 "d" +#define PRIiLEAST64 __PRI64 "i" +#define PRIdFAST64 __PRI64 "d" +#define PRIiFAST64 __PRI64 "i" +#define PRIdMAX __PRI64 "d" +#define PRIiMAX __PRI64 "i" +#define PRIdPTR __PRIPTR "d" +#define PRIiPTR __PRIPTR "i" +#define PRIo8 "o" +#define PRIu8 "u" +#define PRIx8 "x" +#define PRIX8 "X" +#define PRIoLEAST8 "o" +#define PRIuLEAST8 "u" +#define PRIxLEAST8 "x" +#define PRIXLEAST8 "X" +#define PRIoFAST8 "o" +#define PRIuFAST8 "u" +#define PRIxFAST8 "x" +#define PRIXFAST8 "X" +#define PRIo16 "o" +#define PRIu16 "u" +#define PRIx16 "x" +#define PRIX16 "X" +#define PRIoLEAST16 "o" +#define PRIuLEAST16 "u" +#define PRIxLEAST16 "x" +#define PRIXLEAST16 "X" +#define PRIoFAST16 "lo" +#define PRIuFAST16 "lu" +#define PRIxFAST16 "lx" +#define PRIXFAST16 "lX" +#define PRIo32 "o" +#define PRIu32 "u" +#define PRIx32 "x" +#define PRIX32 "X" +#define PRIoLEAST32 "o" +#define PRIuLEAST32 "u" +#define PRIxLEAST32 "x" +#define PRIXLEAST32 "X" +#define PRIoFAST32 "lo" +#define PRIuFAST32 "lu" +#define PRIxFAST32 "lx" +#define PRIXFAST32 "lX" +#define PRIo64 __PRI64 "o" +#define PRIu64 __PRI64 "u" +#define PRIx64 __PRI64 "x" +#define PRIX64 __PRI64 "X" +#define PRIoLEAST64 __PRI64 "o" +#define PRIuLEAST64 __PRI64 "u" +#define PRIxLEAST64 __PRI64 "x" +#define PRIXLEAST64 __PRI64 "X" +#define PRIoFAST64 __PRI64 "o" +#define PRIuFAST64 __PRI64 "u" +#define PRIxFAST64 __PRI64 "x" +#define PRIXFAST64 __PRI64 "X" +#define PRIoMAX __PRI64 "o" +#define PRIuMAX __PRI64 "u" +#define PRIxMAX __PRI64 "x" +#define PRIXMAX __PRI64 "X" +#define PRIoPTR __PRIPTR "o" +#define PRIuPTR __PRIPTR "u" +#define PRIxPTR __PRIPTR "x" +#define PRIXPTR __PRIPTR "X" + +#define SCNu32 "u" +#define SCNu64 __PRI64 "u" +#define SCNuMAX __PRI64 "u" +#define SCNx16 "hx" +#define SCNx32 "x" +#define SCNx64 __PRI64 "x" +#define SCNxMAX __PRI64 "x" +#define SCNi8 "hhi" +#define SCNxPTR __PRIPTR "x" + +#define SCNi8 "hhi" +#define SCNi64 __PRI64 "i" + +#define SCNd32 "d" +#define SCNd64 __PRI64 "d" + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + intmax_t quot; + intmax_t rem; +} imaxdiv_t; + +#ifndef __MLIBC_ABI_ONLY + +intmax_t imaxabs(intmax_t); +imaxdiv_t imaxdiv(intmax_t, intmax_t); +intmax_t strtoimax(const char *__restrict, char **__restrict, int); +uintmax_t strtoumax(const char *__restrict, char **__restrict, int); +intmax_t wcstoimax(const __WCHAR_TYPE__ *__restrict, __WCHAR_TYPE__ **__restrict, int); +uintmax_t wcstoumax(const __WCHAR_TYPE__ *__restrict, __WCHAR_TYPE__ **__restrict, int); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif // _STDINT_H diff --git a/lib/mlibc/options/ansi/include/limits.h b/lib/mlibc/options/ansi/include/limits.h new file mode 100644 index 0000000..86b786e --- /dev/null +++ b/lib/mlibc/options/ansi/include/limits.h @@ -0,0 +1,117 @@ +#ifndef _LIMITS_H +#define _LIMITS_H + +#define CHAR_BIT 8 + +#ifndef MB_LEN_MAX +# define MB_LEN_MAX 4 +#endif + +#ifdef LONG_MAX +# ifdef LONG_MAX == INT32_MAX +# define LONG_BIT 32 +# else +// Safe assumption +# define LONG_BIT 64 +# endif +#elif defined __LONG_MAX__ +# if __LONG_MAX__ == INT32_MAX +# define LONG_BIT 32 +# else +// Safe assumption +# define LONG_BIT 64 +# endif +#else +# error "Unsupported configuration, please define either LONG_MAX or __LONG_MAX__" +#endif + +#undef SCHAR_MIN +#undef SCHAR_MAX +#undef CHAR_MIN +#undef CHAR_MAX +#undef UCHAR_MAX +#undef SHRT_MIN +#undef SHRT_MAX +#undef USHRT_MAX +#undef INT_MIN +#undef INT_MAX +#undef UINT_MAX +#undef LONG_MIN +#undef LONG_MAX +#undef ULONG_MAX +#undef LLONG_MIN +#undef LLONG_MAX +#undef ULLONG_MAX + +#define SCHAR_MIN (-__SCHAR_MAX__ - 1) +#define SCHAR_MAX __SCHAR_MAX__ +#if __SCHAR_MAX__ == __INT_MAX__ +# define UCHAR_MAX (__SCHAR_MAX__ * 2U + 1U) +#else +# define UCHAR_MAX (__SCHAR_MAX__ * 2 + 1) +#endif + +#ifdef __CHAR_UNSIGNED__ +# define CHAR_MAX UCHAR_MAX +# if __SCHAR_MAX__ == __INT_MAX__ +# define CHAR_MIN 0U +# else +# define CHAR_MIN 0 +# endif +#else +# define CHAR_MAX SCHAR_MAX +# define CHAR_MIN SCHAR_MIN +#endif + +#define SHRT_MIN (-__SHRT_MAX__ - 1) +#define SHRT_MAX __SHRT_MAX__ +#if __SHRT_MAX_ == __INT_MAX__ +# define USHRT_MAX (__SHRT_MAX__ * 2U + 1U) +#else +# define USHRT_MAX (__SHRT_MAX__ * 2 + 1) +#endif + +#define INT_MIN (-__INT_MAX__ - 1) +#define INT_MAX __INT_MAX__ +#define UINT_MAX (__INT_MAX__ * 2 + 1) + +#define LONG_MIN (-__LONG_MAX__ - 1L) +#define LONG_MAX __LONG_MAX__ +#define ULONG_MAX (__LONG_MAX__ * 2UL + 1UL) + +#define LLONG_MIN (-__LONG_LONG_MAX__ - 1LL) +#define LLONG_MAX __LONG_LONG_MAX__ +#define ULLONG_MAX (__LONG_LONG_MAX__ * 2ULL + 1ULL) + +#define NAME_MAX 255 +#define PATH_MAX 4096 +#define LINE_MAX 4096 +#define PIPE_BUF 4096 + +#define CHARCLASS_NAME_MAX 14 +#define RE_DUP_MAX 255 + +// This value is a guaranteed minimum, get the current maximum from sysconf +#define NGROUPS_MAX 8 +// POSIX states 9 is the minimum for NL_ARGMAX +#define NL_ARGMAX 9 + +#if INTPTR_MAX == INT64_MAX +# define SSIZE_MAX LONG_MAX +#elif INTPTR_MAX == INT32_MAX +# define SSIZE_MAX INT_MAX +#endif + +#define _POSIX_ARG_MAX 4096 +#define _POSIX_OPEN_MAX 16 +#define _POSIX_HOST_NAME_MAX 255 +#define _POSIX_NAME_MAX 14 +#define _POSIX_TZNAME_MAX 6 +#define _XOPEN_NAME_MAX 255 + +#define PTHREAD_STACK_MIN 16384 +#define PTHREAD_KEYS_MAX 1024 + +#include + +#endif // _LIMITS_H diff --git a/lib/mlibc/options/ansi/include/locale.h b/lib/mlibc/options/ansi/include/locale.h new file mode 100644 index 0000000..3b4773d --- /dev/null +++ b/lib/mlibc/options/ansi/include/locale.h @@ -0,0 +1,81 @@ + +#ifndef _LOCALE_H +#define _LOCALE_H + +#include + +#include + +#define LC_ALL 1 +#define LC_COLLATE 2 +#define LC_CTYPE 3 +#define LC_MONETARY 4 +#define LC_NUMERIC 5 +#define LC_TIME 6 +#define LC_MESSAGES 7 + +#define LC_GLOBAL_LOCALE ((locale_t) -1L) + +#define LC_CTYPE_MASK (1< +#endif // __MLIBC_POSIX_OPTION + +#ifdef __cplusplus +} +#endif + +#endif // _LOCALE_H + diff --git a/lib/mlibc/options/ansi/include/math.h b/lib/mlibc/options/ansi/include/math.h new file mode 100644 index 0000000..7d7ab3c --- /dev/null +++ b/lib/mlibc/options/ansi/include/math.h @@ -0,0 +1,383 @@ + +#ifndef _MATH_H +#define _MATH_H + +#include + +// this is a posix extension +#define M_E 2.7182818284590452354 +#define M_LOG2E 1.4426950408889634074 +#define M_LOG10E 0.43429448190325182765 +#define M_LN2 0.69314718055994530942 +#define M_LN10 2.30258509299404568402 +#define M_PI 3.14159265358979323846 +#define M_PI_2 1.57079632679489661923 +#define M_PI_4 0.78539816339744830962 +#define M_1_PI 0.31830988618379067154 +#define M_2_PI 0.63661977236758134308 +#define M_2_SQRTPI 1.12837916709551257390 +#define M_SQRT2 1.41421356237309504880 +#define M_SQRT1_2 0.70710678118654752440 +#define M_PIl 3.141592653589793238462643383279502884L + +// The following two definitions are from musl. +#define FP_ILOGBNAN (-1 - (int)(((unsigned)-1) >> 1)) +#define FP_ILOGB0 FP_ILOGBNAN + +#ifdef __cplusplus +extern "C" { +#endif + +typedef double double_t; +typedef float float_t; + +#define HUGE_VAL (__builtin_huge_val()) +#define HUGE_VALF (__builtin_huge_valf()) +#define HUGE_VALL (__builtin_huge_vall()) +#define INFINITY (__builtin_inff()) +#define NAN (__builtin_nanf("")) + +// [C11/7.12.1 Treatment of error conditions] + +#define MATH_ERRNO 1 +#define MATH_ERREXCEPT 2 +#define math_errhandling 3 + +// [C11/7.12.3 Classification macros] + +// NOTE: fpclassify always returns exactly one of those constants +// However making them bitwise disjoint simplifies isfinite() etc. +#define FP_INFINITE 1 +#define FP_NAN 2 +#define FP_NORMAL 4 +#define FP_SUBNORMAL 8 +#define FP_ZERO 16 + +#ifndef __MLIBC_ABI_ONLY + +int __fpclassify(double x); +int __fpclassifyf(float x); +int __fpclassifyl(long double x); + +#define fpclassify(x) \ + (sizeof(x) == sizeof(double) ? __fpclassify(x) : \ + (sizeof(x) == sizeof(float) ? __fpclassifyf(x) : \ + (sizeof(x) == sizeof(long double) ? __fpclassifyl(x) : \ + 0))) + +#define isfinite(x) (fpclassify(x) & (FP_NORMAL | FP_SUBNORMAL | FP_ZERO)) +#define isnan(x) (fpclassify(x) == FP_NAN) +#define isinf(x) (fpclassify(x) == FP_INFINITE) +#define isnormal(x) (fpclassify(x) == FP_NORMAL) + +// FIXME: this is gcc specific +#define signbit(x) (__builtin_signbit(x)) + +// [C11/7.12.14 Comparison macros] +#define isunordered(x,y) (isnan((x)) ? ((void)(y),1) : isnan((y))) + +__MLIBC_INLINE_DEFINITION int __mlibc_isless(double_t x, double_t y) { return !isunordered(x, y) && x < y; } +__MLIBC_INLINE_DEFINITION int __mlibc_islessf(float_t x, float_t y) { return !isunordered(x, y) && x < y; } +__MLIBC_INLINE_DEFINITION int __mlibc_islessl(long double x, long double y) { return !isunordered(x, y) && x < y; } +__MLIBC_INLINE_DEFINITION int __mlibc_islessequal(double_t x, double_t y) { return !isunordered(x, y) && x <= y; } +__MLIBC_INLINE_DEFINITION int __mlibc_islessequalf(float_t x, float_t y) { return !isunordered(x, y) && x <= y; } +__MLIBC_INLINE_DEFINITION int __mlibc_islessequall(long double x, long double y) { return !isunordered(x, y) && x <= y; } +__MLIBC_INLINE_DEFINITION int __mlibc_islessgreater(double_t x, double_t y) { return !isunordered(x, y) && x != y; } +__MLIBC_INLINE_DEFINITION int __mlibc_islessgreaterf(float_t x, float_t y) { return !isunordered(x, y) && x != y; } +__MLIBC_INLINE_DEFINITION int __mlibc_islessgreaterl(long double x, long double y) { return !isunordered(x, y) && x != y; } +__MLIBC_INLINE_DEFINITION int __mlibc_isgreater(double_t x, double_t y) { return !isunordered(x, y) && x > y; } +__MLIBC_INLINE_DEFINITION int __mlibc_isgreaterf(float_t x, float_t y) { return !isunordered(x, y) && x > y; } +__MLIBC_INLINE_DEFINITION int __mlibc_isgreaterl(long double x, long double y) { return !isunordered(x, y) && x > y; } +__MLIBC_INLINE_DEFINITION int __mlibc_isgreaterequal(double_t x, double_t y) { return !isunordered(x, y) && x >= y; } +__MLIBC_INLINE_DEFINITION int __mlibc_isgreaterequalf(float_t x, float_t y) { return !isunordered(x, y) && x >= y; } +__MLIBC_INLINE_DEFINITION int __mlibc_isgreaterequall(long double x, long double y) { return !isunordered(x, y) && x >= y; } + +// TODO: We chould use _Generic here but that does not work in C++ code. +#define __MLIBC_CHOOSE_COMPARISON(x, y, p) ( \ + sizeof((x)+(y)) == sizeof(float) ? p##f(x, y) : \ + sizeof((x)+(y)) == sizeof(double) ? p(x, y) : \ + p##l(x, y) ) + +#define isless(x, y) __MLIBC_CHOOSE_COMPARISON(x, y, __mlibc_isless) +#define islessequal(x, y) __MLIBC_CHOOSE_COMPARISON(x, y, __mlibc_islessequal) +#define islessgreater(x, y) __MLIBC_CHOOSE_COMPARISON(x, y, __mlibc_islessgreater) +#define isgreater(x, y) __MLIBC_CHOOSE_COMPARISON(x, y, __mlibc_isgreater) +#define isgreaterequal(x, y) __MLIBC_CHOOSE_COMPARISON(x, y, __mlibc_isgreaterequal) + +// this is a gnu extension +void sincos(double, double *, double *); +void sincosf(float, float *, float *); +void sincosl(long double, long double *, long double *); + +double exp10(double); +float exp10f(float); +long double exp10l(long double); + +double pow10(double); +float pow10f(float); +long double pow10l(long double); + +// [C11/7.12.4 Trigonometric functions] + +double acos(double x); +float acosf(float x); +long double acosl(long double x); + +double asin(double x); +float asinf(float x); +long double asinl(long double x); + +double atan(double x); +float atanf(float x); +long double atanl(long double x); + +double atan2(double x, double y); +float atan2f(float x, float y); +long double atan2l(long double x, long double y); + +double cos(double x); +float cosf(float x); +long double cosl(long double x); + +double sin(double x); +float sinf(float x); +long double sinl(long double x); + +double tan(double x); +float tanf(float x); +long double tanl(long double x); + +// [C11/7.12.5 Hyperbolic functions] + +double acosh(double x); +float acoshf(float x); +long double acoshl(long double x); + +double asinh(double x); +float asinhf(float x); +long double asinhl(long double x); + +double atanh(double x); +float atanhf(float x); +long double atanhl(long double x); + +double cosh(double x); +float coshf(float x); +long double coshl(long double x); + +double sinh(double x); +float sinhf(float x); +long double sinhl(long double x); + +double tanh(double x); +float tanhf(float x); +long double tanhl(long double x); + +// [C11/7.12.6 Exponential and logarithmic functions] + +double exp(double x); +float expf(float x); +long double expl(long double x); + +double exp2(double x); +float exp2f(float x); +long double exp2l(long double x); + +double expm1(double x); +float expm1f(float x); +long double expm1l(long double x); + +double frexp(double x, int *power); +float frexpf(float x, int *power); +long double frexpl(long double x, int *power); + +int ilogb(double x); +int ilogbf(float x); +int ilogbl(long double x); + +double ldexp(double x, int power); +float ldexpf(float x, int power); +long double ldexpl(long double x, int power); + +double log(double x); +float logf(float x); +long double logl(long double x); + +double log10(double x); +float log10f(float x); +long double log10l(long double x); + +double log1p(double x); +float log1pf(float x); +long double log1pl(long double x); + +double log2(double x); +float log2f(float x); +long double log2l(long double x); + +double logb(double x); +float logbf(float x); +long double logbl(long double x); + +double modf(double x, double *integral); +float modff(float x, float *integral); +long double modfl(long double x, long double *integral); + +double scalbn(double x, int power); +float scalbnf(float x, int power); +long double scalbnl(long double x, int power); + +double scalbln(double x, long power); +float scalblnf(float x, long power); +long double scalblnl(long double x, long power); + +// [C11/7.12.7 Power and absolute-value functions] + +double cbrt(double x); +float cbrtf(float x); +long double cbrtl(long double x); + +double fabs(double x); +float fabsf(float x); +long double fabsl(long double x); + +double hypot(double x, double y); +float hypotf(float x, float y); +long double hypotl(long double x, long double y); + +double pow(double x, double y); +float powf(float x, float y); +long double powl(long double x, long double y); + +double sqrt(double x); +float sqrtf(float x); +long double sqrtl(long double x); + +// [C11/7.12.8 Error and gamma functions] + +double erf(double x); +float erff(float x); +long double erfl(long double x); + +double erfc(double x); +float erfcf(float x); +long double erfcl(long double x); + +double lgamma(double x); +float lgammaf(float x); +long double lgammal(long double x); + +double tgamma(double x); +float tgammaf(float x); +long double tgammal(long double x); + +// [C11/7.12.9 Nearest integer functions] + +double ceil(double x); +float ceilf(float x); +long double ceill(long double x); + +double floor(double x); +float floorf(float x); +long double floorl(long double x); + +double nearbyint(double x); +float nearbyintf(float x); +long double nearbyintl(long double x); + +double rint(double x); +float rintf(float x); +long double rintl(long double x); + +long lrint(double x); +long lrintf(float x); +long lrintl(long double x); + +long long llrint(double x); +long long llrintf(float x); +long long llrintl(long double x); + +double round(double x); +float roundf(float x); +long double roundl(long double x); + +long lround(double x); +long lroundf(float x); +long lroundl(long double x); + +long long llround(double x); +long long llroundf(float x); +long long llroundl(long double x); + +double trunc(double x); +float truncf(float x); +long double truncl(long double x); + +// [C11/7.12.10 Remainder functions] + +double fmod(double x, double y); +float fmodf(float x, float y); +long double fmodl(long double x, long double y); + +double remainder(double x, double y); +float remainderf(float x, float y); +long double remainderl(long double x, long double y); + +double remquo(double x, double y, int *quotient); +float remquof(float x, float y, int *quotient); +long double remquol(long double x, long double y, int *quotient); + +// [C11/7.12.11 Manipulation functions] + +double copysign(double x, double sign); +float copysignf(float x, float sign); +long double copysignl(long double x, long double sign); + +double nan(const char *tag); +float nanf(const char *tag); +long double nanl(const char *tag); + +double nextafter(double x, double dir); +float nextafterf(float x, float dir); +long double nextafterl(long double x, long double dir); + +double nexttoward(double x, long double dir); +float nexttowardf(float x, long double dir); +long double nexttowardl(long double x, long double dir); + +// [C11/7.12.12 Maximum, minimum and positive difference functions] + +double fdim(double x, double y); +float fdimf(float x, float y); +long double fdiml(long double x, long double y); + +double fmax(double x, double y); +float fmaxf(float x, float y); +long double fmaxl(long double x, long double y); + +double fmin(double x, double y); +float fminf(float x, float y); +long double fminl(long double x, long double y); + +// [C11/7.12.13 Floating multiply-add] + +double fma(double, double, double); +float fmaf(float, float, float); +long double fmal(long double, long double, long double); + +extern int signgam; +#define __signgam signgam + +// BSD floating-point classification functions - obsolete + +int finite(double x); +int finitef(float x); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif // _MATH_H + diff --git a/lib/mlibc/options/ansi/include/mlibc/ansi-sysdeps.hpp b/lib/mlibc/options/ansi/include/mlibc/ansi-sysdeps.hpp new file mode 100644 index 0000000..203084e --- /dev/null +++ b/lib/mlibc/options/ansi/include/mlibc/ansi-sysdeps.hpp @@ -0,0 +1,71 @@ +#ifndef MLIBC_ANSI_SYSDEPS +#define MLIBC_ANSI_SYSDEPS + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct rusage; + +namespace [[gnu::visibility("hidden")]] mlibc { + +[[noreturn]] void sys_exit(int status); +[[noreturn, gnu::weak]] void sys_thread_exit(); + +// If *stack is not null, it should point to the lowest addressable byte of the stack. +// Returns the new stack pointer in *stack and the stack base in *stack_base. +[[gnu::weak]] int sys_prepare_stack(void **stack, void *entry, void *user_arg, void* tcb, size_t *stack_size, size_t *guard_size, void **stack_base); +[[gnu::weak]] int sys_clone(void *tcb, pid_t *pid_out, void *stack); + +int sys_futex_wait(int *pointer, int expected, const struct timespec *time); +int sys_futex_wake(int *pointer); + +int sys_open(const char *pathname, int flags, mode_t mode, int *fd); +[[gnu::weak]] int sys_flock(int fd, int options); + +[[gnu::weak]] int sys_open_dir(const char *path, int *handle); +[[gnu::weak]] int sys_read_entries(int handle, void *buffer, size_t max_size, + size_t *bytes_read); + +int sys_read(int fd, void *buf, size_t count, ssize_t *bytes_read); + +int sys_write(int fd, const void *buf, size_t count, ssize_t *bytes_written); +[[gnu::weak]] int sys_pread(int fd, void *buf, size_t n, off_t off, ssize_t *bytes_read); + +int sys_seek(int fd, off_t offset, int whence, off_t *new_offset); +int sys_close(int fd); + +int sys_clock_get(int clock, time_t *secs, long *nanos); +[[gnu::weak]] int sys_clock_getres(int clock, time_t *secs, long *nanos); +[[gnu::weak]] int sys_sleep(time_t *secs, long *nanos); +// In contrast to the isatty() library function, the sysdep function uses return value +// zero (and not one) to indicate that the file is a terminal. +[[gnu::weak]] int sys_isatty(int fd); +[[gnu::weak]] int sys_rmdir(const char *path); +[[gnu::weak]] int sys_unlinkat(int dirfd, const char *path, int flags); +[[gnu::weak]] int sys_rename(const char *path, const char *new_path); +[[gnu::weak]] int sys_renameat(int olddirfd, const char *old_path, int newdirfd, const char *new_path); + +[[gnu::weak]] int sys_sigprocmask(int how, const sigset_t *__restrict set, + sigset_t *__restrict retrieve); +[[gnu::weak]] int sys_sigaction(int, const struct sigaction *__restrict, + struct sigaction *__restrict); + +[[gnu::weak]] int sys_fork(pid_t *child); +[[gnu::weak]] int sys_waitpid(pid_t pid, int *status, int flags, struct rusage *ru, pid_t *ret_pid); +[[gnu::weak]] int sys_execve(const char *path, char *const argv[], char *const envp[]); + +[[gnu::weak]] pid_t sys_getpid(); +[[gnu::weak]] int sys_kill(int, int); + +} //namespace mlibc + +#endif // MLIBC_ANSI_SYSDEPS diff --git a/lib/mlibc/options/ansi/include/mlibc/environment.hpp b/lib/mlibc/options/ansi/include/mlibc/environment.hpp new file mode 100644 index 0000000..7fd5cf9 --- /dev/null +++ b/lib/mlibc/options/ansi/include/mlibc/environment.hpp @@ -0,0 +1,10 @@ +#ifndef MLIBC_ENVIRONMENT_HPP +#define MLIBC_ENVIRONMENT_HPP + +namespace mlibc { + +int putenv(char *string); + +} // namespace mlibc + +#endif // MLIBC_ENVIRONMENT_HPP diff --git a/lib/mlibc/options/ansi/include/mlibc/file-io.hpp b/lib/mlibc/options/ansi/include/mlibc/file-io.hpp new file mode 100644 index 0000000..1155a2b --- /dev/null +++ b/lib/mlibc/options/ansi/include/mlibc/file-io.hpp @@ -0,0 +1,111 @@ +#ifndef MLIBC_FILE_IO_HPP +#define MLIBC_FILE_IO_HPP + +#include + +#include +#include +#include + +namespace mlibc { + +enum class stream_type { + unknown, + file_like, + pipe_like +}; + +enum class buffer_mode { + unknown, + no_buffer, + line_buffer, + full_buffer +}; + +struct abstract_file : __mlibc_file_base { +public: + abstract_file(void (*do_dispose)(abstract_file *) = nullptr); + + abstract_file(const abstract_file &) = delete; + + abstract_file &operator= (const abstract_file &) = delete; + + virtual ~abstract_file(); + + void dispose(); + + virtual int close() = 0; + virtual int reopen(const char *path, const char *mode) = 0; + + int read(char *buffer, size_t max_size, size_t *actual_size); + int write(const char *buffer, size_t max_size, size_t *actual_size); + int unget(char c); + + int update_bufmode(buffer_mode mode); + + void purge(); + int flush(); + + int tell(off_t *current_offset); + int seek(off_t offset, int whence); + +protected: + virtual int determine_type(stream_type *type) = 0; + virtual int determine_bufmode(buffer_mode *mode) = 0; + virtual int io_read(char *buffer, size_t max_size, size_t *actual_size) = 0; + virtual int io_write(const char *buffer, size_t max_size, size_t *actual_size) = 0; + virtual int io_seek(off_t offset, int whence, off_t *new_offset) = 0; + + int _reset(); +private: + int _init_type(); + int _init_bufmode(); + + int _write_back(); + int _save_pos(); + + void _ensure_allocation(); + + stream_type _type; + buffer_mode _bufmode; + void (*_do_dispose)(abstract_file *); + +public: + // lock for file operations + RecursiveFutexLock _lock; + // All files are stored in a global linked list, so that they can be flushed at exit(). + frg::default_list_hook _list_hook; +}; + +struct fd_file : abstract_file { + fd_file(int fd, void (*do_dispose)(abstract_file *) = nullptr, bool force_unbuffered = false); + + int fd(); + + int close() override; + int reopen(const char *path, const char *mode) override; + + static int parse_modestring(const char *mode); + +protected: + int determine_type(stream_type *type) override; + int determine_bufmode(buffer_mode *mode) override; + + int io_read(char *buffer, size_t max_size, size_t *actual_size) override; + int io_write(const char *buffer, size_t max_size, size_t *actual_size) override; + int io_seek(off_t offset, int whence, off_t *new_offset) override; + +private: + // Underlying file descriptor. + int _fd; + bool _force_unbuffered; +}; + +template +void file_dispose_cb(abstract_file *base) { + frg::destruct(getAllocator(), static_cast(base)); +} + +} // namespace mlibc + +#endif // MLIBC_FILE_IO_HPP diff --git a/lib/mlibc/options/ansi/include/setjmp.h b/lib/mlibc/options/ansi/include/setjmp.h new file mode 100644 index 0000000..30346f0 --- /dev/null +++ b/lib/mlibc/options/ansi/include/setjmp.h @@ -0,0 +1,48 @@ + +#ifndef _SETJMP_H +#define _SETJMP_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +// [C11/7.13] Non-local jumps + +typedef struct __jmp_buf { + struct __mlibc_jmpbuf_register_state reg_state; +} jmp_buf[1]; + +#ifndef __MLIBC_ABI_ONLY + +__attribute__((__returns_twice__)) int setjmp(jmp_buf buffer); +__attribute__((__noreturn__)) void longjmp(jmp_buf buffer, int value); + +#endif /* !__MLIBC_ABI_ONLY */ + +// POSIX Non-local jumps signal extensions + +typedef struct __sigjmp_buf { + struct __mlibc_jmpbuf_register_state reg_state; + int savesigs; + sigset_t sigset; +} sigjmp_buf[1]; + +#ifndef __MLIBC_ABI_ONLY + +#if __MLIBC_POSIX_OPTION +__attribute__((__returns_twice__)) int sigsetjmp(sigjmp_buf buffer, int savesigs); +__attribute__((__noreturn__)) void siglongjmp(sigjmp_buf buffer, int value); +#endif // __MLIBC_POSIX_OPTION + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif // _SETJMP_H + diff --git a/lib/mlibc/options/ansi/include/signal.h b/lib/mlibc/options/ansi/include/signal.h new file mode 100644 index 0000000..e27592b --- /dev/null +++ b/lib/mlibc/options/ansi/include/signal.h @@ -0,0 +1,48 @@ +#ifndef _SIGNAL_H +#define _SIGNAL_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +// [7.14] Signal handling basics + +typedef int sig_atomic_t; + +#define CLD_EXITED 1 +#define CLD_KILLED 2 +#define CLD_DUMPED 3 +#define CLD_TRAPPED 4 +#define CLD_STOPPED 5 +#define CLD_CONTINUED 6 + +#ifndef __MLIBC_ABI_ONLY + +// [7.14.1] signal() function + +__sighandler signal(int sig, __sighandler handler); + +// [7.14.2] raise() function + +int raise(int sig); + +#endif /* !__MLIBC_ABI_ONLY */ + +#define _NSIG NSIG + +#ifdef __cplusplus +} +#endif + +#if __MLIBC_POSIX_OPTION +# include +#endif + +#if __MLIBC_GLIBC_OPTION +# include +#endif + +#endif // _SIGNAL_H diff --git a/lib/mlibc/options/ansi/include/stdc-predef.h b/lib/mlibc/options/ansi/include/stdc-predef.h new file mode 100644 index 0000000..a0e3e92 --- /dev/null +++ b/lib/mlibc/options/ansi/include/stdc-predef.h @@ -0,0 +1,6 @@ +#ifndef _STDC_PREDEF_H +#define _STDC_PREDEF_H + +#define __STDC_ISO_10646__ 201206L + +#endif /* _STDC_PREDEF_H */ diff --git a/lib/mlibc/options/ansi/include/stdio.h b/lib/mlibc/options/ansi/include/stdio.h new file mode 100644 index 0000000..168a3c7 --- /dev/null +++ b/lib/mlibc/options/ansi/include/stdio.h @@ -0,0 +1,229 @@ + +#ifndef _STDIO_H +#define _STDIO_H + +#include +#include +#include +#include + +// Glibc extensions require ssize_t. +#include + +#ifdef __cplusplus +extern "C" { +#endif + +// [C11-7.21.1] I/O related types + +#define __MLIBC_EOF_BIT 1 +#define __MLIBC_ERROR_BIT 2 + +struct __mlibc_file_base { + // Buffer for I/O operations. + // We reserve a few extra bytes for ungetc operations. This means + // that __buffer_ptr will point a few bytes *into* the allocation. + char *__buffer_ptr; + + // Number of bytes the buffer can hold. + size_t __buffer_size; + + // Current offset inside the buffer. + size_t __offset; + + // Position inside the buffer that matches the current file pointer. + size_t __io_offset; + + // Valid region of the buffer. + size_t __valid_limit; + + // Begin and end of the dirty region inside the buffer. + size_t __dirty_begin; + size_t __dirty_end; + + // This points to the same place as __buffer_ptr, or a few bytes earlier + // if there are bytes pushed by ungetc. If buffering is disabled, calls + // to ungetc will trigger an allocation. + char *__unget_ptr; + + // 0 if we are currently reading from the buffer. + // 1 if we are currently writing to the buffer. + // This is only really important for pipe-like streams. + int __io_mode; + + // EOF and error bits. + int __status_bits; +}; + +typedef struct __mlibc_file_base FILE; +typedef size_t fpos_t; + +// [C11-7.21.1] I/O related macros + +#define _IOFBF 1 +#define _IOLBF 2 +#define _IONBF 3 + +#define BUFSIZ 512 + +#define EOF (-1) + +#define FOPEN_MAX 1024 +#define FILENAME_MAX 256 +#define L_tmpnam 256 + +#define TMP_MAX 1024 + +#ifndef __MLIBC_ABI_ONLY + +extern FILE *stderr; +extern FILE *stdin; +extern FILE *stdout; + +// [C11-7.21.4] Operations on files + +int remove(const char *filename); +int rename(const char *old_path, const char *new_path); +int renameat(int olddirfd, const char *old_path, int newdirfd, const char *new_path); +FILE *tmpfile(void); +char *tmpnam(char *buffer); + +// [C11-7.21.5] File access functions + +int fclose(FILE *stream); +int fflush(FILE *stream); +FILE *fopen(const char *__restrict filename, const char *__restrict mode); +FILE *freopen(const char *__restrict filename, const char *__restrict mode, FILE *__restrict stream); +void setbuf(FILE *__restrict stream, char *__restrict buffer); +int setvbuf(FILE *__restrict stream, char *__restrict buffer, int mode, size_t size); +void setlinebuf(FILE *stream); +void setbuffer(FILE *, char *, size_t); + +// [C11-7.21.6] Formatted input/output functions + +__attribute__((__format__(printf, 2, 3))) +int fprintf(FILE *__restrict stream, const char *__restrict format, ...); + +__attribute__((__format__(scanf, 2, 3))) +int fscanf(FILE *__restrict stream, const char *__restrict format, ...); + +__attribute__((__format__(printf, 1, 2))) +int printf(const char *__restrict format, ...); + +__attribute__((__format__(scanf, 1, 2))) +int scanf(const char *__restrict format, ...); + +__attribute__((__format__(printf, 3, 4))) +int snprintf(char *__restrict buffer, size_t max_size, const char *__restrict format, ...); + +__attribute__((__format__(printf, 2, 3))) +int sprintf(char *__restrict buffer, const char *__restrict format, ...); + +__attribute__((__format__(scanf, 2, 3))) +int sscanf(const char *__restrict buffer, const char *__restrict format, ...); + +__attribute__((__format__(printf, 2, 0))) +int vfprintf(FILE *__restrict stream, const char *__restrict format, __builtin_va_list args); + +__attribute__((__format__(scanf, 2, 0))) +int vfscanf(FILE *__restrict stream, const char *__restrict format, __builtin_va_list args); + +__attribute__((__format__(printf, 1, 0))) +int vprintf(const char *__restrict format, __builtin_va_list args); + +__attribute__((__format__(scanf, 1, 0))) +int vscanf(const char *__restrict format, __builtin_va_list args); + +__attribute__((__format__(printf, 3, 0))) +int vsnprintf(char *__restrict buffer, size_t max_size, + const char *__restrict format, __builtin_va_list args); + +__attribute__((__format__(printf, 2, 0))) +int vsprintf(char *__restrict buffer, const char *__restrict format, __builtin_va_list args); + +__attribute__((__format__(scanf, 2, 0))) +int vsscanf(const char *__restrict buffer, const char *__restrict format, __builtin_va_list args); + +// this is a gnu extension +__attribute__((__format__(printf, 2, 0))) +int vasprintf(char **, const char *, __builtin_va_list); + +// [C11-7.21.7] Character input/output functions + +int fgetc(FILE *stream); +char *fgets(char *__restrict buffer, size_t max_size, FILE *__restrict stream); +int fputc(int c, FILE *stream); +int fputs(const char *__restrict string, FILE *__restrict stream); +char *gets(char *s); +int getc(FILE *stream); +int getchar(void); +int putc(int c, FILE *stream); +int putchar(int c); +int puts(const char *string); +int ungetc(int c, FILE *stream); + +// [C11-7.21.8] Direct input/output functions + +size_t fread(void *__restrict buffer, size_t size, size_t count, FILE *__restrict stream); +size_t fwrite(const void *__restrict buffer, size_t size, size_t count, FILE *__restrict stream); + +// [C11-7.21.9] File positioning functions + +int fgetpos(FILE *__restrict stream, fpos_t *__restrict position); +int fseek(FILE *stream, long offset, int whence); +int fsetpos(FILE *stream, const fpos_t *position); +long ftell(FILE *stream); +void rewind(FILE *stream); + +// [C11-7.21.10] Error handling functions + +void clearerr(FILE *stream); +int feof(FILE *stream); +int ferror(FILE *stream); +void perror(const char *string); + +// POSIX unlocked I/O extensions. + +int getc_unlocked(FILE *); +int getchar_unlocked(void); +int putc_unlocked(int, FILE *); +int putchar_unlocked(int); + +// GLIBC extensions. + +ssize_t getline(char **, size_t *, FILE *); +ssize_t getdelim(char **, size_t *, int, FILE *); + +int asprintf(char **, const char *, ...); + +// Linux unlocked I/O extensions. + +void flockfile(FILE *); +void funlockfile(FILE *); +int ftrylockfile(FILE *); + +void clearerr_unlocked(FILE *); +int feof_unlocked(FILE *); +int ferror_unlocked(FILE *); +int fileno_unlocked(FILE *); +int fflush_unlocked(FILE *); +int fgetc_unlocked(FILE *); +int fputc_unlocked(int, FILE *); +size_t fread_unlocked(void *__restrict, size_t, size_t, FILE *__restrict); +size_t fwrite_unlocked(const void *__restrict, size_t, size_t, FILE *__restrict); + +char *fgets_unlocked(char *, int, FILE *); +int fputs_unlocked(const char *, FILE *); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#if __MLIBC_POSIX_OPTION +# include +#endif + +#endif // _STDIO_H + diff --git a/lib/mlibc/options/ansi/include/stdlib.h b/lib/mlibc/options/ansi/include/stdlib.h new file mode 100644 index 0000000..d0e916a --- /dev/null +++ b/lib/mlibc/options/ansi/include/stdlib.h @@ -0,0 +1,128 @@ +#ifndef _STDLIB_H +#define _STDLIB_H + +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +// [7.22] General utilities + +typedef struct { + int quot, rem; +} div_t; + +typedef struct { + long quot, rem; +} ldiv_t; + +typedef struct { + long long quot, rem; +} lldiv_t; + +#define EXIT_FAILURE 1 +#define EXIT_SUCCESS 0 + +#define RAND_MAX 0x7FFFFFFF + +// TODO: this should not be a compile-time constant +#define MB_CUR_MAX 4 + +#ifndef __MLIBC_ABI_ONLY + +// [7.22.1] Numeric conversion functions + +double atof(const char *string); +int atoi(const char *string); +long atol(const char *string); +long long atoll(const char *string); +double strtod(const char *__restrict string, char **__restrict end); +float strtof(const char *__restrict string, char **__restrict end); +long double strtold(const char *__restrict string, char **__restrict end); +long strtol(const char *__restrict string, char **__restrict end, int base); +long long strtoll(const char *__restrict string, char **__restrict end, int base); +unsigned long strtoul(const char *__restrict string, char **__restrict end, int base); +unsigned long long strtoull(const char *__restrict string, char **__restrict end, int base); + +// [7.22.2] Pseudo-random sequence generation functions + +int rand(void); +int rand_r(unsigned *); +void srand(unsigned int); + +// [7.22.3] Memory management functions + +void *aligned_alloc(size_t alignment, size_t size); +void *calloc(size_t count, size_t size); +void free(void *pointer); +void *malloc(size_t size); +void *realloc(void *pointer, size_t size); + +int posix_memalign(void **, size_t, size_t); + +// [7.22.4] Communication with the environment + +__attribute__((__noreturn__)) void abort(void); +int atexit(void (*func)(void)); +int at_quick_exit(void (*func)(void)); +__attribute__((__noreturn__)) void exit(int status); +__attribute__((__noreturn__)) void _Exit(int status); +char *getenv(const char *name); +__attribute__((__noreturn__)) void quick_exit(int status); +int system(const char *string); + +// GLIBC extension. +char *mktemp(char *); + +// [7.22.5] Searching and sorting utilities + +void *bsearch(const void *key, const void *base, size_t count, size_t size, + int (*compare)(const void *, const void *)); +void qsort(void *base, size_t count, size_t size, + int (*compare)(const void *, const void *)); +void qsort_r(void *base, size_t nmemb, size_t size, + int (*compar)(const void *, const void *, void *), + void *arg); + +// [7.22.6] Integer arithmetic functions + +int abs(int number); +long labs(long number); +long long llabs(long long number); + +div_t div(int number, int denom); +ldiv_t ldiv(long number, long denom); +lldiv_t lldiv(long long number, long long denom); + +// [7.22.7] Multibyte character conversion functions + +int mblen(const char *, size_t); +int mbtowc(wchar_t *__restrict wc, const char *__restrict mb_chr, size_t max_size); +int wctomb(char *mb_chr, wchar_t wc); + +// [7.22.8] Multibyte string conversion functions + +size_t mbstowcs(wchar_t *__restrict wc_string, const char *__restrict mb_string, size_t max_size); +size_t wcstombs(char *mb_string, const wchar_t *__restrict wc_string, size_t max_size); + +#endif /* !__MLIBC_ABI_ONLY */ + +#if __MLIBC_GLIBC_OPTION +typedef int (*comparison_fn_t) (const void *, const void *); +#endif + +#ifdef __cplusplus +} +#endif + +#if __MLIBC_POSIX_OPTION +# include +#endif + +#endif // _STDLIB_H + diff --git a/lib/mlibc/options/ansi/include/string.h b/lib/mlibc/options/ansi/include/string.h new file mode 100644 index 0000000..5297e36 --- /dev/null +++ b/lib/mlibc/options/ansi/include/string.h @@ -0,0 +1,107 @@ +#ifndef _STRING_H +#define _STRING_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +// [7.24.2] Copying functions + +void *memcpy(void *__restrict dest, const void *__restrict src, size_t size); +void *memmove(void *dest, const void *src, size_t size); +char *strcpy(char *__restrict dest, const char *src); +char *strncpy(char *__restrict dest, const char *src, size_t max_size); + +// [7.24.3] Concatenation functions + +char *strcat(char *__restrict dest, const char *__restrict src); +char *strncat(char *__restrict dest, const char *__restrict src, size_t max_size); + +// [7.24.4] Comparison functions + +int memcmp(const void *a, const void *b, size_t size); +int strcmp(const char *a, const char *b); +int strcoll(const char *a, const char *b); +int strncmp(const char *a, const char *b, size_t max_size); +size_t strxfrm(char *__restrict dest, const char *__restrict src, size_t max_size); + +// [7.24.5] Search functions + +void *memchr(const void *s, int c, size_t size); +char *strchr(const char *s, int c); +size_t strcspn(const char *s, const char *chrs); +char *strpbrk(const char *s, const char *chrs); +char *strrchr(const char *s, int c); +size_t strspn(const char *s, const char *chrs); +char *strstr(const char *pattern, const char *s); +char *strtok(char *__restrict s, const char *__restrict delimiter); + +// This is a GNU extension. +char *strchrnul(const char *, int); + +// [7.24.6] Miscellaneous functions + +void *memset(void *dest, int c, size_t size); +char *strerror(int errnum); +size_t strlen(const char *s); + +#endif /* !__MLIBC_ABI_ONLY */ + +#if __MLIBC_POSIX_OPTION && (defined(_BSD_SOURCE) || defined(_GNU_SOURCE)) +#include +#endif + +#ifndef __MLIBC_ABI_ONLY + +// POSIX extensions. +int strerror_r(int, char *, size_t); +void *mempcpy(void *, const void *, size_t); + +// GNU extensions. +int strverscmp(const char *l0, const char *r0); +int ffsl(long i); +int ffsll(long long i); +void *memmem(const void *, size_t, const void *, size_t); + +/* Handling the basename mess: + * If is included *at all*, we use the XPG-defined basename + * implementation, otherwise, we use the GNU one. Since our ABI previously + * provided the XPG one under basename, we'll have to diverge from GNU here and + * provide __mlibc_gnu_basename instead. + */ +#if __MLIBC_GLIBC_OPTION && defined(_GNU_SOURCE) && !defined(basename) +char *__mlibc_gnu_basename_c(const char *path); + +# ifdef __cplusplus +extern "C++" { +static inline const char *__mlibc_gnu_basename(const char *path) { + return __mlibc_gnu_basename_c(path); +} +static inline char *__mlibc_gnu_basename(char *path) { + return __mlibc_gnu_basename_c(path); +} +} +# else +# define __mlibc_gnu_basename __mlibc_gnu_basename_c +# endif + +#define basename __mlibc_gnu_basename +#endif + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#if __MLIBC_POSIX_OPTION +# include +#endif + +#endif // _STRING_H diff --git a/lib/mlibc/options/ansi/include/threads.h b/lib/mlibc/options/ansi/include/threads.h new file mode 100644 index 0000000..f96abcd --- /dev/null +++ b/lib/mlibc/options/ansi/include/threads.h @@ -0,0 +1,61 @@ +#ifndef _THREADS_H +#define _THREADS_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +enum { + mtx_plain, + mtx_recursive, + mtx_timed, +}; + +enum { + thrd_success, + thrd_timedout, + thrd_busy, + thrd_error, + thrd_nomem, +}; + +typedef struct __mlibc_thread_data *thrd_t; +typedef struct __mlibc_mutex mtx_t; +typedef struct __mlibc_cond cnd_t; +#ifndef __cplusplus +#define thread_local _Thread_local +#endif + +typedef int (*thrd_start_t)(void*); + +#ifndef __MLIBC_ABI_ONLY + +int thrd_create(thrd_t *thr, thrd_start_t func, void *arg); +int thrd_equal(thrd_t lhs, thrd_t rhs); +thrd_t thrd_current(void); +int thrd_sleep(const struct timespec *duration, struct timespec *remaining); +void thrd_yield(void); +int thrd_detach(thrd_t thr); +int thrd_join(thrd_t thr, int *res); +__attribute__((__noreturn__)) void thrd_exit(int res); + +int mtx_init(mtx_t *mtx, int type); +void mtx_destroy(mtx_t *mtx); +int mtx_lock(mtx_t *mtx); +int mtx_unlock(mtx_t *mtx); + +int cnd_init(cnd_t *cond); +void cnd_destroy(cnd_t *cond); +int cnd_broadcast(cnd_t *cond); +int cnd_wait(cnd_t *cond, mtx_t *mtx); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _THREADS_H */ + diff --git a/lib/mlibc/options/ansi/include/time.h b/lib/mlibc/options/ansi/include/time.h new file mode 100644 index 0000000..a3239e9 --- /dev/null +++ b/lib/mlibc/options/ansi/include/time.h @@ -0,0 +1,154 @@ +#ifndef _TIME_H +#define _TIME_H + +#include +#include +#include +#include +#include + +// [7.27.1] Components of time + +#define CLOCKS_PER_SEC ((clock_t)1000000) + +#define TIME_UTC 1 + +// POSIX extensions. + +#define CLOCK_REALTIME 0 +#define CLOCK_MONOTONIC 1 +#define CLOCK_PROCESS_CPUTIME_ID 2 +#define CLOCK_THREAD_CPUTIME_ID 3 +#define CLOCK_MONOTONIC_RAW 4 +#define CLOCK_REALTIME_COARSE 5 +#define CLOCK_MONOTONIC_COARSE 6 +#define CLOCK_BOOTTIME 7 +#define CLOCK_REALTIME_ALARM 8 +#define CLOCK_BOOTTIME_ALARM 9 + +#ifdef __cplusplus +extern "C" { +#endif + +// [7.27.1] Components of time + +typedef long clock_t; // Matches Linux' ABI. + +struct tm { + int tm_sec; + int tm_min; + int tm_hour; + int tm_mday; + int tm_mon; + int tm_year; + int tm_wday; + int tm_yday; + int tm_isdst; + long int tm_gmtoff; + const char *tm_zone; +}; + +#ifndef __MLIBC_ABI_ONLY + +// [7.27.2] Time manipulation functions + +clock_t clock(void); +double difftime(time_t a, time_t b); +time_t mktime(struct tm *ptr); +time_t time(time_t *timer); +int timespec_get(struct timespec *ptr, int base); + +// [7.27.3] Time conversion functions + +char *asctime(const struct tm *ptr); +char *ctime(const time_t *timer); +struct tm *gmtime(const time_t *timer); +struct tm *gmtime_r(const time_t *__restrict timer, struct tm *__restrict result); +struct tm *localtime(const time_t *timer); +size_t strftime(char *__restrict dest, size_t max_size, + const char *__restrict format, const struct tm *__restrict ptr); + +void tzset(void); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +// POSIX extensions. + +#if __MLIBC_POSIX_OPTION +# include +# include +#endif // __MLIBC_POSIX_OPTION + +#include + +#define TIMER_ABSTIME 1 + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +extern int daylight; +extern long timezone; +extern char *tzname[2]; + +int nanosleep(const struct timespec *, struct timespec *); + +int clock_getres(clockid_t, struct timespec *); +int clock_gettime(clockid_t, struct timespec *); +int clock_nanosleep(clockid_t, int, const struct timespec *, struct timespec *); +int clock_settime(clockid_t, const struct timespec *); + +struct tm *localtime_r(const time_t *, struct tm *); +char *asctime_r(const struct tm *tm, char *buf); +char *ctime_r(const time_t *, char *); + +#if __MLIBC_POSIX_OPTION +char *strptime(const char *__restrict, const char *__restrict, + struct tm *__restrict); +#endif /* __MLIBC_POSIX_OPTION */ + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +// GNU extensions. + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +time_t timelocal(struct tm *); +time_t timegm(struct tm *); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +// Linux extensions. + +#ifdef __cplusplus +extern "C" { +#endif + +struct itimerspec { + struct timespec it_interval; + struct timespec it_value; +}; + +#ifdef __cplusplus +} +#endif + +#endif // _TIME_H diff --git a/lib/mlibc/options/ansi/include/uchar.h b/lib/mlibc/options/ansi/include/uchar.h new file mode 100644 index 0000000..3651a60 --- /dev/null +++ b/lib/mlibc/options/ansi/include/uchar.h @@ -0,0 +1,29 @@ +#ifndef _UCHAR_H +#define _UCHAR_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +#ifndef __cplusplus +typedef __CHAR16_TYPE__ char16_t; +typedef __CHAR32_TYPE__ char32_t; +#endif /* __cplusplus */ + +typedef struct __mlibc_mbstate mbstate_t; + +#ifndef __MLIBC_ABI_ONLY + +size_t c32rtomb(char *pmb, char32_t c32, mbstate_t *ps); +size_t mbrtoc32(char32_t *pc32, const char *pmb, size_t max, mbstate_t *ps); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _UCHAR_H */ diff --git a/lib/mlibc/options/ansi/include/wchar.h b/lib/mlibc/options/ansi/include/wchar.h new file mode 100644 index 0000000..27198c5 --- /dev/null +++ b/lib/mlibc/options/ansi/include/wchar.h @@ -0,0 +1,128 @@ +#ifndef _WCHAR_H +#define _WCHAR_H + +#include +#include +#include +#include +#include +#include + +#define WEOF 0xffffffffU + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct __mlibc_file_base FILE; + +typedef struct __mlibc_mbstate mbstate_t; + +// MISSING: struct tm + +#ifndef __MLIBC_ABI_ONLY + +// [7.28.2] Wide formatted I/O functions + +int fwprintf(FILE *__restrict, const wchar_t *__restrict, ...); +int fwscanf(FILE *__restrict, const wchar_t *__restrict, ...); +int vfwprintf(FILE *__restrict, const wchar_t *__restrict, __builtin_va_list); +int vfwscanf(FILE *__restrict, const wchar_t *__restrict, __builtin_va_list); + +int swprintf(wchar_t *__restrict, size_t, const wchar_t *__restrict, ...); +int swscanf(wchar_t *__restrict, size_t, const wchar_t *__restrict, ...); +int vswprintf(wchar_t *__restrict, size_t, const wchar_t *__restrict, __builtin_va_list); +int vswscanf(wchar_t *__restrict, size_t, const wchar_t *__restrict, __builtin_va_list); + +int wprintf(const wchar_t *__restrict, ...); +int wscanf(const wchar_t *__restrict, ...); +int vwprintf(const wchar_t *__restrict, __builtin_va_list); +int vwscanf(const wchar_t *__restrict, __builtin_va_list); + +// [7.28.3] Wide character I/O functions + +wint_t fgetwc(FILE *); +wchar_t *fgetws(wchar_t *__restrict, int, FILE *__restrict); +wint_t fputwc(wchar_t, FILE *); +int fputws(const wchar_t *__restrict, FILE *__restrict); +int fwide(FILE *, int); +wint_t getwc(FILE *); +wint_t getwchar(void); +wint_t putwc(wchar_t, FILE *); +wint_t putwchar(wchar_t); +wint_t ungetwc(wint_t, FILE *); + +// [7.28.4] Wide string functions + +double wcstod(const wchar_t *__restrict, wchar_t **__restrict); +float wcstof(const wchar_t *__restrict, wchar_t **__restrict); +long double wcstold(const wchar_t *__restrict, wchar_t **__restrict); + +long wcstol(const wchar_t *__restrict, wchar_t **__restrict, int); +long long wcstoll(const wchar_t *__restrict, wchar_t **__restrict, int); +unsigned long wcstoul(const wchar_t *__restrict, wchar_t **__restrict, int); +unsigned long long wcstoull(const wchar_t *__restrict, wchar_t **__restrict, int); + +wchar_t *wcscpy(wchar_t *__restrict, const wchar_t *__restrict); +wchar_t *wcsncpy(wchar_t *__restrict, const wchar_t *__restrict, size_t); +wchar_t *wmemcpy(wchar_t *__restrict, const wchar_t *__restrict, size_t); +wchar_t *wmemmove(wchar_t *, const wchar_t *, size_t); + +wchar_t *wcscat(wchar_t *__restrict, const wchar_t *__restrict); +wchar_t *wcsncat(wchar_t *__restrict, const wchar_t *__restrict, size_t); + +int wcscmp(const wchar_t *, const wchar_t *); +int wcscoll(const wchar_t *, const wchar_t *); +int wcsncmp(const wchar_t *, const wchar_t *, size_t); +int wcsxfrm(wchar_t *__restrict, const wchar_t *__restrict, size_t); +int wmemcmp(const wchar_t *, const wchar_t *, size_t); + +wchar_t *wcschr(const wchar_t *, wchar_t); +size_t wcscspn(const wchar_t *, const wchar_t *); +wchar_t *wcspbrk(const wchar_t *, const wchar_t *); +wchar_t *wcsrchr(const wchar_t *, wchar_t); +size_t wcsspn(const wchar_t *, const wchar_t *); +wchar_t *wcsstr(const wchar_t *, const wchar_t *); +wchar_t *wcstok(wchar_t *__restrict, const wchar_t *__restrict, wchar_t **__restrict); +wchar_t *wmemchr(const wchar_t *, wchar_t, size_t); + +size_t wcslen(const wchar_t *); +wchar_t *wmemset(wchar_t *, wchar_t, size_t); + +// [7.28.5] Wide date/time functions + +/* POSIX says: + * The tag tm is declared as naming an incomplete structure type, the contents of which are + * described in the header . */ +struct tm; +size_t wcsftime(wchar_t *__restrict, size_t, const wchar_t *__restrict, + const struct tm *__restrict); + +// [7.28.6] Wide conversion functions + +wint_t btowc(int c); +int wctob(wint_t); + +int mbsinit(const mbstate_t *); +size_t mbrlen(const char *__restrict, size_t, mbstate_t *__restrict); +size_t mbrtowc(wchar_t *__restrict, const char *__restrict, size_t, mbstate_t *__restrict); +size_t wcrtomb(char *__restrict, wchar_t, mbstate_t *__restrict); +size_t mbsrtowcs(wchar_t *__restrict, const char **__restrict, size_t, mbstate_t *__restrict); +size_t mbsnrtowcs(wchar_t *__restrict, const char **__restrict, size_t, size_t, mbstate_t *__restrict); +size_t wcsrtombs(char *__restrict, const wchar_t **__restrict, size_t, mbstate_t *__restrict); +size_t wcsnrtombs(char *__restrict, const wchar_t **__restrict, size_t, size_t, mbstate_t *__restrict); + +// POSIX extensions +int wcwidth(wchar_t wc); +int wcswidth(const wchar_t *, size_t); +wchar_t *wcsdup(const wchar_t *s); +int wcsncasecmp(const wchar_t*, const wchar_t*, size_t); +int wcscasecmp(const wchar_t *, const wchar_t *); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif // _WCHAR_H diff --git a/lib/mlibc/options/ansi/include/wctype.h b/lib/mlibc/options/ansi/include/wctype.h new file mode 100644 index 0000000..df5d37a --- /dev/null +++ b/lib/mlibc/options/ansi/include/wctype.h @@ -0,0 +1,52 @@ +#ifndef _WCTYPE_H +#define _WCTYPE_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef unsigned long wctype_t; +typedef unsigned long wctrans_t; + +#ifndef __MLIBC_ABI_ONLY + +// [C11/7.30.2.2] Extensible wide character classification functions. + +int iswalnum(wint_t); +int iswalpha(wint_t); +int iswblank(wint_t); +int iswcntrl(wint_t); +int iswdigit(wint_t); +int iswgraph(wint_t); +int iswlower(wint_t); +int iswprint(wint_t); +int iswpunct(wint_t); +int iswspace(wint_t); +int iswupper(wint_t); +int iswxdigit(wint_t); + +wctype_t wctype(const char *); +int iswctype(wint_t, wctype_t); + +// [C11/7.30.3] Wide character case mapping utilities. + +wint_t towlower(wint_t); +wint_t towupper(wint_t); + +wctrans_t wctrans(const char *); +wint_t towctrans(wint_t, wctrans_t); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#if __MLIBC_POSIX_OPTION +# include +#endif + +#endif // _WCTYPE_H diff --git a/lib/mlibc/options/ansi/meson.build b/lib/mlibc/options/ansi/meson.build new file mode 100644 index 0000000..ae1d3ad --- /dev/null +++ b/lib/mlibc/options/ansi/meson.build @@ -0,0 +1,326 @@ + +if disable_ansi_option + subdir_done() +endif + +ansi_sources = files( + 'generic/stdlib-stubs.cpp', + 'generic/assert-stubs.cpp', + 'generic/complex-stubs.c', + + 'generic/complex/csqrt.c', + 'generic/complex/csinhf.c', + 'generic/complex/ccoshf.c', + 'generic/complex/cacosh.c', + 'generic/complex/casinf.c', + 'generic/complex/clogf.c', + 'generic/complex/csqrtf.c', + 'generic/complex/cimag.c', + 'generic/complex/catanh.c', + 'generic/complex/carg.c', + 'generic/complex/cproj.c', + 'generic/complex/cephes_subr.c', + 'generic/complex/ccos.c', + 'generic/complex/cexp.c', + 'generic/complex/crealf.c', + 'generic/complex/cabs.c', + 'generic/complex/csinh.c', + 'generic/complex/casinhf.c', + 'generic/complex/cephes_subrf.c', + 'generic/complex/creal.c', + 'generic/complex/casin.c', + 'generic/complex/conjf.c', + 'generic/complex/cpowf.c', + 'generic/complex/cacosf.c', + 'generic/complex/csinf.c', + 'generic/complex/ctanh.c', + 'generic/complex/ctanhf.c', + 'generic/complex/cargf.c', + 'generic/complex/cabsf.c', + 'generic/complex/cpow.c', + 'generic/complex/csin.c', + 'generic/complex/cprojf.c', + 'generic/complex/catan.c', + 'generic/complex/ctanf.c', + 'generic/complex/ctan.c', + 'generic/complex/clog.c', + 'generic/complex/catanf.c', + 'generic/complex/cacos.c', + 'generic/complex/cexpf.c', + 'generic/complex/ccosh.c', + 'generic/complex/cimagf.c', + 'generic/complex/cacoshf.c', + 'generic/complex/conj.c', + 'generic/complex/catanhf.c', + 'generic/complex/ccosf.c', + 'generic/complex/casinh.c', + + 'generic/ctype-stubs.cpp', + 'generic/environment.cpp', + 'generic/errno-stubs.cpp', + 'generic/fenv-stubs.cpp', + 'generic/file-io.cpp', + 'generic/inttypes-stubs.cpp', + 'generic/locale-stubs.cpp', + 'generic/signal-stubs.cpp', + 'generic/stdio-stubs.cpp', + 'generic/stdlib-stubs.cpp', + 'generic/string-stubs.cpp', + 'generic/threads.cpp', + 'generic/time-stubs.cpp', + 'generic/uchar.cpp', + 'generic/wchar-stubs.cpp', + 'generic/wctype.cpp', +) + +if not no_headers + install_headers( + 'include/alloca.h', + 'include/assert.h', + 'include/complex.h', + 'include/ctype.h', + 'include/errno.h', + 'include/fenv.h', + 'include/inttypes.h', + 'include/limits.h', + 'include/locale.h', + 'include/math.h', + 'include/setjmp.h', + 'include/signal.h', + 'include/stdc-predef.h', + 'include/stdio.h', + 'include/stdlib.h', + 'include/string.h', + 'include/threads.h', + 'include/time.h', + 'include/uchar.h', + 'include/wchar.h', + 'include/wctype.h', + ) + install_headers( + 'include/bits/ansi/timespec.h', + 'include/bits/ansi/time_t.h', + 'include/bits/ansi/fenv.h', + subdir: 'bits/ansi' + ) +endif + +if not headers_only + libc_sublibs += static_library('mlibc-musl-math', + 'musl-generic-math/acos.c', + 'musl-generic-math/acosf.c', + 'musl-generic-math/acosh.c', + 'musl-generic-math/acoshf.c', + 'musl-generic-math/acoshl.c', + 'musl-generic-math/acosl.c', + 'musl-generic-math/asin.c', + 'musl-generic-math/asinf.c', + 'musl-generic-math/asinh.c', + 'musl-generic-math/asinhf.c', + 'musl-generic-math/asinhl.c', + 'musl-generic-math/asinl.c', + 'musl-generic-math/atan2.c', + 'musl-generic-math/atan2f.c', + 'musl-generic-math/atan2l.c', + 'musl-generic-math/atan.c', + 'musl-generic-math/atanf.c', + 'musl-generic-math/atanh.c', + 'musl-generic-math/atanhf.c', + 'musl-generic-math/atanhl.c', + 'musl-generic-math/atanl.c', + 'musl-generic-math/cbrt.c', + 'musl-generic-math/cbrtf.c', + 'musl-generic-math/cbrtl.c', + 'musl-generic-math/ceil.c', + 'musl-generic-math/ceilf.c', + 'musl-generic-math/ceill.c', + 'musl-generic-math/copysign.c', + 'musl-generic-math/copysignf.c', + 'musl-generic-math/copysignl.c', + 'musl-generic-math/__cos.c', + 'musl-generic-math/cos.c', + 'musl-generic-math/__cosdf.c', + 'musl-generic-math/cosf.c', + 'musl-generic-math/cosh.c', + 'musl-generic-math/coshf.c', + 'musl-generic-math/coshl.c', + 'musl-generic-math/__cosl.c', + 'musl-generic-math/cosl.c', + 'musl-generic-math/erf.c', + 'musl-generic-math/erff.c', + 'musl-generic-math/erfl.c', + 'musl-generic-math/exp10.c', + 'musl-generic-math/exp10f.c', + 'musl-generic-math/exp10l.c', + 'musl-generic-math/exp2.c', + 'musl-generic-math/exp2f.c', + 'musl-generic-math/exp2l.c', + 'musl-generic-math/exp.c', + 'musl-generic-math/expf.c', + 'musl-generic-math/expl.c', + 'musl-generic-math/expm1.c', + 'musl-generic-math/expm1f.c', + 'musl-generic-math/expm1l.c', + 'musl-generic-math/__expo2.c', + 'musl-generic-math/__expo2f.c', + 'musl-generic-math/fabs.c', + 'musl-generic-math/fabsf.c', + 'musl-generic-math/fabsl.c', + 'musl-generic-math/fdim.c', + 'musl-generic-math/fdimf.c', + 'musl-generic-math/fdiml.c', + 'musl-generic-math/finite.c', + 'musl-generic-math/finitef.c', + 'musl-generic-math/floor.c', + 'musl-generic-math/floorf.c', + 'musl-generic-math/floorl.c', + 'musl-generic-math/fma.c', + 'musl-generic-math/fmaf.c', + 'musl-generic-math/fmal.c', + 'musl-generic-math/fmax.c', + 'musl-generic-math/fmaxf.c', + 'musl-generic-math/fmaxl.c', + 'musl-generic-math/fmin.c', + 'musl-generic-math/fminf.c', + 'musl-generic-math/fminl.c', + 'musl-generic-math/fmod.c', + 'musl-generic-math/fmodf.c', + 'musl-generic-math/fmodl.c', + 'musl-generic-math/__fpclassify.c', + 'musl-generic-math/__fpclassifyf.c', + 'musl-generic-math/__fpclassifyl.c', + 'musl-generic-math/frexp.c', + 'musl-generic-math/frexpf.c', + 'musl-generic-math/frexpl.c', + 'musl-generic-math/hypot.c', + 'musl-generic-math/hypotf.c', + 'musl-generic-math/hypotl.c', + 'musl-generic-math/ilogb.c', + 'musl-generic-math/ilogbf.c', + 'musl-generic-math/ilogbl.c', + 'musl-generic-math/__invtrigl.c', + 'musl-generic-math/j0.c', + 'musl-generic-math/j0f.c', + 'musl-generic-math/j1.c', + 'musl-generic-math/j1f.c', + 'musl-generic-math/jn.c', + 'musl-generic-math/jnf.c', + 'musl-generic-math/ldexp.c', + 'musl-generic-math/ldexpf.c', + 'musl-generic-math/ldexpl.c', + 'musl-generic-math/lgamma.c', + 'musl-generic-math/lgammaf.c', + 'musl-generic-math/lgammaf_r.c', + 'musl-generic-math/lgammal.c', + 'musl-generic-math/lgamma_r.c', + 'musl-generic-math/llrint.c', + 'musl-generic-math/llrintf.c', + 'musl-generic-math/llrintl.c', + 'musl-generic-math/llround.c', + 'musl-generic-math/llroundf.c', + 'musl-generic-math/llroundl.c', + 'musl-generic-math/log10.c', + 'musl-generic-math/log10f.c', + 'musl-generic-math/log10l.c', + 'musl-generic-math/log1p.c', + 'musl-generic-math/log1pf.c', + 'musl-generic-math/log1pl.c', + 'musl-generic-math/log2.c', + 'musl-generic-math/log2f.c', + 'musl-generic-math/log2l.c', + 'musl-generic-math/logb.c', + 'musl-generic-math/logbf.c', + 'musl-generic-math/logbl.c', + 'musl-generic-math/log.c', + 'musl-generic-math/logf.c', + 'musl-generic-math/logl.c', + 'musl-generic-math/lrint.c', + 'musl-generic-math/lrintf.c', + 'musl-generic-math/lrintl.c', + 'musl-generic-math/lround.c', + 'musl-generic-math/lroundf.c', + 'musl-generic-math/lroundl.c', + 'musl-generic-math/modf.c', + 'musl-generic-math/modff.c', + 'musl-generic-math/modfl.c', + 'musl-generic-math/nan.c', + 'musl-generic-math/nanf.c', + 'musl-generic-math/nanl.c', + 'musl-generic-math/nearbyint.c', + 'musl-generic-math/nearbyintf.c', + 'musl-generic-math/nearbyintl.c', + 'musl-generic-math/nextafter.c', + 'musl-generic-math/nextafterf.c', + 'musl-generic-math/nextafterl.c', + 'musl-generic-math/nexttoward.c', + 'musl-generic-math/nexttowardf.c', + 'musl-generic-math/nexttowardl.c', + 'musl-generic-math/__polevll.c', + 'musl-generic-math/pow.c', + 'musl-generic-math/powf.c', + 'musl-generic-math/powl.c', + 'musl-generic-math/remainder.c', + 'musl-generic-math/remainderf.c', + 'musl-generic-math/remainderl.c', + 'musl-generic-math/__rem_pio2.c', + 'musl-generic-math/__rem_pio2f.c', + 'musl-generic-math/__rem_pio2_large.c', + 'musl-generic-math/__rem_pio2l.c', + 'musl-generic-math/remquo.c', + 'musl-generic-math/remquof.c', + 'musl-generic-math/remquol.c', + 'musl-generic-math/rint.c', + 'musl-generic-math/rintf.c', + 'musl-generic-math/rintl.c', + 'musl-generic-math/round.c', + 'musl-generic-math/roundf.c', + 'musl-generic-math/roundl.c', + 'musl-generic-math/scalb.c', + 'musl-generic-math/scalbf.c', + 'musl-generic-math/scalbln.c', + 'musl-generic-math/scalblnf.c', + 'musl-generic-math/scalblnl.c', + 'musl-generic-math/scalbn.c', + 'musl-generic-math/scalbnf.c', + 'musl-generic-math/scalbnl.c', + 'musl-generic-math/__signbit.c', + 'musl-generic-math/__signbitf.c', + 'musl-generic-math/__signbitl.c', + 'musl-generic-math/signgam.c', + 'musl-generic-math/significand.c', + 'musl-generic-math/significandf.c', + 'musl-generic-math/__sin.c', + 'musl-generic-math/sin.c', + 'musl-generic-math/sincos.c', + 'musl-generic-math/sincosf.c', + 'musl-generic-math/sincosl.c', + 'musl-generic-math/__sindf.c', + 'musl-generic-math/sinf.c', + 'musl-generic-math/sinh.c', + 'musl-generic-math/sinhf.c', + 'musl-generic-math/sinhl.c', + 'musl-generic-math/__sinl.c', + 'musl-generic-math/sinl.c', + 'musl-generic-math/sqrt.c', + 'musl-generic-math/sqrtf.c', + 'musl-generic-math/sqrtl.c', + 'musl-generic-math/__tan.c', + 'musl-generic-math/tan.c', + 'musl-generic-math/__tandf.c', + 'musl-generic-math/tanf.c', + 'musl-generic-math/tanh.c', + 'musl-generic-math/tanhf.c', + 'musl-generic-math/tanhl.c', + 'musl-generic-math/__tanl.c', + 'musl-generic-math/tanl.c', + 'musl-generic-math/tgamma.c', + 'musl-generic-math/tgammaf.c', + 'musl-generic-math/tgammal.c', + 'musl-generic-math/trunc.c', + 'musl-generic-math/truncf.c', + 'musl-generic-math/truncl.c', + pic: true, + include_directories: libc_include_dirs, + dependencies: libc_deps, + c_args: ['-Wno-unused', '-Wno-implicit', '-Wno-parentheses', '-Wno-sign-compare', '-Wno-attributes', '-Wno-unknown-pragmas', '-Wno-maybe-uninitialized']) +endif diff --git a/lib/mlibc/options/ansi/musl-generic-math/__cos.c b/lib/mlibc/options/ansi/musl-generic-math/__cos.c new file mode 100644 index 0000000..46cefb3 --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/__cos.c @@ -0,0 +1,71 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/k_cos.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* + * __cos( x, y ) + * kernel cos function on [-pi/4, pi/4], pi/4 ~ 0.785398164 + * Input x is assumed to be bounded by ~pi/4 in magnitude. + * Input y is the tail of x. + * + * Algorithm + * 1. Since cos(-x) = cos(x), we need only to consider positive x. + * 2. if x < 2^-27 (hx<0x3e400000 0), return 1 with inexact if x!=0. + * 3. cos(x) is approximated by a polynomial of degree 14 on + * [0,pi/4] + * 4 14 + * cos(x) ~ 1 - x*x/2 + C1*x + ... + C6*x + * where the remez error is + * + * | 2 4 6 8 10 12 14 | -58 + * |cos(x)-(1-.5*x +C1*x +C2*x +C3*x +C4*x +C5*x +C6*x )| <= 2 + * | | + * + * 4 6 8 10 12 14 + * 4. let r = C1*x +C2*x +C3*x +C4*x +C5*x +C6*x , then + * cos(x) ~ 1 - x*x/2 + r + * since cos(x+y) ~ cos(x) - sin(x)*y + * ~ cos(x) - x*y, + * a correction term is necessary in cos(x) and hence + * cos(x+y) = 1 - (x*x/2 - (r - x*y)) + * For better accuracy, rearrange to + * cos(x+y) ~ w + (tmp + (r-x*y)) + * where w = 1 - x*x/2 and tmp is a tiny correction term + * (1 - x*x/2 == w + tmp exactly in infinite precision). + * The exactness of w + tmp in infinite precision depends on w + * and tmp having the same precision as x. If they have extra + * precision due to compiler bugs, then the extra precision is + * only good provided it is retained in all terms of the final + * expression for cos(). Retention happens in all cases tested + * under FreeBSD, so don't pessimize things by forcibly clipping + * any extra precision in w. + */ + +#include "libm.h" + +static const double +C1 = 4.16666666666666019037e-02, /* 0x3FA55555, 0x5555554C */ +C2 = -1.38888888888741095749e-03, /* 0xBF56C16C, 0x16C15177 */ +C3 = 2.48015872894767294178e-05, /* 0x3EFA01A0, 0x19CB1590 */ +C4 = -2.75573143513906633035e-07, /* 0xBE927E4F, 0x809C52AD */ +C5 = 2.08757232129817482790e-09, /* 0x3E21EE9E, 0xBDB4B1C4 */ +C6 = -1.13596475577881948265e-11; /* 0xBDA8FAE9, 0xBE8838D4 */ + +double __cos(double x, double y) +{ + double_t hz,z,r,w; + + z = x*x; + w = z*z; + r = z*(C1+z*(C2+z*C3)) + w*w*(C4+z*(C5+z*C6)); + hz = 0.5*z; + w = 1.0-hz; + return w + (((1.0-w)-hz) + (z*r-x*y)); +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/__cosdf.c b/lib/mlibc/options/ansi/musl-generic-math/__cosdf.c new file mode 100644 index 0000000..2124989 --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/__cosdf.c @@ -0,0 +1,35 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/k_cosf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + * Debugged and optimized by Bruce D. Evans. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "libm.h" + +/* |cos(x) - c(x)| < 2**-34.1 (~[-5.37e-11, 5.295e-11]). */ +static const double +C0 = -0x1ffffffd0c5e81.0p-54, /* -0.499999997251031003120 */ +C1 = 0x155553e1053a42.0p-57, /* 0.0416666233237390631894 */ +C2 = -0x16c087e80f1e27.0p-62, /* -0.00138867637746099294692 */ +C3 = 0x199342e0ee5069.0p-68; /* 0.0000243904487962774090654 */ + +float __cosdf(double x) +{ + double_t r, w, z; + + /* Try to optimize for parallel evaluation as in __tandf.c. */ + z = x*x; + w = z*z; + r = C2+z*C3; + return ((1.0+z*C0) + w*C1) + (w*z)*r; +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/__cosl.c b/lib/mlibc/options/ansi/musl-generic-math/__cosl.c new file mode 100644 index 0000000..fa522dd --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/__cosl.c @@ -0,0 +1,96 @@ +/* origin: FreeBSD /usr/src/lib/msun/ld80/k_cosl.c */ +/* origin: FreeBSD /usr/src/lib/msun/ld128/k_cosl.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * Copyright (c) 2008 Steven G. Kargl, David Schultz, Bruce D. Evans. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + + +#include "libm.h" + +#if (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 +#if LDBL_MANT_DIG == 64 +/* + * ld80 version of __cos.c. See __cos.c for most comments. + */ +/* + * Domain [-0.7854, 0.7854], range ~[-2.43e-23, 2.425e-23]: + * |cos(x) - c(x)| < 2**-75.1 + * + * The coefficients of c(x) were generated by a pari-gp script using + * a Remez algorithm that searches for the best higher coefficients + * after rounding leading coefficients to a specified precision. + * + * Simpler methods like Chebyshev or basic Remez barely suffice for + * cos() in 64-bit precision, because we want the coefficient of x^2 + * to be precisely -0.5 so that multiplying by it is exact, and plain + * rounding of the coefficients of a good polynomial approximation only + * gives this up to about 64-bit precision. Plain rounding also gives + * a mediocre approximation for the coefficient of x^4, but a rounding + * error of 0.5 ulps for this coefficient would only contribute ~0.01 + * ulps to the final error, so this is unimportant. Rounding errors in + * higher coefficients are even less important. + * + * In fact, coefficients above the x^4 one only need to have 53-bit + * precision, and this is more efficient. We get this optimization + * almost for free from the complications needed to search for the best + * higher coefficients. + */ +static const long double +C1 = 0.0416666666666666666136L; /* 0xaaaaaaaaaaaaaa9b.0p-68 */ +static const double +C2 = -0.0013888888888888874, /* -0x16c16c16c16c10.0p-62 */ +C3 = 0.000024801587301571716, /* 0x1a01a01a018e22.0p-68 */ +C4 = -0.00000027557319215507120, /* -0x127e4fb7602f22.0p-74 */ +C5 = 0.0000000020876754400407278, /* 0x11eed8caaeccf1.0p-81 */ +C6 = -1.1470297442401303e-11, /* -0x19393412bd1529.0p-89 */ +C7 = 4.7383039476436467e-14; /* 0x1aac9d9af5c43e.0p-97 */ +#define POLY(z) (z*(C1+z*(C2+z*(C3+z*(C4+z*(C5+z*(C6+z*C7))))))) +#elif LDBL_MANT_DIG == 113 +/* + * ld128 version of __cos.c. See __cos.c for most comments. + */ +/* + * Domain [-0.7854, 0.7854], range ~[-1.80e-37, 1.79e-37]: + * |cos(x) - c(x))| < 2**-122.0 + * + * 113-bit precision requires more care than 64-bit precision, since + * simple methods give a minimax polynomial with coefficient for x^2 + * that is 1 ulp below 0.5, but we want it to be precisely 0.5. See + * above for more details. + */ +static const long double +C1 = 0.04166666666666666666666666666666658424671L, +C2 = -0.001388888888888888888888888888863490893732L, +C3 = 0.00002480158730158730158730158600795304914210L, +C4 = -0.2755731922398589065255474947078934284324e-6L, +C5 = 0.2087675698786809897659225313136400793948e-8L, +C6 = -0.1147074559772972315817149986812031204775e-10L, +C7 = 0.4779477332386808976875457937252120293400e-13L; +static const double +C8 = -0.1561920696721507929516718307820958119868e-15, +C9 = 0.4110317413744594971475941557607804508039e-18, +C10 = -0.8896592467191938803288521958313920156409e-21, +C11 = 0.1601061435794535138244346256065192782581e-23; +#define POLY(z) (z*(C1+z*(C2+z*(C3+z*(C4+z*(C5+z*(C6+z*(C7+ \ + z*(C8+z*(C9+z*(C10+z*C11))))))))))) +#endif + +long double __cosl(long double x, long double y) +{ + long double hz,z,r,w; + + z = x*x; + r = POLY(z); + hz = 0.5*z; + w = 1.0-hz; + return w + (((1.0-w)-hz) + (z*r-x*y)); +} +#endif diff --git a/lib/mlibc/options/ansi/musl-generic-math/__expo2.c b/lib/mlibc/options/ansi/musl-generic-math/__expo2.c new file mode 100644 index 0000000..740ac68 --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/__expo2.c @@ -0,0 +1,16 @@ +#include "libm.h" + +/* k is such that k*ln2 has minimal relative error and x - kln2 > log(DBL_MIN) */ +static const int k = 2043; +static const double kln2 = 0x1.62066151add8bp+10; + +/* exp(x)/2 for x >= log(DBL_MAX), slightly better than 0.5*exp(x/2)*exp(x/2) */ +double __expo2(double x) +{ + double scale; + + /* note that k is odd and scale*scale overflows */ + INSERT_WORDS(scale, (uint32_t)(0x3ff + k/2) << 20, 0); + /* exp(x - k ln2) * 2**(k-1) */ + return exp(x - kln2) * scale * scale; +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/__expo2f.c b/lib/mlibc/options/ansi/musl-generic-math/__expo2f.c new file mode 100644 index 0000000..5163e41 --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/__expo2f.c @@ -0,0 +1,16 @@ +#include "libm.h" + +/* k is such that k*ln2 has minimal relative error and x - kln2 > log(FLT_MIN) */ +static const int k = 235; +static const float kln2 = 0x1.45c778p+7f; + +/* expf(x)/2 for x >= log(FLT_MAX), slightly better than 0.5f*expf(x/2)*expf(x/2) */ +float __expo2f(float x) +{ + float scale; + + /* note that k is odd and scale*scale overflows */ + SET_FLOAT_WORD(scale, (uint32_t)(0x7f + k/2) << 23); + /* exp(x - k ln2) * 2**(k-1) */ + return expf(x - kln2) * scale * scale; +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/__fpclassify.c b/lib/mlibc/options/ansi/musl-generic-math/__fpclassify.c new file mode 100644 index 0000000..f7c0e2d --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/__fpclassify.c @@ -0,0 +1,11 @@ +#include +#include + +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; +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/__fpclassifyf.c b/lib/mlibc/options/ansi/musl-generic-math/__fpclassifyf.c new file mode 100644 index 0000000..fd00eb1 --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/__fpclassifyf.c @@ -0,0 +1,11 @@ +#include +#include + +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; +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/__fpclassifyl.c b/lib/mlibc/options/ansi/musl-generic-math/__fpclassifyl.c new file mode 100644 index 0000000..481c0b9 --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/__fpclassifyl.c @@ -0,0 +1,34 @@ +#include "libm.h" + +#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 (!msb) + return FP_NAN; + if (e == 0x7fff) + return u.i.m << 1 ? FP_NAN : FP_INFINITE; + 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 diff --git a/lib/mlibc/options/ansi/musl-generic-math/__invtrigl.c b/lib/mlibc/options/ansi/musl-generic-math/__invtrigl.c new file mode 100644 index 0000000..48f83aa --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/__invtrigl.c @@ -0,0 +1,63 @@ +#include +#include "__invtrigl.h" + +#if LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 +static const long double +pS0 = 1.66666666666666666631e-01L, +pS1 = -4.16313987993683104320e-01L, +pS2 = 3.69068046323246813704e-01L, +pS3 = -1.36213932016738603108e-01L, +pS4 = 1.78324189708471965733e-02L, +pS5 = -2.19216428382605211588e-04L, +pS6 = -7.10526623669075243183e-06L, +qS1 = -2.94788392796209867269e+00L, +qS2 = 3.27309890266528636716e+00L, +qS3 = -1.68285799854822427013e+00L, +qS4 = 3.90699412641738801874e-01L, +qS5 = -3.14365703596053263322e-02L; + +const long double pio2_hi = 1.57079632679489661926L; +const long double pio2_lo = -2.50827880633416601173e-20L; + +/* used in asinl() and acosl() */ +/* R(x^2) is a rational approximation of (asin(x)-x)/x^3 with Remez algorithm */ +long double __invtrigl_R(long double z) +{ + long double p, q; + p = z*(pS0+z*(pS1+z*(pS2+z*(pS3+z*(pS4+z*(pS5+z*pS6)))))); + q = 1.0+z*(qS1+z*(qS2+z*(qS3+z*(qS4+z*qS5)))); + return p/q; +} +#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 +static const long double +pS0 = 1.66666666666666666666666666666700314e-01L, +pS1 = -7.32816946414566252574527475428622708e-01L, +pS2 = 1.34215708714992334609030036562143589e+00L, +pS3 = -1.32483151677116409805070261790752040e+00L, +pS4 = 7.61206183613632558824485341162121989e-01L, +pS5 = -2.56165783329023486777386833928147375e-01L, +pS6 = 4.80718586374448793411019434585413855e-02L, +pS7 = -4.42523267167024279410230886239774718e-03L, +pS8 = 1.44551535183911458253205638280410064e-04L, +pS9 = -2.10558957916600254061591040482706179e-07L, +qS1 = -4.84690167848739751544716485245697428e+00L, +qS2 = 9.96619113536172610135016921140206980e+00L, +qS3 = -1.13177895428973036660836798461641458e+01L, +qS4 = 7.74004374389488266169304117714658761e+00L, +qS5 = -3.25871986053534084709023539900339905e+00L, +qS6 = 8.27830318881232209752469022352928864e-01L, +qS7 = -1.18768052702942805423330715206348004e-01L, +qS8 = 8.32600764660522313269101537926539470e-03L, +qS9 = -1.99407384882605586705979504567947007e-04L; + +const long double pio2_hi = 1.57079632679489661923132169163975140L; +const long double pio2_lo = 4.33590506506189051239852201302167613e-35L; + +long double __invtrigl_R(long double z) +{ + long double p, q; + p = z*(pS0+z*(pS1+z*(pS2+z*(pS3+z*(pS4+z*(pS5+z*(pS6+z*(pS7+z*(pS8+z*pS9))))))))); + q = 1.0+z*(qS1+z*(qS2+z*(qS3+z*(qS4+z*(qS5+z*(qS6+z*(qS7+z*(qS8+z*qS9)))))))); + return p/q; +} +#endif diff --git a/lib/mlibc/options/ansi/musl-generic-math/__invtrigl.h b/lib/mlibc/options/ansi/musl-generic-math/__invtrigl.h new file mode 100644 index 0000000..6dedac3 --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/__invtrigl.h @@ -0,0 +1,11 @@ +/* shared by acosl, asinl and atan2l */ +#define pio2_hi __pio2_hi +#define pio2_lo __pio2_lo + +#ifndef __MLIBC_ABI_ONLY + +extern const long double pio2_hi, pio2_lo; + +long double __invtrigl_R(long double z); + +#endif /* !__MLIBC_ABI_ONLY */ diff --git a/lib/mlibc/options/ansi/musl-generic-math/__polevll.c b/lib/mlibc/options/ansi/musl-generic-math/__polevll.c new file mode 100644 index 0000000..ce1a840 --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/__polevll.c @@ -0,0 +1,93 @@ +/* origin: OpenBSD /usr/src/lib/libm/src/polevll.c */ +/* + * Copyright (c) 2008 Stephen L. Moshier + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/* + * Evaluate polynomial + * + * + * SYNOPSIS: + * + * int N; + * long double x, y, coef[N+1], polevl[]; + * + * y = polevll( x, coef, N ); + * + * + * DESCRIPTION: + * + * Evaluates polynomial of degree N: + * + * 2 N + * y = C + C x + C x +...+ C x + * 0 1 2 N + * + * Coefficients are stored in reverse order: + * + * coef[0] = C , ..., coef[N] = C . + * N 0 + * + * The function p1evll() assumes that coef[N] = 1.0 and is + * omitted from the array. Its calling arguments are + * otherwise the same as polevll(). + * + * + * SPEED: + * + * In the interest of speed, there are no checks for out + * of bounds arithmetic. This routine is used by most of + * the functions in the library. Depending on available + * equipment features, the user may wish to rewrite the + * program in microcode or assembly language. + * + */ + +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +#else +/* + * Polynomial evaluator: + * P[0] x^n + P[1] x^(n-1) + ... + P[n] + */ +long double __polevll(long double x, const long double *P, int n) +{ + long double y; + + y = *P++; + do { + y = y * x + *P++; + } while (--n); + + return y; +} + +/* + * Polynomial evaluator: + * x^n + P[0] x^(n-1) + P[1] x^(n-2) + ... + P[n] + */ +long double __p1evll(long double x, const long double *P, int n) +{ + long double y; + + n -= 1; + y = x + *P++; + do { + y = y * x + *P++; + } while (--n); + + return y; +} +#endif diff --git a/lib/mlibc/options/ansi/musl-generic-math/__rem_pio2.c b/lib/mlibc/options/ansi/musl-generic-math/__rem_pio2.c new file mode 100644 index 0000000..d403f81 --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/__rem_pio2.c @@ -0,0 +1,177 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_rem_pio2.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + * + * Optimized by Bruce D. Evans. + */ +/* __rem_pio2(x,y) + * + * return the remainder of x rem pi/2 in y[0]+y[1] + * use __rem_pio2_large() for large x + */ + +#include "libm.h" + +#if FLT_EVAL_METHOD==0 || FLT_EVAL_METHOD==1 +#define EPS DBL_EPSILON +#elif FLT_EVAL_METHOD==2 +#define EPS LDBL_EPSILON +#endif + +/* + * invpio2: 53 bits of 2/pi + * pio2_1: first 33 bit of pi/2 + * pio2_1t: pi/2 - pio2_1 + * pio2_2: second 33 bit of pi/2 + * pio2_2t: pi/2 - (pio2_1+pio2_2) + * pio2_3: third 33 bit of pi/2 + * pio2_3t: pi/2 - (pio2_1+pio2_2+pio2_3) + */ +static const double +toint = 1.5/EPS, +invpio2 = 6.36619772367581382433e-01, /* 0x3FE45F30, 0x6DC9C883 */ +pio2_1 = 1.57079632673412561417e+00, /* 0x3FF921FB, 0x54400000 */ +pio2_1t = 6.07710050650619224932e-11, /* 0x3DD0B461, 0x1A626331 */ +pio2_2 = 6.07710050630396597660e-11, /* 0x3DD0B461, 0x1A600000 */ +pio2_2t = 2.02226624879595063154e-21, /* 0x3BA3198A, 0x2E037073 */ +pio2_3 = 2.02226624871116645580e-21, /* 0x3BA3198A, 0x2E000000 */ +pio2_3t = 8.47842766036889956997e-32; /* 0x397B839A, 0x252049C1 */ + +/* caller must handle the case when reduction is not needed: |x| ~<= pi/4 */ +int __rem_pio2(double x, double *y) +{ + union {double f; uint64_t i;} u = {x}; + double_t z,w,t,r,fn; + double tx[3],ty[2]; + uint32_t ix; + int sign, n, ex, ey, i; + + sign = u.i>>63; + ix = u.i>>32 & 0x7fffffff; + if (ix <= 0x400f6a7a) { /* |x| ~<= 5pi/4 */ + if ((ix & 0xfffff) == 0x921fb) /* |x| ~= pi/2 or 2pi/2 */ + goto medium; /* cancellation -- use medium case */ + if (ix <= 0x4002d97c) { /* |x| ~<= 3pi/4 */ + if (!sign) { + z = x - pio2_1; /* one round good to 85 bits */ + y[0] = z - pio2_1t; + y[1] = (z-y[0]) - pio2_1t; + return 1; + } else { + z = x + pio2_1; + y[0] = z + pio2_1t; + y[1] = (z-y[0]) + pio2_1t; + return -1; + } + } else { + if (!sign) { + z = x - 2*pio2_1; + y[0] = z - 2*pio2_1t; + y[1] = (z-y[0]) - 2*pio2_1t; + return 2; + } else { + z = x + 2*pio2_1; + y[0] = z + 2*pio2_1t; + y[1] = (z-y[0]) + 2*pio2_1t; + return -2; + } + } + } + if (ix <= 0x401c463b) { /* |x| ~<= 9pi/4 */ + if (ix <= 0x4015fdbc) { /* |x| ~<= 7pi/4 */ + if (ix == 0x4012d97c) /* |x| ~= 3pi/2 */ + goto medium; + if (!sign) { + z = x - 3*pio2_1; + y[0] = z - 3*pio2_1t; + y[1] = (z-y[0]) - 3*pio2_1t; + return 3; + } else { + z = x + 3*pio2_1; + y[0] = z + 3*pio2_1t; + y[1] = (z-y[0]) + 3*pio2_1t; + return -3; + } + } else { + if (ix == 0x401921fb) /* |x| ~= 4pi/2 */ + goto medium; + if (!sign) { + z = x - 4*pio2_1; + y[0] = z - 4*pio2_1t; + y[1] = (z-y[0]) - 4*pio2_1t; + return 4; + } else { + z = x + 4*pio2_1; + y[0] = z + 4*pio2_1t; + y[1] = (z-y[0]) + 4*pio2_1t; + return -4; + } + } + } + if (ix < 0x413921fb) { /* |x| ~< 2^20*(pi/2), medium size */ +medium: + /* rint(x/(pi/2)), Assume round-to-nearest. */ + fn = (double_t)x*invpio2 + toint - toint; + n = (int32_t)fn; + r = x - fn*pio2_1; + w = fn*pio2_1t; /* 1st round, good to 85 bits */ + y[0] = r - w; + u.f = y[0]; + ey = u.i>>52 & 0x7ff; + ex = ix>>20; + if (ex - ey > 16) { /* 2nd round, good to 118 bits */ + t = r; + w = fn*pio2_2; + r = t - w; + w = fn*pio2_2t - ((t-r)-w); + y[0] = r - w; + u.f = y[0]; + ey = u.i>>52 & 0x7ff; + if (ex - ey > 49) { /* 3rd round, good to 151 bits, covers all cases */ + t = r; + w = fn*pio2_3; + r = t - w; + w = fn*pio2_3t - ((t-r)-w); + y[0] = r - w; + } + } + y[1] = (r - y[0]) - w; + return n; + } + /* + * all other (large) arguments + */ + if (ix >= 0x7ff00000) { /* x is inf or NaN */ + y[0] = y[1] = x - x; + return 0; + } + /* set z = scalbn(|x|,-ilogb(x)+23) */ + u.f = x; + u.i &= (uint64_t)-1>>12; + u.i |= (uint64_t)(0x3ff + 23)<<52; + z = u.f; + for (i=0; i < 2; i++) { + tx[i] = (double)(int32_t)z; + z = (z-tx[i])*0x1p24; + } + tx[i] = z; + /* skip zero terms, first term is non-zero */ + while (tx[i] == 0.0) + i--; + n = __rem_pio2_large(tx,ty,(int)(ix>>20)-(0x3ff+23),i+1,1); + if (sign) { + y[0] = -ty[0]; + y[1] = -ty[1]; + return -n; + } + y[0] = ty[0]; + y[1] = ty[1]; + return n; +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/__rem_pio2_large.c b/lib/mlibc/options/ansi/musl-generic-math/__rem_pio2_large.c new file mode 100644 index 0000000..958f28c --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/__rem_pio2_large.c @@ -0,0 +1,442 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/k_rem_pio2.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* + * __rem_pio2_large(x,y,e0,nx,prec) + * double x[],y[]; int e0,nx,prec; + * + * __rem_pio2_large return the last three digits of N with + * y = x - N*pi/2 + * so that |y| < pi/2. + * + * The method is to compute the integer (mod 8) and fraction parts of + * (2/pi)*x without doing the full multiplication. In general we + * skip the part of the product that are known to be a huge integer ( + * more accurately, = 0 mod 8 ). Thus the number of operations are + * independent of the exponent of the input. + * + * (2/pi) is represented by an array of 24-bit integers in ipio2[]. + * + * Input parameters: + * x[] The input value (must be positive) is broken into nx + * pieces of 24-bit integers in double precision format. + * x[i] will be the i-th 24 bit of x. The scaled exponent + * of x[0] is given in input parameter e0 (i.e., x[0]*2^e0 + * match x's up to 24 bits. + * + * Example of breaking a double positive z into x[0]+x[1]+x[2]: + * e0 = ilogb(z)-23 + * z = scalbn(z,-e0) + * for i = 0,1,2 + * x[i] = floor(z) + * z = (z-x[i])*2**24 + * + * + * y[] ouput result in an array of double precision numbers. + * The dimension of y[] is: + * 24-bit precision 1 + * 53-bit precision 2 + * 64-bit precision 2 + * 113-bit precision 3 + * The actual value is the sum of them. Thus for 113-bit + * precison, one may have to do something like: + * + * long double t,w,r_head, r_tail; + * t = (long double)y[2] + (long double)y[1]; + * w = (long double)y[0]; + * r_head = t+w; + * r_tail = w - (r_head - t); + * + * e0 The exponent of x[0]. Must be <= 16360 or you need to + * expand the ipio2 table. + * + * nx dimension of x[] + * + * prec an integer indicating the precision: + * 0 24 bits (single) + * 1 53 bits (double) + * 2 64 bits (extended) + * 3 113 bits (quad) + * + * External function: + * double scalbn(), floor(); + * + * + * Here is the description of some local variables: + * + * jk jk+1 is the initial number of terms of ipio2[] needed + * in the computation. The minimum and recommended value + * for jk is 3,4,4,6 for single, double, extended, and quad. + * jk+1 must be 2 larger than you might expect so that our + * recomputation test works. (Up to 24 bits in the integer + * part (the 24 bits of it that we compute) and 23 bits in + * the fraction part may be lost to cancelation before we + * recompute.) + * + * jz local integer variable indicating the number of + * terms of ipio2[] used. + * + * jx nx - 1 + * + * jv index for pointing to the suitable ipio2[] for the + * computation. In general, we want + * ( 2^e0*x[0] * ipio2[jv-1]*2^(-24jv) )/8 + * is an integer. Thus + * e0-3-24*jv >= 0 or (e0-3)/24 >= jv + * Hence jv = max(0,(e0-3)/24). + * + * jp jp+1 is the number of terms in PIo2[] needed, jp = jk. + * + * q[] double array with integral value, representing the + * 24-bits chunk of the product of x and 2/pi. + * + * q0 the corresponding exponent of q[0]. Note that the + * exponent for q[i] would be q0-24*i. + * + * PIo2[] double precision array, obtained by cutting pi/2 + * into 24 bits chunks. + * + * f[] ipio2[] in floating point + * + * iq[] integer array by breaking up q[] in 24-bits chunk. + * + * fq[] final product of x*(2/pi) in fq[0],..,fq[jk] + * + * ih integer. If >0 it indicates q[] is >= 0.5, hence + * it also indicates the *sign* of the result. + * + */ +/* + * Constants: + * The hexadecimal values are the intended ones for the following + * constants. The decimal values may be used, provided that the + * compiler will convert from decimal to binary accurately enough + * to produce the hexadecimal values shown. + */ + +#include "libm.h" + +static const int init_jk[] = {3,4,4,6}; /* initial value for jk */ + +/* + * Table of constants for 2/pi, 396 Hex digits (476 decimal) of 2/pi + * + * integer array, contains the (24*i)-th to (24*i+23)-th + * bit of 2/pi after binary point. The corresponding + * floating value is + * + * ipio2[i] * 2^(-24(i+1)). + * + * NB: This table must have at least (e0-3)/24 + jk terms. + * For quad precision (e0 <= 16360, jk = 6), this is 686. + */ +static const int32_t ipio2[] = { +0xA2F983, 0x6E4E44, 0x1529FC, 0x2757D1, 0xF534DD, 0xC0DB62, +0x95993C, 0x439041, 0xFE5163, 0xABDEBB, 0xC561B7, 0x246E3A, +0x424DD2, 0xE00649, 0x2EEA09, 0xD1921C, 0xFE1DEB, 0x1CB129, +0xA73EE8, 0x8235F5, 0x2EBB44, 0x84E99C, 0x7026B4, 0x5F7E41, +0x3991D6, 0x398353, 0x39F49C, 0x845F8B, 0xBDF928, 0x3B1FF8, +0x97FFDE, 0x05980F, 0xEF2F11, 0x8B5A0A, 0x6D1F6D, 0x367ECF, +0x27CB09, 0xB74F46, 0x3F669E, 0x5FEA2D, 0x7527BA, 0xC7EBE5, +0xF17B3D, 0x0739F7, 0x8A5292, 0xEA6BFB, 0x5FB11F, 0x8D5D08, +0x560330, 0x46FC7B, 0x6BABF0, 0xCFBC20, 0x9AF436, 0x1DA9E3, +0x91615E, 0xE61B08, 0x659985, 0x5F14A0, 0x68408D, 0xFFD880, +0x4D7327, 0x310606, 0x1556CA, 0x73A8C9, 0x60E27B, 0xC08C6B, + +#if LDBL_MAX_EXP > 1024 +0x47C419, 0xC367CD, 0xDCE809, 0x2A8359, 0xC4768B, 0x961CA6, +0xDDAF44, 0xD15719, 0x053EA5, 0xFF0705, 0x3F7E33, 0xE832C2, +0xDE4F98, 0x327DBB, 0xC33D26, 0xEF6B1E, 0x5EF89F, 0x3A1F35, +0xCAF27F, 0x1D87F1, 0x21907C, 0x7C246A, 0xFA6ED5, 0x772D30, +0x433B15, 0xC614B5, 0x9D19C3, 0xC2C4AD, 0x414D2C, 0x5D000C, +0x467D86, 0x2D71E3, 0x9AC69B, 0x006233, 0x7CD2B4, 0x97A7B4, +0xD55537, 0xF63ED7, 0x1810A3, 0xFC764D, 0x2A9D64, 0xABD770, +0xF87C63, 0x57B07A, 0xE71517, 0x5649C0, 0xD9D63B, 0x3884A7, +0xCB2324, 0x778AD6, 0x23545A, 0xB91F00, 0x1B0AF1, 0xDFCE19, +0xFF319F, 0x6A1E66, 0x615799, 0x47FBAC, 0xD87F7E, 0xB76522, +0x89E832, 0x60BFE6, 0xCDC4EF, 0x09366C, 0xD43F5D, 0xD7DE16, +0xDE3B58, 0x929BDE, 0x2822D2, 0xE88628, 0x4D58E2, 0x32CAC6, +0x16E308, 0xCB7DE0, 0x50C017, 0xA71DF3, 0x5BE018, 0x34132E, +0x621283, 0x014883, 0x5B8EF5, 0x7FB0AD, 0xF2E91E, 0x434A48, +0xD36710, 0xD8DDAA, 0x425FAE, 0xCE616A, 0xA4280A, 0xB499D3, +0xF2A606, 0x7F775C, 0x83C2A3, 0x883C61, 0x78738A, 0x5A8CAF, +0xBDD76F, 0x63A62D, 0xCBBFF4, 0xEF818D, 0x67C126, 0x45CA55, +0x36D9CA, 0xD2A828, 0x8D61C2, 0x77C912, 0x142604, 0x9B4612, +0xC459C4, 0x44C5C8, 0x91B24D, 0xF31700, 0xAD43D4, 0xE54929, +0x10D5FD, 0xFCBE00, 0xCC941E, 0xEECE70, 0xF53E13, 0x80F1EC, +0xC3E7B3, 0x28F8C7, 0x940593, 0x3E71C1, 0xB3092E, 0xF3450B, +0x9C1288, 0x7B20AB, 0x9FB52E, 0xC29247, 0x2F327B, 0x6D550C, +0x90A772, 0x1FE76B, 0x96CB31, 0x4A1679, 0xE27941, 0x89DFF4, +0x9794E8, 0x84E6E2, 0x973199, 0x6BED88, 0x365F5F, 0x0EFDBB, +0xB49A48, 0x6CA467, 0x427271, 0x325D8D, 0xB8159F, 0x09E5BC, +0x25318D, 0x3974F7, 0x1C0530, 0x010C0D, 0x68084B, 0x58EE2C, +0x90AA47, 0x02E774, 0x24D6BD, 0xA67DF7, 0x72486E, 0xEF169F, +0xA6948E, 0xF691B4, 0x5153D1, 0xF20ACF, 0x339820, 0x7E4BF5, +0x6863B2, 0x5F3EDD, 0x035D40, 0x7F8985, 0x295255, 0xC06437, +0x10D86D, 0x324832, 0x754C5B, 0xD4714E, 0x6E5445, 0xC1090B, +0x69F52A, 0xD56614, 0x9D0727, 0x50045D, 0xDB3BB4, 0xC576EA, +0x17F987, 0x7D6B49, 0xBA271D, 0x296996, 0xACCCC6, 0x5414AD, +0x6AE290, 0x89D988, 0x50722C, 0xBEA404, 0x940777, 0x7030F3, +0x27FC00, 0xA871EA, 0x49C266, 0x3DE064, 0x83DD97, 0x973FA3, +0xFD9443, 0x8C860D, 0xDE4131, 0x9D3992, 0x8C70DD, 0xE7B717, +0x3BDF08, 0x2B3715, 0xA0805C, 0x93805A, 0x921110, 0xD8E80F, +0xAF806C, 0x4BFFDB, 0x0F9038, 0x761859, 0x15A562, 0xBBCB61, +0xB989C7, 0xBD4010, 0x04F2D2, 0x277549, 0xF6B6EB, 0xBB22DB, +0xAA140A, 0x2F2689, 0x768364, 0x333B09, 0x1A940E, 0xAA3A51, +0xC2A31D, 0xAEEDAF, 0x12265C, 0x4DC26D, 0x9C7A2D, 0x9756C0, +0x833F03, 0xF6F009, 0x8C402B, 0x99316D, 0x07B439, 0x15200C, +0x5BC3D8, 0xC492F5, 0x4BADC6, 0xA5CA4E, 0xCD37A7, 0x36A9E6, +0x9492AB, 0x6842DD, 0xDE6319, 0xEF8C76, 0x528B68, 0x37DBFC, +0xABA1AE, 0x3115DF, 0xA1AE00, 0xDAFB0C, 0x664D64, 0xB705ED, +0x306529, 0xBF5657, 0x3AFF47, 0xB9F96A, 0xF3BE75, 0xDF9328, +0x3080AB, 0xF68C66, 0x15CB04, 0x0622FA, 0x1DE4D9, 0xA4B33D, +0x8F1B57, 0x09CD36, 0xE9424E, 0xA4BE13, 0xB52333, 0x1AAAF0, +0xA8654F, 0xA5C1D2, 0x0F3F0B, 0xCD785B, 0x76F923, 0x048B7B, +0x721789, 0x53A6C6, 0xE26E6F, 0x00EBEF, 0x584A9B, 0xB7DAC4, +0xBA66AA, 0xCFCF76, 0x1D02D1, 0x2DF1B1, 0xC1998C, 0x77ADC3, +0xDA4886, 0xA05DF7, 0xF480C6, 0x2FF0AC, 0x9AECDD, 0xBC5C3F, +0x6DDED0, 0x1FC790, 0xB6DB2A, 0x3A25A3, 0x9AAF00, 0x9353AD, +0x0457B6, 0xB42D29, 0x7E804B, 0xA707DA, 0x0EAA76, 0xA1597B, +0x2A1216, 0x2DB7DC, 0xFDE5FA, 0xFEDB89, 0xFDBE89, 0x6C76E4, +0xFCA906, 0x70803E, 0x156E85, 0xFF87FD, 0x073E28, 0x336761, +0x86182A, 0xEABD4D, 0xAFE7B3, 0x6E6D8F, 0x396795, 0x5BBF31, +0x48D784, 0x16DF30, 0x432DC7, 0x356125, 0xCE70C9, 0xB8CB30, +0xFD6CBF, 0xA200A4, 0xE46C05, 0xA0DD5A, 0x476F21, 0xD21262, +0x845CB9, 0x496170, 0xE0566B, 0x015299, 0x375550, 0xB7D51E, +0xC4F133, 0x5F6E13, 0xE4305D, 0xA92E85, 0xC3B21D, 0x3632A1, +0xA4B708, 0xD4B1EA, 0x21F716, 0xE4698F, 0x77FF27, 0x80030C, +0x2D408D, 0xA0CD4F, 0x99A520, 0xD3A2B3, 0x0A5D2F, 0x42F9B4, +0xCBDA11, 0xD0BE7D, 0xC1DB9B, 0xBD17AB, 0x81A2CA, 0x5C6A08, +0x17552E, 0x550027, 0xF0147F, 0x8607E1, 0x640B14, 0x8D4196, +0xDEBE87, 0x2AFDDA, 0xB6256B, 0x34897B, 0xFEF305, 0x9EBFB9, +0x4F6A68, 0xA82A4A, 0x5AC44F, 0xBCF82D, 0x985AD7, 0x95C7F4, +0x8D4D0D, 0xA63A20, 0x5F57A4, 0xB13F14, 0x953880, 0x0120CC, +0x86DD71, 0xB6DEC9, 0xF560BF, 0x11654D, 0x6B0701, 0xACB08C, +0xD0C0B2, 0x485551, 0x0EFB1E, 0xC37295, 0x3B06A3, 0x3540C0, +0x7BDC06, 0xCC45E0, 0xFA294E, 0xC8CAD6, 0x41F3E8, 0xDE647C, +0xD8649B, 0x31BED9, 0xC397A4, 0xD45877, 0xC5E369, 0x13DAF0, +0x3C3ABA, 0x461846, 0x5F7555, 0xF5BDD2, 0xC6926E, 0x5D2EAC, +0xED440E, 0x423E1C, 0x87C461, 0xE9FD29, 0xF3D6E7, 0xCA7C22, +0x35916F, 0xC5E008, 0x8DD7FF, 0xE26A6E, 0xC6FDB0, 0xC10893, +0x745D7C, 0xB2AD6B, 0x9D6ECD, 0x7B723E, 0x6A11C6, 0xA9CFF7, +0xDF7329, 0xBAC9B5, 0x5100B7, 0x0DB2E2, 0x24BA74, 0x607DE5, +0x8AD874, 0x2C150D, 0x0C1881, 0x94667E, 0x162901, 0x767A9F, +0xBEFDFD, 0xEF4556, 0x367ED9, 0x13D9EC, 0xB9BA8B, 0xFC97C4, +0x27A831, 0xC36EF1, 0x36C594, 0x56A8D8, 0xB5A8B4, 0x0ECCCF, +0x2D8912, 0x34576F, 0x89562C, 0xE3CE99, 0xB920D6, 0xAA5E6B, +0x9C2A3E, 0xCC5F11, 0x4A0BFD, 0xFBF4E1, 0x6D3B8E, 0x2C86E2, +0x84D4E9, 0xA9B4FC, 0xD1EEEF, 0xC9352E, 0x61392F, 0x442138, +0xC8D91B, 0x0AFC81, 0x6A4AFB, 0xD81C2F, 0x84B453, 0x8C994E, +0xCC2254, 0xDC552A, 0xD6C6C0, 0x96190B, 0xB8701A, 0x649569, +0x605A26, 0xEE523F, 0x0F117F, 0x11B5F4, 0xF5CBFC, 0x2DBC34, +0xEEBC34, 0xCC5DE8, 0x605EDD, 0x9B8E67, 0xEF3392, 0xB817C9, +0x9B5861, 0xBC57E1, 0xC68351, 0x103ED8, 0x4871DD, 0xDD1C2D, +0xA118AF, 0x462C21, 0xD7F359, 0x987AD9, 0xC0549E, 0xFA864F, +0xFC0656, 0xAE79E5, 0x362289, 0x22AD38, 0xDC9367, 0xAAE855, +0x382682, 0x9BE7CA, 0xA40D51, 0xB13399, 0x0ED7A9, 0x480569, +0xF0B265, 0xA7887F, 0x974C88, 0x36D1F9, 0xB39221, 0x4A827B, +0x21CF98, 0xDC9F40, 0x5547DC, 0x3A74E1, 0x42EB67, 0xDF9DFE, +0x5FD45E, 0xA4677B, 0x7AACBA, 0xA2F655, 0x23882B, 0x55BA41, +0x086E59, 0x862A21, 0x834739, 0xE6E389, 0xD49EE5, 0x40FB49, +0xE956FF, 0xCA0F1C, 0x8A59C5, 0x2BFA94, 0xC5C1D3, 0xCFC50F, +0xAE5ADB, 0x86C547, 0x624385, 0x3B8621, 0x94792C, 0x876110, +0x7B4C2A, 0x1A2C80, 0x12BF43, 0x902688, 0x893C78, 0xE4C4A8, +0x7BDBE5, 0xC23AC4, 0xEAF426, 0x8A67F7, 0xBF920D, 0x2BA365, +0xB1933D, 0x0B7CBD, 0xDC51A4, 0x63DD27, 0xDDE169, 0x19949A, +0x9529A8, 0x28CE68, 0xB4ED09, 0x209F44, 0xCA984E, 0x638270, +0x237C7E, 0x32B90F, 0x8EF5A7, 0xE75614, 0x08F121, 0x2A9DB5, +0x4D7E6F, 0x5119A5, 0xABF9B5, 0xD6DF82, 0x61DD96, 0x023616, +0x9F3AC4, 0xA1A283, 0x6DED72, 0x7A8D39, 0xA9B882, 0x5C326B, +0x5B2746, 0xED3400, 0x7700D2, 0x55F4FC, 0x4D5901, 0x8071E0, +#endif +}; + +static const double PIo2[] = { + 1.57079625129699707031e+00, /* 0x3FF921FB, 0x40000000 */ + 7.54978941586159635335e-08, /* 0x3E74442D, 0x00000000 */ + 5.39030252995776476554e-15, /* 0x3CF84698, 0x80000000 */ + 3.28200341580791294123e-22, /* 0x3B78CC51, 0x60000000 */ + 1.27065575308067607349e-29, /* 0x39F01B83, 0x80000000 */ + 1.22933308981111328932e-36, /* 0x387A2520, 0x40000000 */ + 2.73370053816464559624e-44, /* 0x36E38222, 0x80000000 */ + 2.16741683877804819444e-51, /* 0x3569F31D, 0x00000000 */ +}; + +int __rem_pio2_large(double *x, double *y, int e0, int nx, int prec) +{ + int32_t jz,jx,jv,jp,jk,carry,n,iq[20],i,j,k,m,q0,ih; + double z,fw,f[20],fq[20],q[20]; + + /* initialize jk*/ + jk = init_jk[prec]; + jp = jk; + + /* determine jx,jv,q0, note that 3>q0 */ + jx = nx-1; + jv = (e0-3)/24; if(jv<0) jv=0; + q0 = e0-24*(jv+1); + + /* set up f[0] to f[jx+jk] where f[jx+jk] = ipio2[jv+jk] */ + j = jv-jx; m = jx+jk; + for (i=0; i<=m; i++,j++) + f[i] = j<0 ? 0.0 : (double)ipio2[j]; + + /* compute q[0],q[1],...q[jk] */ + for (i=0; i<=jk; i++) { + for (j=0,fw=0.0; j<=jx; j++) + fw += x[j]*f[jx+i-j]; + q[i] = fw; + } + + jz = jk; +recompute: + /* distill q[] into iq[] reversingly */ + for (i=0,j=jz,z=q[jz]; j>0; i++,j--) { + fw = (double)(int32_t)(0x1p-24*z); + iq[i] = (int32_t)(z - 0x1p24*fw); + z = q[j-1]+fw; + } + + /* compute n */ + z = scalbn(z,q0); /* actual value of z */ + z -= 8.0*floor(z*0.125); /* trim off integer >= 8 */ + n = (int32_t)z; + z -= (double)n; + ih = 0; + if (q0 > 0) { /* need iq[jz-1] to determine n */ + i = iq[jz-1]>>(24-q0); n += i; + iq[jz-1] -= i<<(24-q0); + ih = iq[jz-1]>>(23-q0); + } + else if (q0 == 0) ih = iq[jz-1]>>23; + else if (z >= 0.5) ih = 2; + + if (ih > 0) { /* q > 0.5 */ + n += 1; carry = 0; + for (i=0; i 0) { /* rare case: chance is 1 in 12 */ + switch(q0) { + case 1: + iq[jz-1] &= 0x7fffff; break; + case 2: + iq[jz-1] &= 0x3fffff; break; + } + } + if (ih == 2) { + z = 1.0 - z; + if (carry != 0) + z -= scalbn(1.0,q0); + } + } + + /* check if recomputation is needed */ + if (z == 0.0) { + j = 0; + for (i=jz-1; i>=jk; i--) j |= iq[i]; + if (j == 0) { /* need recomputation */ + for (k=1; iq[jk-k]==0; k++); /* k = no. of terms needed */ + + for (i=jz+1; i<=jz+k; i++) { /* add q[jz+1] to q[jz+k] */ + f[jx+i] = (double)ipio2[jv+i]; + for (j=0,fw=0.0; j<=jx; j++) + fw += x[j]*f[jx+i-j]; + q[i] = fw; + } + jz += k; + goto recompute; + } + } + + /* chop off zero terms */ + if (z == 0.0) { + jz -= 1; + q0 -= 24; + while (iq[jz] == 0) { + jz--; + q0 -= 24; + } + } else { /* break z into 24-bit if necessary */ + z = scalbn(z,-q0); + if (z >= 0x1p24) { + fw = (double)(int32_t)(0x1p-24*z); + iq[jz] = (int32_t)(z - 0x1p24*fw); + jz += 1; + q0 += 24; + iq[jz] = (int32_t)fw; + } else + iq[jz] = (int32_t)z; + } + + /* convert integer "bit" chunk to floating-point value */ + fw = scalbn(1.0,q0); + for (i=jz; i>=0; i--) { + q[i] = fw*(double)iq[i]; + fw *= 0x1p-24; + } + + /* compute PIo2[0,...,jp]*q[jz,...,0] */ + for(i=jz; i>=0; i--) { + for (fw=0.0,k=0; k<=jp && k<=jz-i; k++) + fw += PIo2[k]*q[i+k]; + fq[jz-i] = fw; + } + + /* compress fq[] into y[] */ + switch(prec) { + case 0: + fw = 0.0; + for (i=jz; i>=0; i--) + fw += fq[i]; + y[0] = ih==0 ? fw : -fw; + break; + case 1: + case 2: + fw = 0.0; + for (i=jz; i>=0; i--) + fw += fq[i]; + // TODO: drop excess precision here once double_t is used + fw = (double)fw; + y[0] = ih==0 ? fw : -fw; + fw = fq[0]-fw; + for (i=1; i<=jz; i++) + fw += fq[i]; + y[1] = ih==0 ? fw : -fw; + break; + case 3: /* painful */ + for (i=jz; i>0; i--) { + fw = fq[i-1]+fq[i]; + fq[i] += fq[i-1]-fw; + fq[i-1] = fw; + } + for (i=jz; i>1; i--) { + fw = fq[i-1]+fq[i]; + fq[i] += fq[i-1]-fw; + fq[i-1] = fw; + } + for (fw=0.0,i=jz; i>=2; i--) + fw += fq[i]; + if (ih==0) { + y[0] = fq[0]; y[1] = fq[1]; y[2] = fw; + } else { + y[0] = -fq[0]; y[1] = -fq[1]; y[2] = -fw; + } + } + return n&7; +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/__rem_pio2f.c b/lib/mlibc/options/ansi/musl-generic-math/__rem_pio2f.c new file mode 100644 index 0000000..4473c1c --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/__rem_pio2f.c @@ -0,0 +1,75 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_rem_pio2f.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + * Debugged and optimized by Bruce D. Evans. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* __rem_pio2f(x,y) + * + * return the remainder of x rem pi/2 in *y + * use double precision for everything except passing x + * use __rem_pio2_large() for large x + */ + +#include "libm.h" + +#if FLT_EVAL_METHOD==0 || FLT_EVAL_METHOD==1 +#define EPS DBL_EPSILON +#elif FLT_EVAL_METHOD==2 +#define EPS LDBL_EPSILON +#endif + +/* + * invpio2: 53 bits of 2/pi + * pio2_1: first 25 bits of pi/2 + * pio2_1t: pi/2 - pio2_1 + */ +static const double +toint = 1.5/EPS, +invpio2 = 6.36619772367581382433e-01, /* 0x3FE45F30, 0x6DC9C883 */ +pio2_1 = 1.57079631090164184570e+00, /* 0x3FF921FB, 0x50000000 */ +pio2_1t = 1.58932547735281966916e-08; /* 0x3E5110b4, 0x611A6263 */ + +int __rem_pio2f(float x, double *y) +{ + union {float f; uint32_t i;} u = {x}; + double tx[1],ty[1]; + double_t fn; + uint32_t ix; + int n, sign, e0; + + ix = u.i & 0x7fffffff; + /* 25+53 bit pi is good enough for medium size */ + if (ix < 0x4dc90fdb) { /* |x| ~< 2^28*(pi/2), medium size */ + /* Use a specialized rint() to get fn. Assume round-to-nearest. */ + fn = (double_t)x*invpio2 + toint - toint; + n = (int32_t)fn; + *y = x - fn*pio2_1 - fn*pio2_1t; + return n; + } + if(ix>=0x7f800000) { /* x is inf or NaN */ + *y = x-x; + return 0; + } + /* scale x into [2^23, 2^24-1] */ + sign = u.i>>31; + e0 = (ix>>23) - (0x7f+23); /* e0 = ilogb(|x|)-23, positive */ + u.i = ix - (e0<<23); + tx[0] = u.f; + n = __rem_pio2_large(tx,ty,e0,1,0); + if (sign) { + *y = -ty[0]; + return -n; + } + *y = ty[0]; + return n; +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/__rem_pio2l.c b/lib/mlibc/options/ansi/musl-generic-math/__rem_pio2l.c new file mode 100644 index 0000000..77255bd --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/__rem_pio2l.c @@ -0,0 +1,141 @@ +/* origin: FreeBSD /usr/src/lib/msun/ld80/e_rem_pio2.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * Copyright (c) 2008 Steven G. Kargl, David Schultz, Bruce D. Evans. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + * + * Optimized by Bruce D. Evans. + */ +#include "libm.h" +#if (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 +/* ld80 and ld128 version of __rem_pio2(x,y) + * + * return the remainder of x rem pi/2 in y[0]+y[1] + * use __rem_pio2_large() for large x + */ + +static const long double toint = 1.5/LDBL_EPSILON; + +#if LDBL_MANT_DIG == 64 +/* u ~< 0x1p25*pi/2 */ +#define SMALL(u) (((u.i.se & 0x7fffU)<<16 | u.i.m>>48) < ((0x3fff + 25)<<16 | 0x921f>>1 | 0x8000)) +#define QUOBITS(x) ((uint32_t)(int32_t)x & 0x7fffffff) +#define ROUND1 22 +#define ROUND2 61 +#define NX 3 +#define NY 2 +/* + * invpio2: 64 bits of 2/pi + * pio2_1: first 39 bits of pi/2 + * pio2_1t: pi/2 - pio2_1 + * pio2_2: second 39 bits of pi/2 + * pio2_2t: pi/2 - (pio2_1+pio2_2) + * pio2_3: third 39 bits of pi/2 + * pio2_3t: pi/2 - (pio2_1+pio2_2+pio2_3) + */ +static const double +pio2_1 = 1.57079632679597125389e+00, /* 0x3FF921FB, 0x54444000 */ +pio2_2 = -1.07463465549783099519e-12, /* -0x12e7b967674000.0p-92 */ +pio2_3 = 6.36831716351370313614e-25; /* 0x18a2e037074000.0p-133 */ +static const long double +invpio2 = 6.36619772367581343076e-01L, /* 0xa2f9836e4e44152a.0p-64 */ +pio2_1t = -1.07463465549719416346e-12L, /* -0x973dcb3b399d747f.0p-103 */ +pio2_2t = 6.36831716351095013979e-25L, /* 0xc51701b839a25205.0p-144 */ +pio2_3t = -2.75299651904407171810e-37L; /* -0xbb5bf6c7ddd660ce.0p-185 */ +#elif LDBL_MANT_DIG == 113 +/* u ~< 0x1p45*pi/2 */ +#define SMALL(u) (((u.i.se & 0x7fffU)<<16 | u.i.top) < ((0x3fff + 45)<<16 | 0x921f)) +#define QUOBITS(x) ((uint32_t)(int64_t)x & 0x7fffffff) +#define ROUND1 51 +#define ROUND2 119 +#define NX 5 +#define NY 3 +static const long double +invpio2 = 6.3661977236758134307553505349005747e-01L, /* 0x145f306dc9c882a53f84eafa3ea6a.0p-113 */ +pio2_1 = 1.5707963267948966192292994253909555e+00L, /* 0x1921fb54442d18469800000000000.0p-112 */ +pio2_1t = 2.0222662487959507323996846200947577e-21L, /* 0x13198a2e03707344a4093822299f3.0p-181 */ +pio2_2 = 2.0222662487959507323994779168837751e-21L, /* 0x13198a2e03707344a400000000000.0p-181 */ +pio2_2t = 2.0670321098263988236496903051604844e-43L, /* 0x127044533e63a0105df531d89cd91.0p-254 */ +pio2_3 = 2.0670321098263988236499468110329591e-43L, /* 0x127044533e63a0105e00000000000.0p-254 */ +pio2_3t = -2.5650587247459238361625433492959285e-65L; /* -0x159c4ec64ddaeb5f78671cbfb2210.0p-327 */ +#endif + +int __rem_pio2l(long double x, long double *y) +{ + union ldshape u,uz; + long double z,w,t,r,fn; + double tx[NX],ty[NY]; + int ex,ey,n,i; + + u.f = x; + ex = u.i.se & 0x7fff; + if (SMALL(u)) { + /* rint(x/(pi/2)), Assume round-to-nearest. */ + fn = x*invpio2 + toint - toint; + n = QUOBITS(fn); + r = x-fn*pio2_1; + w = fn*pio2_1t; /* 1st round good to 102/180 bits (ld80/ld128) */ + y[0] = r-w; + u.f = y[0]; + ey = u.i.se & 0x7fff; + if (ex - ey > ROUND1) { /* 2nd iteration needed, good to 141/248 (ld80/ld128) */ + t = r; + w = fn*pio2_2; + r = t-w; + w = fn*pio2_2t-((t-r)-w); + y[0] = r-w; + u.f = y[0]; + ey = u.i.se & 0x7fff; + if (ex - ey > ROUND2) { /* 3rd iteration, good to 180/316 bits */ + t = r; /* will cover all possible cases (not verified for ld128) */ + w = fn*pio2_3; + r = t-w; + w = fn*pio2_3t-((t-r)-w); + y[0] = r-w; + } + } + y[1] = (r - y[0]) - w; + return n; + } + /* + * all other (large) arguments + */ + if (ex == 0x7fff) { /* x is inf or NaN */ + y[0] = y[1] = x - x; + return 0; + } + /* set z = scalbn(|x|,-ilogb(x)+23) */ + uz.f = x; + uz.i.se = 0x3fff + 23; + z = uz.f; + for (i=0; i < NX - 1; i++) { + tx[i] = (double)(int32_t)z; + z = (z-tx[i])*0x1p24; + } + tx[i] = z; + while (tx[i] == 0) + i--; + n = __rem_pio2_large(tx, ty, ex-0x3fff-23, i+1, NY); + w = ty[1]; + if (NY == 3) + w += ty[2]; + r = ty[0] + w; + /* TODO: for ld128 this does not follow the recommendation of the + comments of __rem_pio2_large which seem wrong if |ty[0]| > |ty[1]+ty[2]| */ + w -= r - ty[0]; + if (u.i.se >> 15) { + y[0] = -r; + y[1] = -w; + return -n; + } + y[0] = r; + y[1] = w; + return n; +} +#endif diff --git a/lib/mlibc/options/ansi/musl-generic-math/__signbit.c b/lib/mlibc/options/ansi/musl-generic-math/__signbit.c new file mode 100644 index 0000000..e700b6b --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/__signbit.c @@ -0,0 +1,13 @@ +#include "libm.h" + +// FIXME: macro in math.h +int __signbit(double x) +{ + union { + double d; + uint64_t i; + } y = { x }; + return y.i>>63; +} + + diff --git a/lib/mlibc/options/ansi/musl-generic-math/__signbitf.c b/lib/mlibc/options/ansi/musl-generic-math/__signbitf.c new file mode 100644 index 0000000..40ad3cf --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/__signbitf.c @@ -0,0 +1,11 @@ +#include "libm.h" + +// FIXME: macro in math.h +int __signbitf(float x) +{ + union { + float f; + uint32_t i; + } y = { x }; + return y.i>>31; +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/__signbitl.c b/lib/mlibc/options/ansi/musl-generic-math/__signbitl.c new file mode 100644 index 0000000..63b3dc5 --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/__signbitl.c @@ -0,0 +1,14 @@ +#include "libm.h" + +#if (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 +int __signbitl(long double x) +{ + union ldshape u = {x}; + return u.i.se >> 15; +} +#elif LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +int __signbitl(long double x) +{ + return __signbit(x); +} +#endif diff --git a/lib/mlibc/options/ansi/musl-generic-math/__sin.c b/lib/mlibc/options/ansi/musl-generic-math/__sin.c new file mode 100644 index 0000000..4030949 --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/__sin.c @@ -0,0 +1,64 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/k_sin.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* __sin( x, y, iy) + * kernel sin function on ~[-pi/4, pi/4] (except on -0), pi/4 ~ 0.7854 + * Input x is assumed to be bounded by ~pi/4 in magnitude. + * Input y is the tail of x. + * Input iy indicates whether y is 0. (if iy=0, y assume to be 0). + * + * Algorithm + * 1. Since sin(-x) = -sin(x), we need only to consider positive x. + * 2. Callers must return sin(-0) = -0 without calling here since our + * odd polynomial is not evaluated in a way that preserves -0. + * Callers may do the optimization sin(x) ~ x for tiny x. + * 3. sin(x) is approximated by a polynomial of degree 13 on + * [0,pi/4] + * 3 13 + * sin(x) ~ x + S1*x + ... + S6*x + * where + * + * |sin(x) 2 4 6 8 10 12 | -58 + * |----- - (1+S1*x +S2*x +S3*x +S4*x +S5*x +S6*x )| <= 2 + * | x | + * + * 4. sin(x+y) = sin(x) + sin'(x')*y + * ~ sin(x) + (1-x*x/2)*y + * For better accuracy, let + * 3 2 2 2 2 + * r = x *(S2+x *(S3+x *(S4+x *(S5+x *S6)))) + * then 3 2 + * sin(x) = x + (S1*x + (x *(r-y/2)+y)) + */ + +#include "libm.h" + +static const double +S1 = -1.66666666666666324348e-01, /* 0xBFC55555, 0x55555549 */ +S2 = 8.33333333332248946124e-03, /* 0x3F811111, 0x1110F8A6 */ +S3 = -1.98412698298579493134e-04, /* 0xBF2A01A0, 0x19C161D5 */ +S4 = 2.75573137070700676789e-06, /* 0x3EC71DE3, 0x57B1FE7D */ +S5 = -2.50507602534068634195e-08, /* 0xBE5AE5E6, 0x8A2B9CEB */ +S6 = 1.58969099521155010221e-10; /* 0x3DE5D93A, 0x5ACFD57C */ + +double __sin(double x, double y, int iy) +{ + double_t z,r,v,w; + + z = x*x; + w = z*z; + r = S2 + z*(S3 + z*S4) + z*w*(S5 + z*S6); + v = z*x; + if (iy == 0) + return x + v*(S1 + z*r); + else + return x - ((z*(0.5*y - v*r) - y) - v*S1); +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/__sindf.c b/lib/mlibc/options/ansi/musl-generic-math/__sindf.c new file mode 100644 index 0000000..8fec2a3 --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/__sindf.c @@ -0,0 +1,36 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/k_sinf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + * Optimized by Bruce D. Evans. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "libm.h" + +/* |sin(x)/x - s(x)| < 2**-37.5 (~[-4.89e-12, 4.824e-12]). */ +static const double +S1 = -0x15555554cbac77.0p-55, /* -0.166666666416265235595 */ +S2 = 0x111110896efbb2.0p-59, /* 0.0083333293858894631756 */ +S3 = -0x1a00f9e2cae774.0p-65, /* -0.000198393348360966317347 */ +S4 = 0x16cd878c3b46a7.0p-71; /* 0.0000027183114939898219064 */ + +float __sindf(double x) +{ + double_t r, s, w, z; + + /* Try to optimize for parallel evaluation as in __tandf.c. */ + z = x*x; + w = z*z; + r = S3 + z*S4; + s = z*x; + return (x + s*(S1 + z*S2)) + s*w*r; +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/__sinl.c b/lib/mlibc/options/ansi/musl-generic-math/__sinl.c new file mode 100644 index 0000000..2525bbe --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/__sinl.c @@ -0,0 +1,78 @@ +/* origin: FreeBSD /usr/src/lib/msun/ld80/k_sinl.c */ +/* origin: FreeBSD /usr/src/lib/msun/ld128/k_sinl.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * Copyright (c) 2008 Steven G. Kargl, David Schultz, Bruce D. Evans. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "libm.h" + +#if (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 +#if LDBL_MANT_DIG == 64 +/* + * ld80 version of __sin.c. See __sin.c for most comments. + */ +/* + * Domain [-0.7854, 0.7854], range ~[-1.89e-22, 1.915e-22] + * |sin(x)/x - s(x)| < 2**-72.1 + * + * See __cosl.c for more details about the polynomial. + */ +static const long double +S1 = -0.166666666666666666671L; /* -0xaaaaaaaaaaaaaaab.0p-66 */ +static const double +S2 = 0.0083333333333333332, /* 0x11111111111111.0p-59 */ +S3 = -0.00019841269841269427, /* -0x1a01a01a019f81.0p-65 */ +S4 = 0.0000027557319223597490, /* 0x171de3a55560f7.0p-71 */ +S5 = -0.000000025052108218074604, /* -0x1ae64564f16cad.0p-78 */ +S6 = 1.6059006598854211e-10, /* 0x161242b90243b5.0p-85 */ +S7 = -7.6429779983024564e-13, /* -0x1ae42ebd1b2e00.0p-93 */ +S8 = 2.6174587166648325e-15; /* 0x179372ea0b3f64.0p-101 */ +#define POLY(z) (S2+z*(S3+z*(S4+z*(S5+z*(S6+z*(S7+z*S8)))))) +#elif LDBL_MANT_DIG == 113 +/* + * ld128 version of __sin.c. See __sin.c for most comments. + */ +/* + * Domain [-0.7854, 0.7854], range ~[-1.53e-37, 1.659e-37] + * |sin(x)/x - s(x)| < 2**-122.1 + * + * See __cosl.c for more details about the polynomial. + */ +static const long double +S1 = -0.16666666666666666666666666666666666606732416116558L, +S2 = 0.0083333333333333333333333333333331135404851288270047L, +S3 = -0.00019841269841269841269841269839935785325638310428717L, +S4 = 0.27557319223985890652557316053039946268333231205686e-5L, +S5 = -0.25052108385441718775048214826384312253862930064745e-7L, +S6 = 0.16059043836821614596571832194524392581082444805729e-9L, +S7 = -0.76471637318198151807063387954939213287488216303768e-12L, +S8 = 0.28114572543451292625024967174638477283187397621303e-14L; +static const double +S9 = -0.82206352458348947812512122163446202498005154296863e-17, +S10 = 0.19572940011906109418080609928334380560135358385256e-19, +S11 = -0.38680813379701966970673724299207480965452616911420e-22, +S12 = 0.64038150078671872796678569586315881020659912139412e-25; +#define POLY(z) (S2+z*(S3+z*(S4+z*(S5+z*(S6+z*(S7+z*(S8+ \ + z*(S9+z*(S10+z*(S11+z*S12)))))))))) +#endif + +long double __sinl(long double x, long double y, int iy) +{ + long double z,r,v; + + z = x*x; + v = z*x; + r = POLY(z); + if (iy == 0) + return x+v*(S1+z*r); + return x-((z*(0.5*y-v*r)-y)-v*S1); +} +#endif diff --git a/lib/mlibc/options/ansi/musl-generic-math/__tan.c b/lib/mlibc/options/ansi/musl-generic-math/__tan.c new file mode 100644 index 0000000..8019844 --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/__tan.c @@ -0,0 +1,110 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/k_tan.c */ +/* + * ==================================================== + * Copyright 2004 Sun Microsystems, Inc. All Rights Reserved. + * + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* __tan( x, y, k ) + * kernel tan function on ~[-pi/4, pi/4] (except on -0), pi/4 ~ 0.7854 + * Input x is assumed to be bounded by ~pi/4 in magnitude. + * Input y is the tail of x. + * Input odd indicates whether tan (if odd = 0) or -1/tan (if odd = 1) is returned. + * + * Algorithm + * 1. Since tan(-x) = -tan(x), we need only to consider positive x. + * 2. Callers must return tan(-0) = -0 without calling here since our + * odd polynomial is not evaluated in a way that preserves -0. + * Callers may do the optimization tan(x) ~ x for tiny x. + * 3. tan(x) is approximated by a odd polynomial of degree 27 on + * [0,0.67434] + * 3 27 + * tan(x) ~ x + T1*x + ... + T13*x + * where + * + * |tan(x) 2 4 26 | -59.2 + * |----- - (1+T1*x +T2*x +.... +T13*x )| <= 2 + * | x | + * + * Note: tan(x+y) = tan(x) + tan'(x)*y + * ~ tan(x) + (1+x*x)*y + * Therefore, for better accuracy in computing tan(x+y), let + * 3 2 2 2 2 + * r = x *(T2+x *(T3+x *(...+x *(T12+x *T13)))) + * then + * 3 2 + * tan(x+y) = x + (T1*x + (x *(r+y)+y)) + * + * 4. For x in [0.67434,pi/4], let y = pi/4 - x, then + * tan(x) = tan(pi/4-y) = (1-tan(y))/(1+tan(y)) + * = 1 - 2*(tan(y) - (tan(y)^2)/(1+tan(y))) + */ + +#include "libm.h" + +static const double T[] = { + 3.33333333333334091986e-01, /* 3FD55555, 55555563 */ + 1.33333333333201242699e-01, /* 3FC11111, 1110FE7A */ + 5.39682539762260521377e-02, /* 3FABA1BA, 1BB341FE */ + 2.18694882948595424599e-02, /* 3F9664F4, 8406D637 */ + 8.86323982359930005737e-03, /* 3F8226E3, E96E8493 */ + 3.59207910759131235356e-03, /* 3F6D6D22, C9560328 */ + 1.45620945432529025516e-03, /* 3F57DBC8, FEE08315 */ + 5.88041240820264096874e-04, /* 3F4344D8, F2F26501 */ + 2.46463134818469906812e-04, /* 3F3026F7, 1A8D1068 */ + 7.81794442939557092300e-05, /* 3F147E88, A03792A6 */ + 7.14072491382608190305e-05, /* 3F12B80F, 32F0A7E9 */ + -1.85586374855275456654e-05, /* BEF375CB, DB605373 */ + 2.59073051863633712884e-05, /* 3EFB2A70, 74BF7AD4 */ +}, +pio4 = 7.85398163397448278999e-01, /* 3FE921FB, 54442D18 */ +pio4lo = 3.06161699786838301793e-17; /* 3C81A626, 33145C07 */ + +double __tan(double x, double y, int odd) +{ + double_t z, r, v, w, s, a; + double w0, a0; + uint32_t hx; + int big, sign; + + GET_HIGH_WORD(hx,x); + big = (hx&0x7fffffff) >= 0x3FE59428; /* |x| >= 0.6744 */ + if (big) { + sign = hx>>31; + if (sign) { + x = -x; + y = -y; + } + x = (pio4 - x) + (pio4lo - y); + y = 0.0; + } + z = x * x; + w = z * z; + /* + * Break x^5*(T[1]+x^2*T[2]+...) into + * x^5(T[1]+x^4*T[3]+...+x^20*T[11]) + + * x^5(x^2*(T[2]+x^4*T[4]+...+x^22*[T12])) + */ + r = T[1] + w*(T[3] + w*(T[5] + w*(T[7] + w*(T[9] + w*T[11])))); + v = z*(T[2] + w*(T[4] + w*(T[6] + w*(T[8] + w*(T[10] + w*T[12]))))); + s = z * x; + r = y + z*(s*(r + v) + y) + s*T[0]; + w = x + r; + if (big) { + s = 1 - 2*odd; + v = s - 2.0 * (x + (r - w*w/(w + s))); + return sign ? -v : v; + } + if (!odd) + return w; + /* -1.0/(x+r) has up to 2ulp error, so compute it accurately */ + w0 = w; + SET_LOW_WORD(w0, 0); + v = r - (w0 - x); /* w0+v = r+x */ + a0 = a = -1.0 / w; + SET_LOW_WORD(a0, 0); + return a0 + a*(1.0 + a0*w0 + a0*v); +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/__tandf.c b/lib/mlibc/options/ansi/musl-generic-math/__tandf.c new file mode 100644 index 0000000..25047ee --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/__tandf.c @@ -0,0 +1,54 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/k_tanf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + * Optimized by Bruce D. Evans. + */ +/* + * ==================================================== + * Copyright 2004 Sun Microsystems, Inc. All Rights Reserved. + * + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "libm.h" + +/* |tan(x)/x - t(x)| < 2**-25.5 (~[-2e-08, 2e-08]). */ +static const double T[] = { + 0x15554d3418c99f.0p-54, /* 0.333331395030791399758 */ + 0x1112fd38999f72.0p-55, /* 0.133392002712976742718 */ + 0x1b54c91d865afe.0p-57, /* 0.0533812378445670393523 */ + 0x191df3908c33ce.0p-58, /* 0.0245283181166547278873 */ + 0x185dadfcecf44e.0p-61, /* 0.00297435743359967304927 */ + 0x1362b9bf971bcd.0p-59, /* 0.00946564784943673166728 */ +}; + +float __tandf(double x, int odd) +{ + double_t z,r,w,s,t,u; + + z = x*x; + /* + * Split up the polynomial into small independent terms to give + * opportunities for parallel evaluation. The chosen splitting is + * micro-optimized for Athlons (XP, X64). It costs 2 multiplications + * relative to Horner's method on sequential machines. + * + * We add the small terms from lowest degree up for efficiency on + * non-sequential machines (the lowest degree terms tend to be ready + * earlier). Apart from this, we don't care about order of + * operations, and don't need to to care since we have precision to + * spare. However, the chosen splitting is good for accuracy too, + * and would give results as accurate as Horner's method if the + * small terms were added from highest degree down. + */ + r = T[4] + z*T[5]; + t = T[2] + z*T[3]; + w = z*z; + s = z*x; + u = T[0] + z*T[1]; + r = (x + s*u) + (s*w)*(t + w*r); + return odd ? -1.0/r : r; +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/__tanl.c b/lib/mlibc/options/ansi/musl-generic-math/__tanl.c new file mode 100644 index 0000000..54abc3d --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/__tanl.c @@ -0,0 +1,143 @@ +/* origin: FreeBSD /usr/src/lib/msun/ld80/k_tanl.c */ +/* origin: FreeBSD /usr/src/lib/msun/ld128/k_tanl.c */ +/* + * ==================================================== + * Copyright 2004 Sun Microsystems, Inc. All Rights Reserved. + * Copyright (c) 2008 Steven G. Kargl, David Schultz, Bruce D. Evans. + * + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "libm.h" + +#if (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 +#if LDBL_MANT_DIG == 64 +/* + * ld80 version of __tan.c. See __tan.c for most comments. + */ +/* + * Domain [-0.67434, 0.67434], range ~[-2.25e-22, 1.921e-22] + * |tan(x)/x - t(x)| < 2**-71.9 + * + * See __cosl.c for more details about the polynomial. + */ +static const long double +T3 = 0.333333333333333333180L, /* 0xaaaaaaaaaaaaaaa5.0p-65 */ +T5 = 0.133333333333333372290L, /* 0x88888888888893c3.0p-66 */ +T7 = 0.0539682539682504975744L, /* 0xdd0dd0dd0dc13ba2.0p-68 */ +pio4 = 0.785398163397448309628L, /* 0xc90fdaa22168c235.0p-64 */ +pio4lo = -1.25413940316708300586e-20L; /* -0xece675d1fc8f8cbb.0p-130 */ +static const double +T9 = 0.021869488536312216, /* 0x1664f4882cc1c2.0p-58 */ +T11 = 0.0088632355256619590, /* 0x1226e355c17612.0p-59 */ +T13 = 0.0035921281113786528, /* 0x1d6d3d185d7ff8.0p-61 */ +T15 = 0.0014558334756312418, /* 0x17da354aa3f96b.0p-62 */ +T17 = 0.00059003538700862256, /* 0x13559358685b83.0p-63 */ +T19 = 0.00023907843576635544, /* 0x1f56242026b5be.0p-65 */ +T21 = 0.000097154625656538905, /* 0x1977efc26806f4.0p-66 */ +T23 = 0.000038440165747303162, /* 0x14275a09b3ceac.0p-67 */ +T25 = 0.000018082171885432524, /* 0x12f5e563e5487e.0p-68 */ +T27 = 0.0000024196006108814377, /* 0x144c0d80cc6896.0p-71 */ +T29 = 0.0000078293456938132840, /* 0x106b59141a6cb3.0p-69 */ +T31 = -0.0000032609076735050182, /* -0x1b5abef3ba4b59.0p-71 */ +T33 = 0.0000023261313142559411; /* 0x13835436c0c87f.0p-71 */ +#define RPOLY(w) (T5 + w * (T9 + w * (T13 + w * (T17 + w * (T21 + \ + w * (T25 + w * (T29 + w * T33))))))) +#define VPOLY(w) (T7 + w * (T11 + w * (T15 + w * (T19 + w * (T23 + \ + w * (T27 + w * T31)))))) +#elif LDBL_MANT_DIG == 113 +/* + * ld128 version of __tan.c. See __tan.c for most comments. + */ +/* + * Domain [-0.67434, 0.67434], range ~[-3.37e-36, 1.982e-37] + * |tan(x)/x - t(x)| < 2**-117.8 (XXX should be ~1e-37) + * + * See __cosl.c for more details about the polynomial. + */ +static const long double +T3 = 0x1.5555555555555555555555555553p-2L, +T5 = 0x1.1111111111111111111111111eb5p-3L, +T7 = 0x1.ba1ba1ba1ba1ba1ba1ba1b694cd6p-5L, +T9 = 0x1.664f4882c10f9f32d6bbe09d8bcdp-6L, +T11 = 0x1.226e355e6c23c8f5b4f5762322eep-7L, +T13 = 0x1.d6d3d0e157ddfb5fed8e84e27b37p-9L, +T15 = 0x1.7da36452b75e2b5fce9ee7c2c92ep-10L, +T17 = 0x1.355824803674477dfcf726649efep-11L, +T19 = 0x1.f57d7734d1656e0aceb716f614c2p-13L, +T21 = 0x1.967e18afcb180ed942dfdc518d6cp-14L, +T23 = 0x1.497d8eea21e95bc7e2aa79b9f2cdp-15L, +T25 = 0x1.0b132d39f055c81be49eff7afd50p-16L, +T27 = 0x1.b0f72d33eff7bfa2fbc1059d90b6p-18L, +T29 = 0x1.5ef2daf21d1113df38d0fbc00267p-19L, +T31 = 0x1.1c77d6eac0234988cdaa04c96626p-20L, +T33 = 0x1.cd2a5a292b180e0bdd701057dfe3p-22L, +T35 = 0x1.75c7357d0298c01a31d0a6f7d518p-23L, +T37 = 0x1.2f3190f4718a9a520f98f50081fcp-24L, +pio4 = 0x1.921fb54442d18469898cc51701b8p-1L, +pio4lo = 0x1.cd129024e088a67cc74020bbea60p-116L; +static const double +T39 = 0.000000028443389121318352, /* 0x1e8a7592977938.0p-78 */ +T41 = 0.000000011981013102001973, /* 0x19baa1b1223219.0p-79 */ +T43 = 0.0000000038303578044958070, /* 0x107385dfb24529.0p-80 */ +T45 = 0.0000000034664378216909893, /* 0x1dc6c702a05262.0p-81 */ +T47 = -0.0000000015090641701997785, /* -0x19ecef3569ebb6.0p-82 */ +T49 = 0.0000000029449552300483952, /* 0x194c0668da786a.0p-81 */ +T51 = -0.0000000022006995706097711, /* -0x12e763b8845268.0p-81 */ +T53 = 0.0000000015468200913196612, /* 0x1a92fc98c29554.0p-82 */ +T55 = -0.00000000061311613386849674, /* -0x151106cbc779a9.0p-83 */ +T57 = 1.4912469681508012e-10; /* 0x147edbdba6f43a.0p-85 */ +#define RPOLY(w) (T5 + w * (T9 + w * (T13 + w * (T17 + w * (T21 + \ + w * (T25 + w * (T29 + w * (T33 + w * (T37 + w * (T41 + \ + w * (T45 + w * (T49 + w * (T53 + w * T57))))))))))))) +#define VPOLY(w) (T7 + w * (T11 + w * (T15 + w * (T19 + w * (T23 + \ + w * (T27 + w * (T31 + w * (T35 + w * (T39 + w * (T43 + \ + w * (T47 + w * (T51 + w * T55)))))))))))) +#endif + +long double __tanl(long double x, long double y, int odd) { + long double z, r, v, w, s, a, t; + int big, sign; + + big = fabsl(x) >= 0.67434; + if (big) { + sign = 0; + if (x < 0) { + sign = 1; + x = -x; + y = -y; + } + x = (pio4 - x) + (pio4lo - y); + y = 0.0; + } + z = x * x; + w = z * z; + r = RPOLY(w); + v = z * VPOLY(w); + s = z * x; + r = y + z * (s * (r + v) + y) + T3 * s; + w = x + r; + if (big) { + s = 1 - 2*odd; + v = s - 2.0 * (x + (r - w * w / (w + s))); + return sign ? -v : v; + } + if (!odd) + return w; + /* + * if allow error up to 2 ulp, simply return + * -1.0 / (x+r) here + */ + /* compute -1.0 / (x+r) accurately */ + z = w; + z = z + 0x1p32 - 0x1p32; + v = r - (z - x); /* z+v = r+x */ + t = a = -1.0 / w; /* a = -1.0/w */ + t = t + 0x1p32 - 0x1p32; + s = 1.0 + t * z; + return t + a * (s + t * v); +} +#endif diff --git a/lib/mlibc/options/ansi/musl-generic-math/acos.c b/lib/mlibc/options/ansi/musl-generic-math/acos.c new file mode 100644 index 0000000..ea9c87b --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/acos.c @@ -0,0 +1,101 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_acos.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* acos(x) + * Method : + * acos(x) = pi/2 - asin(x) + * acos(-x) = pi/2 + asin(x) + * For |x|<=0.5 + * acos(x) = pi/2 - (x + x*x^2*R(x^2)) (see asin.c) + * For x>0.5 + * acos(x) = pi/2 - (pi/2 - 2asin(sqrt((1-x)/2))) + * = 2asin(sqrt((1-x)/2)) + * = 2s + 2s*z*R(z) ...z=(1-x)/2, s=sqrt(z) + * = 2f + (2c + 2s*z*R(z)) + * where f=hi part of s, and c = (z-f*f)/(s+f) is the correction term + * for f so that f+c ~ sqrt(z). + * For x<-0.5 + * acos(x) = pi - 2asin(sqrt((1-|x|)/2)) + * = pi - 0.5*(s+s*z*R(z)), where z=(1-|x|)/2,s=sqrt(z) + * + * Special cases: + * if x is NaN, return x itself; + * if |x|>1, return NaN with invalid signal. + * + * Function needed: sqrt + */ + +#include "libm.h" + +static const double +pio2_hi = 1.57079632679489655800e+00, /* 0x3FF921FB, 0x54442D18 */ +pio2_lo = 6.12323399573676603587e-17, /* 0x3C91A626, 0x33145C07 */ +pS0 = 1.66666666666666657415e-01, /* 0x3FC55555, 0x55555555 */ +pS1 = -3.25565818622400915405e-01, /* 0xBFD4D612, 0x03EB6F7D */ +pS2 = 2.01212532134862925881e-01, /* 0x3FC9C155, 0x0E884455 */ +pS3 = -4.00555345006794114027e-02, /* 0xBFA48228, 0xB5688F3B */ +pS4 = 7.91534994289814532176e-04, /* 0x3F49EFE0, 0x7501B288 */ +pS5 = 3.47933107596021167570e-05, /* 0x3F023DE1, 0x0DFDF709 */ +qS1 = -2.40339491173441421878e+00, /* 0xC0033A27, 0x1C8A2D4B */ +qS2 = 2.02094576023350569471e+00, /* 0x40002AE5, 0x9C598AC8 */ +qS3 = -6.88283971605453293030e-01, /* 0xBFE6066C, 0x1B8D0159 */ +qS4 = 7.70381505559019352791e-02; /* 0x3FB3B8C5, 0xB12E9282 */ + +static double R(double z) +{ + double_t p, q; + p = z*(pS0+z*(pS1+z*(pS2+z*(pS3+z*(pS4+z*pS5))))); + q = 1.0+z*(qS1+z*(qS2+z*(qS3+z*qS4))); + return p/q; +} + +double acos(double x) +{ + double z,w,s,c,df; + uint32_t hx,ix; + + GET_HIGH_WORD(hx, x); + ix = hx & 0x7fffffff; + /* |x| >= 1 or nan */ + if (ix >= 0x3ff00000) { + uint32_t lx; + + GET_LOW_WORD(lx,x); + if ((ix-0x3ff00000 | lx) == 0) { + /* acos(1)=0, acos(-1)=pi */ + if (hx >> 31) + return 2*pio2_hi + 0x1p-120f; + return 0; + } + return 0/(x-x); + } + /* |x| < 0.5 */ + if (ix < 0x3fe00000) { + if (ix <= 0x3c600000) /* |x| < 2**-57 */ + return pio2_hi + 0x1p-120f; + return pio2_hi - (x - (pio2_lo-x*R(x*x))); + } + /* x < -0.5 */ + if (hx >> 31) { + z = (1.0+x)*0.5; + s = sqrt(z); + w = R(z)*s-pio2_lo; + return 2*(pio2_hi - (s+w)); + } + /* x > 0.5 */ + z = (1.0-x)*0.5; + s = sqrt(z); + df = s; + SET_LOW_WORD(df,0); + c = (z-df*df)/(s+df); + w = R(z)*s+c; + return 2*(df+w); +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/acosf.c b/lib/mlibc/options/ansi/musl-generic-math/acosf.c new file mode 100644 index 0000000..8ee1a71 --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/acosf.c @@ -0,0 +1,71 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_acosf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "libm.h" + +static const float +pio2_hi = 1.5707962513e+00, /* 0x3fc90fda */ +pio2_lo = 7.5497894159e-08, /* 0x33a22168 */ +pS0 = 1.6666586697e-01, +pS1 = -4.2743422091e-02, +pS2 = -8.6563630030e-03, +qS1 = -7.0662963390e-01; + +static float R(float z) +{ + float_t p, q; + p = z*(pS0+z*(pS1+z*pS2)); + q = 1.0f+z*qS1; + return p/q; +} + +float acosf(float x) +{ + float z,w,s,c,df; + uint32_t hx,ix; + + GET_FLOAT_WORD(hx, x); + ix = hx & 0x7fffffff; + /* |x| >= 1 or nan */ + if (ix >= 0x3f800000) { + if (ix == 0x3f800000) { + if (hx >> 31) + return 2*pio2_hi + 0x1p-120f; + return 0; + } + return 0/(x-x); + } + /* |x| < 0.5 */ + if (ix < 0x3f000000) { + if (ix <= 0x32800000) /* |x| < 2**-26 */ + return pio2_hi + 0x1p-120f; + return pio2_hi - (x - (pio2_lo-x*R(x*x))); + } + /* x < -0.5 */ + if (hx >> 31) { + z = (1+x)*0.5f; + s = sqrtf(z); + w = R(z)*s-pio2_lo; + return 2*(pio2_hi - (s+w)); + } + /* x > 0.5 */ + z = (1-x)*0.5f; + s = sqrtf(z); + GET_FLOAT_WORD(hx,s); + SET_FLOAT_WORD(df,hx&0xfffff000); + c = (z-df*df)/(s+df); + w = R(z)*s+c; + return 2*(df+w); +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/acosh.c b/lib/mlibc/options/ansi/musl-generic-math/acosh.c new file mode 100644 index 0000000..badbf90 --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/acosh.c @@ -0,0 +1,24 @@ +#include "libm.h" + +#if FLT_EVAL_METHOD==2 +#undef sqrt +#define sqrt sqrtl +#endif + +/* acosh(x) = log(x + sqrt(x*x-1)) */ +double acosh(double x) +{ + union {double f; uint64_t i;} u = {.f = x}; + unsigned e = u.i >> 52 & 0x7ff; + + /* x < 1 domain error is handled in the called functions */ + + if (e < 0x3ff + 1) + /* |x| < 2, up to 2ulp error in [1,1.125] */ + return log1p(x-1 + sqrt((x-1)*(x-1)+2*(x-1))); + if (e < 0x3ff + 26) + /* |x| < 0x1p26 */ + return log(2*x - 1/(x+sqrt(x*x-1))); + /* |x| >= 0x1p26 or nan */ + return log(x) + 0.693147180559945309417232121458176568; +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/acoshf.c b/lib/mlibc/options/ansi/musl-generic-math/acoshf.c new file mode 100644 index 0000000..8a4ec4d --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/acoshf.c @@ -0,0 +1,26 @@ +#include "libm.h" + +#if FLT_EVAL_METHOD==2 +#undef sqrtf +#define sqrtf sqrtl +#elif FLT_EVAL_METHOD==1 +#undef sqrtf +#define sqrtf sqrt +#endif + +/* acosh(x) = log(x + sqrt(x*x-1)) */ +float acoshf(float x) +{ + union {float f; uint32_t i;} u = {x}; + uint32_t a = u.i & 0x7fffffff; + + if (a < 0x3f800000+(1<<23)) + /* |x| < 2, invalid if x < 1 or nan */ + /* up to 2ulp error in [1,1.125] */ + return log1pf(x-1 + sqrtf((x-1)*(x-1)+2*(x-1))); + if (a < 0x3f800000+(12<<23)) + /* |x| < 0x1p12 */ + return logf(2*x - 1/(x+sqrtf(x*x-1))); + /* x >= 0x1p12 */ + return logf(x) + 0.693147180559945309417232121458176568f; +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/acoshl.c b/lib/mlibc/options/ansi/musl-generic-math/acoshl.c new file mode 100644 index 0000000..8d4b43f --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/acoshl.c @@ -0,0 +1,29 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double acoshl(long double x) +{ + return acosh(x); +} +#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 +/* acosh(x) = log(x + sqrt(x*x-1)) */ +long double acoshl(long double x) +{ + union ldshape u = {x}; + int e = u.i.se & 0x7fff; + + if (e < 0x3fff + 1) + /* |x| < 2, invalid if x < 1 or nan */ + return log1pl(x-1 + sqrtl((x-1)*(x-1)+2*(x-1))); + if (e < 0x3fff + 32) + /* |x| < 0x1p32 */ + return logl(2*x - 1/(x+sqrtl(x*x-1))); + return logl(x) + 0.693147180559945309417232121458176568L; +} +#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 +// TODO: broken implementation to make things compile +long double acoshl(long double x) +{ + return acosh(x); +} +#endif diff --git a/lib/mlibc/options/ansi/musl-generic-math/acosl.c b/lib/mlibc/options/ansi/musl-generic-math/acosl.c new file mode 100644 index 0000000..c03bdf0 --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/acosl.c @@ -0,0 +1,67 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_acosl.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* + * See comments in acos.c. + * Converted to long double by David Schultz . + */ + +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double acosl(long double x) +{ + return acos(x); +} +#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 +#include "__invtrigl.h" +#if LDBL_MANT_DIG == 64 +#define CLEARBOTTOM(u) (u.i.m &= -1ULL << 32) +#elif LDBL_MANT_DIG == 113 +#define CLEARBOTTOM(u) (u.i.lo = 0) +#endif + +long double acosl(long double x) +{ + union ldshape u = {x}; + long double z, s, c, f; + uint16_t e = u.i.se & 0x7fff; + + /* |x| >= 1 or nan */ + if (e >= 0x3fff) { + if (x == 1) + return 0; + if (x == -1) + return 2*pio2_hi + 0x1p-120f; + return 0/(x-x); + } + /* |x| < 0.5 */ + if (e < 0x3fff - 1) { + if (e < 0x3fff - LDBL_MANT_DIG - 1) + return pio2_hi + 0x1p-120f; + return pio2_hi - (__invtrigl_R(x*x)*x - pio2_lo + x); + } + /* x < -0.5 */ + if (u.i.se >> 15) { + z = (1 + x)*0.5; + s = sqrtl(z); + return 2*(pio2_hi - (__invtrigl_R(z)*s - pio2_lo + s)); + } + /* x > 0.5 */ + z = (1 - x)*0.5; + s = sqrtl(z); + u.f = s; + CLEARBOTTOM(u); + f = u.f; + c = (z - f*f)/(s + f); + return 2*(__invtrigl_R(z)*s + c + f); +} +#endif diff --git a/lib/mlibc/options/ansi/musl-generic-math/asin.c b/lib/mlibc/options/ansi/musl-generic-math/asin.c new file mode 100644 index 0000000..c926b18 --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/asin.c @@ -0,0 +1,107 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_asin.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* asin(x) + * Method : + * Since asin(x) = x + x^3/6 + x^5*3/40 + x^7*15/336 + ... + * we approximate asin(x) on [0,0.5] by + * asin(x) = x + x*x^2*R(x^2) + * where + * R(x^2) is a rational approximation of (asin(x)-x)/x^3 + * and its remez error is bounded by + * |(asin(x)-x)/x^3 - R(x^2)| < 2^(-58.75) + * + * For x in [0.5,1] + * asin(x) = pi/2-2*asin(sqrt((1-x)/2)) + * Let y = (1-x), z = y/2, s := sqrt(z), and pio2_hi+pio2_lo=pi/2; + * then for x>0.98 + * asin(x) = pi/2 - 2*(s+s*z*R(z)) + * = pio2_hi - (2*(s+s*z*R(z)) - pio2_lo) + * For x<=0.98, let pio4_hi = pio2_hi/2, then + * f = hi part of s; + * c = sqrt(z) - f = (z-f*f)/(s+f) ...f+c=sqrt(z) + * and + * asin(x) = pi/2 - 2*(s+s*z*R(z)) + * = pio4_hi+(pio4-2s)-(2s*z*R(z)-pio2_lo) + * = pio4_hi+(pio4-2f)-(2s*z*R(z)-(pio2_lo+2c)) + * + * Special cases: + * if x is NaN, return x itself; + * if |x|>1, return NaN with invalid signal. + * + */ + +#include "libm.h" + +static const double +pio2_hi = 1.57079632679489655800e+00, /* 0x3FF921FB, 0x54442D18 */ +pio2_lo = 6.12323399573676603587e-17, /* 0x3C91A626, 0x33145C07 */ +/* coefficients for R(x^2) */ +pS0 = 1.66666666666666657415e-01, /* 0x3FC55555, 0x55555555 */ +pS1 = -3.25565818622400915405e-01, /* 0xBFD4D612, 0x03EB6F7D */ +pS2 = 2.01212532134862925881e-01, /* 0x3FC9C155, 0x0E884455 */ +pS3 = -4.00555345006794114027e-02, /* 0xBFA48228, 0xB5688F3B */ +pS4 = 7.91534994289814532176e-04, /* 0x3F49EFE0, 0x7501B288 */ +pS5 = 3.47933107596021167570e-05, /* 0x3F023DE1, 0x0DFDF709 */ +qS1 = -2.40339491173441421878e+00, /* 0xC0033A27, 0x1C8A2D4B */ +qS2 = 2.02094576023350569471e+00, /* 0x40002AE5, 0x9C598AC8 */ +qS3 = -6.88283971605453293030e-01, /* 0xBFE6066C, 0x1B8D0159 */ +qS4 = 7.70381505559019352791e-02; /* 0x3FB3B8C5, 0xB12E9282 */ + +static double R(double z) +{ + double_t p, q; + p = z*(pS0+z*(pS1+z*(pS2+z*(pS3+z*(pS4+z*pS5))))); + q = 1.0+z*(qS1+z*(qS2+z*(qS3+z*qS4))); + return p/q; +} + +double asin(double x) +{ + double z,r,s; + uint32_t hx,ix; + + GET_HIGH_WORD(hx, x); + ix = hx & 0x7fffffff; + /* |x| >= 1 or nan */ + if (ix >= 0x3ff00000) { + uint32_t lx; + GET_LOW_WORD(lx, x); + if ((ix-0x3ff00000 | lx) == 0) + /* asin(1) = +-pi/2 with inexact */ + return x*pio2_hi + 0x1p-120f; + return 0/(x-x); + } + /* |x| < 0.5 */ + if (ix < 0x3fe00000) { + /* if 0x1p-1022 <= |x| < 0x1p-26, avoid raising underflow */ + if (ix < 0x3e500000 && ix >= 0x00100000) + return x; + return x + x*R(x*x); + } + /* 1 > |x| >= 0.5 */ + z = (1 - fabs(x))*0.5; + s = sqrt(z); + r = R(z); + if (ix >= 0x3fef3333) { /* if |x| > 0.975 */ + x = pio2_hi-(2*(s+s*r)-pio2_lo); + } else { + double f,c; + /* f+c = sqrt(z) */ + f = s; + SET_LOW_WORD(f,0); + c = (z-f*f)/(s+f); + x = 0.5*pio2_hi - (2*s*r - (pio2_lo-2*c) - (0.5*pio2_hi-2*f)); + } + if (hx >> 31) + return -x; + return x; +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/asinf.c b/lib/mlibc/options/ansi/musl-generic-math/asinf.c new file mode 100644 index 0000000..bcd304a --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/asinf.c @@ -0,0 +1,61 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_asinf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +#include "libm.h" + +static const double +pio2 = 1.570796326794896558e+00; + +static const float +/* coefficients for R(x^2) */ +pS0 = 1.6666586697e-01, +pS1 = -4.2743422091e-02, +pS2 = -8.6563630030e-03, +qS1 = -7.0662963390e-01; + +static float R(float z) +{ + float_t p, q; + p = z*(pS0+z*(pS1+z*pS2)); + q = 1.0f+z*qS1; + return p/q; +} + +float asinf(float x) +{ + double s; + float z; + uint32_t hx,ix; + + GET_FLOAT_WORD(hx, x); + ix = hx & 0x7fffffff; + if (ix >= 0x3f800000) { /* |x| >= 1 */ + if (ix == 0x3f800000) /* |x| == 1 */ + return x*pio2 + 0x1p-120f; /* asin(+-1) = +-pi/2 with inexact */ + return 0/(x-x); /* asin(|x|>1) is NaN */ + } + if (ix < 0x3f000000) { /* |x| < 0.5 */ + /* if 0x1p-126 <= |x| < 0x1p-12, avoid raising underflow */ + if (ix < 0x39800000 && ix >= 0x00800000) + return x; + return x + x*R(x*x); + } + /* 1 > |x| >= 0.5 */ + z = (1 - fabsf(x))*0.5f; + s = sqrt(z); + x = pio2 - 2*(s+s*R(z)); + if (hx >> 31) + return -x; + return x; +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/asinh.c b/lib/mlibc/options/ansi/musl-generic-math/asinh.c new file mode 100644 index 0000000..0829f22 --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/asinh.c @@ -0,0 +1,28 @@ +#include "libm.h" + +/* asinh(x) = sign(x)*log(|x|+sqrt(x*x+1)) ~= x - x^3/6 + o(x^5) */ +double asinh(double x) +{ + union {double f; uint64_t i;} u = {.f = x}; + unsigned e = u.i >> 52 & 0x7ff; + unsigned s = u.i >> 63; + + /* |x| */ + u.i &= (uint64_t)-1/2; + x = u.f; + + if (e >= 0x3ff + 26) { + /* |x| >= 0x1p26 or inf or nan */ + x = log(x) + 0.693147180559945309417232121458176568; + } else if (e >= 0x3ff + 1) { + /* |x| >= 2 */ + x = log(2*x + 1/(sqrt(x*x+1)+x)); + } else if (e >= 0x3ff - 26) { + /* |x| >= 0x1p-26, up to 1.6ulp error in [0.125,0.5] */ + x = log1p(x + x*x/(sqrt(x*x+1)+1)); + } else { + /* |x| < 0x1p-26, raise inexact if x != 0 */ + FORCE_EVAL(x + 0x1p120f); + } + return s ? -x : x; +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/asinhf.c b/lib/mlibc/options/ansi/musl-generic-math/asinhf.c new file mode 100644 index 0000000..fc9f091 --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/asinhf.c @@ -0,0 +1,28 @@ +#include "libm.h" + +/* asinh(x) = sign(x)*log(|x|+sqrt(x*x+1)) ~= x - x^3/6 + o(x^5) */ +float asinhf(float x) +{ + union {float f; uint32_t i;} u = {.f = x}; + uint32_t i = u.i & 0x7fffffff; + unsigned s = u.i >> 31; + + /* |x| */ + u.i = i; + x = u.f; + + if (i >= 0x3f800000 + (12<<23)) { + /* |x| >= 0x1p12 or inf or nan */ + x = logf(x) + 0.693147180559945309417232121458176568f; + } else if (i >= 0x3f800000 + (1<<23)) { + /* |x| >= 2 */ + x = logf(2*x + 1/(sqrtf(x*x+1)+x)); + } else if (i >= 0x3f800000 - (12<<23)) { + /* |x| >= 0x1p-12, up to 1.6ulp error in [0.125,0.5] */ + x = log1pf(x + x*x/(sqrtf(x*x+1)+1)); + } else { + /* |x| < 0x1p-12, raise inexact if x!=0 */ + FORCE_EVAL(x + 0x1p120f); + } + return s ? -x : x; +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/asinhl.c b/lib/mlibc/options/ansi/musl-generic-math/asinhl.c new file mode 100644 index 0000000..8635f52 --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/asinhl.c @@ -0,0 +1,41 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double asinhl(long double x) +{ + return asinh(x); +} +#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 +/* asinh(x) = sign(x)*log(|x|+sqrt(x*x+1)) ~= x - x^3/6 + o(x^5) */ +long double asinhl(long double x) +{ + union ldshape u = {x}; + unsigned e = u.i.se & 0x7fff; + unsigned s = u.i.se >> 15; + + /* |x| */ + u.i.se = e; + x = u.f; + + if (e >= 0x3fff + 32) { + /* |x| >= 0x1p32 or inf or nan */ + x = logl(x) + 0.693147180559945309417232121458176568L; + } else if (e >= 0x3fff + 1) { + /* |x| >= 2 */ + x = logl(2*x + 1/(sqrtl(x*x+1)+x)); + } else if (e >= 0x3fff - 32) { + /* |x| >= 0x1p-32 */ + x = log1pl(x + x*x/(sqrtl(x*x+1)+1)); + } else { + /* |x| < 0x1p-32, raise inexact if x!=0 */ + FORCE_EVAL(x + 0x1p120f); + } + return s ? -x : x; +} +#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 +// TODO: broken implementation to make things compile +long double asinhl(long double x) +{ + return asinh(x); +} +#endif diff --git a/lib/mlibc/options/ansi/musl-generic-math/asinl.c b/lib/mlibc/options/ansi/musl-generic-math/asinl.c new file mode 100644 index 0000000..347c535 --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/asinl.c @@ -0,0 +1,71 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_asinl.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* + * See comments in asin.c. + * Converted to long double by David Schultz . + */ + +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double asinl(long double x) +{ + return asin(x); +} +#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 +#include "__invtrigl.h" +#if LDBL_MANT_DIG == 64 +#define CLOSETO1(u) (u.i.m>>56 >= 0xf7) +#define CLEARBOTTOM(u) (u.i.m &= -1ULL << 32) +#elif LDBL_MANT_DIG == 113 +#define CLOSETO1(u) (u.i.top >= 0xee00) +#define CLEARBOTTOM(u) (u.i.lo = 0) +#endif + +long double asinl(long double x) +{ + union ldshape u = {x}; + long double z, r, s; + uint16_t e = u.i.se & 0x7fff; + int sign = u.i.se >> 15; + + if (e >= 0x3fff) { /* |x| >= 1 or nan */ + /* asin(+-1)=+-pi/2 with inexact */ + if (x == 1 || x == -1) + return x*pio2_hi + 0x1p-120f; + return 0/(x-x); + } + if (e < 0x3fff - 1) { /* |x| < 0.5 */ + if (e < 0x3fff - (LDBL_MANT_DIG+1)/2) { + /* return x with inexact if x!=0 */ + FORCE_EVAL(x + 0x1p120f); + return x; + } + return x + x*__invtrigl_R(x*x); + } + /* 1 > |x| >= 0.5 */ + z = (1.0 - fabsl(x))*0.5; + s = sqrtl(z); + r = __invtrigl_R(z); + if (CLOSETO1(u)) { + x = pio2_hi - (2*(s+s*r)-pio2_lo); + } else { + long double f, c; + u.f = s; + CLEARBOTTOM(u); + f = u.f; + c = (z - f*f)/(s + f); + x = 0.5*pio2_hi-(2*s*r - (pio2_lo-2*c) - (0.5*pio2_hi-2*f)); + } + return sign ? -x : x; +} +#endif diff --git a/lib/mlibc/options/ansi/musl-generic-math/atan.c b/lib/mlibc/options/ansi/musl-generic-math/atan.c new file mode 100644 index 0000000..63b0ab2 --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/atan.c @@ -0,0 +1,116 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_atan.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* atan(x) + * Method + * 1. Reduce x to positive by atan(x) = -atan(-x). + * 2. According to the integer k=4t+0.25 chopped, t=x, the argument + * is further reduced to one of the following intervals and the + * arctangent of t is evaluated by the corresponding formula: + * + * [0,7/16] atan(x) = t-t^3*(a1+t^2*(a2+...(a10+t^2*a11)...) + * [7/16,11/16] atan(x) = atan(1/2) + atan( (t-0.5)/(1+t/2) ) + * [11/16.19/16] atan(x) = atan( 1 ) + atan( (t-1)/(1+t) ) + * [19/16,39/16] atan(x) = atan(3/2) + atan( (t-1.5)/(1+1.5t) ) + * [39/16,INF] atan(x) = atan(INF) + atan( -1/t ) + * + * Constants: + * The hexadecimal values are the intended ones for the following + * constants. The decimal values may be used, provided that the + * compiler will convert from decimal to binary accurately enough + * to produce the hexadecimal values shown. + */ + + +#include "libm.h" + +static const double atanhi[] = { + 4.63647609000806093515e-01, /* atan(0.5)hi 0x3FDDAC67, 0x0561BB4F */ + 7.85398163397448278999e-01, /* atan(1.0)hi 0x3FE921FB, 0x54442D18 */ + 9.82793723247329054082e-01, /* atan(1.5)hi 0x3FEF730B, 0xD281F69B */ + 1.57079632679489655800e+00, /* atan(inf)hi 0x3FF921FB, 0x54442D18 */ +}; + +static const double atanlo[] = { + 2.26987774529616870924e-17, /* atan(0.5)lo 0x3C7A2B7F, 0x222F65E2 */ + 3.06161699786838301793e-17, /* atan(1.0)lo 0x3C81A626, 0x33145C07 */ + 1.39033110312309984516e-17, /* atan(1.5)lo 0x3C700788, 0x7AF0CBBD */ + 6.12323399573676603587e-17, /* atan(inf)lo 0x3C91A626, 0x33145C07 */ +}; + +static const double aT[] = { + 3.33333333333329318027e-01, /* 0x3FD55555, 0x5555550D */ + -1.99999999998764832476e-01, /* 0xBFC99999, 0x9998EBC4 */ + 1.42857142725034663711e-01, /* 0x3FC24924, 0x920083FF */ + -1.11111104054623557880e-01, /* 0xBFBC71C6, 0xFE231671 */ + 9.09088713343650656196e-02, /* 0x3FB745CD, 0xC54C206E */ + -7.69187620504482999495e-02, /* 0xBFB3B0F2, 0xAF749A6D */ + 6.66107313738753120669e-02, /* 0x3FB10D66, 0xA0D03D51 */ + -5.83357013379057348645e-02, /* 0xBFADDE2D, 0x52DEFD9A */ + 4.97687799461593236017e-02, /* 0x3FA97B4B, 0x24760DEB */ + -3.65315727442169155270e-02, /* 0xBFA2B444, 0x2C6A6C2F */ + 1.62858201153657823623e-02, /* 0x3F90AD3A, 0xE322DA11 */ +}; + +double atan(double x) +{ + double_t w,s1,s2,z; + uint32_t ix,sign; + int id; + + GET_HIGH_WORD(ix, x); + sign = ix >> 31; + ix &= 0x7fffffff; + if (ix >= 0x44100000) { /* if |x| >= 2^66 */ + if (isnan(x)) + return x; + z = atanhi[3] + 0x1p-120f; + return sign ? -z : z; + } + if (ix < 0x3fdc0000) { /* |x| < 0.4375 */ + if (ix < 0x3e400000) { /* |x| < 2^-27 */ + if (ix < 0x00100000) + /* raise underflow for subnormal x */ + FORCE_EVAL((float)x); + return x; + } + id = -1; + } else { + x = fabs(x); + if (ix < 0x3ff30000) { /* |x| < 1.1875 */ + if (ix < 0x3fe60000) { /* 7/16 <= |x| < 11/16 */ + id = 0; + x = (2.0*x-1.0)/(2.0+x); + } else { /* 11/16 <= |x| < 19/16 */ + id = 1; + x = (x-1.0)/(x+1.0); + } + } else { + if (ix < 0x40038000) { /* |x| < 2.4375 */ + id = 2; + x = (x-1.5)/(1.0+1.5*x); + } else { /* 2.4375 <= |x| < 2^66 */ + id = 3; + x = -1.0/x; + } + } + } + /* end of argument reduction */ + z = x*x; + w = z*z; + /* break sum from i=0 to 10 aT[i]z**(i+1) into odd and even poly */ + s1 = z*(aT[0]+w*(aT[2]+w*(aT[4]+w*(aT[6]+w*(aT[8]+w*aT[10]))))); + s2 = w*(aT[1]+w*(aT[3]+w*(aT[5]+w*(aT[7]+w*aT[9])))); + if (id < 0) + return x - x*(s1+s2); + z = atanhi[id] - (x*(s1+s2) - atanlo[id] - x); + return sign ? -z : z; +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/atan2.c b/lib/mlibc/options/ansi/musl-generic-math/atan2.c new file mode 100644 index 0000000..5a1903c --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/atan2.c @@ -0,0 +1,107 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_atan2.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + * + */ +/* atan2(y,x) + * Method : + * 1. Reduce y to positive by atan2(y,x)=-atan2(-y,x). + * 2. Reduce x to positive by (if x and y are unexceptional): + * ARG (x+iy) = arctan(y/x) ... if x > 0, + * ARG (x+iy) = pi - arctan[y/(-x)] ... if x < 0, + * + * Special cases: + * + * ATAN2((anything), NaN ) is NaN; + * ATAN2(NAN , (anything) ) is NaN; + * ATAN2(+-0, +(anything but NaN)) is +-0 ; + * ATAN2(+-0, -(anything but NaN)) is +-pi ; + * ATAN2(+-(anything but 0 and NaN), 0) is +-pi/2; + * ATAN2(+-(anything but INF and NaN), +INF) is +-0 ; + * ATAN2(+-(anything but INF and NaN), -INF) is +-pi; + * ATAN2(+-INF,+INF ) is +-pi/4 ; + * ATAN2(+-INF,-INF ) is +-3pi/4; + * ATAN2(+-INF, (anything but,0,NaN, and INF)) is +-pi/2; + * + * Constants: + * The hexadecimal values are the intended ones for the following + * constants. The decimal values may be used, provided that the + * compiler will convert from decimal to binary accurately enough + * to produce the hexadecimal values shown. + */ + +#include "libm.h" + +static const double +pi = 3.1415926535897931160E+00, /* 0x400921FB, 0x54442D18 */ +pi_lo = 1.2246467991473531772E-16; /* 0x3CA1A626, 0x33145C07 */ + +double atan2(double y, double x) +{ + double z; + uint32_t m,lx,ly,ix,iy; + + if (isnan(x) || isnan(y)) + return x+y; + EXTRACT_WORDS(ix, lx, x); + EXTRACT_WORDS(iy, ly, y); + if ((ix-0x3ff00000 | lx) == 0) /* x = 1.0 */ + return atan(y); + m = ((iy>>31)&1) | ((ix>>30)&2); /* 2*sign(x)+sign(y) */ + ix = ix & 0x7fffffff; + iy = iy & 0x7fffffff; + + /* when y = 0 */ + if ((iy|ly) == 0) { + switch(m) { + case 0: + case 1: return y; /* atan(+-0,+anything)=+-0 */ + case 2: return pi; /* atan(+0,-anything) = pi */ + case 3: return -pi; /* atan(-0,-anything) =-pi */ + } + } + /* when x = 0 */ + if ((ix|lx) == 0) + return m&1 ? -pi/2 : pi/2; + /* when x is INF */ + if (ix == 0x7ff00000) { + if (iy == 0x7ff00000) { + switch(m) { + case 0: return pi/4; /* atan(+INF,+INF) */ + case 1: return -pi/4; /* atan(-INF,+INF) */ + case 2: return 3*pi/4; /* atan(+INF,-INF) */ + case 3: return -3*pi/4; /* atan(-INF,-INF) */ + } + } else { + switch(m) { + case 0: return 0.0; /* atan(+...,+INF) */ + case 1: return -0.0; /* atan(-...,+INF) */ + case 2: return pi; /* atan(+...,-INF) */ + case 3: return -pi; /* atan(-...,-INF) */ + } + } + } + /* |y/x| > 0x1p64 */ + if (ix+(64<<20) < iy || iy == 0x7ff00000) + return m&1 ? -pi/2 : pi/2; + + /* z = atan(|y/x|) without spurious underflow */ + if ((m&2) && iy+(64<<20) < ix) /* |y/x| < 0x1p-64, x<0 */ + z = 0; + else + z = atan(fabs(y/x)); + switch (m) { + case 0: return z; /* atan(+,+) */ + case 1: return -z; /* atan(-,+) */ + case 2: return pi - (z-pi_lo); /* atan(+,-) */ + default: /* case 3 */ + return (z-pi_lo) - pi; /* atan(-,-) */ + } +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/atan2f.c b/lib/mlibc/options/ansi/musl-generic-math/atan2f.c new file mode 100644 index 0000000..c634d00 --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/atan2f.c @@ -0,0 +1,83 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_atan2f.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "libm.h" + +static const float +pi = 3.1415927410e+00, /* 0x40490fdb */ +pi_lo = -8.7422776573e-08; /* 0xb3bbbd2e */ + +float atan2f(float y, float x) +{ + float z; + uint32_t m,ix,iy; + + if (isnan(x) || isnan(y)) + return x+y; + GET_FLOAT_WORD(ix, x); + GET_FLOAT_WORD(iy, y); + if (ix == 0x3f800000) /* x=1.0 */ + return atanf(y); + m = ((iy>>31)&1) | ((ix>>30)&2); /* 2*sign(x)+sign(y) */ + ix &= 0x7fffffff; + iy &= 0x7fffffff; + + /* when y = 0 */ + if (iy == 0) { + switch (m) { + case 0: + case 1: return y; /* atan(+-0,+anything)=+-0 */ + case 2: return pi; /* atan(+0,-anything) = pi */ + case 3: return -pi; /* atan(-0,-anything) =-pi */ + } + } + /* when x = 0 */ + if (ix == 0) + return m&1 ? -pi/2 : pi/2; + /* when x is INF */ + if (ix == 0x7f800000) { + if (iy == 0x7f800000) { + switch (m) { + case 0: return pi/4; /* atan(+INF,+INF) */ + case 1: return -pi/4; /* atan(-INF,+INF) */ + case 2: return 3*pi/4; /*atan(+INF,-INF)*/ + case 3: return -3*pi/4; /*atan(-INF,-INF)*/ + } + } else { + switch (m) { + case 0: return 0.0f; /* atan(+...,+INF) */ + case 1: return -0.0f; /* atan(-...,+INF) */ + case 2: return pi; /* atan(+...,-INF) */ + case 3: return -pi; /* atan(-...,-INF) */ + } + } + } + /* |y/x| > 0x1p26 */ + if (ix+(26<<23) < iy || iy == 0x7f800000) + return m&1 ? -pi/2 : pi/2; + + /* z = atan(|y/x|) with correct underflow */ + if ((m&2) && iy+(26<<23) < ix) /*|y/x| < 0x1p-26, x < 0 */ + z = 0.0; + else + z = atanf(fabsf(y/x)); + switch (m) { + case 0: return z; /* atan(+,+) */ + case 1: return -z; /* atan(-,+) */ + case 2: return pi - (z-pi_lo); /* atan(+,-) */ + default: /* case 3 */ + return (z-pi_lo) - pi; /* atan(-,-) */ + } +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/atan2l.c b/lib/mlibc/options/ansi/musl-generic-math/atan2l.c new file mode 100644 index 0000000..f0937a9 --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/atan2l.c @@ -0,0 +1,85 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_atan2l.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + * + */ +/* + * See comments in atan2.c. + * Converted to long double by David Schultz . + */ + +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double atan2l(long double y, long double x) +{ + return atan2(y, x); +} +#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 +#include "__invtrigl.h" + +long double atan2l(long double y, long double x) +{ + union ldshape ux, uy; + long double z; + int m, ex, ey; + + if (isnan(x) || isnan(y)) + return x+y; + if (x == 1) + return atanl(y); + ux.f = x; + uy.f = y; + ex = ux.i.se & 0x7fff; + ey = uy.i.se & 0x7fff; + m = 2*(ux.i.se>>15) | uy.i.se>>15; + if (y == 0) { + switch(m) { + case 0: + case 1: return y; /* atan(+-0,+anything)=+-0 */ + case 2: return 2*pio2_hi; /* atan(+0,-anything) = pi */ + case 3: return -2*pio2_hi; /* atan(-0,-anything) =-pi */ + } + } + if (x == 0) + return m&1 ? -pio2_hi : pio2_hi; + if (ex == 0x7fff) { + if (ey == 0x7fff) { + switch(m) { + case 0: return pio2_hi/2; /* atan(+INF,+INF) */ + case 1: return -pio2_hi/2; /* atan(-INF,+INF) */ + case 2: return 1.5*pio2_hi; /* atan(+INF,-INF) */ + case 3: return -1.5*pio2_hi; /* atan(-INF,-INF) */ + } + } else { + switch(m) { + case 0: return 0.0; /* atan(+...,+INF) */ + case 1: return -0.0; /* atan(-...,+INF) */ + case 2: return 2*pio2_hi; /* atan(+...,-INF) */ + case 3: return -2*pio2_hi; /* atan(-...,-INF) */ + } + } + } + if (ex+120 < ey || ey == 0x7fff) + return m&1 ? -pio2_hi : pio2_hi; + /* z = atan(|y/x|) without spurious underflow */ + if ((m&2) && ey+120 < ex) /* |y/x| < 0x1p-120, x<0 */ + z = 0.0; + else + z = atanl(fabsl(y/x)); + switch (m) { + case 0: return z; /* atan(+,+) */ + case 1: return -z; /* atan(-,+) */ + case 2: return 2*pio2_hi-(z-2*pio2_lo); /* atan(+,-) */ + default: /* case 3 */ + return (z-2*pio2_lo)-2*pio2_hi; /* atan(-,-) */ + } +} +#endif diff --git a/lib/mlibc/options/ansi/musl-generic-math/atanf.c b/lib/mlibc/options/ansi/musl-generic-math/atanf.c new file mode 100644 index 0000000..178341b --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/atanf.c @@ -0,0 +1,94 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_atanf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + + +#include "libm.h" + +static const float atanhi[] = { + 4.6364760399e-01, /* atan(0.5)hi 0x3eed6338 */ + 7.8539812565e-01, /* atan(1.0)hi 0x3f490fda */ + 9.8279368877e-01, /* atan(1.5)hi 0x3f7b985e */ + 1.5707962513e+00, /* atan(inf)hi 0x3fc90fda */ +}; + +static const float atanlo[] = { + 5.0121582440e-09, /* atan(0.5)lo 0x31ac3769 */ + 3.7748947079e-08, /* atan(1.0)lo 0x33222168 */ + 3.4473217170e-08, /* atan(1.5)lo 0x33140fb4 */ + 7.5497894159e-08, /* atan(inf)lo 0x33a22168 */ +}; + +static const float aT[] = { + 3.3333328366e-01, + -1.9999158382e-01, + 1.4253635705e-01, + -1.0648017377e-01, + 6.1687607318e-02, +}; + +float atanf(float x) +{ + float_t w,s1,s2,z; + uint32_t ix,sign; + int id; + + GET_FLOAT_WORD(ix, x); + sign = ix>>31; + ix &= 0x7fffffff; + if (ix >= 0x4c800000) { /* if |x| >= 2**26 */ + if (isnan(x)) + return x; + z = atanhi[3] + 0x1p-120f; + return sign ? -z : z; + } + if (ix < 0x3ee00000) { /* |x| < 0.4375 */ + if (ix < 0x39800000) { /* |x| < 2**-12 */ + if (ix < 0x00800000) + /* raise underflow for subnormal x */ + FORCE_EVAL(x*x); + return x; + } + id = -1; + } else { + x = fabsf(x); + if (ix < 0x3f980000) { /* |x| < 1.1875 */ + if (ix < 0x3f300000) { /* 7/16 <= |x| < 11/16 */ + id = 0; + x = (2.0f*x - 1.0f)/(2.0f + x); + } else { /* 11/16 <= |x| < 19/16 */ + id = 1; + x = (x - 1.0f)/(x + 1.0f); + } + } else { + if (ix < 0x401c0000) { /* |x| < 2.4375 */ + id = 2; + x = (x - 1.5f)/(1.0f + 1.5f*x); + } else { /* 2.4375 <= |x| < 2**26 */ + id = 3; + x = -1.0f/x; + } + } + } + /* end of argument reduction */ + z = x*x; + w = z*z; + /* break sum from i=0 to 10 aT[i]z**(i+1) into odd and even poly */ + s1 = z*(aT[0]+w*(aT[2]+w*aT[4])); + s2 = w*(aT[1]+w*aT[3]); + if (id < 0) + return x - x*(s1+s2); + z = atanhi[id] - ((x*(s1+s2) - atanlo[id]) - x); + return sign ? -z : z; +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/atanh.c b/lib/mlibc/options/ansi/musl-generic-math/atanh.c new file mode 100644 index 0000000..63a035d --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/atanh.c @@ -0,0 +1,29 @@ +#include "libm.h" + +/* atanh(x) = log((1+x)/(1-x))/2 = log1p(2x/(1-x))/2 ~= x + x^3/3 + o(x^5) */ +double atanh(double x) +{ + union {double f; uint64_t i;} u = {.f = x}; + unsigned e = u.i >> 52 & 0x7ff; + unsigned s = u.i >> 63; + double_t y; + + /* |x| */ + u.i &= (uint64_t)-1/2; + y = u.f; + + if (e < 0x3ff - 1) { + if (e < 0x3ff - 32) { + /* handle underflow */ + if (e == 0) + FORCE_EVAL((float)y); + } else { + /* |x| < 0.5, up to 1.7ulp error */ + y = 0.5*log1p(2*y + 2*y*y/(1-y)); + } + } else { + /* avoid overflow */ + y = 0.5*log1p(2*(y/(1-y))); + } + return s ? -y : y; +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/atanhf.c b/lib/mlibc/options/ansi/musl-generic-math/atanhf.c new file mode 100644 index 0000000..65f07c0 --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/atanhf.c @@ -0,0 +1,28 @@ +#include "libm.h" + +/* atanh(x) = log((1+x)/(1-x))/2 = log1p(2x/(1-x))/2 ~= x + x^3/3 + o(x^5) */ +float atanhf(float x) +{ + union {float f; uint32_t i;} u = {.f = x}; + unsigned s = u.i >> 31; + float_t y; + + /* |x| */ + u.i &= 0x7fffffff; + y = u.f; + + if (u.i < 0x3f800000 - (1<<23)) { + if (u.i < 0x3f800000 - (32<<23)) { + /* handle underflow */ + if (u.i < (1<<23)) + FORCE_EVAL((float)(y*y)); + } else { + /* |x| < 0.5, up to 1.7ulp error */ + y = 0.5f*log1pf(2*y + 2*y*y/(1-y)); + } + } else { + /* avoid overflow */ + y = 0.5f*log1pf(2*(y/(1-y))); + } + return s ? -y : y; +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/atanhl.c b/lib/mlibc/options/ansi/musl-generic-math/atanhl.c new file mode 100644 index 0000000..87cd1cd --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/atanhl.c @@ -0,0 +1,35 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double atanhl(long double x) +{ + return atanh(x); +} +#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 +/* atanh(x) = log((1+x)/(1-x))/2 = log1p(2x/(1-x))/2 ~= x + x^3/3 + o(x^5) */ +long double atanhl(long double x) +{ + union ldshape u = {x}; + unsigned e = u.i.se & 0x7fff; + unsigned s = u.i.se >> 15; + + /* |x| */ + u.i.se = e; + x = u.f; + + if (e < 0x3ff - 1) { + if (e < 0x3ff - LDBL_MANT_DIG/2) { + /* handle underflow */ + if (e == 0) + FORCE_EVAL((float)x); + } else { + /* |x| < 0.5, up to 1.7ulp error */ + x = 0.5*log1pl(2*x + 2*x*x/(1-x)); + } + } else { + /* avoid overflow */ + x = 0.5*log1pl(2*(x/(1-x))); + } + return s ? -x : x; +} +#endif diff --git a/lib/mlibc/options/ansi/musl-generic-math/atanl.c b/lib/mlibc/options/ansi/musl-generic-math/atanl.c new file mode 100644 index 0000000..79a3edb --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/atanl.c @@ -0,0 +1,184 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_atanl.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* + * See comments in atan.c. + * Converted to long double by David Schultz . + */ + +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double atanl(long double x) +{ + return atan(x); +} +#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 + +#if LDBL_MANT_DIG == 64 +#define EXPMAN(u) ((u.i.se & 0x7fff)<<8 | (u.i.m>>55 & 0xff)) + +static const long double atanhi[] = { + 4.63647609000806116202e-01L, + 7.85398163397448309628e-01L, + 9.82793723247329067960e-01L, + 1.57079632679489661926e+00L, +}; + +static const long double atanlo[] = { + 1.18469937025062860669e-20L, + -1.25413940316708300586e-20L, + 2.55232234165405176172e-20L, + -2.50827880633416601173e-20L, +}; + +static const long double aT[] = { + 3.33333333333333333017e-01L, + -1.99999999999999632011e-01L, + 1.42857142857046531280e-01L, + -1.11111111100562372733e-01L, + 9.09090902935647302252e-02L, + -7.69230552476207730353e-02L, + 6.66661718042406260546e-02L, + -5.88158892835030888692e-02L, + 5.25499891539726639379e-02L, + -4.70119845393155721494e-02L, + 4.03539201366454414072e-02L, + -2.91303858419364158725e-02L, + 1.24822046299269234080e-02L, +}; + +static long double T_even(long double x) +{ + return aT[0] + x * (aT[2] + x * (aT[4] + x * (aT[6] + + x * (aT[8] + x * (aT[10] + x * aT[12]))))); +} + +static long double T_odd(long double x) +{ + return aT[1] + x * (aT[3] + x * (aT[5] + x * (aT[7] + + x * (aT[9] + x * aT[11])))); +} +#elif LDBL_MANT_DIG == 113 +#define EXPMAN(u) ((u.i.se & 0x7fff)<<8 | u.i.top>>8) + +const long double atanhi[] = { + 4.63647609000806116214256231461214397e-01L, + 7.85398163397448309615660845819875699e-01L, + 9.82793723247329067985710611014666038e-01L, + 1.57079632679489661923132169163975140e+00L, +}; + +const long double atanlo[] = { + 4.89509642257333492668618435220297706e-36L, + 2.16795253253094525619926100651083806e-35L, + -2.31288434538183565909319952098066272e-35L, + 4.33590506506189051239852201302167613e-35L, +}; + +const long double aT[] = { + 3.33333333333333333333333333333333125e-01L, + -1.99999999999999999999999999999180430e-01L, + 1.42857142857142857142857142125269827e-01L, + -1.11111111111111111111110834490810169e-01L, + 9.09090909090909090908522355708623681e-02L, + -7.69230769230769230696553844935357021e-02L, + 6.66666666666666660390096773046256096e-02L, + -5.88235294117646671706582985209643694e-02L, + 5.26315789473666478515847092020327506e-02L, + -4.76190476189855517021024424991436144e-02L, + 4.34782608678695085948531993458097026e-02L, + -3.99999999632663469330634215991142368e-02L, + 3.70370363987423702891250829918659723e-02L, + -3.44827496515048090726669907612335954e-02L, + 3.22579620681420149871973710852268528e-02L, + -3.03020767654269261041647570626778067e-02L, + 2.85641979882534783223403715930946138e-02L, + -2.69824879726738568189929461383741323e-02L, + 2.54194698498808542954187110873675769e-02L, + -2.35083879708189059926183138130183215e-02L, + 2.04832358998165364349957325067131428e-02L, + -1.54489555488544397858507248612362957e-02L, + 8.64492360989278761493037861575248038e-03L, + -2.58521121597609872727919154569765469e-03L, +}; + +static long double T_even(long double x) +{ + return (aT[0] + x * (aT[2] + x * (aT[4] + x * (aT[6] + x * (aT[8] + + x * (aT[10] + x * (aT[12] + x * (aT[14] + x * (aT[16] + + x * (aT[18] + x * (aT[20] + x * aT[22]))))))))))); +} + +static long double T_odd(long double x) +{ + return (aT[1] + x * (aT[3] + x * (aT[5] + x * (aT[7] + x * (aT[9] + + x * (aT[11] + x * (aT[13] + x * (aT[15] + x * (aT[17] + + x * (aT[19] + x * (aT[21] + x * aT[23]))))))))))); +} +#endif + +long double atanl(long double x) +{ + union ldshape u = {x}; + long double w, s1, s2, z; + int id; + unsigned e = u.i.se & 0x7fff; + unsigned sign = u.i.se >> 15; + unsigned expman; + + if (e >= 0x3fff + LDBL_MANT_DIG + 1) { /* if |x| is large, atan(x)~=pi/2 */ + if (isnan(x)) + return x; + return sign ? -atanhi[3] : atanhi[3]; + } + /* Extract the exponent and the first few bits of the mantissa. */ + expman = EXPMAN(u); + if (expman < ((0x3fff - 2) << 8) + 0xc0) { /* |x| < 0.4375 */ + if (e < 0x3fff - (LDBL_MANT_DIG+1)/2) { /* if |x| is small, atanl(x)~=x */ + /* raise underflow if subnormal */ + if (e == 0) + FORCE_EVAL((float)x); + return x; + } + id = -1; + } else { + x = fabsl(x); + if (expman < (0x3fff << 8) + 0x30) { /* |x| < 1.1875 */ + if (expman < ((0x3fff - 1) << 8) + 0x60) { /* 7/16 <= |x| < 11/16 */ + id = 0; + x = (2.0*x-1.0)/(2.0+x); + } else { /* 11/16 <= |x| < 19/16 */ + id = 1; + x = (x-1.0)/(x+1.0); + } + } else { + if (expman < ((0x3fff + 1) << 8) + 0x38) { /* |x| < 2.4375 */ + id = 2; + x = (x-1.5)/(1.0+1.5*x); + } else { /* 2.4375 <= |x| */ + id = 3; + x = -1.0/x; + } + } + } + /* end of argument reduction */ + z = x*x; + w = z*z; + /* break sum aT[i]z**(i+1) into odd and even poly */ + s1 = z*T_even(w); + s2 = w*T_odd(w); + if (id < 0) + return x - x*(s1+s2); + z = atanhi[id] - ((x*(s1+s2) - atanlo[id]) - x); + return sign ? -z : z; +} +#endif diff --git a/lib/mlibc/options/ansi/musl-generic-math/cbrt.c b/lib/mlibc/options/ansi/musl-generic-math/cbrt.c new file mode 100644 index 0000000..7599d3e --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/cbrt.c @@ -0,0 +1,103 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_cbrt.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + * + * Optimized by Bruce D. Evans. + */ +/* cbrt(x) + * Return cube root of x + */ + +#include +#include + +static const uint32_t +B1 = 715094163, /* B1 = (1023-1023/3-0.03306235651)*2**20 */ +B2 = 696219795; /* B2 = (1023-1023/3-54/3-0.03306235651)*2**20 */ + +/* |1/cbrt(x) - p(x)| < 2**-23.5 (~[-7.93e-8, 7.929e-8]). */ +static const double +P0 = 1.87595182427177009643, /* 0x3ffe03e6, 0x0f61e692 */ +P1 = -1.88497979543377169875, /* 0xbffe28e0, 0x92f02420 */ +P2 = 1.621429720105354466140, /* 0x3ff9f160, 0x4a49d6c2 */ +P3 = -0.758397934778766047437, /* 0xbfe844cb, 0xbee751d9 */ +P4 = 0.145996192886612446982; /* 0x3fc2b000, 0xd4e4edd7 */ + +double cbrt(double x) +{ + union {double f; uint64_t i;} u = {x}; + double_t r,s,t,w; + uint32_t hx = u.i>>32 & 0x7fffffff; + + if (hx >= 0x7ff00000) /* cbrt(NaN,INF) is itself */ + return x+x; + + /* + * Rough cbrt to 5 bits: + * cbrt(2**e*(1+m) ~= 2**(e/3)*(1+(e%3+m)/3) + * where e is integral and >= 0, m is real and in [0, 1), and "/" and + * "%" are integer division and modulus with rounding towards minus + * infinity. The RHS is always >= the LHS and has a maximum relative + * error of about 1 in 16. Adding a bias of -0.03306235651 to the + * (e%3+m)/3 term reduces the error to about 1 in 32. With the IEEE + * floating point representation, for finite positive normal values, + * ordinary integer divison of the value in bits magically gives + * almost exactly the RHS of the above provided we first subtract the + * exponent bias (1023 for doubles) and later add it back. We do the + * subtraction virtually to keep e >= 0 so that ordinary integer + * division rounds towards minus infinity; this is also efficient. + */ + if (hx < 0x00100000) { /* zero or subnormal? */ + u.f = x*0x1p54; + hx = u.i>>32 & 0x7fffffff; + if (hx == 0) + return x; /* cbrt(0) is itself */ + hx = hx/3 + B2; + } else + hx = hx/3 + B1; + u.i &= 1ULL<<63; + u.i |= (uint64_t)hx << 32; + t = u.f; + + /* + * New cbrt to 23 bits: + * cbrt(x) = t*cbrt(x/t**3) ~= t*P(t**3/x) + * where P(r) is a polynomial of degree 4 that approximates 1/cbrt(r) + * to within 2**-23.5 when |r - 1| < 1/10. The rough approximation + * has produced t such than |t/cbrt(x) - 1| ~< 1/32, and cubing this + * gives us bounds for r = t**3/x. + * + * Try to optimize for parallel evaluation as in __tanf.c. + */ + r = (t*t)*(t/x); + t = t*((P0+r*(P1+r*P2))+((r*r)*r)*(P3+r*P4)); + + /* + * Round t away from zero to 23 bits (sloppily except for ensuring that + * the result is larger in magnitude than cbrt(x) but not much more than + * 2 23-bit ulps larger). With rounding towards zero, the error bound + * would be ~5/6 instead of ~4/6. With a maximum error of 2 23-bit ulps + * in the rounded t, the infinite-precision error in the Newton + * approximation barely affects third digit in the final error + * 0.667; the error in the rounded t can be up to about 3 23-bit ulps + * before the final error is larger than 0.667 ulps. + */ + u.f = t; + u.i = (u.i + 0x80000000) & 0xffffffffc0000000ULL; + t = u.f; + + /* one step Newton iteration to 53 bits with error < 0.667 ulps */ + s = t*t; /* t*t is exact */ + r = x/s; /* error <= 0.5 ulps; |r| < |t| */ + w = t+t; /* t+t is exact */ + r = (r-t)/(w+r); /* r-t is exact; w+r ~= 3*t */ + t = t+t*r; /* error <= 0.5 + 0.5/3 + epsilon */ + return t; +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/cbrtf.c b/lib/mlibc/options/ansi/musl-generic-math/cbrtf.c new file mode 100644 index 0000000..89c2c86 --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/cbrtf.c @@ -0,0 +1,66 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_cbrtf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + * Debugged and optimized by Bruce D. Evans. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* cbrtf(x) + * Return cube root of x + */ + +#include +#include + +static const unsigned +B1 = 709958130, /* B1 = (127-127.0/3-0.03306235651)*2**23 */ +B2 = 642849266; /* B2 = (127-127.0/3-24/3-0.03306235651)*2**23 */ + +float cbrtf(float x) +{ + double_t r,T; + union {float f; uint32_t i;} u = {x}; + uint32_t hx = u.i & 0x7fffffff; + + if (hx >= 0x7f800000) /* cbrt(NaN,INF) is itself */ + return x + x; + + /* rough cbrt to 5 bits */ + if (hx < 0x00800000) { /* zero or subnormal? */ + if (hx == 0) + return x; /* cbrt(+-0) is itself */ + u.f = x*0x1p24f; + hx = u.i & 0x7fffffff; + hx = hx/3 + B2; + } else + hx = hx/3 + B1; + u.i &= 0x80000000; + u.i |= hx; + + /* + * First step Newton iteration (solving t*t-x/t == 0) to 16 bits. In + * double precision so that its terms can be arranged for efficiency + * without causing overflow or underflow. + */ + T = u.f; + r = T*T*T; + T = T*((double_t)x+x+r)/(x+r+r); + + /* + * Second step Newton iteration to 47 bits. In double precision for + * efficiency and accuracy. + */ + r = T*T*T; + T = T*((double_t)x+x+r)/(x+r+r); + + /* rounding to 24 bits is perfect in round-to-nearest mode */ + return T; +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/cbrtl.c b/lib/mlibc/options/ansi/musl-generic-math/cbrtl.c new file mode 100644 index 0000000..ceff913 --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/cbrtl.c @@ -0,0 +1,124 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_cbrtl.c */ +/*- + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * Copyright (c) 2009-2011, Bruce D. Evans, Steven G. Kargl, David Schultz. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + * + * The argument reduction and testing for exceptional cases was + * written by Steven G. Kargl with input from Bruce D. Evans + * and David A. Schultz. + */ + +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double cbrtl(long double x) +{ + return cbrt(x); +} +#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 +static const unsigned B1 = 709958130; /* B1 = (127-127.0/3-0.03306235651)*2**23 */ + +long double cbrtl(long double x) +{ + union ldshape u = {x}, v; + union {float f; uint32_t i;} uft; + long double r, s, t, w; + double_t dr, dt, dx; + float_t ft; + int e = u.i.se & 0x7fff; + int sign = u.i.se & 0x8000; + + /* + * If x = +-Inf, then cbrt(x) = +-Inf. + * If x = NaN, then cbrt(x) = NaN. + */ + if (e == 0x7fff) + return x + x; + if (e == 0) { + /* Adjust subnormal numbers. */ + u.f *= 0x1p120; + e = u.i.se & 0x7fff; + /* If x = +-0, then cbrt(x) = +-0. */ + if (e == 0) + return x; + e -= 120; + } + e -= 0x3fff; + u.i.se = 0x3fff; + x = u.f; + switch (e % 3) { + case 1: + case -2: + x *= 2; + e--; + break; + case 2: + case -1: + x *= 4; + e -= 2; + break; + } + v.f = 1.0; + v.i.se = sign | (0x3fff + e/3); + + /* + * The following is the guts of s_cbrtf, with the handling of + * special values removed and extra care for accuracy not taken, + * but with most of the extra accuracy not discarded. + */ + + /* ~5-bit estimate: */ + uft.f = x; + uft.i = (uft.i & 0x7fffffff)/3 + B1; + ft = uft.f; + + /* ~16-bit estimate: */ + dx = x; + dt = ft; + dr = dt * dt * dt; + dt = dt * (dx + dx + dr) / (dx + dr + dr); + + /* ~47-bit estimate: */ + dr = dt * dt * dt; + dt = dt * (dx + dx + dr) / (dx + dr + dr); + +#if LDBL_MANT_DIG == 64 + /* + * dt is cbrtl(x) to ~47 bits (after x has been reduced to 1 <= x < 8). + * Round it away from zero to 32 bits (32 so that t*t is exact, and + * away from zero for technical reasons). + */ + t = dt + (0x1.0p32L + 0x1.0p-31L) - 0x1.0p32; +#elif LDBL_MANT_DIG == 113 + /* + * Round dt away from zero to 47 bits. Since we don't trust the 47, + * add 2 47-bit ulps instead of 1 to round up. Rounding is slow and + * might be avoidable in this case, since on most machines dt will + * have been evaluated in 53-bit precision and the technical reasons + * for rounding up might not apply to either case in cbrtl() since + * dt is much more accurate than needed. + */ + t = dt + 0x2.0p-46 + 0x1.0p60L - 0x1.0p60; +#endif + + /* + * Final step Newton iteration to 64 or 113 bits with + * error < 0.667 ulps + */ + s = t*t; /* t*t is exact */ + r = x/s; /* error <= 0.5 ulps; |r| < |t| */ + w = t+t; /* t+t is exact */ + r = (r-t)/(w+r); /* r-t is exact; w+r ~= 3*t */ + t = t+t*r; /* error <= 0.5 + 0.5/3 + epsilon */ + + t *= v.f; + return t; +} +#endif diff --git a/lib/mlibc/options/ansi/musl-generic-math/ceil.c b/lib/mlibc/options/ansi/musl-generic-math/ceil.c new file mode 100644 index 0000000..b13e6f2 --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/ceil.c @@ -0,0 +1,31 @@ +#include "libm.h" + +#if FLT_EVAL_METHOD==0 || FLT_EVAL_METHOD==1 +#define EPS DBL_EPSILON +#elif FLT_EVAL_METHOD==2 +#define EPS LDBL_EPSILON +#endif +static const double_t toint = 1/EPS; + +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; + /* 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 ? -0.0 : 1; + } + if (y < 0) + return x + y + 1; + return x + y; +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/ceilf.c b/lib/mlibc/options/ansi/musl-generic-math/ceilf.c new file mode 100644 index 0000000..869835f --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/ceilf.c @@ -0,0 +1,27 @@ +#include "libm.h" + +float ceilf(float x) +{ + union {float f; uint32_t i;} u = {x}; + int e = (int)(u.i >> 23 & 0xff) - 0x7f; + uint32_t m; + + if (e >= 23) + return x; + if (e >= 0) { + m = 0x007fffff >> e; + if ((u.i & m) == 0) + return x; + FORCE_EVAL(x + 0x1p120f); + if (u.i >> 31 == 0) + u.i += m; + u.i &= ~m; + } else { + FORCE_EVAL(x + 0x1p120f); + if (u.i >> 31) + u.f = -0.0; + else if (u.i << 1) + u.f = 1.0; + } + return u.f; +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/ceill.c b/lib/mlibc/options/ansi/musl-generic-math/ceill.c new file mode 100644 index 0000000..60a8302 --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/ceill.c @@ -0,0 +1,34 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double ceill(long double x) +{ + return ceil(x); +} +#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 + +static const long double toint = 1/LDBL_EPSILON; + +long double ceill(long double x) +{ + union ldshape u = {x}; + int e = u.i.se & 0x7fff; + long double y; + + if (e >= 0x3fff+LDBL_MANT_DIG-1 || x == 0) + return x; + /* y = int(x) - x, where int(x) is an integer neighbor of x */ + if (u.i.se >> 15) + y = x - toint + toint - x; + else + y = x + toint - toint - x; + /* special case because of non-nearest rounding modes */ + if (e <= 0x3fff-1) { + FORCE_EVAL(y); + return u.i.se >> 15 ? -0.0 : 1; + } + if (y < 0) + return x + y + 1; + return x + y; +} +#endif diff --git a/lib/mlibc/options/ansi/musl-generic-math/copysign.c b/lib/mlibc/options/ansi/musl-generic-math/copysign.c new file mode 100644 index 0000000..b09331b --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/copysign.c @@ -0,0 +1,8 @@ +#include "libm.h" + +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; +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/copysignf.c b/lib/mlibc/options/ansi/musl-generic-math/copysignf.c new file mode 100644 index 0000000..0af6ae9 --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/copysignf.c @@ -0,0 +1,10 @@ +#include +#include + +float copysignf(float x, float y) +{ + union {float f; uint32_t i;} ux={x}, uy={y}; + ux.i &= 0x7fffffff; + ux.i |= uy.i & 0x80000000; + return ux.f; +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/copysignl.c b/lib/mlibc/options/ansi/musl-generic-math/copysignl.c new file mode 100644 index 0000000..9dd933c --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/copysignl.c @@ -0,0 +1,16 @@ +#include "libm.h" + +#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 diff --git a/lib/mlibc/options/ansi/musl-generic-math/cos.c b/lib/mlibc/options/ansi/musl-generic-math/cos.c new file mode 100644 index 0000000..ee97f68 --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/cos.c @@ -0,0 +1,77 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_cos.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* cos(x) + * Return cosine function of x. + * + * kernel function: + * __sin ... sine function on [-pi/4,pi/4] + * __cos ... cosine function on [-pi/4,pi/4] + * __rem_pio2 ... argument reduction routine + * + * Method. + * Let S,C and T denote the sin, cos and tan respectively on + * [-PI/4, +PI/4]. Reduce the argument x to y1+y2 = x-k*pi/2 + * in [-pi/4 , +pi/4], and let n = k mod 4. + * We have + * + * n sin(x) cos(x) tan(x) + * ---------------------------------------------------------- + * 0 S C T + * 1 C -S -1/T + * 2 -S -C T + * 3 -C S -1/T + * ---------------------------------------------------------- + * + * Special cases: + * Let trig be any of sin, cos, or tan. + * trig(+-INF) is NaN, with signals; + * trig(NaN) is that NaN; + * + * Accuracy: + * TRIG(x) returns trig(x) nearly rounded + */ + +#include "libm.h" + +double cos(double x) +{ + double y[2]; + uint32_t ix; + unsigned n; + + GET_HIGH_WORD(ix, x); + ix &= 0x7fffffff; + + /* |x| ~< pi/4 */ + if (ix <= 0x3fe921fb) { + if (ix < 0x3e46a09e) { /* |x| < 2**-27 * sqrt(2) */ + /* raise inexact if x!=0 */ + FORCE_EVAL(x + 0x1p120f); + return 1.0; + } + return __cos(x, 0); + } + + /* cos(Inf or NaN) is NaN */ + if (ix >= 0x7ff00000) + return x-x; + + /* argument reduction */ + n = __rem_pio2(x, y); + switch (n&3) { + case 0: return __cos(y[0], y[1]); + case 1: return -__sin(y[0], y[1], 1); + case 2: return -__cos(y[0], y[1]); + default: + return __sin(y[0], y[1], 1); + } +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/cosf.c b/lib/mlibc/options/ansi/musl-generic-math/cosf.c new file mode 100644 index 0000000..23f3e5b --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/cosf.c @@ -0,0 +1,78 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_cosf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + * Optimized by Bruce D. Evans. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "libm.h" + +/* Small multiples of pi/2 rounded to double precision. */ +static const double +c1pio2 = 1*M_PI_2, /* 0x3FF921FB, 0x54442D18 */ +c2pio2 = 2*M_PI_2, /* 0x400921FB, 0x54442D18 */ +c3pio2 = 3*M_PI_2, /* 0x4012D97C, 0x7F3321D2 */ +c4pio2 = 4*M_PI_2; /* 0x401921FB, 0x54442D18 */ + +float cosf(float x) +{ + double y; + uint32_t ix; + unsigned n, sign; + + GET_FLOAT_WORD(ix, x); + sign = ix >> 31; + ix &= 0x7fffffff; + + if (ix <= 0x3f490fda) { /* |x| ~<= pi/4 */ + if (ix < 0x39800000) { /* |x| < 2**-12 */ + /* raise inexact if x != 0 */ + FORCE_EVAL(x + 0x1p120f); + return 1.0f; + } + return __cosdf(x); + } + if (ix <= 0x407b53d1) { /* |x| ~<= 5*pi/4 */ + if (ix > 0x4016cbe3) /* |x| ~> 3*pi/4 */ + return -__cosdf(sign ? x+c2pio2 : x-c2pio2); + else { + if (sign) + return __sindf(x + c1pio2); + else + return __sindf(c1pio2 - x); + } + } + if (ix <= 0x40e231d5) { /* |x| ~<= 9*pi/4 */ + if (ix > 0x40afeddf) /* |x| ~> 7*pi/4 */ + return __cosdf(sign ? x+c4pio2 : x-c4pio2); + else { + if (sign) + return __sindf(-x - c3pio2); + else + return __sindf(x - c3pio2); + } + } + + /* cos(Inf or NaN) is NaN */ + if (ix >= 0x7f800000) + return x-x; + + /* general argument reduction needed */ + n = __rem_pio2f(x,&y); + switch (n&3) { + case 0: return __cosdf(y); + case 1: return __sindf(-y); + case 2: return -__cosdf(y); + default: + return __sindf(y); + } +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/cosh.c b/lib/mlibc/options/ansi/musl-generic-math/cosh.c new file mode 100644 index 0000000..100f823 --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/cosh.c @@ -0,0 +1,40 @@ +#include "libm.h" + +/* cosh(x) = (exp(x) + 1/exp(x))/2 + * = 1 + 0.5*(exp(x)-1)*(exp(x)-1)/exp(x) + * = 1 + x*x/2 + o(x^4) + */ +double cosh(double x) +{ + union {double f; uint64_t i;} u = {.f = x}; + uint32_t w; + double t; + + /* |x| */ + u.i &= (uint64_t)-1/2; + x = u.f; + w = u.i >> 32; + + /* |x| < log(2) */ + if (w < 0x3fe62e42) { + if (w < 0x3ff00000 - (26<<20)) { + /* raise inexact if x!=0 */ + FORCE_EVAL(x + 0x1p120f); + return 1; + } + t = expm1(x); + return 1 + t*t/(2*(1+t)); + } + + /* |x| < log(DBL_MAX) */ + if (w < 0x40862e42) { + t = exp(x); + /* note: if x>log(0x1p26) then the 1/t is not needed */ + return 0.5*(t + 1/t); + } + + /* |x| > log(DBL_MAX) or nan */ + /* note: the result is stored to handle overflow */ + t = __expo2(x); + return t; +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/coshf.c b/lib/mlibc/options/ansi/musl-generic-math/coshf.c new file mode 100644 index 0000000..b09f2ee --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/coshf.c @@ -0,0 +1,33 @@ +#include "libm.h" + +float coshf(float x) +{ + union {float f; uint32_t i;} u = {.f = x}; + uint32_t w; + float t; + + /* |x| */ + u.i &= 0x7fffffff; + x = u.f; + w = u.i; + + /* |x| < log(2) */ + if (w < 0x3f317217) { + if (w < 0x3f800000 - (12<<23)) { + FORCE_EVAL(x + 0x1p120f); + return 1; + } + t = expm1f(x); + return 1 + t*t/(2*(1+t)); + } + + /* |x| < log(FLT_MAX) */ + if (w < 0x42b17217) { + t = expf(x); + return 0.5f*(t + 1/t); + } + + /* |x| > log(FLT_MAX) or nan */ + t = __expo2f(x); + return t; +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/coshl.c b/lib/mlibc/options/ansi/musl-generic-math/coshl.c new file mode 100644 index 0000000..06a56fe --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/coshl.c @@ -0,0 +1,47 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double coshl(long double x) +{ + return cosh(x); +} +#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 +long double coshl(long double x) +{ + union ldshape u = {x}; + unsigned ex = u.i.se & 0x7fff; + uint32_t w; + long double t; + + /* |x| */ + u.i.se = ex; + x = u.f; + w = u.i.m >> 32; + + /* |x| < log(2) */ + if (ex < 0x3fff-1 || (ex == 0x3fff-1 && w < 0xb17217f7)) { + if (ex < 0x3fff-32) { + FORCE_EVAL(x + 0x1p120f); + return 1; + } + t = expm1l(x); + return 1 + t*t/(2*(1+t)); + } + + /* |x| < log(LDBL_MAX) */ + if (ex < 0x3fff+13 || (ex == 0x3fff+13 && w < 0xb17217f7)) { + t = expl(x); + return 0.5*(t + 1/t); + } + + /* |x| > log(LDBL_MAX) or nan */ + t = expl(0.5*x); + return 0.5*t*t; +} +#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 +// TODO: broken implementation to make things compile +long double coshl(long double x) +{ + return cosh(x); +} +#endif diff --git a/lib/mlibc/options/ansi/musl-generic-math/cosl.c b/lib/mlibc/options/ansi/musl-generic-math/cosl.c new file mode 100644 index 0000000..79c41c7 --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/cosl.c @@ -0,0 +1,39 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double cosl(long double x) { + return cos(x); +} +#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 +long double cosl(long double x) +{ + union ldshape u = {x}; + unsigned n; + long double y[2], hi, lo; + + u.i.se &= 0x7fff; + if (u.i.se == 0x7fff) + return x - x; + x = u.f; + if (x < M_PI_4) { + if (u.i.se < 0x3fff - LDBL_MANT_DIG) + /* raise inexact if x!=0 */ + return 1.0 + x; + return __cosl(x, 0); + } + n = __rem_pio2l(x, y); + hi = y[0]; + lo = y[1]; + switch (n & 3) { + case 0: + return __cosl(hi, lo); + case 1: + return -__sinl(hi, lo, 1); + case 2: + return -__cosl(hi, lo); + case 3: + default: + return __sinl(hi, lo, 1); + } +} +#endif diff --git a/lib/mlibc/options/ansi/musl-generic-math/erf.c b/lib/mlibc/options/ansi/musl-generic-math/erf.c new file mode 100644 index 0000000..2f30a29 --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/erf.c @@ -0,0 +1,273 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_erf.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* double erf(double x) + * double erfc(double x) + * x + * 2 |\ + * erf(x) = --------- | exp(-t*t)dt + * sqrt(pi) \| + * 0 + * + * erfc(x) = 1-erf(x) + * Note that + * erf(-x) = -erf(x) + * erfc(-x) = 2 - erfc(x) + * + * Method: + * 1. For |x| in [0, 0.84375] + * erf(x) = x + x*R(x^2) + * erfc(x) = 1 - erf(x) if x in [-.84375,0.25] + * = 0.5 + ((0.5-x)-x*R) if x in [0.25,0.84375] + * where R = P/Q where P is an odd poly of degree 8 and + * Q is an odd poly of degree 10. + * -57.90 + * | R - (erf(x)-x)/x | <= 2 + * + * + * Remark. The formula is derived by noting + * erf(x) = (2/sqrt(pi))*(x - x^3/3 + x^5/10 - x^7/42 + ....) + * and that + * 2/sqrt(pi) = 1.128379167095512573896158903121545171688 + * is close to one. The interval is chosen because the fix + * point of erf(x) is near 0.6174 (i.e., erf(x)=x when x is + * near 0.6174), and by some experiment, 0.84375 is chosen to + * guarantee the error is less than one ulp for erf. + * + * 2. For |x| in [0.84375,1.25], let s = |x| - 1, and + * c = 0.84506291151 rounded to single (24 bits) + * erf(x) = sign(x) * (c + P1(s)/Q1(s)) + * erfc(x) = (1-c) - P1(s)/Q1(s) if x > 0 + * 1+(c+P1(s)/Q1(s)) if x < 0 + * |P1/Q1 - (erf(|x|)-c)| <= 2**-59.06 + * Remark: here we use the taylor series expansion at x=1. + * erf(1+s) = erf(1) + s*Poly(s) + * = 0.845.. + P1(s)/Q1(s) + * That is, we use rational approximation to approximate + * erf(1+s) - (c = (single)0.84506291151) + * Note that |P1/Q1|< 0.078 for x in [0.84375,1.25] + * where + * P1(s) = degree 6 poly in s + * Q1(s) = degree 6 poly in s + * + * 3. For x in [1.25,1/0.35(~2.857143)], + * erfc(x) = (1/x)*exp(-x*x-0.5625+R1/S1) + * erf(x) = 1 - erfc(x) + * where + * R1(z) = degree 7 poly in z, (z=1/x^2) + * S1(z) = degree 8 poly in z + * + * 4. For x in [1/0.35,28] + * erfc(x) = (1/x)*exp(-x*x-0.5625+R2/S2) if x > 0 + * = 2.0 - (1/x)*exp(-x*x-0.5625+R2/S2) if -6 x >= 28 + * erf(x) = sign(x) *(1 - tiny) (raise inexact) + * erfc(x) = tiny*tiny (raise underflow) if x > 0 + * = 2 - tiny if x<0 + * + * 7. Special case: + * erf(0) = 0, erf(inf) = 1, erf(-inf) = -1, + * erfc(0) = 1, erfc(inf) = 0, erfc(-inf) = 2, + * erfc/erf(NaN) is NaN + */ + +#include "libm.h" + +static const double +erx = 8.45062911510467529297e-01, /* 0x3FEB0AC1, 0x60000000 */ +/* + * Coefficients for approximation to erf on [0,0.84375] + */ +efx8 = 1.02703333676410069053e+00, /* 0x3FF06EBA, 0x8214DB69 */ +pp0 = 1.28379167095512558561e-01, /* 0x3FC06EBA, 0x8214DB68 */ +pp1 = -3.25042107247001499370e-01, /* 0xBFD4CD7D, 0x691CB913 */ +pp2 = -2.84817495755985104766e-02, /* 0xBF9D2A51, 0xDBD7194F */ +pp3 = -5.77027029648944159157e-03, /* 0xBF77A291, 0x236668E4 */ +pp4 = -2.37630166566501626084e-05, /* 0xBEF8EAD6, 0x120016AC */ +qq1 = 3.97917223959155352819e-01, /* 0x3FD97779, 0xCDDADC09 */ +qq2 = 6.50222499887672944485e-02, /* 0x3FB0A54C, 0x5536CEBA */ +qq3 = 5.08130628187576562776e-03, /* 0x3F74D022, 0xC4D36B0F */ +qq4 = 1.32494738004321644526e-04, /* 0x3F215DC9, 0x221C1A10 */ +qq5 = -3.96022827877536812320e-06, /* 0xBED09C43, 0x42A26120 */ +/* + * Coefficients for approximation to erf in [0.84375,1.25] + */ +pa0 = -2.36211856075265944077e-03, /* 0xBF6359B8, 0xBEF77538 */ +pa1 = 4.14856118683748331666e-01, /* 0x3FDA8D00, 0xAD92B34D */ +pa2 = -3.72207876035701323847e-01, /* 0xBFD7D240, 0xFBB8C3F1 */ +pa3 = 3.18346619901161753674e-01, /* 0x3FD45FCA, 0x805120E4 */ +pa4 = -1.10894694282396677476e-01, /* 0xBFBC6398, 0x3D3E28EC */ +pa5 = 3.54783043256182359371e-02, /* 0x3FA22A36, 0x599795EB */ +pa6 = -2.16637559486879084300e-03, /* 0xBF61BF38, 0x0A96073F */ +qa1 = 1.06420880400844228286e-01, /* 0x3FBB3E66, 0x18EEE323 */ +qa2 = 5.40397917702171048937e-01, /* 0x3FE14AF0, 0x92EB6F33 */ +qa3 = 7.18286544141962662868e-02, /* 0x3FB2635C, 0xD99FE9A7 */ +qa4 = 1.26171219808761642112e-01, /* 0x3FC02660, 0xE763351F */ +qa5 = 1.36370839120290507362e-02, /* 0x3F8BEDC2, 0x6B51DD1C */ +qa6 = 1.19844998467991074170e-02, /* 0x3F888B54, 0x5735151D */ +/* + * Coefficients for approximation to erfc in [1.25,1/0.35] + */ +ra0 = -9.86494403484714822705e-03, /* 0xBF843412, 0x600D6435 */ +ra1 = -6.93858572707181764372e-01, /* 0xBFE63416, 0xE4BA7360 */ +ra2 = -1.05586262253232909814e+01, /* 0xC0251E04, 0x41B0E726 */ +ra3 = -6.23753324503260060396e+01, /* 0xC04F300A, 0xE4CBA38D */ +ra4 = -1.62396669462573470355e+02, /* 0xC0644CB1, 0x84282266 */ +ra5 = -1.84605092906711035994e+02, /* 0xC067135C, 0xEBCCABB2 */ +ra6 = -8.12874355063065934246e+01, /* 0xC0545265, 0x57E4D2F2 */ +ra7 = -9.81432934416914548592e+00, /* 0xC023A0EF, 0xC69AC25C */ +sa1 = 1.96512716674392571292e+01, /* 0x4033A6B9, 0xBD707687 */ +sa2 = 1.37657754143519042600e+02, /* 0x4061350C, 0x526AE721 */ +sa3 = 4.34565877475229228821e+02, /* 0x407B290D, 0xD58A1A71 */ +sa4 = 6.45387271733267880336e+02, /* 0x40842B19, 0x21EC2868 */ +sa5 = 4.29008140027567833386e+02, /* 0x407AD021, 0x57700314 */ +sa6 = 1.08635005541779435134e+02, /* 0x405B28A3, 0xEE48AE2C */ +sa7 = 6.57024977031928170135e+00, /* 0x401A47EF, 0x8E484A93 */ +sa8 = -6.04244152148580987438e-02, /* 0xBFAEEFF2, 0xEE749A62 */ +/* + * Coefficients for approximation to erfc in [1/.35,28] + */ +rb0 = -9.86494292470009928597e-03, /* 0xBF843412, 0x39E86F4A */ +rb1 = -7.99283237680523006574e-01, /* 0xBFE993BA, 0x70C285DE */ +rb2 = -1.77579549177547519889e+01, /* 0xC031C209, 0x555F995A */ +rb3 = -1.60636384855821916062e+02, /* 0xC064145D, 0x43C5ED98 */ +rb4 = -6.37566443368389627722e+02, /* 0xC083EC88, 0x1375F228 */ +rb5 = -1.02509513161107724954e+03, /* 0xC0900461, 0x6A2E5992 */ +rb6 = -4.83519191608651397019e+02, /* 0xC07E384E, 0x9BDC383F */ +sb1 = 3.03380607434824582924e+01, /* 0x403E568B, 0x261D5190 */ +sb2 = 3.25792512996573918826e+02, /* 0x40745CAE, 0x221B9F0A */ +sb3 = 1.53672958608443695994e+03, /* 0x409802EB, 0x189D5118 */ +sb4 = 3.19985821950859553908e+03, /* 0x40A8FFB7, 0x688C246A */ +sb5 = 2.55305040643316442583e+03, /* 0x40A3F219, 0xCEDF3BE6 */ +sb6 = 4.74528541206955367215e+02, /* 0x407DA874, 0xE79FE763 */ +sb7 = -2.24409524465858183362e+01; /* 0xC03670E2, 0x42712D62 */ + +static double erfc1(double x) +{ + double_t s,P,Q; + + s = fabs(x) - 1; + P = pa0+s*(pa1+s*(pa2+s*(pa3+s*(pa4+s*(pa5+s*pa6))))); + Q = 1+s*(qa1+s*(qa2+s*(qa3+s*(qa4+s*(qa5+s*qa6))))); + return 1 - erx - P/Q; +} + +static double erfc2(uint32_t ix, double x) +{ + double_t s,R,S; + double z; + + if (ix < 0x3ff40000) /* |x| < 1.25 */ + return erfc1(x); + + x = fabs(x); + s = 1/(x*x); + if (ix < 0x4006db6d) { /* |x| < 1/.35 ~ 2.85714 */ + R = ra0+s*(ra1+s*(ra2+s*(ra3+s*(ra4+s*( + ra5+s*(ra6+s*ra7)))))); + S = 1.0+s*(sa1+s*(sa2+s*(sa3+s*(sa4+s*( + sa5+s*(sa6+s*(sa7+s*sa8))))))); + } else { /* |x| > 1/.35 */ + R = rb0+s*(rb1+s*(rb2+s*(rb3+s*(rb4+s*( + rb5+s*rb6))))); + S = 1.0+s*(sb1+s*(sb2+s*(sb3+s*(sb4+s*( + sb5+s*(sb6+s*sb7)))))); + } + z = x; + SET_LOW_WORD(z,0); + return exp(-z*z-0.5625)*exp((z-x)*(z+x)+R/S)/x; +} + +double erf(double x) +{ + double r,s,z,y; + uint32_t ix; + int sign; + + GET_HIGH_WORD(ix, x); + sign = ix>>31; + ix &= 0x7fffffff; + if (ix >= 0x7ff00000) { + /* erf(nan)=nan, erf(+-inf)=+-1 */ + return 1-2*sign + 1/x; + } + if (ix < 0x3feb0000) { /* |x| < 0.84375 */ + if (ix < 0x3e300000) { /* |x| < 2**-28 */ + /* avoid underflow */ + return 0.125*(8*x + efx8*x); + } + z = x*x; + r = pp0+z*(pp1+z*(pp2+z*(pp3+z*pp4))); + s = 1.0+z*(qq1+z*(qq2+z*(qq3+z*(qq4+z*qq5)))); + y = r/s; + return x + x*y; + } + if (ix < 0x40180000) /* 0.84375 <= |x| < 6 */ + y = 1 - erfc2(ix,x); + else + y = 1 - 0x1p-1022; + return sign ? -y : y; +} + +double erfc(double x) +{ + double r,s,z,y; + uint32_t ix; + int sign; + + GET_HIGH_WORD(ix, x); + sign = ix>>31; + ix &= 0x7fffffff; + if (ix >= 0x7ff00000) { + /* erfc(nan)=nan, erfc(+-inf)=0,2 */ + return 2*sign + 1/x; + } + if (ix < 0x3feb0000) { /* |x| < 0.84375 */ + if (ix < 0x3c700000) /* |x| < 2**-56 */ + return 1.0 - x; + z = x*x; + r = pp0+z*(pp1+z*(pp2+z*(pp3+z*pp4))); + s = 1.0+z*(qq1+z*(qq2+z*(qq3+z*(qq4+z*qq5)))); + y = r/s; + if (sign || ix < 0x3fd00000) { /* x < 1/4 */ + return 1.0 - (x+x*y); + } + return 0.5 - (x - 0.5 + x*y); + } + if (ix < 0x403c0000) { /* 0.84375 <= |x| < 28 */ + return sign ? 2 - erfc2(ix,x) : erfc2(ix,x); + } + return sign ? 2 - 0x1p-1022 : 0x1p-1022*0x1p-1022; +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/erff.c b/lib/mlibc/options/ansi/musl-generic-math/erff.c new file mode 100644 index 0000000..ed5f397 --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/erff.c @@ -0,0 +1,183 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_erff.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "libm.h" + +static const float +erx = 8.4506291151e-01, /* 0x3f58560b */ +/* + * Coefficients for approximation to erf on [0,0.84375] + */ +efx8 = 1.0270333290e+00, /* 0x3f8375d4 */ +pp0 = 1.2837916613e-01, /* 0x3e0375d4 */ +pp1 = -3.2504209876e-01, /* 0xbea66beb */ +pp2 = -2.8481749818e-02, /* 0xbce9528f */ +pp3 = -5.7702702470e-03, /* 0xbbbd1489 */ +pp4 = -2.3763017452e-05, /* 0xb7c756b1 */ +qq1 = 3.9791721106e-01, /* 0x3ecbbbce */ +qq2 = 6.5022252500e-02, /* 0x3d852a63 */ +qq3 = 5.0813062117e-03, /* 0x3ba68116 */ +qq4 = 1.3249473704e-04, /* 0x390aee49 */ +qq5 = -3.9602282413e-06, /* 0xb684e21a */ +/* + * Coefficients for approximation to erf in [0.84375,1.25] + */ +pa0 = -2.3621185683e-03, /* 0xbb1acdc6 */ +pa1 = 4.1485610604e-01, /* 0x3ed46805 */ +pa2 = -3.7220788002e-01, /* 0xbebe9208 */ +pa3 = 3.1834661961e-01, /* 0x3ea2fe54 */ +pa4 = -1.1089469492e-01, /* 0xbde31cc2 */ +pa5 = 3.5478305072e-02, /* 0x3d1151b3 */ +pa6 = -2.1663755178e-03, /* 0xbb0df9c0 */ +qa1 = 1.0642088205e-01, /* 0x3dd9f331 */ +qa2 = 5.4039794207e-01, /* 0x3f0a5785 */ +qa3 = 7.1828655899e-02, /* 0x3d931ae7 */ +qa4 = 1.2617121637e-01, /* 0x3e013307 */ +qa5 = 1.3637083583e-02, /* 0x3c5f6e13 */ +qa6 = 1.1984500103e-02, /* 0x3c445aa3 */ +/* + * Coefficients for approximation to erfc in [1.25,1/0.35] + */ +ra0 = -9.8649440333e-03, /* 0xbc21a093 */ +ra1 = -6.9385856390e-01, /* 0xbf31a0b7 */ +ra2 = -1.0558626175e+01, /* 0xc128f022 */ +ra3 = -6.2375331879e+01, /* 0xc2798057 */ +ra4 = -1.6239666748e+02, /* 0xc322658c */ +ra5 = -1.8460508728e+02, /* 0xc3389ae7 */ +ra6 = -8.1287437439e+01, /* 0xc2a2932b */ +ra7 = -9.8143291473e+00, /* 0xc11d077e */ +sa1 = 1.9651271820e+01, /* 0x419d35ce */ +sa2 = 1.3765776062e+02, /* 0x4309a863 */ +sa3 = 4.3456588745e+02, /* 0x43d9486f */ +sa4 = 6.4538726807e+02, /* 0x442158c9 */ +sa5 = 4.2900814819e+02, /* 0x43d6810b */ +sa6 = 1.0863500214e+02, /* 0x42d9451f */ +sa7 = 6.5702495575e+00, /* 0x40d23f7c */ +sa8 = -6.0424413532e-02, /* 0xbd777f97 */ +/* + * Coefficients for approximation to erfc in [1/.35,28] + */ +rb0 = -9.8649431020e-03, /* 0xbc21a092 */ +rb1 = -7.9928326607e-01, /* 0xbf4c9dd4 */ +rb2 = -1.7757955551e+01, /* 0xc18e104b */ +rb3 = -1.6063638306e+02, /* 0xc320a2ea */ +rb4 = -6.3756646729e+02, /* 0xc41f6441 */ +rb5 = -1.0250950928e+03, /* 0xc480230b */ +rb6 = -4.8351919556e+02, /* 0xc3f1c275 */ +sb1 = 3.0338060379e+01, /* 0x41f2b459 */ +sb2 = 3.2579251099e+02, /* 0x43a2e571 */ +sb3 = 1.5367296143e+03, /* 0x44c01759 */ +sb4 = 3.1998581543e+03, /* 0x4547fdbb */ +sb5 = 2.5530502930e+03, /* 0x451f90ce */ +sb6 = 4.7452853394e+02, /* 0x43ed43a7 */ +sb7 = -2.2440952301e+01; /* 0xc1b38712 */ + +static float erfc1(float x) +{ + float_t s,P,Q; + + s = fabsf(x) - 1; + P = pa0+s*(pa1+s*(pa2+s*(pa3+s*(pa4+s*(pa5+s*pa6))))); + Q = 1+s*(qa1+s*(qa2+s*(qa3+s*(qa4+s*(qa5+s*qa6))))); + return 1 - erx - P/Q; +} + +static float erfc2(uint32_t ix, float x) +{ + float_t s,R,S; + float z; + + if (ix < 0x3fa00000) /* |x| < 1.25 */ + return erfc1(x); + + x = fabsf(x); + s = 1/(x*x); + if (ix < 0x4036db6d) { /* |x| < 1/0.35 */ + R = ra0+s*(ra1+s*(ra2+s*(ra3+s*(ra4+s*( + ra5+s*(ra6+s*ra7)))))); + S = 1.0f+s*(sa1+s*(sa2+s*(sa3+s*(sa4+s*( + sa5+s*(sa6+s*(sa7+s*sa8))))))); + } else { /* |x| >= 1/0.35 */ + R = rb0+s*(rb1+s*(rb2+s*(rb3+s*(rb4+s*( + rb5+s*rb6))))); + S = 1.0f+s*(sb1+s*(sb2+s*(sb3+s*(sb4+s*( + sb5+s*(sb6+s*sb7)))))); + } + GET_FLOAT_WORD(ix, x); + SET_FLOAT_WORD(z, ix&0xffffe000); + return expf(-z*z - 0.5625f) * expf((z-x)*(z+x) + R/S)/x; +} + +float erff(float x) +{ + float r,s,z,y; + uint32_t ix; + int sign; + + GET_FLOAT_WORD(ix, x); + sign = ix>>31; + ix &= 0x7fffffff; + if (ix >= 0x7f800000) { + /* erf(nan)=nan, erf(+-inf)=+-1 */ + return 1-2*sign + 1/x; + } + if (ix < 0x3f580000) { /* |x| < 0.84375 */ + if (ix < 0x31800000) { /* |x| < 2**-28 */ + /*avoid underflow */ + return 0.125f*(8*x + efx8*x); + } + z = x*x; + r = pp0+z*(pp1+z*(pp2+z*(pp3+z*pp4))); + s = 1+z*(qq1+z*(qq2+z*(qq3+z*(qq4+z*qq5)))); + y = r/s; + return x + x*y; + } + if (ix < 0x40c00000) /* |x| < 6 */ + y = 1 - erfc2(ix,x); + else + y = 1 - 0x1p-120f; + return sign ? -y : y; +} + +float erfcf(float x) +{ + float r,s,z,y; + uint32_t ix; + int sign; + + GET_FLOAT_WORD(ix, x); + sign = ix>>31; + ix &= 0x7fffffff; + if (ix >= 0x7f800000) { + /* erfc(nan)=nan, erfc(+-inf)=0,2 */ + return 2*sign + 1/x; + } + + if (ix < 0x3f580000) { /* |x| < 0.84375 */ + if (ix < 0x23800000) /* |x| < 2**-56 */ + return 1.0f - x; + z = x*x; + r = pp0+z*(pp1+z*(pp2+z*(pp3+z*pp4))); + s = 1.0f+z*(qq1+z*(qq2+z*(qq3+z*(qq4+z*qq5)))); + y = r/s; + if (sign || ix < 0x3e800000) /* x < 1/4 */ + return 1.0f - (x+x*y); + return 0.5f - (x - 0.5f + x*y); + } + if (ix < 0x41e00000) { /* |x| < 28 */ + return sign ? 2 - erfc2(ix,x) : erfc2(ix,x); + } + return sign ? 2 - 0x1p-120f : 0x1p-120f*0x1p-120f; +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/erfl.c b/lib/mlibc/options/ansi/musl-generic-math/erfl.c new file mode 100644 index 0000000..e267c23 --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/erfl.c @@ -0,0 +1,353 @@ +/* origin: OpenBSD /usr/src/lib/libm/src/ld80/e_erfl.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* + * Copyright (c) 2008 Stephen L. Moshier + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/* double erf(double x) + * double erfc(double x) + * x + * 2 |\ + * erf(x) = --------- | exp(-t*t)dt + * sqrt(pi) \| + * 0 + * + * erfc(x) = 1-erf(x) + * Note that + * erf(-x) = -erf(x) + * erfc(-x) = 2 - erfc(x) + * + * Method: + * 1. For |x| in [0, 0.84375] + * erf(x) = x + x*R(x^2) + * erfc(x) = 1 - erf(x) if x in [-.84375,0.25] + * = 0.5 + ((0.5-x)-x*R) if x in [0.25,0.84375] + * Remark. The formula is derived by noting + * erf(x) = (2/sqrt(pi))*(x - x^3/3 + x^5/10 - x^7/42 + ....) + * and that + * 2/sqrt(pi) = 1.128379167095512573896158903121545171688 + * is close to one. The interval is chosen because the fix + * point of erf(x) is near 0.6174 (i.e., erf(x)=x when x is + * near 0.6174), and by some experiment, 0.84375 is chosen to + * guarantee the error is less than one ulp for erf. + * + * 2. For |x| in [0.84375,1.25], let s = |x| - 1, and + * c = 0.84506291151 rounded to single (24 bits) + * erf(x) = sign(x) * (c + P1(s)/Q1(s)) + * erfc(x) = (1-c) - P1(s)/Q1(s) if x > 0 + * 1+(c+P1(s)/Q1(s)) if x < 0 + * Remark: here we use the taylor series expansion at x=1. + * erf(1+s) = erf(1) + s*Poly(s) + * = 0.845.. + P1(s)/Q1(s) + * Note that |P1/Q1|< 0.078 for x in [0.84375,1.25] + * + * 3. For x in [1.25,1/0.35(~2.857143)], + * erfc(x) = (1/x)*exp(-x*x-0.5625+R1(z)/S1(z)) + * z=1/x^2 + * erf(x) = 1 - erfc(x) + * + * 4. For x in [1/0.35,107] + * erfc(x) = (1/x)*exp(-x*x-0.5625+R2/S2) if x > 0 + * = 2.0 - (1/x)*exp(-x*x-0.5625+R2(z)/S2(z)) + * if -6.666 x >= 107 + * erf(x) = sign(x) *(1 - tiny) (raise inexact) + * erfc(x) = tiny*tiny (raise underflow) if x > 0 + * = 2 - tiny if x<0 + * + * 7. Special case: + * erf(0) = 0, erf(inf) = 1, erf(-inf) = -1, + * erfc(0) = 1, erfc(inf) = 0, erfc(-inf) = 2, + * erfc/erf(NaN) is NaN + */ + + +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double erfl(long double x) +{ + return erf(x); +} +long double erfcl(long double x) +{ + return erfc(x); +} +#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 +static const long double +erx = 0.845062911510467529296875L, + +/* + * Coefficients for approximation to erf on [0,0.84375] + */ +/* 8 * (2/sqrt(pi) - 1) */ +efx8 = 1.0270333367641005911692712249723613735048E0L, +pp[6] = { + 1.122751350964552113068262337278335028553E6L, + -2.808533301997696164408397079650699163276E6L, + -3.314325479115357458197119660818768924100E5L, + -6.848684465326256109712135497895525446398E4L, + -2.657817695110739185591505062971929859314E3L, + -1.655310302737837556654146291646499062882E2L, +}, +qq[6] = { + 8.745588372054466262548908189000448124232E6L, + 3.746038264792471129367533128637019611485E6L, + 7.066358783162407559861156173539693900031E5L, + 7.448928604824620999413120955705448117056E4L, + 4.511583986730994111992253980546131408924E3L, + 1.368902937933296323345610240009071254014E2L, + /* 1.000000000000000000000000000000000000000E0 */ +}, + +/* + * Coefficients for approximation to erf in [0.84375,1.25] + */ +/* erf(x+1) = 0.845062911510467529296875 + pa(x)/qa(x) + -0.15625 <= x <= +.25 + Peak relative error 8.5e-22 */ +pa[8] = { + -1.076952146179812072156734957705102256059E0L, + 1.884814957770385593365179835059971587220E2L, + -5.339153975012804282890066622962070115606E1L, + 4.435910679869176625928504532109635632618E1L, + 1.683219516032328828278557309642929135179E1L, + -2.360236618396952560064259585299045804293E0L, + 1.852230047861891953244413872297940938041E0L, + 9.394994446747752308256773044667843200719E-2L, +}, +qa[7] = { + 4.559263722294508998149925774781887811255E2L, + 3.289248982200800575749795055149780689738E2L, + 2.846070965875643009598627918383314457912E2L, + 1.398715859064535039433275722017479994465E2L, + 6.060190733759793706299079050985358190726E1L, + 2.078695677795422351040502569964299664233E1L, + 4.641271134150895940966798357442234498546E0L, + /* 1.000000000000000000000000000000000000000E0 */ +}, + +/* + * Coefficients for approximation to erfc in [1.25,1/0.35] + */ +/* erfc(1/x) = x exp (-1/x^2 - 0.5625 + ra(x^2)/sa(x^2)) + 1/2.85711669921875 < 1/x < 1/1.25 + Peak relative error 3.1e-21 */ +ra[] = { + 1.363566591833846324191000679620738857234E-1L, + 1.018203167219873573808450274314658434507E1L, + 1.862359362334248675526472871224778045594E2L, + 1.411622588180721285284945138667933330348E3L, + 5.088538459741511988784440103218342840478E3L, + 8.928251553922176506858267311750789273656E3L, + 7.264436000148052545243018622742770549982E3L, + 2.387492459664548651671894725748959751119E3L, + 2.220916652813908085449221282808458466556E2L, +}, +sa[] = { + -1.382234625202480685182526402169222331847E1L, + -3.315638835627950255832519203687435946482E2L, + -2.949124863912936259747237164260785326692E3L, + -1.246622099070875940506391433635999693661E4L, + -2.673079795851665428695842853070996219632E4L, + -2.880269786660559337358397106518918220991E4L, + -1.450600228493968044773354186390390823713E4L, + -2.874539731125893533960680525192064277816E3L, + -1.402241261419067750237395034116942296027E2L, + /* 1.000000000000000000000000000000000000000E0 */ +}, + +/* + * Coefficients for approximation to erfc in [1/.35,107] + */ +/* erfc(1/x) = x exp (-1/x^2 - 0.5625 + rb(x^2)/sb(x^2)) + 1/6.6666259765625 < 1/x < 1/2.85711669921875 + Peak relative error 4.2e-22 */ +rb[] = { + -4.869587348270494309550558460786501252369E-5L, + -4.030199390527997378549161722412466959403E-3L, + -9.434425866377037610206443566288917589122E-2L, + -9.319032754357658601200655161585539404155E-1L, + -4.273788174307459947350256581445442062291E0L, + -8.842289940696150508373541814064198259278E0L, + -7.069215249419887403187988144752613025255E0L, + -1.401228723639514787920274427443330704764E0L, +}, +sb[] = { + 4.936254964107175160157544545879293019085E-3L, + 1.583457624037795744377163924895349412015E-1L, + 1.850647991850328356622940552450636420484E0L, + 9.927611557279019463768050710008450625415E0L, + 2.531667257649436709617165336779212114570E1L, + 2.869752886406743386458304052862814690045E1L, + 1.182059497870819562441683560749192539345E1L, + /* 1.000000000000000000000000000000000000000E0 */ +}, +/* erfc(1/x) = x exp (-1/x^2 - 0.5625 + rc(x^2)/sc(x^2)) + 1/107 <= 1/x <= 1/6.6666259765625 + Peak relative error 1.1e-21 */ +rc[] = { + -8.299617545269701963973537248996670806850E-5L, + -6.243845685115818513578933902532056244108E-3L, + -1.141667210620380223113693474478394397230E-1L, + -7.521343797212024245375240432734425789409E-1L, + -1.765321928311155824664963633786967602934E0L, + -1.029403473103215800456761180695263439188E0L, +}, +sc[] = { + 8.413244363014929493035952542677768808601E-3L, + 2.065114333816877479753334599639158060979E-1L, + 1.639064941530797583766364412782135680148E0L, + 4.936788463787115555582319302981666347450E0L, + 5.005177727208955487404729933261347679090E0L, + /* 1.000000000000000000000000000000000000000E0 */ +}; + +static long double erfc1(long double x) +{ + long double s,P,Q; + + s = fabsl(x) - 1; + P = pa[0] + s * (pa[1] + s * (pa[2] + + s * (pa[3] + s * (pa[4] + s * (pa[5] + s * (pa[6] + s * pa[7])))))); + Q = qa[0] + s * (qa[1] + s * (qa[2] + + s * (qa[3] + s * (qa[4] + s * (qa[5] + s * (qa[6] + s)))))); + return 1 - erx - P / Q; +} + +static long double erfc2(uint32_t ix, long double x) +{ + union ldshape u; + long double s,z,R,S; + + if (ix < 0x3fffa000) /* 0.84375 <= |x| < 1.25 */ + return erfc1(x); + + x = fabsl(x); + s = 1 / (x * x); + if (ix < 0x4000b6db) { /* 1.25 <= |x| < 2.857 ~ 1/.35 */ + R = ra[0] + s * (ra[1] + s * (ra[2] + s * (ra[3] + s * (ra[4] + + s * (ra[5] + s * (ra[6] + s * (ra[7] + s * ra[8]))))))); + S = sa[0] + s * (sa[1] + s * (sa[2] + s * (sa[3] + s * (sa[4] + + s * (sa[5] + s * (sa[6] + s * (sa[7] + s * (sa[8] + s)))))))); + } else if (ix < 0x4001d555) { /* 2.857 <= |x| < 6.6666259765625 */ + R = rb[0] + s * (rb[1] + s * (rb[2] + s * (rb[3] + s * (rb[4] + + s * (rb[5] + s * (rb[6] + s * rb[7])))))); + S = sb[0] + s * (sb[1] + s * (sb[2] + s * (sb[3] + s * (sb[4] + + s * (sb[5] + s * (sb[6] + s)))))); + } else { /* 6.666 <= |x| < 107 (erfc only) */ + R = rc[0] + s * (rc[1] + s * (rc[2] + s * (rc[3] + + s * (rc[4] + s * rc[5])))); + S = sc[0] + s * (sc[1] + s * (sc[2] + s * (sc[3] + + s * (sc[4] + s)))); + } + u.f = x; + u.i.m &= -1ULL << 40; + z = u.f; + return expl(-z*z - 0.5625) * expl((z - x) * (z + x) + R / S) / x; +} + +long double erfl(long double x) +{ + long double r, s, z, y; + union ldshape u = {x}; + uint32_t ix = (u.i.se & 0x7fffU)<<16 | u.i.m>>48; + int sign = u.i.se >> 15; + + if (ix >= 0x7fff0000) + /* erf(nan)=nan, erf(+-inf)=+-1 */ + return 1 - 2*sign + 1/x; + if (ix < 0x3ffed800) { /* |x| < 0.84375 */ + if (ix < 0x3fde8000) { /* |x| < 2**-33 */ + return 0.125 * (8 * x + efx8 * x); /* avoid underflow */ + } + z = x * x; + r = pp[0] + z * (pp[1] + + z * (pp[2] + z * (pp[3] + z * (pp[4] + z * pp[5])))); + s = qq[0] + z * (qq[1] + + z * (qq[2] + z * (qq[3] + z * (qq[4] + z * (qq[5] + z))))); + y = r / s; + return x + x * y; + } + if (ix < 0x4001d555) /* |x| < 6.6666259765625 */ + y = 1 - erfc2(ix,x); + else + y = 1 - 0x1p-16382L; + return sign ? -y : y; +} + +long double erfcl(long double x) +{ + long double r, s, z, y; + union ldshape u = {x}; + uint32_t ix = (u.i.se & 0x7fffU)<<16 | u.i.m>>48; + int sign = u.i.se >> 15; + + if (ix >= 0x7fff0000) + /* erfc(nan) = nan, erfc(+-inf) = 0,2 */ + return 2*sign + 1/x; + if (ix < 0x3ffed800) { /* |x| < 0.84375 */ + if (ix < 0x3fbe0000) /* |x| < 2**-65 */ + return 1.0 - x; + z = x * x; + r = pp[0] + z * (pp[1] + + z * (pp[2] + z * (pp[3] + z * (pp[4] + z * pp[5])))); + s = qq[0] + z * (qq[1] + + z * (qq[2] + z * (qq[3] + z * (qq[4] + z * (qq[5] + z))))); + y = r / s; + if (ix < 0x3ffd8000) /* x < 1/4 */ + return 1.0 - (x + x * y); + return 0.5 - (x - 0.5 + x * y); + } + if (ix < 0x4005d600) /* |x| < 107 */ + return sign ? 2 - erfc2(ix,x) : erfc2(ix,x); + y = 0x1p-16382L; + return sign ? 2 - y : y*y; +} +#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 +// TODO: broken implementation to make things compile +long double erfl(long double x) +{ + return erf(x); +} +long double erfcl(long double x) +{ + return erfc(x); +} +#endif diff --git a/lib/mlibc/options/ansi/musl-generic-math/exp.c b/lib/mlibc/options/ansi/musl-generic-math/exp.c new file mode 100644 index 0000000..9ea672f --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/exp.c @@ -0,0 +1,134 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_exp.c */ +/* + * ==================================================== + * Copyright (C) 2004 by Sun Microsystems, Inc. All rights reserved. + * + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* exp(x) + * Returns the exponential of x. + * + * Method + * 1. Argument reduction: + * Reduce x to an r so that |r| <= 0.5*ln2 ~ 0.34658. + * Given x, find r and integer k such that + * + * x = k*ln2 + r, |r| <= 0.5*ln2. + * + * Here r will be represented as r = hi-lo for better + * accuracy. + * + * 2. Approximation of exp(r) by a special rational function on + * the interval [0,0.34658]: + * Write + * R(r**2) = r*(exp(r)+1)/(exp(r)-1) = 2 + r*r/6 - r**4/360 + ... + * We use a special Remez algorithm on [0,0.34658] to generate + * a polynomial of degree 5 to approximate R. The maximum error + * of this polynomial approximation is bounded by 2**-59. In + * other words, + * R(z) ~ 2.0 + P1*z + P2*z**2 + P3*z**3 + P4*z**4 + P5*z**5 + * (where z=r*r, and the values of P1 to P5 are listed below) + * and + * | 5 | -59 + * | 2.0+P1*z+...+P5*z - R(z) | <= 2 + * | | + * The computation of exp(r) thus becomes + * 2*r + * exp(r) = 1 + ---------- + * R(r) - r + * r*c(r) + * = 1 + r + ----------- (for better accuracy) + * 2 - c(r) + * where + * 2 4 10 + * c(r) = r - (P1*r + P2*r + ... + P5*r ). + * + * 3. Scale back to obtain exp(x): + * From step 1, we have + * exp(x) = 2^k * exp(r) + * + * Special cases: + * exp(INF) is INF, exp(NaN) is NaN; + * exp(-INF) is 0, and + * for finite argument, only exp(0)=1 is exact. + * + * Accuracy: + * according to an error analysis, the error is always less than + * 1 ulp (unit in the last place). + * + * Misc. info. + * For IEEE double + * if x > 709.782712893383973096 then exp(x) overflows + * if x < -745.133219101941108420 then exp(x) underflows + */ + +#include "libm.h" + +static const double +half[2] = {0.5,-0.5}, +ln2hi = 6.93147180369123816490e-01, /* 0x3fe62e42, 0xfee00000 */ +ln2lo = 1.90821492927058770002e-10, /* 0x3dea39ef, 0x35793c76 */ +invln2 = 1.44269504088896338700e+00, /* 0x3ff71547, 0x652b82fe */ +P1 = 1.66666666666666019037e-01, /* 0x3FC55555, 0x5555553E */ +P2 = -2.77777777770155933842e-03, /* 0xBF66C16C, 0x16BEBD93 */ +P3 = 6.61375632143793436117e-05, /* 0x3F11566A, 0xAF25DE2C */ +P4 = -1.65339022054652515390e-06, /* 0xBEBBBD41, 0xC5D26BF1 */ +P5 = 4.13813679705723846039e-08; /* 0x3E663769, 0x72BEA4D0 */ + +double exp(double x) +{ + double_t hi, lo, c, xx, y; + int k, sign; + uint32_t hx; + + GET_HIGH_WORD(hx, x); + sign = hx>>31; + hx &= 0x7fffffff; /* high word of |x| */ + + /* special cases */ + if (hx >= 0x4086232b) { /* if |x| >= 708.39... */ + if (isnan(x)) + return x; + if (x > 709.782712893383973096) { + /* overflow if x!=inf */ + x *= 0x1p1023; + return x; + } + if (x < -708.39641853226410622) { + /* underflow if x!=-inf */ + FORCE_EVAL((float)(-0x1p-149/x)); + if (x < -745.13321910194110842) + return 0; + } + } + + /* argument reduction */ + if (hx > 0x3fd62e42) { /* if |x| > 0.5 ln2 */ + if (hx >= 0x3ff0a2b2) /* if |x| >= 1.5 ln2 */ + k = (int)(invln2*x + half[sign]); + else + k = 1 - sign - sign; + hi = x - k*ln2hi; /* k*ln2hi is exact here */ + lo = k*ln2lo; + x = hi - lo; + } else if (hx > 0x3e300000) { /* if |x| > 2**-28 */ + k = 0; + hi = x; + lo = 0; + } else { + /* inexact if x!=0 */ + FORCE_EVAL(0x1p1023 + x); + return 1 + x; + } + + /* x is now in primary range */ + xx = x*x; + c = x - xx*(P1+xx*(P2+xx*(P3+xx*(P4+xx*P5)))); + y = 1 + (x*c/(2-c) - lo + hi); + if (k == 0) + return y; + return scalbn(y, k); +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/exp10.c b/lib/mlibc/options/ansi/musl-generic-math/exp10.c new file mode 100644 index 0000000..47b4dc7 --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/exp10.c @@ -0,0 +1,26 @@ +#define _GNU_SOURCE +#include +#include +#include "weak_alias.h" +//#include "libc.h" + +double exp10(double x) +{ + static const double p10[] = { + 1e-15, 1e-14, 1e-13, 1e-12, 1e-11, 1e-10, + 1e-9, 1e-8, 1e-7, 1e-6, 1e-5, 1e-4, 1e-3, 1e-2, 1e-1, + 1, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, + 1e10, 1e11, 1e12, 1e13, 1e14, 1e15 + }; + double n, y = modf(x, &n); + union {double f; uint64_t i;} u = {n}; + /* fabs(n) < 16 without raising invalid on nan */ + if ((u.i>>52 & 0x7ff) < 0x3ff+4) { + if (!y) return p10[(int)n+15]; + y = exp2(3.32192809488736234787031942948939 * y); + return y * p10[(int)n+15]; + } + return pow(10.0, x); +} + +weak_alias(exp10, pow10); diff --git a/lib/mlibc/options/ansi/musl-generic-math/exp10f.c b/lib/mlibc/options/ansi/musl-generic-math/exp10f.c new file mode 100644 index 0000000..74f8909 --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/exp10f.c @@ -0,0 +1,24 @@ +#define _GNU_SOURCE +#include +#include +#include "weak_alias.h" +//#include "libc.h" + +float exp10f(float x) +{ + static const float p10[] = { + 1e-7f, 1e-6f, 1e-5f, 1e-4f, 1e-3f, 1e-2f, 1e-1f, + 1, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7 + }; + float n, y = modff(x, &n); + union {float f; uint32_t i;} u = {n}; + /* fabsf(n) < 8 without raising invalid on nan */ + if ((u.i>>23 & 0xff) < 0x7f+3) { + if (!y) return p10[(int)n+7]; + y = exp2f(3.32192809488736234787031942948939f * y); + return y * p10[(int)n+7]; + } + return exp2(3.32192809488736234787031942948939 * x); +} + +weak_alias(exp10f, pow10f); diff --git a/lib/mlibc/options/ansi/musl-generic-math/exp10l.c b/lib/mlibc/options/ansi/musl-generic-math/exp10l.c new file mode 100644 index 0000000..f18e554 --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/exp10l.c @@ -0,0 +1,34 @@ +#define _GNU_SOURCE +#include +#include +//#include "libc.h" +#include "libm.h" +#include "weak_alias.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double exp10l(long double x) +{ + return exp10(x); +} +#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 +long double exp10l(long double x) +{ + static const long double p10[] = { + 1e-15L, 1e-14L, 1e-13L, 1e-12L, 1e-11L, 1e-10L, + 1e-9L, 1e-8L, 1e-7L, 1e-6L, 1e-5L, 1e-4L, 1e-3L, 1e-2L, 1e-1L, + 1, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, + 1e10, 1e11, 1e12, 1e13, 1e14, 1e15 + }; + long double n, y = modfl(x, &n); + union ldshape u = {n}; + /* fabsl(n) < 16 without raising invalid on nan */ + if ((u.i.se & 0x7fff) < 0x3fff+4) { + if (!y) return p10[(int)n+15]; + y = exp2l(3.32192809488736234787031942948939L * y); + return y * p10[(int)n+15]; + } + return powl(10.0, x); +} +#endif + +weak_alias(exp10l, pow10l); diff --git a/lib/mlibc/options/ansi/musl-generic-math/exp2.c b/lib/mlibc/options/ansi/musl-generic-math/exp2.c new file mode 100644 index 0000000..e14adba --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/exp2.c @@ -0,0 +1,375 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_exp2.c */ +/*- + * Copyright (c) 2005 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "libm.h" + +#define TBLSIZE 256 + +static const double +redux = 0x1.8p52 / TBLSIZE, +P1 = 0x1.62e42fefa39efp-1, +P2 = 0x1.ebfbdff82c575p-3, +P3 = 0x1.c6b08d704a0a6p-5, +P4 = 0x1.3b2ab88f70400p-7, +P5 = 0x1.5d88003875c74p-10; + +static const double tbl[TBLSIZE * 2] = { +/* exp2(z + eps) eps */ + 0x1.6a09e667f3d5dp-1, 0x1.9880p-44, + 0x1.6b052fa751744p-1, 0x1.8000p-50, + 0x1.6c012750bd9fep-1, -0x1.8780p-45, + 0x1.6cfdcddd476bfp-1, 0x1.ec00p-46, + 0x1.6dfb23c651a29p-1, -0x1.8000p-50, + 0x1.6ef9298593ae3p-1, -0x1.c000p-52, + 0x1.6ff7df9519386p-1, -0x1.fd80p-45, + 0x1.70f7466f42da3p-1, -0x1.c880p-45, + 0x1.71f75e8ec5fc3p-1, 0x1.3c00p-46, + 0x1.72f8286eacf05p-1, -0x1.8300p-44, + 0x1.73f9a48a58152p-1, -0x1.0c00p-47, + 0x1.74fbd35d7ccfcp-1, 0x1.f880p-45, + 0x1.75feb564267f1p-1, 0x1.3e00p-47, + 0x1.77024b1ab6d48p-1, -0x1.7d00p-45, + 0x1.780694fde5d38p-1, -0x1.d000p-50, + 0x1.790b938ac1d00p-1, 0x1.3000p-49, + 0x1.7a11473eb0178p-1, -0x1.d000p-49, + 0x1.7b17b0976d060p-1, 0x1.0400p-45, + 0x1.7c1ed0130c133p-1, 0x1.0000p-53, + 0x1.7d26a62ff8636p-1, -0x1.6900p-45, + 0x1.7e2f336cf4e3bp-1, -0x1.2e00p-47, + 0x1.7f3878491c3e8p-1, -0x1.4580p-45, + 0x1.80427543e1b4ep-1, 0x1.3000p-44, + 0x1.814d2add1071ap-1, 0x1.f000p-47, + 0x1.82589994ccd7ep-1, -0x1.1c00p-45, + 0x1.8364c1eb942d0p-1, 0x1.9d00p-45, + 0x1.8471a4623cab5p-1, 0x1.7100p-43, + 0x1.857f4179f5bbcp-1, 0x1.2600p-45, + 0x1.868d99b4491afp-1, -0x1.2c40p-44, + 0x1.879cad931a395p-1, -0x1.3000p-45, + 0x1.88ac7d98a65b8p-1, -0x1.a800p-45, + 0x1.89bd0a4785800p-1, -0x1.d000p-49, + 0x1.8ace5422aa223p-1, 0x1.3280p-44, + 0x1.8be05bad619fap-1, 0x1.2b40p-43, + 0x1.8cf3216b54383p-1, -0x1.ed00p-45, + 0x1.8e06a5e08664cp-1, -0x1.0500p-45, + 0x1.8f1ae99157807p-1, 0x1.8280p-45, + 0x1.902fed0282c0ep-1, -0x1.cb00p-46, + 0x1.9145b0b91ff96p-1, -0x1.5e00p-47, + 0x1.925c353aa2ff9p-1, 0x1.5400p-48, + 0x1.93737b0cdc64ap-1, 0x1.7200p-46, + 0x1.948b82b5f98aep-1, -0x1.9000p-47, + 0x1.95a44cbc852cbp-1, 0x1.5680p-45, + 0x1.96bdd9a766f21p-1, -0x1.6d00p-44, + 0x1.97d829fde4e2ap-1, -0x1.1000p-47, + 0x1.98f33e47a23a3p-1, 0x1.d000p-45, + 0x1.9a0f170ca0604p-1, -0x1.8a40p-44, + 0x1.9b2bb4d53ff89p-1, 0x1.55c0p-44, + 0x1.9c49182a3f15bp-1, 0x1.6b80p-45, + 0x1.9d674194bb8c5p-1, -0x1.c000p-49, + 0x1.9e86319e3238ep-1, 0x1.7d00p-46, + 0x1.9fa5e8d07f302p-1, 0x1.6400p-46, + 0x1.a0c667b5de54dp-1, -0x1.5000p-48, + 0x1.a1e7aed8eb8f6p-1, 0x1.9e00p-47, + 0x1.a309bec4a2e27p-1, 0x1.ad80p-45, + 0x1.a42c980460a5dp-1, -0x1.af00p-46, + 0x1.a5503b23e259bp-1, 0x1.b600p-47, + 0x1.a674a8af46213p-1, 0x1.8880p-44, + 0x1.a799e1330b3a7p-1, 0x1.1200p-46, + 0x1.a8bfe53c12e8dp-1, 0x1.6c00p-47, + 0x1.a9e6b5579fcd2p-1, -0x1.9b80p-45, + 0x1.ab0e521356fb8p-1, 0x1.b700p-45, + 0x1.ac36bbfd3f381p-1, 0x1.9000p-50, + 0x1.ad5ff3a3c2780p-1, 0x1.4000p-49, + 0x1.ae89f995ad2a3p-1, -0x1.c900p-45, + 0x1.afb4ce622f367p-1, 0x1.6500p-46, + 0x1.b0e07298db790p-1, 0x1.fd40p-45, + 0x1.b20ce6c9a89a9p-1, 0x1.2700p-46, + 0x1.b33a2b84f1a4bp-1, 0x1.d470p-43, + 0x1.b468415b747e7p-1, -0x1.8380p-44, + 0x1.b59728de5593ap-1, 0x1.8000p-54, + 0x1.b6c6e29f1c56ap-1, 0x1.ad00p-47, + 0x1.b7f76f2fb5e50p-1, 0x1.e800p-50, + 0x1.b928cf22749b2p-1, -0x1.4c00p-47, + 0x1.ba5b030a10603p-1, -0x1.d700p-47, + 0x1.bb8e0b79a6f66p-1, 0x1.d900p-47, + 0x1.bcc1e904bc1ffp-1, 0x1.2a00p-47, + 0x1.bdf69c3f3a16fp-1, -0x1.f780p-46, + 0x1.bf2c25bd71db8p-1, -0x1.0a00p-46, + 0x1.c06286141b2e9p-1, -0x1.1400p-46, + 0x1.c199bdd8552e0p-1, 0x1.be00p-47, + 0x1.c2d1cd9fa64eep-1, -0x1.9400p-47, + 0x1.c40ab5fffd02fp-1, -0x1.ed00p-47, + 0x1.c544778fafd15p-1, 0x1.9660p-44, + 0x1.c67f12e57d0cbp-1, -0x1.a100p-46, + 0x1.c7ba88988c1b6p-1, -0x1.8458p-42, + 0x1.c8f6d9406e733p-1, -0x1.a480p-46, + 0x1.ca3405751c4dfp-1, 0x1.b000p-51, + 0x1.cb720dcef9094p-1, 0x1.1400p-47, + 0x1.ccb0f2e6d1689p-1, 0x1.0200p-48, + 0x1.cdf0b555dc412p-1, 0x1.3600p-48, + 0x1.cf3155b5bab3bp-1, -0x1.6900p-47, + 0x1.d072d4a0789bcp-1, 0x1.9a00p-47, + 0x1.d1b532b08c8fap-1, -0x1.5e00p-46, + 0x1.d2f87080d8a85p-1, 0x1.d280p-46, + 0x1.d43c8eacaa203p-1, 0x1.1a00p-47, + 0x1.d5818dcfba491p-1, 0x1.f000p-50, + 0x1.d6c76e862e6a1p-1, -0x1.3a00p-47, + 0x1.d80e316c9834ep-1, -0x1.cd80p-47, + 0x1.d955d71ff6090p-1, 0x1.4c00p-48, + 0x1.da9e603db32aep-1, 0x1.f900p-48, + 0x1.dbe7cd63a8325p-1, 0x1.9800p-49, + 0x1.dd321f301b445p-1, -0x1.5200p-48, + 0x1.de7d5641c05bfp-1, -0x1.d700p-46, + 0x1.dfc97337b9aecp-1, -0x1.6140p-46, + 0x1.e11676b197d5ep-1, 0x1.b480p-47, + 0x1.e264614f5a3e7p-1, 0x1.0ce0p-43, + 0x1.e3b333b16ee5cp-1, 0x1.c680p-47, + 0x1.e502ee78b3fb4p-1, -0x1.9300p-47, + 0x1.e653924676d68p-1, -0x1.5000p-49, + 0x1.e7a51fbc74c44p-1, -0x1.7f80p-47, + 0x1.e8f7977cdb726p-1, -0x1.3700p-48, + 0x1.ea4afa2a490e8p-1, 0x1.5d00p-49, + 0x1.eb9f4867ccae4p-1, 0x1.61a0p-46, + 0x1.ecf482d8e680dp-1, 0x1.5500p-48, + 0x1.ee4aaa2188514p-1, 0x1.6400p-51, + 0x1.efa1bee615a13p-1, -0x1.e800p-49, + 0x1.f0f9c1cb64106p-1, -0x1.a880p-48, + 0x1.f252b376bb963p-1, -0x1.c900p-45, + 0x1.f3ac948dd7275p-1, 0x1.a000p-53, + 0x1.f50765b6e4524p-1, -0x1.4f00p-48, + 0x1.f6632798844fdp-1, 0x1.a800p-51, + 0x1.f7bfdad9cbe38p-1, 0x1.abc0p-48, + 0x1.f91d802243c82p-1, -0x1.4600p-50, + 0x1.fa7c1819e908ep-1, -0x1.b0c0p-47, + 0x1.fbdba3692d511p-1, -0x1.0e00p-51, + 0x1.fd3c22b8f7194p-1, -0x1.0de8p-46, + 0x1.fe9d96b2a23eep-1, 0x1.e430p-49, + 0x1.0000000000000p+0, 0x0.0000p+0, + 0x1.00b1afa5abcbep+0, -0x1.3400p-52, + 0x1.0163da9fb3303p+0, -0x1.2170p-46, + 0x1.02168143b0282p+0, 0x1.a400p-52, + 0x1.02c9a3e77806cp+0, 0x1.f980p-49, + 0x1.037d42e11bbcap+0, -0x1.7400p-51, + 0x1.04315e86e7f89p+0, 0x1.8300p-50, + 0x1.04e5f72f65467p+0, -0x1.a3f0p-46, + 0x1.059b0d315855ap+0, -0x1.2840p-47, + 0x1.0650a0e3c1f95p+0, 0x1.1600p-48, + 0x1.0706b29ddf71ap+0, 0x1.5240p-46, + 0x1.07bd42b72a82dp+0, -0x1.9a00p-49, + 0x1.0874518759bd0p+0, 0x1.6400p-49, + 0x1.092bdf66607c8p+0, -0x1.0780p-47, + 0x1.09e3ecac6f383p+0, -0x1.8000p-54, + 0x1.0a9c79b1f3930p+0, 0x1.fa00p-48, + 0x1.0b5586cf988fcp+0, -0x1.ac80p-48, + 0x1.0c0f145e46c8ap+0, 0x1.9c00p-50, + 0x1.0cc922b724816p+0, 0x1.5200p-47, + 0x1.0d83b23395dd8p+0, -0x1.ad00p-48, + 0x1.0e3ec32d3d1f3p+0, 0x1.bac0p-46, + 0x1.0efa55fdfa9a6p+0, -0x1.4e80p-47, + 0x1.0fb66affed2f0p+0, -0x1.d300p-47, + 0x1.1073028d7234bp+0, 0x1.1500p-48, + 0x1.11301d0125b5bp+0, 0x1.c000p-49, + 0x1.11edbab5e2af9p+0, 0x1.6bc0p-46, + 0x1.12abdc06c31d5p+0, 0x1.8400p-49, + 0x1.136a814f2047dp+0, -0x1.ed00p-47, + 0x1.1429aaea92de9p+0, 0x1.8e00p-49, + 0x1.14e95934f3138p+0, 0x1.b400p-49, + 0x1.15a98c8a58e71p+0, 0x1.5300p-47, + 0x1.166a45471c3dfp+0, 0x1.3380p-47, + 0x1.172b83c7d5211p+0, 0x1.8d40p-45, + 0x1.17ed48695bb9fp+0, -0x1.5d00p-47, + 0x1.18af9388c8d93p+0, -0x1.c880p-46, + 0x1.1972658375d66p+0, 0x1.1f00p-46, + 0x1.1a35beb6fcba7p+0, 0x1.0480p-46, + 0x1.1af99f81387e3p+0, -0x1.7390p-43, + 0x1.1bbe084045d54p+0, 0x1.4e40p-45, + 0x1.1c82f95281c43p+0, -0x1.a200p-47, + 0x1.1d4873168b9b2p+0, 0x1.3800p-49, + 0x1.1e0e75eb44031p+0, 0x1.ac00p-49, + 0x1.1ed5022fcd938p+0, 0x1.1900p-47, + 0x1.1f9c18438cdf7p+0, -0x1.b780p-46, + 0x1.2063b88628d8fp+0, 0x1.d940p-45, + 0x1.212be3578a81ep+0, 0x1.8000p-50, + 0x1.21f49917ddd41p+0, 0x1.b340p-45, + 0x1.22bdda2791323p+0, 0x1.9f80p-46, + 0x1.2387a6e7561e7p+0, -0x1.9c80p-46, + 0x1.2451ffb821427p+0, 0x1.2300p-47, + 0x1.251ce4fb2a602p+0, -0x1.3480p-46, + 0x1.25e85711eceb0p+0, 0x1.2700p-46, + 0x1.26b4565e27d16p+0, 0x1.1d00p-46, + 0x1.2780e341de00fp+0, 0x1.1ee0p-44, + 0x1.284dfe1f5633ep+0, -0x1.4c00p-46, + 0x1.291ba7591bb30p+0, -0x1.3d80p-46, + 0x1.29e9df51fdf09p+0, 0x1.8b00p-47, + 0x1.2ab8a66d10e9bp+0, -0x1.27c0p-45, + 0x1.2b87fd0dada3ap+0, 0x1.a340p-45, + 0x1.2c57e39771af9p+0, -0x1.0800p-46, + 0x1.2d285a6e402d9p+0, -0x1.ed00p-47, + 0x1.2df961f641579p+0, -0x1.4200p-48, + 0x1.2ecafa93e2ecfp+0, -0x1.4980p-45, + 0x1.2f9d24abd8822p+0, -0x1.6300p-46, + 0x1.306fe0a31b625p+0, -0x1.2360p-44, + 0x1.31432edeea50bp+0, -0x1.0df8p-40, + 0x1.32170fc4cd7b8p+0, -0x1.2480p-45, + 0x1.32eb83ba8e9a2p+0, -0x1.5980p-45, + 0x1.33c08b2641766p+0, 0x1.ed00p-46, + 0x1.3496266e3fa27p+0, -0x1.c000p-50, + 0x1.356c55f929f0fp+0, -0x1.0d80p-44, + 0x1.36431a2de88b9p+0, 0x1.2c80p-45, + 0x1.371a7373aaa39p+0, 0x1.0600p-45, + 0x1.37f26231e74fep+0, -0x1.6600p-46, + 0x1.38cae6d05d838p+0, -0x1.ae00p-47, + 0x1.39a401b713ec3p+0, -0x1.4720p-43, + 0x1.3a7db34e5a020p+0, 0x1.8200p-47, + 0x1.3b57fbfec6e95p+0, 0x1.e800p-44, + 0x1.3c32dc313a8f2p+0, 0x1.f800p-49, + 0x1.3d0e544ede122p+0, -0x1.7a00p-46, + 0x1.3dea64c1234bbp+0, 0x1.6300p-45, + 0x1.3ec70df1c4eccp+0, -0x1.8a60p-43, + 0x1.3fa4504ac7e8cp+0, -0x1.cdc0p-44, + 0x1.40822c367a0bbp+0, 0x1.5b80p-45, + 0x1.4160a21f72e95p+0, 0x1.ec00p-46, + 0x1.423fb27094646p+0, -0x1.3600p-46, + 0x1.431f5d950a920p+0, 0x1.3980p-45, + 0x1.43ffa3f84b9ebp+0, 0x1.a000p-48, + 0x1.44e0860618919p+0, -0x1.6c00p-48, + 0x1.45c2042a7d201p+0, -0x1.bc00p-47, + 0x1.46a41ed1d0016p+0, -0x1.2800p-46, + 0x1.4786d668b3326p+0, 0x1.0e00p-44, + 0x1.486a2b5c13c00p+0, -0x1.d400p-45, + 0x1.494e1e192af04p+0, 0x1.c200p-47, + 0x1.4a32af0d7d372p+0, -0x1.e500p-46, + 0x1.4b17dea6db801p+0, 0x1.7800p-47, + 0x1.4bfdad53629e1p+0, -0x1.3800p-46, + 0x1.4ce41b817c132p+0, 0x1.0800p-47, + 0x1.4dcb299fddddbp+0, 0x1.c700p-45, + 0x1.4eb2d81d8ab96p+0, -0x1.ce00p-46, + 0x1.4f9b2769d2d02p+0, 0x1.9200p-46, + 0x1.508417f4531c1p+0, -0x1.8c00p-47, + 0x1.516daa2cf662ap+0, -0x1.a000p-48, + 0x1.5257de83f51eap+0, 0x1.a080p-43, + 0x1.5342b569d4edap+0, -0x1.6d80p-45, + 0x1.542e2f4f6ac1ap+0, -0x1.2440p-44, + 0x1.551a4ca5d94dbp+0, 0x1.83c0p-43, + 0x1.56070dde9116bp+0, 0x1.4b00p-45, + 0x1.56f4736b529dep+0, 0x1.15a0p-43, + 0x1.57e27dbe2c40ep+0, -0x1.9e00p-45, + 0x1.58d12d497c76fp+0, -0x1.3080p-45, + 0x1.59c0827ff0b4cp+0, 0x1.dec0p-43, + 0x1.5ab07dd485427p+0, -0x1.4000p-51, + 0x1.5ba11fba87af4p+0, 0x1.0080p-44, + 0x1.5c9268a59460bp+0, -0x1.6c80p-45, + 0x1.5d84590998e3fp+0, 0x1.69a0p-43, + 0x1.5e76f15ad20e1p+0, -0x1.b400p-46, + 0x1.5f6a320dcebcap+0, 0x1.7700p-46, + 0x1.605e1b976dcb8p+0, 0x1.6f80p-45, + 0x1.6152ae6cdf715p+0, 0x1.1000p-47, + 0x1.6247eb03a5531p+0, -0x1.5d00p-46, + 0x1.633dd1d1929b5p+0, -0x1.2d00p-46, + 0x1.6434634ccc313p+0, -0x1.a800p-49, + 0x1.652b9febc8efap+0, -0x1.8600p-45, + 0x1.6623882553397p+0, 0x1.1fe0p-40, + 0x1.671c1c708328ep+0, -0x1.7200p-44, + 0x1.68155d44ca97ep+0, 0x1.6800p-49, + 0x1.690f4b19e9471p+0, -0x1.9780p-45, +}; + +/* + * exp2(x): compute the base 2 exponential of x + * + * Accuracy: Peak error < 0.503 ulp for normalized results. + * + * Method: (accurate tables) + * + * Reduce x: + * x = k + y, for integer k and |y| <= 1/2. + * Thus we have exp2(x) = 2**k * exp2(y). + * + * Reduce y: + * y = i/TBLSIZE + z - eps[i] for integer i near y * TBLSIZE. + * Thus we have exp2(y) = exp2(i/TBLSIZE) * exp2(z - eps[i]), + * with |z - eps[i]| <= 2**-9 + 2**-39 for the table used. + * + * We compute exp2(i/TBLSIZE) via table lookup and exp2(z - eps[i]) via + * a degree-5 minimax polynomial with maximum error under 1.3 * 2**-61. + * The values in exp2t[] and eps[] are chosen such that + * exp2t[i] = exp2(i/TBLSIZE + eps[i]), and eps[i] is a small offset such + * that exp2t[i] is accurate to 2**-64. + * + * Note that the range of i is +-TBLSIZE/2, so we actually index the tables + * by i0 = i + TBLSIZE/2. For cache efficiency, exp2t[] and eps[] are + * virtual tables, interleaved in the real table tbl[]. + * + * This method is due to Gal, with many details due to Gal and Bachelis: + * + * Gal, S. and Bachelis, B. An Accurate Elementary Mathematical Library + * for the IEEE Floating Point Standard. TOMS 17(1), 26-46 (1991). + */ +double exp2(double x) +{ + double_t r, t, z; + uint32_t ix, i0; + union {double f; uint64_t i;} u = {x}; + union {uint32_t u; int32_t i;} k; + + /* Filter out exceptional cases. */ + ix = u.i>>32 & 0x7fffffff; + if (ix >= 0x408ff000) { /* |x| >= 1022 or nan */ + if (ix >= 0x40900000 && u.i>>63 == 0) { /* x >= 1024 or nan */ + /* overflow */ + x *= 0x1p1023; + return x; + } + if (ix >= 0x7ff00000) /* -inf or -nan */ + return -1/x; + if (u.i>>63) { /* x <= -1022 */ + /* underflow */ + if (x <= -1075 || x - 0x1p52 + 0x1p52 != x) + FORCE_EVAL((float)(-0x1p-149/x)); + if (x <= -1075) + return 0; + } + } else if (ix < 0x3c900000) { /* |x| < 0x1p-54 */ + return 1.0 + x; + } + + /* Reduce x, computing z, i0, and k. */ + u.f = x + redux; + i0 = u.i; + i0 += TBLSIZE / 2; + k.u = i0 / TBLSIZE * TBLSIZE; + k.i /= TBLSIZE; + i0 %= TBLSIZE; + u.f -= redux; + z = x - u.f; + + /* Compute r = exp2(y) = exp2t[i0] * p(z - eps[i]). */ + t = tbl[2*i0]; /* exp2t[i0] */ + z -= tbl[2*i0 + 1]; /* eps[i0] */ + r = t + t * z * (P1 + z * (P2 + z * (P3 + z * (P4 + z * P5)))); + + return scalbn(r, k.i); +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/exp2f.c b/lib/mlibc/options/ansi/musl-generic-math/exp2f.c new file mode 100644 index 0000000..296b634 --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/exp2f.c @@ -0,0 +1,126 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_exp2f.c */ +/*- + * Copyright (c) 2005 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "libm.h" + +#define TBLSIZE 16 + +static const float +redux = 0x1.8p23f / TBLSIZE, +P1 = 0x1.62e430p-1f, +P2 = 0x1.ebfbe0p-3f, +P3 = 0x1.c6b348p-5f, +P4 = 0x1.3b2c9cp-7f; + +static const double exp2ft[TBLSIZE] = { + 0x1.6a09e667f3bcdp-1, + 0x1.7a11473eb0187p-1, + 0x1.8ace5422aa0dbp-1, + 0x1.9c49182a3f090p-1, + 0x1.ae89f995ad3adp-1, + 0x1.c199bdd85529cp-1, + 0x1.d5818dcfba487p-1, + 0x1.ea4afa2a490dap-1, + 0x1.0000000000000p+0, + 0x1.0b5586cf9890fp+0, + 0x1.172b83c7d517bp+0, + 0x1.2387a6e756238p+0, + 0x1.306fe0a31b715p+0, + 0x1.3dea64c123422p+0, + 0x1.4bfdad5362a27p+0, + 0x1.5ab07dd485429p+0, +}; + +/* + * exp2f(x): compute the base 2 exponential of x + * + * Accuracy: Peak error < 0.501 ulp; location of peak: -0.030110927. + * + * Method: (equally-spaced tables) + * + * Reduce x: + * x = k + y, for integer k and |y| <= 1/2. + * Thus we have exp2f(x) = 2**k * exp2(y). + * + * Reduce y: + * y = i/TBLSIZE + z for integer i near y * TBLSIZE. + * Thus we have exp2(y) = exp2(i/TBLSIZE) * exp2(z), + * with |z| <= 2**-(TBLSIZE+1). + * + * We compute exp2(i/TBLSIZE) via table lookup and exp2(z) via a + * degree-4 minimax polynomial with maximum error under 1.4 * 2**-33. + * Using double precision for everything except the reduction makes + * roundoff error insignificant and simplifies the scaling step. + * + * This method is due to Tang, but I do not use his suggested parameters: + * + * Tang, P. Table-driven Implementation of the Exponential Function + * in IEEE Floating-Point Arithmetic. TOMS 15(2), 144-157 (1989). + */ +float exp2f(float x) +{ + double_t t, r, z; + union {float f; uint32_t i;} u = {x}; + union {double f; uint64_t i;} uk; + uint32_t ix, i0, k; + + /* Filter out exceptional cases. */ + ix = u.i & 0x7fffffff; + if (ix > 0x42fc0000) { /* |x| > 126 */ + if (ix > 0x7f800000) /* NaN */ + return x; + if (u.i >= 0x43000000 && u.i < 0x80000000) { /* x >= 128 */ + x *= 0x1p127f; + return x; + } + if (u.i >= 0x80000000) { /* x < -126 */ + if (u.i >= 0xc3160000 || (u.i & 0x0000ffff)) + FORCE_EVAL(-0x1p-149f/x); + if (u.i >= 0xc3160000) /* x <= -150 */ + return 0; + } + } else if (ix <= 0x33000000) { /* |x| <= 0x1p-25 */ + return 1.0f + x; + } + + /* Reduce x, computing z, i0, and k. */ + u.f = x + redux; + i0 = u.i; + i0 += TBLSIZE / 2; + k = i0 / TBLSIZE; + uk.i = (uint64_t)(0x3ff + k)<<52; + i0 &= TBLSIZE - 1; + u.f -= redux; + z = x - u.f; + /* Compute r = exp2(y) = exp2ft[i0] * p(z). */ + r = exp2ft[i0]; + t = r * z; + r = r + t * (P1 + z * P2) + t * (z * z) * (P3 + z * P4); + + /* Scale by 2**k */ + return r * uk.f; +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/exp2l.c b/lib/mlibc/options/ansi/musl-generic-math/exp2l.c new file mode 100644 index 0000000..3565c1e --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/exp2l.c @@ -0,0 +1,619 @@ +/* origin: FreeBSD /usr/src/lib/msun/ld80/s_exp2l.c and /usr/src/lib/msun/ld128/s_exp2l.c */ +/*- + * Copyright (c) 2005-2008 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double exp2l(long double x) +{ + return exp2(x); +} +#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 +#define TBLBITS 7 +#define TBLSIZE (1 << TBLBITS) + +static const double +redux = 0x1.8p63 / TBLSIZE, +P1 = 0x1.62e42fefa39efp-1, +P2 = 0x1.ebfbdff82c58fp-3, +P3 = 0x1.c6b08d7049fap-5, +P4 = 0x1.3b2ab6fba4da5p-7, +P5 = 0x1.5d8804780a736p-10, +P6 = 0x1.430918835e33dp-13; + +static const double tbl[TBLSIZE * 2] = { + 0x1.6a09e667f3bcdp-1, -0x1.bdd3413b2648p-55, + 0x1.6c012750bdabfp-1, -0x1.2895667ff0cp-57, + 0x1.6dfb23c651a2fp-1, -0x1.bbe3a683c88p-58, + 0x1.6ff7df9519484p-1, -0x1.83c0f25860fp-56, + 0x1.71f75e8ec5f74p-1, -0x1.16e4786887bp-56, + 0x1.73f9a48a58174p-1, -0x1.0a8d96c65d5p-55, + 0x1.75feb564267c9p-1, -0x1.0245957316ep-55, + 0x1.780694fde5d3fp-1, 0x1.866b80a0216p-55, + 0x1.7a11473eb0187p-1, -0x1.41577ee0499p-56, + 0x1.7c1ed0130c132p-1, 0x1.f124cd1164ep-55, + 0x1.7e2f336cf4e62p-1, 0x1.05d02ba157ap-57, + 0x1.80427543e1a12p-1, -0x1.27c86626d97p-55, + 0x1.82589994cce13p-1, -0x1.d4c1dd41533p-55, + 0x1.8471a4623c7adp-1, -0x1.8d684a341cep-56, + 0x1.868d99b4492edp-1, -0x1.fc6f89bd4f68p-55, + 0x1.88ac7d98a6699p-1, 0x1.994c2f37cb5p-55, + 0x1.8ace5422aa0dbp-1, 0x1.6e9f156864bp-55, + 0x1.8cf3216b5448cp-1, -0x1.0d55e32e9e4p-57, + 0x1.8f1ae99157736p-1, 0x1.5cc13a2e397p-56, + 0x1.9145b0b91ffc6p-1, -0x1.dd6792e5825p-55, + 0x1.93737b0cdc5e5p-1, -0x1.75fc781b58p-58, + 0x1.95a44cbc8520fp-1, -0x1.64b7c96a5fp-57, + 0x1.97d829fde4e5p-1, -0x1.d185b7c1b86p-55, + 0x1.9a0f170ca07bap-1, -0x1.173bd91cee6p-55, + 0x1.9c49182a3f09p-1, 0x1.c7c46b071f2p-57, + 0x1.9e86319e32323p-1, 0x1.824ca78e64cp-57, + 0x1.a0c667b5de565p-1, -0x1.359495d1cd5p-55, + 0x1.a309bec4a2d33p-1, 0x1.6305c7ddc368p-55, + 0x1.a5503b23e255dp-1, -0x1.d2f6edb8d42p-55, + 0x1.a799e1330b358p-1, 0x1.bcb7ecac564p-55, + 0x1.a9e6b5579fdbfp-1, 0x1.0fac90ef7fdp-55, + 0x1.ac36bbfd3f37ap-1, -0x1.f9234cae76dp-56, + 0x1.ae89f995ad3adp-1, 0x1.7a1cd345dcc8p-55, + 0x1.b0e07298db666p-1, -0x1.bdef54c80e4p-55, + 0x1.b33a2b84f15fbp-1, -0x1.2805e3084d8p-58, + 0x1.b59728de5593ap-1, -0x1.c71dfbbba6ep-55, + 0x1.b7f76f2fb5e47p-1, -0x1.5584f7e54acp-57, + 0x1.ba5b030a1064ap-1, -0x1.efcd30e5429p-55, + 0x1.bcc1e904bc1d2p-1, 0x1.23dd07a2d9fp-56, + 0x1.bf2c25bd71e09p-1, -0x1.efdca3f6b9c8p-55, + 0x1.c199bdd85529cp-1, 0x1.11065895049p-56, + 0x1.c40ab5fffd07ap-1, 0x1.b4537e083c6p-55, + 0x1.c67f12e57d14bp-1, 0x1.2884dff483c8p-55, + 0x1.c8f6d9406e7b5p-1, 0x1.1acbc48805cp-57, + 0x1.cb720dcef9069p-1, 0x1.503cbd1e94ap-57, + 0x1.cdf0b555dc3fap-1, -0x1.dd83b53829dp-56, + 0x1.d072d4a07897cp-1, -0x1.cbc3743797a8p-55, + 0x1.d2f87080d89f2p-1, -0x1.d487b719d858p-55, + 0x1.d5818dcfba487p-1, 0x1.2ed02d75b37p-56, + 0x1.d80e316c98398p-1, -0x1.11ec18bedep-55, + 0x1.da9e603db3285p-1, 0x1.c2300696db5p-55, + 0x1.dd321f301b46p-1, 0x1.2da5778f019p-55, + 0x1.dfc97337b9b5fp-1, -0x1.1a5cd4f184b8p-55, + 0x1.e264614f5a129p-1, -0x1.7b627817a148p-55, + 0x1.e502ee78b3ff6p-1, 0x1.39e8980a9cdp-56, + 0x1.e7a51fbc74c83p-1, 0x1.2d522ca0c8ep-55, + 0x1.ea4afa2a490dap-1, -0x1.e9c23179c288p-55, + 0x1.ecf482d8e67f1p-1, -0x1.c93f3b411ad8p-55, + 0x1.efa1bee615a27p-1, 0x1.dc7f486a4b68p-55, + 0x1.f252b376bba97p-1, 0x1.3a1a5bf0d8e8p-55, + 0x1.f50765b6e454p-1, 0x1.9d3e12dd8a18p-55, + 0x1.f7bfdad9cbe14p-1, -0x1.dbb12d00635p-55, + 0x1.fa7c1819e90d8p-1, 0x1.74853f3a593p-56, + 0x1.fd3c22b8f71f1p-1, 0x1.2eb74966578p-58, + 0x1p+0, 0x0p+0, + 0x1.0163da9fb3335p+0, 0x1.b61299ab8cd8p-54, + 0x1.02c9a3e778061p+0, -0x1.19083535b08p-56, + 0x1.04315e86e7f85p+0, -0x1.0a31c1977c98p-54, + 0x1.059b0d3158574p+0, 0x1.d73e2a475b4p-55, + 0x1.0706b29ddf6dep+0, -0x1.c91dfe2b13cp-55, + 0x1.0874518759bc8p+0, 0x1.186be4bb284p-57, + 0x1.09e3ecac6f383p+0, 0x1.14878183161p-54, + 0x1.0b5586cf9890fp+0, 0x1.8a62e4adc61p-54, + 0x1.0cc922b7247f7p+0, 0x1.01edc16e24f8p-54, + 0x1.0e3ec32d3d1a2p+0, 0x1.03a1727c58p-59, + 0x1.0fb66affed31bp+0, -0x1.b9bedc44ebcp-57, + 0x1.11301d0125b51p+0, -0x1.6c51039449bp-54, + 0x1.12abdc06c31ccp+0, -0x1.1b514b36ca8p-58, + 0x1.1429aaea92dep+0, -0x1.32fbf9af1368p-54, + 0x1.15a98c8a58e51p+0, 0x1.2406ab9eeabp-55, + 0x1.172b83c7d517bp+0, -0x1.19041b9d78ap-55, + 0x1.18af9388c8deap+0, -0x1.11023d1970f8p-54, + 0x1.1a35beb6fcb75p+0, 0x1.e5b4c7b4969p-55, + 0x1.1bbe084045cd4p+0, -0x1.95386352ef6p-54, + 0x1.1d4873168b9aap+0, 0x1.e016e00a264p-54, + 0x1.1ed5022fcd91dp+0, -0x1.1df98027bb78p-54, + 0x1.2063b88628cd6p+0, 0x1.dc775814a85p-55, + 0x1.21f49917ddc96p+0, 0x1.2a97e9494a6p-55, + 0x1.2387a6e756238p+0, 0x1.9b07eb6c7058p-54, + 0x1.251ce4fb2a63fp+0, 0x1.ac155bef4f5p-55, + 0x1.26b4565e27cddp+0, 0x1.2bd339940eap-55, + 0x1.284dfe1f56381p+0, -0x1.a4c3a8c3f0d8p-54, + 0x1.29e9df51fdee1p+0, 0x1.612e8afad12p-55, + 0x1.2b87fd0dad99p+0, -0x1.10adcd6382p-59, + 0x1.2d285a6e4030bp+0, 0x1.0024754db42p-54, + 0x1.2ecafa93e2f56p+0, 0x1.1ca0f45d524p-56, + 0x1.306fe0a31b715p+0, 0x1.6f46ad23183p-55, + 0x1.32170fc4cd831p+0, 0x1.a9ce78e1804p-55, + 0x1.33c08b26416ffp+0, 0x1.327218436598p-54, + 0x1.356c55f929ff1p+0, -0x1.b5cee5c4e46p-55, + 0x1.371a7373aa9cbp+0, -0x1.63aeabf42ebp-54, + 0x1.38cae6d05d866p+0, -0x1.e958d3c99048p-54, + 0x1.3a7db34e59ff7p+0, -0x1.5e436d661f6p-56, + 0x1.3c32dc313a8e5p+0, -0x1.efff8375d2ap-54, + 0x1.3dea64c123422p+0, 0x1.ada0911f09fp-55, + 0x1.3fa4504ac801cp+0, -0x1.7d023f956fap-54, + 0x1.4160a21f72e2ap+0, -0x1.ef3691c309p-58, + 0x1.431f5d950a897p+0, -0x1.1c7dde35f7ap-55, + 0x1.44e086061892dp+0, 0x1.89b7a04ef8p-59, + 0x1.46a41ed1d0057p+0, 0x1.c944bd1648a8p-54, + 0x1.486a2b5c13cdp+0, 0x1.3c1a3b69062p-56, + 0x1.4a32af0d7d3dep+0, 0x1.9cb62f3d1be8p-54, + 0x1.4bfdad5362a27p+0, 0x1.d4397afec42p-56, + 0x1.4dcb299fddd0dp+0, 0x1.8ecdbbc6a78p-54, + 0x1.4f9b2769d2ca7p+0, -0x1.4b309d25958p-54, + 0x1.516daa2cf6642p+0, -0x1.f768569bd94p-55, + 0x1.5342b569d4f82p+0, -0x1.07abe1db13dp-55, + 0x1.551a4ca5d920fp+0, -0x1.d689cefede6p-55, + 0x1.56f4736b527dap+0, 0x1.9bb2c011d938p-54, + 0x1.58d12d497c7fdp+0, 0x1.295e15b9a1ep-55, + 0x1.5ab07dd485429p+0, 0x1.6324c0546478p-54, + 0x1.5c9268a5946b7p+0, 0x1.c4b1b81698p-60, + 0x1.5e76f15ad2148p+0, 0x1.ba6f93080e68p-54, + 0x1.605e1b976dc09p+0, -0x1.3e2429b56de8p-54, + 0x1.6247eb03a5585p+0, -0x1.383c17e40b48p-54, + 0x1.6434634ccc32p+0, -0x1.c483c759d89p-55, + 0x1.6623882552225p+0, -0x1.bb60987591cp-54, + 0x1.68155d44ca973p+0, 0x1.038ae44f74p-57, +}; + +/* + * exp2l(x): compute the base 2 exponential of x + * + * Accuracy: Peak error < 0.511 ulp. + * + * Method: (equally-spaced tables) + * + * Reduce x: + * x = 2**k + y, for integer k and |y| <= 1/2. + * Thus we have exp2l(x) = 2**k * exp2(y). + * + * Reduce y: + * y = i/TBLSIZE + z for integer i near y * TBLSIZE. + * Thus we have exp2(y) = exp2(i/TBLSIZE) * exp2(z), + * with |z| <= 2**-(TBLBITS+1). + * + * We compute exp2(i/TBLSIZE) via table lookup and exp2(z) via a + * degree-6 minimax polynomial with maximum error under 2**-69. + * The table entries each have 104 bits of accuracy, encoded as + * a pair of double precision values. + */ +long double exp2l(long double x) +{ + union ldshape u = {x}; + int e = u.i.se & 0x7fff; + long double r, z; + uint32_t i0; + union {uint32_t u; int32_t i;} k; + + /* Filter out exceptional cases. */ + if (e >= 0x3fff + 13) { /* |x| >= 8192 or x is NaN */ + if (u.i.se >= 0x3fff + 14 && u.i.se >> 15 == 0) + /* overflow */ + return x * 0x1p16383L; + if (e == 0x7fff) /* -inf or -nan */ + return -1/x; + if (x < -16382) { + if (x <= -16446 || x - 0x1p63 + 0x1p63 != x) + /* underflow */ + FORCE_EVAL((float)(-0x1p-149/x)); + if (x <= -16446) + return 0; + } + } else if (e < 0x3fff - 64) { + return 1 + x; + } + + /* + * Reduce x, computing z, i0, and k. The low bits of x + redux + * contain the 16-bit integer part of the exponent (k) followed by + * TBLBITS fractional bits (i0). We use bit tricks to extract these + * as integers, then set z to the remainder. + * + * Example: Suppose x is 0xabc.123456p0 and TBLBITS is 8. + * Then the low-order word of x + redux is 0x000abc12, + * We split this into k = 0xabc and i0 = 0x12 (adjusted to + * index into the table), then we compute z = 0x0.003456p0. + */ + u.f = x + redux; + i0 = u.i.m + TBLSIZE / 2; + k.u = i0 / TBLSIZE * TBLSIZE; + k.i /= TBLSIZE; + i0 %= TBLSIZE; + u.f -= redux; + z = x - u.f; + + /* Compute r = exp2l(y) = exp2lt[i0] * p(z). */ + long double t_hi = tbl[2*i0]; + long double t_lo = tbl[2*i0 + 1]; + /* XXX This gives > 1 ulp errors outside of FE_TONEAREST mode */ + r = t_lo + (t_hi + t_lo) * z * (P1 + z * (P2 + z * (P3 + z * (P4 + + z * (P5 + z * P6))))) + t_hi; + + return scalbnl(r, k.i); +} +#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 +#define TBLBITS 7 +#define TBLSIZE (1 << TBLBITS) + +static const long double + P1 = 0x1.62e42fefa39ef35793c7673007e6p-1L, + P2 = 0x1.ebfbdff82c58ea86f16b06ec9736p-3L, + P3 = 0x1.c6b08d704a0bf8b33a762bad3459p-5L, + P4 = 0x1.3b2ab6fba4e7729ccbbe0b4f3fc2p-7L, + P5 = 0x1.5d87fe78a67311071dee13fd11d9p-10L, + P6 = 0x1.430912f86c7876f4b663b23c5fe5p-13L; + +static const double + P7 = 0x1.ffcbfc588b041p-17, + P8 = 0x1.62c0223a5c7c7p-20, + P9 = 0x1.b52541ff59713p-24, + P10 = 0x1.e4cf56a391e22p-28, + redux = 0x1.8p112 / TBLSIZE; + +static const long double tbl[TBLSIZE] = { + 0x1.6a09e667f3bcc908b2fb1366dfeap-1L, + 0x1.6c012750bdabeed76a99800f4edep-1L, + 0x1.6dfb23c651a2ef220e2cbe1bc0d4p-1L, + 0x1.6ff7df9519483cf87e1b4f3e1e98p-1L, + 0x1.71f75e8ec5f73dd2370f2ef0b148p-1L, + 0x1.73f9a48a58173bd5c9a4e68ab074p-1L, + 0x1.75feb564267c8bf6e9aa33a489a8p-1L, + 0x1.780694fde5d3f619ae02808592a4p-1L, + 0x1.7a11473eb0186d7d51023f6ccb1ap-1L, + 0x1.7c1ed0130c1327c49334459378dep-1L, + 0x1.7e2f336cf4e62105d02ba1579756p-1L, + 0x1.80427543e1a11b60de67649a3842p-1L, + 0x1.82589994cce128acf88afab34928p-1L, + 0x1.8471a4623c7acce52f6b97c6444cp-1L, + 0x1.868d99b4492ec80e41d90ac2556ap-1L, + 0x1.88ac7d98a669966530bcdf2d4cc0p-1L, + 0x1.8ace5422aa0db5ba7c55a192c648p-1L, + 0x1.8cf3216b5448bef2aa1cd161c57ap-1L, + 0x1.8f1ae991577362b982745c72eddap-1L, + 0x1.9145b0b91ffc588a61b469f6b6a0p-1L, + 0x1.93737b0cdc5e4f4501c3f2540ae8p-1L, + 0x1.95a44cbc8520ee9b483695a0e7fep-1L, + 0x1.97d829fde4e4f8b9e920f91e8eb6p-1L, + 0x1.9a0f170ca07b9ba3109b8c467844p-1L, + 0x1.9c49182a3f0901c7c46b071f28dep-1L, + 0x1.9e86319e323231824ca78e64c462p-1L, + 0x1.a0c667b5de564b29ada8b8cabbacp-1L, + 0x1.a309bec4a2d3358c171f770db1f4p-1L, + 0x1.a5503b23e255c8b424491caf88ccp-1L, + 0x1.a799e1330b3586f2dfb2b158f31ep-1L, + 0x1.a9e6b5579fdbf43eb243bdff53a2p-1L, + 0x1.ac36bbfd3f379c0db966a3126988p-1L, + 0x1.ae89f995ad3ad5e8734d17731c80p-1L, + 0x1.b0e07298db66590842acdfc6fb4ep-1L, + 0x1.b33a2b84f15faf6bfd0e7bd941b0p-1L, + 0x1.b59728de559398e3881111648738p-1L, + 0x1.b7f76f2fb5e46eaa7b081ab53ff6p-1L, + 0x1.ba5b030a10649840cb3c6af5b74cp-1L, + 0x1.bcc1e904bc1d2247ba0f45b3d06cp-1L, + 0x1.bf2c25bd71e088408d7025190cd0p-1L, + 0x1.c199bdd85529c2220cb12a0916bap-1L, + 0x1.c40ab5fffd07a6d14df820f17deap-1L, + 0x1.c67f12e57d14b4a2137fd20f2a26p-1L, + 0x1.c8f6d9406e7b511acbc48805c3f6p-1L, + 0x1.cb720dcef90691503cbd1e949d0ap-1L, + 0x1.cdf0b555dc3f9c44f8958fac4f12p-1L, + 0x1.d072d4a07897b8d0f22f21a13792p-1L, + 0x1.d2f87080d89f18ade123989ea50ep-1L, + 0x1.d5818dcfba48725da05aeb66dff8p-1L, + 0x1.d80e316c98397bb84f9d048807a0p-1L, + 0x1.da9e603db3285708c01a5b6d480cp-1L, + 0x1.dd321f301b4604b695de3c0630c0p-1L, + 0x1.dfc97337b9b5eb968cac39ed284cp-1L, + 0x1.e264614f5a128a12761fa17adc74p-1L, + 0x1.e502ee78b3ff6273d130153992d0p-1L, + 0x1.e7a51fbc74c834b548b2832378a4p-1L, + 0x1.ea4afa2a490d9858f73a18f5dab4p-1L, + 0x1.ecf482d8e67f08db0312fb949d50p-1L, + 0x1.efa1bee615a27771fd21a92dabb6p-1L, + 0x1.f252b376bba974e8696fc3638f24p-1L, + 0x1.f50765b6e4540674f84b762861a6p-1L, + 0x1.f7bfdad9cbe138913b4bfe72bd78p-1L, + 0x1.fa7c1819e90d82e90a7e74b26360p-1L, + 0x1.fd3c22b8f71f10975ba4b32bd006p-1L, + 0x1.0000000000000000000000000000p+0L, + 0x1.0163da9fb33356d84a66ae336e98p+0L, + 0x1.02c9a3e778060ee6f7caca4f7a18p+0L, + 0x1.04315e86e7f84bd738f9a20da442p+0L, + 0x1.059b0d31585743ae7c548eb68c6ap+0L, + 0x1.0706b29ddf6ddc6dc403a9d87b1ep+0L, + 0x1.0874518759bc808c35f25d942856p+0L, + 0x1.09e3ecac6f3834521e060c584d5cp+0L, + 0x1.0b5586cf9890f6298b92b7184200p+0L, + 0x1.0cc922b7247f7407b705b893dbdep+0L, + 0x1.0e3ec32d3d1a2020742e4f8af794p+0L, + 0x1.0fb66affed31af232091dd8a169ep+0L, + 0x1.11301d0125b50a4ebbf1aed9321cp+0L, + 0x1.12abdc06c31cbfb92bad324d6f84p+0L, + 0x1.1429aaea92ddfb34101943b2588ep+0L, + 0x1.15a98c8a58e512480d573dd562aep+0L, + 0x1.172b83c7d517adcdf7c8c50eb162p+0L, + 0x1.18af9388c8de9bbbf70b9a3c269cp+0L, + 0x1.1a35beb6fcb753cb698f692d2038p+0L, + 0x1.1bbe084045cd39ab1e72b442810ep+0L, + 0x1.1d4873168b9aa7805b8028990be8p+0L, + 0x1.1ed5022fcd91cb8819ff61121fbep+0L, + 0x1.2063b88628cd63b8eeb0295093f6p+0L, + 0x1.21f49917ddc962552fd29294bc20p+0L, + 0x1.2387a6e75623866c1fadb1c159c0p+0L, + 0x1.251ce4fb2a63f3582ab7de9e9562p+0L, + 0x1.26b4565e27cdd257a673281d3068p+0L, + 0x1.284dfe1f5638096cf15cf03c9fa0p+0L, + 0x1.29e9df51fdee12c25d15f5a25022p+0L, + 0x1.2b87fd0dad98ffddea46538fca24p+0L, + 0x1.2d285a6e4030b40091d536d0733ep+0L, + 0x1.2ecafa93e2f5611ca0f45d5239a4p+0L, + 0x1.306fe0a31b7152de8d5a463063bep+0L, + 0x1.32170fc4cd8313539cf1c3009330p+0L, + 0x1.33c08b26416ff4c9c8610d96680ep+0L, + 0x1.356c55f929ff0c94623476373be4p+0L, + 0x1.371a7373aa9caa7145502f45452ap+0L, + 0x1.38cae6d05d86585a9cb0d9bed530p+0L, + 0x1.3a7db34e59ff6ea1bc9299e0a1fep+0L, + 0x1.3c32dc313a8e484001f228b58cf0p+0L, + 0x1.3dea64c12342235b41223e13d7eep+0L, + 0x1.3fa4504ac801ba0bf701aa417b9cp+0L, + 0x1.4160a21f72e29f84325b8f3dbacap+0L, + 0x1.431f5d950a896dc704439410b628p+0L, + 0x1.44e086061892d03136f409df0724p+0L, + 0x1.46a41ed1d005772512f459229f0ap+0L, + 0x1.486a2b5c13cd013c1a3b69062f26p+0L, + 0x1.4a32af0d7d3de672d8bcf46f99b4p+0L, + 0x1.4bfdad5362a271d4397afec42e36p+0L, + 0x1.4dcb299fddd0d63b36ef1a9e19dep+0L, + 0x1.4f9b2769d2ca6ad33d8b69aa0b8cp+0L, + 0x1.516daa2cf6641c112f52c84d6066p+0L, + 0x1.5342b569d4f81df0a83c49d86bf4p+0L, + 0x1.551a4ca5d920ec52ec620243540cp+0L, + 0x1.56f4736b527da66ecb004764e61ep+0L, + 0x1.58d12d497c7fd252bc2b7343d554p+0L, + 0x1.5ab07dd48542958c93015191e9a8p+0L, + 0x1.5c9268a5946b701c4b1b81697ed4p+0L, + 0x1.5e76f15ad21486e9be4c20399d12p+0L, + 0x1.605e1b976dc08b076f592a487066p+0L, + 0x1.6247eb03a5584b1f0fa06fd2d9eap+0L, + 0x1.6434634ccc31fc76f8714c4ee122p+0L, + 0x1.66238825522249127d9e29b92ea2p+0L, + 0x1.68155d44ca973081c57227b9f69ep+0L, +}; + +static const float eps[TBLSIZE] = { + -0x1.5c50p-101, + -0x1.5d00p-106, + 0x1.8e90p-102, + -0x1.5340p-103, + 0x1.1bd0p-102, + -0x1.4600p-105, + -0x1.7a40p-104, + 0x1.d590p-102, + -0x1.d590p-101, + 0x1.b100p-103, + -0x1.0d80p-105, + 0x1.6b00p-103, + -0x1.9f00p-105, + 0x1.c400p-103, + 0x1.e120p-103, + -0x1.c100p-104, + -0x1.9d20p-103, + 0x1.a800p-108, + 0x1.4c00p-106, + -0x1.9500p-106, + 0x1.6900p-105, + -0x1.29d0p-100, + 0x1.4c60p-103, + 0x1.13a0p-102, + -0x1.5b60p-103, + -0x1.1c40p-103, + 0x1.db80p-102, + 0x1.91a0p-102, + 0x1.dc00p-105, + 0x1.44c0p-104, + 0x1.9710p-102, + 0x1.8760p-103, + -0x1.a720p-103, + 0x1.ed20p-103, + -0x1.49c0p-102, + -0x1.e000p-111, + 0x1.86a0p-103, + 0x1.2b40p-103, + -0x1.b400p-108, + 0x1.1280p-99, + -0x1.02d8p-102, + -0x1.e3d0p-103, + -0x1.b080p-105, + -0x1.f100p-107, + -0x1.16c0p-105, + -0x1.1190p-103, + -0x1.a7d2p-100, + 0x1.3450p-103, + -0x1.67c0p-105, + 0x1.4b80p-104, + -0x1.c4e0p-103, + 0x1.6000p-108, + -0x1.3f60p-105, + 0x1.93f0p-104, + 0x1.5fe0p-105, + 0x1.6f80p-107, + -0x1.7600p-106, + 0x1.21e0p-106, + -0x1.3a40p-106, + -0x1.40c0p-104, + -0x1.9860p-105, + -0x1.5d40p-108, + -0x1.1d70p-106, + 0x1.2760p-105, + 0x0.0000p+0, + 0x1.21e2p-104, + -0x1.9520p-108, + -0x1.5720p-106, + -0x1.4810p-106, + -0x1.be00p-109, + 0x1.0080p-105, + -0x1.5780p-108, + -0x1.d460p-105, + -0x1.6140p-105, + 0x1.4630p-104, + 0x1.ad50p-103, + 0x1.82e0p-105, + 0x1.1d3cp-101, + 0x1.6100p-107, + 0x1.ec30p-104, + 0x1.f200p-108, + 0x1.0b40p-103, + 0x1.3660p-102, + 0x1.d9d0p-103, + -0x1.02d0p-102, + 0x1.b070p-103, + 0x1.b9c0p-104, + -0x1.01c0p-103, + -0x1.dfe0p-103, + 0x1.1b60p-104, + -0x1.ae94p-101, + -0x1.3340p-104, + 0x1.b3d8p-102, + -0x1.6e40p-105, + -0x1.3670p-103, + 0x1.c140p-104, + 0x1.1840p-101, + 0x1.1ab0p-102, + -0x1.a400p-104, + 0x1.1f00p-104, + -0x1.7180p-103, + 0x1.4ce0p-102, + 0x1.9200p-107, + -0x1.54c0p-103, + 0x1.1b80p-105, + -0x1.1828p-101, + 0x1.5720p-102, + -0x1.a060p-100, + 0x1.9160p-102, + 0x1.a280p-104, + 0x1.3400p-107, + 0x1.2b20p-102, + 0x1.7800p-108, + 0x1.cfd0p-101, + 0x1.2ef0p-102, + -0x1.2760p-99, + 0x1.b380p-104, + 0x1.0048p-101, + -0x1.60b0p-102, + 0x1.a1ccp-100, + -0x1.a640p-104, + -0x1.08a0p-101, + 0x1.7e60p-102, + 0x1.22c0p-103, + -0x1.7200p-106, + 0x1.f0f0p-102, + 0x1.eb4ep-99, + 0x1.c6e0p-103, +}; + +/* + * exp2l(x): compute the base 2 exponential of x + * + * Accuracy: Peak error < 0.502 ulp. + * + * Method: (accurate tables) + * + * Reduce x: + * x = 2**k + y, for integer k and |y| <= 1/2. + * Thus we have exp2(x) = 2**k * exp2(y). + * + * Reduce y: + * y = i/TBLSIZE + z - eps[i] for integer i near y * TBLSIZE. + * Thus we have exp2(y) = exp2(i/TBLSIZE) * exp2(z - eps[i]), + * with |z - eps[i]| <= 2**-8 + 2**-98 for the table used. + * + * We compute exp2(i/TBLSIZE) via table lookup and exp2(z - eps[i]) via + * a degree-10 minimax polynomial with maximum error under 2**-120. + * The values in exp2t[] and eps[] are chosen such that + * exp2t[i] = exp2(i/TBLSIZE + eps[i]), and eps[i] is a small offset such + * that exp2t[i] is accurate to 2**-122. + * + * Note that the range of i is +-TBLSIZE/2, so we actually index the tables + * by i0 = i + TBLSIZE/2. + * + * This method is due to Gal, with many details due to Gal and Bachelis: + * + * Gal, S. and Bachelis, B. An Accurate Elementary Mathematical Library + * for the IEEE Floating Point Standard. TOMS 17(1), 26-46 (1991). + */ +long double +exp2l(long double x) +{ + union ldshape u = {x}; + int e = u.i.se & 0x7fff; + long double r, z, t; + uint32_t i0; + union {uint32_t u; int32_t i;} k; + + /* Filter out exceptional cases. */ + if (e >= 0x3fff + 14) { /* |x| >= 16384 or x is NaN */ + if (u.i.se >= 0x3fff + 15 && u.i.se >> 15 == 0) + /* overflow */ + return x * 0x1p16383L; + if (e == 0x7fff) /* -inf or -nan */ + return -1/x; + if (x < -16382) { + if (x <= -16495 || x - 0x1p112 + 0x1p112 != x) + /* underflow */ + FORCE_EVAL((float)(-0x1p-149/x)); + if (x <= -16446) + return 0; + } + } else if (e < 0x3fff - 114) { + return 1 + x; + } + + /* + * Reduce x, computing z, i0, and k. The low bits of x + redux + * contain the 16-bit integer part of the exponent (k) followed by + * TBLBITS fractional bits (i0). We use bit tricks to extract these + * as integers, then set z to the remainder. + * + * Example: Suppose x is 0xabc.123456p0 and TBLBITS is 8. + * Then the low-order word of x + redux is 0x000abc12, + * We split this into k = 0xabc and i0 = 0x12 (adjusted to + * index into the table), then we compute z = 0x0.003456p0. + */ + u.f = x + redux; + i0 = u.i2.lo + TBLSIZE / 2; + k.u = i0 / TBLSIZE * TBLSIZE; + k.i /= TBLSIZE; + i0 %= TBLSIZE; + u.f -= redux; + z = x - u.f; + + /* Compute r = exp2(y) = exp2t[i0] * p(z - eps[i]). */ + t = tbl[i0]; + z -= eps[i0]; + r = t + t * z * (P1 + z * (P2 + z * (P3 + z * (P4 + z * (P5 + z * (P6 + + z * (P7 + z * (P8 + z * (P9 + z * P10))))))))); + + return scalbnl(r, k.i); +} +#endif diff --git a/lib/mlibc/options/ansi/musl-generic-math/expf.c b/lib/mlibc/options/ansi/musl-generic-math/expf.c new file mode 100644 index 0000000..feee2b0 --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/expf.c @@ -0,0 +1,83 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_expf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "libm.h" + +static const float +half[2] = {0.5,-0.5}, +ln2hi = 6.9314575195e-1f, /* 0x3f317200 */ +ln2lo = 1.4286067653e-6f, /* 0x35bfbe8e */ +invln2 = 1.4426950216e+0f, /* 0x3fb8aa3b */ +/* + * Domain [-0.34568, 0.34568], range ~[-4.278e-9, 4.447e-9]: + * |x*(exp(x)+1)/(exp(x)-1) - p(x)| < 2**-27.74 + */ +P1 = 1.6666625440e-1f, /* 0xaaaa8f.0p-26 */ +P2 = -2.7667332906e-3f; /* -0xb55215.0p-32 */ + +float expf(float x) +{ + float_t hi, lo, c, xx, y; + int k, sign; + uint32_t hx; + + GET_FLOAT_WORD(hx, x); + sign = hx >> 31; /* sign bit of x */ + hx &= 0x7fffffff; /* high word of |x| */ + + /* special cases */ + if (hx >= 0x42aeac50) { /* if |x| >= -87.33655f or NaN */ + if (hx > 0x7f800000) /* NaN */ + return x; + if (hx >= 0x42b17218 && !sign) { /* x >= 88.722839f */ + /* overflow */ + x *= 0x1p127f; + return x; + } + if (sign) { + /* underflow */ + FORCE_EVAL(-0x1p-149f/x); + if (hx >= 0x42cff1b5) /* x <= -103.972084f */ + return 0; + } + } + + /* argument reduction */ + if (hx > 0x3eb17218) { /* if |x| > 0.5 ln2 */ + if (hx > 0x3f851592) /* if |x| > 1.5 ln2 */ + k = invln2*x + half[sign]; + else + k = 1 - sign - sign; + hi = x - k*ln2hi; /* k*ln2hi is exact here */ + lo = k*ln2lo; + x = hi - lo; + } else if (hx > 0x39000000) { /* |x| > 2**-14 */ + k = 0; + hi = x; + lo = 0; + } else { + /* raise inexact */ + FORCE_EVAL(0x1p127f + x); + return 1 + x; + } + + /* x is now in primary range */ + xx = x*x; + c = x - xx*(P1+xx*P2); + y = 1 + (x*c/(2-c) - lo + hi); + if (k == 0) + return y; + return scalbnf(y, k); +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/expl.c b/lib/mlibc/options/ansi/musl-generic-math/expl.c new file mode 100644 index 0000000..0a7f44f --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/expl.c @@ -0,0 +1,128 @@ +/* origin: OpenBSD /usr/src/lib/libm/src/ld80/e_expl.c */ +/* + * Copyright (c) 2008 Stephen L. Moshier + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/* + * Exponential function, long double precision + * + * + * SYNOPSIS: + * + * long double x, y, expl(); + * + * y = expl( x ); + * + * + * DESCRIPTION: + * + * Returns e (2.71828...) raised to the x power. + * + * Range reduction is accomplished by separating the argument + * into an integer k and fraction f such that + * + * x k f + * e = 2 e. + * + * A Pade' form of degree 5/6 is used to approximate exp(f) - 1 + * in the basic range [-0.5 ln 2, 0.5 ln 2]. + * + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * IEEE +-10000 50000 1.12e-19 2.81e-20 + * + * + * Error amplification in the exponential function can be + * a serious matter. The error propagation involves + * exp( X(1+delta) ) = exp(X) ( 1 + X*delta + ... ), + * which shows that a 1 lsb error in representing X produces + * a relative error of X times 1 lsb in the function. + * While the routine gives an accurate result for arguments + * that are exactly represented by a long double precision + * computer number, the result contains amplified roundoff + * error for large arguments not exactly represented. + * + * + * ERROR MESSAGES: + * + * message condition value returned + * exp underflow x < MINLOG 0.0 + * exp overflow x > MAXLOG MAXNUM + * + */ + +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double expl(long double x) +{ + return exp(x); +} +#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 + +static const long double P[3] = { + 1.2617719307481059087798E-4L, + 3.0299440770744196129956E-2L, + 9.9999999999999999991025E-1L, +}; +static const long double Q[4] = { + 3.0019850513866445504159E-6L, + 2.5244834034968410419224E-3L, + 2.2726554820815502876593E-1L, + 2.0000000000000000000897E0L, +}; +static const long double +LN2HI = 6.9314575195312500000000E-1L, +LN2LO = 1.4286068203094172321215E-6L, +LOG2E = 1.4426950408889634073599E0L; + +long double expl(long double x) +{ + long double px, xx; + int k; + + if (isnan(x)) + return x; + if (x > 11356.5234062941439488L) /* x > ln(2^16384 - 0.5) */ + return x * 0x1p16383L; + if (x < -11399.4985314888605581L) /* x < ln(2^-16446) */ + return -0x1p-16445L/x; + + /* Express e**x = e**f 2**k + * = e**(f + k ln(2)) + */ + px = floorl(LOG2E * x + 0.5); + k = px; + x -= px * LN2HI; + x -= px * LN2LO; + + /* rational approximation of the fractional part: + * e**x = 1 + 2x P(x**2)/(Q(x**2) - x P(x**2)) + */ + xx = x * x; + px = x * __polevll(xx, P, 2); + x = px/(__polevll(xx, Q, 3) - px); + x = 1.0 + 2.0 * x; + return scalbnl(x, k); +} +#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 +// TODO: broken implementation to make things compile +long double expl(long double x) +{ + return exp(x); +} +#endif diff --git a/lib/mlibc/options/ansi/musl-generic-math/expm1.c b/lib/mlibc/options/ansi/musl-generic-math/expm1.c new file mode 100644 index 0000000..ac1e61e --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/expm1.c @@ -0,0 +1,201 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_expm1.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* expm1(x) + * Returns exp(x)-1, the exponential of x minus 1. + * + * Method + * 1. Argument reduction: + * Given x, find r and integer k such that + * + * x = k*ln2 + r, |r| <= 0.5*ln2 ~ 0.34658 + * + * Here a correction term c will be computed to compensate + * the error in r when rounded to a floating-point number. + * + * 2. Approximating expm1(r) by a special rational function on + * the interval [0,0.34658]: + * Since + * r*(exp(r)+1)/(exp(r)-1) = 2+ r^2/6 - r^4/360 + ... + * we define R1(r*r) by + * r*(exp(r)+1)/(exp(r)-1) = 2+ r^2/6 * R1(r*r) + * That is, + * R1(r**2) = 6/r *((exp(r)+1)/(exp(r)-1) - 2/r) + * = 6/r * ( 1 + 2.0*(1/(exp(r)-1) - 1/r)) + * = 1 - r^2/60 + r^4/2520 - r^6/100800 + ... + * We use a special Remez algorithm on [0,0.347] to generate + * a polynomial of degree 5 in r*r to approximate R1. The + * maximum error of this polynomial approximation is bounded + * by 2**-61. In other words, + * R1(z) ~ 1.0 + Q1*z + Q2*z**2 + Q3*z**3 + Q4*z**4 + Q5*z**5 + * where Q1 = -1.6666666666666567384E-2, + * Q2 = 3.9682539681370365873E-4, + * Q3 = -9.9206344733435987357E-6, + * Q4 = 2.5051361420808517002E-7, + * Q5 = -6.2843505682382617102E-9; + * z = r*r, + * with error bounded by + * | 5 | -61 + * | 1.0+Q1*z+...+Q5*z - R1(z) | <= 2 + * | | + * + * expm1(r) = exp(r)-1 is then computed by the following + * specific way which minimize the accumulation rounding error: + * 2 3 + * r r [ 3 - (R1 + R1*r/2) ] + * expm1(r) = r + --- + --- * [--------------------] + * 2 2 [ 6 - r*(3 - R1*r/2) ] + * + * To compensate the error in the argument reduction, we use + * expm1(r+c) = expm1(r) + c + expm1(r)*c + * ~ expm1(r) + c + r*c + * Thus c+r*c will be added in as the correction terms for + * expm1(r+c). Now rearrange the term to avoid optimization + * screw up: + * ( 2 2 ) + * ({ ( r [ R1 - (3 - R1*r/2) ] ) } r ) + * expm1(r+c)~r - ({r*(--- * [--------------------]-c)-c} - --- ) + * ({ ( 2 [ 6 - r*(3 - R1*r/2) ] ) } 2 ) + * ( ) + * + * = r - E + * 3. Scale back to obtain expm1(x): + * From step 1, we have + * expm1(x) = either 2^k*[expm1(r)+1] - 1 + * = or 2^k*[expm1(r) + (1-2^-k)] + * 4. Implementation notes: + * (A). To save one multiplication, we scale the coefficient Qi + * to Qi*2^i, and replace z by (x^2)/2. + * (B). To achieve maximum accuracy, we compute expm1(x) by + * (i) if x < -56*ln2, return -1.0, (raise inexact if x!=inf) + * (ii) if k=0, return r-E + * (iii) if k=-1, return 0.5*(r-E)-0.5 + * (iv) if k=1 if r < -0.25, return 2*((r+0.5)- E) + * else return 1.0+2.0*(r-E); + * (v) if (k<-2||k>56) return 2^k(1-(E-r)) - 1 (or exp(x)-1) + * (vi) if k <= 20, return 2^k((1-2^-k)-(E-r)), else + * (vii) return 2^k(1-((E+2^-k)-r)) + * + * Special cases: + * expm1(INF) is INF, expm1(NaN) is NaN; + * expm1(-INF) is -1, and + * for finite argument, only expm1(0)=0 is exact. + * + * Accuracy: + * according to an error analysis, the error is always less than + * 1 ulp (unit in the last place). + * + * Misc. info. + * For IEEE double + * if x > 7.09782712893383973096e+02 then expm1(x) overflow + * + * Constants: + * The hexadecimal values are the intended ones for the following + * constants. The decimal values may be used, provided that the + * compiler will convert from decimal to binary accurately enough + * to produce the hexadecimal values shown. + */ + +#include "libm.h" + +static const double +o_threshold = 7.09782712893383973096e+02, /* 0x40862E42, 0xFEFA39EF */ +ln2_hi = 6.93147180369123816490e-01, /* 0x3fe62e42, 0xfee00000 */ +ln2_lo = 1.90821492927058770002e-10, /* 0x3dea39ef, 0x35793c76 */ +invln2 = 1.44269504088896338700e+00, /* 0x3ff71547, 0x652b82fe */ +/* Scaled Q's: Qn_here = 2**n * Qn_above, for R(2*z) where z = hxs = x*x/2: */ +Q1 = -3.33333333333331316428e-02, /* BFA11111 111110F4 */ +Q2 = 1.58730158725481460165e-03, /* 3F5A01A0 19FE5585 */ +Q3 = -7.93650757867487942473e-05, /* BF14CE19 9EAADBB7 */ +Q4 = 4.00821782732936239552e-06, /* 3ED0CFCA 86E65239 */ +Q5 = -2.01099218183624371326e-07; /* BE8AFDB7 6E09C32D */ + +double expm1(double x) +{ + double_t y,hi,lo,c,t,e,hxs,hfx,r1,twopk; + union {double f; uint64_t i;} u = {x}; + uint32_t hx = u.i>>32 & 0x7fffffff; + int k, sign = u.i>>63; + + /* filter out huge and non-finite argument */ + if (hx >= 0x4043687A) { /* if |x|>=56*ln2 */ + if (isnan(x)) + return x; + if (sign) + return -1; + if (x > o_threshold) { + x *= 0x1p1023; + return x; + } + } + + /* argument reduction */ + if (hx > 0x3fd62e42) { /* if |x| > 0.5 ln2 */ + if (hx < 0x3FF0A2B2) { /* and |x| < 1.5 ln2 */ + if (!sign) { + hi = x - ln2_hi; + lo = ln2_lo; + k = 1; + } else { + hi = x + ln2_hi; + lo = -ln2_lo; + k = -1; + } + } else { + k = invln2*x + (sign ? -0.5 : 0.5); + t = k; + hi = x - t*ln2_hi; /* t*ln2_hi is exact here */ + lo = t*ln2_lo; + } + x = hi-lo; + c = (hi-x)-lo; + } else if (hx < 0x3c900000) { /* |x| < 2**-54, return x */ + if (hx < 0x00100000) + FORCE_EVAL((float)x); + return x; + } else + k = 0; + + /* x is now in primary range */ + hfx = 0.5*x; + hxs = x*hfx; + r1 = 1.0+hxs*(Q1+hxs*(Q2+hxs*(Q3+hxs*(Q4+hxs*Q5)))); + t = 3.0-r1*hfx; + e = hxs*((r1-t)/(6.0 - x*t)); + if (k == 0) /* c is 0 */ + return x - (x*e-hxs); + e = x*(e-c) - c; + e -= hxs; + /* exp(x) ~ 2^k (x_reduced - e + 1) */ + if (k == -1) + return 0.5*(x-e) - 0.5; + if (k == 1) { + if (x < -0.25) + return -2.0*(e-(x+0.5)); + return 1.0+2.0*(x-e); + } + u.i = (uint64_t)(0x3ff + k)<<52; /* 2^k */ + twopk = u.f; + if (k < 0 || k > 56) { /* suffice to return exp(x)-1 */ + y = x - e + 1.0; + if (k == 1024) + y = y*2.0*0x1p1023; + else + y = y*twopk; + return y - 1.0; + } + u.i = (uint64_t)(0x3ff - k)<<52; /* 2^-k */ + if (k < 20) + y = (x-e+(1-u.f))*twopk; + else + y = (x-(e+u.f)+1)*twopk; + return y; +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/expm1f.c b/lib/mlibc/options/ansi/musl-generic-math/expm1f.c new file mode 100644 index 0000000..297e0b4 --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/expm1f.c @@ -0,0 +1,111 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_expm1f.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "libm.h" + +static const float +o_threshold = 8.8721679688e+01, /* 0x42b17180 */ +ln2_hi = 6.9313812256e-01, /* 0x3f317180 */ +ln2_lo = 9.0580006145e-06, /* 0x3717f7d1 */ +invln2 = 1.4426950216e+00, /* 0x3fb8aa3b */ +/* + * Domain [-0.34568, 0.34568], range ~[-6.694e-10, 6.696e-10]: + * |6 / x * (1 + 2 * (1 / (exp(x) - 1) - 1 / x)) - q(x)| < 2**-30.04 + * Scaled coefficients: Qn_here = 2**n * Qn_for_q (see s_expm1.c): + */ +Q1 = -3.3333212137e-2, /* -0x888868.0p-28 */ +Q2 = 1.5807170421e-3; /* 0xcf3010.0p-33 */ + +float expm1f(float x) +{ + float_t y,hi,lo,c,t,e,hxs,hfx,r1,twopk; + union {float f; uint32_t i;} u = {x}; + uint32_t hx = u.i & 0x7fffffff; + int k, sign = u.i >> 31; + + /* filter out huge and non-finite argument */ + if (hx >= 0x4195b844) { /* if |x|>=27*ln2 */ + if (hx > 0x7f800000) /* NaN */ + return x; + if (sign) + return -1; + if (x > o_threshold) { + x *= 0x1p127f; + return x; + } + } + + /* argument reduction */ + if (hx > 0x3eb17218) { /* if |x| > 0.5 ln2 */ + if (hx < 0x3F851592) { /* and |x| < 1.5 ln2 */ + if (!sign) { + hi = x - ln2_hi; + lo = ln2_lo; + k = 1; + } else { + hi = x + ln2_hi; + lo = -ln2_lo; + k = -1; + } + } else { + k = invln2*x + (sign ? -0.5f : 0.5f); + t = k; + hi = x - t*ln2_hi; /* t*ln2_hi is exact here */ + lo = t*ln2_lo; + } + x = hi-lo; + c = (hi-x)-lo; + } else if (hx < 0x33000000) { /* when |x|<2**-25, return x */ + if (hx < 0x00800000) + FORCE_EVAL(x*x); + return x; + } else + k = 0; + + /* x is now in primary range */ + hfx = 0.5f*x; + hxs = x*hfx; + r1 = 1.0f+hxs*(Q1+hxs*Q2); + t = 3.0f - r1*hfx; + e = hxs*((r1-t)/(6.0f - x*t)); + if (k == 0) /* c is 0 */ + return x - (x*e-hxs); + e = x*(e-c) - c; + e -= hxs; + /* exp(x) ~ 2^k (x_reduced - e + 1) */ + if (k == -1) + return 0.5f*(x-e) - 0.5f; + if (k == 1) { + if (x < -0.25f) + return -2.0f*(e-(x+0.5f)); + return 1.0f + 2.0f*(x-e); + } + u.i = (0x7f+k)<<23; /* 2^k */ + twopk = u.f; + if (k < 0 || k > 56) { /* suffice to return exp(x)-1 */ + y = x - e + 1.0f; + if (k == 128) + y = y*2.0f*0x1p127f; + else + y = y*twopk; + return y - 1.0f; + } + u.i = (0x7f-k)<<23; /* 2^-k */ + if (k < 23) + y = (x-e+(1-u.f))*twopk; + else + y = (x-(e+u.f)+1)*twopk; + return y; +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/expm1l.c b/lib/mlibc/options/ansi/musl-generic-math/expm1l.c new file mode 100644 index 0000000..d171507 --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/expm1l.c @@ -0,0 +1,123 @@ +/* origin: OpenBSD /usr/src/lib/libm/src/ld80/e_expm1l.c */ +/* + * Copyright (c) 2008 Stephen L. Moshier + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/* + * Exponential function, minus 1 + * Long double precision + * + * + * SYNOPSIS: + * + * long double x, y, expm1l(); + * + * y = expm1l( x ); + * + * + * DESCRIPTION: + * + * Returns e (2.71828...) raised to the x power, minus 1. + * + * Range reduction is accomplished by separating the argument + * into an integer k and fraction f such that + * + * x k f + * e = 2 e. + * + * An expansion x + .5 x^2 + x^3 R(x) approximates exp(f) - 1 + * in the basic range [-0.5 ln 2, 0.5 ln 2]. + * + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * IEEE -45,+maxarg 200,000 1.2e-19 2.5e-20 + */ + +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double expm1l(long double x) +{ + return expm1(x); +} +#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 + +/* exp(x) - 1 = x + 0.5 x^2 + x^3 P(x)/Q(x) + -.5 ln 2 < x < .5 ln 2 + Theoretical peak relative error = 3.4e-22 */ +static const long double +P0 = -1.586135578666346600772998894928250240826E4L, +P1 = 2.642771505685952966904660652518429479531E3L, +P2 = -3.423199068835684263987132888286791620673E2L, +P3 = 1.800826371455042224581246202420972737840E1L, +P4 = -5.238523121205561042771939008061958820811E-1L, +Q0 = -9.516813471998079611319047060563358064497E4L, +Q1 = 3.964866271411091674556850458227710004570E4L, +Q2 = -7.207678383830091850230366618190187434796E3L, +Q3 = 7.206038318724600171970199625081491823079E2L, +Q4 = -4.002027679107076077238836622982900945173E1L, +/* Q5 = 1.000000000000000000000000000000000000000E0 */ +/* C1 + C2 = ln 2 */ +C1 = 6.93145751953125E-1L, +C2 = 1.428606820309417232121458176568075500134E-6L, +/* ln 2^-65 */ +minarg = -4.5054566736396445112120088E1L, +/* ln 2^16384 */ +maxarg = 1.1356523406294143949492E4L; + +long double expm1l(long double x) +{ + long double px, qx, xx; + int k; + + if (isnan(x)) + return x; + if (x > maxarg) + return x*0x1p16383L; /* overflow, unless x==inf */ + if (x == 0.0) + return x; + if (x < minarg) + return -1.0; + + xx = C1 + C2; + /* Express x = ln 2 (k + remainder), remainder not exceeding 1/2. */ + px = floorl(0.5 + x / xx); + k = px; + /* remainder times ln 2 */ + x -= px * C1; + x -= px * C2; + + /* Approximate exp(remainder ln 2).*/ + px = (((( P4 * x + P3) * x + P2) * x + P1) * x + P0) * x; + qx = (((( x + Q4) * x + Q3) * x + Q2) * x + Q1) * x + Q0; + xx = x * x; + qx = x + (0.5 * xx + xx * px / qx); + + /* exp(x) = exp(k ln 2) exp(remainder ln 2) = 2^k exp(remainder ln 2). + We have qx = exp(remainder ln 2) - 1, so + exp(x) - 1 = 2^k (qx + 1) - 1 = 2^k qx + 2^k - 1. */ + px = scalbnl(1.0, k); + x = px * qx + (px - 1.0); + return x; +} +#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 +// TODO: broken implementation to make things compile +long double expm1l(long double x) +{ + return expm1(x); +} +#endif diff --git a/lib/mlibc/options/ansi/musl-generic-math/fabs.c b/lib/mlibc/options/ansi/musl-generic-math/fabs.c new file mode 100644 index 0000000..e8258cf --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/fabs.c @@ -0,0 +1,9 @@ +#include +#include + +double fabs(double x) +{ + union {double f; uint64_t i;} u = {x}; + u.i &= -1ULL/2; + return u.f; +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/fabsf.c b/lib/mlibc/options/ansi/musl-generic-math/fabsf.c new file mode 100644 index 0000000..4efc8d6 --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/fabsf.c @@ -0,0 +1,9 @@ +#include +#include + +float fabsf(float x) +{ + union {float f; uint32_t i;} u = {x}; + u.i &= 0x7fffffff; + return u.f; +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/fabsl.c b/lib/mlibc/options/ansi/musl-generic-math/fabsl.c new file mode 100644 index 0000000..c4f36ec --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/fabsl.c @@ -0,0 +1,15 @@ +#include "libm.h" +#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 diff --git a/lib/mlibc/options/ansi/musl-generic-math/fdim.c b/lib/mlibc/options/ansi/musl-generic-math/fdim.c new file mode 100644 index 0000000..9585460 --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/fdim.c @@ -0,0 +1,10 @@ +#include + +double fdim(double x, double y) +{ + if (isnan(x)) + return x; + if (isnan(y)) + return y; + return x > y ? x - y : 0; +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/fdimf.c b/lib/mlibc/options/ansi/musl-generic-math/fdimf.c new file mode 100644 index 0000000..543c364 --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/fdimf.c @@ -0,0 +1,10 @@ +#include + +float fdimf(float x, float y) +{ + if (isnan(x)) + return x; + if (isnan(y)) + return y; + return x > y ? x - y : 0; +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/fdiml.c b/lib/mlibc/options/ansi/musl-generic-math/fdiml.c new file mode 100644 index 0000000..62e29b7 --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/fdiml.c @@ -0,0 +1,18 @@ +#include +#include + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double fdiml(long double x, long double y) +{ + return fdim(x, y); +} +#else +long double fdiml(long double x, long double y) +{ + if (isnan(x)) + return x; + if (isnan(y)) + return y; + return x > y ? x - y : 0; +} +#endif diff --git a/lib/mlibc/options/ansi/musl-generic-math/finite.c b/lib/mlibc/options/ansi/musl-generic-math/finite.c new file mode 100644 index 0000000..25a0575 --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/finite.c @@ -0,0 +1,7 @@ +#define _GNU_SOURCE +#include + +int finite(double x) +{ + return isfinite(x); +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/finitef.c b/lib/mlibc/options/ansi/musl-generic-math/finitef.c new file mode 100644 index 0000000..2c4c771 --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/finitef.c @@ -0,0 +1,7 @@ +#define _GNU_SOURCE +#include + +int finitef(float x) +{ + return isfinite(x); +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/floor.c b/lib/mlibc/options/ansi/musl-generic-math/floor.c new file mode 100644 index 0000000..14a31cd --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/floor.c @@ -0,0 +1,31 @@ +#include "libm.h" + +#if FLT_EVAL_METHOD==0 || FLT_EVAL_METHOD==1 +#define EPS DBL_EPSILON +#elif FLT_EVAL_METHOD==2 +#define EPS LDBL_EPSILON +#endif +static const double_t toint = 1/EPS; + +double floor(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; + /* 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; +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/floorf.c b/lib/mlibc/options/ansi/musl-generic-math/floorf.c new file mode 100644 index 0000000..dceec73 --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/floorf.c @@ -0,0 +1,27 @@ +#include "libm.h" + +float floorf(float x) +{ + union {float f; uint32_t i;} u = {x}; + int e = (int)(u.i >> 23 & 0xff) - 0x7f; + uint32_t m; + + if (e >= 23) + return x; + if (e >= 0) { + m = 0x007fffff >> e; + if ((u.i & m) == 0) + return x; + FORCE_EVAL(x + 0x1p120f); + if (u.i >> 31) + u.i += m; + u.i &= ~m; + } else { + FORCE_EVAL(x + 0x1p120f); + if (u.i >> 31 == 0) + u.i = 0; + else if (u.i << 1) + u.f = -1.0; + } + return u.f; +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/floorl.c b/lib/mlibc/options/ansi/musl-generic-math/floorl.c new file mode 100644 index 0000000..16aaec4 --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/floorl.c @@ -0,0 +1,34 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double floorl(long double x) +{ + return floor(x); +} +#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 + +static const long double toint = 1/LDBL_EPSILON; + +long double floorl(long double x) +{ + union ldshape u = {x}; + int e = u.i.se & 0x7fff; + long double y; + + if (e >= 0x3fff+LDBL_MANT_DIG-1 || x == 0) + return x; + /* y = int(x) - x, where int(x) is an integer neighbor of x */ + if (u.i.se >> 15) + y = x - toint + toint - x; + else + y = x + toint - toint - x; + /* special case because of non-nearest rounding modes */ + if (e <= 0x3fff-1) { + FORCE_EVAL(y); + return u.i.se >> 15 ? -1 : 0; + } + if (y > 0) + return x + y - 1; + return x + y; +} +#endif diff --git a/lib/mlibc/options/ansi/musl-generic-math/fma.c b/lib/mlibc/options/ansi/musl-generic-math/fma.c new file mode 100644 index 0000000..f65eab7 --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/fma.c @@ -0,0 +1,194 @@ +#include +#include +#include + +static inline int a_clz_64(uint64_t x) +{ + uint32_t y; + int r; + if (x>>32) y=x>>32, r=0; else y=x, r=32; + if (y>>16) y>>=16; else r |= 16; + if (y>>8) y>>=8; else r |= 8; + if (y>>4) y>>=4; else r |= 4; + if (y>>2) y>>=2; else r |= 2; + return r | !(y>>1); +} + +#define ASUINT64(x) ((union {double f; uint64_t i;}){x}).i +#define ZEROINFNAN (0x7ff-0x3ff-52-1) + +struct num { uint64_t m; int e; int sign; }; + +static struct num normalize(double x) +{ + uint64_t ix = ASUINT64(x); + int e = ix>>52; + int sign = e & 0x800; + e &= 0x7ff; + if (!e) { + ix = ASUINT64(x*0x1p63); + e = ix>>52 & 0x7ff; + e = e ? e-63 : 0x800; + } + ix &= (1ull<<52)-1; + ix |= 1ull<<52; + ix <<= 1; + e -= 0x3ff + 52 + 1; + return (struct num){ix,e,sign}; +} + +static void mul(uint64_t *hi, uint64_t *lo, uint64_t x, uint64_t y) +{ + uint64_t t1,t2,t3; + uint64_t xlo = (uint32_t)x, xhi = x>>32; + uint64_t ylo = (uint32_t)y, yhi = y>>32; + + t1 = xlo*ylo; + t2 = xlo*yhi + xhi*ylo; + t3 = xhi*yhi; + *lo = t1 + (t2<<32); + *hi = t3 + (t2>>32) + (t1 > *lo); +} + +double fma(double x, double y, double z) +{ + #pragma STDC FENV_ACCESS ON + + /* normalize so top 10bits and last bit are 0 */ + struct num nx, ny, nz; + nx = normalize(x); + ny = normalize(y); + nz = normalize(z); + + if (nx.e >= ZEROINFNAN || ny.e >= ZEROINFNAN) + return x*y + z; + if (nz.e >= ZEROINFNAN) { + if (nz.e > ZEROINFNAN) /* z==0 */ + return x*y + z; + return z; + } + + /* mul: r = x*y */ + uint64_t rhi, rlo, zhi, zlo; + mul(&rhi, &rlo, nx.m, ny.m); + /* either top 20 or 21 bits of rhi and last 2 bits of rlo are 0 */ + + /* align exponents */ + int e = nx.e + ny.e; + int d = nz.e - e; + /* shift bits z<<=kz, r>>=kr, so kz+kr == d, set e = e+kr (== ez-kz) */ + if (d > 0) { + if (d < 64) { + zlo = nz.m<>64-d; + } else { + zlo = 0; + zhi = nz.m; + e = nz.e - 64; + d -= 64; + if (d == 0) { + } else if (d < 64) { + rlo = rhi<<64-d | rlo>>d | !!(rlo<<64-d); + rhi = rhi>>d; + } else { + rlo = 1; + rhi = 0; + } + } + } else { + zhi = 0; + d = -d; + if (d == 0) { + zlo = nz.m; + } else if (d < 64) { + zlo = nz.m>>d | !!(nz.m<<64-d); + } else { + zlo = 1; + } + } + + /* add */ + int sign = nx.sign^ny.sign; + int samesign = !(sign^nz.sign); + int nonzero = 1; + if (samesign) { + /* r += z */ + rlo += zlo; + rhi += zhi + (rlo < zlo); + } else { + /* r -= z */ + uint64_t t = rlo; + rlo -= zlo; + rhi = rhi - zhi - (t < rlo); + if (rhi>>63) { + rlo = -rlo; + rhi = -rhi-!!rlo; + sign = !sign; + } + nonzero = !!rhi; + } + + /* set rhi to top 63bit of the result (last bit is sticky) */ + if (nonzero) { + e += 64; + d = a_clz_64(rhi)-1; + /* note: d > 0 */ + rhi = rhi<>64-d | !!(rlo<>1 | (rlo&1); + else + rhi = rlo<>1 | (rhi&1) | 1ull<<62; + if (sign) + i = -i; + r = i; + r = 2*r - c; /* remove top bit */ + + /* raise underflow portably, such that it + cannot be optimized away */ + { + double_t tiny = DBL_MIN/FLT_MIN * r; + r += (double)(tiny*tiny) * (r-r); + } + } + } else { + /* only round once when scaled */ + d = 10; + i = ( rhi>>d | !!(rhi<<64-d) ) << d; + if (sign) + i = -i; + r = i; + } + } + return scalbn(r, e); +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/fmaf.c b/lib/mlibc/options/ansi/musl-generic-math/fmaf.c new file mode 100644 index 0000000..aa57feb --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/fmaf.c @@ -0,0 +1,93 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_fmaf.c */ +/*- + * Copyright (c) 2005-2011 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include + +/* + * Fused multiply-add: Compute x * y + z with a single rounding error. + * + * A double has more than twice as much precision than a float, so + * direct double-precision arithmetic suffices, except where double + * rounding occurs. + */ +float fmaf(float x, float y, float z) +{ + #pragma STDC FENV_ACCESS ON + double xy, result; + union {double f; uint64_t i;} u; + int e; + + xy = (double)x * y; + result = xy + z; + u.f = result; + e = u.i>>52 & 0x7ff; + /* Common case: The double precision result is fine. */ + if ((u.i & 0x1fffffff) != 0x10000000 || /* not a halfway case */ + e == 0x7ff || /* NaN */ + result - xy == z || /* exact */ + fegetround() != FE_TONEAREST) /* not round-to-nearest */ + { + /* + underflow may not be raised correctly, example: + fmaf(0x1p-120f, 0x1p-120f, 0x1p-149f) + */ +#if defined(FE_INEXACT) && defined(FE_UNDERFLOW) + if (e < 0x3ff-126 && e >= 0x3ff-149 && fetestexcept(FE_INEXACT)) { + feclearexcept(FE_INEXACT); + /* TODO: gcc and clang bug workaround */ + volatile float vz = z; + result = xy + vz; + if (fetestexcept(FE_INEXACT)) + feraiseexcept(FE_UNDERFLOW); + else + feraiseexcept(FE_INEXACT); + } +#endif + z = result; + return z; + } + + /* + * If result is inexact, and exactly halfway between two float values, + * we need to adjust the low-order bit in the direction of the error. + */ +#ifdef FE_TOWARDZERO + fesetround(FE_TOWARDZERO); +#endif + volatile double vxy = xy; /* XXX work around gcc CSE bug */ + double adjusted_result = vxy + z; + fesetround(FE_TONEAREST); + if (result == adjusted_result) { + u.f = adjusted_result; + u.i++; + adjusted_result = u.f; + } + z = adjusted_result; + return z; +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/fmal.c b/lib/mlibc/options/ansi/musl-generic-math/fmal.c new file mode 100644 index 0000000..4506aac --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/fmal.c @@ -0,0 +1,293 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_fmal.c */ +/*- + * Copyright (c) 2005-2011 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + + +#include "libm.h" +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double fmal(long double x, long double y, long double z) +{ + return fma(x, y, z); +} +#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 +#include +#if LDBL_MANT_DIG == 64 +#define LASTBIT(u) (u.i.m & 1) +#define SPLIT (0x1p32L + 1) +#elif LDBL_MANT_DIG == 113 +#define LASTBIT(u) (u.i.lo & 1) +#define SPLIT (0x1p57L + 1) +#endif + +/* + * A struct dd represents a floating-point number with twice the precision + * of a long double. We maintain the invariant that "hi" stores the high-order + * bits of the result. + */ +struct dd { + long double hi; + long double lo; +}; + +/* + * Compute a+b exactly, returning the exact result in a struct dd. We assume + * that both a and b are finite, but make no assumptions about their relative + * magnitudes. + */ +static inline struct dd dd_add(long double a, long double b) +{ + struct dd ret; + long double s; + + ret.hi = a + b; + s = ret.hi - a; + ret.lo = (a - (ret.hi - s)) + (b - s); + return (ret); +} + +/* + * Compute a+b, with a small tweak: The least significant bit of the + * result is adjusted into a sticky bit summarizing all the bits that + * were lost to rounding. This adjustment negates the effects of double + * rounding when the result is added to another number with a higher + * exponent. For an explanation of round and sticky bits, see any reference + * on FPU design, e.g., + * + * J. Coonen. An Implementation Guide to a Proposed Standard for + * Floating-Point Arithmetic. Computer, vol. 13, no. 1, Jan 1980. + */ +static inline long double add_adjusted(long double a, long double b) +{ + struct dd sum; + union ldshape u; + + sum = dd_add(a, b); + if (sum.lo != 0) { + u.f = sum.hi; + if (!LASTBIT(u)) + sum.hi = nextafterl(sum.hi, INFINITY * sum.lo); + } + return (sum.hi); +} + +/* + * Compute ldexp(a+b, scale) with a single rounding error. It is assumed + * that the result will be subnormal, and care is taken to ensure that + * double rounding does not occur. + */ +static inline long double add_and_denormalize(long double a, long double b, int scale) +{ + struct dd sum; + int bits_lost; + union ldshape u; + + sum = dd_add(a, b); + + /* + * If we are losing at least two bits of accuracy to denormalization, + * then the first lost bit becomes a round bit, and we adjust the + * lowest bit of sum.hi to make it a sticky bit summarizing all the + * bits in sum.lo. With the sticky bit adjusted, the hardware will + * break any ties in the correct direction. + * + * If we are losing only one bit to denormalization, however, we must + * break the ties manually. + */ + if (sum.lo != 0) { + u.f = sum.hi; + bits_lost = -u.i.se - scale + 1; + if ((bits_lost != 1) ^ LASTBIT(u)) + sum.hi = nextafterl(sum.hi, INFINITY * sum.lo); + } + return scalbnl(sum.hi, scale); +} + +/* + * Compute a*b exactly, returning the exact result in a struct dd. We assume + * that both a and b are normalized, so no underflow or overflow will occur. + * The current rounding mode must be round-to-nearest. + */ +static inline struct dd dd_mul(long double a, long double b) +{ + struct dd ret; + long double ha, hb, la, lb, p, q; + + p = a * SPLIT; + ha = a - p; + ha += p; + la = a - ha; + + p = b * SPLIT; + hb = b - p; + hb += p; + lb = b - hb; + + p = ha * hb; + q = ha * lb + la * hb; + + ret.hi = p + q; + ret.lo = p - ret.hi + q + la * lb; + return (ret); +} + +/* + * Fused multiply-add: Compute x * y + z with a single rounding error. + * + * We use scaling to avoid overflow/underflow, along with the + * canonical precision-doubling technique adapted from: + * + * Dekker, T. A Floating-Point Technique for Extending the + * Available Precision. Numer. Math. 18, 224-242 (1971). + */ +long double fmal(long double x, long double y, long double z) +{ + #pragma STDC FENV_ACCESS ON + long double xs, ys, zs, adj; + struct dd xy, r; + int oround; + int ex, ey, ez; + int spread; + + /* + * Handle special cases. The order of operations and the particular + * return values here are crucial in handling special cases involving + * infinities, NaNs, overflows, and signed zeroes correctly. + */ + if (!isfinite(x) || !isfinite(y)) + return (x * y + z); + if (!isfinite(z)) + return (z); + if (x == 0.0 || y == 0.0) + return (x * y + z); + if (z == 0.0) + return (x * y); + + xs = frexpl(x, &ex); + ys = frexpl(y, &ey); + zs = frexpl(z, &ez); + oround = fegetround(); + spread = ex + ey - ez; + + /* + * If x * y and z are many orders of magnitude apart, the scaling + * will overflow, so we handle these cases specially. Rounding + * modes other than FE_TONEAREST are painful. + */ + if (spread < -LDBL_MANT_DIG) { +#ifdef FE_INEXACT + feraiseexcept(FE_INEXACT); +#endif +#ifdef FE_UNDERFLOW + if (!isnormal(z)) + feraiseexcept(FE_UNDERFLOW); +#endif + switch (oround) { + default: /* FE_TONEAREST */ + return (z); +#ifdef FE_TOWARDZERO + case FE_TOWARDZERO: + if (x > 0.0 ^ y < 0.0 ^ z < 0.0) + return (z); + else + return (nextafterl(z, 0)); +#endif +#ifdef FE_DOWNWARD + case FE_DOWNWARD: + if (x > 0.0 ^ y < 0.0) + return (z); + else + return (nextafterl(z, -INFINITY)); +#endif +#ifdef FE_UPWARD + case FE_UPWARD: + if (x > 0.0 ^ y < 0.0) + return (nextafterl(z, INFINITY)); + else + return (z); +#endif + } + } + if (spread <= LDBL_MANT_DIG * 2) + zs = scalbnl(zs, -spread); + else + zs = copysignl(LDBL_MIN, zs); + + fesetround(FE_TONEAREST); + + /* + * Basic approach for round-to-nearest: + * + * (xy.hi, xy.lo) = x * y (exact) + * (r.hi, r.lo) = xy.hi + z (exact) + * adj = xy.lo + r.lo (inexact; low bit is sticky) + * result = r.hi + adj (correctly rounded) + */ + xy = dd_mul(xs, ys); + r = dd_add(xy.hi, zs); + + spread = ex + ey; + + if (r.hi == 0.0) { + /* + * When the addends cancel to 0, ensure that the result has + * the correct sign. + */ + fesetround(oround); + volatile long double vzs = zs; /* XXX gcc CSE bug workaround */ + return xy.hi + vzs + scalbnl(xy.lo, spread); + } + + if (oround != FE_TONEAREST) { + /* + * There is no need to worry about double rounding in directed + * rounding modes. + * But underflow may not be raised correctly, example in downward rounding: + * fmal(0x1.0000000001p-16000L, 0x1.0000000001p-400L, -0x1p-16440L) + */ + long double ret; +#if defined(FE_INEXACT) && defined(FE_UNDERFLOW) + int e = fetestexcept(FE_INEXACT); + feclearexcept(FE_INEXACT); +#endif + fesetround(oround); + adj = r.lo + xy.lo; + ret = scalbnl(r.hi + adj, spread); +#if defined(FE_INEXACT) && defined(FE_UNDERFLOW) + if (ilogbl(ret) < -16382 && fetestexcept(FE_INEXACT)) + feraiseexcept(FE_UNDERFLOW); + else if (e) + feraiseexcept(FE_INEXACT); +#endif + return ret; + } + + adj = add_adjusted(r.lo, xy.lo); + if (spread + ilogbl(r.hi) > -16383) + return scalbnl(r.hi + adj, spread); + else + return add_and_denormalize(r.hi, adj, spread); +} +#endif diff --git a/lib/mlibc/options/ansi/musl-generic-math/fmax.c b/lib/mlibc/options/ansi/musl-generic-math/fmax.c new file mode 100644 index 0000000..94f0caa --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/fmax.c @@ -0,0 +1,13 @@ +#include + +double fmax(double x, double y) +{ + if (isnan(x)) + return y; + if (isnan(y)) + return x; + /* handle signed zeros, see C99 Annex F.9.9.2 */ + if (signbit(x) != signbit(y)) + return signbit(x) ? y : x; + return x < y ? y : x; +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/fmaxf.c b/lib/mlibc/options/ansi/musl-generic-math/fmaxf.c new file mode 100644 index 0000000..695d817 --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/fmaxf.c @@ -0,0 +1,13 @@ +#include + +float fmaxf(float x, float y) +{ + if (isnan(x)) + return y; + if (isnan(y)) + return x; + /* handle signed zeroes, see C99 Annex F.9.9.2 */ + if (signbit(x) != signbit(y)) + return signbit(x) ? y : x; + return x < y ? y : x; +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/fmaxl.c b/lib/mlibc/options/ansi/musl-generic-math/fmaxl.c new file mode 100644 index 0000000..4b03158 --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/fmaxl.c @@ -0,0 +1,21 @@ +#include +#include + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double fmaxl(long double x, long double y) +{ + return fmax(x, y); +} +#else +long double fmaxl(long double x, long double y) +{ + if (isnan(x)) + return y; + if (isnan(y)) + return x; + /* handle signed zeros, see C99 Annex F.9.9.2 */ + if (signbit(x) != signbit(y)) + return signbit(x) ? y : x; + return x < y ? y : x; +} +#endif diff --git a/lib/mlibc/options/ansi/musl-generic-math/fmin.c b/lib/mlibc/options/ansi/musl-generic-math/fmin.c new file mode 100644 index 0000000..08a8fd1 --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/fmin.c @@ -0,0 +1,13 @@ +#include + +double fmin(double x, double y) +{ + if (isnan(x)) + return y; + if (isnan(y)) + return x; + /* handle signed zeros, see C99 Annex F.9.9.2 */ + if (signbit(x) != signbit(y)) + return signbit(x) ? x : y; + return x < y ? x : y; +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/fminf.c b/lib/mlibc/options/ansi/musl-generic-math/fminf.c new file mode 100644 index 0000000..3573c7d --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/fminf.c @@ -0,0 +1,13 @@ +#include + +float fminf(float x, float y) +{ + if (isnan(x)) + return y; + if (isnan(y)) + return x; + /* handle signed zeros, see C99 Annex F.9.9.2 */ + if (signbit(x) != signbit(y)) + return signbit(x) ? x : y; + return x < y ? x : y; +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/fminl.c b/lib/mlibc/options/ansi/musl-generic-math/fminl.c new file mode 100644 index 0000000..69bc24a --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/fminl.c @@ -0,0 +1,21 @@ +#include +#include + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double fminl(long double x, long double y) +{ + return fmin(x, y); +} +#else +long double fminl(long double x, long double y) +{ + if (isnan(x)) + return y; + if (isnan(y)) + return x; + /* handle signed zeros, see C99 Annex F.9.9.2 */ + if (signbit(x) != signbit(y)) + return signbit(x) ? x : y; + return x < y ? x : y; +} +#endif diff --git a/lib/mlibc/options/ansi/musl-generic-math/fmod.c b/lib/mlibc/options/ansi/musl-generic-math/fmod.c new file mode 100644 index 0000000..6849722 --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/fmod.c @@ -0,0 +1,68 @@ +#include +#include + +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; +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/fmodf.c b/lib/mlibc/options/ansi/musl-generic-math/fmodf.c new file mode 100644 index 0000000..ff58f93 --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/fmodf.c @@ -0,0 +1,65 @@ +#include +#include + +float fmodf(float x, float y) +{ + union {float f; uint32_t i;} ux = {x}, uy = {y}; + int ex = ux.i>>23 & 0xff; + int ey = uy.i>>23 & 0xff; + uint32_t sx = ux.i & 0x80000000; + uint32_t i; + uint32_t uxi = ux.i; + + if (uy.i<<1 == 0 || isnan(y) || ex == 0xff) + 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<<9; i>>31 == 0; ex--, i <<= 1); + uxi <<= -ex + 1; + } else { + uxi &= -1U >> 9; + uxi |= 1U << 23; + } + if (!ey) { + for (i = uy.i<<9; i>>31 == 0; ey--, i <<= 1); + uy.i <<= -ey + 1; + } else { + uy.i &= -1U >> 9; + uy.i |= 1U << 23; + } + + /* x mod y */ + for (; ex > ey; ex--) { + i = uxi - uy.i; + if (i >> 31 == 0) { + if (i == 0) + return 0*x; + uxi = i; + } + uxi <<= 1; + } + i = uxi - uy.i; + if (i >> 31 == 0) { + if (i == 0) + return 0*x; + uxi = i; + } + for (; uxi>>23 == 0; uxi <<= 1, ex--); + + /* scale result up */ + if (ex > 0) { + uxi -= 1U << 23; + uxi |= (uint32_t)ex << 23; + } else { + uxi >>= -ex + 1; + } + uxi |= sx; + ux.i = uxi; + return ux.f; +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/fmodl.c b/lib/mlibc/options/ansi/musl-generic-math/fmodl.c new file mode 100644 index 0000000..9f5b873 --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/fmodl.c @@ -0,0 +1,105 @@ +#include "libm.h" + +#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 diff --git a/lib/mlibc/options/ansi/musl-generic-math/frexp.c b/lib/mlibc/options/ansi/musl-generic-math/frexp.c new file mode 100644 index 0000000..27b6266 --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/frexp.c @@ -0,0 +1,23 @@ +#include +#include + +double frexp(double x, int *e) +{ + union { double d; uint64_t i; } y = { x }; + int ee = y.i>>52 & 0x7ff; + + if (!ee) { + if (x) { + x = frexp(x*0x1p64, e); + *e -= 64; + } else *e = 0; + return x; + } else if (ee == 0x7ff) { + return x; + } + + *e = ee - 0x3fe; + y.i &= 0x800fffffffffffffull; + y.i |= 0x3fe0000000000000ull; + return y.d; +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/frexpf.c b/lib/mlibc/options/ansi/musl-generic-math/frexpf.c new file mode 100644 index 0000000..0787097 --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/frexpf.c @@ -0,0 +1,23 @@ +#include +#include + +float frexpf(float x, int *e) +{ + union { float f; uint32_t i; } y = { x }; + int ee = y.i>>23 & 0xff; + + if (!ee) { + if (x) { + x = frexpf(x*0x1p64, e); + *e -= 64; + } else *e = 0; + return x; + } else if (ee == 0xff) { + return x; + } + + *e = ee - 0x7e; + y.i &= 0x807ffffful; + y.i |= 0x3f000000ul; + return y.f; +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/frexpl.c b/lib/mlibc/options/ansi/musl-generic-math/frexpl.c new file mode 100644 index 0000000..3c1b553 --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/frexpl.c @@ -0,0 +1,29 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double frexpl(long double x, int *e) +{ + return frexp(x, e); +} +#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 +long double frexpl(long double x, int *e) +{ + union ldshape u = {x}; + int ee = u.i.se & 0x7fff; + + if (!ee) { + if (x) { + x = frexpl(x*0x1p120, e); + *e -= 120; + } else *e = 0; + return x; + } else if (ee == 0x7fff) { + return x; + } + + *e = ee - 0x3ffe; + u.i.se &= 0x8000; + u.i.se |= 0x3ffe; + return u.f; +} +#endif diff --git a/lib/mlibc/options/ansi/musl-generic-math/hypot.c b/lib/mlibc/options/ansi/musl-generic-math/hypot.c new file mode 100644 index 0000000..6071bf1 --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/hypot.c @@ -0,0 +1,67 @@ +#include +#include +#include + +#if FLT_EVAL_METHOD > 1U && LDBL_MANT_DIG == 64 +#define SPLIT (0x1p32 + 1) +#else +#define SPLIT (0x1p27 + 1) +#endif + +static void sq(double_t *hi, double_t *lo, double x) +{ + double_t xh, xl, xc; + + xc = (double_t)x*SPLIT; + xh = x - xc + xc; + xl = x - xh; + *hi = (double_t)x*x; + *lo = xh*xh - *hi + 2*xh*xl + xl*xl; +} + +double hypot(double x, double y) +{ + union {double f; uint64_t i;} ux = {x}, uy = {y}, ut; + int ex, ey; + double_t hx, lx, hy, ly, z; + + /* arrange |x| >= |y| */ + ux.i &= -1ULL>>1; + uy.i &= -1ULL>>1; + if (ux.i < uy.i) { + ut = ux; + ux = uy; + uy = ut; + } + + /* special cases */ + ex = ux.i>>52; + ey = uy.i>>52; + x = ux.f; + y = uy.f; + /* note: hypot(inf,nan) == inf */ + if (ey == 0x7ff) + return y; + if (ex == 0x7ff || uy.i == 0) + return x; + /* note: hypot(x,y) ~= x + y*y/x/2 with inexact for small y/x */ + /* 64 difference is enough for ld80 double_t */ + if (ex - ey > 64) + return x + y; + + /* precise sqrt argument in nearest rounding mode without overflow */ + /* xh*xh must not overflow and xl*xl must not underflow in sq */ + z = 1; + if (ex > 0x3ff+510) { + z = 0x1p700; + x *= 0x1p-700; + y *= 0x1p-700; + } else if (ey < 0x3ff-450) { + z = 0x1p-700; + x *= 0x1p700; + y *= 0x1p700; + } + sq(&hx, &lx, x); + sq(&hy, &ly, y); + return z*sqrt(ly+lx+hy+hx); +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/hypotf.c b/lib/mlibc/options/ansi/musl-generic-math/hypotf.c new file mode 100644 index 0000000..2fc214b --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/hypotf.c @@ -0,0 +1,35 @@ +#include +#include + +float hypotf(float x, float y) +{ + union {float f; uint32_t i;} ux = {x}, uy = {y}, ut; + float_t z; + + ux.i &= -1U>>1; + uy.i &= -1U>>1; + if (ux.i < uy.i) { + ut = ux; + ux = uy; + uy = ut; + } + + x = ux.f; + y = uy.f; + if (uy.i == 0xff<<23) + return y; + if (ux.i >= 0xff<<23 || uy.i == 0 || ux.i - uy.i >= 25<<23) + return x + y; + + z = 1; + if (ux.i >= (0x7f+60)<<23) { + z = 0x1p90f; + x *= 0x1p-90f; + y *= 0x1p-90f; + } else if (uy.i < (0x7f-60)<<23) { + z = 0x1p-90f; + x *= 0x1p90f; + y *= 0x1p90f; + } + return z*sqrtf((double)x*x + (double)y*y); +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/hypotl.c b/lib/mlibc/options/ansi/musl-generic-math/hypotl.c new file mode 100644 index 0000000..479aa92 --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/hypotl.c @@ -0,0 +1,66 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double hypotl(long double x, long double y) +{ + return hypot(x, y); +} +#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 +#if LDBL_MANT_DIG == 64 +#define SPLIT (0x1p32L+1) +#elif LDBL_MANT_DIG == 113 +#define SPLIT (0x1p57L+1) +#endif + +static void sq(long double *hi, long double *lo, long double x) +{ + long double xh, xl, xc; + xc = x*SPLIT; + xh = x - xc + xc; + xl = x - xh; + *hi = x*x; + *lo = xh*xh - *hi + 2*xh*xl + xl*xl; +} + +long double hypotl(long double x, long double y) +{ + union ldshape ux = {x}, uy = {y}; + int ex, ey; + long double hx, lx, hy, ly, z; + + ux.i.se &= 0x7fff; + uy.i.se &= 0x7fff; + if (ux.i.se < uy.i.se) { + ex = uy.i.se; + ey = ux.i.se; + x = uy.f; + y = ux.f; + } else { + ex = ux.i.se; + ey = uy.i.se; + x = ux.f; + y = uy.f; + } + + if (ex == 0x7fff && isinf(y)) + return y; + if (ex == 0x7fff || y == 0) + return x; + if (ex - ey > LDBL_MANT_DIG) + return x + y; + + z = 1; + if (ex > 0x3fff+8000) { + z = 0x1p10000L; + x *= 0x1p-10000L; + y *= 0x1p-10000L; + } else if (ey < 0x3fff-8000) { + z = 0x1p-10000L; + x *= 0x1p10000L; + y *= 0x1p10000L; + } + sq(&hx, &lx, x); + sq(&hy, &ly, y); + return z*sqrtl(ly+lx+hy+hx); +} +#endif diff --git a/lib/mlibc/options/ansi/musl-generic-math/ilogb.c b/lib/mlibc/options/ansi/musl-generic-math/ilogb.c new file mode 100644 index 0000000..64d4015 --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/ilogb.c @@ -0,0 +1,26 @@ +#include +#include "libm.h" + +int ilogb(double x) +{ + #pragma STDC FENV_ACCESS ON + union {double f; uint64_t i;} u = {x}; + uint64_t i = u.i; + int e = i>>52 & 0x7ff; + + if (!e) { + i <<= 12; + if (i == 0) { + FORCE_EVAL(0/0.0f); + return FP_ILOGB0; + } + /* subnormal x */ + for (e = -0x3ff; i>>63 == 0; e--, i<<=1); + return e; + } + if (e == 0x7ff) { + FORCE_EVAL(0/0.0f); + return i<<12 ? FP_ILOGBNAN : INT_MAX; + } + return e - 0x3ff; +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/ilogbf.c b/lib/mlibc/options/ansi/musl-generic-math/ilogbf.c new file mode 100644 index 0000000..e23ba20 --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/ilogbf.c @@ -0,0 +1,26 @@ +#include +#include "libm.h" + +int ilogbf(float x) +{ + #pragma STDC FENV_ACCESS ON + union {float f; uint32_t i;} u = {x}; + uint32_t i = u.i; + int e = i>>23 & 0xff; + + if (!e) { + i <<= 9; + if (i == 0) { + FORCE_EVAL(0/0.0f); + return FP_ILOGB0; + } + /* subnormal x */ + for (e = -0x7f; i>>31 == 0; e--, i<<=1); + return e; + } + if (e == 0xff) { + FORCE_EVAL(0/0.0f); + return i<<9 ? FP_ILOGBNAN : INT_MAX; + } + return e - 0x7f; +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/ilogbl.c b/lib/mlibc/options/ansi/musl-generic-math/ilogbl.c new file mode 100644 index 0000000..7b1a9cf --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/ilogbl.c @@ -0,0 +1,55 @@ +#include +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +int ilogbl(long double x) +{ + return ilogb(x); +} +#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 +int ilogbl(long double x) +{ + #pragma STDC FENV_ACCESS ON + union ldshape u = {x}; + uint64_t m = u.i.m; + int e = u.i.se & 0x7fff; + + if (!e) { + if (m == 0) { + FORCE_EVAL(0/0.0f); + return FP_ILOGB0; + } + /* subnormal x */ + for (e = -0x3fff+1; m>>63 == 0; e--, m<<=1); + return e; + } + if (e == 0x7fff) { + FORCE_EVAL(0/0.0f); + return m<<1 ? FP_ILOGBNAN : INT_MAX; + } + return e - 0x3fff; +} +#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 +int ilogbl(long double x) +{ + #pragma STDC FENV_ACCESS ON + union ldshape u = {x}; + int e = u.i.se & 0x7fff; + + if (!e) { + if (x == 0) { + FORCE_EVAL(0/0.0f); + return FP_ILOGB0; + } + /* subnormal x */ + x *= 0x1p120; + return ilogbl(x) - 120; + } + if (e == 0x7fff) { + FORCE_EVAL(0/0.0f); + u.i.se = 0; + return u.f ? FP_ILOGBNAN : INT_MAX; + } + return e - 0x3fff; +} +#endif diff --git a/lib/mlibc/options/ansi/musl-generic-math/j0.c b/lib/mlibc/options/ansi/musl-generic-math/j0.c new file mode 100644 index 0000000..d722d94 --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/j0.c @@ -0,0 +1,375 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_j0.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* j0(x), y0(x) + * Bessel function of the first and second kinds of order zero. + * Method -- j0(x): + * 1. For tiny x, we use j0(x) = 1 - x^2/4 + x^4/64 - ... + * 2. Reduce x to |x| since j0(x)=j0(-x), and + * for x in (0,2) + * j0(x) = 1-z/4+ z^2*R0/S0, where z = x*x; + * (precision: |j0-1+z/4-z^2R0/S0 |<2**-63.67 ) + * for x in (2,inf) + * j0(x) = sqrt(2/(pi*x))*(p0(x)*cos(x0)-q0(x)*sin(x0)) + * where x0 = x-pi/4. It is better to compute sin(x0),cos(x0) + * as follow: + * cos(x0) = cos(x)cos(pi/4)+sin(x)sin(pi/4) + * = 1/sqrt(2) * (cos(x) + sin(x)) + * sin(x0) = sin(x)cos(pi/4)-cos(x)sin(pi/4) + * = 1/sqrt(2) * (sin(x) - cos(x)) + * (To avoid cancellation, use + * sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x)) + * to compute the worse one.) + * + * 3 Special cases + * j0(nan)= nan + * j0(0) = 1 + * j0(inf) = 0 + * + * Method -- y0(x): + * 1. For x<2. + * Since + * y0(x) = 2/pi*(j0(x)*(ln(x/2)+Euler) + x^2/4 - ...) + * therefore y0(x)-2/pi*j0(x)*ln(x) is an even function. + * We use the following function to approximate y0, + * y0(x) = U(z)/V(z) + (2/pi)*(j0(x)*ln(x)), z= x^2 + * where + * U(z) = u00 + u01*z + ... + u06*z^6 + * V(z) = 1 + v01*z + ... + v04*z^4 + * with absolute approximation error bounded by 2**-72. + * Note: For tiny x, U/V = u0 and j0(x)~1, hence + * y0(tiny) = u0 + (2/pi)*ln(tiny), (choose tiny<2**-27) + * 2. For x>=2. + * y0(x) = sqrt(2/(pi*x))*(p0(x)*cos(x0)+q0(x)*sin(x0)) + * where x0 = x-pi/4. It is better to compute sin(x0),cos(x0) + * by the method mentioned above. + * 3. Special cases: y0(0)=-inf, y0(x<0)=NaN, y0(inf)=0. + */ + +#include "libm.h" + +static double pzero(double), qzero(double); + +static const double +invsqrtpi = 5.64189583547756279280e-01, /* 0x3FE20DD7, 0x50429B6D */ +tpi = 6.36619772367581382433e-01; /* 0x3FE45F30, 0x6DC9C883 */ + +/* common method when |x|>=2 */ +static double common(uint32_t ix, double x, int y0) +{ + double s,c,ss,cc,z; + + /* + * j0(x) = sqrt(2/(pi*x))*(p0(x)*cos(x-pi/4)-q0(x)*sin(x-pi/4)) + * y0(x) = sqrt(2/(pi*x))*(p0(x)*sin(x-pi/4)+q0(x)*cos(x-pi/4)) + * + * sin(x-pi/4) = (sin(x) - cos(x))/sqrt(2) + * cos(x-pi/4) = (sin(x) + cos(x))/sqrt(2) + * sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x)) + */ + s = sin(x); + c = cos(x); + if (y0) + c = -c; + cc = s+c; + /* avoid overflow in 2*x, big ulp error when x>=0x1p1023 */ + if (ix < 0x7fe00000) { + ss = s-c; + z = -cos(2*x); + if (s*c < 0) + cc = z/ss; + else + ss = z/cc; + if (ix < 0x48000000) { + if (y0) + ss = -ss; + cc = pzero(x)*cc-qzero(x)*ss; + } + } + return invsqrtpi*cc/sqrt(x); +} + +/* R0/S0 on [0, 2.00] */ +static const double +R02 = 1.56249999999999947958e-02, /* 0x3F8FFFFF, 0xFFFFFFFD */ +R03 = -1.89979294238854721751e-04, /* 0xBF28E6A5, 0xB61AC6E9 */ +R04 = 1.82954049532700665670e-06, /* 0x3EBEB1D1, 0x0C503919 */ +R05 = -4.61832688532103189199e-09, /* 0xBE33D5E7, 0x73D63FCE */ +S01 = 1.56191029464890010492e-02, /* 0x3F8FFCE8, 0x82C8C2A4 */ +S02 = 1.16926784663337450260e-04, /* 0x3F1EA6D2, 0xDD57DBF4 */ +S03 = 5.13546550207318111446e-07, /* 0x3EA13B54, 0xCE84D5A9 */ +S04 = 1.16614003333790000205e-09; /* 0x3E1408BC, 0xF4745D8F */ + +double j0(double x) +{ + double z,r,s; + uint32_t ix; + + GET_HIGH_WORD(ix, x); + ix &= 0x7fffffff; + + /* j0(+-inf)=0, j0(nan)=nan */ + if (ix >= 0x7ff00000) + return 1/(x*x); + x = fabs(x); + + if (ix >= 0x40000000) { /* |x| >= 2 */ + /* large ulp error near zeros: 2.4, 5.52, 8.6537,.. */ + return common(ix,x,0); + } + + /* 1 - x*x/4 + x*x*R(x^2)/S(x^2) */ + if (ix >= 0x3f200000) { /* |x| >= 2**-13 */ + /* up to 4ulp error close to 2 */ + z = x*x; + r = z*(R02+z*(R03+z*(R04+z*R05))); + s = 1+z*(S01+z*(S02+z*(S03+z*S04))); + return (1+x/2)*(1-x/2) + z*(r/s); + } + + /* 1 - x*x/4 */ + /* prevent underflow */ + /* inexact should be raised when x!=0, this is not done correctly */ + if (ix >= 0x38000000) /* |x| >= 2**-127 */ + x = 0.25*x*x; + return 1 - x; +} + +static const double +u00 = -7.38042951086872317523e-02, /* 0xBFB2E4D6, 0x99CBD01F */ +u01 = 1.76666452509181115538e-01, /* 0x3FC69D01, 0x9DE9E3FC */ +u02 = -1.38185671945596898896e-02, /* 0xBF8C4CE8, 0xB16CFA97 */ +u03 = 3.47453432093683650238e-04, /* 0x3F36C54D, 0x20B29B6B */ +u04 = -3.81407053724364161125e-06, /* 0xBECFFEA7, 0x73D25CAD */ +u05 = 1.95590137035022920206e-08, /* 0x3E550057, 0x3B4EABD4 */ +u06 = -3.98205194132103398453e-11, /* 0xBDC5E43D, 0x693FB3C8 */ +v01 = 1.27304834834123699328e-02, /* 0x3F8A1270, 0x91C9C71A */ +v02 = 7.60068627350353253702e-05, /* 0x3F13ECBB, 0xF578C6C1 */ +v03 = 2.59150851840457805467e-07, /* 0x3E91642D, 0x7FF202FD */ +v04 = 4.41110311332675467403e-10; /* 0x3DFE5018, 0x3BD6D9EF */ + +double y0(double x) +{ + double z,u,v; + uint32_t ix,lx; + + EXTRACT_WORDS(ix, lx, x); + + /* y0(nan)=nan, y0(<0)=nan, y0(0)=-inf, y0(inf)=0 */ + if ((ix<<1 | lx) == 0) + return -1/0.0; + if (ix>>31) + return 0/0.0; + if (ix >= 0x7ff00000) + return 1/x; + + if (ix >= 0x40000000) { /* x >= 2 */ + /* large ulp errors near zeros: 3.958, 7.086,.. */ + return common(ix,x,1); + } + + /* U(x^2)/V(x^2) + (2/pi)*j0(x)*log(x) */ + if (ix >= 0x3e400000) { /* x >= 2**-27 */ + /* large ulp error near the first zero, x ~= 0.89 */ + z = x*x; + u = u00+z*(u01+z*(u02+z*(u03+z*(u04+z*(u05+z*u06))))); + v = 1.0+z*(v01+z*(v02+z*(v03+z*v04))); + return u/v + tpi*(j0(x)*log(x)); + } + return u00 + tpi*log(x); +} + +/* The asymptotic expansions of pzero is + * 1 - 9/128 s^2 + 11025/98304 s^4 - ..., where s = 1/x. + * For x >= 2, We approximate pzero by + * pzero(x) = 1 + (R/S) + * where R = pR0 + pR1*s^2 + pR2*s^4 + ... + pR5*s^10 + * S = 1 + pS0*s^2 + ... + pS4*s^10 + * and + * | pzero(x)-1-R/S | <= 2 ** ( -60.26) + */ +static const double pR8[6] = { /* for x in [inf, 8]=1/[0,0.125] */ + 0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */ + -7.03124999999900357484e-02, /* 0xBFB1FFFF, 0xFFFFFD32 */ + -8.08167041275349795626e+00, /* 0xC02029D0, 0xB44FA779 */ + -2.57063105679704847262e+02, /* 0xC0701102, 0x7B19E863 */ + -2.48521641009428822144e+03, /* 0xC0A36A6E, 0xCD4DCAFC */ + -5.25304380490729545272e+03, /* 0xC0B4850B, 0x36CC643D */ +}; +static const double pS8[5] = { + 1.16534364619668181717e+02, /* 0x405D2233, 0x07A96751 */ + 3.83374475364121826715e+03, /* 0x40ADF37D, 0x50596938 */ + 4.05978572648472545552e+04, /* 0x40E3D2BB, 0x6EB6B05F */ + 1.16752972564375915681e+05, /* 0x40FC810F, 0x8F9FA9BD */ + 4.76277284146730962675e+04, /* 0x40E74177, 0x4F2C49DC */ +}; + +static const double pR5[6] = { /* for x in [8,4.5454]=1/[0.125,0.22001] */ + -1.14125464691894502584e-11, /* 0xBDA918B1, 0x47E495CC */ + -7.03124940873599280078e-02, /* 0xBFB1FFFF, 0xE69AFBC6 */ + -4.15961064470587782438e+00, /* 0xC010A370, 0xF90C6BBF */ + -6.76747652265167261021e+01, /* 0xC050EB2F, 0x5A7D1783 */ + -3.31231299649172967747e+02, /* 0xC074B3B3, 0x6742CC63 */ + -3.46433388365604912451e+02, /* 0xC075A6EF, 0x28A38BD7 */ +}; +static const double pS5[5] = { + 6.07539382692300335975e+01, /* 0x404E6081, 0x0C98C5DE */ + 1.05125230595704579173e+03, /* 0x40906D02, 0x5C7E2864 */ + 5.97897094333855784498e+03, /* 0x40B75AF8, 0x8FBE1D60 */ + 9.62544514357774460223e+03, /* 0x40C2CCB8, 0xFA76FA38 */ + 2.40605815922939109441e+03, /* 0x40A2CC1D, 0xC70BE864 */ +}; + +static const double pR3[6] = {/* for x in [4.547,2.8571]=1/[0.2199,0.35001] */ + -2.54704601771951915620e-09, /* 0xBE25E103, 0x6FE1AA86 */ + -7.03119616381481654654e-02, /* 0xBFB1FFF6, 0xF7C0E24B */ + -2.40903221549529611423e+00, /* 0xC00345B2, 0xAEA48074 */ + -2.19659774734883086467e+01, /* 0xC035F74A, 0x4CB94E14 */ + -5.80791704701737572236e+01, /* 0xC04D0A22, 0x420A1A45 */ + -3.14479470594888503854e+01, /* 0xC03F72AC, 0xA892D80F */ +}; +static const double pS3[5] = { + 3.58560338055209726349e+01, /* 0x4041ED92, 0x84077DD3 */ + 3.61513983050303863820e+02, /* 0x40769839, 0x464A7C0E */ + 1.19360783792111533330e+03, /* 0x4092A66E, 0x6D1061D6 */ + 1.12799679856907414432e+03, /* 0x40919FFC, 0xB8C39B7E */ + 1.73580930813335754692e+02, /* 0x4065B296, 0xFC379081 */ +}; + +static const double pR2[6] = {/* for x in [2.8570,2]=1/[0.3499,0.5] */ + -8.87534333032526411254e-08, /* 0xBE77D316, 0xE927026D */ + -7.03030995483624743247e-02, /* 0xBFB1FF62, 0x495E1E42 */ + -1.45073846780952986357e+00, /* 0xBFF73639, 0x8A24A843 */ + -7.63569613823527770791e+00, /* 0xC01E8AF3, 0xEDAFA7F3 */ + -1.11931668860356747786e+01, /* 0xC02662E6, 0xC5246303 */ + -3.23364579351335335033e+00, /* 0xC009DE81, 0xAF8FE70F */ +}; +static const double pS2[5] = { + 2.22202997532088808441e+01, /* 0x40363865, 0x908B5959 */ + 1.36206794218215208048e+02, /* 0x4061069E, 0x0EE8878F */ + 2.70470278658083486789e+02, /* 0x4070E786, 0x42EA079B */ + 1.53875394208320329881e+02, /* 0x40633C03, 0x3AB6FAFF */ + 1.46576176948256193810e+01, /* 0x402D50B3, 0x44391809 */ +}; + +static double pzero(double x) +{ + const double *p,*q; + double_t z,r,s; + uint32_t ix; + + GET_HIGH_WORD(ix, x); + ix &= 0x7fffffff; + if (ix >= 0x40200000){p = pR8; q = pS8;} + else if (ix >= 0x40122E8B){p = pR5; q = pS5;} + else if (ix >= 0x4006DB6D){p = pR3; q = pS3;} + else /*ix >= 0x40000000*/ {p = pR2; q = pS2;} + z = 1.0/(x*x); + r = p[0]+z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5])))); + s = 1.0+z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*q[4])))); + return 1.0 + r/s; +} + + +/* For x >= 8, the asymptotic expansions of qzero is + * -1/8 s + 75/1024 s^3 - ..., where s = 1/x. + * We approximate pzero by + * qzero(x) = s*(-1.25 + (R/S)) + * where R = qR0 + qR1*s^2 + qR2*s^4 + ... + qR5*s^10 + * S = 1 + qS0*s^2 + ... + qS5*s^12 + * and + * | qzero(x)/s +1.25-R/S | <= 2 ** ( -61.22) + */ +static const double qR8[6] = { /* for x in [inf, 8]=1/[0,0.125] */ + 0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */ + 7.32421874999935051953e-02, /* 0x3FB2BFFF, 0xFFFFFE2C */ + 1.17682064682252693899e+01, /* 0x40278952, 0x5BB334D6 */ + 5.57673380256401856059e+02, /* 0x40816D63, 0x15301825 */ + 8.85919720756468632317e+03, /* 0x40C14D99, 0x3E18F46D */ + 3.70146267776887834771e+04, /* 0x40E212D4, 0x0E901566 */ +}; +static const double qS8[6] = { + 1.63776026895689824414e+02, /* 0x406478D5, 0x365B39BC */ + 8.09834494656449805916e+03, /* 0x40BFA258, 0x4E6B0563 */ + 1.42538291419120476348e+05, /* 0x41016652, 0x54D38C3F */ + 8.03309257119514397345e+05, /* 0x412883DA, 0x83A52B43 */ + 8.40501579819060512818e+05, /* 0x4129A66B, 0x28DE0B3D */ + -3.43899293537866615225e+05, /* 0xC114FD6D, 0x2C9530C5 */ +}; + +static const double qR5[6] = { /* for x in [8,4.5454]=1/[0.125,0.22001] */ + 1.84085963594515531381e-11, /* 0x3DB43D8F, 0x29CC8CD9 */ + 7.32421766612684765896e-02, /* 0x3FB2BFFF, 0xD172B04C */ + 5.83563508962056953777e+00, /* 0x401757B0, 0xB9953DD3 */ + 1.35111577286449829671e+02, /* 0x4060E392, 0x0A8788E9 */ + 1.02724376596164097464e+03, /* 0x40900CF9, 0x9DC8C481 */ + 1.98997785864605384631e+03, /* 0x409F17E9, 0x53C6E3A6 */ +}; +static const double qS5[6] = { + 8.27766102236537761883e+01, /* 0x4054B1B3, 0xFB5E1543 */ + 2.07781416421392987104e+03, /* 0x40A03BA0, 0xDA21C0CE */ + 1.88472887785718085070e+04, /* 0x40D267D2, 0x7B591E6D */ + 5.67511122894947329769e+04, /* 0x40EBB5E3, 0x97E02372 */ + 3.59767538425114471465e+04, /* 0x40E19118, 0x1F7A54A0 */ + -5.35434275601944773371e+03, /* 0xC0B4EA57, 0xBEDBC609 */ +}; + +static const double qR3[6] = {/* for x in [4.547,2.8571]=1/[0.2199,0.35001] */ + 4.37741014089738620906e-09, /* 0x3E32CD03, 0x6ADECB82 */ + 7.32411180042911447163e-02, /* 0x3FB2BFEE, 0x0E8D0842 */ + 3.34423137516170720929e+00, /* 0x400AC0FC, 0x61149CF5 */ + 4.26218440745412650017e+01, /* 0x40454F98, 0x962DAEDD */ + 1.70808091340565596283e+02, /* 0x406559DB, 0xE25EFD1F */ + 1.66733948696651168575e+02, /* 0x4064D77C, 0x81FA21E0 */ +}; +static const double qS3[6] = { + 4.87588729724587182091e+01, /* 0x40486122, 0xBFE343A6 */ + 7.09689221056606015736e+02, /* 0x40862D83, 0x86544EB3 */ + 3.70414822620111362994e+03, /* 0x40ACF04B, 0xE44DFC63 */ + 6.46042516752568917582e+03, /* 0x40B93C6C, 0xD7C76A28 */ + 2.51633368920368957333e+03, /* 0x40A3A8AA, 0xD94FB1C0 */ + -1.49247451836156386662e+02, /* 0xC062A7EB, 0x201CF40F */ +}; + +static const double qR2[6] = {/* for x in [2.8570,2]=1/[0.3499,0.5] */ + 1.50444444886983272379e-07, /* 0x3E84313B, 0x54F76BDB */ + 7.32234265963079278272e-02, /* 0x3FB2BEC5, 0x3E883E34 */ + 1.99819174093815998816e+00, /* 0x3FFFF897, 0xE727779C */ + 1.44956029347885735348e+01, /* 0x402CFDBF, 0xAAF96FE5 */ + 3.16662317504781540833e+01, /* 0x403FAA8E, 0x29FBDC4A */ + 1.62527075710929267416e+01, /* 0x403040B1, 0x71814BB4 */ +}; +static const double qS2[6] = { + 3.03655848355219184498e+01, /* 0x403E5D96, 0xF7C07AED */ + 2.69348118608049844624e+02, /* 0x4070D591, 0xE4D14B40 */ + 8.44783757595320139444e+02, /* 0x408A6645, 0x22B3BF22 */ + 8.82935845112488550512e+02, /* 0x408B977C, 0x9C5CC214 */ + 2.12666388511798828631e+02, /* 0x406A9553, 0x0E001365 */ + -5.31095493882666946917e+00, /* 0xC0153E6A, 0xF8B32931 */ +}; + +static double qzero(double x) +{ + const double *p,*q; + double_t s,r,z; + uint32_t ix; + + GET_HIGH_WORD(ix, x); + ix &= 0x7fffffff; + if (ix >= 0x40200000){p = qR8; q = qS8;} + else if (ix >= 0x40122E8B){p = qR5; q = qS5;} + else if (ix >= 0x4006DB6D){p = qR3; q = qS3;} + else /*ix >= 0x40000000*/ {p = qR2; q = qS2;} + z = 1.0/(x*x); + r = p[0]+z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5])))); + s = 1.0+z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*(q[4]+z*q[5]))))); + return (-.125 + r/s)/x; +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/j0f.c b/lib/mlibc/options/ansi/musl-generic-math/j0f.c new file mode 100644 index 0000000..fab554a --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/j0f.c @@ -0,0 +1,314 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_j0f.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#define _GNU_SOURCE +#include "libm.h" + +static float pzerof(float), qzerof(float); + +static const float +invsqrtpi = 5.6418961287e-01, /* 0x3f106ebb */ +tpi = 6.3661974669e-01; /* 0x3f22f983 */ + +static float common(uint32_t ix, float x, int y0) +{ + float z,s,c,ss,cc; + /* + * j0(x) = 1/sqrt(pi) * (P(0,x)*cc - Q(0,x)*ss) / sqrt(x) + * y0(x) = 1/sqrt(pi) * (P(0,x)*ss + Q(0,x)*cc) / sqrt(x) + */ + s = sinf(x); + c = cosf(x); + if (y0) + c = -c; + cc = s+c; + if (ix < 0x7f000000) { + ss = s-c; + z = -cosf(2*x); + if (s*c < 0) + cc = z/ss; + else + ss = z/cc; + if (ix < 0x58800000) { + if (y0) + ss = -ss; + cc = pzerof(x)*cc-qzerof(x)*ss; + } + } + return invsqrtpi*cc/sqrtf(x); +} + +/* R0/S0 on [0, 2.00] */ +static const float +R02 = 1.5625000000e-02, /* 0x3c800000 */ +R03 = -1.8997929874e-04, /* 0xb947352e */ +R04 = 1.8295404516e-06, /* 0x35f58e88 */ +R05 = -4.6183270541e-09, /* 0xb19eaf3c */ +S01 = 1.5619102865e-02, /* 0x3c7fe744 */ +S02 = 1.1692678527e-04, /* 0x38f53697 */ +S03 = 5.1354652442e-07, /* 0x3509daa6 */ +S04 = 1.1661400734e-09; /* 0x30a045e8 */ + +float j0f(float x) +{ + float z,r,s; + uint32_t ix; + + GET_FLOAT_WORD(ix, x); + ix &= 0x7fffffff; + if (ix >= 0x7f800000) + return 1/(x*x); + x = fabsf(x); + + if (ix >= 0x40000000) { /* |x| >= 2 */ + /* large ulp error near zeros */ + return common(ix, x, 0); + } + if (ix >= 0x3a000000) { /* |x| >= 2**-11 */ + /* up to 4ulp error near 2 */ + z = x*x; + r = z*(R02+z*(R03+z*(R04+z*R05))); + s = 1+z*(S01+z*(S02+z*(S03+z*S04))); + return (1+x/2)*(1-x/2) + z*(r/s); + } + if (ix >= 0x21800000) /* |x| >= 2**-60 */ + x = 0.25f*x*x; + return 1 - x; +} + +static const float +u00 = -7.3804296553e-02, /* 0xbd9726b5 */ +u01 = 1.7666645348e-01, /* 0x3e34e80d */ +u02 = -1.3818567619e-02, /* 0xbc626746 */ +u03 = 3.4745343146e-04, /* 0x39b62a69 */ +u04 = -3.8140706238e-06, /* 0xb67ff53c */ +u05 = 1.9559013964e-08, /* 0x32a802ba */ +u06 = -3.9820518410e-11, /* 0xae2f21eb */ +v01 = 1.2730483897e-02, /* 0x3c509385 */ +v02 = 7.6006865129e-05, /* 0x389f65e0 */ +v03 = 2.5915085189e-07, /* 0x348b216c */ +v04 = 4.4111031494e-10; /* 0x2ff280c2 */ + +float y0f(float x) +{ + float z,u,v; + uint32_t ix; + + GET_FLOAT_WORD(ix, x); + if ((ix & 0x7fffffff) == 0) + return -1/0.0f; + if (ix>>31) + return 0/0.0f; + if (ix >= 0x7f800000) + return 1/x; + if (ix >= 0x40000000) { /* |x| >= 2.0 */ + /* large ulp error near zeros */ + return common(ix,x,1); + } + if (ix >= 0x39000000) { /* x >= 2**-13 */ + /* large ulp error at x ~= 0.89 */ + z = x*x; + u = u00+z*(u01+z*(u02+z*(u03+z*(u04+z*(u05+z*u06))))); + v = 1+z*(v01+z*(v02+z*(v03+z*v04))); + return u/v + tpi*(j0f(x)*logf(x)); + } + return u00 + tpi*logf(x); +} + +/* The asymptotic expansions of pzero is + * 1 - 9/128 s^2 + 11025/98304 s^4 - ..., where s = 1/x. + * For x >= 2, We approximate pzero by + * pzero(x) = 1 + (R/S) + * where R = pR0 + pR1*s^2 + pR2*s^4 + ... + pR5*s^10 + * S = 1 + pS0*s^2 + ... + pS4*s^10 + * and + * | pzero(x)-1-R/S | <= 2 ** ( -60.26) + */ +static const float pR8[6] = { /* for x in [inf, 8]=1/[0,0.125] */ + 0.0000000000e+00, /* 0x00000000 */ + -7.0312500000e-02, /* 0xbd900000 */ + -8.0816707611e+00, /* 0xc1014e86 */ + -2.5706311035e+02, /* 0xc3808814 */ + -2.4852163086e+03, /* 0xc51b5376 */ + -5.2530439453e+03, /* 0xc5a4285a */ +}; +static const float pS8[5] = { + 1.1653436279e+02, /* 0x42e91198 */ + 3.8337448730e+03, /* 0x456f9beb */ + 4.0597855469e+04, /* 0x471e95db */ + 1.1675296875e+05, /* 0x47e4087c */ + 4.7627726562e+04, /* 0x473a0bba */ +}; +static const float pR5[6] = { /* for x in [8,4.5454]=1/[0.125,0.22001] */ + -1.1412546255e-11, /* 0xad48c58a */ + -7.0312492549e-02, /* 0xbd8fffff */ + -4.1596107483e+00, /* 0xc0851b88 */ + -6.7674766541e+01, /* 0xc287597b */ + -3.3123129272e+02, /* 0xc3a59d9b */ + -3.4643338013e+02, /* 0xc3ad3779 */ +}; +static const float pS5[5] = { + 6.0753936768e+01, /* 0x42730408 */ + 1.0512523193e+03, /* 0x44836813 */ + 5.9789707031e+03, /* 0x45bad7c4 */ + 9.6254453125e+03, /* 0x461665c8 */ + 2.4060581055e+03, /* 0x451660ee */ +}; + +static const float pR3[6] = {/* for x in [4.547,2.8571]=1/[0.2199,0.35001] */ + -2.5470459075e-09, /* 0xb12f081b */ + -7.0311963558e-02, /* 0xbd8fffb8 */ + -2.4090321064e+00, /* 0xc01a2d95 */ + -2.1965976715e+01, /* 0xc1afba52 */ + -5.8079170227e+01, /* 0xc2685112 */ + -3.1447946548e+01, /* 0xc1fb9565 */ +}; +static const float pS3[5] = { + 3.5856033325e+01, /* 0x420f6c94 */ + 3.6151397705e+02, /* 0x43b4c1ca */ + 1.1936077881e+03, /* 0x44953373 */ + 1.1279968262e+03, /* 0x448cffe6 */ + 1.7358093262e+02, /* 0x432d94b8 */ +}; + +static const float pR2[6] = {/* for x in [2.8570,2]=1/[0.3499,0.5] */ + -8.8753431271e-08, /* 0xb3be98b7 */ + -7.0303097367e-02, /* 0xbd8ffb12 */ + -1.4507384300e+00, /* 0xbfb9b1cc */ + -7.6356959343e+00, /* 0xc0f4579f */ + -1.1193166733e+01, /* 0xc1331736 */ + -3.2336456776e+00, /* 0xc04ef40d */ +}; +static const float pS2[5] = { + 2.2220300674e+01, /* 0x41b1c32d */ + 1.3620678711e+02, /* 0x430834f0 */ + 2.7047027588e+02, /* 0x43873c32 */ + 1.5387539673e+02, /* 0x4319e01a */ + 1.4657617569e+01, /* 0x416a859a */ +}; + +static float pzerof(float x) +{ + const float *p,*q; + float_t z,r,s; + uint32_t ix; + + GET_FLOAT_WORD(ix, x); + ix &= 0x7fffffff; + if (ix >= 0x41000000){p = pR8; q = pS8;} + else if (ix >= 0x409173eb){p = pR5; q = pS5;} + else if (ix >= 0x4036d917){p = pR3; q = pS3;} + else /*ix >= 0x40000000*/ {p = pR2; q = pS2;} + z = 1.0f/(x*x); + r = p[0]+z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5])))); + s = 1.0f+z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*q[4])))); + return 1.0f + r/s; +} + + +/* For x >= 8, the asymptotic expansions of qzero is + * -1/8 s + 75/1024 s^3 - ..., where s = 1/x. + * We approximate pzero by + * qzero(x) = s*(-1.25 + (R/S)) + * where R = qR0 + qR1*s^2 + qR2*s^4 + ... + qR5*s^10 + * S = 1 + qS0*s^2 + ... + qS5*s^12 + * and + * | qzero(x)/s +1.25-R/S | <= 2 ** ( -61.22) + */ +static const float qR8[6] = { /* for x in [inf, 8]=1/[0,0.125] */ + 0.0000000000e+00, /* 0x00000000 */ + 7.3242187500e-02, /* 0x3d960000 */ + 1.1768206596e+01, /* 0x413c4a93 */ + 5.5767340088e+02, /* 0x440b6b19 */ + 8.8591972656e+03, /* 0x460a6cca */ + 3.7014625000e+04, /* 0x471096a0 */ +}; +static const float qS8[6] = { + 1.6377603149e+02, /* 0x4323c6aa */ + 8.0983447266e+03, /* 0x45fd12c2 */ + 1.4253829688e+05, /* 0x480b3293 */ + 8.0330925000e+05, /* 0x49441ed4 */ + 8.4050156250e+05, /* 0x494d3359 */ + -3.4389928125e+05, /* 0xc8a7eb69 */ +}; + +static const float qR5[6] = { /* for x in [8,4.5454]=1/[0.125,0.22001] */ + 1.8408595828e-11, /* 0x2da1ec79 */ + 7.3242180049e-02, /* 0x3d95ffff */ + 5.8356351852e+00, /* 0x40babd86 */ + 1.3511157227e+02, /* 0x43071c90 */ + 1.0272437744e+03, /* 0x448067cd */ + 1.9899779053e+03, /* 0x44f8bf4b */ +}; +static const float qS5[6] = { + 8.2776611328e+01, /* 0x42a58da0 */ + 2.0778142090e+03, /* 0x4501dd07 */ + 1.8847289062e+04, /* 0x46933e94 */ + 5.6751113281e+04, /* 0x475daf1d */ + 3.5976753906e+04, /* 0x470c88c1 */ + -5.3543427734e+03, /* 0xc5a752be */ +}; + +static const float qR3[6] = {/* for x in [4.547,2.8571]=1/[0.2199,0.35001] */ + 4.3774099900e-09, /* 0x3196681b */ + 7.3241114616e-02, /* 0x3d95ff70 */ + 3.3442313671e+00, /* 0x405607e3 */ + 4.2621845245e+01, /* 0x422a7cc5 */ + 1.7080809021e+02, /* 0x432acedf */ + 1.6673394775e+02, /* 0x4326bbe4 */ +}; +static const float qS3[6] = { + 4.8758872986e+01, /* 0x42430916 */ + 7.0968920898e+02, /* 0x44316c1c */ + 3.7041481934e+03, /* 0x4567825f */ + 6.4604252930e+03, /* 0x45c9e367 */ + 2.5163337402e+03, /* 0x451d4557 */ + -1.4924745178e+02, /* 0xc3153f59 */ +}; + +static const float qR2[6] = {/* for x in [2.8570,2]=1/[0.3499,0.5] */ + 1.5044444979e-07, /* 0x342189db */ + 7.3223426938e-02, /* 0x3d95f62a */ + 1.9981917143e+00, /* 0x3fffc4bf */ + 1.4495602608e+01, /* 0x4167edfd */ + 3.1666231155e+01, /* 0x41fd5471 */ + 1.6252708435e+01, /* 0x4182058c */ +}; +static const float qS2[6] = { + 3.0365585327e+01, /* 0x41f2ecb8 */ + 2.6934811401e+02, /* 0x4386ac8f */ + 8.4478375244e+02, /* 0x44533229 */ + 8.8293585205e+02, /* 0x445cbbe5 */ + 2.1266638184e+02, /* 0x4354aa98 */ + -5.3109550476e+00, /* 0xc0a9f358 */ +}; + +static float qzerof(float x) +{ + const float *p,*q; + float_t s,r,z; + uint32_t ix; + + GET_FLOAT_WORD(ix, x); + ix &= 0x7fffffff; + if (ix >= 0x41000000){p = qR8; q = qS8;} + else if (ix >= 0x409173eb){p = qR5; q = qS5;} + else if (ix >= 0x4036d917){p = qR3; q = qS3;} + else /*ix >= 0x40000000*/ {p = qR2; q = qS2;} + z = 1.0f/(x*x); + r = p[0]+z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5])))); + s = 1.0f+z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*(q[4]+z*q[5]))))); + return (-.125f + r/s)/x; +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/j1.c b/lib/mlibc/options/ansi/musl-generic-math/j1.c new file mode 100644 index 0000000..df724d1 --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/j1.c @@ -0,0 +1,362 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_j1.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* j1(x), y1(x) + * Bessel function of the first and second kinds of order zero. + * Method -- j1(x): + * 1. For tiny x, we use j1(x) = x/2 - x^3/16 + x^5/384 - ... + * 2. Reduce x to |x| since j1(x)=-j1(-x), and + * for x in (0,2) + * j1(x) = x/2 + x*z*R0/S0, where z = x*x; + * (precision: |j1/x - 1/2 - R0/S0 |<2**-61.51 ) + * for x in (2,inf) + * j1(x) = sqrt(2/(pi*x))*(p1(x)*cos(x1)-q1(x)*sin(x1)) + * y1(x) = sqrt(2/(pi*x))*(p1(x)*sin(x1)+q1(x)*cos(x1)) + * where x1 = x-3*pi/4. It is better to compute sin(x1),cos(x1) + * as follow: + * cos(x1) = cos(x)cos(3pi/4)+sin(x)sin(3pi/4) + * = 1/sqrt(2) * (sin(x) - cos(x)) + * sin(x1) = sin(x)cos(3pi/4)-cos(x)sin(3pi/4) + * = -1/sqrt(2) * (sin(x) + cos(x)) + * (To avoid cancellation, use + * sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x)) + * to compute the worse one.) + * + * 3 Special cases + * j1(nan)= nan + * j1(0) = 0 + * j1(inf) = 0 + * + * Method -- y1(x): + * 1. screen out x<=0 cases: y1(0)=-inf, y1(x<0)=NaN + * 2. For x<2. + * Since + * y1(x) = 2/pi*(j1(x)*(ln(x/2)+Euler)-1/x-x/2+5/64*x^3-...) + * therefore y1(x)-2/pi*j1(x)*ln(x)-1/x is an odd function. + * We use the following function to approximate y1, + * y1(x) = x*U(z)/V(z) + (2/pi)*(j1(x)*ln(x)-1/x), z= x^2 + * where for x in [0,2] (abs err less than 2**-65.89) + * U(z) = U0[0] + U0[1]*z + ... + U0[4]*z^4 + * V(z) = 1 + v0[0]*z + ... + v0[4]*z^5 + * Note: For tiny x, 1/x dominate y1 and hence + * y1(tiny) = -2/pi/tiny, (choose tiny<2**-54) + * 3. For x>=2. + * y1(x) = sqrt(2/(pi*x))*(p1(x)*sin(x1)+q1(x)*cos(x1)) + * where x1 = x-3*pi/4. It is better to compute sin(x1),cos(x1) + * by method mentioned above. + */ + +#include "libm.h" + +static double pone(double), qone(double); + +static const double +invsqrtpi = 5.64189583547756279280e-01, /* 0x3FE20DD7, 0x50429B6D */ +tpi = 6.36619772367581382433e-01; /* 0x3FE45F30, 0x6DC9C883 */ + +static double common(uint32_t ix, double x, int y1, int sign) +{ + double z,s,c,ss,cc; + + /* + * j1(x) = sqrt(2/(pi*x))*(p1(x)*cos(x-3pi/4)-q1(x)*sin(x-3pi/4)) + * y1(x) = sqrt(2/(pi*x))*(p1(x)*sin(x-3pi/4)+q1(x)*cos(x-3pi/4)) + * + * sin(x-3pi/4) = -(sin(x) + cos(x))/sqrt(2) + * cos(x-3pi/4) = (sin(x) - cos(x))/sqrt(2) + * sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x)) + */ + s = sin(x); + if (y1) + s = -s; + c = cos(x); + cc = s-c; + if (ix < 0x7fe00000) { + /* avoid overflow in 2*x */ + ss = -s-c; + z = cos(2*x); + if (s*c > 0) + cc = z/ss; + else + ss = z/cc; + if (ix < 0x48000000) { + if (y1) + ss = -ss; + cc = pone(x)*cc-qone(x)*ss; + } + } + if (sign) + cc = -cc; + return invsqrtpi*cc/sqrt(x); +} + +/* R0/S0 on [0,2] */ +static const double +r00 = -6.25000000000000000000e-02, /* 0xBFB00000, 0x00000000 */ +r01 = 1.40705666955189706048e-03, /* 0x3F570D9F, 0x98472C61 */ +r02 = -1.59955631084035597520e-05, /* 0xBEF0C5C6, 0xBA169668 */ +r03 = 4.96727999609584448412e-08, /* 0x3E6AAAFA, 0x46CA0BD9 */ +s01 = 1.91537599538363460805e-02, /* 0x3F939D0B, 0x12637E53 */ +s02 = 1.85946785588630915560e-04, /* 0x3F285F56, 0xB9CDF664 */ +s03 = 1.17718464042623683263e-06, /* 0x3EB3BFF8, 0x333F8498 */ +s04 = 5.04636257076217042715e-09, /* 0x3E35AC88, 0xC97DFF2C */ +s05 = 1.23542274426137913908e-11; /* 0x3DAB2ACF, 0xCFB97ED8 */ + +double j1(double x) +{ + double z,r,s; + uint32_t ix; + int sign; + + GET_HIGH_WORD(ix, x); + sign = ix>>31; + ix &= 0x7fffffff; + if (ix >= 0x7ff00000) + return 1/(x*x); + if (ix >= 0x40000000) /* |x| >= 2 */ + return common(ix, fabs(x), 0, sign); + if (ix >= 0x38000000) { /* |x| >= 2**-127 */ + z = x*x; + r = z*(r00+z*(r01+z*(r02+z*r03))); + s = 1+z*(s01+z*(s02+z*(s03+z*(s04+z*s05)))); + z = r/s; + } else + /* avoid underflow, raise inexact if x!=0 */ + z = x; + return (0.5 + z)*x; +} + +static const double U0[5] = { + -1.96057090646238940668e-01, /* 0xBFC91866, 0x143CBC8A */ + 5.04438716639811282616e-02, /* 0x3FA9D3C7, 0x76292CD1 */ + -1.91256895875763547298e-03, /* 0xBF5F55E5, 0x4844F50F */ + 2.35252600561610495928e-05, /* 0x3EF8AB03, 0x8FA6B88E */ + -9.19099158039878874504e-08, /* 0xBE78AC00, 0x569105B8 */ +}; +static const double V0[5] = { + 1.99167318236649903973e-02, /* 0x3F94650D, 0x3F4DA9F0 */ + 2.02552581025135171496e-04, /* 0x3F2A8C89, 0x6C257764 */ + 1.35608801097516229404e-06, /* 0x3EB6C05A, 0x894E8CA6 */ + 6.22741452364621501295e-09, /* 0x3E3ABF1D, 0x5BA69A86 */ + 1.66559246207992079114e-11, /* 0x3DB25039, 0xDACA772A */ +}; + +double y1(double x) +{ + double z,u,v; + uint32_t ix,lx; + + EXTRACT_WORDS(ix, lx, x); + /* y1(nan)=nan, y1(<0)=nan, y1(0)=-inf, y1(inf)=0 */ + if ((ix<<1 | lx) == 0) + return -1/0.0; + if (ix>>31) + return 0/0.0; + if (ix >= 0x7ff00000) + return 1/x; + + if (ix >= 0x40000000) /* x >= 2 */ + return common(ix, x, 1, 0); + if (ix < 0x3c900000) /* x < 2**-54 */ + return -tpi/x; + z = x*x; + u = U0[0]+z*(U0[1]+z*(U0[2]+z*(U0[3]+z*U0[4]))); + v = 1+z*(V0[0]+z*(V0[1]+z*(V0[2]+z*(V0[3]+z*V0[4])))); + return x*(u/v) + tpi*(j1(x)*log(x)-1/x); +} + +/* For x >= 8, the asymptotic expansions of pone is + * 1 + 15/128 s^2 - 4725/2^15 s^4 - ..., where s = 1/x. + * We approximate pone by + * pone(x) = 1 + (R/S) + * where R = pr0 + pr1*s^2 + pr2*s^4 + ... + pr5*s^10 + * S = 1 + ps0*s^2 + ... + ps4*s^10 + * and + * | pone(x)-1-R/S | <= 2 ** ( -60.06) + */ + +static const double pr8[6] = { /* for x in [inf, 8]=1/[0,0.125] */ + 0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */ + 1.17187499999988647970e-01, /* 0x3FBDFFFF, 0xFFFFFCCE */ + 1.32394806593073575129e+01, /* 0x402A7A9D, 0x357F7FCE */ + 4.12051854307378562225e+02, /* 0x4079C0D4, 0x652EA590 */ + 3.87474538913960532227e+03, /* 0x40AE457D, 0xA3A532CC */ + 7.91447954031891731574e+03, /* 0x40BEEA7A, 0xC32782DD */ +}; +static const double ps8[5] = { + 1.14207370375678408436e+02, /* 0x405C8D45, 0x8E656CAC */ + 3.65093083420853463394e+03, /* 0x40AC85DC, 0x964D274F */ + 3.69562060269033463555e+04, /* 0x40E20B86, 0x97C5BB7F */ + 9.76027935934950801311e+04, /* 0x40F7D42C, 0xB28F17BB */ + 3.08042720627888811578e+04, /* 0x40DE1511, 0x697A0B2D */ +}; + +static const double pr5[6] = { /* for x in [8,4.5454]=1/[0.125,0.22001] */ + 1.31990519556243522749e-11, /* 0x3DAD0667, 0xDAE1CA7D */ + 1.17187493190614097638e-01, /* 0x3FBDFFFF, 0xE2C10043 */ + 6.80275127868432871736e+00, /* 0x401B3604, 0x6E6315E3 */ + 1.08308182990189109773e+02, /* 0x405B13B9, 0x452602ED */ + 5.17636139533199752805e+02, /* 0x40802D16, 0xD052D649 */ + 5.28715201363337541807e+02, /* 0x408085B8, 0xBB7E0CB7 */ +}; +static const double ps5[5] = { + 5.92805987221131331921e+01, /* 0x404DA3EA, 0xA8AF633D */ + 9.91401418733614377743e+02, /* 0x408EFB36, 0x1B066701 */ + 5.35326695291487976647e+03, /* 0x40B4E944, 0x5706B6FB */ + 7.84469031749551231769e+03, /* 0x40BEA4B0, 0xB8A5BB15 */ + 1.50404688810361062679e+03, /* 0x40978030, 0x036F5E51 */ +}; + +static const double pr3[6] = { + 3.02503916137373618024e-09, /* 0x3E29FC21, 0xA7AD9EDD */ + 1.17186865567253592491e-01, /* 0x3FBDFFF5, 0x5B21D17B */ + 3.93297750033315640650e+00, /* 0x400F76BC, 0xE85EAD8A */ + 3.51194035591636932736e+01, /* 0x40418F48, 0x9DA6D129 */ + 9.10550110750781271918e+01, /* 0x4056C385, 0x4D2C1837 */ + 4.85590685197364919645e+01, /* 0x4048478F, 0x8EA83EE5 */ +}; +static const double ps3[5] = { + 3.47913095001251519989e+01, /* 0x40416549, 0xA134069C */ + 3.36762458747825746741e+02, /* 0x40750C33, 0x07F1A75F */ + 1.04687139975775130551e+03, /* 0x40905B7C, 0x5037D523 */ + 8.90811346398256432622e+02, /* 0x408BD67D, 0xA32E31E9 */ + 1.03787932439639277504e+02, /* 0x4059F26D, 0x7C2EED53 */ +}; + +static const double pr2[6] = {/* for x in [2.8570,2]=1/[0.3499,0.5] */ + 1.07710830106873743082e-07, /* 0x3E7CE9D4, 0xF65544F4 */ + 1.17176219462683348094e-01, /* 0x3FBDFF42, 0xBE760D83 */ + 2.36851496667608785174e+00, /* 0x4002F2B7, 0xF98FAEC0 */ + 1.22426109148261232917e+01, /* 0x40287C37, 0x7F71A964 */ + 1.76939711271687727390e+01, /* 0x4031B1A8, 0x177F8EE2 */ + 5.07352312588818499250e+00, /* 0x40144B49, 0xA574C1FE */ +}; +static const double ps2[5] = { + 2.14364859363821409488e+01, /* 0x40356FBD, 0x8AD5ECDC */ + 1.25290227168402751090e+02, /* 0x405F5293, 0x14F92CD5 */ + 2.32276469057162813669e+02, /* 0x406D08D8, 0xD5A2DBD9 */ + 1.17679373287147100768e+02, /* 0x405D6B7A, 0xDA1884A9 */ + 8.36463893371618283368e+00, /* 0x4020BAB1, 0xF44E5192 */ +}; + +static double pone(double x) +{ + const double *p,*q; + double_t z,r,s; + uint32_t ix; + + GET_HIGH_WORD(ix, x); + ix &= 0x7fffffff; + if (ix >= 0x40200000){p = pr8; q = ps8;} + else if (ix >= 0x40122E8B){p = pr5; q = ps5;} + else if (ix >= 0x4006DB6D){p = pr3; q = ps3;} + else /*ix >= 0x40000000*/ {p = pr2; q = ps2;} + z = 1.0/(x*x); + r = p[0]+z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5])))); + s = 1.0+z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*q[4])))); + return 1.0+ r/s; +} + +/* For x >= 8, the asymptotic expansions of qone is + * 3/8 s - 105/1024 s^3 - ..., where s = 1/x. + * We approximate pone by + * qone(x) = s*(0.375 + (R/S)) + * where R = qr1*s^2 + qr2*s^4 + ... + qr5*s^10 + * S = 1 + qs1*s^2 + ... + qs6*s^12 + * and + * | qone(x)/s -0.375-R/S | <= 2 ** ( -61.13) + */ + +static const double qr8[6] = { /* for x in [inf, 8]=1/[0,0.125] */ + 0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */ + -1.02539062499992714161e-01, /* 0xBFBA3FFF, 0xFFFFFDF3 */ + -1.62717534544589987888e+01, /* 0xC0304591, 0xA26779F7 */ + -7.59601722513950107896e+02, /* 0xC087BCD0, 0x53E4B576 */ + -1.18498066702429587167e+04, /* 0xC0C724E7, 0x40F87415 */ + -4.84385124285750353010e+04, /* 0xC0E7A6D0, 0x65D09C6A */ +}; +static const double qs8[6] = { + 1.61395369700722909556e+02, /* 0x40642CA6, 0xDE5BCDE5 */ + 7.82538599923348465381e+03, /* 0x40BE9162, 0xD0D88419 */ + 1.33875336287249578163e+05, /* 0x4100579A, 0xB0B75E98 */ + 7.19657723683240939863e+05, /* 0x4125F653, 0x72869C19 */ + 6.66601232617776375264e+05, /* 0x412457D2, 0x7719AD5C */ + -2.94490264303834643215e+05, /* 0xC111F969, 0x0EA5AA18 */ +}; + +static const double qr5[6] = { /* for x in [8,4.5454]=1/[0.125,0.22001] */ + -2.08979931141764104297e-11, /* 0xBDB6FA43, 0x1AA1A098 */ + -1.02539050241375426231e-01, /* 0xBFBA3FFF, 0xCB597FEF */ + -8.05644828123936029840e+00, /* 0xC0201CE6, 0xCA03AD4B */ + -1.83669607474888380239e+02, /* 0xC066F56D, 0x6CA7B9B0 */ + -1.37319376065508163265e+03, /* 0xC09574C6, 0x6931734F */ + -2.61244440453215656817e+03, /* 0xC0A468E3, 0x88FDA79D */ +}; +static const double qs5[6] = { + 8.12765501384335777857e+01, /* 0x405451B2, 0xFF5A11B2 */ + 1.99179873460485964642e+03, /* 0x409F1F31, 0xE77BF839 */ + 1.74684851924908907677e+04, /* 0x40D10F1F, 0x0D64CE29 */ + 4.98514270910352279316e+04, /* 0x40E8576D, 0xAABAD197 */ + 2.79480751638918118260e+04, /* 0x40DB4B04, 0xCF7C364B */ + -4.71918354795128470869e+03, /* 0xC0B26F2E, 0xFCFFA004 */ +}; + +static const double qr3[6] = { + -5.07831226461766561369e-09, /* 0xBE35CFA9, 0xD38FC84F */ + -1.02537829820837089745e-01, /* 0xBFBA3FEB, 0x51AEED54 */ + -4.61011581139473403113e+00, /* 0xC01270C2, 0x3302D9FF */ + -5.78472216562783643212e+01, /* 0xC04CEC71, 0xC25D16DA */ + -2.28244540737631695038e+02, /* 0xC06C87D3, 0x4718D55F */ + -2.19210128478909325622e+02, /* 0xC06B66B9, 0x5F5C1BF6 */ +}; +static const double qs3[6] = { + 4.76651550323729509273e+01, /* 0x4047D523, 0xCCD367E4 */ + 6.73865112676699709482e+02, /* 0x40850EEB, 0xC031EE3E */ + 3.38015286679526343505e+03, /* 0x40AA684E, 0x448E7C9A */ + 5.54772909720722782367e+03, /* 0x40B5ABBA, 0xA61D54A6 */ + 1.90311919338810798763e+03, /* 0x409DBC7A, 0x0DD4DF4B */ + -1.35201191444307340817e+02, /* 0xC060E670, 0x290A311F */ +}; + +static const double qr2[6] = {/* for x in [2.8570,2]=1/[0.3499,0.5] */ + -1.78381727510958865572e-07, /* 0xBE87F126, 0x44C626D2 */ + -1.02517042607985553460e-01, /* 0xBFBA3E8E, 0x9148B010 */ + -2.75220568278187460720e+00, /* 0xC0060484, 0x69BB4EDA */ + -1.96636162643703720221e+01, /* 0xC033A9E2, 0xC168907F */ + -4.23253133372830490089e+01, /* 0xC04529A3, 0xDE104AAA */ + -2.13719211703704061733e+01, /* 0xC0355F36, 0x39CF6E52 */ +}; +static const double qs2[6] = { + 2.95333629060523854548e+01, /* 0x403D888A, 0x78AE64FF */ + 2.52981549982190529136e+02, /* 0x406F9F68, 0xDB821CBA */ + 7.57502834868645436472e+02, /* 0x4087AC05, 0xCE49A0F7 */ + 7.39393205320467245656e+02, /* 0x40871B25, 0x48D4C029 */ + 1.55949003336666123687e+02, /* 0x40637E5E, 0x3C3ED8D4 */ + -4.95949898822628210127e+00, /* 0xC013D686, 0xE71BE86B */ +}; + +static double qone(double x) +{ + const double *p,*q; + double_t s,r,z; + uint32_t ix; + + GET_HIGH_WORD(ix, x); + ix &= 0x7fffffff; + if (ix >= 0x40200000){p = qr8; q = qs8;} + else if (ix >= 0x40122E8B){p = qr5; q = qs5;} + else if (ix >= 0x4006DB6D){p = qr3; q = qs3;} + else /*ix >= 0x40000000*/ {p = qr2; q = qs2;} + z = 1.0/(x*x); + r = p[0]+z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5])))); + s = 1.0+z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*(q[4]+z*q[5]))))); + return (.375 + r/s)/x; +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/j1f.c b/lib/mlibc/options/ansi/musl-generic-math/j1f.c new file mode 100644 index 0000000..3434c53 --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/j1f.c @@ -0,0 +1,310 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_j1f.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#define _GNU_SOURCE +#include "libm.h" + +static float ponef(float), qonef(float); + +static const float +invsqrtpi = 5.6418961287e-01, /* 0x3f106ebb */ +tpi = 6.3661974669e-01; /* 0x3f22f983 */ + +static float common(uint32_t ix, float x, int y1, int sign) +{ + double z,s,c,ss,cc; + + s = sinf(x); + if (y1) + s = -s; + c = cosf(x); + cc = s-c; + if (ix < 0x7f000000) { + ss = -s-c; + z = cosf(2*x); + if (s*c > 0) + cc = z/ss; + else + ss = z/cc; + if (ix < 0x58800000) { + if (y1) + ss = -ss; + cc = ponef(x)*cc-qonef(x)*ss; + } + } + if (sign) + cc = -cc; + return invsqrtpi*cc/sqrtf(x); +} + +/* R0/S0 on [0,2] */ +static const float +r00 = -6.2500000000e-02, /* 0xbd800000 */ +r01 = 1.4070566976e-03, /* 0x3ab86cfd */ +r02 = -1.5995563444e-05, /* 0xb7862e36 */ +r03 = 4.9672799207e-08, /* 0x335557d2 */ +s01 = 1.9153760746e-02, /* 0x3c9ce859 */ +s02 = 1.8594678841e-04, /* 0x3942fab6 */ +s03 = 1.1771846857e-06, /* 0x359dffc2 */ +s04 = 5.0463624390e-09, /* 0x31ad6446 */ +s05 = 1.2354227016e-11; /* 0x2d59567e */ + +float j1f(float x) +{ + float z,r,s; + uint32_t ix; + int sign; + + GET_FLOAT_WORD(ix, x); + sign = ix>>31; + ix &= 0x7fffffff; + if (ix >= 0x7f800000) + return 1/(x*x); + if (ix >= 0x40000000) /* |x| >= 2 */ + return common(ix, fabsf(x), 0, sign); + if (ix >= 0x39000000) { /* |x| >= 2**-13 */ + z = x*x; + r = z*(r00+z*(r01+z*(r02+z*r03))); + s = 1+z*(s01+z*(s02+z*(s03+z*(s04+z*s05)))); + z = 0.5f + r/s; + } else + z = 0.5f; + return z*x; +} + +static const float U0[5] = { + -1.9605709612e-01, /* 0xbe48c331 */ + 5.0443872809e-02, /* 0x3d4e9e3c */ + -1.9125689287e-03, /* 0xbafaaf2a */ + 2.3525259166e-05, /* 0x37c5581c */ + -9.1909917899e-08, /* 0xb3c56003 */ +}; +static const float V0[5] = { + 1.9916731864e-02, /* 0x3ca3286a */ + 2.0255257550e-04, /* 0x3954644b */ + 1.3560879779e-06, /* 0x35b602d4 */ + 6.2274145840e-09, /* 0x31d5f8eb */ + 1.6655924903e-11, /* 0x2d9281cf */ +}; + +float y1f(float x) +{ + float z,u,v; + uint32_t ix; + + GET_FLOAT_WORD(ix, x); + if ((ix & 0x7fffffff) == 0) + return -1/0.0f; + if (ix>>31) + return 0/0.0f; + if (ix >= 0x7f800000) + return 1/x; + if (ix >= 0x40000000) /* |x| >= 2.0 */ + return common(ix,x,1,0); + if (ix < 0x33000000) /* x < 2**-25 */ + return -tpi/x; + z = x*x; + u = U0[0]+z*(U0[1]+z*(U0[2]+z*(U0[3]+z*U0[4]))); + v = 1.0f+z*(V0[0]+z*(V0[1]+z*(V0[2]+z*(V0[3]+z*V0[4])))); + return x*(u/v) + tpi*(j1f(x)*logf(x)-1.0f/x); +} + +/* For x >= 8, the asymptotic expansions of pone is + * 1 + 15/128 s^2 - 4725/2^15 s^4 - ..., where s = 1/x. + * We approximate pone by + * pone(x) = 1 + (R/S) + * where R = pr0 + pr1*s^2 + pr2*s^4 + ... + pr5*s^10 + * S = 1 + ps0*s^2 + ... + ps4*s^10 + * and + * | pone(x)-1-R/S | <= 2 ** ( -60.06) + */ + +static const float pr8[6] = { /* for x in [inf, 8]=1/[0,0.125] */ + 0.0000000000e+00, /* 0x00000000 */ + 1.1718750000e-01, /* 0x3df00000 */ + 1.3239480972e+01, /* 0x4153d4ea */ + 4.1205184937e+02, /* 0x43ce06a3 */ + 3.8747453613e+03, /* 0x45722bed */ + 7.9144794922e+03, /* 0x45f753d6 */ +}; +static const float ps8[5] = { + 1.1420736694e+02, /* 0x42e46a2c */ + 3.6509309082e+03, /* 0x45642ee5 */ + 3.6956207031e+04, /* 0x47105c35 */ + 9.7602796875e+04, /* 0x47bea166 */ + 3.0804271484e+04, /* 0x46f0a88b */ +}; + +static const float pr5[6] = { /* for x in [8,4.5454]=1/[0.125,0.22001] */ + 1.3199052094e-11, /* 0x2d68333f */ + 1.1718749255e-01, /* 0x3defffff */ + 6.8027510643e+00, /* 0x40d9b023 */ + 1.0830818176e+02, /* 0x42d89dca */ + 5.1763616943e+02, /* 0x440168b7 */ + 5.2871520996e+02, /* 0x44042dc6 */ +}; +static const float ps5[5] = { + 5.9280597687e+01, /* 0x426d1f55 */ + 9.9140142822e+02, /* 0x4477d9b1 */ + 5.3532670898e+03, /* 0x45a74a23 */ + 7.8446904297e+03, /* 0x45f52586 */ + 1.5040468750e+03, /* 0x44bc0180 */ +}; + +static const float pr3[6] = { + 3.0250391081e-09, /* 0x314fe10d */ + 1.1718686670e-01, /* 0x3defffab */ + 3.9329774380e+00, /* 0x407bb5e7 */ + 3.5119403839e+01, /* 0x420c7a45 */ + 9.1055007935e+01, /* 0x42b61c2a */ + 4.8559066772e+01, /* 0x42423c7c */ +}; +static const float ps3[5] = { + 3.4791309357e+01, /* 0x420b2a4d */ + 3.3676245117e+02, /* 0x43a86198 */ + 1.0468714600e+03, /* 0x4482dbe3 */ + 8.9081134033e+02, /* 0x445eb3ed */ + 1.0378793335e+02, /* 0x42cf936c */ +}; + +static const float pr2[6] = {/* for x in [2.8570,2]=1/[0.3499,0.5] */ + 1.0771083225e-07, /* 0x33e74ea8 */ + 1.1717621982e-01, /* 0x3deffa16 */ + 2.3685150146e+00, /* 0x401795c0 */ + 1.2242610931e+01, /* 0x4143e1bc */ + 1.7693971634e+01, /* 0x418d8d41 */ + 5.0735230446e+00, /* 0x40a25a4d */ +}; +static const float ps2[5] = { + 2.1436485291e+01, /* 0x41ab7dec */ + 1.2529022980e+02, /* 0x42fa9499 */ + 2.3227647400e+02, /* 0x436846c7 */ + 1.1767937469e+02, /* 0x42eb5bd7 */ + 8.3646392822e+00, /* 0x4105d590 */ +}; + +static float ponef(float x) +{ + const float *p,*q; + float_t z,r,s; + uint32_t ix; + + GET_FLOAT_WORD(ix, x); + ix &= 0x7fffffff; + if (ix >= 0x41000000){p = pr8; q = ps8;} + else if (ix >= 0x409173eb){p = pr5; q = ps5;} + else if (ix >= 0x4036d917){p = pr3; q = ps3;} + else /*ix >= 0x40000000*/ {p = pr2; q = ps2;} + z = 1.0f/(x*x); + r = p[0]+z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5])))); + s = 1.0f+z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*q[4])))); + return 1.0f + r/s; +} + +/* For x >= 8, the asymptotic expansions of qone is + * 3/8 s - 105/1024 s^3 - ..., where s = 1/x. + * We approximate pone by + * qone(x) = s*(0.375 + (R/S)) + * where R = qr1*s^2 + qr2*s^4 + ... + qr5*s^10 + * S = 1 + qs1*s^2 + ... + qs6*s^12 + * and + * | qone(x)/s -0.375-R/S | <= 2 ** ( -61.13) + */ + +static const float qr8[6] = { /* for x in [inf, 8]=1/[0,0.125] */ + 0.0000000000e+00, /* 0x00000000 */ + -1.0253906250e-01, /* 0xbdd20000 */ + -1.6271753311e+01, /* 0xc1822c8d */ + -7.5960174561e+02, /* 0xc43de683 */ + -1.1849806641e+04, /* 0xc639273a */ + -4.8438511719e+04, /* 0xc73d3683 */ +}; +static const float qs8[6] = { + 1.6139537048e+02, /* 0x43216537 */ + 7.8253862305e+03, /* 0x45f48b17 */ + 1.3387534375e+05, /* 0x4802bcd6 */ + 7.1965775000e+05, /* 0x492fb29c */ + 6.6660125000e+05, /* 0x4922be94 */ + -2.9449025000e+05, /* 0xc88fcb48 */ +}; + +static const float qr5[6] = { /* for x in [8,4.5454]=1/[0.125,0.22001] */ + -2.0897993405e-11, /* 0xadb7d219 */ + -1.0253904760e-01, /* 0xbdd1fffe */ + -8.0564479828e+00, /* 0xc100e736 */ + -1.8366960144e+02, /* 0xc337ab6b */ + -1.3731937256e+03, /* 0xc4aba633 */ + -2.6124443359e+03, /* 0xc523471c */ +}; +static const float qs5[6] = { + 8.1276550293e+01, /* 0x42a28d98 */ + 1.9917987061e+03, /* 0x44f8f98f */ + 1.7468484375e+04, /* 0x468878f8 */ + 4.9851425781e+04, /* 0x4742bb6d */ + 2.7948074219e+04, /* 0x46da5826 */ + -4.7191835938e+03, /* 0xc5937978 */ +}; + +static const float qr3[6] = { + -5.0783124372e-09, /* 0xb1ae7d4f */ + -1.0253783315e-01, /* 0xbdd1ff5b */ + -4.6101160049e+00, /* 0xc0938612 */ + -5.7847221375e+01, /* 0xc267638e */ + -2.2824453735e+02, /* 0xc3643e9a */ + -2.1921012878e+02, /* 0xc35b35cb */ +}; +static const float qs3[6] = { + 4.7665153503e+01, /* 0x423ea91e */ + 6.7386511230e+02, /* 0x4428775e */ + 3.3801528320e+03, /* 0x45534272 */ + 5.5477290039e+03, /* 0x45ad5dd5 */ + 1.9031191406e+03, /* 0x44ede3d0 */ + -1.3520118713e+02, /* 0xc3073381 */ +}; + +static const float qr2[6] = {/* for x in [2.8570,2]=1/[0.3499,0.5] */ + -1.7838172539e-07, /* 0xb43f8932 */ + -1.0251704603e-01, /* 0xbdd1f475 */ + -2.7522056103e+00, /* 0xc0302423 */ + -1.9663616180e+01, /* 0xc19d4f16 */ + -4.2325313568e+01, /* 0xc2294d1f */ + -2.1371921539e+01, /* 0xc1aaf9b2 */ +}; +static const float qs2[6] = { + 2.9533363342e+01, /* 0x41ec4454 */ + 2.5298155212e+02, /* 0x437cfb47 */ + 7.5750280762e+02, /* 0x443d602e */ + 7.3939318848e+02, /* 0x4438d92a */ + 1.5594900513e+02, /* 0x431bf2f2 */ + -4.9594988823e+00, /* 0xc09eb437 */ +}; + +static float qonef(float x) +{ + const float *p,*q; + float_t s,r,z; + uint32_t ix; + + GET_FLOAT_WORD(ix, x); + ix &= 0x7fffffff; + if (ix >= 0x41000000){p = qr8; q = qs8;} + else if (ix >= 0x409173eb){p = qr5; q = qs5;} + else if (ix >= 0x4036d917){p = qr3; q = qs3;} + else /*ix >= 0x40000000*/ {p = qr2; q = qs2;} + z = 1.0f/(x*x); + r = p[0]+z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5])))); + s = 1.0f+z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*(q[4]+z*q[5]))))); + return (.375f + r/s)/x; +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/jn.c b/lib/mlibc/options/ansi/musl-generic-math/jn.c new file mode 100644 index 0000000..4878a54 --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/jn.c @@ -0,0 +1,280 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_jn.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* + * jn(n, x), yn(n, x) + * floating point Bessel's function of the 1st and 2nd kind + * of order n + * + * Special cases: + * y0(0)=y1(0)=yn(n,0) = -inf with division by zero signal; + * y0(-ve)=y1(-ve)=yn(n,-ve) are NaN with invalid signal. + * Note 2. About jn(n,x), yn(n,x) + * For n=0, j0(x) is called, + * for n=1, j1(x) is called, + * for n<=x, forward recursion is used starting + * from values of j0(x) and j1(x). + * for n>x, a continued fraction approximation to + * j(n,x)/j(n-1,x) is evaluated and then backward + * recursion is used starting from a supposed value + * for j(n,x). The resulting value of j(0,x) is + * compared with the actual value to correct the + * supposed value of j(n,x). + * + * yn(n,x) is similar in all respects, except + * that forward recursion is used for all + * values of n>1. + */ + +#include "libm.h" + +static const double invsqrtpi = 5.64189583547756279280e-01; /* 0x3FE20DD7, 0x50429B6D */ + +double jn(int n, double x) +{ + uint32_t ix, lx; + int nm1, i, sign; + double a, b, temp; + + EXTRACT_WORDS(ix, lx, x); + sign = ix>>31; + ix &= 0x7fffffff; + + if ((ix | (lx|-lx)>>31) > 0x7ff00000) /* nan */ + return x; + + /* J(-n,x) = (-1)^n * J(n, x), J(n, -x) = (-1)^n * J(n, x) + * Thus, J(-n,x) = J(n,-x) + */ + /* nm1 = |n|-1 is used instead of |n| to handle n==INT_MIN */ + if (n == 0) + return j0(x); + if (n < 0) { + nm1 = -(n+1); + x = -x; + sign ^= 1; + } else + nm1 = n-1; + if (nm1 == 0) + return j1(x); + + sign &= n; /* even n: 0, odd n: signbit(x) */ + x = fabs(x); + if ((ix|lx) == 0 || ix == 0x7ff00000) /* if x is 0 or inf */ + b = 0.0; + else if (nm1 < x) { + /* Safe to use J(n+1,x)=2n/x *J(n,x)-J(n-1,x) */ + if (ix >= 0x52d00000) { /* x > 2**302 */ + /* (x >> n**2) + * Jn(x) = cos(x-(2n+1)*pi/4)*sqrt(2/x*pi) + * Yn(x) = sin(x-(2n+1)*pi/4)*sqrt(2/x*pi) + * Let s=sin(x), c=cos(x), + * xn=x-(2n+1)*pi/4, sqt2 = sqrt(2),then + * + * n sin(xn)*sqt2 cos(xn)*sqt2 + * ---------------------------------- + * 0 s-c c+s + * 1 -s-c -c+s + * 2 -s+c -c-s + * 3 s+c c-s + */ + switch(nm1&3) { + case 0: temp = -cos(x)+sin(x); break; + case 1: temp = -cos(x)-sin(x); break; + case 2: temp = cos(x)-sin(x); break; + default: + case 3: temp = cos(x)+sin(x); break; + } + b = invsqrtpi*temp/sqrt(x); + } else { + a = j0(x); + b = j1(x); + for (i=0; i 32) /* underflow */ + b = 0.0; + else { + temp = x*0.5; + b = temp; + a = 1.0; + for (i=2; i<=nm1+1; i++) { + a *= (double)i; /* a = n! */ + b *= temp; /* b = (x/2)^n */ + } + b = b/a; + } + } else { + /* use backward recurrence */ + /* x x^2 x^2 + * J(n,x)/J(n-1,x) = ---- ------ ------ ..... + * 2n - 2(n+1) - 2(n+2) + * + * 1 1 1 + * (for large x) = ---- ------ ------ ..... + * 2n 2(n+1) 2(n+2) + * -- - ------ - ------ - + * x x x + * + * Let w = 2n/x and h=2/x, then the above quotient + * is equal to the continued fraction: + * 1 + * = ----------------------- + * 1 + * w - ----------------- + * 1 + * w+h - --------- + * w+2h - ... + * + * To determine how many terms needed, let + * Q(0) = w, Q(1) = w(w+h) - 1, + * Q(k) = (w+k*h)*Q(k-1) - Q(k-2), + * When Q(k) > 1e4 good for single + * When Q(k) > 1e9 good for double + * When Q(k) > 1e17 good for quadruple + */ + /* determine k */ + double t,q0,q1,w,h,z,tmp,nf; + int k; + + nf = nm1 + 1.0; + w = 2*nf/x; + h = 2/x; + z = w+h; + q0 = w; + q1 = w*z - 1.0; + k = 1; + while (q1 < 1.0e9) { + k += 1; + z += h; + tmp = z*q1 - q0; + q0 = q1; + q1 = tmp; + } + for (t=0.0, i=k; i>=0; i--) + t = 1/(2*(i+nf)/x - t); + a = t; + b = 1.0; + /* estimate log((2/x)^n*n!) = n*log(2/x)+n*ln(n) + * Hence, if n*(log(2n/x)) > ... + * single 8.8722839355e+01 + * double 7.09782712893383973096e+02 + * long double 1.1356523406294143949491931077970765006170e+04 + * then recurrent value may overflow and the result is + * likely underflow to zero + */ + tmp = nf*log(fabs(w)); + if (tmp < 7.09782712893383973096e+02) { + for (i=nm1; i>0; i--) { + temp = b; + b = b*(2.0*i)/x - a; + a = temp; + } + } else { + for (i=nm1; i>0; i--) { + temp = b; + b = b*(2.0*i)/x - a; + a = temp; + /* scale b to avoid spurious overflow */ + if (b > 0x1p500) { + a /= b; + t /= b; + b = 1.0; + } + } + } + z = j0(x); + w = j1(x); + if (fabs(z) >= fabs(w)) + b = t*z/b; + else + b = t*w/a; + } + } + return sign ? -b : b; +} + + +double yn(int n, double x) +{ + uint32_t ix, lx, ib; + int nm1, sign, i; + double a, b, temp; + + EXTRACT_WORDS(ix, lx, x); + sign = ix>>31; + ix &= 0x7fffffff; + + if ((ix | (lx|-lx)>>31) > 0x7ff00000) /* nan */ + return x; + if (sign && (ix|lx)!=0) /* x < 0 */ + return 0/0.0; + if (ix == 0x7ff00000) + return 0.0; + + if (n == 0) + return y0(x); + if (n < 0) { + nm1 = -(n+1); + sign = n&1; + } else { + nm1 = n-1; + sign = 0; + } + if (nm1 == 0) + return sign ? -y1(x) : y1(x); + + if (ix >= 0x52d00000) { /* x > 2**302 */ + /* (x >> n**2) + * Jn(x) = cos(x-(2n+1)*pi/4)*sqrt(2/x*pi) + * Yn(x) = sin(x-(2n+1)*pi/4)*sqrt(2/x*pi) + * Let s=sin(x), c=cos(x), + * xn=x-(2n+1)*pi/4, sqt2 = sqrt(2),then + * + * n sin(xn)*sqt2 cos(xn)*sqt2 + * ---------------------------------- + * 0 s-c c+s + * 1 -s-c -c+s + * 2 -s+c -c-s + * 3 s+c c-s + */ + switch(nm1&3) { + case 0: temp = -sin(x)-cos(x); break; + case 1: temp = -sin(x)+cos(x); break; + case 2: temp = sin(x)+cos(x); break; + default: + case 3: temp = sin(x)-cos(x); break; + } + b = invsqrtpi*temp/sqrt(x); + } else { + a = y0(x); + b = y1(x); + /* quit if b is -inf */ + GET_HIGH_WORD(ib, b); + for (i=0; i>31; + ix &= 0x7fffffff; + if (ix > 0x7f800000) /* nan */ + return x; + + /* J(-n,x) = J(n,-x), use |n|-1 to avoid overflow in -n */ + if (n == 0) + return j0f(x); + if (n < 0) { + nm1 = -(n+1); + x = -x; + sign ^= 1; + } else + nm1 = n-1; + if (nm1 == 0) + return j1f(x); + + sign &= n; /* even n: 0, odd n: signbit(x) */ + x = fabsf(x); + if (ix == 0 || ix == 0x7f800000) /* if x is 0 or inf */ + b = 0.0f; + else if (nm1 < x) { + /* Safe to use J(n+1,x)=2n/x *J(n,x)-J(n-1,x) */ + a = j0f(x); + b = j1f(x); + for (i=0; i 8) /* underflow */ + nm1 = 8; + temp = 0.5f * x; + b = temp; + a = 1.0f; + for (i=2; i<=nm1+1; i++) { + a *= (float)i; /* a = n! */ + b *= temp; /* b = (x/2)^n */ + } + b = b/a; + } else { + /* use backward recurrence */ + /* x x^2 x^2 + * J(n,x)/J(n-1,x) = ---- ------ ------ ..... + * 2n - 2(n+1) - 2(n+2) + * + * 1 1 1 + * (for large x) = ---- ------ ------ ..... + * 2n 2(n+1) 2(n+2) + * -- - ------ - ------ - + * x x x + * + * Let w = 2n/x and h=2/x, then the above quotient + * is equal to the continued fraction: + * 1 + * = ----------------------- + * 1 + * w - ----------------- + * 1 + * w+h - --------- + * w+2h - ... + * + * To determine how many terms needed, let + * Q(0) = w, Q(1) = w(w+h) - 1, + * Q(k) = (w+k*h)*Q(k-1) - Q(k-2), + * When Q(k) > 1e4 good for single + * When Q(k) > 1e9 good for double + * When Q(k) > 1e17 good for quadruple + */ + /* determine k */ + float t,q0,q1,w,h,z,tmp,nf; + int k; + + nf = nm1+1.0f; + w = 2*nf/x; + h = 2/x; + z = w+h; + q0 = w; + q1 = w*z - 1.0f; + k = 1; + while (q1 < 1.0e4f) { + k += 1; + z += h; + tmp = z*q1 - q0; + q0 = q1; + q1 = tmp; + } + for (t=0.0f, i=k; i>=0; i--) + t = 1.0f/(2*(i+nf)/x-t); + a = t; + b = 1.0f; + /* estimate log((2/x)^n*n!) = n*log(2/x)+n*ln(n) + * Hence, if n*(log(2n/x)) > ... + * single 8.8722839355e+01 + * double 7.09782712893383973096e+02 + * long double 1.1356523406294143949491931077970765006170e+04 + * then recurrent value may overflow and the result is + * likely underflow to zero + */ + tmp = nf*logf(fabsf(w)); + if (tmp < 88.721679688f) { + for (i=nm1; i>0; i--) { + temp = b; + b = 2.0f*i*b/x - a; + a = temp; + } + } else { + for (i=nm1; i>0; i--){ + temp = b; + b = 2.0f*i*b/x - a; + a = temp; + /* scale b to avoid spurious overflow */ + if (b > 0x1p60f) { + a /= b; + t /= b; + b = 1.0f; + } + } + } + z = j0f(x); + w = j1f(x); + if (fabsf(z) >= fabsf(w)) + b = t*z/b; + else + b = t*w/a; + } + } + return sign ? -b : b; +} + +float ynf(int n, float x) +{ + uint32_t ix, ib; + int nm1, sign, i; + float a, b, temp; + + GET_FLOAT_WORD(ix, x); + sign = ix>>31; + ix &= 0x7fffffff; + if (ix > 0x7f800000) /* nan */ + return x; + if (sign && ix != 0) /* x < 0 */ + return 0/0.0f; + if (ix == 0x7f800000) + return 0.0f; + + if (n == 0) + return y0f(x); + if (n < 0) { + nm1 = -(n+1); + sign = n&1; + } else { + nm1 = n-1; + sign = 0; + } + if (nm1 == 0) + return sign ? -y1f(x) : y1f(x); + + a = y0f(x); + b = y1f(x); + /* quit if b is -inf */ + GET_FLOAT_WORD(ib,b); + for (i = 0; i < nm1 && ib != 0xff800000; ) { + i++; + temp = b; + b = (2.0f*i/x)*b - a; + GET_FLOAT_WORD(ib, b); + a = temp; + } + return sign ? -b : b; +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/ldexp.c b/lib/mlibc/options/ansi/musl-generic-math/ldexp.c new file mode 100644 index 0000000..f4d1cd6 --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/ldexp.c @@ -0,0 +1,6 @@ +#include + +double ldexp(double x, int n) +{ + return scalbn(x, n); +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/ldexpf.c b/lib/mlibc/options/ansi/musl-generic-math/ldexpf.c new file mode 100644 index 0000000..3bad5f3 --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/ldexpf.c @@ -0,0 +1,6 @@ +#include + +float ldexpf(float x, int n) +{ + return scalbnf(x, n); +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/ldexpl.c b/lib/mlibc/options/ansi/musl-generic-math/ldexpl.c new file mode 100644 index 0000000..fd145cc --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/ldexpl.c @@ -0,0 +1,6 @@ +#include + +long double ldexpl(long double x, int n) +{ + return scalbnl(x, n); +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/lgamma.c b/lib/mlibc/options/ansi/musl-generic-math/lgamma.c new file mode 100644 index 0000000..e25ec8e --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/lgamma.c @@ -0,0 +1,9 @@ +#include + +extern int __signgam; +double __lgamma_r(double, int *); + +double lgamma(double x) +{ + return __lgamma_r(x, &__signgam); +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/lgamma_r.c b/lib/mlibc/options/ansi/musl-generic-math/lgamma_r.c new file mode 100644 index 0000000..84596a3 --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/lgamma_r.c @@ -0,0 +1,285 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_lgamma_r.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + * + */ +/* lgamma_r(x, signgamp) + * Reentrant version of the logarithm of the Gamma function + * with user provide pointer for the sign of Gamma(x). + * + * Method: + * 1. Argument Reduction for 0 < x <= 8 + * Since gamma(1+s)=s*gamma(s), for x in [0,8], we may + * reduce x to a number in [1.5,2.5] by + * lgamma(1+s) = log(s) + lgamma(s) + * for example, + * lgamma(7.3) = log(6.3) + lgamma(6.3) + * = log(6.3*5.3) + lgamma(5.3) + * = log(6.3*5.3*4.3*3.3*2.3) + lgamma(2.3) + * 2. Polynomial approximation of lgamma around its + * minimun ymin=1.461632144968362245 to maintain monotonicity. + * On [ymin-0.23, ymin+0.27] (i.e., [1.23164,1.73163]), use + * Let z = x-ymin; + * lgamma(x) = -1.214862905358496078218 + z^2*poly(z) + * where + * poly(z) is a 14 degree polynomial. + * 2. Rational approximation in the primary interval [2,3] + * We use the following approximation: + * s = x-2.0; + * lgamma(x) = 0.5*s + s*P(s)/Q(s) + * with accuracy + * |P/Q - (lgamma(x)-0.5s)| < 2**-61.71 + * Our algorithms are based on the following observation + * + * zeta(2)-1 2 zeta(3)-1 3 + * lgamma(2+s) = s*(1-Euler) + --------- * s - --------- * s + ... + * 2 3 + * + * where Euler = 0.5771... is the Euler constant, which is very + * close to 0.5. + * + * 3. For x>=8, we have + * lgamma(x)~(x-0.5)log(x)-x+0.5*log(2pi)+1/(12x)-1/(360x**3)+.... + * (better formula: + * lgamma(x)~(x-0.5)*(log(x)-1)-.5*(log(2pi)-1) + ...) + * Let z = 1/x, then we approximation + * f(z) = lgamma(x) - (x-0.5)(log(x)-1) + * by + * 3 5 11 + * w = w0 + w1*z + w2*z + w3*z + ... + w6*z + * where + * |w - f(z)| < 2**-58.74 + * + * 4. For negative x, since (G is gamma function) + * -x*G(-x)*G(x) = pi/sin(pi*x), + * we have + * G(x) = pi/(sin(pi*x)*(-x)*G(-x)) + * since G(-x) is positive, sign(G(x)) = sign(sin(pi*x)) for x<0 + * Hence, for x<0, signgam = sign(sin(pi*x)) and + * lgamma(x) = log(|Gamma(x)|) + * = log(pi/(|x*sin(pi*x)|)) - lgamma(-x); + * Note: one should avoid compute pi*(-x) directly in the + * computation of sin(pi*(-x)). + * + * 5. Special Cases + * lgamma(2+s) ~ s*(1-Euler) for tiny s + * lgamma(1) = lgamma(2) = 0 + * lgamma(x) ~ -log(|x|) for tiny x + * lgamma(0) = lgamma(neg.integer) = inf and raise divide-by-zero + * lgamma(inf) = inf + * lgamma(-inf) = inf (bug for bug compatible with C99!?) + * + */ + +#include "libm.h" +#include "weak_alias.h" +//#include "libc.h" + +static const double +pi = 3.14159265358979311600e+00, /* 0x400921FB, 0x54442D18 */ +a0 = 7.72156649015328655494e-02, /* 0x3FB3C467, 0xE37DB0C8 */ +a1 = 3.22467033424113591611e-01, /* 0x3FD4A34C, 0xC4A60FAD */ +a2 = 6.73523010531292681824e-02, /* 0x3FB13E00, 0x1A5562A7 */ +a3 = 2.05808084325167332806e-02, /* 0x3F951322, 0xAC92547B */ +a4 = 7.38555086081402883957e-03, /* 0x3F7E404F, 0xB68FEFE8 */ +a5 = 2.89051383673415629091e-03, /* 0x3F67ADD8, 0xCCB7926B */ +a6 = 1.19270763183362067845e-03, /* 0x3F538A94, 0x116F3F5D */ +a7 = 5.10069792153511336608e-04, /* 0x3F40B6C6, 0x89B99C00 */ +a8 = 2.20862790713908385557e-04, /* 0x3F2CF2EC, 0xED10E54D */ +a9 = 1.08011567247583939954e-04, /* 0x3F1C5088, 0x987DFB07 */ +a10 = 2.52144565451257326939e-05, /* 0x3EFA7074, 0x428CFA52 */ +a11 = 4.48640949618915160150e-05, /* 0x3F07858E, 0x90A45837 */ +tc = 1.46163214496836224576e+00, /* 0x3FF762D8, 0x6356BE3F */ +tf = -1.21486290535849611461e-01, /* 0xBFBF19B9, 0xBCC38A42 */ +/* tt = -(tail of tf) */ +tt = -3.63867699703950536541e-18, /* 0xBC50C7CA, 0xA48A971F */ +t0 = 4.83836122723810047042e-01, /* 0x3FDEF72B, 0xC8EE38A2 */ +t1 = -1.47587722994593911752e-01, /* 0xBFC2E427, 0x8DC6C509 */ +t2 = 6.46249402391333854778e-02, /* 0x3FB08B42, 0x94D5419B */ +t3 = -3.27885410759859649565e-02, /* 0xBFA0C9A8, 0xDF35B713 */ +t4 = 1.79706750811820387126e-02, /* 0x3F9266E7, 0x970AF9EC */ +t5 = -1.03142241298341437450e-02, /* 0xBF851F9F, 0xBA91EC6A */ +t6 = 6.10053870246291332635e-03, /* 0x3F78FCE0, 0xE370E344 */ +t7 = -3.68452016781138256760e-03, /* 0xBF6E2EFF, 0xB3E914D7 */ +t8 = 2.25964780900612472250e-03, /* 0x3F6282D3, 0x2E15C915 */ +t9 = -1.40346469989232843813e-03, /* 0xBF56FE8E, 0xBF2D1AF1 */ +t10 = 8.81081882437654011382e-04, /* 0x3F4CDF0C, 0xEF61A8E9 */ +t11 = -5.38595305356740546715e-04, /* 0xBF41A610, 0x9C73E0EC */ +t12 = 3.15632070903625950361e-04, /* 0x3F34AF6D, 0x6C0EBBF7 */ +t13 = -3.12754168375120860518e-04, /* 0xBF347F24, 0xECC38C38 */ +t14 = 3.35529192635519073543e-04, /* 0x3F35FD3E, 0xE8C2D3F4 */ +u0 = -7.72156649015328655494e-02, /* 0xBFB3C467, 0xE37DB0C8 */ +u1 = 6.32827064025093366517e-01, /* 0x3FE4401E, 0x8B005DFF */ +u2 = 1.45492250137234768737e+00, /* 0x3FF7475C, 0xD119BD6F */ +u3 = 9.77717527963372745603e-01, /* 0x3FEF4976, 0x44EA8450 */ +u4 = 2.28963728064692451092e-01, /* 0x3FCD4EAE, 0xF6010924 */ +u5 = 1.33810918536787660377e-02, /* 0x3F8B678B, 0xBF2BAB09 */ +v1 = 2.45597793713041134822e+00, /* 0x4003A5D7, 0xC2BD619C */ +v2 = 2.12848976379893395361e+00, /* 0x40010725, 0xA42B18F5 */ +v3 = 7.69285150456672783825e-01, /* 0x3FE89DFB, 0xE45050AF */ +v4 = 1.04222645593369134254e-01, /* 0x3FBAAE55, 0xD6537C88 */ +v5 = 3.21709242282423911810e-03, /* 0x3F6A5ABB, 0x57D0CF61 */ +s0 = -7.72156649015328655494e-02, /* 0xBFB3C467, 0xE37DB0C8 */ +s1 = 2.14982415960608852501e-01, /* 0x3FCB848B, 0x36E20878 */ +s2 = 3.25778796408930981787e-01, /* 0x3FD4D98F, 0x4F139F59 */ +s3 = 1.46350472652464452805e-01, /* 0x3FC2BB9C, 0xBEE5F2F7 */ +s4 = 2.66422703033638609560e-02, /* 0x3F9B481C, 0x7E939961 */ +s5 = 1.84028451407337715652e-03, /* 0x3F5E26B6, 0x7368F239 */ +s6 = 3.19475326584100867617e-05, /* 0x3F00BFEC, 0xDD17E945 */ +r1 = 1.39200533467621045958e+00, /* 0x3FF645A7, 0x62C4AB74 */ +r2 = 7.21935547567138069525e-01, /* 0x3FE71A18, 0x93D3DCDC */ +r3 = 1.71933865632803078993e-01, /* 0x3FC601ED, 0xCCFBDF27 */ +r4 = 1.86459191715652901344e-02, /* 0x3F9317EA, 0x742ED475 */ +r5 = 7.77942496381893596434e-04, /* 0x3F497DDA, 0xCA41A95B */ +r6 = 7.32668430744625636189e-06, /* 0x3EDEBAF7, 0xA5B38140 */ +w0 = 4.18938533204672725052e-01, /* 0x3FDACFE3, 0x90C97D69 */ +w1 = 8.33333333333329678849e-02, /* 0x3FB55555, 0x5555553B */ +w2 = -2.77777777728775536470e-03, /* 0xBF66C16C, 0x16B02E5C */ +w3 = 7.93650558643019558500e-04, /* 0x3F4A019F, 0x98CF38B6 */ +w4 = -5.95187557450339963135e-04, /* 0xBF4380CB, 0x8C0FE741 */ +w5 = 8.36339918996282139126e-04, /* 0x3F4B67BA, 0x4CDAD5D1 */ +w6 = -1.63092934096575273989e-03; /* 0xBF5AB89D, 0x0B9E43E4 */ + +/* sin(pi*x) assuming x > 2^-100, if sin(pi*x)==0 the sign is arbitrary */ +static double sin_pi(double x) +{ + int n; + + /* spurious inexact if odd int */ + x = 2.0*(x*0.5 - floor(x*0.5)); /* x mod 2.0 */ + + n = (int)(x*4.0); + n = (n+1)/2; + x -= n*0.5f; + x *= pi; + + switch (n) { + default: /* case 4: */ + case 0: return __sin(x, 0.0, 0); + case 1: return __cos(x, 0.0); + case 2: return __sin(-x, 0.0, 0); + case 3: return -__cos(x, 0.0); + } +} + +double __lgamma_r(double x, int *signgamp) +{ + union {double f; uint64_t i;} u = {x}; + double_t t,y,z,nadj,p,p1,p2,p3,q,r,w; + uint32_t ix; + int sign,i; + + /* purge off +-inf, NaN, +-0, tiny and negative arguments */ + *signgamp = 1; + sign = u.i>>63; + ix = u.i>>32 & 0x7fffffff; + if (ix >= 0x7ff00000) + return x*x; + if (ix < (0x3ff-70)<<20) { /* |x|<2**-70, return -log(|x|) */ + if(sign) { + x = -x; + *signgamp = -1; + } + return -log(x); + } + if (sign) { + x = -x; + t = sin_pi(x); + if (t == 0.0) /* -integer */ + return 1.0/(x-x); + if (t > 0.0) + *signgamp = -1; + else + t = -t; + nadj = log(pi/(t*x)); + } + + /* purge off 1 and 2 */ + if ((ix == 0x3ff00000 || ix == 0x40000000) && (uint32_t)u.i == 0) + r = 0; + /* for x < 2.0 */ + else if (ix < 0x40000000) { + if (ix <= 0x3feccccc) { /* lgamma(x) = lgamma(x+1)-log(x) */ + r = -log(x); + if (ix >= 0x3FE76944) { + y = 1.0 - x; + i = 0; + } else if (ix >= 0x3FCDA661) { + y = x - (tc-1.0); + i = 1; + } else { + y = x; + i = 2; + } + } else { + r = 0.0; + if (ix >= 0x3FFBB4C3) { /* [1.7316,2] */ + y = 2.0 - x; + i = 0; + } else if(ix >= 0x3FF3B4C4) { /* [1.23,1.73] */ + y = x - tc; + i = 1; + } else { + y = x - 1.0; + i = 2; + } + } + switch (i) { + case 0: + z = y*y; + p1 = a0+z*(a2+z*(a4+z*(a6+z*(a8+z*a10)))); + p2 = z*(a1+z*(a3+z*(a5+z*(a7+z*(a9+z*a11))))); + p = y*p1+p2; + r += (p-0.5*y); + break; + case 1: + z = y*y; + w = z*y; + p1 = t0+w*(t3+w*(t6+w*(t9 +w*t12))); /* parallel comp */ + p2 = t1+w*(t4+w*(t7+w*(t10+w*t13))); + p3 = t2+w*(t5+w*(t8+w*(t11+w*t14))); + p = z*p1-(tt-w*(p2+y*p3)); + r += tf + p; + break; + case 2: + p1 = y*(u0+y*(u1+y*(u2+y*(u3+y*(u4+y*u5))))); + p2 = 1.0+y*(v1+y*(v2+y*(v3+y*(v4+y*v5)))); + r += -0.5*y + p1/p2; + } + } else if (ix < 0x40200000) { /* x < 8.0 */ + i = (int)x; + y = x - (double)i; + p = y*(s0+y*(s1+y*(s2+y*(s3+y*(s4+y*(s5+y*s6)))))); + q = 1.0+y*(r1+y*(r2+y*(r3+y*(r4+y*(r5+y*r6))))); + r = 0.5*y+p/q; + z = 1.0; /* lgamma(1+s) = log(s) + lgamma(s) */ + switch (i) { + case 7: z *= y + 6.0; /* FALLTHRU */ + case 6: z *= y + 5.0; /* FALLTHRU */ + case 5: z *= y + 4.0; /* FALLTHRU */ + case 4: z *= y + 3.0; /* FALLTHRU */ + case 3: z *= y + 2.0; /* FALLTHRU */ + r += log(z); + break; + } + } else if (ix < 0x43900000) { /* 8.0 <= x < 2**58 */ + t = log(x); + z = 1.0/x; + y = z*z; + w = w0+z*(w1+y*(w2+y*(w3+y*(w4+y*(w5+y*w6))))); + r = (x-0.5)*(t-1.0)+w; + } else /* 2**58 <= x <= inf */ + r = x*(log(x)-1.0); + if (sign) + r = nadj - r; + return r; +} + +weak_alias(__lgamma_r, lgamma_r); diff --git a/lib/mlibc/options/ansi/musl-generic-math/lgammaf.c b/lib/mlibc/options/ansi/musl-generic-math/lgammaf.c new file mode 100644 index 0000000..badb6df --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/lgammaf.c @@ -0,0 +1,9 @@ +#include + +extern int __signgam; +float __lgammaf_r(float, int *); + +float lgammaf(float x) +{ + return __lgammaf_r(x, &__signgam); +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/lgammaf_r.c b/lib/mlibc/options/ansi/musl-generic-math/lgammaf_r.c new file mode 100644 index 0000000..f73e89d --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/lgammaf_r.c @@ -0,0 +1,220 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_lgammaf_r.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "libm.h" +#include "weak_alias.h" +//#include "libc.h" + +static const float +pi = 3.1415927410e+00, /* 0x40490fdb */ +a0 = 7.7215664089e-02, /* 0x3d9e233f */ +a1 = 3.2246702909e-01, /* 0x3ea51a66 */ +a2 = 6.7352302372e-02, /* 0x3d89f001 */ +a3 = 2.0580807701e-02, /* 0x3ca89915 */ +a4 = 7.3855509982e-03, /* 0x3bf2027e */ +a5 = 2.8905137442e-03, /* 0x3b3d6ec6 */ +a6 = 1.1927076848e-03, /* 0x3a9c54a1 */ +a7 = 5.1006977446e-04, /* 0x3a05b634 */ +a8 = 2.2086278477e-04, /* 0x39679767 */ +a9 = 1.0801156895e-04, /* 0x38e28445 */ +a10 = 2.5214456400e-05, /* 0x37d383a2 */ +a11 = 4.4864096708e-05, /* 0x383c2c75 */ +tc = 1.4616321325e+00, /* 0x3fbb16c3 */ +tf = -1.2148628384e-01, /* 0xbdf8cdcd */ +/* tt = -(tail of tf) */ +tt = 6.6971006518e-09, /* 0x31e61c52 */ +t0 = 4.8383611441e-01, /* 0x3ef7b95e */ +t1 = -1.4758771658e-01, /* 0xbe17213c */ +t2 = 6.4624942839e-02, /* 0x3d845a15 */ +t3 = -3.2788541168e-02, /* 0xbd064d47 */ +t4 = 1.7970675603e-02, /* 0x3c93373d */ +t5 = -1.0314224288e-02, /* 0xbc28fcfe */ +t6 = 6.1005386524e-03, /* 0x3bc7e707 */ +t7 = -3.6845202558e-03, /* 0xbb7177fe */ +t8 = 2.2596477065e-03, /* 0x3b141699 */ +t9 = -1.4034647029e-03, /* 0xbab7f476 */ +t10 = 8.8108185446e-04, /* 0x3a66f867 */ +t11 = -5.3859531181e-04, /* 0xba0d3085 */ +t12 = 3.1563205994e-04, /* 0x39a57b6b */ +t13 = -3.1275415677e-04, /* 0xb9a3f927 */ +t14 = 3.3552918467e-04, /* 0x39afe9f7 */ +u0 = -7.7215664089e-02, /* 0xbd9e233f */ +u1 = 6.3282704353e-01, /* 0x3f2200f4 */ +u2 = 1.4549225569e+00, /* 0x3fba3ae7 */ +u3 = 9.7771751881e-01, /* 0x3f7a4bb2 */ +u4 = 2.2896373272e-01, /* 0x3e6a7578 */ +u5 = 1.3381091878e-02, /* 0x3c5b3c5e */ +v1 = 2.4559779167e+00, /* 0x401d2ebe */ +v2 = 2.1284897327e+00, /* 0x4008392d */ +v3 = 7.6928514242e-01, /* 0x3f44efdf */ +v4 = 1.0422264785e-01, /* 0x3dd572af */ +v5 = 3.2170924824e-03, /* 0x3b52d5db */ +s0 = -7.7215664089e-02, /* 0xbd9e233f */ +s1 = 2.1498242021e-01, /* 0x3e5c245a */ +s2 = 3.2577878237e-01, /* 0x3ea6cc7a */ +s3 = 1.4635047317e-01, /* 0x3e15dce6 */ +s4 = 2.6642270386e-02, /* 0x3cda40e4 */ +s5 = 1.8402845599e-03, /* 0x3af135b4 */ +s6 = 3.1947532989e-05, /* 0x3805ff67 */ +r1 = 1.3920053244e+00, /* 0x3fb22d3b */ +r2 = 7.2193557024e-01, /* 0x3f38d0c5 */ +r3 = 1.7193385959e-01, /* 0x3e300f6e */ +r4 = 1.8645919859e-02, /* 0x3c98bf54 */ +r5 = 7.7794247773e-04, /* 0x3a4beed6 */ +r6 = 7.3266842264e-06, /* 0x36f5d7bd */ +w0 = 4.1893854737e-01, /* 0x3ed67f1d */ +w1 = 8.3333335817e-02, /* 0x3daaaaab */ +w2 = -2.7777778450e-03, /* 0xbb360b61 */ +w3 = 7.9365057172e-04, /* 0x3a500cfd */ +w4 = -5.9518753551e-04, /* 0xba1c065c */ +w5 = 8.3633989561e-04, /* 0x3a5b3dd2 */ +w6 = -1.6309292987e-03; /* 0xbad5c4e8 */ + +/* sin(pi*x) assuming x > 2^-100, if sin(pi*x)==0 the sign is arbitrary */ +static float sin_pi(float x) +{ + double_t y; + int n; + + /* spurious inexact if odd int */ + x = 2*(x*0.5f - floorf(x*0.5f)); /* x mod 2.0 */ + + n = (int)(x*4); + n = (n+1)/2; + y = x - n*0.5f; + y *= 3.14159265358979323846; + switch (n) { + default: /* case 4: */ + case 0: return __sindf(y); + case 1: return __cosdf(y); + case 2: return __sindf(-y); + case 3: return -__cosdf(y); + } +} + +float __lgammaf_r(float x, int *signgamp) +{ + union {float f; uint32_t i;} u = {x}; + float t,y,z,nadj,p,p1,p2,p3,q,r,w; + uint32_t ix; + int i,sign; + + /* purge off +-inf, NaN, +-0, tiny and negative arguments */ + *signgamp = 1; + sign = u.i>>31; + ix = u.i & 0x7fffffff; + if (ix >= 0x7f800000) + return x*x; + if (ix < 0x35000000) { /* |x| < 2**-21, return -log(|x|) */ + if (sign) { + *signgamp = -1; + x = -x; + } + return -logf(x); + } + if (sign) { + x = -x; + t = sin_pi(x); + if (t == 0.0f) /* -integer */ + return 1.0f/(x-x); + if (t > 0.0f) + *signgamp = -1; + else + t = -t; + nadj = logf(pi/(t*x)); + } + + /* purge off 1 and 2 */ + if (ix == 0x3f800000 || ix == 0x40000000) + r = 0; + /* for x < 2.0 */ + else if (ix < 0x40000000) { + if (ix <= 0x3f666666) { /* lgamma(x) = lgamma(x+1)-log(x) */ + r = -logf(x); + if (ix >= 0x3f3b4a20) { + y = 1.0f - x; + i = 0; + } else if (ix >= 0x3e6d3308) { + y = x - (tc-1.0f); + i = 1; + } else { + y = x; + i = 2; + } + } else { + r = 0.0f; + if (ix >= 0x3fdda618) { /* [1.7316,2] */ + y = 2.0f - x; + i = 0; + } else if (ix >= 0x3F9da620) { /* [1.23,1.73] */ + y = x - tc; + i = 1; + } else { + y = x - 1.0f; + i = 2; + } + } + switch(i) { + case 0: + z = y*y; + p1 = a0+z*(a2+z*(a4+z*(a6+z*(a8+z*a10)))); + p2 = z*(a1+z*(a3+z*(a5+z*(a7+z*(a9+z*a11))))); + p = y*p1+p2; + r += p - 0.5f*y; + break; + case 1: + z = y*y; + w = z*y; + p1 = t0+w*(t3+w*(t6+w*(t9 +w*t12))); /* parallel comp */ + p2 = t1+w*(t4+w*(t7+w*(t10+w*t13))); + p3 = t2+w*(t5+w*(t8+w*(t11+w*t14))); + p = z*p1-(tt-w*(p2+y*p3)); + r += (tf + p); + break; + case 2: + p1 = y*(u0+y*(u1+y*(u2+y*(u3+y*(u4+y*u5))))); + p2 = 1.0f+y*(v1+y*(v2+y*(v3+y*(v4+y*v5)))); + r += -0.5f*y + p1/p2; + } + } else if (ix < 0x41000000) { /* x < 8.0 */ + i = (int)x; + y = x - (float)i; + p = y*(s0+y*(s1+y*(s2+y*(s3+y*(s4+y*(s5+y*s6)))))); + q = 1.0f+y*(r1+y*(r2+y*(r3+y*(r4+y*(r5+y*r6))))); + r = 0.5f*y+p/q; + z = 1.0f; /* lgamma(1+s) = log(s) + lgamma(s) */ + switch (i) { + case 7: z *= y + 6.0f; /* FALLTHRU */ + case 6: z *= y + 5.0f; /* FALLTHRU */ + case 5: z *= y + 4.0f; /* FALLTHRU */ + case 4: z *= y + 3.0f; /* FALLTHRU */ + case 3: z *= y + 2.0f; /* FALLTHRU */ + r += logf(z); + break; + } + } else if (ix < 0x5c800000) { /* 8.0 <= x < 2**58 */ + t = logf(x); + z = 1.0f/x; + y = z*z; + w = w0+z*(w1+y*(w2+y*(w3+y*(w4+y*(w5+y*w6))))); + r = (x-0.5f)*(t-1.0f)+w; + } else /* 2**58 <= x <= inf */ + r = x*(logf(x)-1.0f); + if (sign) + r = nadj - r; + return r; +} + +weak_alias(__lgammaf_r, lgammaf_r); diff --git a/lib/mlibc/options/ansi/musl-generic-math/lgammal.c b/lib/mlibc/options/ansi/musl-generic-math/lgammal.c new file mode 100644 index 0000000..f0bea36 --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/lgammal.c @@ -0,0 +1,361 @@ +/* origin: OpenBSD /usr/src/lib/libm/src/ld80/e_lgammal.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* + * Copyright (c) 2008 Stephen L. Moshier + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/* lgammal(x) + * Reentrant version of the logarithm of the Gamma function + * with user provide pointer for the sign of Gamma(x). + * + * Method: + * 1. Argument Reduction for 0 < x <= 8 + * Since gamma(1+s)=s*gamma(s), for x in [0,8], we may + * reduce x to a number in [1.5,2.5] by + * lgamma(1+s) = log(s) + lgamma(s) + * for example, + * lgamma(7.3) = log(6.3) + lgamma(6.3) + * = log(6.3*5.3) + lgamma(5.3) + * = log(6.3*5.3*4.3*3.3*2.3) + lgamma(2.3) + * 2. Polynomial approximation of lgamma around its + * minimun ymin=1.461632144968362245 to maintain monotonicity. + * On [ymin-0.23, ymin+0.27] (i.e., [1.23164,1.73163]), use + * Let z = x-ymin; + * lgamma(x) = -1.214862905358496078218 + z^2*poly(z) + * 2. Rational approximation in the primary interval [2,3] + * We use the following approximation: + * s = x-2.0; + * lgamma(x) = 0.5*s + s*P(s)/Q(s) + * Our algorithms are based on the following observation + * + * zeta(2)-1 2 zeta(3)-1 3 + * lgamma(2+s) = s*(1-Euler) + --------- * s - --------- * s + ... + * 2 3 + * + * where Euler = 0.5771... is the Euler constant, which is very + * close to 0.5. + * + * 3. For x>=8, we have + * lgamma(x)~(x-0.5)log(x)-x+0.5*log(2pi)+1/(12x)-1/(360x**3)+.... + * (better formula: + * lgamma(x)~(x-0.5)*(log(x)-1)-.5*(log(2pi)-1) + ...) + * Let z = 1/x, then we approximation + * f(z) = lgamma(x) - (x-0.5)(log(x)-1) + * by + * 3 5 11 + * w = w0 + w1*z + w2*z + w3*z + ... + w6*z + * + * 4. For negative x, since (G is gamma function) + * -x*G(-x)*G(x) = pi/sin(pi*x), + * we have + * G(x) = pi/(sin(pi*x)*(-x)*G(-x)) + * since G(-x) is positive, sign(G(x)) = sign(sin(pi*x)) for x<0 + * Hence, for x<0, signgam = sign(sin(pi*x)) and + * lgamma(x) = log(|Gamma(x)|) + * = log(pi/(|x*sin(pi*x)|)) - lgamma(-x); + * Note: one should avoid compute pi*(-x) directly in the + * computation of sin(pi*(-x)). + * + * 5. Special Cases + * lgamma(2+s) ~ s*(1-Euler) for tiny s + * lgamma(1)=lgamma(2)=0 + * lgamma(x) ~ -log(x) for tiny x + * lgamma(0) = lgamma(inf) = inf + * lgamma(-integer) = +-inf + * + */ + +#define _GNU_SOURCE +#include "libm.h" +#include "weak_alias.h" +//#include "libc.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +double __lgamma_r(double x, int *sg); + +long double __lgammal_r(long double x, int *sg) +{ + return __lgamma_r(x, sg); +} +#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 +static const long double +pi = 3.14159265358979323846264L, + +/* lgam(1+x) = 0.5 x + x a(x)/b(x) + -0.268402099609375 <= x <= 0 + peak relative error 6.6e-22 */ +a0 = -6.343246574721079391729402781192128239938E2L, +a1 = 1.856560238672465796768677717168371401378E3L, +a2 = 2.404733102163746263689288466865843408429E3L, +a3 = 8.804188795790383497379532868917517596322E2L, +a4 = 1.135361354097447729740103745999661157426E2L, +a5 = 3.766956539107615557608581581190400021285E0L, + +b0 = 8.214973713960928795704317259806842490498E3L, +b1 = 1.026343508841367384879065363925870888012E4L, +b2 = 4.553337477045763320522762343132210919277E3L, +b3 = 8.506975785032585797446253359230031874803E2L, +b4 = 6.042447899703295436820744186992189445813E1L, +/* b5 = 1.000000000000000000000000000000000000000E0 */ + + +tc = 1.4616321449683623412626595423257213284682E0L, +tf = -1.2148629053584961146050602565082954242826E-1, /* double precision */ +/* tt = (tail of tf), i.e. tf + tt has extended precision. */ +tt = 3.3649914684731379602768989080467587736363E-18L, +/* lgam ( 1.4616321449683623412626595423257213284682E0 ) = +-1.2148629053584960809551455717769158215135617312999903886372437313313530E-1 */ + +/* lgam (x + tc) = tf + tt + x g(x)/h(x) + -0.230003726999612341262659542325721328468 <= x + <= 0.2699962730003876587373404576742786715318 + peak relative error 2.1e-21 */ +g0 = 3.645529916721223331888305293534095553827E-18L, +g1 = 5.126654642791082497002594216163574795690E3L, +g2 = 8.828603575854624811911631336122070070327E3L, +g3 = 5.464186426932117031234820886525701595203E3L, +g4 = 1.455427403530884193180776558102868592293E3L, +g5 = 1.541735456969245924860307497029155838446E2L, +g6 = 4.335498275274822298341872707453445815118E0L, + +h0 = 1.059584930106085509696730443974495979641E4L, +h1 = 2.147921653490043010629481226937850618860E4L, +h2 = 1.643014770044524804175197151958100656728E4L, +h3 = 5.869021995186925517228323497501767586078E3L, +h4 = 9.764244777714344488787381271643502742293E2L, +h5 = 6.442485441570592541741092969581997002349E1L, +/* h6 = 1.000000000000000000000000000000000000000E0 */ + + +/* lgam (x+1) = -0.5 x + x u(x)/v(x) + -0.100006103515625 <= x <= 0.231639862060546875 + peak relative error 1.3e-21 */ +u0 = -8.886217500092090678492242071879342025627E1L, +u1 = 6.840109978129177639438792958320783599310E2L, +u2 = 2.042626104514127267855588786511809932433E3L, +u3 = 1.911723903442667422201651063009856064275E3L, +u4 = 7.447065275665887457628865263491667767695E2L, +u5 = 1.132256494121790736268471016493103952637E2L, +u6 = 4.484398885516614191003094714505960972894E0L, + +v0 = 1.150830924194461522996462401210374632929E3L, +v1 = 3.399692260848747447377972081399737098610E3L, +v2 = 3.786631705644460255229513563657226008015E3L, +v3 = 1.966450123004478374557778781564114347876E3L, +v4 = 4.741359068914069299837355438370682773122E2L, +v5 = 4.508989649747184050907206782117647852364E1L, +/* v6 = 1.000000000000000000000000000000000000000E0 */ + + +/* lgam (x+2) = .5 x + x s(x)/r(x) + 0 <= x <= 1 + peak relative error 7.2e-22 */ +s0 = 1.454726263410661942989109455292824853344E6L, +s1 = -3.901428390086348447890408306153378922752E6L, +s2 = -6.573568698209374121847873064292963089438E6L, +s3 = -3.319055881485044417245964508099095984643E6L, +s4 = -7.094891568758439227560184618114707107977E5L, +s5 = -6.263426646464505837422314539808112478303E4L, +s6 = -1.684926520999477529949915657519454051529E3L, + +r0 = -1.883978160734303518163008696712983134698E7L, +r1 = -2.815206082812062064902202753264922306830E7L, +r2 = -1.600245495251915899081846093343626358398E7L, +r3 = -4.310526301881305003489257052083370058799E6L, +r4 = -5.563807682263923279438235987186184968542E5L, +r5 = -3.027734654434169996032905158145259713083E4L, +r6 = -4.501995652861105629217250715790764371267E2L, +/* r6 = 1.000000000000000000000000000000000000000E0 */ + + +/* lgam(x) = ( x - 0.5 ) * log(x) - x + LS2PI + 1/x w(1/x^2) + x >= 8 + Peak relative error 1.51e-21 +w0 = LS2PI - 0.5 */ +w0 = 4.189385332046727417803e-1L, +w1 = 8.333333333333331447505E-2L, +w2 = -2.777777777750349603440E-3L, +w3 = 7.936507795855070755671E-4L, +w4 = -5.952345851765688514613E-4L, +w5 = 8.412723297322498080632E-4L, +w6 = -1.880801938119376907179E-3L, +w7 = 4.885026142432270781165E-3L; + +/* sin(pi*x) assuming x > 2^-1000, if sin(pi*x)==0 the sign is arbitrary */ +static long double sin_pi(long double x) +{ + int n; + + /* spurious inexact if odd int */ + x *= 0.5; + x = 2.0*(x - floorl(x)); /* x mod 2.0 */ + + n = (int)(x*4.0); + n = (n+1)/2; + x -= n*0.5f; + x *= pi; + + switch (n) { + default: /* case 4: */ + case 0: return __sinl(x, 0.0, 0); + case 1: return __cosl(x, 0.0); + case 2: return __sinl(-x, 0.0, 0); + case 3: return -__cosl(x, 0.0); + } +} + +long double __lgammal_r(long double x, int *sg) { + long double t, y, z, nadj, p, p1, p2, q, r, w; + union ldshape u = {x}; + uint32_t ix = (u.i.se & 0x7fffU)<<16 | u.i.m>>48; + int sign = u.i.se >> 15; + int i; + + *sg = 1; + + /* purge off +-inf, NaN, +-0, tiny and negative arguments */ + if (ix >= 0x7fff0000) + return x * x; + if (ix < 0x3fc08000) { /* |x|<2**-63, return -log(|x|) */ + if (sign) { + *sg = -1; + x = -x; + } + return -logl(x); + } + if (sign) { + x = -x; + t = sin_pi(x); + if (t == 0.0) + return 1.0 / (x-x); /* -integer */ + if (t > 0.0) + *sg = -1; + else + t = -t; + nadj = logl(pi / (t * x)); + } + + /* purge off 1 and 2 (so the sign is ok with downward rounding) */ + if ((ix == 0x3fff8000 || ix == 0x40008000) && u.i.m == 0) { + r = 0; + } else if (ix < 0x40008000) { /* x < 2.0 */ + if (ix <= 0x3ffee666) { /* 8.99993896484375e-1 */ + /* lgamma(x) = lgamma(x+1) - log(x) */ + r = -logl(x); + if (ix >= 0x3ffebb4a) { /* 7.31597900390625e-1 */ + y = x - 1.0; + i = 0; + } else if (ix >= 0x3ffced33) { /* 2.31639862060546875e-1 */ + y = x - (tc - 1.0); + i = 1; + } else { /* x < 0.23 */ + y = x; + i = 2; + } + } else { + r = 0.0; + if (ix >= 0x3fffdda6) { /* 1.73162841796875 */ + /* [1.7316,2] */ + y = x - 2.0; + i = 0; + } else if (ix >= 0x3fff9da6) { /* 1.23162841796875 */ + /* [1.23,1.73] */ + y = x - tc; + i = 1; + } else { + /* [0.9, 1.23] */ + y = x - 1.0; + i = 2; + } + } + switch (i) { + case 0: + p1 = a0 + y * (a1 + y * (a2 + y * (a3 + y * (a4 + y * a5)))); + p2 = b0 + y * (b1 + y * (b2 + y * (b3 + y * (b4 + y)))); + r += 0.5 * y + y * p1/p2; + break; + case 1: + p1 = g0 + y * (g1 + y * (g2 + y * (g3 + y * (g4 + y * (g5 + y * g6))))); + p2 = h0 + y * (h1 + y * (h2 + y * (h3 + y * (h4 + y * (h5 + y))))); + p = tt + y * p1/p2; + r += (tf + p); + break; + case 2: + p1 = y * (u0 + y * (u1 + y * (u2 + y * (u3 + y * (u4 + y * (u5 + y * u6)))))); + p2 = v0 + y * (v1 + y * (v2 + y * (v3 + y * (v4 + y * (v5 + y))))); + r += (-0.5 * y + p1 / p2); + } + } else if (ix < 0x40028000) { /* 8.0 */ + /* x < 8.0 */ + i = (int)x; + y = x - (double)i; + p = y * (s0 + y * (s1 + y * (s2 + y * (s3 + y * (s4 + y * (s5 + y * s6)))))); + q = r0 + y * (r1 + y * (r2 + y * (r3 + y * (r4 + y * (r5 + y * (r6 + y)))))); + r = 0.5 * y + p / q; + z = 1.0; + /* lgamma(1+s) = log(s) + lgamma(s) */ + switch (i) { + case 7: + z *= (y + 6.0); /* FALLTHRU */ + case 6: + z *= (y + 5.0); /* FALLTHRU */ + case 5: + z *= (y + 4.0); /* FALLTHRU */ + case 4: + z *= (y + 3.0); /* FALLTHRU */ + case 3: + z *= (y + 2.0); /* FALLTHRU */ + r += logl(z); + break; + } + } else if (ix < 0x40418000) { /* 2^66 */ + /* 8.0 <= x < 2**66 */ + t = logl(x); + z = 1.0 / x; + y = z * z; + w = w0 + z * (w1 + y * (w2 + y * (w3 + y * (w4 + y * (w5 + y * (w6 + y * w7)))))); + r = (x - 0.5) * (t - 1.0) + w; + } else /* 2**66 <= x <= inf */ + r = x * (logl(x) - 1.0); + if (sign) + r = nadj - r; + return r; +} +#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 +// TODO: broken implementation to make things compile +double __lgamma_r(double x, int *sg); + +long double __lgammal_r(long double x, int *sg) +{ + return __lgamma_r(x, sg); +} +#endif + +extern int __signgam; + +long double lgammal(long double x) +{ + return __lgammal_r(x, &__signgam); +} + +weak_alias(__lgammal_r, lgammal_r); diff --git a/lib/mlibc/options/ansi/musl-generic-math/libm.h b/lib/mlibc/options/ansi/musl-generic-math/libm.h new file mode 100644 index 0000000..8120292 --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/libm.h @@ -0,0 +1,186 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/math_private.h */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#ifndef _LIBM_H +#define _LIBM_H + +#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 == 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 + +#define FORCE_EVAL(x) do { \ + if (sizeof(x) == sizeof(float)) { \ + volatile float __x; \ + __x = (x); \ + } else if (sizeof(x) == sizeof(double)) { \ + volatile double __x; \ + __x = (x); \ + } else { \ + volatile long double __x; \ + __x = (x); \ + } \ +} while(0) + +/* Get two 32 bit ints from a double. */ +#define EXTRACT_WORDS(hi,lo,d) \ +do { \ + union {double f; uint64_t i;} __u; \ + __u.f = (d); \ + (hi) = __u.i >> 32; \ + (lo) = (uint32_t)__u.i; \ +} while (0) + +/* Get the more significant 32 bit int from a double. */ +#define GET_HIGH_WORD(hi,d) \ +do { \ + union {double f; uint64_t i;} __u; \ + __u.f = (d); \ + (hi) = __u.i >> 32; \ +} while (0) + +/* Get the less significant 32 bit int from a double. */ +#define GET_LOW_WORD(lo,d) \ +do { \ + union {double f; uint64_t i;} __u; \ + __u.f = (d); \ + (lo) = (uint32_t)__u.i; \ +} while (0) + +/* Set a double from two 32 bit ints. */ +#define INSERT_WORDS(d,hi,lo) \ +do { \ + union {double f; uint64_t i;} __u; \ + __u.i = ((uint64_t)(hi)<<32) | (uint32_t)(lo); \ + (d) = __u.f; \ +} while (0) + +/* Set the more significant 32 bits of a double from an int. */ +#define SET_HIGH_WORD(d,hi) \ +do { \ + union {double f; uint64_t i;} __u; \ + __u.f = (d); \ + __u.i &= 0xffffffff; \ + __u.i |= (uint64_t)(hi) << 32; \ + (d) = __u.f; \ +} while (0) + +/* Set the less significant 32 bits of a double from an int. */ +#define SET_LOW_WORD(d,lo) \ +do { \ + union {double f; uint64_t i;} __u; \ + __u.f = (d); \ + __u.i &= 0xffffffff00000000ull; \ + __u.i |= (uint32_t)(lo); \ + (d) = __u.f; \ +} while (0) + +/* Get a 32 bit int from a float. */ +#define GET_FLOAT_WORD(w,d) \ +do { \ + union {float f; uint32_t i;} __u; \ + __u.f = (d); \ + (w) = __u.i; \ +} while (0) + +/* Set a float from a 32 bit int. */ +#define SET_FLOAT_WORD(d,w) \ +do { \ + union {float f; uint32_t i;} __u; \ + __u.i = (w); \ + (d) = __u.f; \ +} while (0) + +#undef __CMPLX +#undef CMPLX +#undef CMPLXF +#undef CMPLXL + +#define __CMPLX(x, y, t) \ + ((union { _Complex t __z; t __xy[2]; }){.__xy = {(x),(y)}}.__z) + +#define CMPLX(x, y) __CMPLX(x, y, double) +#define CMPLXF(x, y) __CMPLX(x, y, float) +#define CMPLXL(x, y) __CMPLX(x, y, long double) + +#ifndef __MLIBC_ABI_ONLY + +/* fdlibm kernel functions */ + +int __rem_pio2_large(double*,double*,int,int,int); + +int __rem_pio2(double,double*); +double __sin(double,double,int); +double __cos(double,double); +double __tan(double,double,int); +double __expo2(double); +//double complex __ldexp_cexp(double complex,int); + +int __rem_pio2f(float,double*); +float __sindf(double); +float __cosdf(double); +float __tandf(double,int); +float __expo2f(float); +//float complex __ldexp_cexpf(float complex,int); + +int __rem_pio2l(long double, long double *); +long double __sinl(long double, long double, int); +long double __cosl(long double, long double); +long double __tanl(long double, long double, int); + +/* polynomial evaluation */ +long double __polevll(long double, const long double *, int); +long double __p1evll(long double, const long double *, int); + +#endif /* !__MLIBC_ABI_ONLY */ + +#endif diff --git a/lib/mlibc/options/ansi/musl-generic-math/llrint.c b/lib/mlibc/options/ansi/musl-generic-math/llrint.c new file mode 100644 index 0000000..4f583ae --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/llrint.c @@ -0,0 +1,8 @@ +#include + +/* uses LLONG_MAX > 2^53, see comments in lrint.c */ + +long long llrint(double x) +{ + return rint(x); +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/llrintf.c b/lib/mlibc/options/ansi/musl-generic-math/llrintf.c new file mode 100644 index 0000000..96949a0 --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/llrintf.c @@ -0,0 +1,8 @@ +#include + +/* uses LLONG_MAX > 2^24, see comments in lrint.c */ + +long long llrintf(float x) +{ + return rintf(x); +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/llrintl.c b/lib/mlibc/options/ansi/musl-generic-math/llrintl.c new file mode 100644 index 0000000..3449f6f --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/llrintl.c @@ -0,0 +1,36 @@ +#include +#include +#include "libm.h" + + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long long llrintl(long double x) +{ + return llrint(x); +} +#elif defined(FE_INEXACT) +/* +see comments in lrint.c + +Note that if LLONG_MAX == 0x7fffffffffffffff && LDBL_MANT_DIG == 64 +then x == 2**63 - 0.5 is the only input that overflows and +raises inexact (with tonearest or upward rounding mode) +*/ +long long llrintl(long double x) +{ + #pragma STDC FENV_ACCESS ON + int e; + + e = fetestexcept(FE_INEXACT); + x = rintl(x); + if (!e && (x > LLONG_MAX || x < LLONG_MIN)) + feclearexcept(FE_INEXACT); + /* conversion */ + return x; +} +#else +long long llrintl(long double x) +{ + return rintl(x); +} +#endif diff --git a/lib/mlibc/options/ansi/musl-generic-math/llround.c b/lib/mlibc/options/ansi/musl-generic-math/llround.c new file mode 100644 index 0000000..4d94787 --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/llround.c @@ -0,0 +1,6 @@ +#include + +long long llround(double x) +{ + return round(x); +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/llroundf.c b/lib/mlibc/options/ansi/musl-generic-math/llroundf.c new file mode 100644 index 0000000..19eb77e --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/llroundf.c @@ -0,0 +1,6 @@ +#include + +long long llroundf(float x) +{ + return roundf(x); +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/llroundl.c b/lib/mlibc/options/ansi/musl-generic-math/llroundl.c new file mode 100644 index 0000000..2c2ee5e --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/llroundl.c @@ -0,0 +1,6 @@ +#include + +long long llroundl(long double x) +{ + return roundl(x); +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/log.c b/lib/mlibc/options/ansi/musl-generic-math/log.c new file mode 100644 index 0000000..e61e113 --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/log.c @@ -0,0 +1,118 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_log.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* log(x) + * Return the logarithm of x + * + * Method : + * 1. Argument Reduction: find k and f such that + * x = 2^k * (1+f), + * where sqrt(2)/2 < 1+f < sqrt(2) . + * + * 2. Approximation of log(1+f). + * Let s = f/(2+f) ; based on log(1+f) = log(1+s) - log(1-s) + * = 2s + 2/3 s**3 + 2/5 s**5 + ....., + * = 2s + s*R + * We use a special Remez algorithm on [0,0.1716] to generate + * a polynomial of degree 14 to approximate R The maximum error + * of this polynomial approximation is bounded by 2**-58.45. In + * other words, + * 2 4 6 8 10 12 14 + * R(z) ~ Lg1*s +Lg2*s +Lg3*s +Lg4*s +Lg5*s +Lg6*s +Lg7*s + * (the values of Lg1 to Lg7 are listed in the program) + * and + * | 2 14 | -58.45 + * | Lg1*s +...+Lg7*s - R(z) | <= 2 + * | | + * Note that 2s = f - s*f = f - hfsq + s*hfsq, where hfsq = f*f/2. + * In order to guarantee error in log below 1ulp, we compute log + * by + * log(1+f) = f - s*(f - R) (if f is not too large) + * log(1+f) = f - (hfsq - s*(hfsq+R)). (better accuracy) + * + * 3. Finally, log(x) = k*ln2 + log(1+f). + * = k*ln2_hi+(f-(hfsq-(s*(hfsq+R)+k*ln2_lo))) + * Here ln2 is split into two floating point number: + * ln2_hi + ln2_lo, + * where n*ln2_hi is always exact for |n| < 2000. + * + * Special cases: + * log(x) is NaN with signal if x < 0 (including -INF) ; + * log(+INF) is +INF; log(0) is -INF with signal; + * log(NaN) is that NaN with no signal. + * + * Accuracy: + * according to an error analysis, the error is always less than + * 1 ulp (unit in the last place). + * + * Constants: + * The hexadecimal values are the intended ones for the following + * constants. The decimal values may be used, provided that the + * compiler will convert from decimal to binary accurately enough + * to produce the hexadecimal values shown. + */ + +#include +#include + +static const double +ln2_hi = 6.93147180369123816490e-01, /* 3fe62e42 fee00000 */ +ln2_lo = 1.90821492927058770002e-10, /* 3dea39ef 35793c76 */ +Lg1 = 6.666666666666735130e-01, /* 3FE55555 55555593 */ +Lg2 = 3.999999999940941908e-01, /* 3FD99999 9997FA04 */ +Lg3 = 2.857142874366239149e-01, /* 3FD24924 94229359 */ +Lg4 = 2.222219843214978396e-01, /* 3FCC71C5 1D8E78AF */ +Lg5 = 1.818357216161805012e-01, /* 3FC74664 96CB03DE */ +Lg6 = 1.531383769920937332e-01, /* 3FC39A09 D078C69F */ +Lg7 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */ + +double log(double x) +{ + union {double f; uint64_t i;} u = {x}; + double_t hfsq,f,s,z,R,w,t1,t2,dk; + uint32_t hx; + int k; + + hx = u.i>>32; + k = 0; + if (hx < 0x00100000 || hx>>31) { + if (u.i<<1 == 0) + return -1/(x*x); /* log(+-0)=-inf */ + if (hx>>31) + return (x-x)/0.0; /* log(-#) = NaN */ + /* subnormal number, scale x up */ + k -= 54; + x *= 0x1p54; + u.f = x; + hx = u.i>>32; + } else if (hx >= 0x7ff00000) { + return x; + } else if (hx == 0x3ff00000 && u.i<<32 == 0) + return 0; + + /* reduce x into [sqrt(2)/2, sqrt(2)] */ + hx += 0x3ff00000 - 0x3fe6a09e; + k += (int)(hx>>20) - 0x3ff; + hx = (hx&0x000fffff) + 0x3fe6a09e; + u.i = (uint64_t)hx<<32 | (u.i&0xffffffff); + x = u.f; + + f = x - 1.0; + hfsq = 0.5*f*f; + s = f/(2.0+f); + z = s*s; + w = z*z; + t1 = w*(Lg2+w*(Lg4+w*Lg6)); + t2 = z*(Lg1+w*(Lg3+w*(Lg5+w*Lg7))); + R = t2 + t1; + dk = k; + return s*(hfsq+R) + dk*ln2_lo - hfsq + f + dk*ln2_hi; +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/log10.c b/lib/mlibc/options/ansi/musl-generic-math/log10.c new file mode 100644 index 0000000..8102687 --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/log10.c @@ -0,0 +1,101 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_log10.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* + * Return the base 10 logarithm of x. See log.c for most comments. + * + * Reduce x to 2^k (1+f) and calculate r = log(1+f) - f + f*f/2 + * as in log.c, then combine and scale in extra precision: + * log10(x) = (f - f*f/2 + r)/log(10) + k*log10(2) + */ + +#include +#include + +static const double +ivln10hi = 4.34294481878168880939e-01, /* 0x3fdbcb7b, 0x15200000 */ +ivln10lo = 2.50829467116452752298e-11, /* 0x3dbb9438, 0xca9aadd5 */ +log10_2hi = 3.01029995663611771306e-01, /* 0x3FD34413, 0x509F6000 */ +log10_2lo = 3.69423907715893078616e-13, /* 0x3D59FEF3, 0x11F12B36 */ +Lg1 = 6.666666666666735130e-01, /* 3FE55555 55555593 */ +Lg2 = 3.999999999940941908e-01, /* 3FD99999 9997FA04 */ +Lg3 = 2.857142874366239149e-01, /* 3FD24924 94229359 */ +Lg4 = 2.222219843214978396e-01, /* 3FCC71C5 1D8E78AF */ +Lg5 = 1.818357216161805012e-01, /* 3FC74664 96CB03DE */ +Lg6 = 1.531383769920937332e-01, /* 3FC39A09 D078C69F */ +Lg7 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */ + +double log10(double x) +{ + union {double f; uint64_t i;} u = {x}; + double_t hfsq,f,s,z,R,w,t1,t2,dk,y,hi,lo,val_hi,val_lo; + uint32_t hx; + int k; + + hx = u.i>>32; + k = 0; + if (hx < 0x00100000 || hx>>31) { + if (u.i<<1 == 0) + return -1/(x*x); /* log(+-0)=-inf */ + if (hx>>31) + return (x-x)/0.0; /* log(-#) = NaN */ + /* subnormal number, scale x up */ + k -= 54; + x *= 0x1p54; + u.f = x; + hx = u.i>>32; + } else if (hx >= 0x7ff00000) { + return x; + } else if (hx == 0x3ff00000 && u.i<<32 == 0) + return 0; + + /* reduce x into [sqrt(2)/2, sqrt(2)] */ + hx += 0x3ff00000 - 0x3fe6a09e; + k += (int)(hx>>20) - 0x3ff; + hx = (hx&0x000fffff) + 0x3fe6a09e; + u.i = (uint64_t)hx<<32 | (u.i&0xffffffff); + x = u.f; + + f = x - 1.0; + hfsq = 0.5*f*f; + s = f/(2.0+f); + z = s*s; + w = z*z; + t1 = w*(Lg2+w*(Lg4+w*Lg6)); + t2 = z*(Lg1+w*(Lg3+w*(Lg5+w*Lg7))); + R = t2 + t1; + + /* See log2.c for details. */ + /* hi+lo = f - hfsq + s*(hfsq+R) ~ log(1+f) */ + hi = f - hfsq; + u.f = hi; + u.i &= (uint64_t)-1<<32; + hi = u.f; + lo = f - hi - hfsq + s*(hfsq+R); + + /* val_hi+val_lo ~ log10(1+f) + k*log10(2) */ + val_hi = hi*ivln10hi; + dk = k; + y = dk*log10_2hi; + val_lo = dk*log10_2lo + (lo+hi)*ivln10lo + lo*ivln10hi; + + /* + * Extra precision in for adding y is not strictly needed + * since there is no very large cancellation near x = sqrt(2) or + * x = 1/sqrt(2), but we do it anyway since it costs little on CPUs + * with some parallelism and it reduces the error for many args. + */ + w = y + val_hi; + val_lo += (y - w) + val_hi; + val_hi = w; + + return val_lo + val_hi; +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/log10f.c b/lib/mlibc/options/ansi/musl-generic-math/log10f.c new file mode 100644 index 0000000..9ca2f01 --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/log10f.c @@ -0,0 +1,77 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_log10f.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* + * See comments in log10.c. + */ + +#include +#include + +static const float +ivln10hi = 4.3432617188e-01, /* 0x3ede6000 */ +ivln10lo = -3.1689971365e-05, /* 0xb804ead9 */ +log10_2hi = 3.0102920532e-01, /* 0x3e9a2080 */ +log10_2lo = 7.9034151668e-07, /* 0x355427db */ +/* |(log(1+s)-log(1-s))/s - Lg(s)| < 2**-34.24 (~[-4.95e-11, 4.97e-11]). */ +Lg1 = 0xaaaaaa.0p-24, /* 0.66666662693 */ +Lg2 = 0xccce13.0p-25, /* 0.40000972152 */ +Lg3 = 0x91e9ee.0p-25, /* 0.28498786688 */ +Lg4 = 0xf89e26.0p-26; /* 0.24279078841 */ + +float log10f(float x) +{ + union {float f; uint32_t i;} u = {x}; + float_t hfsq,f,s,z,R,w,t1,t2,dk,hi,lo; + uint32_t ix; + int k; + + ix = u.i; + k = 0; + if (ix < 0x00800000 || ix>>31) { /* x < 2**-126 */ + if (ix<<1 == 0) + return -1/(x*x); /* log(+-0)=-inf */ + if (ix>>31) + return (x-x)/0.0f; /* log(-#) = NaN */ + /* subnormal number, scale up x */ + k -= 25; + x *= 0x1p25f; + u.f = x; + ix = u.i; + } else if (ix >= 0x7f800000) { + return x; + } else if (ix == 0x3f800000) + return 0; + + /* reduce x into [sqrt(2)/2, sqrt(2)] */ + ix += 0x3f800000 - 0x3f3504f3; + k += (int)(ix>>23) - 0x7f; + ix = (ix&0x007fffff) + 0x3f3504f3; + u.i = ix; + x = u.f; + + f = x - 1.0f; + s = f/(2.0f + f); + z = s*s; + w = z*z; + t1= w*(Lg2+w*Lg4); + t2= z*(Lg1+w*Lg3); + R = t2 + t1; + hfsq = 0.5f*f*f; + + hi = f - hfsq; + u.f = hi; + u.i &= 0xfffff000; + hi = u.f; + lo = f - hi - hfsq + s*(hfsq+R); + dk = k; + return dk*log10_2lo + (lo+hi)*ivln10lo + lo*ivln10hi + hi*ivln10hi + dk*log10_2hi; +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/log10l.c b/lib/mlibc/options/ansi/musl-generic-math/log10l.c new file mode 100644 index 0000000..63dcc28 --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/log10l.c @@ -0,0 +1,191 @@ +/* origin: OpenBSD /usr/src/lib/libm/src/ld80/e_log10l.c */ +/* + * Copyright (c) 2008 Stephen L. Moshier + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/* + * Common logarithm, long double precision + * + * + * SYNOPSIS: + * + * long double x, y, log10l(); + * + * y = log10l( x ); + * + * + * DESCRIPTION: + * + * Returns the base 10 logarithm of x. + * + * The argument is separated into its exponent and fractional + * parts. If the exponent is between -1 and +1, the logarithm + * of the fraction is approximated by + * + * log(1+x) = x - 0.5 x**2 + x**3 P(x)/Q(x). + * + * Otherwise, setting z = 2(x-1)/x+1), + * + * log(x) = z + z**3 P(z)/Q(z). + * + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * IEEE 0.5, 2.0 30000 9.0e-20 2.6e-20 + * IEEE exp(+-10000) 30000 6.0e-20 2.3e-20 + * + * In the tests over the interval exp(+-10000), the logarithms + * of the random arguments were uniformly distributed over + * [-10000, +10000]. + * + * ERROR MESSAGES: + * + * log singularity: x = 0; returns MINLOG + * log domain: x < 0; returns MINLOG + */ + +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double log10l(long double x) +{ + return log10(x); +} +#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 +/* Coefficients for log(1+x) = x - x**2/2 + x**3 P(x)/Q(x) + * 1/sqrt(2) <= x < sqrt(2) + * Theoretical peak relative error = 6.2e-22 + */ +static const long double P[] = { + 4.9962495940332550844739E-1L, + 1.0767376367209449010438E1L, + 7.7671073698359539859595E1L, + 2.5620629828144409632571E2L, + 4.2401812743503691187826E2L, + 3.4258224542413922935104E2L, + 1.0747524399916215149070E2L, +}; +static const long double Q[] = { +/* 1.0000000000000000000000E0,*/ + 2.3479774160285863271658E1L, + 1.9444210022760132894510E2L, + 7.7952888181207260646090E2L, + 1.6911722418503949084863E3L, + 2.0307734695595183428202E3L, + 1.2695660352705325274404E3L, + 3.2242573199748645407652E2L, +}; + +/* Coefficients for log(x) = z + z^3 P(z^2)/Q(z^2), + * where z = 2(x-1)/(x+1) + * 1/sqrt(2) <= x < sqrt(2) + * Theoretical peak relative error = 6.16e-22 + */ +static const long double R[4] = { + 1.9757429581415468984296E-3L, +-7.1990767473014147232598E-1L, + 1.0777257190312272158094E1L, +-3.5717684488096787370998E1L, +}; +static const long double S[4] = { +/* 1.00000000000000000000E0L,*/ +-2.6201045551331104417768E1L, + 1.9361891836232102174846E2L, +-4.2861221385716144629696E2L, +}; +/* log10(2) */ +#define L102A 0.3125L +#define L102B -1.1470004336018804786261e-2L +/* log10(e) */ +#define L10EA 0.5L +#define L10EB -6.5705518096748172348871e-2L + +#define SQRTH 0.70710678118654752440L + +long double log10l(long double x) +{ + long double y, z; + int e; + + if (isnan(x)) + return x; + if(x <= 0.0) { + if(x == 0.0) + return -1.0 / (x*x); + return (x - x) / 0.0; + } + if (x == INFINITY) + return INFINITY; + /* separate mantissa from exponent */ + /* Note, frexp is used so that denormal numbers + * will be handled properly. + */ + x = frexpl(x, &e); + + /* logarithm using log(x) = z + z**3 P(z)/Q(z), + * where z = 2(x-1)/x+1) + */ + if (e > 2 || e < -2) { + if (x < SQRTH) { /* 2(2x-1)/(2x+1) */ + e -= 1; + z = x - 0.5; + y = 0.5 * z + 0.5; + } else { /* 2 (x-1)/(x+1) */ + z = x - 0.5; + z -= 0.5; + y = 0.5 * x + 0.5; + } + x = z / y; + z = x*x; + y = x * (z * __polevll(z, R, 3) / __p1evll(z, S, 3)); + goto done; + } + + /* logarithm using log(1+x) = x - .5x**2 + x**3 P(x)/Q(x) */ + if (x < SQRTH) { + e -= 1; + x = 2.0*x - 1.0; + } else { + x = x - 1.0; + } + z = x*x; + y = x * (z * __polevll(x, P, 6) / __p1evll(x, Q, 7)); + y = y - 0.5*z; + +done: + /* Multiply log of fraction by log10(e) + * and base 2 exponent by log10(2). + * + * ***CAUTION*** + * + * This sequence of operations is critical and it may + * be horribly defeated by some compiler optimizers. + */ + z = y * (L10EB); + z += x * (L10EB); + z += e * (L102B); + z += y * (L10EA); + z += x * (L10EA); + z += e * (L102A); + return z; +} +#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 +// TODO: broken implementation to make things compile +long double log10l(long double x) +{ + return log10(x); +} +#endif diff --git a/lib/mlibc/options/ansi/musl-generic-math/log1p.c b/lib/mlibc/options/ansi/musl-generic-math/log1p.c new file mode 100644 index 0000000..0097134 --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/log1p.c @@ -0,0 +1,122 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_log1p.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* double log1p(double x) + * Return the natural logarithm of 1+x. + * + * Method : + * 1. Argument Reduction: find k and f such that + * 1+x = 2^k * (1+f), + * where sqrt(2)/2 < 1+f < sqrt(2) . + * + * Note. If k=0, then f=x is exact. However, if k!=0, then f + * may not be representable exactly. In that case, a correction + * term is need. Let u=1+x rounded. Let c = (1+x)-u, then + * log(1+x) - log(u) ~ c/u. Thus, we proceed to compute log(u), + * and add back the correction term c/u. + * (Note: when x > 2**53, one can simply return log(x)) + * + * 2. Approximation of log(1+f): See log.c + * + * 3. Finally, log1p(x) = k*ln2 + log(1+f) + c/u. See log.c + * + * Special cases: + * log1p(x) is NaN with signal if x < -1 (including -INF) ; + * log1p(+INF) is +INF; log1p(-1) is -INF with signal; + * log1p(NaN) is that NaN with no signal. + * + * Accuracy: + * according to an error analysis, the error is always less than + * 1 ulp (unit in the last place). + * + * Constants: + * The hexadecimal values are the intended ones for the following + * constants. The decimal values may be used, provided that the + * compiler will convert from decimal to binary accurately enough + * to produce the hexadecimal values shown. + * + * Note: Assuming log() return accurate answer, the following + * algorithm can be used to compute log1p(x) to within a few ULP: + * + * u = 1+x; + * if(u==1.0) return x ; else + * return log(u)*(x/(u-1.0)); + * + * See HP-15C Advanced Functions Handbook, p.193. + */ + +#include "libm.h" + +static const double +ln2_hi = 6.93147180369123816490e-01, /* 3fe62e42 fee00000 */ +ln2_lo = 1.90821492927058770002e-10, /* 3dea39ef 35793c76 */ +Lg1 = 6.666666666666735130e-01, /* 3FE55555 55555593 */ +Lg2 = 3.999999999940941908e-01, /* 3FD99999 9997FA04 */ +Lg3 = 2.857142874366239149e-01, /* 3FD24924 94229359 */ +Lg4 = 2.222219843214978396e-01, /* 3FCC71C5 1D8E78AF */ +Lg5 = 1.818357216161805012e-01, /* 3FC74664 96CB03DE */ +Lg6 = 1.531383769920937332e-01, /* 3FC39A09 D078C69F */ +Lg7 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */ + +double log1p(double x) +{ + union {double f; uint64_t i;} u = {x}; + double_t hfsq,f,c,s,z,R,w,t1,t2,dk; + uint32_t hx,hu; + int k; + + hx = u.i>>32; + k = 1; + if (hx < 0x3fda827a || hx>>31) { /* 1+x < sqrt(2)+ */ + if (hx >= 0xbff00000) { /* x <= -1.0 */ + if (x == -1) + return x/0.0; /* log1p(-1) = -inf */ + return (x-x)/0.0; /* log1p(x<-1) = NaN */ + } + if (hx<<1 < 0x3ca00000<<1) { /* |x| < 2**-53 */ + /* underflow if subnormal */ + if ((hx&0x7ff00000) == 0) + FORCE_EVAL((float)x); + return x; + } + if (hx <= 0xbfd2bec4) { /* sqrt(2)/2- <= 1+x < sqrt(2)+ */ + k = 0; + c = 0; + f = x; + } + } else if (hx >= 0x7ff00000) + return x; + if (k) { + u.f = 1 + x; + hu = u.i>>32; + hu += 0x3ff00000 - 0x3fe6a09e; + k = (int)(hu>>20) - 0x3ff; + /* correction term ~ log(1+x)-log(u), avoid underflow in c/u */ + if (k < 54) { + c = k >= 2 ? 1-(u.f-x) : x-(u.f-1); + c /= u.f; + } else + c = 0; + /* reduce u into [sqrt(2)/2, sqrt(2)] */ + hu = (hu&0x000fffff) + 0x3fe6a09e; + u.i = (uint64_t)hu<<32 | (u.i&0xffffffff); + f = u.f - 1; + } + hfsq = 0.5*f*f; + s = f/(2.0+f); + z = s*s; + w = z*z; + t1 = w*(Lg2+w*(Lg4+w*Lg6)); + t2 = z*(Lg1+w*(Lg3+w*(Lg5+w*Lg7))); + R = t2 + t1; + dk = k; + return s*(hfsq+R) + (dk*ln2_lo+c) - hfsq + f + dk*ln2_hi; +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/log1pf.c b/lib/mlibc/options/ansi/musl-generic-math/log1pf.c new file mode 100644 index 0000000..23985c3 --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/log1pf.c @@ -0,0 +1,77 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_log1pf.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "libm.h" + +static const float +ln2_hi = 6.9313812256e-01, /* 0x3f317180 */ +ln2_lo = 9.0580006145e-06, /* 0x3717f7d1 */ +/* |(log(1+s)-log(1-s))/s - Lg(s)| < 2**-34.24 (~[-4.95e-11, 4.97e-11]). */ +Lg1 = 0xaaaaaa.0p-24, /* 0.66666662693 */ +Lg2 = 0xccce13.0p-25, /* 0.40000972152 */ +Lg3 = 0x91e9ee.0p-25, /* 0.28498786688 */ +Lg4 = 0xf89e26.0p-26; /* 0.24279078841 */ + +float log1pf(float x) +{ + union {float f; uint32_t i;} u = {x}; + float_t hfsq,f,c,s,z,R,w,t1,t2,dk; + uint32_t ix,iu; + int k; + + ix = u.i; + k = 1; + if (ix < 0x3ed413d0 || ix>>31) { /* 1+x < sqrt(2)+ */ + if (ix >= 0xbf800000) { /* x <= -1.0 */ + if (x == -1) + return x/0.0f; /* log1p(-1)=+inf */ + return (x-x)/0.0f; /* log1p(x<-1)=NaN */ + } + if (ix<<1 < 0x33800000<<1) { /* |x| < 2**-24 */ + /* underflow if subnormal */ + if ((ix&0x7f800000) == 0) + FORCE_EVAL(x*x); + return x; + } + if (ix <= 0xbe95f619) { /* sqrt(2)/2- <= 1+x < sqrt(2)+ */ + k = 0; + c = 0; + f = x; + } + } else if (ix >= 0x7f800000) + return x; + if (k) { + u.f = 1 + x; + iu = u.i; + iu += 0x3f800000 - 0x3f3504f3; + k = (int)(iu>>23) - 0x7f; + /* correction term ~ log(1+x)-log(u), avoid underflow in c/u */ + if (k < 25) { + c = k >= 2 ? 1-(u.f-x) : x-(u.f-1); + c /= u.f; + } else + c = 0; + /* reduce u into [sqrt(2)/2, sqrt(2)] */ + iu = (iu&0x007fffff) + 0x3f3504f3; + u.i = iu; + f = u.f - 1; + } + s = f/(2.0f + f); + z = s*s; + w = z*z; + t1= w*(Lg2+w*Lg4); + t2= z*(Lg1+w*Lg3); + R = t2 + t1; + hfsq = 0.5f*f*f; + dk = k; + return s*(hfsq+R) + (dk*ln2_lo+c) - hfsq + f + dk*ln2_hi; +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/log1pl.c b/lib/mlibc/options/ansi/musl-generic-math/log1pl.c new file mode 100644 index 0000000..141b5f0 --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/log1pl.c @@ -0,0 +1,177 @@ +/* origin: OpenBSD /usr/src/lib/libm/src/ld80/s_log1pl.c */ +/* + * Copyright (c) 2008 Stephen L. Moshier + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/* + * Relative error logarithm + * Natural logarithm of 1+x, long double precision + * + * + * SYNOPSIS: + * + * long double x, y, log1pl(); + * + * y = log1pl( x ); + * + * + * DESCRIPTION: + * + * Returns the base e (2.718...) logarithm of 1+x. + * + * The argument 1+x is separated into its exponent and fractional + * parts. If the exponent is between -1 and +1, the logarithm + * of the fraction is approximated by + * + * log(1+x) = x - 0.5 x^2 + x^3 P(x)/Q(x). + * + * Otherwise, setting z = 2(x-1)/x+1), + * + * log(x) = z + z^3 P(z)/Q(z). + * + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * IEEE -1.0, 9.0 100000 8.2e-20 2.5e-20 + */ + +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double log1pl(long double x) +{ + return log1p(x); +} +#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 +/* Coefficients for log(1+x) = x - x^2 / 2 + x^3 P(x)/Q(x) + * 1/sqrt(2) <= x < sqrt(2) + * Theoretical peak relative error = 2.32e-20 + */ +static const long double P[] = { + 4.5270000862445199635215E-5L, + 4.9854102823193375972212E-1L, + 6.5787325942061044846969E0L, + 2.9911919328553073277375E1L, + 6.0949667980987787057556E1L, + 5.7112963590585538103336E1L, + 2.0039553499201281259648E1L, +}; +static const long double Q[] = { +/* 1.0000000000000000000000E0,*/ + 1.5062909083469192043167E1L, + 8.3047565967967209469434E1L, + 2.2176239823732856465394E2L, + 3.0909872225312059774938E2L, + 2.1642788614495947685003E2L, + 6.0118660497603843919306E1L, +}; + +/* Coefficients for log(x) = z + z^3 P(z^2)/Q(z^2), + * where z = 2(x-1)/(x+1) + * 1/sqrt(2) <= x < sqrt(2) + * Theoretical peak relative error = 6.16e-22 + */ +static const long double R[4] = { + 1.9757429581415468984296E-3L, +-7.1990767473014147232598E-1L, + 1.0777257190312272158094E1L, +-3.5717684488096787370998E1L, +}; +static const long double S[4] = { +/* 1.00000000000000000000E0L,*/ +-2.6201045551331104417768E1L, + 1.9361891836232102174846E2L, +-4.2861221385716144629696E2L, +}; +static const long double C1 = 6.9314575195312500000000E-1L; +static const long double C2 = 1.4286068203094172321215E-6L; + +#define SQRTH 0.70710678118654752440L + +long double log1pl(long double xm1) +{ + long double x, y, z; + int e; + + if (isnan(xm1)) + return xm1; + if (xm1 == INFINITY) + return xm1; + if (xm1 == 0.0) + return xm1; + + x = xm1 + 1.0; + + /* Test for domain errors. */ + if (x <= 0.0) { + if (x == 0.0) + return -1/(x*x); /* -inf with divbyzero */ + return 0/0.0f; /* nan with invalid */ + } + + /* Separate mantissa from exponent. + Use frexp so that denormal numbers will be handled properly. */ + x = frexpl(x, &e); + + /* logarithm using log(x) = z + z^3 P(z)/Q(z), + where z = 2(x-1)/x+1) */ + if (e > 2 || e < -2) { + if (x < SQRTH) { /* 2(2x-1)/(2x+1) */ + e -= 1; + z = x - 0.5; + y = 0.5 * z + 0.5; + } else { /* 2 (x-1)/(x+1) */ + z = x - 0.5; + z -= 0.5; + y = 0.5 * x + 0.5; + } + x = z / y; + z = x*x; + z = x * (z * __polevll(z, R, 3) / __p1evll(z, S, 3)); + z = z + e * C2; + z = z + x; + z = z + e * C1; + return z; + } + + /* logarithm using log(1+x) = x - .5x**2 + x**3 P(x)/Q(x) */ + if (x < SQRTH) { + e -= 1; + if (e != 0) + x = 2.0 * x - 1.0; + else + x = xm1; + } else { + if (e != 0) + x = x - 1.0; + else + x = xm1; + } + z = x*x; + y = x * (z * __polevll(x, P, 6) / __p1evll(x, Q, 6)); + y = y + e * C2; + z = y - 0.5 * z; + z = z + x; + z = z + e * C1; + return z; +} +#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 +// TODO: broken implementation to make things compile +long double log1pl(long double x) +{ + return log1p(x); +} +#endif diff --git a/lib/mlibc/options/ansi/musl-generic-math/log2.c b/lib/mlibc/options/ansi/musl-generic-math/log2.c new file mode 100644 index 0000000..0aafad4 --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/log2.c @@ -0,0 +1,122 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_log2.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* + * Return the base 2 logarithm of x. See log.c for most comments. + * + * Reduce x to 2^k (1+f) and calculate r = log(1+f) - f + f*f/2 + * as in log.c, then combine and scale in extra precision: + * log2(x) = (f - f*f/2 + r)/log(2) + k + */ + +#include +#include + +static const double +ivln2hi = 1.44269504072144627571e+00, /* 0x3ff71547, 0x65200000 */ +ivln2lo = 1.67517131648865118353e-10, /* 0x3de705fc, 0x2eefa200 */ +Lg1 = 6.666666666666735130e-01, /* 3FE55555 55555593 */ +Lg2 = 3.999999999940941908e-01, /* 3FD99999 9997FA04 */ +Lg3 = 2.857142874366239149e-01, /* 3FD24924 94229359 */ +Lg4 = 2.222219843214978396e-01, /* 3FCC71C5 1D8E78AF */ +Lg5 = 1.818357216161805012e-01, /* 3FC74664 96CB03DE */ +Lg6 = 1.531383769920937332e-01, /* 3FC39A09 D078C69F */ +Lg7 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */ + +double log2(double x) +{ + union {double f; uint64_t i;} u = {x}; + double_t hfsq,f,s,z,R,w,t1,t2,y,hi,lo,val_hi,val_lo; + uint32_t hx; + int k; + + hx = u.i>>32; + k = 0; + if (hx < 0x00100000 || hx>>31) { + if (u.i<<1 == 0) + return -1/(x*x); /* log(+-0)=-inf */ + if (hx>>31) + return (x-x)/0.0; /* log(-#) = NaN */ + /* subnormal number, scale x up */ + k -= 54; + x *= 0x1p54; + u.f = x; + hx = u.i>>32; + } else if (hx >= 0x7ff00000) { + return x; + } else if (hx == 0x3ff00000 && u.i<<32 == 0) + return 0; + + /* reduce x into [sqrt(2)/2, sqrt(2)] */ + hx += 0x3ff00000 - 0x3fe6a09e; + k += (int)(hx>>20) - 0x3ff; + hx = (hx&0x000fffff) + 0x3fe6a09e; + u.i = (uint64_t)hx<<32 | (u.i&0xffffffff); + x = u.f; + + f = x - 1.0; + hfsq = 0.5*f*f; + s = f/(2.0+f); + z = s*s; + w = z*z; + t1 = w*(Lg2+w*(Lg4+w*Lg6)); + t2 = z*(Lg1+w*(Lg3+w*(Lg5+w*Lg7))); + R = t2 + t1; + + /* + * f-hfsq must (for args near 1) be evaluated in extra precision + * to avoid a large cancellation when x is near sqrt(2) or 1/sqrt(2). + * This is fairly efficient since f-hfsq only depends on f, so can + * be evaluated in parallel with R. Not combining hfsq with R also + * keeps R small (though not as small as a true `lo' term would be), + * so that extra precision is not needed for terms involving R. + * + * Compiler bugs involving extra precision used to break Dekker's + * theorem for spitting f-hfsq as hi+lo, unless double_t was used + * or the multi-precision calculations were avoided when double_t + * has extra precision. These problems are now automatically + * avoided as a side effect of the optimization of combining the + * Dekker splitting step with the clear-low-bits step. + * + * y must (for args near sqrt(2) and 1/sqrt(2)) be added in extra + * precision to avoid a very large cancellation when x is very near + * these values. Unlike the above cancellations, this problem is + * specific to base 2. It is strange that adding +-1 is so much + * harder than adding +-ln2 or +-log10_2. + * + * This uses Dekker's theorem to normalize y+val_hi, so the + * compiler bugs are back in some configurations, sigh. And I + * don't want to used double_t to avoid them, since that gives a + * pessimization and the support for avoiding the pessimization + * is not yet available. + * + * The multi-precision calculations for the multiplications are + * routine. + */ + + /* hi+lo = f - hfsq + s*(hfsq+R) ~ log(1+f) */ + hi = f - hfsq; + u.f = hi; + u.i &= (uint64_t)-1<<32; + hi = u.f; + lo = f - hi - hfsq + s*(hfsq+R); + + val_hi = hi*ivln2hi; + val_lo = (lo+hi)*ivln2lo + lo*ivln2hi; + + /* spadd(val_hi, val_lo, y), except for not using double_t: */ + y = k; + w = y + val_hi; + val_lo += (y - w) + val_hi; + val_hi = w; + + return val_lo + val_hi; +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/log2f.c b/lib/mlibc/options/ansi/musl-generic-math/log2f.c new file mode 100644 index 0000000..b3e305f --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/log2f.c @@ -0,0 +1,74 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_log2f.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* + * See comments in log2.c. + */ + +#include +#include + +static const float +ivln2hi = 1.4428710938e+00, /* 0x3fb8b000 */ +ivln2lo = -1.7605285393e-04, /* 0xb9389ad4 */ +/* |(log(1+s)-log(1-s))/s - Lg(s)| < 2**-34.24 (~[-4.95e-11, 4.97e-11]). */ +Lg1 = 0xaaaaaa.0p-24, /* 0.66666662693 */ +Lg2 = 0xccce13.0p-25, /* 0.40000972152 */ +Lg3 = 0x91e9ee.0p-25, /* 0.28498786688 */ +Lg4 = 0xf89e26.0p-26; /* 0.24279078841 */ + +float log2f(float x) +{ + union {float f; uint32_t i;} u = {x}; + float_t hfsq,f,s,z,R,w,t1,t2,hi,lo; + uint32_t ix; + int k; + + ix = u.i; + k = 0; + if (ix < 0x00800000 || ix>>31) { /* x < 2**-126 */ + if (ix<<1 == 0) + return -1/(x*x); /* log(+-0)=-inf */ + if (ix>>31) + return (x-x)/0.0f; /* log(-#) = NaN */ + /* subnormal number, scale up x */ + k -= 25; + x *= 0x1p25f; + u.f = x; + ix = u.i; + } else if (ix >= 0x7f800000) { + return x; + } else if (ix == 0x3f800000) + return 0; + + /* reduce x into [sqrt(2)/2, sqrt(2)] */ + ix += 0x3f800000 - 0x3f3504f3; + k += (int)(ix>>23) - 0x7f; + ix = (ix&0x007fffff) + 0x3f3504f3; + u.i = ix; + x = u.f; + + f = x - 1.0f; + s = f/(2.0f + f); + z = s*s; + w = z*z; + t1= w*(Lg2+w*Lg4); + t2= z*(Lg1+w*Lg3); + R = t2 + t1; + hfsq = 0.5f*f*f; + + hi = f - hfsq; + u.f = hi; + u.i &= 0xfffff000; + hi = u.f; + lo = f - hi - hfsq + s*(hfsq+R); + return (lo+hi)*ivln2lo + lo*ivln2hi + hi*ivln2hi + k; +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/log2l.c b/lib/mlibc/options/ansi/musl-generic-math/log2l.c new file mode 100644 index 0000000..722b451 --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/log2l.c @@ -0,0 +1,182 @@ +/* origin: OpenBSD /usr/src/lib/libm/src/ld80/e_log2l.c */ +/* + * Copyright (c) 2008 Stephen L. Moshier + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/* + * Base 2 logarithm, long double precision + * + * + * SYNOPSIS: + * + * long double x, y, log2l(); + * + * y = log2l( x ); + * + * + * DESCRIPTION: + * + * Returns the base 2 logarithm of x. + * + * The argument is separated into its exponent and fractional + * parts. If the exponent is between -1 and +1, the (natural) + * logarithm of the fraction is approximated by + * + * log(1+x) = x - 0.5 x**2 + x**3 P(x)/Q(x). + * + * Otherwise, setting z = 2(x-1)/x+1), + * + * log(x) = z + z**3 P(z)/Q(z). + * + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * IEEE 0.5, 2.0 30000 9.8e-20 2.7e-20 + * IEEE exp(+-10000) 70000 5.4e-20 2.3e-20 + * + * In the tests over the interval exp(+-10000), the logarithms + * of the random arguments were uniformly distributed over + * [-10000, +10000]. + */ + +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double log2l(long double x) +{ + return log2(x); +} +#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 +/* Coefficients for ln(1+x) = x - x**2/2 + x**3 P(x)/Q(x) + * 1/sqrt(2) <= x < sqrt(2) + * Theoretical peak relative error = 6.2e-22 + */ +static const long double P[] = { + 4.9962495940332550844739E-1L, + 1.0767376367209449010438E1L, + 7.7671073698359539859595E1L, + 2.5620629828144409632571E2L, + 4.2401812743503691187826E2L, + 3.4258224542413922935104E2L, + 1.0747524399916215149070E2L, +}; +static const long double Q[] = { +/* 1.0000000000000000000000E0,*/ + 2.3479774160285863271658E1L, + 1.9444210022760132894510E2L, + 7.7952888181207260646090E2L, + 1.6911722418503949084863E3L, + 2.0307734695595183428202E3L, + 1.2695660352705325274404E3L, + 3.2242573199748645407652E2L, +}; + +/* Coefficients for log(x) = z + z^3 P(z^2)/Q(z^2), + * where z = 2(x-1)/(x+1) + * 1/sqrt(2) <= x < sqrt(2) + * Theoretical peak relative error = 6.16e-22 + */ +static const long double R[4] = { + 1.9757429581415468984296E-3L, +-7.1990767473014147232598E-1L, + 1.0777257190312272158094E1L, +-3.5717684488096787370998E1L, +}; +static const long double S[4] = { +/* 1.00000000000000000000E0L,*/ +-2.6201045551331104417768E1L, + 1.9361891836232102174846E2L, +-4.2861221385716144629696E2L, +}; +/* log2(e) - 1 */ +#define LOG2EA 4.4269504088896340735992e-1L + +#define SQRTH 0.70710678118654752440L + +long double log2l(long double x) +{ + long double y, z; + int e; + + if (isnan(x)) + return x; + if (x == INFINITY) + return x; + if (x <= 0.0) { + if (x == 0.0) + return -1/(x*x); /* -inf with divbyzero */ + return 0/0.0f; /* nan with invalid */ + } + + /* separate mantissa from exponent */ + /* Note, frexp is used so that denormal numbers + * will be handled properly. + */ + x = frexpl(x, &e); + + /* logarithm using log(x) = z + z**3 P(z)/Q(z), + * where z = 2(x-1)/x+1) + */ + if (e > 2 || e < -2) { + if (x < SQRTH) { /* 2(2x-1)/(2x+1) */ + e -= 1; + z = x - 0.5; + y = 0.5 * z + 0.5; + } else { /* 2 (x-1)/(x+1) */ + z = x - 0.5; + z -= 0.5; + y = 0.5 * x + 0.5; + } + x = z / y; + z = x*x; + y = x * (z * __polevll(z, R, 3) / __p1evll(z, S, 3)); + goto done; + } + + /* logarithm using log(1+x) = x - .5x**2 + x**3 P(x)/Q(x) */ + if (x < SQRTH) { + e -= 1; + x = 2.0*x - 1.0; + } else { + x = x - 1.0; + } + z = x*x; + y = x * (z * __polevll(x, P, 6) / __p1evll(x, Q, 7)); + y = y - 0.5*z; + +done: + /* Multiply log of fraction by log2(e) + * and base 2 exponent by 1 + * + * ***CAUTION*** + * + * This sequence of operations is critical and it may + * be horribly defeated by some compiler optimizers. + */ + z = y * LOG2EA; + z += x * LOG2EA; + z += y; + z += x; + z += e; + return z; +} +#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 +// TODO: broken implementation to make things compile +long double log2l(long double x) +{ + return log2(x); +} +#endif diff --git a/lib/mlibc/options/ansi/musl-generic-math/logb.c b/lib/mlibc/options/ansi/musl-generic-math/logb.c new file mode 100644 index 0000000..7f8bdfa --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/logb.c @@ -0,0 +1,17 @@ +#include + +/* +special cases: + logb(+-0) = -inf, and raise divbyzero + logb(+-inf) = +inf + logb(nan) = nan +*/ + +double logb(double x) +{ + if (!isfinite(x)) + return x * x; + if (x == 0) + return -1/(x*x); + return ilogb(x); +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/logbf.c b/lib/mlibc/options/ansi/musl-generic-math/logbf.c new file mode 100644 index 0000000..a0a0b5e --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/logbf.c @@ -0,0 +1,10 @@ +#include + +float logbf(float x) +{ + if (!isfinite(x)) + return x * x; + if (x == 0) + return -1/(x*x); + return ilogbf(x); +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/logbl.c b/lib/mlibc/options/ansi/musl-generic-math/logbl.c new file mode 100644 index 0000000..962973a --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/logbl.c @@ -0,0 +1,16 @@ +#include +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double logbl(long double x) +{ + return logb(x); +} +#else +long double logbl(long double x) +{ + if (!isfinite(x)) + return x * x; + if (x == 0) + return -1/(x*x); + return ilogbl(x); +} +#endif diff --git a/lib/mlibc/options/ansi/musl-generic-math/logf.c b/lib/mlibc/options/ansi/musl-generic-math/logf.c new file mode 100644 index 0000000..52230a1 --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/logf.c @@ -0,0 +1,69 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_logf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include +#include + +static const float +ln2_hi = 6.9313812256e-01, /* 0x3f317180 */ +ln2_lo = 9.0580006145e-06, /* 0x3717f7d1 */ +/* |(log(1+s)-log(1-s))/s - Lg(s)| < 2**-34.24 (~[-4.95e-11, 4.97e-11]). */ +Lg1 = 0xaaaaaa.0p-24, /* 0.66666662693 */ +Lg2 = 0xccce13.0p-25, /* 0.40000972152 */ +Lg3 = 0x91e9ee.0p-25, /* 0.28498786688 */ +Lg4 = 0xf89e26.0p-26; /* 0.24279078841 */ + +float logf(float x) +{ + union {float f; uint32_t i;} u = {x}; + float_t hfsq,f,s,z,R,w,t1,t2,dk; + uint32_t ix; + int k; + + ix = u.i; + k = 0; + if (ix < 0x00800000 || ix>>31) { /* x < 2**-126 */ + if (ix<<1 == 0) + return -1/(x*x); /* log(+-0)=-inf */ + if (ix>>31) + return (x-x)/0.0f; /* log(-#) = NaN */ + /* subnormal number, scale up x */ + k -= 25; + x *= 0x1p25f; + u.f = x; + ix = u.i; + } else if (ix >= 0x7f800000) { + return x; + } else if (ix == 0x3f800000) + return 0; + + /* reduce x into [sqrt(2)/2, sqrt(2)] */ + ix += 0x3f800000 - 0x3f3504f3; + k += (int)(ix>>23) - 0x7f; + ix = (ix&0x007fffff) + 0x3f3504f3; + u.i = ix; + x = u.f; + + f = x - 1.0f; + s = f/(2.0f + f); + z = s*s; + w = z*z; + t1= w*(Lg2+w*Lg4); + t2= z*(Lg1+w*Lg3); + R = t2 + t1; + hfsq = 0.5f*f*f; + dk = k; + return s*(hfsq+R) + dk*ln2_lo - hfsq + f + dk*ln2_hi; +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/logl.c b/lib/mlibc/options/ansi/musl-generic-math/logl.c new file mode 100644 index 0000000..5d53659 --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/logl.c @@ -0,0 +1,175 @@ +/* origin: OpenBSD /usr/src/lib/libm/src/ld80/e_logl.c */ +/* + * Copyright (c) 2008 Stephen L. Moshier + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/* + * Natural logarithm, long double precision + * + * + * SYNOPSIS: + * + * long double x, y, logl(); + * + * y = logl( x ); + * + * + * DESCRIPTION: + * + * Returns the base e (2.718...) logarithm of x. + * + * The argument is separated into its exponent and fractional + * parts. If the exponent is between -1 and +1, the logarithm + * of the fraction is approximated by + * + * log(1+x) = x - 0.5 x**2 + x**3 P(x)/Q(x). + * + * Otherwise, setting z = 2(x-1)/(x+1), + * + * log(x) = log(1+z/2) - log(1-z/2) = z + z**3 P(z)/Q(z). + * + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * IEEE 0.5, 2.0 150000 8.71e-20 2.75e-20 + * IEEE exp(+-10000) 100000 5.39e-20 2.34e-20 + * + * In the tests over the interval exp(+-10000), the logarithms + * of the random arguments were uniformly distributed over + * [-10000, +10000]. + */ + +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double logl(long double x) +{ + return log(x); +} +#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 +/* Coefficients for log(1+x) = x - x**2/2 + x**3 P(x)/Q(x) + * 1/sqrt(2) <= x < sqrt(2) + * Theoretical peak relative error = 2.32e-20 + */ +static const long double P[] = { + 4.5270000862445199635215E-5L, + 4.9854102823193375972212E-1L, + 6.5787325942061044846969E0L, + 2.9911919328553073277375E1L, + 6.0949667980987787057556E1L, + 5.7112963590585538103336E1L, + 2.0039553499201281259648E1L, +}; +static const long double Q[] = { +/* 1.0000000000000000000000E0,*/ + 1.5062909083469192043167E1L, + 8.3047565967967209469434E1L, + 2.2176239823732856465394E2L, + 3.0909872225312059774938E2L, + 2.1642788614495947685003E2L, + 6.0118660497603843919306E1L, +}; + +/* Coefficients for log(x) = z + z^3 P(z^2)/Q(z^2), + * where z = 2(x-1)/(x+1) + * 1/sqrt(2) <= x < sqrt(2) + * Theoretical peak relative error = 6.16e-22 + */ +static const long double R[4] = { + 1.9757429581415468984296E-3L, +-7.1990767473014147232598E-1L, + 1.0777257190312272158094E1L, +-3.5717684488096787370998E1L, +}; +static const long double S[4] = { +/* 1.00000000000000000000E0L,*/ +-2.6201045551331104417768E1L, + 1.9361891836232102174846E2L, +-4.2861221385716144629696E2L, +}; +static const long double C1 = 6.9314575195312500000000E-1L; +static const long double C2 = 1.4286068203094172321215E-6L; + +#define SQRTH 0.70710678118654752440L + +long double logl(long double x) +{ + long double y, z; + int e; + + if (isnan(x)) + return x; + if (x == INFINITY) + return x; + if (x <= 0.0) { + if (x == 0.0) + return -1/(x*x); /* -inf with divbyzero */ + return 0/0.0f; /* nan with invalid */ + } + + /* separate mantissa from exponent */ + /* Note, frexp is used so that denormal numbers + * will be handled properly. + */ + x = frexpl(x, &e); + + /* logarithm using log(x) = z + z**3 P(z)/Q(z), + * where z = 2(x-1)/(x+1) + */ + if (e > 2 || e < -2) { + if (x < SQRTH) { /* 2(2x-1)/(2x+1) */ + e -= 1; + z = x - 0.5; + y = 0.5 * z + 0.5; + } else { /* 2 (x-1)/(x+1) */ + z = x - 0.5; + z -= 0.5; + y = 0.5 * x + 0.5; + } + x = z / y; + z = x*x; + z = x * (z * __polevll(z, R, 3) / __p1evll(z, S, 3)); + z = z + e * C2; + z = z + x; + z = z + e * C1; + return z; + } + + /* logarithm using log(1+x) = x - .5x**2 + x**3 P(x)/Q(x) */ + if (x < SQRTH) { + e -= 1; + x = 2.0*x - 1.0; + } else { + x = x - 1.0; + } + z = x*x; + y = x * (z * __polevll(x, P, 6) / __p1evll(x, Q, 6)); + y = y + e * C2; + z = y - 0.5*z; + /* Note, the sum of above terms does not exceed x/4, + * so it contributes at most about 1/4 lsb to the error. + */ + z = z + x; + z = z + e * C1; /* This sum has an error of 1/2 lsb. */ + return z; +} +#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 +// TODO: broken implementation to make things compile +long double logl(long double x) +{ + return log(x); +} +#endif diff --git a/lib/mlibc/options/ansi/musl-generic-math/lrint.c b/lib/mlibc/options/ansi/musl-generic-math/lrint.c new file mode 100644 index 0000000..bdca8b7 --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/lrint.c @@ -0,0 +1,46 @@ +#include +#include +#include "libm.h" + +/* +If the result cannot be represented (overflow, nan), then +lrint raises the invalid exception. + +Otherwise if the input was not an integer then the inexact +exception is raised. + +C99 is a bit vague about whether inexact exception is +allowed to be raised when invalid is raised. +(F.9 explicitly allows spurious inexact exceptions, F.9.6.5 +does not make it clear if that rule applies to lrint, but +IEEE 754r 7.8 seems to forbid spurious inexact exception in +the ineger conversion functions) + +So we try to make sure that no spurious inexact exception is +raised in case of an overflow. + +If the bit size of long > precision of double, then there +cannot be inexact rounding in case the result overflows, +otherwise LONG_MAX and LONG_MIN can be represented exactly +as a double. +*/ + +#if LONG_MAX < 1U<<53 && defined(FE_INEXACT) +long lrint(double x) +{ + #pragma STDC FENV_ACCESS ON + int e; + + e = fetestexcept(FE_INEXACT); + x = rint(x); + if (!e && (x > LONG_MAX || x < LONG_MIN)) + feclearexcept(FE_INEXACT); + /* conversion */ + return x; +} +#else +long lrint(double x) +{ + return rint(x); +} +#endif diff --git a/lib/mlibc/options/ansi/musl-generic-math/lrintf.c b/lib/mlibc/options/ansi/musl-generic-math/lrintf.c new file mode 100644 index 0000000..ca0b6a4 --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/lrintf.c @@ -0,0 +1,8 @@ +#include + +/* uses LONG_MAX > 2^24, see comments in lrint.c */ + +long lrintf(float x) +{ + return rintf(x); +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/lrintl.c b/lib/mlibc/options/ansi/musl-generic-math/lrintl.c new file mode 100644 index 0000000..b2a8106 --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/lrintl.c @@ -0,0 +1,36 @@ +#include +#include +#include "libm.h" + + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long lrintl(long double x) +{ + return lrint(x); +} +#elif defined(FE_INEXACT) +/* +see comments in lrint.c + +Note that if LONG_MAX == 0x7fffffffffffffff && LDBL_MANT_DIG == 64 +then x == 2**63 - 0.5 is the only input that overflows and +raises inexact (with tonearest or upward rounding mode) +*/ +long lrintl(long double x) +{ + #pragma STDC FENV_ACCESS ON + int e; + + e = fetestexcept(FE_INEXACT); + x = rintl(x); + if (!e && (x > LONG_MAX || x < LONG_MIN)) + feclearexcept(FE_INEXACT); + /* conversion */ + return x; +} +#else +long lrintl(long double x) +{ + return rintl(x); +} +#endif diff --git a/lib/mlibc/options/ansi/musl-generic-math/lround.c b/lib/mlibc/options/ansi/musl-generic-math/lround.c new file mode 100644 index 0000000..b8b7954 --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/lround.c @@ -0,0 +1,6 @@ +#include + +long lround(double x) +{ + return round(x); +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/lroundf.c b/lib/mlibc/options/ansi/musl-generic-math/lroundf.c new file mode 100644 index 0000000..c4707e7 --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/lroundf.c @@ -0,0 +1,6 @@ +#include + +long lroundf(float x) +{ + return roundf(x); +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/lroundl.c b/lib/mlibc/options/ansi/musl-generic-math/lroundl.c new file mode 100644 index 0000000..094fdf6 --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/lroundl.c @@ -0,0 +1,6 @@ +#include + +long lroundl(long double x) +{ + return roundl(x); +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/modf.c b/lib/mlibc/options/ansi/musl-generic-math/modf.c new file mode 100644 index 0000000..1c8a1db --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/modf.c @@ -0,0 +1,34 @@ +#include "libm.h" + +double modf(double x, double *iptr) +{ + union {double f; uint64_t i;} u = {x}; + uint64_t mask; + int e = (int)(u.i>>52 & 0x7ff) - 0x3ff; + + /* no fractional part */ + if (e >= 52) { + *iptr = x; + if (e == 0x400 && u.i<<12 != 0) /* nan */ + return x; + u.i &= 1ULL<<63; + return u.f; + } + + /* no integral part*/ + if (e < 0) { + u.i &= 1ULL<<63; + *iptr = u.f; + return x; + } + + mask = -1ULL>>12>>e; + if ((u.i & mask) == 0) { + *iptr = x; + u.i &= 1ULL<<63; + return u.f; + } + u.i &= ~mask; + *iptr = u.f; + return x - u.f; +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/modff.c b/lib/mlibc/options/ansi/musl-generic-math/modff.c new file mode 100644 index 0000000..639514e --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/modff.c @@ -0,0 +1,34 @@ +#include "libm.h" + +float modff(float x, float *iptr) +{ + union {float f; uint32_t i;} u = {x}; + uint32_t mask; + int e = (int)(u.i>>23 & 0xff) - 0x7f; + + /* no fractional part */ + if (e >= 23) { + *iptr = x; + if (e == 0x80 && u.i<<9 != 0) { /* nan */ + return x; + } + u.i &= 0x80000000; + return u.f; + } + /* no integral part */ + if (e < 0) { + u.i &= 0x80000000; + *iptr = u.f; + return x; + } + + mask = 0x007fffff>>e; + if ((u.i & mask) == 0) { + *iptr = x; + u.i &= 0x80000000; + return u.f; + } + u.i &= ~mask; + *iptr = u.f; + return x - u.f; +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/modfl.c b/lib/mlibc/options/ansi/musl-generic-math/modfl.c new file mode 100644 index 0000000..a47b192 --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/modfl.c @@ -0,0 +1,53 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double modfl(long double x, long double *iptr) +{ + double d; + long double r; + + r = modf(x, &d); + *iptr = d; + return r; +} +#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 + +static const long double toint = 1/LDBL_EPSILON; + +long double modfl(long double x, long double *iptr) +{ + union ldshape u = {x}; + int e = (u.i.se & 0x7fff) - 0x3fff; + int s = u.i.se >> 15; + long double absx; + long double y; + + /* no fractional part */ + if (e >= LDBL_MANT_DIG-1) { + *iptr = x; + if (isnan(x)) + return x; + return s ? -0.0 : 0.0; + } + + /* no integral part*/ + if (e < 0) { + *iptr = s ? -0.0 : 0.0; + return x; + } + + /* raises spurious inexact */ + absx = s ? -x : x; + y = absx + toint - toint - absx; + if (y == 0) { + *iptr = x; + return s ? -0.0 : 0.0; + } + if (y > 0) + y -= 1; + if (s) + y = -y; + *iptr = x + y; + return -y; +} +#endif diff --git a/lib/mlibc/options/ansi/musl-generic-math/nan.c b/lib/mlibc/options/ansi/musl-generic-math/nan.c new file mode 100644 index 0000000..9e0826c --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/nan.c @@ -0,0 +1,6 @@ +#include + +double nan(const char *s) +{ + return NAN; +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/nanf.c b/lib/mlibc/options/ansi/musl-generic-math/nanf.c new file mode 100644 index 0000000..752ce54 --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/nanf.c @@ -0,0 +1,6 @@ +#include + +float nanf(const char *s) +{ + return NAN; +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/nanl.c b/lib/mlibc/options/ansi/musl-generic-math/nanl.c new file mode 100644 index 0000000..969af56 --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/nanl.c @@ -0,0 +1,6 @@ +#include + +long double nanl(const char *s) +{ + return NAN; +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/nearbyint.c b/lib/mlibc/options/ansi/musl-generic-math/nearbyint.c new file mode 100644 index 0000000..f4e8aac --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/nearbyint.c @@ -0,0 +1,20 @@ +#include +#include + +/* nearbyint is the same as rint, but it must not raise the inexact exception */ + +double nearbyint(double x) +{ +#ifdef FE_INEXACT + #pragma STDC FENV_ACCESS ON + int e; + + e = fetestexcept(FE_INEXACT); +#endif + x = rint(x); +#ifdef FE_INEXACT + if (!e) + feclearexcept(FE_INEXACT); +#endif + return x; +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/nearbyintf.c b/lib/mlibc/options/ansi/musl-generic-math/nearbyintf.c new file mode 100644 index 0000000..092e9ff --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/nearbyintf.c @@ -0,0 +1,18 @@ +#include +#include + +float nearbyintf(float x) +{ +#ifdef FE_INEXACT + #pragma STDC FENV_ACCESS ON + int e; + + e = fetestexcept(FE_INEXACT); +#endif + x = rintf(x); +#ifdef FE_INEXACT + if (!e) + feclearexcept(FE_INEXACT); +#endif + return x; +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/nearbyintl.c b/lib/mlibc/options/ansi/musl-generic-math/nearbyintl.c new file mode 100644 index 0000000..8285249 --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/nearbyintl.c @@ -0,0 +1,26 @@ +#include +#include + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double nearbyintl(long double x) +{ + return nearbyint(x); +} +#else +#include +long double nearbyintl(long double x) +{ +#ifdef FE_INEXACT + #pragma STDC FENV_ACCESS ON + int e; + + e = fetestexcept(FE_INEXACT); +#endif + x = rintl(x); +#ifdef FE_INEXACT + if (!e) + feclearexcept(FE_INEXACT); +#endif + return x; +} +#endif diff --git a/lib/mlibc/options/ansi/musl-generic-math/nextafter.c b/lib/mlibc/options/ansi/musl-generic-math/nextafter.c new file mode 100644 index 0000000..ab5795a --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/nextafter.c @@ -0,0 +1,31 @@ +#include "libm.h" + +double nextafter(double x, double y) +{ + union {double f; uint64_t i;} ux={x}, uy={y}; + uint64_t ax, ay; + int e; + + if (isnan(x) || isnan(y)) + return x + y; + if (ux.i == uy.i) + return y; + ax = ux.i & -1ULL/2; + ay = uy.i & -1ULL/2; + if (ax == 0) { + if (ay == 0) + return y; + ux.i = (uy.i & 1ULL<<63) | 1; + } else if (ax > ay || ((ux.i ^ uy.i) & 1ULL<<63)) + ux.i--; + else + ux.i++; + e = ux.i >> 52 & 0x7ff; + /* raise overflow if ux.f is infinite and x is finite */ + if (e == 0x7ff) + FORCE_EVAL(x+x); + /* raise underflow if ux.f is subnormal or zero */ + if (e == 0) + FORCE_EVAL(x*x + ux.f*ux.f); + return ux.f; +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/nextafterf.c b/lib/mlibc/options/ansi/musl-generic-math/nextafterf.c new file mode 100644 index 0000000..75a09f7 --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/nextafterf.c @@ -0,0 +1,30 @@ +#include "libm.h" + +float nextafterf(float x, float y) +{ + union {float f; uint32_t i;} ux={x}, uy={y}; + uint32_t ax, ay, e; + + if (isnan(x) || isnan(y)) + return x + y; + if (ux.i == uy.i) + return y; + ax = ux.i & 0x7fffffff; + ay = uy.i & 0x7fffffff; + if (ax == 0) { + if (ay == 0) + return y; + ux.i = (uy.i & 0x80000000) | 1; + } else if (ax > ay || ((ux.i ^ uy.i) & 0x80000000)) + ux.i--; + else + ux.i++; + e = ux.i & 0x7f800000; + /* raise overflow if ux.f is infinite and x is finite */ + if (e == 0x7f800000) + FORCE_EVAL(x+x); + /* raise underflow if ux.f is subnormal or zero */ + if (e == 0) + FORCE_EVAL(x*x + ux.f*ux.f); + return ux.f; +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/nextafterl.c b/lib/mlibc/options/ansi/musl-generic-math/nextafterl.c new file mode 100644 index 0000000..37e858f --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/nextafterl.c @@ -0,0 +1,75 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double nextafterl(long double x, long double y) +{ + return nextafter(x, y); +} +#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 +long double nextafterl(long double x, long double y) +{ + union ldshape ux, uy; + + if (isnan(x) || isnan(y)) + return x + y; + if (x == y) + return y; + ux.f = x; + if (x == 0) { + uy.f = y; + ux.i.m = 1; + ux.i.se = uy.i.se & 0x8000; + } else if ((x < y) == !(ux.i.se & 0x8000)) { + ux.i.m++; + if (ux.i.m << 1 == 0) { + ux.i.m = 1ULL << 63; + ux.i.se++; + } + } else { + if (ux.i.m << 1 == 0) { + ux.i.se--; + if (ux.i.se) + ux.i.m = 0; + } + ux.i.m--; + } + /* raise overflow if ux is infinite and x is finite */ + if ((ux.i.se & 0x7fff) == 0x7fff) + return x + x; + /* raise underflow if ux is subnormal or zero */ + if ((ux.i.se & 0x7fff) == 0) + FORCE_EVAL(x*x + ux.f*ux.f); + return ux.f; +} +#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 +long double nextafterl(long double x, long double y) +{ + union ldshape ux, uy; + + if (isnan(x) || isnan(y)) + return x + y; + if (x == y) + return y; + ux.f = x; + if (x == 0) { + uy.f = y; + ux.i.lo = 1; + ux.i.se = uy.i.se & 0x8000; + } else if ((x < y) == !(ux.i.se & 0x8000)) { + ux.i2.lo++; + if (ux.i2.lo == 0) + ux.i2.hi++; + } else { + if (ux.i2.lo == 0) + ux.i2.hi--; + ux.i2.lo--; + } + /* raise overflow if ux is infinite and x is finite */ + if ((ux.i.se & 0x7fff) == 0x7fff) + return x + x; + /* raise underflow if ux is subnormal or zero */ + if ((ux.i.se & 0x7fff) == 0) + FORCE_EVAL(x*x + ux.f*ux.f); + return ux.f; +} +#endif diff --git a/lib/mlibc/options/ansi/musl-generic-math/nexttoward.c b/lib/mlibc/options/ansi/musl-generic-math/nexttoward.c new file mode 100644 index 0000000..827ee5c --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/nexttoward.c @@ -0,0 +1,42 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +double nexttoward(double x, long double y) +{ + return nextafter(x, y); +} +#else +double nexttoward(double x, long double y) +{ + union {double f; uint64_t i;} ux = {x}; + int e; + + if (isnan(x) || isnan(y)) + return x + y; + if (x == y) + return y; + if (x == 0) { + ux.i = 1; + if (signbit(y)) + ux.i |= 1ULL<<63; + } else if (x < y) { + if (signbit(x)) + ux.i--; + else + ux.i++; + } else { + if (signbit(x)) + ux.i++; + else + ux.i--; + } + e = ux.i>>52 & 0x7ff; + /* raise overflow if ux.f is infinite and x is finite */ + if (e == 0x7ff) + FORCE_EVAL(x+x); + /* raise underflow if ux.f is subnormal or zero */ + if (e == 0) + FORCE_EVAL(x*x + ux.f*ux.f); + return ux.f; +} +#endif diff --git a/lib/mlibc/options/ansi/musl-generic-math/nexttowardf.c b/lib/mlibc/options/ansi/musl-generic-math/nexttowardf.c new file mode 100644 index 0000000..bbf172f --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/nexttowardf.c @@ -0,0 +1,35 @@ +#include "libm.h" + +float nexttowardf(float x, long double y) +{ + union {float f; uint32_t i;} ux = {x}; + uint32_t e; + + if (isnan(x) || isnan(y)) + return x + y; + if (x == y) + return y; + if (x == 0) { + ux.i = 1; + if (signbit(y)) + ux.i |= 0x80000000; + } else if (x < y) { + if (signbit(x)) + ux.i--; + else + ux.i++; + } else { + if (signbit(x)) + ux.i++; + else + ux.i--; + } + e = ux.i & 0x7f800000; + /* raise overflow if ux.f is infinite and x is finite */ + if (e == 0x7f800000) + FORCE_EVAL(x+x); + /* raise underflow if ux.f is subnormal or zero */ + if (e == 0) + FORCE_EVAL(x*x + ux.f*ux.f); + return ux.f; +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/nexttowardl.c b/lib/mlibc/options/ansi/musl-generic-math/nexttowardl.c new file mode 100644 index 0000000..67a6340 --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/nexttowardl.c @@ -0,0 +1,6 @@ +#include + +long double nexttowardl(long double x, long double y) +{ + return nextafterl(x, y); +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/pow.c b/lib/mlibc/options/ansi/musl-generic-math/pow.c new file mode 100644 index 0000000..3ddc1b6 --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/pow.c @@ -0,0 +1,328 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_pow.c */ +/* + * ==================================================== + * Copyright (C) 2004 by Sun Microsystems, Inc. All rights reserved. + * + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* pow(x,y) return x**y + * + * n + * Method: Let x = 2 * (1+f) + * 1. Compute and return log2(x) in two pieces: + * log2(x) = w1 + w2, + * where w1 has 53-24 = 29 bit trailing zeros. + * 2. Perform y*log2(x) = n+y' by simulating muti-precision + * arithmetic, where |y'|<=0.5. + * 3. Return x**y = 2**n*exp(y'*log2) + * + * Special cases: + * 1. (anything) ** 0 is 1 + * 2. 1 ** (anything) is 1 + * 3. (anything except 1) ** NAN is NAN + * 4. NAN ** (anything except 0) is NAN + * 5. +-(|x| > 1) ** +INF is +INF + * 6. +-(|x| > 1) ** -INF is +0 + * 7. +-(|x| < 1) ** +INF is +0 + * 8. +-(|x| < 1) ** -INF is +INF + * 9. -1 ** +-INF is 1 + * 10. +0 ** (+anything except 0, NAN) is +0 + * 11. -0 ** (+anything except 0, NAN, odd integer) is +0 + * 12. +0 ** (-anything except 0, NAN) is +INF, raise divbyzero + * 13. -0 ** (-anything except 0, NAN, odd integer) is +INF, raise divbyzero + * 14. -0 ** (+odd integer) is -0 + * 15. -0 ** (-odd integer) is -INF, raise divbyzero + * 16. +INF ** (+anything except 0,NAN) is +INF + * 17. +INF ** (-anything except 0,NAN) is +0 + * 18. -INF ** (+odd integer) is -INF + * 19. -INF ** (anything) = -0 ** (-anything), (anything except odd integer) + * 20. (anything) ** 1 is (anything) + * 21. (anything) ** -1 is 1/(anything) + * 22. (-anything) ** (integer) is (-1)**(integer)*(+anything**integer) + * 23. (-anything except 0 and inf) ** (non-integer) is NAN + * + * Accuracy: + * pow(x,y) returns x**y nearly rounded. In particular + * pow(integer,integer) + * always returns the correct integer provided it is + * representable. + * + * Constants : + * The hexadecimal values are the intended ones for the following + * constants. The decimal values may be used, provided that the + * compiler will convert from decimal to binary accurately enough + * to produce the hexadecimal values shown. + */ + +#include "libm.h" + +static const double +bp[] = {1.0, 1.5,}, +dp_h[] = { 0.0, 5.84962487220764160156e-01,}, /* 0x3FE2B803, 0x40000000 */ +dp_l[] = { 0.0, 1.35003920212974897128e-08,}, /* 0x3E4CFDEB, 0x43CFD006 */ +two53 = 9007199254740992.0, /* 0x43400000, 0x00000000 */ +huge = 1.0e300, +tiny = 1.0e-300, +/* poly coefs for (3/2)*(log(x)-2s-2/3*s**3 */ +L1 = 5.99999999999994648725e-01, /* 0x3FE33333, 0x33333303 */ +L2 = 4.28571428578550184252e-01, /* 0x3FDB6DB6, 0xDB6FABFF */ +L3 = 3.33333329818377432918e-01, /* 0x3FD55555, 0x518F264D */ +L4 = 2.72728123808534006489e-01, /* 0x3FD17460, 0xA91D4101 */ +L5 = 2.30660745775561754067e-01, /* 0x3FCD864A, 0x93C9DB65 */ +L6 = 2.06975017800338417784e-01, /* 0x3FCA7E28, 0x4A454EEF */ +P1 = 1.66666666666666019037e-01, /* 0x3FC55555, 0x5555553E */ +P2 = -2.77777777770155933842e-03, /* 0xBF66C16C, 0x16BEBD93 */ +P3 = 6.61375632143793436117e-05, /* 0x3F11566A, 0xAF25DE2C */ +P4 = -1.65339022054652515390e-06, /* 0xBEBBBD41, 0xC5D26BF1 */ +P5 = 4.13813679705723846039e-08, /* 0x3E663769, 0x72BEA4D0 */ +lg2 = 6.93147180559945286227e-01, /* 0x3FE62E42, 0xFEFA39EF */ +lg2_h = 6.93147182464599609375e-01, /* 0x3FE62E43, 0x00000000 */ +lg2_l = -1.90465429995776804525e-09, /* 0xBE205C61, 0x0CA86C39 */ +ovt = 8.0085662595372944372e-017, /* -(1024-log2(ovfl+.5ulp)) */ +cp = 9.61796693925975554329e-01, /* 0x3FEEC709, 0xDC3A03FD =2/(3ln2) */ +cp_h = 9.61796700954437255859e-01, /* 0x3FEEC709, 0xE0000000 =(float)cp */ +cp_l = -7.02846165095275826516e-09, /* 0xBE3E2FE0, 0x145B01F5 =tail of cp_h*/ +ivln2 = 1.44269504088896338700e+00, /* 0x3FF71547, 0x652B82FE =1/ln2 */ +ivln2_h = 1.44269502162933349609e+00, /* 0x3FF71547, 0x60000000 =24b 1/ln2*/ +ivln2_l = 1.92596299112661746887e-08; /* 0x3E54AE0B, 0xF85DDF44 =1/ln2 tail*/ + +double pow(double x, double y) +{ + double z,ax,z_h,z_l,p_h,p_l; + double y1,t1,t2,r,s,t,u,v,w; + int32_t i,j,k,yisint,n; + int32_t hx,hy,ix,iy; + uint32_t lx,ly; + + EXTRACT_WORDS(hx, lx, x); + EXTRACT_WORDS(hy, ly, y); + ix = hx & 0x7fffffff; + iy = hy & 0x7fffffff; + + /* x**0 = 1, even if x is NaN */ + if ((iy|ly) == 0) + return 1.0; + /* 1**y = 1, even if y is NaN */ + if (hx == 0x3ff00000 && lx == 0) + return 1.0; + /* NaN if either arg is NaN */ + if (ix > 0x7ff00000 || (ix == 0x7ff00000 && lx != 0) || + iy > 0x7ff00000 || (iy == 0x7ff00000 && ly != 0)) + return x + y; + + /* determine if y is an odd int when x < 0 + * yisint = 0 ... y is not an integer + * yisint = 1 ... y is an odd int + * yisint = 2 ... y is an even int + */ + yisint = 0; + if (hx < 0) { + if (iy >= 0x43400000) + yisint = 2; /* even integer y */ + else if (iy >= 0x3ff00000) { + k = (iy>>20) - 0x3ff; /* exponent */ + if (k > 20) { + uint32_t j = ly>>(52-k); + if ((j<<(52-k)) == ly) + yisint = 2 - (j&1); + } else if (ly == 0) { + uint32_t j = iy>>(20-k); + if ((j<<(20-k)) == iy) + yisint = 2 - (j&1); + } + } + } + + /* special value of y */ + if (ly == 0) { + if (iy == 0x7ff00000) { /* y is +-inf */ + if (((ix-0x3ff00000)|lx) == 0) /* (-1)**+-inf is 1 */ + return 1.0; + else if (ix >= 0x3ff00000) /* (|x|>1)**+-inf = inf,0 */ + return hy >= 0 ? y : 0.0; + else /* (|x|<1)**+-inf = 0,inf */ + return hy >= 0 ? 0.0 : -y; + } + if (iy == 0x3ff00000) { /* y is +-1 */ + if (hy >= 0) + return x; + y = 1/x; +#if FLT_EVAL_METHOD!=0 + { + union {double f; uint64_t i;} u = {y}; + uint64_t i = u.i & -1ULL/2; + if (i>>52 == 0 && (i&(i-1))) + FORCE_EVAL((float)y); + } +#endif + return y; + } + if (hy == 0x40000000) /* y is 2 */ + return x*x; + if (hy == 0x3fe00000) { /* y is 0.5 */ + if (hx >= 0) /* x >= +0 */ + return sqrt(x); + } + } + + ax = fabs(x); + /* special value of x */ + if (lx == 0) { + if (ix == 0x7ff00000 || ix == 0 || ix == 0x3ff00000) { /* x is +-0,+-inf,+-1 */ + z = ax; + if (hy < 0) /* z = (1/|x|) */ + z = 1.0/z; + if (hx < 0) { + if (((ix-0x3ff00000)|yisint) == 0) { + z = (z-z)/(z-z); /* (-1)**non-int is NaN */ + } else if (yisint == 1) + z = -z; /* (x<0)**odd = -(|x|**odd) */ + } + return z; + } + } + + s = 1.0; /* sign of result */ + if (hx < 0) { + if (yisint == 0) /* (x<0)**(non-int) is NaN */ + return (x-x)/(x-x); + if (yisint == 1) /* (x<0)**(odd int) */ + s = -1.0; + } + + /* |y| is huge */ + if (iy > 0x41e00000) { /* if |y| > 2**31 */ + if (iy > 0x43f00000) { /* if |y| > 2**64, must o/uflow */ + if (ix <= 0x3fefffff) + return hy < 0 ? huge*huge : tiny*tiny; + if (ix >= 0x3ff00000) + return hy > 0 ? huge*huge : tiny*tiny; + } + /* over/underflow if x is not close to one */ + if (ix < 0x3fefffff) + return hy < 0 ? s*huge*huge : s*tiny*tiny; + if (ix > 0x3ff00000) + return hy > 0 ? s*huge*huge : s*tiny*tiny; + /* now |1-x| is tiny <= 2**-20, suffice to compute + log(x) by x-x^2/2+x^3/3-x^4/4 */ + t = ax - 1.0; /* t has 20 trailing zeros */ + w = (t*t)*(0.5 - t*(0.3333333333333333333333-t*0.25)); + u = ivln2_h*t; /* ivln2_h has 21 sig. bits */ + v = t*ivln2_l - w*ivln2; + t1 = u + v; + SET_LOW_WORD(t1, 0); + t2 = v - (t1-u); + } else { + double ss,s2,s_h,s_l,t_h,t_l; + n = 0; + /* take care subnormal number */ + if (ix < 0x00100000) { + ax *= two53; + n -= 53; + GET_HIGH_WORD(ix,ax); + } + n += ((ix)>>20) - 0x3ff; + j = ix & 0x000fffff; + /* determine interval */ + ix = j | 0x3ff00000; /* normalize ix */ + if (j <= 0x3988E) /* |x|>1)|0x20000000) + 0x00080000 + (k<<18)); + t_l = ax - (t_h-bp[k]); + s_l = v*((u-s_h*t_h)-s_h*t_l); + /* compute log(ax) */ + s2 = ss*ss; + r = s2*s2*(L1+s2*(L2+s2*(L3+s2*(L4+s2*(L5+s2*L6))))); + r += s_l*(s_h+ss); + s2 = s_h*s_h; + t_h = 3.0 + s2 + r; + SET_LOW_WORD(t_h, 0); + t_l = r - ((t_h-3.0)-s2); + /* u+v = ss*(1+...) */ + u = s_h*t_h; + v = s_l*t_h + t_l*ss; + /* 2/(3log2)*(ss+...) */ + p_h = u + v; + SET_LOW_WORD(p_h, 0); + p_l = v - (p_h-u); + z_h = cp_h*p_h; /* cp_h+cp_l = 2/(3*log2) */ + z_l = cp_l*p_h+p_l*cp + dp_l[k]; + /* log2(ax) = (ss+..)*2/(3*log2) = n + dp_h + z_h + z_l */ + t = (double)n; + t1 = ((z_h + z_l) + dp_h[k]) + t; + SET_LOW_WORD(t1, 0); + t2 = z_l - (((t1 - t) - dp_h[k]) - z_h); + } + + /* split up y into y1+y2 and compute (y1+y2)*(t1+t2) */ + y1 = y; + SET_LOW_WORD(y1, 0); + p_l = (y-y1)*t1 + y*t2; + p_h = y1*t1; + z = p_l + p_h; + EXTRACT_WORDS(j, i, z); + if (j >= 0x40900000) { /* z >= 1024 */ + if (((j-0x40900000)|i) != 0) /* if z > 1024 */ + return s*huge*huge; /* overflow */ + if (p_l + ovt > z - p_h) + return s*huge*huge; /* overflow */ + } else if ((j&0x7fffffff) >= 0x4090cc00) { /* z <= -1075 */ // FIXME: instead of abs(j) use unsigned j + if (((j-0xc090cc00)|i) != 0) /* z < -1075 */ + return s*tiny*tiny; /* underflow */ + if (p_l <= z - p_h) + return s*tiny*tiny; /* underflow */ + } + /* + * compute 2**(p_h+p_l) + */ + i = j & 0x7fffffff; + k = (i>>20) - 0x3ff; + n = 0; + if (i > 0x3fe00000) { /* if |z| > 0.5, set n = [z+0.5] */ + n = j + (0x00100000>>(k+1)); + k = ((n&0x7fffffff)>>20) - 0x3ff; /* new k for n */ + t = 0.0; + SET_HIGH_WORD(t, n & ~(0x000fffff>>k)); + n = ((n&0x000fffff)|0x00100000)>>(20-k); + if (j < 0) + n = -n; + p_h -= t; + } + t = p_l + p_h; + SET_LOW_WORD(t, 0); + u = t*lg2_h; + v = (p_l-(t-p_h))*lg2 + t*lg2_l; + z = u + v; + w = v - (z-u); + t = z*z; + t1 = z - t*(P1+t*(P2+t*(P3+t*(P4+t*P5)))); + r = (z*t1)/(t1-2.0) - (w + z*w); + z = 1.0 - (r-z); + GET_HIGH_WORD(j, z); + j += n<<20; + if ((j>>20) <= 0) /* subnormal output */ + z = scalbn(z,n); + else + SET_HIGH_WORD(z, j); + return s*z; +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/powf.c b/lib/mlibc/options/ansi/musl-generic-math/powf.c new file mode 100644 index 0000000..427c896 --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/powf.c @@ -0,0 +1,259 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_powf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "libm.h" + +static const float +bp[] = {1.0, 1.5,}, +dp_h[] = { 0.0, 5.84960938e-01,}, /* 0x3f15c000 */ +dp_l[] = { 0.0, 1.56322085e-06,}, /* 0x35d1cfdc */ +two24 = 16777216.0, /* 0x4b800000 */ +huge = 1.0e30, +tiny = 1.0e-30, +/* poly coefs for (3/2)*(log(x)-2s-2/3*s**3 */ +L1 = 6.0000002384e-01, /* 0x3f19999a */ +L2 = 4.2857143283e-01, /* 0x3edb6db7 */ +L3 = 3.3333334327e-01, /* 0x3eaaaaab */ +L4 = 2.7272811532e-01, /* 0x3e8ba305 */ +L5 = 2.3066075146e-01, /* 0x3e6c3255 */ +L6 = 2.0697501302e-01, /* 0x3e53f142 */ +P1 = 1.6666667163e-01, /* 0x3e2aaaab */ +P2 = -2.7777778450e-03, /* 0xbb360b61 */ +P3 = 6.6137559770e-05, /* 0x388ab355 */ +P4 = -1.6533901999e-06, /* 0xb5ddea0e */ +P5 = 4.1381369442e-08, /* 0x3331bb4c */ +lg2 = 6.9314718246e-01, /* 0x3f317218 */ +lg2_h = 6.93145752e-01, /* 0x3f317200 */ +lg2_l = 1.42860654e-06, /* 0x35bfbe8c */ +ovt = 4.2995665694e-08, /* -(128-log2(ovfl+.5ulp)) */ +cp = 9.6179670095e-01, /* 0x3f76384f =2/(3ln2) */ +cp_h = 9.6191406250e-01, /* 0x3f764000 =12b cp */ +cp_l = -1.1736857402e-04, /* 0xb8f623c6 =tail of cp_h */ +ivln2 = 1.4426950216e+00, /* 0x3fb8aa3b =1/ln2 */ +ivln2_h = 1.4426879883e+00, /* 0x3fb8aa00 =16b 1/ln2*/ +ivln2_l = 7.0526075433e-06; /* 0x36eca570 =1/ln2 tail*/ + +float powf(float x, float y) +{ + float z,ax,z_h,z_l,p_h,p_l; + float y1,t1,t2,r,s,sn,t,u,v,w; + int32_t i,j,k,yisint,n; + int32_t hx,hy,ix,iy,is; + + GET_FLOAT_WORD(hx, x); + GET_FLOAT_WORD(hy, y); + ix = hx & 0x7fffffff; + iy = hy & 0x7fffffff; + + /* x**0 = 1, even if x is NaN */ + if (iy == 0) + return 1.0f; + /* 1**y = 1, even if y is NaN */ + if (hx == 0x3f800000) + return 1.0f; + /* NaN if either arg is NaN */ + if (ix > 0x7f800000 || iy > 0x7f800000) + return x + y; + + /* determine if y is an odd int when x < 0 + * yisint = 0 ... y is not an integer + * yisint = 1 ... y is an odd int + * yisint = 2 ... y is an even int + */ + yisint = 0; + if (hx < 0) { + if (iy >= 0x4b800000) + yisint = 2; /* even integer y */ + else if (iy >= 0x3f800000) { + k = (iy>>23) - 0x7f; /* exponent */ + j = iy>>(23-k); + if ((j<<(23-k)) == iy) + yisint = 2 - (j & 1); + } + } + + /* special value of y */ + if (iy == 0x7f800000) { /* y is +-inf */ + if (ix == 0x3f800000) /* (-1)**+-inf is 1 */ + return 1.0f; + else if (ix > 0x3f800000) /* (|x|>1)**+-inf = inf,0 */ + return hy >= 0 ? y : 0.0f; + else /* (|x|<1)**+-inf = 0,inf */ + return hy >= 0 ? 0.0f: -y; + } + if (iy == 0x3f800000) /* y is +-1 */ + return hy >= 0 ? x : 1.0f/x; + if (hy == 0x40000000) /* y is 2 */ + return x*x; + if (hy == 0x3f000000) { /* y is 0.5 */ + if (hx >= 0) /* x >= +0 */ + return sqrtf(x); + } + + ax = fabsf(x); + /* special value of x */ + if (ix == 0x7f800000 || ix == 0 || ix == 0x3f800000) { /* x is +-0,+-inf,+-1 */ + z = ax; + if (hy < 0) /* z = (1/|x|) */ + z = 1.0f/z; + if (hx < 0) { + if (((ix-0x3f800000)|yisint) == 0) { + z = (z-z)/(z-z); /* (-1)**non-int is NaN */ + } else if (yisint == 1) + z = -z; /* (x<0)**odd = -(|x|**odd) */ + } + return z; + } + + sn = 1.0f; /* sign of result */ + if (hx < 0) { + if (yisint == 0) /* (x<0)**(non-int) is NaN */ + return (x-x)/(x-x); + if (yisint == 1) /* (x<0)**(odd int) */ + sn = -1.0f; + } + + /* |y| is huge */ + if (iy > 0x4d000000) { /* if |y| > 2**27 */ + /* over/underflow if x is not close to one */ + if (ix < 0x3f7ffff8) + return hy < 0 ? sn*huge*huge : sn*tiny*tiny; + if (ix > 0x3f800007) + return hy > 0 ? sn*huge*huge : sn*tiny*tiny; + /* now |1-x| is tiny <= 2**-20, suffice to compute + log(x) by x-x^2/2+x^3/3-x^4/4 */ + t = ax - 1; /* t has 20 trailing zeros */ + w = (t*t)*(0.5f - t*(0.333333333333f - t*0.25f)); + u = ivln2_h*t; /* ivln2_h has 16 sig. bits */ + v = t*ivln2_l - w*ivln2; + t1 = u + v; + GET_FLOAT_WORD(is, t1); + SET_FLOAT_WORD(t1, is & 0xfffff000); + t2 = v - (t1-u); + } else { + float s2,s_h,s_l,t_h,t_l; + n = 0; + /* take care subnormal number */ + if (ix < 0x00800000) { + ax *= two24; + n -= 24; + GET_FLOAT_WORD(ix, ax); + } + n += ((ix)>>23) - 0x7f; + j = ix & 0x007fffff; + /* determine interval */ + ix = j | 0x3f800000; /* normalize ix */ + if (j <= 0x1cc471) /* |x|>1) & 0xfffff000) | 0x20000000; + SET_FLOAT_WORD(t_h, is + 0x00400000 + (k<<21)); + t_l = ax - (t_h - bp[k]); + s_l = v*((u - s_h*t_h) - s_h*t_l); + /* compute log(ax) */ + s2 = s*s; + r = s2*s2*(L1+s2*(L2+s2*(L3+s2*(L4+s2*(L5+s2*L6))))); + r += s_l*(s_h+s); + s2 = s_h*s_h; + t_h = 3.0f + s2 + r; + GET_FLOAT_WORD(is, t_h); + SET_FLOAT_WORD(t_h, is & 0xfffff000); + t_l = r - ((t_h - 3.0f) - s2); + /* u+v = s*(1+...) */ + u = s_h*t_h; + v = s_l*t_h + t_l*s; + /* 2/(3log2)*(s+...) */ + p_h = u + v; + GET_FLOAT_WORD(is, p_h); + SET_FLOAT_WORD(p_h, is & 0xfffff000); + p_l = v - (p_h - u); + z_h = cp_h*p_h; /* cp_h+cp_l = 2/(3*log2) */ + z_l = cp_l*p_h + p_l*cp+dp_l[k]; + /* log2(ax) = (s+..)*2/(3*log2) = n + dp_h + z_h + z_l */ + t = (float)n; + t1 = (((z_h + z_l) + dp_h[k]) + t); + GET_FLOAT_WORD(is, t1); + SET_FLOAT_WORD(t1, is & 0xfffff000); + t2 = z_l - (((t1 - t) - dp_h[k]) - z_h); + } + + /* split up y into y1+y2 and compute (y1+y2)*(t1+t2) */ + GET_FLOAT_WORD(is, y); + SET_FLOAT_WORD(y1, is & 0xfffff000); + p_l = (y-y1)*t1 + y*t2; + p_h = y1*t1; + z = p_l + p_h; + GET_FLOAT_WORD(j, z); + if (j > 0x43000000) /* if z > 128 */ + return sn*huge*huge; /* overflow */ + else if (j == 0x43000000) { /* if z == 128 */ + if (p_l + ovt > z - p_h) + return sn*huge*huge; /* overflow */ + } else if ((j&0x7fffffff) > 0x43160000) /* z < -150 */ // FIXME: check should be (uint32_t)j > 0xc3160000 + return sn*tiny*tiny; /* underflow */ + else if (j == 0xc3160000) { /* z == -150 */ + if (p_l <= z-p_h) + return sn*tiny*tiny; /* underflow */ + } + /* + * compute 2**(p_h+p_l) + */ + i = j & 0x7fffffff; + k = (i>>23) - 0x7f; + n = 0; + if (i > 0x3f000000) { /* if |z| > 0.5, set n = [z+0.5] */ + n = j + (0x00800000>>(k+1)); + k = ((n&0x7fffffff)>>23) - 0x7f; /* new k for n */ + SET_FLOAT_WORD(t, n & ~(0x007fffff>>k)); + n = ((n&0x007fffff)|0x00800000)>>(23-k); + if (j < 0) + n = -n; + p_h -= t; + } + t = p_l + p_h; + GET_FLOAT_WORD(is, t); + SET_FLOAT_WORD(t, is & 0xffff8000); + u = t*lg2_h; + v = (p_l-(t-p_h))*lg2 + t*lg2_l; + z = u + v; + w = v - (z - u); + t = z*z; + t1 = z - t*(P1+t*(P2+t*(P3+t*(P4+t*P5)))); + r = (z*t1)/(t1-2.0f) - (w+z*w); + z = 1.0f - (r - z); + GET_FLOAT_WORD(j, z); + j += n<<23; + if ((j>>23) <= 0) /* subnormal output */ + z = scalbnf(z, n); + else + SET_FLOAT_WORD(z, j); + return sn*z; +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/powl.c b/lib/mlibc/options/ansi/musl-generic-math/powl.c new file mode 100644 index 0000000..5b6da07 --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/powl.c @@ -0,0 +1,522 @@ +/* origin: OpenBSD /usr/src/lib/libm/src/ld80/e_powl.c */ +/* + * Copyright (c) 2008 Stephen L. Moshier + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/* powl.c + * + * Power function, long double precision + * + * + * SYNOPSIS: + * + * long double x, y, z, powl(); + * + * z = powl( x, y ); + * + * + * DESCRIPTION: + * + * Computes x raised to the yth power. Analytically, + * + * x**y = exp( y log(x) ). + * + * Following Cody and Waite, this program uses a lookup table + * of 2**-i/32 and pseudo extended precision arithmetic to + * obtain several extra bits of accuracy in both the logarithm + * and the exponential. + * + * + * ACCURACY: + * + * The relative error of pow(x,y) can be estimated + * by y dl ln(2), where dl is the absolute error of + * the internally computed base 2 logarithm. At the ends + * of the approximation interval the logarithm equal 1/32 + * and its relative error is about 1 lsb = 1.1e-19. Hence + * the predicted relative error in the result is 2.3e-21 y . + * + * Relative error: + * arithmetic domain # trials peak rms + * + * IEEE +-1000 40000 2.8e-18 3.7e-19 + * .001 < x < 1000, with log(x) uniformly distributed. + * -1000 < y < 1000, y uniformly distributed. + * + * IEEE 0,8700 60000 6.5e-18 1.0e-18 + * 0.99 < x < 1.01, 0 < y < 8700, uniformly distributed. + * + * + * ERROR MESSAGES: + * + * message condition value returned + * pow overflow x**y > MAXNUM INFINITY + * pow underflow x**y < 1/MAXNUM 0.0 + * pow domain x<0 and y noninteger 0.0 + * + */ + +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double powl(long double x, long double y) +{ + return pow(x, y); +} +#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 + +/* Table size */ +#define NXT 32 + +/* log(1+x) = x - .5x^2 + x^3 * P(z)/Q(z) + * on the domain 2^(-1/32) - 1 <= x <= 2^(1/32) - 1 + */ +static const long double P[] = { + 8.3319510773868690346226E-4L, + 4.9000050881978028599627E-1L, + 1.7500123722550302671919E0L, + 1.4000100839971580279335E0L, +}; +static const long double Q[] = { +/* 1.0000000000000000000000E0L,*/ + 5.2500282295834889175431E0L, + 8.4000598057587009834666E0L, + 4.2000302519914740834728E0L, +}; +/* A[i] = 2^(-i/32), rounded to IEEE long double precision. + * If i is even, A[i] + B[i/2] gives additional accuracy. + */ +static const long double A[33] = { + 1.0000000000000000000000E0L, + 9.7857206208770013448287E-1L, + 9.5760328069857364691013E-1L, + 9.3708381705514995065011E-1L, + 9.1700404320467123175367E-1L, + 8.9735453750155359320742E-1L, + 8.7812608018664974155474E-1L, + 8.5930964906123895780165E-1L, + 8.4089641525371454301892E-1L, + 8.2287773907698242225554E-1L, + 8.0524516597462715409607E-1L, + 7.8799042255394324325455E-1L, + 7.7110541270397041179298E-1L, + 7.5458221379671136985669E-1L, + 7.3841307296974965571198E-1L, + 7.2259040348852331001267E-1L, + 7.0710678118654752438189E-1L, + 6.9195494098191597746178E-1L, + 6.7712777346844636413344E-1L, + 6.6261832157987064729696E-1L, + 6.4841977732550483296079E-1L, + 6.3452547859586661129850E-1L, + 6.2092890603674202431705E-1L, + 6.0762367999023443907803E-1L, + 5.9460355750136053334378E-1L, + 5.8186242938878875689693E-1L, + 5.6939431737834582684856E-1L, + 5.5719337129794626814472E-1L, + 5.4525386633262882960438E-1L, + 5.3357020033841180906486E-1L, + 5.2213689121370692017331E-1L, + 5.1094857432705833910408E-1L, + 5.0000000000000000000000E-1L, +}; +static const long double B[17] = { + 0.0000000000000000000000E0L, + 2.6176170809902549338711E-20L, +-1.0126791927256478897086E-20L, + 1.3438228172316276937655E-21L, + 1.2207982955417546912101E-20L, +-6.3084814358060867200133E-21L, + 1.3164426894366316434230E-20L, +-1.8527916071632873716786E-20L, + 1.8950325588932570796551E-20L, + 1.5564775779538780478155E-20L, + 6.0859793637556860974380E-21L, +-2.0208749253662532228949E-20L, + 1.4966292219224761844552E-20L, + 3.3540909728056476875639E-21L, +-8.6987564101742849540743E-22L, +-1.2327176863327626135542E-20L, + 0.0000000000000000000000E0L, +}; + +/* 2^x = 1 + x P(x), + * on the interval -1/32 <= x <= 0 + */ +static const long double R[] = { + 1.5089970579127659901157E-5L, + 1.5402715328927013076125E-4L, + 1.3333556028915671091390E-3L, + 9.6181291046036762031786E-3L, + 5.5504108664798463044015E-2L, + 2.4022650695910062854352E-1L, + 6.9314718055994530931447E-1L, +}; + +#define MEXP (NXT*16384.0L) +/* The following if denormal numbers are supported, else -MEXP: */ +#define MNEXP (-NXT*(16384.0L+64.0L)) +/* log2(e) - 1 */ +#define LOG2EA 0.44269504088896340735992L + +#define F W +#define Fa Wa +#define Fb Wb +#define G W +#define Ga Wa +#define Gb u +#define H W +#define Ha Wb +#define Hb Wb + +static const long double MAXLOGL = 1.1356523406294143949492E4L; +static const long double MINLOGL = -1.13994985314888605586758E4L; +static const long double LOGE2L = 6.9314718055994530941723E-1L; +static const long double huge = 0x1p10000L; +/* XXX Prevent gcc from erroneously constant folding this. */ +static const volatile long double twom10000 = 0x1p-10000L; + +static long double reducl(long double); +static long double powil(long double, int); + +long double powl(long double x, long double y) +{ + /* double F, Fa, Fb, G, Ga, Gb, H, Ha, Hb */ + int i, nflg, iyflg, yoddint; + long e; + volatile long double z=0; + long double w=0, W=0, Wa=0, Wb=0, ya=0, yb=0, u=0; + + /* make sure no invalid exception is raised by nan comparision */ + if (isnan(x)) { + if (!isnan(y) && y == 0.0) + return 1.0; + return x; + } + if (isnan(y)) { + if (x == 1.0) + return 1.0; + return y; + } + if (x == 1.0) + return 1.0; /* 1**y = 1, even if y is nan */ + if (x == -1.0 && !isfinite(y)) + return 1.0; /* -1**inf = 1 */ + if (y == 0.0) + return 1.0; /* x**0 = 1, even if x is nan */ + if (y == 1.0) + return x; + if (y >= LDBL_MAX) { + if (x > 1.0 || x < -1.0) + return INFINITY; + if (x != 0.0) + return 0.0; + } + if (y <= -LDBL_MAX) { + if (x > 1.0 || x < -1.0) + return 0.0; + if (x != 0.0 || y == -INFINITY) + return INFINITY; + } + if (x >= LDBL_MAX) { + if (y > 0.0) + return INFINITY; + return 0.0; + } + + w = floorl(y); + + /* Set iyflg to 1 if y is an integer. */ + iyflg = 0; + if (w == y) + iyflg = 1; + + /* Test for odd integer y. */ + yoddint = 0; + if (iyflg) { + ya = fabsl(y); + ya = floorl(0.5 * ya); + yb = 0.5 * fabsl(w); + if( ya != yb ) + yoddint = 1; + } + + if (x <= -LDBL_MAX) { + if (y > 0.0) { + if (yoddint) + return -INFINITY; + return INFINITY; + } + if (y < 0.0) { + if (yoddint) + return -0.0; + return 0.0; + } + } + nflg = 0; /* (x<0)**(odd int) */ + if (x <= 0.0) { + if (x == 0.0) { + if (y < 0.0) { + if (signbit(x) && yoddint) + /* (-0.0)**(-odd int) = -inf, divbyzero */ + return -1.0/0.0; + /* (+-0.0)**(negative) = inf, divbyzero */ + return 1.0/0.0; + } + if (signbit(x) && yoddint) + return -0.0; + return 0.0; + } + if (iyflg == 0) + return (x - x) / (x - x); /* (x<0)**(non-int) is NaN */ + /* (x<0)**(integer) */ + if (yoddint) + nflg = 1; /* negate result */ + x = -x; + } + /* (+integer)**(integer) */ + if (iyflg && floorl(x) == x && fabsl(y) < 32768.0) { + w = powil(x, (int)y); + return nflg ? -w : w; + } + + /* separate significand from exponent */ + x = frexpl(x, &i); + e = i; + + /* find significand in antilog table A[] */ + i = 1; + if (x <= A[17]) + i = 17; + if (x <= A[i+8]) + i += 8; + if (x <= A[i+4]) + i += 4; + if (x <= A[i+2]) + i += 2; + if (x >= A[1]) + i = -1; + i += 1; + + /* Find (x - A[i])/A[i] + * in order to compute log(x/A[i]): + * + * log(x) = log( a x/a ) = log(a) + log(x/a) + * + * log(x/a) = log(1+v), v = x/a - 1 = (x-a)/a + */ + x -= A[i]; + x -= B[i/2]; + x /= A[i]; + + /* rational approximation for log(1+v): + * + * log(1+v) = v - v**2/2 + v**3 P(v) / Q(v) + */ + z = x*x; + w = x * (z * __polevll(x, P, 3) / __p1evll(x, Q, 3)); + w = w - 0.5*z; + + /* Convert to base 2 logarithm: + * multiply by log2(e) = 1 + LOG2EA + */ + z = LOG2EA * w; + z += w; + z += LOG2EA * x; + z += x; + + /* Compute exponent term of the base 2 logarithm. */ + w = -i; + w /= NXT; + w += e; + /* Now base 2 log of x is w + z. */ + + /* Multiply base 2 log by y, in extended precision. */ + + /* separate y into large part ya + * and small part yb less than 1/NXT + */ + ya = reducl(y); + yb = y - ya; + + /* (w+z)(ya+yb) + * = w*ya + w*yb + z*y + */ + F = z * y + w * yb; + Fa = reducl(F); + Fb = F - Fa; + + G = Fa + w * ya; + Ga = reducl(G); + Gb = G - Ga; + + H = Fb + Gb; + Ha = reducl(H); + w = (Ga + Ha) * NXT; + + /* Test the power of 2 for overflow */ + if (w > MEXP) + return huge * huge; /* overflow */ + if (w < MNEXP) + return twom10000 * twom10000; /* underflow */ + + e = w; + Hb = H - Ha; + + if (Hb > 0.0) { + e += 1; + Hb -= 1.0/NXT; /*0.0625L;*/ + } + + /* Now the product y * log2(x) = Hb + e/NXT. + * + * Compute base 2 exponential of Hb, + * where -0.0625 <= Hb <= 0. + */ + z = Hb * __polevll(Hb, R, 6); /* z = 2**Hb - 1 */ + + /* Express e/NXT as an integer plus a negative number of (1/NXT)ths. + * Find lookup table entry for the fractional power of 2. + */ + if (e < 0) + i = 0; + else + i = 1; + i = e/NXT + i; + e = NXT*i - e; + w = A[e]; + z = w * z; /* 2**-e * ( 1 + (2**Hb-1) ) */ + z = z + w; + z = scalbnl(z, i); /* multiply by integer power of 2 */ + + if (nflg) + z = -z; + return z; +} + + +/* Find a multiple of 1/NXT that is within 1/NXT of x. */ +static long double reducl(long double x) +{ + long double t; + + t = x * NXT; + t = floorl(t); + t = t / NXT; + return t; +} + +/* + * Positive real raised to integer power, long double precision + * + * + * SYNOPSIS: + * + * long double x, y, powil(); + * int n; + * + * y = powil( x, n ); + * + * + * DESCRIPTION: + * + * Returns argument x>0 raised to the nth power. + * The routine efficiently decomposes n as a sum of powers of + * two. The desired power is a product of two-to-the-kth + * powers of x. Thus to compute the 32767 power of x requires + * 28 multiplications instead of 32767 multiplications. + * + * + * ACCURACY: + * + * Relative error: + * arithmetic x domain n domain # trials peak rms + * IEEE .001,1000 -1022,1023 50000 4.3e-17 7.8e-18 + * IEEE 1,2 -1022,1023 20000 3.9e-17 7.6e-18 + * IEEE .99,1.01 0,8700 10000 3.6e-16 7.2e-17 + * + * Returns MAXNUM on overflow, zero on underflow. + */ + +static long double powil(long double x, int nn) +{ + long double ww, y; + long double s; + int n, e, sign, lx; + + if (nn == 0) + return 1.0; + + if (nn < 0) { + sign = -1; + n = -nn; + } else { + sign = 1; + n = nn; + } + + /* Overflow detection */ + + /* Calculate approximate logarithm of answer */ + s = x; + s = frexpl( s, &lx); + e = (lx - 1)*n; + if ((e == 0) || (e > 64) || (e < -64)) { + s = (s - 7.0710678118654752e-1L) / (s + 7.0710678118654752e-1L); + s = (2.9142135623730950L * s - 0.5 + lx) * nn * LOGE2L; + } else { + s = LOGE2L * e; + } + + if (s > MAXLOGL) + return huge * huge; /* overflow */ + + if (s < MINLOGL) + return twom10000 * twom10000; /* underflow */ + /* Handle tiny denormal answer, but with less accuracy + * since roundoff error in 1.0/x will be amplified. + * The precise demarcation should be the gradual underflow threshold. + */ + if (s < -MAXLOGL+2.0) { + x = 1.0/x; + sign = -sign; + } + + /* First bit of the power */ + if (n & 1) + y = x; + else + y = 1.0; + + ww = x; + n >>= 1; + while (n) { + ww = ww * ww; /* arg to the 2-to-the-kth power */ + if (n & 1) /* if that bit is set, then include in product */ + y *= ww; + n >>= 1; + } + + if (sign < 0) + y = 1.0/y; + return y; +} +#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 +// TODO: broken implementation to make things compile +long double powl(long double x, long double y) +{ + return pow(x, y); +} +#endif diff --git a/lib/mlibc/options/ansi/musl-generic-math/remainder.c b/lib/mlibc/options/ansi/musl-generic-math/remainder.c new file mode 100644 index 0000000..e4abcd7 --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/remainder.c @@ -0,0 +1,11 @@ +#include +#include "weak_alias.h" +//#include "libc.h" + +double remainder(double x, double y) +{ + int q; + return remquo(x, y, &q); +} + +weak_alias(remainder, drem); diff --git a/lib/mlibc/options/ansi/musl-generic-math/remainderf.c b/lib/mlibc/options/ansi/musl-generic-math/remainderf.c new file mode 100644 index 0000000..e1fcdaa --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/remainderf.c @@ -0,0 +1,11 @@ +#include +#include "weak_alias.h" +//#include "libc.h" + +float remainderf(float x, float y) +{ + int q; + return remquof(x, y, &q); +} + +weak_alias(remainderf, dremf); diff --git a/lib/mlibc/options/ansi/musl-generic-math/remainderl.c b/lib/mlibc/options/ansi/musl-generic-math/remainderl.c new file mode 100644 index 0000000..2a13c1d --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/remainderl.c @@ -0,0 +1,15 @@ +#include +#include + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double remainderl(long double x, long double y) +{ + return remainder(x, y); +} +#else +long double remainderl(long double x, long double y) +{ + int q; + return remquol(x, y, &q); +} +#endif diff --git a/lib/mlibc/options/ansi/musl-generic-math/remquo.c b/lib/mlibc/options/ansi/musl-generic-math/remquo.c new file mode 100644 index 0000000..59d5ad5 --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/remquo.c @@ -0,0 +1,82 @@ +#include +#include + +double remquo(double x, double y, int *quo) +{ + 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; + int sy = uy.i>>63; + uint32_t q; + uint64_t i; + uint64_t uxi = ux.i; + + *quo = 0; + if (uy.i<<1 == 0 || isnan(y) || ex == 0x7ff) + return (x*y)/(x*y); + if (ux.i<<1 == 0) + 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; + } + + q = 0; + if (ex < ey) { + if (ex+1 == ey) + goto end; + return x; + } + + /* x mod y */ + for (; ex > ey; ex--) { + i = uxi - uy.i; + if (i >> 63 == 0) { + uxi = i; + q++; + } + uxi <<= 1; + q <<= 1; + } + i = uxi - uy.i; + if (i >> 63 == 0) { + uxi = i; + q++; + } + if (uxi == 0) + ex = -60; + else + for (; uxi>>52 == 0; uxi <<= 1, ex--); +end: + /* scale result and decide between |x| and |x|-|y| */ + if (ex > 0) { + uxi -= 1ULL << 52; + uxi |= (uint64_t)ex << 52; + } else { + uxi >>= -ex + 1; + } + ux.i = uxi; + x = ux.f; + if (sy) + y = -y; + if (ex == ey || (ex+1 == ey && (2*x > y || (2*x == y && q%2)))) { + x -= y; + q++; + } + q &= 0x7fffffff; + *quo = sx^sy ? -(int)q : (int)q; + return sx ? -x : x; +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/remquof.c b/lib/mlibc/options/ansi/musl-generic-math/remquof.c new file mode 100644 index 0000000..2f41ff7 --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/remquof.c @@ -0,0 +1,82 @@ +#include +#include + +float remquof(float x, float y, int *quo) +{ + union {float f; uint32_t i;} ux = {x}, uy = {y}; + int ex = ux.i>>23 & 0xff; + int ey = uy.i>>23 & 0xff; + int sx = ux.i>>31; + int sy = uy.i>>31; + uint32_t q; + uint32_t i; + uint32_t uxi = ux.i; + + *quo = 0; + if (uy.i<<1 == 0 || isnan(y) || ex == 0xff) + return (x*y)/(x*y); + if (ux.i<<1 == 0) + return x; + + /* normalize x and y */ + if (!ex) { + for (i = uxi<<9; i>>31 == 0; ex--, i <<= 1); + uxi <<= -ex + 1; + } else { + uxi &= -1U >> 9; + uxi |= 1U << 23; + } + if (!ey) { + for (i = uy.i<<9; i>>31 == 0; ey--, i <<= 1); + uy.i <<= -ey + 1; + } else { + uy.i &= -1U >> 9; + uy.i |= 1U << 23; + } + + q = 0; + if (ex < ey) { + if (ex+1 == ey) + goto end; + return x; + } + + /* x mod y */ + for (; ex > ey; ex--) { + i = uxi - uy.i; + if (i >> 31 == 0) { + uxi = i; + q++; + } + uxi <<= 1; + q <<= 1; + } + i = uxi - uy.i; + if (i >> 31 == 0) { + uxi = i; + q++; + } + if (uxi == 0) + ex = -30; + else + for (; uxi>>23 == 0; uxi <<= 1, ex--); +end: + /* scale result and decide between |x| and |x|-|y| */ + if (ex > 0) { + uxi -= 1U << 23; + uxi |= (uint32_t)ex << 23; + } else { + uxi >>= -ex + 1; + } + ux.i = uxi; + x = ux.f; + if (sy) + y = -y; + if (ex == ey || (ex+1 == ey && (2*x > y || (2*x == y && q%2)))) { + x -= y; + q++; + } + q &= 0x7fffffff; + *quo = sx^sy ? -(int)q : (int)q; + return sx ? -x : x; +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/remquol.c b/lib/mlibc/options/ansi/musl-generic-math/remquol.c new file mode 100644 index 0000000..9b065c0 --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/remquol.c @@ -0,0 +1,124 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double remquol(long double x, long double y, int *quo) +{ + return remquo(x, y, quo); +} +#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 +long double remquol(long double x, long double y, int *quo) +{ + union ldshape ux = {x}, uy = {y}; + int ex = ux.i.se & 0x7fff; + int ey = uy.i.se & 0x7fff; + int sx = ux.i.se >> 15; + int sy = uy.i.se >> 15; + uint32_t q; + + *quo = 0; + if (y == 0 || isnan(y) || ex == 0x7fff) + return (x*y)/(x*y); + if (x == 0) + return x; + + /* normalize x and y */ + if (!ex) { + ux.i.se = ex; + ux.f *= 0x1p120f; + ex = ux.i.se - 120; + } + if (!ey) { + uy.i.se = ey; + uy.f *= 0x1p120f; + ey = uy.i.se - 120; + } + + q = 0; + if (ex >= ey) { + /* 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) { + mx = 2*i; + q++; + q <<= 1; + } else if (2*mx < mx) { + mx = 2*mx - my; + q <<= 1; + q++; + } else { + mx = 2*mx; + q <<= 1; + } + } + i = mx - my; + if (mx >= my) { + mx = i; + q++; + } + if (mx == 0) + ex = -120; + else + 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 = ux.i2.lo; + for (; ex > ey; ex--) { + hi = xhi - yhi; + lo = xlo - ylo; + if (xlo < ylo) + hi -= 1; + if (hi >> 63 == 0) { + xhi = 2*hi + (lo>>63); + xlo = 2*lo; + q++; + } else { + xhi = 2*xhi + (xlo>>63); + xlo = 2*xlo; + } + q <<= 1; + } + hi = xhi - yhi; + lo = xlo - ylo; + if (xlo < ylo) + hi -= 1; + if (hi >> 63 == 0) { + xhi = hi; + xlo = lo; + q++; + } + if ((xhi|xlo) == 0) + ex = -120; + else + for (; xhi >> 48 == 0; xhi = 2*xhi + (xlo>>63), xlo = 2*xlo, ex--); + ux.i2.hi = xhi; + ux.i2.lo = xlo; +#endif + } + + /* scale result and decide between |x| and |x|-|y| */ + if (ex <= 0) { + ux.i.se = ex + 120; + ux.f *= 0x1p-120f; + } else + ux.i.se = ex; + x = ux.f; + if (sy) + y = -y; + if (ex == ey || (ex+1 == ey && (2*x > y || (2*x == y && q%2)))) { + x -= y; + q++; + } + q &= 0x7fffffff; + *quo = sx^sy ? -(int)q : (int)q; + return sx ? -x : x; +} +#endif diff --git a/lib/mlibc/options/ansi/musl-generic-math/rint.c b/lib/mlibc/options/ansi/musl-generic-math/rint.c new file mode 100644 index 0000000..fbba390 --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/rint.c @@ -0,0 +1,28 @@ +#include +#include +#include + +#if FLT_EVAL_METHOD==0 || FLT_EVAL_METHOD==1 +#define EPS DBL_EPSILON +#elif FLT_EVAL_METHOD==2 +#define EPS LDBL_EPSILON +#endif +static const double_t toint = 1/EPS; + +double rint(double x) +{ + union {double f; uint64_t i;} u = {x}; + int e = u.i>>52 & 0x7ff; + int s = u.i>>63; + double_t y; + + if (e >= 0x3ff+52) + return x; + if (s) + y = x - toint + toint; + else + y = x + toint - toint; + if (y == 0) + return s ? -0.0 : 0; + return y; +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/rintf.c b/lib/mlibc/options/ansi/musl-generic-math/rintf.c new file mode 100644 index 0000000..9047688 --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/rintf.c @@ -0,0 +1,30 @@ +#include +#include +#include + +#if FLT_EVAL_METHOD==0 +#define EPS FLT_EPSILON +#elif FLT_EVAL_METHOD==1 +#define EPS DBL_EPSILON +#elif FLT_EVAL_METHOD==2 +#define EPS LDBL_EPSILON +#endif +static const float_t toint = 1/EPS; + +float rintf(float x) +{ + union {float f; uint32_t i;} u = {x}; + int e = u.i>>23 & 0xff; + int s = u.i>>31; + float_t y; + + if (e >= 0x7f+23) + return x; + if (s) + y = x - toint + toint; + else + y = x + toint - toint; + if (y == 0) + return s ? -0.0f : 0.0f; + return y; +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/rintl.c b/lib/mlibc/options/ansi/musl-generic-math/rintl.c new file mode 100644 index 0000000..374327d --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/rintl.c @@ -0,0 +1,29 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double rintl(long double x) +{ + return rint(x); +} +#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 + +static const long double toint = 1/LDBL_EPSILON; + +long double rintl(long double x) +{ + union ldshape u = {x}; + int e = u.i.se & 0x7fff; + int s = u.i.se >> 15; + long double y; + + if (e >= 0x3fff+LDBL_MANT_DIG-1) + return x; + if (s) + y = x - toint + toint; + else + y = x + toint - toint; + if (y == 0) + return 0*x; + return y; +} +#endif diff --git a/lib/mlibc/options/ansi/musl-generic-math/round.c b/lib/mlibc/options/ansi/musl-generic-math/round.c new file mode 100644 index 0000000..130d58d --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/round.c @@ -0,0 +1,35 @@ +#include "libm.h" + +#if FLT_EVAL_METHOD==0 || FLT_EVAL_METHOD==1 +#define EPS DBL_EPSILON +#elif FLT_EVAL_METHOD==2 +#define EPS LDBL_EPSILON +#endif +static const double_t toint = 1/EPS; + +double round(double x) +{ + union {double f; uint64_t i;} u = {x}; + int e = u.i >> 52 & 0x7ff; + double_t y; + + if (e >= 0x3ff+52) + return x; + if (u.i >> 63) + x = -x; + if (e < 0x3ff-1) { + /* raise inexact if x!=0 */ + FORCE_EVAL(x + toint); + return 0*u.f; + } + y = x + toint - toint - x; + if (y > 0.5) + y = y + x - 1; + else if (y <= -0.5) + y = y + x + 1; + else + y = y + x; + if (u.i >> 63) + y = -y; + return y; +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/roundf.c b/lib/mlibc/options/ansi/musl-generic-math/roundf.c new file mode 100644 index 0000000..e8210af --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/roundf.c @@ -0,0 +1,36 @@ +#include "libm.h" + +#if FLT_EVAL_METHOD==0 +#define EPS FLT_EPSILON +#elif FLT_EVAL_METHOD==1 +#define EPS DBL_EPSILON +#elif FLT_EVAL_METHOD==2 +#define EPS LDBL_EPSILON +#endif +static const float_t toint = 1/EPS; + +float roundf(float x) +{ + union {float f; uint32_t i;} u = {x}; + int e = u.i >> 23 & 0xff; + float_t y; + + if (e >= 0x7f+23) + return x; + if (u.i >> 31) + x = -x; + if (e < 0x7f-1) { + FORCE_EVAL(x + toint); + return 0*u.f; + } + y = x + toint - toint - x; + if (y > 0.5f) + y = y + x - 1; + else if (y <= -0.5f) + y = y + x + 1; + else + y = y + x; + if (u.i >> 31) + y = -y; + return y; +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/roundl.c b/lib/mlibc/options/ansi/musl-generic-math/roundl.c new file mode 100644 index 0000000..f4ff682 --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/roundl.c @@ -0,0 +1,37 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double roundl(long double x) +{ + return round(x); +} +#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 + +static const long double toint = 1/LDBL_EPSILON; + +long double roundl(long double x) +{ + union ldshape u = {x}; + int e = u.i.se & 0x7fff; + long double y; + + if (e >= 0x3fff+LDBL_MANT_DIG-1) + return x; + if (u.i.se >> 15) + x = -x; + if (e < 0x3fff-1) { + FORCE_EVAL(x + toint); + return 0*u.f; + } + y = x + toint - toint - x; + if (y > 0.5) + y = y + x - 1; + else if (y <= -0.5) + y = y + x + 1; + else + y = y + x; + if (u.i.se >> 15) + y = -y; + return y; +} +#endif diff --git a/lib/mlibc/options/ansi/musl-generic-math/scalb.c b/lib/mlibc/options/ansi/musl-generic-math/scalb.c new file mode 100644 index 0000000..efe69e6 --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/scalb.c @@ -0,0 +1,35 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_scalb.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* + * scalb(x, fn) is provide for + * passing various standard test suite. One + * should use scalbn() instead. + */ + +#define _GNU_SOURCE +#include + +double scalb(double x, double fn) +{ + if (isnan(x) || isnan(fn)) + return x*fn; + if (!isfinite(fn)) { + if (fn > 0.0) + return x*fn; + else + return x/(-fn); + } + if (rint(fn) != fn) return (fn-fn)/(fn-fn); + if ( fn > 65000.0) return scalbn(x, 65000); + if (-fn > 65000.0) return scalbn(x,-65000); + return scalbn(x,(int)fn); +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/scalbf.c b/lib/mlibc/options/ansi/musl-generic-math/scalbf.c new file mode 100644 index 0000000..f44ed5b --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/scalbf.c @@ -0,0 +1,32 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_scalbf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#define _GNU_SOURCE +#include + +float scalbf(float x, float fn) +{ + if (isnan(x) || isnan(fn)) return x*fn; + if (!isfinite(fn)) { + if (fn > 0.0f) + return x*fn; + else + return x/(-fn); + } + if (rintf(fn) != fn) return (fn-fn)/(fn-fn); + if ( fn > 65000.0f) return scalbnf(x, 65000); + if (-fn > 65000.0f) return scalbnf(x,-65000); + return scalbnf(x,(int)fn); +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/scalbln.c b/lib/mlibc/options/ansi/musl-generic-math/scalbln.c new file mode 100644 index 0000000..4fb3d06 --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/scalbln.c @@ -0,0 +1,12 @@ +#include +#include +#include "libm.h" + +double scalbln(double x, long n) +{ + if (n > INT_MAX) + n = INT_MAX; + else if (n < INT_MIN) + n = INT_MIN; + return scalbn(x, n); +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/scalblnf.c b/lib/mlibc/options/ansi/musl-generic-math/scalblnf.c new file mode 100644 index 0000000..b6bdeed --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/scalblnf.c @@ -0,0 +1,12 @@ +#include +#include +#include "libm.h" + +float scalblnf(float x, long n) +{ + if (n > INT_MAX) + n = INT_MAX; + else if (n < INT_MIN) + n = INT_MIN; + return scalbnf(x, n); +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/scalblnl.c b/lib/mlibc/options/ansi/musl-generic-math/scalblnl.c new file mode 100644 index 0000000..b1a0f7f --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/scalblnl.c @@ -0,0 +1,20 @@ +#include +#include +#include +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double scalblnl(long double x, long n) +{ + return scalbln(x, n); +} +#else +long double scalblnl(long double x, long n) +{ + if (n > INT_MAX) + n = INT_MAX; + else if (n < INT_MIN) + n = INT_MIN; + return scalbnl(x, n); +} +#endif diff --git a/lib/mlibc/options/ansi/musl-generic-math/scalbn.c b/lib/mlibc/options/ansi/musl-generic-math/scalbn.c new file mode 100644 index 0000000..182f561 --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/scalbn.c @@ -0,0 +1,33 @@ +#include +#include + +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; +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/scalbnf.c b/lib/mlibc/options/ansi/musl-generic-math/scalbnf.c new file mode 100644 index 0000000..a5ad208 --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/scalbnf.c @@ -0,0 +1,31 @@ +#include +#include + +float scalbnf(float x, int n) +{ + union {float f; uint32_t i;} u; + float_t y = x; + + if (n > 127) { + y *= 0x1p127f; + n -= 127; + if (n > 127) { + y *= 0x1p127f; + n -= 127; + if (n > 127) + n = 127; + } + } else if (n < -126) { + y *= 0x1p-126f * 0x1p24f; + n += 126 - 24; + if (n < -126) { + y *= 0x1p-126f * 0x1p24f; + n += 126 - 24; + if (n < -126) + n = -126; + } + } + u.i = (uint32_t)(0x7f+n)<<23; + x = y * u.f; + return x; +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/scalbnl.c b/lib/mlibc/options/ansi/musl-generic-math/scalbnl.c new file mode 100644 index 0000000..db44dab --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/scalbnl.c @@ -0,0 +1,36 @@ +#include "libm.h" + +#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 diff --git a/lib/mlibc/options/ansi/musl-generic-math/signgam.c b/lib/mlibc/options/ansi/musl-generic-math/signgam.c new file mode 100644 index 0000000..3a5b9f7 --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/signgam.c @@ -0,0 +1,5 @@ +#include +#include "weak_alias.h" +//#include "libc.h" + +int signgam = 0; diff --git a/lib/mlibc/options/ansi/musl-generic-math/significand.c b/lib/mlibc/options/ansi/musl-generic-math/significand.c new file mode 100644 index 0000000..40d9aa9 --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/significand.c @@ -0,0 +1,7 @@ +#define _GNU_SOURCE +#include + +double significand(double x) +{ + return scalbn(x, -ilogb(x)); +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/significandf.c b/lib/mlibc/options/ansi/musl-generic-math/significandf.c new file mode 100644 index 0000000..8a697e1 --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/significandf.c @@ -0,0 +1,7 @@ +#define _GNU_SOURCE +#include + +float significandf(float x) +{ + return scalbnf(x, -ilogbf(x)); +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/sin.c b/lib/mlibc/options/ansi/musl-generic-math/sin.c new file mode 100644 index 0000000..055e215 --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/sin.c @@ -0,0 +1,78 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_sin.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* sin(x) + * Return sine function of x. + * + * kernel function: + * __sin ... sine function on [-pi/4,pi/4] + * __cos ... cose function on [-pi/4,pi/4] + * __rem_pio2 ... argument reduction routine + * + * Method. + * Let S,C and T denote the sin, cos and tan respectively on + * [-PI/4, +PI/4]. Reduce the argument x to y1+y2 = x-k*pi/2 + * in [-pi/4 , +pi/4], and let n = k mod 4. + * We have + * + * n sin(x) cos(x) tan(x) + * ---------------------------------------------------------- + * 0 S C T + * 1 C -S -1/T + * 2 -S -C T + * 3 -C S -1/T + * ---------------------------------------------------------- + * + * Special cases: + * Let trig be any of sin, cos, or tan. + * trig(+-INF) is NaN, with signals; + * trig(NaN) is that NaN; + * + * Accuracy: + * TRIG(x) returns trig(x) nearly rounded + */ + +#include "libm.h" + +double sin(double x) +{ + double y[2]; + uint32_t ix; + unsigned n; + + /* High word of x. */ + GET_HIGH_WORD(ix, x); + ix &= 0x7fffffff; + + /* |x| ~< pi/4 */ + if (ix <= 0x3fe921fb) { + if (ix < 0x3e500000) { /* |x| < 2**-26 */ + /* raise inexact if x != 0 and underflow if subnormal*/ + FORCE_EVAL(ix < 0x00100000 ? x/0x1p120f : x+0x1p120f); + return x; + } + return __sin(x, 0.0, 0); + } + + /* sin(Inf or NaN) is NaN */ + if (ix >= 0x7ff00000) + return x - x; + + /* argument reduction needed */ + n = __rem_pio2(x, y); + switch (n&3) { + case 0: return __sin(y[0], y[1], 1); + case 1: return __cos(y[0], y[1]); + case 2: return -__sin(y[0], y[1], 1); + default: + return -__cos(y[0], y[1]); + } +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/sincos.c b/lib/mlibc/options/ansi/musl-generic-math/sincos.c new file mode 100644 index 0000000..35b2d92 --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/sincos.c @@ -0,0 +1,69 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_sin.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#define _GNU_SOURCE +#include "libm.h" + +void sincos(double x, double *sin, double *cos) +{ + double y[2], s, c; + uint32_t ix; + unsigned n; + + GET_HIGH_WORD(ix, x); + ix &= 0x7fffffff; + + /* |x| ~< pi/4 */ + if (ix <= 0x3fe921fb) { + /* if |x| < 2**-27 * sqrt(2) */ + if (ix < 0x3e46a09e) { + /* raise inexact if x!=0 and underflow if subnormal */ + FORCE_EVAL(ix < 0x00100000 ? x/0x1p120f : x+0x1p120f); + *sin = x; + *cos = 1.0; + return; + } + *sin = __sin(x, 0.0, 0); + *cos = __cos(x, 0.0); + return; + } + + /* sincos(Inf or NaN) is NaN */ + if (ix >= 0x7ff00000) { + *sin = *cos = x - x; + return; + } + + /* argument reduction needed */ + n = __rem_pio2(x, y); + s = __sin(y[0], y[1], 1); + c = __cos(y[0], y[1]); + switch (n&3) { + case 0: + *sin = s; + *cos = c; + break; + case 1: + *sin = c; + *cos = -s; + break; + case 2: + *sin = -s; + *cos = -c; + break; + case 3: + default: + *sin = -c; + *cos = s; + break; + } +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/sincosf.c b/lib/mlibc/options/ansi/musl-generic-math/sincosf.c new file mode 100644 index 0000000..f8ca723 --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/sincosf.c @@ -0,0 +1,117 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_sinf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + * Optimized by Bruce D. Evans. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#define _GNU_SOURCE +#include "libm.h" + +/* Small multiples of pi/2 rounded to double precision. */ +static const double +s1pio2 = 1*M_PI_2, /* 0x3FF921FB, 0x54442D18 */ +s2pio2 = 2*M_PI_2, /* 0x400921FB, 0x54442D18 */ +s3pio2 = 3*M_PI_2, /* 0x4012D97C, 0x7F3321D2 */ +s4pio2 = 4*M_PI_2; /* 0x401921FB, 0x54442D18 */ + +void sincosf(float x, float *sin, float *cos) +{ + double y; + float_t s, c; + uint32_t ix; + unsigned n, sign; + + GET_FLOAT_WORD(ix, x); + sign = ix >> 31; + ix &= 0x7fffffff; + + /* |x| ~<= pi/4 */ + if (ix <= 0x3f490fda) { + /* |x| < 2**-12 */ + if (ix < 0x39800000) { + /* raise inexact if x!=0 and underflow if subnormal */ + FORCE_EVAL(ix < 0x00100000 ? x/0x1p120f : x+0x1p120f); + *sin = x; + *cos = 1.0f; + return; + } + *sin = __sindf(x); + *cos = __cosdf(x); + return; + } + + /* |x| ~<= 5*pi/4 */ + if (ix <= 0x407b53d1) { + if (ix <= 0x4016cbe3) { /* |x| ~<= 3pi/4 */ + if (sign) { + *sin = -__cosdf(x + s1pio2); + *cos = __sindf(x + s1pio2); + } else { + *sin = __cosdf(s1pio2 - x); + *cos = __sindf(s1pio2 - x); + } + return; + } + /* -sin(x+c) is not correct if x+c could be 0: -0 vs +0 */ + *sin = -__sindf(sign ? x + s2pio2 : x - s2pio2); + *cos = -__cosdf(sign ? x + s2pio2 : x - s2pio2); + return; + } + + /* |x| ~<= 9*pi/4 */ + if (ix <= 0x40e231d5) { + if (ix <= 0x40afeddf) { /* |x| ~<= 7*pi/4 */ + if (sign) { + *sin = __cosdf(x + s3pio2); + *cos = -__sindf(x + s3pio2); + } else { + *sin = -__cosdf(x - s3pio2); + *cos = __sindf(x - s3pio2); + } + return; + } + *sin = __sindf(sign ? x + s4pio2 : x - s4pio2); + *cos = __cosdf(sign ? x + s4pio2 : x - s4pio2); + return; + } + + /* sin(Inf or NaN) is NaN */ + if (ix >= 0x7f800000) { + *sin = *cos = x - x; + return; + } + + /* general argument reduction needed */ + n = __rem_pio2f(x, &y); + s = __sindf(y); + c = __cosdf(y); + switch (n&3) { + case 0: + *sin = s; + *cos = c; + break; + case 1: + *sin = c; + *cos = -s; + break; + case 2: + *sin = -s; + *cos = -c; + break; + case 3: + default: + *sin = -c; + *cos = s; + break; + } +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/sincosl.c b/lib/mlibc/options/ansi/musl-generic-math/sincosl.c new file mode 100644 index 0000000..d3ac1c4 --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/sincosl.c @@ -0,0 +1,60 @@ +#define _GNU_SOURCE +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +void sincosl(long double x, long double *sin, long double *cos) +{ + double sind, cosd; + sincos(x, &sind, &cosd); + *sin = sind; + *cos = cosd; +} +#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 +void sincosl(long double x, long double *sin, long double *cos) +{ + union ldshape u = {x}; + unsigned n; + long double y[2], s, c; + + u.i.se &= 0x7fff; + if (u.i.se == 0x7fff) { + *sin = *cos = x - x; + return; + } + if (u.f < M_PI_4) { + if (u.i.se < 0x3fff - LDBL_MANT_DIG) { + /* raise underflow if subnormal */ + if (u.i.se == 0) FORCE_EVAL(x*0x1p-120f); + *sin = x; + /* raise inexact if x!=0 */ + *cos = 1.0 + x; + return; + } + *sin = __sinl(x, 0, 0); + *cos = __cosl(x, 0); + return; + } + n = __rem_pio2l(x, y); + s = __sinl(y[0], y[1], 1); + c = __cosl(y[0], y[1]); + switch (n & 3) { + case 0: + *sin = s; + *cos = c; + break; + case 1: + *sin = c; + *cos = -s; + break; + case 2: + *sin = -s; + *cos = -c; + break; + case 3: + default: + *sin = -c; + *cos = s; + break; + } +} +#endif diff --git a/lib/mlibc/options/ansi/musl-generic-math/sinf.c b/lib/mlibc/options/ansi/musl-generic-math/sinf.c new file mode 100644 index 0000000..64e39f5 --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/sinf.c @@ -0,0 +1,76 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_sinf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + * Optimized by Bruce D. Evans. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "libm.h" + +/* Small multiples of pi/2 rounded to double precision. */ +static const double +s1pio2 = 1*M_PI_2, /* 0x3FF921FB, 0x54442D18 */ +s2pio2 = 2*M_PI_2, /* 0x400921FB, 0x54442D18 */ +s3pio2 = 3*M_PI_2, /* 0x4012D97C, 0x7F3321D2 */ +s4pio2 = 4*M_PI_2; /* 0x401921FB, 0x54442D18 */ + +float sinf(float x) +{ + double y; + uint32_t ix; + int n, sign; + + GET_FLOAT_WORD(ix, x); + sign = ix >> 31; + ix &= 0x7fffffff; + + if (ix <= 0x3f490fda) { /* |x| ~<= pi/4 */ + if (ix < 0x39800000) { /* |x| < 2**-12 */ + /* raise inexact if x!=0 and underflow if subnormal */ + FORCE_EVAL(ix < 0x00800000 ? x/0x1p120f : x+0x1p120f); + return x; + } + return __sindf(x); + } + if (ix <= 0x407b53d1) { /* |x| ~<= 5*pi/4 */ + if (ix <= 0x4016cbe3) { /* |x| ~<= 3pi/4 */ + if (sign) + return -__cosdf(x + s1pio2); + else + return __cosdf(x - s1pio2); + } + return __sindf(sign ? -(x + s2pio2) : -(x - s2pio2)); + } + if (ix <= 0x40e231d5) { /* |x| ~<= 9*pi/4 */ + if (ix <= 0x40afeddf) { /* |x| ~<= 7*pi/4 */ + if (sign) + return __cosdf(x + s3pio2); + else + return -__cosdf(x - s3pio2); + } + return __sindf(sign ? x + s4pio2 : x - s4pio2); + } + + /* sin(Inf or NaN) is NaN */ + if (ix >= 0x7f800000) + return x - x; + + /* general argument reduction needed */ + n = __rem_pio2f(x, &y); + switch (n&3) { + case 0: return __sindf(y); + case 1: return __cosdf(y); + case 2: return __sindf(-y); + default: + return -__cosdf(y); + } +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/sinh.c b/lib/mlibc/options/ansi/musl-generic-math/sinh.c new file mode 100644 index 0000000..00022c4 --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/sinh.c @@ -0,0 +1,39 @@ +#include "libm.h" + +/* sinh(x) = (exp(x) - 1/exp(x))/2 + * = (exp(x)-1 + (exp(x)-1)/exp(x))/2 + * = x + x^3/6 + o(x^5) + */ +double sinh(double x) +{ + union {double f; uint64_t i;} u = {.f = x}; + uint32_t w; + double t, h, absx; + + h = 0.5; + if (u.i >> 63) + h = -h; + /* |x| */ + u.i &= (uint64_t)-1/2; + absx = u.f; + w = u.i >> 32; + + /* |x| < log(DBL_MAX) */ + if (w < 0x40862e42) { + t = expm1(absx); + if (w < 0x3ff00000) { + if (w < 0x3ff00000 - (26<<20)) + /* note: inexact and underflow are raised by expm1 */ + /* note: this branch avoids spurious underflow */ + return x; + return h*(2*t - t*t/(t+1)); + } + /* note: |x|>log(0x1p26)+eps could be just h*exp(x) */ + return h*(t + t/(t+1)); + } + + /* |x| > log(DBL_MAX) or nan */ + /* note: the result is stored to handle overflow */ + t = 2*h*__expo2(absx); + return t; +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/sinhf.c b/lib/mlibc/options/ansi/musl-generic-math/sinhf.c new file mode 100644 index 0000000..6ad19ea --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/sinhf.c @@ -0,0 +1,31 @@ +#include "libm.h" + +float sinhf(float x) +{ + union {float f; uint32_t i;} u = {.f = x}; + uint32_t w; + float t, h, absx; + + h = 0.5; + if (u.i >> 31) + h = -h; + /* |x| */ + u.i &= 0x7fffffff; + absx = u.f; + w = u.i; + + /* |x| < log(FLT_MAX) */ + if (w < 0x42b17217) { + t = expm1f(absx); + if (w < 0x3f800000) { + if (w < 0x3f800000 - (12<<23)) + return x; + return h*(2*t - t*t/(t+1)); + } + return h*(t + t/(t+1)); + } + + /* |x| > logf(FLT_MAX) or nan */ + t = 2*h*__expo2f(absx); + return t; +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/sinhl.c b/lib/mlibc/options/ansi/musl-generic-math/sinhl.c new file mode 100644 index 0000000..b305d4d --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/sinhl.c @@ -0,0 +1,43 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double sinhl(long double x) +{ + return sinh(x); +} +#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 +long double sinhl(long double x) +{ + union ldshape u = {x}; + unsigned ex = u.i.se & 0x7fff; + long double h, t, absx; + + h = 0.5; + if (u.i.se & 0x8000) + h = -h; + /* |x| */ + u.i.se = ex; + absx = u.f; + + /* |x| < log(LDBL_MAX) */ + if (ex < 0x3fff+13 || (ex == 0x3fff+13 && u.i.m>>32 < 0xb17217f7)) { + t = expm1l(absx); + if (ex < 0x3fff) { + if (ex < 0x3fff-32) + return x; + return h*(2*t - t*t/(1+t)); + } + return h*(t + t/(t+1)); + } + + /* |x| > log(LDBL_MAX) or nan */ + t = expl(0.5*absx); + return h*t*t; +} +#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 +// TODO: broken implementation to make things compile +long double sinhl(long double x) +{ + return sinh(x); +} +#endif diff --git a/lib/mlibc/options/ansi/musl-generic-math/sinl.c b/lib/mlibc/options/ansi/musl-generic-math/sinl.c new file mode 100644 index 0000000..9c0b16e --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/sinl.c @@ -0,0 +1,41 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double sinl(long double x) +{ + return sin(x); +} +#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 +long double sinl(long double x) +{ + union ldshape u = {x}; + unsigned n; + long double y[2], hi, lo; + + u.i.se &= 0x7fff; + if (u.i.se == 0x7fff) + return x - x; + if (u.f < M_PI_4) { + if (u.i.se < 0x3fff - LDBL_MANT_DIG/2) { + /* raise inexact if x!=0 and underflow if subnormal */ + FORCE_EVAL(u.i.se == 0 ? x*0x1p-120f : x+0x1p120f); + return x; + } + return __sinl(x, 0.0, 0); + } + n = __rem_pio2l(x, y); + hi = y[0]; + lo = y[1]; + switch (n & 3) { + case 0: + return __sinl(hi, lo, 1); + case 1: + return __cosl(hi, lo); + case 2: + return -__sinl(hi, lo, 1); + case 3: + default: + return -__cosl(hi, lo); + } +} +#endif diff --git a/lib/mlibc/options/ansi/musl-generic-math/sqrt.c b/lib/mlibc/options/ansi/musl-generic-math/sqrt.c new file mode 100644 index 0000000..b277567 --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/sqrt.c @@ -0,0 +1,185 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_sqrt.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* sqrt(x) + * Return correctly rounded sqrt. + * ------------------------------------------ + * | Use the hardware sqrt if you have one | + * ------------------------------------------ + * Method: + * Bit by bit method using integer arithmetic. (Slow, but portable) + * 1. Normalization + * Scale x to y in [1,4) with even powers of 2: + * find an integer k such that 1 <= (y=x*2^(2k)) < 4, then + * sqrt(x) = 2^k * sqrt(y) + * 2. Bit by bit computation + * Let q = sqrt(y) truncated to i bit after binary point (q = 1), + * i 0 + * i+1 2 + * s = 2*q , and y = 2 * ( y - q ). (1) + * i i i i + * + * To compute q from q , one checks whether + * i+1 i + * + * -(i+1) 2 + * (q + 2 ) <= y. (2) + * i + * -(i+1) + * If (2) is false, then q = q ; otherwise q = q + 2 . + * i+1 i i+1 i + * + * With some algebric manipulation, it is not difficult to see + * that (2) is equivalent to + * -(i+1) + * s + 2 <= y (3) + * i i + * + * The advantage of (3) is that s and y can be computed by + * i i + * the following recurrence formula: + * if (3) is false + * + * s = s , y = y ; (4) + * i+1 i i+1 i + * + * otherwise, + * -i -(i+1) + * s = s + 2 , y = y - s - 2 (5) + * i+1 i i+1 i i + * + * One may easily use induction to prove (4) and (5). + * Note. Since the left hand side of (3) contain only i+2 bits, + * it does not necessary to do a full (53-bit) comparison + * in (3). + * 3. Final rounding + * After generating the 53 bits result, we compute one more bit. + * Together with the remainder, we can decide whether the + * result is exact, bigger than 1/2ulp, or less than 1/2ulp + * (it will never equal to 1/2ulp). + * The rounding mode can be detected by checking whether + * huge + tiny is equal to huge, and whether huge - tiny is + * equal to huge for some floating point number "huge" and "tiny". + * + * Special cases: + * sqrt(+-0) = +-0 ... exact + * sqrt(inf) = inf + * sqrt(-ve) = NaN ... with invalid signal + * sqrt(NaN) = NaN ... with invalid signal for signaling NaN + */ + +#include "libm.h" + +static const double tiny = 1.0e-300; + +double sqrt(double x) +{ + double z; + int32_t sign = (int)0x80000000; + int32_t ix0,s0,q,m,t,i; + uint32_t r,t1,s1,ix1,q1; + + EXTRACT_WORDS(ix0, ix1, x); + + /* take care of Inf and NaN */ + if ((ix0&0x7ff00000) == 0x7ff00000) { + return x*x + x; /* sqrt(NaN)=NaN, sqrt(+inf)=+inf, sqrt(-inf)=sNaN */ + } + /* take care of zero */ + if (ix0 <= 0) { + if (((ix0&~sign)|ix1) == 0) + return x; /* sqrt(+-0) = +-0 */ + if (ix0 < 0) + return (x-x)/(x-x); /* sqrt(-ve) = sNaN */ + } + /* normalize x */ + m = ix0>>20; + if (m == 0) { /* subnormal x */ + while (ix0 == 0) { + m -= 21; + ix0 |= (ix1>>11); + ix1 <<= 21; + } + for (i=0; (ix0&0x00100000) == 0; i++) + ix0<<=1; + m -= i - 1; + ix0 |= ix1>>(32-i); + ix1 <<= i; + } + m -= 1023; /* unbias exponent */ + ix0 = (ix0&0x000fffff)|0x00100000; + if (m & 1) { /* odd m, double x to make it even */ + ix0 += ix0 + ((ix1&sign)>>31); + ix1 += ix1; + } + m >>= 1; /* m = [m/2] */ + + /* generate sqrt(x) bit by bit */ + ix0 += ix0 + ((ix1&sign)>>31); + ix1 += ix1; + q = q1 = s0 = s1 = 0; /* [q,q1] = sqrt(x) */ + r = 0x00200000; /* r = moving bit from right to left */ + + while (r != 0) { + t = s0 + r; + if (t <= ix0) { + s0 = t + r; + ix0 -= t; + q += r; + } + ix0 += ix0 + ((ix1&sign)>>31); + ix1 += ix1; + r >>= 1; + } + + r = sign; + while (r != 0) { + t1 = s1 + r; + t = s0; + if (t < ix0 || (t == ix0 && t1 <= ix1)) { + s1 = t1 + r; + if ((t1&sign) == sign && (s1&sign) == 0) + s0++; + ix0 -= t; + if (ix1 < t1) + ix0--; + ix1 -= t1; + q1 += r; + } + ix0 += ix0 + ((ix1&sign)>>31); + ix1 += ix1; + r >>= 1; + } + + /* use floating add to find out rounding direction */ + if ((ix0|ix1) != 0) { + z = 1.0 - tiny; /* raise inexact flag */ + if (z >= 1.0) { + z = 1.0 + tiny; + if (q1 == (uint32_t)0xffffffff) { + q1 = 0; + q++; + } else if (z > 1.0) { + if (q1 == (uint32_t)0xfffffffe) + q++; + q1 += 2; + } else + q1 += q1 & 1; + } + } + ix0 = (q>>1) + 0x3fe00000; + ix1 = q1>>1; + if (q&1) + ix1 |= sign; + ix0 += m << 20; + INSERT_WORDS(z, ix0, ix1); + return z; +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/sqrtf.c b/lib/mlibc/options/ansi/musl-generic-math/sqrtf.c new file mode 100644 index 0000000..28cb4ad --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/sqrtf.c @@ -0,0 +1,84 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_sqrtf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "libm.h" + +static const float tiny = 1.0e-30; + +float sqrtf(float x) +{ + float z; + int32_t sign = (int)0x80000000; + int32_t ix,s,q,m,t,i; + uint32_t r; + + GET_FLOAT_WORD(ix, x); + + /* take care of Inf and NaN */ + if ((ix&0x7f800000) == 0x7f800000) + return x*x + x; /* sqrt(NaN)=NaN, sqrt(+inf)=+inf, sqrt(-inf)=sNaN */ + + /* take care of zero */ + if (ix <= 0) { + if ((ix&~sign) == 0) + return x; /* sqrt(+-0) = +-0 */ + if (ix < 0) + return (x-x)/(x-x); /* sqrt(-ve) = sNaN */ + } + /* normalize x */ + m = ix>>23; + if (m == 0) { /* subnormal x */ + for (i = 0; (ix&0x00800000) == 0; i++) + ix<<=1; + m -= i - 1; + } + m -= 127; /* unbias exponent */ + ix = (ix&0x007fffff)|0x00800000; + if (m&1) /* odd m, double x to make it even */ + ix += ix; + m >>= 1; /* m = [m/2] */ + + /* generate sqrt(x) bit by bit */ + ix += ix; + q = s = 0; /* q = sqrt(x) */ + r = 0x01000000; /* r = moving bit from right to left */ + + while (r != 0) { + t = s + r; + if (t <= ix) { + s = t+r; + ix -= t; + q += r; + } + ix += ix; + r >>= 1; + } + + /* use floating add to find out rounding direction */ + if (ix != 0) { + z = 1.0f - tiny; /* raise inexact flag */ + if (z >= 1.0f) { + z = 1.0f + tiny; + if (z > 1.0f) + q += 2; + else + q += q & 1; + } + } + ix = (q>>1) + 0x3f000000; + ix += m << 23; + SET_FLOAT_WORD(z, ix); + return z; +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/sqrtl.c b/lib/mlibc/options/ansi/musl-generic-math/sqrtl.c new file mode 100644 index 0000000..83a8f80 --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/sqrtl.c @@ -0,0 +1,7 @@ +#include + +long double sqrtl(long double x) +{ + /* FIXME: implement in C, this is for LDBL_MANT_DIG == 64 only */ + return sqrt(x); +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/tan.c b/lib/mlibc/options/ansi/musl-generic-math/tan.c new file mode 100644 index 0000000..9c724a4 --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/tan.c @@ -0,0 +1,70 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_tan.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* tan(x) + * Return tangent function of x. + * + * kernel function: + * __tan ... tangent function on [-pi/4,pi/4] + * __rem_pio2 ... argument reduction routine + * + * Method. + * Let S,C and T denote the sin, cos and tan respectively on + * [-PI/4, +PI/4]. Reduce the argument x to y1+y2 = x-k*pi/2 + * in [-pi/4 , +pi/4], and let n = k mod 4. + * We have + * + * n sin(x) cos(x) tan(x) + * ---------------------------------------------------------- + * 0 S C T + * 1 C -S -1/T + * 2 -S -C T + * 3 -C S -1/T + * ---------------------------------------------------------- + * + * Special cases: + * Let trig be any of sin, cos, or tan. + * trig(+-INF) is NaN, with signals; + * trig(NaN) is that NaN; + * + * Accuracy: + * TRIG(x) returns trig(x) nearly rounded + */ + +#include "libm.h" + +double tan(double x) +{ + double y[2]; + uint32_t ix; + unsigned n; + + GET_HIGH_WORD(ix, x); + ix &= 0x7fffffff; + + /* |x| ~< pi/4 */ + if (ix <= 0x3fe921fb) { + if (ix < 0x3e400000) { /* |x| < 2**-27 */ + /* raise inexact if x!=0 and underflow if subnormal */ + FORCE_EVAL(ix < 0x00100000 ? x/0x1p120f : x+0x1p120f); + return x; + } + return __tan(x, 0.0, 0); + } + + /* tan(Inf or NaN) is NaN */ + if (ix >= 0x7ff00000) + return x - x; + + /* argument reduction */ + n = __rem_pio2(x, y); + return __tan(y[0], y[1], n&1); +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/tanf.c b/lib/mlibc/options/ansi/musl-generic-math/tanf.c new file mode 100644 index 0000000..aba1977 --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/tanf.c @@ -0,0 +1,64 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_tanf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + * Optimized by Bruce D. Evans. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "libm.h" + +/* Small multiples of pi/2 rounded to double precision. */ +static const double +t1pio2 = 1*M_PI_2, /* 0x3FF921FB, 0x54442D18 */ +t2pio2 = 2*M_PI_2, /* 0x400921FB, 0x54442D18 */ +t3pio2 = 3*M_PI_2, /* 0x4012D97C, 0x7F3321D2 */ +t4pio2 = 4*M_PI_2; /* 0x401921FB, 0x54442D18 */ + +float tanf(float x) +{ + double y; + uint32_t ix; + unsigned n, sign; + + GET_FLOAT_WORD(ix, x); + sign = ix >> 31; + ix &= 0x7fffffff; + + if (ix <= 0x3f490fda) { /* |x| ~<= pi/4 */ + if (ix < 0x39800000) { /* |x| < 2**-12 */ + /* raise inexact if x!=0 and underflow if subnormal */ + FORCE_EVAL(ix < 0x00800000 ? x/0x1p120f : x+0x1p120f); + return x; + } + return __tandf(x, 0); + } + if (ix <= 0x407b53d1) { /* |x| ~<= 5*pi/4 */ + if (ix <= 0x4016cbe3) /* |x| ~<= 3pi/4 */ + return __tandf((sign ? x+t1pio2 : x-t1pio2), 1); + else + return __tandf((sign ? x+t2pio2 : x-t2pio2), 0); + } + if (ix <= 0x40e231d5) { /* |x| ~<= 9*pi/4 */ + if (ix <= 0x40afeddf) /* |x| ~<= 7*pi/4 */ + return __tandf((sign ? x+t3pio2 : x-t3pio2), 1); + else + return __tandf((sign ? x+t4pio2 : x-t4pio2), 0); + } + + /* tan(Inf or NaN) is NaN */ + if (ix >= 0x7f800000) + return x - x; + + /* argument reduction */ + n = __rem_pio2f(x, &y); + return __tandf(y, n&1); +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/tanh.c b/lib/mlibc/options/ansi/musl-generic-math/tanh.c new file mode 100644 index 0000000..20d6dbc --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/tanh.c @@ -0,0 +1,45 @@ +#include "libm.h" + +/* tanh(x) = (exp(x) - exp(-x))/(exp(x) + exp(-x)) + * = (exp(2*x) - 1)/(exp(2*x) - 1 + 2) + * = (1 - exp(-2*x))/(exp(-2*x) - 1 + 2) + */ +double tanh(double x) +{ + union {double f; uint64_t i;} u = {.f = x}; + uint32_t w; + int sign; + double_t t; + + /* x = |x| */ + sign = u.i >> 63; + u.i &= (uint64_t)-1/2; + x = u.f; + w = u.i >> 32; + + if (w > 0x3fe193ea) { + /* |x| > log(3)/2 ~= 0.5493 or nan */ + if (w > 0x40340000) { + /* |x| > 20 or nan */ + /* note: this branch avoids raising overflow */ + t = 1 - 0/x; + } else { + t = expm1(2*x); + t = 1 - 2/(t+2); + } + } else if (w > 0x3fd058ae) { + /* |x| > log(5/3)/2 ~= 0.2554 */ + t = expm1(2*x); + t = t/(t+2); + } else if (w >= 0x00100000) { + /* |x| >= 0x1p-1022, up to 2ulp error in [0.1,0.2554] */ + t = expm1(-2*x); + t = -t/(t+2); + } else { + /* |x| is subnormal */ + /* note: the branch above would not raise underflow in [0x1p-1023,0x1p-1022) */ + FORCE_EVAL((float)x); + t = x; + } + return sign ? -t : t; +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/tanhf.c b/lib/mlibc/options/ansi/musl-generic-math/tanhf.c new file mode 100644 index 0000000..10636fb --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/tanhf.c @@ -0,0 +1,39 @@ +#include "libm.h" + +float tanhf(float x) +{ + union {float f; uint32_t i;} u = {.f = x}; + uint32_t w; + int sign; + float t; + + /* x = |x| */ + sign = u.i >> 31; + u.i &= 0x7fffffff; + x = u.f; + w = u.i; + + if (w > 0x3f0c9f54) { + /* |x| > log(3)/2 ~= 0.5493 or nan */ + if (w > 0x41200000) { + /* |x| > 10 */ + t = 1 + 0/x; + } else { + t = expm1f(2*x); + t = 1 - 2/(t+2); + } + } else if (w > 0x3e82c578) { + /* |x| > log(5/3)/2 ~= 0.2554 */ + t = expm1f(2*x); + t = t/(t+2); + } else if (w >= 0x00800000) { + /* |x| >= 0x1p-126 */ + t = expm1f(-2*x); + t = -t/(t+2); + } else { + /* |x| is subnormal */ + FORCE_EVAL(x*x); + t = x; + } + return sign ? -t : t; +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/tanhl.c b/lib/mlibc/options/ansi/musl-generic-math/tanhl.c new file mode 100644 index 0000000..4e1aa9f --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/tanhl.c @@ -0,0 +1,48 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double tanhl(long double x) +{ + return tanh(x); +} +#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 +long double tanhl(long double x) +{ + union ldshape u = {x}; + unsigned ex = u.i.se & 0x7fff; + unsigned sign = u.i.se & 0x8000; + uint32_t w; + long double t; + + /* x = |x| */ + u.i.se = ex; + x = u.f; + w = u.i.m >> 32; + + if (ex > 0x3ffe || (ex == 0x3ffe && w > 0x8c9f53d5)) { + /* |x| > log(3)/2 ~= 0.5493 or nan */ + if (ex >= 0x3fff+5) { + /* |x| >= 32 */ + t = 1 + 0/(x + 0x1p-120f); + } else { + t = expm1l(2*x); + t = 1 - 2/(t+2); + } + } else if (ex > 0x3ffd || (ex == 0x3ffd && w > 0x82c577d4)) { + /* |x| > log(5/3)/2 ~= 0.2554 */ + t = expm1l(2*x); + t = t/(t+2); + } else { + /* |x| is small */ + t = expm1l(-2*x); + t = -t/(t+2); + } + return sign ? -t : t; +} +#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 +// TODO: broken implementation to make things compile +long double tanhl(long double x) +{ + return tanh(x); +} +#endif diff --git a/lib/mlibc/options/ansi/musl-generic-math/tanl.c b/lib/mlibc/options/ansi/musl-generic-math/tanl.c new file mode 100644 index 0000000..6af0671 --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/tanl.c @@ -0,0 +1,29 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double tanl(long double x) +{ + return tan(x); +} +#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 +long double tanl(long double x) +{ + union ldshape u = {x}; + long double y[2]; + unsigned n; + + u.i.se &= 0x7fff; + if (u.i.se == 0x7fff) + return x - x; + if (u.f < M_PI_4) { + if (u.i.se < 0x3fff - LDBL_MANT_DIG/2) { + /* raise inexact if x!=0 and underflow if subnormal */ + FORCE_EVAL(u.i.se == 0 ? x*0x1p-120f : x+0x1p120f); + return x; + } + return __tanl(x, 0, 0); + } + n = __rem_pio2l(x, y); + return __tanl(y[0], y[1], n&1); +} +#endif diff --git a/lib/mlibc/options/ansi/musl-generic-math/tgamma.c b/lib/mlibc/options/ansi/musl-generic-math/tgamma.c new file mode 100644 index 0000000..28f6e0f --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/tgamma.c @@ -0,0 +1,222 @@ +/* +"A Precision Approximation of the Gamma Function" - Cornelius Lanczos (1964) +"Lanczos Implementation of the Gamma Function" - Paul Godfrey (2001) +"An Analysis of the Lanczos Gamma Approximation" - Glendon Ralph Pugh (2004) + +approximation method: + + (x - 0.5) S(x) +Gamma(x) = (x + g - 0.5) * ---------------- + exp(x + g - 0.5) + +with + a1 a2 a3 aN +S(x) ~= [ a0 + ----- + ----- + ----- + ... + ----- ] + x + 1 x + 2 x + 3 x + N + +with a0, a1, a2, a3,.. aN constants which depend on g. + +for x < 0 the following reflection formula is used: + +Gamma(x)*Gamma(-x) = -pi/(x sin(pi x)) + +most ideas and constants are from boost and python +*/ +#include "libm.h" + +static const double pi = 3.141592653589793238462643383279502884; + +/* sin(pi x) with x > 0x1p-100, if sin(pi*x)==0 the sign is arbitrary */ +static double sinpi(double x) +{ + int n; + + /* argument reduction: x = |x| mod 2 */ + /* spurious inexact when x is odd int */ + x = x * 0.5; + x = 2 * (x - floor(x)); + + /* reduce x into [-.25,.25] */ + n = 4 * x; + n = (n+1)/2; + x -= n * 0.5; + + x *= pi; + switch (n) { + default: /* case 4 */ + case 0: + return __sin(x, 0, 0); + case 1: + return __cos(x, 0); + case 2: + return __sin(-x, 0, 0); + case 3: + return -__cos(x, 0); + } +} + +#define N 12 +//static const double g = 6.024680040776729583740234375; +static const double gmhalf = 5.524680040776729583740234375; +static const double Snum[N+1] = { + 23531376880.410759688572007674451636754734846804940, + 42919803642.649098768957899047001988850926355848959, + 35711959237.355668049440185451547166705960488635843, + 17921034426.037209699919755754458931112671403265390, + 6039542586.3520280050642916443072979210699388420708, + 1439720407.3117216736632230727949123939715485786772, + 248874557.86205415651146038641322942321632125127801, + 31426415.585400194380614231628318205362874684987640, + 2876370.6289353724412254090516208496135991145378768, + 186056.26539522349504029498971604569928220784236328, + 8071.6720023658162106380029022722506138218516325024, + 210.82427775157934587250973392071336271166969580291, + 2.5066282746310002701649081771338373386264310793408, +}; +static const double Sden[N+1] = { + 0, 39916800, 120543840, 150917976, 105258076, 45995730, 13339535, + 2637558, 357423, 32670, 1925, 66, 1, +}; +/* n! for small integer n */ +static const double fact[] = { + 1, 1, 2, 6, 24, 120, 720, 5040.0, 40320.0, 362880.0, 3628800.0, 39916800.0, + 479001600.0, 6227020800.0, 87178291200.0, 1307674368000.0, 20922789888000.0, + 355687428096000.0, 6402373705728000.0, 121645100408832000.0, + 2432902008176640000.0, 51090942171709440000.0, 1124000727777607680000.0, +}; + +/* S(x) rational function for positive x */ +static double S(double x) +{ + double_t num = 0, den = 0; + int i; + + /* to avoid overflow handle large x differently */ + if (x < 8) + for (i = N; i >= 0; i--) { + num = num * x + Snum[i]; + den = den * x + Sden[i]; + } + else + for (i = 0; i <= N; i++) { + num = num / x + Snum[i]; + den = den / x + Sden[i]; + } + return num/den; +} + +double tgamma(double x) +{ + union {double f; uint64_t i;} u = {x}; + double absx, y; + double_t dy, z, r; + uint32_t ix = u.i>>32 & 0x7fffffff; + int sign = u.i>>63; + + /* special cases */ + if (ix >= 0x7ff00000) + /* tgamma(nan)=nan, tgamma(inf)=inf, tgamma(-inf)=nan with invalid */ + return x + INFINITY; + if (ix < (0x3ff-54)<<20) + /* |x| < 2^-54: tgamma(x) ~ 1/x, +-0 raises div-by-zero */ + return 1/x; + + /* integer arguments */ + /* raise inexact when non-integer */ + if (x == floor(x)) { + if (sign) + return 0/0.0; + if (x <= sizeof fact/sizeof *fact) + return fact[(int)x - 1]; + } + + /* x >= 172: tgamma(x)=inf with overflow */ + /* x =< -184: tgamma(x)=+-0 with underflow */ + if (ix >= 0x40670000) { /* |x| >= 184 */ + if (sign) { + FORCE_EVAL((float)(0x1p-126/x)); + if (floor(x) * 0.5 == floor(x * 0.5)) + return 0; + return -0.0; + } + x *= 0x1p1023; + return x; + } + + absx = sign ? -x : x; + + /* handle the error of x + g - 0.5 */ + y = absx + gmhalf; + if (absx > gmhalf) { + dy = y - absx; + dy -= gmhalf; + } else { + dy = y - gmhalf; + dy -= absx; + } + + z = absx - 0.5; + r = S(absx) * exp(-y); + if (x < 0) { + /* reflection formula for negative x */ + /* sinpi(absx) is not 0, integers are already handled */ + r = -pi / (sinpi(absx) * absx * r); + dy = -dy; + z = -z; + } + r += dy * (gmhalf+0.5) * r / y; + z = pow(y, 0.5*z); + y = r * z * z; + return y; +} + +#if 0 +double __lgamma_r(double x, int *sign) +{ + double r, absx; + + *sign = 1; + + /* special cases */ + if (!isfinite(x)) + /* lgamma(nan)=nan, lgamma(+-inf)=inf */ + return x*x; + + /* integer arguments */ + if (x == floor(x) && x <= 2) { + /* n <= 0: lgamma(n)=inf with divbyzero */ + /* n == 1,2: lgamma(n)=0 */ + if (x <= 0) + return 1/0.0; + return 0; + } + + absx = fabs(x); + + /* lgamma(x) ~ -log(|x|) for tiny |x| */ + if (absx < 0x1p-54) { + *sign = 1 - 2*!!signbit(x); + return -log(absx); + } + + /* use tgamma for smaller |x| */ + if (absx < 128) { + x = tgamma(x); + *sign = 1 - 2*!!signbit(x); + return log(fabs(x)); + } + + /* second term (log(S)-g) could be more precise here.. */ + /* or with stirling: (|x|-0.5)*(log(|x|)-1) + poly(1/|x|) */ + r = (absx-0.5)*(log(absx+gmhalf)-1) + (log(S(absx)) - (gmhalf+0.5)); + if (x < 0) { + /* reflection formula for negative x */ + x = sinpi(absx); + *sign = 2*!!signbit(x) - 1; + r = log(pi/(fabs(x)*absx)) - r; + } + return r; +} + +weak_alias(__lgamma_r, lgamma_r); +#endif diff --git a/lib/mlibc/options/ansi/musl-generic-math/tgammaf.c b/lib/mlibc/options/ansi/musl-generic-math/tgammaf.c new file mode 100644 index 0000000..b4ca51c --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/tgammaf.c @@ -0,0 +1,6 @@ +#include + +float tgammaf(float x) +{ + return tgamma(x); +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/tgammal.c b/lib/mlibc/options/ansi/musl-generic-math/tgammal.c new file mode 100644 index 0000000..5336c5b --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/tgammal.c @@ -0,0 +1,281 @@ +/* origin: OpenBSD /usr/src/lib/libm/src/ld80/e_tgammal.c */ +/* + * Copyright (c) 2008 Stephen L. Moshier + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/* + * Gamma function + * + * + * SYNOPSIS: + * + * long double x, y, tgammal(); + * + * y = tgammal( x ); + * + * + * DESCRIPTION: + * + * Returns gamma function of the argument. The result is + * correctly signed. + * + * Arguments |x| <= 13 are reduced by recurrence and the function + * approximated by a rational function of degree 7/8 in the + * interval (2,3). Large arguments are handled by Stirling's + * formula. Large negative arguments are made positive using + * a reflection formula. + * + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * IEEE -40,+40 10000 3.6e-19 7.9e-20 + * IEEE -1755,+1755 10000 4.8e-18 6.5e-19 + * + * Accuracy for large arguments is dominated by error in powl(). + * + */ + +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double tgammal(long double x) +{ + return tgamma(x); +} +#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 +/* +tgamma(x+2) = tgamma(x+2) P(x)/Q(x) +0 <= x <= 1 +Relative error +n=7, d=8 +Peak error = 1.83e-20 +Relative error spread = 8.4e-23 +*/ +static const long double P[8] = { + 4.212760487471622013093E-5L, + 4.542931960608009155600E-4L, + 4.092666828394035500949E-3L, + 2.385363243461108252554E-2L, + 1.113062816019361559013E-1L, + 3.629515436640239168939E-1L, + 8.378004301573126728826E-1L, + 1.000000000000000000009E0L, +}; +static const long double Q[9] = { +-1.397148517476170440917E-5L, + 2.346584059160635244282E-4L, +-1.237799246653152231188E-3L, +-7.955933682494738320586E-4L, + 2.773706565840072979165E-2L, +-4.633887671244534213831E-2L, +-2.243510905670329164562E-1L, + 4.150160950588455434583E-1L, + 9.999999999999999999908E-1L, +}; + +/* +static const long double P[] = { +-3.01525602666895735709e0L, +-3.25157411956062339893e1L, +-2.92929976820724030353e2L, +-1.70730828800510297666e3L, +-7.96667499622741999770e3L, +-2.59780216007146401957e4L, +-5.99650230220855581642e4L, +-7.15743521530849602425e4L +}; +static const long double Q[] = { + 1.00000000000000000000e0L, +-1.67955233807178858919e1L, + 8.85946791747759881659e1L, + 5.69440799097468430177e1L, +-1.98526250512761318471e3L, + 3.31667508019495079814e3L, + 1.60577839621734713377e4L, +-2.97045081369399940529e4L, +-7.15743521530849602412e4L +}; +*/ +#define MAXGAML 1755.455L +/*static const long double LOGPI = 1.14472988584940017414L;*/ + +/* Stirling's formula for the gamma function +tgamma(x) = sqrt(2 pi) x^(x-.5) exp(-x) (1 + 1/x P(1/x)) +z(x) = x +13 <= x <= 1024 +Relative error +n=8, d=0 +Peak error = 9.44e-21 +Relative error spread = 8.8e-4 +*/ +static const long double STIR[9] = { + 7.147391378143610789273E-4L, +-2.363848809501759061727E-5L, +-5.950237554056330156018E-4L, + 6.989332260623193171870E-5L, + 7.840334842744753003862E-4L, +-2.294719747873185405699E-4L, +-2.681327161876304418288E-3L, + 3.472222222230075327854E-3L, + 8.333333333333331800504E-2L, +}; + +#define MAXSTIR 1024.0L +static const long double SQTPI = 2.50662827463100050242E0L; + +/* 1/tgamma(x) = z P(z) + * z(x) = 1/x + * 0 < x < 0.03125 + * Peak relative error 4.2e-23 + */ +static const long double S[9] = { +-1.193945051381510095614E-3L, + 7.220599478036909672331E-3L, +-9.622023360406271645744E-3L, +-4.219773360705915470089E-2L, + 1.665386113720805206758E-1L, +-4.200263503403344054473E-2L, +-6.558780715202540684668E-1L, + 5.772156649015328608253E-1L, + 1.000000000000000000000E0L, +}; + +/* 1/tgamma(-x) = z P(z) + * z(x) = 1/x + * 0 < x < 0.03125 + * Peak relative error 5.16e-23 + * Relative error spread = 2.5e-24 + */ +static const long double SN[9] = { + 1.133374167243894382010E-3L, + 7.220837261893170325704E-3L, + 9.621911155035976733706E-3L, +-4.219773343731191721664E-2L, +-1.665386113944413519335E-1L, +-4.200263503402112910504E-2L, + 6.558780715202536547116E-1L, + 5.772156649015328608727E-1L, +-1.000000000000000000000E0L, +}; + +static const long double PIL = 3.1415926535897932384626L; + +/* Gamma function computed by Stirling's formula. + */ +static long double stirf(long double x) +{ + long double y, w, v; + + w = 1.0/x; + /* For large x, use rational coefficients from the analytical expansion. */ + if (x > 1024.0) + w = (((((6.97281375836585777429E-5L * w + + 7.84039221720066627474E-4L) * w + - 2.29472093621399176955E-4L) * w + - 2.68132716049382716049E-3L) * w + + 3.47222222222222222222E-3L) * w + + 8.33333333333333333333E-2L) * w + + 1.0; + else + w = 1.0 + w * __polevll(w, STIR, 8); + y = expl(x); + if (x > MAXSTIR) { /* Avoid overflow in pow() */ + v = powl(x, 0.5L * x - 0.25L); + y = v * (v / y); + } else { + y = powl(x, x - 0.5L) / y; + } + y = SQTPI * y * w; + return y; +} + +long double tgammal(long double x) +{ + long double p, q, z; + + if (!isfinite(x)) + return x + INFINITY; + + q = fabsl(x); + if (q > 13.0) { + if (x < 0.0) { + p = floorl(q); + z = q - p; + if (z == 0) + return 0 / z; + if (q > MAXGAML) { + z = 0; + } else { + if (z > 0.5) { + p += 1.0; + z = q - p; + } + z = q * sinl(PIL * z); + z = fabsl(z) * stirf(q); + z = PIL/z; + } + if (0.5 * p == floorl(q * 0.5)) + z = -z; + } else if (x > MAXGAML) { + z = x * 0x1p16383L; + } else { + z = stirf(x); + } + return z; + } + + z = 1.0; + while (x >= 3.0) { + x -= 1.0; + z *= x; + } + while (x < -0.03125L) { + z /= x; + x += 1.0; + } + if (x <= 0.03125L) + goto small; + while (x < 2.0) { + z /= x; + x += 1.0; + } + if (x == 2.0) + return z; + + x -= 2.0; + p = __polevll(x, P, 7); + q = __polevll(x, Q, 8); + z = z * p / q; + return z; + +small: + /* z==1 if x was originally +-0 */ + if (x == 0 && z != 1) + return x / x; + if (x < 0.0) { + x = -x; + q = z / (x * __polevll(x, SN, 8)); + } else + q = z / (x * __polevll(x, S, 8)); + return q; +} +#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 +// TODO: broken implementation to make things compile +long double tgammal(long double x) +{ + return tgamma(x); +} +#endif diff --git a/lib/mlibc/options/ansi/musl-generic-math/trunc.c b/lib/mlibc/options/ansi/musl-generic-math/trunc.c new file mode 100644 index 0000000..d13711b --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/trunc.c @@ -0,0 +1,19 @@ +#include "libm.h" + +double trunc(double x) +{ + union {double f; uint64_t i;} u = {x}; + int e = (int)(u.i >> 52 & 0x7ff) - 0x3ff + 12; + uint64_t m; + + if (e >= 52 + 12) + return x; + if (e < 12) + e = 1; + m = -1ULL >> e; + if ((u.i & m) == 0) + return x; + FORCE_EVAL(x + 0x1p120f); + u.i &= ~m; + return u.f; +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/truncf.c b/lib/mlibc/options/ansi/musl-generic-math/truncf.c new file mode 100644 index 0000000..1a7d03c --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/truncf.c @@ -0,0 +1,19 @@ +#include "libm.h" + +float truncf(float x) +{ + union {float f; uint32_t i;} u = {x}; + int e = (int)(u.i >> 23 & 0xff) - 0x7f + 9; + uint32_t m; + + if (e >= 23 + 9) + return x; + if (e < 9) + e = 1; + m = -1U >> e; + if ((u.i & m) == 0) + return x; + FORCE_EVAL(x + 0x1p120f); + u.i &= ~m; + return u.f; +} diff --git a/lib/mlibc/options/ansi/musl-generic-math/truncl.c b/lib/mlibc/options/ansi/musl-generic-math/truncl.c new file mode 100644 index 0000000..f07b193 --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/truncl.c @@ -0,0 +1,34 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double truncl(long double x) +{ + return trunc(x); +} +#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 + +static const long double toint = 1/LDBL_EPSILON; + +long double truncl(long double x) +{ + union ldshape u = {x}; + int e = u.i.se & 0x7fff; + int s = u.i.se >> 15; + long double y; + + if (e >= 0x3fff+LDBL_MANT_DIG-1) + return x; + if (e <= 0x3fff-1) { + FORCE_EVAL(x + 0x1p120f); + return x*0; + } + /* y = int(|x|) - |x|, where int(|x|) is an integer neighbor of |x| */ + if (s) + x = -x; + y = x + toint - toint - x; + if (y > 0) + y -= 1; + x += y; + return s ? -x : x; +} +#endif diff --git a/lib/mlibc/options/ansi/musl-generic-math/weak_alias.h b/lib/mlibc/options/ansi/musl-generic-math/weak_alias.h new file mode 100644 index 0000000..785f9d1 --- /dev/null +++ b/lib/mlibc/options/ansi/musl-generic-math/weak_alias.h @@ -0,0 +1,7 @@ +#ifndef _WEAK_ALIAS_H +#define _WEAK_ALIAS_H + +#define weak_alias(name, alias_to) \ + extern __typeof (name) alias_to __attribute__((__weak__, __alias__(#name))); + +#endif diff --git a/lib/mlibc/options/bsd/generic/arpa-nameser-stubs.cpp b/lib/mlibc/options/bsd/generic/arpa-nameser-stubs.cpp new file mode 100644 index 0000000..e89f2bb --- /dev/null +++ b/lib/mlibc/options/bsd/generic/arpa-nameser-stubs.cpp @@ -0,0 +1,41 @@ +#include +#include +#include +#include + +// The ns_get* and ns_put* functions are taken from musl. +unsigned ns_get16(const unsigned char *cp) { + return cp[0] << 8 | cp[1]; +} + +unsigned long ns_get32(const unsigned char *cp) { + return (unsigned)cp[0] << 24 | cp[1] << 16 | cp[2] << 8 | cp[3]; +} + +void ns_put16(unsigned s, unsigned char *cp) { + *cp++ = s >> 8; + *cp++ = s; +} + +void ns_put32(unsigned long l, unsigned char *cp) { + *cp++ = l >> 24; + *cp++ = l >> 16; + *cp++ = l >> 8; + *cp++ = l; +} + +int ns_initparse(const unsigned char *, int, ns_msg *) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +int ns_parserr(ns_msg *, ns_sect, int, ns_rr *) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +int ns_name_uncompress(const unsigned char *, const unsigned char *, + const unsigned char *, char *, size_t) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} diff --git a/lib/mlibc/options/bsd/generic/ether.cpp b/lib/mlibc/options/bsd/generic/ether.cpp new file mode 100644 index 0000000..2619320 --- /dev/null +++ b/lib/mlibc/options/bsd/generic/ether.cpp @@ -0,0 +1,19 @@ +#include +#include +#include + +char *ether_ntoa_r(const struct ether_addr *addr, char *buf) { + char *orig_ptr = buf; + + for(int i = 0; i < ETH_ALEN; i++) { + buf += sprintf(buf, i == 0 ? "%.2X" : ":%.2X", addr->ether_addr_octet[i]); + } + + return orig_ptr; +} + + +struct ether_addr *ether_aton(const char *) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} diff --git a/lib/mlibc/options/bsd/generic/getopt.cpp b/lib/mlibc/options/bsd/generic/getopt.cpp new file mode 100644 index 0000000..cc124ef --- /dev/null +++ b/lib/mlibc/options/bsd/generic/getopt.cpp @@ -0,0 +1,8 @@ +#include + +#if __MLIBC_GLIBC_OPTION + +int __optreset = 0; +extern int optreset __attribute__((__weak__, __alias__("__optreset"))); + +#endif //__MLIBC_GLIBC_OPTION diff --git a/lib/mlibc/options/bsd/include/arpa/nameser.h b/lib/mlibc/options/bsd/include/arpa/nameser.h new file mode 100644 index 0000000..aabb26d --- /dev/null +++ b/lib/mlibc/options/bsd/include/arpa/nameser.h @@ -0,0 +1,266 @@ +#ifndef _ARPA_NAMESER_H +#define _ARPA_NAMESER_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define NS_PACKETSZ 512 +#define NS_MAXDNAME 1025 +#define NS_MAXLABEL 63 + +typedef enum __ns_rcode { + ns_r_noerror = 0, + ns_r_formerr = 1, + ns_r_servfail = 2, + ns_r_nxdomain = 3, + ns_r_notimpl = 4, + ns_r_refused = 5, + ns_r_yxdomain = 6, + ns_r_yxrrset = 7, + ns_r_nxrrset = 8, + ns_r_notauth = 9, + ns_r_notzone = 10, + ns_r_max = 11, + ns_r_badvers = 16, + ns_r_badsig = 16, + ns_r_badkey = 17, + ns_r_badtime = 18 +} ns_rcode; + +typedef enum __ns_type { + ns_t_invalid = 0, + ns_t_a = 1, + ns_t_ns = 2, + ns_t_md = 3, + ns_t_mf = 4, + ns_t_cname = 5, + ns_t_soa = 6, + ns_t_mb = 7, + ns_t_mg = 8, + ns_t_mr = 9, + ns_t_null = 10, + ns_t_wks = 11, + ns_t_ptr = 12, + ns_t_hinfo = 13, + ns_t_minfo = 14, + ns_t_mx = 15, + ns_t_txt = 16, + ns_t_rp = 17, + ns_t_afsdb = 18, + ns_t_x25 = 19, + ns_t_isdn = 20, + ns_t_rt = 21, + ns_t_nsap = 22, + ns_t_nsap_ptr = 23, + ns_t_sig = 24, + ns_t_key = 25, + ns_t_px = 26, + ns_t_gpos = 27, + ns_t_aaaa = 28, + ns_t_loc = 29, + ns_t_nxt = 30, + ns_t_eid = 31, + ns_t_nimloc = 32, + ns_t_srv = 33, + ns_t_atma = 34, + ns_t_naptr = 35, + ns_t_kx = 36, + ns_t_cert = 37, + ns_t_a6 = 38, + ns_t_dname = 39, + ns_t_sink = 40, + ns_t_opt = 41, + ns_t_apl = 42, + ns_t_tkey = 249, + ns_t_tsig = 250, + ns_t_ixfr = 251, + ns_t_axfr = 252, + ns_t_mailb = 253, + ns_t_maila = 254, + ns_t_any = 255, + ns_t_zxfr = 256, + ns_t_max = 65536 +} ns_type; + +typedef enum __ns_class { + ns_c_invalid = 0, + ns_c_in = 1, + ns_c_2 = 2, + ns_c_chaos = 3, + ns_c_hs = 4, + ns_c_none = 254, + ns_c_any = 255, + ns_c_max = 65536 +} ns_class; + +typedef enum __ns_sect { + ns_s_qd = 0, + ns_s_zn = 0, + ns_s_an = 1, + ns_s_pr = 1, + ns_s_ns = 2, + ns_s_ud = 2, + ns_s_ar = 3, + ns_s_max = 4 +} ns_sect; + +typedef struct __ns_msg { + const unsigned char *_msg, *_eom; + uint16_t _id, _flags, _counts[ns_s_max]; + const unsigned char *_sections[ns_s_max]; + ns_sect _sect; + int _rrnum; + const unsigned char *_msg_ptr; +} ns_msg; + +#define ns_msg_id(handle) ((handle)._id + 0) +#define ns_msg_base(handle) ((handle)._msg + 0) +#define ns_msg_end(handle) ((handle)._eom + 0) +#define ns_msg_size(handle) ((handle)._eom - (handle)._msg) +#define ns_msg_count(handle, section) ((handle)._counts[section] + 0) + +typedef struct __ns_rr { + char name[NS_MAXDNAME]; + uint16_t type; + uint16_t rr_class; + uint32_t ttl; + uint16_t rdlength; + const unsigned char *rdata; +} ns_rr; + +#define ns_rr_name(rr) (((rr).name[0] != '\0') ? (rr).name : ".") +#define ns_rr_type(rr) ((ns_type)((rr).type + 0)) +#define ns_rr_class(rr) ((ns_class)((rr).rr_class + 0)) +#define ns_rr_ttl(rr) ((rr).ttl + 0) +#define ns_rr_rdlen(rr) ((rr).rdlength + 0) +#define ns_rr_rdata(rr) ((rr).rdata + 0) + +#ifndef __MLIBC_ABI_ONLY + +#define NS_GET16(s, cp) (void)((s) = ns_get16(((cp) += 2) - 2)) +#define NS_GET32(l, cp) (void)((l) = ns_get32(((cp) += 4) - 4)) +#define NS_PUT16(s, cp) ns_put16((s), ((cp) += 2) - 2) +#define NS_PUT32(l, cp) ns_put32((l), ((cp) += 4) - 4) + +unsigned ns_get16(const unsigned char *); +unsigned long ns_get32(const unsigned char *); +void ns_put16(unsigned, unsigned char *); +void ns_put32(unsigned long, unsigned char *); + +int ns_initparse(const unsigned char *msg, int msglen, ns_msg *handle); +int ns_parserr(ns_msg *msg, ns_sect section, int rrnum, ns_rr *rr); +int ns_name_uncompress(const unsigned char *msg, const unsigned char *eom, + const unsigned char *src, char *dst, size_t dstsize); + +#endif /* !__MLIBC_ABI_ONLY */ + +typedef struct { + unsigned id :16; +#if __BYTE_ORDER == __BIG_ENDIAN + unsigned qr: 1; + unsigned opcode: 4; + unsigned aa: 1; + unsigned tc: 1; + unsigned rd: 1; + unsigned ra: 1; + unsigned unused :1; + unsigned ad: 1; + unsigned cd: 1; + unsigned rcode :4; +#else + unsigned rd :1; + unsigned tc :1; + unsigned aa :1; + unsigned opcode :4; + unsigned qr :1; + unsigned rcode :4; + unsigned cd: 1; + unsigned ad: 1; + unsigned unused :1; + unsigned ra :1; +#endif + unsigned qdcount :16; + unsigned ancount :16; + unsigned nscount :16; + unsigned arcount :16; +} HEADER; + +#define PACKETSZ NS_PACKETSZ +#define MAXDNAME NS_MAXDNAME + +#define NOERROR ns_r_noerror +#define FORMERR ns_r_formerr +#define SERVFAIL ns_r_servfail +#define NXDOMAIN ns_r_nxdomain +#define NOTIMP ns_r_notimpl +#define REFUSED ns_r_refused +#define YXDOMAIN ns_r_yxdomain +#define YXRRSET ns_r_yxrrset +#define NXRRSET ns_r_nxrrset +#define NOTAUTH ns_r_notauth +#define NOTZONE ns_r_notzone + +#define T_A ns_t_a +#define T_NS ns_t_ns +#define T_MD ns_t_md +#define T_MF ns_t_mf +#define T_CNAME ns_t_cname +#define T_SOA ns_t_soa +#define T_MB ns_t_mb +#define T_MG ns_t_mg +#define T_MR ns_t_mr +#define T_NULL ns_t_null +#define T_WKS ns_t_wks +#define T_PTR ns_t_ptr +#define T_HINFO ns_t_hinfo +#define T_MINFO ns_t_minfo +#define T_MX ns_t_mx +#define T_TXT ns_t_txt +#define T_RP ns_t_rp +#define T_AFSDB ns_t_afsdb +#define T_X25 ns_t_x25 +#define T_ISDN ns_t_isdn +#define T_RT ns_t_rt +#define T_NSAP ns_t_nsap +#define T_NSAP_PTR ns_t_nsap_ptr +#define T_SIG ns_t_sig +#define T_KEY ns_t_key +#define T_PX ns_t_px +#define T_GPOS ns_t_gpos +#define T_AAAA ns_t_aaaa +#define T_LOC ns_t_loc +#define T_NXT ns_t_nxt +#define T_EID ns_t_eid +#define T_NIMLOC ns_t_nimloc +#define T_SRV ns_t_srv +#define T_ATMA ns_t_atma +#define T_NAPTR ns_t_naptr +#define T_A6 ns_t_a6 +#define T_DNAME ns_t_dname +#define T_TSIG ns_t_tsig +#define T_IXFR ns_t_ixfr +#define T_AXFR ns_t_axfr +#define T_MAILB ns_t_mailb +#define T_MAILA ns_t_maila +#define T_ANY ns_t_any + +#define C_IN ns_c_in +#define C_CHAOS ns_c_chaos +#define C_HS ns_c_hs +#define C_NONE ns_c_none +#define C_ANY ns_c_any + +#define GETSHORT NS_GET16 +#define GETLONG NS_GET32 +#define PUTSHORT NS_PUT16 +#define PUTLONG NS_PUT32 + +#ifdef __cplusplus +} +#endif + +#endif // _ARPA_NAMESER_H diff --git a/lib/mlibc/options/bsd/include/arpa/nameser_compat.h b/lib/mlibc/options/bsd/include/arpa/nameser_compat.h new file mode 100644 index 0000000..ee3b1a9 --- /dev/null +++ b/lib/mlibc/options/bsd/include/arpa/nameser_compat.h @@ -0,0 +1 @@ +#include diff --git a/lib/mlibc/options/bsd/include/bits/bsd/bsd_unistd.h b/lib/mlibc/options/bsd/include/bits/bsd/bsd_unistd.h new file mode 100644 index 0000000..2fe0391 --- /dev/null +++ b/lib/mlibc/options/bsd/include/bits/bsd/bsd_unistd.h @@ -0,0 +1,20 @@ +#ifndef _BSD_UNISTD_H +#define _BSD_UNISTD_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#ifndef __MLIBC_ABI_ONLY + +void *sbrk(intptr_t increment); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _BSD_UNISTD_H */ diff --git a/lib/mlibc/options/bsd/include/fstab.h b/lib/mlibc/options/bsd/include/fstab.h new file mode 100644 index 0000000..2a445f0 --- /dev/null +++ b/lib/mlibc/options/bsd/include/fstab.h @@ -0,0 +1,23 @@ +#ifndef _FSTAB_H +#define _FSTAB_H + +#define _PATH_FSTAB "/etc/fstab" +#define FSTAB "/etc/fstab" + +#define FSTAB_RW "rw" +#define FSTAB_RQ "rq" +#define FSTAB_RO "ro" +#define FSTAB_SW "sw" +#define FSTAB_XX "xx" + +struct fstab { + char *fs_spec; + char *fs_file; + char *fs_vfstype; + char *fs_mntops; + const char *fs_type; + int fs_freq; + int fs_passno; +}; + +#endif /* _FSTAB_H */ diff --git a/lib/mlibc/options/bsd/include/mlibc/bsd-sysdeps.hpp b/lib/mlibc/options/bsd/include/mlibc/bsd-sysdeps.hpp new file mode 100644 index 0000000..de3ada0 --- /dev/null +++ b/lib/mlibc/options/bsd/include/mlibc/bsd-sysdeps.hpp @@ -0,0 +1,10 @@ +#ifndef MLIBC_BSD_SYSDEPS +#define MLIBC_BSD_SYSDEPS + +namespace [[gnu::visibility("hidden")]] mlibc { + +[[gnu::weak]] int sys_brk(void **out); + +} // namespace mlibc + +#endif // MLIBC_BSD_SYSDEPS diff --git a/lib/mlibc/options/bsd/include/netinet/ether.h b/lib/mlibc/options/bsd/include/netinet/ether.h new file mode 100644 index 0000000..4be14ad --- /dev/null +++ b/lib/mlibc/options/bsd/include/netinet/ether.h @@ -0,0 +1,23 @@ +#ifndef _NETINET_ETHER_H +#define _NETINET_ETHER_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +char *ether_ntoa_r(const struct ether_addr *p_a, char *x); + +struct ether_addr *ether_aton(const char *asc); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif //_NETINET_ETHER_H diff --git a/lib/mlibc/options/bsd/include/sys/queue.h b/lib/mlibc/options/bsd/include/sys/queue.h new file mode 100644 index 0000000..7006b05 --- /dev/null +++ b/lib/mlibc/options/bsd/include/sys/queue.h @@ -0,0 +1,574 @@ +/* + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)queue.h 8.5 (Berkeley) 8/20/94 + */ + +#ifndef _SYS_QUEUE_H_ +#define _SYS_QUEUE_H_ + +/* + * This file defines five types of data structures: singly-linked lists, + * lists, simple queues, tail queues, and circular queues. + * + * A singly-linked list is headed by a single forward pointer. The + * elements are singly linked for minimum space and pointer manipulation + * overhead at the expense of O(n) removal for arbitrary elements. New + * elements can be added to the list after an existing element or at the + * head of the list. Elements being removed from the head of the list + * should use the explicit macro for this purpose for optimum + * efficiency. A singly-linked list may only be traversed in the forward + * direction. Singly-linked lists are ideal for applications with large + * datasets and few or no removals or for implementing a LIFO queue. + * + * A list is headed by a single forward pointer (or an array of forward + * pointers for a hash table header). The elements are doubly linked + * so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before + * or after an existing element or at the head of the list. A list + * may only be traversed in the forward direction. + * + * A simple queue is headed by a pair of pointers, one the head of the + * list and the other to the tail of the list. The elements are singly + * linked to save space, so elements can only be removed from the + * head of the list. New elements can be added to the list after + * an existing element, at the head of the list, or at the end of the + * list. A simple queue may only be traversed in the forward direction. + * + * A tail queue is headed by a pair of pointers, one to the head of the + * list and the other to the tail of the list. The elements are doubly + * linked so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before or + * after an existing element, at the head of the list, or at the end of + * the list. A tail queue may be traversed in either direction. + * + * A circle queue is headed by a pair of pointers, one to the head of the + * list and the other to the tail of the list. The elements are doubly + * linked so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before or after + * an existing element, at the head of the list, or at the end of the list. + * A circle queue may be traversed in either direction, but has a more + * complex end of list detection. + * + * For details on the use of these macros, see the queue(3) manual page. + */ + +/* + * List definitions. + */ +#define LIST_HEAD(name, type) \ +struct name { \ + struct type *lh_first; /* first element */ \ +} + +#define LIST_HEAD_INITIALIZER(head) \ + { NULL } + +#define LIST_ENTRY(type) \ +struct { \ + struct type *le_next; /* next element */ \ + struct type **le_prev; /* address of previous next element */ \ +} + +/* + * List functions. + */ +#define LIST_INIT(head) do { \ + (head)->lh_first = NULL; \ +} while (0) + +#define LIST_INSERT_AFTER(listelm, elm, field) do { \ + if (((elm)->field.le_next = (listelm)->field.le_next) != NULL) \ + (listelm)->field.le_next->field.le_prev = \ + &(elm)->field.le_next; \ + (listelm)->field.le_next = (elm); \ + (elm)->field.le_prev = &(listelm)->field.le_next; \ +} while (0) + +#define LIST_INSERT_BEFORE(listelm, elm, field) do { \ + (elm)->field.le_prev = (listelm)->field.le_prev; \ + (elm)->field.le_next = (listelm); \ + *(listelm)->field.le_prev = (elm); \ + (listelm)->field.le_prev = &(elm)->field.le_next; \ +} while (0) + +#define LIST_INSERT_HEAD(head, elm, field) do { \ + if (((elm)->field.le_next = (head)->lh_first) != NULL) \ + (head)->lh_first->field.le_prev = &(elm)->field.le_next;\ + (head)->lh_first = (elm); \ + (elm)->field.le_prev = &(head)->lh_first; \ +} while (0) + +#define LIST_REMOVE(elm, field) do { \ + if ((elm)->field.le_next != NULL) \ + (elm)->field.le_next->field.le_prev = \ + (elm)->field.le_prev; \ + *(elm)->field.le_prev = (elm)->field.le_next; \ +} while (0) + +#define LIST_FOREACH(var, head, field) \ + for ((var) = ((head)->lh_first); \ + (var); \ + (var) = ((var)->field.le_next)) + +/* + * List access methods. + */ +#define LIST_EMPTY(head) ((head)->lh_first == NULL) +#define LIST_FIRST(head) ((head)->lh_first) +#define LIST_NEXT(elm, field) ((elm)->field.le_next) + + +/* + * Singly-linked List definitions. + */ +#define SLIST_HEAD(name, type) \ +struct name { \ + struct type *slh_first; /* first element */ \ +} + +#define SLIST_HEAD_INITIALIZER(head) \ + { NULL } + +#define SLIST_ENTRY(type) \ +struct { \ + struct type *sle_next; /* next element */ \ +} + +/* + * Singly-linked List functions. + */ +#define SLIST_INIT(head) do { \ + (head)->slh_first = NULL; \ +} while (0) + +#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \ + (elm)->field.sle_next = (slistelm)->field.sle_next; \ + (slistelm)->field.sle_next = (elm); \ +} while (0) + +#define SLIST_INSERT_HEAD(head, elm, field) do { \ + (elm)->field.sle_next = (head)->slh_first; \ + (head)->slh_first = (elm); \ +} while (0) + +#define SLIST_REMOVE_HEAD(head, field) do { \ + (head)->slh_first = (head)->slh_first->field.sle_next; \ +} while (0) + +#define SLIST_REMOVE(head, elm, type, field) do { \ + if ((head)->slh_first == (elm)) { \ + SLIST_REMOVE_HEAD((head), field); \ + } \ + else { \ + struct type *curelm = (head)->slh_first; \ + while(curelm->field.sle_next != (elm)) \ + curelm = curelm->field.sle_next; \ + curelm->field.sle_next = \ + curelm->field.sle_next->field.sle_next; \ + } \ +} while (0) + +#define SLIST_FOREACH(var, head, field) \ + for((var) = (head)->slh_first; (var); (var) = (var)->field.sle_next) + +/* + * Singly-linked List access methods. + */ +#define SLIST_EMPTY(head) ((head)->slh_first == NULL) +#define SLIST_FIRST(head) ((head)->slh_first) +#define SLIST_NEXT(elm, field) ((elm)->field.sle_next) + + +/* + * Singly-linked Tail queue declarations. + */ +#define STAILQ_HEAD(name, type) \ +struct name { \ + struct type *stqh_first; /* first element */ \ + struct type **stqh_last; /* addr of last next element */ \ +} + +#define STAILQ_HEAD_INITIALIZER(head) \ + { NULL, &(head).stqh_first } + +#define STAILQ_ENTRY(type) \ +struct { \ + struct type *stqe_next; /* next element */ \ +} + +/* + * Singly-linked Tail queue functions. + */ +#define STAILQ_INIT(head) do { \ + (head)->stqh_first = NULL; \ + (head)->stqh_last = &(head)->stqh_first; \ +} while (0) + +#define STAILQ_INSERT_HEAD(head, elm, field) do { \ + if (((elm)->field.stqe_next = (head)->stqh_first) == NULL) \ + (head)->stqh_last = &(elm)->field.stqe_next; \ + (head)->stqh_first = (elm); \ +} while (0) + +#define STAILQ_INSERT_TAIL(head, elm, field) do { \ + (elm)->field.stqe_next = NULL; \ + *(head)->stqh_last = (elm); \ + (head)->stqh_last = &(elm)->field.stqe_next; \ +} while (0) + +#define STAILQ_INSERT_AFTER(head, listelm, elm, field) do { \ + if (((elm)->field.stqe_next = (listelm)->field.stqe_next) == NULL)\ + (head)->stqh_last = &(elm)->field.stqe_next; \ + (listelm)->field.stqe_next = (elm); \ +} while (0) + +#define STAILQ_REMOVE_HEAD(head, field) do { \ + if (((head)->stqh_first = (head)->stqh_first->field.stqe_next) == NULL) \ + (head)->stqh_last = &(head)->stqh_first; \ +} while (0) + +#define STAILQ_REMOVE(head, elm, type, field) do { \ + if ((head)->stqh_first == (elm)) { \ + STAILQ_REMOVE_HEAD((head), field); \ + } else { \ + struct type *curelm = (head)->stqh_first; \ + while (curelm->field.stqe_next != (elm)) \ + curelm = curelm->field.stqe_next; \ + if ((curelm->field.stqe_next = \ + curelm->field.stqe_next->field.stqe_next) == NULL) \ + (head)->stqh_last = &(curelm)->field.stqe_next; \ + } \ +} while (0) + +#define STAILQ_FOREACH(var, head, field) \ + for ((var) = ((head)->stqh_first); \ + (var); \ + (var) = ((var)->field.stqe_next)) + +#define STAILQ_CONCAT(head1, head2) do { \ + if (!STAILQ_EMPTY((head2))) { \ + *(head1)->stqh_last = (head2)->stqh_first; \ + (head1)->stqh_last = (head2)->stqh_last; \ + STAILQ_INIT((head2)); \ + } \ +} while (0) + +/* + * Singly-linked Tail queue access methods. + */ +#define STAILQ_EMPTY(head) ((head)->stqh_first == NULL) +#define STAILQ_FIRST(head) ((head)->stqh_first) +#define STAILQ_NEXT(elm, field) ((elm)->field.stqe_next) + + +/* + * Simple queue definitions. + */ +#define SIMPLEQ_HEAD(name, type) \ +struct name { \ + struct type *sqh_first; /* first element */ \ + struct type **sqh_last; /* addr of last next element */ \ +} + +#define SIMPLEQ_HEAD_INITIALIZER(head) \ + { NULL, &(head).sqh_first } + +#define SIMPLEQ_ENTRY(type) \ +struct { \ + struct type *sqe_next; /* next element */ \ +} + +/* + * Simple queue functions. + */ +#define SIMPLEQ_INIT(head) do { \ + (head)->sqh_first = NULL; \ + (head)->sqh_last = &(head)->sqh_first; \ +} while (0) + +#define SIMPLEQ_INSERT_HEAD(head, elm, field) do { \ + if (((elm)->field.sqe_next = (head)->sqh_first) == NULL) \ + (head)->sqh_last = &(elm)->field.sqe_next; \ + (head)->sqh_first = (elm); \ +} while (0) + +#define SIMPLEQ_INSERT_TAIL(head, elm, field) do { \ + (elm)->field.sqe_next = NULL; \ + *(head)->sqh_last = (elm); \ + (head)->sqh_last = &(elm)->field.sqe_next; \ +} while (0) + +#define SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \ + if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL)\ + (head)->sqh_last = &(elm)->field.sqe_next; \ + (listelm)->field.sqe_next = (elm); \ +} while (0) + +#define SIMPLEQ_REMOVE_HEAD(head, field) do { \ + if (((head)->sqh_first = (head)->sqh_first->field.sqe_next) == NULL) \ + (head)->sqh_last = &(head)->sqh_first; \ +} while (0) + +#define SIMPLEQ_REMOVE(head, elm, type, field) do { \ + if ((head)->sqh_first == (elm)) { \ + SIMPLEQ_REMOVE_HEAD((head), field); \ + } else { \ + struct type *curelm = (head)->sqh_first; \ + while (curelm->field.sqe_next != (elm)) \ + curelm = curelm->field.sqe_next; \ + if ((curelm->field.sqe_next = \ + curelm->field.sqe_next->field.sqe_next) == NULL) \ + (head)->sqh_last = &(curelm)->field.sqe_next; \ + } \ +} while (0) + +#define SIMPLEQ_FOREACH(var, head, field) \ + for ((var) = ((head)->sqh_first); \ + (var); \ + (var) = ((var)->field.sqe_next)) + +/* + * Simple queue access methods. + */ +#define SIMPLEQ_EMPTY(head) ((head)->sqh_first == NULL) +#define SIMPLEQ_FIRST(head) ((head)->sqh_first) +#define SIMPLEQ_NEXT(elm, field) ((elm)->field.sqe_next) + + +/* + * Tail queue definitions. + */ +#define _TAILQ_HEAD(name, type, qual) \ +struct name { \ + qual type *tqh_first; /* first element */ \ + qual type *qual *tqh_last; /* addr of last next element */ \ +} +#define TAILQ_HEAD(name, type) _TAILQ_HEAD(name, struct type,) + +#define TAILQ_HEAD_INITIALIZER(head) \ + { NULL, &(head).tqh_first } + +#define _TAILQ_ENTRY(type, qual) \ +struct { \ + qual type *tqe_next; /* next element */ \ + qual type *qual *tqe_prev; /* address of previous next element */\ +} +#define TAILQ_ENTRY(type) _TAILQ_ENTRY(struct type,) + +/* + * Tail queue functions. + */ +#define TAILQ_INIT(head) do { \ + (head)->tqh_first = NULL; \ + (head)->tqh_last = &(head)->tqh_first; \ +} while (0) + +#define TAILQ_INSERT_HEAD(head, elm, field) do { \ + if (((elm)->field.tqe_next = (head)->tqh_first) != NULL) \ + (head)->tqh_first->field.tqe_prev = \ + &(elm)->field.tqe_next; \ + else \ + (head)->tqh_last = &(elm)->field.tqe_next; \ + (head)->tqh_first = (elm); \ + (elm)->field.tqe_prev = &(head)->tqh_first; \ +} while (0) + +#define TAILQ_INSERT_TAIL(head, elm, field) do { \ + (elm)->field.tqe_next = NULL; \ + (elm)->field.tqe_prev = (head)->tqh_last; \ + *(head)->tqh_last = (elm); \ + (head)->tqh_last = &(elm)->field.tqe_next; \ +} while (0) + +#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \ + if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\ + (elm)->field.tqe_next->field.tqe_prev = \ + &(elm)->field.tqe_next; \ + else \ + (head)->tqh_last = &(elm)->field.tqe_next; \ + (listelm)->field.tqe_next = (elm); \ + (elm)->field.tqe_prev = &(listelm)->field.tqe_next; \ +} while (0) + +#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \ + (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \ + (elm)->field.tqe_next = (listelm); \ + *(listelm)->field.tqe_prev = (elm); \ + (listelm)->field.tqe_prev = &(elm)->field.tqe_next; \ +} while (0) + +#define TAILQ_REMOVE(head, elm, field) do { \ + if (((elm)->field.tqe_next) != NULL) \ + (elm)->field.tqe_next->field.tqe_prev = \ + (elm)->field.tqe_prev; \ + else \ + (head)->tqh_last = (elm)->field.tqe_prev; \ + *(elm)->field.tqe_prev = (elm)->field.tqe_next; \ +} while (0) + +#define TAILQ_FOREACH(var, head, field) \ + for ((var) = ((head)->tqh_first); \ + (var); \ + (var) = ((var)->field.tqe_next)) + +#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \ + for ((var) = (*(((struct headname *)((head)->tqh_last))->tqh_last)); \ + (var); \ + (var) = (*(((struct headname *)((var)->field.tqe_prev))->tqh_last))) + +#define TAILQ_CONCAT(head1, head2, field) do { \ + if (!TAILQ_EMPTY(head2)) { \ + *(head1)->tqh_last = (head2)->tqh_first; \ + (head2)->tqh_first->field.tqe_prev = (head1)->tqh_last; \ + (head1)->tqh_last = (head2)->tqh_last; \ + TAILQ_INIT((head2)); \ + } \ +} while (0) + +/* + * Tail queue access methods. + */ +#define TAILQ_EMPTY(head) ((head)->tqh_first == NULL) +#define TAILQ_FIRST(head) ((head)->tqh_first) +#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) + +#define TAILQ_LAST(head, headname) \ + (*(((struct headname *)((head)->tqh_last))->tqh_last)) +#define TAILQ_PREV(elm, headname, field) \ + (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last)) + + +/* + * Circular queue definitions. + */ +#define CIRCLEQ_HEAD(name, type) \ +struct name { \ + struct type *cqh_first; /* first element */ \ + struct type *cqh_last; /* last element */ \ +} + +#define CIRCLEQ_HEAD_INITIALIZER(head) \ + { (void *)&head, (void *)&head } + +#define CIRCLEQ_ENTRY(type) \ +struct { \ + struct type *cqe_next; /* next element */ \ + struct type *cqe_prev; /* previous element */ \ +} + +/* + * Circular queue functions. + */ +#define CIRCLEQ_INIT(head) do { \ + (head)->cqh_first = (void *)(head); \ + (head)->cqh_last = (void *)(head); \ +} while (0) + +#define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do { \ + (elm)->field.cqe_next = (listelm)->field.cqe_next; \ + (elm)->field.cqe_prev = (listelm); \ + if ((listelm)->field.cqe_next == (void *)(head)) \ + (head)->cqh_last = (elm); \ + else \ + (listelm)->field.cqe_next->field.cqe_prev = (elm); \ + (listelm)->field.cqe_next = (elm); \ +} while (0) + +#define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do { \ + (elm)->field.cqe_next = (listelm); \ + (elm)->field.cqe_prev = (listelm)->field.cqe_prev; \ + if ((listelm)->field.cqe_prev == (void *)(head)) \ + (head)->cqh_first = (elm); \ + else \ + (listelm)->field.cqe_prev->field.cqe_next = (elm); \ + (listelm)->field.cqe_prev = (elm); \ +} while (0) + +#define CIRCLEQ_INSERT_HEAD(head, elm, field) do { \ + (elm)->field.cqe_next = (head)->cqh_first; \ + (elm)->field.cqe_prev = (void *)(head); \ + if ((head)->cqh_last == (void *)(head)) \ + (head)->cqh_last = (elm); \ + else \ + (head)->cqh_first->field.cqe_prev = (elm); \ + (head)->cqh_first = (elm); \ +} while (0) + +#define CIRCLEQ_INSERT_TAIL(head, elm, field) do { \ + (elm)->field.cqe_next = (void *)(head); \ + (elm)->field.cqe_prev = (head)->cqh_last; \ + if ((head)->cqh_first == (void *)(head)) \ + (head)->cqh_first = (elm); \ + else \ + (head)->cqh_last->field.cqe_next = (elm); \ + (head)->cqh_last = (elm); \ +} while (0) + +#define CIRCLEQ_REMOVE(head, elm, field) do { \ + if ((elm)->field.cqe_next == (void *)(head)) \ + (head)->cqh_last = (elm)->field.cqe_prev; \ + else \ + (elm)->field.cqe_next->field.cqe_prev = \ + (elm)->field.cqe_prev; \ + if ((elm)->field.cqe_prev == (void *)(head)) \ + (head)->cqh_first = (elm)->field.cqe_next; \ + else \ + (elm)->field.cqe_prev->field.cqe_next = \ + (elm)->field.cqe_next; \ +} while (0) + +#define CIRCLEQ_FOREACH(var, head, field) \ + for ((var) = ((head)->cqh_first); \ + (var) != (const void *)(head); \ + (var) = ((var)->field.cqe_next)) + +#define CIRCLEQ_FOREACH_REVERSE(var, head, field) \ + for ((var) = ((head)->cqh_last); \ + (var) != (const void *)(head); \ + (var) = ((var)->field.cqe_prev)) + +/* + * Circular queue access methods. + */ +#define CIRCLEQ_EMPTY(head) ((head)->cqh_first == (void *)(head)) +#define CIRCLEQ_FIRST(head) ((head)->cqh_first) +#define CIRCLEQ_LAST(head) ((head)->cqh_last) +#define CIRCLEQ_NEXT(elm, field) ((elm)->field.cqe_next) +#define CIRCLEQ_PREV(elm, field) ((elm)->field.cqe_prev) + +#define CIRCLEQ_LOOP_NEXT(head, elm, field) \ + (((elm)->field.cqe_next == (void *)(head)) \ + ? ((head)->cqh_first) \ + : (elm->field.cqe_next)) +#define CIRCLEQ_LOOP_PREV(head, elm, field) \ + (((elm)->field.cqe_prev == (void *)(head)) \ + ? ((head)->cqh_last) \ + : (elm->field.cqe_prev)) + +#endif // _SYS_QUEUE_H_ diff --git a/lib/mlibc/options/bsd/meson.build b/lib/mlibc/options/bsd/meson.build new file mode 100644 index 0000000..3a7c911 --- /dev/null +++ b/lib/mlibc/options/bsd/meson.build @@ -0,0 +1,32 @@ +if disable_bsd_option + subdir_done() +endif + +libc_sources += files( + 'generic/arpa-nameser-stubs.cpp', + 'generic/ether.cpp', + 'generic/getopt.cpp', +) + +if not no_headers + install_headers( + 'include/fstab.h', + ) + install_headers( + 'include/arpa/nameser.h', + 'include/arpa/nameser_compat.h', + subdir: 'arpa' + ) + install_headers( + 'include/sys/queue.h', + subdir: 'sys' + ) + install_headers( + 'include/netinet/ether.h', + subdir: 'netinet' + ) + install_headers( + 'include/bits/bsd/bsd_unistd.h', + subdir: 'bits/bsd' + ) +endif diff --git a/lib/mlibc/options/crypt/generic/crypt-stubs.cpp b/lib/mlibc/options/crypt/generic/crypt-stubs.cpp new file mode 100644 index 0000000..65e0d23 --- /dev/null +++ b/lib/mlibc/options/crypt/generic/crypt-stubs.cpp @@ -0,0 +1,7 @@ +#include +#include + +char *crypt(const char *, const char *) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} diff --git a/lib/mlibc/options/crypt/include/crypt.h b/lib/mlibc/options/crypt/include/crypt.h new file mode 100644 index 0000000..bf3a512 --- /dev/null +++ b/lib/mlibc/options/crypt/include/crypt.h @@ -0,0 +1,18 @@ +#ifndef _CRYPT_H +#define _CRYPT_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +char *crypt(const char *, const char *); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif // _CRYPT_H diff --git a/lib/mlibc/options/crypt/meson.build b/lib/mlibc/options/crypt/meson.build new file mode 100644 index 0000000..a476f34 --- /dev/null +++ b/lib/mlibc/options/crypt/meson.build @@ -0,0 +1,13 @@ +if disable_crypt_option + subdir_done() +endif + +libc_sources += files( + 'generic/crypt-stubs.cpp', +) + +if not no_headers + install_headers( + 'include/crypt.h', + ) +endif diff --git a/lib/mlibc/options/elf/generic/phdr.cpp b/lib/mlibc/options/elf/generic/phdr.cpp new file mode 100644 index 0000000..334d52c --- /dev/null +++ b/lib/mlibc/options/elf/generic/phdr.cpp @@ -0,0 +1,10 @@ +#include + +#include +#include + +extern "C" int __dlapi_iterate_phdr(int (*)(struct dl_phdr_info*, size_t, void*), void *); + +int dl_iterate_phdr(int (*callback)(struct dl_phdr_info*, size_t, void*), void *data) { + return __dlapi_iterate_phdr(callback, data); +} diff --git a/lib/mlibc/options/elf/generic/startup.cpp b/lib/mlibc/options/elf/generic/startup.cpp new file mode 100644 index 0000000..d53881b --- /dev/null +++ b/lib/mlibc/options/elf/generic/startup.cpp @@ -0,0 +1,73 @@ + +#include +#include +#include +#include +#include +#include +#include + +extern "C" size_t __init_array_start[]; +extern "C" size_t __init_array_end[]; +extern "C" size_t __preinit_array_start[]; +extern "C" size_t __preinit_array_end[]; + +static int constructors_ran_already = 0; + +struct global_constructor_guard { + global_constructor_guard() { + constructors_ran_already = 1; + } +}; + +static global_constructor_guard g; + +void __mlibc_run_constructors() { +/* + if (!constructors_ran_already) { + size_t constructor_count = (size_t)__init_array_end - (size_t)__init_array_start; + constructor_count /= sizeof(void*); + for (size_t i = 0; i < constructor_count; i++) { + void (*ptr)(void) = (void(*)(void))(__init_array_start[i]); + ptr(); + } + } +*/ +} + +namespace mlibc { + +void parse_exec_stack(void *opaque_sp, exec_stack_data *data) { + auto sp = reinterpret_cast(opaque_sp); + data->argc = *sp++; + data->argv = reinterpret_cast(sp); + sp += data->argc; // Skip all arguments. + __ensure(!*sp); // Skip the terminating null element. + sp++; + data->envp = reinterpret_cast(sp); +} + +// TODO: This does not have to be here; we could also move it to options/internal. +void set_startup_data(int argc, char **argv, char **envp) { + if(argc) { + program_invocation_name = argv[0]; + + if(auto slash = strrchr(argv[0], '/'); slash) { + program_invocation_short_name = slash + 1; + }else{ + program_invocation_short_name = argv[0]; + } + } + + // Initialize environ. + // TODO: Copy the arguments instead of pointing to them? + auto ev = envp; + while(*ev) { + auto fail = mlibc::putenv(*ev); + __ensure(!fail); + ev++; + } +} + +} // namespace mlibc + diff --git a/lib/mlibc/options/elf/include/elf.h b/lib/mlibc/options/elf/include/elf.h new file mode 100644 index 0000000..68d70c2 --- /dev/null +++ b/lib/mlibc/options/elf/include/elf.h @@ -0,0 +1,667 @@ +#ifndef _ELF_H +#define _ELF_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +// TODO: Convert the enums to #defines so that they work with #ifdef. + +#define ELFCLASS64 2 +#define ELFDATA2LSB 1 +#define ELFOSABI_SYSV 0 +#define EM_X86_64 62 + +#define SHF_WRITE 1 +#define SHF_ALLOC 2 +#define SHF_EXECINSTR 4 +#define SHF_STRINGS 32 +#define SHF_INFO_LINK 64 +#define SHF_TLS 1024 + +#define NT_AUXV 6 + +typedef uint64_t Elf64_Addr; +typedef uint64_t Elf64_Off; +typedef uint16_t Elf64_Half; +typedef uint32_t Elf64_Word; +typedef int32_t Elf64_Sword; +typedef uint64_t Elf64_Xword; +typedef int64_t Elf64_Sxword; +typedef uint16_t Elf64_Section; +typedef Elf64_Half Elf64_Versym; + +typedef uint32_t Elf32_Addr; +typedef uint32_t Elf32_Off; +typedef uint16_t Elf32_Half; +typedef uint32_t Elf32_Word; +typedef int32_t Elf32_Sword; +typedef uint64_t Elf32_Xword; +typedef int64_t Elf32_Sxword; +typedef uint16_t Elf32_Section; +typedef Elf32_Half Elf32_Versym; + +#define EI_NIDENT (16) + +typedef struct { + unsigned char e_ident[EI_NIDENT]; /* ELF identification */ + Elf32_Half e_type; /* Object file type */ + Elf32_Half e_machine; /* Machine type */ + Elf32_Word e_version; /* Object file version */ + Elf32_Addr e_entry; /* Entry point address */ + Elf32_Off e_phoff; /* Program header offset */ + Elf32_Off e_shoff; /* Section header offset */ + Elf32_Word e_flags; /* Processor-specific flags */ + Elf32_Half e_ehsize; /* ELF header size */ + Elf32_Half e_phentsize; /* Size of program header entry */ + Elf32_Half e_phnum; /* Number of program header entries */ + Elf32_Half e_shentsize; /* Size of section header entry */ + Elf32_Half e_shnum; /* Number of section header entries */ + Elf32_Half e_shstrndx; /* Section name string table index */ +} Elf32_Ehdr; + +typedef struct { + unsigned char e_ident[EI_NIDENT]; /* ELF identification */ + Elf64_Half e_type; /* Object file type */ + Elf64_Half e_machine; /* Machine type */ + Elf64_Word e_version; /* Object file version */ + Elf64_Addr e_entry; /* Entry point address */ + Elf64_Off e_phoff; /* Program header offset */ + Elf64_Off e_shoff; /* Section header offset */ + Elf64_Word e_flags; /* Processor-specific flags */ + Elf64_Half e_ehsize; /* ELF header size */ + Elf64_Half e_phentsize; /* Size of program header entry */ + Elf64_Half e_phnum; /* Number of program header entries */ + Elf64_Half e_shentsize; /* Size of section header entry */ + Elf64_Half e_shnum; /* Number of section header entries */ + Elf64_Half e_shstrndx; /* Section name string table index */ +} Elf64_Ehdr; + +typedef struct { + Elf32_Half vd_version; /* Version revision */ + Elf32_Half vd_flags; /* Version information */ + Elf32_Half vd_ndx; /* Version Index */ + Elf32_Half vd_cnt; /* Number of associated aux entries */ + Elf32_Word vd_hash; /* Version name hash value */ + Elf32_Word vd_aux; /* Offset in bytes to verdaux array */ + Elf32_Word vd_next; /* Offset in bytes to next verdef entry */ +} Elf32_Verdef; + +typedef struct { + Elf64_Half vd_version; /* Version revision */ + Elf64_Half vd_flags; /* Version information */ + Elf64_Half vd_ndx; /* Version Index */ + Elf64_Half vd_cnt; /* Number of associated aux entries */ + Elf64_Word vd_hash; /* Version name hash value */ + Elf64_Word vd_aux; /* Offset in bytes to verdaux array */ + Elf64_Word vd_next; /* Offset in bytes to next verdef entry */ +} Elf64_Verdef; + +typedef struct { + Elf32_Word vda_name; /* Version or dependency names */ + Elf32_Word vda_next; /* Offset in bytes to next verdaux entry */ +} Elf32_Verdaux; + +typedef struct { + Elf64_Word vda_name; /* Version or dependency names */ + Elf64_Word vda_next; /* Offset in bytes to next verdaux entry */ +} Elf64_Verdaux; + +typedef struct { + Elf64_Half vn_version; + Elf64_Half vn_cnt; + Elf64_Word vn_file; + Elf64_Word vn_aux; + Elf64_Word vn_next; +} Elf64_Verneed; + +typedef struct { + Elf64_Word vna_hash; + Elf64_Half vna_flags; + Elf64_Half vna_other; + Elf64_Word vna_name; + Elf64_Word vna_next; +} Elf64_Vernaux; + +typedef struct { + Elf64_Xword m_value; + Elf64_Xword m_info; + Elf64_Xword m_poffset; + Elf64_Half m_repeat; + Elf64_Half m_stride; +} Elf64_Move; + +typedef struct { + Elf64_Word l_name; + Elf64_Word l_time_stamp; + Elf64_Word l_checksum; + Elf64_Word l_version; + Elf64_Word l_flags; +} Elf64_Lib; + +enum { + ET_NONE = 0, + ET_REL = 1, + ET_EXEC = 2, + ET_DYN = 3, + ET_CORE = 4, +}; + +enum { + SHN_UNDEF = 0, + SHN_ABS = 0xFFF1 +}; + +enum { + STN_UNDEF = 0, +}; + +typedef struct { + Elf32_Word st_name; + Elf32_Addr st_value; + Elf32_Word st_size; + unsigned char st_info; + unsigned char st_other; + Elf32_Section st_shndx; +} Elf32_Sym; + +typedef struct { + Elf64_Word st_name; + unsigned char st_info; + unsigned char st_other; + Elf64_Half st_shndx; + Elf64_Addr st_value; + Elf64_Xword st_size; +} Elf64_Sym; + +__MLIBC_INLINE_DEFINITION unsigned char ELF64_ST_BIND(unsigned char info) { + return info >> 4; +} +__MLIBC_INLINE_DEFINITION unsigned char ELF64_ST_TYPE(unsigned char info) { + return info & 0x0F; +} +__MLIBC_INLINE_DEFINITION unsigned char ELF64_ST_INFO(unsigned char bind, unsigned char type) { + return (bind << 4) | type; +} + +typedef struct { + Elf64_Half si_boundto; + Elf64_Half si_flags; +} Elf64_Syminfo; + +__MLIBC_INLINE_DEFINITION unsigned char ELF32_ST_BIND(unsigned char info) { + return info >> 4; +} +__MLIBC_INLINE_DEFINITION unsigned char ELF32_ST_TYPE(unsigned char info) { + return info & 0xF; +} +__MLIBC_INLINE_DEFINITION unsigned char ELF32_ST_INFO(unsigned char bind, unsigned char type) { + return (bind << 4) | (type & 0xF); +} + +enum { + STB_GLOBAL = 1, + STB_WEAK = 2, + STB_GNU_UNIQUE = 10, + STB_LOPROC = 13, + STB_HIPROC = 15 +}; + +enum { + STT_OBJECT = 1, + STT_FUNC = 2, + STT_TLS = 6, + STT_LOPROC = 13, + STT_HIPROC = 15 +}; + +enum { + R_X86_64_NONE = 0, + R_X86_64_64 = 1, + R_X86_64_PC32 = 2, + R_X86_64_PLT32 = 4, + R_X86_64_COPY = 5, + R_X86_64_GLOB_DAT = 6, + R_X86_64_JUMP_SLOT = 7, + R_X86_64_RELATIVE = 8, + R_X86_64_GOTPCREL = 9, + R_X86_64_32 = 10, + R_X86_64_32S = 11, + R_X86_64_PC16 = 13, + R_X86_64_PC8 = 15, + R_X86_64_DTPMOD64 = 16, + R_X86_64_DTPOFF64 = 17, + R_X86_64_TPOFF64 = 18, + R_X86_64_PC64 = 24, + R_X86_64_GOTPC32 = 26, + R_X86_64_TLSDESC = 36, + R_X86_64_IRELATIVE = 37, +}; + +enum { + R_386_NONE = 0, + R_386_32 = 1, + R_386_PC32 = 2, + R_386_COPY = 5, + R_386_GLOB_DAT = 6, + R_386_JMP_SLOT = 7, + R_386_RELATIVE = 8, + R_386_TLS_TPOFF = 14, + R_386_TLS_DTPMOD32 = 35, + R_386_TLS_DTPOFF32 = 36, + R_386_TLS_DESC = 41, + R_386_IRELATIVE = 42, +}; + +enum { + R_AARCH64_NONE = 0, + R_AARCH64_ABS64 = 257, + R_AARCH64_COPY = 1024, + R_AARCH64_GLOB_DAT = 1025, + R_AARCH64_JUMP_SLOT = 1026, + R_AARCH64_RELATIVE = 1027, + R_AARCH64_TLS_DTPREL64 = 1028, + R_AARCH64_TLS_DTPMOD64 = 1029, + R_AARCH64_TLS_TPREL64 = 1030, + R_AARCH64_TLSDESC = 1031, + R_AARCH64_IRELATIVE = 1032, +}; + +#define R_AARCH64_TLS_DTPREL R_AARCH64_TLS_DTPREL64 +#define R_AARCH64_TLS_DTPMOD R_AARCH64_TLS_DTPMOD64 +#define R_AARCH64_TLS_TPREL R_AARCH64_TLS_TPREL64 + +enum { + R_RISCV_NONE = 0, + R_RISCV_32 = 1, + R_RISCV_64 = 2, + R_RISCV_RELATIVE = 3, + R_RISCV_COPY = 4, + R_RISCV_JUMP_SLOT = 5, + R_RISCV_TLS_DTPMOD32 = 6, + R_RISCV_TLS_DTPMOD64 = 7, + R_RISCV_TLS_DTPREL32 = 8, + R_RISCV_TLS_DTPREL64 = 9, + R_RISCV_TLS_TPREL32 = 10, + R_RISCV_TLS_TPREL64 = 11, + R_RISCV_TLSDESC = 12, // currently a draft but looking good + R_RISCV_IRELATIVE = 58 +}; + +typedef struct { + Elf32_Addr r_offset; + Elf32_Word r_info; +} Elf32_Rel; + +typedef struct { + Elf64_Addr r_offset; + uint64_t r_info; +} Elf64_Rel; + +typedef struct { + Elf32_Addr r_offset; + Elf32_Word r_info; + Elf32_Sword r_addend; +} Elf32_Rela; + +typedef struct { + Elf64_Addr r_offset; + Elf64_Xword r_info; + Elf64_Sxword r_addend; +} Elf64_Rela; + +typedef Elf32_Word Elf32_Relr; +typedef Elf64_Xword Elf64_Relr; + +__MLIBC_INLINE_DEFINITION Elf64_Xword ELF64_R_SYM(Elf64_Xword info) { + return info >> 32; +} +__MLIBC_INLINE_DEFINITION Elf64_Xword ELF64_R_TYPE(Elf64_Xword info) { + return info & 0xFFFFFFFF; +} +__MLIBC_INLINE_DEFINITION Elf64_Xword ELF64_R_INFO(Elf64_Xword sym, Elf64_Xword type) { + return ((((Elf64_Xword)(sym)) << 32) + (type)); +} + +__MLIBC_INLINE_DEFINITION Elf32_Word ELF32_R_SYM(Elf32_Word info) { + return info >> 8; +} +__MLIBC_INLINE_DEFINITION Elf32_Word ELF32_R_TYPE(Elf32_Word info) { + return info & 0xFF; +} + +enum { + PT_NULL = 0, + PT_LOAD = 1, + PT_DYNAMIC = 2, + PT_INTERP = 3, + PT_NOTE = 4, + PT_SHLIB = 5, + PT_PHDR = 6, + PT_TLS = 7, + PT_NUM = 8, + PT_LOOS = 0x60000000, + PT_GNU_EH_FRAME = 0x6474E550, + PT_GNU_STACK = 0x6474E551, + PT_GNU_RELRO = 0x6474E552, + PT_GNU_PROPERTY = 0x6474E553, + PT_SUNWBSS = 0x6ffffffa, + PT_SUNWSTACK = 0x6ffffffb, + PT_HISUNW = 0x6fffffff, + PT_HIOS = 0x6fffffff, + PT_LOPROC = 0x70000000, + PT_RISCV_ATTRIBUTES = 0x70000003, + PT_HIPROC = 0x7fffffff, +}; + +enum { + PF_X = 1, + PF_W = 2, + PF_R = 4 +}; + +typedef struct { + Elf32_Word p_type; /* Type of segment */ + Elf32_Off p_offset; /* Offset in file */ + Elf32_Addr p_vaddr; /* Virtual address in memory */ + Elf32_Addr p_paddr; /* Reserved */ + Elf32_Word p_filesz; /* Size of segment in file */ + Elf32_Word p_memsz; /* Size of segment in memory */ + Elf32_Word p_flags; /* Segment attributes */ + Elf32_Word p_align; /* Alignment of segment */ +} Elf32_Phdr; + +typedef struct { + Elf64_Word p_type; /* Type of segment */ + Elf64_Word p_flags; /* Segment attributes */ + Elf64_Off p_offset; /* Offset in file */ + Elf64_Addr p_vaddr; /* Virtual address in memory */ + Elf64_Addr p_paddr; /* Reserved */ + Elf64_Xword p_filesz; /* Size of segment in file */ + Elf64_Xword p_memsz; /* Size of segment in memory */ + Elf64_Xword p_align; /* Alignment of segment */ +} Elf64_Phdr; + +enum { + DT_NULL = 0, + DT_NEEDED = 1, + DT_PLTRELSZ = 2, + DT_PLTGOT = 3, + DT_HASH = 4, + DT_STRTAB = 5, + DT_SYMTAB = 6, + DT_RELA = 7, + DT_RELASZ = 8, + DT_RELAENT = 9, + DT_STRSZ = 10, + DT_SYMENT = 11, + DT_INIT = 12, + DT_FINI = 13, + DT_SONAME = 14, + DT_RPATH = 15, + DT_SYMBOLIC = 16, + DT_REL = 17, + DT_RELSZ = 18, + DT_RELENT = 19, + DT_TEXTREL = 22, + DT_BIND_NOW = 24, + DT_INIT_ARRAY = 25, + DT_FINI_ARRAY = 26, + DT_INIT_ARRAYSZ = 27, + DT_FINI_ARRAYSZ = 28, + DT_RUNPATH = 29, + DT_PLTREL = 20, + DT_DEBUG = 21, + DT_JMPREL = 23, + DT_FLAGS = 30, + DT_PREINIT_ARRAY = 32, + DT_PREINIT_ARRAYSZ = 33, + DT_RELRSZ = 35, + DT_RELR = 36, + DT_RELRENT = 37, + DT_LOOS = 0x6000000d, + DT_HIOS = 0x6ffff000, + DT_GNU_HASH = 0x6ffffef5, + DT_TLSDESC_PLT = 0x6ffffef6, + DT_TLSDESC_GOT = 0x6ffffef7, + DT_VERSYM = 0x6ffffff0, + DT_RELACOUNT = 0x6ffffff9, + DT_RELCOUNT = 0x6ffffffa, + DT_FLAGS_1 = 0x6ffffffb, + DT_VERDEF = 0x6ffffffc, + DT_VERDEFNUM = 0x6ffffffd, + DT_VERNEED = 0x6ffffffe, + DT_VERNEEDNUM = 0x6fffffff +}; + +enum { + // For DT_FLAGS. + DF_SYMBOLIC = 0x02, + DF_TEXTREL = 0x04, + DF_BIND_NOW = 0x08, + DF_STATIC_TLS = 0x10, + + // For DT_FLAGS_1. + DF_1_NOW = 0x00000001, + DF_1_NODELETE = 0x00000008, + DF_1_PIE = 0x08000000 +}; + +// Valid values for note segment descriptor files for core files +#define NT_PRSTATUS 1 +#define NT_FPREGSET 2 +#define NT_PRPSINFO 3 + +// Build ID bits as generated by ld --build-id +#define NT_GNU_BUILD_ID 3 + +typedef struct { + Elf32_Sword d_tag; + union { + Elf32_Word d_val; + Elf32_Addr d_ptr; + } d_un; +} Elf32_Dyn; + +typedef struct { + Elf64_Sxword d_tag; + union { + Elf64_Xword d_val; + Elf64_Addr d_ptr; + } d_un; +} Elf64_Dyn; + +typedef struct { + Elf32_Word sh_name; + Elf32_Word sh_type; + Elf32_Word sh_flags; + Elf32_Addr sh_addr; + Elf32_Off sh_offset; + Elf32_Word sh_size; + Elf32_Word sh_link; + Elf32_Word sh_info; + Elf32_Word sh_addralign; + Elf32_Word sh_entsize; +} Elf32_Shdr; + +typedef struct { + Elf64_Word sh_name; + Elf64_Word sh_type; + Elf64_Xword sh_flags; + Elf64_Addr sh_addr; + Elf64_Off sh_offset; + Elf64_Xword sh_size; + Elf64_Word sh_link; + Elf64_Word sh_info; + Elf64_Xword sh_addralign; + Elf64_Xword sh_entsize; +} Elf64_Shdr; + +typedef struct { + uint64_t a_type; + union { + uint64_t a_val; + } a_un; +} Elf64_auxv_t; + +typedef struct { + uint32_t a_type; + union { + uint32_t a_val; + } a_un; +} Elf32_auxv_t; + +typedef struct { + Elf32_Word n_namesz; + Elf32_Word n_descsz; + Elf32_Word n_type; +} Elf32_Nhdr; + +typedef struct { + Elf64_Word n_namesz; + Elf64_Word n_descsz; + Elf64_Word n_type; +} Elf64_Nhdr; + +/* ST_TYPE (subfield of st_info) values (symbol type) */ +#define STT_NOTYPE 0 +#define STT_OBJECT 1 +#define STT_FUNC 2 +#define STT_SECTION 3 +#define STT_FILE 4 + +/* ST_BIND (subfield of st_info) values (symbol binding) */ +#define STB_LOCAL 0 +#define STB_GLOBAL 1 +#define STB_WEAK 2 + +/* sh_type (section type) values */ +#define SHT_NULL 0 +#define SHT_PROGBITS 1 +#define SHT_SYMTAB 2 +#define SHT_STRTAB 3 +#define SHT_RELA 4 +#define SHT_HASH 5 +#define SHT_DYNAMIC 6 +#define SHT_NOTE 7 +#define SHT_NOBITS 8 +#define SHT_REL 9 +#define SHT_DYNSYM 11 +#define SHT_INIT_ARRAY 14 +#define SHT_FINI_ARRAY 15 +#define SHT_SYMTAB_SHNDX 18 + +/* special section indices */ +#define SHN_UNDEF 0 +#define SHN_LORESERVE 0xff00 +#define SHN_COMMON 0xfff2 +#define SHN_XINDEX 0xffff +#define SHN_HIRESERVE 0xff00 + +/* values for e_machine */ +#define EM_NONE 0 +#define EM_M32 1 +#define EM_SPARC 2 +#define EM_386 3 +#define EM_68K 4 +#define EM_MIPS 8 +#define EM_PARISC 15 +#define EM_PPC 20 +#define EM_PPC64 21 +#define EM_S390 22 +#define EM_ARM 40 +#define EM_SH 42 +#define EM_SPARCV9 43 +#define EM_IA_64 50 +#define EM_X86_64 62 +#define EM_BLACKFIN 106 +#define EM_AARCH64 183 +#define EM_RISCV 243 + +/* Linux notes this value as being interim; however applications are using this (Qt6), so we define it here. */ +#define EM_ALPHA 0x9026 + +/* values for e_version */ +#define EV_NONE 0 +#define EV_CURRENT 1 +#define EV_NUM 2 + +/* e_indent constants */ +#define EI_MAG0 0 +#define ELFMAG0 0x7f + +#define EI_MAG1 1 +#define ELFMAG1 'E' + +#define EI_MAG2 2 +#define ELFMAG2 'L' + +#define EI_MAG3 3 +#define ELFMAG3 'F' + +#define ELFMAG "\177ELF" +#define SELFMAG 4 + +#define EI_CLASS 4 +#define ELFCLASSNONE 0 +#define ELFCLASS32 1 +#define ELFCLASS64 2 +#define ELFCLASSNUM 3 + +#define EI_DATA 5 +#define ELFDATANONE 0 +#define ELFDATA2LSB 1 +#define ELFDATA2MSB 2 +#define ELFDATANUM 3 + +#define EI_VERSION 6 + +#define EI_OSABI 7 +#define ELFOSABI_HPUX 1 +#define ELFOSABI_NETBSD 2 +#define ELFOSABI_GNU 3 +#define ELFOSABI_LINUX ELFOSABI_GNU +#define ELFOSABI_SOLARIS 6 +#define ELFOSABI_AIX 7 +#define ELFOSABI_IRIX 8 +#define ELFOSABI_FREEBSD 9 +#define ELFOSABI_OPENBSD 12 + +#define EI_ABIVERSION 8 + +#define ELF_NOTE_GNU "GNU" + +/* Values for a_type + * these are standard values and shared across at least glibc, musl and freebsd + */ + +#define AT_NULL 0 +#define AT_IGNORE 1 +#define AT_EXECFD 2 +#define AT_PHDR 3 +#define AT_PHENT 4 +#define AT_PHNUM 5 +#define AT_PAGESZ 6 +#define AT_BASE 7 +#define AT_FLAGS 8 +#define AT_ENTRY 9 +#define AT_NOTELF 10 +#define AT_UID 11 +#define AT_EUID 12 +#define AT_GID 13 +#define AT_EGID 14 + +/* rtdl requires presence of some a_type (AT_*) values that are not standardized in the ELF spec */ +#if !defined(AT_EXECFN) || !defined(AT_RANDOM) || !defined(AT_SECURE) +#error "sysdeps' auxv.h is missing some defines that are required for rtdl operation" +#endif + +#ifdef __cplusplus +} +#endif + +#endif // _ELF_H diff --git a/lib/mlibc/options/elf/include/link.h b/lib/mlibc/options/elf/include/link.h new file mode 100644 index 0000000..65d54b9 --- /dev/null +++ b/lib/mlibc/options/elf/include/link.h @@ -0,0 +1,58 @@ +#ifndef _LINK_H +#define _LINK_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +#if defined(__x86_64__) || defined(__aarch64__) \ + || (defined(__riscv) && __riscv_xlen == 64) +# define ElfW(type) Elf64_ ## type +#elif defined(__i386__) +# define ElfW(type) Elf32_ ## type +#else +# error Unknown architecture +#endif + +struct dl_phdr_info { + ElfW(Addr) dlpi_addr; + const char *dlpi_name; + const ElfW(Phdr) *dlpi_phdr; + ElfW(Half) dlpi_phnum; + unsigned long long int dlpi_adds; + unsigned long long int dlpi_subs; + size_t dlpi_tls_modid; + void *dlpi_tls_data; +}; + +struct link_map { + Elf64_Addr l_addr; + char *l_name; + ElfW(Dyn) *l_ld; + struct link_map *l_next, *l_prev; +}; + +struct r_debug { + int r_version; + struct link_map *r_map; + Elf64_Addr r_brk; + enum { RT_CONSISTENT, RT_ADD, RT_DELETE } r_state; + Elf64_Addr r_ldbase; +}; + +#ifndef __MLIBC_ABI_ONLY + +int dl_iterate_phdr(int (*callback)(struct dl_phdr_info*, size_t, void*), void* data); + +extern ElfW(Dyn) _DYNAMIC[]; + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif // _LINK_H diff --git a/lib/mlibc/options/elf/include/mlibc/elf/startup.h b/lib/mlibc/options/elf/include/mlibc/elf/startup.h new file mode 100644 index 0000000..7e8a8d7 --- /dev/null +++ b/lib/mlibc/options/elf/include/mlibc/elf/startup.h @@ -0,0 +1,28 @@ +#ifndef MLIBC_ELF_STARTUP +#define MLIBC_ELF_STARTUP + +#ifndef __MLIBC_ABI_ONLY + +void __mlibc_run_constructors(); + +#endif /* !__MLIBC_ABI_ONLY */ + +namespace mlibc { + +struct exec_stack_data { + int argc; + char **argv; + char **envp; +}; + +#ifndef __MLIBC_ABI_ONLY + +void parse_exec_stack(void *sp, exec_stack_data *data); + +void set_startup_data(int argc, char **argv, char **envp); + +#endif /* !__MLIBC_ABI_ONLY */ + +} // namespace mlibc + +#endif // MLIBC_ELF_STARTUP diff --git a/lib/mlibc/options/elf/meson.build b/lib/mlibc/options/elf/meson.build new file mode 100644 index 0000000..b096801 --- /dev/null +++ b/lib/mlibc/options/elf/meson.build @@ -0,0 +1,11 @@ +libc_sources += files( + 'generic/startup.cpp', + 'generic/phdr.cpp', +) + +if not no_headers + install_headers( + 'include/elf.h', + 'include/link.h', + ) +endif diff --git a/lib/mlibc/options/glibc/generic/err.cpp b/lib/mlibc/options/glibc/generic/err.cpp new file mode 100644 index 0000000..042c1d8 --- /dev/null +++ b/lib/mlibc/options/glibc/generic/err.cpp @@ -0,0 +1,64 @@ +#include + +#include +#include +#include + +// va_list + +void vwarn(const char *fmt, va_list params) { + fprintf(stderr, "%s: ", program_invocation_short_name); + if (fmt) { + vfprintf(stderr, fmt, params); + fwrite(": ", 1, 2, stderr); + } + perror(NULL); +} + +void vwarnx(const char *fmt, va_list params) { + fprintf(stderr, "%s: ", program_invocation_short_name); + if (fmt) { + vfprintf(stderr, fmt, params); + } + putc('\n', stderr); +} + +__attribute__((__noreturn__)) void verr(int status, const char *fmt, va_list params) { + vwarn(fmt, params); + exit(status); +} + +__attribute__((__noreturn__)) void verrx(int status, const char *fmt, va_list params) { + vwarnx(fmt, params); + exit(status); +} + +// variadic + +void warn(const char *fmt, ...) { + va_list params; + va_start(params, fmt); + vwarn(fmt, params); + va_end(params); +} + +void warnx(const char *fmt, ...) { + va_list params; + va_start(params, fmt); + vwarnx(fmt, params); + va_end(params); +} + +__attribute__((__noreturn__)) void err(int status, const char *fmt, ...) { + va_list params; + va_start(params, fmt); + verr(status, fmt, params); + va_end(params); +} + +__attribute__((__noreturn__)) void errx(int status, const char *fmt, ...) { + va_list params; + va_start(params, fmt); + verrx(status, fmt, params); + va_end(params); +} diff --git a/lib/mlibc/options/glibc/generic/error.cpp b/lib/mlibc/options/glibc/generic/error.cpp new file mode 100644 index 0000000..45203b2 --- /dev/null +++ b/lib/mlibc/options/glibc/generic/error.cpp @@ -0,0 +1,65 @@ +#include +#include +#include +#include +#include +#include + +unsigned int error_message_count = 0; +int error_one_per_line = 0; +void (*error_print_progname)(void) = NULL; + +void error(int status, int errnum, const char *format, ...) { + va_list args; + va_start(args, format); + + error_message_count++; + + fflush(stdout); + if(error_print_progname) { + error_print_progname(); + } else { + fprintf(stderr, "%s: ", program_invocation_name); + } + vfprintf(stderr, format, args); + va_end(args); + + if(errnum) { + fprintf(stderr, ": %s\n", strerror(errnum)); + } + + if(status) { + exit(status); + } +} + +void error_at_line(int status, int errnum, const char *filename, unsigned int linenum, const char *format, ...) { + va_list args; + va_start(args, format); + + static bool first_call = true; + static unsigned int last_line = 0; + if(!(last_line == linenum && error_one_per_line && !first_call)) { + first_call = false; + last_line = linenum; + error_message_count++; + + fflush(stdout); + if(error_print_progname) { + error_print_progname(); + } else { + fprintf(stderr, "%s:", program_invocation_name); + } + fprintf(stderr, "%s:%u: ", filename, linenum); + vfprintf(stderr, format, args); + + if(errnum) { + fprintf(stderr, ": %s\n", strerror(errnum)); + } + } + va_end(args); + + if(status) { + exit(status); + } +} diff --git a/lib/mlibc/options/glibc/generic/execinfo.cpp b/lib/mlibc/options/glibc/generic/execinfo.cpp new file mode 100644 index 0000000..3474615 --- /dev/null +++ b/lib/mlibc/options/glibc/generic/execinfo.cpp @@ -0,0 +1,17 @@ +#include +#include + +int backtrace(void **, int) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +char **backtrace_symbols(void *const *, int) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +void backtrace_symbols_fd(void *const *, int, int) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} diff --git a/lib/mlibc/options/glibc/generic/getopt-stubs.cpp b/lib/mlibc/options/glibc/generic/getopt-stubs.cpp new file mode 100644 index 0000000..d13d4eb --- /dev/null +++ b/lib/mlibc/options/glibc/generic/getopt-stubs.cpp @@ -0,0 +1,253 @@ +#include +#include +#include +#include +#include +#include + +#include +#include + +char *optarg; +int optind = 1; +int opterr = 1; +int optopt; + +namespace { + +int __optpos = 1; + +enum GetoptMode { + Short, + Long, + LongOnly, +}; + +int getopt_common(int argc, char * const argv[], const char *optstring, const struct option *longopts, int *longindex, enum GetoptMode mode) { + auto longopt_consume = [&](const char *arg, char *s, int k, bool colon) -> frg::optional { + // Consume the option and its argument. + if(longopts[k].has_arg == required_argument) { + if(s) { + // Consume the long option and its argument. + optarg = s + 1; + optind++; + }else if(argv[optind + 1]) { + // Consume the long option. + optind++; + + // Consume the option's argument. + optarg = argv[optind]; + optind++; + }else{ + /* If an error was detected, and the first character of optstring is not a colon, + and the external variable opterr is nonzero (which is the default), + getopt() prints an error message. */ + if(!colon && opterr) + fprintf(stderr, "--%s requires an argument.\n", arg); + /* If the first character of optstring is a colon (':'), then getopt() + returns ':' instead of '?' to indicate a missing option argument. */ + return colon ? ':' : '?'; + } + }else if(longopts[k].has_arg == optional_argument) { + if(s) { + // Consume the long option and its argument. + optarg = s + 1; + optind++; + }else{ + // Consume the long option. + optarg = nullptr; + optind++; + } + }else{ + __ensure(longopts[k].has_arg == no_argument); + + // Consume the long option. + optind++; + } + + return frg::null_opt; + }; + + bool colon = optstring[0] == ':'; + bool stop_at_first_nonarg = (optstring[0] == '+' || getenv("POSIXLY_CORRECT")); + + // glibc extension: Setting optind to zero causes a full reset. + // TODO: Should we really reset opterr and the other flags? + if(!optind +#if __MLIBC_BSD_OPTION + || optreset +#endif //__MLIBC_BSD_OPTION + ) { + optarg = nullptr; + optind = 1; + opterr = 1; + optopt = 0; + __optpos = 1; +#if __MLIBC_BSD_OPTION + optreset = 0; +#endif //__MLIBC_BSD_OPTION + } + + auto isOptionArg = [](char *arg){ + // If the first character of arg '-', and the arg is not exactly + // equal to "-" or "--", then the arg is an option argument. + return arg[0] == '-' && strcmp(arg, "-") && strcmp(arg, "--"); + }; + + while(optind < argc) { + char *arg = argv[optind]; + if(!isOptionArg(arg)) { + if(stop_at_first_nonarg) { + return -1; + } + + bool further_options = false; + int skip = optind; + + for(; skip < argc; ++skip) { + if(isOptionArg(argv[skip])) { + further_options = true; + break; + } + } + + if(further_options) { + optind += skip - optind; + continue; + } else { + optarg = nullptr; + return -1; + } + } + + if(arg[1] == '-') { + arg += 2; + + // Determine the end of the option name (vs. the start of the argument). + auto s = strchr(arg, '='); + size_t n = s ? (s - arg) : strlen(arg); + + int k = -1; + for(int i = 0; longopts[i].name; i++) { + if(strncmp(arg, longopts[i].name, n) || longopts[i].name[n]) + continue; + + if(k >= 0) { + if(opterr) + fprintf(stderr, "Multiple option declaration detected: %s\n", arg); + return '?'; + } + k = i; + } + + if(k == -1) { + if(opterr) + fprintf(stderr, "--%s is not a valid option.\n", arg); + return '?'; + } + + if(longindex) + *longindex = k; + + if(auto r = longopt_consume(arg, s, k, colon); r) + return r.value(); + + if(!longopts[k].flag) { + return longopts[k].val; + }else{ + *longopts[k].flag = longopts[k].val; + return 0; + } + }else{ + /* handle short options, i.e. options with only one dash prefixed; e.g. `program -s` */ + unsigned int i = __optpos; + while(true) { + if(mode == GetoptMode::LongOnly) { + const char *lo_arg = &arg[1]; + auto s = strchr(lo_arg, '='); + size_t n = s ? (s - lo_arg) : strlen(lo_arg); + int k = -1; + + for(int longopt = 0; longopts[longopt].name; longopt++) { + if(strncmp(lo_arg, longopts[longopt].name, n) || longopts[longopt].name[n]) + continue; + + if(k >= 0) { + if(opterr) + fprintf(stderr, "Multiple option declaration detected: %s\n", arg); + return '?'; + } + + k = longopt; + } + + if(k != -1) { + if(auto r = longopt_consume(lo_arg, s, k, colon); r) + return r.value(); + + if(!longopts[k].flag) { + return longopts[k].val; + }else{ + *longopts[k].flag = longopts[k].val; + return 0; + } + } + } + + auto opt = strchr(optstring, arg[i]); + if(opt) { + if(opt[1] == ':') { + bool required = (opt[2] != ':'); + + if(arg[i+1]) { + optarg = arg + i + 1; + } else if(optind + 1 < argc && argv[optind + 1] && (required || argv[optind + 1][0] != '-')) { + /* there is an argument to this short option, separated by a space */ + optarg = argv[optind + 1]; + optind++; + __optpos = 1; + } else if(!required) { + optarg = nullptr; + } else { + __optpos = 1; + optopt = arg[i]; + return colon ? ':' : '?'; + } + optind++; + } else { + if(arg[i+1]) { + __optpos++; + } else if(arg[i]) { + optind++; + } else { + return -1; + } + } + + return arg[i]; + } else { + /* If getopt() does not recognize an option character, it prints an error message to stderr, + stores the character in optopt, and returns '?'. The calling program may prevent + the error message by setting opterr to 0. */ + optopt = arg[1]; + if(opterr) + fprintf(stderr, "%s is not a valid option.\n", arg); + return '?'; + } + } + } + } + return -1; +} + +} + +int getopt_long(int argc, char * const argv[], const char *optstring, + const struct option *longopts, int *longindex) { + return getopt_common(argc, argv, optstring, longopts, longindex, GetoptMode::Long); +} + +int getopt_long_only(int argc, char * const argv[], const char *optstring, + const struct option *longopts, int *longindex) { + return getopt_common(argc, argv, optstring, longopts, longindex, GetoptMode::LongOnly); +} diff --git a/lib/mlibc/options/glibc/generic/glibc-assert.cpp b/lib/mlibc/options/glibc/generic/glibc-assert.cpp new file mode 100644 index 0000000..77cd498 --- /dev/null +++ b/lib/mlibc/options/glibc/generic/glibc-assert.cpp @@ -0,0 +1,14 @@ +#include +#include +#include +#include + +#include + +[[gnu::noreturn]] void __assert_fail_perror(int errno, const char *file, unsigned int line, + const char *function) { + char *errormsg = strerror(errno); + fprintf(stderr, "In function %s, file %s:%d: Errno '%s' failed!\n", + function, file, line, errormsg); + abort(); +} diff --git a/lib/mlibc/options/glibc/generic/glibc-signal.cpp b/lib/mlibc/options/glibc/generic/glibc-signal.cpp new file mode 100644 index 0000000..41bc455 --- /dev/null +++ b/lib/mlibc/options/glibc/generic/glibc-signal.cpp @@ -0,0 +1,14 @@ +#include +#include +#include +#include +#include + +int tgkill(int tgid, int tid, int sig) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_tgkill, -1); + if(int e = mlibc::sys_tgkill(tgid, tid, sig); e) { + errno = e; + return -1; + } + return 0; +} diff --git a/lib/mlibc/options/glibc/generic/gshadow.cpp b/lib/mlibc/options/glibc/generic/gshadow.cpp new file mode 100644 index 0000000..f93a47d --- /dev/null +++ b/lib/mlibc/options/glibc/generic/gshadow.cpp @@ -0,0 +1,7 @@ +#include +#include + +int getsgnam_r(const char *, struct sgrp *, char *, size_t, struct sgrp **) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} diff --git a/lib/mlibc/options/glibc/generic/malloc.cpp b/lib/mlibc/options/glibc/generic/malloc.cpp new file mode 100644 index 0000000..b5a4daf --- /dev/null +++ b/lib/mlibc/options/glibc/generic/malloc.cpp @@ -0,0 +1,6 @@ +#include +#include + +size_t malloc_usable_size(void *p) { + return getAllocator().get_size(p); +} diff --git a/lib/mlibc/options/glibc/generic/personality.cpp b/lib/mlibc/options/glibc/generic/personality.cpp new file mode 100644 index 0000000..3bfd9aa --- /dev/null +++ b/lib/mlibc/options/glibc/generic/personality.cpp @@ -0,0 +1,15 @@ +#include +#include +#include +#include + +int personality(unsigned long persona) { + int out = 0; + auto sysdep = MLIBC_CHECK_OR_ENOSYS(mlibc::sys_personality, -1); + + if(int e = sysdep(persona, &out); e) { + errno = e; + return -1; + } + return out; +} diff --git a/lib/mlibc/options/glibc/generic/printf.cpp b/lib/mlibc/options/glibc/generic/printf.cpp new file mode 100644 index 0000000..4abb00d --- /dev/null +++ b/lib/mlibc/options/glibc/generic/printf.cpp @@ -0,0 +1,7 @@ +#include +#include + +size_t parse_printf_format(const char * __restrict, size_t, int * __restrict) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} diff --git a/lib/mlibc/options/glibc/generic/resolv-stubs.cpp b/lib/mlibc/options/glibc/generic/resolv-stubs.cpp new file mode 100644 index 0000000..7c0723e --- /dev/null +++ b/lib/mlibc/options/glibc/generic/resolv-stubs.cpp @@ -0,0 +1,36 @@ +#include +#include +#include + +int dn_expand(const unsigned char *, const unsigned char *, + const unsigned char *, char *, int) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +int res_query(const char *, int, int, unsigned char *, int) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +int res_init() { + mlibc::infoLogger() << "mlibc: res_init is a stub!" << frg::endlog; + return 0; +} + +int res_ninit(res_state) { + mlibc::infoLogger() << "mlibc: res_ninit is a stub!" << frg::endlog; + return 0; +} + +void res_nclose(res_state) { + mlibc::infoLogger() << "mlibc: res_nclose is a stub!" << frg::endlog; + return; +} + +/* This is completely unused, and exists purely to satisfy broken apps. */ + +struct __res_state *__res_state() { + static struct __res_state res; + return &res; +} diff --git a/lib/mlibc/options/glibc/generic/shadow-stubs.cpp b/lib/mlibc/options/glibc/generic/shadow-stubs.cpp new file mode 100644 index 0000000..9ce6584 --- /dev/null +++ b/lib/mlibc/options/glibc/generic/shadow-stubs.cpp @@ -0,0 +1,217 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +/* + * The code in this file is largely based on or taken from musl. + * This includes: + * - xatol + * - __parsespent + * - cleanup + * - getspnam_r + * - getspnam + */ +#define NUM(n) ((n) == -1 ? 0 : -1), ((n) == -1 ? 0 : (n)) + +int putspent(const struct spwd *sp, FILE *f) { + auto str = [] (char *s) { + return ((s) ? (s) : ""); + }; + return fprintf(f, "%s:%s:%.*d:%.*d:%.*d:%.*d:%.*d:%.*d:%.*u\n", + str(sp->sp_namp), str(sp->sp_pwdp), NUM(sp->sp_lstchg), + NUM(sp->sp_min), NUM(sp->sp_max), NUM(sp->sp_warn), + NUM(sp->sp_inact), NUM(sp->sp_expire), NUM((int)sp->sp_flag)) < 0 ? -1 : 0; +} +#undef NUM + +static long xatol(char **s) { + long x; + if(**s == ':' || **s == '\n') { + return -1; + } + for(x = 0; (unsigned int)**s - '0' < 10U; ++*s) { + x = 10 * x + (**s - '0'); + } + return x; +} + +static int __parsespent(char *s, struct spwd *sp) { + sp->sp_namp = s; + if(!(s = strchr(s, ':'))) { + return -1; + } + *s = 0; + + sp->sp_pwdp = ++s; + if(!(s = strchr(s, ':'))) { + return -1; + } + *s = 0; + + s++; + sp->sp_lstchg = xatol(&s); + if(*s != ':') { + return -1; + } + + s++; + sp->sp_min = xatol(&s); + if(*s != ':') { + return -1; + } + + s++; + sp->sp_max = xatol(&s); + if(*s != ':') { + return -1; + } + + s++; + sp->sp_warn = xatol(&s); + if(*s != ':') { + return -1; + } + + s++; + sp->sp_inact = xatol(&s); + if(*s != ':') { + return -1; + } + + s++; + sp->sp_expire = xatol(&s); + if(*s != ':') { + return -1; + } + + s++; + sp->sp_flag = xatol(&s); + if(*s != '\n') { + return -1; + } + return 0; +} + +static void cleanup(void *p) { + fclose((FILE *)p); +} + +int getspnam_r(const char *name, struct spwd *sp, char *buf, size_t size, struct spwd **res) { + char path[20 + NAME_MAX]; + FILE *f = 0; + int rv = 0; + int fd; + size_t k, l = strlen(name); + int skip = 0; + int cs; + int orig_errno = errno; + + *res = 0; + + /* Disallow potentially-malicious user names */ + if(*name=='.' || strchr(name, '/') || !l) { + return errno = EINVAL; + } + + /* Buffer size must at least be able to hold name, plus some.. */ + if(size < l + 100) { + return errno = ERANGE; + } + + /* Protect against truncation */ + if(snprintf(path, sizeof path, "/etc/tcb/%s/shadow", name) >= (int)sizeof path) { + return errno = EINVAL; + } + + fd = open(path, O_RDONLY|O_NOFOLLOW|O_NONBLOCK|O_CLOEXEC); + if(fd >= 0) { + struct stat st = {}; + errno = EINVAL; + if(fstat(fd, &st) || !S_ISREG(st.st_mode) || !(f = fdopen(fd, "rb"))) { + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs); + close(fd); + pthread_setcancelstate(cs, 0); + return errno; + } + } else { + if(errno != ENOENT && errno != ENOTDIR) { + return errno; + } + f = fopen("/etc/shadow", "rbe"); + if(!f) { + if(errno != ENOENT && errno != ENOTDIR) { + return errno; + } + return 0; + } + } + + pthread_cleanup_push(cleanup, f); + while(fgets(buf, size, f) && (k = strlen(buf)) > 0) { + if(skip || strncmp(name, buf, l) || buf[l] != ':') { + skip = buf[k - 1] != '\n'; + continue; + } + if(buf[k - 1] != '\n') { + rv = ERANGE; + break; + } + + if(__parsespent(buf, sp) < 0) { + continue; + } + *res = sp; + break; + } + pthread_cleanup_pop(1); + errno = rv ? rv : orig_errno; + return rv; +} + +int lckpwdf(void) { + mlibc::infoLogger() << "mlibc: lckpwdf is unimplemented like musl" << frg::endlog; + return 0; +} + +int ulckpwdf(void) { + mlibc::infoLogger() << "mlibc: ulckpwdf is unimplemented like musl" << frg::endlog; + return 0; +} + +// Musl defines LINE_LIM to 256 +#define LINE_LIM 256 + +struct spwd *getspnam(const char *name) { + static struct spwd sp; + static char *line; + struct spwd *res; + int e; + int orig_errno = errno; + + if(!line) { + line = (char *)malloc(LINE_LIM); + } + if(!line) { + return 0; + } + e = getspnam_r(name, &sp, line, LINE_LIM, &res); + errno = e ? e : orig_errno; + return res; +} + +struct spwd *fgetspent(FILE *) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +void endspent(void) { + mlibc::infoLogger() << "mlibc: endspent is a stub" << frg::endlog; +} diff --git a/lib/mlibc/options/glibc/generic/stdio_ext-stubs.cpp b/lib/mlibc/options/glibc/generic/stdio_ext-stubs.cpp new file mode 100644 index 0000000..b9b61fc --- /dev/null +++ b/lib/mlibc/options/glibc/generic/stdio_ext-stubs.cpp @@ -0,0 +1,64 @@ + +#include +#include +#include + +size_t __fbufsize(FILE *) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +size_t __fpending(FILE *file_base) { + __ensure(file_base->__dirty_end >= file_base->__dirty_begin); + return file_base->__dirty_end - file_base->__dirty_begin; +} + +int __flbf(FILE *) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +int __freadable(FILE *) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +int __fwritable(FILE *) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +int __freading(FILE *file_base) { + return file_base->__io_mode == 0; +} + +int __fwriting(FILE *file_base) { + return file_base->__io_mode == 1; +} + +int __fsetlocking(FILE *, int) { + mlibc::infoLogger() << "mlibc: __fsetlocking() is a no-op" << frg::endlog; + return FSETLOCKING_INTERNAL; +} + +void _flushlbf(void) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +// The following functions are defined by musl. + +size_t __freadahead(FILE *file_base) { + if(file_base->__io_mode != 0) { + mlibc::infoLogger() << "mlibc: __freadahead() called but file is not open for reading" << frg::endlog; + return 0; + } + return file_base->__valid_limit - file_base->__offset; +} +const char *__freadptr(FILE *, size_t *) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +void __fseterr(FILE *) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + diff --git a/lib/mlibc/options/glibc/generic/string.cpp b/lib/mlibc/options/glibc/generic/string.cpp new file mode 100644 index 0000000..19f77c7 --- /dev/null +++ b/lib/mlibc/options/glibc/generic/string.cpp @@ -0,0 +1,32 @@ +#ifndef _GNU_SOURCE +# define _GNU_SOURCE +#endif +#include +#include + +/* This is a bit of a weird detail of the GNU implementation and C's lack of + * overloading and strictness: GNU takes const char * and returns a char * so + * that it autocasts to your desired constness, this function never actually + * modifies the string. + */ +char *__mlibc_gnu_basename_c(const char *path) { + char *basename_component = strrchr(path, '/'); + if (!basename_component) { + return const_cast(path); + } + return basename_component + 1; +} + + +/* GNU exposes these overloads, and as a result, we should probably have them + * checked, to make sure we actually match expectations. + */ +static_assert( + std::is_same_v, + "C++ overloads broken" +); + +static_assert( + std::is_same_v, + "C++ overloads broken" +); diff --git a/lib/mlibc/options/glibc/generic/sys-io.cpp b/lib/mlibc/options/glibc/generic/sys-io.cpp new file mode 100644 index 0000000..fbd9070 --- /dev/null +++ b/lib/mlibc/options/glibc/generic/sys-io.cpp @@ -0,0 +1,25 @@ +#include +#include + +#include +#include + +int ioperm(unsigned long int from, unsigned long int num, int turn_on) { + auto sysdep = MLIBC_CHECK_OR_ENOSYS(mlibc::sys_ioperm, -1); + + if(int e = sysdep(from, num, turn_on); e) { + errno = e; + return -1; + } + return 0; +} + +int iopl(int level) { + auto sysdep = MLIBC_CHECK_OR_ENOSYS(mlibc::sys_iopl, -1); + + if(int e = sysdep(level); e) { + errno = e; + return -1; + } + return 0; +} diff --git a/lib/mlibc/options/glibc/generic/sys-ioctl.cpp b/lib/mlibc/options/glibc/generic/sys-ioctl.cpp new file mode 100644 index 0000000..021d2a3 --- /dev/null +++ b/lib/mlibc/options/glibc/generic/sys-ioctl.cpp @@ -0,0 +1,21 @@ + +#include +#include + +#include +#include +#include + +int ioctl(int fd, unsigned long request, ...) { + va_list args; + va_start(args, request); + int result; + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_ioctl, -1); + void *arg = va_arg(args, void *); + if(int e = mlibc::sys_ioctl(fd, request, arg, &result); e) { + errno = e; + return -1; + } + return result; +} + diff --git a/lib/mlibc/options/glibc/generic/sys-timex.cpp b/lib/mlibc/options/glibc/generic/sys-timex.cpp new file mode 100644 index 0000000..6173399 --- /dev/null +++ b/lib/mlibc/options/glibc/generic/sys-timex.cpp @@ -0,0 +1,17 @@ +#include +#include + +int adjtimex(struct timex *) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +int clock_adjtime(clockid_t, struct timex *) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +int ntp_adjtime(struct timex *) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} diff --git a/lib/mlibc/options/glibc/include/ar.h b/lib/mlibc/options/glibc/include/ar.h new file mode 100644 index 0000000..c7a9f38 --- /dev/null +++ b/lib/mlibc/options/glibc/include/ar.h @@ -0,0 +1,27 @@ + +#ifndef _AR_H +#define _AR_H + +#define ARMAG "!\n" +#define SARMAG 8 +#define ARFMAG "`\n" + +#ifdef __cplusplus +extern "C" { +#endif + +struct ar_hdr { + char ar_name[16]; + char ar_date[12]; + char ar_uid[6]; + char ar_gid[6]; + char ar_mode[8]; + char ar_size[10]; + char ar_fmag[2]; +}; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib/mlibc/options/glibc/include/bits/glibc/glibc_assert.h b/lib/mlibc/options/glibc/include/bits/glibc/glibc_assert.h new file mode 100644 index 0000000..4461c5e --- /dev/null +++ b/lib/mlibc/options/glibc/include/bits/glibc/glibc_assert.h @@ -0,0 +1,32 @@ +#ifndef MLIBC_GLIBC_ASSERT_H +#define MLIBC_GLIBC_ASSERT_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +__attribute__ ((__noreturn__)) void __assert_fail_perror(int errno, const char *file, unsigned int line, + const char *function); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* MLIBC_GLIBC_ASSERT_H */ + +#ifdef NDEBUG + +#undef assert_perror +#define assert_perror(ignore) ((void)0) + +#else /* NDEBUG */ + +#undef assert_perror +#define assert_perror(errno) (!(errno) \ + || (__assert_fail_perror((errno), __FILE__, __LINE__, __func__), 0)) + +#endif /* NDEBUG */ diff --git a/lib/mlibc/options/glibc/include/bits/glibc/glibc_icmp6.h b/lib/mlibc/options/glibc/include/bits/glibc/glibc_icmp6.h new file mode 100644 index 0000000..eafde16 --- /dev/null +++ b/lib/mlibc/options/glibc/include/bits/glibc/glibc_icmp6.h @@ -0,0 +1,21 @@ +#ifndef _GLIBC_NETINET_ICMP6_H +#define _GLIBC_NETINET_ICMP6_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define ND_OPT_SOURCE_LINKADDR 1 +#define ND_OPT_TARGET_LINKADDR 2 +#define ND_OPT_PREFIX_INFORMATION 3 +#define ND_OPT_REDIRECTED_HEADER 4 +#define ND_OPT_MTU 5 +#define ND_OPT_RTR_ADV_INTERVAL 7 +#define ND_OPT_HOME_AGENT_INFO 8 + +#ifdef __cplusplus +} +#endif + +#endif /* _GLIBC_NETINET_ICMP6_H */ + diff --git a/lib/mlibc/options/glibc/include/bits/glibc/glibc_malloc.h b/lib/mlibc/options/glibc/include/bits/glibc/glibc_malloc.h new file mode 100644 index 0000000..7ce6c5e --- /dev/null +++ b/lib/mlibc/options/glibc/include/bits/glibc/glibc_malloc.h @@ -0,0 +1,17 @@ +#ifndef _GLIBC_MALLOC_H +#define _GLIBC_MALLOC_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +size_t malloc_usable_size(void *ptr); + +#ifdef __cplusplus +} +#endif + +#endif /* _GLIBC_MALLOC_H */ + diff --git a/lib/mlibc/options/glibc/include/bits/glibc/glibc_signal.h b/lib/mlibc/options/glibc/include/bits/glibc/glibc_signal.h new file mode 100644 index 0000000..4d34e20 --- /dev/null +++ b/lib/mlibc/options/glibc/include/bits/glibc/glibc_signal.h @@ -0,0 +1,24 @@ +#ifndef MLIBC_GLIBC_SIGNAL_H +#define MLIBC_GLIBC_SIGNAL_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +int tgkill(int, int, int); + +#if defined(_GNU_SOURCE) + +typedef void (*sighandler_t)(int); + +#endif + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif // MLIBC_GLIBC_SIGNAL_H diff --git a/lib/mlibc/options/glibc/include/endian.h b/lib/mlibc/options/glibc/include/endian.h new file mode 100644 index 0000000..00d5ee1 --- /dev/null +++ b/lib/mlibc/options/glibc/include/endian.h @@ -0,0 +1,54 @@ +#ifndef _ENDIAN_H +#define _ENDIAN_H + +#include + +#ifdef __GNUC__ +# define BYTE_ORDER __BYTE_ORDER__ +# define LITTLE_ENDIAN __ORDER_LITTLE_ENDIAN__ +# define BIG_ENDIAN __ORDER_BIG_ENDIAN__ +# define PDP_ENDIAN __ORDER_PDP_ENDIAN__ + +# define __BYTE_ORDER __BYTE_ORDER__ +#ifndef __LITTLE_ENDIAN // Linux kernel headers define this already +# define __LITTLE_ENDIAN __ORDER_LITTLE_ENDIAN__ +#endif +# define __BIG_ENDIAN __ORDER_BIG_ENDIAN__ +# define __PDP_ENDIAN __ORDER_PDP_ENDIAN__ +#else +# error "Unsupported compiler" +#endif + +#if BYTE_ORDER == LITTLE_ENDIAN +# define htobe16(x) __bswap_16(x) +# define htole16(x) (uint16_t)(x) +# define be16toh(x) __bswap_16(x) +# define le16toh(x) (uint16_t)(x) + +# define htobe32(x) __bswap_32(x) +# define htole32(x) (uint32_t)(x) +# define be32toh(x) __bswap_32(x) +# define le32toh(x) (uint32_t)(x) + +# define htobe64(x) __bswap_64(x) +# define htole64(x) (uint64_t)(x) +# define be64toh(x) __bswap_64(x) +# define le64toh(x) (uint64_t)(x) +#else +# define htobe16(x) (uint16_t)(x) +# define htole16(x) __bswap_16(x) +# define be16toh(x) (uint16_t)(x) +# define le16toh(x) __bswap_16(x) + +# define htobe32(x) (uint32_t)(x) +# define htole32(x) __bswap_32(x) +# define be32toh(x) (uint32_t)(x) +# define le32toh(x) __bswap_32(x) + +# define htobe64(x) (uint64_t)(x) +# define htole64(x) __bswap_64(x) +# define be64toh(x) (uint64_t)(x) +# define le64toh(x) __bswap_64(x) +#endif + +#endif // _ENDIAN_H diff --git a/lib/mlibc/options/glibc/include/err.h b/lib/mlibc/options/glibc/include/err.h new file mode 100644 index 0000000..c3757ab --- /dev/null +++ b/lib/mlibc/options/glibc/include/err.h @@ -0,0 +1,29 @@ +#ifndef _ERR_H +#define _ERR_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +void warn(const char *, ...); +void vwarn(const char *, va_list); +void warnx(const char *, ...); +void vwarnx(const char *, va_list); + +__attribute__((__noreturn__)) void err(int, const char *, ...); +__attribute__((__noreturn__)) void verr(int, const char *, va_list); +__attribute__((__noreturn__)) void errx(int, const char *, ...); +__attribute__((__noreturn__)) void verrx(int, const char *, va_list); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif // _ERR_H + diff --git a/lib/mlibc/options/glibc/include/error.h b/lib/mlibc/options/glibc/include/error.h new file mode 100644 index 0000000..782101d --- /dev/null +++ b/lib/mlibc/options/glibc/include/error.h @@ -0,0 +1,25 @@ +#ifndef _ERROR_H +#define _ERROR_H + +#include + +#ifdef __cplusplus +extern "C"{ +#endif + +#ifndef __MLIBC_ABI_ONLY + +void error(int status, int errnum, const char *format, ...); +void error_at_line(int status, int errnum, const char *filename, unsigned int linenum, const char *format, ...); + +extern unsigned int error_message_count; +extern int error_one_per_line; +extern void (*error_print_progname)(void); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _ERROR_H */ diff --git a/lib/mlibc/options/glibc/include/execinfo.h b/lib/mlibc/options/glibc/include/execinfo.h new file mode 100644 index 0000000..addbc4e --- /dev/null +++ b/lib/mlibc/options/glibc/include/execinfo.h @@ -0,0 +1,20 @@ +#ifndef _EXECINFO_H +#define _EXECINFO_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +int backtrace(void **, int); +char **backtrace_symbols(void *const *, int); +void backtrace_symbols_fd(void *const *, int, int); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib/mlibc/options/glibc/include/features.h b/lib/mlibc/options/glibc/include/features.h new file mode 100644 index 0000000..382b684 --- /dev/null +++ b/lib/mlibc/options/glibc/include/features.h @@ -0,0 +1,6 @@ +#ifndef FEATURES_H +#define FEATURES_H + +// This header is a stub + +#endif diff --git a/lib/mlibc/options/glibc/include/getopt.h b/lib/mlibc/options/glibc/include/getopt.h new file mode 100644 index 0000000..5b24cc8 --- /dev/null +++ b/lib/mlibc/options/glibc/include/getopt.h @@ -0,0 +1,44 @@ + +#ifndef _GETOPT_H +#define _GETOPT_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct option { + const char *name; + int has_arg; + int *flag; + int val; +}; + +#ifndef __MLIBC_ABI_ONLY + +extern char **environ; +extern char *optarg; +extern int optind; +extern int opterr; +extern int optopt; +#if __MLIBC_BSD_OPTION +extern int optreset; +#endif //__MLIBC_BSD_OPTION + +int getopt(int, char *const [], const char *); +int getopt_long(int, char *const[], const char *, const struct option *, int *); +int getopt_long_only(int, char *const[], const char *, const struct option *, int *); + +#endif /* !__MLIBC_ABI_ONLY */ + +#define no_argument 0 +#define required_argument 1 +#define optional_argument 2 + +#ifdef __cplusplus +} +#endif + +#endif // _GETOPT_H + diff --git a/lib/mlibc/options/glibc/include/gshadow.h b/lib/mlibc/options/glibc/include/gshadow.h new file mode 100644 index 0000000..61ec91f --- /dev/null +++ b/lib/mlibc/options/glibc/include/gshadow.h @@ -0,0 +1,30 @@ +#ifndef _GSHADOW_H +#define _GSHADOW_H + +#include +#include + +#define GSHADOW _PATH_GSHADOW + +struct sgrp { + char *sg_namp; + char *sg_passwd; + char **sg_adm; + char **sg_mem; +}; + +#ifndef __MLIBC_ABI_ONLY + +#ifdef __cplusplus +extern "C" { +#endif + +int getsgnam_r(const char *name, struct sgrp *result_buf, char *buffer, size_t len, struct sgrp **result); + +#ifdef __cplusplus +} +#endif + +#endif /* !__MLIBC_ABI_ONLY */ + +#endif diff --git a/lib/mlibc/options/glibc/include/memory.h b/lib/mlibc/options/glibc/include/memory.h new file mode 100644 index 0000000..39adee7 --- /dev/null +++ b/lib/mlibc/options/glibc/include/memory.h @@ -0,0 +1,6 @@ +#ifndef _MEMORY_H +#define _MEMORY_H + +#include + +#endif diff --git a/lib/mlibc/options/glibc/include/mlibc/glibc-sysdeps.hpp b/lib/mlibc/options/glibc/include/mlibc/glibc-sysdeps.hpp new file mode 100644 index 0000000..a3888ce --- /dev/null +++ b/lib/mlibc/options/glibc/include/mlibc/glibc-sysdeps.hpp @@ -0,0 +1,16 @@ +#ifndef MLIBC_GLIBC_SYSDEPS +#define MLIBC_GLIBC_SYSDEPS + +namespace [[gnu::visibility("hidden")]] mlibc { + +[[gnu::weak]] int sys_ioctl(int fd, unsigned long request, void *arg, int *result); +[[gnu::weak]] int sys_tgkill(int tgid, int tid, int sig); + +[[gnu::weak]] int sys_personality(unsigned long persona, int *out); + +[[gnu::weak]] int sys_ioperm(unsigned long int from, unsigned long int num, int turn_on); +[[gnu::weak]] int sys_iopl(int level); + +} // namespace mlibc + +#endif // MLIBC_GLIBC_SYSDEPS diff --git a/lib/mlibc/options/glibc/include/net/ethernet.h b/lib/mlibc/options/glibc/include/net/ethernet.h new file mode 100644 index 0000000..8dac98a --- /dev/null +++ b/lib/mlibc/options/glibc/include/net/ethernet.h @@ -0,0 +1,42 @@ +#ifndef _NET_ETHERNET_H +#define _NET_ETHERNET_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#if __MLIBC_LINUX_OPTION +# include +#endif /* __MLIBC_LINUX_OPTION */ + +#define ETHERTYPE_PUP 0x0200 +#define ETHERTYPE_SPRITE 0x0500 +#define ETHERTYPE_IP 0x0800 +#define ETHERTYPE_ARP 0x0806 +#define ETHERTYPE_REVARP 0x8035 +#define ETHERTYPE_AT 0x809B +#define ETHERTYPE_AARP 0x80F3 +#define ETHERTYPE_VLAN 0x8100 +#define ETHERTYPE_IPX 0x8137 +#define ETHERTYPE_IPV6 0x86dd +#define ETHERTYPE_LOOPBACK 0x9000 + +struct ether_header { + uint8_t ether_dhost[6]; + uint8_t ether_shost[6]; + uint16_t ether_type; +}; + +#define ETHER_ADDR_LEN 6 + +#define ETHERTYPE_IP 0x0800 + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib/mlibc/options/glibc/include/net/if_ppp.h b/lib/mlibc/options/glibc/include/net/if_ppp.h new file mode 100644 index 0000000..55f46b5 --- /dev/null +++ b/lib/mlibc/options/glibc/include/net/if_ppp.h @@ -0,0 +1,23 @@ +#ifndef _NET_IF_PPP_H +#define _NET_IF_PPP_H + +#include + +#if __MLIBC_LINUX_OPTION +#include +#include + +#define PPPIOCGFLAGS _IOR('t', 90, int) +#define PPPIOCSFLAGS _IOW('t', 89, int) +#define PPPIOCGASYNCMAP _IOR('t', 88, int) +#define PPPIOCSASYNCMAP _IOW('t', 87, int) +#define PPPIOCGUNIT _IOR('t', 86, int) +#define PPPIOCSMRU _IOW('t', 82, int) +#define PPPIOCSMAXCID _IOW('t', 81, int) +#define PPPIOCGXASYNCMAP _IOR('t', 80, ext_accm) +#define PPPIOCSXASYNCMAP _IOW('t', 79, ext_accm) +#define PPPIOCGDEBUG _IOR('t', 65, int) +#define PPPIOCSDEBUG _IOW('t', 64, int) +#endif + +#endif /* _NET_IF_PPP_H */ diff --git a/lib/mlibc/options/glibc/include/net/route.h b/lib/mlibc/options/glibc/include/net/route.h new file mode 100644 index 0000000..7537241 --- /dev/null +++ b/lib/mlibc/options/glibc/include/net/route.h @@ -0,0 +1,35 @@ +#ifndef _NET_ROUTE_H +#define _NET_ROUTE_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define RTF_HOST 0x0004 +#define RTF_REJECT 0x0200 + +struct rtentry { + unsigned long int rt_pad1; + struct sockaddr rt_dst; + struct sockaddr rt_gateway; + struct sockaddr rt_genmask; + unsigned short int rt_flags; + short int rt_pad2; + unsigned long int rt_pad3; + unsigned char rt_tos; + unsigned char rt_class; + short int rt_pad4[3]; + short int rt_metric; + char *rt_dev; + unsigned long int rt_mtu; + unsigned long int rt_window; + unsigned short int rt_irtt; +}; + +#ifdef __cplusplus +} +#endif + +#endif /* _NET_ROUTE_H */ diff --git a/lib/mlibc/options/glibc/include/netax25/ax25.h b/lib/mlibc/options/glibc/include/netax25/ax25.h new file mode 100644 index 0000000..3fb82da --- /dev/null +++ b/lib/mlibc/options/glibc/include/netax25/ax25.h @@ -0,0 +1,51 @@ +#ifndef _NETAX25_AX25_H +#define _NETAX25_AX25_H + +#include +#include + +#define AX25_VALUES_IPDEFMODE 0 +#define AX25_VALUES_AXDEFMODE 1 +#define AX25_VALUES_NETROM 2 +#define AX25_VALUES_TEXT 3 +#define AX25_VALUES_BACKOFF 4 +#define AX25_VALUES_CONMODE 5 +#define AX25_VALUES_WINDOW 6 +#define AX25_VALUES_EWINDOW 7 +#define AX25_VALUES_T1 8 +#define AX25_VALUES_T2 9 +#define AX25_VALUES_T3 10 +#define AX25_VALUES_N2 11 +#define AX25_VALUES_DIGI 12 +#define AX25_VALUES_IDLE 13 +#define AX25_VALUES_PACLEN 14 +#define AX25_VALUES_IPMAXQUEUE 15 +#define AX25_MAX_VALUES 20 + +typedef struct { + char ax25_call[7]; +} ax25_address; + +struct sockaddr_ax25 { + sa_family_t sax25_family; + ax25_address sax25_call; + int sax25_ndigis; +}; + +struct ax25_parms_struct { + ax25_address port_addr; + unsigned short values[AX25_MAX_VALUES]; +}; + +#if __MLIBC_LINUX_OPTION +#include + +#define SIOCAX25GETUID (SIOCPROTOPRIVATE) +#define SIOCAX25ADDUID (SIOCPROTOPRIVATE + 1) +#define SIOCAX25DELUID (SIOCPROTOPRIVATE + 2) +#define SIOCAX25NOUID (SIOCPROTOPRIVATE + 3) +#define SIOCAX25GETPARMS (SIOCPROTOPRIVATE + 5) +#define SIOCAX25SETPARMS (SIOCPROTOPRIVATE + 6) +#endif /* __MLIBC_LINUX_OPTION */ + +#endif /* _NETAX25_AX25_H */ diff --git a/lib/mlibc/options/glibc/include/netinet/in_systm.h b/lib/mlibc/options/glibc/include/netinet/in_systm.h new file mode 100644 index 0000000..c98298f --- /dev/null +++ b/lib/mlibc/options/glibc/include/netinet/in_systm.h @@ -0,0 +1,7 @@ + +#ifndef _NETINET_IN_SYSTM_H +#define _NETINET_IN_SYSTM_H + + + +#endif // _NETINET_IN_SYSTM_H diff --git a/lib/mlibc/options/glibc/include/netipx/ipx.h b/lib/mlibc/options/glibc/include/netipx/ipx.h new file mode 100644 index 0000000..7b5c774 --- /dev/null +++ b/lib/mlibc/options/glibc/include/netipx/ipx.h @@ -0,0 +1,35 @@ +#ifndef _NETIPX_IPX_H +#define _NETIPX_IPX_H + +#include +#include +#include + +typedef struct ipx_config_data { + unsigned char ipxcfg_auto_select_primary; + unsigned char ipxcfg_auto_create_interfaces; +} ipx_config_data; + +#define IPX_TYPE 1 +#define IPX_NODE_LEN 6 + +struct sockaddr_ipx { + sa_family_t sipx_family; + uint16_t sipx_port; + uint32_t sipx_network; + unsigned char sipx_node[IPX_NODE_LEN]; + uint8_t sipx_type; + unsigned char sipx_zero; +}; + +#define SOL_IPX 256 + +#if __MLIBC_LINUX_OPTION +#include + +#define SIOCAIPXITFCRT (SIOCPROTOPRIVATE) +#define SIOCAIPXPRISLT (SIOCPROTOPRIVATE + 1) +#define SIOCIPXCFGDATA (SIOCPROTOPRIVATE + 2) +#endif + +#endif /* _NETIPX_IPX_H */ diff --git a/lib/mlibc/options/glibc/include/netrom/netrom.h b/lib/mlibc/options/glibc/include/netrom/netrom.h new file mode 100644 index 0000000..69497d9 --- /dev/null +++ b/lib/mlibc/options/glibc/include/netrom/netrom.h @@ -0,0 +1,27 @@ +#ifndef _NETROM_NETROM_H +#define _NETROM_NETROM_H + +#include + +struct nr_parms_struct { + unsigned int quality; + unsigned int obs_count; + unsigned int ttl; + unsigned int timeout; + unsigned int ack_delay; + unsigned int busy_delay; + unsigned int tries; + unsigned int window; + unsigned int paclen; +}; + +#if __MLIBC_LINUX_OPTION +#include + +#define SIOCNRGETPARMS (SIOCPROTOPRIVATE) +#define SIOCNRSETPARMS (SIOCPROTOPRIVATE + 1) +#define SIOCNRDECOBS (SIOCPROTOPRIVATE + 2) +#define SIOCNRRTCTL (SIOCPROTOPRIVATE + 3) +#endif + +#endif /* _NETROM_NETROM_H */ diff --git a/lib/mlibc/options/glibc/include/paths.h b/lib/mlibc/options/glibc/include/paths.h new file mode 100644 index 0000000..3d8a4a6 --- /dev/null +++ b/lib/mlibc/options/glibc/include/paths.h @@ -0,0 +1,41 @@ +// This file is taken from musl +// Path to original: include/paths.h + +#ifndef _PATHS_H +#define _PATHS_H + +#define _PATH_DEFPATH "/usr/local/bin:/bin:/usr/bin" +#define _PATH_STDPATH "/bin:/usr/bin:/sbin:/usr/sbin" + +#define _PATH_BSHELL "/bin/sh" +#define _PATH_CONSOLE "/dev/console" +#define _PATH_DEVNULL "/dev/null" +#define _PATH_GSHADOW "/etc/gshadow" +#define _PATH_KLOG "/proc/kmsg" +#define _PATH_LASTLOG "/var/log/lastlog" +#define _PATH_MAILDIR "/var/mail" +#define _PATH_MAN "/usr/share/man" +#define _PATH_MNTTAB "/etc/fstab" +#define _PATH_MOUNTED "/etc/mtab" +#define _PATH_NOLOGIN "/etc/nologin" +#define _PATH_PRESERVE "/var/lib" +#define _PATH_SENDMAIL "/usr/sbin/sendmail" +#define _PATH_SHADOW "/etc/shadow" +#define _PATH_SHELLS "/etc/shells" +#define _PATH_TTY "/dev/tty" +#define _PATH_UTMP "/dev/null/utmp" +#define _PATH_VI "/usr/bin/vi" +#define _PATH_WTMP "/dev/null/wtmp" + +#define _PATH_DEV "/dev/" +#define _PATH_TMP "/tmp/" +#define _PATH_VARDB "/var/lib/misc/" +#define _PATH_VARRUN "/var/run/" +#define _PATH_VARTMP "/var/tmp/" + +#ifdef _GNU_SOURCE +#define _PATH_UTMPX _PATH_UTMP +#define _PATH_WTMPX _PATH_WTMP +#endif + +#endif // _PATHS_H diff --git a/lib/mlibc/options/glibc/include/printf.h b/lib/mlibc/options/glibc/include/printf.h new file mode 100644 index 0000000..e7dd0d8 --- /dev/null +++ b/lib/mlibc/options/glibc/include/printf.h @@ -0,0 +1,41 @@ +#ifndef _PRINTF_H +#define _PRINTF_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +#ifndef __MLIBC_ABI_ONLY + +// This seems to be a glibc thing, so constants are from glibc +size_t parse_printf_format(const char * __restrict, size_t, int * __restrict); + +#endif /* !__MLIBC_ABI_ONLY */ + +enum { + PA_INT, + PA_CHAR, + PA_WCHAR, + PA_STRING, + PA_WSTRING, + PA_POINTER, + PA_FLOAT, + PA_DOUBLE, + PA_LAST +}; + +#define PA_FLAG_MASK 0xff00 +#define PA_FLAG_LONG_LONG (1 << 8) +#define PA_FLAG_LONG_DOUBLE PA_FLAG_LONG_LONG +#define PA_FLAG_LONG (1 << 9) +#define PA_FLAG_SHORT (1 << 10) +#define PA_FLAG_PTR (1 << 11) + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib/mlibc/options/glibc/include/resolv.h b/lib/mlibc/options/glibc/include/resolv.h new file mode 100644 index 0000000..71b4fe5 --- /dev/null +++ b/lib/mlibc/options/glibc/include/resolv.h @@ -0,0 +1,73 @@ +#ifndef _RESOLV_H +#define _RESOLV_H + +#include + +#define RES_INIT 0x00000001 +#define RES_DEBUG 0x00000002 +#define RES_USEVC 0x00000008 +#define RES_IGNTC 0x00000020 +#define RES_RECURSE 0x00000040 +#define RES_DEFNAMES 0x00000080 +#define RES_STAYOPEN 0x00000100 +#define RES_DNSRCH 0x00000200 + +#define MAXNS 3 +#define MAXDNSRCH 6 + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +int dn_expand(const unsigned char *, const unsigned char *, + const unsigned char *, char *, int); + +int res_query(const char *, int, int, unsigned char *, int); + +int res_init(void); + +#endif /* !__MLIBC_ABI_ONLY */ + +/* From musl: Unused; purely for broken apps + * To avoid an massive struct, only add the items requested. */ +typedef struct __res_state { + int retrans; + int retry; + unsigned long options; + int nscount; + struct sockaddr_in nsaddr_list[MAXNS]; + char *dnsrch[MAXDNSRCH + 1]; + char defdname[256]; + unsigned ndots:4; + unsigned nsort:4; + union { + char pad[52]; + struct { + uint16_t nscount; + uint16_t nsmap[MAXNS]; + int nssocks[MAXNS]; + uint16_t nscount6; + uint16_t nsinit; + struct sockaddr_in6 *nsaddrs[MAXNS]; + unsigned int _initstamp[2]; + } _ext; + } _u; +} *res_state; + +#ifndef __MLIBC_ABI_ONLY + +struct __res_state *__res_state(void); +#define _res (*__res_state()) + +int res_ninit(res_state); +void res_nclose(res_state); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif // _RESOLV_H diff --git a/lib/mlibc/options/glibc/include/shadow.h b/lib/mlibc/options/glibc/include/shadow.h new file mode 100644 index 0000000..caad9cf --- /dev/null +++ b/lib/mlibc/options/glibc/include/shadow.h @@ -0,0 +1,42 @@ +#ifndef _SHADOW_H +#define _SHADOW_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct spwd { + char *sp_namp; + char *sp_pwdp; + int32_t sp_lstchg; + int32_t sp_min; + int32_t sp_max; + int32_t sp_warn; + int32_t sp_inact; + int32_t sp_expire; + uint32_t sp_flag; +}; + +#define SHADOW _PATH_SHADOW + +#ifndef __MLIBC_ABI_ONLY + +int putspent(const struct spwd *, FILE *); +int lckpwdf(void); +int ulckpwdf(void); +struct spwd *getspnam(const char *); +int getspnam_r(const char *, struct spwd *, char *, size_t, struct spwd **); +struct spwd *fgetspent(FILE *); +void endspent(void); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib/mlibc/options/glibc/include/stdio_ext.h b/lib/mlibc/options/glibc/include/stdio_ext.h new file mode 100644 index 0000000..f22e05d --- /dev/null +++ b/lib/mlibc/options/glibc/include/stdio_ext.h @@ -0,0 +1,41 @@ +#ifndef _STDIO_EXT_H +#define _STDIO_EXT_H + +#include +#include + +#define FSETLOCKING_INTERNAL 1 +#define FSETLOCKING_BYCALLER 2 +#define FSETLOCKING_QUERY 3 + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +size_t __fbufsize(FILE *); +size_t __fpending(FILE *); +int __flbf(FILE *); +int __freadable(FILE *); +int __fwritable(FILE *); +int __freading(FILE *); +int __fwriting(FILE *); +int __fsetlocking(FILE *, int); +void __fpurge(FILE *); + +void _flushlbf(void); + +// The following functions are defined by musl. + +size_t __freadahead(FILE *); +const char *__freadptr(FILE *, size_t *); +void __fseterr(FILE *); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif // _STDIO_EXT_H diff --git a/lib/mlibc/options/glibc/include/sys/dir.h b/lib/mlibc/options/glibc/include/sys/dir.h new file mode 100644 index 0000000..eff112c --- /dev/null +++ b/lib/mlibc/options/glibc/include/sys/dir.h @@ -0,0 +1,8 @@ +#ifndef _SYS_DIR_H +#define _SYS_DIR_H + +#include + +#define direct dirent + +#endif diff --git a/lib/mlibc/options/glibc/include/sys/endian.h b/lib/mlibc/options/glibc/include/sys/endian.h new file mode 100644 index 0000000..e69de29 diff --git a/lib/mlibc/options/glibc/include/sys/errno.h b/lib/mlibc/options/glibc/include/sys/errno.h new file mode 100644 index 0000000..339f4fc --- /dev/null +++ b/lib/mlibc/options/glibc/include/sys/errno.h @@ -0,0 +1 @@ +#include diff --git a/lib/mlibc/options/glibc/include/sys/io.h b/lib/mlibc/options/glibc/include/sys/io.h new file mode 100644 index 0000000..311b25f --- /dev/null +++ b/lib/mlibc/options/glibc/include/sys/io.h @@ -0,0 +1,108 @@ +#ifndef _SYS_IO_H +#define _SYS_IO_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +int ioperm(unsigned long int from, unsigned long int num, int turn_on); + +__attribute__((deprecated)) int iopl(int level); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __x86_64__ +__MLIBC_INLINE_DEFINITION unsigned char inb(unsigned short int port) { + unsigned char _v; + __asm__ __volatile__ ("inb %w1,%0":"=a" (_v):"Nd" (port)); + return _v; +} + +__MLIBC_INLINE_DEFINITION unsigned char inb_p(unsigned short int port) { + unsigned char _v; + __asm__ __volatile__ ("inb %w1,%0\noutb %%al,$0x80":"=a" (_v):"Nd" (port)); + return _v; +} + +__MLIBC_INLINE_DEFINITION unsigned short int inw(unsigned short int port) { + unsigned short _v; + __asm__ __volatile__ ("inw %w1,%0":"=a" (_v):"Nd" (port)); + return _v; +} + +__MLIBC_INLINE_DEFINITION unsigned short int inw_p(unsigned short int port) { + unsigned short int _v; + __asm__ __volatile__ ("inw %w1,%0\noutb %%al,$0x80":"=a" (_v):"Nd" (port)); + return _v; +} + +__MLIBC_INLINE_DEFINITION unsigned int inl(unsigned short int port) { + unsigned int _v; + __asm__ __volatile__ ("inl %w1,%0":"=a" (_v):"Nd" (port)); + return _v; +} + +__MLIBC_INLINE_DEFINITION unsigned int inl_p(unsigned short int port) { + unsigned int _v; + __asm__ __volatile__ ("inl %w1,%0\noutb %%al,$0x80":"=a" (_v):"Nd" (port)); + return _v; +} + +__MLIBC_INLINE_DEFINITION void outb(unsigned char value, unsigned short int port) { + __asm__ __volatile__ ("outb %b0,%w1": :"a" (value), "Nd" (port)); +} + +__MLIBC_INLINE_DEFINITION void outb_p(unsigned char value, unsigned short int port) { + __asm__ __volatile__ ("outb %b0,%w1\noutb %%al,$0x80": :"a" (value), "Nd" (port)); +} + +__MLIBC_INLINE_DEFINITION void outw(unsigned short int value, unsigned short int port) { + __asm__ __volatile__ ("outw %w0,%w1": :"a" (value), "Nd" (port)); +} + +__MLIBC_INLINE_DEFINITION void outw_p(unsigned short int value, unsigned short int port) { + __asm__ __volatile__ ("outw %w0,%w1\noutb %%al,$0x80": :"a" (value), "Nd" (port)); +} + +__MLIBC_INLINE_DEFINITION void outl(unsigned int value, unsigned short int port) { + __asm__ __volatile__ ("outl %0,%w1": :"a" (value), "Nd" (port)); +} + +__MLIBC_INLINE_DEFINITION void outl_p(unsigned int value, unsigned short int port) { + __asm__ __volatile__ ("outl %0,%w1\noutb %%al,$0x80": :"a" (value), "Nd" (port)); +} + +__MLIBC_INLINE_DEFINITION void insb(unsigned short int port, void *addr, unsigned long int count) { + __asm__ __volatile__ ("cld ; rep ; insb":"=D" (addr), "=c" (count) :"d" (port), "0" (addr), "1" (count)); +} + +__MLIBC_INLINE_DEFINITION void insw(unsigned short int port, void *addr, unsigned long int count) { + __asm__ __volatile__ ("cld ; rep ; insw":"=D" (addr), "=c" (count) :"d" (port), "0" (addr), "1" (count)); +} + +__MLIBC_INLINE_DEFINITION void insl(unsigned short int port, void *addr, unsigned long int count) { + __asm__ __volatile__ ("cld ; rep ; insl":"=D" (addr), "=c" (count) :"d" (port), "0" (addr), "1" (count)); +} + +__MLIBC_INLINE_DEFINITION void outsb(unsigned short int port, const void *addr, unsigned long int count) { + __asm__ __volatile__ ("cld ; rep ; outsb":"=S" (addr), "=c" (count) :"d" (port), "0" (addr), "1" (count)); +} + +__MLIBC_INLINE_DEFINITION void outsw(unsigned short int port, const void *addr, unsigned long int count) { + __asm__ __volatile__ ("cld ; rep ; outsw":"=S" (addr), "=c" (count) :"d" (port), "0" (addr), "1" (count)); +} + +__MLIBC_INLINE_DEFINITION void outsl(unsigned short int port, const void *addr, unsigned long int count) { + __asm__ __volatile__ ("cld ; rep ; outsl":"=S" (addr), "=c" (count) :"d" (port), "0" (addr), "1" (count)); +} +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_IO_H */ diff --git a/lib/mlibc/options/glibc/include/sys/ioctl.h b/lib/mlibc/options/glibc/include/sys/ioctl.h new file mode 100644 index 0000000..6121446 --- /dev/null +++ b/lib/mlibc/options/glibc/include/sys/ioctl.h @@ -0,0 +1,44 @@ +#ifndef _SYS_IOCTL_H +#define _SYS_IOCTL_H + +#include +#include + +// On Linux, sys/ioctl.h includes the termios ioctls. +#if __MLIBC_LINUX_OPTION +# include +# include +# include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +int ioctl(int fd, unsigned long request, ...); + +#endif /* !__MLIBC_ABI_ONLY */ + +#define FIONREAD 0x541B +#define FIONBIO 0x5421 +#define FIONCLEX 0x5450 +#define FIOCLEX 0x5451 + +#define SIOCGIFNAME 0x8910 +#define SIOCGIFCONF 0x8912 +#define SIOCGIFFLAGS 0x8913 +#define SIOCSIFFLAGS 0x8914 +#define SIOCGIFMTU 0x8921 +#define SIOCSIFMTU 0x8922 +#define SIOCGIFINDEX 0x8933 + +#define SIOCPROTOPRIVATE 0x89E0 +#define SIOCDEVPRIVATE 0x89F0 + +#ifdef __cplusplus +} +#endif + +#endif // _SYS_IOCTL_H diff --git a/lib/mlibc/options/glibc/include/sys/kd.h b/lib/mlibc/options/glibc/include/sys/kd.h new file mode 100644 index 0000000..285c694 --- /dev/null +++ b/lib/mlibc/options/glibc/include/sys/kd.h @@ -0,0 +1,17 @@ +#ifndef _SYS_KD_H +#define _SYS_KD_H + +/* Make sure the header is not loaded. */ +#ifndef _LINUX_TYPES_H +# define _LINUX_TYPES_H 1 +# define __undef_LINUX_TYPES_H +#endif + +#include + +#ifdef __undef_LINUX_TYPES_H +# undef _LINUX_TYPES_H +# undef __undef_LINUX_TYPES_H +#endif + +#endif /* _SYS_KD_H */ diff --git a/lib/mlibc/options/glibc/include/sys/mtio.h b/lib/mlibc/options/glibc/include/sys/mtio.h new file mode 100644 index 0000000..c2f9d98 --- /dev/null +++ b/lib/mlibc/options/glibc/include/sys/mtio.h @@ -0,0 +1,103 @@ +#ifndef _SYS_MTIO_H +#define _SYS_MTIO_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +struct mtop { + short int mt_op; + int mt_count; +}; + +struct mtget { + long int mt_type; + long int mt_resid; + long int mt_dsreg; + long int mt_gstat; + long int mt_erreg; + int mt_fileno; + int mt_blkno; +}; + +struct mtpos { + long int mt_blkno; +}; + +struct mtconfiginfo { + long int mt_type; + long int ifc_type; + unsigned short int irqnr; + unsigned short int dmanr; + unsigned short int port; + + unsigned long int debug; + + unsigned have_dens:1; + unsigned have_bsf:1; + unsigned have_fsr:1; + unsigned have_bsr:1; + unsigned have_eod:1; + unsigned have_seek:1; + unsigned have_tell:1; + unsigned have_ras1:1; + unsigned have_ras2:1; + unsigned have_ras3:1; + unsigned have_qfa:1; + + unsigned pad1:5; + char reserved[10]; +}; + +#define MTRESET 0 +#define MTFSF 1 +#define MTBSF 2 +#define MTFSR 3 +#define MTBSR 4 +#define MTWEOF 5 +#define MTREW 6 +#define MTOFFL 7 +#define MTNOP 8 +#define MTRETEN 9 +#define MTBSFM 10 +#define MTFSFM 11 +#define MTEOM 12 +#define MTERASE 13 +#define MTRAS1 14 +#define MTRAS2 15 +#define MTRAS3 16 +#define MTSETBLK 20 +#define MTSETDENSITY 21 +#define MTSEEK 22 +#define MTTELL 23 +#define MTSETDRVBUFFER 24 +#define MTFSS 25 +#define MTBSS 26 +#define MTWSM 27 +#define MTLOCK 28 +#define MTUNLOCK 29 +#define MTLOAD 30 +#define MTUNLOAD 31 +#define MTCOMPRESSION 32 +#define MTSETPART 33 +#define MTMKPART 34 + +#define GMT_WR_PROT(x) ((x) & 0x04000000) + +#if __MLIBC_LINUX_OPTION +#include + +#define MTIOCTOP _IOR('m', 1, struct mtop) +#define MTIOCGET _IOR('m', 2, struct mtget) +#define MTIOCPOS _IOR('m', 3, struct mtpos) +#define MTIOCGETCONFIG _IOR('m', 4, struct mtconfiginfo) +#define MTIOCSETCONFIG _IOR('m', 5, struct mtconfiginfo) +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_MTIO_H */ diff --git a/lib/mlibc/options/glibc/include/sys/personality.h b/lib/mlibc/options/glibc/include/sys/personality.h new file mode 100644 index 0000000..04563a0 --- /dev/null +++ b/lib/mlibc/options/glibc/include/sys/personality.h @@ -0,0 +1,58 @@ +#ifndef _SYS_PERSONALITY_H +#define _SYS_PERSONALITY_H + +#ifdef __cplusplus +extern "C" { +#endif + +enum { + UNAME26 = 0x0020000, + ADDR_NO_RANDOMIZE = 0x0040000, + FDPIC_FUNCPTRS = 0x0080000, + MMAP_PAGE_ZERO = 0x0100000, + ADDR_COMPAT_LAYOUT = 0x0200000, + READ_IMPLIES_EXEC = 0x0400000, + ADDR_LIMIT_32BIT = 0x0800000, + SHORT_INODE = 0x1000000, + WHOLE_SECONDS = 0x2000000, + STICKY_TIMEOUTS = 0x4000000, + ADDR_LIMIT_3GB = 0x8000000, +}; + +enum { + PER_LINUX = 0x0000, + PER_LINUX_32BIT = 0x0000 | ADDR_LIMIT_32BIT, + PER_LINUX_FDPIC = 0x0000 | FDPIC_FUNCPTRS, + PER_SVR4 = 0x0001 | STICKY_TIMEOUTS | MMAP_PAGE_ZERO, + PER_SVR3 = 0x0002 | STICKY_TIMEOUTS | SHORT_INODE, + PER_SCOSVR3 = 0x0003 | STICKY_TIMEOUTS | WHOLE_SECONDS | SHORT_INODE, + PER_OSR5 = 0x0003 | STICKY_TIMEOUTS | WHOLE_SECONDS, + PER_WYSEV386 = 0x0004 | STICKY_TIMEOUTS | SHORT_INODE, + PER_ISCR4 = 0x0005 | STICKY_TIMEOUTS, + PER_BSD = 0x0006, + PER_SUNOS = 0x0006 | STICKY_TIMEOUTS, + PER_XENIX = 0x0007 | STICKY_TIMEOUTS | SHORT_INODE, + PER_LINUX32 = 0x0008, + PER_LINUX32_3GB = 0x0008 | ADDR_LIMIT_3GB, + PER_IRIX32 = 0x0009 | STICKY_TIMEOUTS, + PER_IRIXN32 = 0x000a | STICKY_TIMEOUTS, + PER_IRIX64 = 0x000b | STICKY_TIMEOUTS, + PER_RISCOS = 0x000c, + PER_SOLARIS = 0x000d | STICKY_TIMEOUTS, + PER_UW7 = 0x000e | STICKY_TIMEOUTS | MMAP_PAGE_ZERO, + PER_OSF4 = 0x000f, + PER_HPUX = 0x0010, + PER_MASK = 0x00ff, +}; + +#ifndef __MLIBC_ABI_ONLY + +int personality(unsigned long persona); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif // _SYS_PERSONALITY_H diff --git a/lib/mlibc/options/glibc/include/sys/procfs.h b/lib/mlibc/options/glibc/include/sys/procfs.h new file mode 100644 index 0000000..b13a81d --- /dev/null +++ b/lib/mlibc/options/glibc/include/sys/procfs.h @@ -0,0 +1,54 @@ +#ifndef _SYS_PROCFS_H +#define _SYS_PROCFS_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef unsigned long long elf_greg_t; + +#define ELF_NGREG (sizeof (struct user_regs_struct) / sizeof (elf_greg_t)) +typedef elf_greg_t elf_gregset_t[ELF_NGREG]; + +typedef struct user_fpregs_struct elf_fpregset_t; +typedef struct user_regs_struct prgregset_t; +typedef struct user_fpregs_struct prfpregset_t; + +#define ELF_PRARGSZ 80 + +struct elf_siginfo { + int si_signo; + int si_code; + int si_errno; +}; + +struct elf_prstatus { + struct elf_siginfo pr_info; + short int pr_cursig; + unsigned long int pr_sigpend; + unsigned long int pr_sighold; + pid_t pr_pid; + pid_t pr_ppid; + pid_t pr_pgrp; + pid_t pr_sid; + struct timeval pr_utime; + struct timeval pr_stime; + struct timeval pr_cutime; + struct timeval pr_cstime; + elf_gregset_t pr_reg; + int pr_fpvalid; +}; + +typedef pid_t lwpid_t; +typedef void *psaddr_t; +typedef struct elf_prstatus prstatus_t; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib/mlibc/options/glibc/include/sys/reg.h b/lib/mlibc/options/glibc/include/sys/reg.h new file mode 100644 index 0000000..c6e3429 --- /dev/null +++ b/lib/mlibc/options/glibc/include/sys/reg.h @@ -0,0 +1,36 @@ +#ifndef _SYS_REG_H +#define _SYS_REG_H + +#ifdef __x86_64__ +#define R15 0 +#define R14 1 +#define R13 2 +#define R12 3 +#define RBP 4 +#define RBX 5 +#define R11 6 +#define R10 7 +#define R9 8 +#define R8 9 +#define RAX 10 +#define RCX 11 +#define RDX 12 +#define RSI 13 +#define RDI 14 +#define ORIG_RAX 15 +#define RIP 16 +#define CS 17 +#define EFLAGS 18 +#define RSP 19 +#define SS 20 +#define FS_BASE 21 +#define GS_BASE 22 +#define DS 23 +#define ES 24 +#define FS 25 +#define GS 26 +#else +#error "Add architecture specific code here" +#endif + +#endif diff --git a/lib/mlibc/options/glibc/include/sys/signal.h b/lib/mlibc/options/glibc/include/sys/signal.h new file mode 100644 index 0000000..2e602da --- /dev/null +++ b/lib/mlibc/options/glibc/include/sys/signal.h @@ -0,0 +1 @@ +#include diff --git a/lib/mlibc/options/glibc/include/sys/timeb.h b/lib/mlibc/options/glibc/include/sys/timeb.h new file mode 100644 index 0000000..d27173b --- /dev/null +++ b/lib/mlibc/options/glibc/include/sys/timeb.h @@ -0,0 +1,14 @@ +#ifndef _SYS_TIMEB_H +#define _SYS_TIMEB_H + +#ifdef __cplusplus +extern "C" { +#endif + + + +#ifdef __cplusplus +} +#endif + +#endif // _SYS_TIMEB_H diff --git a/lib/mlibc/options/glibc/include/sys/timex.h b/lib/mlibc/options/glibc/include/sys/timex.h new file mode 100644 index 0000000..97153ad --- /dev/null +++ b/lib/mlibc/options/glibc/include/sys/timex.h @@ -0,0 +1,78 @@ +#ifndef _SYS_TIMEX_H +#define _SYS_TIMEX_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +struct timex { + int modes; + long offset; + long freq; + long maxerror; + long esterror; + int status; + long constant; + long precision; + long tolerance; + struct timeval time; + long tick; + long ppsfreq; + long jitter; + int shift; + long stabil; + long jitcnt; + long calcnt; + long errcnt; + long stbcnt; + int tai; + int __padding[11]; +}; + +#define ADJ_OFFSET 0x0001 +#define ADJ_FREQUENCY 0x0002 +#define ADJ_MAXERROR 0x0004 +#define ADJ_ESTERROR 0x0008 +#define ADJ_STATUS 0x0010 +#define ADJ_TIMECONST 0x0020 +#define ADJ_TAI 0x0080 +#define ADJ_SETOFFSET 0x0100 +#define ADJ_MICRO 0x1000 +#define ADJ_NANO 0x2000 +#define ADJ_TICK 0x4000 +#define ADJ_OFFSET_SINGLESHOT 0x8001 +#define ADJ_OFFSET_SS_READ 0xa001 + +#define STA_PLL 0x0001 +#define STA_PPSFREQ 0x0002 +#define STA_PPSTIME 0x0004 +#define STA_FLL 0x0008 +#define STA_INS 0x0010 +#define STA_DEL 0x0020 +#define STA_UNSYNC 0x0040 +#define STA_FREQHOLD 0x0080 +#define STA_PPSSIGNAL 0x0100 +#define STA_PPSJITTER 0x0200 +#define STA_PPSWANDER 0x0400 +#define STA_PPSERROR 0x0800 +#define STA_CLOCKERR 0x1000 +#define STA_NANO 0x2000 +#define STA_MODE 0x4000 +#define STA_CLK 0x8000 + +#ifndef __MLIBC_ABI_ONLY + +int adjtimex(struct timex *); +int clock_adjtime(clockid_t clk_id, struct timex *buf); +int ntp_adjtime(struct timex *); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif // _SYS_TIMEX_H diff --git a/lib/mlibc/options/glibc/include/sys/ucontext.h b/lib/mlibc/options/glibc/include/sys/ucontext.h new file mode 100644 index 0000000..b4798ee --- /dev/null +++ b/lib/mlibc/options/glibc/include/sys/ucontext.h @@ -0,0 +1,14 @@ +#ifndef _SYS_UCONTEXT_H +#define _SYS_UCONTEXT_H + +#ifdef __cplusplus +extern "C" { +#endif + + + +#ifdef __cplusplus +} +#endif + +#endif // _SYS_UCONTEXT_H diff --git a/lib/mlibc/options/glibc/include/sys/user.h b/lib/mlibc/options/glibc/include/sys/user.h new file mode 100644 index 0000000..9a07ac6 --- /dev/null +++ b/lib/mlibc/options/glibc/include/sys/user.h @@ -0,0 +1,49 @@ +#ifndef _SYS_USER_H +#define _SYS_USER_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct user_fpregs_struct { + uint16_t cwd, swd, ftw, fop; + uint64_t rip, rdp; + uint32_t mxcsr, mxcr_mask; + uint32_t st_space[32], xmm_space[64], padding[24]; +} elf_fpregset_t; + +struct user_regs_struct { + unsigned long r15, r14, r13, r12, rbp, rbx, r11, r10, r9, r8; + unsigned long rax, rcx, rdx, rsi, rdi, orig_rax, rip; + unsigned long cs, eflags, rsp, ss, fs_base, gs_base, ds, es, fs, gs; +}; + +struct user { + struct user_regs_struct regs; + int u_fpvalid; + struct user_fpregs_struct i387; + unsigned long u_tsize; + unsigned long u_dsize; + unsigned long u_ssize; + unsigned long start_code; + unsigned long start_stack; + long signal; + int reserved; + struct user_regs_struct *u_ar0; + struct user_fpregs_struct *u_fpstate; + unsigned long magic; + char u_comm[32]; + unsigned long u_debugreg[8]; +}; + +#ifdef __cplusplus +} +#endif + +#define PAGE_SHIFT 12 +#define PAGE_SIZE (1UL << PAGE_SHIFT) +#define PAGE_MASK (~(PAGE_SIZE - 1)) + +#endif diff --git a/lib/mlibc/options/glibc/include/sysexits.h b/lib/mlibc/options/glibc/include/sysexits.h new file mode 100644 index 0000000..f3bde25 --- /dev/null +++ b/lib/mlibc/options/glibc/include/sysexits.h @@ -0,0 +1,24 @@ +#ifndef _SYSEXITS_H +#define _SYSEXITS_H + +#define EX_OK 0 +#define EX_USAGE 64 +#define EX_DATAERR 65 +#define EX_NOINPUT 66 +#define EX_NOUSER 67 +#define EX_NOHOST 68 +#define EX_UNAVAILABLE 69 +#define EX_SOFTWARE 70 +#define EX_OSERR 71 +#define EX_OSFILE 72 +#define EX_CANTCREAT 73 +#define EX_IOERR 74 +#define EX_TEMPFAIL 75 +#define EX_PROTOCOL 76 +#define EX_NOPERM 77 +#define EX_CONFIG 78 + +#define EX__BASE 64 +#define EX__MAX 78 + +#endif // _SYSEXITS_H diff --git a/lib/mlibc/options/glibc/meson.build b/lib/mlibc/options/glibc/meson.build new file mode 100644 index 0000000..93bad85 --- /dev/null +++ b/lib/mlibc/options/glibc/meson.build @@ -0,0 +1,90 @@ +if disable_glibc_option + subdir_done() +endif +libc_sources += files( + 'generic/getopt-stubs.cpp', + 'generic/stdio_ext-stubs.cpp', + 'generic/sys-ioctl.cpp', + 'generic/err.cpp', + 'generic/error.cpp', + 'generic/resolv-stubs.cpp', + 'generic/shadow-stubs.cpp', + 'generic/printf.cpp', + 'generic/glibc-signal.cpp', + 'generic/execinfo.cpp', + 'generic/string.cpp', + 'generic/personality.cpp', + 'generic/gshadow.cpp', + 'generic/sys-timex.cpp', + 'generic/glibc-assert.cpp', + 'generic/malloc.cpp', + 'generic/sys-io.cpp', +) + +if not no_headers + install_headers( + 'include/getopt.h', + 'include/stdio_ext.h', + 'include/err.h', + 'include/error.h', + 'include/paths.h', + 'include/sysexits.h', + 'include/resolv.h', + 'include/endian.h', + 'include/ar.h', + 'include/shadow.h', + 'include/memory.h', + 'include/printf.h', + 'include/gshadow.h', + 'include/execinfo.h', + 'include/features.h' + ) + install_headers( + 'include/sys/dir.h', + 'include/sys/ioctl.h', + 'include/sys/user.h', + 'include/sys/procfs.h', + 'include/sys/reg.h', + 'include/sys/errno.h', + 'include/sys/signal.h', + 'include/sys/ucontext.h', + 'include/sys/personality.h', + 'include/sys/timeb.h', + 'include/sys/mtio.h', + 'include/sys/endian.h', + 'include/sys/timex.h', + 'include/sys/kd.h', + 'include/sys/io.h', + subdir: 'sys' + ) + install_headers( + 'include/net/ethernet.h', + 'include/net/route.h', + 'include/net/if_ppp.h', + subdir: 'net' + ) + install_headers( + 'include/netax25/ax25.h', + subdir: 'netax25' + ) + install_headers( + 'include/netipx/ipx.h', + subdir: 'netipx' + ) + install_headers( + 'include/netrom/netrom.h', + subdir: 'netrom' + ) + install_headers( + 'include/netinet/in_systm.h', + subdir: 'netinet' + ) + install_headers( + 'include/bits/glibc/glibc_signal.h', + 'include/bits/glibc/glibc_assert.h', + 'include/bits/glibc/glibc_malloc.h', + 'include/bits/glibc/glibc_icmp6.h', + subdir: 'bits/glibc' + ) +endif + diff --git a/lib/mlibc/options/iconv/generic/iconv-stubs.cpp b/lib/mlibc/options/iconv/generic/iconv-stubs.cpp new file mode 100644 index 0000000..ecaa7bf --- /dev/null +++ b/lib/mlibc/options/iconv/generic/iconv-stubs.cpp @@ -0,0 +1,34 @@ +#include +#include +#include + +size_t iconv(iconv_t cd, char **__restrict inbuf, size_t *__restrict inbytesleft, char **__restrict outbuf, size_t *__restrict outbytesleft) { + (void)inbytesleft; + (void)outbytesleft; + + mlibc::infoLogger() << "iconv() is unimplemented!" << frg::endlog; + if(cd == (iconv_t)1) { // UTF-8 to UTF-8 + mlibc::infoLogger() << "iconv() from and to are the same, memcpy it is" << frg::endlog; + memcpy(inbuf, outbuf, sizeof(inbuf)); + return sizeof(outbuf); + } + __ensure(!"iconv() not implemented"); + __builtin_unreachable(); +} + +int iconv_close(iconv_t) { + return 0; +} + +iconv_t iconv_open(const char *tocode, const char *fromcode) { + mlibc::infoLogger() << "iconv_open() is unimplemented! args: " << tocode << " and: " << fromcode << frg::endlog; + if(!strcmp(tocode, "UTF-8") && !strcmp(fromcode, "UTF-8")) { + mlibc::infoLogger() << "iconv_open() with UTF-8 on both is a no-op!" << frg::endlog; + iconv_t cd = (iconv_t)1; + return cd; + } + __ensure(!"iconv_open() not implemented"); + __builtin_unreachable(); +} + + diff --git a/lib/mlibc/options/iconv/include/iconv.h b/lib/mlibc/options/iconv/include/iconv.h new file mode 100644 index 0000000..68c1114 --- /dev/null +++ b/lib/mlibc/options/iconv/include/iconv.h @@ -0,0 +1,25 @@ +#ifndef _ICONV_H +#define _ICONV_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void *iconv_t; + +#ifndef __MLIBC_ABI_ONLY + +size_t iconv(iconv_t, char **__restrict, size_t *__restrict, char **__restrict, size_t *__restrict); +int iconv_close(iconv_t); +iconv_t iconv_open(const char *, const char *); + +#endif /* !__MLIBC_ABI_ONLY */ + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib/mlibc/options/iconv/meson.build b/lib/mlibc/options/iconv/meson.build new file mode 100644 index 0000000..079d868 --- /dev/null +++ b/lib/mlibc/options/iconv/meson.build @@ -0,0 +1,12 @@ +if disable_iconv_option + subdir_done() +endif +libc_sources += files( + 'generic/iconv-stubs.cpp', +) + +if not no_headers + install_headers( + 'include/iconv.h', + ) +endif diff --git a/lib/mlibc/options/internal/aarch64-include/mlibc/arch-defs.hpp b/lib/mlibc/options/internal/aarch64-include/mlibc/arch-defs.hpp new file mode 100644 index 0000000..0a4789f --- /dev/null +++ b/lib/mlibc/options/internal/aarch64-include/mlibc/arch-defs.hpp @@ -0,0 +1,12 @@ +#ifndef MLIBC_ARCH_DEFS_HPP +#define MLIBC_ARCH_DEFS_HPP + +#include + +namespace mlibc { + +inline constexpr size_t page_size = 0x1000; + +} // namespace mlibc + +#endif // MLIBC_ARCH_DEFS_HPP diff --git a/lib/mlibc/options/internal/aarch64-include/mlibc/thread.hpp b/lib/mlibc/options/internal/aarch64-include/mlibc/thread.hpp new file mode 100644 index 0000000..b62d832 --- /dev/null +++ b/lib/mlibc/options/internal/aarch64-include/mlibc/thread.hpp @@ -0,0 +1,21 @@ +#pragma once + +#include +#include + +namespace mlibc { + +inline Tcb *get_current_tcb() { + // On AArch64, TPIDR_EL0 points to 0x10 bytes before the first TLS block. + uintptr_t ptr; + asm ("mrs %0, tpidr_el0" : "=r"(ptr)); + return reinterpret_cast(ptr + 0x10 - sizeof(Tcb)); +} + +inline uintptr_t get_sp() { + uintptr_t sp; + asm ("mov %0, sp" : "=r"(sp)); + return sp; +} + +} // namespace mlibc diff --git a/lib/mlibc/options/internal/aarch64/fenv.S b/lib/mlibc/options/internal/aarch64/fenv.S new file mode 100644 index 0000000..1b02e87 --- /dev/null +++ b/lib/mlibc/options/internal/aarch64/fenv.S @@ -0,0 +1,69 @@ +# The functions below are taken from musl. +.global fegetround +.type fegetround,%function +fegetround: + mrs x0, fpcr + and w0, w0, #0xc00000 + ret + +.global __fesetround +.hidden __fesetround +.type __fesetround,%function +__fesetround: + mrs x1, fpcr + bic w1, w1, #0xc00000 + orr w1, w1, w0 + msr fpcr, x1 + mov w0, #0 + ret + +.global fetestexcept +.type fetestexcept,%function +fetestexcept: + and w0, w0, #0x1f + mrs x1, fpsr + and w0, w0, w1 + ret + +.global feclearexcept +.type feclearexcept,%function +feclearexcept: + and w0, w0, #0x1f + mrs x1, fpsr + bic w1, w1, w0 + msr fpsr, x1 + mov w0, #0 + ret + +.global feraiseexcept +.type feraiseexcept,%function +feraiseexcept: + and w0, w0, #0x1f + mrs x1, fpsr + orr w1, w1, w0 + msr fpsr, x1 + mov w0, #0 + ret + +.global fegetenv +.type fegetenv,%function +fegetenv: + mrs x1, fpcr + mrs x2, fpsr + stp w1, w2, [x0] + mov w0, #0 + ret + +// TODO preserve some bits +.global fesetenv +.type fesetenv,%function +fesetenv: + mov x1, #0 + mov x2, #0 + cmn x0, #1 + b.eq 1f + ldp w1, w2, [x0] +1: msr fpcr, x1 + msr fpsr, x2 + mov w0, #0 + ret diff --git a/lib/mlibc/options/internal/aarch64/mlibc_crtbegin.S b/lib/mlibc/options/internal/aarch64/mlibc_crtbegin.S new file mode 100644 index 0000000..b99748b --- /dev/null +++ b/lib/mlibc/options/internal/aarch64/mlibc_crtbegin.S @@ -0,0 +1,29 @@ + +.section .data +.hidden __dso_handle +.global __dso_handle +__dso_handle: + .quad __dso_handle + +.section .init +.hidden _init +.global _init +_init: + +.section .fini +.hidden _fini +.global _fini +_fini: + +.section .ctors +.hidden __CTOR_LIST__ +.global __CTOR_LIST__ +__CTOR_LIST__: + +.section .dtors +.hidden __DTOR_LIST__ +.global __DTOR_LIST__ +__DTOR_LIST__: + +.section .note.GNU-stack,"",%progbits + diff --git a/lib/mlibc/options/internal/aarch64/mlibc_crtend.S b/lib/mlibc/options/internal/aarch64/mlibc_crtend.S new file mode 100644 index 0000000..2bf6254 --- /dev/null +++ b/lib/mlibc/options/internal/aarch64/mlibc_crtend.S @@ -0,0 +1,22 @@ + +.hidden __mlibc_do_ctors +.hidden __mlibc_do_dtors + +.section .init + b __mlibc_do_ctors + +.section .fini + b __mlibc_do_dtors + +.section .ctors +.hidden __CTOR_END__ +.global __CTOR_END__ +__CTOR_END__: + +.section .dtors +.hidden __DTOR_END__ +.global __DTOR_END__ +__DTOR_END__: + +.section .note.GNU-stack,"",%progbits + diff --git a/lib/mlibc/options/internal/aarch64/setjmp.S b/lib/mlibc/options/internal/aarch64/setjmp.S new file mode 100644 index 0000000..9dddaa8 --- /dev/null +++ b/lib/mlibc/options/internal/aarch64/setjmp.S @@ -0,0 +1,63 @@ +// vim: ft=arm64asm + +.extern __sigsetjmp + +.type __setjmp, "function" +__setjmp: + stp x19, x20, [x0, #0] + stp x21, x22, [x0, #16] + stp x23, x24, [x0, #24] + stp x25, x26, [x0, #32] + stp x27, x28, [x0, #48] + stp x29, x30, [x0, #64] + stp x29, x30, [x0, #80] + mov x4, sp + str x4, [x0, #96] + + stp d8, d9, [x0, #112] + stp d10, d11, [x0, #128] + stp d12, d13, [x0, #144] + stp d14, d15, [x0, #160] + + cbnz x2, 1f + + mov x0, xzr + ret +1: + b __sigsetjmp + +.global setjmp +.type setjmp, "function" +setjmp: + mov x2, xzr + b __setjmp + +.global sigsetjmp +.type sigsetjmp, "function" +sigsetjmp: + mov x2, #1 + b __setjmp + +.global longjmp +.type longjmp, "function" +longjmp: + ldp x19, x20, [x0, #0] + ldp x21, x22, [x0, #16] + ldp x23, x24, [x0, #24] + ldp x25, x26, [x0, #32] + ldp x27, x28, [x0, #48] + ldp x29, x30, [x0, #64] + ldp x29, x30, [x0, #80] + ldr x4, [x0, #96] + mov sp, x4 + + 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 +.section .note.GNU-stack,"",%progbits + diff --git a/lib/mlibc/options/internal/gcc-extra/cxxabi.cpp b/lib/mlibc/options/internal/gcc-extra/cxxabi.cpp new file mode 100644 index 0000000..c5bd92f --- /dev/null +++ b/lib/mlibc/options/internal/gcc-extra/cxxabi.cpp @@ -0,0 +1,20 @@ + +#include + +// The cxxabi needs operator delete for *deleting* destructors, i.e., destructors that +// are called by delete expressions. We never use such expressions in mlibc. +// Note that G++ complains if we make the operator hidden, +// thus we use it's mangled name as a workaround. +#if defined(__clang__) + extern "C" [[gnu::visibility("hidden")]] void _ZdlPv() { // operator delete (void *, size_t) + __ensure(!"operator delete called! delete expressions cannot be used in mlibc."); + } +#else + extern "C" [[gnu::visibility("hidden")]] void _ZdlPvj() { // operator delete (void *, unsigned int) + __ensure(!"operator delete called! delete expressions cannot be used in mlibc."); + } + + extern "C" [[gnu::visibility("hidden")]] void _ZdlPvm() { // operator delete (void *, size_t) + __ensure(!"operator delete called! delete expressions cannot be used in mlibc."); + } +#endif \ No newline at end of file diff --git a/lib/mlibc/options/internal/gcc/guard-abi.cpp b/lib/mlibc/options/internal/gcc/guard-abi.cpp new file mode 100644 index 0000000..945582a --- /dev/null +++ b/lib/mlibc/options/internal/gcc/guard-abi.cpp @@ -0,0 +1,68 @@ + +#include +#include +#include + +#include +#include + +namespace { + +// Itanium ABI static initialization guard. +struct Guard { + // bit of the mutex member variable. + // indicates that the mutex is locked. + static constexpr int32_t locked = 1; + + void lock() { + uint32_t v = 0; + if(__atomic_compare_exchange_n(&mutex, &v, Guard::locked, false, + __ATOMIC_ACQUIRE, __ATOMIC_RELAXED)) + return; + + mlibc::sys_libc_log("__cxa_guard_acquire contention"); + __builtin_trap(); + } + + void unlock() { + __atomic_store_n(&mutex, 0, __ATOMIC_RELEASE); + } + + // the first byte's meaning is fixed by the ABI. + // it indicates whether initialization has already been completed. + uint8_t complete; + + // we use some of the remaining bytes to implement a mutex. + uint32_t mutex; +}; + +static_assert(sizeof(Guard) == sizeof(int64_t)); + +} // namespace { } + +extern "C" [[ gnu::visibility("hidden") ]] void __cxa_pure_virtual() { + mlibc::panicLogger() << "mlibc: Pure virtual function called from IP " + << (void *)__builtin_return_address(0) << frg::endlog; +} + +extern "C" [[ gnu::visibility("hidden") ]] int __cxa_guard_acquire(int64_t *ptr) { + auto guard = reinterpret_cast(ptr); + guard->lock(); + // relaxed ordering is sufficient because + // Guard::complete is only modified while the mutex is held. + if(__atomic_load_n(&guard->complete, __ATOMIC_RELAXED)) { + guard->unlock(); + return 0; + }else{ + return 1; + } +} + +extern "C" [[ gnu::visibility("hidden") ]] void __cxa_guard_release(int64_t *ptr) { + auto guard = reinterpret_cast(ptr); + // do a store-release so that compiler generated code can skip calling + // __cxa_guard_acquire by doing a load-acquire on Guard::complete. + __atomic_store_n(&guard->complete, 1, __ATOMIC_RELEASE); + guard->unlock(); +} + diff --git a/lib/mlibc/options/internal/gcc/initfini.cpp b/lib/mlibc/options/internal/gcc/initfini.cpp new file mode 100644 index 0000000..b329f38 --- /dev/null +++ b/lib/mlibc/options/internal/gcc/initfini.cpp @@ -0,0 +1,23 @@ + +#include +#include +#include + +#include +#include + +typedef void (*InitPtr)(); + +extern InitPtr __CTOR_LIST__ [[ gnu::visibility("hidden") ]]; +extern InitPtr __CTOR_END__ [[ gnu::visibility("hidden") ]]; + +extern "C" [[ gnu::visibility("hidden") ]] void __mlibc_do_ctors() { + auto it = &__CTOR_LIST__; + while(it != &__CTOR_END__) + (*it++)(); +} + +extern "C" [[ gnu::visibility("hidden") ]] void __mlibc_do_dtors() { + mlibc::sys_libc_log("__mlibc_do_dtors() called"); +} + diff --git a/lib/mlibc/options/internal/gcc/stack_protector.cpp b/lib/mlibc/options/internal/gcc/stack_protector.cpp new file mode 100644 index 0000000..e5e50f0 --- /dev/null +++ b/lib/mlibc/options/internal/gcc/stack_protector.cpp @@ -0,0 +1,31 @@ +#include +#include +#include +#include + +uintptr_t __stack_chk_guard = 0; + +namespace mlibc { + +void initStackGuard(void *entropy) { + if(entropy != nullptr) { + memcpy(&__stack_chk_guard, entropy, sizeof(__stack_chk_guard)); + } else { + // If no entropy is available, set it to the terminator canary + __stack_chk_guard = 0; + __stack_chk_guard |= ('\n' << 16); + __stack_chk_guard |= (255 << 24); + } +} + +} // namespace mlibc + +extern "C" [[noreturn]] void __stack_chk_fail() { + mlibc::panicLogger() << "Stack smashing detected!" << frg::endlog; + __builtin_unreachable(); +} + +extern "C" [[noreturn, gnu::visibility("hidden")]] void __stack_chk_fail_local() { + __stack_chk_fail(); +}; + diff --git a/lib/mlibc/options/internal/generic/allocator.cpp b/lib/mlibc/options/internal/generic/allocator.cpp new file mode 100644 index 0000000..d738212 --- /dev/null +++ b/lib/mlibc/options/internal/generic/allocator.cpp @@ -0,0 +1,196 @@ + +#include + +#include +#include +#include +#include +#include + +#if !MLIBC_DEBUG_ALLOCATOR + +// -------------------------------------------------------- +// Globals +// -------------------------------------------------------- + +MemoryAllocator &getAllocator() { + // use frg::eternal to prevent a call to __cxa_atexit(). + // this is necessary because __cxa_atexit() call this function. + static frg::eternal virtualAllocator; + static frg::eternal heap{virtualAllocator.get()}; + static frg::eternal singleton{&heap.get()}; + return singleton.get(); +} + +// -------------------------------------------------------- +// VirtualAllocator +// -------------------------------------------------------- + +uintptr_t VirtualAllocator::map(size_t length) { + void *ptr; + __ensure(!mlibc::sys_anon_allocate(length, &ptr)); + return (uintptr_t)ptr; +} + +void VirtualAllocator::unmap(uintptr_t address, size_t length) { + __ensure(!mlibc::sys_anon_free((void *)address, length)); +} + +#else + +namespace { + struct AllocatorMeta { + size_t allocatedSize; + size_t pagesSize; + frg::array magic; + }; + + constexpr frg::array allocatorMagic { + 0x6d4bbb9f3446e83f, 0x25e213a7a7f9f954, + 0x1a3c667586538bef, 0x994f34ff71c090bc + }; +} // namespace anonymous + +// Turn vm_unmap calls in free into vm_map(..., PROT_NONE, ...) calls to prevent +// those addresses from being reused. This is useful for detecting situations like this: +// 1. Allocate object X at address Y +// 2. Do some computation using object X +// 3. Free object X at address Y +// 4. Allocate object Z at address W, and it so happens that W == Y +// 5. Try to use object X, but the memory which was backing it now contains object Z +constexpr bool neverReleaseVa = false; +constexpr bool logAllocations = false; + +// Area before the returned allocated block (which exists due to us offseting +// the block to be as close to the edge of a page). +constexpr uint8_t offsetAreaValue = 'A'; +// Area which we return a pointer to in allocate and reallocate. +constexpr uint8_t allocatedAreaValue = 'B'; +// Area after the allocated block, which exists due to the alignment constraints. +constexpr uint8_t alignmentAreaValue = 'C'; +// Remaining area within the metadata page after the metadata. +constexpr uint8_t metaAreaValue = 'D'; + +// Alignment of the returned memory. +// TODO(qookie): Eventually accept alignment as an argument of allocate. +constexpr size_t pointerAlignment = 16; + +// TODO(qookie): Support this. Perhaps by overallocating by 2x and then picking +// an offset that guarantees the desired alignment. +static_assert(pointerAlignment <= 4096, "Pointer aligment of more than 4096 bytes is unsupported"); +static_assert(!(pointerAlignment & (pointerAlignment - 1)), + "Pointer aligment must be a power of 2"); + +constexpr size_t pageSize = 0x1000; + +void *MemoryAllocator::allocate(size_t size) { + size_t pg_size = (size + size_t{pageSize - 1}) & ~size_t{pageSize - 1}; + size_t offset = (pg_size - size) & ~size_t{pointerAlignment - 1}; + + void *ptr; + + // Two extra pages for metadata in front and guard page at the end + // Reserve the whole region as PROT_NONE... + if (int e = mlibc::sys_vm_map(nullptr, pg_size + pageSize * 2, PROT_NONE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0, &ptr)) + mlibc::panicLogger() << "sys_vm_map failed in MemoryAllocator::allocate (errno " << e << ")" << frg::endlog; + + // ...Then replace pages to make them accessible, excluding the guard page + if (int e = mlibc::sys_vm_map(ptr, pg_size + pageSize, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, -1, 0, &ptr)) + mlibc::panicLogger() << "sys_vm_map failed in MemoryAllocator::allocate (errno " << e << ")" << frg::endlog; + + void *meta = ptr; + void *out_page = reinterpret_cast(reinterpret_cast(ptr) + pageSize); + void *out = reinterpret_cast(reinterpret_cast(out_page) + offset); + void *out_align_area = reinterpret_cast(reinterpret_cast(out) + size); + + AllocatorMeta metaData{size, pg_size, allocatorMagic}; + + memset(meta, metaAreaValue, pageSize); + memcpy(meta, &metaData, sizeof(AllocatorMeta)); + + memset(out_page, offsetAreaValue, offset); + memset(out, allocatedAreaValue, size); + memset(out_align_area, alignmentAreaValue, pg_size - offset - size); + + if constexpr (logAllocations) + mlibc::infoLogger() << "MemoryAllocator::allocate(" << size << ") = " << out << frg::endlog; + + return out; +} + +void MemoryAllocator::free(void *ptr) { + if (!ptr) + return; + + if constexpr (logAllocations) + mlibc::infoLogger() << "MemoryAllocator::free(" << ptr << ")" << frg::endlog; + + uintptr_t page_addr = reinterpret_cast(ptr) & ~size_t{pageSize - 1}; + AllocatorMeta *meta = reinterpret_cast(page_addr - pageSize); + + if (meta->magic != allocatorMagic) + mlibc::panicLogger() << "Invalid allocator metadata magic in MemoryAllocator::free" << frg::endlog; + + deallocate(ptr, meta->allocatedSize); +} + +void MemoryAllocator::deallocate(void *ptr, size_t size) { + if (!ptr) + return; + + if constexpr (logAllocations) + mlibc::infoLogger() << "MemoryAllocator::deallocate(" << ptr << ", " << size << ")" << frg::endlog; + + uintptr_t page_addr = reinterpret_cast(ptr) & ~size_t{pageSize - 1}; + AllocatorMeta *meta = reinterpret_cast(page_addr - pageSize); + + if (meta->magic != allocatorMagic) + mlibc::panicLogger() << "Invalid allocator metadata magic in MemoryAllocator::deallocate" << frg::endlog; + + if (size != meta->allocatedSize) + mlibc::panicLogger() << "Invalid allocated size in metadata in MemoryAllocator::deallocate (given " << size << ", stored " << meta->allocatedSize << ")" << frg::endlog; + + if constexpr (neverReleaseVa) { + void *unused; + if (int e = mlibc::sys_vm_map(meta, meta->pagesSize + pageSize * 2, PROT_NONE, MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, -1, 0, &unused)) + mlibc::panicLogger() << "sys_vm_map failed in MemoryAllocator::deallocate (errno " << e << ")" << frg::endlog; + } else { + if (int e = mlibc::sys_vm_unmap(meta, meta->pagesSize + pageSize * 2)) + mlibc::panicLogger() << "sys_vm_unmap failed in MemoryAllocator::deallocate (errno " << e << ")" << frg::endlog; + } +} + +void *MemoryAllocator::reallocate(void *ptr, size_t size) { + if (!size) { + free(ptr); + return nullptr; + } + + void *newArea = allocate(size); + + if (ptr) { + uintptr_t page_addr = reinterpret_cast(ptr) & ~size_t{pageSize - 1}; + AllocatorMeta *meta = reinterpret_cast(page_addr - pageSize); + + if (meta->magic != allocatorMagic) + mlibc::panicLogger() << "Invalid allocator metadata magic in MemoryAllocator::reallocate" << frg::endlog; + + memcpy(newArea, ptr, frg::min(meta->allocatedSize, size)); + + deallocate(ptr, meta->allocatedSize); + } + + if constexpr (logAllocations) + mlibc::infoLogger() << "MemoryAllocator::reallocate(" << ptr << ", " << size << ") = " << newArea << frg::endlog; + + return newArea; +} + +MemoryAllocator &getAllocator() { + // use frg::eternal to prevent a call to __cxa_atexit(). + // this is necessary because __cxa_atexit() call this function. + static frg::eternal singleton{}; + return singleton.get(); +} + +#endif /* !MLIBC_DEBUG_ALLOCATOR */ diff --git a/lib/mlibc/options/internal/generic/charcode.cpp b/lib/mlibc/options/internal/generic/charcode.cpp new file mode 100644 index 0000000..e09d5cd --- /dev/null +++ b/lib/mlibc/options/internal/generic/charcode.cpp @@ -0,0 +1,244 @@ + +#include +#include +#include +#include + +namespace mlibc { + +struct utf8_charcode { + static constexpr bool preserves_7bit_units = true; + static constexpr bool has_shift_states = false; + + struct decode_state { + decode_state() + : _progress{0}, _cpoint{0} { } + + auto progress() { return _progress; } + auto cpoint() { return _cpoint; } + + charcode_error operator() (code_seq &seq) { + auto uc = static_cast(*seq.it); + if(!_progress) { + if(!(uc & 0b1000'0000)) { + // ASCII-compatible. + _cpoint = uc; + }else if((uc & 0b1110'0000) == 0b1100'0000) { + _cpoint = uc & 0b1'1111; + _progress = 1; + }else if((uc & 0b1111'0000) == 0b1110'0000) { + _cpoint = uc & 0b1111; + _progress = 2; + }else if((uc & 0b1111'1000) == 0b1111'0000) { + _cpoint = uc & 0b111; + _progress = 3; + }else{ + // If the highest two bits are 0b10, this is the second (or later) unit. + // Units with highest five bits = 0b11111 do not occur in valid UTF-8. + __ensure((uc & 0b1100'0000) == 0b1000'0000 + || (uc & 0b1111'1000) == 0b1111'1000); + return charcode_error::illegal_input; + } + }else{ + // TODO: Return an error. + __ensure((uc & 0b1100'0000) == 0b1000'0000); + _cpoint = (_cpoint << 6) | (uc & 0x3F); + --_progress; + } + ++seq.it; + return charcode_error::null; + } + + private: + int _progress; + codepoint _cpoint; + }; + + struct encode_state { + // Encodes a single character from wseq + the current state and stores it in nseq. + // TODO: Convert decode_state to the same strategy. + charcode_error operator() (code_seq &nseq, code_seq &wseq) { + auto wc = *wseq.it; + __ensure(wc <= 0x7F && "utf8_charcode cannot encode multibyte chars yet"); + *nseq.it = wc; + ++wseq.it; + ++nseq.it; + return charcode_error::null; + } + }; +}; + +polymorphic_charcode::~polymorphic_charcode() = default; + +// For *decoding, this class assumes that: +// - G::decode_state has members progress() and cpoint(). +// - G::decode_state::progress() >= 0 at all times. +// TODO: This will be needed on platforms like Windows, where wchar_t is UTF-16. +// TODO: There, we can use negative __mlibc_mbstate::progress to represent encoding to UTF-16. +// - If G::decode_state::progress() == 0, the code point (given by cpoint()) +// was decoded successfully. +template +struct polymorphic_charcode_adapter : polymorphic_charcode { + polymorphic_charcode_adapter() + : polymorphic_charcode{G::preserves_7bit_units, G::has_shift_states} { } + + charcode_error decode(code_seq &nseq, code_seq &wseq, + __mlibc_mbstate &st) override { + __ensure(!st.__progress); // TODO: Update st with ds.progress() and ds.cpoint(). + + code_seq decode_nseq = nseq; + typename G::decode_state ds; + + while(decode_nseq && wseq) { + // Consume the next code unit. + if(auto e = ds(decode_nseq); e != charcode_error::null) + return e; + + // Produce a new code point. + if(!ds.progress()) { + // "Commit" consumed code units (as there was no decode error). + nseq.it = decode_nseq.it; + if(!ds.cpoint()) // Stop on null characters. + return charcode_error::null; + *wseq.it = ds.cpoint(); + ++wseq.it; + } + } + + if(ds.progress()) + return charcode_error::input_underflow; + return charcode_error::null; + } + + charcode_error decode_wtranscode(code_seq &nseq, code_seq &wseq, + __mlibc_mbstate &st) override { + __ensure(!st.__progress); // TODO: Update st with ds.progress() and ds.cpoint(). + + code_seq decode_nseq = nseq; + typename G::decode_state ds; + + while(decode_nseq && wseq) { + // Consume the next code unit. + if(auto e = ds(decode_nseq); e != charcode_error::null) + return e; + + // Produce a new code point. + if(!ds.progress()) { + nseq.it = decode_nseq.it; + // "Commit" consumed code units (as there was no decode error). + if(!ds.cpoint()) // Stop on null characters. + return charcode_error::null; + *wseq.it = ds.cpoint(); + ++wseq.it; + } + } + + if(ds.progress()) + return charcode_error::input_underflow; + return charcode_error::null; + } + + charcode_error decode_wtranscode_length(code_seq &nseq, size_t *n, + __mlibc_mbstate &st) override { + __ensure(!st.__progress); // TODO: Update st with ds.progress() and ds.cpoint(). + + code_seq decode_nseq = nseq; + typename G::decode_state ds; + + *n = 0; + while(decode_nseq) { + // Consume the next code unit. + if(auto e = ds(decode_nseq); e != charcode_error::null) + return e; + + if(!ds.progress()) { + nseq.it = decode_nseq.it; + // "Commit" consumed code units (as there was no decode error). + if(!ds.cpoint()) // Stop on null code points. + return charcode_error::null; + ++(*n); + } + } + + if(ds.progress()) + return charcode_error::input_underflow; + return charcode_error::null; + } + + charcode_error encode_wtranscode(code_seq &nseq, code_seq &wseq, + __mlibc_mbstate &st) override { + __ensure(!st.__progress); // TODO: Update st with es.progress() and es.cpoint(). + + code_seq encode_nseq = nseq; + typename G::encode_state es; + + while(encode_nseq && wseq) { + codepoint cp = *wseq.it; + if(!cp) + return charcode_error::null; + + code_seq cps{&cp, &cp + 1}; + if(auto e = es(encode_nseq, cps); e == charcode_error::dirty) { + continue; + }else if(e != charcode_error::null) { + return e; + } + __ensure(cps.it == cps.end); + ++wseq.it; + + // "Commit" produced code units (as there was no encode error). + nseq.it = encode_nseq.it; + } + + if(encode_nseq.it != nseq.it) + return charcode_error::output_overflow; + return charcode_error::null; + } + + charcode_error encode_wtranscode_length(code_seq &wseq, size_t *n, + __mlibc_mbstate &st) override { + __ensure(!st.__progress); // TODO: Update st with es.progress() and es.cpoint(). + + typename G::encode_state es; + + *n = 0; + while(wseq) { + char temp[4]; + code_seq encode_nseq{temp, temp + 4}; + codepoint cp = *wseq.it; + if(!cp) + return charcode_error::null; + // Consume the next code unit. + code_seq cps{&cp, &cp + 1}; + if(auto e = es(encode_nseq, cps); e == charcode_error::dirty) { + continue; + }else if(e != charcode_error::null) { + return e; + } + + ++(*n); + ++wseq.it; + } + + return charcode_error::null; + } +}; + +polymorphic_charcode *current_charcode() { + static polymorphic_charcode_adapter global_charcode; + return &global_charcode; +} + +charcode_error wide_charcode::promote(wchar_t nc, codepoint &wc) { + // TODO: Allow non-identity encodings of wchar_t. + wc = nc; + return charcode_error::null; +} + +wide_charcode *platform_wide_charcode() { + static wide_charcode global_wide_charcode; + return &global_wide_charcode; +} + +} // namespace mlibc + diff --git a/lib/mlibc/options/internal/generic/charset.cpp b/lib/mlibc/options/internal/generic/charset.cpp new file mode 100644 index 0000000..c42b4f4 --- /dev/null +++ b/lib/mlibc/options/internal/generic/charset.cpp @@ -0,0 +1,144 @@ + +#include +#include +#include + +namespace mlibc { + +bool charset::is_ascii_superset() { + // TODO: For locales that change the meaning of ASCII chars, this needs to be changed. + return true; +} + +bool charset::is_alpha(codepoint c) { + if(c <= 0x7F && is_ascii_superset()) + return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); + if(c > 0x7F) + mlibc::infoLogger() << "mlibc: charset::is_alpha() is not implemented" + " for the full Unicode charset" << frg::endlog; + return false; +} + +bool charset::is_digit(codepoint c) { + if(c <= 0x7F && is_ascii_superset()) + return c >= '0' && c <= '9'; + if(c > 0x7F) + mlibc::infoLogger() << "mlibc: charset::is_digit() is not implemented" + " for the full Unicode charset" << frg::endlog; + return false; +} + +bool charset::is_xdigit(codepoint c) { + if(c <= 0x7F && is_ascii_superset()) + return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'); + if(c > 0x7F) + mlibc::infoLogger() << "mlibc: charset::is_xdigit() is not implemented" + " for the full Unicode charset" << frg::endlog; + return false; +} + +bool charset::is_alnum(codepoint c) { + if(c <= 0x7F && is_ascii_superset()) + return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); + if(c > 0x7F) + mlibc::infoLogger() << "mlibc: charset::is_alnum() is not implemented" + " for the full Unicode charset" << frg::endlog; + return false; +} + +bool charset::is_punct(codepoint c) { + if(c <= 0x7F && is_ascii_superset()) + return c == '!' || c == '"' || c == '#' || c == '$' || c == '%' || c == '&' + || c == '\'' || c == '(' || c == ')' || c == '*' || c == '+' || c == ',' + || c == '-' || c == '.' || c == '/' + || c == ':' || c == ';' || c == '<' || c == '=' || c == '>' || c == '?' + || c == '@' + || c == '[' || c == '\\' || c == ']' || c == '^' || c == '_' || c == '`' + || c == '{' || c == '|' || c == '}' || c == '~'; + if(c > 0x7F) + mlibc::infoLogger() << "mlibc: charset::is_punct() is not implemented" + " for the full Unicode charset" << frg::endlog; + return false; +} + +bool charset::is_graph(codepoint c) { + if(c <= 0x7F && is_ascii_superset()) + return c >= 0x21 && c <= 0x7E; + if(c > 0x7F) + mlibc::infoLogger() << "mlibc: charset::is_graph() is not implemented" + " for the full Unicode charset" << frg::endlog; + return false; +} + +bool charset::is_blank(codepoint c) { + if(c <= 0x7F && is_ascii_superset()) + return c == ' ' || c == '\t'; + if(c > 0x7F) + mlibc::infoLogger() << "mlibc: charset::is_blank() is not implemented" + " for the full Unicode charset " << c << frg::endlog; + return false; +} + +bool charset::is_space(codepoint c) { + if(c <= 0x7F && is_ascii_superset()) + return c == ' ' || c == '\t' || c == '\n' || c == '\v' || c == '\f' || c == '\r'; + if(c > 0x7F) + mlibc::infoLogger() << "mlibc: charset::is_space() is not implemented" + " for the full Unicode charset" << frg::endlog; + return false; +} + +bool charset::is_print(codepoint c) { + if(c <= 0x7F && is_ascii_superset()) + return c >= 0x20 && c <= 0x7E; + if(c > 0x7F) + mlibc::infoLogger() << "mlibc: charset::is_print() is not implemented" + " for the full Unicode charset" << frg::endlog; + return false; +} + +bool charset::is_lower(codepoint c) { + if(c <= 0x7F && is_ascii_superset()) + return (c >= 'a' && c <= 'z'); + if(c > 0x7F) + mlibc::infoLogger() << "mlibc: charset::is_print() is not implemented" + " for the full Unicode charset" << frg::endlog; + return false; +} + +bool charset::is_upper(codepoint c) { + if(c <= 0x7F && is_ascii_superset()) + return (c >= 'A' && c <= 'Z'); + if(c > 0x7F) + mlibc::infoLogger() << "mlibc: charset::is_print() is not implemented" + " for the full Unicode charset" << frg::endlog; + return false; +} + +codepoint charset::to_lower(codepoint c) { + if(c <= 0x7F && is_ascii_superset()) + if(c >= 'A' && c <= 'Z') + return c - 'A' + 'a'; + if(c > 0x7F) + mlibc::infoLogger() << "mlibc: charset::to_lower() is not implemented" + " for the full Unicode charset" << frg::endlog; + return c; +} + +codepoint charset::to_upper(codepoint c) { + if(c <= 0x7F && is_ascii_superset()) + if(c >= 'a' && c <= 'z') + return c - 'a' + 'A'; + if(c > 0x7F) + mlibc::infoLogger() << "mlibc: charset::to_upper() is not implemented" + " for the full Unicode charset" << frg::endlog; + return c; +} + +charset *current_charset() { + static charset global_charset; + return &global_charset; +} + +} // namespace mlibc + diff --git a/lib/mlibc/options/internal/generic/debug.cpp b/lib/mlibc/options/internal/generic/debug.cpp new file mode 100644 index 0000000..19427c8 --- /dev/null +++ b/lib/mlibc/options/internal/generic/debug.cpp @@ -0,0 +1,22 @@ + +#include +#include +#include + +namespace mlibc { + +frg::stack_buffer_logger infoLogger; +frg::stack_buffer_logger panicLogger; + +void InfoSink::operator() (const char *message) { + sys_libc_log(message); +} + +void PanicSink::operator() (const char *message) { +// sys_libc_log("mlibc: Write to PanicSink"); + sys_libc_log(message); + sys_libc_panic(); +} + +} // namespace mlibc + diff --git a/lib/mlibc/options/internal/generic/ensure.cpp b/lib/mlibc/options/internal/generic/ensure.cpp new file mode 100644 index 0000000..57c953a --- /dev/null +++ b/lib/mlibc/options/internal/generic/ensure.cpp @@ -0,0 +1,18 @@ + +#include +#include + +void __ensure_fail(const char *assertion, const char *file, unsigned int line, + const char *function) { + mlibc::panicLogger() << "In function " << function + << ", file " << file << ":" << line << "\n" + << "__ensure(" << assertion << ") failed" << frg::endlog; +} + +void __ensure_warn(const char *assertion, const char *file, unsigned int line, + const char *function) { + mlibc::infoLogger() << "In function " << function + << ", file " << file << ":" << line << "\n" + << "__ensure(" << assertion << ") failed" << frg::endlog; +} + diff --git a/lib/mlibc/options/internal/generic/essential.cpp b/lib/mlibc/options/internal/generic/essential.cpp new file mode 100644 index 0000000..d00df1e --- /dev/null +++ b/lib/mlibc/options/internal/generic/essential.cpp @@ -0,0 +1,217 @@ +#include +#include + +namespace { + // Needed since we cannot declare a templated enum. + template + struct word_helper { + using underlying [[gnu::aligned(1)]] = T; + enum class [[gnu::may_alias]] word_enum : underlying { }; + }; + + template + using word = typename word_helper::word_enum; + + template + [[gnu::always_inline]] + inline word alias_load(const unsigned char *&p) { + word value = *reinterpret_cast *>(p); + p += sizeof(T); + return value; + } + + template + [[gnu::always_inline]] + inline void alias_store(unsigned char *&p, word value) { + *reinterpret_cast *>(p) = value; + p += sizeof(T); + } + +#ifdef __LP64__ + void *forward_copy(void *__restrict dest, const void *__restrict src, size_t n) { + auto curDest = reinterpret_cast(dest); + auto curSrc = reinterpret_cast(src); + + while(n >= 8 * 8) { + auto w1 = alias_load(curSrc); + auto w2 = alias_load(curSrc); + auto w3 = alias_load(curSrc); + auto w4 = alias_load(curSrc); + auto w5 = alias_load(curSrc); + auto w6 = alias_load(curSrc); + auto w7 = alias_load(curSrc); + auto w8 = alias_load(curSrc); + alias_store(curDest, w1); + alias_store(curDest, w2); + alias_store(curDest, w3); + alias_store(curDest, w4); + alias_store(curDest, w5); + alias_store(curDest, w6); + alias_store(curDest, w7); + alias_store(curDest, w8); + n -= 8 * 8; + } + if(n >= 4 * 8) { + auto w1 = alias_load(curSrc); + auto w2 = alias_load(curSrc); + auto w3 = alias_load(curSrc); + auto w4 = alias_load(curSrc); + alias_store(curDest, w1); + alias_store(curDest, w2); + alias_store(curDest, w3); + alias_store(curDest, w4); + n -= 4 * 8; + } + if(n >= 2 * 8) { + auto w1 = alias_load(curSrc); + auto w2 = alias_load(curSrc); + alias_store(curDest, w1); + alias_store(curDest, w2); + n -= 2 * 8; + } + if(n >= 8) { + auto w = alias_load(curSrc); + alias_store(curDest, w); + n -= 8; + } + if(n >= 4) { + auto w = alias_load(curSrc); + alias_store(curDest, w); + n -= 4; + } + if(n >= 2) { + auto w = alias_load(curSrc); + alias_store(curDest, w); + n -= 2; + } + if(n) + *curDest = *curSrc; + return dest; + } +#else // !__LP64__ + void *forward_copy(void *dest, const void *src, size_t n) { + for(size_t i = 0; i < n; i++) + ((char *)dest)[i] = ((const char *)src)[i]; + return dest; + } +#endif // __LP64__ / !__LP64__ +} + +// -------------------------------------------------------------------------------------- +// memcpy() implementation. +// -------------------------------------------------------------------------------------- + + +void *memcpy(void *__restrict dest, const void *__restrict src, size_t n) { + return forward_copy(dest, src, n); +} + + +// -------------------------------------------------------------------------------------- +// memset() implementation. +// -------------------------------------------------------------------------------------- + +#ifdef __LP64__ + +void *memset(void *dest, int val, size_t n) { + auto curDest = reinterpret_cast(dest); + unsigned char byte = val; + + // Get rid of misalignment. + while(n && (reinterpret_cast(curDest) & 7)) { + *curDest++ = byte; + --n; + } + + auto pattern64 = static_cast>( + static_cast(byte) + | (static_cast(byte) << 8) + | (static_cast(byte) << 16) + | (static_cast(byte) << 24) + | (static_cast(byte) << 32) + | (static_cast(byte) << 40) + | (static_cast(byte) << 48) + | (static_cast(byte) << 56)); + + auto pattern32 = static_cast>( + static_cast(byte) + | (static_cast(byte) << 8) + | (static_cast(byte) << 16) + | (static_cast(byte) << 24)); + + auto pattern16 = static_cast>( + static_cast(byte) + | (static_cast(byte) << 8)); + + while(n >= 8 * 8) { + alias_store(curDest, pattern64); + alias_store(curDest, pattern64); + alias_store(curDest, pattern64); + alias_store(curDest, pattern64); + alias_store(curDest, pattern64); + alias_store(curDest, pattern64); + alias_store(curDest, pattern64); + alias_store(curDest, pattern64); + n -= 8 * 8; + } + if(n >= 4 * 8) { + alias_store(curDest, pattern64); + alias_store(curDest, pattern64); + alias_store(curDest, pattern64); + alias_store(curDest, pattern64); + n -= 4 * 8; + } + if(n >= 2 * 8) { + alias_store(curDest, pattern64); + alias_store(curDest, pattern64); + n -= 2 * 8; + } + if(n >= 8) { + alias_store(curDest, pattern64); + n -= 8; + } + if(n >= 4) { + alias_store(curDest, pattern32); + n -= 4; + } + if(n >= 2) { + alias_store(curDest, pattern16); + n -= 2; + } + if(n) + *curDest = byte; + return dest; +} + +#else // !__LP64__ + +void *memset(void *dest, int byte, size_t count) { + for(size_t i = 0; i < count; i++) + ((char *)dest)[i] = (char)byte; + return dest; +} + +#endif // __LP64__ / !__LP64__ + +// -------------------------------------------------------------------------------------- +// "Non-optimized" functions. +// -------------------------------------------------------------------------------------- + +void *memmove(void *dest, const void *src, size_t size) { + char *dest_bytes = (char *)dest; + char *src_bytes = (char *)src; + if(dest_bytes < src_bytes) { + return forward_copy(dest, src, size); + }else if(dest_bytes > src_bytes) { + for(size_t i = 0; i < size; i++) + dest_bytes[size - i - 1] = src_bytes[size - i - 1]; + } + return dest; +} + +size_t strlen(const char *s) { + size_t len = 0; + for(size_t i = 0; s[i]; i++) + len++; + return len; +} diff --git a/lib/mlibc/options/internal/generic/frigg.cpp b/lib/mlibc/options/internal/generic/frigg.cpp new file mode 100644 index 0000000..7575c9c --- /dev/null +++ b/lib/mlibc/options/internal/generic/frigg.cpp @@ -0,0 +1,14 @@ + +#include +#include +#include + +extern "C" void frg_panic(const char *mstr) { +// mlibc::sys_libc_log("mlibc: Call to frg_panic"); + mlibc::sys_libc_log(mstr); + mlibc::sys_libc_panic(); +} + +extern "C" void frg_log(const char *mstr) { + mlibc::sys_libc_log(mstr); +} diff --git a/lib/mlibc/options/internal/generic/global-config.cpp b/lib/mlibc/options/internal/generic/global-config.cpp new file mode 100644 index 0000000..264a984 --- /dev/null +++ b/lib/mlibc/options/internal/generic/global-config.cpp @@ -0,0 +1,27 @@ +#include +#include +#include + +namespace mlibc { + +struct GlobalConfigGuard { + GlobalConfigGuard(); +}; + +GlobalConfigGuard guard; + +GlobalConfigGuard::GlobalConfigGuard() { + // Force the config to be created during initialization of libc.so. + mlibc::globalConfig(); +} + +static bool envEnabled(const char *env) { + auto value = getenv(env); + return value && *value && *value != '0'; +} + +GlobalConfig::GlobalConfig() { + debugMalloc = envEnabled("MLIBC_DEBUG_MALLOC"); +} + +} diff --git a/lib/mlibc/options/internal/generic/inline-emitter.cpp b/lib/mlibc/options/internal/generic/inline-emitter.cpp new file mode 100644 index 0000000..bf81c0b --- /dev/null +++ b/lib/mlibc/options/internal/generic/inline-emitter.cpp @@ -0,0 +1,16 @@ +// This translation unit provides symbols for functions marked with __MLIBC_INLINE_DEFINITION. +// All headers with such functions must be included here. + +#define __MLIBC_EMIT_INLINE_DEFINITIONS + +#include + +#include + +#if __MLIBC_LINUX_OPTION +#include +#endif /* __MLIBC_LINUX_OPTION */ + +#ifndef MLIBC_BUILDING_RTDL +#include +#endif diff --git a/lib/mlibc/options/internal/generic/locale.cpp b/lib/mlibc/options/internal/generic/locale.cpp new file mode 100644 index 0000000..7ba040f --- /dev/null +++ b/lib/mlibc/options/internal/generic/locale.cpp @@ -0,0 +1,87 @@ +#include +#include +#include + +namespace mlibc { + +char *nl_langinfo(nl_item item) { + if(item == CODESET) { + return const_cast("UTF-8"); + } else if(item >= ABMON_1 && item <= ABMON_12) { + switch(item) { + case ABMON_1: return const_cast("Jan"); + case ABMON_2: return const_cast("Feb"); + case ABMON_3: return const_cast("Mar"); + case ABMON_4: return const_cast("Apr"); + case ABMON_5: return const_cast("May"); + case ABMON_6: return const_cast("Jun"); + case ABMON_7: return const_cast("Jul"); + case ABMON_8: return const_cast("Aug"); + case ABMON_9: return const_cast("Sep"); + case ABMON_10: return const_cast("Oct"); + case ABMON_11: return const_cast("Nov"); + case ABMON_12: return const_cast("Dec"); + default: + __ensure(!"ABMON_* constants don't seem to be contiguous!"); + __builtin_unreachable(); + } + } else if(item >= MON_1 && item <= MON_12) { + switch(item) { + case MON_1: return const_cast("January"); + case MON_2: return const_cast("Feburary"); + case MON_3: return const_cast("March"); + case MON_4: return const_cast("April"); + case MON_5: return const_cast("May"); + case MON_6: return const_cast("June"); + case MON_7: return const_cast("July"); + case MON_8: return const_cast("August"); + case MON_9: return const_cast("September"); + case MON_10: return const_cast("October"); + case MON_11: return const_cast("November"); + case MON_12: return const_cast("December"); + default: + __ensure(!"MON_* constants don't seem to be contiguous!"); + __builtin_unreachable(); + } + } else if(item == AM_STR) { + return const_cast("AM"); + } else if(item == PM_STR) { + return const_cast("PM"); + } else if(item >= DAY_1 && item <= DAY_7) { + switch(item) { + case DAY_1: return const_cast("Sunday"); + case DAY_2: return const_cast("Monday"); + case DAY_3: return const_cast("Tuesday"); + case DAY_4: return const_cast("Wednesday"); + case DAY_5: return const_cast("Thursday"); + case DAY_6: return const_cast("Friday"); + case DAY_7: return const_cast("Saturday"); + default: + __ensure(!"DAY_* constants don't seem to be contiguous!"); + __builtin_unreachable(); + } + } else if(item >= ABDAY_1 && item <= ABDAY_7) { + switch(item) { + case ABDAY_1: return const_cast("Sun"); + case ABDAY_2: return const_cast("Mon"); + case ABDAY_3: return const_cast("Tue"); + case ABDAY_4: return const_cast("Wed"); + case ABDAY_5: return const_cast("Thu"); + case ABDAY_6: return const_cast("Fri"); + case ABDAY_7: return const_cast("Sat"); + default: + __ensure(!"ABDAY_* constants don't seem to be contiguous!"); + __builtin_unreachable(); + } + }else if(item == D_FMT) { + return const_cast("%m/%d/%y"); + }else if(item == T_FMT) { + return const_cast("%H:%M:%S"); + }else{ + mlibc::infoLogger() << "mlibc: nl_langinfo item " + << item << " is not implemented properly" << frg::endlog; + return const_cast(""); + } +} + +} diff --git a/lib/mlibc/options/internal/generic/sigset.cpp b/lib/mlibc/options/internal/generic/sigset.cpp new file mode 100644 index 0000000..134277d --- /dev/null +++ b/lib/mlibc/options/internal/generic/sigset.cpp @@ -0,0 +1,37 @@ +#include +#include + +int sigemptyset(sigset_t *sigset) { + *sigset = 0; + return 0; +} + +int sigfillset(sigset_t *sigset) { + *sigset = ~sigset_t(0); + return 0; +} + +// TODO: Return EINVAL instead of __ensure()ing. + +int sigaddset(sigset_t *sigset, int sig) { + int signo = sig - 1; + // TODO: do not hard code CHAR_BITS + __ensure((unsigned int)signo < sizeof(sigset_t) * 8); + *sigset |= sigset_t(1) << signo; + return 0; +} + +int sigdelset(sigset_t *sigset, int sig) { + int signo = sig - 1; + // TODO: do not hard code CHAR_BITS + __ensure((unsigned int)signo < sizeof(sigset_t) * 8); + *sigset &= ~(sigset_t(1) << signo); + return 0; +} + +int sigismember(const sigset_t *set, int sig) { + int signo = sig - 1; + // TODO: do not hard code CHAR_BITS + __ensure((unsigned int)signo < sizeof(sigset_t) * 8); + return (*set) & (sigset_t(1) << signo); +} diff --git a/lib/mlibc/options/internal/generic/strings.cpp b/lib/mlibc/options/internal/generic/strings.cpp new file mode 100644 index 0000000..ce4f84b --- /dev/null +++ b/lib/mlibc/options/internal/generic/strings.cpp @@ -0,0 +1,22 @@ +#include + +#include + +namespace mlibc { + +int strncasecmp(const char *a, const char *b, size_t size) { + for(size_t i = 0; i < size; i++) { + unsigned char a_byte = tolower(a[i]); + unsigned char b_byte = tolower(b[i]); + if(!a_byte && !b_byte) + return 0; + // If only one char is null, one of the following cases applies. + if(a_byte < b_byte) + return -1; + if(a_byte > b_byte) + return 1; + } + return 0; +} + +} diff --git a/lib/mlibc/options/internal/generic/threads.cpp b/lib/mlibc/options/internal/generic/threads.cpp new file mode 100644 index 0000000..5f1168c --- /dev/null +++ b/lib/mlibc/options/internal/generic/threads.cpp @@ -0,0 +1,342 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +extern "C" Tcb *__rtdl_allocateTcb(); + +namespace mlibc { + +int thread_create(struct __mlibc_thread_data **__restrict thread, const struct __mlibc_threadattr *__restrict attrp, void *entry, void *__restrict user_arg, bool returns_int) { + auto new_tcb = __rtdl_allocateTcb(); + pid_t tid; + struct __mlibc_threadattr attr = {}; + if (!attrp) + thread_attr_init(&attr); + else + attr = *attrp; + + if (attr.__mlibc_cpuset) + mlibc::infoLogger() << "pthread_create(): cpuset is ignored!" << frg::endlog; + if (attr.__mlibc_sigmaskset) + mlibc::infoLogger() << "pthread_create(): sigmask is ignored!" << frg::endlog; + + // TODO: due to alignment guarantees, the stackaddr and stacksize might change + // when the stack is allocated. Currently this isn't propagated to the TCB, + // but it should be. + void *stack = attr.__mlibc_stackaddr; + if (!mlibc::sys_prepare_stack) { + MLIBC_MISSING_SYSDEP(); + return ENOSYS; + } + int ret = mlibc::sys_prepare_stack(&stack, entry, + user_arg, new_tcb, &attr.__mlibc_stacksize, &attr.__mlibc_guardsize, &new_tcb->stackAddr); + if (ret) + return ret; + + if (!mlibc::sys_clone) { + MLIBC_MISSING_SYSDEP(); + return ENOSYS; + } + new_tcb->stackSize = attr.__mlibc_stacksize; + new_tcb->guardSize = attr.__mlibc_guardsize; + new_tcb->returnValueType = (returns_int) ? TcbThreadReturnValue::Integer : TcbThreadReturnValue::Pointer; + mlibc::sys_clone(new_tcb, &tid, stack); + *thread = reinterpret_cast(new_tcb); + + __atomic_store_n(&new_tcb->tid, tid, __ATOMIC_RELAXED); + mlibc::sys_futex_wake(&new_tcb->tid); + + return 0; +} + +int thread_join(struct __mlibc_thread_data *thread, void *ret) { + auto tcb = reinterpret_cast(thread); + + if (!__atomic_load_n(&tcb->isJoinable, __ATOMIC_ACQUIRE)) + return EINVAL; + + while (!__atomic_load_n(&tcb->didExit, __ATOMIC_ACQUIRE)) { + mlibc::sys_futex_wait(&tcb->didExit, 0, nullptr); + } + + if(ret && tcb->returnValueType == TcbThreadReturnValue::Pointer) + *reinterpret_cast(ret) = tcb->returnValue.voidPtr; + else if(ret && tcb->returnValueType == TcbThreadReturnValue::Integer) + *reinterpret_cast(ret) = tcb->returnValue.intVal; + + // FIXME: destroy tcb here, currently we leak it + + return 0; +} + +static constexpr size_t default_stacksize = 0x200000; +static constexpr size_t default_guardsize = 4096; + +int thread_attr_init(struct __mlibc_threadattr *attr) { + *attr = __mlibc_threadattr{}; + attr->__mlibc_stacksize = default_stacksize; + attr->__mlibc_guardsize = default_guardsize; + attr->__mlibc_detachstate = __MLIBC_THREAD_CREATE_JOINABLE; + return 0; +} + +static constexpr unsigned int mutexRecursive = 1; +static constexpr unsigned int mutexErrorCheck = 2; + +// TODO: either use uint32_t or determine the bit based on sizeof(int). +static constexpr unsigned int mutex_owner_mask = (static_cast(1) << 30) - 1; +static constexpr unsigned int mutex_waiters_bit = static_cast(1) << 31; + +// Only valid for the internal __mlibc_m mutex of wrlocks. +static constexpr unsigned int mutex_excl_bit = static_cast(1) << 30; + +int thread_mutex_init(struct __mlibc_mutex *__restrict mutex, + const struct __mlibc_mutexattr *__restrict attr) { + auto type = attr ? attr->__mlibc_type : __MLIBC_THREAD_MUTEX_DEFAULT; + auto robust = attr ? attr->__mlibc_robust : __MLIBC_THREAD_MUTEX_STALLED; + auto protocol = attr ? attr->__mlibc_protocol : __MLIBC_THREAD_PRIO_NONE; + auto pshared = attr ? attr->__mlibc_pshared : __MLIBC_THREAD_PROCESS_PRIVATE; + + mutex->__mlibc_state = 0; + mutex->__mlibc_recursion = 0; + mutex->__mlibc_flags = 0; + mutex->__mlibc_prioceiling = 0; // TODO: We don't implement this. + + if(type == __MLIBC_THREAD_MUTEX_RECURSIVE) { + mutex->__mlibc_flags |= mutexRecursive; + }else if(type == __MLIBC_THREAD_MUTEX_ERRORCHECK) { + mutex->__mlibc_flags |= mutexErrorCheck; + }else{ + __ensure(type == __MLIBC_THREAD_MUTEX_NORMAL); + } + + // TODO: Other values aren't supported yet. + __ensure(robust == __MLIBC_THREAD_MUTEX_STALLED); + __ensure(protocol == __MLIBC_THREAD_PRIO_NONE); + __ensure(pshared == __MLIBC_THREAD_PROCESS_PRIVATE); + + return 0; +} + +int thread_mutex_destroy(struct __mlibc_mutex *mutex) { + __ensure(!mutex->__mlibc_state); + return 0; +} + +int thread_mutex_lock(struct __mlibc_mutex *mutex) { + unsigned int this_tid = mlibc::this_tid(); + unsigned int expected = 0; + while(true) { + if(!expected) { + // Try to take the mutex here. + if(__atomic_compare_exchange_n(&mutex->__mlibc_state, + &expected, this_tid, false, __ATOMIC_ACQUIRE, __ATOMIC_ACQUIRE)) { + __ensure(!mutex->__mlibc_recursion); + mutex->__mlibc_recursion = 1; + return 0; + } + }else{ + // If this (recursive) mutex is already owned by us, increment the recursion level. + if((expected & mutex_owner_mask) == this_tid) { + if(!(mutex->__mlibc_flags & mutexRecursive)) { + if (mutex->__mlibc_flags & mutexErrorCheck) + return EDEADLK; + else + mlibc::panicLogger() << "mlibc: pthread_mutex deadlock detected!" + << frg::endlog; + } + ++mutex->__mlibc_recursion; + return 0; + } + + // Wait on the futex if the waiters flag is set. + if(expected & mutex_waiters_bit) { + int e = mlibc::sys_futex_wait((int *)&mutex->__mlibc_state, expected, nullptr); + + // If the wait returns EAGAIN, that means that the mutex_waiters_bit was just unset by + // some other thread. In this case, we should loop back around. + if (e && e != EAGAIN) + mlibc::panicLogger() << "sys_futex_wait() failed with error code " << e << frg::endlog; + + // Opportunistically try to take the lock after we wake up. + expected = 0; + }else{ + // Otherwise we have to set the waiters flag first. + unsigned int desired = expected | mutex_waiters_bit; + if(__atomic_compare_exchange_n((int *)&mutex->__mlibc_state, + reinterpret_cast(&expected), desired, false, __ATOMIC_RELAXED, __ATOMIC_RELAXED)) + expected = desired; + } + } + } +} + +int thread_mutex_unlock(struct __mlibc_mutex *mutex) { + // Decrement the recursion level and unlock if we hit zero. + __ensure(mutex->__mlibc_recursion); + if(--mutex->__mlibc_recursion) + return 0; + + auto flags = mutex->__mlibc_flags; + + // Reset the mutex to the unlocked state. + auto state = __atomic_exchange_n(&mutex->__mlibc_state, 0, __ATOMIC_RELEASE); + + // After this point the mutex is unlocked, and therefore we cannot access its contents as it + // may have been destroyed by another thread. + + unsigned int this_tid = mlibc::this_tid(); + if ((flags & mutexErrorCheck) && (state & mutex_owner_mask) != this_tid) + return EPERM; + + if ((flags & mutexErrorCheck) && !(state & mutex_owner_mask)) + return EINVAL; + + __ensure((state & mutex_owner_mask) == this_tid); + + if(state & mutex_waiters_bit) { + // Wake the futex if there were waiters. Since the mutex might not exist at this location + // anymore, we must conservatively ignore EACCES and EINVAL which may occur as a result. + int e = mlibc::sys_futex_wake((int *)&mutex->__mlibc_state); + __ensure(e >= 0 || e == EACCES || e == EINVAL); + } + + return 0; +} + +int thread_mutexattr_init(struct __mlibc_mutexattr *attr) { + attr->__mlibc_type = __MLIBC_THREAD_MUTEX_DEFAULT; + attr->__mlibc_robust = __MLIBC_THREAD_MUTEX_STALLED; + attr->__mlibc_pshared = __MLIBC_THREAD_PROCESS_PRIVATE; + attr->__mlibc_protocol = __MLIBC_THREAD_PRIO_NONE; + return 0; +} + +int thread_mutexattr_destroy(struct __mlibc_mutexattr *attr) { + memset(attr, 0, sizeof(*attr)); + return 0; +} + +int thread_mutexattr_gettype(const struct __mlibc_mutexattr *__restrict attr, int *__restrict type) { + *type = attr->__mlibc_type; + return 0; +} + +int thread_mutexattr_settype(struct __mlibc_mutexattr *attr, int type) { + if (type != __MLIBC_THREAD_MUTEX_NORMAL && type != __MLIBC_THREAD_MUTEX_ERRORCHECK + && type != __MLIBC_THREAD_MUTEX_RECURSIVE) + return EINVAL; + + attr->__mlibc_type = type; + return 0; +} + +int thread_cond_init(struct __mlibc_cond *__restrict cond, const struct __mlibc_condattr *__restrict attr) { + auto clock = attr ? attr->__mlibc_clock : CLOCK_REALTIME; + auto pshared = attr ? attr->__mlibc_pshared : __MLIBC_THREAD_PROCESS_PRIVATE; + + cond->__mlibc_clock = clock; + cond->__mlibc_flags = pshared; + + __atomic_store_n(&cond->__mlibc_seq, 1, __ATOMIC_RELAXED); + + return 0; +} + +int thread_cond_destroy(struct __mlibc_cond *) { + return 0; +} + +int thread_cond_broadcast(struct __mlibc_cond *cond) { + __atomic_fetch_add(&cond->__mlibc_seq, 1, __ATOMIC_RELEASE); + if(int e = mlibc::sys_futex_wake((int *)&cond->__mlibc_seq); e) + __ensure(!"sys_futex_wake() failed"); + + return 0; +} + +int thread_cond_timedwait(struct __mlibc_cond *__restrict cond, __mlibc_mutex *__restrict mutex, + const struct timespec *__restrict abstime) { + // TODO: pshared isn't supported yet. + __ensure(cond->__mlibc_flags == 0); + + constexpr long nanos_per_second = 1'000'000'000; + if (abstime && (abstime->tv_nsec < 0 || abstime->tv_nsec >= nanos_per_second)) + return EINVAL; + + auto seq = __atomic_load_n(&cond->__mlibc_seq, __ATOMIC_ACQUIRE); + + // TODO: handle locking errors and cancellation properly. + while (true) { + if (thread_mutex_unlock(mutex)) + __ensure(!"Failed to unlock the mutex"); + + int e; + if (abstime) { + // Adjust for the fact that sys_futex_wait accepts a *timeout*, but + // pthread_cond_timedwait accepts an *absolute time*. + // Note: mlibc::sys_clock_get is available unconditionally. + struct timespec now; + if (mlibc::sys_clock_get(cond->__mlibc_clock, &now.tv_sec, &now.tv_nsec)) + __ensure(!"sys_clock_get() failed"); + + struct timespec timeout; + timeout.tv_sec = abstime->tv_sec - now.tv_sec; + timeout.tv_nsec = abstime->tv_nsec - now.tv_nsec; + + // Check if abstime has already passed. + if (timeout.tv_sec < 0 || (timeout.tv_sec == 0 && timeout.tv_nsec < 0)) { + if (thread_mutex_lock(mutex)) + __ensure(!"Failed to lock the mutex"); + return ETIMEDOUT; + } else if (timeout.tv_nsec >= nanos_per_second) { + timeout.tv_nsec -= nanos_per_second; + timeout.tv_sec++; + __ensure(timeout.tv_nsec < nanos_per_second); + } else if (timeout.tv_nsec < 0) { + timeout.tv_nsec += nanos_per_second; + timeout.tv_sec--; + __ensure(timeout.tv_nsec >= 0); + } + + e = mlibc::sys_futex_wait((int *)&cond->__mlibc_seq, seq, &timeout); + } else { + e = mlibc::sys_futex_wait((int *)&cond->__mlibc_seq, seq, nullptr); + } + + if (thread_mutex_lock(mutex)) + __ensure(!"Failed to lock the mutex"); + + // There are four cases to handle: + // 1. e == 0: this indicates a (potentially spurious) wakeup. The value of + // seq *must* be checked to distinguish these two cases. + // 2. e == EAGAIN: this indicates that the value of seq changed before we + // went to sleep. We don't need to check seq in this case. + // 3. e == EINTR: a signal was delivered. The man page allows us to choose + // whether to go to sleep again or to return 0, but we do the former + // to match other libcs. + // 4. e == ETIMEDOUT: this should only happen if abstime is set. + if (e == 0) { + auto cur_seq = __atomic_load_n(&cond->__mlibc_seq, __ATOMIC_ACQUIRE); + if (cur_seq > seq) + return 0; + } else if (e == EAGAIN) { + __ensure(__atomic_load_n(&cond->__mlibc_seq, __ATOMIC_ACQUIRE) > seq); + return 0; + } else if (e == EINTR) { + continue; + } else if (e == ETIMEDOUT) { + __ensure(abstime); + return ETIMEDOUT; + } else { + mlibc::panicLogger() << "sys_futex_wait() failed with error " << e << frg::endlog; + } + } +} + +} // namespace mlibc diff --git a/lib/mlibc/options/internal/generic/ubsan.cpp b/lib/mlibc/options/internal/generic/ubsan.cpp new file mode 100644 index 0000000..3491729 --- /dev/null +++ b/lib/mlibc/options/internal/generic/ubsan.cpp @@ -0,0 +1,254 @@ +#include +#include + +#define FMT(obj) format_object((obj), opts, formatter) + +#define LOG_NAME_LOC(name, loc) "ubsan: " name " at " << loc << "\n " +#define LOG_LHS_RHS(lhs, rhs) "LHS = " << (lhs) << ", RHS = " << (rhs) + +struct SourceLocation { + const char *filename; + uint32_t line; + uint32_t column; +}; + +template +void format_object(const SourceLocation &loc, frg::format_options opts, F &formatter) { + FMT(loc.filename); + FMT(":"); + FMT(loc.line); + FMT(":"); + FMT(loc.column); +} + +using ValueHandle = uintptr_t; + +struct TypeDescriptor { + enum class Kind : uint16_t { + Integer = 0x0000, + Float = 0x0001, + Unknown = 0xffff + } kind; + + uint16_t info; + char name[]; + + unsigned bitWidthInt() const { + return 1 << (info >> 1); + } + + bool isInlineInt() const { + if (kind != Kind::Integer) + return false; + + auto inlineBits = sizeof(ValueHandle) * CHAR_BIT; + auto valueBits = bitWidthInt(); + return inlineBits <= valueBits; + } + + bool isSigned() const { + return info & 1; + } +}; + +template +void format_object(const TypeDescriptor &type, frg::format_options opts, F &formatter) { + FMT(type.name); +} + +struct Value { + const TypeDescriptor &type; + ValueHandle val; + + Value(const TypeDescriptor &type, ValueHandle val) : type(type), val(val) {} +}; + +template +void format_object(const Value &val, frg::format_options opts, F &formatter) { + if (val.type.isInlineInt() && val.type.isSigned()) { + auto signedValue = static_cast(val.val); + FMT(signedValue); + } else if (val.type.isInlineInt() && !val.type.isSigned()) { + auto unsignedValue = static_cast(val.val); + FMT(unsignedValue); + } + + FMT(" ("); + FMT(val.type); + FMT(")"); +} + + +// --- Hook implementations --- + +struct TypeMismatch { + SourceLocation loc; + const TypeDescriptor &type; + unsigned char logAlignment; + unsigned char kind; +}; + +extern "C" [[gnu::visibility("hidden")]] +void __ubsan_handle_type_mismatch_v1(TypeMismatch *tm, ValueHandle pointer) { + // TODO: Make this print more information. + mlibc::panicLogger() + << LOG_NAME_LOC("type mismatch", tm->loc) + << "accessed address " << (void *)pointer << " but type " + << tm->type << " requires alignment " << (1 << tm->logAlignment) + << frg::endlog; +} + +struct PointerOverflowData { + SourceLocation loc; +}; + +extern "C" [[gnu::visibility("hidden")]] +void __ubsan_handle_pointer_overflow(PointerOverflowData *pod, ValueHandle base, ValueHandle result) { + (void)base; + (void)result; + mlibc::panicLogger() + << LOG_NAME_LOC("pointer overflow", pod->loc) + << frg::endlog; +} + +struct InvalidValueData { + SourceLocation loc; + const TypeDescriptor &type; +}; + +extern "C" [[gnu::visibility("hidden")]] +void __ubsan_handle_load_invalid_value(InvalidValueData *ivd, ValueHandle value) { + (void)value; + mlibc::panicLogger() + << LOG_NAME_LOC("load of invalid value", ivd->loc) + << frg::endlog; +} + +struct OverflowData { + SourceLocation loc; + const TypeDescriptor &type; +}; + +extern "C" [[gnu::visibility("hidden")]] +void __ubsan_handle_add_overflow(OverflowData *od, ValueHandle lhs, ValueHandle rhs) { + mlibc::panicLogger() + << LOG_NAME_LOC("add overflowed ", od->loc) + << LOG_LHS_RHS(Value(od->type, lhs), Value(od->type, rhs)) + << frg::endlog; +} + +extern "C" [[gnu::visibility("hidden")]] +void __ubsan_handle_sub_overflow(OverflowData *od, ValueHandle lhs, ValueHandle rhs) { + mlibc::panicLogger() + << LOG_NAME_LOC("sub overflowed", od->loc) + << LOG_LHS_RHS(Value(od->type, lhs), Value(od->type, rhs)) + << frg::endlog; +} + +extern "C" [[gnu::visibility("hidden")]] +void __ubsan_handle_mul_overflow(OverflowData *od, ValueHandle lhs, ValueHandle rhs) { + mlibc::panicLogger() + << LOG_NAME_LOC("mul overflowed", od->loc) + << LOG_LHS_RHS(Value(od->type, lhs), Value(od->type, rhs)) + << frg::endlog; +} + +extern "C" [[gnu::visibility("hidden")]] +void __ubsan_handle_divrem_overflow(OverflowData *od, ValueHandle lhs, ValueHandle rhs) { + mlibc::panicLogger() + << LOG_NAME_LOC("divrem overflowed", od->loc) + << LOG_LHS_RHS(Value(od->type, lhs), Value(od->type, rhs)) + << frg::endlog; +} + +extern "C" [[gnu::visibility("hidden")]] +void __ubsan_handle_negate_overflow(OverflowData *od, ValueHandle lhs, ValueHandle rhs) { + mlibc::panicLogger() + << LOG_NAME_LOC("negate overflowed", od->loc) + << LOG_LHS_RHS(Value(od->type, lhs), Value(od->type, rhs)) + << frg::endlog; +} + +struct ShiftOutOfBoundsData { + SourceLocation loc; + const TypeDescriptor &lhsType; + const TypeDescriptor &rhsType; +}; + +extern "C" [[gnu::visibility("hidden")]] +void __ubsan_handle_shift_out_of_bounds(ShiftOutOfBoundsData *soob, ValueHandle lhs, ValueHandle rhs) { + mlibc::panicLogger() + << LOG_NAME_LOC("shift out of bounds", soob->loc) + << LOG_LHS_RHS(Value(soob->lhsType, lhs), Value(soob->rhsType, rhs)) + << frg::endlog; +} + +struct OutOfBoundsData { + SourceLocation loc; + const TypeDescriptor &arrayType; + const TypeDescriptor &indexType; +}; + +extern "C" [[gnu::visibility("hidden")]] +void __ubsan_handle_out_of_bounds(OutOfBoundsData *oobd, ValueHandle data) { + (void)data; + mlibc::panicLogger() + << LOG_NAME_LOC("out of bounds access", oobd->loc) + << frg::endlog; +} + +struct UnreachableData { + SourceLocation loc; +}; + +extern "C" [[gnu::visibility("hidden")]] +void __ubsan_handle_builtin_unreachable(UnreachableData *ubd) { + mlibc::panicLogger() + << LOG_NAME_LOC("reached __builtin_unreachable()", ubd->loc) + << frg::endlog; +} + +struct InvalidBuiltinData { + SourceLocation loc; + unsigned char kind; +}; + +extern "C" [[gnu::visibility("hidden")]] +void __ubsan_handle_invalid_builtin(InvalidBuiltinData *ibd) { + mlibc::panicLogger() + << LOG_NAME_LOC("reached invalid builtin", ibd->loc) + << frg::endlog; +} + +struct VLABoundData { + SourceLocation loc; + const TypeDescriptor &type; +}; + +extern "C" [[gnu::visibility("hidden")]] +void __ubsan_handle_vla_bound_not_positive(VLABoundData *vlabd) { + mlibc::panicLogger() + << LOG_NAME_LOC("VLA bound not positive", vlabd->loc) + << frg::endlog; +} + +extern "C" [[gnu::visibility("hidden")]] +void __ubsan_handle_missing_return(UnreachableData *data) { + mlibc::panicLogger() + << LOG_NAME_LOC("reached end of a value-returning function without returning a value", data->loc) + << frg::endlog; +} + +struct NonNullArgData { + SourceLocation loc; + SourceLocation attr_loc; + int arg_index; +}; + +extern "C" [[gnu::visibility("hidden")]] +void __ubsan_handle_nonnull_arg(NonNullArgData *data) { + mlibc::panicLogger() + << LOG_NAME_LOC("null pointer passed to non-null argument", data->loc) + << "argument " << data->arg_index << " is required to be non-null in " + << data->attr_loc << frg::endlog; +} diff --git a/lib/mlibc/options/internal/include/bits/cpu_set.h b/lib/mlibc/options/internal/include/bits/cpu_set.h new file mode 100644 index 0000000..69f6923 --- /dev/null +++ b/lib/mlibc/options/internal/include/bits/cpu_set.h @@ -0,0 +1,13 @@ +#ifndef _MLIBC_INTERNAL_CPU_SET_H +#define _MLIBC_INTERNAL_CPU_SET_H + +typedef unsigned long __cpu_mask; + +#define CPU_SETSIZE 1024 +#define __NCPUBITS (8 * sizeof(__cpu_mask)) + +typedef struct { + __cpu_mask __bits[CPU_SETSIZE / __NCPUBITS]; +} cpu_set_t; + +#endif /* _MLIBC_INTERNAL_CPU_SET_H */ diff --git a/lib/mlibc/options/internal/include/bits/ensure.h b/lib/mlibc/options/internal/include/bits/ensure.h new file mode 100644 index 0000000..f75a2e9 --- /dev/null +++ b/lib/mlibc/options/internal/include/bits/ensure.h @@ -0,0 +1,45 @@ + +#ifndef MLIBC_ENSURE_H +#define MLIBC_ENSURE_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +void __ensure_fail(const char *assertion, const char *file, unsigned int line, + const char *function); + +void __ensure_warn(const char *assertion, const char *file, unsigned int line, + const char *function); + +#endif /* !__MLIBC_ABI_ONLY */ + +#define __ensure(assertion) do { if(!(assertion)) \ + __ensure_fail(#assertion, __FILE__, __LINE__, __func__); } while(0) + +#define MLIBC_UNIMPLEMENTED() __ensure_fail("Functionality is not implemented", \ + __FILE__, __LINE__, __func__) + +#define MLIBC_MISSING_SYSDEP() __ensure_warn("Library function fails due to missing sysdep", \ + __FILE__, __LINE__, __func__) + +#define MLIBC_CHECK_OR_ENOSYS(sysdep, ret) ({ \ + if (!(sysdep)) { \ + __ensure_warn("Library function fails due to missing sysdep", \ + __FILE__, __LINE__, __func__); \ + errno = ENOSYS; \ + return (ret); \ + } \ + sysdep; \ + }) + +#define MLIBC_STUB_BODY { MLIBC_UNIMPLEMENTED(); __builtin_unreachable(); } + +#ifdef __cplusplus +} +#endif + +#endif // MLIBC_ENSURE_H + diff --git a/lib/mlibc/options/internal/include/bits/ether_addr.h b/lib/mlibc/options/internal/include/bits/ether_addr.h new file mode 100644 index 0000000..1631e98 --- /dev/null +++ b/lib/mlibc/options/internal/include/bits/ether_addr.h @@ -0,0 +1,10 @@ +#ifndef MLIBC_ETHER_ADDR_H +#define MLIBC_ETHER_ADDR_H + +#include + +struct ether_addr { + uint8_t ether_addr_octet[6]; +} __attribute__((__packed__)); + +#endif // MLIBC_ETHER_ADDR_H diff --git a/lib/mlibc/options/internal/include/bits/inline-definition.h b/lib/mlibc/options/internal/include/bits/inline-definition.h new file mode 100644 index 0000000..ec4c4da --- /dev/null +++ b/lib/mlibc/options/internal/include/bits/inline-definition.h @@ -0,0 +1,19 @@ +#ifndef MLIBC_INLINE_DEFINITION_H +#define MLIBC_INLINE_DEFINITION_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef __MLIBC_EMIT_INLINE_DEFINITIONS +#define __MLIBC_INLINE_DEFINITION +#else +#define __MLIBC_INLINE_DEFINITION __attribute__((__gnu_inline__)) extern __inline__ +#endif + +#ifdef __cplusplus +} +#endif + +#endif // MLIBC_INLINE_DEFINITION_H + diff --git a/lib/mlibc/options/internal/include/bits/machine.h b/lib/mlibc/options/internal/include/bits/machine.h new file mode 100644 index 0000000..371a94b --- /dev/null +++ b/lib/mlibc/options/internal/include/bits/machine.h @@ -0,0 +1,86 @@ + +#ifndef MLIBC_MACHINE_H +#define MLIBC_MACHINE_H + +#include + +#if defined (__i386__) +struct __mlibc_jmpbuf_register_state { + uint32_t ebx; + uint32_t ebp; + uint32_t esi; + uint32_t edi; + uint32_t esp; + uint32_t eip; +}; +#elif defined (__x86_64__) +struct __mlibc_jmpbuf_register_state { + uint64_t rbx; + uint64_t rbp; + uint64_t r12; + uint64_t r13; + uint64_t r14; + uint64_t r15; + uint64_t rsp; + uint64_t rip; +}; +#elif defined (__aarch64__) +struct __mlibc_jmpbuf_register_state { + uint64_t x19; + uint64_t x20; + uint64_t x21; + uint64_t x22; + uint64_t x23; + uint64_t x24; + uint64_t x25; + uint64_t x26; + uint64_t x27; + uint64_t x28; + uint64_t x29; + uint64_t x30; + uint64_t sp; + uint64_t pad; + uint64_t d8; + uint64_t d9; + uint64_t d10; + uint64_t d11; + uint64_t d12; + uint64_t d13; + uint64_t d14; + uint64_t d15; +}; +#elif defined (__riscv) && __riscv_xlen == 64 +struct __mlibc_jmpbuf_register_state { + uint64_t ra; + uint64_t s0; + uint64_t s1; + uint64_t s2; + uint64_t s3; + uint64_t s4; + uint64_t s5; + uint64_t s6; + uint64_t s7; + uint64_t s8; + uint64_t s9; + uint64_t s10; + uint64_t s11; + uint64_t sp; + double fs0; + double fs1; + double fs2; + double fs3; + double fs4; + double fs5; + double fs6; + double fs7; + double fs8; + double fs9; + double fs10; + double fs11; +}; +#else +# error "Missing architecture specific code" +#endif + +#endif // MLIBC_MACHINE_H + diff --git a/lib/mlibc/options/internal/include/bits/mbstate.h b/lib/mlibc/options/internal/include/bits/mbstate.h new file mode 100644 index 0000000..2bfb3eb --- /dev/null +++ b/lib/mlibc/options/internal/include/bits/mbstate.h @@ -0,0 +1,12 @@ +#ifndef MLIBC_MBSTATE_H +#define MLIBC_MBSTATE_H + +struct __mlibc_mbstate { + short __progress; + short __shift; + unsigned int __cpoint; +}; + +#define __MLIBC_MBSTATE_INITIALIZER {0, 0, 0} + +#endif // MLIBC_MBSTATE_H diff --git a/lib/mlibc/options/internal/include/bits/nl_item.h b/lib/mlibc/options/internal/include/bits/nl_item.h new file mode 100644 index 0000000..dc882dc --- /dev/null +++ b/lib/mlibc/options/internal/include/bits/nl_item.h @@ -0,0 +1,82 @@ + +#ifndef _NL_ITEM_H +#define _NL_ITEM_H + +#ifdef __cplusplus +extern "C" { +#endif + +typedef int nl_item; + +#define ABDAY_1 0x60000 +#define ABDAY_2 0x60001 +#define ABDAY_3 0x60002 +#define ABDAY_4 0x60003 +#define ABDAY_5 0x60004 +#define ABDAY_6 0x60005 +#define ABDAY_7 0x60006 + +#define DAY_1 0x60007 +#define DAY_2 0x60008 +#define DAY_3 0x60009 +#define DAY_4 0x6000A +#define DAY_5 0x6000B +#define DAY_6 0x6000C +#define DAY_7 0x6000D + +#define ABMON_1 0x6000E +#define ABMON_2 0x6000F +#define ABMON_3 0x60010 +#define ABMON_4 0x60011 +#define ABMON_5 0x60012 +#define ABMON_6 0x60013 +#define ABMON_7 0x60014 +#define ABMON_8 0x60015 +#define ABMON_9 0x60016 +#define ABMON_10 0x60017 +#define ABMON_11 0x60018 +#define ABMON_12 0x60019 + +#define MON_1 0x6001A +#define MON_2 0x6001B +#define MON_3 0x6001C +#define MON_4 0x6001D +#define MON_5 0x6001E +#define MON_6 0x6001F +#define MON_7 0x60020 +#define MON_8 0x60021 +#define MON_9 0x60022 +#define MON_10 0x60023 +#define MON_11 0x60024 +#define MON_12 0x60025 + +#define AM_STR 0x60026 +#define PM_STR 0x60027 + +#define D_T_FMT 0x60028 +#define D_FMT 0x60029 +#define T_FMT 0x6002A +#define T_FMT_AMPM 0x6002B + +#define ERA 0x6002C +#define ERA_D_FMT 0x6002D +#define ALT_DIGITS 0x6002E +#define ERA_D_T_FMT 0x6002F +#define ERA_T_FMT 0x60030 + +#define CODESET 0x30000 + +#define CRNCYSTR 0x40000 + +#define RADIXCHAR 0x50000 +#define THOUSEP 0x50001 + +#define YESEXPR 0x70000 +#define NOEXPR 0x70001 + +#ifdef __cplusplus +} +#endif + +#endif // _NL_ITEM_H + diff --git a/lib/mlibc/options/internal/include/bits/null.h b/lib/mlibc/options/internal/include/bits/null.h new file mode 100644 index 0000000..7d3fa7b --- /dev/null +++ b/lib/mlibc/options/internal/include/bits/null.h @@ -0,0 +1,16 @@ + +#ifndef MLIBC_NULL_H +#define MLIBC_NULL_H + +#ifdef NULL +#undef NULL +#endif + +#ifndef __cplusplus +# define NULL ((void *)0) +#else +# define NULL 0 +#endif + +#endif // MLIBC_NULL_H + diff --git a/lib/mlibc/options/internal/include/bits/off_t.h b/lib/mlibc/options/internal/include/bits/off_t.h new file mode 100644 index 0000000..929fae9 --- /dev/null +++ b/lib/mlibc/options/internal/include/bits/off_t.h @@ -0,0 +1,8 @@ +#ifndef MLIBC_OFF_T_H +#define MLIBC_OFF_T_H + +// TODO: use something like int64_t instead? +typedef long off_t; +typedef long off64_t; + +#endif // MLIBC_OFF_T_H diff --git a/lib/mlibc/options/internal/include/bits/sigset_t.h b/lib/mlibc/options/internal/include/bits/sigset_t.h new file mode 100644 index 0000000..bb86848 --- /dev/null +++ b/lib/mlibc/options/internal/include/bits/sigset_t.h @@ -0,0 +1,25 @@ +#ifndef MLIBC_BITS_SIGSET_T_H +#define MLIBC_BITS_SIGSET_T_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +// functions to manage sigset_t +int sigemptyset(sigset_t *); +int sigfillset(sigset_t *); +int sigaddset(sigset_t *, int); +int sigdelset(sigset_t *, int); +int sigismember(const sigset_t *set, int sig); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif //MLIBC_BITS_SIGSET_T_H diff --git a/lib/mlibc/options/internal/include/bits/size_t.h b/lib/mlibc/options/internal/include/bits/size_t.h new file mode 100644 index 0000000..46d7486 --- /dev/null +++ b/lib/mlibc/options/internal/include/bits/size_t.h @@ -0,0 +1,6 @@ +#ifndef MLIBC_SIZE_T_H +#define MLIBC_SIZE_T_H + +typedef __SIZE_TYPE__ size_t; + +#endif // MLIBC_SIZE_T_H diff --git a/lib/mlibc/options/internal/include/bits/ssize_t.h b/lib/mlibc/options/internal/include/bits/ssize_t.h new file mode 100644 index 0000000..c450233 --- /dev/null +++ b/lib/mlibc/options/internal/include/bits/ssize_t.h @@ -0,0 +1,15 @@ + +#ifndef MLIBC_SSIZE_T_H +#define MLIBC_SSIZE_T_H + +// TODO: use ptrdiff_t instead? +#if __UINTPTR_MAX__ == __UINT64_MAX__ +typedef long ssize_t; +#elif __UINTPTR_MAX__ == __UINT32_MAX__ +typedef int ssize_t; +#else +#error "unsupported architecture" +#endif + +#endif // MLIBC_SSIZE_T_H + diff --git a/lib/mlibc/options/internal/include/bits/threads.h b/lib/mlibc/options/internal/include/bits/threads.h new file mode 100644 index 0000000..3feb4c3 --- /dev/null +++ b/lib/mlibc/options/internal/include/bits/threads.h @@ -0,0 +1,79 @@ +#ifndef _INTERNAL_THREADS_H +#define _INTERNAL_THREADS_H + +#include +#include +#include +#include + +// values for pthread_attr_{get,set}detachstate(). +#define __MLIBC_THREAD_CREATE_JOINABLE 0 +#define __MLIBC_THREAD_CREATE_DETACHED 1 + +// values for pthread_mutexattr_{get,set}type(). +#define __MLIBC_THREAD_MUTEX_DEFAULT 0 +#define __MLIBC_THREAD_MUTEX_NORMAL 0 +#define __MLIBC_THREAD_MUTEX_ERRORCHECK 1 +#define __MLIBC_THREAD_MUTEX_RECURSIVE 2 + +// values for pthread_mutexattr_{get,set}pshared(). +#define __MLIBC_THREAD_PROCESS_PRIVATE 0 +#define __MLIBC_THREAD_PROCESS_SHARED 1 + +// values for pthread_mutexattr_{get,set}robust(). +#define __MLIBC_THREAD_MUTEX_STALLED 0 +#define __MLIBC_THREAD_MUTEX_ROBUST 1 + +// Values for pthread_mutexattr_{get,set}protocol() +#define __MLIBC_THREAD_PRIO_NONE 0 +#define __MLIBC_THREAD_PRIO_INHERIT 1 +#define __MLIBC_THREAD_PRIO_PROTECT 2 + +struct sched_param { + int sched_priority; +}; + +struct __mlibc_thread_data; + +struct __mlibc_threadattr { + size_t __mlibc_guardsize; + size_t __mlibc_stacksize; + void *__mlibc_stackaddr; + int __mlibc_detachstate; + int __mlibc_scope; + int __mlibc_inheritsched; + struct sched_param __mlibc_schedparam; + int __mlibc_schedpolicy; + cpu_set_t *__mlibc_cpuset; + size_t __mlibc_cpusetsize; + sigset_t __mlibc_sigmask; + int __mlibc_sigmaskset; +}; + +struct __mlibc_mutex { + unsigned int __mlibc_state; + unsigned int __mlibc_recursion; + unsigned int __mlibc_flags; + int __mlibc_prioceiling; +}; + +struct __mlibc_mutexattr { + int __mlibc_type; + int __mlibc_robust; + int __mlibc_protocol; + int __mlibc_pshared; + int __mlibc_prioceiling; +}; + +struct __mlibc_cond { + unsigned int __mlibc_seq; + unsigned int __mlibc_flags; + clockid_t __mlibc_clock; +}; + +struct __mlibc_condattr { + int __mlibc_pshared; + clockid_t __mlibc_clock; +}; + +#endif /* _INTERNAL_THREADS_H */ diff --git a/lib/mlibc/options/internal/include/bits/types.h b/lib/mlibc/options/internal/include/bits/types.h new file mode 100644 index 0000000..935c5e0 --- /dev/null +++ b/lib/mlibc/options/internal/include/bits/types.h @@ -0,0 +1,319 @@ +#ifndef _MLIBC_INTERNAL_TYPES_H +#define _MLIBC_INTERNAL_TYPES_H + +typedef __UINT8_TYPE__ __mlibc_uint8; +typedef __UINT16_TYPE__ __mlibc_uint16; +typedef __UINT32_TYPE__ __mlibc_uint32; +typedef __UINT64_TYPE__ __mlibc_uint64; + +typedef __INT8_TYPE__ __mlibc_int8; +typedef __INT16_TYPE__ __mlibc_int16; +typedef __INT32_TYPE__ __mlibc_int32; +typedef __INT64_TYPE__ __mlibc_int64; + +// Clang and GCC have different mechanisms for INT32_C and friends. +#ifdef __clang__ +# define __MLIBC_C_EXPAND_JOIN(x, suffix) x ## suffix +# define __MLIBC_C_JOIN(x, suffix) __MLIBC_C_EXPAND_JOIN(x, suffix) + +# define __MLIBC_INT8_C(x) __MLIBC_C_JOIN(x, __INT8_C_SUFFIX__) +# define __MLIBC_INT16_C(x) __MLIBC_C_JOIN(x, __INT16_C_SUFFIX__) +# define __MLIBC_INT32_C(x) __MLIBC_C_JOIN(x, __INT32_C_SUFFIX__) +# define __MLIBC_INT64_C(x) __MLIBC_C_JOIN(x, __INT64_C_SUFFIX__) + +# define __MLIBC_UINT8_C(x) __MLIBC_C_JOIN(x, __UINT8_C_SUFFIX__) +# define __MLIBC_UINT16_C(x) __MLIBC_C_JOIN(x, __UINT16_C_SUFFIX__) +# define __MLIBC_UINT32_C(x) __MLIBC_C_JOIN(x, __UINT32_C_SUFFIX__) +# define __MLIBC_UINT64_C(x) __MLIBC_C_JOIN(x, __UINT64_C_SUFFIX__) + +# define __MLIBC_INTMAX_C(x) __MLIBC_C_JOIN(x, __INTMAX_C_SUFFIX__) +# define __MLIBC_UINTMAX_C(x) __MLIBC_C_JOIN(x, __UINTMAX_C_SUFFIX__) +#else +# define __MLIBC_INT8_C(x) __INT8_C(x) +# define __MLIBC_INT16_C(x) __INT16_C(x) +# define __MLIBC_INT32_C(x) __INT32_C(x) +# define __MLIBC_INT64_C(x) __INT64_C(x) + +# define __MLIBC_UINT8_C(x) __UINT8_C(x) +# define __MLIBC_UINT16_C(x) __UINT16_C(x) +# define __MLIBC_UINT32_C(x) __UINT32_C(x) +# define __MLIBC_UINT64_C(x) __UINT64_C(x) + +# define __MLIBC_INTMAX_C(x) __INTMAX_C(x) +# define __MLIBC_UINTMAX_C(x) __UINTMAX_C(x) +#endif + +#define __MLIBC_INT8_MAX __INT8_MAX__ +#define __MLIBC_INT16_MAX __INT16_MAX__ +#define __MLIBC_INT32_MAX __INT32_MAX__ +#define __MLIBC_INT64_MAX __INT64_MAX__ + +#define __MLIBC_INT8_MIN (-__MLIBC_INT8_MAX - 1) +#define __MLIBC_INT16_MIN (-__MLIBC_INT16_MAX - 1) +#define __MLIBC_INT32_MIN (-__MLIBC_INT32_MAX - 1) +#define __MLIBC_INT64_MIN (-__MLIBC_INT64_MAX - 1) + +#define __MLIBC_UINT8_MAX __UINT8_MAX__ +#define __MLIBC_UINT16_MAX __UINT16_MAX__ +#define __MLIBC_UINT32_MAX __UINT32_MAX__ +#define __MLIBC_UINT64_MAX __UINT64_MAX__ + +// Fast types (signed). + +#if defined (__i386__) + +typedef __mlibc_int8 __mlibc_int_fast8; +#define __MLIBC_INT_FAST8_C(x) __MLIBC_INT8_C(x) +#define __MLIBC_INT_FAST8_MAX __MLIBC_INT8_MAX +#define __MLIBC_INT_FAST8_MIN __MLIBC_INT8_MIN + +typedef __mlibc_int32 __mlibc_int_fast16; +#define __MLIBC_INT_FAST16_C(x) __MLIBC_INT32_C(x) +#define __MLIBC_INT_FAST16_MAX __MLIBC_INT32_MAX +#define __MLIBC_INT_FAST16_MIN __MLIBC_INT32_MIN + +typedef __mlibc_int32 __mlibc_int_fast32; +#define __MLIBC_INT_FAST32_C(x) __MLIBC_INT32_C(x) +#define __MLIBC_INT_FAST32_MAX __MLIBC_INT32_MAX +#define __MLIBC_INT_FAST32_MIN __MLIBC_INT32_MIN + +typedef __mlibc_int64 __mlibc_int_fast64; +#define __MLIBC_INT_FAST64_C(x) __MLIBC_INT64_C(x) +#define __MLIBC_INT_FAST64_MAX __MLIBC_INT64_MAX +#define __MLIBC_INT_FAST64_MIN __MLIBC_INT64_MIN + +#elif defined (__x86_64__) + +typedef __mlibc_int8 __mlibc_int_fast8; +#define __MLIBC_INT_FAST8_C(x) __MLIBC_INT8_C(x) +#define __MLIBC_INT_FAST8_MAX __MLIBC_INT8_MAX +#define __MLIBC_INT_FAST8_MIN __MLIBC_INT8_MIN + +typedef __mlibc_int64 __mlibc_int_fast16; +#define __MLIBC_INT_FAST16_C(x) __MLIBC_INT64_C(x) +#define __MLIBC_INT_FAST16_MAX __MLIBC_INT64_MAX +#define __MLIBC_INT_FAST16_MIN __MLIBC_INT64_MIN + +typedef __mlibc_int64 __mlibc_int_fast32; +#define __MLIBC_INT_FAST32_C(x) __MLIBC_INT64_C(x) +#define __MLIBC_INT_FAST32_MAX __MLIBC_INT64_MAX +#define __MLIBC_INT_FAST32_MIN __MLIBC_INT64_MIN + +typedef __mlibc_int64 __mlibc_int_fast64; +#define __MLIBC_INT_FAST64_C(x) __MLIBC_INT64_C(x) +#define __MLIBC_INT_FAST64_MAX __MLIBC_INT64_MAX +#define __MLIBC_INT_FAST64_MIN __MLIBC_INT64_MIN + +#elif defined (__aarch64__) + +typedef __mlibc_int8 __mlibc_int_fast8; +#define __MLIBC_INT_FAST8_C(x) __MLIBC_INT8_C(x) +#define __MLIBC_INT_FAST8_MAX __MLIBC_INT8_MAX +#define __MLIBC_INT_FAST8_MIN __MLIBC_INT8_MIN + +typedef __mlibc_int64 __mlibc_int_fast16; +#define __MLIBC_INT_FAST16_C(x) __MLIBC_INT64_C(x) +#define __MLIBC_INT_FAST16_MAX __MLIBC_INT64_MAX +#define __MLIBC_INT_FAST16_MIN __MLIBC_INT64_MIN + +typedef __mlibc_int64 __mlibc_int_fast32; +#define __MLIBC_INT_FAST32_C(x) __MLIBC_INT64_C(x) +#define __MLIBC_INT_FAST32_MAX __MLIBC_INT64_MAX +#define __MLIBC_INT_FAST32_MIN __MLIBC_INT64_MIN + +typedef __mlibc_int64 __mlibc_int_fast64; +#define __MLIBC_INT_FAST64_C(x) __MLIBC_INT64_C(x) +#define __MLIBC_INT_FAST64_MAX __MLIBC_INT64_MAX +#define __MLIBC_INT_FAST64_MIN __MLIBC_INT64_MIN + +#elif defined (__riscv) && __riscv_xlen == 64 + +typedef __mlibc_int8 __mlibc_int_fast8; +#define __MLIBC_INT_FAST8_C(x) __MLIBC_INT8_C(x) +#define __MLIBC_INT_FAST8_MAX __MLIBC_INT8_MAX +#define __MLIBC_INT_FAST8_MIN __MLIBC_INT8_MIN + +typedef __mlibc_int64 __mlibc_int_fast16; +#define __MLIBC_INT_FAST16_C(x) __MLIBC_INT64_C(x) +#define __MLIBC_INT_FAST16_MAX __MLIBC_INT64_MAX +#define __MLIBC_INT_FAST16_MIN __MLIBC_INT64_MIN + +typedef __mlibc_int64 __mlibc_int_fast32; +#define __MLIBC_INT_FAST32_C(x) __MLIBC_INT64_C(x) +#define __MLIBC_INT_FAST32_MAX __MLIBC_INT64_MAX +#define __MLIBC_INT_FAST32_MIN __MLIBC_INT64_MIN + +typedef __mlibc_int64 __mlibc_int_fast64; +#define __MLIBC_INT_FAST64_C(x) __MLIBC_INT64_C(x) +#define __MLIBC_INT_FAST64_MAX __MLIBC_INT64_MAX +#define __MLIBC_INT_FAST64_MIN __MLIBC_INT64_MIN + +#else +# error "Missing architecture specific code" +#endif + +// Fast types (unsigned). + +#if defined (__i386__) + +typedef __mlibc_uint8 __mlibc_uint_fast8; +#define __MLIBC_UINT_FAST8_C(x) __MLIBC_UINT8_C(x) +#define __MLIBC_UINT_FAST8_MAX __MLIBC_UINT8_MAX +#define __MLIBC_UINT_FAST8_MIN __MLIBC_UINT8_MIN + +typedef __mlibc_uint32 __mlibc_uint_fast16; +#define __MLIBC_UINT_FAST16_C(x) __MLIBC_UINT32_C(x) +#define __MLIBC_UINT_FAST16_MAX __MLIBC_UINT32_MAX +#define __MLIBC_UINT_FAST16_MIN __MLIBC_UINT32_MIN + +typedef __mlibc_uint32 __mlibc_uint_fast32; +#define __MLIBC_UINT_FAST32_C(x) __MLIBC_UINT32_C(x) +#define __MLIBC_UINT_FAST32_MAX __MLIBC_UINT32_MAX +#define __MLIBC_UINT_FAST32_MIN __MLIBC_UINT32_MIN + +typedef __mlibc_uint64 __mlibc_uint_fast64; +#define __MLIBC_UINT_FAST64_C(x) __MLIBC_UINT64_C(x) +#define __MLIBC_UINT_FAST64_MAX __MLIBC_UINT64_MAX +#define __MLIBC_UINT_FAST64_MIN __MLIBC_UINT64_MIN + +#elif defined (__x86_64__) + +typedef __mlibc_uint8 __mlibc_uint_fast8; +#define __MLIBC_UINT_FAST8_C(x) __MLIBC_UINT8_C(x) +#define __MLIBC_UINT_FAST8_MAX __MLIBC_UINT8_MAX +#define __MLIBC_UINT_FAST8_MIN __MLIBC_UINT8_MIN + +typedef __mlibc_uint64 __mlibc_uint_fast16; +#define __MLIBC_UINT_FAST16_C(x) __MLIBC_UINT64_C(x) +#define __MLIBC_UINT_FAST16_MAX __MLIBC_UINT64_MAX +#define __MLIBC_UINT_FAST16_MIN __MLIBC_UINT64_MIN + +typedef __mlibc_uint64 __mlibc_uint_fast32; +#define __MLIBC_UINT_FAST32_C(x) __MLIBC_UINT64_C(x) +#define __MLIBC_UINT_FAST32_MAX __MLIBC_UINT64_MAX +#define __MLIBC_UINT_FAST32_MIN __MLIBC_UINT64_MIN + +typedef __mlibc_uint64 __mlibc_uint_fast64; +#define __MLIBC_UINT_FAST64_C(x) __MLIBC_UINT64_C(x) +#define __MLIBC_UINT_FAST64_MAX __MLIBC_UINT64_MAX +#define __MLIBC_UINT_FAST64_MIN __MLIBC_UINT64_MIN + +#elif defined (__aarch64__) + +typedef __mlibc_uint8 __mlibc_uint_fast8; +#define __MLIBC_UINT_FAST8_C(x) __MLIBC_UINT8_C(x) +#define __MLIBC_UINT_FAST8_MAX __MLIBC_UINT8_MAX +#define __MLIBC_UINT_FAST8_MIN __MLIBC_UINT8_MIN + +typedef __mlibc_uint64 __mlibc_uint_fast16; +#define __MLIBC_UINT_FAST16_C(x) __MLIBC_UINT64_C(x) +#define __MLIBC_UINT_FAST16_MAX __MLIBC_UINT64_MAX +#define __MLIBC_UINT_FAST16_MIN __MLIBC_UINT64_MIN + +typedef __mlibc_uint64 __mlibc_uint_fast32; +#define __MLIBC_UINT_FAST32_C(x) __MLIBC_UINT64_C(x) +#define __MLIBC_UINT_FAST32_MAX __MLIBC_UINT64_MAX +#define __MLIBC_UINT_FAST32_MIN __MLIBC_UINT64_MIN + +typedef __mlibc_uint64 __mlibc_uint_fast64; +#define __MLIBC_UINT_FAST64_C(x) __MLIBC_UINT64_C(x) +#define __MLIBC_UINT_FAST64_MAX __MLIBC_UINT64_MAX +#define __MLIBC_UINT_FAST64_MIN __MLIBC_UINT64_MIN + +#elif defined (__riscv) && __riscv_xlen == 64 + +typedef __mlibc_uint8 __mlibc_uint_fast8; +#define __MLIBC_UINT_FAST8_C(x) __MLIBC_UINT8_C(x) +#define __MLIBC_UINT_FAST8_MAX __MLIBC_UINT8_MAX +#define __MLIBC_UINT_FAST8_MIN __MLIBC_UINT8_MIN + +typedef __mlibc_uint64 __mlibc_uint_fast16; +#define __MLIBC_UINT_FAST16_C(x) __MLIBC_UINT64_C(x) +#define __MLIBC_UINT_FAST16_MAX __MLIBC_UINT64_MAX +#define __MLIBC_UINT_FAST16_MIN __MLIBC_UINT64_MIN + +typedef __mlibc_uint64 __mlibc_uint_fast32; +#define __MLIBC_UINT_FAST32_C(x) __MLIBC_UINT64_C(x) +#define __MLIBC_UINT_FAST32_MAX __MLIBC_UINT64_MAX +#define __MLIBC_UINT_FAST32_MIN __MLIBC_UINT64_MIN + +typedef __mlibc_uint64 __mlibc_uint_fast64; +#define __MLIBC_UINT_FAST64_C(x) __MLIBC_UINT64_C(x) +#define __MLIBC_UINT_FAST64_MAX __MLIBC_UINT64_MAX +#define __MLIBC_UINT_FAST64_MIN __MLIBC_UINT64_MIN + +#else +# error "Missing architecture specific code" +#endif + +// Special types. + +typedef __INTMAX_TYPE__ __mlibc_intmax; +typedef __INTPTR_TYPE__ __mlibc_intptr; +typedef __PTRDIFF_TYPE__ __mlibc_ptrdiff; +#define __MLIBC_INTMAX_MAX __INTMAX_MAX__ +#define __MLIBC_INTMAX_MIN (-__INTMAX_MAX__ - 1) +#define __MLIBC_INTPTR_MAX __INTPTR_MAX__ +#define __MLIBC_INTPTR_MIN (-__INTPTR_MAX__ - 1) +#define __MLIBC_PTRDIFF_MAX __PTRDIFF_MAX__ +#define __MLIBC_PTRDIFF_MIN (-__PTRDIFF_MAX__ - 1) + +typedef __UINTMAX_TYPE__ __mlibc_uintmax; +typedef __UINTPTR_TYPE__ __mlibc_uintptr; +typedef __SIZE_TYPE__ __mlibc_size; +#define __MLIBC_UINTMAX_MAX __UINTMAX_MAX__ +#define __MLIBC_UINTPTR_MAX __UINTPTR_MAX__ +#define __MLIBC_SIZE_MAX __SIZE_MAX__ + +// Other limits. + +#define __MLIBC_WCHAR_MAX __WCHAR_MAX__ +#define __MLIBC_WCHAR_MIN __WCHAR_MIN__ + +#define __MLIBC_WINT_MAX __WINT_MAX__ +#define __MLIBC_WINT_MIN __WINT_MIN__ + +#define __MLIBC_SIG_ATOMIC_MAX __SIG_ATOMIC_MAX__ +#define __MLIBC_SIG_ATOMIC_MIN __SIG_ATOMIC_MIN__ + +// ---------------------------------------------------------------------------- +// Sanity checking. Make sure that we agree with the compiler's ABI. +// ---------------------------------------------------------------------------- + +#if defined(__cpp_static_assert) +# define __MLIBC_STATIC_ASSERT(c, text) static_assert(c, text) +#elif !defined(__cplusplus) +# define __MLIBC_STATIC_ASSERT(c, text) _Static_assert(c, text) +#else +# define __MLIBC_STATIC_ASSERT(c, text) +#endif + +#define __MLIBC_CHECK_TYPE(T1, T2) __MLIBC_STATIC_ASSERT(sizeof(T1) == sizeof(T2),\ + #T1 " != " #T2); + +// Least-width. +__MLIBC_CHECK_TYPE(__mlibc_int8, __INT_LEAST8_TYPE__); +__MLIBC_CHECK_TYPE(__mlibc_int16, __INT_LEAST16_TYPE__); +__MLIBC_CHECK_TYPE(__mlibc_int32, __INT_LEAST32_TYPE__); +__MLIBC_CHECK_TYPE(__mlibc_int64, __INT_LEAST64_TYPE__); + +__MLIBC_CHECK_TYPE(__mlibc_uint8, __UINT_LEAST8_TYPE__); +__MLIBC_CHECK_TYPE(__mlibc_uint16, __UINT_LEAST16_TYPE__); +__MLIBC_CHECK_TYPE(__mlibc_uint32, __UINT_LEAST32_TYPE__); +__MLIBC_CHECK_TYPE(__mlibc_uint64, __UINT_LEAST64_TYPE__); + +// Fast-width. +// Unfortunately, GCC and Clang disagree about fast types. +#ifndef __clang__ + __MLIBC_CHECK_TYPE(__mlibc_int_fast8, __INT_FAST8_TYPE__); + __MLIBC_CHECK_TYPE(__mlibc_int_fast16, __INT_FAST16_TYPE__); + __MLIBC_CHECK_TYPE(__mlibc_int_fast32, __INT_FAST32_TYPE__); + __MLIBC_CHECK_TYPE(__mlibc_int_fast64, __INT_FAST64_TYPE__); + + __MLIBC_CHECK_TYPE(__mlibc_uint_fast8, __UINT_FAST8_TYPE__); + __MLIBC_CHECK_TYPE(__mlibc_uint_fast16, __UINT_FAST16_TYPE__); + __MLIBC_CHECK_TYPE(__mlibc_uint_fast32, __UINT_FAST32_TYPE__); + __MLIBC_CHECK_TYPE(__mlibc_uint_fast64, __UINT_FAST64_TYPE__); +#endif + +#endif // _MLIBC_INTERNAL_TYPES_H diff --git a/lib/mlibc/options/internal/include/bits/wchar.h b/lib/mlibc/options/internal/include/bits/wchar.h new file mode 100644 index 0000000..a422ef7 --- /dev/null +++ b/lib/mlibc/options/internal/include/bits/wchar.h @@ -0,0 +1,9 @@ +#ifndef MLIBC_WCHAR_H +#define MLIBC_WCHAR_H + +#include + +#define WCHAR_MAX __MLIBC_WCHAR_MAX +#define WCHAR_MIN __MLIBC_WCHAR_MIN + +#endif // MLIBC_WCHAR_H diff --git a/lib/mlibc/options/internal/include/bits/wchar_t.h b/lib/mlibc/options/internal/include/bits/wchar_t.h new file mode 100644 index 0000000..4eb4e9c --- /dev/null +++ b/lib/mlibc/options/internal/include/bits/wchar_t.h @@ -0,0 +1,12 @@ + +#ifndef MLIBC_WCHAR_T_H +#define MLIBC_WCHAR_T_H + +#ifndef __cplusplus + +typedef __WCHAR_TYPE__ wchar_t; + +#endif + +#endif // MLIBC_WCHAR_T_H + diff --git a/lib/mlibc/options/internal/include/bits/winsize.h b/lib/mlibc/options/internal/include/bits/winsize.h new file mode 100644 index 0000000..7b3006a --- /dev/null +++ b/lib/mlibc/options/internal/include/bits/winsize.h @@ -0,0 +1,13 @@ + +#ifndef MLIBC_WINSIZE_H +#define MLIBC_WINSIZE_H + +struct winsize { + unsigned short ws_row; + unsigned short ws_col; + unsigned short ws_xpixel; + unsigned short ws_ypixel; +}; + +#endif // MLIBC_WINSIZE_H + diff --git a/lib/mlibc/options/internal/include/bits/wint_t.h b/lib/mlibc/options/internal/include/bits/wint_t.h new file mode 100644 index 0000000..b4f57bf --- /dev/null +++ b/lib/mlibc/options/internal/include/bits/wint_t.h @@ -0,0 +1,6 @@ +#ifndef MLIBC_WINT_T_H +#define MLIBC_WINT_T_H + +typedef __WINT_TYPE__ wint_t; + +#endif // MLIBC_WINT_T_H diff --git a/lib/mlibc/options/internal/include/mlibc/all-sysdeps.hpp b/lib/mlibc/options/internal/include/mlibc/all-sysdeps.hpp new file mode 100644 index 0000000..7189286 --- /dev/null +++ b/lib/mlibc/options/internal/include/mlibc/all-sysdeps.hpp @@ -0,0 +1,33 @@ +#ifndef MLIBC_ALL_SYSDEPS +#define MLIBC_ALL_SYSDEPS + +#include +#include + +#if __MLIBC_ANSI_OPTION +# include +#endif /* __MLIBC_ANSI_OPTION */ + +#if __MLIBC_POSIX_OPTION +# include +#endif /* __MLIBC_POSIX_OPTION */ + +#if __MLIBC_LINUX_OPTION +# include +#endif /* __MLIBC_LINUX_OPTION */ + +#if __MLIBC_GLIBC_OPTION +# include +#endif /* __MLIBC_GLIBC_OPTION */ + +#if __MLIBC_BSD_OPTION +# include +#endif /* __MLIBC_BSD_OPTION */ + +#if MLIBC_BUILDING_RTDL +# include +#endif /* MLIBC_BUILDING_RTDL */ + +#include + +#endif /* MLIBC_ALL_SYSDEPS */ diff --git a/lib/mlibc/options/internal/include/mlibc/allocator.hpp b/lib/mlibc/options/internal/include/mlibc/allocator.hpp new file mode 100644 index 0000000..5f9617e --- /dev/null +++ b/lib/mlibc/options/internal/include/mlibc/allocator.hpp @@ -0,0 +1,37 @@ +#ifndef MLIBC_FRIGG_ALLOC +#define MLIBC_FRIGG_ALLOC + +#include +#include +#include +#include + +#if !MLIBC_DEBUG_ALLOCATOR + +struct VirtualAllocator { +public: + uintptr_t map(size_t length); + + void unmap(uintptr_t address, size_t length); +}; + +typedef frg::slab_pool MemoryPool; + +typedef frg::slab_allocator MemoryAllocator; + +MemoryAllocator &getAllocator(); + +#else + +struct MemoryAllocator { + void *allocate(size_t size); + void free(void *ptr); + void deallocate(void *ptr, size_t size); + void *reallocate(void *ptr, size_t size); +}; + +MemoryAllocator &getAllocator(); + +#endif // !MLIBC_DEBUG_ALLOCATOR + +#endif // MLIBC_FRIGG_ALLOC diff --git a/lib/mlibc/options/internal/include/mlibc/bitutil.hpp b/lib/mlibc/options/internal/include/mlibc/bitutil.hpp new file mode 100644 index 0000000..6d2b25e --- /dev/null +++ b/lib/mlibc/options/internal/include/mlibc/bitutil.hpp @@ -0,0 +1,34 @@ +#ifndef MLIBC_BITUTIL +#define MLIBC_BITUTIL + +#include + +namespace mlibc { + +template +struct bit_util; + +template<> +struct bit_util { + static uint64_t byteswap(uint64_t x) { + return __builtin_bswap64(x); + } +}; + +template<> +struct bit_util { + static uint32_t byteswap(uint32_t x) { + return __builtin_bswap32(x); + } +}; + +template<> +struct bit_util { + static uint16_t byteswap(uint16_t x) { + return __builtin_bswap16(x); + } +}; + +} // namespace mlibc + +#endif // MLIBC_BITUTIL diff --git a/lib/mlibc/options/internal/include/mlibc/charcode.hpp b/lib/mlibc/options/internal/include/mlibc/charcode.hpp new file mode 100644 index 0000000..67bd03d --- /dev/null +++ b/lib/mlibc/options/internal/include/mlibc/charcode.hpp @@ -0,0 +1,124 @@ +#ifndef MLIBC_CHARCODE_HPP +#define MLIBC_CHARCODE_HPP + +#include +#include +#include +#include +#include + +namespace mlibc { + +enum class charcode_error { + null, + dirty, + illegal_input, + input_underflow, + output_overflow +}; + +template +struct code_seq { + C *it; + const C *end; + + explicit operator bool () { + return it != end; + } +}; + +// Some encodings (e.g. the one defined in RFC 1843) have "shift states", +// i.e. escape sequences that switch between different encodings (e.g. between single-byte ASCII +// and 2-byte encoding of Chinese characters). +// TODO: Implement that using the __shift member of __mlibc_mbstate. + +typedef uint32_t codepoint; + +// The following class deals with decoding/encoding "code units" (of type char) +// to "code points" that are defined by unicode (of type codepoint). +// It also offers convenience functions to transcode to wchar_t, char16_t and char32_t. +// We assume that the encoding of wchar_t (and char16_t, char32_t) is fixed. +// char is allowed to have an arbitrary encoding. +// TODO: char16_t and char32_t variants are missing. +// TODO: For iconv(), first decode and then encode to the destination encoding. +struct polymorphic_charcode { + virtual ~polymorphic_charcode(); + + // Helper function to decode a single char. + charcode_error promote(char nc, codepoint &wc) { + auto uc = static_cast(nc); + if(uc <= 0x7F && preserves_7bit_units) { + wc = uc; + return charcode_error::null; + } + + code_seq nseq{&nc, &nc + 1}; + code_seq wseq{&wc, &wc + 1}; + __mlibc_mbstate st = __MLIBC_MBSTATE_INITIALIZER; + + if(auto e = decode(nseq, wseq, st); e != charcode_error::null) + return e; + // This should have read/written exactly one code unit/code point. + __ensure(nseq.it == nseq.end); + __ensure(wseq.it == wseq.end); + return charcode_error::null; + } + + // Helper function to decode a single char. + charcode_error promote_wtranscode(char nc, wchar_t &wc) { + auto uc = static_cast(nc); + if(uc <= 0x7F && preserves_7bit_units) { // TODO: Use "wtranscode_preserves_7bit_units". + wc = uc; + return charcode_error::null; + } + + code_seq nseq{&nc, &nc + 1}; + code_seq wseq{&wc, &wc + 1}; + __mlibc_mbstate st = __MLIBC_MBSTATE_INITIALIZER; + + if(auto e = decode_wtranscode(nseq, wseq, st); e != charcode_error::null) + return e; + // This should have read/written exactly one code unit/code point. + __ensure(nseq.it == nseq.end); + __ensure(wseq.it == wseq.end); + return charcode_error::null; + } + + polymorphic_charcode(bool preserves_7bit_units_, bool has_shift_states_) + : preserves_7bit_units{preserves_7bit_units_}, has_shift_states{has_shift_states_} { } + + virtual charcode_error decode(code_seq &nseq, code_seq &wseq, + __mlibc_mbstate &st) = 0; + + virtual charcode_error decode_wtranscode(code_seq &nseq, code_seq &wseq, + __mlibc_mbstate &st) = 0; + + virtual charcode_error decode_wtranscode_length(code_seq &nseq, size_t *n, + __mlibc_mbstate &st) = 0; + + virtual charcode_error encode_wtranscode(code_seq &nseq, code_seq &wseq, + __mlibc_mbstate &st) = 0; + + virtual charcode_error encode_wtranscode_length(code_seq &wseq, size_t *n, + __mlibc_mbstate &st) = 0; + + // True if promotion only zero-extends units below 0x7F. + const bool preserves_7bit_units; + + // Whether the encoding has shift states. + const bool has_shift_states; +}; + +polymorphic_charcode *current_charcode(); + +// Similar to polymorphic_charcode but for wchar_t. Note that this encoding is fixed per-platform; +// thus, it does not need to be polymorphic. +struct wide_charcode { + charcode_error promote(wchar_t nc, codepoint &wc); +}; + +wide_charcode *platform_wide_charcode(); + +} // namespace mlibc + +#endif // MLIBC_CHARCODE_HPP diff --git a/lib/mlibc/options/internal/include/mlibc/charset.hpp b/lib/mlibc/options/internal/include/mlibc/charset.hpp new file mode 100644 index 0000000..a068f05 --- /dev/null +++ b/lib/mlibc/options/internal/include/mlibc/charset.hpp @@ -0,0 +1,40 @@ +#ifndef MLIBC_CHARSET_HPP +#define MLIBC_CHARSET_HPP + +#include + +namespace mlibc { + +// Represents the charset of a certain locale. We define the charset as +// a set of characters, together with their properties and conversion rules +// *but not* their encoding (e.g. to UTF-8 or UTF-16). +struct charset { + // Returns true iif the meaning of the first 0x7F characters matches ASCII. + bool is_ascii_superset(); + + bool is_alpha(codepoint c); + bool is_digit(codepoint c); + bool is_xdigit(codepoint c); + bool is_alnum(codepoint c); + bool is_punct(codepoint c); + bool is_graph(codepoint c); + bool is_blank(codepoint c); + bool is_space(codepoint c); + bool is_print(codepoint c); + + bool is_lower(codepoint c); + bool is_upper(codepoint c); + codepoint to_lower(codepoint c); + codepoint to_upper(codepoint c); +}; + +charset *current_charset(); + +// The property if a character is a control character is locale-independent. +inline bool generic_is_control(codepoint c) { + return (c <= 0x1F) || (c == 0x7F) || (c >= 0x80 && c <= 0x9F); +} + +} // namespace mlibc + +#endif // MLIBC_CHARSET_HPP diff --git a/lib/mlibc/options/internal/include/mlibc/debug.hpp b/lib/mlibc/options/internal/include/mlibc/debug.hpp new file mode 100644 index 0000000..7067039 --- /dev/null +++ b/lib/mlibc/options/internal/include/mlibc/debug.hpp @@ -0,0 +1,27 @@ +#ifndef MLIBC_DEBUG_HPP +#define MLIBC_DEBUG_HPP + +#include + +namespace mlibc { + +struct InfoSink { + // constexpr so that this can be initialized statically. + constexpr InfoSink() = default; + + void operator() (const char *message); +}; + +struct PanicSink { + // constexpr so that this can be initialized statically. + constexpr PanicSink() = default; + + void operator() (const char *message); +}; + +extern frg::stack_buffer_logger infoLogger; +extern frg::stack_buffer_logger panicLogger; + +} // namespace mlibc + +#endif // MLIBC_DEBUG_HPP diff --git a/lib/mlibc/options/internal/include/mlibc/file-window.hpp b/lib/mlibc/options/internal/include/mlibc/file-window.hpp new file mode 100644 index 0000000..68c3ebf --- /dev/null +++ b/lib/mlibc/options/internal/include/mlibc/file-window.hpp @@ -0,0 +1,64 @@ +#ifndef MLIBC_FILE_WINDOW +#define MLIBC_FILE_WINDOW + +#include +#include +#include +#include +#include + +struct file_window { + file_window(const char *path) { + int fd; + if(mlibc::sys_open("/etc/localtime", O_RDONLY, 0, &fd)) + mlibc::panicLogger() << "mlibc: Error opening file_window to " + << path << frg::endlog; + + if(!mlibc::sys_stat) { + MLIBC_MISSING_SYSDEP(); + __ensure(!"cannot proceed without sys_stat"); + } + struct stat info; + if(mlibc::sys_stat(mlibc::fsfd_target::fd, fd, "", 0, &info)) + mlibc::panicLogger() << "mlibc: Error getting TZinfo stats" << frg::endlog; + +#if MLIBC_MAP_FILE_WINDOWS + if(mlibc::sys_vm_map(nullptr, (size_t)info.st_size, PROT_READ, MAP_PRIVATE, + fd, 0, &_ptr)) + mlibc::panicLogger() << "mlibc: Error mapping TZinfo" << frg::endlog; +#else + _ptr = getAllocator().allocate(info.st_size); + __ensure(_ptr); + + size_t progress = 0; + size_t st_size = static_cast(info.st_size); + while(progress < st_size) { + ssize_t chunk; + if(int e = mlibc::sys_read(fd, reinterpret_cast(_ptr) + progress, + st_size - progress, &chunk); e) + mlibc::panicLogger() << "mlibc: Read from file_window failed" << frg::endlog; + if(!chunk) + break; + progress += chunk; + } + if(progress != st_size) + mlibc::panicLogger() << "stat reports " << info.st_size << " but we only read " + << progress << " bytes" << frg::endlog; +#endif + + if(mlibc::sys_close(fd)) + mlibc::panicLogger() << "mlibc: Error closing TZinfo" << frg::endlog; + } + + // TODO: Write destructor to deallocate/unmap memory. + + void *get() { + return _ptr; + } + +private: + void *_ptr; +}; + +#endif // MLIBC_FILE_WINDOW + diff --git a/lib/mlibc/options/internal/include/mlibc/fsfd_target.hpp b/lib/mlibc/options/internal/include/mlibc/fsfd_target.hpp new file mode 100644 index 0000000..b577325 --- /dev/null +++ b/lib/mlibc/options/internal/include/mlibc/fsfd_target.hpp @@ -0,0 +1,15 @@ +#ifndef MLIBC_FSFD_TARGET +#define MLIBC_FSFD_TARGET + +namespace mlibc { + +enum class fsfd_target { + none, + path, + fd, + fd_path +}; + +} // namespace mlibc + +#endif // MLIBC_FSFD_TARGET diff --git a/lib/mlibc/options/internal/include/mlibc/global-config.hpp b/lib/mlibc/options/internal/include/mlibc/global-config.hpp new file mode 100644 index 0000000..7eaed3c --- /dev/null +++ b/lib/mlibc/options/internal/include/mlibc/global-config.hpp @@ -0,0 +1,19 @@ +#ifndef MLIBC_GLOBAL_CONFIG +#define MLIBC_GLOBAL_CONFIG + +namespace mlibc { + +struct GlobalConfig { + GlobalConfig(); + + bool debugMalloc; +}; + +inline const GlobalConfig &globalConfig() { + static GlobalConfig cached; + return cached; +} + +} + +#endif // MLIBC_GLOBAL_CONFIG diff --git a/lib/mlibc/options/internal/include/mlibc/internal-sysdeps.hpp b/lib/mlibc/options/internal/include/mlibc/internal-sysdeps.hpp new file mode 100644 index 0000000..02df713 --- /dev/null +++ b/lib/mlibc/options/internal/include/mlibc/internal-sysdeps.hpp @@ -0,0 +1,41 @@ +#ifndef MLIBC_INTERNAL_SYSDEPS +#define MLIBC_INTERNAL_SYSDEPS + +#include + +#include +#include +#include +#include +#include +#include + +namespace [[gnu::visibility("hidden")]] mlibc { + +void sys_libc_log(const char *message); +[[noreturn]] void sys_libc_panic(); + +int sys_tcb_set(void *pointer); + +[[gnu::weak]] int sys_futex_tid(); +int sys_futex_wait(int *pointer, int expected, const struct timespec *time); +int sys_futex_wake(int *pointer); + +int sys_anon_allocate(size_t size, void **pointer); +int sys_anon_free(void *pointer, size_t size); + +int sys_open(const char *pathname, int flags, mode_t mode, int *fd); +int sys_read(int fd, void *buf, size_t count, ssize_t *bytes_read); +int sys_seek(int fd, off_t offset, int whence, off_t *new_offset); +int sys_close(int fd); + +[[gnu::weak]] int sys_stat(fsfd_target fsfdt, int fd, const char *path, int flags, + struct stat *statbuf); +// mlibc assumes that anonymous memory returned by sys_vm_map() is zeroed by the kernel / whatever is behind the sysdeps +int sys_vm_map(void *hint, size_t size, int prot, int flags, int fd, off_t offset, void **window); +int sys_vm_unmap(void *pointer, size_t size); +[[gnu::weak]] int sys_vm_protect(void *pointer, size_t size, int prot); + +} //namespace mlibc + +#endif // MLIBC_INTERNAL_SYSDEPS diff --git a/lib/mlibc/options/internal/include/mlibc/locale.hpp b/lib/mlibc/options/internal/include/mlibc/locale.hpp new file mode 100644 index 0000000..a46a2c3 --- /dev/null +++ b/lib/mlibc/options/internal/include/mlibc/locale.hpp @@ -0,0 +1,12 @@ +#ifndef MLIBC_LOCALE +#define MLIBC_LOCALE + +#include + +namespace mlibc { + +char *nl_langinfo(nl_item item); + +} // namespace mlibc + +#endif // MLIBC_LOCALE diff --git a/lib/mlibc/options/internal/include/mlibc/lock.hpp b/lib/mlibc/options/internal/include/mlibc/lock.hpp new file mode 100644 index 0000000..aa05079 --- /dev/null +++ b/lib/mlibc/options/internal/include/mlibc/lock.hpp @@ -0,0 +1,124 @@ +#ifndef MLIBC_LOCK_HPP +#define MLIBC_LOCK_HPP + +#include +#include +#include +#include +#include +#include + +template +struct FutexLockImpl { + FutexLockImpl() : _state{0}, _recursion{0} { } + + FutexLockImpl(const FutexLockImpl &) = delete; + + FutexLockImpl &operator= (const FutexLockImpl &) = delete; + + static constexpr uint32_t waitersBit = (1 << 31); + static constexpr uint32_t ownerMask = (static_cast(1) << 30) - 1; + + void lock() { + unsigned int this_tid = mlibc::this_tid(); + unsigned int expected = 0; + + while(true) { + if(!expected) { + // Try to take the mutex here. + if(__atomic_compare_exchange_n(&_state, + &expected, this_tid, false, __ATOMIC_ACQUIRE, __ATOMIC_ACQUIRE)) { + if constexpr (Recursive) { + __ensure(!_recursion); + _recursion = 1; + } + return; + } + }else{ + // If this (recursive) mutex is already owned by us, increment the recursion level. + if((expected & ownerMask) == this_tid) { + if constexpr (Recursive) + ++_recursion; + else + mlibc::panicLogger() << "mlibc: FutexLock deadlock detected!" << frg::endlog; + return; + } + + // Wait on the futex if the waiters flag is set. + if(expected & waitersBit) { + int e = mlibc::sys_futex_wait((int *)&_state, expected, nullptr); + + // If the wait returns EAGAIN, that means that the waitersBit was just unset by + // some other thread. In this case, we should loop back around. + if (e && e != EAGAIN) + mlibc::panicLogger() << "sys_futex_wait() failed with error code " << e << frg::endlog; + + // Opportunistically try to take the lock after we wake up. + expected = 0; + }else{ + // Otherwise we have to set the waiters flag first. + unsigned int desired = expected | waitersBit; + if(__atomic_compare_exchange_n((int *)&_state, + reinterpret_cast(&expected), desired, false, __ATOMIC_RELAXED, __ATOMIC_RELAXED)) + expected = desired; + } + } + } + } + + bool try_lock() { + unsigned int this_tid = mlibc::this_tid(); + unsigned int expected = __atomic_load_n(&_state, __ATOMIC_RELAXED); + + if(!expected) { + // Try to take the mutex here. + if(__atomic_compare_exchange_n(&_state, + &expected, this_tid, false, __ATOMIC_ACQUIRE, __ATOMIC_ACQUIRE)) { + if constexpr (Recursive) + _recursion = 1; + return true; + } + } else { + // If this (recursive) mutex is already owned by us, increment the recursion level. + if((expected & ownerMask) == this_tid) { + if constexpr (Recursive) { + __ensure(!_recursion); + ++_recursion; + return true; + } else { + return false; + } + } + } + + return false; + } + + void unlock() { + // Decrement the recursion level and unlock if we hit zero. + if constexpr (Recursive) { + __ensure(_recursion); + if(--_recursion) + return; + } + + // Reset the mutex to the unlocked state. + auto state = __atomic_exchange_n(&_state, 0, __ATOMIC_RELEASE); + __ensure((state & ownerMask) == mlibc::this_tid()); + + if(state & waitersBit) { + // Wake the futex if there were waiters. Since the mutex might not exist at this location + // anymore, we must conservatively ignore EACCES and EINVAL which may occur as a result. + int e = mlibc::sys_futex_wake((int *)&_state); + __ensure(e >= 0 || e == EACCES || e == EINVAL); + } + } +private: + uint32_t _state; + uint32_t _recursion; +}; + +using FutexLock = FutexLockImpl; +using RecursiveFutexLock = FutexLockImpl; + +#endif diff --git a/lib/mlibc/options/internal/include/mlibc/stack_protector.hpp b/lib/mlibc/options/internal/include/mlibc/stack_protector.hpp new file mode 100644 index 0000000..47290fc --- /dev/null +++ b/lib/mlibc/options/internal/include/mlibc/stack_protector.hpp @@ -0,0 +1,10 @@ +#ifndef MLIBC_STACK_PROTECTOR_HPP +#define MLIBC_STACK_PROTECTOR_HPP + +namespace mlibc { + +void initStackGuard(void *); + +} // namespace mlibc + +#endif // MLIBC_STACK_PROTECTOR_HPP diff --git a/lib/mlibc/options/internal/include/mlibc/strings.hpp b/lib/mlibc/options/internal/include/mlibc/strings.hpp new file mode 100644 index 0000000..5a93c7c --- /dev/null +++ b/lib/mlibc/options/internal/include/mlibc/strings.hpp @@ -0,0 +1,12 @@ +#ifndef MLIBC_STRINGS +#define MLIBC_STRINGS + +#include + +namespace mlibc { + +int strncasecmp(const char *a, const char *b, size_t size); + +} // namespace mlibc + +#endif // MLIBC_STRINGS diff --git a/lib/mlibc/options/internal/include/mlibc/strtofp.hpp b/lib/mlibc/options/internal/include/mlibc/strtofp.hpp new file mode 100644 index 0000000..f9c5e20 --- /dev/null +++ b/lib/mlibc/options/internal/include/mlibc/strtofp.hpp @@ -0,0 +1,165 @@ +#ifndef MLIBC_STRTOFP_HPP +#define MLIBC_STRTOFP_HPP + +#include +#include +#include + +namespace mlibc { + +template +T strtofp(const char *str, char **endptr) { + if (strcmp(str, "INF") == 0 || strcmp(str, "inf") == 0) { + if (endptr) + *endptr = (char *)str + 3; + if constexpr (std::is_same_v) + return __builtin_inff(); + else if constexpr (std::is_same_v) + return __builtin_inf(); + else + return __builtin_infl(); + } else if (strcmp(str, "INFINITY") == 0 || strcmp(str, "infinity") == 0) { + if (endptr) + *endptr = (char *)str + 8; + if constexpr (std::is_same_v) + return __builtin_inff(); + else if constexpr (std::is_same_v) + return __builtin_inf(); + else + return __builtin_infl(); + } else if (strncmp(str, "NAN", 3) == 0 || strncmp(str, "nan", 3) == 0) { + if (endptr) + *endptr = (char *)str + 3; + if constexpr (std::is_same_v) + return __builtin_nanf(""); + else if constexpr (std::is_same_v) + return __builtin_nan(""); + else + return __builtin_nanl(""); + } + + bool negative = *str == '-'; + if (*str == '+' || *str == '-') + str++; + + bool hex = false; + if (*str == '0' && (*(str + 1) == 'x' || *(str + 1) == 'X')) { + str += 2; + hex = true; + } + + T result = static_cast(0); + + const char *tmp = str; + + if (!hex) { + while (true) { + if (!isdigit(*tmp)) + break; + result *= static_cast(10); + result += static_cast(*tmp - '0'); + tmp++; + } + } else { + while (true) { + if (!isxdigit(*tmp)) + break; + result *= static_cast(16); + result += static_cast(*tmp <= '9' ? (*tmp - '0') : (tolower(*tmp) - 'a' + 10)); + tmp++; + } + } + + if (*tmp == '.') { + tmp++; + + if (!hex) { + T d = static_cast(10); + + while (true) { + if (!isdigit(*tmp)) + break; + result += static_cast(*tmp - '0') / d; + d *= static_cast(10); + tmp++; + } + } else { + T d = static_cast(16); + + while (true) { + if (!isxdigit(*tmp)) + break; + result += static_cast(*tmp <= '9' ? (*tmp - '0') : (tolower(*tmp) - 'a' + 10)) / d; + d *= static_cast(16); + tmp++; + } + } + } + + if (!hex) { + if (*tmp == 'e' || *tmp == 'E') { + tmp++; + + bool exp_negative = *tmp == '-'; + if (*tmp == '+' || *tmp == '-') + tmp++; + + int exp = 0; + while (true) { + if (!isdigit(*tmp)) + break; + exp *= 10; + exp += *tmp - '0'; + tmp++; + } + + if (!exp_negative) { + for (int i = 0; i < exp; ++i) { + result *= static_cast(10); + } + } else { + for (int i = 0; i < exp; ++i) { + result /= static_cast(10); + } + } + } + } else { + if (*tmp == 'p' || *tmp == 'P') { + tmp++; + + bool exp_negative = *tmp == '-'; + if (*tmp == '+' || *tmp == '-') + tmp++; + + int exp = 0; + while (true) { + if (!isdigit(*tmp)) + break; + exp *= 10; + exp += *tmp - '0'; + tmp++; + } + + if (!exp_negative) { + for (int i = 0; i < exp; ++i) { + result *= static_cast(2); + } + } else { + for (int i = 0; i < exp; ++i) { + result /= static_cast(2); + } + } + } + } + + if (endptr) + *endptr = const_cast(tmp); + if (negative) + result = -result; + + return result; +} + +} + +#endif // MLIBC_STRTOFP_HPP diff --git a/lib/mlibc/options/internal/include/mlibc/strtol.hpp b/lib/mlibc/options/internal/include/mlibc/strtol.hpp new file mode 100644 index 0000000..3b8fca9 --- /dev/null +++ b/lib/mlibc/options/internal/include/mlibc/strtol.hpp @@ -0,0 +1,159 @@ +#ifndef MLIBC_STRTOL_HPP +#define MLIBC_STRTOL_HPP + +#include +#include +#include +#include + +namespace mlibc { + +template struct int_limits {}; + +template<> +struct int_limits { + static long max() { return LONG_MAX; } + static long min() { return LONG_MIN; } +}; + +template<> +struct int_limits { + static unsigned long max() { return ULONG_MAX; } + static unsigned long min() { return 0; } +}; + +template<> +struct int_limits { + static long long max() { return LLONG_MAX; } + static long long min() { return LLONG_MIN; } +}; + +template<> +struct int_limits { + static unsigned long long max() { return ULLONG_MAX; } + static unsigned long long min() { return 0; } +}; + +template struct char_detail {}; + +template<> +struct char_detail { + static bool isSpace(char c) { return isspace(c); } + static bool isDigit(char c) { return isdigit(c); } + static bool isHexDigit(char c) { return isxdigit(c); } + static bool isLower(char c) { return islower(c); } + static bool isUpper(char c) { return isupper(c); } +}; + +template<> +struct char_detail { + static bool isSpace(wchar_t c) { return iswspace(c); } + static bool isDigit(wchar_t c) { return iswdigit(c); } + static bool isHexDigit(wchar_t c) { return iswxdigit(c); } + static bool isLower(wchar_t c) { return iswlower(c); } + static bool isUpper(wchar_t c) { return iswupper(c); } +}; + +template Char widen(char c) { return static_cast(c); } + +template +Return stringToInteger(const Char *__restrict nptr, Char **__restrict endptr, int baseInt) { + using UnsignedReturn = std::make_unsigned_t; + + auto base = static_cast(baseInt); + auto s = nptr; + + if (base < 0 || base == 1) { + if (endptr) + *endptr = const_cast(nptr); + return 0; + } + + while (char_detail::isSpace(*s)) + s++; + + bool negative = false; + if (*s == widen('-')) { + negative = true; + s++; + } else if (*s == widen('+')) { + s++; + } + + + bool hasOctalPrefix = s[0] == widen('0'); + bool hasHexPrefix = hasOctalPrefix && (s[1] == widen('x') || s[1] == widen('X')); + + // There's two tricky cases we need to keep in mind here: + // 1. We should interpret "0x5" as hex 5 rather than octal 0. + // 2. We should interpret "0x" as octal 0 (and set endptr correctly). + // To deal with 2, we check the charcacter following the hex prefix. + if ((base == 0 || base == 16) && hasHexPrefix && char_detail::isHexDigit(s[2])) { + s += 2; + base = 16; + } else if ((base == 0 || base == 8) && hasOctalPrefix) { + base = 8; + } else if (base == 0) { + base = 10; + } + + // Compute the range of acceptable values. + UnsignedReturn cutoff, cutlim; + if (std::is_unsigned_v) { + cutoff = int_limits::max() / base; + cutlim = int_limits::max() % base; + } else { + Return co = negative ? int_limits::min() : int_limits::max(); + cutlim = negative ? -(co % base) : co % base; + co /= negative ? -base : base; + cutoff = co; + } + + UnsignedReturn totalValue = 0; + bool convertedAny = false; + bool outOfRange = false; + for (Char c = *s; c != widen('\0'); c = *++s) { + UnsignedReturn digitValue; + if (char_detail::isDigit(c)) + digitValue = c - widen('0'); + else if (char_detail::isUpper(c)) + digitValue = c - widen('A') + 10; + else if (char_detail::isLower(c)) + digitValue = c - widen('a') + 10; + else + break; + + if (digitValue >= static_cast(base)) + break; + + if (outOfRange) { + // The value is already known to be out of range, but we need to keep + // consuming characters until we can't (to set endptr correctly). + } else if (totalValue > cutoff || (totalValue == cutoff && digitValue > cutlim)) { + // The value will be out of range if we accumulate digitValue. + outOfRange = true; + } else { + totalValue = (totalValue * base) + digitValue; + convertedAny = true; + } + } + + if (endptr) + *endptr = const_cast(convertedAny ? s : nptr); + + if (outOfRange) { + errno = ERANGE; + + if (std::is_unsigned_v) { + return int_limits::max(); + } else { + return negative ? int_limits::min() : int_limits::max(); + } + } + + return negative ? -totalValue : totalValue; +} + +} + +#endif // MLIBC_STRTOL_HPP diff --git a/lib/mlibc/options/internal/include/mlibc/tcb.hpp b/lib/mlibc/options/internal/include/mlibc/tcb.hpp new file mode 100644 index 0000000..92aad7a --- /dev/null +++ b/lib/mlibc/options/internal/include/mlibc/tcb.hpp @@ -0,0 +1,180 @@ +#pragma once + +#include +#include +#include +#include + +#include "elf.hpp" + +/* + * Explanation of cancellation bits: + * + * tcbCancelEnableBit and tcbCancelAsyncBit should be self-explanatory, + * they are set if cancellation is enabled, or asynchronous, respectively. + * + * tcbCancelTriggerBit is set whenever a cancellation is triggered, which is + * in pthread_cancel() or in the signal handler. This bit is used by + * pthread_testcancel() to check whether a cancellation has been requested, + * and also by cancellable syscalls. + * + * tcbCancelingBit is set when a cancellation is currently being handled. This + * is to avoid a situation in which a cancellation handler gets interrupted by + * a SIGCANCEL and a second cancellation handler gets executed on top of the + * previous one. Right now this cannot happen, since we stay in signal handler + * context when canceling/exiting. In the future this might be done outside + * of a signal handler, in which case we shouldn't restart the cancellation process. + * + * tcbExitingBit is set when the thread starts the exit procedure. Currently + * this is just an exit, but in the future this will be a stack unwinding + * procedure, which shouldn't be reentered. Not currently set anywhere, + * may be done so in the future. + * + * TODO(geert): update this comment when we do unwinding in the exit procedure. + */ + +namespace { + // Set when the cancellation is enabled + constexpr unsigned int tcbCancelEnableBit = 1 << 0; + // 1 - cancellation is asynchronous, 0 - cancellation is deferred + constexpr unsigned int tcbCancelAsyncBit = 1 << 1; + // Set when the thread has been cancelled + constexpr unsigned int tcbCancelTriggerBit = 1 << 2; + // Set when the thread is in the process of being cancelled. + constexpr unsigned int tcbCancelingBit = 1 << 3; + // Set when the thread is exiting. + constexpr unsigned int tcbExitingBit = 1 << 4; +} + +namespace mlibc { + // Returns true when bitmask indicates thread has been asynchronously + // cancelled. + static constexpr bool tcb_async_cancelled(int value) { + return (value & (tcbCancelEnableBit | tcbCancelAsyncBit + | tcbCancelTriggerBit)) == (tcbCancelEnableBit + | tcbCancelAsyncBit | tcbCancelTriggerBit); + } + + // Returns true when bitmask indicates async cancellation is enabled. + static constexpr bool tcb_async_cancel(int value) { + return (value & (tcbCancelEnableBit | tcbCancelAsyncBit)) + == (tcbCancelEnableBit | tcbCancelAsyncBit); + } + + // Returns true when bitmask indicates cancellation is enabled. + static constexpr bool tcb_cancel_enabled(int value) { + return (value & tcbCancelEnableBit); + } + + // Returns true when bitmask indicates threas has been cancelled. + static constexpr bool tcb_cancelled(int value) { + return (value & (tcbCancelEnableBit | tcbCancelTriggerBit)) + == (tcbCancelEnableBit | tcbCancelTriggerBit); + } + +#if !MLIBC_STATIC_BUILD && !MLIBC_BUILDING_RTDL + // In non-static builds, libc.so always has a TCB available. + constexpr bool tcb_available_flag = true; +#else + // Otherwise this will be set to true after RTDL has initialized the TCB. + extern bool tcb_available_flag; +#endif +} + +enum class TcbThreadReturnValue { + Pointer, + Integer, +}; + +struct Tcb { + Tcb *selfPointer; + size_t dtvSize; + void **dtvPointers; + int tid; + int didExit; +#if defined(__x86_64__) + uint8_t padding[8]; +#endif + uintptr_t stackCanary; + int cancelBits; + + union { + void *voidPtr; + int intVal; + } returnValue; + TcbThreadReturnValue returnValueType; + + struct AtforkHandler { + void (*prepare)(void); + void (*parent)(void); + void (*child)(void); + + AtforkHandler *next; + AtforkHandler *prev; + }; + + AtforkHandler *atforkBegin; + AtforkHandler *atforkEnd; + + struct CleanupHandler { + void (*func)(void *); + void *arg; + + CleanupHandler *next; + CleanupHandler *prev; + }; + + CleanupHandler *cleanupBegin; + CleanupHandler *cleanupEnd; + int isJoinable; + + struct LocalKey { + void *value; + uint64_t generation; + }; + frg::array *localKeys; + + size_t stackSize; + void *stackAddr; + size_t guardSize; + + inline void invokeThreadFunc(void *entry, void *user_arg) { + if(returnValueType == TcbThreadReturnValue::Pointer) { + auto func = reinterpret_cast(entry); + returnValue.voidPtr = func(user_arg); + } else { + auto func = reinterpret_cast(entry); + returnValue.intVal = func(user_arg); + } + } +}; + +// There are a few places where we assume the layout of the TCB: +#if defined(__x86_64__) +// GCC expects the stack canary to be at fs:0x28. +static_assert(offsetof(Tcb, stackCanary) == 0x28); +// sysdeps/linux/x86_64/cp_syscall.S uses the offset of cancelBits. +static_assert(offsetof(Tcb, cancelBits) == 0x30); +#elif defined(__i386__) +// GCC expects the stack canary to be at gs:0x14. +// The offset differs from x86_64 due to the change in the pointer size +// and removed padding before the stack canary. +static_assert(offsetof(Tcb, stackCanary) == 0x14); +// sysdeps/linux/x86/cp_syscall.S uses the offset of cancelBits. +// It differs from x86_64 for the same reasons as the stack canary. +static_assert(offsetof(Tcb, cancelBits) == 0x18); +#elif defined(__aarch64__) +// The thread pointer on AArch64 points to 16 bytes before the end of the TCB. +// options/linker/aarch64/runtime.S uses the offset of dtvPointers. +static_assert(sizeof(Tcb) - offsetof(Tcb, dtvPointers) - TP_TCB_OFFSET == 104); +// sysdeps/linux/aarch64/cp_syscall.S uses the offset of cancelBits. +static_assert(sizeof(Tcb) - offsetof(Tcb, cancelBits) - TP_TCB_OFFSET == 80); +#elif defined(__riscv) && __riscv_xlen == 64 +// The thread pointer on RISC-V points to *after* the TCB, and since +// we need to access specific fields that means that the value in +// sysdeps/linux/riscv64/cp_syscall.S needs to be updated whenever +// the struct is expanded. +static_assert(sizeof(Tcb) - offsetof(Tcb, cancelBits) == 96); +#else +#error "Missing architecture specific code." +#endif diff --git a/lib/mlibc/options/internal/include/mlibc/threads.hpp b/lib/mlibc/options/internal/include/mlibc/threads.hpp new file mode 100644 index 0000000..989a8e5 --- /dev/null +++ b/lib/mlibc/options/internal/include/mlibc/threads.hpp @@ -0,0 +1,27 @@ +#pragma once + +#include +#include + +namespace mlibc { + +int thread_create(struct __mlibc_thread_data **__restrict thread, const struct __mlibc_threadattr *__restrict attrp, void *entry, void *__restrict user_arg, bool returns_int); +int thread_attr_init(struct __mlibc_threadattr *attr); +int thread_join(struct __mlibc_thread_data *thread, void *res); + +int thread_mutex_init(struct __mlibc_mutex *__restrict mutex, const struct __mlibc_mutexattr *__restrict attr); +int thread_mutex_destroy(struct __mlibc_mutex *mutex); +int thread_mutex_lock(struct __mlibc_mutex *mutex); +int thread_mutex_unlock(struct __mlibc_mutex *mutex); + +int thread_mutexattr_init(struct __mlibc_mutexattr *attr); +int thread_mutexattr_destroy(struct __mlibc_mutexattr *attr); +int thread_mutexattr_gettype(const struct __mlibc_mutexattr *__restrict attr, int *__restrict type); +int thread_mutexattr_settype(struct __mlibc_mutexattr *attr, int type); + +int thread_cond_init(struct __mlibc_cond *__restrict cond, const struct __mlibc_condattr *__restrict attr); +int thread_cond_destroy(struct __mlibc_cond *cond); +int thread_cond_broadcast(struct __mlibc_cond *cond); +int thread_cond_timedwait(struct __mlibc_cond *__restrict cond, __mlibc_mutex *__restrict mutex, const struct timespec *__restrict abstime); + +} diff --git a/lib/mlibc/options/internal/include/mlibc/tid.hpp b/lib/mlibc/options/internal/include/mlibc/tid.hpp new file mode 100644 index 0000000..e85c19f --- /dev/null +++ b/lib/mlibc/options/internal/include/mlibc/tid.hpp @@ -0,0 +1,18 @@ +#pragma once + +#include +#include + +namespace mlibc { + inline unsigned int this_tid() { + // During RTDL initialization, we don't have a TCB. + if (mlibc::tcb_available_flag) { + auto tcb = get_current_tcb(); + return tcb->tid; + } else if (mlibc::sys_futex_tid) { + return mlibc::sys_futex_tid(); + } else { + return 1; + } + } +} diff --git a/lib/mlibc/options/internal/include/stdint.h b/lib/mlibc/options/internal/include/stdint.h new file mode 100644 index 0000000..4d8df66 --- /dev/null +++ b/lib/mlibc/options/internal/include/stdint.h @@ -0,0 +1,150 @@ +#ifndef _MLIBC_STDINT_H +#define _MLIBC_STDINT_H + +#include +#include + +// ---------------------------------------------------------------------------- +// Type definitions. +// ---------------------------------------------------------------------------- + +// Fixed-width (signed). +typedef __mlibc_int8 int8_t; +typedef __mlibc_int16 int16_t; +typedef __mlibc_int32 int32_t; +typedef __mlibc_int64 int64_t; + +// Fixed-width (unsigned). +typedef __mlibc_uint8 uint8_t; +typedef __mlibc_uint16 uint16_t; +typedef __mlibc_uint32 uint32_t; +typedef __mlibc_uint64 uint64_t; + +// Least-width (signed). +typedef __mlibc_int8 int_least8_t; +typedef __mlibc_int16 int_least16_t; +typedef __mlibc_int32 int_least32_t; +typedef __mlibc_int64 int_least64_t; + +// Least-width (unsigned). +typedef __mlibc_uint8 uint_least8_t; +typedef __mlibc_uint16 uint_least16_t; +typedef __mlibc_uint32 uint_least32_t; +typedef __mlibc_uint64 uint_least64_t; + +// Fast-width (signed). +typedef __mlibc_int_fast8 int_fast8_t; +typedef __mlibc_int_fast16 int_fast16_t; +typedef __mlibc_int_fast32 int_fast32_t; +typedef __mlibc_int_fast64 int_fast64_t; + +// Fast-width (unsigned). +typedef __mlibc_uint_fast8 uint_fast8_t; +typedef __mlibc_uint_fast16 uint_fast16_t; +typedef __mlibc_uint_fast32 uint_fast32_t; +typedef __mlibc_uint_fast64 uint_fast64_t; + +// Miscellaneous (signed). +typedef __mlibc_intmax intmax_t; +typedef __mlibc_intptr intptr_t; + +// Miscellaneous (unsigned). +typedef __mlibc_uintmax uintmax_t; +typedef __mlibc_uintptr uintptr_t; + +// ---------------------------------------------------------------------------- +// Constants. +// ---------------------------------------------------------------------------- + +// Fixed-width (signed). +#define INT8_C(x) __MLIBC_INT8_C(x) +#define INT16_C(x) __MLIBC_INT16_C(x) +#define INT32_C(x) __MLIBC_INT32_C(x) +#define INT64_C(x) __MLIBC_INT64_C(x) +#define INTMAX_C(x) __MLIBC_INTMAX_C(x) + +// Fixed-width (unsigned). +#define UINT8_C(x) __MLIBC_UINT8_C(x) +#define UINT16_C(x) __MLIBC_UINT16_C(x) +#define UINT32_C(x) __MLIBC_UINT32_C(x) +#define UINT64_C(x) __MLIBC_UINT64_C(x) +#define UINTMAX_C(x) __MLIBC_UINTMAX_C(x) + +// ---------------------------------------------------------------------------- +// Limits. +// ---------------------------------------------------------------------------- + +// Fixed-width (signed). +#define INT8_MAX __MLIBC_INT8_MAX +#define INT16_MAX __MLIBC_INT16_MAX +#define INT32_MAX __MLIBC_INT32_MAX +#define INT64_MAX __MLIBC_INT64_MAX + +#define INT8_MIN __MLIBC_INT8_MIN +#define INT16_MIN __MLIBC_INT16_MIN +#define INT32_MIN __MLIBC_INT32_MIN +#define INT64_MIN __MLIBC_INT64_MIN + +// Fixed-width (unsigned). +#define UINT8_MAX __MLIBC_UINT8_MAX +#define UINT16_MAX __MLIBC_UINT16_MAX +#define UINT32_MAX __MLIBC_UINT32_MAX +#define UINT64_MAX __MLIBC_UINT64_MAX + +// Least-width (signed). +#define INT_LEAST8_MAX __MLIBC_INT8_MAX +#define INT_LEAST16_MAX __MLIBC_INT16_MAX +#define INT_LEAST32_MAX __MLIBC_INT32_MAX +#define INT_LEAST64_MAX __MLIBC_INT64_MAX + +#define INT_LEAST8_MIN __MLIBC_INT8_MIN +#define INT_LEAST16_MIN __MLIBC_INT16_MIN +#define INT_LEAST32_MIN __MLIBC_INT32_MIN +#define INT_LEAST64_MIN __MLIBC_INT64_MIN + +// Least-width (unsigned). +#define UINT_LEAST8_MAX __MLIBC_UINT8_MAX +#define UINT_LEAST16_MAX __MLIBC_UINT16_MAX +#define UINT_LEAST32_MAX __MLIBC_UINT32_MAX +#define UINT_LEAST64_MAX __MLIBC_UINT64_MAX + +// Fast-width (signed). +#define INT_FAST8_MAX __MLIBC_INT_FAST8_MAX +#define INT_FAST16_MAX __MLIBC_INT_FAST16_MAX +#define INT_FAST32_MAX __MLIBC_INT_FAST32_MAX +#define INT_FAST64_MAX __MLIBC_INT_FAST64_MAX + +#define INT_FAST8_MIN __MLIBC_INT_FAST8_MIN +#define INT_FAST16_MIN __MLIBC_INT_FAST16_MIN +#define INT_FAST32_MIN __MLIBC_INT_FAST32_MIN +#define INT_FAST64_MIN __MLIBC_INT_FAST64_MIN + +// Fast-width (unsigned). +#define UINT_FAST8_MAX __MLIBC_UINT_FAST8_MAX +#define UINT_FAST16_MAX __MLIBC_UINT_FAST16_MAX +#define UINT_FAST32_MAX __MLIBC_UINT_FAST32_MAX +#define UINT_FAST64_MAX __MLIBC_UINT_FAST64_MAX + +// Miscellaneous (signed). +#define INTMAX_MAX __MLIBC_INTMAX_MAX +#define INTPTR_MAX __MLIBC_INTPTR_MAX + +#define INTMAX_MIN __MLIBC_INTMAX_MIN +#define INTPTR_MIN __MLIBC_INTPTR_MIN + +// Miscellaneous (unsigned). +#define UINTMAX_MAX __MLIBC_UINTMAX_MAX +#define UINTPTR_MAX __MLIBC_UINTPTR_MAX + +// Other limits (signed). +#define PTRDIFF_MAX __MLIBC_PTRDIFF_MAX +#define PTRDIFF_MIN __MLIBC_PTRDIFF_MIN +#define SIG_ATOMIC_MAX __MLIBC_SIG_ATOMIC_MAX +#define SIG_ATOMIC_MIN __MLIBC_SIG_ATOMIC_MIN +#define WINT_MAX __MLIBC_WINT_MAX +#define WINT_MIN __MLIBC_WINT_MIN + +// Other limits (unsigned). +#define SIZE_MAX __MLIBC_SIZE_MAX + +#endif // _MLIBC_STDINT_H diff --git a/lib/mlibc/options/internal/riscv64-include/mlibc/arch-defs.hpp b/lib/mlibc/options/internal/riscv64-include/mlibc/arch-defs.hpp new file mode 100644 index 0000000..0a4789f --- /dev/null +++ b/lib/mlibc/options/internal/riscv64-include/mlibc/arch-defs.hpp @@ -0,0 +1,12 @@ +#ifndef MLIBC_ARCH_DEFS_HPP +#define MLIBC_ARCH_DEFS_HPP + +#include + +namespace mlibc { + +inline constexpr size_t page_size = 0x1000; + +} // namespace mlibc + +#endif // MLIBC_ARCH_DEFS_HPP diff --git a/lib/mlibc/options/internal/riscv64-include/mlibc/thread.hpp b/lib/mlibc/options/internal/riscv64-include/mlibc/thread.hpp new file mode 100644 index 0000000..7428b75 --- /dev/null +++ b/lib/mlibc/options/internal/riscv64-include/mlibc/thread.hpp @@ -0,0 +1,23 @@ +#pragma once + +#include +#include +#include + +namespace mlibc { + +inline Tcb *get_current_tcb() { + // On RISC-V, the TCB is below the thread pointer. + uintptr_t tp = (uintptr_t)__builtin_thread_pointer(); + auto tcb = reinterpret_cast(tp - sizeof(Tcb)); + __ensure(tcb == tcb->selfPointer); + return tcb; +} + +inline uintptr_t get_sp() { + uintptr_t sp; + asm ("mv %0, sp" : "=r"(sp)); + return sp; +} + +} // namespace mlibc diff --git a/lib/mlibc/options/internal/riscv64/fenv.S b/lib/mlibc/options/internal/riscv64/fenv.S new file mode 100644 index 0000000..c62ea36 --- /dev/null +++ b/lib/mlibc/options/internal/riscv64/fenv.S @@ -0,0 +1,57 @@ + +#ifdef __riscv_flen + +.global feclearexcept +.type feclearexcept, %function +feclearexcept: + csrc fflags, a0 + li a0, 0 + ret + +.global feraiseexcept +.type feraiseexcept, %function +feraiseexcept: + csrs fflags, a0 + li a0, 0 + ret + +.global fetestexcept +.type fetestexcept, %function +fetestexcept: + frflags t0 + and a0, t0, a0 + ret + +.global fegetround +.type fegetround, %function +fegetround: + frrm a0 + ret + +.global __fesetround +.type __fesetround, %function +__fesetround: + fsrm t0, a0 + li a0, 0 + ret + +.global fegetenv +.type fegetenv, %function +fegetenv: + frcsr t0 + sw t0, 0(a0) + li a0, 0 + ret + +.global fesetenv +.type fesetenv, %function +fesetenv: + li t2, -1 + li t1, 0 + beq a0, t2, 1f + lw t1, 0(a0) +1: fscsr t1 + li a0, 0 + ret + +#endif \ No newline at end of file diff --git a/lib/mlibc/options/internal/riscv64/mlibc_crtbegin.S b/lib/mlibc/options/internal/riscv64/mlibc_crtbegin.S new file mode 100644 index 0000000..b99748b --- /dev/null +++ b/lib/mlibc/options/internal/riscv64/mlibc_crtbegin.S @@ -0,0 +1,29 @@ + +.section .data +.hidden __dso_handle +.global __dso_handle +__dso_handle: + .quad __dso_handle + +.section .init +.hidden _init +.global _init +_init: + +.section .fini +.hidden _fini +.global _fini +_fini: + +.section .ctors +.hidden __CTOR_LIST__ +.global __CTOR_LIST__ +__CTOR_LIST__: + +.section .dtors +.hidden __DTOR_LIST__ +.global __DTOR_LIST__ +__DTOR_LIST__: + +.section .note.GNU-stack,"",%progbits + diff --git a/lib/mlibc/options/internal/riscv64/mlibc_crtend.S b/lib/mlibc/options/internal/riscv64/mlibc_crtend.S new file mode 100644 index 0000000..bd0cebc --- /dev/null +++ b/lib/mlibc/options/internal/riscv64/mlibc_crtend.S @@ -0,0 +1,21 @@ +.hidden __mlibc_do_ctors +.hidden __mlibc_do_dtors + +.section .init + tail __mlibc_do_ctors + +.section .fini + tail __mlibc_do_dtors + +.section .ctors +.hidden __CTOR_END__ +.global __CTOR_END__ +__CTOR_END__: + +.section .dtors +.hidden __DTOR_END__ +.global __DTOR_END__ +__DTOR_END__: + +.section .note.GNU-stack,"",%progbits + diff --git a/lib/mlibc/options/internal/riscv64/setjmp.S b/lib/mlibc/options/internal/riscv64/setjmp.S new file mode 100644 index 0000000..51568f7 --- /dev/null +++ b/lib/mlibc/options/internal/riscv64/setjmp.S @@ -0,0 +1,71 @@ +.global setjmp +.type setjmp, "function" +setjmp: + sd ra, 0(a0) + sd s0, 8(a0) + sd s1, 16(a0) + sd s2, 24(a0) + sd s3, 32(a0) + sd s4, 40(a0) + sd s5, 48(a0) + sd s6, 56(a0) + sd s7, 64(a0) + sd s8, 72(a0) + sd s9, 80(a0) + sd s10, 88(a0) + sd s11, 96(a0) + sd sp, 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 + +.global sigsetjmp +.type sigsetjmp, "function" +sigsetjmp: + unimp // TODO + +.global longjmp +.type longjmp, "function" +longjmp: + ld ra,0(a0) + ld s0,8(a0) + ld s1,16(a0) + ld s2,24(a0) + ld s3,32(a0) + ld s4,40(a0) + ld s5,48(a0) + ld s6,56(a0) + ld s7,64(a0) + ld s8,72(a0) + ld s9,80(a0) + ld s10,88(a0) + ld s11,96(a0) + ld sp,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 +.section .note.GNU-stack,"",%progbits + diff --git a/lib/mlibc/options/internal/x86-include/mlibc/arch-defs.hpp b/lib/mlibc/options/internal/x86-include/mlibc/arch-defs.hpp new file mode 100755 index 0000000..aa8fe38 --- /dev/null +++ b/lib/mlibc/options/internal/x86-include/mlibc/arch-defs.hpp @@ -0,0 +1,13 @@ +#ifndef MLIBC_ARCH_DEFS_HPP +#define MLIBC_ARCH_DEFS_HPP + +#include + +namespace mlibc { + +inline constexpr size_t page_size = 0x1000; + +} // namespace mlibc + +#endif // MLIBC_ARCH_DEFS_HPP + diff --git a/lib/mlibc/options/internal/x86-include/mlibc/thread.hpp b/lib/mlibc/options/internal/x86-include/mlibc/thread.hpp new file mode 100755 index 0000000..3475fb4 --- /dev/null +++ b/lib/mlibc/options/internal/x86-include/mlibc/thread.hpp @@ -0,0 +1,21 @@ +#pragma once + +#include +#include + +namespace mlibc { + +inline Tcb *get_current_tcb() { + uintptr_t ptr; + asm ("movl %%gs:0, %0" : "=r"(ptr)); + return reinterpret_cast(ptr); +} + +inline uintptr_t get_sp() { + uintptr_t esp; + asm ("mov %%esp, %0" : "=r"(esp)); + return esp; +} + +} // namespace mlibc + diff --git a/lib/mlibc/options/internal/x86/fenv.S b/lib/mlibc/options/internal/x86/fenv.S new file mode 100644 index 0000000..a46b5fa --- /dev/null +++ b/lib/mlibc/options/internal/x86/fenv.S @@ -0,0 +1,168 @@ +# The functions below are taken from musl. + +.hidden __hwcap + +.global feclearexcept +.type feclearexcept,@function +feclearexcept: + mov 4(%esp),%ecx + and $0x3f,%ecx + fnstsw %ax + # consider sse fenv as well if the cpu has XMM capability + call 1f +1: addl $__hwcap-1b,(%esp) + pop %edx + testl $0x02000000,(%edx) + jz 2f + # maintain exceptions in the sse mxcsr, clear x87 exceptions + test %eax,%ecx + jz 1f + fnclex +1: push %edx + stmxcsr (%esp) + pop %edx + and $0x3f,%eax + or %eax,%edx + test %edx,%ecx + jz 1f + not %ecx + and %ecx,%edx + push %edx + ldmxcsr (%esp) + pop %edx +1: xor %eax,%eax + ret + # only do the expensive x87 fenv load/store when needed +2: test %eax,%ecx + jz 1b + not %ecx + and %ecx,%eax + test $0x3f,%eax + jz 1f + fnclex + jmp 1b +1: sub $32,%esp + fnstenv (%esp) + mov %al,4(%esp) + fldenv (%esp) + add $32,%esp + xor %eax,%eax + ret + +.global feraiseexcept +.type feraiseexcept,@function +feraiseexcept: + mov 4(%esp),%eax + and $0x3f,%eax + sub $32,%esp + fnstenv (%esp) + or %al,4(%esp) + fldenv (%esp) + add $32,%esp + xor %eax,%eax + ret + +.global __fesetround +.hidden __fesetround +.type __fesetround,@function +__fesetround: + mov 4(%esp),%ecx + push %eax + xor %eax,%eax + fnstcw (%esp) + andb $0xf3,1(%esp) + or %ch,1(%esp) + fldcw (%esp) + # consider sse fenv as well if the cpu has XMM capability + call 1f +1: addl $__hwcap-1b,(%esp) + pop %edx + testl $0x02000000,(%edx) + jz 1f + stmxcsr (%esp) + shl $3,%ch + andb $0x9f,1(%esp) + or %ch,1(%esp) + ldmxcsr (%esp) +1: pop %ecx + ret + +.global fegetround +.type fegetround,@function +fegetround: + push %eax + fnstcw (%esp) + pop %eax + and $0xc00,%eax + ret + +.global fegetenv +.type fegetenv,@function +fegetenv: + mov 4(%esp),%ecx + xor %eax,%eax + fnstenv (%ecx) + # consider sse fenv as well if the cpu has XMM capability + call 1f +1: addl $__hwcap-1b,(%esp) + pop %edx + testl $0x02000000,(%edx) + jz 1f + push %eax + stmxcsr (%esp) + pop %edx + and $0x3f,%edx + or %edx,4(%ecx) +1: ret + +.global fesetenv +.type fesetenv,@function +fesetenv: + mov 4(%esp),%ecx + xor %eax,%eax + inc %ecx + jz 1f + fldenv -1(%ecx) + movl -1(%ecx),%ecx + jmp 2f +1: push %eax + push %eax + push %eax + push %eax + pushl $0xffff + push %eax + pushl $0x37f + fldenv (%esp) + add $28,%esp + # consider sse fenv as well if the cpu has XMM capability +2: call 1f +1: addl $__hwcap-1b,(%esp) + pop %edx + testl $0x02000000,(%edx) + jz 1f + # mxcsr := same rounding mode, cleared exceptions, default mask + and $0xc00,%ecx + shl $3,%ecx + or $0x1f80,%ecx + mov %ecx,4(%esp) + ldmxcsr 4(%esp) +1: ret + +.global fetestexcept +.type fetestexcept,@function +fetestexcept: + mov 4(%esp),%ecx + and $0x3f,%ecx + fnstsw %ax + # consider sse fenv as well if the cpu has XMM capability + call 1f +1: addl $__hwcap-1b,(%esp) + pop %edx + testl $0x02000000,(%edx) + jz 1f + stmxcsr 4(%esp) + or 4(%esp),%eax +1: and %ecx,%eax + ret + +.section .note.GNU-stack,"",%progbits diff --git a/lib/mlibc/options/internal/x86/mlibc_crtbegin.S b/lib/mlibc/options/internal/x86/mlibc_crtbegin.S new file mode 100644 index 0000000..d317451 --- /dev/null +++ b/lib/mlibc/options/internal/x86/mlibc_crtbegin.S @@ -0,0 +1,29 @@ + +.section .data +.hidden __dso_handle +.global __dso_handle +__dso_handle: + .long __dso_handle + +.section .init +.hidden _init +.global _init +_init: + +.section .fini +.hidden _fini +.global _fini +_fini: + +.section .ctors +.hidden __CTOR_LIST__ +.global __CTOR_LIST__ +__CTOR_LIST__: + +.section .dtors +.hidden __DTOR_LIST__ +.global __DTOR_LIST__ +__DTOR_LIST__: + +.section .note.GNU-stack,"",%progbits + diff --git a/lib/mlibc/options/internal/x86/mlibc_crtend.S b/lib/mlibc/options/internal/x86/mlibc_crtend.S new file mode 100644 index 0000000..e9d9136 --- /dev/null +++ b/lib/mlibc/options/internal/x86/mlibc_crtend.S @@ -0,0 +1,24 @@ + +.hidden __mlibc_do_ctors +.hidden __mlibc_do_dtors + +.section .init + call __mlibc_do_ctors + ret + +.section .fini + call __mlibc_do_dtors + ret + +.section .ctors +.hidden __CTOR_END__ +.global __CTOR_END__ +__CTOR_END__: + +.section .dtors +.hidden __DTOR_END__ +.global __DTOR_END__ +__DTOR_END__: + +.section .note.GNU-stack,"",%progbits + diff --git a/lib/mlibc/options/internal/x86/setjmp.S b/lib/mlibc/options/internal/x86/setjmp.S new file mode 100644 index 0000000..fa6644c --- /dev/null +++ b/lib/mlibc/options/internal/x86/setjmp.S @@ -0,0 +1,53 @@ + +.type __setjmp, "function" +__setjmp: + mov 4(%esp), %eax # Save argument (buffer) in edi + mov %ebx, 0x00(%eax) + mov %ebp, 0x04(%eax) + mov %esi, 0x08(%eax) + mov %edi, 0x0c(%eax) + + lea 4(%esp), %ecx # esp before return eip is pushed + mov %ecx, 0x10(%eax) + mov (%esp), %ecx # Return eip + mov %ecx, 0x14(%eax) + + test %edx, %edx + jnz 1f + xor %eax, %eax + ret + +1: + jmp __sigsetjmp@PLT + +.global setjmp +.type setjmp, "function" +setjmp: + xor %edx, %edx + jmp __setjmp + +.global sigsetjmp +.type sigsetjmp, "function" +sigsetjmp: + mov $1, %edx + jmp __setjmp + +.global longjmp +.type longjmp, "function" +longjmp: + mov 4(%esp), %ecx + mov 0x00(%ecx), %ebx + mov 0x04(%ecx), %ebp + mov 0x08(%ecx), %esi + mov 0x0c(%ecx), %edi + + mov 8(%esp), %eax + test %eax, %eax + jnz 1f + inc %eax +1: + mov 0x10(%ecx), %esp + jmp *0x14(%ecx) + +.section .note.GNU-stack,"",%progbits + diff --git a/lib/mlibc/options/internal/x86_64-include/mlibc/arch-defs.hpp b/lib/mlibc/options/internal/x86_64-include/mlibc/arch-defs.hpp new file mode 100644 index 0000000..0a4789f --- /dev/null +++ b/lib/mlibc/options/internal/x86_64-include/mlibc/arch-defs.hpp @@ -0,0 +1,12 @@ +#ifndef MLIBC_ARCH_DEFS_HPP +#define MLIBC_ARCH_DEFS_HPP + +#include + +namespace mlibc { + +inline constexpr size_t page_size = 0x1000; + +} // namespace mlibc + +#endif // MLIBC_ARCH_DEFS_HPP diff --git a/lib/mlibc/options/internal/x86_64-include/mlibc/thread.hpp b/lib/mlibc/options/internal/x86_64-include/mlibc/thread.hpp new file mode 100644 index 0000000..ed02b67 --- /dev/null +++ b/lib/mlibc/options/internal/x86_64-include/mlibc/thread.hpp @@ -0,0 +1,20 @@ +#pragma once + +#include +#include + +namespace mlibc { + +inline Tcb *get_current_tcb() { + uintptr_t ptr; + asm ("movq %%fs:0, %0" : "=r"(ptr)); + return reinterpret_cast(ptr); +} + +inline uintptr_t get_sp() { + uintptr_t rsp; + asm ("mov %%rsp, %0" : "=r"(rsp)); + return rsp; +} + +} // namespace mlibc diff --git a/lib/mlibc/options/internal/x86_64/fenv.S b/lib/mlibc/options/internal/x86_64/fenv.S new file mode 100644 index 0000000..3748988 --- /dev/null +++ b/lib/mlibc/options/internal/x86_64/fenv.S @@ -0,0 +1,102 @@ +# The functions below are taken from musl. +.global feclearexcept +.type feclearexcept,@function +feclearexcept: + # maintain exceptions in the sse mxcsr, clear x87 exceptions + mov %edi,%ecx + and $0x3f,%ecx + fnstsw %ax + test %eax,%ecx + jz 1f + fnclex +1: stmxcsr -8(%rsp) + and $0x3f,%eax + or %eax,-8(%rsp) + test %ecx,-8(%rsp) + jz 1f + not %ecx + and %ecx,-8(%rsp) + ldmxcsr -8(%rsp) +1: xor %eax,%eax + ret + +.global feraiseexcept +.type feraiseexcept,@function +feraiseexcept: + and $0x3f,%edi + stmxcsr -8(%rsp) + or %edi,-8(%rsp) + ldmxcsr -8(%rsp) + xor %eax,%eax + ret + +.global __fesetround +.hidden __fesetround +.type __fesetround,@function +__fesetround: + push %rax + xor %eax,%eax + mov %edi,%ecx + fnstcw (%rsp) + andb $0xf3,1(%rsp) + or %ch,1(%rsp) + fldcw (%rsp) + stmxcsr (%rsp) + shl $3,%ch + andb $0x9f,1(%rsp) + or %ch,1(%rsp) + ldmxcsr (%rsp) + pop %rcx + ret + +.global fegetround +.type fegetround,@function +fegetround: + push %rax + stmxcsr (%rsp) + pop %rax + shr $3,%eax + and $0xc00,%eax + ret + +.global fegetenv +.type fegetenv,@function +fegetenv: + xor %eax,%eax + fnstenv (%rdi) + stmxcsr 28(%rdi) + ret + +.global fesetenv +.type fesetenv,@function +fesetenv: + xor %eax,%eax + inc %rdi + jz 1f + fldenv -1(%rdi) + ldmxcsr 27(%rdi) + ret +1: push %rax + push %rax + pushq $0xffff + pushq $0x37f + fldenv (%rsp) + pushq $0x1f80 + ldmxcsr (%rsp) + add $40,%rsp + ret + +.global fetestexcept +.type fetestexcept,@function +fetestexcept: + and $0x3f,%edi + push %rax + stmxcsr (%rsp) + pop %rsi + fnstsw %ax + or %esi,%eax + and %edi,%eax + ret + +.section .note.GNU-stack,"",%progbits + diff --git a/lib/mlibc/options/internal/x86_64/mlibc_crtbegin.S b/lib/mlibc/options/internal/x86_64/mlibc_crtbegin.S new file mode 100644 index 0000000..b99748b --- /dev/null +++ b/lib/mlibc/options/internal/x86_64/mlibc_crtbegin.S @@ -0,0 +1,29 @@ + +.section .data +.hidden __dso_handle +.global __dso_handle +__dso_handle: + .quad __dso_handle + +.section .init +.hidden _init +.global _init +_init: + +.section .fini +.hidden _fini +.global _fini +_fini: + +.section .ctors +.hidden __CTOR_LIST__ +.global __CTOR_LIST__ +__CTOR_LIST__: + +.section .dtors +.hidden __DTOR_LIST__ +.global __DTOR_LIST__ +__DTOR_LIST__: + +.section .note.GNU-stack,"",%progbits + diff --git a/lib/mlibc/options/internal/x86_64/mlibc_crtend.S b/lib/mlibc/options/internal/x86_64/mlibc_crtend.S new file mode 100644 index 0000000..e9d9136 --- /dev/null +++ b/lib/mlibc/options/internal/x86_64/mlibc_crtend.S @@ -0,0 +1,24 @@ + +.hidden __mlibc_do_ctors +.hidden __mlibc_do_dtors + +.section .init + call __mlibc_do_ctors + ret + +.section .fini + call __mlibc_do_dtors + ret + +.section .ctors +.hidden __CTOR_END__ +.global __CTOR_END__ +__CTOR_END__: + +.section .dtors +.hidden __DTOR_END__ +.global __DTOR_END__ +__DTOR_END__: + +.section .note.GNU-stack,"",%progbits + diff --git a/lib/mlibc/options/internal/x86_64/setjmp.S b/lib/mlibc/options/internal/x86_64/setjmp.S new file mode 100644 index 0000000..aa8a134 --- /dev/null +++ b/lib/mlibc/options/internal/x86_64/setjmp.S @@ -0,0 +1,54 @@ + +.type __setjmp, "function" +__setjmp: + mov %rbx, 0x00(%rdi) + mov %rbp, 0x08(%rdi) + mov %r12, 0x10(%rdi) + mov %r13, 0x18(%rdi) + mov %r14, 0x20(%rdi) + mov %r15, 0x28(%rdi) + + lea 8(%rsp), %rax # rsp before return rip is pushed + mov %rax, 0x30(%rdi) + mov (%rsp), %rax # return rip + mov %rax, 0x38(%rdi) + + test %rdx, %rdx + jnz 1f + xor %rax, %rax + ret + +1: + jmp __sigsetjmp + +.global setjmp +.type setjmp, "function" +setjmp: + xor %rdx, %rdx + jmp __setjmp + +.global sigsetjmp +.type sigsetjmp, "function" +sigsetjmp: + mov $1, %rdx + jmp __setjmp + +.global longjmp +.type longjmp, "function" +longjmp: + mov 0x00(%rdi), %rbx + mov 0x08(%rdi), %rbp + mov 0x10(%rdi), %r12 + mov 0x18(%rdi), %r13 + mov 0x20(%rdi), %r14 + mov 0x28(%rdi), %r15 + + mov %rsi, %rax + test %rax, %rax + jnz 1f + inc %rax +1: + mov 0x30(%rdi), %rsp + jmp *0x38(%rdi) +.section .note.GNU-stack,"",%progbits + diff --git a/lib/mlibc/options/intl/generic/libintl-stubs.cpp b/lib/mlibc/options/intl/generic/libintl-stubs.cpp new file mode 100644 index 0000000..8d4b28f --- /dev/null +++ b/lib/mlibc/options/intl/generic/libintl-stubs.cpp @@ -0,0 +1,73 @@ +#include +#include + +char *gettext(const char *msgid) { + (void)msgid; + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +char *dgettext(const char *domainname, const char *msgid) { + (void)domainname; + (void)msgid; + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +char *dcgettext(const char *domainname, const char *msgid, + int category) { + (void)domainname; + (void)msgid; + (void)category; + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +char *ngettext(const char *msgid, const char *msgid_plural, unsigned long int n) { + (void)msgid; + (void)msgid_plural; + (void)n; + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +char *dngettext(const char *domainname, const char *msgid, + const char *msgid_plural, unsigned long int n) { + (void)domainname; + (void)msgid; + (void)msgid_plural; + (void)n; + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +char *dcngettext(const char *domainname, const char *msgid, + const char *msgid_plural, unsigned long int n, int category) { + (void)domainname; + (void)msgid; + (void)msgid_plural; + (void)n; + (void)category; + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +char *textdomain(const char *domainname) { + (void)domainname; + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +char *bindtextdomain(const char *domainname, const char *dirname) { + (void)domainname; + (void)dirname; + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +char *bind_textdomain_codeset(const char *domainname, const char *codeset) { + (void)domainname; + (void)codeset; + __ensure(!"Not implemented"); + __builtin_unreachable(); +} diff --git a/lib/mlibc/options/intl/include/libintl.h b/lib/mlibc/options/intl/include/libintl.h new file mode 100644 index 0000000..a897dac --- /dev/null +++ b/lib/mlibc/options/intl/include/libintl.h @@ -0,0 +1,33 @@ + +#ifndef _LIBINTL_H +#define _LIBINTL_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +char *gettext(const char *msgid); +char *dgettext(const char *domainname, const char *msgid); +char *dcgettext(const char *domainname, const char *msgid, + int category); + +char *ngettext(const char *msgid, const char *msgid_plural, unsigned long int n); +char *dngettext(const char *domainname, const char *msgid, + const char *msgid_plural, unsigned long int n); +char *dcngettext(const char *domainname, const char *msgid, + const char *msgid_plural, unsigned long int n, int category); + +char *textdomain(const char *domainname); +char *bindtextdomain(const char *domainname, const char *dirname); +char *bind_textdomain_codeset(const char *domainname, const char *codeset); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif // _LIBINTL_H + diff --git a/lib/mlibc/options/intl/meson.build b/lib/mlibc/options/intl/meson.build new file mode 100644 index 0000000..94057f4 --- /dev/null +++ b/lib/mlibc/options/intl/meson.build @@ -0,0 +1,12 @@ +if disable_intl_option + subdir_done() +endif +libc_sources += files( + 'generic/libintl-stubs.cpp', +) + +if not no_headers + install_headers( + 'include/libintl.h', + ) +endif diff --git a/lib/mlibc/options/linux/generic/capabilities.cpp b/lib/mlibc/options/linux/generic/capabilities.cpp new file mode 100644 index 0000000..871822a --- /dev/null +++ b/lib/mlibc/options/linux/generic/capabilities.cpp @@ -0,0 +1,19 @@ +#include + +#ifdef __cplusplus +extern "C" { +#endif + +int capset(void *, void *) { + mlibc::infoLogger() << "mlibc: capset is a no-op!" << frg::endlog; + return 0; +} + +int capget(void *, void *) { + mlibc::infoLogger() << "mlibc: capget is a no-op!" << frg::endlog; + return 0; +} + +#ifdef __cplusplus +} +#endif diff --git a/lib/mlibc/options/linux/generic/cpuset.cpp b/lib/mlibc/options/linux/generic/cpuset.cpp new file mode 100644 index 0000000..d0292b7 --- /dev/null +++ b/lib/mlibc/options/linux/generic/cpuset.cpp @@ -0,0 +1,71 @@ +#include +#include +#include +#include + +cpu_set_t *__mlibc_cpu_alloc(int num_cpus) { + return reinterpret_cast(calloc(1, CPU_ALLOC_SIZE(num_cpus))); +} + +#define CPU_MASK_BITS (CHAR_BIT * sizeof(__cpu_mask)) + +size_t __mlibc_cpu_alloc_size(int num_cpus) { + /* calculate the (unaligned) remainder that doesn't neatly fit in one __cpu_mask; 0 or 1 */ + size_t remainder = ((num_cpus % CPU_MASK_BITS) + CPU_MASK_BITS - 1) / CPU_MASK_BITS; + return sizeof(__cpu_mask) * (num_cpus / CPU_MASK_BITS + remainder); +} + +void __mlibc_cpu_zero(const size_t setsize, cpu_set_t *set) { + memset(set, 0, CPU_ALLOC_SIZE(setsize)); +} + +void __mlibc_cpu_set(const int cpu, const size_t setsize, cpu_set_t *set) { + if(cpu >= static_cast(setsize * CHAR_BIT)) { + return; + } + + unsigned char *ptr = reinterpret_cast(set); + size_t off = cpu / CHAR_BIT; + size_t mask = 1 << (cpu % CHAR_BIT); + + ptr[off] |= mask; +} + +void __mlibc_cpu_clear(const int cpu, const size_t setsize, cpu_set_t *set) { + if(cpu >= static_cast(setsize * CHAR_BIT)) { + return; + } + + unsigned char *ptr = reinterpret_cast(set); + size_t off = cpu / CHAR_BIT; + size_t mask = 1 << (cpu % CHAR_BIT); + + ptr[off] &= ~mask; +} + + +int __mlibc_cpu_isset(const int cpu, const size_t setsize, const cpu_set_t *set) { + if(cpu >= static_cast(setsize * CHAR_BIT)) { + return false; + } + + const unsigned char *ptr = reinterpret_cast(set); + size_t off = cpu / CHAR_BIT; + size_t mask = 1 << (cpu % CHAR_BIT); + + return (ptr[off] & mask); +} + +int __mlibc_cpu_count(const size_t setsize, const cpu_set_t *set) { + size_t count = 0; + const unsigned char *ptr = reinterpret_cast(set); + + for(size_t i = 0; i < setsize; i++) { + for(size_t bit = 0; bit < CHAR_BIT; bit++) { + if((1 << bit) & ptr[i]) + count++; + } + } + + return count; +} diff --git a/lib/mlibc/options/linux/generic/ifaddrs.cpp b/lib/mlibc/options/linux/generic/ifaddrs.cpp new file mode 100644 index 0000000..67dfbc6 --- /dev/null +++ b/lib/mlibc/options/linux/generic/ifaddrs.cpp @@ -0,0 +1,15 @@ +#include +#include +#include +#include + +int getifaddrs(struct ifaddrs **) { + mlibc::infoLogger() << "mlibc: getifaddrs fails unconditionally!" << frg::endlog; + errno = ENOSYS; + return -1; +} + +void freeifaddrs(struct ifaddrs *) { + mlibc::infoLogger() << "mlibc: freeifaddrs is a stub!" << frg::endlog; + return; +} diff --git a/lib/mlibc/options/linux/generic/linux-unistd.cpp b/lib/mlibc/options/linux/generic/linux-unistd.cpp new file mode 100644 index 0000000..ec13f72 --- /dev/null +++ b/lib/mlibc/options/linux/generic/linux-unistd.cpp @@ -0,0 +1,33 @@ +#include +#include + +#include +#include +#include + +int dup3(int oldfd, int newfd, int flags) { + if(oldfd == newfd) { + errno = EINVAL; + return -1; + } + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_dup2, -1); + if(int e = mlibc::sys_dup2(oldfd, flags, newfd); e) { + errno = e; + return -1; + } + return newfd; +} + +int vhangup(void) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +int getdtablesize(void){ + return sysconf(_SC_OPEN_MAX); +} + +int syncfs(int) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} diff --git a/lib/mlibc/options/linux/generic/malloc.cpp b/lib/mlibc/options/linux/generic/malloc.cpp new file mode 100644 index 0000000..065de6c --- /dev/null +++ b/lib/mlibc/options/linux/generic/malloc.cpp @@ -0,0 +1,7 @@ +#include +#include + +void *memalign(size_t, size_t) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} diff --git a/lib/mlibc/options/linux/generic/mntent-stubs.cpp b/lib/mlibc/options/linux/generic/mntent-stubs.cpp new file mode 100644 index 0000000..35c0e92 --- /dev/null +++ b/lib/mlibc/options/linux/generic/mntent-stubs.cpp @@ -0,0 +1,98 @@ + +#include +#include +#include +#include +#include +#include + +namespace { + +char *internal_buf; +size_t internal_bufsize; + +} + +#define SENTINEL (char *)&internal_buf + +FILE *setmntent(const char *name, const char *mode) { + return fopen(name, mode); +} + +struct mntent *getmntent(FILE *f) { + static struct mntent mnt; + return getmntent_r(f, &mnt, SENTINEL, 0); +} + +int addmntent(FILE *f, const struct mntent *mnt) { + if(fseek(f, 0, SEEK_END)) { + return 1; + } + return fprintf(f, "%s\t%s\t%s\t%s\t%d\t%d\n", + mnt->mnt_fsname, mnt->mnt_dir, mnt->mnt_type, mnt->mnt_opts, + mnt->mnt_freq, mnt->mnt_passno) < 0; +} + +int endmntent(FILE *f) { + if(f) { + fclose(f); + } + return 1; +} + +char *hasmntopt(const struct mntent *mnt, const char *opt) { + return strstr(mnt->mnt_opts, opt); +} + +/* Adapted from musl */ +struct mntent *getmntent_r(FILE *f, struct mntent *mnt, char *linebuf, int buflen) { + int n[8]; + bool use_internal = (linebuf == SENTINEL); + int len; + size_t i; + + mnt->mnt_freq = 0; + mnt->mnt_passno = 0; + + do { + if(use_internal) { + getline(&internal_buf, &internal_bufsize, f); + linebuf = internal_buf; + } else { + fgets(linebuf, buflen, f); + } + if(feof(f) || ferror(f)) { + return 0; + } + if(!strchr(linebuf, '\n')) { + fscanf(f, "%*[^\n]%*[\n]"); + errno = ERANGE; + return 0; + } + + len = strlen(linebuf); + if(len > INT_MAX) { + continue; + } + + for(i = 0; i < sizeof n / sizeof *n; i++) { + n[i] = len; + } + + sscanf(linebuf, " %n%*s%n %n%*s%n %n%*s%n %n%*s%n %d %d", + n, n + 1, n + 2, n + 3, n + 4, n + 5, n + 6, n + 7, + &mnt->mnt_freq, &mnt->mnt_passno); + } while(linebuf[n[0]] == '#' || n[1] == len); + + linebuf[n[1]] = 0; + linebuf[n[3]] = 0; + linebuf[n[5]] = 0; + linebuf[n[7]] = 0; + + mnt->mnt_fsname = linebuf + n[0]; + mnt->mnt_dir = linebuf + n[2]; + mnt->mnt_type = linebuf + n[4]; + mnt->mnt_opts = linebuf + n[6]; + + return mnt; +} diff --git a/lib/mlibc/options/linux/generic/module.cpp b/lib/mlibc/options/linux/generic/module.cpp new file mode 100644 index 0000000..53b6dc8 --- /dev/null +++ b/lib/mlibc/options/linux/generic/module.cpp @@ -0,0 +1,24 @@ +#include +#include + +#include +#include +#include + +int init_module(void *module, unsigned long length, const char *args) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_init_module, -1); + if(int e = mlibc::sys_init_module(module, length, args); e) { + errno = e; + return -1; + } + return 0; +} + +int delete_module(const char *name, unsigned flags) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_delete_module, -1); + if(int e = mlibc::sys_delete_module(name, flags); e) { + errno = e; + return -1; + } + return 0; +} diff --git a/lib/mlibc/options/linux/generic/pty-stubs.cpp b/lib/mlibc/options/linux/generic/pty-stubs.cpp new file mode 100644 index 0000000..8d95027 --- /dev/null +++ b/lib/mlibc/options/linux/generic/pty-stubs.cpp @@ -0,0 +1,101 @@ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +int openpty(int *mfd, int *sfd, char *name, const struct termios *ios, const struct winsize *win) { + int ptmx_fd; + if(int e = mlibc::sys_open("/dev/ptmx", O_RDWR | O_NOCTTY, 0, &ptmx_fd); e) { + errno = e; + goto fail; + } + + char spath[32]; + if(!name) + name = spath; + if(ptsname_r(ptmx_fd, name, 32)) + goto fail; + + int pts_fd; + unlockpt(ptmx_fd); + if(int e = mlibc::sys_open(name, O_RDWR | O_NOCTTY, 0, &pts_fd); e) { + errno = e; + goto fail; + } + + if(ios) + tcsetattr(ptmx_fd, TCSAFLUSH, ios); + + if(win) + ioctl(ptmx_fd, TIOCSWINSZ, (void*)win); + + *mfd = ptmx_fd; + *sfd = pts_fd; + return 0; + +fail: + mlibc::sys_close(ptmx_fd); + return -1; +} + +int login_tty(int fd) { + if(setsid() == -1) + return -1; + if(ioctl(fd, TIOCSCTTY, 0)) + return -1; + + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_dup2, -1); + if(int e = mlibc::sys_dup2(fd, 0, STDIN_FILENO); e) { + errno = e; + return -1; + } + if(int e = mlibc::sys_dup2(fd, 0, STDOUT_FILENO); e) { + errno = e; + return -1; + } + if(int e = mlibc::sys_dup2(fd, 0, STDERR_FILENO); e) { + errno = e; + return -1; + } + + if(int e = mlibc::sys_close(fd); e) { + errno = e; + return -1; + } + return 0; +} + +int forkpty(int *mfd, char *name, const struct termios *ios, const struct winsize *win) { + int sfd; + if(openpty(mfd, &sfd, name, ios, win)) + return -1; + + pid_t child; + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_fork, -1); + if(int e = mlibc::sys_fork(&child); e) { + errno = e; + return -1; + } + + if(!child) { + if(login_tty(sfd)) + mlibc::panicLogger() << "mlibc: TTY login fail in forkpty() child" << frg::endlog; + }else{ + if(int e = mlibc::sys_close(sfd); e) { + errno = e; + return -1; + } + } + + return child; +} + diff --git a/lib/mlibc/options/linux/generic/sched.cpp b/lib/mlibc/options/linux/generic/sched.cpp new file mode 100644 index 0000000..760a9f5 --- /dev/null +++ b/lib/mlibc/options/linux/generic/sched.cpp @@ -0,0 +1,50 @@ +#include +#include +#include + +#include +#include + +int sched_getcpu(void) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_getcpu, -1); + int cpu; + if(int e = mlibc::sys_getcpu(&cpu); e) { + errno = e; + return -1; + } + return cpu; +} + +int setns(int, int) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +int sched_getscheduler(pid_t) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +int sched_getaffinity(pid_t pid, size_t cpusetsize, cpu_set_t *mask) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_getaffinity, -1); + if(int e = mlibc::sys_getaffinity(pid, cpusetsize, mask); e) { + errno = e; + return -1; + } + return 0; +} + +int unshare(int) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +int sched_setaffinity(pid_t, size_t, const cpu_set_t *) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +int clone(int (*)(void *), void *, int, void *, ...) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} diff --git a/lib/mlibc/options/linux/generic/sys-epoll.cpp b/lib/mlibc/options/linux/generic/sys-epoll.cpp new file mode 100644 index 0000000..799d1a9 --- /dev/null +++ b/lib/mlibc/options/linux/generic/sys-epoll.cpp @@ -0,0 +1,58 @@ + +#include +#include + +#include +#include +#include + +int epoll_create(int) { + int fd; + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_epoll_create, -1); + if(int e = mlibc::sys_epoll_create(0, &fd); e) { + errno = e; + return -1; + } + return fd; +} + +int epoll_pwait(int epfd, struct epoll_event *evnts, int n, int timeout, + const sigset_t *sigmask) { + int raised; + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_epoll_pwait, -1); + if(int e = mlibc::sys_epoll_pwait(epfd, evnts, n, timeout, sigmask, &raised)) { + errno = e; + return -1; + } + return raised; +} + +int epoll_create1(int flags) { + int fd; + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_epoll_create, -1); + if(int e = mlibc::sys_epoll_create(flags, &fd); e) { + errno = e; + return -1; + } + return fd; +} + +int epoll_ctl(int epfd, int mode, int fd, struct epoll_event *ev) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_epoll_ctl, -1); + if(int e = mlibc::sys_epoll_ctl(epfd, mode, fd, ev); e) { + errno = e; + return -1; + } + return 0; +} + +int epoll_wait(int epfd, struct epoll_event *evnts, int n, int timeout) { + int raised; + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_epoll_pwait, -1); + if(int e = mlibc::sys_epoll_pwait(epfd, evnts, n, timeout, NULL, &raised)) { + errno = e; + return -1; + } + return raised; +} + diff --git a/lib/mlibc/options/linux/generic/sys-eventfd.cpp b/lib/mlibc/options/linux/generic/sys-eventfd.cpp new file mode 100644 index 0000000..1d83d8c --- /dev/null +++ b/lib/mlibc/options/linux/generic/sys-eventfd.cpp @@ -0,0 +1,45 @@ +#include +#include + +#include +#include + +int eventfd(unsigned int initval, int flags) { + int fd = 0; + + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_eventfd_create, -1); + if (int e = mlibc::sys_eventfd_create(initval, flags, &fd); e) { + errno = e; + return -1; + } + + return fd; +} + +int eventfd_read(int fd, eventfd_t *value) { + ssize_t bytes_read; + if (int e = mlibc::sys_read(fd, value, 8, &bytes_read); e) { + errno = e; + return -1; + } + + if (bytes_read != 8) { + return -1; + } + + return 0; +} + +int eventfd_write(int fd, eventfd_t value) { + ssize_t bytes_written; + if (int e = mlibc::sys_write(fd, &value, 8, &bytes_written); e) { + errno = e; + return -1; + } + + if (bytes_written != 8) { + return -1; + } + + return 0; +} diff --git a/lib/mlibc/options/linux/generic/sys-fsuid.cpp b/lib/mlibc/options/linux/generic/sys-fsuid.cpp new file mode 100644 index 0000000..653456c --- /dev/null +++ b/lib/mlibc/options/linux/generic/sys-fsuid.cpp @@ -0,0 +1,12 @@ +#include +#include + +int setfsuid(uid_t) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +int setfsgid(gid_t) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} diff --git a/lib/mlibc/options/linux/generic/sys-inotify-stubs.cpp b/lib/mlibc/options/linux/generic/sys-inotify-stubs.cpp new file mode 100644 index 0000000..0bc25c9 --- /dev/null +++ b/lib/mlibc/options/linux/generic/sys-inotify-stubs.cpp @@ -0,0 +1,47 @@ + +#include +#include + +#include +#include +#include + +int inotify_init(void) { + int fd; + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_inotify_create, -1); + if(int e = mlibc::sys_inotify_create(0, &fd); e) { + errno = e; + return -1; + } + return fd; +} + +int inotify_init1(int flags) { + int fd; + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_inotify_create, -1); + if(int e = mlibc::sys_inotify_create(flags, &fd); e) { + errno = e; + return -1; + } + return fd; +} + +int inotify_add_watch(int ifd, const char *path, uint32_t mask) { + int wd; + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_inotify_add_watch, -1); + if(int e = mlibc::sys_inotify_add_watch(ifd, path, mask, &wd); e) { + errno = e; + return -1; + } + return wd; +} + +int inotify_rm_watch(int ifd, int wd) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_inotify_rm_watch, -1); + if(int e = mlibc::sys_inotify_rm_watch(ifd, wd); e) { + errno = e; + return -1; + } + return 0; +} + diff --git a/lib/mlibc/options/linux/generic/sys-klog.cpp b/lib/mlibc/options/linux/generic/sys-klog.cpp new file mode 100644 index 0000000..059e292 --- /dev/null +++ b/lib/mlibc/options/linux/generic/sys-klog.cpp @@ -0,0 +1,16 @@ +#include +#include + +#include + +#include + +int klogctl(int type, char *bufp, int len) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_klogctl, -1); + int out; + if (int e = mlibc::sys_klogctl(type, bufp, len, &out); e) { + errno = e; + return -1; + } + return out; +} diff --git a/lib/mlibc/options/linux/generic/sys-mount.cpp b/lib/mlibc/options/linux/generic/sys-mount.cpp new file mode 100644 index 0000000..4783183 --- /dev/null +++ b/lib/mlibc/options/linux/generic/sys-mount.cpp @@ -0,0 +1,29 @@ + +#include +#include + +#include +#include + +int mount(const char *source, const char *target, + const char *fstype, unsigned long flags, const void *data) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_mount, -1); + if(int e = mlibc::sys_mount(source, target, fstype, flags, data); e) { + errno = e; + return -1; + } + return 0; +} + +int umount(const char *target) { + return umount2(target, 0); +} + +int umount2(const char *target, int flags) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_umount2, -1); + if(int e = mlibc::sys_umount2(target, flags); e) { + errno = e; + return -1; + } + return 0; +} diff --git a/lib/mlibc/options/linux/generic/sys-prctl-stubs.cpp b/lib/mlibc/options/linux/generic/sys-prctl-stubs.cpp new file mode 100644 index 0000000..5280332 --- /dev/null +++ b/lib/mlibc/options/linux/generic/sys-prctl-stubs.cpp @@ -0,0 +1,25 @@ + +#include +#include +#include +#include + +#include + +#include "mlibc/linux-sysdeps.hpp" + +int prctl(int op, ...) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_prctl, -1); + + int val; + va_list ap; + va_start(ap, op); + if(int e = mlibc::sys_prctl(op, ap, &val); e) { + errno = e; + return -1; + } + va_end(ap); + + return val; +} + diff --git a/lib/mlibc/options/linux/generic/sys-ptrace-stubs.cpp b/lib/mlibc/options/linux/generic/sys-ptrace-stubs.cpp new file mode 100644 index 0000000..8c836c5 --- /dev/null +++ b/lib/mlibc/options/linux/generic/sys-ptrace-stubs.cpp @@ -0,0 +1,36 @@ + +#include +#include +#include + +#include +#include +#include + +long ptrace(int req, ...) { + va_list ap; + + va_start(ap, req); + auto pid = va_arg(ap, pid_t); + auto addr = va_arg(ap, void *); + auto data = va_arg(ap, void *); + va_end(ap); + + long ret; + if(req > 0 && req < 4) { + data = &ret; + } + + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_ptrace, -1); + long out; + if(int e = mlibc::sys_ptrace(req, pid, addr, data, &out); e) { + errno = e; + return -1; + } else if(req > 0 && req < 4) { + errno = 0; + return ret; + } + + return out; +} + diff --git a/lib/mlibc/options/linux/generic/sys-quota.cpp b/lib/mlibc/options/linux/generic/sys-quota.cpp new file mode 100644 index 0000000..27c0e6d --- /dev/null +++ b/lib/mlibc/options/linux/generic/sys-quota.cpp @@ -0,0 +1,7 @@ +#include +#include + +int quotactl(int, const char *, int, caddr_t) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} diff --git a/lib/mlibc/options/linux/generic/sys-random-stubs.cpp b/lib/mlibc/options/linux/generic/sys-random-stubs.cpp new file mode 100644 index 0000000..5e5057f --- /dev/null +++ b/lib/mlibc/options/linux/generic/sys-random-stubs.cpp @@ -0,0 +1,21 @@ + +#include +#include + +#include +#include + +#include + +ssize_t getrandom(void *buffer, size_t max_size, unsigned int flags) { + if(flags & ~(GRND_RANDOM | GRND_NONBLOCK)) { + errno = EINVAL; + return -1; + } + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_getentropy, -1); + if(int e = mlibc::sys_getentropy(buffer, max_size); e) { + errno = e; + return -1; + } + return max_size; +} diff --git a/lib/mlibc/options/linux/generic/sys-reboot.cpp b/lib/mlibc/options/linux/generic/sys-reboot.cpp new file mode 100644 index 0000000..c9b503f --- /dev/null +++ b/lib/mlibc/options/linux/generic/sys-reboot.cpp @@ -0,0 +1,13 @@ +#include +#include +#include +#include + +int reboot(int what) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_reboot, -1); + if (int e = mlibc::sys_reboot(what); e) { + errno = e; + return -1; + } + return 0; +} diff --git a/lib/mlibc/options/linux/generic/sys-sendfile-stubs.cpp b/lib/mlibc/options/linux/generic/sys-sendfile-stubs.cpp new file mode 100644 index 0000000..25cd0a0 --- /dev/null +++ b/lib/mlibc/options/linux/generic/sys-sendfile-stubs.cpp @@ -0,0 +1,9 @@ + +#include +#include + +ssize_t sendfile(int, int, off_t *, size_t) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + diff --git a/lib/mlibc/options/linux/generic/sys-signalfd.cpp b/lib/mlibc/options/linux/generic/sys-signalfd.cpp new file mode 100644 index 0000000..28cfea0 --- /dev/null +++ b/lib/mlibc/options/linux/generic/sys-signalfd.cpp @@ -0,0 +1,17 @@ + +#include +#include + +#include +#include + +int signalfd(int fd, const sigset_t *mask, int flags) { + __ensure(fd == -1); + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_signalfd_create, -1); + if(int e = mlibc::sys_signalfd_create(mask, flags, &fd); e) { + errno = e; + return -1; + } + return fd; +} + diff --git a/lib/mlibc/options/linux/generic/sys-statfs-stubs.cpp b/lib/mlibc/options/linux/generic/sys-statfs-stubs.cpp new file mode 100644 index 0000000..6152ef2 --- /dev/null +++ b/lib/mlibc/options/linux/generic/sys-statfs-stubs.cpp @@ -0,0 +1,26 @@ + +#include +#include +#include + +#include +#include + +int statfs(const char *path, struct statfs *buf) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_statfs, -1); + if(int e = mlibc::sys_statfs(path, buf); e) { + errno = e; + return -1; + } + return 0; +} + +int fstatfs(int fd, struct statfs *buf) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_fstatfs, -1); + if (int e = mlibc::sys_fstatfs(fd, buf); e) { + errno = e; + return -1; + } + return 0; +} + diff --git a/lib/mlibc/options/linux/generic/sys-swap.cpp b/lib/mlibc/options/linux/generic/sys-swap.cpp new file mode 100644 index 0000000..44ddf98 --- /dev/null +++ b/lib/mlibc/options/linux/generic/sys-swap.cpp @@ -0,0 +1,24 @@ +#include +#include + +#include +#include +#include + +int swapon(const char *path, int flags) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_swapon, -1); + if(int e = mlibc::sys_swapon(path, flags); e) { + errno = e; + return -1; + } + return 0; +} + +int swapoff(const char *path) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_swapoff, -1); + if(int e = mlibc::sys_swapoff(path); e) { + errno = e; + return -1; + } + return 0; +} diff --git a/lib/mlibc/options/linux/generic/sys-sysinfo.cpp b/lib/mlibc/options/linux/generic/sys-sysinfo.cpp new file mode 100644 index 0000000..950c38a --- /dev/null +++ b/lib/mlibc/options/linux/generic/sys-sysinfo.cpp @@ -0,0 +1,15 @@ +#include +#include + +#include +#include +#include + +int sysinfo(struct sysinfo *info) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_sysinfo, -1); + if(int e = mlibc::sys_sysinfo(info); e) { + errno = e; + return -1; + } + return 0; +} diff --git a/lib/mlibc/options/linux/generic/sys-timerfd.cpp b/lib/mlibc/options/linux/generic/sys-timerfd.cpp new file mode 100644 index 0000000..80bca1b --- /dev/null +++ b/lib/mlibc/options/linux/generic/sys-timerfd.cpp @@ -0,0 +1,33 @@ + +#include +#include + +#include +#include +#include + +int timerfd_create(int clockid, int flags) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_timerfd_create, -1); + int fd; + if(int e = mlibc::sys_timerfd_create(clockid, flags, &fd); e) { + errno = e; + return -1; + } + return fd; +} + +int timerfd_settime(int fd, int flags, const struct itimerspec *value, + struct itimerspec *oldvalue) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_timerfd_settime, -1); + if(int e = mlibc::sys_timerfd_settime(fd, flags, value, oldvalue); e) { + errno = e; + return -1; + } + return 0; +} + +int timerfd_gettime(int, struct itimerspec *) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + diff --git a/lib/mlibc/options/linux/generic/sys-xattr.cpp b/lib/mlibc/options/linux/generic/sys-xattr.cpp new file mode 100644 index 0000000..c8d598f --- /dev/null +++ b/lib/mlibc/options/linux/generic/sys-xattr.cpp @@ -0,0 +1,122 @@ +#include +#include + +#include +#include + +int setxattr(const char *path, const char *name, const void *val, size_t size, + int flags) { + auto sysdep = MLIBC_CHECK_OR_ENOSYS(mlibc::sys_setxattr, -1); + + if (int e = sysdep(path, name, val, size, flags); e) { + errno = e; + return -1; + } + return 0; +} + +int lsetxattr(const char *path, const char *name, const void *val, size_t size, + int flags) { + auto sysdep = MLIBC_CHECK_OR_ENOSYS(mlibc::sys_lsetxattr, -1); + + if (int e = sysdep(path, name, val, size, flags); e) { + errno = e; + return -1; + } + return 0; +} + +int fsetxattr(int fd, const char *name, const void *val, size_t size, + int flags) { + auto sysdep = MLIBC_CHECK_OR_ENOSYS(mlibc::sys_fsetxattr, -1); + + if (int e = sysdep(fd, name, val, size, flags); e) { + errno = e; + return -1; + } + return 0; +} + +ssize_t getxattr(const char *path, const char *name, void *val, size_t size) { + auto sysdep = MLIBC_CHECK_OR_ENOSYS(mlibc::sys_getxattr, -1); + + ssize_t nread; + if (int e = sysdep(path, name, val, size, &nread); e) { + errno = e; + return -1; + } + + return nread; +} + +ssize_t lgetxattr(const char *path, const char *name, void *val, size_t size) { + auto sysdep = MLIBC_CHECK_OR_ENOSYS(mlibc::sys_lgetxattr, -1); + + ssize_t nread; + if (int e = sysdep(path, name, val, size, &nread); e) { + errno = e; + return -1; + } + + return nread; +} + +ssize_t fgetxattr(int fd, const char *name, void *val, size_t size) { + auto sysdep = MLIBC_CHECK_OR_ENOSYS(mlibc::sys_fgetxattr, -1); + + ssize_t nread; + if (int e = sysdep(fd, name, val, size, &nread); e) { + errno = e; + return -1; + } + + return nread; +} + +int removexattr(const char *path, const char *name) { + auto sysdep = MLIBC_CHECK_OR_ENOSYS(mlibc::sys_removexattr, -1); + return sysdep(path, name); +} + +int lremovexattr(const char *path, const char *name) { + auto sysdep = MLIBC_CHECK_OR_ENOSYS(mlibc::sys_lremovexattr, -1); + return sysdep(path, name); +} + +int fremovexattr(int fd, const char *name) { + auto sysdep = MLIBC_CHECK_OR_ENOSYS(mlibc::sys_fremovexattr, -1); + return sysdep(fd, name); +} + +ssize_t listxattr(const char *path, char *list, size_t size) { + auto sysdep = MLIBC_CHECK_OR_ENOSYS(mlibc::sys_listxattr, -1); + + ssize_t nread; + if (int e = sysdep(path, list, size, &nread); e) { + errno = e; + return -1; + } + return nread; +} + +ssize_t llistxattr(const char *path, char *list, size_t size) { + auto sysdep = MLIBC_CHECK_OR_ENOSYS(mlibc::sys_llistxattr, -1); + + ssize_t nread; + if (int e = sysdep(path, list, size, &nread); e) { + errno = e; + return -1; + } + return nread; +} + +ssize_t flistxattr(int fd, char *list, size_t size) { + auto sysdep = MLIBC_CHECK_OR_ENOSYS(mlibc::sys_flistxattr, -1); + + ssize_t nread; + if (int e = sysdep(fd, list, size, &nread); e) { + errno = e; + return -1; + } + return nread; +} diff --git a/lib/mlibc/options/linux/generic/utmp-stubs.cpp b/lib/mlibc/options/linux/generic/utmp-stubs.cpp new file mode 100644 index 0000000..658dfd3 --- /dev/null +++ b/lib/mlibc/options/linux/generic/utmp-stubs.cpp @@ -0,0 +1,116 @@ +#include +#include +#include +#include +#include + +#include +#include + +/* + * The code in this file is largely based on glibc. + * This includes: + * - setutent + * - read_last_entry + * - getutent + * - getutent_r + * - endutent + */ +static int fd = -1; +static off_t offset; + +static struct utmp last_entry; + +void setutent(void) { + if(fd < 0) { + fd = open("/run/utmp", O_RDONLY | O_LARGEFILE | O_CLOEXEC); + if(fd == -1) { + return; + } + } + + lseek(fd, 0, SEEK_SET); + offset = 0; +} + +static ssize_t read_last_entry(void) { + struct utmp buf; + ssize_t bytes_read = pread(fd, &buf, sizeof(buf), offset); + + if(bytes_read < 0) { + return -1; + } else if(bytes_read != sizeof(buf)) { + // EOF + return 0; + } else { + last_entry = buf; + offset += sizeof(buf); + return 1; + } +} + +struct utmp *getutent(void) { + struct utmp *result; + static struct utmp *buf; + if(buf == NULL) { + buf = (struct utmp *)malloc(sizeof(struct utmp)); + if(buf == NULL) { + return NULL; + } + } + + if(getutent_r(buf, &result) < 0) { + return NULL; + } + return result; +} + +int getutent_r(struct utmp *buf, struct utmp **res) { + int saved_errno = errno; + + if(fd < 0) { + setutent(); + } + + ssize_t bytes_read = read_last_entry(); + + if(bytes_read <= 0) { + if(bytes_read == 0) { + errno = saved_errno; + *res = NULL; + return -1; + } + } + + memcpy(buf, &last_entry, sizeof(struct utmp)); + *res = buf; + + return 0; +} + +void endutent(void) { + if(fd >= 0) { + close(fd); + fd = -1; + } +} + +struct utmp *pututline(const struct utmp *) { + mlibc::infoLogger() << "\e[31mmlibc: pututline() is a stub!\e[39m" << frg::endlog; + return NULL; +} + +struct utmp *getutline(const struct utmp *) { + mlibc::infoLogger() << "\e[31mmlibc: getutline() is a stub!\e[39m" << frg::endlog; + return NULL; +} + +int utmpname(const char *) { + mlibc::infoLogger() << "\e[31mmlibc: utmpname() is a stub!\e[39m" << frg::endlog; + return -1; +} + +struct utmp *getutid(const struct utmp *) { + mlibc::infoLogger() << "\e[31mmlibc: getutid() is a stub!\e[39m" << frg::endlog; + return NULL; +} diff --git a/lib/mlibc/options/linux/generic/utmpx.cpp b/lib/mlibc/options/linux/generic/utmpx.cpp new file mode 100644 index 0000000..4742567 --- /dev/null +++ b/lib/mlibc/options/linux/generic/utmpx.cpp @@ -0,0 +1,45 @@ +#include +#include +#include +#include +#include + +void updwtmpx(const char *, const struct utmpx *) { + // Empty as musl does + mlibc::infoLogger() << "\e[31mmlibc: updwtmpx() is a stub\e[39m" << frg::endlog; +} + +void endutxent(void) { + // Empty as musl does + mlibc::infoLogger() << "\e[31mmlibc: endutxent() is a stub\e[39m" << frg::endlog; +} + +void setutxent(void) { + // Empty as musl does + mlibc::infoLogger() << "\e[31mmlibc: setutxent() is a stub\e[39m" << frg::endlog; +} + +struct utmpx *getutxent(void) { + // return NULL as musl does + mlibc::infoLogger() << "\e[31mmlibc: getutxent() is a stub\e[39m" << frg::endlog; + return NULL; +} + +struct utmpx *pututxline(const struct utmpx *) { + // return NULL as musl does + mlibc::infoLogger() << "\e[31mmlibc: pututxline() is a stub\e[39m" << frg::endlog; + return NULL; +} + +int utmpxname(const char *) { + // return -1 as musl does + mlibc::infoLogger() << "\e[31mmlibc: utmpxname() is a stub\e[39m" << frg::endlog; + errno = ENOSYS; + return -1; +} + +struct utmpx *getutxid(const struct utmpx *) { + // return NULL as musl does + mlibc::infoLogger() << "\e[31mmlibc: getutxid() is a stub\e[39m" << frg::endlog; + return NULL; +} diff --git a/lib/mlibc/options/linux/include/bits/linux/cpu_set.h b/lib/mlibc/options/linux/include/bits/linux/cpu_set.h new file mode 100644 index 0000000..f3c753e --- /dev/null +++ b/lib/mlibc/options/linux/include/bits/linux/cpu_set.h @@ -0,0 +1,49 @@ +#ifndef _LINUX_CPU_SET_H +#define _LINUX_CPU_SET_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include +#include + +#ifndef __MLIBC_ABI_ONLY + +cpu_set_t *__mlibc_cpu_alloc(int num_cpus); +size_t __mlibc_cpu_alloc_size(int num_cpus); + +void __mlibc_cpu_zero(const size_t setsize, cpu_set_t *set); +void __mlibc_cpu_set(const int cpu, const size_t setsize, cpu_set_t *set); +void __mlibc_cpu_clear(const int cpu, const size_t setsize, cpu_set_t *set); +int __mlibc_cpu_isset(const int cpu, const size_t setsize, const cpu_set_t *set); +int __mlibc_cpu_count(const size_t setsize, const cpu_set_t *set); + +#define CPU_ALLOC_SIZE(n) __mlibc_cpu_alloc_size((n)) +#define CPU_ALLOC(n) __mlibc_cpu_alloc((n)) +#define CPU_FREE(set) free((set)) + +#define CPU_ZERO_S(setsize, set) __mlibc_cpu_zero((setsize), (set)) +#define CPU_ZERO(set) CPU_ZERO_S(sizeof(cpu_set_t), set) + +#define CPU_SET_S(cpu, setsize, set) __mlibc_cpu_set((cpu), (setsize), (set)) +#define CPU_SET(cpu, set) CPU_SET_S(cpu, sizeof(cpu_set_t), set) + +#define CPU_CLR_S(cpu, setsize, set) __mlibc_cpu_clear((cpu), (setsize), (set)) +#define CPU_CLR(cpu, set) CPU_CLR_S(cpu, sizeof(cpu_set_t), set) + +#define CPU_ISSET_S(cpu, setsize, set) __mlibc_cpu_isset((cpu), (setsize), (set)) +#define CPU_ISSET(cpu, set) CPU_ISSET_S(cpu, sizeof(cpu_set_t), set) + +#define CPU_COUNT_S(setsize, set) __mlibc_cpu_count((setsize), (set)) +#define CPU_COUNT(set) CPU_COUNT_S(sizeof(cpu_set_t), set) + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _LINUX_CPU_SET_H */ diff --git a/lib/mlibc/options/linux/include/bits/linux/linux_sched.h b/lib/mlibc/options/linux/include/bits/linux/linux_sched.h new file mode 100644 index 0000000..6a1209a --- /dev/null +++ b/lib/mlibc/options/linux/include/bits/linux/linux_sched.h @@ -0,0 +1,59 @@ + +#ifndef _LINUX_SCHED_H +#define _LINUX_SCHED_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include + +#define CLONE_VM 0x00000100 +#define CLONE_FS 0x00000200 +#define CLONE_FILES 0x00000400 +#define CLONE_SIGHAND 0x00000800 +#define CLONE_PTRACE 0x00002000 +#define CLONE_VFORK 0x00004000 +#define CLONE_PARENT 0x00008000 +#define CLONE_THREAD 0x00010000 +#define CLONE_NEWNS 0x00020000 +#define CLONE_SYSVSEM 0x00040000 +#define CLONE_SETTLS 0x00080000 +#define CLONE_PARENT_SETTID 0x00100000 +#define CLONE_CHILD_CLEARTID 0x00200000 +#define CLONE_DETACHED 0x00400000 +#define CLONE_UNTRACED 0x00800000 +#define CLONE_CHILD_SETTID 0x01000000 +#define CLONE_NEWCGROUP 0x02000000 +#define CLONE_NEWUTS 0x04000000 +#define CLONE_NEWIPC 0x08000000 +#define CLONE_NEWUSER 0x10000000 +#define CLONE_NEWPID 0x20000000 +#define CLONE_NEWNET 0x40000000 +#define CLONE_IO 0x80000000 + +#ifndef __MLIBC_ABI_ONLY + +int sched_getscheduler(pid_t pid); +int sched_setaffinity(pid_t pid, size_t cpusetsize, const cpu_set_t *mask); +int sched_getaffinity(pid_t pid, size_t cpusetsize, cpu_set_t *mask); + +int unshare(int flags); +int clone(int (*)(void *), void *, int, void *, ...); + +/* Glibc extension */ +int sched_getcpu(void); + +#if defined(_GNU_SOURCE) +int setns(int fd, int nstype); +#endif /* _GNU_SOURCE */ + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _LINUX_SCHED_H */ diff --git a/lib/mlibc/options/linux/include/bits/linux/linux_unistd.h b/lib/mlibc/options/linux/include/bits/linux/linux_unistd.h new file mode 100644 index 0000000..77534ba --- /dev/null +++ b/lib/mlibc/options/linux/include/bits/linux/linux_unistd.h @@ -0,0 +1,21 @@ +#ifndef _LINUX_UNISTD_H +#define _LINUX_UNISTD_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +int dup3(int fd, int newfd, int flags); +int vhangup(void); +int getdtablesize(void); +int syncfs(int fd); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif // _LINUX_UNISTD_H diff --git a/lib/mlibc/options/linux/include/ifaddrs.h b/lib/mlibc/options/linux/include/ifaddrs.h new file mode 100644 index 0000000..2604e3e --- /dev/null +++ b/lib/mlibc/options/linux/include/ifaddrs.h @@ -0,0 +1,35 @@ + +#ifndef _IFADDRS_H +#define _IFADDRS_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +// Struct definitions taken from musl +struct ifaddrs { + struct ifaddrs *ifa_next; + char *ifa_name; + unsigned ifa_flags; + struct sockaddr *ifa_addr; + struct sockaddr *ifa_netmask; + struct sockaddr *ifa_broadaddr; + struct sockaddr *ifa_dstaddr; + void *ifa_data; +}; + +#ifndef __MLIBC_ABI_ONLY + +int getifaddrs(struct ifaddrs **); +void freeifaddrs(struct ifaddrs *); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif // _IFADDRS_H diff --git a/lib/mlibc/options/linux/include/lastlog.h b/lib/mlibc/options/linux/include/lastlog.h new file mode 100644 index 0000000..0930aaf --- /dev/null +++ b/lib/mlibc/options/linux/include/lastlog.h @@ -0,0 +1,2 @@ +// Maches glibc +#include \ No newline at end of file diff --git a/lib/mlibc/options/linux/include/linux/libc-compat.h b/lib/mlibc/options/linux/include/linux/libc-compat.h new file mode 100644 index 0000000..696f4af --- /dev/null +++ b/lib/mlibc/options/linux/include/linux/libc-compat.h @@ -0,0 +1,61 @@ +#ifndef _LINUX_LIBC_COMPAT_H +#define _LINUX_LIBC_COMPAT_H + +#if defined(_NET_IF_H) + +#define __UAPI_DEF_IF_IFCONF 0 +#define __UAPI_DEF_IF_IFMAP 0 +#define __UAPI_DEF_IF_IFNAMSIZ 0 +#define __UAPI_DEF_IF_IFREQ 0 +#define __UAPI_DEF_IF_NET_DEVICE_FLAGS 0 + +#else // _NET_IF_H + +#define __UAPI_DEF_IF_IFCONF 1 +#define __UAPI_DEF_IF_IFMAP 1 +#define __UAPI_DEF_IF_IFNAMSIZ 1 +#define __UAPI_DEF_IF_IFREQ 1 +#define __UAPI_DEF_IF_NET_DEVICE_FLAGS 1 +#define __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO 1 + +#endif //_NET_IF_H + +#if defined(_NETINET_IN_H) + +#define __UAPI_DEF_IN_ADDR 0 +#define __UAPI_DEF_IN_CLASS 0 +#define __UAPI_DEF_IN_IPPROTO 0 +#define __UAPI_DEF_IN_PKTINFO 0 +#define __UAPI_DEF_IP_MREQ 0 +#define __UAPI_DEF_SOCKADDR_IN 0 + +#define __UAPI_DEF_IN6_ADDR 0 +#define __UAPI_DEF_IN6_ADDR_ALT 1 +#define __UAPI_DEF_IN6_PKTINFO 0 +#define __UAPI_DEF_IP6_MTUINFO 0 +#define __UAPI_DEF_IPPROTO_V6 0 +#define __UAPI_DEF_IPV6_MREQ 0 +#define __UAPI_DEF_IPV6_OPTIONS 0 +#define __UAPI_DEF_SOCKADDR_IN6 0 + +#else + +#define __UAPI_DEF_IN_ADDR 1 +#define __UAPI_DEF_IN_CLASS 1 +#define __UAPI_DEF_IN_IPPROTO 1 +#define __UAPI_DEF_IN_PKTINFO 1 +#define __UAPI_DEF_IP_MREQ 1 +#define __UAPI_DEF_SOCKADDR_IN 1 + +#define __UAPI_DEF_IN6_ADDR 1 +#define __UAPI_DEF_IN6_ADDR_ALT 1 +#define __UAPI_DEF_IN6_PKTINFO 1 +#define __UAPI_DEF_IP6_MTUINFO 1 +#define __UAPI_DEF_IPPROTO_V6 1 +#define __UAPI_DEF_IPV6_MREQ 1 +#define __UAPI_DEF_IPV6_OPTIONS 1 +#define __UAPI_DEF_SOCKADDR_IN6 1 + +#endif /* _NETINET_IN_H */ + +#endif // _LINUX_LIBC_COMPAT_H diff --git a/lib/mlibc/options/linux/include/malloc.h b/lib/mlibc/options/linux/include/malloc.h new file mode 100644 index 0000000..b03f9b4 --- /dev/null +++ b/lib/mlibc/options/linux/include/malloc.h @@ -0,0 +1,32 @@ + +#ifndef _MALLOC_H +#define _MALLOC_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +#ifndef __MLIBC_ABI_ONLY + +// [7.22.3] Memory management functions +void *calloc(size_t count, size_t size); +void free(void *pointer); +void *malloc(size_t size); +void *realloc(void *pointer, size_t size); +void *memalign(size_t, size_t); + +#if __MLIBC_GLIBC_OPTION +#include +#endif + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif // _MALLOC_H + diff --git a/lib/mlibc/options/linux/include/memory.h b/lib/mlibc/options/linux/include/memory.h new file mode 100644 index 0000000..586822b --- /dev/null +++ b/lib/mlibc/options/linux/include/memory.h @@ -0,0 +1,9 @@ + +#ifndef _MEMORY_H +#define _MEMORY_H + +// This is a linux extension +#include + +#endif // _MEMORY_H + diff --git a/lib/mlibc/options/linux/include/mlibc/linux-sysdeps.hpp b/lib/mlibc/options/linux/include/mlibc/linux-sysdeps.hpp new file mode 100644 index 0000000..b18544a --- /dev/null +++ b/lib/mlibc/options/linux/include/mlibc/linux-sysdeps.hpp @@ -0,0 +1,82 @@ +#ifndef MLIBC_LINUX_SYSDEPS +#define MLIBC_LINUX_SYSDEPS + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace [[gnu::visibility("hidden")]] mlibc { + +int sys_open(const char *pathname, int flags, mode_t mode, int *fd); +int sys_close(int fd); +int sys_read(int fd, void *buf, size_t count, ssize_t *bytes_read); +int sys_write(int fd, const void *buf, size_t count, ssize_t *bytes_written); +int sys_ioctl(int fd, unsigned long request, void *arg, int *result); + +[[gnu::weak]] int sys_dup2(int fd, int flags, int newfd); +[[gnu::weak]] int sys_fork(pid_t *child); +[[gnu::weak]] int sys_inotify_create(int flags, int *fd); +[[gnu::weak]] int sys_inotify_add_watch(int ifd, const char *path, uint32_t mask, int *wd); +[[gnu::weak]] int sys_inotify_rm_watch(int ifd, int wd); +[[gnu::weak]] int sys_epoll_create(int flags, int *fd); +[[gnu::weak]] int sys_epoll_ctl(int epfd, int mode, int fd, struct epoll_event *ev); +[[gnu::weak]] int sys_epoll_pwait(int epfd, struct epoll_event *ev, int n, + int timeout, const sigset_t *sigmask, int *raised); +[[gnu::weak]] int sys_mount(const char *source, const char *target, + const char *fstype, unsigned long flags, const void *data); +[[gnu::weak]] int sys_umount2(const char *target, int flags); +[[gnu::weak]] int sys_eventfd_create(unsigned int initval, int flags, int *fd); +[[gnu::weak]] int sys_timerfd_create(int clockid, int flags, int *fd); +[[gnu::weak]] int sys_timerfd_settime(int fd, int flags, + const struct itimerspec *value, struct itimerspec *oldvalue); +[[gnu::weak]] int sys_signalfd_create(const sigset_t *, int flags, int *fd); +[[gnu::weak]] int sys_reboot(int cmd); +[[gnu::weak]] int sys_ptrace(long req, pid_t pid, void *addr, void *data, long *out); +[[gnu::weak]] int sys_prctl(int option, va_list va, int *out); +[[gnu::weak]] int sys_init_module(void *module, unsigned long length, const char *args); +[[gnu::weak]] int sys_delete_module(const char *name, unsigned flags); +[[gnu::weak]] int sys_klogctl(int type, char *bufp, int len, int *out); +[[gnu::weak]] int sys_getcpu(int *cpu); + +[[gnu::weak]] int sys_sysinfo(struct sysinfo *info); +[[gnu::weak]] int sys_swapon(const char *path, int flags); +[[gnu::weak]] int sys_swapoff(const char *path); + +[[gnu::weak]] int sys_setxattr(const char *path, const char *name, + const void *val, size_t size, int flags); +[[gnu::weak]] int sys_lsetxattr(const char *path, const char *name, + const void *val, size_t size, int flags); +[[gnu::weak]] int sys_fsetxattr(int fd, const char *name, const void *val, + size_t size, int flags); + +[[gnu::weak]] int sys_getxattr(const char *path, const char *name, + void *val, size_t size, ssize_t *nread); +[[gnu::weak]] int sys_lgetxattr(const char *path, const char *name, + void *val, size_t size, ssize_t *nread); +[[gnu::weak]] int sys_fgetxattr(int fd, const char *name, void *val, + size_t size, ssize_t *nread); + +[[gnu::weak]] int sys_listxattr(const char *path, char *list, size_t size, + ssize_t *nread); +[[gnu::weak]] int sys_llistxattr(const char *path, char *list, size_t size, + ssize_t *nread); +[[gnu::weak]] int sys_flistxattr(int fd, char *list, size_t size, + ssize_t *nread); + +[[gnu::weak]] int sys_removexattr(const char *path, const char *name); +[[gnu::weak]] int sys_lremovexattr(const char *path, const char *name); +[[gnu::weak]] int sys_fremovexattr(int fd, const char *name); + +[[gnu::weak]] int sys_statfs(const char *path, struct statfs *buf); +[[gnu::weak]] int sys_fstatfs(int fd, struct statfs *buf); + +} // namespace mlibc + +#endif // MLIBX_LINUX_SYSDEPS diff --git a/lib/mlibc/options/linux/include/mntent.h b/lib/mlibc/options/linux/include/mntent.h new file mode 100644 index 0000000..bafd289 --- /dev/null +++ b/lib/mlibc/options/linux/include/mntent.h @@ -0,0 +1,50 @@ +#ifndef _MNTENT_H +#define _MNTENT_H + +#include + +// TODO: Refer to _PATH_MOUNTED +#define MOUNTED "/etc/mtab" + +/* Generic mount options */ +#define MNTOPT_DEFAULTS "defaults" /* Use all default options. */ +#define MNTOPT_RO "ro" /* Read only. */ +#define MNTOPT_RW "rw" /* Read/write. */ +#define MNTOPT_SUID "suid" /* Set uid allowed. */ +#define MNTOPT_NOSUID "nosuid" /* No set uid allowed. */ +#define MNTOPT_NOAUTO "noauto" /* Do not auto mount. */ + +#ifdef __cplusplus +extern "C" { +#endif + +struct mntent { + char *mnt_fsname; + char *mnt_dir; + char *mnt_type; + char *mnt_opts; + int mnt_freq; + int mnt_passno; +}; + +#ifndef __MLIBC_ABI_ONLY + +FILE *setmntent(const char *, const char *); + +struct mntent *getmntent(FILE *); + +int addmntent(FILE *, const struct mntent *); + +int endmntent(FILE *); + +char *hasmntopt(const struct mntent *, const char *); + +struct mntent *getmntent_r(FILE *, struct mntent *, char *, int); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif // _MNTENT_H diff --git a/lib/mlibc/options/linux/include/module.h b/lib/mlibc/options/linux/include/module.h new file mode 100644 index 0000000..ef715a4 --- /dev/null +++ b/lib/mlibc/options/linux/include/module.h @@ -0,0 +1,25 @@ +#ifndef _MODULE_H +#define _MODULE_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +/* + * Musl adds these, even though they aren't specified, but doesn't export them. + * See https://github.com/bminor/musl/commit/2169265ec6c902cd460bf96a1a0b5103657a4954 + * for more information and the rationale behind it. + * For our infrastructure, we expose them, and make it call into the sysdeps. + */ +int init_module(void *module, unsigned long len, const char *args); +int delete_module(const char *name, unsigned flags); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif // _MODULE_H diff --git a/lib/mlibc/options/linux/include/netpacket/packet.h b/lib/mlibc/options/linux/include/netpacket/packet.h new file mode 100644 index 0000000..1fa0917 --- /dev/null +++ b/lib/mlibc/options/linux/include/netpacket/packet.h @@ -0,0 +1,40 @@ +#ifndef _NETPACKET_PACKET_H +#define _NETPACKET_PACKET_H + +#include + +/* Packet types */ +#define PACKET_HOST 0 +#define PACKET_BROADCAST 1 +#define PACKET_MULTICAST 2 +#define PACKET_OTHERHOST 3 +#define PACKET_OUTGOING 4 +#define PACKET_LOOPBACK 5 +#define PACKET_FASTROUTE 6 + +struct sockaddr_ll { + unsigned short int sll_family; + unsigned short int sll_protocol; + int sll_ifindex; + unsigned short int sll_hatype; + unsigned char sll_pkttype; + unsigned char sll_halen; + unsigned char sll_addr[8]; +}; + +struct packet_mreq { + int mr_ifindex; + unsigned short int mr_type; + unsigned short int mr_alen; + unsigned char mr_address[8]; +}; + +#define PACKET_ADD_MEMBERSHIP 1 +#define PACKET_DROP_MEMBERSHIP 2 + +#define PACKET_MR_MULTICAST 0 +#define PACKET_MR_PROMISC 1 +#define PACKET_MR_ALLMULTI 2 +#define PACKET_MR_UNICAST 3 + +#endif // _NETPACKET_PACKET_H diff --git a/lib/mlibc/options/linux/include/pty.h b/lib/mlibc/options/linux/include/pty.h new file mode 100644 index 0000000..562fbb8 --- /dev/null +++ b/lib/mlibc/options/linux/include/pty.h @@ -0,0 +1,23 @@ + +#ifndef _PTY_H +#define _PTY_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +int openpty(int *, int *, char *, const struct termios *, const struct winsize *); +int forkpty(int *, char *, const struct termios *, const struct winsize *); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif // _PTY_H + diff --git a/lib/mlibc/options/linux/include/scsi/scsi.h b/lib/mlibc/options/linux/include/scsi/scsi.h new file mode 100644 index 0000000..f7f92d8 --- /dev/null +++ b/lib/mlibc/options/linux/include/scsi/scsi.h @@ -0,0 +1,18 @@ + +#ifndef _LINUX_SCSI_SCSI_H +#define _LINUX_SCSI_SCSI_H + +#define RECOVERED_ERROR 0x01 +#define ILLEGAL_REQUEST 0x05 +#define UNIT_ATTENTION 0x06 +#define INQUIRY 0x12 +#define START_STOP 0x1b +#define ALLOW_MEDIUM_REMOVAL 0x1e + +#define SCSI_IOCTL_GET_IDLUN 0x5382 +#define SCSI_IOCTL_TAGGED_ENABLE 0x5383 +#define SCSI_IOCTL_TAGGED_DISABLE 0x5384 +#define SCSI_IOCTL_PROBE_HOST 0x5385 + +#endif // _LINUX_SCSI_SCSI_H + diff --git a/lib/mlibc/options/linux/include/scsi/scsi_ioctl.h b/lib/mlibc/options/linux/include/scsi/scsi_ioctl.h new file mode 100644 index 0000000..16c7cfa --- /dev/null +++ b/lib/mlibc/options/linux/include/scsi/scsi_ioctl.h @@ -0,0 +1,6 @@ + +#ifndef _LINUX_SCSI_SCSI_IOCTL_H +#define _LINUX_SCSI_SCSI_IOCTL_H + +#endif // _LINUX_SCSI_SCSI_IOCTL_H + diff --git a/lib/mlibc/options/linux/include/scsi/sg.h b/lib/mlibc/options/linux/include/scsi/sg.h new file mode 100644 index 0000000..a9dfc7a --- /dev/null +++ b/lib/mlibc/options/linux/include/scsi/sg.h @@ -0,0 +1,77 @@ + +#ifndef _LINUX_SCSI_SG_H +#define _LINUX_SCSI_SG_H + +#define SG_IO 0x2285 + +#define SG_GET_VERSION_NUM 0x2282 + +#define SG_FLAG_DIRECT_IO 1 +#define SG_FLAG_LUN_INHIBIT 2 + +#define SG_INFO_OK 0x0 +#define SG_INFO_OK_MASK 0x1 + +#define SG_DXFER_NONE (-1) +#define SG_DXFER_TO_DEV (-2) +#define SG_DXFER_FROM_DEV (-3) +#define SG_DXFER_TO_FROM_DEV (-4) + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct sg_io_hdr { + int interface_id; + int dxfer_direction; + unsigned char cmd_len; + unsigned char mx_sb_len; + unsigned short iovec_count; + unsigned int dxfer_len; + void *dxferp; + unsigned char *cmdp; + unsigned char *sbp; + unsigned int timeout; + unsigned int flags; + int pack_id; + void *usr_ptr; + unsigned char status; + unsigned char masked_status; + unsigned char msg_status; + unsigned char sb_len_wr; + unsigned short host_status; + unsigned short driver_status; + int resid; + unsigned int duration; + unsigned int info; +} sg_io_hdr_t; + +struct sg_scsi_id { + int host_no; + int channel; + int scsi_id; + int lun; + int scsi_type; + short int h_cmd_per_lun; + short int d_queue_depth; + int unused[2]; +}; + +typedef struct sg_req_info { + char req_state; + char orphan; + char sg_io_owned; + char problem; + int pack_id; + void *usr_ptr; + unsigned int duration; + + int unused; +} sg_req_info_t; + +#ifdef __cplusplus +} +#endif + +#endif // _LINUX_SCSI_SG_H + diff --git a/lib/mlibc/options/linux/include/sys/epoll.h b/lib/mlibc/options/linux/include/sys/epoll.h new file mode 100644 index 0000000..f84da7a --- /dev/null +++ b/lib/mlibc/options/linux/include/sys/epoll.h @@ -0,0 +1,66 @@ +#ifndef _SYS_EPOLL_H +#define _SYS_EPOLL_H + +#include +#include +#include +#include + +#define EPOLL_NONBLOCK O_NONBLOCK + +// These constants match the Linux definitions. +#define EPOLLIN 0x001 +#define EPOLLPRI 0x002 +#define EPOLLOUT 0x004 +#define EPOLLRDNORM 0x040 +#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 + +#ifdef __cplusplus +extern "C" { +#endif + +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 +; + +#ifndef __MLIBC_ABI_ONLY + +int epoll_create(int); +int epoll_create1(int); +int epoll_ctl(int, int, int, struct epoll_event *); +int epoll_wait(int, struct epoll_event *, int, int); +int epoll_pwait(int, struct epoll_event *, int, int, const sigset_t *); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif // _SYS_EPOLL_H diff --git a/lib/mlibc/options/linux/include/sys/eventfd.h b/lib/mlibc/options/linux/include/sys/eventfd.h new file mode 100644 index 0000000..454a8c1 --- /dev/null +++ b/lib/mlibc/options/linux/include/sys/eventfd.h @@ -0,0 +1,29 @@ +#ifndef _SYS_EVENTFD_H +#define _SYS_EVENTFD_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +typedef uint64_t eventfd_t; + +#define EFD_SEMAPHORE 1 +#define EFD_CLOEXEC O_CLOEXEC +#define EFD_NONBLOCK O_NONBLOCK + +#ifndef __MLIBC_ABI_ONLY + +int eventfd(unsigned int, int); +int eventfd_read(int, eventfd_t *); +int eventfd_write(int, eventfd_t); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif // _SYS_EVENTFD_H diff --git a/lib/mlibc/options/linux/include/sys/fsuid.h b/lib/mlibc/options/linux/include/sys/fsuid.h new file mode 100644 index 0000000..9df9efc --- /dev/null +++ b/lib/mlibc/options/linux/include/sys/fsuid.h @@ -0,0 +1,22 @@ +#ifndef _SYS_FSUID_H +#define _SYS_FSUID_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +int setfsuid(uid_t uid); +int setfsgid(gid_t gid); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif // _SYS_FSUID_H diff --git a/lib/mlibc/options/linux/include/sys/inotify.h b/lib/mlibc/options/linux/include/sys/inotify.h new file mode 100644 index 0000000..3c48403 --- /dev/null +++ b/lib/mlibc/options/linux/include/sys/inotify.h @@ -0,0 +1,63 @@ +#ifndef _SYS_INOTIFY_H +#define _SYS_INOTIFY_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define IN_ACCESS 0x1 +#define IN_ATTRIB 0x4 +#define IN_CLOSE_WRITE 0x8 +#define IN_CLOSE_NOWRITE 0x10 +#define IN_CREATE 0x100 +#define IN_DELETE 0x200 +#define IN_DELETE_SELF 0x400 +#define IN_MODIFY 0x2 +#define IN_MOVE_SELF 0x800 +#define IN_MOVED_FROM 0x40 +#define IN_MOVED_TO 0x80 +#define IN_OPEN 0x20 +#define IN_MOVE (IN_MOVED_FROM | IN_MOVED_TO) +#define IN_CLOSE (IN_CLOSE_WRITE | IN_CLOSE_NOWRITE) +#define IN_DONT_FOLLOW 0x2000000 +#define IN_EXCL_UNLINK 0x4000000 +#define IN_MASK_ADD 0x20000000 +#define IN_ONESHOT 0x80000000 +#define IN_ONLYDIR 0x1000000 +#define IN_IGNORED 0x8000 +#define IN_ISDIR 0x40000000 +#define IN_Q_OVERFLOW 0x4000 +#define IN_UNMOUNT 0x2000 + +#define IN_ALL_EVENTS (IN_ACCESS | IN_MODIFY | IN_ATTRIB | IN_CLOSE_WRITE | \ + IN_CLOSE_NOWRITE | IN_OPEN | IN_MOVED_FROM | \ + IN_MOVED_TO | IN_DELETE | IN_CREATE | IN_DELETE_SELF | \ + IN_MOVE_SELF) + +struct inotify_event { + int wd; + unsigned int mask; + unsigned int cookie; + unsigned int len; + char name[]; +}; + +#ifndef __MLIBC_ABI_ONLY + +int inotify_init(void); +int inotify_init1(int); +int inotify_add_watch(int, const char *, uint32_t); +int inotify_rm_watch(int, int); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif //_SYS_INOTIFY_H + diff --git a/lib/mlibc/options/linux/include/sys/klog.h b/lib/mlibc/options/linux/include/sys/klog.h new file mode 100644 index 0000000..520bdd1 --- /dev/null +++ b/lib/mlibc/options/linux/include/sys/klog.h @@ -0,0 +1,18 @@ +#ifndef _SYS_KLOG_H +#define _SYS_KLOG_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +int klogctl(int type, char *bufp, int len); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_KLOG_H */ diff --git a/lib/mlibc/options/linux/include/sys/mount.h b/lib/mlibc/options/linux/include/sys/mount.h new file mode 100644 index 0000000..2486128 --- /dev/null +++ b/lib/mlibc/options/linux/include/sys/mount.h @@ -0,0 +1,90 @@ +#ifndef _SYS_MOUNT_H +#define _SYS_MOUNT_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define MS_RDONLY 1 +#define MS_NOSUID 2 +#define MS_NODEV 4 +#define MS_NOEXEC 8 +#define MS_SYNCHRONOUS 16 +#define MS_REMOUNT 32 +#define MS_MANDLOCK 64 +#define MS_DIRSYNC 128 +#define MS_NOSYMFOLLOW 256 +#define MS_NOATIME 1024 +#define MS_NODIRATIME 2048 +#define MS_BIND 4096 +#define MS_MOVE 8192 +#define MS_REC 16384 +#define MS_SILENT 32768 +#define MS_POSIXACL (1 << 16) +#define MS_UNBINDABLE (1 << 17) +#define MS_PRIVATE (1 << 18) +#define MS_SLAVE (1 << 19) +#define MS_SHARED (1 << 20) +#define MS_RELATIME (1 << 21) +#define MS_KERNMOUNT (1 << 22) +#define MS_I_VERSION (1 << 23) +#define MS_STRICTATIME (1 << 24) +#define MS_LAZYTIME (1 << 25) +#define MS_NOREMOTELOCK (1 << 27) +#define MS_NOSEC (1 << 28) +#define MS_BORN (1 << 29) +#define MS_ACTIVE (1 << 30) +#define MS_NOUSER (1 << 31) + +#define MNT_FORCE 1 +#define MNT_DETACH 2 +#define MNT_EXPIRE 4 +#define UMOUNT_NOFOLLOW 8 + +#undef BLKROSET +#define BLKROSET _IO(0x12, 93) +#undef BLKROGET +#define BLKROGET _IO(0x12, 94) +#undef BLKRRPART +#define BLKRRPART _IO(0x12, 95) +#undef BLKGETSIZE +#define BLKGETSIZE _IO(0x12, 96) +#undef BLKFLSBUF +#define BLKFLSBUF _IO(0x12, 97) +#undef BLKRASET +#define BLKRASET _IO(0x12, 98) +#undef BLKRAGET +#define BLKRAGET _IO(0x12, 99) +#undef BLKFRASET +#define BLKFRASET _IO(0x12, 100) +#undef BLKFRAGET +#define BLKFRAGET _IO(0x12, 101) +#undef BLKSECTSET +#define BLKSECTSET _IO(0x12, 102) +#undef BLKSECTGET +#define BLKSECTGET _IO(0x12, 103) +#undef BLKSSZGET +#define BLKSSZGET _IO(0x12, 104) +#undef BLKBSZGET +#define BLKBSZGET _IOR(0x12, 112, size_t) +#undef BLKBSZSET +#define BLKBSZSET _IOW(0x12, 113, size_t) +#undef BLKGETSIZE64 +#define BLKGETSIZE64 _IOR(0x12, 114, size_t) + +#ifndef __MLIBC_ABI_ONLY + +int mount(const char *source, const char *target, + const char *fstype, unsigned long flags, const void *data); +int umount(const char *target); +int umount2(const char *target, int flags); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif // _SYS_MOUNT_H diff --git a/lib/mlibc/options/linux/include/sys/prctl.h b/lib/mlibc/options/linux/include/sys/prctl.h new file mode 100644 index 0000000..de987c1 --- /dev/null +++ b/lib/mlibc/options/linux/include/sys/prctl.h @@ -0,0 +1,128 @@ + +#ifndef _SYS_PRCTL_H +#define _SYS_PRCTL_H + +#include + +#define PR_SET_PDEATHSIG 1 +#define PR_GET_PDEATHSIG 2 +#define PR_GET_DUMPABLE 3 +#define PR_SET_DUMPABLE 4 +#define PR_GET_UNALIGN 5 +#define PR_SET_UNALIGN 6 +#define PR_UNALIGN_NOPRINT 1 +#define PR_UNALIGN_SIGBUS 2 +#define PR_GET_KEEPCAPS 7 +#define PR_SET_KEEPCAPS 8 +#define PR_GET_FPEMU 9 +#define PR_SET_FPEMU 10 +#define PR_FPEMU_NOPRINT 1 +#define PR_FPEMU_SIGFPE 2 +#define PR_GET_FPEXC 11 +#define PR_SET_FPEXC 12 +#define PR_FP_EXC_SW_ENABLE 0x80 +#define PR_FP_EXC_DIV 0x010000 +#define PR_FP_EXC_OVF 0x020000 +#define PR_FP_EXC_UND 0x040000 +#define PR_FP_EXC_RES 0x080000 +#define PR_FP_EXC_INV 0x100000 +#define PR_FP_EXC_DISABLED 0 +#define PR_FP_EXC_NONRECOV 1 +#define PR_FP_EXC_ASYNC 2 +#define PR_FP_EXC_PRECISE 3 +#define PR_GET_TIMING 13 +#define PR_SET_TIMING 14 +#define PR_TIMING_STATISTICAL 0 +#define PR_TIMING_TIMESTAMP 1 +#define PR_SET_NAME 15 +#define PR_GET_NAME 16 +#define PR_GET_ENDIAN 19 +#define PR_SET_ENDIAN 20 +#define PR_ENDIAN_BIG 0 +#define PR_ENDIAN_LITTLE 1 +#define PR_ENDIAN_PPC_LITTLE 2 +#define PR_GET_SECCOMP 21 +#define PR_SET_SECCOMP 22 +#define PR_CAPBSET_READ 23 +#define PR_CAPBSET_DROP 24 +#define PR_GET_TSC 25 +#define PR_SET_TSC 26 +#define PR_TSC_ENABLE 1 +#define PR_TSC_SIGSEGV 2 +#define PR_GET_SECUREBITS 27 +#define PR_SET_SECUREBITS 28 +#define PR_SET_TIMERSLACK 29 +#define PR_GET_TIMERSLACK 30 + +#define PR_TASK_PERF_EVENTS_DISABLE 31 +#define PR_TASK_PERF_EVENTS_ENABLE 32 + +#define PR_MCE_KILL 33 +#define PR_MCE_KILL_CLEAR 0 +#define PR_MCE_KILL_SET 1 +#define PR_MCE_KILL_LATE 0 +#define PR_MCE_KILL_EARLY 1 +#define PR_MCE_KILL_DEFAULT 2 +#define PR_MCE_KILL_GET 34 + +#define PR_SET_MM 35 +#define PR_SET_MM_START_CODE 1 +#define PR_SET_MM_END_CODE 2 +#define PR_SET_MM_START_DATA 3 +#define PR_SET_MM_END_DATA 4 +#define PR_SET_MM_START_STACK 5 +#define PR_SET_MM_START_BRK 6 +#define PR_SET_MM_BRK 7 +#define PR_SET_MM_ARG_START 8 +#define PR_SET_MM_ARG_END 9 +#define PR_SET_MM_ENV_START 10 +#define PR_SET_MM_ENV_END 11 +#define PR_SET_MM_AUXV 12 +#define PR_SET_MM_EXE_FILE 13 +#define PR_SET_MM_MAP 14 +#define PR_SET_MM_MAP_SIZE 15 + +#define PR_SET_PTRACER 0x59616d61 +#define PR_SET_PTRACER_ANY (-1UL) + +#define PR_SET_CHILD_SUBREAPER 36 +#define PR_GET_CHILD_SUBREAPER 37 + +#define PR_SET_NO_NEW_PRIVS 38 +#define PR_GET_NO_NEW_PRIVS 39 + +#define PR_GET_TID_ADDRESS 40 + +#define PR_SET_THP_DISABLE 41 +#define PR_GET_THP_DISABLE 42 + +#define PR_MPX_ENABLE_MANAGEMENT 43 +#define PR_MPX_DISABLE_MANAGEMENT 44 + +#define PR_SET_FP_MODE 45 +#define PR_GET_FP_MODE 46 +#define PR_FP_MODE_FR (1 << 0) +#define PR_FP_MODE_FRE (1 << 1) + +#define PR_CAP_AMBIENT 47 +#define PR_CAP_AMBIENT_IS_SET 1 +#define PR_CAP_AMBIENT_RAISE 2 +#define PR_CAP_AMBIENT_LOWER 3 +#define PR_CAP_AMBIENT_CLEAR_ALL 4 + +#ifndef __MLIBC_ABI_ONLY + +#ifdef __cplusplus +extern "C" { +#endif + +int prctl (int, ...); + +#ifdef __cplusplus +} +#endif + +#endif /* !__MLIBC_ABI_ONLY */ + +#endif // _SYS_PRCTL_H + diff --git a/lib/mlibc/options/linux/include/sys/ptrace.h b/lib/mlibc/options/linux/include/sys/ptrace.h new file mode 100644 index 0000000..e98d38a --- /dev/null +++ b/lib/mlibc/options/linux/include/sys/ptrace.h @@ -0,0 +1,55 @@ + +#ifndef _SYS_PTRACE_H +#define _SYS_PTRACE_H + +#include +#include + +#define PTRACE_TRACEME 0 +#define PT_TRACE_ME PTRACE_TRACEME + +#define PT_READ_I PTRACE_PEEKTEXT +#define PT_READ_D PTRACE_PEEKDATA +#define PT_READ_U PTRACE_PEEKUSER +#define PT_WRITE_I PTRACE_POKETEXT +#define PT_WRITE_D PTRACE_POKEDATA +#define PT_WRITE_U PTRACE_POKEUSER +#define PT_CONTINUE PTRACE_CONT +#define PT_KILL PTRACE_KILL +#define PT_STEP PTRACE_SINGLESTEP +#define PT_GETREGS PTRACE_GETREGS +#define PT_SETREGS PTRACE_SETREGS +#define PT_GETFPREGS PTRACE_GETFPREGS +#define PT_SETFPREGS PTRACE_SETFPREGS +#define PT_ATTACH PTRACE_ATTACH +#define PT_DETACH PTRACE_DETACH +#define PT_GETFPXREGS PTRACE_GETFPXREGS +#define PT_SETFPXREGS PTRACE_SETFPXREGS +#define PT_SYSCALL PTRACE_SYSCALL +#define PT_SETOPTIONS PTRACE_SETOPTIONS +#define PT_GETEVENTMSG PTRACE_GETEVENTMSG +#define PT_GETSIGINFO PTRACE_GETSIGINFO +#define PT_SETSIGINFO PTRACE_SETSIGINFO + +#ifdef __cplusplus +extern "C" { +#endif + +struct ptrace_peeksiginfo_args { + uint64_t offset; + uint32_t flags; + int32_t nr; +}; + +#ifndef __MLIBC_ABI_ONLY + +long ptrace(int, ...); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif // _SYS_PTRACE_H + diff --git a/lib/mlibc/options/linux/include/sys/quota.h b/lib/mlibc/options/linux/include/sys/quota.h new file mode 100644 index 0000000..f668d9b --- /dev/null +++ b/lib/mlibc/options/linux/include/sys/quota.h @@ -0,0 +1,24 @@ +#ifndef _SYS_QUOTA_H +#define _SYS_QUOTA_H + +#include + +#define SUBCMDMASK 0x00ff +#define SUBCMDSHIFT 8 +#define QCMD(cmd, type) (((cmd) << SUBCMDSHIFT) | ((type) & SUBCMDMASK)) + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +int quotactl(int cmd, const char *special, int id, caddr_t addr); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif // _SYS_QUOTA_H diff --git a/lib/mlibc/options/linux/include/sys/random.h b/lib/mlibc/options/linux/include/sys/random.h new file mode 100644 index 0000000..0b24b74 --- /dev/null +++ b/lib/mlibc/options/linux/include/sys/random.h @@ -0,0 +1,26 @@ + +#ifndef _SYS_RANDOM_H +#define _SYS_RANDOM_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define GRND_RANDOM 1 +#define GRND_NONBLOCK 2 + +#include +#include + +#ifndef __MLIBC_ABI_ONLY + +ssize_t getrandom(void *, size_t, unsigned int); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif //_SYS_RANDOM_H + diff --git a/lib/mlibc/options/linux/include/sys/reboot.h b/lib/mlibc/options/linux/include/sys/reboot.h new file mode 100644 index 0000000..6c4e495 --- /dev/null +++ b/lib/mlibc/options/linux/include/sys/reboot.h @@ -0,0 +1,20 @@ +#ifndef MLIBC_SYS_REBOOT_H +#define MLIBC_SYS_REBOOT_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +int reboot(int arg); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif // MLIBC_SYS_REBOOT_H diff --git a/lib/mlibc/options/linux/include/sys/sendfile.h b/lib/mlibc/options/linux/include/sys/sendfile.h new file mode 100644 index 0000000..32b17ce --- /dev/null +++ b/lib/mlibc/options/linux/include/sys/sendfile.h @@ -0,0 +1,22 @@ + +#ifndef _SYS_SENDFILE_H_ +#define _SYS_SENDFILE_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#ifndef __MLIBC_ABI_ONLY + +ssize_t sendfile(int, int, off_t *, size_t); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif // _SYS_SENDFILE_H_ + diff --git a/lib/mlibc/options/linux/include/sys/signalfd.h b/lib/mlibc/options/linux/include/sys/signalfd.h new file mode 100644 index 0000000..adf7c1b --- /dev/null +++ b/lib/mlibc/options/linux/include/sys/signalfd.h @@ -0,0 +1,48 @@ +#ifndef _SYS_SIGNALFD_H +#define _SYS_SIGNALFD_H + +// TODO: Define sigset separately and remove this include. +#include +// musl includes those. Restructure this so we do not need them? +#include +#include + +#define SFD_CLOEXEC O_CLOEXEC +#define SFD_NONBLOCK O_NONBLOCK + +#ifdef __cplusplus +extern "C" { +#endif + +struct signalfd_siginfo { + uint32_t ssi_signo; + int32_t ssi_errno; + int32_t ssi_code; + uint32_t ssi_pid; + uint32_t ssi_uid; + int32_t ssi_fd; + uint32_t ssi_tid; + uint32_t ssi_band; + uint32_t ssi_overrun; + uint32_t ssi_trapno; + int32_t ssi_status; + int32_t ssi_int; + uint64_t ssi_ptr; + uint64_t ssi_utime; + uint64_t ssi_stime; + uint64_t ssi_addr; + uint16_t ssi_addr_lsb; + uint8_t pad[128-12*4-4*8-2]; +}; + +#ifndef __MLIBC_ABI_ONLY + +int signalfd(int, const sigset_t *, int); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif // _SYS_SIGNALFD_H diff --git a/lib/mlibc/options/linux/include/sys/statfs.h b/lib/mlibc/options/linux/include/sys/statfs.h new file mode 100644 index 0000000..07ae693 --- /dev/null +++ b/lib/mlibc/options/linux/include/sys/statfs.h @@ -0,0 +1,22 @@ +#ifndef _SYS_STATFS_H +#define _SYS_STATFS_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#ifndef __MLIBC_ABI_ONLY + +int statfs(const char *, struct statfs *); +int fstatfs(int, struct statfs *); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif // _SYS_STATFS_H + diff --git a/lib/mlibc/options/linux/include/sys/swap.h b/lib/mlibc/options/linux/include/sys/swap.h new file mode 100644 index 0000000..79e89c6 --- /dev/null +++ b/lib/mlibc/options/linux/include/sys/swap.h @@ -0,0 +1,24 @@ +#ifndef _SYS_SWAP_H +#define _SYS_SWAP_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define SWAP_FLAG_PREFER 0x8000 +#define SWAP_FLAG_PRIO_MASK 0x7fff +#define SWAP_FLAG_PRIO_SHIFT 0 +#define SWAP_FLAG_DISCARD 0x10000 + +#ifndef __MLIBC_ABI_ONLY + +int swapon(const char *, int); +int swapoff(const char *); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_SWAP_H */ diff --git a/lib/mlibc/options/linux/include/sys/sysinfo.h b/lib/mlibc/options/linux/include/sys/sysinfo.h new file mode 100644 index 0000000..917f861 --- /dev/null +++ b/lib/mlibc/options/linux/include/sys/sysinfo.h @@ -0,0 +1,34 @@ +#ifndef _SYS_SYSINFO_H +#define _SYS_SYSINFO_H + +#ifdef __cplusplus +extern "C" { +#endif + +struct sysinfo { + long uptime; + unsigned long loads[3]; + unsigned long totalram; + unsigned long freeram; + unsigned long sharedram; + unsigned long bufferram; + unsigned long totalswap; + unsigned long freeswap; + unsigned short procs; + unsigned long totalhigh; + unsigned long freehigh; + unsigned int mem_unit; + char _f[20 - 2 * sizeof(long) - sizeof(int)]; // Padding to 64 bytes according to my man page +}; + +#ifndef __MLIBC_ABI_ONLY + +int sysinfo(struct sysinfo *); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif // _SYS_SYSINFO_H diff --git a/lib/mlibc/options/linux/include/sys/sysmacros.h b/lib/mlibc/options/linux/include/sys/sysmacros.h new file mode 100644 index 0000000..230858b --- /dev/null +++ b/lib/mlibc/options/linux/include/sys/sysmacros.h @@ -0,0 +1,35 @@ +#ifndef _SYS_SYSMACROS_H +#define _SYS_SYSMACROS_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +__MLIBC_INLINE_DEFINITION unsigned int __mlibc_dev_major( + unsigned long long int __dev) { + return ((__dev >> 8) & 0xfff) | ((unsigned int)(__dev >> 32) & ~0xfff); +} + +__MLIBC_INLINE_DEFINITION unsigned int __mlibc_dev_minor( + unsigned long long int __dev) { + return (__dev & 0xff) | ((unsigned int)(__dev >> 12) & ~0xff); +} + +__MLIBC_INLINE_DEFINITION unsigned long long int __mlibc_dev_makedev( + unsigned int __major, unsigned int __minor) { + return ((__minor & 0xff) | ((__major & 0xfff) << 8) + | (((unsigned long long int)(__minor & ~0xff)) << 12) + | (((unsigned long long int)(__major & ~0xfff)) << 32)); +} + +#define major(dev) __mlibc_dev_major(dev) +#define minor(dev) __mlibc_dev_minor(dev) +#define makedev(major, minor) __mlibc_dev_makedev(major, minor) + +#ifdef __cplusplus +} +#endif + +#endif // _SYS_SYSMACROS_H diff --git a/lib/mlibc/options/linux/include/sys/timerfd.h b/lib/mlibc/options/linux/include/sys/timerfd.h new file mode 100644 index 0000000..b8a2932 --- /dev/null +++ b/lib/mlibc/options/linux/include/sys/timerfd.h @@ -0,0 +1,32 @@ +#ifndef _SYS_TIMERFD_H +#define _SYS_TIMERFD_H + +// musl includes those. Refactor and remove them? +#include +#include + +#define TFD_NONBLOCK O_NONBLOCK +#define TFD_CLOEXEC O_CLOEXEC + +#define TFD_TIMER_ABSTIME 1 +#define TFD_TIMER_CANCEL_ON_SET (1 << 1) + +#ifdef __cplusplus +extern "C" { +#endif + +struct itimerspec; + +#ifndef __MLIBC_ABI_ONLY + +int timerfd_create(int, int); +int timerfd_settime(int, int, const struct itimerspec *, struct itimerspec *); +int timerfd_gettime(int, struct itimerspec *); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif // _SYS_TIMERFD_H diff --git a/lib/mlibc/options/linux/include/sys/vfs.h b/lib/mlibc/options/linux/include/sys/vfs.h new file mode 100644 index 0000000..61a6aa3 --- /dev/null +++ b/lib/mlibc/options/linux/include/sys/vfs.h @@ -0,0 +1,16 @@ + +#ifndef _SYS_VFS_H +#define _SYS_VFS_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#ifdef __cplusplus +} +#endif + +#endif // _SYS_VFS_H + diff --git a/lib/mlibc/options/linux/include/sys/vt.h b/lib/mlibc/options/linux/include/sys/vt.h new file mode 100644 index 0000000..d9dfbd9 --- /dev/null +++ b/lib/mlibc/options/linux/include/sys/vt.h @@ -0,0 +1,6 @@ +#ifndef _SYS_VT_H +#define _SYS_VT_H + +#include + +#endif // _SYS_VT_H diff --git a/lib/mlibc/options/linux/include/sys/xattr.h b/lib/mlibc/options/linux/include/sys/xattr.h new file mode 100644 index 0000000..e54c58c --- /dev/null +++ b/lib/mlibc/options/linux/include/sys/xattr.h @@ -0,0 +1,38 @@ +#ifndef _MLIBC_LINUX_SYS_XATTR_H +#define _MLIBC_LINUX_SYS_XATTR_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +int setxattr(const char *path, const char *name, const void *val, size_t size, + int flags); +int lsetxattr(const char *path, const char *name, const void *val, size_t size, + int flags); +int fsetxattr(int fd, const char *name, const void *val, size_t size, + int flags); + +ssize_t getxattr(const char *path, const char *name, void *val, size_t size); +ssize_t lgetxattr(const char *path, const char *name, void *val, size_t size); +ssize_t fgetxattr(int fd, const char *name, void *val, size_t size); + +ssize_t listxattr(const char *path, char *list, size_t size); +ssize_t llistxattr(const char *path, char *list, size_t size); +ssize_t flistxattr(int fd, char *list, size_t size); + +int removexattr(const char *path, const char *name); +int lremovexattr(const char *path, const char *name); +int fremovexattr(int fd, const char *name); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _MLIBC_LINUX_SYS_XATTR_H */ diff --git a/lib/mlibc/options/linux/include/utmp.h b/lib/mlibc/options/linux/include/utmp.h new file mode 100644 index 0000000..e83d7a5 --- /dev/null +++ b/lib/mlibc/options/linux/include/utmp.h @@ -0,0 +1,84 @@ +#ifndef _UTMP_H +#define _UTMP_H + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define EMPTY 0 +#define RUN_LVL 1 +#define BOOT_TIME 2 +#define NEW_TIME 3 +#define OLD_TIME 4 +#define INIT_PROCESS 5 +#define LOGIN_PROCESS 6 +#define USER_PROCESS 7 +#define DEAD_PROCESS 8 +#define ACCOUNTING 9 + +#define UT_LINESIZE 32 +#define UT_NAMESIZE 32 +#define UT_HOSTSIZE 256 + +#define WTMP_FILE _PATH_WTMP +#define WTMP_FILENAME _PATH_WTMP + +#define UTMP_FILE _PATH_UTMP +#define UTMP_FILENAME _PATH_UTMP + +struct exit_status { + short int e_termination; + short int e_exit; +}; + +struct utmp { + short ut_type; + pid_t ut_pid; + char ut_line[UT_LINESIZE]; + char ut_id[4]; + char ut_user[UT_NAMESIZE]; + char ut_host[UT_HOSTSIZE]; + struct exit_status ut_exit; + long ut_session; + struct timeval ut_tv; + __mlibc_int32 ut_addr_v6[4]; + char __unused[20]; +}; + +struct lastlog { + time_t ll_time; + char ll_line[UT_LINESIZE]; + char ll_host[UT_HOSTSIZE]; +}; + +/* Hacks for compability reasons */ +#define ut_name ut_user +#ifndef _NO_UT_TIME +#define ut_time ut_tv.tv_sec +#endif +#define ut_xtime ut_tv.tv_sec +#define ut_addr ut_addr_v6[0] + +#ifndef __MLIBC_ABI_ONLY + +void setutent(void); +struct utmp *getutent(void); +int getutent_r(struct utmp *, struct utmp **); +void endutent(void); +struct utmp *pututline(const struct utmp *); +struct utmp *getutline(const struct utmp *); +struct utmp *getutid(const struct utmp *); +int utmpname(const char *); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif // _UTMP_H diff --git a/lib/mlibc/options/linux/include/utmpx.h b/lib/mlibc/options/linux/include/utmpx.h new file mode 100644 index 0000000..32629dd --- /dev/null +++ b/lib/mlibc/options/linux/include/utmpx.h @@ -0,0 +1,68 @@ + +#ifndef _UTMPX_H +#define _UTMPX_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +// Struct definition taken from musl +struct utmpx { + short ut_type; + short __ut_pad1; + pid_t ut_pid; + char ut_line[32]; + char ut_id[4]; + char ut_user[32]; + char ut_host[256]; + struct { + short __e_termination; + short __e_exit; + } ut_exit; + int ut_session, __ut_pad2; + struct timeval ut_tv; + unsigned ut_addr_v6[4]; + char __unused[20]; +}; + +#define e_exit __e_exit +#define e_termination __e_termination + +#ifndef __MLIBC_ABI_ONLY + +void updwtmpx(const char *, const struct utmpx *); +int utmpxname(const char *); +struct utmpx *pututxline(const struct utmpx *); +struct utmpx *getutxent(void); +struct utmpx *getutxid(const struct utmpx *id); +void setutxent(void); +void endutxent(void); + +#endif /* !__MLIBC_ABI_ONLY */ + +#define EMPTY 0 +#define RUN_LVL 1 +#define BOOT_TIME 2 +#define NEW_TIME 3 +#define OLD_TIME 4 +#define INIT_PROCESS 5 +#define LOGIN_PROCESS 6 +#define USER_PROCESS 7 +#define DEAD_PROCESS 8 + +#ifdef _GNU_SOURCE +#define ACCOUNTING 9 +#endif + +#define __UT_HOSTSIZE 256 +#define __UT_NAMESIZE 32 +#define __UT_LINESIZE 32 + +#ifdef __cplusplus +} +#endif + +#endif // _UTMPX_H diff --git a/lib/mlibc/options/linux/include/values.h b/lib/mlibc/options/linux/include/values.h new file mode 100644 index 0000000..55a50cd --- /dev/null +++ b/lib/mlibc/options/linux/include/values.h @@ -0,0 +1,39 @@ + +#ifndef _VALUES_H +#define _VALUES_H + +#include +#include + +#define CHARBITS (sizeof(char) * 8) +#define SHORTBITS (sizeof(short) * 8) +#define INTBITS (sizeof(int) * 8) +#define LONGBITS (sizeof(long) * 8) +#define PTRBITS (sizeof(char *) * 8) +#define DOUBLEBITS (sizeof(double) * 8) +#define FLOATBITS (sizeof(float) * 8) + +#define MINSHORT SHRT_MIN +#define MININT INT_MIN +#define MINLONG LONG_MIN + +#define MAXSHORT SHRT_MAX +#define MAXINT INT_MAX +#define MAXLONG LONG_MAX + +#define HIBITS MINSHORT +#define HIBITL MINLONG + +#define MAXDOUBLE DBL_MAX +#define MAXFLOAT FLT_MAX +#define MINDOUBLE DBL_MIN +#define MINFLOAT FLT_MIN +#define DMINEXP DBL_MIN_EXP +#define FMINEXP FLT_MIN_EXP +#define DMAXEXP DBL_MAX_EXP +#define FMAXEXP FLT_MAX_EXP + +#define BITSPERBYTE CHAR_BIT + +#endif // _VALUES_H + diff --git a/lib/mlibc/options/linux/meson.build b/lib/mlibc/options/linux/meson.build new file mode 100644 index 0000000..eb8fefc --- /dev/null +++ b/lib/mlibc/options/linux/meson.build @@ -0,0 +1,96 @@ + +if disable_linux_option + subdir_done() +endif +libc_sources += files( + 'generic/mntent-stubs.cpp', + 'generic/pty-stubs.cpp', + 'generic/sys-epoll.cpp', + 'generic/sys-inotify-stubs.cpp', + 'generic/sys-mount.cpp', + 'generic/sys-prctl-stubs.cpp', + 'generic/sys-ptrace-stubs.cpp', + 'generic/sys-random-stubs.cpp', + 'generic/sys-sendfile-stubs.cpp', + 'generic/sys-signalfd.cpp', + 'generic/sys-timerfd.cpp', + 'generic/sys-eventfd.cpp', + 'generic/sys-reboot.cpp', + 'generic/sys-xattr.cpp', + 'generic/utmp-stubs.cpp', + 'generic/utmpx.cpp', + 'generic/linux-unistd.cpp', + 'generic/malloc.cpp', + 'generic/sys-fsuid.cpp', + 'generic/ifaddrs.cpp', + 'generic/sys-sysinfo.cpp', + 'generic/module.cpp', + 'generic/sys-klog.cpp', + 'generic/sched.cpp', + 'generic/sys-quota.cpp', + 'generic/capabilities.cpp', + 'generic/cpuset.cpp', + 'generic/sys-swap.cpp', + 'generic/sys-statfs-stubs.cpp', +) + +if not no_headers + install_headers( + 'include/ifaddrs.h', + 'include/malloc.h', + 'include/memory.h', + 'include/mntent.h', + 'include/pty.h', + 'include/utmp.h', + 'include/utmpx.h', + 'include/values.h', + 'include/lastlog.h', + 'include/module.h', + ) + install_headers( + 'include/bits/linux/linux_unistd.h', + 'include/bits/linux/linux_sched.h', + 'include/bits/linux/cpu_set.h', + subdir: 'bits/linux' + ) + install_headers( + 'include/netpacket/packet.h', + subdir: 'netpacket' + ) + # libc provides these, not the kernel, so the Linux option shall provide them too. + install_headers( + 'include/scsi/scsi.h', + 'include/scsi/scsi_ioctl.h', + 'include/scsi/sg.h', + subdir: 'scsi' + ) + install_headers( + 'include/sys/epoll.h', + 'include/sys/inotify.h', + 'include/sys/mount.h', + 'include/sys/prctl.h', + 'include/sys/ptrace.h', + 'include/sys/random.h', + 'include/sys/sendfile.h', + 'include/sys/signalfd.h', + 'include/sys/sysmacros.h', + 'include/sys/timerfd.h', + 'include/sys/eventfd.h', + 'include/sys/reboot.h', + 'include/sys/fsuid.h', + 'include/sys/vt.h', + 'include/sys/sysinfo.h', + 'include/sys/klog.h', + 'include/sys/xattr.h', + 'include/sys/quota.h', + 'include/sys/swap.h', + 'include/sys/statfs.h', + 'include/sys/vfs.h', + subdir: 'sys' + ) + install_headers( + 'include/linux/libc-compat.h', + subdir: 'linux' + ) +endif + diff --git a/lib/mlibc/options/lsb/generic/auxv.cpp b/lib/mlibc/options/lsb/generic/auxv.cpp new file mode 100644 index 0000000..a4d2c8f --- /dev/null +++ b/lib/mlibc/options/lsb/generic/auxv.cpp @@ -0,0 +1,59 @@ + +#include +#include +#include + +#include + +extern "C" uintptr_t *__dlapi_entrystack(); + +int peekauxval(unsigned long type, unsigned long *out) { + // Find the auxiliary vector by skipping args and environment. + auto aux = __dlapi_entrystack(); + aux += *aux + 1; // Skip argc and all arguments + __ensure(!*aux); + aux++; + while(*aux) // Now, we skip the environment. + aux++; + aux++; + + // Parse the auxiliary vector. + while(true) { + auto value = aux + 1; + if(*aux == AT_NULL) { + errno = ENOENT; + return -1; + }else if(*aux == type) { + *out = *value; + return 0; + } + aux += 2; + } +} + +unsigned long getauxval(unsigned long type) { + unsigned long value = 0; + if(peekauxval(type, &value)) + return 0; + return value; +} + +// XXX(qookie): +// This is here because libgcc will call into __getauxval on glibc Linux +// (which is what it believes we are due to the aarch64-linux-gnu toolchain) +// in order to find AT_HWCAP to discover if LSE atomics are supported. +// +// This is not necessary on a custom Linux toolchain and is purely an artifact of +// using the host toolchain. + +// __gnu_linux__ is the define checked by libgcc +#if defined(__aarch64__) && defined(__gnu_linux__) + +extern "C" unsigned long __getauxval(unsigned long type) { + unsigned long value = 0; + if(peekauxval(type, &value)) + return 0; + return value; +} + +#endif diff --git a/lib/mlibc/options/lsb/generic/dso_exit.cpp b/lib/mlibc/options/lsb/generic/dso_exit.cpp new file mode 100644 index 0000000..b8b239d --- /dev/null +++ b/lib/mlibc/options/lsb/generic/dso_exit.cpp @@ -0,0 +1,42 @@ + +// for memcpy() +#include + +#include +#include + +#include +#include + +struct ExitHandler { + void (*function)(void *); + void *argument; + void *dsoHandle; +}; + +using ExitQueue = frg::vector; + +ExitQueue &getExitQueue() { + // use frg::eternal to prevent the compiler from scheduling the destructor + // by generating a call to __cxa_atexit(). + static frg::eternal singleton(getAllocator()); + return singleton.get(); +} + +extern "C" int __cxa_atexit(void (*function)(void *), void *argument, void *handle) { + ExitHandler handler; + handler.function = function; + handler.argument = argument; + handler.dsoHandle = handle; + getExitQueue().push(handler); + return 0; +} + +void __mlibc_do_finalize() { + ExitQueue &eq = getExitQueue(); + for(size_t i = eq.size(); i > 0; i--) { + auto handler = &eq[i - 1]; + handler->function(handler->argument); + } +} + diff --git a/lib/mlibc/options/lsb/generic/tls.cpp b/lib/mlibc/options/lsb/generic/tls.cpp new file mode 100644 index 0000000..1d7cc30 --- /dev/null +++ b/lib/mlibc/options/lsb/generic/tls.cpp @@ -0,0 +1,23 @@ +#include +#include +#include + +#if defined(__riscv) && defined(MLIBC_STATIC_BUILD) + // On RISC-V, linker optimisation is not guaranteed and so we may still get + // calls to this function in statically linked binaries. + // TODO: This will break dlopen calls from statically linked programs. + extern "C" void *__tls_get_addr(struct __abi_tls_entry *entry) { + Tcb *tcbPtr = mlibc::get_current_tcb(); + auto dtvPtr = reinterpret_cast(tcbPtr->dtvPointers[0]); + return reinterpret_cast(dtvPtr + entry->offset + TLS_DTV_OFFSET); + } +#elif defined(__i386__) + extern "C" __attribute__((regparm(1))) void *___tls_get_addr(struct __abi_tls_entry *entry) { + return __dlapi_get_tls(entry); + } +#else + extern "C" void *__tls_get_addr(struct __abi_tls_entry *entry) { + return __dlapi_get_tls(entry); + } +#endif + diff --git a/lib/mlibc/options/lsb/include/sys/auxv.h b/lib/mlibc/options/lsb/include/sys/auxv.h new file mode 100644 index 0000000..a3e028c --- /dev/null +++ b/lib/mlibc/options/lsb/include/sys/auxv.h @@ -0,0 +1,26 @@ +#ifndef _SYS_AUXV_H +#define _SYS_AUXV_H + +#define AT_NULL 0 +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +// mlibc extension: Like getauxval but handles errors in a sane way. +// Success: Return 0. +// Failure: Return -1 and set errno. +int peekauxval(unsigned long type, unsigned long *value); + +unsigned long getauxval(unsigned long type); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif diff --git a/lib/mlibc/options/lsb/meson.build b/lib/mlibc/options/lsb/meson.build new file mode 100644 index 0000000..322a912 --- /dev/null +++ b/lib/mlibc/options/lsb/meson.build @@ -0,0 +1,14 @@ + +lsb_sources = files( + 'generic/auxv.cpp', + 'generic/dso_exit.cpp', + 'generic/tls.cpp', +) + +if not no_headers + install_headers( + 'include/sys/auxv.h', + subdir: 'sys' + ) +endif + diff --git a/lib/mlibc/options/posix/generic/arpa-inet-stubs.cpp b/lib/mlibc/options/posix/generic/arpa-inet-stubs.cpp new file mode 100644 index 0000000..0bc9727 --- /dev/null +++ b/lib/mlibc/options/posix/generic/arpa-inet-stubs.cpp @@ -0,0 +1,220 @@ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT; +const struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT; + +uint32_t htonl(uint32_t x) { +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + return mlibc::bit_util::byteswap(x); +#else + return x; +#endif +} +uint16_t htons(uint16_t x) { +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + return mlibc::bit_util::byteswap(x); +#else + return x; +#endif +} +uint32_t ntohl(uint32_t x) { +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + return mlibc::bit_util::byteswap(x); +#else + return x; +#endif +} +uint16_t ntohs(uint16_t x) { +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + return mlibc::bit_util::byteswap(x); +#else + return x; +#endif +} + +// ---------------------------------------------------------------------------- +// IPv4 address manipulation. +// ---------------------------------------------------------------------------- +in_addr_t inet_addr(const char *p) { + struct in_addr a; + if(!inet_aton(p, &a)) + return -1; + return a.s_addr; +} +char *inet_ntoa(struct in_addr addr) { + // string: xxx.yyy.zzz.aaa + // 4 * 3 + 3 + 1 = 12 + 4 = 16 + thread_local static char buffer[16]; + uint32_t proper = htonl(addr.s_addr); + snprintf(buffer, sizeof(buffer), "%d.%d.%d.%d", + (proper >> 24) & 0xff, ((proper >> 16) & 0xff), + (proper >> 8) & 0xff, proper & 0xff); + return buffer; +} +int inet_aton(const char *string, struct in_addr *dest) { + int array[4]; + int i = 0; + char *end; + + for (; i < 4; i++) { + array[i] = strtoul(string, &end, 0); + if (*end && *end != '.') + return 0; + if (!*end) + break; + string = end + 1; + } + + switch (i) { + case 0: + dest->s_addr = htonl(array[0]); + break; + case 1: + if (array[0] > 255 || array[1] > 0xffffff) + return 0; + dest->s_addr = htonl((array[0] << 24) | array[1]); + break; + case 2: + if (array[0] > 255 || array[1] > 255 || + array[2] > 0xffff) + return 0; + dest->s_addr = htonl((array[0] << 24) | (array[1] << 16) | + array[2]); + break; + case 3: + if (array[0] > 255 || array[1] > 255 || + array[2] > 255 || array[3] > 255) + return 0; + dest->s_addr = htonl((array[0] << 24) | (array[1] << 16) | + (array[2] << 8) | array[3]); + break; + } + + return 1; +} + +// ---------------------------------------------------------------------------- +// Generic IP address manipulation. +// ---------------------------------------------------------------------------- +const char *inet_ntop(int af, const void *__restrict src, char *__restrict dst, + socklen_t size) { + switch (af) { + case AF_INET: { + auto source = reinterpret_cast(src); + if (snprintf(dst, size, "%d.%d.%d.%d", + source->s_addr & 0xff, + (source->s_addr & 0xffff) >> 8, + (source->s_addr & 0xffffff) >> 16, + source->s_addr >> 24) < (int)size) + return dst; + break; + } + case AF_INET6: { + auto source = reinterpret_cast(src); + size_t cur_zeroes_off = 0; + size_t cur_zeroes_len = 0; + size_t max_zeroes_off = 0; + size_t max_zeroes_len = 0; + + /* we look for the largest block of zeroed quartet(s) */ + for(size_t i = 0; i < 8; i++) { + auto ptr = source->s6_addr + (i * 2); + if(!ptr[0] && !ptr[1]) { + cur_zeroes_len++; + if(max_zeroes_len < cur_zeroes_len) { + max_zeroes_len = cur_zeroes_len; + max_zeroes_off = cur_zeroes_off; + } + } else { + /* advance the offset to the next quartet to check */ + cur_zeroes_len = 0; + cur_zeroes_off = i + 1; + } + } + + size_t off = 0; + for(size_t i = 0; i < 8; i++) { + auto ptr = source->s6_addr + (i * 2); + + /* if we are at the beginning of the largest block of zeroed quartets, place "::" */ + if(i == max_zeroes_off && max_zeroes_len >= 2) { + if(off < size) { + dst[off++] = ':'; + } + if(off < size) { + dst[off++] = ':'; + } + i += max_zeroes_len - 1; + + continue; + } + + /* place a colon if we're not at the beginning of the string and it is not already there */ + if(off && dst[off - 1] != ':') { + if(off < size) { + dst[off++] = ':'; + } + } + + off += snprintf(dst + off, size - off, "%x", ptr[0] << 8 | ptr[1]); + } + + dst[off] = 0; + + return dst; + } + default: + errno = EAFNOSUPPORT; + return NULL; + } + + errno = ENOSPC; + return NULL; +} +int inet_pton(int af, const char *__restrict src, void *__restrict dst) { + switch (af) { + case AF_INET: { + uint8_t array[4] = {}; + for (int i = 0; i < 4; i++) { + char *end; + long int value = strtol(src, &end, 10); + if (value > 255) + return 0; + if (*end != '\0' && *end != '.') + return 0; + src = end + 1; + array[i] = value; + } + auto addr = reinterpret_cast(dst); + memcpy(&addr->s_addr, array, 4); + break; + } + case AF_INET6: + mlibc::infoLogger() << "inet_pton: ipv6 is not implemented!" << frg::endlog; + /* fallthrough */ + default: + errno = EAFNOSUPPORT; + return -1; + } + + return 1; +} + +struct in_addr inet_makeaddr(in_addr_t, in_addr_t) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +in_addr_t inet_netof(struct in_addr) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} diff --git a/lib/mlibc/options/posix/generic/dirent-stubs.cpp b/lib/mlibc/options/posix/generic/dirent-stubs.cpp new file mode 100644 index 0000000..1352585 --- /dev/null +++ b/lib/mlibc/options/posix/generic/dirent-stubs.cpp @@ -0,0 +1,180 @@ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +// Code taken from musl +int alphasort(const struct dirent **a, const struct dirent **b) { + return strcoll((*a)->d_name, (*b)->d_name); +} + +int closedir(DIR *dir) { + // TODO: Deallocate the dir structure. + close(dir->__handle); + return 0; +} +int dirfd(DIR *dir) { + return dir->__handle; +} +DIR *fdopendir(int fd) { + struct stat st; + + if(fstat(fd, &st) < 0) { + return nullptr; + } + // Musl implements this, but O_PATH is only declared on the linux abi + /*if(fcntl(fd, F_GETFL) & O_PATH) { + errno = EBADF; + return nullptr; + }*/ + if(!S_ISDIR(st.st_mode)) { + errno = ENOTDIR; + return nullptr; + } + auto dir = frg::construct<__mlibc_dir_struct>(getAllocator()); + __ensure(dir); + dir->__ent_next = 0; + dir->__ent_limit = 0; + int flags = fcntl(fd, F_GETFD); + fcntl(fd, F_SETFD, flags | FD_CLOEXEC); + dir->__handle = fd; + return dir; +} +DIR *opendir(const char *path) { + auto dir = frg::construct<__mlibc_dir_struct>(getAllocator()); + __ensure(dir); + dir->__ent_next = 0; + dir->__ent_limit = 0; + + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_open_dir, nullptr); + if(int e = mlibc::sys_open_dir(path, &dir->__handle); e) { + errno = e; + frg::destruct(getAllocator(), dir); + return nullptr; + }else{ + return dir; + } +} +struct dirent *readdir(DIR *dir) { + __ensure(dir->__ent_next <= dir->__ent_limit); + if(dir->__ent_next == dir->__ent_limit) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_read_entries, nullptr); + if(int e = mlibc::sys_read_entries(dir->__handle, dir->__ent_buffer, 2048, &dir->__ent_limit); e) + __ensure(!"mlibc::sys_read_entries() failed"); + dir->__ent_next = 0; + if(!dir->__ent_limit) + return nullptr; + } + + auto entp = reinterpret_cast(dir->__ent_buffer + dir->__ent_next); + // We only copy as many bytes as we need to avoid buffer-overflows. + memcpy(&dir->__current, entp, offsetof(struct dirent, d_name) + strlen(entp->d_name) + 1); + dir->__ent_next += entp->d_reclen; + return &dir->__current; +} +int readdir_r(DIR *dir, struct dirent *entry, struct dirent **result) { + if(!mlibc::sys_read_entries) { + MLIBC_MISSING_SYSDEP(); + return ENOSYS; + } + + __ensure(dir->__ent_next <= dir->__ent_limit); + if(dir->__ent_next == dir->__ent_limit) { + if(int e = mlibc::sys_read_entries(dir->__handle, dir->__ent_buffer, 2048, &dir->__ent_limit); e) + __ensure(!"mlibc::sys_read_entries() failed"); + dir->__ent_next = 0; + if(!dir->__ent_limit) { + *result = NULL; + return 0; + } + } + + auto entp = reinterpret_cast(dir->__ent_buffer + dir->__ent_next); + // We only copy as many bytes as we need to avoid buffer-overflows. + memcpy(entry, entp, offsetof(struct dirent, d_name) + strlen(entp->d_name) + 1); + dir->__ent_next += entp->d_reclen; + *result = entry; + return 0; +} + +void rewinddir(DIR *dir) { + lseek(dir->__handle, 0, SEEK_SET); + dir->__ent_next = 0; +} + +int scandir(const char *path, struct dirent ***res, int (*select)(const struct dirent *), + int (*compare)(const struct dirent **, const struct dirent **)) { + DIR *dir = opendir(path); + if (!dir) + return -1; // errno will be set by opendir() + + // we should save the errno + int old_errno = errno; + errno = 0; + + struct dirent *dir_ent; + struct dirent **array = nullptr, **tmp = nullptr; + int length = 0; + int count = 0; + while((dir_ent = readdir(dir)) && !errno) { + if(select && !select(dir_ent)) + continue; + + if(count >= length) { + length = 2*length + 1; + tmp = static_cast(realloc(array, + length * sizeof(struct dirent*))); + // we need to check the call actually goes through + // before we overwrite array so that we can + // deallocate the already written entries should realloc() + // have failed + if(!tmp) + break; + array = tmp; + } + array[count] = static_cast(malloc(dir_ent->d_reclen)); + if(!array[count]) + break; + + memcpy(array[count], dir_ent, dir_ent->d_reclen); + count++; + } + + if(errno) { + if(array) + while(count-- > 0) + free(array[count]); + free(array); + return -1; + } + + // from here we can set the old errno back + errno = old_errno; + + if(compare) + qsort(array, count, sizeof(struct dirent*), + (int (*)(const void *, const void *)) compare); + *res = array; + return count; +} +void seekdir(DIR *, long) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +long telldir(DIR *) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +int versionsort(const struct dirent **a, const struct dirent **b) { + return strverscmp((*a)->d_name, (*b)->d_name); +} diff --git a/lib/mlibc/options/posix/generic/dlfcn-stubs.cpp b/lib/mlibc/options/posix/generic/dlfcn-stubs.cpp new file mode 100644 index 0000000..fc9fd84 --- /dev/null +++ b/lib/mlibc/options/posix/generic/dlfcn-stubs.cpp @@ -0,0 +1,64 @@ + +#include +#include + +#include + +struct __dlapi_symbol { + const char *file; + void *base; + const char *symbol; + void *address; +}; + +extern "C" const char *__dlapi_error(); +extern "C" void *__dlapi_open(const char *, int, void *); +extern "C" void *__dlapi_resolve(void *, const char *, void *); +extern "C" int __dlapi_reverse(const void *, __dlapi_symbol *); +extern "C" int __dlapi_close(void *); + +int dlclose(void *handle) { + return __dlapi_close(handle); +} + +char *dlerror(void) { + return const_cast(__dlapi_error()); +} + +[[gnu::noinline]] +void *dlopen(const char *file, int flags) { + auto ra = __builtin_extract_return_addr(__builtin_return_address(0)); + return __dlapi_open(file, flags, ra); +} + +[[gnu::noinline]] +void *dlsym(void *__restrict handle, const char *__restrict string) { + auto ra = __builtin_extract_return_addr(__builtin_return_address(0)); + return __dlapi_resolve(handle, string, ra); +} + +[[gnu::noinline]] +void *dlvsym(void *__restrict handle, const char *__restrict string, const char *__restrict version) { + mlibc::infoLogger() << "mlibc: dlvsym ignores version " << version << frg::endlog; + auto ra = __builtin_extract_return_addr(__builtin_return_address(0)); + return __dlapi_resolve(handle, string, ra); +} + +//gnu extensions +int dladdr(const void *ptr, Dl_info *out) { + __dlapi_symbol info; + if(__dlapi_reverse(ptr, &info)) + return 0; + + out->dli_fname = info.file; + out->dli_fbase = info.base; + out->dli_sname = info.symbol; + out->dli_saddr = info.address; + return 1; +} + +int dlinfo(void *, int, void *) { + __ensure(!"dlinfo() not implemented"); + __builtin_unreachable(); +} + diff --git a/lib/mlibc/options/posix/generic/fcntl-stubs.cpp b/lib/mlibc/options/posix/generic/fcntl-stubs.cpp new file mode 100644 index 0000000..66e2d12 --- /dev/null +++ b/lib/mlibc/options/posix/generic/fcntl-stubs.cpp @@ -0,0 +1,108 @@ + +#include +#include +#include +#include + +#include +#include + +int creat(const char *pathname, mode_t mode) { + return open(pathname, O_CREAT|O_WRONLY|O_TRUNC, mode); +} + +int fallocate(int, int, off_t, off_t) { + mlibc::infoLogger() << "mlibc: fallocate() is a no-op" << frg::endlog; + errno = ENOSYS; + return -1; +} + +int fcntl(int fd, int command, ...) { + va_list args; + va_start(args, command); + int result; + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_fcntl, -1); + if(int e = mlibc::sys_fcntl(fd, command, args, &result); e) { + errno = e; + return -1; + } + va_end(args); + return result; +} + +int openat(int dirfd, const char *pathname, int flags, ...) { + va_list args; + va_start(args, flags); + mode_t mode = 0; + int fd; + + if((flags & (O_CREAT | O_TMPFILE))) + mode = va_arg(args, mode_t); + + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_openat, -1); + if(int e = mlibc::sys_openat(dirfd, pathname, flags, mode, &fd); e) { + errno = e; + return -1; + } + va_end(args); + return fd; +} + +int posix_fadvise(int fd, off_t offset, off_t length, int advice) { + if(!mlibc::sys_fadvise) { + mlibc::infoLogger() << "mlibc: fadvise() ignored due to missing sysdep" << frg::endlog; + return 0; + } + + // posix_fadvise() returns an error instead of setting errno. + return mlibc::sys_fadvise(fd, offset, length, advice); +} + +int posix_fallocate(int fd, off_t offset, off_t size) { + // posix_fallocate() returns an error instead of setting errno. + if(!mlibc::sys_fallocate) { + MLIBC_MISSING_SYSDEP(); + return ENOSYS; + } + return mlibc::sys_fallocate(fd, offset, size); +} + +// This is a linux extension +int name_to_handle_at(int, const char *, struct file_handle *, int *, int) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +int open_by_handle_at(int, struct file_handle *, int) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +ssize_t splice(int, off_t *, int, off_t *, size_t, unsigned int) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +ssize_t vmsplice(int, const struct iovec *, size_t, unsigned int) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +int open(const char *pathname, int flags, ...) { + mode_t mode = 0; + + if ((flags & O_CREAT) || (flags & O_TMPFILE)) { + va_list args; + va_start(args, flags); + mode = va_arg(args, mode_t); + va_end(args); + } + + int fd; + if(int e = mlibc::sys_open(pathname, flags, mode, &fd); e) { + errno = e; + return -1; + } + return fd; +} + diff --git a/lib/mlibc/options/posix/generic/ftw-stubs.cpp b/lib/mlibc/options/posix/generic/ftw-stubs.cpp new file mode 100644 index 0000000..2d93995 --- /dev/null +++ b/lib/mlibc/options/posix/generic/ftw-stubs.cpp @@ -0,0 +1,18 @@ + +#include + +#include + +int ftw(const char *, int (*fn)(const char *, const struct stat *, int), int) { + (void)fn; + __ensure(!"ftw() not implemented"); + __builtin_unreachable(); +} + +int nftw(const char *, int (*fn)(const char *, const struct stat *, int, struct FTW *), + int, int) { + (void)fn; + __ensure(!"nftw() not implemented"); + __builtin_unreachable(); +} + diff --git a/lib/mlibc/options/posix/generic/grp-stubs.cpp b/lib/mlibc/options/posix/generic/grp-stubs.cpp new file mode 100644 index 0000000..f8b2813 --- /dev/null +++ b/lib/mlibc/options/posix/generic/grp-stubs.cpp @@ -0,0 +1,316 @@ + +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace { + FILE *global_file; + + bool open_global_file() { + if(!global_file) { + global_file = fopen("/etc/group", "r"); + if(!global_file) { + errno = EIO; + return false; + } + } + + return true; + } + + void close_global_file() { + if(global_file) { + fclose(global_file); + global_file = nullptr; + } + } + + template + void walk_segments(frg::string_view line, char delimiter, F fn) { + size_t s = 0; + while(true) { + size_t d = line.find_first(delimiter, s); + if(d == size_t(-1)) + break; + auto chunk = line.sub_string(s, d - s); + fn(chunk); + s = d + 1; + } + if(line[s]) { + auto chunk = line.sub_string(s, line.size() - s); + + if (chunk.size() > 0) { + // Remove trailing newline + if (chunk[chunk.size() - 1] == '\n') + chunk = chunk.sub_string(0, chunk.size() - 1); + + fn(chunk); + } + } + } + + bool extract_entry(frg::string_view line, group *entry) { + frg::string_view segments[5]; + + // Parse the line into 3 or 4 segments (depending if the group has members or not) + int n = 0; + walk_segments(line, ':', [&] (frg::string_view s) { + __ensure(n < 4); + segments[n++] = s; + }); + + if(n < 3) // n can be 3 when there are no members in the group + return false; + + // TODO: Handle strndup() and malloc() failure. + auto name = strndup(segments[0].data(), segments[0].size()); + __ensure(name); + + auto passwd = strndup(segments[1].data(), segments[1].size()); + + auto gid = segments[2].to_number(); + if(!gid) + return false; + + size_t n_members = 0; + walk_segments(segments[3], ',', [&] (frg::string_view) { + n_members++; + }); + + auto members = reinterpret_cast(malloc(sizeof(char *) * (n_members + 1))); + __ensure(members); + size_t k = 0; + walk_segments(segments[3], ',', [&] (frg::string_view m) { + members[k] = strndup(m.data(), m.size()); + __ensure(members[k]); + k++; + }); + members[k] = nullptr; + + entry->gr_name = name; + entry->gr_passwd = passwd; + entry->gr_gid = *gid; + entry->gr_mem = members; + return true; + } + + void clear_entry(group *entry) { + free(entry->gr_name); + if(entry->gr_mem) { + for(size_t i = 0; entry->gr_mem[i]; i++) + free(entry->gr_mem[i]); + free(entry->gr_mem); + } + entry->gr_name = nullptr; + entry->gr_mem = nullptr; + } + + template + int walk_file(struct group *entry, C cond) { + auto file = fopen("/etc/group", "r"); + if(!file) { + return EIO; + } + + char line[512]; + while(fgets(line, 512, file)) { + if(!extract_entry(line, entry)) + continue; + if(cond(entry)) { + fclose(file); + return 0; + } + } + + int err = ESRCH; + if(ferror(file)) { + err = EIO; + } + + fclose(file); + return err; + } + + int copy_to_buffer(struct group *grp, char *buffer, size_t size) { + // Adjust to correct alignment so that we can put gr_mem first in buffer + uintptr_t mask = sizeof(char *) - 1; + size_t offset = (reinterpret_cast(buffer) % sizeof(char *) + mask) & ~mask; + if (size < offset) + return ERANGE; + + buffer += offset; + size -= offset; + + // Calculate the amount of space we need + size_t nmemb, required_size = 0; + for (nmemb = 0; grp->gr_mem[nmemb] != nullptr; nmemb++) { + // One for the string's null terminator and one for the pointer in gr_mem + required_size += strlen(grp->gr_mem[nmemb]) + 1 + sizeof(char *); + } + + // One for null terminator of gr_name, plus sizeof(char *) for nullptr terminator of gr_mem + required_size += strlen(grp->gr_name) + 1 + sizeof(char *); + if (size < required_size) + return ERANGE; + + // Put the gr_mem array first in the buffer as we are guaranteed + // that the pointer is aligned correctly + char *string_data = buffer + (nmemb + 1) * sizeof(char *); + + for (size_t i = 0; i < nmemb; i++) { + reinterpret_cast(buffer)[i] = string_data; + string_data = stpcpy(string_data, grp->gr_mem[i]) + 1; + free(grp->gr_mem[i]); + } + + reinterpret_cast(buffer)[nmemb] = nullptr; + free(grp->gr_mem); + grp->gr_mem = reinterpret_cast(buffer); + + char *gr_name = stpcpy(string_data, grp->gr_name) + 1; + free(grp->gr_name); + grp->gr_name = string_data; + + __ensure(gr_name <= buffer + size); + return 0; + } +} + +void endgrent(void) { + close_global_file(); +} + +struct group *getgrent(void) { + static group entry; + char line[512]; + + if(!open_global_file()) { + return nullptr; + } + + if(fgets(line, 512, global_file)) { + clear_entry(&entry); + if(!extract_entry(line, &entry)) { + errno = EINVAL; + return nullptr; + } + return &entry; + } + + if(ferror(global_file)) { + errno = EIO; + } + + return nullptr; +} + +struct group *getgrgid(gid_t gid) { + static group entry; + + int err = walk_file(&entry, [&] (group *entry) { + return entry->gr_gid == gid; + }); + + if (err) { + errno = err; + return nullptr; + } + + return &entry; +} + +int getgrgid_r(gid_t gid, struct group *grp, char *buffer, size_t size, struct group **result) { + *result = nullptr; + int err = walk_file(grp, [&] (group *entry) { + return entry->gr_gid == gid; + }); + + if (err) { + return err; + } + + err = copy_to_buffer(grp, buffer, size); + if (err) { + return err; + } + + *result = grp; + return 0; +} + +struct group *getgrnam(const char *name) { + static group entry; + + int err = walk_file(&entry, [&] (group *entry) { + return !strcmp(entry->gr_name, name); + }); + + if (err) { + errno = err; + return nullptr; + } + + return &entry; +} + +int getgrnam_r(const char *name, struct group *grp, char *buffer, size_t size, struct group **result) { + *result = nullptr; + + int err = walk_file(grp, [&] (group *entry) { + return !strcmp(entry->gr_name, name); + }); + + if (err) { + return err; + } + + err = copy_to_buffer(grp, buffer, size); + if (err) { + return err; + } + + *result = grp; + return 0; +} + +void setgrent(void) { + if(!open_global_file()) { + return; + } + rewind(global_file); +} + +int setgroups(size_t size, const gid_t *list) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_setgroups, -1); + if(int e = mlibc::sys_setgroups(size, list); e) { + errno = e; + return -1; + } + return 0; +} + +int initgroups(const char *, gid_t) { + mlibc::infoLogger() << "mlibc: initgroups is a stub" << frg::endlog; + return 0; +} + +int putgrent(const struct group *, FILE *) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +struct group *fgetgrent(FILE *) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +int getgrouplist(const char *, gid_t, gid_t *, int *) { + mlibc::infoLogger() << "mlibc: getgrouplist is a stub" << frg::endlog; + return 0; +} diff --git a/lib/mlibc/options/posix/generic/langinfo-stubs.cpp b/lib/mlibc/options/posix/generic/langinfo-stubs.cpp new file mode 100644 index 0000000..b239cbd --- /dev/null +++ b/lib/mlibc/options/posix/generic/langinfo-stubs.cpp @@ -0,0 +1,15 @@ + +#include +#include +#include +#include + +char *nl_langinfo(nl_item item) { + return mlibc::nl_langinfo(item); +} + +char *nl_langinfo_l(nl_item, locale_t) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + diff --git a/lib/mlibc/options/posix/generic/libgen-stubs.cpp b/lib/mlibc/options/posix/generic/libgen-stubs.cpp new file mode 100644 index 0000000..ff80349 --- /dev/null +++ b/lib/mlibc/options/posix/generic/libgen-stubs.cpp @@ -0,0 +1,51 @@ + +#include +#include +#include + +#include + +// Adopted from musl's code. +char *basename(char *s) { + // This empty string behavior is specified by POSIX. + if (!s || !*s) + return const_cast("."); + + // Delete trailing slashes. + // Note that we do not delete the slash at index zero. + auto i = strlen(s) - 1; + for(; i && s[i] == '/'; i--) + s[i] = 0; + + // Find the last non-trailing slash. + for(; i && s[i - 1] != '/'; i--) + ; + return s + i; +} + +char *dirname(char *s) { + if (!s || !(*s)) + return const_cast("."); + + auto i = strlen(s) - 1; + + // Skip trailing slashes. + for (; s[i] == '/'; i--) + if(!i) // Path only consists of slashes. + return const_cast("/"); + + // Skip the last non-slash path component. + for (; s[i] != '/'; i--) + if(!i) // Path only contains a single component. + return const_cast("."); + + // Skip slashes. + for (; s[i] == '/'; i--) + if(!i) // Path is entry in root directory. + return const_cast("/"); + + s[i+1] = 0; + + return s; +} + diff --git a/lib/mlibc/options/posix/generic/lookup.cpp b/lib/mlibc/options/posix/generic/lookup.cpp new file mode 100644 index 0000000..f877fe5 --- /dev/null +++ b/lib/mlibc/options/posix/generic/lookup.cpp @@ -0,0 +1,512 @@ +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace mlibc { + +namespace { + constexpr unsigned int RECORD_A = 1; + constexpr unsigned int RECORD_CNAME = 5; + constexpr unsigned int RECORD_PTR = 12; +} + +static frg::string read_dns_name(char *buf, char *&it) { + frg::string res{getAllocator()}; + while (true) { + char code = *it++; + if ((code & 0xC0) == 0xC0) { + // pointer + uint8_t offset = ((code & 0x3F) << 8) | *it++; + auto offset_it = buf + offset; + return res + read_dns_name(buf, offset_it); + } else if (!(code & 0xC0)) { + if (!code) + break; + + for (int i = 0; i < code; i++) + res += (*it++); + + if (*it) + res += '.'; + } else { + break; + } + } + + return res; +} + +int lookup_name_dns(struct lookup_result &buf, const char *name, + frg::string &canon_name) { + frg::string request{getAllocator()}; + + int num_q = 1; + struct dns_header header; + header.identification = htons(123); + header.flags = htons(0x100); + header.no_q = htons(num_q); + header.no_ans = htons(0); + header.no_auths = htons(0); + header.no_additional = htons(0); + + request.resize(sizeof(header)); + memcpy(request.data(), &header, sizeof(header)); + + const char *end = name; + while (*end != '\0') { + end = strchrnul(name, '.'); + size_t length = end - name; + frg::string_view substring{name, length}; + name += length + 1; + request += char(length); + request += substring; + } + + request += char(0); + // set question type to fetch A records + request += 0; + request += 1; + // set CLASS to IN + request += 0; + request += 1; + + struct sockaddr_in sin = {}; + sin.sin_family = AF_INET; + // TODO(geert): we could probably make this use the service lookup + // for dns + sin.sin_port = htons(53); + + auto nameserver = get_nameserver(); + if (!inet_aton(nameserver ? nameserver->name.data() : "127.0.0.1", &sin.sin_addr)) { + mlibc::infoLogger() << "lookup_name_dns(): inet_aton() failed!" << frg::endlog; + return -EAI_SYSTEM; + } + + int fd = socket(AF_INET, SOCK_DGRAM, 0); + if (fd < 0) { + mlibc::infoLogger() << "lookup_name_dns(): socket() failed" << frg::endlog; + return -EAI_SYSTEM; + } + + size_t sent = sendto(fd, request.data(), request.size(), 0, + (struct sockaddr*)&sin, sizeof(sin)); + if (sent != request.size()) { + mlibc::infoLogger() << "lookup_name_dns(): sendto() failed to send everything" << frg::endlog; + return -EAI_SYSTEM; + } + + char response[256]; + ssize_t rlen; + int num_ans = 0; + while ((rlen = recvfrom(fd, response, 256, 0, NULL, NULL)) >= 0) { + if ((size_t)rlen < sizeof(struct dns_header)) + continue; + auto response_header = reinterpret_cast(response); + if (response_header->identification != header.identification) + return -EAI_FAIL; + + auto it = response + sizeof(struct dns_header); + for (int i = 0; i < ntohs(response_header->no_q); i++) { + auto dns_name = read_dns_name(response, it); + (void) dns_name; + it += 4; + } + + for (int i = 0; i < ntohs(response_header->no_ans); i++) { + struct dns_addr_buf buffer; + auto dns_name = read_dns_name(response, it); + + uint16_t rr_type = (it[0] << 8) | it[1]; + uint16_t rr_class = (it[2] << 8) | it[3]; + uint16_t rr_length = (it[8] << 8) | it[9]; + it += 10; + (void)rr_class; + + switch (rr_type) { + case RECORD_A: + memcpy(buffer.addr, it, rr_length); + it += rr_length; + buffer.family = AF_INET; + buffer.name = std::move(dns_name); + buf.buf.push(std::move(buffer)); + break; + case RECORD_CNAME: + canon_name = read_dns_name(response, it); + buf.aliases.push(std::move(dns_name)); + break; + default: + mlibc::infoLogger() << "lookup_name_dns: unknown rr type " + << rr_type << frg::endlog; + break; + } + } + num_ans += ntohs(response_header->no_ans); + + if (num_ans >= num_q) + break; + } + + close(fd); + return buf.buf.size(); +} + +int lookup_addr_dns(frg::span name, frg::array &addr, int family) { + frg::string request{getAllocator()}; + + int num_q = 1; + struct dns_header header; + header.identification = htons(123); + header.flags = htons(0x100); + header.no_q = htons(num_q); + header.no_ans = htons(0); + header.no_auths = htons(0); + header.no_additional = htons(0); + + request.resize(sizeof(header)); + memcpy(request.data(), &header, sizeof(header)); + + char addr_str[64]; + if(!inet_ntop(family, addr.data(), addr_str, sizeof(addr_str))) { + switch(errno) { + case EAFNOSUPPORT: + return -EAI_FAMILY; + case ENOSPC: + return -EAI_OVERFLOW; + default: + return -EAI_FAIL; + } + } + frg::string req_str{getAllocator(), addr_str}; + req_str += ".in-addr.arpa"; + + frg::string_view req_view{req_str.data(), req_str.size()}; + size_t ptr = 0; + do { + size_t next = req_view.find_first('.', ptr); + size_t length = next != (size_t)-1 ? next - ptr : req_view.size() - ptr; + frg::string_view substring = req_view.sub_string(ptr, length); + request += char(length); + request += substring; + ptr = next + 1; + } while(ptr != 0); + + request += char(0); + // set question type to fetch PTR records + request += 0; + request += 12; + // set CLASS to IN + request += 0; + request += 1; + + + struct sockaddr_in sin = {}; + sin.sin_family = AF_INET; + // TODO(geert): we could probably make this use the service lookup + // for dns + sin.sin_port = htons(53); + + auto nameserver = get_nameserver(); + if (!inet_aton(nameserver ? nameserver->name.data() : "127.0.0.1", &sin.sin_addr)) { + mlibc::infoLogger() << "lookup_name_dns(): inet_aton() failed!" << frg::endlog; + return -EAI_SYSTEM; + } + + int fd = socket(AF_INET, SOCK_DGRAM, 0); + if (fd < 0) { + mlibc::infoLogger() << "lookup_name_dns(): socket() failed" << frg::endlog; + return -EAI_SYSTEM; + } + + size_t sent = sendto(fd, request.data(), request.size(), 0, + (struct sockaddr*)&sin, sizeof(sin)); + if (sent != request.size()) { + mlibc::infoLogger() << "lookup_name_dns(): sendto() failed to send everything" << frg::endlog; + return -EAI_SYSTEM; + } + + char response[256]; + ssize_t rlen; + int num_ans = 0; + while ((rlen = recvfrom(fd, response, 256, 0, NULL, NULL)) >= 0) { + if ((size_t)rlen < sizeof(struct dns_header)) + continue; + auto response_header = reinterpret_cast(response); + if (response_header->identification != header.identification) + return -EAI_FAIL; + + auto it = response + sizeof(struct dns_header); + for (int i = 0; i < ntohs(response_header->no_q); i++) { + auto dns_name = read_dns_name(response, it); + (void) dns_name; + it += 4; + } + + for (int i = 0; i < ntohs(response_header->no_ans); i++) { + struct dns_addr_buf buffer; + auto dns_name = read_dns_name(response, it); + + uint16_t rr_type = (it[0] << 8) | it[1]; + uint16_t rr_class = (it[2] << 8) | it[3]; + uint16_t rr_length = (it[8] << 8) | it[9]; + it += 10; + (void)rr_class; + (void)rr_length; + + (void)dns_name; + + switch (rr_type) { + case RECORD_PTR: { + auto ptr_name = read_dns_name(response, it); + if (ptr_name.size() >= name.size()) + return -EAI_OVERFLOW; + std::copy(ptr_name.begin(), ptr_name.end(), name.data()); + name.data()[ptr_name.size()] = '\0'; + return 1; + } + default: + mlibc::infoLogger() << "lookup_addr_dns: unknown rr type " + << rr_type << frg::endlog; + break; + } + num_ans += ntohs(response_header->no_ans); + + if (num_ans >= num_q) + break; + } + } + + close(fd); + return 0; +} + +int lookup_name_hosts(struct lookup_result &buf, const char *name, + frg::string &canon_name) { + auto file = fopen("/etc/hosts", "r"); + if (!file) { + switch (errno) { + case ENOENT: + case ENOTDIR: + case EACCES: + return -EAI_SERVICE; + default: + return -EAI_SYSTEM; + } + } + + char line[128]; + int name_length = strlen(name); + while (fgets(line, 128, file)) { + char *pos; + // same way to deal with comments as in services.cpp + if ((pos = strchr(line, '#'))) { + *pos++ = '\n'; + *pos = '\0'; + } + + for(pos = line + 1; (pos = strstr(pos, name)) && + (!isspace(pos[-1]) || !isspace(pos[name_length])); pos++); + if (!pos) + continue; + + for (pos = line; !isspace(*pos); pos++); + *pos = '\0'; + + // TODO(geert): we assume ipv4 for now + struct in_addr addr; + if (!inet_aton(line, &addr)) + continue; + + pos++; + for(; *pos && isspace(*pos); pos++); + char *end; + for(end = pos; *end && !isspace(*end); end++); + + struct dns_addr_buf buffer; + memcpy(buffer.addr, &addr, 4); + buffer.family = AF_INET; + buffer.name = frg::string{pos, + static_cast(end - pos), getAllocator()}; + canon_name = buffer.name; + + buf.buf.push(std::move(buffer)); + + pos = end; + while (pos[1]) { + for (; *pos && isspace(*pos); pos++); + for (end = pos; *end && !isspace(*end); end++); + auto name = frg::string{pos, + static_cast(end - pos), getAllocator()}; + buf.aliases.push(std::move(name)); + pos = end; + } + } + + fclose(file); + return buf.buf.size(); +} + +int lookup_addr_hosts(frg::span name, frg::array &addr, int family) { + auto file = fopen("/etc/hosts", "r"); + if (!file) { + switch (errno) { + case ENOENT: + case ENOTDIR: + case EACCES: + return -EAI_SERVICE; + default: + return -EAI_SYSTEM; + } + } + + // Buffer to hold ASCII version of address + char addr_str[64]; + if(!inet_ntop(family, addr.data(), addr_str, sizeof(addr_str))) { + switch(errno) { + case EAFNOSUPPORT: + return -EAI_FAMILY; + case ENOSPC: + return -EAI_OVERFLOW; + default: + return -EAI_FAIL; + } + } + int addr_str_len = strlen(addr_str); + + char line[128]; + while (fgets(line, 128, file)) { + char *pos; + // same way to deal with comments as in services.cpp + if ((pos = strchr(line, '#'))) { + *pos++ = '\n'; + *pos = '\0'; + } + if (strncmp(line, addr_str, addr_str_len)) + continue; + + for (pos = line + addr_str_len + 1; isspace(*pos); pos++); + char *begin = pos; + for (; !isspace(*pos); pos++); + char *end = pos; + + size_t size = end - begin; + if (size >= name.size()) + return -EAI_OVERFLOW; + std::copy(begin, end, name.data()); + name.data()[size] = '\0'; + return 1; + } + return 0; +} + +int lookup_name_null(struct lookup_result &buf, int flags, int family) { + if (flags & AI_PASSIVE) { + if (family != AF_INET6) { + struct dns_addr_buf addr_buf; + addr_buf.family = AF_INET; + + in_addr_t addr = INADDR_ANY; + memcpy(&addr_buf.addr, &addr, 4); + + buf.buf.push_back(addr_buf); + } + if (family != AF_INET) { + struct dns_addr_buf addr_buf; + addr_buf.family = AF_INET6; + + struct in6_addr addr = IN6ADDR_ANY_INIT; + memcpy(&addr_buf.addr, &addr, 16); + + buf.buf.push_back(addr_buf); + } + } else { + if (family != AF_INET6) { + struct dns_addr_buf addr_buf; + addr_buf.family = AF_INET; + + in_addr_t addr = INADDR_LOOPBACK; + memcpy(&addr_buf.addr, &addr, 4); + + buf.buf.push_back(addr_buf); + } + if (family != AF_INET) { + struct dns_addr_buf addr_buf; + addr_buf.family = AF_INET6; + + struct in6_addr addr = IN6ADDR_LOOPBACK_INIT; + memcpy(&addr_buf.addr, &addr, 16); + + buf.buf.push_back(addr_buf); + } + } + return buf.buf.size(); +} + +int lookup_name_ip(struct lookup_result &buf, const char *name, int family) { + if (family == AF_INET) { + in_addr_t addr = 0; + int res = inet_pton(AF_INET, name, &addr); + + if (res <= 0) + return -EAI_NONAME; + + struct dns_addr_buf addr_buf; + addr_buf.family = AF_INET; + memcpy(&addr_buf.addr, &addr, 4); + + buf.buf.push_back(addr_buf); + return 1; + } + + if (family == AF_INET6) { + struct in6_addr addr{0}; + int res = inet_pton(AF_INET6, name, &addr); + + if (res <= 0) + return -EAI_NONAME; + + struct dns_addr_buf addr_buf; + addr_buf.family = AF_INET6; + memcpy(&addr_buf.addr, &addr, 16); + + buf.buf.push_back(addr_buf); + return 1; + } + + // If no family was specified we try ipv4 and then ipv6. + in_addr_t addr4 = 0; + int res = inet_pton(AF_INET, name, &addr4); + + if (res > 0) { + struct dns_addr_buf addr_buf; + addr_buf.family = AF_INET; + memcpy(&addr_buf.addr, &addr4, 4); + + buf.buf.push_back(addr_buf); + return 1; + } + + struct in6_addr addr6{0}; + res = inet_pton(AF_INET6, name, &addr6); + + if (res <= 0) + return -EAI_NONAME; + + struct dns_addr_buf addr_buf; + addr_buf.family = AF_INET6; + memcpy(&addr_buf.addr, &addr6, 16); + + buf.buf.push_back(addr_buf); + return 1; +} + +} // namespace mlibc diff --git a/lib/mlibc/options/posix/generic/mqueue.cpp b/lib/mlibc/options/posix/generic/mqueue.cpp new file mode 100644 index 0000000..d635419 --- /dev/null +++ b/lib/mlibc/options/posix/generic/mqueue.cpp @@ -0,0 +1,22 @@ +#include +#include + +int mq_getattr(mqd_t, struct mq_attr *) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +int mq_setattr(mqd_t, const struct mq_attr *__restrict__, struct mq_attr *__restrict__) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +int mq_unlink(const char *) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +mqd_t mq_open(const char *, int, ...) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} diff --git a/lib/mlibc/options/posix/generic/net-if-stubs.cpp b/lib/mlibc/options/posix/generic/net-if-stubs.cpp new file mode 100644 index 0000000..6a65a5c --- /dev/null +++ b/lib/mlibc/options/posix/generic/net-if-stubs.cpp @@ -0,0 +1,40 @@ +#include +#include +#include + +#include +#include +#include + +void if_freenameindex(struct if_nameindex *) { + mlibc::infoLogger() << "mlibc: if_freenameindex is a no-op" << frg::endlog; +} + +char *if_indextoname(unsigned int index, char *name) { + auto sysdep = MLIBC_CHECK_OR_ENOSYS(mlibc::sys_if_indextoname, NULL); + + if(int e = sysdep(index, name); e) { + errno = e; + return NULL; + } + + return name; +} + +struct if_nameindex *if_nameindex(void) { + mlibc::infoLogger() << "mlibc: if_nameindex() is a no-op" << frg::endlog; + errno = ENOSYS; + return NULL; +} + +unsigned int if_nametoindex(const char *name) { + auto sysdep = MLIBC_CHECK_OR_ENOSYS(mlibc::sys_if_nametoindex, 0); + unsigned int ret = 0; + + if(int e = sysdep(name, &ret); e) { + errno = e; + return 0; + } + + return ret; +} diff --git a/lib/mlibc/options/posix/generic/netdb-stubs.cpp b/lib/mlibc/options/posix/generic/netdb-stubs.cpp new file mode 100644 index 0000000..455444b --- /dev/null +++ b/lib/mlibc/options/posix/generic/netdb-stubs.cpp @@ -0,0 +1,486 @@ +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +__thread int __mlibc_h_errno; + +// This function is from musl +int *__h_errno_location(void) { + return &__mlibc_h_errno; +} + +void endhostent(void) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +void endnetent(void) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +void endprotoent(void) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +void endservent(void) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +void freeaddrinfo(struct addrinfo *ptr) { + if (ptr) { + auto buf = (struct mlibc::ai_buf*) ptr - offsetof(struct mlibc::ai_buf, ai); + // this string was allocated by a frg::string + getAllocator().free(ptr->ai_canonname); + free(buf); + } +} + +const char *gai_strerror(int code) { + static thread_local char buffer[128]; + snprintf(buffer, sizeof(buffer), "Unknown error (%d)", code); + return buffer; +} + +int getaddrinfo(const char *__restrict node, const char *__restrict service, + const struct addrinfo *__restrict hints, struct addrinfo **__restrict res) { + if (!node && !service) + return EAI_NONAME; + + int socktype = 0, protocol = 0, family = AF_UNSPEC, flags = AI_V4MAPPED | AI_ADDRCONFIG; + if (hints) { + socktype = hints->ai_socktype; + protocol = hints->ai_protocol; + family = hints->ai_family; + flags = hints->ai_flags; + + int mask = AI_V4MAPPED | AI_ADDRCONFIG | AI_NUMERICHOST | AI_PASSIVE | + AI_CANONNAME | AI_ALL | AI_NUMERICSERV; + if ((flags & mask) != flags) + return EAI_BADFLAGS; + + if (family != AF_INET && family != AF_INET6 && family != AF_UNSPEC) + return EAI_FAMILY; + } + + mlibc::service_result serv_buf{getAllocator()}; + int serv_count = mlibc::lookup_serv_by_name(serv_buf, service, protocol, socktype, flags); + if (serv_count < 0) + return -serv_count; + + struct mlibc::lookup_result addr_buf; + int addr_count = 1; + frg::string canon{getAllocator()}; + if (node) { + if ((addr_count = mlibc::lookup_name_ip(addr_buf, node, family)) <= 0) { + if (flags & AI_NUMERICHOST) + addr_count = -EAI_NONAME; + else if ((addr_count = mlibc::lookup_name_hosts(addr_buf, node, canon)) <= 0) + addr_count = mlibc::lookup_name_dns(addr_buf, node, canon); + else + addr_count = 1; + } + + if (addr_count < 0) + return -addr_count; + if (!addr_count) + return EAI_NONAME; + } else { + /* There is no node specified */ + if (flags & AI_NUMERICHOST) + return EAI_NONAME; + addr_count = lookup_name_null(addr_buf, flags, family); + } + + auto out = (struct mlibc::ai_buf *) calloc(serv_count * addr_count, + sizeof(struct mlibc::ai_buf)); + + if (node && !canon.size()) + canon = frg::string{node, getAllocator()}; + + for (int i = 0, k = 0; i < addr_count; i++) { + for (int j = 0; j < serv_count; j++, k++) { + out[i].ai.ai_family = addr_buf.buf[i].family; + out[i].ai.ai_socktype = serv_buf[j].socktype; + out[i].ai.ai_protocol = serv_buf[j].protocol; + out[i].ai.ai_flags = flags; + out[i].ai.ai_addr = (struct sockaddr *) &out[i].sa; + if (canon.size()) + out[i].ai.ai_canonname = canon.data(); + else + out[i].ai.ai_canonname = NULL; + out[i].ai.ai_next = NULL; + switch (addr_buf.buf[i].family) { + case AF_INET: + out[i].ai.ai_addrlen = sizeof(struct sockaddr_in); + out[i].sa.sin.sin_port = htons(serv_buf[j].port); + out[i].sa.sin.sin_family = AF_INET; + memcpy(&out[i].sa.sin.sin_addr, addr_buf.buf[i].addr, 4); + break; + case AF_INET6: + out[i].ai.ai_addrlen = sizeof(struct sockaddr_in6); + out[i].sa.sin6.sin6_family = htons(serv_buf[j].port); + out[i].sa.sin6.sin6_family = AF_INET6; + memcpy(&out[i].sa.sin6.sin6_addr, addr_buf.buf[i].addr, 16); + break; + } + } + } + if (canon.size()) + canon.detach(); + + *res = &out[0].ai; + return 0; +} + +struct hostent *gethostent(void) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +int getnameinfo(const struct sockaddr *__restrict addr, socklen_t addr_len, + char *__restrict host, socklen_t host_len, char *__restrict serv, + socklen_t serv_len, int flags) { + frg::array addr_array; + int family = addr->sa_family; + + switch(family) { + case AF_INET: { + if (addr_len < sizeof(struct sockaddr_in)) + return EAI_FAMILY; + auto sockaddr = reinterpret_cast(addr); + memcpy(addr_array.data(), reinterpret_cast(&sockaddr->sin_addr), 4); + break; + } + case AF_INET6: { + mlibc::infoLogger() << "getnameinfo(): ipv6 is not fully supported in this function" << frg::endlog; + if (addr_len < sizeof(struct sockaddr_in6)) + return EAI_FAMILY; + auto sockaddr = reinterpret_cast(addr); + memcpy(addr_array.data(), reinterpret_cast(&sockaddr->sin6_addr), 16); + break; + } + default: + return EAI_FAMILY; + } + + if (host && host_len) { + frg::span host_span{host, host_len}; + int res = 0; + if (!(flags & NI_NUMERICHOST)) + res = mlibc::lookup_addr_hosts(host_span, addr_array, family); + if (!(flags & NI_NUMERICHOST) && !res) + res = mlibc::lookup_addr_dns(host_span, addr_array, family); + + if (!res) { + if (flags & NI_NAMEREQD) + return EAI_NONAME; + if(!inet_ntop(family, addr_array.data(), host, host_len)) { + switch(errno) { + case EAFNOSUPPORT: + return EAI_FAMILY; + case ENOSPC: + return EAI_OVERFLOW; + default: + return EAI_FAIL; + } + } + } + + if (res < 0) + return -res; + } + + if (serv && serv_len) { + __ensure("getnameinfo(): not implemented service resolution yet!"); + __builtin_unreachable(); + } + + return 0; +} + +struct netent *getnetbyaddr(uint32_t, int) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +struct netent *getnetbyname(const char *) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +struct netent *getnetent(void) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +struct hostent *gethostbyname(const char *name) { + if (!name) { + h_errno = HOST_NOT_FOUND; + return NULL; + } + + struct mlibc::lookup_result buf; + frg::string canon{getAllocator()}; + int ret = 0; + if ((ret = mlibc::lookup_name_hosts(buf, name, canon)) <= 0) + ret = mlibc::lookup_name_dns(buf, name, canon); + if (ret <= 0) { + h_errno = HOST_NOT_FOUND; + return NULL; + } + + static struct hostent h; + if (h.h_name) { + getAllocator().free(h.h_name); + for (int i = 0; h.h_aliases[i] != NULL; i++) + getAllocator().free(h.h_aliases[i]); + free(h.h_aliases); + + if (h.h_addr_list) { + for (int i = 0; h.h_addr_list[i] != NULL; i++) + free(h.h_addr_list[i]); + free(h.h_addr_list); + } + } + h = {}; + + if (!canon.size()) + canon = frg::string{name, getAllocator()}; + + h.h_name = canon.data(); + + h.h_aliases = reinterpret_cast(malloc((buf.aliases.size() + 1) + * sizeof(char*))); + int alias_pos = 0; + for (auto &buf_name : buf.aliases) { + h.h_aliases[alias_pos] = buf_name.data(); + buf_name.detach(); + alias_pos++; + } + h.h_aliases[alias_pos] = NULL; + canon.detach(); + + // just pick the first family as the one for all addresses...?? + h.h_addrtype = buf.buf[0].family; + if (h.h_addrtype != AF_INET && h.h_addrtype != AF_INET6) { + // this is not allowed per spec + h_errno = NO_DATA; + return NULL; + } + + // can only be AF_INET or AF_INET6 + h.h_length = h.h_addrtype == AF_INET ? 4 : 16; + h.h_addr_list = reinterpret_cast(malloc((ret + 1) * sizeof(char*))); + int addr_pos = 0; + for (int i = 0; i < ret; i++) { + if (buf.buf[i].family != h.h_addrtype) + continue; + h.h_addr_list[addr_pos] = reinterpret_cast(malloc(h.h_length)); + memcpy(h.h_addr_list[addr_pos], buf.buf[i].addr, h.h_length); + addr_pos++; + } + h.h_addr_list[addr_pos] = NULL; + + return &h; +} + +struct hostent *gethostbyname2(const char *, int) { + __ensure(!"gethostbyname2() not implemented"); + __builtin_unreachable(); +} + +struct hostent *gethostbyaddr(const void *, socklen_t, int) { + __ensure(!"gethostbyaddr() not implemented"); + __builtin_unreachable(); +} + +int gethostbyaddr_r(const void *__restrict, socklen_t, int, struct hostent *__restrict, + char *__restrict, size_t, struct hostent **__restrict, int *__restrict) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +int gethostbyname_r(const char *__restrict, struct hostent *__restrict, char *__restrict, size_t, + struct hostent **__restrict, int *__restrict) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +struct protoent *getprotobyname(const char *) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +struct protoent *getprotobynumber(int) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +struct protoent *getprotoent(void) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +struct servent *getservbyname(const char *name, const char *proto) { + int iproto = -1; + if (proto &&(!strncmp(proto, "tcp", 3) || !strncmp(proto, "TCP", 3))) + iproto = IPPROTO_TCP; + else if (proto && (!strncmp(proto, "udp", 3) || !strncmp(proto, "UDP", 3))) + iproto = IPPROTO_UDP; + + static struct servent ret; + if (ret.s_name) { + free(ret.s_name); + ret.s_name = nullptr; + + for (char **alias = ret.s_aliases; *alias != NULL; alias++) { + free(*alias); + *alias = nullptr; + } + + free(ret.s_proto); + ret.s_proto = nullptr; + } + + mlibc::service_result serv_buf{getAllocator()}; + int count = mlibc::lookup_serv_by_name(serv_buf, name, iproto, + 0, 0); + if (count <= 0) + return NULL; + + ret.s_name = serv_buf[0].name.data(); + serv_buf[0].name.detach(); + // Sanity check. + if (strncmp(name, serv_buf[0].name.data(), serv_buf[0].name.size())) + return NULL; + + ret.s_aliases = reinterpret_cast(malloc((serv_buf[0].aliases.size() + 1) * sizeof(char*))); + int alias_pos = 0; + for (auto &buf_name : serv_buf[0].aliases) { + ret.s_aliases[alias_pos] = buf_name.data(); + buf_name.detach(); + alias_pos++; + } + ret.s_aliases[alias_pos] = NULL; + + ret.s_port = htons(serv_buf[0].port); + + auto proto_string = frg::string(getAllocator()); + if (!proto) { + if (serv_buf[0].protocol == IPPROTO_TCP) + proto_string = frg::string("tcp", getAllocator()); + else if (serv_buf[0].protocol == IPPROTO_UDP) + proto_string = frg::string("udp", getAllocator()); + else + return NULL; + } else { + proto_string = frg::string(proto, getAllocator()); + } + ret.s_proto = proto_string.data(); + proto_string.detach(); + + return &ret; +} + +struct servent *getservbyport(int port, const char *proto) { + int iproto = -1; + if (proto && (!strncmp(proto, "tcp", 3) || !strncmp(proto, "TCP", 3))) + iproto = IPPROTO_TCP; + else if (proto && (!strncmp(proto, "udp", 3) || !strncmp(proto, "UDP", 3))) + iproto = IPPROTO_UDP; + + static struct servent ret; + if (ret.s_name) { + free(ret.s_name); + ret.s_name = nullptr; + + for (char **alias = ret.s_aliases; *alias != NULL; alias++) { + free(*alias); + *alias = nullptr; + } + + free(ret.s_proto); + ret.s_proto = nullptr; + } + + mlibc::service_result serv_buf{getAllocator()}; + int count = mlibc::lookup_serv_by_port(serv_buf, iproto, ntohs(port)); + if (count <= 0) + return NULL; + + ret.s_name = serv_buf[0].name.data(); + serv_buf[0].name.detach(); + + ret.s_aliases = reinterpret_cast(malloc((serv_buf[0].aliases.size() + 1) * sizeof(char*))); + int alias_pos = 0; + for (auto &buf_name : serv_buf[0].aliases) { + ret.s_aliases[alias_pos] = buf_name.data(); + buf_name.detach(); + alias_pos++; + } + ret.s_aliases[alias_pos] = NULL; + + ret.s_port = port; + + auto proto_string = frg::string(getAllocator()); + if (!proto) { + if (serv_buf[0].protocol == IPPROTO_TCP) + proto_string = frg::string("tcp", getAllocator()); + else if (serv_buf[0].protocol == IPPROTO_UDP) + proto_string = frg::string("udp", getAllocator()); + else + return NULL; + } else { + proto_string = frg::string(proto, getAllocator()); + } + ret.s_proto = proto_string.data(); + proto_string.detach(); + + return &ret; +} + +struct servent *getservent(void) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +void sethostent(int) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +void setnetent(int) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +void setprotoent(int) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +void setservent(int) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +const char *hstrerror(int) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} diff --git a/lib/mlibc/options/posix/generic/poll.cpp b/lib/mlibc/options/posix/generic/poll.cpp new file mode 100644 index 0000000..c34e25e --- /dev/null +++ b/lib/mlibc/options/posix/generic/poll.cpp @@ -0,0 +1,31 @@ + +#include +#include + +#include +#include +#include + +int poll(struct pollfd *fds, nfds_t count, int timeout) { + int num_events; + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_poll, -1); + if(int e = mlibc::sys_poll(fds, count, timeout, &num_events); e) { + errno = e; + return -1; + } + return num_events; +} + +#if __MLIBC_LINUX_OPTION +int ppoll(struct pollfd *fds, nfds_t nfds, const struct timespec *timeout_ts, const sigset_t *sigmask) { + sigset_t origmask; + int timeout = (timeout_ts == NULL) ? -1 : (timeout_ts->tv_sec * 1000 + timeout_ts->tv_nsec / 1000000); + + sigprocmask(SIG_SETMASK, sigmask, &origmask); + int ready = poll(fds, nfds, timeout); + sigprocmask(SIG_SETMASK, &origmask, NULL); + + return ready; +} +#endif // __MLIBC_LINUX_OPTION + diff --git a/lib/mlibc/options/posix/generic/posix-file-io.cpp b/lib/mlibc/options/posix/generic/posix-file-io.cpp new file mode 100644 index 0000000..1a4f38b --- /dev/null +++ b/lib/mlibc/options/posix/generic/posix-file-io.cpp @@ -0,0 +1,275 @@ +#include +#include +#include + +#include + +namespace mlibc { + +int mem_file::reopen(const char *, const char *) { + mlibc::panicLogger() << "mlibc: freopen() on a mem_file stream is unimplemented!" << frg::endlog; + return -1; +} + +int mem_file::determine_type(stream_type *type) { + *type = stream_type::file_like; + return 0; +} + +int mem_file::determine_bufmode(buffer_mode *mode) { + *mode = buffer_mode::no_buffer; + return 0; +} + +memstream_mem_file::memstream_mem_file(char **ptr, size_t *sizeloc, int flags, void (*do_dispose)(abstract_file *)) +: mem_file{flags, do_dispose}, _bufloc{ptr}, _sizeloc{sizeloc} { } + + +int memstream_mem_file::close() { + _update_ptrs(); + _buf.detach(); + + return 0; +} + +int memstream_mem_file::io_read(char *buffer, size_t max_size, size_t *actual_size) { + if ((_pos >= 0 && _pos >= _max_size) || !max_size) { + *actual_size = 0; + return 0; + } + + size_t bytes_read = std::min(size_t(_max_size - _pos), max_size); + memcpy(buffer, _buffer().data() + _pos, bytes_read); + _pos += bytes_read; + *actual_size = bytes_read; + return 0; +} + +int memstream_mem_file::io_write(const char *buffer, size_t max_size, size_t *actual_size) { + if (_pos + max_size >= _buffer_size()) { + _buf.resize(_pos + max_size + 1, '\0'); + _update_ptrs(); + } + + size_t bytes_write = std::min(static_cast(_buffer_size() - _pos), max_size); + memcpy(_buffer().data() + _pos, buffer, bytes_write); + _pos += max_size; + *actual_size = max_size; + + return 0; +} + +int memstream_mem_file::io_seek(off_t offset, int whence, off_t *new_offset) { + switch (whence) { + case SEEK_SET: + _pos = offset; + if (_pos >= 0 && size_t(_pos) >= _buffer_size()) { + _buf.resize(_pos + 1, '\0'); + _update_ptrs(); + } + *new_offset = _pos; + break; + case SEEK_CUR: + _pos += offset; + if (_pos >= 0 && size_t(_pos) >= _buffer_size()) { + _buf.resize(_pos + 1, '\0'); + _update_ptrs(); + } + *new_offset = _pos; + break; + case SEEK_END: + _pos = _buffer_size() ? _buffer_size() - 1 + offset : _buffer_size() + offset; + _buf.resize(_pos + 1, '\0'); + _update_ptrs(); + *new_offset = _pos; + break; + default: + return EINVAL; + } + return 0; +} + +void memstream_mem_file::_update_ptrs() { + *_bufloc = _buf.data(); + *_sizeloc = _buf.size() - 1; +} + +fmemopen_mem_file::fmemopen_mem_file(void *in_buf, size_t size, int flags, void (*do_dispose)(abstract_file *)) +: mem_file{flags, do_dispose}, _inBuffer{in_buf}, _inBufferSize{size} { + if(!_inBuffer) { + _inBuffer = getAllocator().allocate(size); + _needsDeallocation = true; + } + + if(_flags & O_APPEND) { + // the initial seek-size for append is zero if buf was NULL, or the first '\0' found, or the size + _max_size = (_needsDeallocation) ? 0 : strnlen(reinterpret_cast(_inBuffer), _inBufferSize); + _pos = _max_size; + } else if((_flags & O_WRONLY || _flags & O_RDWR) && _flags & O_CREAT && _flags & O_TRUNC) { + // modes: "w", "w+" + _max_size = 0; + } else { + _max_size = size; + } +} + +int fmemopen_mem_file::close() { + if(_needsDeallocation) { + getAllocator().free(_inBuffer); + } + + return 0; +} + +int fmemopen_mem_file::io_read(char *buffer, size_t max_size, size_t *actual_size) { + if ((_pos >= 0 && _pos >= _max_size) || !max_size) { + *actual_size = 0; + return 0; + } + + size_t bytes_read = std::min(size_t(_max_size - _pos), max_size); + memcpy(buffer, _buffer().data() + _pos, bytes_read); + _pos += bytes_read; + *actual_size = bytes_read; + return 0; +} + +int fmemopen_mem_file::io_write(const char *buffer, size_t max_size, size_t *actual_size) { + off_t bytes_write = std::min(static_cast(_buffer_size() - _pos), max_size); + memcpy(_buffer().data() + _pos, buffer, bytes_write); + _pos += bytes_write; + *actual_size = bytes_write; + + if(_pos > _max_size) { + _max_size = _pos; + } + + // upon flushing, we need to put a null byte at the current position or at the end of the buffer + size_t null = _pos; + // a special case is if the mode is set to updating ('+'), then it always goes at the end + if(null >= _buffer_size() || _flags & O_RDWR) { + null = _buffer_size() - 1; + } + + if(_buffer_size()) { + _buffer()[null] = '\0'; + } + + return 0; +} + +int fmemopen_mem_file::io_seek(off_t offset, int whence, off_t *new_offset) { + switch (whence) { + case SEEK_SET: + if(offset < 0 || size_t(offset) > _buffer_size()) { + return EINVAL; + } + _pos = offset; + *new_offset = _pos; + break; + case SEEK_CUR: + // seeking to negative positions or positions larger than the buffer is disallowed in fmemopen(3) + if((_pos + offset) < 0 || size_t(_pos + offset) > _buffer_size()) { + return EINVAL; + } + _pos += offset; + *new_offset = _pos; + break; + case SEEK_END: + if((_max_size + offset) < 0 || size_t(_max_size + offset) > _buffer_size()) { + return EINVAL; + } + _pos = _max_size + offset; + *new_offset = _pos; + break; + default: + return EINVAL; + } + return 0; +} + +int cookie_file::close() { + if(!_funcs.close) { + return 0; + } + + return _funcs.close(_cookie); +} + +int cookie_file::reopen(const char *, const char *) { + mlibc::panicLogger() << "mlibc: freopen() on a cookie_file stream is unimplemented!" << frg::endlog; + return -1; +} + +int cookie_file::determine_type(stream_type *type) { + *type = stream_type::file_like; + return 0; +} + +int cookie_file::determine_bufmode(buffer_mode *mode) { + *mode = buffer_mode::no_buffer; + return 0; +} + +int cookie_file::io_read(char *buffer, size_t max_size, size_t *actual_size) { + if(!_funcs.read) { + return EOF; + } + + *actual_size = _funcs.read(_cookie, buffer, max_size); + + return 0; +} + +int cookie_file::io_write(const char *buffer, size_t max_size, size_t *actual_size) { + if(!_funcs.write) { + return 0; + } + + *actual_size = _funcs.write(_cookie, buffer, max_size); + + return 0; +} + +int cookie_file::io_seek(off_t offset, int whence, off_t *new_offset) { + if(!_funcs.seek) { + return ENOTSUP; + } + + *new_offset = offset; + + return _funcs.seek(_cookie, new_offset, whence); +} + +} // namespace mlibc + +FILE *fdopen(int fd, const char *mode) { + int flags = mlibc::fd_file::parse_modestring(mode); + + flags &= ~O_TRUNC; // 'w' should not truncate the file + + if (flags & O_APPEND) { + int cur_flags = fcntl(fd, F_GETFL, 0); + if (cur_flags < 0) { + errno = EINVAL; + return nullptr; + } else if (!(cur_flags & O_APPEND)) { + if (fcntl(fd, F_SETFL, cur_flags | O_APPEND)) { + errno = EINVAL; + return nullptr; + } + } + } + + if (flags & O_CLOEXEC) { + if (fcntl(fd, F_SETFD, FD_CLOEXEC)) { + errno = EINVAL; + return nullptr; + } + } + + // TODO: We may need to activate line buffered mode for terminals. + + return frg::construct(getAllocator(), fd, + mlibc::file_dispose_cb); +} diff --git a/lib/mlibc/options/posix/generic/posix_ctype.cpp b/lib/mlibc/options/posix/generic/posix_ctype.cpp new file mode 100644 index 0000000..19f129f --- /dev/null +++ b/lib/mlibc/options/posix/generic/posix_ctype.cpp @@ -0,0 +1,136 @@ +#include +#include + +#include + +int isalnum_l(int c, locale_t) { + return isalnum(c); +} + +int isalpha_l(int c, locale_t) { + return isalpha(c); +} + +int isblank_l(int c, locale_t) { + return isblank(c); +} + +int iscntrl_l(int c, locale_t) { + return iscntrl(c); +} + +int isdigit_l(int c, locale_t) { + return isdigit(c); +} + +int isgraph_l(int c, locale_t) { + return isgraph(c); +} + +int islower_l(int c, locale_t) { + return islower(c); +} + +int isprint_l(int c, locale_t) { + return isprint(c); +} + +int ispunct_l(int c, locale_t) { + return ispunct(c); +} + +int isspace_l(int c, locale_t) { + return isspace(c); +} + +int isupper_l(int c, locale_t) { + return isupper(c); +} + +int isxdigit_l(int c, locale_t) { + return isxdigit(c); +} + +int isascii_l(int c, locale_t) { + return isascii(c); +} + +int tolower_l(int c, locale_t) { + return tolower(c); +} + +int toupper_l(int c, locale_t) { + return toupper(c); +} + +int iswalnum_l(wint_t c, locale_t) { + return iswalnum(c); +} + +int iswblank_l(wint_t c, locale_t) { + return iswblank(c); +} + +int iswcntrl_l(wint_t c, locale_t) { + return iswcntrl(c); +} + +int iswdigit_l(wint_t c, locale_t) { + return iswdigit(c); +} + +int iswgraph_l(wint_t c, locale_t) { + return iswgraph(c); +} + +int iswlower_l(wint_t c, locale_t) { + return iswlower(c); +} + +int iswprint_l(wint_t c, locale_t) { + return iswprint(c); +} + +int iswpunct_l(wint_t c, locale_t) { + return iswpunct(c); +} + +int iswspace_l(wint_t c, locale_t) { + return iswspace(c); +} + +int iswupper_l(wint_t c, locale_t) { + return iswupper(c); +} + +int iswxdigit_l(wint_t c, locale_t) { + return iswxdigit(c); +} + +int iswalpha_l(wint_t c, locale_t) { + return iswalpha(c); +} + +wctype_t wctype_l(const char* p, locale_t) { + return wctype(p); +} + +int iswctype_l(wint_t w, wctype_t t, locale_t) { + return iswctype(w, t); +} + +wint_t towlower_l(wint_t c, locale_t) { + return towlower(c); +} + +wint_t towupper_l(wint_t c, locale_t) { + return towupper(c); +} + +wctrans_t wctrans_l(const char* c, locale_t) { + return wctrans(c); +} + +wint_t towctrans_l(wint_t c, wctrans_t desc, locale_t) { + return towctrans(c, desc); +} diff --git a/lib/mlibc/options/posix/generic/posix_locale.cpp b/lib/mlibc/options/posix/generic/posix_locale.cpp new file mode 100644 index 0000000..bd8710a --- /dev/null +++ b/lib/mlibc/options/posix/generic/posix_locale.cpp @@ -0,0 +1,37 @@ +#include +#include +#include + +namespace { + +bool newlocale_seen = false; +bool uselocale_seen = false; + +} + +locale_t newlocale(int, const char *, locale_t) { + // Due to all of the locale functions being stubs, the locale will not be used + if(!newlocale_seen) { + mlibc::infoLogger() << "mlibc: newlocale() is a no-op" << frg::endlog; + newlocale_seen = true; + } + return nullptr; +} + +void freelocale(locale_t) { + mlibc::infoLogger() << "mlibc: freelocale() is a no-op" << frg::endlog; + return; +} + +locale_t uselocale(locale_t) { + if(!uselocale_seen) { + mlibc::infoLogger() << "mlibc: uselocale() is a no-op" << frg::endlog; + uselocale_seen = true; + } + return nullptr; +} + +locale_t duplocale(locale_t) { + mlibc::infoLogger() << "mlibc: duplocale() is a no-op" << frg::endlog; + return nullptr; +} diff --git a/lib/mlibc/options/posix/generic/posix_signal.cpp b/lib/mlibc/options/posix/generic/posix_signal.cpp new file mode 100644 index 0000000..eef3ef3 --- /dev/null +++ b/lib/mlibc/options/posix/generic/posix_signal.cpp @@ -0,0 +1,151 @@ + +#include +#include +#include +#include + +#include +#include + +int sigsuspend(const sigset_t *sigmask) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_sigsuspend, -1); + + // This is guaranteed to return an error (EINTR most probably) + errno = mlibc::sys_sigsuspend(sigmask); + return -1; +} + +int pthread_sigmask(int how, const sigset_t *__restrict set, sigset_t *__restrict retrieve) { + if(!mlibc::sys_sigprocmask) { + MLIBC_MISSING_SYSDEP(); + return ENOSYS; + } + if(int e = mlibc::sys_sigprocmask(how, set, retrieve); e) { + return e; + } + return 0; +} + +int pthread_kill(pthread_t thread, int sig) { + auto tcb = reinterpret_cast(thread); + auto pid = getpid(); + + if(!mlibc::sys_tgkill) { + MLIBC_MISSING_SYSDEP(); + return ENOSYS; + } + + if(int e = mlibc::sys_tgkill(pid, tcb->tid, sig); e) { + return e; + } + + return 0; +} + +int sigaction(int signum, const struct sigaction *__restrict act, struct sigaction *__restrict oldact) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_sigaction, -1); + if(int e = mlibc::sys_sigaction(signum, act, oldact); e) { + errno = e; + return -1; + } + return 0; +} + +int siginterrupt(int sig, int flag) { + int ret; + struct sigaction act; + + sigaction(sig, NULL, &act); + if (flag) + act.sa_flags &= ~SA_RESTART; + else + act.sa_flags |= SA_RESTART; + + ret = sigaction(sig, &act, NULL); + return ret; +} + +int kill(pid_t pid, int number) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_kill, -1); + if(int e = mlibc::sys_kill(pid, number); e) { + errno = e; + return -1; + } + return 0; +} + +int killpg(pid_t pgrp, int sig) { + if(pgrp > 1) { + return kill(-pgrp, sig); + } + + errno = EINVAL; + return -1; +} + +int sigtimedwait(const sigset_t *__restrict set, siginfo_t *__restrict info, const struct timespec *__restrict timeout) { + auto sysdep = MLIBC_CHECK_OR_ENOSYS(mlibc::sys_sigtimedwait, -1); + + int signo; + + if (int e = sysdep(set, info, timeout, &signo)) { + errno = e; + return -1; + } + + return signo; +} + +int sigwaitinfo(const sigset_t *__restrict set, siginfo_t *__restrict info) { + // NOTE: This assumes the sysdep behavior noted in mlibc/posix-sysdeps.hpp + return sigtimedwait(set, info, nullptr); +} + +int sigwait(const sigset_t *__restrict set, int *__restrict sig) { + if (int e = sigwaitinfo(set, nullptr); e < 0) { + return e; + } else { + if (sig) + *sig = e; + + return 0; + } +} + +int sigpending(sigset_t *set) { + auto sysdep = MLIBC_CHECK_OR_ENOSYS(mlibc::sys_sigpending, -1); + + if(int e = sysdep(set)) { + errno = e; + return -1; + } + + return 0; +} + +int sigaltstack(const stack_t *__restrict ss, stack_t *__restrict oss) { + if (ss && ss->ss_size < MINSIGSTKSZ && !(ss->ss_flags & SS_DISABLE)) { + errno = ENOMEM; + return -1; + } + + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_sigaltstack, -1); + if (int e = mlibc::sys_sigaltstack(ss, oss); e) { + errno = e; + return -1; + } + + return 0; +} + +#if __MLIBC_GLIBC_OPTION +int sigisemptyset(const sigset_t *set) { + return !(*set); +} +#endif // __MLIBC_GLIBC_OPTION + +int sigqueue(pid_t, int, const union sigval) { + __ensure(!"sigqueue() not implemented"); + __builtin_unreachable(); +} + diff --git a/lib/mlibc/options/posix/generic/posix_stdio.cpp b/lib/mlibc/options/posix/generic/posix_stdio.cpp new file mode 100644 index 0000000..fc77a54 --- /dev/null +++ b/lib/mlibc/options/posix/generic/posix_stdio.cpp @@ -0,0 +1,209 @@ +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +struct popen_file : mlibc::fd_file { + popen_file(int fd, void (*do_dispose)(abstract_file *) = nullptr) + : fd_file(fd, do_dispose) {} + + pid_t get_popen_pid() { + return _popen_pid; + } + + void set_popen_pid(pid_t new_pid) { + _popen_pid = new_pid; + } + +private: + // Underlying PID in case of popen() + pid_t _popen_pid; +}; + +FILE *fmemopen(void *buf, size_t size, const char *__restrict mode) { + int flags = mlibc::fd_file::parse_modestring(mode); + + return frg::construct(getAllocator(), buf, size, flags, + mlibc::file_dispose_cb); +} + +int pclose(FILE *stream) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_waitpid, -1); + + auto file = static_cast(stream); + + int status; + pid_t pid = file->get_popen_pid(); + + fclose(file); + + if (mlibc::sys_waitpid(pid, &status, 0, NULL, &pid) != 0) { + errno = ECHILD; + return -1; + } + + return status; +} + +FILE *popen(const char *command, const char *typestr) { + bool is_write; + pid_t child; + FILE *ret = nullptr; + + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_fork && mlibc::sys_dup2 && mlibc::sys_execve && + mlibc::sys_sigprocmask && mlibc::sys_sigaction && mlibc::sys_pipe, nullptr); + + if (typestr == NULL) { + errno = EINVAL; + return nullptr; + } + + if (strstr(typestr, "w") != NULL) { + is_write = true; + } else if (strstr(typestr, "r") != NULL) { + is_write = false; + } else { + errno = EINVAL; + return nullptr; + } + + bool cloexec = false; + if (strstr(typestr, "e") != NULL) { + // Set FD_CLOEXEC on the new file descriptor + cloexec = true; + } + + int fds[2]; + if (int e = mlibc::sys_pipe(fds, 0)) { + errno = e; + return nullptr; + } + + struct sigaction new_sa, old_int, old_quit; + sigset_t new_mask, old_mask; + + new_sa.sa_handler = SIG_IGN; + new_sa.sa_flags = 0; + sigemptyset(&new_sa.sa_mask); + mlibc::sys_sigaction(SIGINT, &new_sa, &old_int); + mlibc::sys_sigaction(SIGQUIT, &new_sa, &old_quit); + + sigemptyset(&new_mask); + sigaddset(&new_mask, SIGCHLD); + mlibc::sys_sigprocmask(SIG_BLOCK, &new_mask, &old_mask); + + int parent_end = is_write ? 1 : 0; + int child_end = is_write ? 0 : 1; + + if (int e = mlibc::sys_fork(&child)) { + errno = e; + mlibc::sys_close(fds[0]); + mlibc::sys_close(fds[1]); + } else if (!child) { + // For the child + mlibc::sys_sigaction(SIGINT, &old_int, nullptr); + mlibc::sys_sigaction(SIGQUIT, &old_quit, nullptr); + mlibc::sys_sigprocmask(SIG_SETMASK, &old_mask, nullptr); + + mlibc::sys_close(fds[parent_end]); + + if (mlibc::sys_dup2(fds[child_end], 0, is_write ? 0 : 1)) { + __ensure(!"sys_dup2() failed in popen()"); + } + mlibc::sys_close(fds[child_end]); + + const char *args[] = { + "sh", "-c", command, nullptr + }; + + mlibc::sys_execve("/bin/sh", const_cast(args), environ); + _Exit(127); + } else { + // For the parent + mlibc::sys_close(fds[child_end]); + + ret = frg::construct( + getAllocator(), + fds[parent_end], + mlibc::file_dispose_cb + ); + __ensure(ret); + + auto file = static_cast(ret); + + file->set_popen_pid(child); + + if (cloexec == true) { + fcntl(file->fd(), F_SETFD, O_CLOEXEC); + } + } + + mlibc::sys_sigaction(SIGINT, &old_int, nullptr); + mlibc::sys_sigaction(SIGQUIT, &old_quit, nullptr); + mlibc::sys_sigprocmask(SIG_SETMASK, &old_mask, nullptr); + + return ret; +} + +FILE *open_memstream(char **buf, size_t *sizeloc) { + return frg::construct(getAllocator(), buf, sizeloc, O_RDWR, + mlibc::file_dispose_cb); +} + +int fseeko(FILE *file_base, off_t offset, int whence) { + auto file = static_cast(file_base); + if(int e = file->seek(offset, whence); e) { + errno = e; + return -1; + } + return 0; +} + +off_t ftello(FILE *file_base) { + auto file = static_cast(file_base); + off_t current_offset; + if(int e = file->tell(¤t_offset); e) { + errno = e; + return -1; + } + return current_offset; +} + +int dprintf(int fd, const char *format, ...) { + va_list args; + va_start(args, format); + int result = vdprintf(fd, format, args); + va_end(args); + return result; +} + +int vdprintf(int fd, const char *format, __builtin_va_list args) { + mlibc::fd_file file{fd}; + int ret = vfprintf(&file, format, args); + file.flush(); + return ret; +} + +char *fgetln(FILE *, size_t *) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +FILE *fopencookie(void *cookie, const char *__restrict mode, cookie_io_functions_t funcs) { + int flags = mlibc::fd_file::parse_modestring(mode); + + return frg::construct(getAllocator(), cookie, flags, funcs, + mlibc::file_dispose_cb); +} diff --git a/lib/mlibc/options/posix/generic/posix_stdlib.cpp b/lib/mlibc/options/posix/generic/posix_stdlib.cpp new file mode 100644 index 0000000..4010998 --- /dev/null +++ b/lib/mlibc/options/posix/generic/posix_stdlib.cpp @@ -0,0 +1,513 @@ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +namespace { + constexpr bool debugPathResolution = false; +} + +// Borrowed from musl +static uint32_t init[] = { +0x00000000,0x5851f42d,0xc0b18ccf,0xcbb5f646, +0xc7033129,0x30705b04,0x20fd5db4,0x9a8b7f78, +0x502959d8,0xab894868,0x6c0356a7,0x88cdb7ff, +0xb477d43f,0x70a3a52b,0xa8e4baf1,0xfd8341fc, +0x8ae16fd9,0x742d2f7a,0x0d1f0796,0x76035e09, +0x40f7702c,0x6fa72ca5,0xaaa84157,0x58a0df74, +0xc74a0364,0xae533cc4,0x04185faf,0x6de3b115, +0x0cab8628,0xf043bfa4,0x398150e9,0x37521657}; + +static int n = 31; +static int i = 3; +static int j = 0; +static uint32_t *x = init + 1; + + +static uint32_t lcg31(uint32_t x) { + return (1103515245 * x + 12345) & 0x7fffffff; +} + +static uint64_t lcg64(uint64_t x) { + return 6364136223846793005ull * x + 1; +} + +static void *savestate(void) { + x[-1] = (n << 16) | (i << 8) | j; + return x - 1; +} + +static void loadstate(uint32_t *state) { + x = state + 1; + n = x[-1] >> 16; + i = (x[-1] >> 8) & 0xff; + j = x[-1] & 0xff; +} + +long random(void) { + long k; + + if(n == 0) { + k = x[0] = lcg31(x[0]); + return k; + } + x[i] += x[j]; + k = x[i] >> 1; + if(++i == n) + i = 0; + if(++j == n) + j = 0; + + return k; +} + +double drand48(void) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +void srand48(long int) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +// Borrowed from musl +void srandom(unsigned int seed) { + int k; + uint64_t s = seed; + + if(n == 0) { + x[0] = s; + return; + } + i = n == 31 || n == 7 ? 3 : 1; + j = 0; + for(k = 0; k < n; k++) { + s = lcg64(s); + x[k] = s >> 32; + } + // Make sure x contains at least one odd number + x[0] |= 1; +} + +char *initstate(unsigned int seed, char *state, size_t size) { + void *old; + + if(size < 8) + return 0; + old = savestate(); + if(size < 32) + n = 0; + else if(size < 64) + n = 7; + else if(size < 128) + n = 15; + else if(size < 256) + n = 31; + else + n = 63; + x = (uint32_t *)state + 1; + srandom(seed); + savestate(); + return (char *)old; +} + +char *setstate(char *state) { + void *old; + + old = savestate(); + loadstate((uint32_t *)state); + return (char *)old; +} + +// ---------------------------------------------------------------------------- +// Path handling. +// ---------------------------------------------------------------------------- + + +int mkostemps(char *pattern, int suffixlen, int flags) { + auto n = strlen(pattern); + if(n < (6 + static_cast(suffixlen))) { + errno = EINVAL; + return -1; + } + + flags &= ~O_WRONLY; + + for(size_t i = 0; i < 6; i++) { + if(pattern[n - (6 + suffixlen) + i] == 'X') + continue; + errno = EINVAL; + return -1; + } + + // TODO: Do an exponential search. + for(size_t i = 0; i < 999999; i++) { + char sfx = pattern[n - suffixlen]; + __ensure(sprintf(pattern + (n - (6 + suffixlen)), "%06zu", i) == 6); + pattern[n - suffixlen] = sfx; + + int fd; + if(int e = mlibc::sys_open(pattern, O_RDWR | O_CREAT | O_EXCL | flags, S_IRUSR | S_IWUSR, &fd); !e) { + return fd; + }else if(e != EEXIST) { + errno = e; + return -1; + } + } + + errno = EEXIST; + return -1; +} + +int mkostemp(char *pattern, int flags) { + return mkostemps(pattern, flags, 0); +} + +int mkstemp(char *path) { + return mkostemp(path, 0); +} + +int mkstemps(char *pattern, int suffixlen) { + return mkostemps(pattern, suffixlen, 0); +} + +char *mkdtemp(char *pattern) { + mlibc::infoLogger() << "mlibc mkdtemp(" << pattern << ") called" << frg::endlog; + auto n = strlen(pattern); + __ensure(n >= 6); + if(n < 6) { + errno = EINVAL; + return NULL; + } + for(size_t i = 0; i < 6; i++) { + if(pattern[n - 6 + i] == 'X') + continue; + errno = EINVAL; + return NULL; + } + + // TODO: Do an exponential search. + for(size_t i = 0; i < 999999; i++) { + __ensure(sprintf(pattern + (n - 6), "%06zu", i) == 6); + if(int e = mlibc::sys_mkdir(pattern, S_IRWXU); !e) { + return pattern; + }else if(e != EEXIST) { + errno = e; + return NULL; + } + } + + errno = EEXIST; + return NULL; +} + +char *realpath(const char *path, char *out) { + if(debugPathResolution) + mlibc::infoLogger() << "mlibc realpath(): Called on '" << path << "'" << frg::endlog; + frg::string_view path_view{path}; + + // In case of the root, the string only contains the null-terminator. + frg::small_vector resolv{getAllocator()}; + size_t ps; + + // If the path is relative, we have to preprend the working directory. + if(path[0] == '/') { + resolv.push_back(0); + ps = 1; + }else{ + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_getcwd, nullptr); + + // Try to getcwd() until the buffer is large enough. + resolv.resize(128); + while(true) { + int e = mlibc::sys_getcwd(resolv.data(), resolv.size()); + if(e == ERANGE) { + resolv.resize(2 * resolv.size()); + }else if(!e) { + break; + }else{ + errno = e; + return nullptr; + } + } + frg::string_view cwd_view{resolv.data()}; + if(cwd_view == "/") { + // Restore our invariant that we only store the null-terminator for the root. + resolv.resize(1); + resolv[0] = 0; + }else{ + resolv.resize(cwd_view.size() + 1); + } + ps = 0; + } + + // Contains unresolved links as a relative path compared to resolv. + frg::small_vector lnk{getAllocator()}; + size_t ls = 0; + + auto process_segment = [&] (frg::string_view s_view) -> int { + if(debugPathResolution) + mlibc::infoLogger() << "mlibc realpath(): resolv is '" << resolv.data() << "'" + << ", segment is " << s_view.data() + << ", size: " << s_view.size() << frg::endlog; + + if(!s_view.size() || s_view == ".") { + // Keep resolv invariant. + return 0; + }else if(s_view == "..") { + // Remove a single segment from resolv. + if(resolv.size() > 1) { + auto slash = strrchr(resolv.data(), '/'); + __ensure(slash); // We never remove the leading sla. + resolv.resize((slash - resolv.data()) + 1); + *slash = 0; // Replace the slash by a null-terminator. + } + return 0; + } + + // Append the segment to resolv. + auto rsz = resolv.size(); + resolv[rsz - 1] = '/'; // Replace null-terminator by a slash. + resolv.resize(rsz + s_view.size() + 1); + memcpy(resolv.data() + rsz, s_view.data(), s_view.size()); + resolv[rsz + s_view.size()] = 0; + + // stat() the path to (1) see if it exists and (2) see if it is a link. + if(!mlibc::sys_stat) { + MLIBC_MISSING_SYSDEP(); + return ENOSYS; + } + if(debugPathResolution) + mlibc::infoLogger() << "mlibc realpath(): stat()ing '" + << resolv.data() << "'" << frg::endlog; + struct stat st; + if(int e = mlibc::sys_stat(mlibc::fsfd_target::path, + -1, resolv.data(), AT_SYMLINK_NOFOLLOW, &st); e) + return e; + + if(S_ISLNK(st.st_mode)) { + if(debugPathResolution) { + mlibc::infoLogger() << "mlibc realpath(): Encountered symlink '" + << resolv.data() << "'" << frg::endlog; + } + + if(!mlibc::sys_readlink) { + MLIBC_MISSING_SYSDEP(); + return ENOSYS; + } + + ssize_t sz = 0; + char path[512]; + + if (int e = mlibc::sys_readlink(resolv.data(), path, 512, &sz); e) + return e; + + if(debugPathResolution) { + mlibc::infoLogger() << "mlibc realpath(): Symlink resolves to '" + << frg::string_view{path, static_cast(sz)} << "'" << frg::endlog; + } + + if (path[0] == '/') { + // Absolute path, replace resolv + resolv.resize(sz); + strncpy(resolv.data(), path, sz - 1); + resolv.data()[sz - 1] = 0; + + if(debugPathResolution) { + mlibc::infoLogger() << "mlibc realpath(): Symlink is absolute, resolv: '" + << resolv.data() << "'" << frg::endlog; + } + } else { + // Relative path, revert changes to resolv, prepend to lnk + resolv.resize(rsz); + resolv[rsz - 1] = 0; + + auto lsz = lnk.size(); + lnk.resize((lsz - ls) + sz + 1); + memmove(lnk.data() + sz, lnk.data() + ls, lsz - ls); + memcpy(lnk.data(), path, sz); + lnk[(lsz - ls) + sz] = 0; + + ls = 0; + + if(debugPathResolution) { + mlibc::infoLogger() << "mlibc realpath(): Symlink is relative, resolv: '" + << resolv.data() << "' lnk: '" + << frg::string_view{lnk.data(), lnk.size()} << "'" << frg::endlog; + } + } + } + + return 0; + }; + + // Each iteration of this outer loop consumes segment of the input path. + // This design avoids copying the input path into lnk; + // the latter could often involve additional allocations. + while(ps < path_view.size()) { + frg::string_view ps_view; + if(auto slash = strchr(path + ps, '/'); slash) { + ps_view = frg::string_view{path + ps, static_cast(slash - (path + ps))}; + }else{ + ps_view = frg::string_view{path + ps, strlen(path) - ps}; + } + ps += ps_view.size() + 1; + + // Handle one segment from the input path. + if(int e = process_segment(ps_view); e) { + errno = e; + return nullptr; + } + + // This inner loop consumes segments of lnk. + while(ls < lnk.size()) { + frg::string_view ls_view; + if(auto slash = strchr(lnk.data() + ls, '/'); slash) { + ls_view = frg::string_view{lnk.data() + ls, static_cast(slash - (lnk.data() + ls))}; + }else{ + ls_view = frg::string_view{lnk.data() + ls, strlen(lnk.data()) - ls}; + } + ls += ls_view.size() + 1; + + // Handle one segment from the link + if(int e = process_segment(ls_view); e) { + errno = e; + return nullptr; + } + } + + // All of lnk was consumed, reset it + lnk.resize(0); + ls = 0; + } + + if(resolv.size() == 1) { + resolv.resize(0); + resolv.push_back('/'); + resolv.push_back(0); + } + + if(debugPathResolution) + mlibc::infoLogger() << "mlibc realpath(): Returns '" << resolv.data() << "'" << frg::endlog; + + if(resolv.size() > PATH_MAX) { + errno = ENAMETOOLONG; + return nullptr; + } + + if(!out) + out = reinterpret_cast(getAllocator().allocate(resolv.size())); + strcpy(out, resolv.data()); + return out; +} + +// ---------------------------------------------------------------------------- +// Pseudoterminals +// ---------------------------------------------------------------------------- + +int ptsname_r(int fd, char *buffer, size_t length) { + auto sysdep = MLIBC_CHECK_OR_ENOSYS(mlibc::sys_ptsname, ENOSYS); + + if(int e = sysdep(fd, buffer, length); e) + return e; + + return 0; +} + +char *ptsname(int fd) { + static char buffer[128]; + + auto sysdep = MLIBC_CHECK_OR_ENOSYS(mlibc::sys_ptsname, NULL); + + if(int e = sysdep(fd, buffer, 128); e) { + errno = e; + return NULL; + } + + return buffer; +} + +int posix_openpt(int flags) { + int fd; + if(int e = mlibc::sys_open("/dev/ptmx", flags, 0, &fd); e) { + errno = e; + return -1; + } + + return fd; +} + +int unlockpt(int fd) { + auto sysdep = MLIBC_CHECK_OR_ENOSYS(mlibc::sys_unlockpt, -1); + + if(int e = sysdep(fd); e) { + errno = e; + return -1; + } + + return 0; +} + +int grantpt(int) { + return 0; +} + +double strtod_l(const char *__restrict__ nptr, char ** __restrict__ endptr, locale_t) { + mlibc::infoLogger() << "mlibc: strtod_l ignores locale!" << frg::endlog; + return strtod(nptr, endptr); +} + +long double strtold_l(const char *__restrict__, char ** __restrict__, locale_t) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +float strtof_l(const char *__restrict__ nptr, char **__restrict__ endptr, locale_t) { + mlibc::infoLogger() << "mlibc: strtof_l ignores locales" << frg::endlog; + return strtof(nptr, endptr); +} + +int strcoll_l(const char *, const char *, locale_t) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +int getloadavg(double *, int) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +char *secure_getenv(const char *name) { + if (mlibc::rtdlConfig().secureRequired) + return NULL; + else + return getenv(name); +} + +void *reallocarray(void *ptr, size_t m, size_t n) { + if(n && m > -1 / n) { + errno = ENOMEM; + return 0; + } + + return realloc(ptr, m * n); +} + +char *canonicalize_file_name(const char *name) { + return realpath(name, NULL); +} diff --git a/lib/mlibc/options/posix/generic/posix_string.cpp b/lib/mlibc/options/posix/generic/posix_string.cpp new file mode 100644 index 0000000..d0bc7b5 --- /dev/null +++ b/lib/mlibc/options/posix/generic/posix_string.cpp @@ -0,0 +1,174 @@ +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#include +#include +#include +#include +#include + +#include + +char *strdup(const char *string) { + auto num_bytes = strlen(string); + + char *new_string = (char *)malloc(num_bytes + 1); + if(!new_string) // TODO: set errno + return nullptr; + + memcpy(new_string, string, num_bytes); + new_string[num_bytes] = 0; + return new_string; +} + +char *strndup(const char *string, size_t max_size) { + auto num_bytes = strnlen(string, max_size); + char *new_string = (char *)malloc(num_bytes + 1); + if(!new_string) // TODO: set errno + return nullptr; + + memcpy(new_string, string, num_bytes); + new_string[num_bytes] = 0; + return new_string; +} + +char *stpcpy(char *__restrict dest, const char *__restrict src) { + auto n = strlen(src); + memcpy(dest, src, n + 1); + return dest + n; +} + +char *stpncpy(char *__restrict dest, const char *__restrict src, size_t n) { + size_t nulls, copied, srcLen = strlen(src); + if (n >= srcLen) { + nulls = n - srcLen; + copied = srcLen; + } else { + nulls = 0; + copied = n; + } + + memcpy(dest, src, copied); + memset(dest + srcLen, 0, nulls); + return dest + n - nulls; +} + +size_t strnlen(const char *s, size_t n) { + size_t len = 0; + while(len < n && s[len]) + ++len; + return len; +} + +char *strsep(char **m, const char *del) { + __ensure(m); + + auto tok = *m; + if(!tok) + return nullptr; + + // Replace the following delimiter by a null-terminator. + // After this loop: *p is null iff we reached the end of the string. + auto p = tok; + while(*p && !strchr(del, *p)) + p++; + + if(*p) { + *p = 0; + *m = p + 1; + }else{ + *m = nullptr; + } + return tok; +} + +char *strsignal(int sig) { + #define CASE_FOR(sigconst) case sigconst: s = #sigconst; break; + const char *s; + switch(sig) { + CASE_FOR(SIGABRT) + CASE_FOR(SIGFPE) + CASE_FOR(SIGILL) + CASE_FOR(SIGINT) + CASE_FOR(SIGSEGV) + CASE_FOR(SIGTERM) + CASE_FOR(SIGPROF) + CASE_FOR(SIGIO) + CASE_FOR(SIGPWR) + CASE_FOR(SIGALRM) + CASE_FOR(SIGBUS) + CASE_FOR(SIGCHLD) + CASE_FOR(SIGCONT) + CASE_FOR(SIGHUP) + CASE_FOR(SIGKILL) + CASE_FOR(SIGPIPE) + CASE_FOR(SIGQUIT) + CASE_FOR(SIGSTOP) + CASE_FOR(SIGTSTP) + CASE_FOR(SIGTTIN) + CASE_FOR(SIGTTOU) + CASE_FOR(SIGUSR1) + CASE_FOR(SIGUSR2) + CASE_FOR(SIGSYS) + CASE_FOR(SIGTRAP) + CASE_FOR(SIGURG) + CASE_FOR(SIGVTALRM) + CASE_FOR(SIGXCPU) + CASE_FOR(SIGXFSZ) + CASE_FOR(SIGWINCH) + default: + mlibc::infoLogger() << "mlibc: Unknown signal number " << sig << frg::endlog; + s = "Unknown signal number"; + } + return const_cast(s); +} + +char *strcasestr(const char *s, const char *pattern) { + size_t plen = strlen(pattern); + const char *p = s; + while(*p) { + // Need strncasecmp() to avoid checking past the end of a successful match. + if(!strncasecmp(p, pattern, plen)) + return const_cast(p); + ++p; + } + return nullptr; +} + +void *memccpy(void *__restrict, const void *__restrict, int, size_t) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +// This implementation was taken from musl +void *memrchr(const void *m, int c, size_t n) { + const unsigned char *s = (const unsigned char *)m; + c = (unsigned char)c; + while(n--) { + if(s[n] == c) + return (void *)(s + n); + } + return 0; +} + +// BSD extensions. +// Taken from musl +size_t strlcpy(char *d, const char *s, size_t n) { + char *d0 = d; + + if(!n--) + goto finish; + for(; n && (*d=*s); n--, s++, d++); + *d = 0; +finish: + return d-d0 + strlen(s); +} + +size_t strlcat(char *d, const char *s, size_t n) { + size_t l = strnlen(d, n); + if(l == n) { + return l + strlen(s); + } + return l + strlcpy(d + l, s, n - l); +} diff --git a/lib/mlibc/options/posix/generic/posix_time.cpp b/lib/mlibc/options/posix/generic/posix_time.cpp new file mode 100644 index 0000000..d93ebbc --- /dev/null +++ b/lib/mlibc/options/posix/generic/posix_time.cpp @@ -0,0 +1,32 @@ +#include +#include +#include +#include + +int utimes(const char *filename, const struct timeval times[2]) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_utimensat, -1); + struct timespec time[2]; + if(times == nullptr) { + time[0].tv_sec = UTIME_NOW; + time[0].tv_nsec = UTIME_NOW; + time[1].tv_sec = UTIME_NOW; + time[1].tv_nsec = UTIME_NOW; + } else { + time[0].tv_sec = times[0].tv_sec; + time[0].tv_nsec = times[0].tv_usec * 1000; + time[1].tv_sec = times[1].tv_sec; + time[1].tv_nsec = times[1].tv_usec * 1000; + } + + if (int e = mlibc::sys_utimensat(AT_FDCWD, filename, time, 0); e) { + errno = e; + return -1; + } + + return 0; +} + +int futimes(int, const struct timeval[2]) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} diff --git a/lib/mlibc/options/posix/generic/pthread-stubs.cpp b/lib/mlibc/options/posix/generic/pthread-stubs.cpp new file mode 100644 index 0000000..9720bc2 --- /dev/null +++ b/lib/mlibc/options/posix/generic/pthread-stubs.cpp @@ -0,0 +1,1426 @@ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static bool enableTrace = false; + +struct ScopeTrace { + ScopeTrace(const char *file, int line, const char *function) + : _file(file), _line(line), _function(function) { + if(!enableTrace) + return; + mlibc::infoLogger() << "trace: Enter scope " + << _file << ":" << _line << " (in function " + << _function << ")" << frg::endlog; + } + + ~ScopeTrace() { + if(!enableTrace) + return; + mlibc::infoLogger() << "trace: Exit scope" << frg::endlog; + } + +private: + const char *_file; + int _line; + const char *_function; +}; + +#define SCOPE_TRACE() ScopeTrace(__FILE__, __LINE__, __FUNCTION__) + +static constexpr unsigned int mutexRecursive = 1; +static constexpr unsigned int mutexErrorCheck = 2; + +// TODO: either use uint32_t or determine the bit based on sizeof(int). +static constexpr unsigned int mutex_owner_mask = (static_cast(1) << 30) - 1; +static constexpr unsigned int mutex_waiters_bit = static_cast(1) << 31; + +// Only valid for the internal __mlibc_m mutex of wrlocks. +static constexpr unsigned int mutex_excl_bit = static_cast(1) << 30; + +static constexpr unsigned int rc_count_mask = (static_cast(1) << 31) - 1; +static constexpr unsigned int rc_waiters_bit = static_cast(1) << 31; + +static constexpr size_t default_stacksize = 0x200000; +static constexpr size_t default_guardsize = 4096; + +// ---------------------------------------------------------------------------- +// pthread_attr and pthread functions. +// ---------------------------------------------------------------------------- + +// pthread_attr functions. +int pthread_attr_init(pthread_attr_t *attr) { + *attr = pthread_attr_t{}; + attr->__mlibc_stacksize = default_stacksize; + attr->__mlibc_guardsize = default_guardsize; + attr->__mlibc_detachstate = PTHREAD_CREATE_JOINABLE; + return 0; +} + +int pthread_attr_destroy(pthread_attr_t *) { + return 0; +} + +int pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detachstate) { + *detachstate = attr->__mlibc_detachstate; + return 0; +} +int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate) { + if (detachstate != PTHREAD_CREATE_DETACHED && + detachstate != PTHREAD_CREATE_JOINABLE) + return EINVAL; + + attr->__mlibc_detachstate = detachstate; + return 0; +} + +int pthread_attr_getstacksize(const pthread_attr_t *__restrict attr, size_t *__restrict stacksize) { + *stacksize = attr->__mlibc_stacksize; + return 0; +} + +int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize) { + if (stacksize < PTHREAD_STACK_MIN) + return EINVAL; + attr->__mlibc_stacksize = stacksize; + return 0; +} + +int pthread_attr_getstackaddr(const pthread_attr_t *attr, void **stackaddr) { + *stackaddr = attr->__mlibc_stackaddr; + return 0; +} +int pthread_attr_setstackaddr(pthread_attr_t *attr, void *stackaddr) { + attr->__mlibc_stackaddr = stackaddr; + return 0; +} + +int pthread_attr_getstack(const pthread_attr_t *attr, void **stackaddr, size_t *stacksize) { + *stackaddr = attr->__mlibc_stackaddr; + *stacksize = attr->__mlibc_stacksize; + return 0; +} +int pthread_attr_setstack(pthread_attr_t *attr, void *stackaddr, size_t stacksize) { + if (stacksize < PTHREAD_STACK_MIN) + return EINVAL; + attr->__mlibc_stacksize = stacksize; + attr->__mlibc_stackaddr = stackaddr; + return 0; +} + +int pthread_attr_getguardsize(const pthread_attr_t *__restrict attr, size_t *__restrict guardsize) { + *guardsize = attr->__mlibc_guardsize; + return 0; +} +int pthread_attr_setguardsize(pthread_attr_t *attr, size_t guardsize) { + attr->__mlibc_guardsize = guardsize; + return 0; +} + +int pthread_attr_getscope(const pthread_attr_t *attr, int *scope) { + *scope = attr->__mlibc_scope; + return 0; +} +int pthread_attr_setscope(pthread_attr_t *attr, int scope) { + if (scope != PTHREAD_SCOPE_SYSTEM && + scope != PTHREAD_SCOPE_PROCESS) + return EINVAL; + if (scope == PTHREAD_SCOPE_PROCESS) + return ENOTSUP; + attr->__mlibc_scope = scope; + return 0; +} + +int pthread_attr_getinheritsched(const pthread_attr_t *attr, int *inheritsched) { + *inheritsched = attr->__mlibc_inheritsched; + return 0; +} +int pthread_attr_setinheritsched(pthread_attr_t *attr, int inheritsched) { + if (inheritsched != PTHREAD_INHERIT_SCHED && + inheritsched != PTHREAD_EXPLICIT_SCHED) + return EINVAL; + attr->__mlibc_inheritsched = inheritsched; + return 0; +} + +int pthread_attr_getschedparam(const pthread_attr_t *__restrict attr, struct sched_param *__restrict schedparam) { + *schedparam = attr->__mlibc_schedparam; + return 0; +} +int pthread_attr_setschedparam(pthread_attr_t *__restrict attr, const struct sched_param *__restrict schedparam) { + // TODO: this is supposed to return EINVAL for when the schedparam doesn't make sense + // for the given schedpolicy. + attr->__mlibc_schedparam = *schedparam; + return 0; +} + +int pthread_attr_getschedpolicy(const pthread_attr_t *__restrict attr, int *__restrict policy) { + *policy = attr->__mlibc_schedpolicy; + return 0; +} +int pthread_attr_setschedpolicy(pthread_attr_t *__restrict attr, int policy) { + if (policy != SCHED_FIFO && policy != SCHED_RR && + policy != SCHED_OTHER) + return EINVAL; + attr->__mlibc_schedpolicy = policy; + return 0; +} + +#if __MLIBC_LINUX_OPTION +int pthread_attr_getaffinity_np(const pthread_attr_t *__restrict attr, + size_t cpusetsize, cpu_set_t *__restrict cpusetp) { + if (!attr) + return EINVAL; + + if (!attr->__mlibc_cpuset) { + memset(cpusetp, -1, cpusetsize); + return 0; + } + + for (size_t cnt = cpusetsize; cnt < attr->__mlibc_cpusetsize; cnt++) + if (reinterpret_cast(attr->__mlibc_cpuset)[cnt] != '\0') + return ERANGE; + + auto p = memcpy(cpusetp, attr->__mlibc_cpuset, + std::min(cpusetsize, attr->__mlibc_cpusetsize)); + if (cpusetsize > attr->__mlibc_cpusetsize) + memset(p, '\0', cpusetsize - attr->__mlibc_cpusetsize); + + return 0; +} + +int pthread_attr_setaffinity_np(pthread_attr_t *__restrict attr, + size_t cpusetsize, const cpu_set_t *__restrict cpusetp) { + if (!attr) + return EINVAL; + + if (!cpusetp || !cpusetsize) { + attr->__mlibc_cpuset = NULL; + attr->__mlibc_cpusetsize = 0; + return 0; + } + + if (attr->__mlibc_cpusetsize != cpusetsize) { + auto newp = realloc(attr->__mlibc_cpuset, cpusetsize); + if (!newp) + return ENOMEM; + + attr->__mlibc_cpuset = static_cast(newp); + attr->__mlibc_cpusetsize = cpusetsize; + } + + memcpy(attr->__mlibc_cpuset, cpusetp, cpusetsize); + return 0; +} + +int pthread_attr_getsigmask_np(const pthread_attr_t *__restrict attr, + sigset_t *__restrict sigmask) { + if (!attr) + return EINVAL; + + if (!attr->__mlibc_sigmaskset) { + sigemptyset(sigmask); + return PTHREAD_ATTR_NO_SIGMASK_NP; + } + + *sigmask = attr->__mlibc_sigmask; + + return 0; +} +int pthread_attr_setsigmask_np(pthread_attr_t *__restrict attr, + const sigset_t *__restrict sigmask) { + if (!attr) + return EINVAL; + + if (!sigmask) { + attr->__mlibc_sigmaskset = 0; + return 0; + } + + attr->__mlibc_sigmask = *sigmask; + attr->__mlibc_sigmaskset = 1; + + // Filter out internally used signals. + sigdelset(&attr->__mlibc_sigmask, SIGCANCEL); + + return 0; +} + +namespace { + void get_own_stackinfo(void **stack_addr, size_t *stack_size) { + auto fp = fopen("/proc/self/maps", "r"); + if (!fp) { + mlibc::infoLogger() << "mlibc pthreads: /proc/self/maps does not exist! Producing incorrect" + " stack results!" << frg::endlog; + return; + } + + char line[256]; + auto sp = mlibc::get_sp(); + while (fgets(line, 256, fp)) { + uintptr_t from, to; + if(sscanf(line, "%" SCNxPTR "-%" SCNxPTR, &from, &to) != 2) + continue; + if (sp < to && sp > from) { + // We need to return the lowest byte of the stack. + *stack_addr = reinterpret_cast(from); + *stack_size = to - from; + fclose(fp); + return; + } + } + + fclose(fp); + } +} + +int pthread_getattr_np(pthread_t thread, pthread_attr_t *attr) { + auto tcb = reinterpret_cast(thread); + *attr = pthread_attr_t{}; + + if (!tcb->stackAddr || !tcb->stackSize) { + get_own_stackinfo(&attr->__mlibc_stackaddr, &attr->__mlibc_stacksize); + } else { + attr->__mlibc_stacksize = tcb->stackSize; + attr->__mlibc_stackaddr = tcb->stackAddr; + } + + attr->__mlibc_guardsize = tcb->guardSize; + attr->__mlibc_detachstate = tcb->isJoinable ? PTHREAD_CREATE_JOINABLE : PTHREAD_CREATE_DETACHED; + mlibc::infoLogger() << "pthread_getattr_np(): Implementation is incomplete!" << frg::endlog; + return 0; +} + +int pthread_getaffinity_np(pthread_t thread, size_t cpusetsize, cpu_set_t *mask) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_getthreadaffinity, ENOSYS); + return mlibc::sys_getthreadaffinity(reinterpret_cast(thread)->tid, cpusetsize, mask); +} + +int pthread_setaffinity_np(pthread_t thread, size_t cpusetsize, const cpu_set_t *mask) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_setthreadaffinity, ENOSYS); + return mlibc::sys_setthreadaffinity(reinterpret_cast(thread)->tid, cpusetsize, mask); +} +#endif // __MLIBC_LINUX_OPTION + +extern "C" Tcb *__rtdl_allocateTcb(); + +// pthread functions. +int pthread_create(pthread_t *__restrict thread, const pthread_attr_t *__restrict attrp, + void *(*entry) (void *), void *__restrict user_arg) { + return mlibc::thread_create(thread, attrp, reinterpret_cast(entry), user_arg, false); +} + +pthread_t pthread_self(void) { + return reinterpret_cast(mlibc::get_current_tcb()); +} + +int pthread_equal(pthread_t t1, pthread_t t2) { + if(t1 == t2) + return 1; + return 0; +} + +namespace { + struct key_global_info { + bool in_use; + + void (*dtor)(void *); + uint64_t generation; + }; + + constinit frg::array< + key_global_info, + PTHREAD_KEYS_MAX + > key_globals_{}; + + FutexLock key_mutex_; +} + +namespace mlibc { + __attribute__ ((__noreturn__)) void do_exit() { + sys_thread_exit(); + __builtin_unreachable(); + } +} + +__attribute__ ((__noreturn__)) void pthread_exit(void *ret_val) { + auto self = mlibc::get_current_tcb(); + + if (__atomic_load_n(&self->cancelBits, __ATOMIC_RELAXED) & tcbExitingBit) + mlibc::do_exit(); + + __atomic_fetch_or(&self->cancelBits, tcbExitingBit, __ATOMIC_RELAXED); + + auto hand = self->cleanupEnd; + while (hand) { + auto old = hand; + hand->func(hand->arg); + hand = hand->prev; + frg::destruct(getAllocator(), old); + } + + for (size_t j = 0; j < PTHREAD_DESTRUCTOR_ITERATIONS; j++) { + for (size_t i = 0; i < PTHREAD_KEYS_MAX; i++) { + if (auto v = pthread_getspecific(i)) { + key_mutex_.lock(); + auto dtor = key_globals_[i].dtor; + key_mutex_.unlock(); + + if (dtor) { + dtor(v); + (*self->localKeys)[i].value = nullptr; + } + } + } + } + + self->returnValue.voidPtr = ret_val; + __atomic_store_n(&self->didExit, 1, __ATOMIC_RELEASE); + mlibc::sys_futex_wake(&self->didExit); + + // TODO: clean up thread resources when we are detached. + + // TODO: do exit(0) when we're the only thread instead + mlibc::do_exit(); +} + +int pthread_join(pthread_t thread, void **ret) { + return mlibc::thread_join(thread, ret); +} + +int pthread_detach(pthread_t thread) { + auto tcb = reinterpret_cast(thread); + if (!__atomic_load_n(&tcb->isJoinable, __ATOMIC_RELAXED)) + return EINVAL; + + int expected = 1; + if(!__atomic_compare_exchange_n(&tcb->isJoinable, &expected, 0, false, __ATOMIC_RELEASE, + __ATOMIC_RELAXED)) + return EINVAL; + + return 0; +} + +void pthread_cleanup_push(void (*func) (void *), void *arg) { + auto self = mlibc::get_current_tcb(); + + auto hand = frg::construct(getAllocator()); + hand->func = func; + hand->arg = arg; + hand->next = nullptr; + hand->prev = self->cleanupEnd; + + if (self->cleanupEnd) + self->cleanupEnd->next = hand; + + self->cleanupEnd = hand; + + if (!self->cleanupBegin) + self->cleanupBegin = self->cleanupEnd; +} + +void pthread_cleanup_pop(int execute) { + auto self = mlibc::get_current_tcb(); + + auto hand = self->cleanupEnd; + + if (self->cleanupEnd) + self->cleanupEnd = self->cleanupEnd->prev; + if (self->cleanupEnd) + self->cleanupEnd->next = nullptr; + + if (execute) + hand->func(hand->arg); + + frg::destruct(getAllocator(), hand); +} + +int pthread_setname_np(pthread_t thread, const char *name) { + auto tcb = reinterpret_cast(thread); + + auto sysdep = MLIBC_CHECK_OR_ENOSYS(mlibc::sys_thread_setname, ENOSYS); + if(int e = sysdep(tcb, name); e) { + return e; + } + + return 0; +} + +int pthread_getname_np(pthread_t thread, char *name, size_t size) { + auto tcb = reinterpret_cast(thread); + + auto sysdep = MLIBC_CHECK_OR_ENOSYS(mlibc::sys_thread_getname, ENOSYS); + if(int e = sysdep(tcb, name, size); e) { + return e; + } + + return 0; +} + +int pthread_setschedparam(pthread_t thread, int policy, const struct sched_param *param) { + auto tcb = reinterpret_cast(thread); + + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_setschedparam, ENOSYS); + if(int e = mlibc::sys_setschedparam(tcb, policy, param); e) { + return e; + } + + return 0; +} + +int pthread_getschedparam(pthread_t thread, int *policy, struct sched_param *param) { + auto tcb = reinterpret_cast(thread); + + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_getschedparam, ENOSYS); + if(int e = mlibc::sys_getschedparam(tcb, policy, param); e) { + return e; + } + + return 0; +} + +//pthread cancel functions + +extern "C" void __mlibc_do_cancel() { + //TODO(geert): for now the same as pthread_exit() + pthread_exit(PTHREAD_CANCELED); +} + +namespace { + + void sigcancel_handler(int signal, siginfo_t *info, void *ucontext) { + ucontext_t *uctx = static_cast(ucontext); + // The function could be called from other signals, or from another + // process, in which case we should do nothing. + if (signal != SIGCANCEL || info->si_pid != getpid() || + info->si_code != SI_TKILL) + return; + + auto tcb = reinterpret_cast(mlibc::get_current_tcb()); + int old_value = tcb->cancelBits; + + /* + * When a thread is marked with deferred cancellation and performs a blocking syscall, + * the spec mandates that the syscall can get interrupted before it has caused any side + * effects (e.g. before a read() has read any bytes from disk). If the syscall has + * already caused side effects it should return its partial work, and set the program + * counter just after the syscall. If the syscall hasn't caused any side effects, it + * should fail with EINTR and set the program counter to the syscall instruction. + * + * cancellable_syscall: + * test whether_a_cancel_is_queued + * je cancel + * syscall + * end_cancellable_syscall + * + * The mlibc::sys_before_cancellable_syscall sysdep should return 1 when the + * program counter is between the 'canellable_syscall' and 'end_cancellable_syscall' label. + */ + if (!(old_value & tcbCancelAsyncBit) && + mlibc::sys_before_cancellable_syscall && !mlibc::sys_before_cancellable_syscall(uctx)) + return; + + int bitmask = tcbCancelTriggerBit | tcbCancelingBit; + while (1) { + int new_value = old_value | bitmask; + + // Check if we are already cancelled or exiting + if (old_value == new_value || old_value & tcbExitingBit) + return; + + int current_value = old_value; + if (__atomic_compare_exchange_n(&tcb->cancelBits, ¤t_value, + new_value, true,__ATOMIC_RELAXED, __ATOMIC_RELAXED)) { + tcb->returnValue.voidPtr = PTHREAD_CANCELED; + + // Perform cancellation + __mlibc_do_cancel(); + + break; + } + + old_value = current_value; + } + } +} + +namespace mlibc { +namespace { + +struct PthreadSignalInstaller { + PthreadSignalInstaller() { + struct sigaction sa; + sa.sa_sigaction = sigcancel_handler; + sa.sa_flags = SA_SIGINFO; + auto e = ENOSYS; + if(sys_sigaction) + e = sys_sigaction(SIGCANCEL, &sa, NULL); + // Opt-out of cancellation support. + if(e == ENOSYS) + return; + __ensure(!e); + } +}; + +PthreadSignalInstaller pthread_signal_installer; + +} // anonymous namespace +} // namespace mlibc + +int pthread_setcanceltype(int type, int *oldtype) { + if (type != PTHREAD_CANCEL_DEFERRED && type != PTHREAD_CANCEL_ASYNCHRONOUS) + return EINVAL; + + auto self = reinterpret_cast(mlibc::get_current_tcb()); + int old_value = self->cancelBits; + while (1) { + int new_value = old_value & ~tcbCancelAsyncBit; + if (type == PTHREAD_CANCEL_ASYNCHRONOUS) + new_value |= tcbCancelAsyncBit; + + if (oldtype) + *oldtype = ((old_value & tcbCancelAsyncBit) + ? PTHREAD_CANCEL_ASYNCHRONOUS + : PTHREAD_CANCEL_DEFERRED); + + // Avoid unecessary atomic op. + if (old_value == new_value) + break; + + int current_value = old_value; + if (__atomic_compare_exchange_n(&self->cancelBits, ¤t_value, + new_value, true, __ATOMIC_RELAXED, __ATOMIC_RELAXED)) { + + if (mlibc::tcb_async_cancelled(new_value)) + __mlibc_do_cancel(); + + break; + } + + old_value = current_value; + } + + return 0; +} +int pthread_setcancelstate(int state, int *oldstate) { + if (state != PTHREAD_CANCEL_ENABLE && state != PTHREAD_CANCEL_DISABLE) + return EINVAL; + + auto self = reinterpret_cast(mlibc::get_current_tcb()); + int old_value = self->cancelBits; + while (1) { + int new_value = old_value & ~tcbCancelEnableBit; + if (state == PTHREAD_CANCEL_ENABLE) + new_value |= tcbCancelEnableBit; + + if (oldstate) + *oldstate = ((old_value & tcbCancelEnableBit) + ? PTHREAD_CANCEL_ENABLE + : PTHREAD_CANCEL_DISABLE); + + // Avoid unecessary atomic op. + if (old_value == new_value) + break; + + int current_value = old_value; + if (__atomic_compare_exchange_n(&self->cancelBits, ¤t_value, + new_value, true, __ATOMIC_RELAXED, __ATOMIC_RELAXED)) { + + if (mlibc::tcb_async_cancelled(new_value)) + __mlibc_do_cancel(); + + sigset_t set = {}; + sigaddset(&set, SIGCANCEL); + if (new_value & PTHREAD_CANCEL_ENABLE) + sigprocmask(SIG_UNBLOCK, &set, NULL); + else + sigprocmask(SIG_BLOCK, &set, NULL); + break; + } + + old_value = current_value; + } + + return 0; +} +void pthread_testcancel(void) { + auto self = reinterpret_cast(mlibc::get_current_tcb()); + int value = self->cancelBits; + if ((value & tcbCancelEnableBit) && (value & tcbCancelTriggerBit)) { + __mlibc_do_cancel(); + __builtin_unreachable(); + } +} +int pthread_cancel(pthread_t thread) { + if (!mlibc::sys_tgkill) { + MLIBC_MISSING_SYSDEP(); + return ENOSYS; + } + + auto tcb = reinterpret_cast(thread); + // Check if the TCB is valid, somewhat.. + if (tcb->selfPointer != tcb) + return ESRCH; + + int old_value = __atomic_load_n(&tcb->cancelBits, __ATOMIC_RELAXED); + while (1) { + int bitmask = tcbCancelTriggerBit; + + int new_value = old_value | bitmask; + if (old_value == new_value) + break; + + int current_value = old_value; + if (__atomic_compare_exchange_n(&tcb->cancelBits, ¤t_value, + new_value, true, __ATOMIC_RELAXED, __ATOMIC_RELAXED)) { + if (mlibc::tcb_cancel_enabled(new_value)) { + pid_t pid = getpid(); + + int res = mlibc::sys_tgkill(pid, tcb->tid, SIGCANCEL); + + current_value = __atomic_load_n(&tcb->cancelBits, __ATOMIC_RELAXED); + + // If we can't find the thread anymore, it's possible that it exited between + // us setting the cancel trigger bit, and us sending the signal. Check the + // cancelBits for tcbExitingBit to confirm that. + // XXX(qookie): This will be an use-after-free once we start freeing TCBs on + // exit. Perhaps the TCB should be refcounted. + if (!(res == ESRCH && (current_value & tcbExitingBit))) + return res; + } + + break; + } + + old_value = current_value; + } + + return 0; +} + +int pthread_atfork(void (*prepare) (void), void (*parent) (void), void (*child) (void)) { + auto self = mlibc::get_current_tcb(); + + auto hand = frg::construct(getAllocator()); + if (!hand) + return -1; + + hand->prepare = prepare; + hand->parent = parent; + hand->child = child; + hand->next = nullptr; + hand->prev = self->atforkEnd; + + if (self->atforkEnd) + self->atforkEnd->next = hand; + + self->atforkEnd = hand; + + if (!self->atforkBegin) + self->atforkBegin = self->atforkEnd; + + return 0; +} + +// ---------------------------------------------------------------------------- +// pthread_key functions. +// ---------------------------------------------------------------------------- + +int pthread_key_create(pthread_key_t *out, void (*destructor)(void *)) { + SCOPE_TRACE(); + + auto g = frg::guard(&key_mutex_); + + pthread_key_t key = PTHREAD_KEYS_MAX; + for (size_t i = 0; i < PTHREAD_KEYS_MAX; i++) { + if (!key_globals_[i].in_use) { + key = i; + break; + } + } + + if (key == PTHREAD_KEYS_MAX) + return EAGAIN; + + key_globals_[key].in_use = true; + key_globals_[key].dtor = destructor; + + *out = key; + + return 0; +} + +int pthread_key_delete(pthread_key_t key) { + SCOPE_TRACE(); + + auto g = frg::guard(&key_mutex_); + + if (key >= PTHREAD_KEYS_MAX || !key_globals_[key].in_use) + return EINVAL; + + key_globals_[key].in_use = false; + key_globals_[key].dtor = nullptr; + key_globals_[key].generation++; + + return 0; +} + +void *pthread_getspecific(pthread_key_t key) { + SCOPE_TRACE(); + + auto self = mlibc::get_current_tcb(); + auto g = frg::guard(&key_mutex_); + + if (key >= PTHREAD_KEYS_MAX || !key_globals_[key].in_use) + return nullptr; + + if (key_globals_[key].generation > (*self->localKeys)[key].generation) { + (*self->localKeys)[key].value = nullptr; + (*self->localKeys)[key].generation = key_globals_[key].generation; + } + + return (*self->localKeys)[key].value; +} + +int pthread_setspecific(pthread_key_t key, const void *value) { + SCOPE_TRACE(); + + auto self = mlibc::get_current_tcb(); + auto g = frg::guard(&key_mutex_); + + if (key >= PTHREAD_KEYS_MAX || !key_globals_[key].in_use) + return EINVAL; + + (*self->localKeys)[key].value = const_cast(value); + (*self->localKeys)[key].generation = key_globals_[key].generation; + + return 0; +} + +// ---------------------------------------------------------------------------- +// pthread_once functions. +// ---------------------------------------------------------------------------- + +static constexpr unsigned int onceComplete = 1; +static constexpr unsigned int onceLocked = 2; + +int pthread_once(pthread_once_t *once, void (*function) (void)) { + SCOPE_TRACE(); + + auto expected = __atomic_load_n(&once->__mlibc_done, __ATOMIC_ACQUIRE); + + // fast path: the function was already run. + while(!(expected & onceComplete)) { + if(!expected) { + // try to acquire the mutex. + if(!__atomic_compare_exchange_n(&once->__mlibc_done, + &expected, onceLocked, false, __ATOMIC_ACQUIRE, __ATOMIC_ACQUIRE)) + continue; + + function(); + + // unlock the mutex. + __atomic_exchange_n(&once->__mlibc_done, onceComplete, __ATOMIC_RELEASE); + if(int e = mlibc::sys_futex_wake((int *)&once->__mlibc_done); e) + __ensure(!"sys_futex_wake() failed"); + return 0; + }else{ + // a different thread is currently running the initializer. + __ensure(expected == onceLocked); + if(int e = mlibc::sys_futex_wait((int *)&once->__mlibc_done, onceLocked, nullptr); e) + __ensure(!"sys_futex_wait() failed"); + expected = __atomic_load_n(&once->__mlibc_done, __ATOMIC_ACQUIRE); + } + } + + return 0; +} + +// ---------------------------------------------------------------------------- +// pthread_mutexattr and pthread_mutex functions. +// ---------------------------------------------------------------------------- + +// pthread_mutexattr functions +int pthread_mutexattr_init(pthread_mutexattr_t *attr) { + SCOPE_TRACE(); + return mlibc::thread_mutexattr_init(attr); +} + +int pthread_mutexattr_destroy(pthread_mutexattr_t *attr) { + SCOPE_TRACE(); + return mlibc::thread_mutexattr_destroy(attr); +} + +int pthread_mutexattr_gettype(const pthread_mutexattr_t *__restrict attr, int *__restrict type) { + return mlibc::thread_mutexattr_gettype(attr, type); +} + +int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type) { + return mlibc::thread_mutexattr_settype(attr, type); +} + +int pthread_mutexattr_getrobust(const pthread_mutexattr_t *__restrict attr, + int *__restrict robust) { + *robust = attr->__mlibc_robust; + return 0; +} +int pthread_mutexattr_setrobust(pthread_mutexattr_t *attr, int robust) { + if (robust != PTHREAD_MUTEX_STALLED && robust != PTHREAD_MUTEX_ROBUST) + return EINVAL; + + attr->__mlibc_robust = robust; + return 0; +} + +int pthread_mutexattr_getpshared(const pthread_mutexattr_t *attr, int *pshared) { + *pshared = attr->__mlibc_pshared; + return 0; +} +int pthread_mutexattr_setpshared(pthread_mutexattr_t *attr, int pshared) { + if (pshared != PTHREAD_PROCESS_PRIVATE && pshared != PTHREAD_PROCESS_SHARED) + return EINVAL; + + attr->__mlibc_pshared = pshared; + return 0; +} + +int pthread_mutexattr_getprotocol(const pthread_mutexattr_t *__restrict attr, + int *__restrict protocol) { + *protocol = attr->__mlibc_protocol; + return 0; +} + +int pthread_mutexattr_setprotocol(pthread_mutexattr_t *attr, int protocol) { + if (protocol != PTHREAD_PRIO_NONE && protocol != PTHREAD_PRIO_INHERIT + && protocol != PTHREAD_PRIO_PROTECT) + return EINVAL; + + attr->__mlibc_protocol = protocol; + return 0; +} + +int pthread_mutexattr_getprioceiling(const pthread_mutexattr_t *__restrict attr, + int *__restrict prioceiling) { + (void)attr; + (void)prioceiling; + return EINVAL; +} + +int pthread_mutexattr_setprioceiling(pthread_mutexattr_t *attr, int prioceiling) { + (void)attr; + (void)prioceiling; + return EINVAL; +} + +// pthread_mutex functions +int pthread_mutex_init(pthread_mutex_t *__restrict mutex, + const pthread_mutexattr_t *__restrict attr) { + SCOPE_TRACE(); + + return mlibc::thread_mutex_init(mutex, attr); +} + +int pthread_mutex_destroy(pthread_mutex_t *mutex) { + return mlibc::thread_mutex_destroy(mutex); +} + +int pthread_mutex_lock(pthread_mutex_t *mutex) { + SCOPE_TRACE(); + + return mlibc::thread_mutex_lock(mutex); +} + +int pthread_mutex_trylock(pthread_mutex_t *mutex) { + SCOPE_TRACE(); + + unsigned int this_tid = mlibc::this_tid(); + unsigned int expected = __atomic_load_n(&mutex->__mlibc_state, __ATOMIC_RELAXED); + if(!expected) { + // Try to take the mutex here. + if(__atomic_compare_exchange_n(&mutex->__mlibc_state, + &expected, this_tid, false, __ATOMIC_ACQUIRE, __ATOMIC_ACQUIRE)) { + __ensure(!mutex->__mlibc_recursion); + mutex->__mlibc_recursion = 1; + return 0; + } + } else { + // If this (recursive) mutex is already owned by us, increment the recursion level. + if((expected & mutex_owner_mask) == this_tid) { + if(!(mutex->__mlibc_flags & mutexRecursive)) { + return EBUSY; + } + ++mutex->__mlibc_recursion; + return 0; + } + } + + return EBUSY; +} + +int pthread_mutex_timedlock(pthread_mutex_t *__restrict, + const struct timespec *__restrict) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +int pthread_mutex_unlock(pthread_mutex_t *mutex) { + SCOPE_TRACE(); + + return mlibc::thread_mutex_unlock(mutex); +} + +int pthread_mutex_consistent(pthread_mutex_t *) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +// ---------------------------------------------------------------------------- +// pthread_condattr and pthread_cond functions. +// ---------------------------------------------------------------------------- + +int pthread_condattr_init(pthread_condattr_t *attr) { + attr->__mlibc_pshared = PTHREAD_PROCESS_PRIVATE; + attr->__mlibc_clock = CLOCK_REALTIME; + return 0; +} + +int pthread_condattr_destroy(pthread_condattr_t *attr) { + memset(attr, 0, sizeof(*attr)); + return 0; +} + +int pthread_condattr_getclock(const pthread_condattr_t *__restrict attr, + clockid_t *__restrict clock) { + *clock = attr->__mlibc_clock; + return 0; +} + +int pthread_condattr_setclock(pthread_condattr_t *attr, clockid_t clock) { + if (clock != CLOCK_REALTIME && clock != CLOCK_MONOTONIC + && clock != CLOCK_MONOTONIC_RAW && clock != CLOCK_REALTIME_COARSE + && clock != CLOCK_MONOTONIC_COARSE && clock != CLOCK_BOOTTIME) + return EINVAL; + + attr->__mlibc_clock = clock; + return 0; +} + +int pthread_condattr_getpshared(const pthread_condattr_t *__restrict attr, + int *__restrict pshared) { + *pshared = attr->__mlibc_pshared; + return 0; +} + +int pthread_condattr_setpshared(pthread_condattr_t *attr, int pshared) { + if (pshared != PTHREAD_PROCESS_PRIVATE && pshared != PTHREAD_PROCESS_SHARED) + return EINVAL; + + attr->__mlibc_pshared = pshared; + return 0; +} + +int pthread_cond_init(pthread_cond_t *__restrict cond, const pthread_condattr_t *__restrict attr) { + SCOPE_TRACE(); + + return mlibc::thread_cond_init(cond, attr); +} + +int pthread_cond_destroy(pthread_cond_t *cond) { + SCOPE_TRACE(); + + return mlibc::thread_cond_destroy(cond); +} + +int pthread_cond_wait(pthread_cond_t *__restrict cond, pthread_mutex_t *__restrict mutex) { + return pthread_cond_timedwait(cond, mutex, nullptr); +} + +int pthread_cond_timedwait(pthread_cond_t *__restrict cond, pthread_mutex_t *__restrict mutex, + const struct timespec *__restrict abstime) { + return mlibc::thread_cond_timedwait(cond, mutex, abstime); +} + +int pthread_cond_signal(pthread_cond_t *cond) { + SCOPE_TRACE(); + + return pthread_cond_broadcast(cond); +} + +int pthread_cond_broadcast(pthread_cond_t *cond) { + SCOPE_TRACE(); + + return mlibc::thread_cond_broadcast(cond); +} + +// ---------------------------------------------------------------------------- +// pthread_barrierattr and pthread_barrier functions. +// ---------------------------------------------------------------------------- + +int pthread_barrierattr_init(pthread_barrierattr_t *attr) { + attr->__mlibc_pshared = PTHREAD_PROCESS_PRIVATE; + return 0; +} + +int pthread_barrierattr_getpshared(const pthread_barrierattr_t *__restrict attr, + int *__restrict pshared) { + *pshared = attr->__mlibc_pshared; + return 0; +} + +int pthread_barrierattr_setpshared(pthread_barrierattr_t *attr, int pshared) { + if (pshared != PTHREAD_PROCESS_SHARED && pshared != PTHREAD_PROCESS_PRIVATE) + return EINVAL; + + attr->__mlibc_pshared = pshared; + return 0; +} + +int pthread_barrierattr_destroy(pthread_barrierattr_t *) { + return 0; +} + +int pthread_barrier_init(pthread_barrier_t *__restrict barrier, + const pthread_barrierattr_t *__restrict attr, unsigned count) { + if (count == 0) + return EINVAL; + + barrier->__mlibc_waiting = 0; + barrier->__mlibc_inside = 0; + barrier->__mlibc_seq = 0; + barrier->__mlibc_count = count; + + // Since we don't implement these yet, set a flag to error later. + auto pshared = attr ? attr->__mlibc_pshared : PTHREAD_PROCESS_PRIVATE; + barrier->__mlibc_flags = pshared; + + return 0; +} + +int pthread_barrier_destroy(pthread_barrier_t *barrier) { + // Wait until there are no threads still using the barrier. + unsigned inside = 0; + do { + unsigned expected = __atomic_load_n(&barrier->__mlibc_inside, __ATOMIC_RELAXED); + if (expected == 0) + break; + + int e = mlibc::sys_futex_wait((int *)&barrier->__mlibc_inside, expected, nullptr); + if (e != 0 && e != EAGAIN && e != EINTR) + mlibc::panicLogger() << "mlibc: sys_futex_wait() returned error " << e << frg::endlog; + } while (inside > 0); + + memset(barrier, 0, sizeof *barrier); + return 0; +} + +int pthread_barrier_wait(pthread_barrier_t *barrier) { + if (barrier->__mlibc_flags != 0) { + mlibc::panicLogger() << "mlibc: pthread_barrier_t flags were non-zero" + << frg::endlog; + } + + // inside is incremented on entry and decremented on exit. + // This is used to synchronise with pthread_barrier_destroy, to ensure that a thread doesn't pass + // the barrier and immediately destroy its state while other threads still rely on it. + + __atomic_fetch_add(&barrier->__mlibc_inside, 1, __ATOMIC_ACQUIRE); + + auto leave = [&](){ + unsigned inside = __atomic_sub_fetch(&barrier->__mlibc_inside, 1, __ATOMIC_RELEASE); + if (inside == 0) + mlibc::sys_futex_wake((int *)&barrier->__mlibc_inside); + }; + + unsigned seq = __atomic_load_n(&barrier->__mlibc_seq, __ATOMIC_ACQUIRE); + + while (true) { + unsigned expected = __atomic_load_n(&barrier->__mlibc_waiting, __ATOMIC_RELAXED); + bool swapped = __atomic_compare_exchange_n(&barrier->__mlibc_waiting, &expected, expected + 1, false, __ATOMIC_ACQUIRE, __ATOMIC_ACQUIRE); + + if (swapped) { + if (expected + 1 == barrier->__mlibc_count) { + // We were the last thread to hit the barrier. Reset waiters and wake the others. + __atomic_fetch_add(&barrier->__mlibc_seq, 1, __ATOMIC_ACQUIRE); + __atomic_store_n(&barrier->__mlibc_waiting, 0, __ATOMIC_RELEASE); + + mlibc::sys_futex_wake((int *)&barrier->__mlibc_seq); + + leave(); + return PTHREAD_BARRIER_SERIAL_THREAD; + } + + while (true) { + int e = mlibc::sys_futex_wait((int *)&barrier->__mlibc_seq, seq, nullptr); + if (e != 0 && e != EAGAIN && e != EINTR) + mlibc::panicLogger() << "mlibc: sys_futex_wait() returned error " << e << frg::endlog; + + unsigned newSeq = __atomic_load_n(&barrier->__mlibc_seq, __ATOMIC_ACQUIRE); + if (newSeq > seq) { + leave(); + return 0; + } + } + } + } +} + +// ---------------------------------------------------------------------------- +// pthread_rwlock functions. +// ---------------------------------------------------------------------------- + +namespace { + void rwlock_m_lock(pthread_rwlock_t *rw, bool excl) { + unsigned int m_expected = __atomic_load_n(&rw->__mlibc_m, __ATOMIC_RELAXED); + while(true) { + if(m_expected) { + __ensure(m_expected & mutex_owner_mask); + + // Try to set the waiters bit. + if(!(m_expected & mutex_waiters_bit)) { + unsigned int desired = m_expected | mutex_waiters_bit; + if(!__atomic_compare_exchange_n(&rw->__mlibc_m, + &m_expected, desired, false, __ATOMIC_RELAXED, __ATOMIC_RELAXED)) + continue; + } + + // Wait on the futex. + mlibc::sys_futex_wait((int *)&rw->__mlibc_m, m_expected | mutex_waiters_bit, nullptr); + + // Opportunistically try to take the lock after we wake up. + m_expected = 0; + }else{ + // Try to lock the mutex. + unsigned int desired = 1; + if(excl) + desired |= mutex_excl_bit; + if(__atomic_compare_exchange_n(&rw->__mlibc_m, + &m_expected, desired, false, __ATOMIC_ACQUIRE, __ATOMIC_RELAXED)) + break; + } + } + } + + int rwlock_m_trylock(pthread_rwlock_t *rw, bool excl) { + unsigned int m_expected = __atomic_load_n(&rw->__mlibc_m, __ATOMIC_RELAXED); + if(!m_expected) { + // Try to lock the mutex. + unsigned int desired = 1; + if(excl) + desired |= mutex_excl_bit; + if(__atomic_compare_exchange_n(&rw->__mlibc_m, + &m_expected, desired, false, __ATOMIC_ACQUIRE, __ATOMIC_RELAXED)) + return 0; + } + + __ensure(m_expected & mutex_owner_mask); + + // POSIX says that this function should never block but also that + // readers should not be blocked by readers. We implement this by returning EAGAIN + // (and not EBUSY) if a reader would block a reader. + if(!excl && !(m_expected & mutex_excl_bit)) + return EAGAIN; + + return EBUSY; + } + + void rwlock_m_unlock(pthread_rwlock_t *rw) { + auto m = __atomic_exchange_n(&rw->__mlibc_m, 0, __ATOMIC_RELEASE); + if(m & mutex_waiters_bit) + mlibc::sys_futex_wake((int *)&rw->__mlibc_m); + } +} + +int pthread_rwlockattr_init(pthread_rwlockattr_t *attr) { + attr->__mlibc_pshared = PTHREAD_PROCESS_PRIVATE; + return 0; +} + +int pthread_rwlockattr_getpshared(const pthread_rwlockattr_t *__restrict attr, + int *__restrict pshared) { + *pshared = attr->__mlibc_pshared; + return 0; +} + +int pthread_rwlockattr_setpshared(pthread_rwlockattr_t *attr, int pshared) { + if (pshared != PTHREAD_PROCESS_SHARED && pshared != PTHREAD_PROCESS_PRIVATE) + return EINVAL; + + attr->__mlibc_pshared = pshared; + return 0; +} + +int pthread_rwlockattr_destroy(pthread_rwlockattr_t *) { + return 0; +} + +int pthread_rwlock_init(pthread_rwlock_t *__restrict rw, const pthread_rwlockattr_t *__restrict attr) { + SCOPE_TRACE(); + rw->__mlibc_m = 0; + rw->__mlibc_rc = 0; + + // Since we don't implement this yet, set a flag to error later. + auto pshared = attr ? attr->__mlibc_pshared : PTHREAD_PROCESS_PRIVATE; + rw->__mlibc_flags = pshared; + return 0; +} + +int pthread_rwlock_destroy(pthread_rwlock_t *rw) { + __ensure(!rw->__mlibc_m); + __ensure(!rw->__mlibc_rc); + return 0; +} + +int pthread_rwlock_trywrlock(pthread_rwlock_t *rw) { + SCOPE_TRACE(); + + if (rw->__mlibc_flags != 0) { + mlibc::panicLogger() << "mlibc: pthread_rwlock_t flags were non-zero" + << frg::endlog; + } + + // Take the __mlibc_m mutex. + // Will be released in pthread_rwlock_unlock(). + if(int e = rwlock_m_trylock(rw, true)) + return e; + + // Check that there are no readers. + unsigned int rc_expected = __atomic_load_n(&rw->__mlibc_rc, __ATOMIC_ACQUIRE); + if(rc_expected) { + rwlock_m_unlock(rw); + return EBUSY; + } + + return 0; +} + +int pthread_rwlock_wrlock(pthread_rwlock_t *rw) { + SCOPE_TRACE(); + + if (rw->__mlibc_flags != 0) { + mlibc::panicLogger() << "mlibc: pthread_rwlock_t flags were non-zero" + << frg::endlog; + } + + // Take the __mlibc_m mutex. + // Will be released in pthread_rwlock_unlock(). + rwlock_m_lock(rw, true); + + // Now wait until there are no more readers. + unsigned int rc_expected = __atomic_load_n(&rw->__mlibc_rc, __ATOMIC_ACQUIRE); + while(true) { + if(!rc_expected) + break; + + __ensure(rc_expected & rc_count_mask); + + // Try to set the waiters bit. + if(!(rc_expected & rc_waiters_bit)) { + unsigned int desired = rc_expected | rc_count_mask; + if(!__atomic_compare_exchange_n(&rw->__mlibc_rc, + &rc_expected, desired, false, __ATOMIC_ACQUIRE, __ATOMIC_ACQUIRE)) + continue; + } + + // Wait on the futex. + mlibc::sys_futex_wait((int *)&rw->__mlibc_rc, rc_expected | rc_waiters_bit, nullptr); + + // Re-check the reader counter. + rc_expected = __atomic_load_n(&rw->__mlibc_rc, __ATOMIC_ACQUIRE); + } + + return 0; +} + +int pthread_rwlock_tryrdlock(pthread_rwlock_t *rw) { + SCOPE_TRACE(); + + if (rw->__mlibc_flags != 0) { + mlibc::panicLogger() << "mlibc: pthread_rwlock_t flags were non-zero" + << frg::endlog; + } + + // Increment the reader count while holding the __mlibc_m mutex. + if(int e = rwlock_m_trylock(rw, false); e) + return e; + __atomic_fetch_add(&rw->__mlibc_rc, 1, __ATOMIC_ACQUIRE); + rwlock_m_unlock(rw); + + return 0; +} + +int pthread_rwlock_rdlock(pthread_rwlock_t *rw) { + SCOPE_TRACE(); + + if (rw->__mlibc_flags != 0) { + mlibc::panicLogger() << "mlibc: pthread_rwlock_t flags were non-zero" + << frg::endlog; + } + + // Increment the reader count while holding the __mlibc_m mutex. + rwlock_m_lock(rw, false); + __atomic_fetch_add(&rw->__mlibc_rc, 1, __ATOMIC_ACQUIRE); + rwlock_m_unlock(rw); + + return 0; +} + +int pthread_rwlock_unlock(pthread_rwlock_t *rw) { + SCOPE_TRACE(); + + unsigned int rc_expected = __atomic_load_n(&rw->__mlibc_rc, __ATOMIC_RELAXED); + if(!rc_expected) { + // We are doing a write-unlock. + rwlock_m_unlock(rw); + return 0; + }else{ + // We are doing a read-unlock. + while(true) { + unsigned int count = rc_expected & rc_count_mask; + __ensure(count); + + // Try to decrement the count. + if(count == 1 && (rc_expected & rc_waiters_bit)) { + unsigned int desired = 0; + if(!__atomic_compare_exchange_n(&rw->__mlibc_rc, + &rc_expected, desired, false, __ATOMIC_RELEASE, __ATOMIC_RELAXED)) + continue; + + // Wake the futex. + mlibc::sys_futex_wake((int *)&rw->__mlibc_rc); + break; + }else{ + unsigned int desired = (rc_expected & ~rc_count_mask) | (count - 1); + if(!__atomic_compare_exchange_n(&rw->__mlibc_rc, + &rc_expected, desired, false, __ATOMIC_RELEASE, __ATOMIC_RELAXED)) + continue; + break; + } + } + + return 0; + } +} + +int pthread_getcpuclockid(pthread_t, clockid_t *) { + mlibc::infoLogger() << "mlibc: pthread_getcpuclockid() always returns ENOENT" + << frg::endlog; + return ENOENT; +} diff --git a/lib/mlibc/options/posix/generic/pwd-stubs.cpp b/lib/mlibc/options/posix/generic/pwd-stubs.cpp new file mode 100644 index 0000000..5d8f618 --- /dev/null +++ b/lib/mlibc/options/posix/generic/pwd-stubs.cpp @@ -0,0 +1,284 @@ + +#include +#include +#include +#include +#include + +#include + +namespace { + FILE *global_file; // Used by setpwent/getpwent/endpwent. + + bool open_global_file() { + if(!global_file) { + global_file = fopen("/etc/passwd", "r"); + if(!global_file) { + errno = EIO; + return false; + } + } + + return true; + } + + void close_global_file() { + if(global_file) { + fclose(global_file); + global_file = nullptr; + } + } + + bool extract_entry(frg::string_view line, passwd *entry) { + frg::string_view segments[8]; + + // Parse the line into 7 or 8 segments. + size_t s = 0; + int n; + for(n = 0; n < 7; n++) { + size_t d = line.find_first(':', s); + if(d == size_t(-1)) + break; + segments[n] = line.sub_string(s, d - s); + s = d + 1; + } + if(line.find_first(':', s) != size_t(-1)) + return false; + segments[n] = line.sub_string(s, line.size() - s); + n++; + + if(n < 7) + return false; + + // TODO: Handle strndup() failure. + auto name = strndup(segments[0].data(), segments[0].size()); + __ensure(name); + + auto passwd = strndup(segments[1].data(), segments[1].size()); + __ensure(passwd); + + auto uid = segments[2].to_number(); + if(!uid) + return false; + auto gid = segments[3].to_number(); + if(!gid) + return false; + + auto real_name = strndup(segments[4].data(), segments[4].size()); + __ensure(real_name); + auto dir = strndup(segments[5].data(), segments[5].size()); + __ensure(dir); + auto shell = strndup(segments[6].data(), segments[6].size()); + __ensure(shell); + + // Chop the newline off the end of shell + __ensure(strlen(shell) > 0); + shell[strlen(shell) - 1] = '\0'; + + entry->pw_name = name; + entry->pw_passwd = passwd; + entry->pw_uid = *uid; + entry->pw_gid = *gid; + entry->pw_dir = dir; + entry->pw_shell = shell; + entry->pw_gecos = real_name; + return true; + } + + void copy_to_buffer(passwd *pwd, char *buffer, size_t size) { + char *pw_dir = stpcpy(buffer, pwd->pw_name) + 1; + free(pwd->pw_name); + pwd->pw_name = buffer; + + char *pw_shell = stpcpy(pw_dir, pwd->pw_dir) + 1; + free(pwd->pw_dir); + pwd->pw_dir = pw_dir; + + char *pw_passwd = stpcpy(pw_shell, pwd->pw_shell) + 1; + free(pwd->pw_shell); + pwd->pw_shell = pw_shell; + + char *end = stpcpy(pw_passwd, pwd->pw_passwd); + __ensure(end <= buffer + size); + free(pwd->pw_passwd); + pwd->pw_passwd = pw_passwd; + } + + void clear_entry(passwd *entry) { + free(entry->pw_name); + free(entry->pw_dir); + free(entry->pw_passwd); + free(entry->pw_shell); + entry->pw_name = nullptr; + entry->pw_dir = nullptr; + entry->pw_passwd = nullptr; + entry->pw_shell = nullptr; + } +} + +struct passwd *getpwent(void) { + static passwd entry; + char line[NSS_BUFLEN_PASSWD]; + + if(!open_global_file()) { + return nullptr; + } + + if (fgets(line, NSS_BUFLEN_PASSWD, global_file)) { + clear_entry(&entry); + if(!extract_entry(line, &entry)) { + errno = EINVAL; // I suppose this can be a valid errno? + return nullptr; + } + return &entry; + } + + if(ferror(global_file)) { + errno = EIO; + } + + return nullptr; +} + +struct passwd *getpwnam(const char *name) { + static passwd entry; + auto file = fopen("/etc/passwd", "r"); + if(!file) + return nullptr; + + char line[NSS_BUFLEN_PASSWD]; + while(fgets(line, NSS_BUFLEN_PASSWD, file)) { + clear_entry(&entry); + if(!extract_entry(line, &entry)) + continue; + if(!strcmp(entry.pw_name, name)) { + fclose(file); + return &entry; + } + } + + int err = errno; + if(ferror(file)) { + err = EIO; + } + + fclose(file); + errno = err; + return nullptr; +} + +int getpwnam_r(const char *name, struct passwd *pwd, char *buffer, size_t size, struct passwd **result) { + *result = nullptr; + auto file = fopen("/etc/passwd", "r"); + if(!file) { + return EIO; + } + + char line[NSS_BUFLEN_PASSWD]; + while(fgets(line, NSS_BUFLEN_PASSWD, file)) { + if(!extract_entry(line, pwd)) + continue; + if(!strcmp(pwd->pw_name, name)) { + fclose(file); + + size_t required_size = strlen(pwd->pw_name) + strlen(pwd->pw_dir) + + strlen(pwd->pw_shell) + strlen(pwd->pw_passwd) + 4; + if (size < required_size) + return ERANGE; + + copy_to_buffer(pwd, buffer, size); + *result = pwd; + return 0; + } + } + + int ret = 0; + if(ferror(file)) { + ret = EIO; + } + + fclose(file); + return ret; +} + +struct passwd *getpwuid(uid_t uid) { + static passwd entry; + auto file = fopen("/etc/passwd", "r"); + if(!file) + return nullptr; + + char line[NSS_BUFLEN_PASSWD]; + while(fgets(line, NSS_BUFLEN_PASSWD, file)) { + clear_entry(&entry); + if(!extract_entry(line, &entry)) + continue; + if(entry.pw_uid == uid) { + fclose(file); + return &entry; + } + } + + int err = ESRCH; + if(ferror(file)) { + err = EIO; + } + + fclose(file); + errno = err; + return nullptr; +} + +int getpwuid_r(uid_t uid, struct passwd *pwd, char *buffer, size_t size, struct passwd **result) { + *result = nullptr; + auto file = fopen("/etc/passwd", "r"); + if(!file) { + return EIO; + } + + char line[NSS_BUFLEN_PASSWD]; + while(fgets(line, NSS_BUFLEN_PASSWD, file)) { + if(!extract_entry(line, pwd)) + continue; + if(pwd->pw_uid == uid) { + fclose(file); + + size_t required_size = strlen(pwd->pw_name) + strlen(pwd->pw_dir) + + strlen(pwd->pw_shell) + + strlen(pwd->pw_passwd) + 4; + if (size < required_size) + return ERANGE; + + copy_to_buffer(pwd, buffer, size); + *result = pwd; + return 0; + } + } + + int ret = 0; + if(ferror(file)) { + ret = EIO; + } + + fclose(file); + return ret; +} + +void setpwent(void) { + if(!open_global_file()) { + return; + } + rewind(global_file); +} + +void endpwent(void) { + close_global_file(); +} + +int putpwent(const struct passwd *, FILE *) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +struct passwd *fgetpwent(FILE *) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} diff --git a/lib/mlibc/options/posix/generic/resolv_conf.cpp b/lib/mlibc/options/posix/generic/resolv_conf.cpp new file mode 100644 index 0000000..a5c3aa7 --- /dev/null +++ b/lib/mlibc/options/posix/generic/resolv_conf.cpp @@ -0,0 +1,42 @@ +#include +#include +#include +#include + +namespace mlibc { + +frg::optional get_nameserver() { + auto file = fopen("/etc/resolv.conf", "r"); + if (!file) + return frg::null_opt; + + char line[128]; + struct nameserver_data ret; + while (fgets(line, 128, file)) { + char *pos; + if (!strchr(line, '\n') && !feof(file)) { + // skip truncated lines + for (int c = getc(file); c != '\n' && c != EOF; c = getc(file)); + continue; + } + + // TODO(geert): resolv.conf can actually have multiple nameservers + // but we just pick the first one for now + if (!strncmp(line, "nameserver", 10) && isspace(line[10])) { + char *end; + for (pos = line + 11; isspace(*pos); pos++); + for (end = pos; *end && !isspace(*end); end++); + *end = '\0'; + ret.name = frg::string( + pos, end - pos, getAllocator()); + break; + } + } + + fclose(file); + if(ret.name.empty()) + return frg::null_opt; + return ret; +} + +} // namespace mlibc diff --git a/lib/mlibc/options/posix/generic/sched-stubs.cpp b/lib/mlibc/options/posix/generic/sched-stubs.cpp new file mode 100644 index 0000000..9d75d50 --- /dev/null +++ b/lib/mlibc/options/posix/generic/sched-stubs.cpp @@ -0,0 +1,50 @@ + +#include +#include +#include +#include + +#include +#include + +int sched_yield(void) { + if(mlibc::sys_yield) { + mlibc::sys_yield(); + }else{ + // Missing sched_yield() is not an error. + MLIBC_MISSING_SYSDEP(); + } + return 0; +} + +int sched_get_priority_max(int policy) { + int res = 0; + + auto sysdep = MLIBC_CHECK_OR_ENOSYS(mlibc::sys_get_max_priority, -1); + if(int e = sysdep(policy, &res); e) { + errno = e; + return -1; + } + return res; +} + +int sched_get_priority_min(int policy) { + int res = 0; + + auto sysdep = MLIBC_CHECK_OR_ENOSYS(mlibc::sys_get_min_priority, -1); + if(int e = sysdep(policy, &res); e) { + errno = e; + return -1; + } + return res; +} + +int sched_setscheduler(pid_t, int, const struct sched_param *) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +int sched_getparam(pid_t, struct sched_param *) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} diff --git a/lib/mlibc/options/posix/generic/search.cpp b/lib/mlibc/options/posix/generic/search.cpp new file mode 100644 index 0000000..e6f8c1d --- /dev/null +++ b/lib/mlibc/options/posix/generic/search.cpp @@ -0,0 +1,151 @@ + +#include +#include +#include +#include +#include +#include +#include + +struct node { + const void *key; + void *a[2]; + int h; +}; + +namespace { + int height(struct node *node) { + return node ? node->h : 0; + } + + int rotate(struct node **nodep, int side) { + struct node *node = *nodep; + struct node *x = static_cast(node->a[side]); + struct node *y = static_cast(x->a[!side]); + struct node *z = static_cast(x->a[side]); + + int height_node = node->h; + int height_y = height(y); + if (height_y > height(z)) { + // Perform double rotation + node->a[side] = y->a[!side]; + x->a[!side] = y->a[side]; + y->a[!side] = node; + y->a[side] = x; + node->h = height_y; + x->h = height_y; + y->h = height_y + 1; + } else { + // Perform single rotation + node->a[side] = y; + x->a[!side] = node; + node->h = height_y + 1; + x->h = height_y + 2; + y = x; + + } + *nodep = y; + return y->h - height_node; + } + + int balance_tree(struct node **nodep) { + struct node *node = *nodep; + int height_a = height(static_cast(node->a[0])); + int height_b = height(static_cast(node->a[1])); + if (height_a - height_b < 2) { + int old = node->h; + node->h = height_a < height_b ? height_b + 1 : height_a + 1; + return node->h - old; + } + + return rotate(nodep, height_a < height_b); + } +} + +void *tsearch(const void *key, void **rootp, int(*compar)(const void *, const void *)) { + if (!rootp) + return NULL; + + struct node *n = static_cast(*rootp); + frg::stack nodes(getAllocator()); + nodes.push(reinterpret_cast(rootp)); + int c = 0; + for (;;) { + if (!n) + break; + c = compar(key, n->key); + if (!c) + return n; + nodes.push(reinterpret_cast(&n->a[c > 0])); + n = static_cast(n->a[c > 0]); + } + + struct node *insert = static_cast(malloc(sizeof(struct node))); + if (!insert) + return NULL; + insert->key = key; + insert->a[0] = insert->a[1] = NULL; + insert->h = 1; + + (*nodes.top()) = insert; + nodes.pop(); + while(nodes.size() && balance_tree(nodes.top())) nodes.pop(); + return insert; +} + +// This implementation is taken from musl +void *tfind(const void *key, void *const *rootp, int (*compar)(const void *, const void *)) { + if(!rootp) + return 0; + + struct node *n = (struct node *)*rootp; + for(;;) { + if(!n) + break; + int c = compar(key, n->key); + if(!c) + break; + n = (struct node *)n->a[c > 0]; + } + return n; +} + +void *tdelete(const void *, void **, int(*compar)(const void *, const void *)) { + (void)compar; + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +void twalk(const void *, void (*action)(const void *, VISIT, int)) { + (void)action; + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +void tdestroy(void *, void (*free_node)(void *)) { + (void)free_node; + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +void *lsearch(const void *key, void *base, size_t *nelp, size_t width, + int (*compar)(const void *, const void *)) { + (void)key; + (void)base; + (void)nelp; + (void)width; + (void)compar; + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +void *lfind(const void *key, const void *base, size_t *nelp, + size_t width, int (*compar)(const void *, const void *)) { + (void)key; + (void)base; + (void)nelp; + (void)width; + (void)compar; + __ensure(!"Not implemented"); + __builtin_unreachable(); +} diff --git a/lib/mlibc/options/posix/generic/semaphore-stubs.cpp b/lib/mlibc/options/posix/generic/semaphore-stubs.cpp new file mode 100644 index 0000000..d41eccb --- /dev/null +++ b/lib/mlibc/options/posix/generic/semaphore-stubs.cpp @@ -0,0 +1,114 @@ +#include +#include + +#include +#include +#include +#include + +static constexpr unsigned int semaphoreHasWaiters = static_cast(1 << 31); +static constexpr unsigned int semaphoreCountMask = static_cast(1 << 31) - 1; + +int sem_init(sem_t *sem, int pshared, unsigned int initial_count) { + if (pshared) { + mlibc::infoLogger() << "mlibc: shared semaphores are unsuppored" << frg::endlog; + errno = ENOSYS; + return -1; + } + + if (initial_count > SEM_VALUE_MAX) { + errno = EINVAL; + return -1; + } + + sem->__mlibc_count = initial_count; + + return 0; +} + +int sem_destroy(sem_t *) { + return 0; +} + +int sem_wait(sem_t *sem) { + unsigned int state = 0; + + while (1) { + if (!(state & semaphoreCountMask)) { + if (__atomic_compare_exchange_n(&sem->__mlibc_count, &state, semaphoreHasWaiters, + false, __ATOMIC_ACQUIRE, __ATOMIC_ACQUIRE)) { + int e = mlibc::sys_futex_wait((int *)&sem->__mlibc_count, state, nullptr); + if (e == 0 || e == EAGAIN) { + continue; + } else if (e == EINTR) { + errno = EINTR; + return -1; + } else { + mlibc::panicLogger() << "sys_futex_wait() failed with error code " << e << frg::endlog; + } + } + } else { + unsigned int desired = (state - 1); + if (__atomic_compare_exchange_n(&sem->__mlibc_count, &state, desired, false, + __ATOMIC_RELAXED, __ATOMIC_RELAXED)) + return 0; + } + } +} + +int sem_timedwait(sem_t *sem, const struct timespec *) { + mlibc::infoLogger() << "\e[31mmlibc: sem_timedwait is implemented as sem_wait\e[0m" << frg::endlog; + return sem_wait(sem); +} + +int sem_post(sem_t *sem) { + auto old_count = __atomic_load_n(&sem->__mlibc_count, __ATOMIC_RELAXED) & semaphoreCountMask; + + if (old_count + 1 > SEM_VALUE_MAX) { + errno = EOVERFLOW; + return -1; + } + + auto state = __atomic_exchange_n(&sem->__mlibc_count, old_count + 1, __ATOMIC_RELEASE); + + if (state & semaphoreHasWaiters) + if (int e = mlibc::sys_futex_wake((int *)&sem->__mlibc_count); e) + __ensure(!"sys_futex_wake() failed"); + + return 0; +} + +sem_t *sem_open(const char *, int, ...) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +int sem_close(sem_t *) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +int sem_getvalue(sem_t *, int *) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +int sem_unlink(const char *) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +int sem_trywait(sem_t *sem) { + while (true) { + auto state = __atomic_load_n(&sem->__mlibc_count, __ATOMIC_ACQUIRE); + + if (state & semaphoreHasWaiters) { + return EAGAIN; + } + + auto desired = state - 1; + if (__atomic_compare_exchange_n(&sem->__mlibc_count, &state, desired, false, __ATOMIC_RELEASE, __ATOMIC_RELAXED)) { + return 0; + } + } +} diff --git a/lib/mlibc/options/posix/generic/services.cpp b/lib/mlibc/options/posix/generic/services.cpp new file mode 100644 index 0000000..8ae0656 --- /dev/null +++ b/lib/mlibc/options/posix/generic/services.cpp @@ -0,0 +1,222 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace mlibc { + +static int parse_rest(service_buf &buf, char *end, int proto) { + if (!strncmp(end, "/udp", 4)) { + if (proto == IPPROTO_TCP && proto != -1) + return 0; + buf.protocol = IPPROTO_UDP; + buf.socktype = SOCK_DGRAM; + } else if (!strncmp(end, "/tcp", 4)) { + if (proto == IPPROTO_UDP && proto != -1) + return 0; + buf.protocol = IPPROTO_TCP; + buf.socktype = SOCK_STREAM; + } else { + return 0; + } + + //TODO(geert): also parse aliases. + + return 1; +} + +static int lookup_serv_file_port(service_result &buf, int proto, int port) { + auto file = fopen(_PATH_SERVICES, "r"); + if (!file) { + switch (errno) { + case ENOENT: + case ENOTDIR: + case EACCES: + return -EAI_SERVICE; + default: + return -EAI_SYSTEM; + } + } + + char line_buf[129] = {0}; + char *line = line_buf + 1; + while(fgets(line, 128, file)) { + int name_length = 0; + char *pos; + // easy way to handle comments, just move the end of the line + // to the beginning of the comment + if ((pos = strchr(line, '#'))) { + *pos++ = '\n'; + *pos = '\0'; + } + + char *end = NULL; + for (pos = line; *pos; pos++) { + for (; isalpha(*pos); pos++); + int rport = strtoul(pos, &end, 10); + if (rport != port || rport > 65535) { + pos = end; + continue; + } + + // We have found the port, time to rewind to the start + // of the line. + for (; pos[-1]; pos--) + if(!isspace(pos[-1])) + name_length++; + break; + } + + if (!pos) + continue; + + if (!name_length) + continue; + + auto name = frg::string(pos, name_length, + getAllocator()); + + struct service_buf sbuf = {}; + sbuf.port = port; + sbuf.name = std::move(name); + if (!parse_rest(sbuf, end, proto)) + continue; + buf.push_back(std::move(sbuf)); + } + + fclose(file); + return buf.size(); +} + +static int lookup_serv_file_name(service_result &buf, const char *name, + int proto) { + auto file = fopen(_PATH_SERVICES, "r"); + if (!file) { + switch (errno) { + case ENOENT: + case ENOTDIR: + case EACCES: + return -EAI_SERVICE; + default: + return -EAI_SYSTEM; + } + } + + char line[128]; + int name_length = strlen(name); + while(fgets(line, 128, file)) { + char *pos; + // easy way to handle comments, just move the end of the line + // to the beginning of the comment + if ((pos = strchr(line, '#'))) { + *pos++ = '\n'; + *pos = '\0'; + } + + for (pos = line; (pos = strstr(pos, name)); pos++) { + // the name must start and end with a space + if (pos > line && !isspace(pos[-1])) + continue; + if (pos[name_length] && !isspace(pos[name_length])) + continue; + break; + } + if (!pos) + continue; + + // Skip the name at the beginning of the line. + for(pos = line; *pos && !isspace(*pos); pos++) + ; + + char *end = NULL; + int port = strtoul(pos, &end, 10); + if (port > 65535 || end == pos) + continue; + + struct service_buf sbuf; + sbuf.port = port; + sbuf.name = frg::string(name, getAllocator()); + if (!parse_rest(sbuf, end, proto)) + continue; + + buf.push_back(sbuf); + + } + + fclose(file); + return buf.size(); +} + + +// This function returns a negative error code, since a positive +// return code means success. +int lookup_serv_by_name(service_result &buf, const char *name, int proto, + int socktype, int flags) { + switch(socktype) { + case SOCK_STREAM: + if (!proto) + proto = IPPROTO_TCP; + else if (proto != IPPROTO_TCP) + return -EAI_SERVICE; + break; + case SOCK_DGRAM: + if (!proto) + proto = IPPROTO_UDP; + else if (proto != IPPROTO_UDP) + return -EAI_SERVICE; + break; + case 0: + break; + default: + if (name) + return -EAI_SERVICE; + buf[0].port = 0; + buf[0].socktype = socktype; + buf[0].protocol = proto; + return 1; + } + + char *end = nullptr; + unsigned int port = 0; + int count = 0; + + if (name) { + if (!*name) + return -EAI_SERVICE; + port = strtoul(name, &end, 10); + } + // The end pointer is a null pointer so the name was a port + // or the name was not specified. + if (!end || !*end) { + if (proto != IPPROTO_UDP) { + buf[count].port = port; + buf[count].protocol = IPPROTO_TCP; + buf[count].socktype = SOCK_STREAM; + count++; + } + if (proto != IPPROTO_TCP) { + buf[count].port = port; + buf[count].protocol = IPPROTO_UDP; + buf[count].socktype = SOCK_DGRAM; + count++; + } + return count; + } + + if (flags & AI_NUMERICSERV) + return -EAI_NONAME; + + return lookup_serv_file_name(buf, name, proto); +} + +int lookup_serv_by_port(service_result &buf, int proto, int port) { + return lookup_serv_file_port(buf, proto, port); +} + +} // namespace mlibc diff --git a/lib/mlibc/options/posix/generic/spawn-stubs.cpp b/lib/mlibc/options/posix/generic/spawn-stubs.cpp new file mode 100644 index 0000000..cf7edfc --- /dev/null +++ b/lib/mlibc/options/posix/generic/spawn-stubs.cpp @@ -0,0 +1,376 @@ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +/* + * Musl places this in a seperate header called fdop.h + * This header isn't present in glibc, or on my host, so I + * include it's contents here + */ + +#define FDOP_CLOSE 1 +#define FDOP_DUP2 2 +#define FDOP_OPEN 3 +#define FDOP_CHDIR 4 +#define FDOP_FCHDIR 5 + +struct fdop { + struct fdop *next, *prev; + int cmd, fd, srcfd, oflag; + mode_t mode; + char path[]; +}; + +/* + * This posix_spawn implementation is taken from musl + */ + +static unsigned long handler_set[NSIG / (8 * sizeof(long))]; + +static void __get_handler_set(sigset_t *set) { + memcpy(set, handler_set, sizeof handler_set); +} + +struct args { + int p[2]; + sigset_t oldmask; + const char *path; + const posix_spawn_file_actions_t *fa; + const posix_spawnattr_t *__restrict attr; + char *const *argv, *const *envp; +}; + +static int child(void *args_vp) { + int i, ret; + struct sigaction sa = {}; + struct args *args = (struct args *)args_vp; + int p = args->p[1]; + const posix_spawn_file_actions_t *fa = args->fa; + const posix_spawnattr_t *__restrict attr = args->attr; + sigset_t hset; + bool use_execvpe = false; + + if(attr->__fn) + use_execvpe = true; + + close(args->p[0]); + + /* All signal dispositions must be either SIG_DFL or SIG_IGN + * before signals are unblocked. Otherwise a signal handler + * from the parent might get run in the child while sharing + * memory, with unpredictable and dangerous results. To + * reduce overhead, sigaction has tracked for us which signals + * potentially have a signal handler. */ + __get_handler_set(&hset); + for(i = 1; i < NSIG; i++) { + if((attr->__flags & POSIX_SPAWN_SETSIGDEF) && sigismember(&attr->__def, i)) { + sa.sa_handler = SIG_DFL; + } else if(sigismember(&hset, i)) { + if (i - 32 < 3) { + sa.sa_handler = SIG_IGN; + } else {; + sigaction(i, 0, &sa); + if(sa.sa_handler == SIG_IGN) + continue; + sa.sa_handler = SIG_DFL; + } + } else { + continue; + } + sigaction(i, &sa, 0); + } + + if(attr->__flags & POSIX_SPAWN_SETSID) { + if((ret = setsid()) < 0) + goto fail; + } + + if(attr->__flags & POSIX_SPAWN_SETPGROUP) { + mlibc::infoLogger() << "mlibc: posix_spawn: ignoring SETPGROUP" << frg::endlog; + //if((ret = setpgid(0, attr->__pgrp))) + // goto fail; + } + + if(attr->__flags & POSIX_SPAWN_RESETIDS) { + if((ret = setgid(getgid())) || (ret = setuid(getuid())) ) + goto fail; + } + + if(fa && fa->__actions) { + struct fdop *op; + int fd; + for(op = (struct fdop *)fa->__actions; op->next; op = op->next); + for(; op; op = op->prev) { + /* It's possible that a file operation would clobber + * the pipe fd used for synchronizing with the + * parent. To avoid that, we dup the pipe onto + * an unoccupied fd. */ + if(op->fd == p) { + ret = dup(p); + if(ret < 0) + goto fail; + close(p); + p = ret; + } + switch(op->cmd) { + case FDOP_CLOSE: + close(op->fd); + break; + case FDOP_DUP2: + fd = op->srcfd; + if(fd == p) { + ret = -EBADF; + goto fail; + } + if(fd != op->fd) { + if((ret = dup2(fd, op->fd)) < 0) + goto fail; + } else { + ret = fcntl(fd, F_GETFD); + ret = fcntl(fd, F_SETFD, ret & ~FD_CLOEXEC); + if(ret < 0) + goto fail; + } + break; + case FDOP_OPEN: + fd = open(op->path, op->oflag, op->mode); + if((ret = fd) < 0) + goto fail; + if(fd != op->fd) { + if((ret = dup2(fd, op->fd)) < 0) + goto fail; + close(fd); + } + break; + case FDOP_CHDIR: + ret = chdir(op->path); + if(ret < 0) + goto fail; + break; + case FDOP_FCHDIR: + ret = fchdir(op->fd); + if(ret < 0) + goto fail; + break; + } + } + } + + /* Close-on-exec flag may have been lost if we moved the pipe + * to a different fd. */ + fcntl(p, F_SETFD, FD_CLOEXEC); + + pthread_sigmask(SIG_SETMASK, (attr->__flags & POSIX_SPAWN_SETSIGMASK) + ? &attr->__mask : &args->oldmask, 0); + + if(use_execvpe) + execvpe(args->path, args->argv, args->envp); + else + execve(args->path, args->argv, args->envp); + ret = -errno; + +fail: + /* Since sizeof errno < PIPE_BUF, the write is atomic. */ + ret = -ret; + if(ret) + while(write(p, &ret, sizeof ret) < 0); + _exit(127); +} + +int posix_spawn(pid_t *__restrict res, const char *__restrict path, + const posix_spawn_file_actions_t *file_actions, + const posix_spawnattr_t *__restrict attrs, + char *const argv[], char *const envp[]) { + pid_t pid; + int ec = 0, cs; + struct args args; + const posix_spawnattr_t empty_attr = {}; + sigset_t full_sigset; + sigfillset(&full_sigset); + + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs); + + args.path = path; + args.fa = file_actions; + args.attr = attrs ? attrs : &empty_attr; + args.argv = argv; + args.envp = envp; + pthread_sigmask(SIG_BLOCK, &full_sigset, &args.oldmask); + + /* The lock guards both against seeing a SIGABRT disposition change + * by abort and against leaking the pipe fd to fork-without-exec. */ + //LOCK(__abort_lock); + + if(pipe2(args.p, O_CLOEXEC)) { + //UNLOCK(__abort_lock); + ec = errno; + goto fail; + } + + /* Mlibc change: We use fork + execve, as clone is not implemented. + * This yields the same result in the end. */ + //pid = clone(child, stack + sizeof stack, CLONE_VM | CLONE_VFORK | SIGCHLD, &args); + pid = fork(); + if(!pid) { + child(&args); + } + close(args.p[1]); + //UNLOCK(__abort_lock); + + if(pid > 0) { + if(read(args.p[0], &ec, sizeof ec) != sizeof ec) + ec = 0; + else + waitpid(pid, 0, 0); + } else { + ec = -pid; + } + + close(args.p[0]); + + if(!ec && res) + *res = pid; + +fail: + pthread_sigmask(SIG_SETMASK, &args.oldmask, 0); + pthread_setcancelstate(cs, 0); + + return ec; +} + +int posix_spawnattr_init(posix_spawnattr_t *attr) { + *attr = (posix_spawnattr_t){}; + return 0; +} + +int posix_spawnattr_destroy(posix_spawnattr_t *) { + return 0; +} + +int posix_spawnattr_setflags(posix_spawnattr_t *attr, short flags) { + const unsigned all_flags = + POSIX_SPAWN_RESETIDS | + POSIX_SPAWN_SETPGROUP | + POSIX_SPAWN_SETSIGDEF | + POSIX_SPAWN_SETSIGMASK | + POSIX_SPAWN_SETSCHEDPARAM | + POSIX_SPAWN_SETSCHEDULER | + POSIX_SPAWN_USEVFORK | + POSIX_SPAWN_SETSID; + if(flags & ~all_flags) + return EINVAL; + attr->__flags = flags; + return 0; +} + +int posix_spawnattr_setsigdefault(posix_spawnattr_t *__restrict attr, + const sigset_t *__restrict sigdefault) { + attr->__def = *sigdefault; + return 0; +} + +int posix_spawnattr_setschedparam(posix_spawnattr_t *__restrict, + const struct sched_param *__restrict) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +int posix_spawnattr_setschedpolicy(posix_spawnattr_t *, int) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +int posix_spawnattr_setsigmask(posix_spawnattr_t *__restrict attr, + const sigset_t *__restrict sigmask) { + attr->__mask = *sigmask; + return 0; +} + +int posix_spawnattr_setpgroup(posix_spawnattr_t *attr, pid_t pgroup) { + attr->__pgrp = pgroup; + return 0; +} + +int posix_spawn_file_actions_init(posix_spawn_file_actions_t *file_actions) { + file_actions->__actions = 0; + return 0; +} + +int posix_spawn_file_actions_destroy(posix_spawn_file_actions_t *file_actions) { + struct fdop *op = (struct fdop *)file_actions->__actions, *next; + while(op) { + next = op->next; + free(op); + op = next; + } + return 0; +} + +int posix_spawn_file_actions_adddup2(posix_spawn_file_actions_t *file_actions, + int fildes, int newfildes) { + struct fdop *op = (struct fdop *)malloc(sizeof *op); + if(!op) + return ENOMEM; + op->cmd = FDOP_DUP2; + op->srcfd = fildes; + op->fd = newfildes; + if((op->next = (struct fdop *)file_actions->__actions)) + op->next->prev = op; + op->prev = 0; + file_actions->__actions = op; + return 0; +} + +int posix_spawn_file_actions_addclose(posix_spawn_file_actions_t *file_actions, + int fildes) { + struct fdop *op = (struct fdop *)malloc(sizeof *op); + if(!op) + return ENOMEM; + op->cmd = FDOP_CLOSE; + op->fd = fildes; + if((op->next = (struct fdop *)file_actions->__actions)) + op->next->prev = op; + op->prev = 0; + file_actions->__actions = op; + return 0; +} + +int posix_spawn_file_actions_addopen(posix_spawn_file_actions_t *__restrict file_actions, + int fildes, const char *__restrict path, int oflag, mode_t mode) { + struct fdop *op = (struct fdop *)malloc(sizeof *op + strlen(path) + 1); + if(!op) + return ENOMEM; + op->cmd = FDOP_OPEN; + op->fd = fildes; + op->oflag = oflag; + op->mode = mode; + strcpy(op->path, path); + if((op->next = (struct fdop *)file_actions->__actions)) + op->next->prev = op; + op->prev = 0; + file_actions->__actions = op; + return 0; +} + +int posix_spawnp(pid_t *__restrict pid, const char *__restrict file, + const posix_spawn_file_actions_t *file_actions, + const posix_spawnattr_t *__restrict attrp, + char *const argv[], char *const envp[]) { + posix_spawnattr_t spawnp_attr = {}; + if(attrp) + spawnp_attr = *attrp; + spawnp_attr.__fn = (void *)execvpe; + return posix_spawn(pid, file, file_actions, &spawnp_attr, argv, envp); +} + diff --git a/lib/mlibc/options/posix/generic/strings-stubs.cpp b/lib/mlibc/options/posix/generic/strings-stubs.cpp new file mode 100644 index 0000000..524c424 --- /dev/null +++ b/lib/mlibc/options/posix/generic/strings-stubs.cpp @@ -0,0 +1,107 @@ + +#include +#include + +#include +#include +#include + +char *index (const char *s, int c) { + return strchr(s, c); +} + +char *rindex(const char *s, int c) { + return strrchr(s, c); +} + +namespace { + + template + int ffs_generic(T i) { + //Non-portably assume a byte has 8 bits; fine in all plausible cases. + for(size_t b = 0; b < sizeof(T) * 8;) + if(i & (static_cast(0x1) << b++)) + return b; + + return 0; + } + +} + +// On RISC-V, __builtin_ffs just calls into ffs, so we can't use it here. +#if defined(__has_builtin) && !defined(__riscv) +# if __has_builtin(__builtin_ffs) +# define __mlibc_ffs __builtin_ffs +# endif +# if __has_builtin(__builtin_ffsl) +# define __mlibc_ffsl __builtin_ffsl +# endif +# if __has_builtin(__builtin_ffsll) +# define __mlibc_ffsll __builtin_ffsll +# endif +#endif + +int ffs(int i) { +#ifdef __mlibc_ffs + return __mlibc_ffs(i); +#else + return ffs_generic(i); +#endif +} + +/* + Both ffsl() and ffsll() are glibc extensions + defined in string.h. They are however implemented + here because of similarity in logic and + shared code. +*/ + +int ffsl(long i) { +#ifdef __mlibc_ffsl + return __mlibc_ffsl(i); +#else + return ffs_generic(i); +#endif +} + +int ffsll(long long i) { +#ifdef __mlibc_ffsll + return __mlibc_ffsll(i); +#else + return ffs_generic(i); +#endif +} + +int strcasecmp(const char *a, const char *b) { + size_t i = 0; + while(true) { + unsigned char a_byte = tolower(a[i]); + unsigned char b_byte = tolower(b[i]); + if(!a_byte && !b_byte) + return 0; + // If only one char is null, one of the following cases applies. + if(a_byte < b_byte) + return -1; + if(a_byte > b_byte) + return 1; + i++; + } +} + +int strncasecmp(const char *a, const char *b, size_t size) { + return mlibc::strncasecmp(a, b, size); +} + +// Marked as obsolete in posix 2008 but used by at least tracker +int bcmp(const void *s1, const void *s2, size_t n) { + return memcmp(s1, s2, n); +} + +void bcopy(const void *s1, void *s2, size_t n) { + memmove(s2, s1, n); +} + +void bzero(void *s, size_t n) { + memset(s, 0, n); +} + diff --git a/lib/mlibc/options/posix/generic/sys-file-stubs.cpp b/lib/mlibc/options/posix/generic/sys-file-stubs.cpp new file mode 100644 index 0000000..e1cc9ab --- /dev/null +++ b/lib/mlibc/options/posix/generic/sys-file-stubs.cpp @@ -0,0 +1,16 @@ + +#include +#include +#include + +#include + +int flock(int fd, int opt) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_flock, -1); + if(int e = mlibc::sys_flock(fd, opt); e) { + errno = e; + return -1; + } + return 0; +} + diff --git a/lib/mlibc/options/posix/generic/sys-ipc.cpp b/lib/mlibc/options/posix/generic/sys-ipc.cpp new file mode 100644 index 0000000..b9e0d3d --- /dev/null +++ b/lib/mlibc/options/posix/generic/sys-ipc.cpp @@ -0,0 +1,8 @@ +#include + +#include + +key_t ftok(const char *, int) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} diff --git a/lib/mlibc/options/posix/generic/sys-mman-stubs.cpp b/lib/mlibc/options/posix/generic/sys-mman-stubs.cpp new file mode 100644 index 0000000..9383976 --- /dev/null +++ b/lib/mlibc/options/posix/generic/sys-mman-stubs.cpp @@ -0,0 +1,177 @@ + +#include +#include +#include +#include +#include +#include + +#include +#include + +int mprotect(void *pointer, size_t size, int prot) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_vm_protect, -1); + if(int e = mlibc::sys_vm_protect(pointer, size, prot); e) { + errno = e; + return -1; + } + return 0; +} + +int mlock(const void *addr, size_t len) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_mlock, -1); + if(int e = mlibc::sys_mlock(addr, len); e) { + errno = e; + return -1; + } + return 0; +} + +int mlockall(int flags) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_mlockall, -1); + if(int e = mlibc::sys_mlockall(flags); e) { + errno = e; + return -1; + } + return 0; +} + +int munlock(const void *addr, size_t len) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_munlock, -1); + if(int e = mlibc::sys_munlock(addr, len); e) { + errno = e; + return -1; + } + return 0; +} + +int munlockall(void) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_munlockall, -1); + if(int e = mlibc::sys_munlockall(); e) { + errno = e; + return -1; + } + return 0; +} + + +int posix_madvise(void *, size_t, int) { + mlibc::infoLogger() << "\e[31m" "mlibc: posix_madvise() fails unconditionally" "\e[39m" + << frg::endlog; + return ENOSYS; +} + +int msync(void *addr, size_t length, int flags) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_msync, -1); + if(int e = mlibc::sys_msync(addr, length, flags); e) { + errno = e; + return -1; + } + return 0; +} + +void *mremap(void *pointer, size_t size, size_t new_size, int flags, ...) { + __ensure(flags == MREMAP_MAYMOVE); + + void *window; + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_vm_remap, (void *)-1); + if(int e = mlibc::sys_vm_remap(pointer, size, new_size, &window); e) { + errno = e; + return (void *)-1; + } + return window; +} + +int remap_file_pages(void *, size_t, int, size_t, int) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +void *mmap(void *hint, size_t size, int prot, int flags, int fd, off_t offset) { + void *window; + if(int e = mlibc::sys_vm_map(hint, size, prot, flags, fd, offset, &window); e) { + errno = e; + return (void *)-1; + } + return window; +} + +int munmap(void *pointer, size_t size) { + if(int e = mlibc::sys_vm_unmap(pointer, size); e) { + errno = e; + return -1; + } + return 0; +} + +// The implementation of shm_open and shm_unlink is taken from musl. +namespace { + char *shm_mapname(const char *name, char *buf) { + char *p; + while(*name == '/') + name++; + if(*(p = strchrnul(name, '/')) || p == name || + (p - name <= 2 && name[0] == '.' && p[-1] == '.')) { + errno = EINVAL; + return 0; + } + if(p - name > NAME_MAX) { + errno = ENAMETOOLONG; + return 0; + } + memcpy(buf, "/dev/shm/", 9); + memcpy(buf + 9, name, p - name + 1); + return buf; + } +} + +int shm_open(const char *name, int flags, mode_t mode) { + int cs; + char buf[NAME_MAX + 10]; + if(!(name = shm_mapname(name, buf))) + return -1; + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs); + int fd = open(name, flags | O_NOFOLLOW | O_CLOEXEC | O_NONBLOCK, mode); + pthread_setcancelstate(cs, 0); + return fd; +} + +int shm_unlink(const char *name) { + char buf[NAME_MAX + 10]; + if(!(name = shm_mapname(name, buf))) + return -1; + return unlink(name); +} + +#if __MLIBC_LINUX_OPTION +int memfd_create(const char *name, unsigned int flags) { + int ret = -1; + + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_memfd_create, -1); + if(int e = mlibc::sys_memfd_create(name, flags, &ret)) { + errno = e; + return -1; + } + + return ret; +} + +int madvise(void *addr, size_t length, int advice) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_madvise, -1); + if(int e = mlibc::sys_madvise(addr, length, advice)) { + errno = e; + return -1; + } + + return 0; +} + +int mincore(void *addr, size_t length, unsigned char *vec) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_munlockall, -1); + if(int e = mlibc::sys_mincore(addr, length, vec); e) { + errno = e; + return -1; + } + return 0; +} +#endif /* __MLIBC_LINUX_OPTION */ diff --git a/lib/mlibc/options/posix/generic/sys-msg.cpp b/lib/mlibc/options/posix/generic/sys-msg.cpp new file mode 100644 index 0000000..95f067e --- /dev/null +++ b/lib/mlibc/options/posix/generic/sys-msg.cpp @@ -0,0 +1,23 @@ + +#include +#include + +int msgget(key_t, int) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +int msgctl(int, int, struct msqid_ds *) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +ssize_t msgrcv(int, void *, size_t, long, int) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +int msgsnd(int, const void *, size_t, int) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} diff --git a/lib/mlibc/options/posix/generic/sys-resource-stubs.cpp b/lib/mlibc/options/posix/generic/sys-resource-stubs.cpp new file mode 100644 index 0000000..597de4d --- /dev/null +++ b/lib/mlibc/options/posix/generic/sys-resource-stubs.cpp @@ -0,0 +1,57 @@ + +#include +#include + +#include +#include +#include + +int getpriority(int which, id_t who) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_getpriority, -1); + int value = 0; + if(int e = mlibc::sys_getpriority(which, who, &value); e) { + errno = e; + } + return value; +} + +int setpriority(int which, id_t who, int prio) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_setpriority, -1); + if(int e = mlibc::sys_setpriority(which, who, prio); e) { + errno = e; + return -1; + } + return 0; +} + +int getrusage(int scope, struct rusage *usage) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_getrusage, -1); + if(int e = mlibc::sys_getrusage(scope, usage); e) { + errno = e; + return -1; + } + return 0; +} + +int getrlimit(int resource, struct rlimit *limit) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_getrlimit, -1); + if(int e = mlibc::sys_getrlimit(resource, limit); e) { + errno = e; + return -1; + } + return 0; +} + +int setrlimit(int resource, const struct rlimit *limit) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_setrlimit, -1); + if(int e = mlibc::sys_setrlimit(resource, limit); e) { + errno = e; + return -1; + } + return 0; +} + +int prlimit(pid_t, int, const struct rlimit *, struct rlimit *) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} diff --git a/lib/mlibc/options/posix/generic/sys-select-stubs.cpp b/lib/mlibc/options/posix/generic/sys-select-stubs.cpp new file mode 100644 index 0000000..e8ff927 --- /dev/null +++ b/lib/mlibc/options/posix/generic/sys-select-stubs.cpp @@ -0,0 +1,58 @@ + +#include +#include +#include +#include + +#include +#include + +#include + +void __FD_CLR(int fd, fd_set *set) { + __ensure(fd < FD_SETSIZE); + set->__mlibc_elems[fd / 8] &= ~(1 << (fd % 8)); +} +int __FD_ISSET(int fd, fd_set *set) { + __ensure(fd < FD_SETSIZE); + return set->__mlibc_elems[fd / 8] & (1 << (fd % 8)); +} +void __FD_SET(int fd, fd_set *set) { + __ensure(fd < FD_SETSIZE); + set->__mlibc_elems[fd / 8] |= 1 << (fd % 8); +} +void __FD_ZERO(fd_set *set) { + memset(set->__mlibc_elems, 0, sizeof(fd_set)); +} + +int select(int num_fds, fd_set *__restrict read_set, fd_set *__restrict write_set, + fd_set *__restrict except_set, struct timeval *__restrict timeout) { + int num_events = 0; + struct timespec timeouts = {}; + struct timespec *timeout_ptr = NULL; + if (timeout) { + timeouts.tv_sec = timeout->tv_sec; + timeouts.tv_nsec = timeout->tv_usec * 1000; + timeout_ptr = &timeouts; + } + + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_pselect, -1); + if(int e = mlibc::sys_pselect(num_fds, read_set, write_set, except_set, + timeout_ptr, NULL, &num_events); e) { + errno = e; + return -1; + } + return num_events; +} + +int pselect(int num_fds, fd_set *read_set, fd_set *write_set, fd_set *except_set, + const struct timespec *timeout, const sigset_t *sigmask) { + int num_events = 0; + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_pselect, -1); + if(int e = mlibc::sys_pselect(num_fds, read_set, write_set, except_set, + timeout, sigmask, &num_events); e) { + errno = e; + return -1; + } + return num_events; +} diff --git a/lib/mlibc/options/posix/generic/sys-sem.cpp b/lib/mlibc/options/posix/generic/sys-sem.cpp new file mode 100644 index 0000000..ac3df69 --- /dev/null +++ b/lib/mlibc/options/posix/generic/sys-sem.cpp @@ -0,0 +1,51 @@ + +#include +#include +#include +#include + +#include + +int semget(key_t key, int n, int fl) { + if(n > USHRT_MAX) { + errno = EINVAL; + return -1; + } + + int id = 0; + auto sysdep = MLIBC_CHECK_OR_ENOSYS(mlibc::sys_semget, -1); + if(int e = sysdep(key, n, fl, &id); e) { + errno = e; + return -1; + } + return id; +} + +int semop(int, struct sembuf *, size_t) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +union semun { + int val; + struct semid_ds *buf; + unsigned short *array; +}; + +int semctl(int id, int num, int cmd, ...) { + union semun semun; + int ret = 0; + + va_list ap; + va_start(ap, cmd); + semun = va_arg(ap, union semun); + va_end(ap); + + auto sysdep = MLIBC_CHECK_OR_ENOSYS(mlibc::sys_semctl, -1); + if(int e = sysdep(id, num, cmd, semun.buf, &ret); e) { + errno = e; + return -1; + } + + return ret; +} diff --git a/lib/mlibc/options/posix/generic/sys-shm.cpp b/lib/mlibc/options/posix/generic/sys-shm.cpp new file mode 100644 index 0000000..3af7e90 --- /dev/null +++ b/lib/mlibc/options/posix/generic/sys-shm.cpp @@ -0,0 +1,24 @@ +#include + +#include +#include + +void *shmat(int, const void *, int) { + __ensure(!"Function is not implemented"); + __builtin_unreachable(); +} + +int shmctl(int, int, struct shmid_ds *) { + __ensure(!"Function is not implemented"); + __builtin_unreachable(); +} + +int shmdt(const void *) { + __ensure(!"Function is not implemented"); + __builtin_unreachable(); +} + +int shmget(key_t, size_t, int) { + mlibc::infoLogger() << "mlibc: shmget() is a no-op!" << frg::endlog; + return -1; +} diff --git a/lib/mlibc/options/posix/generic/sys-socket-stubs.cpp b/lib/mlibc/options/posix/generic/sys-socket-stubs.cpp new file mode 100644 index 0000000..037a994 --- /dev/null +++ b/lib/mlibc/options/posix/generic/sys-socket-stubs.cpp @@ -0,0 +1,225 @@ + +#include +#include +#include +#include + +#include +#include +#include + +int accept(int fd, struct sockaddr *__restrict addr_ptr, socklen_t *__restrict addr_length) { + int newfd; + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_accept, -1); + if(int e = mlibc::sys_accept(fd, &newfd, addr_ptr, addr_length, 0); e) { + errno = e; + return -1; + } + return newfd; +} + +int accept4(int fd, struct sockaddr *__restrict addr_ptr, socklen_t *__restrict addr_length, int flags) { + int newfd; + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_accept, -1); + if(int e = mlibc::sys_accept(fd, &newfd, addr_ptr, addr_length, flags); e) { + errno = e; + return -1; + } + + return newfd; +} + +int bind(int fd, const struct sockaddr *addr_ptr, socklen_t addr_len) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_bind, -1); + if(int e = mlibc::sys_bind(fd, addr_ptr, addr_len); e) { + errno = e; + return -1; + } + return 0; +} + +int connect(int fd, const struct sockaddr *addr_ptr, socklen_t addr_len) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_connect, -1); + if(int e = mlibc::sys_connect(fd, addr_ptr, addr_len); e) { + errno = e; + return -1; + } + return 0; +} + +int getpeername(int fd, struct sockaddr *addr_ptr, socklen_t *__restrict addr_length) { + socklen_t actual_length; + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_peername, -1); + if(int e = mlibc::sys_peername(fd, addr_ptr, *addr_length, &actual_length); e) { + errno = e; + return -1; + } + *addr_length = actual_length; + return 0; +} + +int getsockname(int fd, struct sockaddr *__restrict addr_ptr, socklen_t *__restrict addr_length) { + socklen_t actual_length; + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_sockname, -1); + if(int e = mlibc::sys_sockname(fd, addr_ptr, *addr_length, &actual_length); e) { + errno = e; + return -1; + } + *addr_length = actual_length; + return 0; +} + +int getsockopt(int fd, int layer, int number, + void *__restrict buffer, socklen_t *__restrict size) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_getsockopt, -1); + return mlibc::sys_getsockopt(fd, layer, number, buffer, size); +} + +int listen(int fd, int backlog) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_listen, -1); + if(int e = mlibc::sys_listen(fd, backlog); e) { + errno = e; + return -1; + } + return 0; +} + +ssize_t recv(int sockfd, void *__restrict buf, size_t len, int flags) { + return recvfrom(sockfd, buf, len, flags, NULL, NULL); +} + +ssize_t recvfrom(int sockfd, void *__restrict buf, size_t len, int flags, + struct sockaddr *__restrict src_addr, socklen_t *__restrict addrlen) { + if(mlibc::sys_recvfrom) { + ssize_t length; + if(int e = mlibc::sys_recvfrom(sockfd, buf, len, flags, src_addr, addrlen, &length); e) { + errno = e; + return -1; + } + return length; + } + + struct iovec iov = {}; + iov.iov_base = buf; + iov.iov_len = len; + + struct msghdr hdr = {}; + hdr.msg_name = src_addr; + if (addrlen) { + hdr.msg_namelen = *addrlen; + } + hdr.msg_iov = &iov; + hdr.msg_iovlen = 1; + + int ret = recvmsg(sockfd, &hdr, flags); + if (ret < 0) + return ret; + + if(addrlen) + *addrlen = hdr.msg_namelen; + return ret; +} + +ssize_t recvmsg(int fd, struct msghdr *hdr, int flags) { + ssize_t length; + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_msg_recv, -1); + if(int e = mlibc::sys_msg_recv(fd, hdr, flags, &length); e) { + errno = e; + return -1; + } + return length; +} + +int recvmmsg(int, struct mmsghdr *, unsigned int, int, struct timespec *) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +ssize_t send(int fd, const void *buffer, size_t size, int flags) { + return sendto(fd, buffer, size, flags, nullptr, 0); +} + +ssize_t sendto(int fd, const void *buffer, size_t size, int flags, + const struct sockaddr *sock_addr, socklen_t addr_length) { + if(mlibc::sys_sendto) { + ssize_t length; + if(int e = mlibc::sys_sendto(fd, buffer, size, flags, sock_addr, addr_length, &length); e) { + errno = e; + return -1; + } + return length; + } + + struct iovec iov = {}; + iov.iov_base = const_cast(buffer); + iov.iov_len = size; + + struct msghdr hdr = {}; + hdr.msg_name = const_cast(sock_addr); + hdr.msg_namelen = addr_length; + hdr.msg_iov = &iov; + hdr.msg_iovlen = 1; + + return sendmsg(fd, &hdr, flags); +} + +ssize_t sendmsg(int fd, const struct msghdr *hdr, int flags) { + if(hdr->msg_iovlen > IOV_MAX) + return EMSGSIZE; + + ssize_t length; + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_msg_send, -1); + if(int e = mlibc::sys_msg_send(fd, hdr, flags, &length); e) { + errno = e; + return -1; + } + return length; +} + +int sendmmsg(int, struct mmsghdr *, unsigned int, int) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +int setsockopt(int fd, int layer, int number, + const void *buffer, socklen_t size) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_setsockopt, -1); + return mlibc::sys_setsockopt(fd, layer, number, buffer, size); +} + +int shutdown(int sockfd, int how) { + auto sysdep = MLIBC_CHECK_OR_ENOSYS(mlibc::sys_shutdown, -1); + if(int e = sysdep(sockfd, how); e) { + errno = e; + return -1; + } + + return 0; +} + +int sockatmark(int) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +int socket(int family, int type, int protocol) { + int fd; + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_socket, -1); + if(int e = mlibc::sys_socket(family, type, protocol, &fd); e) { + errno = e; + return -1; + } + return fd; +} + +int socketpair(int domain, int type, int protocol, int sv[2]) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_socketpair, -1); + if(int e = mlibc::sys_socketpair(domain, type, protocol, sv); e) { + errno = e; + return -1; + } + return 0; +} + +// connectpair() is provided by the platform + diff --git a/lib/mlibc/options/posix/generic/sys-stat-stubs.cpp b/lib/mlibc/options/posix/generic/sys-stat-stubs.cpp new file mode 100644 index 0000000..2eca445 --- /dev/null +++ b/lib/mlibc/options/posix/generic/sys-stat-stubs.cpp @@ -0,0 +1,155 @@ + +#include +#include +#include + +#include +#include + +int chmod(const char *pathname, mode_t mode) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_chmod, -1); + if(int e = mlibc::sys_chmod(pathname, mode); e) { + errno = e; + return -1; + } + return 0; +} + +int fchmod(int fd, mode_t mode) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_fchmod, -1); + if(int e = mlibc::sys_fchmod(fd, mode); e) { + errno = e; + return -1; + } + return 0; +} + +int fchmodat(int dirfd, const char *pathname, mode_t mode, int flags) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_fchmodat, -1); + if(int e = mlibc::sys_fchmodat(dirfd, pathname, mode, flags); e) { + errno = e; + return -1; + } + return 0; +} + +int fstatat(int dirfd, const char *path, struct stat *result, int flags) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_stat, -1); + if(int e = mlibc::sys_stat(mlibc::fsfd_target::fd_path, dirfd, path, flags, result); e) { + errno = e; + return -1; + } + return 0; +} + +int futimens(int fd, const struct timespec times[2]) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_utimensat, -1); + + if (int e = mlibc::sys_utimensat(fd, nullptr, times, 0); e) { + errno = e; + return -1; + } + + return 0; +} + +int mkdir(const char *path, mode_t mode) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_mkdir, -1); + if(int e = mlibc::sys_mkdir(path, mode); e) { + errno = e; + return -1; + } + return 0; +} + +int mkdirat(int dirfd, const char *path, mode_t mode) { + mlibc::infoLogger() << "\e[31mmlibc: mkdirat() ignores its mode\e[39m" << frg::endlog; + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_mkdirat, -1); + if(int e = mlibc::sys_mkdirat(dirfd, path, mode); e) { + errno = e; + return -1; + } + return 0; +} + +int mkfifo(const char *path, mode_t mode) { + return mkfifoat(AT_FDCWD, path, mode); +} + +int mkfifoat(int dirfd, const char *path, mode_t mode) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_mkfifoat, -1); + if (int e = mlibc::sys_mkfifoat(dirfd, path, mode); e) { + errno = e; + return -1; + } + + return 0; +} + +int mknod(const char *path, mode_t mode, dev_t dev) { + return mknodat(AT_FDCWD, path, mode, dev); +} + +int mknodat(int dirfd, const char *path, mode_t mode, dev_t dev) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_mknodat, -1); + if (int e = mlibc::sys_mknodat(dirfd, path, mode, dev); e) { + errno = e; + return -1; + } + + return 0; +} + +mode_t umask(mode_t mode) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_umask, -1); + mode_t old; + if (int e = mlibc::sys_umask(mode, &old); e) { + errno = e; + return -1; + } + return old; +} + +int utimensat(int dirfd, const char *pathname, const struct timespec times[2], int flags) { + if(pathname == nullptr) { + errno = EINVAL; + return -1; + } + + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_utimensat, -1); + if (int e = mlibc::sys_utimensat(dirfd, pathname, times, flags); e) { + errno = e; + return -1; + } + + return 0; +} + +int stat(const char *path, struct stat *result) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_stat, -1); + if(int e = mlibc::sys_stat(mlibc::fsfd_target::path, -1, path, 0, result); e) { + errno = e; + return -1; + } + return 0; +} + +int lstat(const char *path, struct stat *result) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_stat, -1); + if(int e = mlibc::sys_stat(mlibc::fsfd_target::path, + -1, path, AT_SYMLINK_NOFOLLOW, result); e) { + errno = e; + return -1; + } + return 0; +} + +int fstat(int fd, struct stat *result) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_stat, -1); + if(int e = mlibc::sys_stat(mlibc::fsfd_target::fd, fd, "", 0, result); e) { + errno = e; + return -1; + } + return 0; +} + diff --git a/lib/mlibc/options/posix/generic/sys-statvfs-stubs.cpp b/lib/mlibc/options/posix/generic/sys-statvfs-stubs.cpp new file mode 100644 index 0000000..c02cc39 --- /dev/null +++ b/lib/mlibc/options/posix/generic/sys-statvfs-stubs.cpp @@ -0,0 +1,24 @@ +#include +#include + +#include +#include + +int statvfs(const char *path, struct statvfs *out) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_statvfs, -1); + if(int e = mlibc::sys_statvfs(path, out); e) { + errno = e; + return -1; + } + return 0; +} + +int fstatvfs(int fd, struct statvfs *out) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_fstatvfs, -1); + if(int e = mlibc::sys_fstatvfs(fd, out); e) { + errno = e; + return -1; + } + return 0; +} + diff --git a/lib/mlibc/options/posix/generic/sys-time-stubs.cpp b/lib/mlibc/options/posix/generic/sys-time-stubs.cpp new file mode 100644 index 0000000..5cc0fe5 --- /dev/null +++ b/lib/mlibc/options/posix/generic/sys-time-stubs.cpp @@ -0,0 +1,107 @@ + +#include +#include +#include + +#include +#include +#include + +int gettimeofday(struct timeval *__restrict result, void *__restrict unused) { + (void)unused; // Linux just ignores gettimeofday(). + + if(result) { + long nanos; + if(int e = mlibc::sys_clock_get(CLOCK_REALTIME, &result->tv_sec, &nanos); e) { + errno = e; + return -1; + } + result->tv_usec = nanos / 1000; + } + return 0; +} + +int settimeofday(const struct timeval *, const struct timezone *) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +void timeradd(const struct timeval *a, const struct timeval *b, struct timeval *res) { + res->tv_sec = a->tv_sec + b->tv_sec; + res->tv_usec = a->tv_usec + b->tv_usec; + while(res->tv_usec > 999999) { + res->tv_usec -= 1000000; + res->tv_sec += 1; + } +} + +void timersub(const struct timeval *a, const struct timeval *b, struct timeval *res) { + res->tv_sec = a->tv_sec - b->tv_sec; + res->tv_usec = a->tv_usec - b->tv_usec; + while(res->tv_usec < 0) { + res->tv_usec += 1000000; + res->tv_sec -= 1; + } +} + +void timerclear(struct timeval *tvp) { + tvp->tv_sec = 0; + tvp->tv_usec = 0; +} + +int timerisset(struct timeval *tvp) { + if(tvp->tv_sec != 0 || tvp->tv_usec != 0) { + return 1; + } + return 0; +} + +int getitimer(int which, struct itimerval *curr_value) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_getitimer, -1); + if(int e = mlibc::sys_getitimer(which, curr_value); e) { + errno = e; + return -1; + } + return 0; +} + +int setitimer(int which, const struct itimerval *new_value, struct itimerval *old_value) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_setitimer, -1); + if(int e = mlibc::sys_setitimer(which, new_value, old_value); e) { + errno = e; + return -1; + } + return 0; +} + +int timer_create(clockid_t clk, struct sigevent *__restrict evp, timer_t *__restrict res) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_timer_create, -1); + if(int e = mlibc::sys_timer_create(clk, evp, res); e) { + errno = e; + return -1; + } + return 0; +} + +int timer_settime(timer_t t, int flags, const struct itimerspec *__restrict val, struct itimerspec *__restrict old) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_timer_settime, -1); + if(int e = mlibc::sys_timer_settime(t, flags, val, old); e) { + errno = e; + return -1; + } + return 0; +} + +int timer_gettime(timer_t, struct itimerspec *) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +int timer_delete(timer_t t) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_timer_delete, -1); + if(int e = mlibc::sys_timer_delete(t); e) { + errno = e; + return -1; + } + return 0; +} diff --git a/lib/mlibc/options/posix/generic/sys-times.cpp b/lib/mlibc/options/posix/generic/sys-times.cpp new file mode 100644 index 0000000..61b6e25 --- /dev/null +++ b/lib/mlibc/options/posix/generic/sys-times.cpp @@ -0,0 +1,19 @@ + +#include +#include + +#include +#include +#include +#include + +clock_t times(struct tms *tms) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_times, -1); + clock_t ret; + if(int e = mlibc::sys_times(tms, &ret); e) { + errno = e; + return -1; + } + return ret; +} + diff --git a/lib/mlibc/options/posix/generic/sys-uio.cpp b/lib/mlibc/options/posix/generic/sys-uio.cpp new file mode 100644 index 0000000..0f14bc0 --- /dev/null +++ b/lib/mlibc/options/posix/generic/sys-uio.cpp @@ -0,0 +1,67 @@ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +ssize_t readv(int fd, const struct iovec *iovs, int iovc) { + ssize_t read_bytes = 0; + + auto sysdep = MLIBC_CHECK_OR_ENOSYS(mlibc::sys_readv, -1); + + if (int e = sysdep(fd, iovs, iovc, &read_bytes); e) { + errno = e; + return -1; + } + + return read_bytes; +} + +ssize_t writev(int fd, const struct iovec *iovs, int iovc) { + __ensure(iovc); + + ssize_t written = 0; + size_t bytes = 0; + for(int i = 0; i < iovc; i++) { + if(SSIZE_MAX - bytes < iovs[i].iov_len) { + errno = EINVAL; + return -1; + } + bytes += iovs[i].iov_len; + } + frg::vector buffer{getAllocator()}; + buffer.resize(bytes); + + size_t to_copy = bytes; + char *bp = buffer.data(); + for(int i = 0; i < iovc; i++) { + size_t copy = frg::min(iovs[i].iov_len, to_copy); + + bp = (char *)mempcpy((void *)bp, (void *)iovs[i].iov_base, copy); + + to_copy -= copy; + if(to_copy == 0) + break; + } + + written = write(fd, buffer.data(), bytes); + return written; +} + +ssize_t preadv(int, const struct iovec *, int, off_t) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +ssize_t pwritev(int, const struct iovec *, int, off_t) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} diff --git a/lib/mlibc/options/posix/generic/sys-utsname.cpp b/lib/mlibc/options/posix/generic/sys-utsname.cpp new file mode 100644 index 0000000..3176574 --- /dev/null +++ b/lib/mlibc/options/posix/generic/sys-utsname.cpp @@ -0,0 +1,24 @@ + +#include +#include +#include + +#include +#include +#include +#include + +int uname(struct utsname *p) { + if (p == NULL) { + errno = EFAULT; + return -1; + } + + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_uname, -1); + if(int e = mlibc::sys_uname(p); e) { + errno = e; + return -1; + } + return 0; +} + diff --git a/lib/mlibc/options/posix/generic/sys-wait-stubs.cpp b/lib/mlibc/options/posix/generic/sys-wait-stubs.cpp new file mode 100644 index 0000000..6e7cc78 --- /dev/null +++ b/lib/mlibc/options/posix/generic/sys-wait-stubs.cpp @@ -0,0 +1,52 @@ + +#include +#include +#include + +#include +#include +#include + +int waitid(idtype_t idtype, id_t id, siginfo_t *info, int options) { + auto sysdep = MLIBC_CHECK_OR_ENOSYS(mlibc::sys_waitid, -1); + if(int e = sysdep(idtype, id, info, options); e) { + errno = e; + return -1; + } + return 0; +} + +pid_t waitpid(pid_t pid, int *status, int flags) { + pid_t ret; + int tmp_status = 0; + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_waitpid, -1); + if(int e = mlibc::sys_waitpid(pid, &tmp_status, flags, NULL, &ret); e) { + errno = e; + return -1; + } + if(status) { + *status = tmp_status; + } + return ret; +} + +pid_t wait(int *status) { + return waitpid(-1, status, 0); +} + +pid_t wait3(int *status, int options, struct rusage *rusage) { + (void) rusage; + mlibc::infoLogger() << "\e[31mmlibc: wait3() is not implemented correctly\e[39m" + << frg::endlog; + return waitpid(-1, status, options); +} + +pid_t wait4(pid_t pid, int *status, int options, struct rusage *ru) { + pid_t ret; + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_waitpid, -1); + if(int e = mlibc::sys_waitpid(pid, status, options, ru, &ret); e) { + errno = e; + return -1; + } + return ret; +} diff --git a/lib/mlibc/options/posix/generic/syslog-stubs.cpp b/lib/mlibc/options/posix/generic/syslog-stubs.cpp new file mode 100644 index 0000000..6a80ff9 --- /dev/null +++ b/lib/mlibc/options/posix/generic/syslog-stubs.cpp @@ -0,0 +1,152 @@ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +// This syslog implementation is largely taken from musl + +static char log_ident[32]; +static int log_options; +static int log_facility = LOG_USER; +static int log_fd = -1; +static int log_opt; +static int log_mask = 0xff; + +static int use_mlibc_logger = 0; +static FutexLock __syslog_lock; + +static const struct sockaddr_un log_addr {AF_UNIX, "/dev/log"}; + +void closelog(void) { + frg::unique_lock holder { __syslog_lock }; + close(log_fd); + log_fd = -1; +} + +static void __openlog() { + log_fd = socket(AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0); + if(log_fd >= 0) { + int ret = connect(log_fd, (const sockaddr *)&log_addr, sizeof log_addr); + if(ret) { + mlibc::infoLogger() << "\e[31mmlibc: syslog: connect returned an error, falling back to infoLogger\e[39m" << frg::endlog; + use_mlibc_logger = 1; + } + } +} + +void openlog(const char *ident, int options, int facility) { + frg::unique_lock holder { __syslog_lock }; + if(ident) { + size_t n = strnlen(ident, sizeof log_ident - 1); + memcpy(log_ident, ident, n); + log_ident[n] = 0; + } else { + log_ident[0] = 0; + } + log_options = options; + log_facility = facility; + + if((options & LOG_NDELAY) && log_fd < 0) + __openlog(); +} + +int setlogmask(int mask) { + int old_mask = log_mask; + + log_mask = mask; + + return old_mask; +} + +static void _vsyslog(int priority, const char *message, va_list ap) { + auto is_lost_conn = [] (int e) { + return e == ECONNREFUSED || e == ECONNRESET || e == ENOTCONN || e == EPIPE; + }; + + if(!(priority & log_mask)) { + return; + } + + char timebuf[16]; + time_t now; + struct tm tm; + char buf[1024]; + int errno_save = errno; + int pid; + int l, l2; + int hlen; + int fd; + + if(log_fd < 0) + __openlog(); + + if(use_mlibc_logger) { + vsnprintf(buf, sizeof buf, message, ap); + mlibc::infoLogger() << "mlibc: syslog: " << buf << frg::endlog; + return; + } + + if(!(priority & LOG_FACMASK)) + priority |= log_facility; + + now = time(NULL); + gmtime_r(&now, &tm); + strftime(timebuf, sizeof timebuf, "%b %e %T", &tm); + + pid = (log_opt & LOG_PID) ? getpid() : 0; + l = snprintf(buf, sizeof buf, "<%d>%s %n%s%s%.0d%s: ", + priority, timebuf, &hlen, log_ident, "[" + !pid, pid, "]" + !pid); + errno = errno_save; + l2 = vsnprintf(buf + l, sizeof buf - l, message, ap); + if(l2 >= 0) { + if(l2 >= (long int)(sizeof buf - l)) + l = sizeof buf - 1; + else + l += l2; + if(buf[l - 1] != '\n') + buf[l++] = '\n'; + if(send(log_fd, buf, l, 0) < 0 && (!is_lost_conn(errno) + || connect(log_fd, (const sockaddr *)&log_addr, sizeof log_addr) < 0 + || send(log_fd, buf, l, 0) < 0) + && (log_opt & LOG_CONS)) { + fd = open("/dev/console", O_WRONLY|O_NOCTTY|O_CLOEXEC); + if(fd >= 0) { + dprintf(fd, "%.*s", l - hlen, buf + hlen); + close(fd); + } + } + if(log_opt & LOG_PERROR) + dprintf(STDERR_FILENO, "%.*s", l - hlen, buf + hlen); + } +} + +void syslog(int priority, const char *format, ...) { + va_list ap; + va_start(ap, format); + vsyslog(priority, format, ap); + va_end(ap); +} + +void vsyslog(int priority, const char *message, va_list ap) { + int cs; + if(!(log_mask & LOG_MASK(priority & 7)) || (priority & ~0x3ff)) { + mlibc::infoLogger() << "\e[31mmlibc: syslog: log_mask or priority out of range, not printing anything\e[39m" << frg::endlog; + return; + } + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs); + frg::unique_lock lock(__syslog_lock); + _vsyslog(priority, message, ap); + pthread_setcancelstate(cs, 0); +} diff --git a/lib/mlibc/options/posix/generic/termios-stubs.cpp b/lib/mlibc/options/posix/generic/termios-stubs.cpp new file mode 100644 index 0000000..631456a --- /dev/null +++ b/lib/mlibc/options/posix/generic/termios-stubs.cpp @@ -0,0 +1,103 @@ +#ifndef _GNU_SOURCE +# define _GNU_SOURCE +#endif + +#include +#include +#include + +#include +#include + +speed_t cfgetispeed(const struct termios *tios) { + return tios->c_cflag & CBAUD; +} + +speed_t cfgetospeed(const struct termios *tios) { + return tios->c_cflag & CBAUD; +} + +int cfsetispeed(struct termios *termios, speed_t speed) { + return speed ? cfsetospeed(termios, speed) : 0; +} + +int cfsetospeed(struct termios *termios, speed_t speed) { + if(speed & ~CBAUD) { + errno = EINVAL; + return -1; + } + + termios->c_cflag &= ~CBAUD; + termios->c_cflag |= speed; + + return 0; +} + +void cfmakeraw(struct termios *t) { + t->c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON); + t->c_oflag &= ~OPOST; + t->c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN); + t->c_cflag &= ~(CSIZE | PARENB); + t->c_cflag |= CS8; + t->c_cc[VMIN] = 1; + t->c_cc[VTIME] = 0; +} + +int tcdrain(int fd) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_tcdrain, -1); + if(int e = mlibc::sys_tcdrain(fd); e) { + errno = e; + return -1; + } + return 0; +} + +int tcflow(int fd, int action) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_tcflow, -1); + if(int e = mlibc::sys_tcflow(fd, action); e) { + errno = e; + return -1; + } + return 0; +} + +int tcflush(int fd, int queue_selector) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_tcflush, -1); + if(int e = mlibc::sys_tcflush(fd, queue_selector); e) { + errno = e; + return -1; + } + return 0; +} + +int tcgetattr(int fd, struct termios *attr) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_tcgetattr, -1); + if(int e = mlibc::sys_tcgetattr(fd, attr); e) { + errno = e; + return -1; + } + return 0; +} + +pid_t tcgetsid(int fd) { + int sid; + if(ioctl(fd, TIOCGSID, &sid) < 0) { + return -1; + } + return sid; +} + +int tcsendbreak(int, int) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +int tcsetattr(int fd, int opts, const struct termios *attr) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_tcsetattr, -1); + if(int e = mlibc::sys_tcsetattr(fd, opts, attr); e) { + errno = e; + return -1; + } + return 0; +} + diff --git a/lib/mlibc/options/posix/generic/time.cpp b/lib/mlibc/options/posix/generic/time.cpp new file mode 100644 index 0000000..14193af --- /dev/null +++ b/lib/mlibc/options/posix/generic/time.cpp @@ -0,0 +1,505 @@ +#include +#include +#include +#include +#include + +#include +#include + +namespace { + +int month_to_day(int month) { + switch(month){ + case 0: return 0; + case 1: return 31; + case 2: return 59; + case 3: return 90; + case 4: return 120; + case 5: return 151; + case 6: return 181; + case 7: return 212; + case 8: return 243; + case 9: return 273; + case 10: return 304; + case 11: return 334; + } + return -1; +} + +int is_leapyear(int year) { + return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0); +} + +int month_and_year_to_day_in_year(int month, int year){ + int day = month_to_day(month); + if(is_leapyear(year) && month < 2) + return day + 1; + + return day; +} + +int target_determination(int month) { + switch(month){ + case 0: return 3; + case 1: return 14; + case 2: return 14; + case 3: return 4; + case 4: return 9; + case 5: return 6; + case 6: return 11; + case 7: return 8; + case 8: return 5; + case 9: return 10; + case 10: return 7; + case 11: return 12; + } + + return -1; +} + +int doom_determination(int full_year) { + int century = full_year / 100; + int anchor = 2 + 5 * (century % 4) % 7; + + int year = full_year % 100; + + if(year % 2) + year += 11; + + year /= 2; + + if(year % 2) + year += 11; + + return 7 - (year % 7) + anchor; +} + +//Determine day of week through the doomsday algorithm. +int day_determination(int day, int month, int year) { + int doom = doom_determination(year); + bool leap = is_leapyear(year); + + int target = target_determination(month); + if(leap && month < 2) + target++; + + int doom_dif = (day - target) % 7; + return (doom + doom_dif) % 7; +} + +struct strptime_internal_state { + bool has_century; + bool has_year; + bool has_month; + bool has_day_of_month; + bool has_day_of_year; + bool has_day_of_week; + + bool full_year_given; + + int century; + + size_t format_index; + size_t input_index; +}; + +char *strptime_internal(const char *__restrict input, const char *__restrict format, + struct tm *__restrict tm, struct strptime_internal_state *__restrict state) { + auto matchLanginfoItem = [&] (int start, size_t num, int &dest, bool &flag) -> bool { + for(size_t i = start; i < (start + num); i++) { + const char *mon = nl_langinfo(i); + size_t len = strlen(mon); + if(mlibc::strncasecmp(&input[state->input_index], mon, len)) + continue; + state->input_index += len; + dest = i - start; + flag = true; + return true; + } + return false; + }; + + auto matchNumericRange = [&] (int start, int end, int &dest, bool *flag) -> bool { + int product = 0, n = 0; + sscanf(&input[state->input_index], "%d%n", &product, &n); + if(n == 0 || 2 < n) + return false; + if(product < start || product > end) + return false; + state->input_index += n; + dest = product; + if(flag) *flag = true; + return true; + }; + + while(isspace(input[state->input_index])) + state->input_index++; + + if(input[state->input_index] == '\0') + return NULL; + + while(format[state->format_index] != '\0'){ + if(format[state->format_index] != '%'){ + if(isspace(format[state->format_index])){ + while(isspace(input[state->input_index++])); + state->input_index--; + } + else { + if(format[state->format_index] != input[state->input_index++]) + return NULL; + } + state->format_index++; + continue; + } + state->format_index++; + switch(format[state->format_index]){ + case '%': + if(input[state->input_index++] != '%') + return NULL; + break; + case 'a': + case 'A': { + if (!matchLanginfoItem(DAY_1, 7, tm->tm_wday, state->has_day_of_week) && \ + !matchLanginfoItem(ABDAY_1, 7, tm->tm_wday, state->has_day_of_week)) + return NULL; + break; + } + case 'b': + case 'B': + case 'h': { + if (!matchLanginfoItem(MON_1, 12, tm->tm_mon, state->has_month) && \ + !matchLanginfoItem(ABMON_1, 12, tm->tm_mon, state->has_month)) + return NULL; + break; + } + case 'c': + __ensure(!"strptime() %c directive unimplemented."); + __builtin_unreachable(); + break; + case 'C': { + int product = 0, n = 0; + sscanf(&input[state->input_index], "%d%n", &product, &n); + if(n == 0 || 2 < n) + return NULL; + state->input_index += n; + state->century = product; + state->has_century = true; + break; + } + case 'd': //`%d` and `%e` are equivalent + case 'e': { + if(!matchNumericRange(1, 31, tm->tm_mday, &state->has_day_of_month)) + return NULL; + break; + } + case 'D': { //equivalent to `%m/%d/%y` + size_t pre_fi = state->format_index; + state->format_index = 0; + + char *result = strptime_internal(input, "%m/%d/%y", tm, state); + if(result == NULL) + return NULL; + + state->format_index = pre_fi; + break; + } + case 'H': { + if(!matchNumericRange(0, 23, tm->tm_hour, nullptr)) + return NULL; + break; + } + case 'I': { + if(!matchNumericRange(1, 12, tm->tm_hour, nullptr)) + return NULL; + break; + } + case 'j': { + if(!matchNumericRange(1, 366, tm->tm_yday, &state->has_day_of_year)) + return NULL; + tm->tm_yday--; + break; + } + case 'm': { + if(!matchNumericRange(1, 12, tm->tm_mon, &state->has_month)) + return NULL; + tm->tm_mon--; + break; + } + case 'M': { + if(!matchNumericRange(0, 59, tm->tm_min, nullptr)) + return NULL; + break; + } + case 'n': + case 't': { + size_t n = 0; + while(isspace(input[state->input_index++])) + n++; + if(n == 0) + return NULL; + state->input_index--; + break; + } + case 'p': { + const char *meridian_str = nl_langinfo(AM_STR); + size_t len = strlen(meridian_str); + if (!mlibc::strncasecmp(&input[state->input_index], meridian_str, len)) { + tm->tm_hour %= 12; + state->input_index += len; + break; + } + meridian_str = nl_langinfo(PM_STR); + len = strlen(meridian_str); + if (!mlibc::strncasecmp(&input[state->input_index], meridian_str, len)) { + tm->tm_hour %= 12; + tm->tm_hour += 12; + state->input_index += len; + break; + } + break; + } + case 'r': { //equivalent to `%I:%M:%S %p` + size_t pre_fi = state->format_index; + state->format_index = 0; + + char *result = strptime_internal(input, "%I:%M:%S %p", tm, state); + if(result == NULL) + return NULL; + + state->format_index = pre_fi; + break; + } + case 'R': { //equivalent to `%H:%M` + size_t pre_fi = state->format_index; + state->format_index = 0; + + char *result = strptime_internal(input, "%H:%M", tm, state); + if(result == NULL) + return NULL; + + state->format_index = pre_fi; + break; + } + case 'S': { + if(!matchNumericRange(0, 60, tm->tm_sec, nullptr)) + return NULL; + break; + } + case 'T': { //equivalent to `%H:%M:%S` + size_t pre_fi = state->format_index; + state->format_index = 0; + + char *result = strptime_internal(input, "%H:%M:%S", tm, state); + if(result == NULL) + return NULL; + + state->format_index = pre_fi; + break; + } + case 'U': + __ensure(!"strptime() %U directive unimplemented."); + __builtin_unreachable(); + break; + case 'w': { + int product = 0, n = 0; + sscanf(&input[state->input_index], "%d%n", &product, &n); + if(n == 0 || 1 < n) + return NULL; + state->input_index += n; + tm->tm_wday = product; + state->has_day_of_week = true; + break; + } + case 'W': + __ensure(!"strptime() %W directive unimplemented."); + __builtin_unreachable(); + break; + case 'x': + __ensure(!"strptime() %x directive unimplemented."); + __builtin_unreachable(); + break; + case 'X': + __ensure(!"strptime() %X directive unimplemented."); + __builtin_unreachable(); + break; + case 'y': { + int product = 0, n = 0; + sscanf(&input[state->input_index], "%d%n", &product, &n); + if(n == 0 || 2 < n) + return NULL; + if(product < 69) + product += 100; + state->input_index += n; + tm->tm_year = product; + state->has_year = true; + break; + } + case 'Y': { + int product = 0, n = 0; + sscanf(&input[state->input_index], "%d%n", &product, &n); + if(n == 0 || 4 < n) + return NULL; + state->input_index += n; + tm->tm_year = product - 1900; + state->has_year = true; + state->has_century = true; + state->full_year_given = true; + state->century = product / 100; + break; + } + case 'F': { //GNU extensions + //equivalent to `%Y-%m-%d` + size_t pre_fi = state->format_index; + state->format_index = 0; + + char *result = strptime_internal(input, "%Y-%m-%d", tm, state); + if(result == NULL) + return NULL; + + state->format_index = pre_fi; + break; + } + case 'g': + __ensure(!"strptime() %g directive unimplemented."); + __builtin_unreachable(); + break; + case 'G': + __ensure(!"strptime() %G directive unimplemented."); + __builtin_unreachable(); + break; + case 'u': { + if(!matchNumericRange(1, 7, tm->tm_wday, nullptr)) + return NULL; + tm->tm_wday--; + break; + } + case 'V': + __ensure(!"strptime() %V directive unimplemented."); + __builtin_unreachable(); + break; + case 'z': + __ensure(!"strptime() %z directive unimplemented."); + __builtin_unreachable(); + break; + case 'Z': + __ensure(!"strptime() %Z directive unimplemented."); + __builtin_unreachable(); + break; + case 's': //end of GNU extensions + __ensure(!"strptime() %s directive unimplemented."); + __builtin_unreachable(); + break; + case 'E': { //locale-dependent date & time representation + __ensure(!"strptime() %E* directives unimplemented."); + __builtin_unreachable(); + /* + state->format_index++; + switch(format[state->format_index]){ + case 'c': + break; + case 'C': + break; + case 'x': + break; + case 'X': + break; + case 'y': + break; + case 'Y': + break; + default: + return NULL; + } + */ + } + case 'O': { //locale-dependent numeric symbols + __ensure(!"strptime() %O* directives unimplemented."); + __builtin_unreachable(); + /* + state->format_index++; + switch(format[state->format_index]){ + case 'd': + case 'e': + break; + case 'H': + break; + case 'I': + break; + case 'm': + break; + case 'M': + break; + case 'S': + break; + case 'U': + break; + case 'w': + break; + case 'W': + break; + case 'y': + break; + default: + return NULL; + } + */ + } + default: + return NULL; + } + state->format_index++; + } + + return (char*)input + state->input_index; +} + +} //anonymous namespace + +char *strptime(const char *__restrict s, const char *__restrict format, struct tm *__restrict tm){ + struct strptime_internal_state state = {}; + + char *result = strptime_internal(s, format, tm, &state); + + if(result == NULL) + return NULL; + + if(state.has_century && !state.full_year_given){ + int full_year = state.century * 100; + + if(state.has_year){ + //Compensate for default century-adjustment of `%j` operand + if(tm->tm_year >= 100) + full_year += tm->tm_year - 100; + else + full_year += tm->tm_year; + } + + tm->tm_year = full_year - 1900; + + state.has_year = true; + } + + if(state.has_month && !state.has_day_of_year){ + int day = 0; + if(state.has_year) + day = month_and_year_to_day_in_year(tm->tm_mon, tm->tm_year); + else + day = month_to_day(tm->tm_mon); + + tm->tm_yday = day + tm->tm_mday - 1; + state.has_day_of_year = true; + } + + if(state.has_year && !state.has_day_of_week){ + if(!state.has_month && !state.has_day_of_month){ + tm->tm_wday = day_determination(0, 0, tm->tm_year + 1900); + } + else if(state.has_month && state.has_day_of_month){ + tm->tm_wday = day_determination(tm->tm_mday, tm->tm_mon, tm->tm_year + 1900); + } + state.has_day_of_week = true; + } + + return result; +} diff --git a/lib/mlibc/options/posix/generic/ucontext-stubs.cpp b/lib/mlibc/options/posix/generic/ucontext-stubs.cpp new file mode 100644 index 0000000..9413a78 --- /dev/null +++ b/lib/mlibc/options/posix/generic/ucontext-stubs.cpp @@ -0,0 +1,19 @@ +#include +#include + +int getcontext(ucontext_t *) { + __ensure(!"Not implemented!"); + __builtin_unreachable(); +} +int setcontext(const ucontext_t *) { + __ensure(!"Not implemented!"); + __builtin_unreachable(); +} +void makecontext(ucontext_t *, void (*)(), int, ...) { + __ensure(!"Not implemented!"); + __builtin_unreachable(); +} +int swapcontext(ucontext_t *, const ucontext_t *) { + __ensure(!"Not implemented!"); + __builtin_unreachable(); +} diff --git a/lib/mlibc/options/posix/generic/unistd-stubs.cpp b/lib/mlibc/options/posix/generic/unistd-stubs.cpp new file mode 100644 index 0000000..39cf76a --- /dev/null +++ b/lib/mlibc/options/posix/generic/unistd-stubs.cpp @@ -0,0 +1,1227 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +namespace { + +constexpr bool logExecvpeTries = false; + +} + +unsigned int alarm(unsigned int seconds) { + struct itimerval it = {}, old = {}; + it.it_value.tv_sec = seconds; + setitimer(ITIMER_REAL, &it, &old); + return old.it_value.tv_sec + !! old.it_value.tv_usec; +} + +int chdir(const char *path) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_chdir, -1); + if(int e = mlibc::sys_chdir(path); e) { + errno = e; + return -1; + } + return 0; +} + +int fchdir(int fd) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_fchdir, -1); + if(int e = mlibc::sys_fchdir(fd); e) { + errno = e; + return -1; + } + return 0; +} + +int chown(const char *path, uid_t uid, gid_t gid) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_fchownat, -1); + if(int e = mlibc::sys_fchownat(AT_FDCWD, path, uid, gid, 0); e) { + errno = e; + return -1; + } + return 0; +} + +ssize_t confstr(int name, char *buf, size_t len) { + const char *str = ""; + if (name == _CS_PATH) { + str = "/bin:/usr/bin"; + } else if(name == _CS_GNU_LIBPTHREAD_VERSION) { + // We are not glibc, so we can return 0 here. + return 0; + } else if(name == _CS_GNU_LIBC_VERSION) { + // We are not glibc, so we can return 0 here. + return 0; + } else { + mlibc::infoLogger() << "\e[31mmlibc: confstr() request " << name << " is unimplemented\e[39m" + << frg::endlog; + __ensure(!"Not implemented"); + } + + return snprintf(buf, len, "%s", str) + 1; +} + +void _exit(int status) { + mlibc::sys_exit(status); +} + +int execl(const char *path, const char *arg0, ...) { + // TODO: It's a stupid idea to limit the number of arguments here. + char *argv[16]; + argv[0] = const_cast(arg0); + + va_list args; + int n = 1; + va_start(args, arg0); + while(true) { + __ensure(n < 15); + auto argn = va_arg(args, const char *); + argv[n++] = const_cast(argn); + if(!argn) + break; + } + va_end(args); + argv[n] = nullptr; + + return execve(path, argv, environ); +} + +// This function is taken from musl. +int execle(const char *path, const char *arg0, ...) { + int argc; + va_list ap; + va_start(ap, arg0); + for(argc = 1; va_arg(ap, const char *); argc++); + va_end(ap); + + int i; + char *argv[argc + 1]; + char **envp; + va_start(ap, arg0); + argv[0] = (char *)argv; + for(i = 1; i <= argc; i++) + argv[i] = va_arg(ap, char *); + envp = va_arg(ap, char **); + va_end(ap); + return execve(path, argv, envp); +} + +// This function is taken from musl +int execlp(const char *file, const char *argv0, ...) { + int argc; + va_list ap; + va_start(ap, argv0); + for(argc = 1; va_arg(ap, const char *); argc++); + va_end(ap); + { + int i; + char *argv[argc + 1]; + va_start(ap, argv0); + argv[0] = (char *)argv0; + for(i = 1; i < argc; i++) + argv[i] = va_arg(ap, char *); + argv[i] = NULL; + va_end(ap); + return execvp(file, argv); + } +} + +int execv(const char *path, char *const argv[]) { + return execve(path, argv, environ); +} + +int execvp(const char *file, char *const argv[]) { + return execvpe(file, argv, environ); +} + +int execvpe(const char *file, char *const argv[], char *const envp[]) { + char *null_list[] = { + nullptr + }; + + if(!argv) + argv = null_list; + if(!envp) + envp = null_list; + + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_execve, -1); + + if(strchr(file, '/')) { + int e = mlibc::sys_execve(file, argv, envp); + __ensure(e && "sys_execve() is supposed to never return with success"); + errno = e; + return -1; + } + + frg::string_view dirs; + if(const char *pv = getenv("PATH"); pv) { + dirs = pv; + }else{ + dirs = "/bin:/usr/bin"; + } + + size_t p = 0; + int res = ENOENT; + while(p < dirs.size()) { + size_t s; // Offset of next colon or end of string. + if(size_t cs = dirs.find_first(':', p); cs != size_t(-1)) { + s = cs; + }else{ + s = dirs.size(); + } + + frg::string path{getAllocator()}; + path += dirs.sub_string(p, s - p); + path += "/"; + path += file; + + if(logExecvpeTries) + mlibc::infoLogger() << "mlibc: execvpe() tries '" << path.data() << "'" << frg::endlog; + + int e = mlibc::sys_execve(path.data(), argv, envp); + __ensure(e && "sys_execve() is supposed to never return with success"); + switch(e) { + case ENOENT: + case ENOTDIR: + break; + case EACCES: + res = EACCES; + break; + default: + errno = e; + return -1; + } + + p = s + 1; + } + + errno = res; + return -1; +} + +int faccessat(int dirfd, const char *pathname, int mode, int flags) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_faccessat, -1); + if(int e = mlibc::sys_faccessat(dirfd, pathname, mode, flags); e) { + errno = e; + return -1; + } + return 0; +} + +int fchown(int fd, uid_t uid, gid_t gid) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_fchownat, -1); + if(int e = mlibc::sys_fchownat(fd, "", uid, gid, AT_EMPTY_PATH); e) { + errno = e; + return -1; + } + return 0; +} + +int fchownat(int fd, const char *path, uid_t uid, gid_t gid, int flags) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_fchownat, -1); + if(int e = mlibc::sys_fchownat(fd, path, uid, gid, flags); e) { + errno = e; + return -1; + } + return 0; +} + +int fdatasync(int fd) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_fdatasync, -1); + if(int e = mlibc::sys_fdatasync(fd); e) { + errno = e; + return -1; + } + return 0; +} + +int fexecve(int, char *const [], char *const []) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +long fpathconf(int, int) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +int fsync(int fd) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_fsync, -1); + if(auto e = mlibc::sys_fsync(fd); e) { + errno = e; + return -1; + } + return 0; +} + +int ftruncate(int fd, off_t size) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_ftruncate, -1); + if(int e = mlibc::sys_ftruncate(fd, size); e) { + errno = e; + return -1; + } + return 0; +} + +char *getcwd(char *buffer, size_t size) { + if (buffer) { + if (size == 0) { + errno = EINVAL; + return NULL; + } + } else if (!buffer) { + if (size == 0) + size = PATH_MAX; + + buffer = (char *)malloc(size); + } + + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_getcwd, nullptr); + if(int e = mlibc::sys_getcwd(buffer, size); e) { + errno = e; + return NULL; + } + + return buffer; +} + +int getgroups(int size, gid_t list[]) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_getgroups, -1); + int ret; + if(int e = mlibc::sys_getgroups(size, list, &ret); e) { + errno = e; + return -1; + } + return ret; +} + +long gethostid(void) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +int gethostname(char *buffer, size_t bufsize) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_gethostname, -1); + if(auto e = mlibc::sys_gethostname(buffer, bufsize); e) { + errno = e; + return -1; + } + return 0; +} + +int sethostname(const char *buffer, size_t bufsize) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_sethostname, -1); + if(auto e = mlibc::sys_sethostname(buffer, bufsize); e) { + errno = e; + return -1; + } + return 0; +} + +// Code taken from musl +char *getlogin(void) { + return getenv("LOGNAME"); +} + +int getlogin_r(char *, size_t) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +// optarg and optind are provided to us by the GLIBC part of the mlibc. + +static char *scan = NULL; /* Private scan pointer. */ + +int getopt(int argc, char *const argv[], const char *optstring) { + char c; + char *place; + + optarg = NULL; + + if (!scan || *scan == '\0') { + if (optind == 0) + optind++; + + if (optind >= argc || argv[optind][0] != '-' || argv[optind][1] == '\0') + return EOF; + if (argv[optind][1] == '-' && argv[optind][2] == '\0') { + optind++; + return EOF; + } + + scan = argv[optind]+1; + optind++; + } + + c = *scan++; + place = strchr(optstring, c); + + if (!place || c == ':') { + fprintf(stderr, "%s: unknown option -%c\n", argv[0], c); + return '?'; + } + + place++; + if (*place == ':') { + if (*scan != '\0') { + optarg = scan; + scan = NULL; + } else if( optind < argc ) { + optarg = argv[optind]; + optind++; + } else { + fprintf(stderr, "%s: option requires argument -%c\n", argv[0], c); + return ':'; + } + } + + return c; +} + +pid_t getpgid(pid_t pid) { + pid_t pgid; + + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_getpgid, -1); + if(int e = mlibc::sys_getpgid(pid, &pgid); e) { + errno = e; + return -1; + } + return pgid; +} + +pid_t getpgrp(void) { + return getpgid(0); +} + +pid_t getsid(pid_t pid) { + if(!mlibc::sys_getsid) { + MLIBC_MISSING_SYSDEP(); + return -1; + } + pid_t sid; + if(int e = mlibc::sys_getsid(pid, &sid); e) { + errno = e; + return -1; + } + return sid; +} + +int lchown(const char *path, uid_t uid, gid_t gid) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_fchownat, -1); + if(int e = mlibc::sys_fchownat(AT_FDCWD, path, uid, gid, AT_SYMLINK_NOFOLLOW); e) { + errno = e; + return -1; + } + return 0; +} + +int link(const char *old_path, const char *new_path) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_link, -1); + if(int e = mlibc::sys_link(old_path, new_path); e) { + errno = e; + return -1; + } + return 0; +} + +int linkat(int olddirfd, const char *old_path, int newdirfd, const char *new_path, int flags) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_linkat, -1); + if(int e = mlibc::sys_linkat(olddirfd, old_path, newdirfd, new_path, flags); e) { + errno = e; + return -1; + } + return 0; +} + +// Code take from musl +int lockf(int fd, int op, off_t size) { + struct flock l = { + .l_type = F_WRLCK, + .l_whence = SEEK_CUR, + .l_start = 0, + .l_len = size, + .l_pid = 0, + }; + + switch(op) { + case F_TEST: + l.l_type = F_RDLCK; + if(fcntl(fd, F_GETLK, &l) < 0) + return -1; + if(l.l_type == F_UNLCK || l.l_pid == getpid()) + return 0; + errno = EACCES; + return -1; + case F_ULOCK: + l.l_type = F_UNLCK; + [[fallthrough]]; + case F_TLOCK: + return fcntl(fd, F_SETLK, &l); + case F_LOCK: + return fcntl(fd, F_SETLKW, &l); + } + + errno = EINVAL; + return -1; +} + +int nice(int) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +long pathconf(const char *, int name) { + switch (name) { + case _PC_NAME_MAX: + return NAME_MAX; + default: + mlibc::infoLogger() << "missing pathconf() entry " << name << frg::endlog; + errno = EINVAL; + return -1; + } +} + +int pause(void) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_pause, -1); + if(int e = mlibc::sys_pause(); e) { + errno = e; + return -1; + } + __ensure(!"There is no successful completion return value for pause"); + __builtin_unreachable(); +} + +int pipe(int *fds) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_pipe, -1); + if(int e = mlibc::sys_pipe(fds, 0); e) { + errno = e; + return -1; + } + return 0; +} + +int pipe2(int *fds, int flags) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_pipe, -1); + if(int e = mlibc::sys_pipe(fds, flags); e) { + errno = e; + return -1; + } + return 0; +} + +ssize_t pread(int fd, void *buf, size_t n, off_t off) { + ssize_t num_read; + + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_pread, -1); + if(int e = mlibc::sys_pread(fd, buf, n, off, &num_read); e) { + errno = e; + return -1; + } + return num_read; +} + +ssize_t pwrite(int fd, const void *buf, size_t n, off_t off) { + ssize_t num_written; + + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_pwrite, -1); + if(int e = mlibc::sys_pwrite(fd, buf, n, off, &num_written); e) { + errno = e; + return -1; + } + return num_written; +} + +ssize_t readlink(const char *__restrict path, char *__restrict buffer, size_t max_size) { + ssize_t length; + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_readlink, -1); + if(int e = mlibc::sys_readlink(path, buffer, max_size, &length); e) { + errno = e; + return -1; + } + return length; +} + +ssize_t readlinkat(int, const char *__restrict, char *__restrict, size_t) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +int rmdir(const char *path) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_rmdir, -1); + if(int e = mlibc::sys_rmdir(path); e) { + errno = e; + return -1; + } + return 0; +} + +int setegid(gid_t egid) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_setegid, 0); + if(int e = mlibc::sys_setegid(egid); e) { + errno = e; + return -1; + } + return 0; +} + +int seteuid(uid_t euid) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_seteuid, 0); + if(int e = mlibc::sys_seteuid(euid); e) { + errno = e; + return -1; + } + return 0; +} + +int setgid(gid_t gid) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_setgid, 0); + if(int e = mlibc::sys_setgid(gid); e) { + errno = e; + return -1; + } + return 0; +} + +int setpgid(pid_t pid, pid_t pgid) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_setpgid, -1); + if(int e = mlibc::sys_setpgid(pid, pgid); e) { + errno = e; + return -1; + } + return 0; +} + +pid_t setpgrp(void) { + return setpgid(0, 0); +} + +int setregid(gid_t rgid, gid_t egid) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_setregid, -1); + if(int e = mlibc::sys_setregid(rgid, egid); e) { + errno = e; + return -1; + } + return 0; +} + +int setreuid(uid_t ruid, uid_t euid) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_setreuid, -1); + if(int e = mlibc::sys_setreuid(ruid, euid); e) { + errno = e; + return -1; + } + return 0; +} + +pid_t setsid(void) { + if(!mlibc::sys_setsid) { + MLIBC_MISSING_SYSDEP(); + return -1; + } + pid_t sid; + if(int e = mlibc::sys_setsid(&sid); e) { + errno = e; + return -1; + } + return sid; +} + +int setuid(uid_t uid) { + if(!mlibc::sys_setuid) { + MLIBC_MISSING_SYSDEP(); + mlibc::infoLogger() << "mlibc: missing sysdep sys_setuid(). Returning 0" << frg::endlog; + return 0; + } + if(int e = mlibc::sys_setuid(uid); e) { + errno = e; + return -1; + } + return 0; +} + +void swab(const void *__restrict, void *__restrict, ssize_t) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +int symlink(const char *target_path, const char *link_path) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_symlink, -1); + if(int e = mlibc::sys_symlink(target_path, link_path); e) { + errno = e; + return -1; + } + return 0; +} + +int symlinkat(const char *target_path, int dirfd, const char *link_path) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_symlinkat, -1); + if(int e = mlibc::sys_symlinkat(target_path, dirfd, link_path); e) { + errno = e; + return -1; + } + return 0; +} + +void sync(void) { + if(!mlibc::sys_sync) { + MLIBC_MISSING_SYSDEP(); + } else { + mlibc::sys_sync(); + } +} + +long sysconf(int number) { + if(mlibc::sys_sysconf) { + long ret = 0; + + int e = mlibc::sys_sysconf(number, &ret); + + if(e && e != EINVAL) { + errno = e; + return -1; + } + + if(e != EINVAL) { + return ret; + } + } + + /* default return values, if not overriden by sysdep */ + switch(number) { + case _SC_ARG_MAX: + // On linux, it is defined to 2097152 in most cases, so define it to be 2097152 + return 2097152; + case _SC_PAGE_SIZE: + return mlibc::page_size; + case _SC_OPEN_MAX: + mlibc::infoLogger() << "\e[31mmlibc: sysconf(_SC_OPEN_MAX) returns fallback value 256\e[39m" << frg::endlog; + return 256; + case _SC_PHYS_PAGES: + mlibc::infoLogger() << "\e[31mmlibc: sysconf(_SC_PHYS_PAGES) returns fallback value 1024\e[39m" << frg::endlog; + return 1024; + case _SC_NPROCESSORS_ONLN: + mlibc::infoLogger() << "\e[31mmlibc: sysconf(_SC_NPROCESSORS_ONLN) returns fallback value 1\e[39m" << frg::endlog; + return 1; + case _SC_GETPW_R_SIZE_MAX: + return NSS_BUFLEN_PASSWD; + case _SC_GETGR_R_SIZE_MAX: + mlibc::infoLogger() << "\e[31mmlibc: sysconf(_SC_GETGR_R_SIZE_MAX) returns fallback value 1024\e[39m" << frg::endlog; + return 1024; + case _SC_CHILD_MAX: + mlibc::infoLogger() << "\e[31mmlibc: sysconf(_SC_CHILD_MAX) returns fallback value 25\e[39m" << frg::endlog; + // On linux, it is defined to 25 in most cases, so define it to be 25 + return 25; + case _SC_JOB_CONTROL: + mlibc::infoLogger() << "\e[31mmlibc: sysconf(_SC_JOB_CONTROL) returns fallback value 1\e[39m" << frg::endlog; + // If 1, job control is supported + return 1; + case _SC_CLK_TCK: + // TODO: This should be obsolete? + mlibc::infoLogger() << "\e[31mmlibc: sysconf(_SC_CLK_TCK) is obsolete and returns arbitrary value 1000000\e[39m" << frg::endlog; + return 1000000; + case _SC_NGROUPS_MAX: + mlibc::infoLogger() << "\e[31mmlibc: sysconf(_SC_NGROUPS_MAX) returns fallback value 65536\e[39m" << frg::endlog; + // On linux, it is defined to 65536 in most cases, so define it to be 65536 + return 65536; + case _SC_RE_DUP_MAX: + mlibc::infoLogger() << "\e[31mmlibc: sysconf(_SC_RE_DUP_MAX) returns fallback value RE_DUP_MAX\e[39m" << frg::endlog; + return RE_DUP_MAX; + case _SC_LINE_MAX: + mlibc::infoLogger() << "\e[31mmlibc: sysconf(_SC_LINE_MAX) returns fallback value 2048\e[39m" << frg::endlog; + // Linux defines it as 2048. + return 2048; + case _SC_XOPEN_CRYPT: +#if __MLIBC_CRYPT_OPTION + return _XOPEN_CRYPT; +#else + return -1; +#endif /* __MLIBC_CRYPT_OPTION */ + case _SC_NPROCESSORS_CONF: + // TODO: actually return a proper value for _SC_NPROCESSORS_CONF + mlibc::infoLogger() << "\e[31mmlibc: sysconf(_SC_NPROCESSORS_CONF) unconditionally returns fallback value 1\e[39m" << frg::endlog; + return 1; + case _SC_HOST_NAME_MAX: + mlibc::infoLogger() << "\e[31mmlibc: sysconf(_SC_HOST_NAME_MAX) unconditionally returns fallback value 256\e[39m" << frg::endlog; + return 256; + default: + mlibc::infoLogger() << "\e[31mmlibc: sysconf() call is not implemented, number: " << number << "\e[39m" << frg::endlog; + errno = EINVAL; + return -1; + } +} + +pid_t tcgetpgrp(int fd) { + int pgrp; + if(ioctl(fd, TIOCGPGRP, &pgrp) < 0) { + return -1; + } + return pgrp; +} + +int tcsetpgrp(int fd, pid_t pgrp) { + return ioctl(fd, TIOCSPGRP, &pgrp); +} + +int truncate(const char *, off_t) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +char *ttyname(int fd) { + const size_t size = 128; + static thread_local char buf[size]; + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_ttyname, nullptr); + if(int e = mlibc::sys_ttyname(fd, buf, size); e) { + errno = e; + return nullptr; + } + return buf; +} + +int ttyname_r(int fd, char *buf, size_t size) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_ttyname, -1); + if(int e = mlibc::sys_ttyname(fd, buf, size); e) { + return e; + } + return 0; +} + +int unlink(const char *path) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_unlinkat, -1); + if(int e = mlibc::sys_unlinkat(AT_FDCWD, path, 0); e) { + errno = e; + return -1; + } + return 0; +} + +int unlinkat(int fd, const char *path, int flags) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_unlinkat, -1); + if(int e = mlibc::sys_unlinkat(fd, path, flags); e) { + errno = e; + return -1; + } + return 0; +} + +int getpagesize() { + return mlibc::page_size; +} + +// Code taken from musl +// GLIBC extension for stdin/stdout +char *getpass(const char *prompt) { + int fdin, fdout; + struct termios s, t; + ssize_t l; + static char password[128]; + + if((fdin = open("/dev/tty", O_RDWR|O_NOCTTY|O_CLOEXEC)) < 0) { + fdin = STDIN_FILENO; + fdout = STDOUT_FILENO; + } else { + fdout = fdin; + } + + tcgetattr(fdin, &t); + s = t; + t.c_lflag &= ~(ECHO | ISIG); + t.c_lflag |= ICANON; + t.c_iflag &= ~(INLCR | IGNCR); + t.c_iflag |= ICRNL; + tcsetattr(fdin, TCSAFLUSH, &t); + tcdrain(fdin); + + dprintf(fdout, "%s", prompt); + + l = read(fdin, password, sizeof password); + if(l >= 0) { + if((l > 0 && password[l - 1] == '\n') || l == sizeof password) + l--; + password[l] = 0; + } + + tcsetattr(fdin, TCSAFLUSH, &s); + + dprintf(fdout, "\n"); + if(fdin != STDIN_FILENO) { + close(fdin); + } + + return l < 0 ? 0 : password; +} + +char *get_current_dir_name(void) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +// This is a Linux extension +pid_t gettid(void) { + if(!mlibc::sys_gettid) { + MLIBC_MISSING_SYSDEP(); + __ensure(!"Cannot continue without sys_gettid()"); + } + return mlibc::sys_gettid(); +} + +int getentropy(void *buffer, size_t length) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_getentropy, -1); + if(length > 256) { + errno = EIO; + return -1; + } + if(int e = mlibc::sys_getentropy(buffer, length); e) { + errno = e; + return -1; + } + return 0; +} + +ssize_t write(int fd, const void *buf, size_t count) { + ssize_t bytes_written; + if(int e = mlibc::sys_write(fd, buf, count, &bytes_written); e) { + errno = e; + return (ssize_t)-1; + } + return bytes_written; +} + +ssize_t read(int fd, void *buf, size_t count) { + ssize_t bytes_read; + if(int e = mlibc::sys_read(fd, buf, count, &bytes_read); e) { + errno = e; + return (ssize_t)-1; + } + return bytes_read; +} + +off_t lseek(int fd, off_t offset, int whence) { + off_t new_offset; + if(int e = mlibc::sys_seek(fd, offset, whence, &new_offset); e) { + errno = e; + return (off_t)-1; + } + return new_offset; +} + +off64_t lseek64(int fd, off64_t offset, int whence) { + off64_t new_offset; + if(int e = mlibc::sys_seek(fd, offset, whence, &new_offset); e) { + errno = e; + return (off64_t)-1; + } + return new_offset; +} + +int close(int fd) { + return mlibc::sys_close(fd); +} + +unsigned int sleep(unsigned int secs) { + time_t seconds = secs; + long nanos = 0; + if(!mlibc::sys_sleep) { + MLIBC_MISSING_SYSDEP(); + __ensure(!"Cannot continue without sys_sleep()"); + } + mlibc::sys_sleep(&seconds, &nanos); + return seconds; +} + +// In contrast to sleep() this functions returns 0/-1 on success/failure. +int usleep(useconds_t usecs) { + time_t seconds = 0; + long nanos = usecs * 1000; + if(!mlibc::sys_sleep) { + MLIBC_MISSING_SYSDEP(); + __ensure(!"Cannot continue without sys_sleep()"); + } + return mlibc::sys_sleep(&seconds, &nanos); +} + +int dup(int fd) { + int newfd; + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_dup, -1); + if(int e = mlibc::sys_dup(fd, 0, &newfd); e) { + errno = e; + return -1; + } + return newfd; +} + +int dup2(int fd, int newfd) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_dup2, -1); + if(int e = mlibc::sys_dup2(fd, 0, newfd); e) { + errno = e; + return -1; + } + return newfd; +} + +pid_t fork(void) { + auto self = mlibc::get_current_tcb(); + pid_t child; + + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_fork, -1); + + auto hand = self->atforkEnd; + while (hand) { + if (hand->prepare) + hand->prepare(); + + hand = hand->prev; + } + + if(int e = mlibc::sys_fork(&child); e) { + errno = e; + return -1; + } + + hand = self->atforkBegin; + while (hand) { + if (!child) { + if (hand->child) + hand->child(); + } else { + if (hand->parent) + hand->parent(); + } + hand = hand->next; + } + + return child; +} + +pid_t vfork(void) { + pid_t child; + /* + * Fork handlers established using pthread_atfork(3) are not + * called when a multithreaded program employing the NPTL + * threading library calls vfork(). Fork handlers are called + * in this case in a program using the LinuxThreads threading + * library. (See pthreads(7) for a description of Linux + * threading libraries.) + * - vfork(2), release 5.13 of the Linux man-pages project + * + * as a result, we call sys_fork instead of running atforks + */ + + /* deferring to fork as implementing vfork correctly requires assembly + * to handle not mucking up the stack + */ + if(!mlibc::sys_fork) { + MLIBC_MISSING_SYSDEP(); + errno = ENOSYS; + return -1; + } + + if(int e = mlibc::sys_fork(&child); e) { + errno = e; + return -1; + } + + return child; +} + +int execve(const char *path, char *const argv[], char *const envp[]) { + char *null_list[] = { + nullptr + }; + + if(!argv) + argv = null_list; + if(!envp) + envp = null_list; + + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_execve, -1); + int e = mlibc::sys_execve(path, argv, envp); + __ensure(e && "sys_execve() is expected to fail if it returns"); + errno = e; + return -1; +} + +gid_t getgid(void) { + if(!mlibc::sys_getgid) { + MLIBC_MISSING_SYSDEP(); + __ensure(!"Cannot continue without sys_getgid()"); + } + return mlibc::sys_getgid(); +} + +gid_t getegid(void) { + if(!mlibc::sys_getegid) { + MLIBC_MISSING_SYSDEP(); + __ensure(!"Cannot continue without sys_getegid()"); + } + return mlibc::sys_getegid(); +} + +uid_t getuid(void) { + if(!mlibc::sys_getuid) { + MLIBC_MISSING_SYSDEP(); + __ensure(!"Cannot continue without sys_getuid()"); + } + return mlibc::sys_getuid(); +} + +uid_t geteuid(void) { + if(!mlibc::sys_geteuid) { + MLIBC_MISSING_SYSDEP(); + __ensure(!"Cannot continue without sys_geteuid()"); + } + return mlibc::sys_geteuid(); +} + +pid_t getpid(void) { + if(!mlibc::sys_getpid) { + MLIBC_MISSING_SYSDEP(); + __ensure(!"Cannot continue without sys_getpid()"); + } + return mlibc::sys_getpid(); +} + +pid_t getppid(void) { + if(!mlibc::sys_getppid) { + MLIBC_MISSING_SYSDEP(); + __ensure(!"Cannot continue without sys_getppid()"); + } + return mlibc::sys_getppid(); +} + +int access(const char *path, int mode) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_access, -1); + if(int e = mlibc::sys_access(path, mode); e) { + errno = e; + return -1; + } + return 0; +} + +char *getusershell(void) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +void setusershell(void) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +void endusershell(void) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +int isatty(int fd) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_isatty, 0); + if(int e = mlibc::sys_isatty(fd); e) { + errno = e; + return 0; + } + return 1; +} + +int chroot(const char *ptr) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_chroot, -1); + if(int e = mlibc::sys_chroot(ptr); e) { + errno = e; + return -1; + } + return 0; +} + +int daemon(int, int) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +char *ctermid(char *s) { + return s ? strcpy(s, "/dev/tty") : const_cast("/dev/tty"); +} + +int setresuid(uid_t ruid, uid_t euid, uid_t suid) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_setresuid, -1); + if(int e = mlibc::sys_setresuid(ruid, euid, suid); e) { + errno = e; + return -1; + } + return 0; +} + +int setresgid(gid_t rgid, gid_t egid, gid_t sgid) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_setresgid, -1); + if(int e = mlibc::sys_setresgid(rgid, egid, sgid); e) { + errno = e; + return -1; + } + return 0; +} + +int getdomainname(char *, size_t) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +int setdomainname(const char *, size_t) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} + +int getresuid(uid_t *ruid, uid_t *euid, uid_t *suid) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_getresuid, -1); + if(int e = mlibc::sys_getresuid(ruid, euid, suid); e) { + errno = e; + return -1; + } + return 0; +} + +int getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_getresgid, -1); + if(int e = mlibc::sys_getresgid(rgid, egid, sgid); e) { + errno = e; + return -1; + } + return 0; +} + +#if __MLIBC_CRYPT_OPTION +void encrypt(char[64], int) { + __ensure(!"Not implemented"); + __builtin_unreachable(); +} +#endif + +#if __MLIBC_BSD_OPTION +void *sbrk(intptr_t increment) { + if(increment) { + errno = ENOMEM; + return (void *)-1; + } + + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_brk, (void *)-1); + void *out; + if(int e = mlibc::sys_brk(&out); e) { + errno = e; + return (void *)-1; + } + return out; +} +#endif diff --git a/lib/mlibc/options/posix/generic/utime-stubs.cpp b/lib/mlibc/options/posix/generic/utime-stubs.cpp new file mode 100644 index 0000000..f78729f --- /dev/null +++ b/lib/mlibc/options/posix/generic/utime-stubs.cpp @@ -0,0 +1,31 @@ + +#include +#include +#include + +#include +#include + +int utime(const char *filename, const struct utimbuf *times) { + MLIBC_CHECK_OR_ENOSYS(mlibc::sys_utimensat, -1); + struct timespec time[2]; + if(times) { + time[0].tv_sec = times->actime; + time[0].tv_nsec = 0; + time[1].tv_sec = times->modtime; + time[1].tv_nsec = 0; + } else { + time[0].tv_sec = UTIME_NOW; + time[0].tv_nsec = UTIME_NOW; + time[1].tv_sec = UTIME_NOW; + time[1].tv_nsec = UTIME_NOW; + } + + if (int e = mlibc::sys_utimensat(AT_FDCWD, filename, time, 0); e) { + errno = e; + return -1; + } + + return 0; +} + diff --git a/lib/mlibc/options/posix/generic/wordexp-stubs.cpp b/lib/mlibc/options/posix/generic/wordexp-stubs.cpp new file mode 100644 index 0000000..8443527 --- /dev/null +++ b/lib/mlibc/options/posix/generic/wordexp-stubs.cpp @@ -0,0 +1,342 @@ +/* + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * code taken from OPNSense, with modifications + * + * Copyright (c) 2002 Tim J. Robbins. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define SHELL_PATH "/bin/sh" +#define SHELL_NAME "sh" + +static size_t we_read_fully(int fd, char *buffer, size_t len) { + size_t done = 0; + + do { + ssize_t nread = read(fd, buffer + done, len - done); + if(nread == -1 && errno == EINTR) + continue; + if(nread <= 0) + break; + done += nread; + } while (done != len); + + return done; +} + +static int we_askshell(const char *words, wordexp_t *we, int flags) { + int pdes[2]; /* pipe to child */ + char bbuf[9]; /* buffer for byte count */ + char wbuf[9]; /* buffer for word count */ + size_t nwords = 0; /* number of words from child */ + size_t nbytes = 0; /* number of bytes from child */ + size_t sofs = 0; /* offset into we->we_strings */ + size_t vofs = 0; /* offset into we->we_wordv */ + pid_t pid; /* PID of child */ + pid_t wpid; /* waitpid return value */ + int status; /* child exit status */ + int error; /* our return value */ + int serrno; /* errno to return */ + char *np, *p; /* handy pointers */ + char *nstrings; /* temporary for realloc() */ + char **new_wordv; /* temporary for realloc() */ + sigset_t newsigblock; + sigset_t oldsigblock; + const char *ifs = getenv("IFS"); + + serrno = errno; + + if(pipe2(pdes, O_CLOEXEC) < 0) + return WRDE_NOSPACE; + + (void)sigemptyset(&newsigblock); + (void)sigaddset(&newsigblock, SIGCHLD); + (void)sigprocmask(SIG_BLOCK, &newsigblock, &oldsigblock); + + if((pid = fork()) < 0) { + serrno = errno; + close(pdes[0]); + close(pdes[1]); + (void)sigprocmask(SIG_SETMASK, &oldsigblock, NULL); + errno = serrno; + return WRDE_NOSPACE; + } else if(pid == 0) { + /* + * We are the child; make /bin/sh expand `words'. + */ + (void)sigprocmask(SIG_SETMASK, &oldsigblock, NULL); + if((pdes[1] != STDOUT_FILENO ? dup2(pdes[1], STDOUT_FILENO) : fcntl(pdes[1], F_SETFD, 0)) < 0) + _exit(1); + + execl(SHELL_PATH, SHELL_NAME, flags & WRDE_UNDEF ? "-u" : "+u", + "-c", "IFS=$1;eval \"$2\";eval \"set -- $3\";IFS=;a=\"$*\";" + "printf '%08x' \"$#\" \"${#a}\";printf '%s\\0' \"$@\"", "", + ifs != NULL ? ifs : " \t\n", + flags & WRDE_SHOWERR ? "" : "exec 2>/dev/null", + words, + (char *)NULL); + _exit(1); + } + + /* + * We are the parent; read the output of the shell wordexp function, + * which is a 32-bit hexadecimal word count, a 32-bit hexadecimal + * byte count (not including terminating null bytes), followed by + * the expanded words separated by nulls. + */ + close(pdes[1]); + if(we_read_fully(pdes[0], wbuf, 8) != 8 || we_read_fully(pdes[0], bbuf, 8) != 8) { + error = flags & WRDE_UNDEF ? WRDE_BADVAL : WRDE_SYNTAX; + serrno = errno; + goto cleanup; + } + wbuf[8] = bbuf[8] = '\0'; + nwords = strtol(wbuf, NULL, 16); + nbytes = strtol(bbuf, NULL, 16) + nwords; + + /* + * Allocate or reallocate (when flags & WRDE_APPEND) the word vector + * and string storage buffers for the expanded words we're about to + * read from the child. + */ + sofs = we->we_nbytes; + vofs = we->we_wordc; + if((flags & (WRDE_DOOFFS|WRDE_APPEND)) == (WRDE_DOOFFS | WRDE_APPEND)) + vofs += we->we_offs; + we->we_wordc += nwords; + we->we_nbytes += nbytes; + + if((new_wordv = (char **) realloc(we->we_wordv, (we->we_wordc + 1 + (flags & WRDE_DOOFFS ? we->we_offs : 0)) * sizeof(char *))) == NULL) { + error = WRDE_NOSPACE; + goto cleanup; + } + + we->we_wordv = new_wordv; + + if((nstrings = (char *) realloc(we->we_strings, we->we_nbytes)) == NULL) { + error = WRDE_NOSPACE; + goto cleanup; + } + + for(size_t i = 0; i < vofs; i++) { + if(we->we_wordv[i] != NULL) + we->we_wordv[i] += nstrings - we->we_strings; + } + we->we_strings = nstrings; + + if(we_read_fully(pdes[0], we->we_strings + sofs, nbytes) != nbytes) { + error = flags & WRDE_UNDEF ? WRDE_BADVAL : WRDE_SYNTAX; + serrno = errno; + goto cleanup; + } + + error = 0; +cleanup: + close(pdes[0]); + + do { + wpid = waitpid(pid, &status, 0); + } while(wpid < 0 && errno == EINTR); + + (void)sigprocmask(SIG_SETMASK, &oldsigblock, NULL); + + if(error != 0) { + errno = serrno; + return error; + } + + if(wpid < 0 || !WIFEXITED(status) || WEXITSTATUS(status) != 0) + return flags & WRDE_UNDEF ? WRDE_BADVAL : WRDE_SYNTAX; + + /* + * Break the null-terminated expanded word strings out into + * the vector. + */ + if(vofs == 0 && flags & WRDE_DOOFFS) { + while (vofs < we->we_offs) + we->we_wordv[vofs++] = NULL; + } + + p = we->we_strings + sofs; + while (nwords-- != 0) { + we->we_wordv[vofs++] = p; + if((np = (char *) memchr(p, '\0', nbytes)) == NULL) + return WRDE_NOSPACE; + + nbytes -= np - p + 1; + p = np + 1; + } + + we->we_wordv[vofs] = NULL; + return 0; +} + +/* + * we_check -- + * Check that the string contains none of the following unquoted + * special characters: |&;<>(){} + * or command substitutions when WRDE_NOCMD is set in flags. + */ +static int we_check(const char *words, int flags) +{ + char c; + int dquote, level, quote, squote; + + quote = squote = dquote = 0; + while ((c = *words++) != '\0') { + switch (c) { + case '\\': { + if(squote == 0) + quote ^= 1; + continue; + } + case '\'': { + if(quote + dquote == 0) + squote ^= 1; + break; + } + case '"': { + if(quote + squote == 0) + dquote ^= 1; + break; + } + case '`': { + if(quote + squote == 0 && flags & WRDE_NOCMD) + return WRDE_CMDSUB; + while ((c = *words++) != '\0' && c != '`') + if(c == '\\' && (c = *words++) == '\0') + break; + if(c == '\0') + return WRDE_SYNTAX; + break; + } + case '|': + case '&': + case ';': + case '<': + case '>': + case '{': + case '}': + case '(': + case ')': + case '\n': { + if(quote + squote + dquote == 0) + return WRDE_BADCHAR; + break; + } + case '$': { + if((c = *words++) == '\0') + break; + else if(quote + squote == 0 && c == '(') { + if(flags & WRDE_NOCMD && *words != '(') + return WRDE_CMDSUB; + level = 1; + while ((c = *words++) != '\0') { + if(c == '\\') { + if((c = *words++) == '\0') + break; + } else if(c == '(') + level++; + else if(c == ')' && --level == 0) + break; + } + if(c == '\0' || level != 0) + return WRDE_SYNTAX; + } else if(quote + squote == 0 && c == '{') { + level = 1; + while ((c = *words++) != '\0') { + if(c == '\\') { + if((c = *words++) == '\0') + break; + } else if(c == '{') + level++; + else if(c == '}' && --level == 0) + break; + } + if(c == '\0' || level != 0) + return WRDE_SYNTAX; + } else + --words; + break; + } + default: { + break; + } + } + quote = 0; + } + + if(quote + squote + dquote != 0) + return WRDE_SYNTAX; + + return 0; +} + +int wordexp(const char * __restrict words, wordexp_t * __restrict we, int flags) { + int error; + + if(flags & WRDE_REUSE) + wordfree(we); + + if((flags & WRDE_APPEND) == 0) { + we->we_wordc = 0; + we->we_wordv = NULL; + we->we_strings = NULL; + we->we_nbytes = 0; + } + + if((error = we_check(words, flags)) != 0) { + wordfree(we); + return error; + } + + if((error = we_askshell(words, we, flags)) != 0) { + wordfree(we); + return error; + } + + return 0; +} + +void wordfree(wordexp_t *we) { + if (we == NULL) + return; + free(we->we_wordv); + free(we->we_strings); + we->we_wordv = NULL; + we->we_strings = NULL; + we->we_nbytes = 0; + we->we_wordc = 0; +} diff --git a/lib/mlibc/options/posix/include/arpa/inet.h b/lib/mlibc/options/posix/include/arpa/inet.h new file mode 100644 index 0000000..599987e --- /dev/null +++ b/lib/mlibc/options/posix/include/arpa/inet.h @@ -0,0 +1,46 @@ +#ifndef _ARPA_INET_H +#define _ARPA_INET_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +uint32_t htonl(uint32_t); +uint16_t htons(uint16_t); +uint32_t ntohl(uint32_t); +uint16_t ntohs(uint16_t); + +// ---------------------------------------------------------------------------- +// IPv4 address manipulation. +// ---------------------------------------------------------------------------- + +in_addr_t inet_addr(const char *); +char *inet_ntoa(struct in_addr); + +// GLIBC replacement for inet_addr(). +int inet_aton(const char *, struct in_addr *); + +// ---------------------------------------------------------------------------- +// Generic IP address manipulation. +// ---------------------------------------------------------------------------- +const char *inet_ntop(int, const void *__restrict, char *__restrict, + socklen_t) __attribute__((__nonnull__(3))); +int inet_pton(int, const char *__restrict, void *__restrict); + +struct in_addr inet_makeaddr(in_addr_t net, in_addr_t host); +in_addr_t inet_netof(struct in_addr in); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif // _ARPA_INET_H + diff --git a/lib/mlibc/options/posix/include/bits/posix/fd_set.h b/lib/mlibc/options/posix/include/bits/posix/fd_set.h new file mode 100644 index 0000000..554738e --- /dev/null +++ b/lib/mlibc/options/posix/include/bits/posix/fd_set.h @@ -0,0 +1,14 @@ +#ifndef MLIBC_FD_SET_H +#define MLIBC_FD_SET_H + +#include + +typedef struct { + union { + __mlibc_uint8 __mlibc_elems[128]; + // Some programs require the fds_bits field to be present + __mlibc_uint8 fds_bits[128]; + }; +} fd_set; + +#endif // MLIBC_FD_SET_H diff --git a/lib/mlibc/options/posix/include/bits/posix/id_t.h b/lib/mlibc/options/posix/include/bits/posix/id_t.h new file mode 100644 index 0000000..f222bc1 --- /dev/null +++ b/lib/mlibc/options/posix/include/bits/posix/id_t.h @@ -0,0 +1,6 @@ +#ifndef _MLIBC_ID_T_H +#define _MLIBC_ID_T_H + +typedef unsigned int id_t; + +#endif // _MLIBC_ID_T_H diff --git a/lib/mlibc/options/posix/include/bits/posix/in_addr_t.h b/lib/mlibc/options/posix/include/bits/posix/in_addr_t.h new file mode 100644 index 0000000..bac9ff2 --- /dev/null +++ b/lib/mlibc/options/posix/include/bits/posix/in_addr_t.h @@ -0,0 +1,8 @@ +#ifndef MLIBC_IN_ADDR_H +#define MLIBC_IN_ADDR_H + +#include + +typedef uint32_t in_addr_t; + +#endif // MLIBC_IN_ADDR_H diff --git a/lib/mlibc/options/posix/include/bits/posix/in_port_t.h b/lib/mlibc/options/posix/include/bits/posix/in_port_t.h new file mode 100644 index 0000000..0368159 --- /dev/null +++ b/lib/mlibc/options/posix/include/bits/posix/in_port_t.h @@ -0,0 +1,8 @@ +#ifndef MLIBC_IN_PORT_H +#define MLIBC_IN_PORT_H + +#include + +typedef uint16_t in_port_t; + +#endif // MLIBC_IN_PORT_H diff --git a/lib/mlibc/options/posix/include/bits/posix/iovec.h b/lib/mlibc/options/posix/include/bits/posix/iovec.h new file mode 100644 index 0000000..c004f1c --- /dev/null +++ b/lib/mlibc/options/posix/include/bits/posix/iovec.h @@ -0,0 +1,11 @@ +#ifndef MLIBC_IOVEC_H +#define MLIBC_IOVEC_H + +#include + +struct iovec { + void *iov_base; + __mlibc_size iov_len; +}; + +#endif // MLIBC_IOVEC_H diff --git a/lib/mlibc/options/posix/include/bits/posix/locale_t.h b/lib/mlibc/options/posix/include/bits/posix/locale_t.h new file mode 100644 index 0000000..c128d58 --- /dev/null +++ b/lib/mlibc/options/posix/include/bits/posix/locale_t.h @@ -0,0 +1,14 @@ +#ifndef _LOCALE_T_H +#define _LOCALE_T_H + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void *locale_t; + +#ifdef __cplusplus +} +#endif + +#endif // _LOCALE_T_H diff --git a/lib/mlibc/options/posix/include/bits/posix/posix_ctype.h b/lib/mlibc/options/posix/include/bits/posix/posix_ctype.h new file mode 100644 index 0000000..2b11057 --- /dev/null +++ b/lib/mlibc/options/posix/include/bits/posix/posix_ctype.h @@ -0,0 +1,36 @@ +#ifndef _POSIX_CTYPE_H +#define _POSIX_CTYPE_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#ifndef __MLIBC_ABI_ONLY + +int isalnum_l(int c, locale_t loc); +int isalpha_l(int c, locale_t loc); +int isblank_l(int c, locale_t loc); +int iscntrl_l(int c, locale_t loc); +int isdigit_l(int c, locale_t loc); +int isgraph_l(int c, locale_t loc); +int islower_l(int c, locale_t loc); +int isprint_l(int c, locale_t loc); +int ispunct_l(int c, locale_t loc); +int isspace_l(int c, locale_t loc); +int isupper_l(int c, locale_t loc); +int isxdigit_l(int c, locale_t loc); + +int isascii_l(int c, locale_t loc); + +int tolower_l(int c, locale_t loc); +int toupper_l(int c, locale_t loc); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif // _POSIX_CTYPE_H diff --git a/lib/mlibc/options/posix/include/bits/posix/posix_locale.h b/lib/mlibc/options/posix/include/bits/posix/posix_locale.h new file mode 100644 index 0000000..7554bc5 --- /dev/null +++ b/lib/mlibc/options/posix/include/bits/posix/posix_locale.h @@ -0,0 +1,23 @@ +#ifndef MLIBC_POSIX_LOCALE_H +#define MLIBC_POSIX_LOCALE_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +locale_t newlocale(int category_mask, const char *locale, locale_t base); +void freelocale(locale_t locobj); +locale_t uselocale(locale_t locobj); +locale_t duplocale(locale_t locobj); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif // MLIBC_POSIX_LOCALE_H diff --git a/lib/mlibc/options/posix/include/bits/posix/posix_signal.h b/lib/mlibc/options/posix/include/bits/posix/posix_signal.h new file mode 100644 index 0000000..20f030f --- /dev/null +++ b/lib/mlibc/options/posix/include/bits/posix/posix_signal.h @@ -0,0 +1,111 @@ + +#ifndef MLIBC_POSIX_SIGNAL_H +#define MLIBC_POSIX_SIGNAL_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include +#include +#include +#include +#include + +#define FPE_INTDIV 1 /* integer divide by zero */ +#define FPE_INTOVF 2 /* integer overflow */ +#define FPE_FLTDIV 3 /* floating point divide by zero */ +#define FPE_FLTOVF 4 /* floating point overflow */ +#define FPE_FLTUND 5 /* floating point underflow */ +#define FPE_FLTRES 6 /* floating point inexact result */ +#define FPE_FLTINV 7 /* floating point invalid operation */ +#define FPE_FLTSUB 8 /* subscript out of range */ + +#define TRAP_BRKPT 1 /* process breakpoint */ +#define TRAP_TRACE 2 /* process trace trap */ + +// Start Glibc stuff + +struct _libc_fpxreg { + unsigned short int significand[4]; + unsigned short int exponent; + unsigned short int __glibc_reserved1[3]; +}; + +struct _libc_xmmreg { + uint32_t element[4]; +}; + +struct _libc_fpstate { + uint16_t cwd; + int16_t swd; + uint16_t ftw; + uint16_t fop; + uint64_t rip; + uint64_t dp; + uint32_t mxcsr; + uint32_t mxcr_mask; + struct _libc_fpxreg _st[8]; + struct _libc_xmmreg _xmm[16]; + uint32_t __glibc_reserved1[24]; +}; + +typedef struct _libc_fpstate *fpregset_t; +// End Glibc stuff + +typedef unsigned long int greg_t; + +#define FPE_INTDIV 1 /* integer divide by zero */ +#define FPE_INTOVF 2 /* integer overflow */ +#define FPE_FLTDIV 3 /* floating point divide by zero */ +#define FPE_FLTOVF 4 /* floating point overflow */ +#define FPE_FLTUND 5 /* floating point underflow */ +#define FPE_FLTRES 6 /* floating point inexact result */ +#define FPE_FLTINV 7 /* floating point invalid operation */ +#define FPE_FLTSUB 8 /* subscript out of range */ + +#define TRAP_BRKPT 1 /* process breakpoint */ +#define TRAP_TRACE 2 /* process trace trap */ + +#ifndef __MLIBC_ABI_ONLY + +// functions to block / wait for signals +int sigsuspend(const sigset_t *); +int sigprocmask(int, const sigset_t *__restrict, sigset_t *__restrict); + +int pthread_sigmask(int, const sigset_t *__restrict, sigset_t *__restrict); +int pthread_kill(pthread_t, int); + +// functions to handle signals +int sigaction(int, const struct sigaction *__restrict, struct sigaction *__restrict); +int sigpending(sigset_t *); + +int siginterrupt(int sig, int flag); + +int sigaltstack(const stack_t *__restrict ss, stack_t *__restrict oss); + +// functions to raise signals +int kill(pid_t, int); +int killpg(int, int); + +int sigtimedwait(const sigset_t *__restrict set, siginfo_t *__restrict info, const struct timespec *__restrict timeout); +int sigwait(const sigset_t *__restrict set, int *__restrict sig); +int sigwaitinfo(const sigset_t *__restrict set, siginfo_t *__restrict info); + +// Glibc extension +#if __MLIBC_GLIBC_OPTION +int sigisemptyset(const sigset_t *set); +#endif // __MLIBC_GLIBC_OPTION + +int sigqueue(pid_t pid, int sig, const union sigval value); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif // MLIBC_POSIX_SIGNAL_H + diff --git a/lib/mlibc/options/posix/include/bits/posix/posix_stdio.h b/lib/mlibc/options/posix/include/bits/posix/posix_stdio.h new file mode 100644 index 0000000..4572a04 --- /dev/null +++ b/lib/mlibc/options/posix/include/bits/posix/posix_stdio.h @@ -0,0 +1,72 @@ + +#ifndef MLIBC_POSIX_STDIO_H +#define MLIBC_POSIX_STDIO_H + +#include +#include +#include + +// MISSING: var_list + +#ifdef __cplusplus +extern "C" { +#endif + +#define P_tmpdir "/tmp" + +#ifndef __MLIBC_ABI_ONLY + +typedef struct __mlibc_file_base FILE; + +int fileno(FILE *file); +FILE *fdopen(int fd, const char *mode); + +FILE *fmemopen(void *__restrict, size_t, const char *__restrict); +int pclose(FILE *); +FILE *popen(const char*, const char *); +FILE *open_memstream(char **, size_t *); + +int fseeko(FILE *stream, off_t offset, int whence); +off_t ftello(FILE *stream); + +int dprintf(int fd, const char *format, ...); +int vdprintf(int fd, const char *format, __builtin_va_list args); + +char *fgetln(FILE *, size_t *); + +#endif /* !__MLIBC_ABI_ONLY */ + +#define RENAME_EXCHANGE (1 << 1) + +// GNU extensions +typedef ssize_t (cookie_read_function_t)(void *, char *, size_t); +typedef ssize_t (cookie_write_function_t)(void *, const char *, size_t); +typedef int (cookie_seek_function_t)(void *, off_t *, int); +typedef int (cookie_close_function_t)(void *); + +typedef struct _IO_cookie_io_functions_t { + cookie_read_function_t *read; + cookie_write_function_t *write; + cookie_seek_function_t *seek; + cookie_close_function_t *close; +} cookie_io_functions_t; + +#ifndef __MLIBC_ABI_ONLY + +#if defined(_GNU_SOURCE) + +FILE *fopencookie(void *__restrict cookie, const char *__restrict mode, cookie_io_functions_t io_funcs); + +#endif // defined(_GNU_SOURCE) + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +// MISSING: various functions and macros + +#endif /* MLIBC_POSIX_STDIO_H */ + + diff --git a/lib/mlibc/options/posix/include/bits/posix/posix_stdlib.h b/lib/mlibc/options/posix/include/bits/posix/posix_stdlib.h new file mode 100644 index 0000000..5248fca --- /dev/null +++ b/lib/mlibc/options/posix/include/bits/posix/posix_stdlib.h @@ -0,0 +1,73 @@ + +#ifndef MLIBC_POSIX_STDLIB_H +#define MLIBC_POSIX_STDLIB_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +long random(void); +double drand48(void); +void srand48(long int); +char *initstate(unsigned int, char *, size_t); +char *setstate(char *); +void srandom(unsigned int); + +// ---------------------------------------------------------------------------- +// Environment. +// ---------------------------------------------------------------------------- + +int putenv(char *); +int setenv(const char *, const char *, int); +int unsetenv(const char *); + +// ---------------------------------------------------------------------------- +// Path handling. +// ---------------------------------------------------------------------------- + +int mkstemp(char *); +int mkstemps(char *pattern, int suffixlen); +int mkostemp(char *, int flags); +int mkostemps(char *pattern, int suffixlen, int flags); +char *mkdtemp(char *path); + +char *realpath(const char *__restrict, char *__restrict); + +// ---------------------------------------------------------------------------- +// Pseudoterminals +// ---------------------------------------------------------------------------- + +int posix_openpt(int flags); +int grantpt(int fd); +int unlockpt(int fd); +char *ptsname(int fd); +int ptsname_r(int fd, char *buf, size_t len); + +double strtod_l(const char *__restrict__ nptr, char ** __restrict__ endptr, locale_t loc); +long double strtold_l(const char *__restrict__ nptr, char ** __restrict__ endptr, locale_t loc); +float strtof_l(const char *__restrict string, char **__restrict end, locale_t loc); + +int getloadavg(double *, int); + +// GNU extension +char *secure_getenv(const char *); +char *canonicalize_file_name(const char *); + +// BSD extension +void *reallocarray(void *, size_t, size_t); + +int clearenv(void); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif // MLIBC_POSIX_STDLIB_H + diff --git a/lib/mlibc/options/posix/include/bits/posix/posix_string.h b/lib/mlibc/options/posix/include/bits/posix/posix_string.h new file mode 100644 index 0000000..1f61942 --- /dev/null +++ b/lib/mlibc/options/posix/include/bits/posix/posix_string.h @@ -0,0 +1,57 @@ + +#ifndef MLIBC_POSIX_STRING_H +#define MLIBC_POSIX_STRING_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +char *strdup(const char *string); +char *strndup(const char *, size_t); +size_t strnlen(const char *, size_t); +char *strtok_r(char *__restrict, const char *__restrict, char **__restrict); +char *strsep(char **stringp, const char *delim); +char *strsignal(int sig); +char *stpcpy(char *__restrict, const char *__restrict); +char *stpncpy(char *__restrict, const char *__restrict, size_t n); +void *memccpy(void *__restrict dest, const void *__restrict src, int c, size_t n); + +int strcoll_l(const char *s1, const char *s2, locale_t locale); + +// GNU extensions. +#if defined(_GNU_SOURCE) +char *strcasestr(const char *, const char *); +#define strdupa(x) ({ \ + const char *str = (x); \ + size_t len = strlen(str) + 1; \ + char *buf = alloca(len); \ + (char *) memcpy(buf, str, len); \ +}) +#define strndupa(x, y) ({ \ + const char *str = (x); \ + size_t len = strnlen(str, (y)) + 1; \ + char *buf = alloca(len); \ + buf[len - 1] = '\0'; \ + (char *) memcpy(buf, str, len - 1); \ +}) +void *memrchr(const void *, int, size_t); +#endif /* defined(_GNU_SOURCE) */ + +// BSD extensions +size_t strlcpy(char *d, const char *s, size_t n); +size_t strlcat(char *d, const char *s, size_t n); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif // MLIBC_POSIX_STRING_H + diff --git a/lib/mlibc/options/posix/include/bits/posix/posix_time.h b/lib/mlibc/options/posix/include/bits/posix/posix_time.h new file mode 100644 index 0000000..d3e8e1d --- /dev/null +++ b/lib/mlibc/options/posix/include/bits/posix/posix_time.h @@ -0,0 +1,25 @@ +#ifndef MLIBC_POSIX_TIME_H +#define MLIBC_POSIX_TIME_H + +#include + +#define TIMER_ABSTIME 1 + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +int utimes(const char *, const struct timeval[2]); + +// Not standardized, Linux and BSDs have it +int futimes(int, const struct timeval[2]); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif // MLIBC_POSIX_TIME_H diff --git a/lib/mlibc/options/posix/include/bits/posix/posix_wctype.h b/lib/mlibc/options/posix/include/bits/posix/posix_wctype.h new file mode 100644 index 0000000..4d2887c --- /dev/null +++ b/lib/mlibc/options/posix/include/bits/posix/posix_wctype.h @@ -0,0 +1,44 @@ +#ifndef _POSIX_WCTYPE_H +#define _POSIX_WCTYPE_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +typedef unsigned long wctype_t; +typedef unsigned long wctrans_t; + +int iswalnum_l(wint_t, locale_t); +int iswblank_l(wint_t, locale_t); +int iswcntrl_l(wint_t, locale_t); +int iswdigit_l(wint_t, locale_t); +int iswgraph_l(wint_t, locale_t); +int iswlower_l(wint_t, locale_t); +int iswprint_l(wint_t, locale_t); +int iswpunct_l(wint_t, locale_t); +int iswspace_l(wint_t, locale_t); +int iswupper_l(wint_t, locale_t); +int iswxdigit_l(wint_t, locale_t); +int iswalpha_l(wint_t, locale_t); + +wctype_t wctype_l(const char *); +int iswctype_l(wint_t, wctype_t); + +wint_t towlower_l(wint_t, locale_t); +wint_t towupper_l(wint_t, locale_t); + +wctrans_t wctrans_l(const char *, locale_t); +wint_t towctrans_l(wint_t, wctrans_t, locale_t); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif // _POSIX_WCTYPE_H diff --git a/lib/mlibc/options/posix/include/bits/posix/pthread_t.h b/lib/mlibc/options/posix/include/bits/posix/pthread_t.h new file mode 100644 index 0000000..1310c40 --- /dev/null +++ b/lib/mlibc/options/posix/include/bits/posix/pthread_t.h @@ -0,0 +1,8 @@ +#ifndef _MLIBC_BITS_PTHREAD_T_HPP +#define _MLIBC_BITS_PTHREAD_T_HPP + +#include + +typedef struct __mlibc_thread_data *pthread_t; + +#endif // _MLIBC_BITS_PTHREAD_T_HPP diff --git a/lib/mlibc/options/posix/include/bits/posix/stat.h b/lib/mlibc/options/posix/include/bits/posix/stat.h new file mode 100644 index 0000000..4dd081d --- /dev/null +++ b/lib/mlibc/options/posix/include/bits/posix/stat.h @@ -0,0 +1,24 @@ +#ifndef MLIBC_STAT_H +#define MLIBC_STAT_H + +#include + +// Used by utimensat and friends +#define UTIME_NOW ((1l << 30) - 1l) +#define UTIME_OMIT ((1l << 30) - 2l) + +#define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK) +#define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR) +#define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO) +#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) +#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) +#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK) +#define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK) + +// POSIX compatibility macros +#define st_atime st_atim.tv_sec +#define st_mtime st_mtim.tv_sec +#define st_ctime st_ctim.tv_sec + +#endif // MLIBC_STAT_H + diff --git a/lib/mlibc/options/posix/include/bits/posix/timer_t.h b/lib/mlibc/options/posix/include/bits/posix/timer_t.h new file mode 100644 index 0000000..b230501 --- /dev/null +++ b/lib/mlibc/options/posix/include/bits/posix/timer_t.h @@ -0,0 +1,6 @@ +#ifndef _MLIBC_TIMER_T_H +#define _MLIBC_TIMER_T_H + +typedef void * timer_t; + +#endif // _MLIBC_TIMER_T_H diff --git a/lib/mlibc/options/posix/include/bits/posix/timeval.h b/lib/mlibc/options/posix/include/bits/posix/timeval.h new file mode 100644 index 0000000..445ee7f --- /dev/null +++ b/lib/mlibc/options/posix/include/bits/posix/timeval.h @@ -0,0 +1,12 @@ +#ifndef MLIBC_TIMEVAL_H +#define MLIBC_TIMEVAL_H + +#include +#include + +struct timeval { + time_t tv_sec; + suseconds_t tv_usec; +}; + +#endif // MLIBC_TIMEVAL_H diff --git a/lib/mlibc/options/posix/include/byteswap.h b/lib/mlibc/options/posix/include/byteswap.h new file mode 100644 index 0000000..74b9fe2 --- /dev/null +++ b/lib/mlibc/options/posix/include/byteswap.h @@ -0,0 +1,23 @@ + +#ifndef _BYTESWAP_H +#define _BYTESWAP_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define bswap_16(x) __builtin_bswap16(x) +#define bswap_32(x) __builtin_bswap32(x) +#define bswap_64(x) __builtin_bswap64(x) + +// Some programs like eudev call these functions instead +#define __bswap_16(x) __builtin_bswap16(x) +#define __bswap_32(x) __builtin_bswap32(x) +#define __bswap_64(x) __builtin_bswap64(x) + +#ifdef __cplusplus +} +#endif + +#endif // _BYTESWAP_H + diff --git a/lib/mlibc/options/posix/include/dirent.h b/lib/mlibc/options/posix/include/dirent.h new file mode 100644 index 0000000..b50566d --- /dev/null +++ b/lib/mlibc/options/posix/include/dirent.h @@ -0,0 +1,76 @@ + +#ifndef _DIRENT_H +#define _DIRENT_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#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 __MLIBC_DIRENT_BODY ino_t d_ino; \ + off_t d_off; \ + unsigned short d_reclen; \ + unsigned char d_type; \ + char d_name[1024]; + +struct dirent { + __MLIBC_DIRENT_BODY +}; + +struct dirent64 { + __MLIBC_DIRENT_BODY +}; + +#define d_fileno d_ino + +#undef __MLIBC_DIRENT_BODY + +#define IFTODT(mode) (((mode) & 0170000) >> 12) + +struct __mlibc_dir_struct { + int __handle; + __mlibc_size __ent_next; + __mlibc_size __ent_limit; + char __ent_buffer[2048]; + struct dirent __current; +}; + +typedef struct __mlibc_dir_struct DIR; + +#ifndef __MLIBC_ABI_ONLY + +int alphasort(const struct dirent **, const struct dirent **); +int closedir(DIR *); +int dirfd(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 scandir(const char *, struct dirent ***, int (*)(const struct dirent *), + int (*)(const struct dirent **, const struct dirent **)); +void seekdir(DIR *, long); +long telldir(DIR *); +int versionsort(const struct dirent **, const struct dirent **); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif // _DIRENT_H + diff --git a/lib/mlibc/options/posix/include/dlfcn.h b/lib/mlibc/options/posix/include/dlfcn.h new file mode 100644 index 0000000..3bb8a02 --- /dev/null +++ b/lib/mlibc/options/posix/include/dlfcn.h @@ -0,0 +1,52 @@ + +#ifndef _DLFCN_H +#define _DLFCN_H + +#define RTLD_LOCAL 0 +#define RTLD_NOW 1 +#define RTLD_GLOBAL 2 +#define RTLD_NOLOAD 4 +#define RTLD_NODELETE 8 +#define RTLD_DEEPBIND 16 +#define RTLD_LAZY 32 + +#define RTLD_NEXT ((void *)-1) +#define RTLD_DEFAULT ((void *)0) + +#define RTLD_DI_LINKMAP 2 + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +int dlclose(void *); +char *dlerror(void); +void *dlopen(const char *, int); +void *dlsym(void *__restrict, const char *__restrict); +void *dlvsym(void *__restrict, const char *__restrict, const char *__restrict); + +#endif /* !__MLIBC_ABI_ONLY */ + +//gnu extension +typedef struct { + const char *dli_fname; + void *dli_fbase; + const char *dli_sname; + void *dli_saddr; +} Dl_info; + +#ifndef __MLIBC_ABI_ONLY + +int dladdr(const void *, Dl_info *); +int dlinfo(void *, int, void *); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif // _DLFCN_H + diff --git a/lib/mlibc/options/posix/include/fcntl.h b/lib/mlibc/options/posix/include/fcntl.h new file mode 100644 index 0000000..9983219 --- /dev/null +++ b/lib/mlibc/options/posix/include/fcntl.h @@ -0,0 +1,76 @@ + +#ifndef _FCNTL_H +#define _FCNTL_H + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define O_NDELAY O_NONBLOCK + +struct flock { + short l_type; + short l_whence; + off_t l_start; + off_t l_len; + pid_t l_pid; +}; + +#ifndef __MLIBC_ABI_ONLY + +int creat(const char *, mode_t); +int fallocate(int fd, int mode, off_t offset, off_t len); +int fcntl(int fd, int command, ...); +int open(const char *path, int flags, ...); +int openat(int, const char *, int, ...); +int posix_fadvise(int, off_t, off_t, int); +int posix_fallocate(int, off_t, off_t); + +#endif /* !__MLIBC_ABI_ONLY */ + +// This is a linux extension + +struct file_handle { + unsigned int handle_bytes; + int handle_type; + unsigned char f_handle[0]; +}; + +#ifndef __MLIBC_ABI_ONLY + +int name_to_handle_at(int, const char *, struct file_handle *, int *, int); +int open_by_handle_at(int, struct file_handle *, int); + +ssize_t splice(int fd_in, off_t *off_in, int fd_out, off_t *off_out, size_t len, unsigned int flags); +ssize_t vmsplice(int fd, const struct iovec *iov, size_t nr_segs, unsigned int flags); + +#endif /* !__MLIBC_ABI_ONLY */ + +#define SPLICE_F_MOVE 1 +#define SPLICE_F_NONBLOCK 2 +#define SPLICE_F_MORE 4 +#define SPLICE_F_GIFT 8 + +#define AT_NO_AUTOMOUNT 0x800 + +#define F_SETPIPE_SZ 1031 +#define F_GETPIPE_SZ 1032 + +#define FALLOC_FL_KEEP_SIZE 1 +#define FALLOC_FL_PUNCH_HOLE 2 + +#ifdef __cplusplus +} +#endif + +#endif // _FCNTL_H + diff --git a/lib/mlibc/options/posix/include/fnmatch.h b/lib/mlibc/options/posix/include/fnmatch.h new file mode 100644 index 0000000..3eccbd0 --- /dev/null +++ b/lib/mlibc/options/posix/include/fnmatch.h @@ -0,0 +1,33 @@ + +#ifndef _FNMATCH_H +#define _FNMATCH_H + +#ifdef __cplusplus +extern "C" { +#endif + +// POSIX-defined fnmatch() flags. +#define FNM_PATHNAME 0x1 +#define FNM_NOESCAPE 0x2 +#define FNM_PERIOD 0x4 + +// GNU extensions for fnmatch() flags. +#define FNM_LEADING_DIR 0x8 +#define FNM_CASEFOLD 0x10 +#define FNM_EXTMATCH 0x20 + +// fnmatch() return values. +#define FNM_NOMATCH 1 + +#ifndef __MLIBC_ABI_ONLY + +int fnmatch(const char *, const char *, int); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif // _FNMATCH_H + diff --git a/lib/mlibc/options/posix/include/ftw.h b/lib/mlibc/options/posix/include/ftw.h new file mode 100644 index 0000000..bde283d --- /dev/null +++ b/lib/mlibc/options/posix/include/ftw.h @@ -0,0 +1,43 @@ + +#ifndef _FTW_H +#define _FTW_H + +#include + +#define FTW_F 1 +#define FTW_D 2 +#define FTW_DNR 3 +#define FTW_DP 4 +#define FTW_NS 5 +#define FTW_SL 6 +#define FTW_SLN 7 + +#define FTW_PHYS 1 +#define FTW_MOUNT 2 +#define FTW_DEPTH 4 +#define FTW_CHDIR 8 + +#define FTW_CONTINUE 0 + +#ifdef __cplusplus +extern "C" { +#endif + +struct FTW { + int base; + int level; +}; + +#ifndef __MLIBC_ABI_ONLY + +int ftw(const char *, int (*)(const char *, const struct stat *, int), int); +int nftw(const char *, int (*)(const char *, const struct stat *, int, struct FTW *), int, int); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif // _FTW_H + diff --git a/lib/mlibc/options/posix/include/glob.h b/lib/mlibc/options/posix/include/glob.h new file mode 100644 index 0000000..2bf9e48 --- /dev/null +++ b/lib/mlibc/options/posix/include/glob.h @@ -0,0 +1,58 @@ + +#ifndef _GLOB_H +#define _GLOB_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#define GLOB_APPEND 0x01 +#define GLOB_DOOFFS 0x02 +#define GLOB_ERR 0x04 +#define GLOB_MARK 0x08 +#define GLOB_NOCHECK 0x10 +#define GLOB_NOESCAPE 0x20 +#define GLOB_NOSORT 0x40 +#define GLOB_PERIOD 0x80 +#define GLOB_TILDE 0x100 +#define GLOB_TILDE_CHECK 0x200 +#define GLOB_BRACE 0x400 +#define GLOB_NOMAGIC 0x800 +#define GLOB_ALTDIRFUNC 0x1000 +#define GLOB_ONLYDIR 0x2000 +#define GLOB_MAGCHAR 0x4000 + +#define GLOB_ABORTED 1 +#define GLOB_NOMATCH 2 +#define GLOB_NOSPACE 3 +#define GLOB_NOSYS 4 + +struct stat; +typedef struct glob_t { + size_t gl_pathc; + char **gl_pathv; + size_t gl_offs; + int gl_flags; + void (*gl_closedir) (void *); + struct dirent *(*gl_readdir) (void *); + void *(*gl_opendir) (const char *); + int (*gl_lstat) (const char *__restrict, struct stat *__restrict); + int (*gl_stat) (const char *__restrict, struct stat *__restrict); +} glob_t; + +#ifndef __MLIBC_ABI_ONLY + +int glob(const char *__restirct, int, int(*)(const char *, int), struct glob_t *__restrict); +void globfree(struct glob_t *); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif // _GLOB_H + + diff --git a/lib/mlibc/options/posix/include/grp.h b/lib/mlibc/options/posix/include/grp.h new file mode 100644 index 0000000..a50396e --- /dev/null +++ b/lib/mlibc/options/posix/include/grp.h @@ -0,0 +1,43 @@ +#ifndef _GRP_H +#define _GRP_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct group { + char *gr_name; + char *gr_passwd; + gid_t gr_gid; + char **gr_mem; +}; + +#ifndef __MLIBC_ABI_ONLY + +void endgrent(void); +struct group *getgrent(void); +struct group *getgrgid(gid_t); +int getgrgid_r(gid_t, struct group *, char *, size_t, struct group **); +struct group *getgrnam(const char *); +int getgrnam_r(const char *, struct group *, char *, size_t, struct group **); +void setgrent(void); +int putgrent(const struct group *, FILE *); +struct group *fgetgrent(FILE *); + +int setgroups(size_t size, const gid_t *list); +int initgroups(const char *user, gid_t group); + +// Non standard extension +int getgrouplist(const char *, gid_t, gid_t *, int *); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif // _GRP_H diff --git a/lib/mlibc/options/posix/include/langinfo.h b/lib/mlibc/options/posix/include/langinfo.h new file mode 100644 index 0000000..5436a54 --- /dev/null +++ b/lib/mlibc/options/posix/include/langinfo.h @@ -0,0 +1,24 @@ + +#ifndef _LANGINFO_H +#define _LANGINFO_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +#ifndef __MLIBC_ABI_ONLY + +char *nl_langinfo(nl_item); +char *nl_langinfo_l(nl_item, locale_t); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif // _LANGINFO_H + diff --git a/lib/mlibc/options/posix/include/libgen.h b/lib/mlibc/options/posix/include/libgen.h new file mode 100644 index 0000000..fa53fc5 --- /dev/null +++ b/lib/mlibc/options/posix/include/libgen.h @@ -0,0 +1,28 @@ + +#ifndef _LIBGEN_H +#define _LIBGEN_H + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(basename) && defined(_GNU_SOURCE) +/* see: ./options/ansi/include/string.h, search for __mlibc_gnu_basename */ +# undef basename +#endif + +#ifndef __MLIBC_ABI_ONLY + +char *basename(char *); +#define basename basename +char *dirname(char *); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif // _LIBGEN_H + + diff --git a/lib/mlibc/options/posix/include/mlibc/lookup.hpp b/lib/mlibc/options/posix/include/mlibc/lookup.hpp new file mode 100644 index 0000000..71f84e7 --- /dev/null +++ b/lib/mlibc/options/posix/include/mlibc/lookup.hpp @@ -0,0 +1,58 @@ +#ifndef _MLIBC_LOOKUP +#define _MLIBC_LOOKUP + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace mlibc { + +struct dns_addr_buf { + dns_addr_buf() + : name(getAllocator()) {} + frg::string name; + int family; + uint8_t addr[16]; +}; + +struct lookup_result { + lookup_result() + : buf(getAllocator()), aliases(getAllocator()) {} + frg::vector buf; + frg::vector, MemoryAllocator> aliases; +}; + +struct dns_header { + uint16_t identification; + uint16_t flags; + uint16_t no_q; + uint16_t no_ans; + uint16_t no_auths; + uint16_t no_additional; +}; + +struct ai_buf { + struct addrinfo ai; + union sa { + struct sockaddr_in sin; + struct sockaddr_in6 sin6; + } sa; +}; + +int lookup_name_dns(struct lookup_result &buf, const char *name, + frg::string &canon_name); +int lookup_addr_dns(frg::span name, frg::array &addr, int family); +int lookup_name_hosts(struct lookup_result &buf, const char *name, + frg::string &canon_name); +int lookup_addr_hosts(frg::span name, frg::array &addr, int family); +int lookup_name_null(struct lookup_result &buf, int flags, int family); +int lookup_name_ip(struct lookup_result &buf, const char *name, int family); + +} // namespace mlibc + +#endif // _MLIBC_LOOKUP diff --git a/lib/mlibc/options/posix/include/mlibc/posix-file-io.hpp b/lib/mlibc/options/posix/include/mlibc/posix-file-io.hpp new file mode 100644 index 0000000..ac316ac --- /dev/null +++ b/lib/mlibc/options/posix/include/mlibc/posix-file-io.hpp @@ -0,0 +1,102 @@ +#ifndef MLIBC_POSIX_FILE_IO_HPP +#define MLIBC_POSIX_FILE_IO_HPP + +#include +#include +#include +#include + +namespace mlibc { + +struct mem_file : abstract_file { + mem_file(int flags, void (*do_dispose)(abstract_file *) = nullptr) : abstract_file{do_dispose}, _flags{flags} { }; + + int reopen(const char *path, const char *mode) override; +protected: + int determine_type(stream_type *type) override; + int determine_bufmode(buffer_mode *mode) override; + + virtual frg::span _buffer() = 0; + virtual size_t _buffer_size() const = 0; + + off_t _pos = 0; + int _flags = 0; + // maintains the size of buffer contents as required by POSIX + off_t _max_size = 0; +}; + +struct memstream_mem_file final : public mem_file { + memstream_mem_file(char **ptr, size_t *sizeloc, int flags, void (*do_dispose)(abstract_file *) = nullptr); + + int close() override; + + int io_read(char *buffer, size_t max_size, size_t *actual_size) override; + int io_write(const char *buffer, size_t max_size, size_t *actual_size) override; + int io_seek(off_t offset, int whence, off_t *new_offset) override; + + frg::span _buffer() override { + return {_buf.data(), _buffer_size()}; + } + + size_t _buffer_size() const override { + return _buf.size(); + } + +private: + void _update_ptrs(); + + // Where to write back buffer and size on flush and close. + char **_bufloc; + size_t *_sizeloc; + + frg::vector _buf = {getAllocator()}; +}; + +struct fmemopen_mem_file final : public mem_file { + fmemopen_mem_file(void *in_buf, size_t size, int flags, void (*do_dispose)(abstract_file *) = nullptr); + + int close() override; + + int io_read(char *buffer, size_t max_size, size_t *actual_size) override; + int io_write(const char *buffer, size_t max_size, size_t *actual_size) override; + int io_seek(off_t offset, int whence, off_t *new_offset) override; + + frg::span _buffer() override { + return {reinterpret_cast(_inBuffer), _buffer_size()}; + } + + size_t _buffer_size() const override { + return _inBufferSize; + } + +private: + void *_inBuffer; + size_t _inBufferSize; + + bool _needsDeallocation = false; +}; + +struct cookie_file : abstract_file { + cookie_file(void *cookie, int flags, cookie_io_functions_t funcs, void (*do_dispose)(abstract_file *) = nullptr) + : abstract_file{do_dispose}, _cookie{cookie}, _flags{flags}, _funcs{funcs} { } + + int close() override; + int reopen(const char *path, const char *mode) override; +protected: + int determine_type(stream_type *type) override; + int determine_bufmode(buffer_mode *mode) override; + + int io_read(char *buffer, size_t max_size, size_t *actual_size) override; + int io_write(const char *buffer, size_t max_size, size_t *actual_size) override; + int io_seek(off_t offset, int whence, off_t *new_offset) override; + +private: + void *_cookie; + + int _flags; + cookie_io_functions_t _funcs; +}; + +} // namespace mlibc + +#endif // MLIBC_POSIX_FILE_IO_HPP diff --git a/lib/mlibc/options/posix/include/mlibc/posix-sysdeps.hpp b/lib/mlibc/options/posix/include/mlibc/posix-sysdeps.hpp new file mode 100644 index 0000000..ba77b32 --- /dev/null +++ b/lib/mlibc/options/posix/include/mlibc/posix-sysdeps.hpp @@ -0,0 +1,240 @@ +#ifndef MLIBC_POSIX_SYSDEPS +#define MLIBC_POSIX_SYSDEPS + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace [[gnu::visibility("hidden")]] mlibc { + +void sys_libc_log(const char *message); +[[noreturn]] void sys_libc_panic(); + +[[noreturn]] void sys_exit(int status); +[[noreturn, gnu::weak]] void sys_thread_exit(); +int sys_clock_get(int clock, time_t *secs, long *nanos); + +int sys_open(const char *pathname, int flags, mode_t mode, int *fd); +[[gnu::weak]] int sys_flock(int fd, int options); + +[[gnu::weak]] int sys_open_dir(const char *path, int *handle); +[[gnu::weak]] int sys_read_entries(int handle, void *buffer, size_t max_size, + size_t *bytes_read); + +int sys_read(int fd, void *buf, size_t count, ssize_t *bytes_read); +[[gnu::weak]] int sys_readv(int fd, const struct iovec *iovs, int iovc, ssize_t *bytes_read); + +int sys_write(int fd, const void *buf, size_t count, ssize_t *bytes_written); +[[gnu::weak]] int sys_pread(int fd, void *buf, size_t n, off_t off, ssize_t *bytes_read); +[[gnu::weak]] int sys_pwrite(int fd, const void *buf, size_t n, off_t off, ssize_t *bytes_read); + +int sys_seek(int fd, off_t offset, int whence, off_t *new_offset); +int sys_close(int fd); + +[[gnu::weak]] int sys_access(const char *path, int mode); +[[gnu::weak]] int sys_faccessat(int dirfd, const char *pathname, int mode, int flags); +[[gnu::weak]] int sys_dup(int fd, int flags, int *newfd); +[[gnu::weak]] int sys_dup2(int fd, int flags, int newfd); +// In contrast to the isatty() library function, the sysdep function uses return value +// zero (and not one) to indicate that the file is a terminal. +[[gnu::weak]] int sys_isatty(int fd); +[[gnu::weak]] int sys_stat(fsfd_target fsfdt, int fd, const char *path, int flags, + struct stat *statbuf); +[[gnu::weak]] int sys_statvfs(const char *path, struct statvfs *out); +[[gnu::weak]] int sys_fstatvfs(int fd, struct statvfs *out); +[[gnu::weak]] int sys_readlink(const char *path, void *buffer, size_t max_size, ssize_t *length); +[[gnu::weak]] int sys_rmdir(const char *path); +[[gnu::weak]] int sys_ftruncate(int fd, size_t size); +[[gnu::weak]] int sys_fallocate(int fd, off_t offset, size_t size); +[[gnu::weak]] int sys_unlinkat(int fd, const char *path, int flags); +[[gnu::weak]] int sys_openat(int dirfd, const char *path, int flags, mode_t mode, int *fd); +[[gnu::weak]] int sys_socket(int family, int type, int protocol, int *fd); +[[gnu::weak]] int sys_msg_send(int fd, const struct msghdr *hdr, int flags, ssize_t *length); +[[gnu::weak]] ssize_t sys_sendto(int fd, const void *buffer, size_t size, int flags, const struct sockaddr *sock_addr, socklen_t addr_length, ssize_t *length); +[[gnu::weak]] int sys_msg_recv(int fd, struct msghdr *hdr, int flags, ssize_t *length); +[[gnu::weak]] ssize_t sys_recvfrom(int fd, void *buffer, size_t size, int flags, struct sockaddr *sock_addr, socklen_t *addr_length, ssize_t *length); +[[gnu::weak]] int sys_listen(int fd, int backlog); +[[gnu::weak]] gid_t sys_getgid(); +[[gnu::weak]] gid_t sys_getegid(); +[[gnu::weak]] uid_t sys_getuid(); +[[gnu::weak]] uid_t sys_geteuid(); +[[gnu::weak]] pid_t sys_getpid(); +[[gnu::weak]] pid_t sys_gettid(); +[[gnu::weak]] pid_t sys_getppid(); +[[gnu::weak]] int sys_getpgid(pid_t pid, pid_t *pgid); +[[gnu::weak]] int sys_getsid(pid_t pid, pid_t *sid); +[[gnu::weak]] int sys_setpgid(pid_t pid, pid_t pgid); +[[gnu::weak]] int sys_setuid(uid_t uid); +[[gnu::weak]] int sys_seteuid(uid_t euid); +[[gnu::weak]] int sys_setgid(gid_t gid); +[[gnu::weak]] int sys_setegid(gid_t egid); +[[gnu::weak]] int sys_getgroups(size_t size, const gid_t *list, int *ret); +[[gnu::weak]] void sys_yield(); +[[gnu::weak]] int sys_sleep(time_t *secs, long *nanos); +[[gnu::weak]] int sys_fork(pid_t *child); +[[gnu::weak]] int sys_execve(const char *path, char *const argv[], char *const envp[]); +[[gnu::weak]] int sys_pselect(int num_fds, fd_set *read_set, fd_set *write_set, + fd_set *except_set, const struct timespec *timeout, const sigset_t *sigmask, int *num_events); +[[gnu::weak]] int sys_getrusage(int scope, struct rusage *usage); +[[gnu::weak]] int sys_getrlimit(int resource, struct rlimit *limit); +[[gnu::weak]] int sys_setrlimit(int resource, const struct rlimit *limit); +[[gnu::weak]] int sys_getpriority(int which, id_t who, int *value); +[[gnu::weak]] int sys_setpriority(int which, id_t who, int prio); +[[gnu::weak]] int sys_getschedparam(void *tcb, int *policy, struct sched_param *param); +[[gnu::weak]] int sys_setschedparam(void *tcb, int policy, const struct sched_param *param); +[[gnu::weak]] int sys_get_max_priority(int policy, int *out); +[[gnu::weak]] int sys_get_min_priority(int policy, int *out); +[[gnu::weak]] int sys_getcwd(char *buffer, size_t size); +[[gnu::weak]] int sys_chdir(const char *path); +[[gnu::weak]] int sys_fchdir(int fd); +[[gnu::weak]] int sys_chroot(const char *path); +[[gnu::weak]] int sys_mkdir(const char *path, mode_t mode); +[[gnu::weak]] int sys_mkdirat(int dirfd, const char *path, mode_t mode); +[[gnu::weak]] int sys_link(const char *old_path, const char *new_path); +[[gnu::weak]] int sys_linkat(int olddirfd, const char *old_path, int newdirfd, const char *new_path, int flags); +[[gnu::weak]] int sys_symlink(const char *target_path, const char *link_path); +[[gnu::weak]] int sys_symlinkat(const char *target_path, int dirfd, const char *link_path); +[[gnu::weak]] int sys_rename(const char *path, const char *new_path); +[[gnu::weak]] int sys_renameat(int olddirfd, const char *old_path, int newdirfd, const char *new_path); +[[gnu::weak]] int sys_fcntl(int fd, int request, va_list args, int *result); +[[gnu::weak]] int sys_ttyname(int fd, char *buf, size_t size); +[[gnu::weak]] int sys_fadvise(int fd, off_t offset, off_t length, int advice); +[[gnu::weak]] void sys_sync(); +[[gnu::weak]] int sys_fsync(int fd); +[[gnu::weak]] int sys_fdatasync(int fd); +[[gnu::weak]] int sys_chmod(const char *pathname, mode_t mode); +[[gnu::weak]] int sys_fchmod(int fd, mode_t mode); +[[gnu::weak]] int sys_fchmodat(int fd, const char *pathname, mode_t mode, int flags); +[[gnu::weak]] int sys_utimensat(int dirfd, const char *pathname, const struct timespec times[2], int flags); +[[gnu::weak]] int sys_mlock(const void *addr, size_t length); +[[gnu::weak]] int sys_munlock(const void *addr, size_t length); +[[gnu::weak]] int sys_mlockall(int flags); +[[gnu::weak]] int sys_mlock(const void *addr, size_t len); +[[gnu::weak]] int sys_munlockall(void); +[[gnu::weak]] int sys_mincore(void *addr, size_t length, unsigned char *vec); + +// mlibc assumes that anonymous memory returned by sys_vm_map() is zeroed by the kernel / whatever is behind the sysdeps +int sys_vm_map(void *hint, size_t size, int prot, int flags, int fd, off_t offset, void **window); + +[[gnu::weak]] int sys_vm_remap(void *pointer, size_t size, size_t new_size, void **window); +[[gnu::weak]] int sys_vm_protect(void *pointer, size_t size, int prot); + +int sys_vm_unmap(void *pointer, size_t size); + +[[gnu::weak]] int sys_setsid(pid_t *sid); +[[gnu::weak]] int sys_tcgetattr(int fd, struct termios *attr); +[[gnu::weak]] int sys_tcsetattr(int, int, const struct termios *attr); +[[gnu::weak]] int sys_tcflow(int, int); +[[gnu::weak]] int sys_tcflush(int fd, int queue); +[[gnu::weak]] int sys_tcdrain(int); +[[gnu::weak]] int sys_pipe(int *fds, int flags); +[[gnu::weak]] int sys_socketpair(int domain, int type_and_flags, int proto, int *fds); +[[gnu::weak]] int sys_poll(struct pollfd *fds, nfds_t count, int timeout, int *num_events); +[[gnu::weak]] int sys_ioctl(int fd, unsigned long request, void *arg, int *result); +[[gnu::weak]] int sys_getsockopt(int fd, int layer, int number, + void *__restrict buffer, socklen_t *__restrict size); +[[gnu::weak]] int sys_setsockopt(int fd, int layer, int number, + const void *buffer, socklen_t size); +[[gnu::weak]] int sys_shutdown(int sockfd, int how); +[[gnu::weak]] int sys_sigprocmask(int how, const sigset_t *__restrict set, + sigset_t *__restrict retrieve); +[[gnu::weak]] int sys_sigaction(int, const struct sigaction *__restrict, + struct sigaction *__restrict); +// NOTE: POSIX says that behavior of timeout = nullptr is unspecified. We treat this case +// as an infinite timeout, making sigtimedwait(..., nullptr) equivalent to sigwaitinfo(...) +[[gnu::weak]] int sys_sigtimedwait(const sigset_t *__restrict set, siginfo_t *__restrict info, const struct timespec *__restrict timeout, int *out_signal); +[[gnu::weak]] int sys_kill(int, int); +[[gnu::weak]] int sys_accept(int fd, int *newfd, struct sockaddr *addr_ptr, socklen_t *addr_length, int flags); +[[gnu::weak]] int sys_bind(int fd, const struct sockaddr *addr_ptr, socklen_t addr_length); +[[gnu::weak]] int sys_connect(int fd, const struct sockaddr *addr_ptr, socklen_t addr_length); +[[gnu::weak]] int sys_sockname(int fd, struct sockaddr *addr_ptr, socklen_t max_addr_length, + socklen_t *actual_length); +[[gnu::weak]] int sys_peername(int fd, struct sockaddr *addr_ptr, socklen_t max_addr_length, + socklen_t *actual_length); +[[gnu::weak]] int sys_gethostname(char *buffer, size_t bufsize); +[[gnu::weak]] int sys_sethostname(const char *buffer, size_t bufsize); +[[gnu::weak]] int sys_mkfifoat(int dirfd, const char *path, int mode); +[[gnu::weak]] int sys_getentropy(void *buffer, size_t length); +[[gnu::weak]] int sys_mknodat(int dirfd, const char *path, int mode, int dev); +[[gnu::weak]] int sys_umask(mode_t mode, mode_t *old); + +[[gnu::weak]] int sys_before_cancellable_syscall(ucontext_t *uctx); +[[gnu::weak]] int sys_tgkill(int tgid, int tid, int sig); + +[[gnu::weak]] int sys_fchownat(int dirfd, const char *pathname, uid_t owner, gid_t group, int flags); +[[gnu::weak]] int sys_sigaltstack(const stack_t *ss, stack_t *oss); +[[gnu::weak]] int sys_sigsuspend(const sigset_t *set); +[[gnu::weak]] int sys_sigpending(sigset_t *set); +[[gnu::weak]] int sys_setgroups(size_t size, const gid_t *list); +[[gnu::weak]] int sys_memfd_create(const char *name, int flags, int *fd); +[[gnu::weak]] int sys_madvise(void *addr, size_t length, int advice); +[[gnu::weak]] int sys_msync(void *addr, size_t length, int flags); + +[[gnu::weak]] int sys_getitimer(int which, struct itimerval *curr_value); +[[gnu::weak]] int sys_setitimer(int which, const struct itimerval *new_value, struct itimerval *old_value); +[[gnu::weak]] int sys_timer_create(clockid_t clk, struct sigevent *__restrict evp, timer_t *__restrict res); +[[gnu::weak]] int sys_timer_settime(timer_t t, int flags, const struct itimerspec *__restrict val, struct itimerspec *__restrict old); +[[gnu::weak]] int sys_timer_delete(timer_t t); +[[gnu::weak]] int sys_times(struct tms *tms, clock_t *out); +[[gnu::weak]] int sys_uname(struct utsname *buf); +[[gnu::weak]] int sys_pause(); + +[[gnu::weak]] int sys_setresuid(uid_t ruid, uid_t euid, uid_t suid); +[[gnu::weak]] int sys_setresgid(gid_t rgid, gid_t egid, gid_t sgid); +[[gnu::weak]] int sys_getresuid(uid_t *ruid, uid_t *euid, uid_t *suid); +[[gnu::weak]] int sys_getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid); +[[gnu::weak]] int sys_setreuid(uid_t ruid, uid_t euid); +[[gnu::weak]] int sys_setregid(gid_t rgid, gid_t egid); + +[[gnu::weak]] int sys_poll(struct pollfd *fds, nfds_t count, int timeout, int *num_events); + +[[gnu::weak]] int sys_if_indextoname(unsigned int index, char *name); +[[gnu::weak]] int sys_if_nametoindex(const char *name, unsigned int *ret); + +[[gnu::weak]] int sys_ptsname(int fd, char *buffer, size_t length); +[[gnu::weak]] int sys_unlockpt(int fd); + +[[gnu::weak]] int sys_thread_setname(void *tcb, const char *name); +[[gnu::weak]] int sys_thread_getname(void *tcb, char *name, size_t size); + +[[gnu::weak]] int sys_sysconf(int num, long *ret); + +[[gnu::weak]] int sys_semget(key_t key, int n, int fl, int *id); +[[gnu::weak]] int sys_semctl(int semid, int semnum, int cmd, void *semun, int *ret); + +[[gnu::weak]] int sys_getaffinity(pid_t pid, size_t cpusetsize, cpu_set_t *mask); +[[gnu::weak]] int sys_getthreadaffinity(pid_t tid, size_t cpusetsize, cpu_set_t *mask); + +[[gnu::weak]] int sys_setaffinity(pid_t pid, size_t cpusetsize, const cpu_set_t *mask); +[[gnu::weak]] int sys_setthreadaffinity(pid_t tid, size_t cpusetsize, const cpu_set_t *mask); + +[[gnu::weak]] int sys_waitid(idtype_t idtype, id_t id, siginfo_t *info, int options); + +} //namespace mlibc + +#endif // MLIBC_POSIX_SYSDEPS diff --git a/lib/mlibc/options/posix/include/mlibc/resolv_conf.hpp b/lib/mlibc/options/posix/include/mlibc/resolv_conf.hpp new file mode 100644 index 0000000..2a349c7 --- /dev/null +++ b/lib/mlibc/options/posix/include/mlibc/resolv_conf.hpp @@ -0,0 +1,21 @@ +#ifndef _MLIBC_RESOLV_CONF +#define _MLIBC_RESOLV_CONF + +#include +#include +#include + +namespace mlibc { + +struct nameserver_data { + nameserver_data() + : name(getAllocator()) {} + frg::string name; + // for in the future we can also store options here +}; + +frg::optional get_nameserver(); + +} // namespace mlibc + +#endif // _MLIBC_RESOLV_CONF diff --git a/lib/mlibc/options/posix/include/mlibc/services.hpp b/lib/mlibc/options/posix/include/mlibc/services.hpp new file mode 100644 index 0000000..10dec47 --- /dev/null +++ b/lib/mlibc/options/posix/include/mlibc/services.hpp @@ -0,0 +1,33 @@ +#ifndef _MLIBC_SERVICES +#define _MLIBC_SERVICES + +#include +#include +#include +#include + +namespace mlibc { + +// Only two services for tcp and udp +#define SERV_MAX 2 + +struct service_buf { + service_buf() + : name(getAllocator()), aliases(getAllocator()) + { } + int port, protocol, socktype; + frg::string name; + frg::vector, MemoryAllocator> aliases; +}; + +using service_result = frg::small_vector; + +int lookup_serv_by_name(service_result &buf, const char *name, int proto, + int socktype, int flags); + +int lookup_serv_by_port(service_result &buf, int proto, int port); + + +} // namespace mlibc + +#endif // _MLIBC_SERVICES diff --git a/lib/mlibc/options/posix/include/mqueue.h b/lib/mlibc/options/posix/include/mqueue.h new file mode 100644 index 0000000..34ac990 --- /dev/null +++ b/lib/mlibc/options/posix/include/mqueue.h @@ -0,0 +1,26 @@ +#ifndef _MQUEUE_H +#define _MQUEUE_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef int mqd_t; + +#ifndef __MLIBC_ABI_ONLY + +int mq_getattr(mqd_t mqdes, struct mq_attr *attr); +int mq_setattr(mqd_t mqdes, const struct mq_attr *__restrict__ newattr, struct mq_attr *__restrict__ oldattr); +int mq_unlink(const char *name); +mqd_t mq_open(const char *name, int flags, ...); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif /* _MQUEUE_H */ + diff --git a/lib/mlibc/options/posix/include/net/if.h b/lib/mlibc/options/posix/include/net/if.h new file mode 100644 index 0000000..10016fd --- /dev/null +++ b/lib/mlibc/options/posix/include/net/if.h @@ -0,0 +1,118 @@ + +#ifndef _NET_IF_H +#define _NET_IF_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#define IF_NAMESIZE 16 +#define IFNAMSIZ IF_NAMESIZE +#define ALTIFNAMSIZ 128 +#define IFALIASZ 256 + +struct if_nameindex { + unsigned int if_index; + char *if_name; +}; + +struct ifmap { + unsigned long mem_start; + unsigned long mem_end; + unsigned short base_addr; + unsigned char irq; + unsigned char dma; + unsigned char port; +}; + +struct ifreq { + union { + char ifrn_name[IFNAMSIZ]; + } ifr_ifrn; + + union { + struct sockaddr ifru_addr; + struct sockaddr ifru_dstaddr; + struct sockaddr ifru_broadaddr; + struct sockaddr ifru_netmask; + struct sockaddr ifru_hwaddr; + short int ifru_flags; + int ifru_ivalue; + int ifru_mtu; + struct ifmap ifru_map; + char ifru_slave[IFNAMSIZ]; + char ifru_newname[IFNAMSIZ]; + char *ifru_data; + } ifr_ifru; +}; + +#define ifr_name ifr_ifrn.ifrn_name +#define ifr_hwaddr ifr_ifru.ifru_hwaddr +#define ifr_addr ifr_ifru.ifru_addr +#define ifr_dstaddr ifr_ifru.ifru_dstaddr +#define ifr_broadaddr ifr_ifru.ifru_broadaddr +#define ifr_netmask ifr_ifru.ifru_netmask +#define ifr_flags ifr_ifru.ifru_flags +#define ifr_metric ifr_ifru.ifru_ivalue +#define ifr_mtu ifr_ifru.ifru_mtu +#define ifr_map ifr_ifru.ifru_map +#define ifr_slave ifr_ifru.ifru_slave +#define ifr_data ifr_ifru.ifru_data +#define ifr_ifindex ifr_ifru.ifru_ivalue +#define ifr_bandwidth ifr_ifru.ifru_ivalue +#define ifr_qlen ifr_ifru.ifru_ivalue +#define ifr_newname ifr_ifru.ifru_newname + +struct ifconf { + int ifc_len; + union { + char *ifcu_buf; + struct ifreq *ifcu_req; + } ifc_ifcu; +}; + +#define ifc_buf ifc_ifcu.ifcu_buf +#define ifc_req ifc_ifcu.ifcu_req + +#ifndef __MLIBC_ABI_ONLY + +void if_freenameindex(struct if_nameindex *); +char *if_indextoname(unsigned int, char *); +struct if_nameindex *if_nameindex(void); +unsigned int if_nametoindex(const char *); + +#endif /* !__MLIBC_ABI_ONLY */ + +#define IFHWADDRLEN 6 + +#define IFF_UP 0x1 +#define IFF_BROADCAST 0x2 +#define IFF_DEBUG 0x4 +#define IFF_LOOPBACK 0x8 +#define IFF_POINTOPOINT 0x10 +#define IFF_NOTRAILERS 0x20 +#define IFF_RUNNING 0x40 +#define IFF_NOARP 0x80 +#define IFF_PROMISC 0x100 +#define IFF_ALLMULTI 0x200 +#define IFF_MASTER 0x400 +#define IFF_SLAVE 0x800 +#define IFF_MULTICAST 0x1000 +#define IFF_PORTSEL 0x2000 +#define IFF_AUTOMEDIA 0x4000 +#define IFF_DYNAMIC 0x8000 +#define IFF_LOWER_UP 0x10000 +#define IFF_DORMANT 0x20000 +#define IFF_ECHO 0x40000 +#define IFF_VOLATILE (IFF_LOOPBACK|IFF_POINTOPOINT|IFF_BROADCAST| \ + IFF_ECHO|IFF_MASTER|IFF_SLAVE|IFF_RUNNING|IFF_LOWER_UP|IFF_DORMANT) + +#ifdef __cplusplus +} +#endif + +#endif // _NET_IF_H + + diff --git a/lib/mlibc/options/posix/include/net/if_arp.h b/lib/mlibc/options/posix/include/net/if_arp.h new file mode 100644 index 0000000..de8a0c2 --- /dev/null +++ b/lib/mlibc/options/posix/include/net/if_arp.h @@ -0,0 +1,103 @@ +#ifndef _NET_IF_ARP_H +#define _NET_IF_ARP_H + +#include +#include +#include + +#define ARPOP_REQUEST 1 +#define ARPOP_REPLY 2 +#define ARPOP_RREQUEST 3 +#define ARPOP_RREPLY 4 +#define ARPOP_InREQUEST 8 +#define ARPOP_InREPLY 9 +#define ARPOP_NAK 10 + +#define ARPHRD_NETROM 0 +#define ARPHRD_ETHER 1 +#define ARPHRD_EETHER 2 +#define ARPHRD_AX25 3 +#define ARPHRD_PRONET 4 +#define ARPHRD_CHAOS 5 +#define ARPHRD_IEEE802 6 +#define ARPHRD_ARCNET 7 +#define ARPHRD_APPLETLK 8 +#define ARPHRD_DLCI 15 +#define ARPHRD_ATM 19 +#define ARPHRD_METRICOM 23 +#define ARPHRD_IEEE1394 24 +#define ARPHRD_EUI64 27 +#define ARPHRD_INFINIBAND 32 +#define ARPHRD_SLIP 256 +#define ARPHRD_CSLIP 257 +#define ARPHRD_SLIP6 258 +#define ARPHRD_CSLIP6 259 +#define ARPHRD_RSRVD 260 +#define ARPHRD_ADAPT 264 +#define ARPHRD_ROSE 270 +#define ARPHRD_X25 271 +#define ARPHRD_HWX25 272 +#define ARPHRD_CAN 280 +#define ARPHRD_PPP 512 +#define ARPHRD_CISCO 513 +#define ARPHRD_HDLC ARPHRD_CISCO +#define ARPHRD_LAPB 516 +#define ARPHRD_DDCMP 517 +#define ARPHRD_RAWHDLC 518 +#define ARPHRD_RAWIP 519 + +#define ARPHRD_TUNNEL 768 +#define ARPHRD_TUNNEL6 769 +#define ARPHRD_FRAD 770 +#define ARPHRD_SKIP 771 +#define ARPHRD_LOOPBACK 772 +#define ARPHRD_LOCALTLK 773 +#define ARPHRD_FDDI 774 +#define ARPHRD_BIF 775 +#define ARPHRD_SIT 776 +#define ARPHRD_IPDDP 777 +#define ARPHRD_IPGRE 778 +#define ARPHRD_PIMREG 779 +#define ARPHRD_HIPPI 780 +#define ARPHRD_ASH 781 +#define ARPHRD_ECONET 782 +#define ARPHRD_IRDA 783 +#define ARPHRD_FCPP 784 +#define ARPHRD_FCAL 785 +#define ARPHRD_FCPL 786 +#define ARPHRD_FCFABRIC 787 +#define ARPHRD_IEEE802_TR 800 +#define ARPHRD_IEEE80211 801 +#define ARPHRD_IEEE80211_PRISM 802 +#define ARPHRD_IEEE80211_RADIOTAP 803 +#define ARPHRD_IEEE802154 804 +#define ARPHRD_IEEE802154_MONITOR 805 +#define ARPHRD_PHONET 820 +#define ARPHRD_PHONET_PIPE 821 +#define ARPHRD_CAIF 822 +#define ARPHRD_IP6GRE 823 +#define ARPHRD_NETLINK 824 +#define ARPHRD_6LOWPAN 825 +#define ARPHRD_VSOCKMON 826 + +#define ARPHRD_VOID 0xFFFF +#define ARPHRD_NONE 0xFFFE + +struct arphdr { + uint16_t ar_hrd; + uint16_t ar_pro; + uint8_t ar_hln; + uint8_t ar_pln; + uint16_t ar_op; +}; + +struct arpreq { + struct sockaddr arp_pa; + struct sockaddr arp_ha; + int arp_flags; + struct sockaddr arp_netmask; + char arp_dev[16]; +}; + +#endif // _NET_IF_ARP_H + diff --git a/lib/mlibc/options/posix/include/netdb.h b/lib/mlibc/options/posix/include/netdb.h new file mode 100644 index 0000000..368c74f --- /dev/null +++ b/lib/mlibc/options/posix/include/netdb.h @@ -0,0 +1,148 @@ +#ifndef _NETDB_H +#define _NETDB_H + +#include +#include +#include +#include +#include + +#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 0x40 + +#define NI_NOFQDN 0x01 +#define NI_NUMERICHOST 0x02 +#define NI_NAMEREQD 0x04 +#define NI_NUMERICSCOPE 0x08 +#define NI_DGRAM 0x10 + +#define NI_NUMERICSERV 2 +#define NI_MAXSERV 32 +#define NI_IDN 32 + +#define NI_MAXHOST 1025 + +#define EAI_AGAIN 1 +#define EAI_BADFLAGS 2 +#define EAI_FAIL 3 +#define EAI_FAMILY 4 +#define EAI_MEMORY 5 +#define EAI_NONAME 6 +#define EAI_SERVICE 7 +#define EAI_SOCKTYPE 8 +#define EAI_SYSTEM 9 +#define EAI_OVERFLOW 10 +#define EAI_NODATA 11 +#define EAI_ADDRFAMILY 12 + +#define HOST_NOT_FOUND 1 +#define TRY_AGAIN 2 +#define NO_RECOVERY 3 +#define NO_DATA 4 +#define NO_ADDRESS NO_DATA + +#define IPPORT_RESERVED 1024 + +#define _PATH_SERVICES "/etc/services" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +int *__h_errno_location(void); +#define h_errno (*__h_errno_location()) + +#endif /* !__MLIBC_ABI_ONLY */ + +struct hostent { + char *h_name; + char **h_aliases; + int h_addrtype; + int h_length; + char **h_addr_list; +}; + +#define h_addr h_addr_list[0] // Required by some programs + +struct netent { + char *n_name; + char **n_aliases; + int n_addrtype; + uint32_t n_net; +}; + +struct protoent { + char *p_name; + char **p_aliases; + int p_proto; +}; + +struct servent { + char *s_name; + char **s_aliases; + int s_port; + char *s_proto; +}; + +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; +}; + +#ifndef __MLIBC_ABI_ONLY + +void endhostent(void); +void endnetent(void); +void endprotoent(void); +void endservent(void); +void freeaddrinfo(struct addrinfo *); +const char *gai_strerror(int); +int getaddrinfo(const char *__restrict, const char *__restrict, + const struct addrinfo *__restrict, struct addrinfo **__restrict); +struct hostent *gethostent(void); +struct hostent *gethostbyname(const char *); +struct hostent *gethostbyname2(const char *, int); +struct hostent *gethostbyaddr(const void *, socklen_t, int); +int gethostbyaddr_r(const void *__restrict, socklen_t, int, struct hostent *__restrict, + char *__restrict, size_t, struct hostent **__restrict, int *__restrict); +int gethostbyname_r(const char *__restrict, struct hostent *__restrict, char *__restrict, size_t, + struct hostent **__restrict, int *__restrict); +int getnameinfo(const struct sockaddr *__restrict, socklen_t, + char *__restrict, socklen_t, char *__restrict, socklen_t, int); +struct netent *getnetbyaddr(uint32_t, int); +struct netent *getnetbyname(const char *); +struct netent *getnetent(void); +struct protoent *getprotobyname(const char *); +struct protoent *getprotobynumber(int); +struct protoent *getprotoent(void); +struct servent *getservbyname(const char *, const char *); +struct servent *getservbyport(int, const char *); +struct servent *getservent(void); +void sethostent(int); +void setnetent(int); +void setprotoent(int); +void setservent(int); + +// Deprecated GNU extension +const char *hstrerror(int err); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif // _NETDB_H diff --git a/lib/mlibc/options/posix/include/netinet/icmp6.h b/lib/mlibc/options/posix/include/netinet/icmp6.h new file mode 100644 index 0000000..7dfe237 --- /dev/null +++ b/lib/mlibc/options/posix/include/netinet/icmp6.h @@ -0,0 +1,139 @@ +#ifndef _NETINET_ICMP6_H +#define _NETINET_ICMP6_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include + +#if __MLIBC_GLIBC_OPTION +#include +#endif // __MLIBC_GLIBC_OPTION + +#define ICMP6_FILTER 1 + +#define ICMP6_FILTER_BLOCK 1 +#define ICMP6_FILTER_PASS 2 +#define ICMP6_FILTER_BLOCKOTHERS 3 +#define ICMP6_FILTER_PASSONLY 4 +#define ICMP6_ECHO_REQUEST 128 + +struct icmp6_filter { + uint32_t icmp6_filt[8]; +}; + +struct icmp6_hdr { + uint8_t icmp6_type; + uint8_t icmp6_code; + uint16_t icmp6_cksum; + union { + uint32_t icmp6_un_data32[1]; + uint16_t icmp6_un_data16[2]; + uint8_t icmp6_un_data8[4]; + } icmp6_dataun; +}; + +#define icmp6_data32 icmp6_dataun.icmp6_un_data32 +#define icmp6_data16 icmp6_dataun.icmp6_un_data16 +#define icmp6_data8 icmp6_dataun.icmp6_un_data8 + +#define icmp6_pptr icmp6_data32[0] +#define icmp6_mtu icmp6_data32[0] +#define icmp6_id icmp6_data16[0] +#define icmp6_seq icmp6_data16[1] +#define icmp6_maxdelay icmp6_data16[0] + +#define ICMP6_FILTER_WILLPASS(type, filterp) \ + ((((filterp)->icmp6_filt[(type) >> 5]) & (1U << ((type) & 31))) == 0) + +#define ICMP6_FILTER_WILLBLOCK(type, filterp) \ + ((((filterp)->icmp6_filt[(type) >> 5]) & (1U << ((type) & 31))) != 0) + +#define ICMP6_FILTER_SETPASS(type, filterp) \ + ((((filterp)->icmp6_filt[(type) >> 5]) &= ~(1U << ((type) & 31)))) + +#define ICMP6_FILTER_SETBLOCK(type, filterp) \ + ((((filterp)->icmp6_filt[(type) >> 5]) |= (1U << ((type) & 31)))) + +#define ICMP6_FILTER_SETPASSALL(filterp) \ + memset (filterp, 0, sizeof (struct icmp6_filter)); + +#define ICMP6_FILTER_SETBLOCKALL(filterp) \ + memset (filterp, 0xFF, sizeof (struct icmp6_filter)); + +#define ND_ROUTER_SOLICIT 133 +#define ND_ROUTER_ADVERT 134 +#define ND_NEIGHBOR_SOLICIT 135 +#define ND_NEIGHBOR_ADVERT 136 +#define ND_REDIRECT 137 + +struct nd_router_solicit { + struct icmp6_hdr nd_rs_hdr; +}; + +#define nd_rs_type nd_rs_hdr.icmp6_type +#define nd_rs_code nd_rs_hdr.icmp6_code +#define nd_rs_cksum nd_rs_hdr.icmp6_cksum +#define nd_rs_reserved nd_rs_hdr.icmp6_data32[0] + +struct nd_router_advert { + struct icmp6_hdr nd_ra_hdr; + uint32_t nd_ra_reachable; + uint32_t nd_ra_retransmit; +}; + +struct nd_opt_hdr { + uint8_t nd_opt_type; + uint8_t nd_opt_len; +}; + +#define ND_OPT_SOURCE_LINKADDR 1 +#define ND_OPT_TARGET_LINKADDR 2 +#define ND_OPT_PREFIX_INFORMATION 3 +#define ND_OPT_REDIRECTED_HEADER 4 +#define ND_OPT_MTU 5 +#define ND_OPT_RTR_ADV_INTERVAL 7 +#define ND_OPT_HOME_AGENT_INFO 8 + +struct nd_opt_prefix_info { + uint8_t nd_opt_pi_type; + uint8_t nd_opt_pi_len; + uint8_t nd_opt_pi_prefix_len; + uint8_t nd_opt_pi_flags_reserved; + uint32_t nd_opt_pi_valid_time; + uint32_t nd_opt_pi_preferred_time; + uint32_t nd_opt_pi_reserved2; + struct in6_addr nd_opt_pi_prefix; +}; + +#define ND_OPT_PI_FLAG_RADDR 0x20 +#define ND_OPT_PI_FLAG_AUTO 0x40 +#define ND_OPT_PI_FLAG_ONLINK 0x80 + +#define nd_ra_type nd_ra_hdr.icmp6_type +#define nd_ra_code nd_ra_hdr.icmp6_code +#define nd_ra_cksum nd_ra_hdr.icmp6_cksum +#define nd_ra_curhoplimit nd_ra_hdr.icmp6_data8[0] +#define nd_ra_flags_reserved nd_ra_hdr.icmp6_data8[1] +#define nd_ra_router_lifetime nd_ra_hdr.icmp6_data16[1] + +#define ND_RA_FLAG_HOME_AGENT 0x20 +#define ND_RA_FLAG_OTHER 0x40 +#define ND_RA_FLAG_MANAGED 0x80 + +struct nd_opt_mtu { + uint8_t nd_opt_mtu_type; + uint8_t nd_opt_mtu_len; + uint16_t nd_opt_mtu_reserved; + uint32_t nd_opt_mtu_mtu; +}; + +#ifdef __cplusplus +} +#endif + +#endif // _NETINET_ICMP6_H + diff --git a/lib/mlibc/options/posix/include/netinet/if_ether.h b/lib/mlibc/options/posix/include/netinet/if_ether.h new file mode 100644 index 0000000..c4ce173 --- /dev/null +++ b/lib/mlibc/options/posix/include/netinet/if_ether.h @@ -0,0 +1,105 @@ +#ifndef _NETINET_IF_ETHER_H +#define _NETINET_IF_ETHER_H + +#include + +#define ETH_ALEN 6 +#define ETH_HLEN 14 +#define ETH_ZLEN 60 +#define ETH_FRAME_LEN 1514 +#define ETH_FCS_LEN 4 + +#define ETH_P_LOOP 0x0060 +#define ETH_P_PUP 0x0200 +#define ETH_P_PUPAT 0x0201 +#define ETH_P_IP 0x0800 +#define ETH_P_X25 0x0805 +#define ETH_P_ARP 0x0806 +#define ETH_P_BPQ 0x08FF +#define ETH_P_IEEEPUP 0x0a00 +#define ETH_P_IEEEPUPAT 0x0a01 +#define ETH_P_BATMAN 0x4305 +#define ETH_P_DEC 0x6000 +#define ETH_P_DNA_DL 0x6001 +#define ETH_P_DNA_RC 0x6002 +#define ETH_P_DNA_RT 0x6003 +#define ETH_P_LAT 0x6004 +#define ETH_P_DIAG 0x6005 +#define ETH_P_CUST 0x6006 +#define ETH_P_SCA 0x6007 +#define ETH_P_TEB 0x6558 +#define ETH_P_RARP 0x8035 +#define ETH_P_ATALK 0x809B +#define ETH_P_AARP 0x80F3 +#define ETH_P_8021Q 0x8100 +#define ETH_P_IPX 0x8137 +#define ETH_P_IPV6 0x86DD +#define ETH_P_PAUSE 0x8808 +#define ETH_P_SLOW 0x8809 +#define ETH_P_WCCP 0x883E +#define ETH_P_MPLS_UC 0x8847 +#define ETH_P_MPLS_MC 0x8848 +#define ETH_P_ATMMPOA 0x884c +#define ETH_P_PPP_DISC 0x8863 +#define ETH_P_PPP_SES 0x8864 +#define ETH_P_LINK_CTL 0x886c +#define ETH_P_ATMFATE 0x8884 +#define ETH_P_PAE 0x888E +#define ETH_P_AOE 0x88A2 +#define ETH_P_8021AD 0x88A8 +#define ETH_P_802_EX1 0x88B5 +#define ETH_P_TIPC 0x88CA +#define ETH_P_8021AH 0x88E7 +#define ETH_P_MVRP 0x88F5 +#define ETH_P_1588 0x88F7 +#define ETH_P_PRP 0x88FB +#define ETH_P_FCOE 0x8906 +#define ETH_P_TDLS 0x890D +#define ETH_P_FIP 0x8914 +#define ETH_P_80221 0x8917 +#define ETH_P_LOOPBACK 0x9000 +#define ETH_P_QINQ1 0x9100 +#define ETH_P_QINQ2 0x9200 +#define ETH_P_QINQ3 0x9300 +#define ETH_P_EDSA 0xDADA +#define ETH_P_AF_IUCV 0xFBFB + +#define ETH_P_802_3_MIN 0x0600 + +#define ETH_P_802_3 0x0001 +#define ETH_P_AX25 0x0002 +#define ETH_P_ALL 0x0003 +#define ETH_P_802_2 0x0004 +#define ETH_P_SNAP 0x0005 +#define ETH_P_DDCMP 0x0006 +#define ETH_P_WAN_PPP 0x0007 +#define ETH_P_PPP_MP 0x0008 +#define ETH_P_LOCALTALK 0x0009 +#define ETH_P_CAN 0x000C +#define ETH_P_CANFD 0x000D +#define ETH_P_PPPTALK 0x0010 +#define ETH_P_TR_802_2 0x0011 +#define ETH_P_MOBITEX 0x0015 +#define ETH_P_CONTROL 0x0016 +#define ETH_P_IRDA 0x0017 +#define ETH_P_ECONET 0x0018 +#define ETH_P_HDLC 0x0019 +#define ETH_P_ARCNET 0x001A +#define ETH_P_DSA 0x001B +#define ETH_P_TRAILER 0x001C +#define ETH_P_PHONET 0x00F5 +#define ETH_P_IEEE802154 0x00F6 +#define ETH_P_CAIF 0x00F7 + +#include +#include + +struct ether_arp { + struct arphdr ea_hdr; + uint8_t arp_sha[ETH_ALEN]; + uint8_t arp_spa[4]; + uint8_t arp_tha[ETH_ALEN]; + uint8_t arp_tpa[4]; +}; + +#endif //_NETINET_IF_ETHER_H diff --git a/lib/mlibc/options/posix/include/netinet/in.h b/lib/mlibc/options/posix/include/netinet/in.h new file mode 100644 index 0000000..9a42c47 --- /dev/null +++ b/lib/mlibc/options/posix/include/netinet/in.h @@ -0,0 +1,118 @@ + +#ifndef _NETINET_IN_H +#define _NETINET_IN_H + +#include +#include +#include // struct sockaddr +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +extern const struct in6_addr in6addr_any; +extern const struct in6_addr in6addr_loopback; + +uint32_t htonl(uint32_t); +uint16_t htons(uint16_t); +uint32_t ntohl(uint32_t); +uint16_t ntohs(uint16_t); + +#endif /* !__MLIBC_ABI_ONLY */ + +#define IN6_IS_ADDR_UNSPECIFIED(a) ({ \ + uint32_t *_a = (uint32_t *)(((struct in6_addr *) a)->s6_addr); \ + !_a[0] && \ + !_a[1] && \ + !_a[2] && \ + !_a[3]; \ +}) +#define IN6_IS_ADDR_LOOPBACK(a) ({ \ + uint32_t *_a = (uint32_t *)(((struct in6_addr *) a)->s6_addr); \ + !_a[0] && \ + !_a[1] && \ + !_a[2] && \ + _a[3] == htonl(0x0001); \ +}) +#define IN6_IS_ADDR_MULTICAST(a) (((const uint8_t *) (a))[0] == 0xff) +#define IN6_IS_ADDR_LINKLOCAL(a) ({ \ + uint32_t *_a = (uint32_t *)(((struct in6_addr *) a)->s6_addr); \ + _a[0] & htonl(0xffc00000) == htonl(0xfe800000); \ +}) +#define IN6_IS_ADDR_SITELOCAL(a) ({ \ + uint32_t *_a = (uint32_t *)(((struct in6_addr *) a)->s6_addr); \ + _a[0] & htonl(0xffc00000) == htonl(0xfec00000); \ +}) +#define IN6_IS_ADDR_V4MAPPED(a) ({ \ + uint32_t *_a = (uint32_t *)(((struct in6_addr *) a)->s6_addr); \ + !_a[0] && \ + !_a[1] && \ + _a[2] == htonl(0xffff); \ +}) +#define __ARE_4_BYTE_EQUAL(a, b) \ + ((a)[0] == (b)[0] && (a)[1] == (b)[1] && (a)[2] == (b)[2] && \ + (a)[3] == (b)[3] && (a)[4] == (b)[4]) +#define IN6_ARE_ADDR_EQUAL(a, b) \ + __ARE_4_BYTE_EQUAL((const uint32_t *)(a), (const uint32_t *)(b)) + +#define IN6_IS_ADDR_V4COMPAT(a) ({ \ + uint32_t *_a = (uint32_t *)(((struct in6_addr *) a)->s6_addr); \ + uint8_t *_a8 = (uint8_t *)(((struct in6_addr *) a)->s6_addr); \ + !_a[0] && !_a[1] && !_a[2] && (_a8[15] > 1); \ +}) +#define IN6_IS_ADDR_MC_NODELOCAL(a) ({ \ + (IN6_IS_ADDR_MULTICAST(a) && \ + ((((const uint8_t *)(a))[1] & 0xf) == 0x1)); \ +}) +#define IN6_IS_ADDR_MC_LINKLOCAL(a) ({ \ + (IN6_IS_ADDR_MULTICAST(a) && \ + ((((const uint8_t *)(a))[1] & 0xf) == 0x2)); \ +}) +#define IN6_IS_ADDR_MC_SITELOCAL(a) ({ \ + (IN6_IS_ADDR_MULTICAST(a) && \ + ((((const uint8_t *)(a))[1] & 0xf) == 0x5)); \ +}) +#define IN6_IS_ADDR_MC_ORGLOCAL(a) ({ \ + (IN6_IS_ADDR_MULTICAST(a) && \ + ((((const uint8_t *)(a))[1] & 0xf) == 0x8)); \ +}) +#define IN6_IS_ADDR_MC_GLOBAL(a) ({ \ + (IN6_IS_ADDR_MULTICAST(a) && \ + ((((const uint8_t *)(a))[1] & 0xf) == 0xe)); \ +}) + +#define IN_CLASSA(a) ((((in_addr_t)(a)) & 0x80000000) == 0) +#define IN_CLASSA_NET 0xff000000 +#define IN_CLASSA_NSHIFT 24 +#define IN_CLASSA_HOST (0xffffffff & ~IN_CLASSA_NET) +#define IN_CLASSA_MAX 128 +#define IN_CLASSB(a) ((((in_addr_t)(a)) & 0xc0000000) == 0x80000000) +#define IN_CLASSB_NET 0xffff0000 +#define IN_CLASSB_NSHIFT 16 +#define IN_CLASSB_HOST (0xffffffff & ~IN_CLASSB_NET) +#define IN_CLASSB_MAX 65536 +#define IN_CLASSC(a) ((((in_addr_t)(a)) & 0xe0000000) == 0xc0000000) +#define IN_CLASSC_NET 0xffffff00 +#define IN_CLASSC_NSHIFT 8 +#define IN_CLASSC_HOST (0xffffffff & ~IN_CLASSC_NET) +#define IN_CLASSD(a) ((((in_addr_t)(a)) & 0xf0000000) == 0xe0000000) +#define IN_MULTICAST(a) IN_CLASSD(a) +#define IN_EXPERIMENTAL(a) ((((in_addr_t)(a)) & 0xe0000000) == 0xe0000000) +#define IN_BADCLASS(a) ((((in_addr_t)(a)) & 0xf0000000) == 0xf0000000) + +#define IN_LOOPBACKNET 127 + +#define MCAST_EXCLUDE 0 +#define MCAST_INCLUDE 1 + +#ifdef __cplusplus +} +#endif + +#endif // _NETINET_IN_H + diff --git a/lib/mlibc/options/posix/include/netinet/ip.h b/lib/mlibc/options/posix/include/netinet/ip.h new file mode 100644 index 0000000..161aa18 --- /dev/null +++ b/lib/mlibc/options/posix/include/netinet/ip.h @@ -0,0 +1,75 @@ + +#ifndef _NETINET_IP_H +#define _NETINET_IP_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +#define IPTOS_TOS_MASK 0x1E +#define IPTOS_TOS(tos) ((tos) & IPTOS_TOS_MASK) +#define IPTOS_LOWDELAY 0x10 +#define IPTOS_THROUGHPUT 0x08 +#define IPTOS_RELIABILITY 0x04 +#define IPTOS_LOWCOST 0x02 +#define IPTOS_MINCOST IPTOS_LOWCOST +#define IPTOS_CLASS_CS4 0x80 +#define IPTOS_CLASS_CS6 0xC0 + +#define IPDEFTTL 64 + +struct ip { +#if __BYTE_ORDER == __LITTLE_ENDIAN + unsigned int ip_hl:4; + unsigned int ip_v:4; +#endif +#if __BYTE_ORDER == __BIG_ENDIAN + unsigned int ip_v:4; + unsigned int ip_hl:4; +#endif + uint8_t ip_tos; + unsigned short ip_len; + unsigned short ip_id; + unsigned short ip_off; +#define IP_RF 0x8000 +#define IP_DF 0x4000 +#define IP_MF 0x2000 +#define IP_OFFMASK 0x1fff + uint8_t ip_ttl; + uint8_t ip_p; + unsigned short ip_sum; + struct in_addr ip_src, ip_dst; +}; + +#define IPVERSION 4 + +struct iphdr { +#if __BYTE_ORDER == __LITTLE_ENDIAN + unsigned int ihl:4; + unsigned int version:4; +#elif __BYTE_ORDER == __BIG_ENDIAN + unsigned int version:4; + unsigned int ihl:4; +#else +# error "Please fix " +#endif + uint8_t tos; + uint16_t tot_len; + uint16_t id; + uint16_t frag_off; + uint8_t ttl; + uint8_t protocol; + uint16_t check; + uint32_t saddr; + uint32_t daddr; +}; + +#ifdef __cplusplus +} +#endif + +#endif // _NETINET_IP_H + diff --git a/lib/mlibc/options/posix/include/netinet/ip6.h b/lib/mlibc/options/posix/include/netinet/ip6.h new file mode 100644 index 0000000..88f0cb6 --- /dev/null +++ b/lib/mlibc/options/posix/include/netinet/ip6.h @@ -0,0 +1,28 @@ +#ifndef _NETINET_IP6_H +#define _NETINET_IP6_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct ip6_hdr { + union { + struct ip6_hdrctl { + uint32_t ip6_un1_flow; + uint16_t ip6_un1_plen; + uint8_t ip6_un1_nxt; + uint8_t ip6_un1_hlim; + } ip6_un1; + uint8_t ip6_un2_vfc; + } ip6_ctlun; + struct in6_addr ip6_src; + struct in6_addr ip6_dst; +}; + +#ifdef __cplusplus +} +#endif + +#endif // _NETINET_IP6_H diff --git a/lib/mlibc/options/posix/include/netinet/ip_icmp.h b/lib/mlibc/options/posix/include/netinet/ip_icmp.h new file mode 100644 index 0000000..56615e4 --- /dev/null +++ b/lib/mlibc/options/posix/include/netinet/ip_icmp.h @@ -0,0 +1,84 @@ +#ifndef _NETINET_ICMP_H +#define _NETINET_ICMP_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +#define ICMP_ECHOREPLY 0 +#define ICMP_ECHO 8 +#define ICMP_ADVLENMIN (8 + sizeof(struct ip) + 8) + +struct icmp_ra_addr { + uint32_t ira_addr; + uint32_t ira_preference; +}; + +struct icmp { + uint8_t icmp_type; + uint8_t icmp_code; + uint16_t icmp_cksum; + union { + unsigned char ih_pptr; + struct in_addr ih_gwaddr; + struct ih_idseq { + uint16_t icd_id; + uint16_t icd_seq; + } ih_idseq; + uint32_t ih_void; + + struct ih_pmtu { + uint16_t ipm_void; + uint16_t ipm_nextmtu; + } ih_pmtu; + + struct ih_rtradv { + uint8_t irt_num_addrs; + uint8_t irt_wpa; + uint16_t irt_lifetime; + } ih_rtradv; + } icmp_hun; + union { + struct { + uint32_t its_otime; + uint32_t its_rtime; + uint32_t its_ttime; + } id_ts; + struct { + struct ip idi_ip; + } id_ip; + struct icmp_ra_addr id_radv; + uint32_t id_mask; + uint8_t id_data[1]; + } icmp_dun; +}; + +#define icmp_pptr icmp_hun.ih_pptr +#define icmp_gwaddr icmp_hun.ih_gwaddr +#define icmp_id icmp_hun.ih_idseq.icd_id +#define icmp_seq icmp_hun.ih_idseq.icd_seq +#define icmp_void icmp_hun.ih_void +#define icmp_pmvoid icmp_hun.ih_pmtu.ipm_void +#define icmp_nextmtu icmp_hun.ih_pmtu.ipm_nextmtu +#define icmp_num_addrs icmp_hun.ih_rtradv.irt_num_addrs +#define icmp_wpa icmp_hun.ih_rtradv.irt_wpa +#define icmp_lifetime icmp_hun.ih_rtradv.irt_lifetime + +#define icmp_otime icmp_dun.id_ts.its_otime +#define icmp_rtime icmp_dun.id_ts.its_rtime +#define icmp_ttime icmp_dun.id_ts.its_ttime +#define icmp_ip icmp_dun.id_ip.idi_ip +#define icmp_radv icmp_dun.id_radv +#define icmp_mask icmp_dun.id_mask +#define icmp_data icmp_dun.id_data + +#ifdef __cplusplus +} +#endif + +#endif // _NETINET_ICMP_H diff --git a/lib/mlibc/options/posix/include/netinet/tcp.h b/lib/mlibc/options/posix/include/netinet/tcp.h new file mode 100644 index 0000000..9d64d7a --- /dev/null +++ b/lib/mlibc/options/posix/include/netinet/tcp.h @@ -0,0 +1,37 @@ +#ifndef _NETINET_TCP_H +#define _NETINET_TCP_H + +#ifdef __cplusplus +extern "C" { +#endif + +// Define some macros using same ABI as Linux +#define TCP_NODELAY 1 +#define TCP_MAXSEG 2 +#define TCP_KEEPIDLE 4 +#define TCP_KEEPINTVL 5 +#define TCP_KEEPCNT 6 +#define TCP_DEFER_ACCEPT 9 +#define TCP_CONGESTION 13 +#define TCP_FASTOPEN 23 + +#define TCP_ESTABLISHED 1 +#define TCP_SYN_SENT 2 +#define TCP_SYN_RECV 3 +#define TCP_FIN_WAIT1 4 +#define TCP_FIN_WAIT2 5 +#define TCP_TIME_WAIT 6 +#define TCP_CLOSE 7 +#define TCP_CLOSE_WAIT 8 +#define TCP_LAST_ACK 9 +#define TCP_LISTEN 10 +#define TCP_CLOSING 11 +#define TCP_QUICKACK 12 + +#define SOL_TCP 6 + +#ifdef __cplusplus +} +#endif + +#endif // _NETINET_TCP_H diff --git a/lib/mlibc/options/posix/include/netinet/udp.h b/lib/mlibc/options/posix/include/netinet/udp.h new file mode 100644 index 0000000..5cc887d --- /dev/null +++ b/lib/mlibc/options/posix/include/netinet/udp.h @@ -0,0 +1,31 @@ +#ifndef _NETINET_UDP_H +#define _NETINET_UDP_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct udphdr { + union { + struct { + uint16_t uh_sport; + uint16_t uh_dport; + uint16_t uh_ulen; + uint16_t uh_sum; + }; + struct { + uint16_t source; + uint16_t dest; + uint16_t len; + uint16_t check; + }; + }; +}; + +#ifdef __cplusplus +} +#endif + +#endif // _NETINET_UDP_H diff --git a/lib/mlibc/options/posix/include/nl_types.h b/lib/mlibc/options/posix/include/nl_types.h new file mode 100644 index 0000000..f0099ba --- /dev/null +++ b/lib/mlibc/options/posix/include/nl_types.h @@ -0,0 +1,6 @@ +#ifndef NL_TYPES_H +#define NL_TYPES_H + + + +#endif // NL_TYPES_H \ No newline at end of file diff --git a/lib/mlibc/options/posix/include/poll.h b/lib/mlibc/options/posix/include/poll.h new file mode 100644 index 0000000..7550015 --- /dev/null +++ b/lib/mlibc/options/posix/include/poll.h @@ -0,0 +1,6 @@ +#ifndef _POLL_H +#define _POLL_H + +#include + +#endif // _POLL_H diff --git a/lib/mlibc/options/posix/include/pthread.h b/lib/mlibc/options/posix/include/pthread.h new file mode 100644 index 0000000..739f607 --- /dev/null +++ b/lib/mlibc/options/posix/include/pthread.h @@ -0,0 +1,325 @@ + +#ifndef _PTHREAD_H +#define _PTHREAD_H + +#include +#include +// TODO: pthread is not required to define size_t. +#include +#include +#include +#include + +#include +#include + +// pthread.h is required to include sched.h and time.h +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define PTHREAD_CREATE_JOINABLE __MLIBC_THREAD_CREATE_JOINABLE +#define PTHREAD_CREATE_DETACHED __MLIBC_THREAD_CREATE_DETACHED + +// Values for pthread_attr_{get,set}scope +#define PTHREAD_SCOPE_SYSTEM 0 +#define PTHREAD_SCOPE_PROCESS 1 + +// Values for pthread_attr_{get,set}inheritsched +#define PTHREAD_INHERIT_SCHED 0 +#define PTHREAD_EXPLICIT_SCHED 1 + +// values for pthread_{get,set}canceltype(). +#define PTHREAD_CANCEL_DEFERRED 0 +#define PTHREAD_CANCEL_ASYNCHRONOUS 1 + +// values for pthread_{get,set}cancelstate(). +#define PTHREAD_CANCEL_ENABLE 0 +#define PTHREAD_CANCEL_DISABLE 1 + +// values for pthread_mutexattr_{get,set}type(). +#define PTHREAD_MUTEX_DEFAULT __MLIBC_THREAD_MUTEX_DEFAULT +#define PTHREAD_MUTEX_NORMAL __MLIBC_THREAD_MUTEX_NORMAL +#define PTHREAD_MUTEX_ERRORCHECK __MLIBC_THREAD_MUTEX_ERRORCHECK +#define PTHREAD_MUTEX_RECURSIVE __MLIBC_THREAD_MUTEX_RECURSIVE + +// values for pthread_mutexattr_{get,set}robust(). +#define PTHREAD_MUTEX_STALLED __MLIBC_THREAD_MUTEX_STALLED +#define PTHREAD_MUTEX_ROBUST __MLIBC_THREAD_MUTEX_ROBUST + +// values for pthread_mutexattr_{get,set}pshared(). +#define PTHREAD_PROCESS_PRIVATE __MLIBC_THREAD_PROCESS_PRIVATE +#define PTHREAD_PROCESS_SHARED __MLIBC_THREAD_PROCESS_SHARED + +// Values for pthread_mutexattr_{get,set}protocol() +#define PTHREAD_PRIO_NONE __MLIBC_THREAD_PRIO_NONE +#define PTHREAD_PRIO_INHERIT __MLIBC_THREAD_PRIO_INHERIT +#define PTHREAD_PRIO_PROTECT __MLIBC_THREAD_PRIO_PROTECT + +#define PTHREAD_ONCE_INIT {0} +#define PTHREAD_COND_INITIALIZER {0} +#define PTHREAD_MUTEX_INITIALIZER {0, 0, 0, 0} +#define PTHREAD_RWLOCK_INITIALIZER {0, 0, 0} + +#define PTHREAD_CANCELED ((void*) -1) + +#define PTHREAD_BARRIER_SERIAL_THREAD -1 + +// values for pthread_key +#define PTHREAD_DESTRUCTOR_ITERATIONS 8 + +#define PTHREAD_INHERIT_SCHED 0 +#define PTHREAD_EXPLICIT_SCHED 1 + +#define PTHREAD_STACK_MIN 16384 + +#define PTHREAD_ATTR_NO_SIGMASK_NP (-1) + +// TODO: move to own file and include in sys/types.h +typedef struct __mlibc_threadattr pthread_attr_t; + +typedef uintptr_t pthread_key_t; + +struct __mlibc_once { + unsigned int __mlibc_done; +}; +typedef struct __mlibc_once pthread_once_t; + +typedef struct __mlibc_mutexattr pthread_mutexattr_t; + +typedef struct __mlibc_mutex pthread_mutex_t; + +typedef struct __mlibc_condattr pthread_condattr_t; + +typedef struct __mlibc_cond pthread_cond_t; + +struct __mlibc_barrierattr_struct { + int __mlibc_pshared; +}; +typedef struct __mlibc_barrierattr_struct pthread_barrierattr_t; + +struct __mlibc_barrier { + unsigned int __mlibc_waiting; + unsigned int __mlibc_inside; + unsigned int __mlibc_count; + unsigned int __mlibc_seq; + unsigned int __mlibc_flags; +}; +typedef struct __mlibc_barrier pthread_barrier_t; + +struct __mlibc_fair_rwlock { + unsigned int __mlibc_m; // Mutex. + unsigned int __mlibc_rc; // Reader count (not reference count). + unsigned int __mlibc_flags; +}; +typedef struct __mlibc_fair_rwlock pthread_rwlock_t; + +struct __mlibc_rwlockattr { + int __mlibc_pshared; +}; +typedef struct __mlibc_rwlockattr pthread_rwlockattr_t; + +#ifndef __MLIBC_ABI_ONLY + +// ---------------------------------------------------------------------------- +// pthread_attr and pthread functions. +// ---------------------------------------------------------------------------- + +// pthread_attr functions. +int pthread_attr_init(pthread_attr_t *); +int pthread_attr_destroy(pthread_attr_t *); + +int pthread_attr_getdetachstate(const pthread_attr_t *, int *); +int pthread_attr_setdetachstate(pthread_attr_t *, int); + +int pthread_attr_getstacksize(const pthread_attr_t *__restrict, size_t *__restrict); +int pthread_attr_setstacksize(pthread_attr_t *, size_t); + +int pthread_attr_getstackaddr(const pthread_attr_t *, void **); +int pthread_attr_setstackaddr(pthread_attr_t *, void *); + +int pthread_attr_getstack(const pthread_attr_t *, void **, size_t*); +int pthread_attr_setstack(pthread_attr_t *, void *, size_t); + +int pthread_attr_getguardsize(const pthread_attr_t *__restrict, size_t *__restrict); +int pthread_attr_setguardsize(pthread_attr_t *, size_t); + +int pthread_attr_getscope(const pthread_attr_t *, int*); +int pthread_attr_setscope(pthread_attr_t *, int); + +int pthread_attr_getschedparam(const pthread_attr_t *__restrict, struct sched_param *__restrict); +int pthread_attr_setschedparam(pthread_attr_t *__restrict, const struct sched_param *__restrict); + +int pthread_attr_getschedpolicy(const pthread_attr_t *__restrict, int *__restrict); +int pthread_attr_setschedpolicy(pthread_attr_t *__restrict, int); + +int pthread_attr_getinheritsched(const pthread_attr_t *__restrict, int *__restrict); +int pthread_attr_setinheritsched(pthread_attr_t *__restrict, int); + +int pthread_attr_getschedparam(const pthread_attr_t *__restrict, struct sched_param *__restrict); +int pthread_attr_setschedparam(pthread_attr_t *__restrict, const struct sched_param *__restrict); + +#if __MLIBC_LINUX_OPTION +int pthread_attr_getaffinity_np(const pthread_attr_t *__restrict, size_t, cpu_set_t *__restrict); +int pthread_attr_setaffinity_np(pthread_attr_t *__restrict, size_t, const cpu_set_t *__restrict); + +int pthread_attr_getsigmask_np(const pthread_attr_t *__restrict, sigset_t *__restrict); +int pthread_attr_setsigmask_np(pthread_attr_t *__restrict, const sigset_t *__restrict); + +int pthread_getattr_np(pthread_t, pthread_attr_t *); + +int pthread_getaffinity_np(pthread_t thread, size_t cpusetsize, cpu_set_t *cpuset); +int pthread_setaffinity_np(pthread_t thread, size_t cpusetsize, const cpu_set_t *cpuset); +#endif /* __MLIBC_LINUX_OPTION */ + +// pthread functions. +int pthread_create(pthread_t *__restrict, const pthread_attr_t *__restrict, + void *(*) (void *), void *__restrict); +pthread_t pthread_self(void); +int pthread_equal(pthread_t, pthread_t); +__attribute__ ((__noreturn__)) void pthread_exit(void *); + +int pthread_join(pthread_t, void **); +int pthread_detach(pthread_t); + +void pthread_cleanup_push(void (*) (void *), void *); +void pthread_cleanup_pop(int); + +int pthread_setname_np(pthread_t, const char *); +int pthread_getname_np(pthread_t, char *, size_t); + +int pthread_attr_setstack(pthread_attr_t *, void *, size_t); +int pthread_attr_getstack(const pthread_attr_t *, void **, size_t *); + +int pthread_getattr_np(pthread_t, pthread_attr_t *); + +int pthread_setschedparam(pthread_t, int, const struct sched_param *); +int pthread_getschedparam(pthread_t, int *, struct sched_param *); + +int pthread_setcanceltype(int, int *); +int pthread_setcancelstate(int, int *); +void pthread_testcancel(void); +int pthread_cancel(pthread_t); + +int pthread_atfork(void (*) (void), void (*) (void), void (*) (void)); + +// ---------------------------------------------------------------------------- +// pthread_key functions. +// ---------------------------------------------------------------------------- + +int pthread_key_create(pthread_key_t *, void (*) (void *)); +int pthread_key_delete(pthread_key_t); + +void *pthread_getspecific(pthread_key_t); +int pthread_setspecific(pthread_key_t, const void *); + +// ---------------------------------------------------------------------------- +// pthread_once functions. +// ---------------------------------------------------------------------------- + +int pthread_once(pthread_once_t *, void (*) (void)); + +// ---------------------------------------------------------------------------- +// pthread_mutexattr and pthread_mutex functions. +// ---------------------------------------------------------------------------- + +// pthread_mutexattr functions +int pthread_mutexattr_init(pthread_mutexattr_t *); +int pthread_mutexattr_destroy(pthread_mutexattr_t *); + +int pthread_mutexattr_gettype(const pthread_mutexattr_t *__restrict, int *__restrict); +int pthread_mutexattr_settype(pthread_mutexattr_t *, int); + +int pthread_mutexattr_getrobust(const pthread_mutexattr_t *__restrict, int *__restrict); +int pthread_mutexattr_setrobust(pthread_mutexattr_t *, int); + +int pthread_mutexattr_getpshared(const pthread_mutexattr_t *, int *); +int pthread_mutexattr_setpshared(pthread_mutexattr_t *, int); + +int pthread_mutexattr_getprotocol(const pthread_mutexattr_t *__restrict, int *__restrict); +int pthread_mutexattr_setprotocol(pthread_mutexattr_t *, int); + +int pthread_mutexattr_getprioceiling(const pthread_mutexattr_t *, int *); +int pthread_mutexattr_setprioceiling(pthread_mutexattr_t *, int); + +// pthread_mutex functions +int pthread_mutex_init(pthread_mutex_t *__restrict, const pthread_mutexattr_t *__restrict); +int pthread_mutex_destroy(pthread_mutex_t *); + +int pthread_mutex_lock(pthread_mutex_t *); +int pthread_mutex_trylock(pthread_mutex_t *); +int pthread_mutex_timedlock(pthread_mutex_t *__restrict, + const struct timespec *__restrict); +int pthread_mutex_unlock(pthread_mutex_t *); + +int pthread_mutex_consistent(pthread_mutex_t *); + +// ---------------------------------------------------------------------------- +// pthread_condattr and pthread_cond functions. +// ---------------------------------------------------------------------------- + +int pthread_condattr_init(pthread_condattr_t *); +int pthread_condattr_destroy(pthread_condattr_t *); + +int pthread_condattr_getclock(const pthread_condattr_t *__restrict, clockid_t *__restrict); +int pthread_condattr_setclock(pthread_condattr_t *, clockid_t); + +int pthread_condattr_getpshared(const pthread_condattr_t *__restrict, int *__restrict); +int pthread_condattr_setpshared(pthread_condattr_t *, int); + +int pthread_cond_init(pthread_cond_t *__restrict, const pthread_condattr_t *__restrict); +int pthread_cond_destroy(pthread_cond_t *); + +int pthread_cond_wait(pthread_cond_t *__restrict, pthread_mutex_t *__restrict); +int pthread_cond_timedwait(pthread_cond_t *__restrict, pthread_mutex_t *__restrict, + const struct timespec *__restrict); +int pthread_cond_signal(pthread_cond_t *); +int pthread_cond_broadcast(pthread_cond_t *); + +// ---------------------------------------------------------------------------- +// pthread_barrierattr and pthread_barrier functions. +// ---------------------------------------------------------------------------- + +int pthread_barrierattr_init(pthread_barrierattr_t *); +int pthread_barrierattr_destroy(pthread_barrierattr_t *); +int pthread_barrierattr_setpshared(pthread_barrierattr_t *, int); +int pthread_barrierattr_getpshared(const pthread_barrierattr_t *__restrict, + int *__restrict); + +int pthread_barrier_init(pthread_barrier_t *__restrict, const pthread_barrierattr_t *__restrict, + unsigned int); +int pthread_barrier_destroy(pthread_barrier_t *); + +int pthread_barrier_wait(pthread_barrier_t *); + +// ---------------------------------------------------------------------------- +// pthread_wrlockattr and pthread_rwlock functions. +// ---------------------------------------------------------------------------- + +int pthread_rwlockattr_init(pthread_rwlockattr_t *); +int pthread_rwlockattr_destroy(pthread_rwlockattr_t *); +int pthread_rwlockattr_setpshared(pthread_rwlockattr_t *, int); +int pthread_rwlockattr_getpshared(const pthread_rwlockattr_t *__restrict, + int *__restrict); + +int pthread_rwlock_init(pthread_rwlock_t *__restrict, const pthread_rwlockattr_t *__restrict); +int pthread_rwlock_destroy(pthread_rwlock_t *); +int pthread_rwlock_trywrlock(pthread_rwlock_t *); +int pthread_rwlock_wrlock(pthread_rwlock_t *); +int pthread_rwlock_tryrdlock(pthread_rwlock_t *); +int pthread_rwlock_rdlock(pthread_rwlock_t *); +int pthread_rwlock_unlock(pthread_rwlock_t *); + +int pthread_getcpuclockid(pthread_t, clockid_t *); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif // _PTHREAD_H + diff --git a/lib/mlibc/options/posix/include/pwd.h b/lib/mlibc/options/posix/include/pwd.h new file mode 100644 index 0000000..b885f57 --- /dev/null +++ b/lib/mlibc/options/posix/include/pwd.h @@ -0,0 +1,45 @@ + +#ifndef _PWD_H +#define _PWD_H + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +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; +}; + +#define NSS_BUFLEN_PASSWD 512 + +#ifndef __MLIBC_ABI_ONLY + +void endpwent(void); +struct passwd *getpwent(void); +struct passwd *getpwnam(const char *); +int getpwnam_r(const char *, struct passwd *, char *, size_t, struct passwd **); +struct passwd *getpwuid(uid_t); +int getpwuid_r(uid_t, struct passwd *, char *, size_t, struct passwd **); +void setpwent(void); +int putpwent(const struct passwd *, FILE *); +struct passwd *fgetpwent(FILE *); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif // _PWD_H + diff --git a/lib/mlibc/options/posix/include/regex.h b/lib/mlibc/options/posix/include/regex.h new file mode 100644 index 0000000..b7f0a46 --- /dev/null +++ b/lib/mlibc/options/posix/include/regex.h @@ -0,0 +1,66 @@ +#ifndef _REGEX_H +#define _REGEX_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +typedef ptrdiff_t regoff_t; + +typedef struct re_pattern_buffer { + size_t re_nsub; + void *__opaque, *__padding[4]; + size_t __nsub2; + char __padding2; +} regex_t; + +typedef struct { + regoff_t rm_so; + regoff_t rm_eo; +} regmatch_t; + +// Flags for regcomp(). +#define REG_EXTENDED 1 +#define REG_ICASE 2 +#define REG_NEWLINE 4 +#define REG_NOSUB 8 + +// Flags for regexec(). +#define REG_NOTBOL 1 +#define REG_NOTEOL 2 + +// Errors for regcomp() and regexec(). +#define REG_OK 0 +#define REG_NOMATCH 1 +#define REG_BADPAT 2 +#define REG_ECOLLATE 3 +#define REG_ECTYPE 4 +#define REG_EESCAPE 5 +#define REG_ESUBREG 6 +#define REG_EBRACK 7 +#define REG_EPAREN 8 +#define REG_EBRACE 9 +#define REG_BADBR 10 +#define REG_ERANGE 11 +#define REG_ESPACE 12 +#define REG_BADRPT 13 + +// Obsolete in POSIX. +#define REG_ENOSYS -1 + +#ifndef __MLIBC_ABI_ONLY + +int regcomp(regex_t *__restrict, const char *__restrict, int); +int regexec(const regex_t *__restrict, const char *__restrict, size_t, regmatch_t *__restrict, int); +size_t regerror(int, const regex_t *__restrict, char *__restrict, size_t); +void regfree(regex_t *); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib/mlibc/options/posix/include/sched.h b/lib/mlibc/options/posix/include/sched.h new file mode 100644 index 0000000..739d91e --- /dev/null +++ b/lib/mlibc/options/posix/include/sched.h @@ -0,0 +1,49 @@ + +#ifndef _SCHED_H +#define _SCHED_H + +#include +#include +#include +#include + +// MISSING: time_t, struct timespec + +// MISSING: POSIX [PS], [SS] and [TSP] options + +#ifdef __cplusplus +extern "C" { +#endif + +#if __MLIBC_LINUX_OPTION +#include +#include +#endif + +#define SCHED_OTHER 0 +#define SCHED_FIFO 1 +#define SCHED_RR 2 +#define SCHED_BATCH 3 +#define SCHED_IDLE 5 +#define SCHED_DEADLINE 6 +#define SCHED_RESET_ON_FORK 0x40000000 + +#ifndef __MLIBC_ABI_ONLY + +int sched_yield(void); + +int sched_get_priority_max(int policy); +int sched_get_priority_min(int policy); + +int sched_setscheduler(pid_t pid, int policy, const struct sched_param *param); + +int sched_getparam(pid_t pid, struct sched_param *param); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif // _SCHED_H + diff --git a/lib/mlibc/options/posix/include/search.h b/lib/mlibc/options/posix/include/search.h new file mode 100644 index 0000000..02e1913 --- /dev/null +++ b/lib/mlibc/options/posix/include/search.h @@ -0,0 +1,37 @@ + +#ifndef _SEARCH_H +#define _SEARCH_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + preorder, + postorder, + endorder, + leaf +} VISIT; + +#ifndef __MLIBC_ABI_ONLY + +void *tsearch(const void *, void **, int(*compar)(const void *, const void *)); +void *tfind(const void *, void *const *, int (*compar)(const void *, const void *)); +void *tdelete(const void *, void **, int(*compar)(const void *, const void *)); +void twalk(const void *, void (*action)(const void *, VISIT, int)); +void tdestroy(void *, void (*free_node)(void *)); + +void *lsearch(const void *key, void *base, size_t *nelp, size_t width, + int (*compar)(const void *, const void *)); +void *lfind(const void *key, const void *base, size_t *nelp, + size_t width, int (*compar)(const void *, const void *)); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif // _SEARCH_H diff --git a/lib/mlibc/options/posix/include/semaphore.h b/lib/mlibc/options/posix/include/semaphore.h new file mode 100644 index 0000000..877527f --- /dev/null +++ b/lib/mlibc/options/posix/include/semaphore.h @@ -0,0 +1,37 @@ +#ifndef _SEMAPHORE_H +#define _SEMAPHORE_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +#define SEM_VALUE_MAX 0x7FFFFFFF +#define SEM_FAILED ((sem_t *) 0) + +typedef struct sem_ { + unsigned int __mlibc_count; +} sem_t; + +#ifndef __MLIBC_ABI_ONLY + +int sem_init(sem_t *sem, int pshared, unsigned int initial_count); +sem_t *sem_open(const char *, int, ...); +int sem_close(sem_t *sem); +int sem_unlink(const char *); +int sem_destroy(sem_t *sem); +int sem_wait(sem_t *sem); +int sem_trywait(sem_t *sem); +int sem_timedwait(sem_t *sem, const struct timespec *abstime); +int sem_post(sem_t *sem); +int sem_getvalue(sem_t *sem, int *sval); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif //_SEMAPHORE_H diff --git a/lib/mlibc/options/posix/include/spawn.h b/lib/mlibc/options/posix/include/spawn.h new file mode 100644 index 0000000..3ab2004 --- /dev/null +++ b/lib/mlibc/options/posix/include/spawn.h @@ -0,0 +1,82 @@ + +#ifndef _SPAWN_H +#define _SPAWN_H + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + int __flags; + pid_t __pgrp; + sigset_t __def, __mask; + int __prio, __pol; + void *__fn; + char __pad[64 - sizeof(void *)]; +} posix_spawnattr_t; + +typedef struct { + int __pad0[2]; + void *__actions; + int __pad[16]; +} posix_spawn_file_actions_t; + +// MISSIG: sigset_t + +struct sched_param; + +#define POSIX_SPAWN_RESETIDS 1 +#define POSIX_SPAWN_SETPGROUP 2 +#define POSIX_SPAWN_SETSIGDEF 4 +#define POSIX_SPAWN_SETSIGMASK 8 +#define POSIX_SPAWN_SETSCHEDPARAM 16 +#define POSIX_SPAWN_SETSCHEDULER 32 +#define POSIX_SPAWN_USEVFORK 64 +#define POSIX_SPAWN_SETSID 128 + +#ifndef __MLIBC_ABI_ONLY + +int posix_spawn(pid_t *__restrict pid, const char *__restrict path, + const posix_spawn_file_actions_t *file_actions, + const posix_spawnattr_t *__restrict attrs, + char *const argv[], char *const envp[]); + +int posix_spawnattr_init(posix_spawnattr_t *attr); +int posix_spawnattr_destroy(posix_spawnattr_t *attr); +int posix_spawnattr_setflags(posix_spawnattr_t *attr, short flags); +int posix_spawnattr_setsigdefault(posix_spawnattr_t *__restrict attr, + const sigset_t *__restrict sigdefault); +int posix_spawnattr_setschedparam(posix_spawnattr_t *__restrict attr, + const struct sched_param *__restrict schedparam); +int posix_spawnattr_setschedpolicy(posix_spawnattr_t *attr, int schedpolicy); +int posix_spawnattr_setsigmask(posix_spawnattr_t *__restrict attr, + const sigset_t *__restrict sigmask); +int posix_spawnattr_setpgroup(posix_spawnattr_t *attr, pid_t pgroup); +int posix_spawn_file_actions_init(posix_spawn_file_actions_t *file_actions); +int posix_spawn_file_actions_destroy(posix_spawn_file_actions_t *file_actions); +int posix_spawn_file_actions_adddup2(posix_spawn_file_actions_t *file_actions, + int fildes, int newfildes); +int posix_spawn_file_actions_addclose(posix_spawn_file_actions_t *file_actions, + int fildes); +int posix_spawn_file_actions_addopen(posix_spawn_file_actions_t *__restrict file_actions, + int fildes, const char *__restrict path, int oflag, mode_t mode); +int posix_spawnp(pid_t *__restrict pid, const char *__restrict file, + const posix_spawn_file_actions_t *file_actions, + const posix_spawnattr_t *__restrict attrp, + char *const argv[], char *const envp[]); + +// MISSING: all other functions + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif // SPAWN_H + diff --git a/lib/mlibc/options/posix/include/strings.h b/lib/mlibc/options/posix/include/strings.h new file mode 100644 index 0000000..a21c3d7 --- /dev/null +++ b/lib/mlibc/options/posix/include/strings.h @@ -0,0 +1,32 @@ + +#ifndef _STRINGS_H +#define _STRINGS_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +char *index (const char *s, int c); +char *rindex(const char *s, int c); + +int ffs(int word); +int strcasecmp(const char *a, const char *b); +int strncasecmp(const char *a, const char *b, size_t size); + +/* Marked as obsolete in posix 2008 but used by at least tracker */ +int bcmp(const void *s1, const void *s2, size_t n); +void bcopy(const void *s1, void *s2, size_t n); +void bzero(void *s, size_t n); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif // _STRINGS_H + diff --git a/lib/mlibc/options/posix/include/sys/file.h b/lib/mlibc/options/posix/include/sys/file.h new file mode 100644 index 0000000..add43d3 --- /dev/null +++ b/lib/mlibc/options/posix/include/sys/file.h @@ -0,0 +1,25 @@ + +#ifndef _SYS_FILE_H +#define _SYS_FILE_H + +#define LOCK_SH 1 +#define LOCK_EX 2 +#define LOCK_NB 4 +#define LOCK_UN 8 + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +int flock(int, int); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif // _SYS_FILE_H + diff --git a/lib/mlibc/options/posix/include/sys/ipc.h b/lib/mlibc/options/posix/include/sys/ipc.h new file mode 100644 index 0000000..8318dde --- /dev/null +++ b/lib/mlibc/options/posix/include/sys/ipc.h @@ -0,0 +1,53 @@ +#ifndef _SYS_IPC_H +#define _SYS_IPC_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define IPC_CREAT 01000 +#define IPC_EXCL 02000 +#define IPC_NOWAIT 04000 + +#define IPC_RMID 0 +#define IPC_SET 1 +#define IPC_STAT 2 +#define IPC_INFO 3 + +#define IPC_PRIVATE ((key_t) 0) + +#if defined(__aarch64__) || defined(__i386__) +#define IPC_64 0x100 +#elif defined(__x86_64__) || (defined(__riscv) && __riscv_xlen == 64) +#define IPC_64 0 +#else +#error "Unsupported arch!" +#endif + +typedef int key_t; + +struct ipc_perm { + key_t __ipc_perm_key; + uid_t uid; + gid_t gid; + uid_t cuid; + gid_t cgid; + mode_t mode; + int __ipc_perm_seq; +}; + +#ifndef __MLIBC_ABI_ONLY + +key_t ftok(const char *, int); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib/mlibc/options/posix/include/sys/mman.h b/lib/mlibc/options/posix/include/sys/mman.h new file mode 100644 index 0000000..784878e --- /dev/null +++ b/lib/mlibc/options/posix/include/sys/mman.h @@ -0,0 +1,47 @@ +#ifndef _SYS_MMAN_H +#define _SYS_MMAN_H + +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +void *mmap(void *, size_t, int, int, int, off_t); +int mprotect(void *, size_t, int); +int munmap(void *, size_t); + +int mlock(const void *, size_t); +int mlockall(int); +int munlock(const void *, size_t); +int munlockall(void); + +int posix_madvise(void *, size_t, int); +int msync(void *, size_t, int); + +int shm_open(const char *, int, mode_t); +int shm_unlink(const char *); + +// Linux extension: +void *mremap(void *, size_t, size_t, int, ...); +int remap_file_pages(void *, size_t, int, size_t, int); + +#if __MLIBC_LINUX_OPTION +int memfd_create(const char *, unsigned int); +int madvise(void *, size_t, int); +int mincore(void *, size_t, unsigned char *); +#endif /* __MLIBC_LINUX_OPTION */ + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif // _SYS_MMAN_H diff --git a/lib/mlibc/options/posix/include/sys/msg.h b/lib/mlibc/options/posix/include/sys/msg.h new file mode 100644 index 0000000..d602f76 --- /dev/null +++ b/lib/mlibc/options/posix/include/sys/msg.h @@ -0,0 +1,27 @@ +#ifndef _SYS_MSG_H +#define _SYS_MSG_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +int msgget(key_t, int); + +int msgctl(int msqid, int cmd, struct msqid_ds *buf); + +ssize_t msgrcv(int, void *, size_t, long, int); +int msgsnd(int, const void *, size_t, int); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif // _SYS_MSG_H diff --git a/lib/mlibc/options/posix/include/sys/param.h b/lib/mlibc/options/posix/include/sys/param.h new file mode 100644 index 0000000..9bb4552 --- /dev/null +++ b/lib/mlibc/options/posix/include/sys/param.h @@ -0,0 +1,36 @@ + +#ifndef _SYS_PARAM_H +#define _SYS_PARAM_H + +#include +#include + +#define NBBY CHAR_BIT +#define NGROUPS NGROUPS_MAX + +// Report the same value as Linux here. +#define MAXNAMLEN 255 +#define MAXPATHLEN 4096 +#define HOST_NAME_MAX 64 +#define MAXSYMLINKS 20 +#define MAXHOSTNAMELEN HOST_NAME_MAX + +#ifdef __cplusplus +extern "C" { +#endif + +#undef MIN +#define MIN(a,b) (((a) < (b)) ? (a) : (b)) +#undef MAX +#define MAX(a,b) (((a) > (b)) ? (a) : (b)) + +#define howmany(x, y) (((x) + ((y) - 1)) / (y)) + +#define roundup(x, y) ((((x) + ((y) - 1)) / (y)) * (y)) + +#ifdef __cplusplus +} +#endif + +#endif // _SYS_PARAM_H + diff --git a/lib/mlibc/options/posix/include/sys/poll.h b/lib/mlibc/options/posix/include/sys/poll.h new file mode 100644 index 0000000..3edecab --- /dev/null +++ b/lib/mlibc/options/posix/include/sys/poll.h @@ -0,0 +1,37 @@ +#ifndef _SYS_POLL_H +#define _SYS_POLL_H + +#include +#include +#include +#include +#include +#include + +typedef __mlibc_size nfds_t; + +#ifdef __cplusplus +extern "C" { +#endif + +struct pollfd { + int fd; + short events; + short revents; +}; + +#ifndef __MLIBC_ABI_ONLY + +int poll(struct pollfd *, nfds_t, int); + +#if __MLIBC_LINUX_OPTION +int ppoll(struct pollfd *fds, nfds_t nfds, const struct timespec *timeout_ts, const sigset_t *sigmask); +#endif // __MLIBC_LINUX_OPTION + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif // _SYS_POLL_H diff --git a/lib/mlibc/options/posix/include/sys/resource.h b/lib/mlibc/options/posix/include/sys/resource.h new file mode 100644 index 0000000..c5453e2 --- /dev/null +++ b/lib/mlibc/options/posix/include/sys/resource.h @@ -0,0 +1,52 @@ +#ifndef _SYS_RESOURCE_H +#define _SYS_RESOURCE_H + +#include +#include +#include +#include +#include +#include + +#define PRIO_PROCESS 1 +#define PRIO_PGRP 2 +#define PRIO_USER 3 + +#define PRIO_MIN (-20) +#define PRIO_MAX 20 + +#define RLIM_INFINITY ((rlim_t)-1) +#define RLIM_SAVED_MAX ((rlim_t)-1) +#define RLIM_SAVED_CUR ((rlim_t)-1) + +#define RLIM_NLIMITS RLIMIT_NLIMITS + +#ifdef __cplusplus +extern "C" { +#endif + +typedef unsigned long rlim_t; + +struct rlimit { + rlim_t rlim_cur; + rlim_t rlim_max; +}; + +#ifndef __MLIBC_ABI_ONLY + +int getpriority(int, id_t); +int setpriority(int, id_t, int); + +int getrusage(int, struct rusage *); +int getrlimit(int, struct rlimit *); +int setrlimit(int, const struct rlimit *); + +int prlimit(pid_t pid, int resource, const struct rlimit *new_limits, struct rlimit *old_limits); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif // _SYS_RESOURCE_H diff --git a/lib/mlibc/options/posix/include/sys/select.h b/lib/mlibc/options/posix/include/sys/select.h new file mode 100644 index 0000000..85a15b0 --- /dev/null +++ b/lib/mlibc/options/posix/include/sys/select.h @@ -0,0 +1,49 @@ + +#ifndef _SYS_SELECT_H +#define _SYS_SELECT_H + +#include + +#include +#include +#include +#include +#include + +#define FD_SETSIZE 1024 + +#ifdef __cplusplus +extern "C" { +#endif + +typedef long int __fd_mask; +#define __NFDBITS (8 * (int) sizeof (__fd_mask)) + +typedef __fd_mask fd_mask; +#define NFDBITS __NFDBITS + +#ifndef __MLIBC_ABI_ONLY + +void __FD_CLR(int fd, fd_set *); +int __FD_ISSET(int fd, fd_set *); +void __FD_SET(int fd, fd_set *); +void __FD_ZERO(fd_set *); + +#define FD_CLR(fd, set) __FD_CLR(fd, set) +#define FD_ISSET(fd, set) __FD_ISSET(fd, set) +#define FD_SET(fd, set) __FD_SET(fd, set) +#define FD_ZERO(set) __FD_ZERO(set) + +int select(int, fd_set *__restrict, fd_set *__restrict, fd_set *__restrict, + struct timeval *__restrict); +int pselect(int, fd_set *, fd_set *, fd_set *, const struct timespec *, + const sigset_t *); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif // _SYS_SELECT_H + diff --git a/lib/mlibc/options/posix/include/sys/sem.h b/lib/mlibc/options/posix/include/sys/sem.h new file mode 100644 index 0000000..cb3516a --- /dev/null +++ b/lib/mlibc/options/posix/include/sys/sem.h @@ -0,0 +1,44 @@ +#ifndef _SYS_SEM_H +#define _SYS_SEM_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define GETALL 13 +#define SETVAL 16 +#define SETALL 17 + +#define SEM_UNDO 0x1000 + +struct sembuf { + unsigned short int sem_num; + short int sem_op; + short int sem_flg; +}; + +struct semid_ds { + struct ipc_perm sem_perm; + time_t sem_otime; + time_t sem_ctime; + + unsigned long sem_nsems; +}; + +#ifndef __MLIBC_ABI_ONLY + +int semget(key_t, int, int); +int semop(int, struct sembuf *, size_t); +int semctl(int, int, int, ...); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif // _SYS_SEM_H diff --git a/lib/mlibc/options/posix/include/sys/shm.h b/lib/mlibc/options/posix/include/sys/shm.h new file mode 100644 index 0000000..3767ced --- /dev/null +++ b/lib/mlibc/options/posix/include/sys/shm.h @@ -0,0 +1,83 @@ +#ifndef _SYS_SHM_H +#define _SYS_SHM_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include +#include + +#include + +#define SHM_R 0400 +#define SHM_W 0200 + +#define SHM_RDONLY 010000 +#define SHM_RND 020000 +#define SHM_REMAP 040000 +#define SHM_EXEC 0100000 + +#define SHM_LOCK 11 +#define SHM_UNLOCK 12 +#define SHM_STAT 13 +#define SHM_INFO 14 +#define SHM_STAT_ANY 15 +#define SHM_DEST 01000 +#define SHM_LOCKED 02000 +#define SHM_HUGETLB 04000 +#define SHM_NORESERVE 010000 + +#define SHM_HUGE_SHIFT 26 +#define SHM_HUGE_MASK 0x3f +#define SHM_HUGE_64KB (16 << 26) +#define SHM_HUGE_512KB (19 << 26) +#define SHM_HUGE_1MB (20 << 26) +#define SHM_HUGE_2MB (21 << 26) +#define SHM_HUGE_8MB (23 << 26) +#define SHM_HUGE_16MB (24 << 26) +#define SHM_HUGE_32MB (25 << 26) +#define SHM_HUGE_256MB (28 << 26) +#define SHM_HUGE_512MB (29 << 26) +#define SHM_HUGE_1GB (30 << 26) +#define SHM_HUGE_2GB (31 << 26) +#define SHM_HUGE_16GB (34U << 26) + +typedef unsigned long shmatt_t; + +struct shmid_ds { + struct ipc_perm shm_perm; + size_t shm_segsz; + time_t shm_atime; + time_t shm_dtime; + time_t shm_ctime; + pid_t shm_cpid; + pid_t shm_lpid; + unsigned long shm_nattch; +}; + +struct shminfo { + unsigned long shmmax; + unsigned long shmmin; + unsigned long shmmni; + unsigned long shmseg; + unsigned long shmall; + unsigned long __unused[4]; +}; + +#ifndef __MLIBC_ABI_ONLY + +void *shmat(int, const void *, int); +int shmctl(int, int, struct shmid_ds *); +int shmdt(const void *); +int shmget(key_t, size_t, int); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif // _SYS_SHM_H diff --git a/lib/mlibc/options/posix/include/sys/socket.h b/lib/mlibc/options/posix/include/sys/socket.h new file mode 100644 index 0000000..9552f93 --- /dev/null +++ b/lib/mlibc/options/posix/include/sys/socket.h @@ -0,0 +1,105 @@ + +#ifndef _SOCKET_H +#define _SOCKET_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct sockaddr { + sa_family_t sa_family; + char sa_data[14]; +}; + +// Control message format: +// The offsets marked with ^ are aligned to alignof(size_t). +// +// |---HEADER---|---DATA---|---PADDING---|---HEADER---|... +// ^ ^ ^ +// |---------CMSG_LEN------| +// |---------------CMSG_SPACE------------| + +// Auxiliary macro. While there is basically no reason for applications +// to use this, it is exported by glibc. +#define CMSG_ALIGN(s) (((s) + __alignof__(size_t) - 1) & \ + ~(__alignof__(size_t) - 1)) + +// Basic macros to return content and padding size of a control message. +#define CMSG_LEN(s) (CMSG_ALIGN(sizeof(struct cmsghdr)) + (s)) +#define CMSG_SPACE(s) (CMSG_ALIGN(sizeof(struct cmsghdr)) + CMSG_ALIGN(s)) + +// Provides access to the data of a control message. +#define CMSG_DATA(c) ((char *)(c) + CMSG_ALIGN(sizeof(struct cmsghdr))) + +#define __MLIBC_CMSG_NEXT(c) ((char *)(c) + CMSG_ALIGN((c)->cmsg_len)) +#define __MLIBC_MHDR_LIMIT(m) ((char *)(m)->msg_control + (m)->msg_controllen) + +// For parsing control messages only. +// Returns a pointer to the first header or nullptr if there is none. +#define CMSG_FIRSTHDR(m) ((size_t)(m)->msg_controllen <= sizeof(struct cmsghdr) \ + ? (struct cmsghdr *)0 : (struct cmsghdr *) (m)->msg_control) + +// For parsing control messages only. +// Returns a pointer to the next header or nullptr if there is none. +#define CMSG_NXTHDR(m, c) \ + ((c)->cmsg_len < sizeof(struct cmsghdr) || \ + (ptrdiff_t)(sizeof(struct cmsghdr) + CMSG_ALIGN((c)->cmsg_len)) \ + >= __MLIBC_MHDR_LIMIT(m) - (char *)(c) \ + ? (struct cmsghdr *)0 : (struct cmsghdr *)__MLIBC_CMSG_NEXT(c)) + +struct linger{ + int l_onoff; + int l_linger; +}; + +struct ucred { + pid_t pid; + uid_t uid; + gid_t gid; +}; + +#ifndef __MLIBC_ABI_ONLY + +int accept(int, struct sockaddr *__restrict, socklen_t *__restrict); +int accept4(int, struct sockaddr *__restrict, socklen_t *__restrict, int); +int bind(int, const struct sockaddr *, socklen_t); +int connect(int, const struct sockaddr *, socklen_t); +int getpeername(int, struct sockaddr *__restrict, socklen_t *__restrict); +int getsockname(int, struct sockaddr *__restrict, socklen_t *__restrict); +int getsockopt(int, int, int, void *__restrict, socklen_t *__restrict); +int listen(int, int); +ssize_t recv(int, void *, size_t, int); +ssize_t recvfrom(int, void *__restrict, size_t, int, struct sockaddr *__restrict, socklen_t *__restrict); +ssize_t recvmsg(int, struct msghdr *, int); +ssize_t send(int, const void *, size_t, int); +ssize_t sendmsg(int, const struct msghdr *, int); +ssize_t sendto(int, const void *, size_t, int, const struct sockaddr *, socklen_t); +int recvmmsg(int sockfd, struct mmsghdr *msgvec, unsigned int vlen, int flags, struct timespec *timeout); +int sendmmsg(int sockfd, struct mmsghdr *msgvec, unsigned int vlen, int flags); +int setsockopt(int, int, int, const void *, socklen_t); +int shutdown(int, int); +int sockatmark(int); +int socket(int, int, int); +int socketpair(int, int, int, int [2]); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif // _UNISTD_H + diff --git a/lib/mlibc/options/posix/include/sys/stat.h b/lib/mlibc/options/posix/include/sys/stat.h new file mode 100644 index 0000000..7159a77 --- /dev/null +++ b/lib/mlibc/options/posix/include/sys/stat.h @@ -0,0 +1,37 @@ + +#ifndef _SYS_STAT_H +#define _SYS_STAT_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +int chmod(const char *, mode_t); +int fchmod(int, mode_t); +int fchmodat(int, const char *, mode_t, int); +int fstat(int fd, struct stat *result); +int fstatat(int, const char *__restrict, struct stat *__restrict, int); +int futimens(int fd, const struct timespec times[2]); +int lstat(const char *__restrict, struct stat *__restrict); +int mkdir(const char *, mode_t); +int mkdirat(int, const char *, mode_t); +int mkfifo(const char *, mode_t); +int mkfifoat(int, const char *, mode_t); +int mknod(const char *, mode_t, dev_t); +int mknodat(int, const char *, mode_t, dev_t); +int stat(const char *__restrict, struct stat *__restrict); +mode_t umask(mode_t); +int utimensat(int, const char *, const struct timespec times[2], int); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif // _SYS_STAT_H + diff --git a/lib/mlibc/options/posix/include/sys/statvfs.h b/lib/mlibc/options/posix/include/sys/statvfs.h new file mode 100644 index 0000000..0e4c308 --- /dev/null +++ b/lib/mlibc/options/posix/include/sys/statvfs.h @@ -0,0 +1,22 @@ +#ifndef _SYS_STATVFS_H +#define _SYS_STATVFS_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#ifndef __MLIBC_ABI_ONLY + +int statvfs(const char *__restrict, struct statvfs *__restrict); +int fstatvfs(int, struct statvfs *); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif // _SYS_STATVFS_H + diff --git a/lib/mlibc/options/posix/include/sys/syslog.h b/lib/mlibc/options/posix/include/sys/syslog.h new file mode 100644 index 0000000..7761ece --- /dev/null +++ b/lib/mlibc/options/posix/include/sys/syslog.h @@ -0,0 +1 @@ +#include diff --git a/lib/mlibc/options/posix/include/sys/termios.h b/lib/mlibc/options/posix/include/sys/termios.h new file mode 100644 index 0000000..b23f171 --- /dev/null +++ b/lib/mlibc/options/posix/include/sys/termios.h @@ -0,0 +1,6 @@ + +#ifndef _SYS_TERMIOS_H +#define _SYS_TERMIOS_H +#include +#endif // _SYS_TERMIOS_H + diff --git a/lib/mlibc/options/posix/include/sys/time.h b/lib/mlibc/options/posix/include/sys/time.h new file mode 100644 index 0000000..838d7cc --- /dev/null +++ b/lib/mlibc/options/posix/include/sys/time.h @@ -0,0 +1,68 @@ +#ifndef _SYS_TIME_H +#define _SYS_TIME_H + +#include +#include +#include +#include +#include +#include +#include + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct timezone { + int tz_minuteswest; + int tz_dsttime; +}; + +#ifndef __MLIBC_ABI_ONLY + +// TODO: this function is [OB]. disable it by default and add a macro to enable it +int gettimeofday(struct timeval *__restrict result, void *__restrict unused); +int settimeofday(const struct timeval *result, const struct timezone *zone); + +void timeradd(const struct timeval *a, const struct timeval *b, struct timeval *res); +void timersub(const struct timeval *a, const struct timeval *b, struct timeval *res); +void timerclear(struct timeval *tvp); +int timerisset(struct timeval *tvp); + +#endif /* !__MLIBC_ABI_ONLY */ + +// timercmp taken from musl +#define timercmp(s,t,op) ((s)->tv_sec == (t)->tv_sec ? \ + (s)->tv_usec op (t)->tv_usec : (s)->tv_sec op (t)->tv_sec) + +#ifndef __MLIBC_ABI_ONLY + +int getitimer(int which, struct itimerval *curr_value); +int setitimer(int which, const struct itimerval *new_value, + struct itimerval *old_value); + +int timer_create(clockid_t clockid, struct sigevent *__restrict sevp, timer_t *__restrict timerid); +int timer_settime(timer_t timerid, int flags, const struct itimerspec *__restrict new_value, + struct itimerspec *__restrict old_value); +int timer_gettime(timer_t timerid, struct itimerspec *curr_value); +int timer_delete(timer_t timerid); + +#endif /* !__MLIBC_ABI_ONLY */ + +// The following 2 macros are taken from musl +#define TIMEVAL_TO_TIMESPEC(tv, ts) ( \ + (ts)->tv_sec = (tv)->tv_sec, \ + (ts)->tv_nsec = (tv)->tv_usec * 1000, \ + (void)0 ) +#define TIMESPEC_TO_TIMEVAL(tv, ts) ( \ + (tv)->tv_sec = (ts)->tv_sec, \ + (tv)->tv_usec = (ts)->tv_nsec / 1000, \ + (void)0 ) + +#ifdef __cplusplus +} +#endif + +#endif // _SYS_TIME_H diff --git a/lib/mlibc/options/posix/include/sys/times.h b/lib/mlibc/options/posix/include/sys/times.h new file mode 100644 index 0000000..2dd2889 --- /dev/null +++ b/lib/mlibc/options/posix/include/sys/times.h @@ -0,0 +1,28 @@ +#ifndef _SYS_TIMES_H +#define _SYS_TIMES_H + +// TODO: Only define the clock_t type. +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct tms { + clock_t tms_utime; + clock_t tms_stime; + clock_t tms_cutime; + clock_t tms_cstime; +}; + +#ifndef __MLIBC_ABI_ONLY + +clock_t times(struct tms *); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif // _SYS_TIMES_H diff --git a/lib/mlibc/options/posix/include/sys/ttydefaults.h b/lib/mlibc/options/posix/include/sys/ttydefaults.h new file mode 100644 index 0000000..c6d04f6 --- /dev/null +++ b/lib/mlibc/options/posix/include/sys/ttydefaults.h @@ -0,0 +1,39 @@ + +#ifndef _SYS_TTYDEFAULTS_H +#define _SYS_TTYDEFAULTS_H + +// Values taken from musl + +#define TTYDEF_IFLAG (BRKINT | ISTRIP | ICRNL | IMAXBEL | IXON | IXANY) +#define TTYDEF_OFLAG (OPOST | ONLCR | XTABS) +#define TTYDEF_LFLAG (ECHO | ICANON | ISIG | IEXTEN | ECHOE|ECHOKE|ECHOCTL) +#define TTYDEF_CFLAG (CREAD | CS7 | PARENB | HUPCL) +#define TTYDEF_SPEED (B9600) + +#define CTRL(x) ((x) & 037) +#define CEOF CTRL('d') + +#define CEOL '\0' +#define CEOL2 '\0' +#define CSTATUS '\0' + +#define CERASE 0177 +#define CINTR CTRL('c') +#define CKILL CTRL('u') +#define CMIN 1 +#define CQUIT 034 +#define CSUSP CTRL('z') +#define CTIME 0 +#define CDSUSP CTRL('y') +#define CSTART CTRL('q') +#define CSTOP CTRL('s') +#define CLNEXT CTRL('v') +#define CDISCARD CTRL('o') +#define CWERASE CTRL('w') +#define CREPRINT CTRL('r') +#define CEOT CEOF +#define CBRK CEOL +#define CRPRNT CREPRINT +#define CFLUSH CDISCARD + +#endif // _SYS_TTYDEFAULTS_H diff --git a/lib/mlibc/options/posix/include/sys/types.h b/lib/mlibc/options/posix/include/sys/types.h new file mode 100644 index 0000000..ad837fc --- /dev/null +++ b/lib/mlibc/options/posix/include/sys/types.h @@ -0,0 +1,53 @@ + +#ifndef _SYS_TYPES_H +#define _SYS_TYPES_H + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include + +#include + +typedef unsigned int u_int; +typedef unsigned char u_char; +typedef unsigned short u_short; +typedef unsigned long int u_long; +typedef char *caddr_t; +typedef off64_t loff_t; + +typedef unsigned long int ulong; +typedef unsigned short int ushort; +typedef unsigned int uint; + +typedef uint8_t u_int8_t; +typedef uint16_t u_int16_t; +typedef uint32_t u_int32_t; +typedef uint64_t u_int64_t; + +// BSD extensions +typedef int64_t quad_t; +typedef uint64_t u_quad_t; + +#endif // _SYS_TYPES_H + diff --git a/lib/mlibc/options/posix/include/sys/uio.h b/lib/mlibc/options/posix/include/sys/uio.h new file mode 100644 index 0000000..04679a6 --- /dev/null +++ b/lib/mlibc/options/posix/include/sys/uio.h @@ -0,0 +1,31 @@ +#ifndef _SYS_UIO_H +#define _SYS_UIO_H + +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define UIO_MAXIOV IOV_MAX + +#ifndef __MLIBC_ABI_ONLY + +ssize_t readv(int fd, const struct iovec *iov, int iovcnt); +ssize_t writev(int fd, const struct iovec *iov, int iovcnt); + +// Non standard extensions, also found on modern BSD's +ssize_t preadv(int fd, const struct iovec *iov, int iovcnt, off_t offset); +ssize_t pwritev(int fd, const struct iovec *iov, int iovcnt, off_t offset); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif // _SYS_UIO_H diff --git a/lib/mlibc/options/posix/include/sys/un.h b/lib/mlibc/options/posix/include/sys/un.h new file mode 100644 index 0000000..bb9b5ad --- /dev/null +++ b/lib/mlibc/options/posix/include/sys/un.h @@ -0,0 +1,24 @@ + +#ifndef _SYS_UN_H +#define _SYS_UN_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +struct sockaddr_un { + sa_family_t sun_family; + char sun_path[108]; +}; + +// Evaluate to actual length of the `sockaddr_un' structure. +#define SUN_LEN(ptr) ((size_t) offsetof(struct sockaddr_un, sun_path) + strlen((ptr)->sun_path)) + +#ifdef __cplusplus +} +#endif + +#endif // _SYS_UN_H + diff --git a/lib/mlibc/options/posix/include/sys/utsname.h b/lib/mlibc/options/posix/include/sys/utsname.h new file mode 100644 index 0000000..bd7b174 --- /dev/null +++ b/lib/mlibc/options/posix/include/sys/utsname.h @@ -0,0 +1,22 @@ + +#ifndef _SYS_UTSNAME_H +#define _SYS_UTSNAME_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +int uname(struct utsname *); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif // _SYS_UTSNAME_H + diff --git a/lib/mlibc/options/posix/include/sys/wait.h b/lib/mlibc/options/posix/include/sys/wait.h new file mode 100644 index 0000000..5081041 --- /dev/null +++ b/lib/mlibc/options/posix/include/sys/wait.h @@ -0,0 +1,40 @@ + +#ifndef _SYS_WAIT_H +#define _SYS_WAIT_H + +#include +#include +// for siginfo_t +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +// According to POSIX, does not make rusage available. +struct rusage; + +// TODO: move to own file and include in sys/types.h +typedef enum { + P_ALL, P_PID, P_PGID +} idtype_t; + +#ifndef __MLIBC_ABI_ONLY + +pid_t wait(int *status); +int waitid(idtype_t idtype, id_t id, siginfo_t *siginfo, int flags); +pid_t waitpid(pid_t pid, int *status, int flags); + +// GNU extensions. +pid_t wait3(int *, int, struct rusage *); +pid_t wait4(pid_t pid, int *status, int options, struct rusage *ru); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif // _SYS_WAIT_H + diff --git a/lib/mlibc/options/posix/include/syslog.h b/lib/mlibc/options/posix/include/syslog.h new file mode 100644 index 0000000..6c258cf --- /dev/null +++ b/lib/mlibc/options/posix/include/syslog.h @@ -0,0 +1,75 @@ + +#ifndef _SYSLOG_H +#define _SYSLOG_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define LOG_PID 0x01 +#define LOG_CONS 0x02 +#define LOG_NDELAY 0x08 +#define LOG_ODELAY 0x04 +#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) + +#define LOG_PRIMASK 7 +#define LOG_PRI(p) ((p)&LOG_PRIMASK) +#define LOG_MAKEPRI(f, p) (((f)<<3) | (p)) +#define LOG_MASK(p) (1<<(p)) +#define LOG_UPTO(p) ((1<<((p)+1))-1) +#define LOG_NFACILITIES 24 +#define LOG_FACMASK (0x7F<<3) +#define LOG_FAC(p) (((p)&LOG_FACMASK)>>3) + +#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 + +#ifndef __MLIBC_ABI_ONLY + +void closelog(void); +void openlog(const char *, int, int); +int setlogmask(int); +void syslog(int, const char *, ...); + +// This is a linux extension +void vsyslog(int, const char *, va_list); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif // _SYSLOG_H + diff --git a/lib/mlibc/options/posix/include/termios.h b/lib/mlibc/options/posix/include/termios.h new file mode 100644 index 0000000..a5a6a2f --- /dev/null +++ b/lib/mlibc/options/posix/include/termios.h @@ -0,0 +1,100 @@ + +#ifndef _TERMIOS_H +#define _TERMIOS_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE) +#include +#endif + +// baud rate constants for speed_t +#define B0 0 +#define B50 1 +#define B75 2 +#define B110 3 +#define B134 4 +#define B150 5 +#define B200 6 +#define B300 7 +#define B600 8 +#define B1200 9 +#define B1800 10 +#define B2400 11 +#define B4800 12 +#define B9600 13 +#define B19200 14 +#define B38400 15 +#define B57600 0010001 +#define B115200 0010002 +#define B230400 0010003 +#define B460800 0010004 +#define B500000 0010005 +#define B576000 0010006 +#define B921600 0010007 +#define B1000000 0010010 +#define B1152000 0010011 +#define B1500000 0010012 +#define B2000000 0010013 +#define B2500000 0010014 +#define B3000000 0010015 +#define B3500000 0010016 +#define B4000000 0010017 + +// constants for tcsetattr() +#define TCSANOW 0 +#define TCSADRAIN 1 +#define TCSAFLUSH 2 + +// constants for tcflush() +#define TCIFLUSH 0 +#define TCOFLUSH 1 +#define TCIOFLUSH 2 + +// constants for tcflow() +#define TCOOFF 0 +#define TCOON 1 +#define TCIOFF 2 +#define TCION 3 + +#define TIOCM_DTR 0x002 +#define TIOCM_RTS 0x004 + +#ifndef __MLIBC_ABI_ONLY + +speed_t cfgetispeed(const struct termios *); +speed_t cfgetospeed(const struct termios *); +int cfsetispeed(struct termios *, speed_t); +int cfsetospeed(struct termios *, speed_t); +void cfmakeraw(struct termios *); +int tcdrain(int); +int tcflow(int, int); +int tcflush(int, int); +int tcgetattr(int fd, struct termios *attr); +pid_t tcgetsid(int); +int tcsendbreak(int, int); +int tcsetattr(int, int, const struct termios *); + +#endif /* !__MLIBC_ABI_ONLY */ + +// This is a linux extension + +#define TIOCGPGRP 0x540F +#define TIOCSPGRP 0x5410 +#define TIOCGWINSZ 0x5413 +#define TIOCSWINSZ 0x5414 +#define TIOCGSID 0x5429 + +#ifdef __cplusplus +} +#endif + +#endif // _TERMIOS_H + diff --git a/lib/mlibc/options/posix/include/ucontext.h b/lib/mlibc/options/posix/include/ucontext.h new file mode 100644 index 0000000..c50b0b1 --- /dev/null +++ b/lib/mlibc/options/posix/include/ucontext.h @@ -0,0 +1,23 @@ +#ifndef _UCONTEXT_H +#define _UCONTEXT_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +#ifndef __MLIBC_ABI_ONLY + +int getcontext(ucontext_t *); +int setcontext(const ucontext_t *); +void makecontext(ucontext_t *, void (*)(void), int, ...); +int swapcontext(ucontext_t *, const ucontext_t *); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif // __cplusplus + +#endif // _UCONTEXT_H diff --git a/lib/mlibc/options/posix/include/unistd.h b/lib/mlibc/options/posix/include/unistd.h new file mode 100644 index 0000000..d29257d --- /dev/null +++ b/lib/mlibc/options/posix/include/unistd.h @@ -0,0 +1,360 @@ + +#ifndef _UNISTD_H +#define _UNISTD_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if __MLIBC_SYSDEP_HAS_BITS_SYSCALL_H && __MLIBC_LINUX_OPTION +#include +#endif /* __MLIBC_SYSDEP_HAS_BITS_SYSCALL_H && __MLIBC_LINUX_OPTION */ + +#ifdef __cplusplus +extern "C" { +#endif + +#define _POSIX_VERSION 200809L +#define _POSIX2_VERSION _POSIX_VERSION +#define _XOPEN_VERSION 700 + +#define _POSIX_FSYNC _POSIX_VERSION +#define _POSIX_IPV6 _POSIX_VERSION +#define _POSIX_JOB_CONTROL 1 +#define _POSIX_SAVED_IDS 1 +#define _POSIX_SHELL 1 +#define _POSIX_SPAWN _POSIX_VERSION +#define _POSIX_THREADS _POSIX_VERSION +#define _POSIX_THREAD_SAFE_FUNCTIONS _POSIX_VERSION +#define _POSIX_MONOTONIC_CLOCK 0 + +#if __MLIBC_CRYPT_OPTION +#define _XOPEN_CRYPT 1 +#endif + +// MISSING: additional _POSIX and _XOPEN feature macros +// MISSING: _POSIX_TIMESTAMP_RESOLUTION and _POSIX2_SYMLINKS + +#define _CS_PATH 0 +#define _CS_POSIX_V6_WIDTH_RESTRICTED_ENVS 1 +#define _CS_GNU_LIBC_VERSION 2 +#define _CS_GNU_LIBPTHREAD_VERSION 3 +#define _CS_POSIX_V5_WIDTH_RESTRICTED_ENVS 4 +#define _CS_POSIX_V7_WIDTH_RESTRICTED_ENVS 5 + +#define _CS_POSIX_V6_ILP32_OFF32_CFLAGS 1116 +#define _CS_POSIX_V6_ILP32_OFF32_LDFLAGS 1117 +#define _CS_POSIX_V6_ILP32_OFF32_LIBS 1118 +#define _CS_POSIX_V6_ILP32_OFF32_LINTFLAGS 1119 +#define _CS_POSIX_V6_ILP32_OFFBIG_CFLAGS 1120 +#define _CS_POSIX_V6_ILP32_OFFBIG_LDFLAGS 1121 +#define _CS_POSIX_V6_ILP32_OFFBIG_LIBS 1122 +#define _CS_POSIX_V6_ILP32_OFFBIG_LINTFLAGS 1123 +#define _CS_POSIX_V6_LP64_OFF64_CFLAGS 1124 +#define _CS_POSIX_V6_LP64_OFF64_LDFLAGS 1125 +#define _CS_POSIX_V6_LP64_OFF64_LIBS 1126 +#define _CS_POSIX_V6_LP64_OFF64_LINTFLAGS 1127 +#define _CS_POSIX_V6_LPBIG_OFFBIG_CFLAGS 1128 +#define _CS_POSIX_V6_LPBIG_OFFBIG_LDFLAGS 1129 +#define _CS_POSIX_V6_LPBIG_OFFBIG_LIBS 1130 +#define _CS_POSIX_V6_LPBIG_OFFBIG_LINTFLAGS 1131 +#define _CS_POSIX_V7_ILP32_OFF32_CFLAGS 1132 +#define _CS_POSIX_V7_ILP32_OFF32_LDFLAGS 1133 +#define _CS_POSIX_V7_ILP32_OFF32_LIBS 1134 +#define _CS_POSIX_V7_ILP32_OFF32_LINTFLAGS 1135 +#define _CS_POSIX_V7_ILP32_OFFBIG_CFLAGS 1136 +#define _CS_POSIX_V7_ILP32_OFFBIG_LDFLAGS 1137 +#define _CS_POSIX_V7_ILP32_OFFBIG_LIBS 1138 +#define _CS_POSIX_V7_ILP32_OFFBIG_LINTFLAGS 1139 +#define _CS_POSIX_V7_LP64_OFF64_CFLAGS 1140 +#define _CS_POSIX_V7_LP64_OFF64_LDFLAGS 1141 +#define _CS_POSIX_V7_LP64_OFF64_LIBS 1142 +#define _CS_POSIX_V7_LP64_OFF64_LINTFLAGS 1143 +#define _CS_POSIX_V7_LPBIG_OFFBIG_CFLAGS 1144 +#define _CS_POSIX_V7_LPBIG_OFFBIG_LDFLAGS 1145 +#define _CS_POSIX_V7_LPBIG_OFFBIG_LIBS 1146 +#define _CS_POSIX_V7_LPBIG_OFFBIG_LINTFLAGS 1147 +#define _CS_V6_ENV 1148 +#define _CS_V7_ENV 1149 + +// MISSING: SEEK macros from stdio.h + +#define F_LOCK 1 +#define F_TEST 2 +#define F_TLOCK 3 +#define F_ULOCK 4 + +// MISSING: _PC macros +// For now, use the Linux ABI for _PC constants. +#define _PC_LINK_MAX 0 +#define _PC_MAX_CANON 1 +#define _PC_MAX_INPUT 2 +#define _PC_NAME_MAX 3 +#define _PC_PATH_MAX 4 +#define _PC_PIPE_BUF 5 +#define _PC_CHOWN_RESTRICTED 6 +#define _PC_NO_TRUNC 7 +#define _PC_VDISABLE 8 + +#define _PC_FILESIZEBITS 9 +#define _PC_SYMLINK_MAX 10 + +// MISSING: remaining _SC_macros +#define _SC_ARG_MAX 0 +#define _SC_GETPW_R_SIZE_MAX 1 +#define _SC_PHYS_PAGES 2 +#define _SC_PAGE_SIZE 3 +#define _SC_PAGESIZE _SC_PAGE_SIZE +#define _SC_OPEN_MAX 5 +#define _SC_NPROCESSORS_ONLN 6 +#define _SC_GETGR_R_SIZE_MAX 7 + +#define _SC_CHILD_MAX 8 +#define _SC_CLK_TCK 9 +#define _SC_NGROUPS_MAX 10 +#define _SC_VERSION 11 +#define _SC_SAVED_IDS 12 +#define _SC_JOB_CONTROL 13 +#define _SC_HOST_NAME_MAX 14 +#define _SC_LINE_MAX 15 +#define _SC_XOPEN_CRYPT 16 +#define _SC_NPROCESSORS_CONF 17 +#define _SC_SYMLOOP_MAX 18 +#define _SC_TTY_NAME_MAX 19 +#define _SC_RE_DUP_MAX 20 + +#define _SC_ATEXIT_MAX 21 +#define _SC_LOGIN_NAME_MAX 22 +#define _SC_THREAD_DESTRUCTOR_ITERATIONS 23 +#define _SC_THREAD_KEYS_MAX 24 +#define _SC_THREAD_STACK_MIN 25 +#define _SC_THREAD_THREADS_MAX 26 +#define _SC_TZNAME_MAX 27 +#define _SC_ASYNCHRONOUS_IO 28 +#define _SC_FSYNC 29 +#define _SC_MAPPED_FILES 30 +#define _SC_MEMLOCK 31 +#define _SC_MEMLOCK_RANGE 32 +#define _SC_MEMORY_PROTECTION 33 +#define _SC_MESSAGE_PASSING 34 +#define _SC_PRIORITY_SCHEDULING 35 +#define _SC_REALTIME_SIGNALS 36 +#define _SC_SEMAPHORES 37 +#define _SC_SHARED_MEMORY_OBJECTS 38 +#define _SC_SYNCHRONIZED_IO 39 +#define _SC_THREADS 40 +#define _SC_THREAD_ATTR_STACKADDR 41 +#define _SC_THREAD_ATTR_STACKSIZE 42 +#define _SC_THREAD_PRIORITY_SCHEDULING 43 +#define _SC_THREAD_PRIO_INHERIT 44 +#define _SC_THREAD_PRIO_PROTECT 45 +#define _SC_THREAD_PROCESS_SHARED 46 +#define _SC_THREAD_SAFE_FUNCTIONS 47 +#define _SC_TIMERS 48 +#define _SC_TIMER_MAX 49 +#define _SC_2_CHAR_TERM 50 +#define _SC_2_C_BIND 51 +#define _SC_2_C_DEV 52 +#define _SC_2_FORT_DEV 53 +#define _SC_2_FORT_RUN 54 +#define _SC_2_LOCALEDEF 55 +#define _SC_2_SW_DEV 56 +#define _SC_2_UPE 57 +#define _SC_2_VERSION 58 +#define _SC_CLOCK_SELECTION 59 +#define _SC_CPUTIME 60 +#define _SC_THREAD_CPUTIME 61 +#define _SC_MONOTONIC_CLOCK 62 +#define _SC_READER_WRITER_LOCKS 63 +#define _SC_SPIN_LOCKS 64 +#define _SC_REGEXP 65 +#define _SC_SHELL 66 +#define _SC_SPAWN 67 +#define _SC_2_PBS 68 +#define _SC_2_PBS_ACCOUNTING 69 +#define _SC_2_PBS_LOCATE 70 +#define _SC_2_PBS_TRACK 71 +#define _SC_2_PBS_MESSAGE 72 +#define _SC_STREAM_MAX 73 +#define _SC_AIO_LISTIO_MAX 74 +#define _SC_AIO_MAX 75 +#define _SC_DELAYTIMER_MAX 76 +#define _SC_MQ_OPEN_MAX 77 +#define _SC_MQ_PRIO_MAX 78 +#define _SC_RTSIG_MAX 79 +#define _SC_SIGQUEUE_MAX 80 +#define _SC_IOV_MAX 81 + +#define STDERR_FILENO 2 +#define STDIN_FILENO 0 +#define STDOUT_FILENO 1 + +#define _POSIX_VDISABLE '\0' + +#define L_ctermid 20 + +#ifndef intptr_t +typedef __mlibc_intptr intptr_t; +#endif + +#ifndef __MLIBC_ABI_ONLY + +int access(const char *path, int mode); +unsigned int alarm(unsigned int seconds); +int chdir(const char *path); +int chown(const char *path, uid_t uid, gid_t gid); +int close(int fd); +ssize_t confstr(int, char *, size_t); +char *ctermid(char *s); +int dup(int fd); +int dup2(int src_fd, int dest_fd); +__attribute__((__noreturn__)) void _exit(int status); +void endusershell(void); +int execl(const char *, const char *, ...); +int execle(const char *, const char *, ...); +int execlp(const char *, const char *, ...); +int execv(const char *, char *const []); +int execve(const char *path, char *const argv[], char *const envp[]); +int execvp(const char *, char *const[]); +int execvpe(const char *path, char *const argv[], char *const envp[]); +int faccessat(int, const char *, int, int); +int fchdir(int fd); +int fchown(int fd, uid_t uid, gid_t gid); +int fchownat(int fd, const char *path, uid_t uid, gid_t gid, int flags); +int fdatasync(int); +int fexecve(int, char *const [], char *const []); +pid_t fork(void); +pid_t vfork(void); +long fpathconf(int, int); +int fsync(int); +int ftruncate(int, off_t); +char *getcwd(char *, size_t); +gid_t getegid(void); +uid_t geteuid(void); +gid_t getgid(void); +int getgroups(int, gid_t []); +long gethostid(void); +int gethostname(char *buffer, size_t max_length); +int sethostname(const char *buffer, size_t max_length); +char *getlogin(void); +int getlogin_r(char *, size_t); +int getopt(int, char *const [], const char *); +char *getpass(const char *); +pid_t getpgid(pid_t); +pid_t getpgrp(void); +pid_t getpid(void); +pid_t getppid(void); +pid_t getsid(pid_t); +uid_t getuid(void); +char *getusershell(void); +int isatty(int fd); +int lchown(const char *path, uid_t uid, gid_t gid); +int link(const char *, const char *); +int linkat(int, const char *, int, const char *, int); +int lockf(int, int, off_t); +off_t lseek(int fd, off_t offset, int whence); +off64_t lseek64(int fd, off64_t offset, int whence); +int nice(int); +long pathconf(const char *, int); +int pause(void); +int pipe(int [2]); +ssize_t pread(int, void *, size_t, off_t); +ssize_t pwrite(int, const void *, size_t, off_t); +ssize_t read(int fd, void *buffer, size_t size); +ssize_t readlink(const char *__restrict, char *__restrict, size_t); +ssize_t readlinkat(int, const char *__restrict, char *__restrict, size_t); +int rmdir(const char *); +int setegid(gid_t); +int seteuid(uid_t); +int setgid(gid_t); +int setpgid(pid_t, pid_t); +pid_t setpgrp(void); +int setregid(gid_t, gid_t); +int setreuid(uid_t, uid_t); +pid_t setsid(void); +int setuid(uid_t); +void setusershell(void); +unsigned int sleep(unsigned int); +void swab(const void *__restrict, void *__restrict, ssize_t); +int symlink(const char *, const char *); +int symlinkat(const char *, int, const char *); +void sync(void); +long sysconf(int); +pid_t tcgetpgrp(int); +int tcsetpgrp(int, pid_t); +int truncate(const char *, off_t); +char *ttyname(int); +int ttyname_r(int, char *, size_t); +int unlink(const char *); +int unlinkat(int, const char *, int); +ssize_t write(int fd, const void *buffer, size_t size); + +extern char **environ; +extern char *optarg; +extern int optind; +extern int opterr; +extern int optopt; + +#endif /* !__MLIBC_ABI_ONLY */ + +// Non-POSIX functions supported by Linux. +#if UINTPTR_MAX == UINT64_MAX +typedef __mlibc_uint64 useconds_t; +#else +typedef __mlibc_uint32 useconds_t; +#endif + +#ifndef __MLIBC_ABI_ONLY + +int getpagesize(void); +char *get_current_dir_name(void); +int usleep(useconds_t); +int chroot(const char *); +int daemon(int, int); + +// This is a Linux extension +pid_t gettid(void); +int getentropy(void *, size_t); + +int pipe2(int *pipefd, int flags); + +int setresuid(uid_t ruid, uid_t euid, uid_t suid); +int setresgid(gid_t rgid, gid_t egid, gid_t sgid); + +/* Glibc extensions. */ +int getdomainname(char *name, size_t len); +int setdomainname(const char *name, size_t len); + +int getresuid(uid_t *ruid, uid_t *euid, uid_t *suid); +int getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid); + +// Glibc doesn't provide them by default anymore, lock behind an option +#if __MLIBC_CRYPT_OPTION +char *crypt(const char *, const char *); +void encrypt(char block[64], int flags); +#endif + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#if __MLIBC_LINUX_OPTION +# include +#endif + +#if __MLIBC_BSD_OPTION +# include +#endif + +#endif // _UNISTD_H + diff --git a/lib/mlibc/options/posix/include/utime.h b/lib/mlibc/options/posix/include/utime.h new file mode 100644 index 0000000..dcf053d --- /dev/null +++ b/lib/mlibc/options/posix/include/utime.h @@ -0,0 +1,25 @@ +#ifndef _UTIME_H +#define _UTIME_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct utimbuf { + time_t actime; + time_t modtime; +}; + +#ifndef __MLIBC_ABI_ONLY + +int utime(const char *, const struct utimbuf *); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif // _UTIME_H diff --git a/lib/mlibc/options/posix/include/wordexp.h b/lib/mlibc/options/posix/include/wordexp.h new file mode 100644 index 0000000..e5d69ce --- /dev/null +++ b/lib/mlibc/options/posix/include/wordexp.h @@ -0,0 +1,43 @@ +#ifndef _WORDEXP_H +#define _WORDEXP_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#define WRDE_APPEND 1 +#define WRDE_DOOFFS 2 +#define WRDE_NOCMD 4 +#define WRDE_REUSE 8 +#define WRDE_SHOWERR 16 +#define WRDE_UNDEF 32 + +#define WRDE_SUCCESS 1 +#define WRDE_BADCHAR 1 +#define WRDE_BADVAL 2 +#define WRDE_CMDSUB 3 +#define WRDE_NOSPACE 4 +#define WRDE_SYNTAX 5 + +typedef struct { + size_t we_wordc; + char **we_wordv; + size_t we_offs; + char *we_strings; + size_t we_nbytes; +} wordexp_t; + +#ifndef __MLIBC_ABI_ONLY + +int wordexp(const char *s, wordexp_t *p, int flags); +void wordfree(wordexp_t *p); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib/mlibc/options/posix/meson.build b/lib/mlibc/options/posix/meson.build new file mode 100644 index 0000000..038dd2c --- /dev/null +++ b/lib/mlibc/options/posix/meson.build @@ -0,0 +1,175 @@ + +if disable_posix_option + subdir_done() +endif +libc_sources += files( + 'generic/arpa-inet-stubs.cpp', + 'generic/dirent-stubs.cpp', + 'generic/dlfcn-stubs.cpp', + 'generic/fcntl-stubs.cpp', + 'generic/ftw-stubs.cpp', + 'generic/grp-stubs.cpp', + 'generic/langinfo-stubs.cpp', + 'generic/libgen-stubs.cpp', + 'generic/lookup.cpp', + 'generic/netdb-stubs.cpp', + 'generic/net-if-stubs.cpp', + 'generic/poll.cpp', + 'generic/posix_ctype.cpp', + 'generic/posix-file-io.cpp', + 'generic/posix_locale.cpp', + 'generic/posix_signal.cpp', + 'generic/posix_stdio.cpp', + 'generic/posix_stdlib.cpp', + 'generic/posix_string.cpp', + 'generic/posix_time.cpp', + 'generic/pthread-stubs.cpp', + 'generic/pwd-stubs.cpp', + 'generic/resolv_conf.cpp', + 'generic/sched-stubs.cpp', + 'generic/spawn-stubs.cpp', + 'generic/strings-stubs.cpp', + 'generic/services.cpp', + 'generic/sys-file-stubs.cpp', + 'generic/syslog-stubs.cpp', + 'generic/sys-mman-stubs.cpp', + 'generic/sys-resource-stubs.cpp', + 'generic/sys-select-stubs.cpp', + 'generic/sys-shm.cpp', + 'generic/sys-socket-stubs.cpp', + 'generic/sys-stat-stubs.cpp', + 'generic/sys-statvfs-stubs.cpp', + 'generic/sys-times.cpp', + 'generic/sys-time-stubs.cpp', + 'generic/sys-uio.cpp', + 'generic/sys-utsname.cpp', + 'generic/sys-wait-stubs.cpp', + 'generic/termios-stubs.cpp', + 'generic/unistd-stubs.cpp', + 'generic/utime-stubs.cpp', + 'generic/ucontext-stubs.cpp', + 'generic/semaphore-stubs.cpp', + 'generic/search.cpp', + 'generic/sys-msg.cpp', + 'generic/sys-sem.cpp', + 'generic/sys-ipc.cpp', + 'generic/time.cpp', + 'generic/wordexp-stubs.cpp', + 'generic/mqueue.cpp' +) + +if not headers_only + libc_sublibs += static_library('musl-generic-regex', + 'musl-generic-regex/fnmatch.c', + 'musl-generic-regex/glob.c', + 'musl-generic-regex/regcomp.c', + 'musl-generic-regex/regerror.c', + 'musl-generic-regex/regexec.c', + 'musl-generic-regex/tre-mem.c', + pic: true, + include_directories: libc_include_dirs, + dependencies: libc_deps, + c_args: ['-Wno-unused', '-Wno-implicit', '-Wno-parentheses', '-Wno-sign-compare', '-Wno-attributes', '-Wno-unknown-pragmas', '-Wno-implicit-fallthrough'] + ) +endif + +if not no_headers + install_headers( + 'include/byteswap.h', + 'include/dirent.h', + 'include/dlfcn.h', + 'include/fcntl.h', + 'include/fnmatch.h', + 'include/ftw.h', + 'include/glob.h', + 'include/grp.h', + 'include/langinfo.h', + 'include/libgen.h', + 'include/netdb.h', + 'include/nl_types.h', + 'include/pthread.h', + 'include/pwd.h', + 'include/poll.h', + 'include/regex.h', + 'include/sched.h', + 'include/search.h', + 'include/spawn.h', + 'include/strings.h', + 'include/syslog.h', + 'include/termios.h', + 'include/unistd.h', + 'include/utime.h', + 'include/ucontext.h', + 'include/wordexp.h', + 'include/semaphore.h', + 'include/mqueue.h', + ) + install_headers( + 'include/arpa/inet.h', + subdir: 'arpa' + ) + install_headers( + 'include/net/if.h', + 'include/net/if_arp.h', + subdir: 'net' + ) + install_headers( + 'include/netinet/in.h', + 'include/netinet/ip.h', + 'include/netinet/tcp.h', + 'include/netinet/icmp6.h', + 'include/netinet/if_ether.h', + 'include/netinet/udp.h', + 'include/netinet/ip6.h', + 'include/netinet/ip_icmp.h', + subdir: 'netinet' + ) + install_headers( + 'include/sys/file.h', + 'include/sys/ipc.h', + 'include/sys/mman.h', + 'include/sys/msg.h', + 'include/sys/param.h', + 'include/sys/poll.h', + 'include/sys/resource.h', + 'include/sys/select.h', + 'include/sys/sem.h', + 'include/sys/shm.h', + 'include/sys/socket.h', + 'include/sys/stat.h', + 'include/sys/statvfs.h', + 'include/sys/termios.h', + 'include/sys/time.h', + 'include/sys/times.h', + 'include/sys/ttydefaults.h', + 'include/sys/types.h', + 'include/sys/uio.h', + 'include/sys/un.h', + 'include/sys/utsname.h', + 'include/sys/wait.h', + 'include/sys/syslog.h', + subdir: 'sys' + ) + install_headers( + 'include/bits/posix/id_t.h', + 'include/bits/posix/in_addr_t.h', + 'include/bits/posix/in_port_t.h', + 'include/bits/posix/iovec.h', + 'include/bits/posix/locale_t.h', + 'include/bits/posix/posix_ctype.h', + 'include/bits/posix/posix_locale.h', + 'include/bits/posix/posix_signal.h', + 'include/bits/posix/posix_stdio.h', + 'include/bits/posix/posix_stdlib.h', + 'include/bits/posix/posix_string.h', + 'include/bits/posix/posix_time.h', + 'include/bits/posix/posix_wctype.h', + 'include/bits/posix/stat.h', + 'include/bits/posix/timeval.h', + 'include/bits/posix/fd_set.h', + 'include/bits/posix/pthread_t.h', + 'include/bits/posix/timer_t.h', + subdir: 'bits/posix' + ) +endif + diff --git a/lib/mlibc/options/posix/musl-generic-regex/fnmatch.c b/lib/mlibc/options/posix/musl-generic-regex/fnmatch.c new file mode 100644 index 0000000..0e6de47 --- /dev/null +++ b/lib/mlibc/options/posix/musl-generic-regex/fnmatch.c @@ -0,0 +1,321 @@ +/* + * An implementation of what I call the "Sea of Stars" algorithm for + * POSIX fnmatch(). The basic idea is that we factor the pattern into + * a head component (which we match first and can reject without ever + * measuring the length of the string), an optional tail component + * (which only exists if the pattern contains at least one star), and + * an optional "sea of stars", a set of star-separated components + * between the head and tail. After the head and tail matches have + * been removed from the input string, the components in the "sea of + * stars" are matched sequentially by searching for their first + * occurrence past the end of the previous match. + * + * - Rich Felker, April 2012 + */ + +#include +#include +#include +#include +#include +// #include "locale_impl.h" + +#define END 0 +#define UNMATCHABLE -2 +#define BRACKET -3 +#define QUESTION -4 +#define STAR -5 + +static int str_next(const char *str, size_t n, size_t *step) +{ + if (!n) { + *step = 0; + return 0; + } + if (str[0] >= 128U) { + wchar_t wc; + int k = mbtowc(&wc, str, n); + if (k<0) { + *step = 1; + return -1; + } + *step = k; + return wc; + } + *step = 1; + return str[0]; +} + +static int pat_next(const char *pat, size_t m, size_t *step, int flags) +{ + int esc = 0; + if (!m || !*pat) { + *step = 0; + return END; + } + *step = 1; + if (pat[0]=='\\' && pat[1] && !(flags & FNM_NOESCAPE)) { + *step = 2; + pat++; + esc = 1; + goto escaped; + } + if (pat[0]=='[') { + size_t k = 1; + if (k= 128U) { + wchar_t wc; + int k = mbtowc(&wc, pat, m); + if (k<0) { + *step = 0; + return UNMATCHABLE; + } + *step = k + esc; + return wc; + } + return pat[0]; +} + +static int casefold(int k) +{ + int c = towupper(k); + return c == k ? towlower(k) : c; +} + +static int match_bracket(const char *p, int k, int kfold) +{ + wchar_t wc; + int inv = 0; + p++; + if (*p=='^' || *p=='!') { + inv = 1; + p++; + } + if (*p==']') { + if (k==']') return !inv; + p++; + } else if (*p=='-') { + if (k=='-') return !inv; + p++; + } + wc = p[-1]; + for (; *p != ']'; p++) { + if (p[0]=='-' && p[1]!=']') { + wchar_t wc2; + int l = mbtowc(&wc2, p+1, 4); + if (l < 0) return 0; + if (wc <= wc2) + if ((unsigned)k-wc <= wc2-wc || + (unsigned)kfold-wc <= wc2-wc) + return !inv; + p += l-1; + continue; + } + if (p[0]=='[' && (p[1]==':' || p[1]=='.' || p[1]=='=')) { + const char *p0 = p+2; + int z = p[1]; + p+=3; + while (p[-1]!=z || p[0]!=']') p++; + if (z == ':' && p-1-p0 < 16) { + char buf[16]; + memcpy(buf, p0, p-1-p0); + buf[p-1-p0] = 0; + if (iswctype(k, wctype(buf)) || + iswctype(kfold, wctype(buf))) + return !inv; + } + continue; + } + if (*p < 128U) { + wc = (unsigned char)*p; + } else { + int l = mbtowc(&wc, p, 4); + if (l < 0) return 0; + p += l-1; + } + if (wc==(wchar_t)k || wc==(wchar_t)kfold) return !inv; + } + return inv; +} + +static int fnmatch_internal(const char *pat, size_t m, const char *str, size_t n, int flags) +{ + const char *p, *ptail, *endpat; + const char *s, *stail, *endstr; + size_t pinc, sinc, tailcnt=0; + int c, k, kfold; + + if (flags & FNM_PERIOD) { + if (*str == '.' && *pat != '.') + return FNM_NOMATCH; + } + for (;;) { + switch ((c = pat_next(pat, m, &pinc, flags))) { + case UNMATCHABLE: + return FNM_NOMATCH; + case STAR: + pat++; + m--; + break; + default: + k = str_next(str, n, &sinc); + if (k <= 0) + return (c==END) ? 0 : FNM_NOMATCH; + str += sinc; + n -= sinc; + kfold = flags & FNM_CASEFOLD ? casefold(k) : k; + if (c == BRACKET) { + if (!match_bracket(pat, k, kfold)) + return FNM_NOMATCH; + } else if (c != QUESTION && k != c && kfold != c) { + return FNM_NOMATCH; + } + pat+=pinc; + m-=pinc; + continue; + } + break; + } + + /* Compute real pat length if it was initially unknown/-1 */ + m = strnlen(pat, m); + endpat = pat + m; + + /* Find the last * in pat and count chars needed after it */ + for (p=ptail=pat; pstr && tailcnt; tailcnt--) { + if (s[-1] < 128U || MB_CUR_MAX==1) s--; + else while ((unsigned char)*--s-0x80U<0x40 && s>str); + } + if (tailcnt) return FNM_NOMATCH; + stail = s; + + /* Check that the pat and str tails match */ + p = ptail; + for (;;) { + c = pat_next(p, endpat-p, &pinc, flags); + p += pinc; + if ((k = str_next(s, endstr-s, &sinc)) <= 0) { + if (c != END) return FNM_NOMATCH; + break; + } + s += sinc; + kfold = flags & FNM_CASEFOLD ? casefold(k) : k; + if (c == BRACKET) { + if (!match_bracket(p-pinc, k, kfold)) + return FNM_NOMATCH; + } else if (c != QUESTION && k != c && kfold != c) { + return FNM_NOMATCH; + } + } + + /* We're all done with the tails now, so throw them out */ + endstr = stail; + endpat = ptail; + + /* Match pattern components until there are none left */ + while (pat 0) str += sinc; + else for (str++; str_next(str, endstr-str, &sinc)<0; str++); + } + + return 0; +} + +int fnmatch(const char *pat, const char *str, int flags) +{ + const char *s, *p; + size_t inc; + int c; + if (flags & FNM_PATHNAME) for (;;) { + for (s=str; *s && *s!='/'; s++); + for (p=pat; (c=pat_next(p, -1, &inc, flags))!=END && c!='/'; p+=inc); + if (c!=*s && (!*s || !(flags & FNM_LEADING_DIR))) + return FNM_NOMATCH; + if (fnmatch_internal(pat, p-pat, str, s-str, flags)) + return FNM_NOMATCH; + if (!c) return 0; + str = s+1; + pat = p+inc; + } else if (flags & FNM_LEADING_DIR) { + for (s=str; *s; s++) { + if (*s != '/') continue; + if (!fnmatch_internal(pat, -1, str, s-str, flags)) + return 0; + } + } + return fnmatch_internal(pat, -1, str, -1, flags); +} diff --git a/lib/mlibc/options/posix/musl-generic-regex/glob.c b/lib/mlibc/options/posix/musl-generic-regex/glob.c new file mode 100644 index 0000000..b57f2f3 --- /dev/null +++ b/lib/mlibc/options/posix/musl-generic-regex/glob.c @@ -0,0 +1,311 @@ +#define _BSD_SOURCE +#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. */ + ptrdiff_t 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; igl_pathv[i] = NULL; + } + for (i=0, tail=head.next; inext, 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; igl_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; +} + +// weak_alias(glob, glob64); +// weak_alias(globfree, globfree64); diff --git a/lib/mlibc/options/posix/musl-generic-regex/regcomp.c b/lib/mlibc/options/posix/musl-generic-regex/regcomp.c new file mode 100644 index 0000000..ab03984 --- /dev/null +++ b/lib/mlibc/options/posix/musl-generic-regex/regcomp.c @@ -0,0 +1,2953 @@ +/* + regcomp.c - TRE POSIX compatible regex compilation functions. + + Copyright (c) 2001-2009 Ville Laurikari + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +#include +#include +#include +#include +#include +#include + +#include "tre.h" + +#include + +/*********************************************************************** + from tre-compile.h +***********************************************************************/ + +typedef struct { + int position; + int code_min; + int code_max; + int *tags; + int assertions; + tre_ctype_t class; + tre_ctype_t *neg_classes; + int backref; +} tre_pos_and_tags_t; + + +/*********************************************************************** + from tre-ast.c and tre-ast.h +***********************************************************************/ + +/* The different AST node types. */ +typedef enum { + LITERAL, + CATENATION, + ITERATION, + UNION +} tre_ast_type_t; + +/* Special subtypes of TRE_LITERAL. */ +#define EMPTY -1 /* Empty leaf (denotes empty string). */ +#define ASSERTION -2 /* Assertion leaf. */ +#define TAG -3 /* Tag leaf. */ +#define BACKREF -4 /* Back reference leaf. */ + +#define IS_SPECIAL(x) ((x)->code_min < 0) +#define IS_EMPTY(x) ((x)->code_min == EMPTY) +#define IS_ASSERTION(x) ((x)->code_min == ASSERTION) +#define IS_TAG(x) ((x)->code_min == TAG) +#define IS_BACKREF(x) ((x)->code_min == BACKREF) + + +/* A generic AST node. All AST nodes consist of this node on the top + level with `obj' pointing to the actual content. */ +typedef struct { + tre_ast_type_t type; /* Type of the node. */ + void *obj; /* Pointer to actual node. */ + int nullable; + int submatch_id; + int num_submatches; + int num_tags; + tre_pos_and_tags_t *firstpos; + tre_pos_and_tags_t *lastpos; +} tre_ast_node_t; + + +/* A "literal" node. These are created for assertions, back references, + tags, matching parameter settings, and all expressions that match one + character. */ +typedef struct { + long code_min; + long code_max; + int position; + tre_ctype_t class; + tre_ctype_t *neg_classes; +} tre_literal_t; + +/* A "catenation" node. These are created when two regexps are concatenated. + If there are more than one subexpressions in sequence, the `left' part + holds all but the last, and `right' part holds the last subexpression + (catenation is left associative). */ +typedef struct { + tre_ast_node_t *left; + tre_ast_node_t *right; +} tre_catenation_t; + +/* An "iteration" node. These are created for the "*", "+", "?", and "{m,n}" + operators. */ +typedef struct { + /* Subexpression to match. */ + tre_ast_node_t *arg; + /* Minimum number of consecutive matches. */ + int min; + /* Maximum number of consecutive matches. */ + int max; + /* If 0, match as many characters as possible, if 1 match as few as + possible. Note that this does not always mean the same thing as + matching as many/few repetitions as possible. */ + unsigned int minimal:1; +} tre_iteration_t; + +/* An "union" node. These are created for the "|" operator. */ +typedef struct { + tre_ast_node_t *left; + tre_ast_node_t *right; +} tre_union_t; + + +static tre_ast_node_t * +tre_ast_new_node(tre_mem_t mem, int type, void *obj) +{ + tre_ast_node_t *node = tre_mem_calloc(mem, sizeof *node); + if (!node || !obj) + return 0; + node->obj = obj; + node->type = type; + node->nullable = -1; + node->submatch_id = -1; + return node; +} + +static tre_ast_node_t * +tre_ast_new_literal(tre_mem_t mem, int code_min, int code_max, int position) +{ + tre_ast_node_t *node; + tre_literal_t *lit; + + lit = tre_mem_calloc(mem, sizeof *lit); + node = tre_ast_new_node(mem, LITERAL, lit); + if (!node) + return 0; + lit->code_min = code_min; + lit->code_max = code_max; + lit->position = position; + return node; +} + +static tre_ast_node_t * +tre_ast_new_iter(tre_mem_t mem, tre_ast_node_t *arg, int min, int max, int minimal) +{ + tre_ast_node_t *node; + tre_iteration_t *iter; + + iter = tre_mem_calloc(mem, sizeof *iter); + node = tre_ast_new_node(mem, ITERATION, iter); + if (!node) + return 0; + iter->arg = arg; + iter->min = min; + iter->max = max; + iter->minimal = minimal; + node->num_submatches = arg->num_submatches; + return node; +} + +static tre_ast_node_t * +tre_ast_new_union(tre_mem_t mem, tre_ast_node_t *left, tre_ast_node_t *right) +{ + tre_ast_node_t *node; + tre_union_t *un; + + if (!left) + return right; + un = tre_mem_calloc(mem, sizeof *un); + node = tre_ast_new_node(mem, UNION, un); + if (!node || !right) + return 0; + un->left = left; + un->right = right; + node->num_submatches = left->num_submatches + right->num_submatches; + return node; +} + +static tre_ast_node_t * +tre_ast_new_catenation(tre_mem_t mem, tre_ast_node_t *left, tre_ast_node_t *right) +{ + tre_ast_node_t *node; + tre_catenation_t *cat; + + if (!left) + return right; + cat = tre_mem_calloc(mem, sizeof *cat); + node = tre_ast_new_node(mem, CATENATION, cat); + if (!node) + return 0; + cat->left = left; + cat->right = right; + node->num_submatches = left->num_submatches + right->num_submatches; + return node; +} + + +/*********************************************************************** + from tre-stack.c and tre-stack.h +***********************************************************************/ + +typedef struct tre_stack_rec tre_stack_t; + +/* Creates a new stack object. `size' is initial size in bytes, `max_size' + is maximum size, and `increment' specifies how much more space will be + allocated with realloc() if all space gets used up. Returns the stack + object or NULL if out of memory. */ +static tre_stack_t * +tre_stack_new(int size, int max_size, int increment); + +/* Frees the stack object. */ +static void +tre_stack_destroy(tre_stack_t *s); + +/* Returns the current number of objects in the stack. */ +static int +tre_stack_num_objects(tre_stack_t *s); + +/* Each tre_stack_push_*(tre_stack_t *s, value) function pushes + `value' on top of stack `s'. Returns REG_ESPACE if out of memory. + This tries to realloc() more space before failing if maximum size + has not yet been reached. Returns REG_OK if successful. */ +#define declare_pushf(typetag, type) \ + static reg_errcode_t tre_stack_push_ ## typetag(tre_stack_t *s, type value) + +declare_pushf(voidptr, void *); +declare_pushf(int, int); + +/* Each tre_stack_pop_*(tre_stack_t *s) function pops the topmost + element off of stack `s' and returns it. The stack must not be + empty. */ +#define declare_popf(typetag, type) \ + static type tre_stack_pop_ ## typetag(tre_stack_t *s) + +declare_popf(voidptr, void *); +declare_popf(int, int); + +/* Just to save some typing. */ +#define STACK_PUSH(s, typetag, value) \ + do \ + { \ + status = tre_stack_push_ ## typetag(s, value); \ + } \ + while (/*CONSTCOND*/0) + +#define STACK_PUSHX(s, typetag, value) \ + { \ + status = tre_stack_push_ ## typetag(s, value); \ + if (status != REG_OK) \ + break; \ + } + +#define STACK_PUSHR(s, typetag, value) \ + { \ + reg_errcode_t _status; \ + _status = tre_stack_push_ ## typetag(s, value); \ + if (_status != REG_OK) \ + return _status; \ + } + +union tre_stack_item { + void *voidptr_value; + int int_value; +}; + +struct tre_stack_rec { + int size; + int max_size; + int increment; + int ptr; + union tre_stack_item *stack; +}; + + +static tre_stack_t * +tre_stack_new(int size, int max_size, int increment) +{ + tre_stack_t *s; + + s = xmalloc(sizeof(*s)); + if (s != NULL) + { + s->stack = xmalloc(sizeof(*s->stack) * size); + if (s->stack == NULL) + { + xfree(s); + return NULL; + } + s->size = size; + s->max_size = max_size; + s->increment = increment; + s->ptr = 0; + } + return s; +} + +static void +tre_stack_destroy(tre_stack_t *s) +{ + xfree(s->stack); + xfree(s); +} + +static int +tre_stack_num_objects(tre_stack_t *s) +{ + return s->ptr; +} + +static reg_errcode_t +tre_stack_push(tre_stack_t *s, union tre_stack_item value) +{ + if (s->ptr < s->size) + { + s->stack[s->ptr] = value; + s->ptr++; + } + else + { + if (s->size >= s->max_size) + { + return REG_ESPACE; + } + else + { + union tre_stack_item *new_buffer; + int new_size; + new_size = s->size + s->increment; + if (new_size > s->max_size) + new_size = s->max_size; + new_buffer = xrealloc(s->stack, sizeof(*new_buffer) * new_size); + if (new_buffer == NULL) + { + return REG_ESPACE; + } + assert(new_size > s->size); + s->size = new_size; + s->stack = new_buffer; + tre_stack_push(s, value); + } + } + return REG_OK; +} + +#define define_pushf(typetag, type) \ + declare_pushf(typetag, type) { \ + union tre_stack_item item; \ + item.typetag ## _value = value; \ + return tre_stack_push(s, item); \ +} + +define_pushf(int, int) +define_pushf(voidptr, void *) + +#define define_popf(typetag, type) \ + declare_popf(typetag, type) { \ + return s->stack[--s->ptr].typetag ## _value; \ + } + +define_popf(int, int) +define_popf(voidptr, void *) + + +/*********************************************************************** + from tre-parse.c and tre-parse.h +***********************************************************************/ + +/* Parse context. */ +typedef struct { + /* Memory allocator. The AST is allocated using this. */ + tre_mem_t mem; + /* Stack used for keeping track of regexp syntax. */ + tre_stack_t *stack; + /* The parsed node after a parse function returns. */ + tre_ast_node_t *n; + /* Position in the regexp pattern after a parse function returns. */ + const char *s; + /* The first character of the last subexpression parsed. */ + const char *start; + /* Current submatch ID. */ + int submatch_id; + /* Current position (number of literal). */ + int position; + /* The highest back reference or -1 if none seen so far. */ + int max_backref; + /* Compilation flags. */ + int cflags; +} tre_parse_ctx_t; + +/* Some macros for expanding \w, \s, etc. */ +static const struct { + char c; + const char *expansion; +} tre_macros[] = { + {'t', "\t"}, {'n', "\n"}, {'r', "\r"}, + {'f', "\f"}, {'a', "\a"}, {'e', "\033"}, + {'w', "[[:alnum:]_]"}, {'W', "[^[:alnum:]_]"}, {'s', "[[:space:]]"}, + {'S', "[^[:space:]]"}, {'d', "[[:digit:]]"}, {'D', "[^[:digit:]]"}, + { 0, 0 } +}; + +/* Expands a macro delimited by `regex' and `regex_end' to `buf', which + must have at least `len' items. Sets buf[0] to zero if the there + is no match in `tre_macros'. */ +static const char *tre_expand_macro(const char *s) +{ + int i; + for (i = 0; tre_macros[i].c && tre_macros[i].c != *s; i++); + return tre_macros[i].expansion; +} + +static int +tre_compare_lit(const void *a, const void *b) +{ + const tre_literal_t *const *la = a; + const tre_literal_t *const *lb = b; + /* assumes the range of valid code_min is < INT_MAX */ + return la[0]->code_min - lb[0]->code_min; +} + +struct literals { + tre_mem_t mem; + tre_literal_t **a; + int len; + int cap; +}; + +static tre_literal_t *tre_new_lit(struct literals *p) +{ + tre_literal_t **a; + if (p->len >= p->cap) { + if (p->cap >= 1<<15) + return 0; + p->cap *= 2; + a = xrealloc(p->a, p->cap * sizeof *p->a); + if (!a) + return 0; + p->a = a; + } + a = p->a + p->len++; + *a = tre_mem_calloc(p->mem, sizeof **a); + return *a; +} + +static int add_icase_literals(struct literals *ls, int min, int max) +{ + tre_literal_t *lit; + int b, e, c; + for (c=min; c<=max; ) { + /* assumes islower(c) and isupper(c) are exclusive + and toupper(c)!=c if islower(c). + multiple opposite case characters are not supported */ + if (tre_islower(c)) { + b = e = tre_toupper(c); + for (c++, e++; c<=max; c++, e++) + if (tre_toupper(c) != e) break; + } else if (tre_isupper(c)) { + b = e = tre_tolower(c); + for (c++, e++; c<=max; c++, e++) + if (tre_tolower(c) != e) break; + } else { + c++; + continue; + } + lit = tre_new_lit(ls); + if (!lit) + return -1; + lit->code_min = b; + lit->code_max = e-1; + lit->position = -1; + } + return 0; +} + + +/* Maximum number of character classes in a negated bracket expression. */ +#define MAX_NEG_CLASSES 64 + +struct neg { + int negate; + int len; + tre_ctype_t a[MAX_NEG_CLASSES]; +}; + +// TODO: parse bracket into a set of non-overlapping [lo,hi] ranges + +/* +bracket grammar: +Bracket = '[' List ']' | '[^' List ']' +List = Term | List Term +Term = Char | Range | Chclass | Eqclass +Range = Char '-' Char | Char '-' '-' +Char = Coll | coll_single +Meta = ']' | '-' +Coll = '[.' coll_single '.]' | '[.' coll_multi '.]' | '[.' Meta '.]' +Eqclass = '[=' coll_single '=]' | '[=' coll_multi '=]' +Chclass = '[:' class ':]' + +coll_single is a single char collating element but it can be + '-' only at the beginning or end of a List and + ']' only at the beginning of a List and + '^' anywhere except after the openning '[' +*/ + +static reg_errcode_t parse_bracket_terms(tre_parse_ctx_t *ctx, const char *s, struct literals *ls, struct neg *neg) +{ + const char *start = s; + tre_ctype_t class; + int min, max; + wchar_t wc; + int len; + + for (;;) { + class = 0; + len = mbtowc(&wc, s, -1); + if (len <= 0) + return *s ? REG_BADPAT : REG_EBRACK; + if (*s == ']' && s != start) { + ctx->s = s+1; + return REG_OK; + } + if (*s == '-' && s != start && s[1] != ']' && + /* extension: [a-z--@] is accepted as [a-z]|[--@] */ + (s[1] != '-' || s[2] == ']')) + return REG_ERANGE; + if (*s == '[' && (s[1] == '.' || s[1] == '=')) + /* collating symbols and equivalence classes are not supported */ + return REG_ECOLLATE; + if (*s == '[' && s[1] == ':') { + char tmp[CHARCLASS_NAME_MAX+1]; + s += 2; + for (len=0; len < CHARCLASS_NAME_MAX && s[len]; len++) { + if (s[len] == ':') { + memcpy(tmp, s, len); + tmp[len] = 0; + class = tre_ctype(tmp); + break; + } + } + if (!class || s[len+1] != ']') + return REG_ECTYPE; + min = 0; + max = TRE_CHAR_MAX; + s += len+2; + } else { + min = max = wc; + s += len; + if (*s == '-' && s[1] != ']') { + s++; + len = mbtowc(&wc, s, -1); + max = wc; + /* XXX - Should use collation order instead of + encoding values in character ranges. */ + if (len <= 0 || min > max) + return REG_ERANGE; + s += len; + } + } + + if (class && neg->negate) { + if (neg->len >= MAX_NEG_CLASSES) + return REG_ESPACE; + neg->a[neg->len++] = class; + } else { + tre_literal_t *lit = tre_new_lit(ls); + if (!lit) + return REG_ESPACE; + lit->code_min = min; + lit->code_max = max; + lit->class = class; + lit->position = -1; + + /* Add opposite-case codepoints if REG_ICASE is present. + It seems that POSIX requires that bracket negation + should happen before case-folding, but most practical + implementations do it the other way around. Changing + the order would need efficient representation of + case-fold ranges and bracket range sets even with + simple patterns so this is ok for now. */ + if (ctx->cflags & REG_ICASE && !class) + if (add_icase_literals(ls, min, max)) + return REG_ESPACE; + } + } +} + +static reg_errcode_t parse_bracket(tre_parse_ctx_t *ctx, const char *s) +{ + int i, max, min, negmax, negmin; + tre_ast_node_t *node = 0, *n; + tre_ctype_t *nc = 0; + tre_literal_t *lit; + struct literals ls; + struct neg neg; + reg_errcode_t err; + + ls.mem = ctx->mem; + ls.len = 0; + ls.cap = 32; + ls.a = xmalloc(ls.cap * sizeof *ls.a); + if (!ls.a) + return REG_ESPACE; + neg.len = 0; + neg.negate = *s == '^'; + if (neg.negate) + s++; + + err = parse_bracket_terms(ctx, s, &ls, &neg); + if (err != REG_OK) + goto parse_bracket_done; + + if (neg.negate) { + /* + * With REG_NEWLINE, POSIX requires that newlines are not matched by + * any form of a non-matching list. + */ + if (ctx->cflags & REG_NEWLINE) { + lit = tre_new_lit(&ls); + if (!lit) { + err = REG_ESPACE; + goto parse_bracket_done; + } + lit->code_min = '\n'; + lit->code_max = '\n'; + lit->position = -1; + } + /* Sort the array if we need to negate it. */ + qsort(ls.a, ls.len, sizeof *ls.a, tre_compare_lit); + /* extra lit for the last negated range */ + lit = tre_new_lit(&ls); + if (!lit) { + err = REG_ESPACE; + goto parse_bracket_done; + } + lit->code_min = TRE_CHAR_MAX+1; + lit->code_max = TRE_CHAR_MAX+1; + lit->position = -1; + /* negated classes */ + if (neg.len) { + nc = tre_mem_alloc(ctx->mem, (neg.len+1)*sizeof *neg.a); + if (!nc) { + err = REG_ESPACE; + goto parse_bracket_done; + } + memcpy(nc, neg.a, neg.len*sizeof *neg.a); + nc[neg.len] = 0; + } + } + + /* Build a union of the items in the array, negated if necessary. */ + negmax = negmin = 0; + for (i = 0; i < ls.len; i++) { + lit = ls.a[i]; + min = lit->code_min; + max = lit->code_max; + if (neg.negate) { + if (min <= negmin) { + /* Overlap. */ + negmin = MAX(max + 1, negmin); + continue; + } + negmax = min - 1; + lit->code_min = negmin; + lit->code_max = negmax; + negmin = max + 1; + } + lit->position = ctx->position; + lit->neg_classes = nc; + n = tre_ast_new_node(ctx->mem, LITERAL, lit); + node = tre_ast_new_union(ctx->mem, node, n); + if (!node) { + err = REG_ESPACE; + break; + } + } + +parse_bracket_done: + xfree(ls.a); + ctx->position++; + ctx->n = node; + return err; +} + +static const char *parse_dup_count(const char *s, int *n) +{ + *n = -1; + if (!isdigit(*s)) + return s; + *n = 0; + for (;;) { + *n = 10 * *n + (*s - '0'); + s++; + if (!isdigit(*s) || *n > RE_DUP_MAX) + break; + } + return s; +} + +static const char *parse_dup(const char *s, int ere, int *pmin, int *pmax) +{ + int min, max; + + s = parse_dup_count(s, &min); + if (*s == ',') + s = parse_dup_count(s+1, &max); + else + max = min; + + if ( + (max < min && max >= 0) || + max > RE_DUP_MAX || + min > RE_DUP_MAX || + min < 0 || + (!ere && *s++ != '\\') || + *s++ != '}' + ) + return 0; + *pmin = min; + *pmax = max; + return s; +} + +static int hexval(unsigned c) +{ + if (c-'0'<10) return c-'0'; + c |= 32; + if (c-'a'<6) return c-'a'+10; + return -1; +} + +static reg_errcode_t marksub(tre_parse_ctx_t *ctx, tre_ast_node_t *node, int subid) +{ + if (node->submatch_id >= 0) { + tre_ast_node_t *n = tre_ast_new_literal(ctx->mem, EMPTY, -1, -1); + if (!n) + return REG_ESPACE; + n = tre_ast_new_catenation(ctx->mem, n, node); + if (!n) + return REG_ESPACE; + n->num_submatches = node->num_submatches; + node = n; + } + node->submatch_id = subid; + node->num_submatches++; + ctx->n = node; + return REG_OK; +} + +/* +BRE grammar: +Regex = Branch | '^' | '$' | '^$' | '^' Branch | Branch '$' | '^' Branch '$' +Branch = Atom | Branch Atom +Atom = char | quoted_char | '.' | Bracket | Atom Dup | '\(' Branch '\)' | back_ref +Dup = '*' | '\{' Count '\}' | '\{' Count ',\}' | '\{' Count ',' Count '\}' + +(leading ^ and trailing $ in a sub expr may be an anchor or literal as well) + +ERE grammar: +Regex = Branch | Regex '|' Branch +Branch = Atom | Branch Atom +Atom = char | quoted_char | '.' | Bracket | Atom Dup | '(' Regex ')' | '^' | '$' +Dup = '*' | '+' | '?' | '{' Count '}' | '{' Count ',}' | '{' Count ',' Count '}' + +(a*+?, ^*, $+, \X, {, (|a) are unspecified) +*/ + +static reg_errcode_t parse_atom(tre_parse_ctx_t *ctx, const char *s) +{ + int len, ere = ctx->cflags & REG_EXTENDED; + const char *p; + tre_ast_node_t *node; + wchar_t wc; + switch (*s) { + case '[': + return parse_bracket(ctx, s+1); + case '\\': + p = tre_expand_macro(s+1); + if (p) { + /* assume \X expansion is a single atom */ + reg_errcode_t err = parse_atom(ctx, p); + ctx->s = s+2; + return err; + } + /* extensions: \b, \B, \<, \>, \xHH \x{HHHH} */ + switch (*++s) { + case 0: + return REG_EESCAPE; + case 'b': + node = tre_ast_new_literal(ctx->mem, ASSERTION, ASSERT_AT_WB, -1); + break; + case 'B': + node = tre_ast_new_literal(ctx->mem, ASSERTION, ASSERT_AT_WB_NEG, -1); + break; + case '<': + node = tre_ast_new_literal(ctx->mem, ASSERTION, ASSERT_AT_BOW, -1); + break; + case '>': + node = tre_ast_new_literal(ctx->mem, ASSERTION, ASSERT_AT_EOW, -1); + break; + case 'x': + s++; + int i, v = 0, c; + len = 2; + if (*s == '{') { + len = 8; + s++; + } + for (i=0; imem, v, v, ctx->position++); + s--; + break; + case '{': + case '+': + case '?': + /* extension: treat \+, \? as repetitions in BRE */ + /* reject repetitions after empty expression in BRE */ + if (!ere) + return REG_BADRPT; + case '|': + /* extension: treat \| as alternation in BRE */ + if (!ere) { + node = tre_ast_new_literal(ctx->mem, EMPTY, -1, -1); + s--; + goto end; + } + /* fallthrough */ + default: + if (!ere && (unsigned)*s-'1' < 9) { + /* back reference */ + int val = *s - '0'; + node = tre_ast_new_literal(ctx->mem, BACKREF, val, ctx->position++); + ctx->max_backref = MAX(val, ctx->max_backref); + } else { + /* extension: accept unknown escaped char + as a literal */ + goto parse_literal; + } + } + s++; + break; + case '.': + if (ctx->cflags & REG_NEWLINE) { + tre_ast_node_t *tmp1, *tmp2; + tmp1 = tre_ast_new_literal(ctx->mem, 0, '\n'-1, ctx->position++); + tmp2 = tre_ast_new_literal(ctx->mem, '\n'+1, TRE_CHAR_MAX, ctx->position++); + if (tmp1 && tmp2) + node = tre_ast_new_union(ctx->mem, tmp1, tmp2); + else + node = 0; + } else { + node = tre_ast_new_literal(ctx->mem, 0, TRE_CHAR_MAX, ctx->position++); + } + s++; + break; + case '^': + /* '^' has a special meaning everywhere in EREs, and at beginning of BRE. */ + if (!ere && s != ctx->start) + goto parse_literal; + node = tre_ast_new_literal(ctx->mem, ASSERTION, ASSERT_AT_BOL, -1); + s++; + break; + case '$': + /* '$' is special everywhere in EREs, and at the end of a BRE subexpression. */ + if (!ere && s[1] && (s[1]!='\\'|| (s[2]!=')' && s[2]!='|'))) + goto parse_literal; + node = tre_ast_new_literal(ctx->mem, ASSERTION, ASSERT_AT_EOL, -1); + s++; + break; + case '*': + case '{': + case '+': + case '?': + /* reject repetitions after empty expression in ERE */ + if (ere) + return REG_BADRPT; + case '|': + if (!ere) + goto parse_literal; + case 0: + node = tre_ast_new_literal(ctx->mem, EMPTY, -1, -1); + break; + default: +parse_literal: + len = mbtowc(&wc, s, -1); + if (len < 0) + return REG_BADPAT; + if (ctx->cflags & REG_ICASE && (tre_isupper(wc) || tre_islower(wc))) { + tre_ast_node_t *tmp1, *tmp2; + /* multiple opposite case characters are not supported */ + tmp1 = tre_ast_new_literal(ctx->mem, tre_toupper(wc), tre_toupper(wc), ctx->position); + tmp2 = tre_ast_new_literal(ctx->mem, tre_tolower(wc), tre_tolower(wc), ctx->position); + if (tmp1 && tmp2) + node = tre_ast_new_union(ctx->mem, tmp1, tmp2); + else + node = 0; + } else { + node = tre_ast_new_literal(ctx->mem, wc, wc, ctx->position); + } + ctx->position++; + s += len; + break; + } +end: + if (!node) + return REG_ESPACE; + ctx->n = node; + ctx->s = s; + return REG_OK; +} + +#define PUSHPTR(err, s, v) do { \ + if ((err = tre_stack_push_voidptr(s, v)) != REG_OK) \ + return err; \ +} while(0) + +#define PUSHINT(err, s, v) do { \ + if ((err = tre_stack_push_int(s, v)) != REG_OK) \ + return err; \ +} while(0) + +static reg_errcode_t tre_parse(tre_parse_ctx_t *ctx) +{ + tre_ast_node_t *nbranch=0, *nunion=0; + int ere = ctx->cflags & REG_EXTENDED; + const char *s = ctx->start; + int subid = 0; + int depth = 0; + reg_errcode_t err; + tre_stack_t *stack = ctx->stack; + + PUSHINT(err, stack, subid++); + for (;;) { + if ((!ere && *s == '\\' && s[1] == '(') || + (ere && *s == '(')) { + PUSHPTR(err, stack, nunion); + PUSHPTR(err, stack, nbranch); + PUSHINT(err, stack, subid++); + s++; + if (!ere) + s++; + depth++; + nbranch = nunion = 0; + ctx->start = s; + continue; + } + if ((!ere && *s == '\\' && s[1] == ')') || + (ere && *s == ')' && depth)) { + ctx->n = tre_ast_new_literal(ctx->mem, EMPTY, -1, -1); + if (!ctx->n) + return REG_ESPACE; + } else { + err = parse_atom(ctx, s); + if (err != REG_OK) + return err; + s = ctx->s; + } + + parse_iter: + for (;;) { + int min, max; + + if (*s!='\\' && *s!='*') { + if (!ere) + break; + if (*s!='+' && *s!='?' && *s!='{') + break; + } + if (*s=='\\' && ere) + break; + /* extension: treat \+, \? as repetitions in BRE */ + if (*s=='\\' && s[1]!='+' && s[1]!='?' && s[1]!='{') + break; + if (*s=='\\') + s++; + + /* handle ^* at the start of a BRE. */ + if (!ere && s==ctx->start+1 && s[-1]=='^') + break; + + /* extension: multiple consecutive *+?{,} is unspecified, + but (a+)+ has to be supported so accepting a++ makes + sense, note however that the RE_DUP_MAX limit can be + circumvented: (a{255}){255} uses a lot of memory.. */ + if (*s=='{') { + s = parse_dup(s+1, ere, &min, &max); + if (!s) + return REG_BADBR; + } else { + min=0; + max=-1; + if (*s == '+') + min = 1; + if (*s == '?') + max = 1; + s++; + } + if (max == 0) + ctx->n = tre_ast_new_literal(ctx->mem, EMPTY, -1, -1); + else + ctx->n = tre_ast_new_iter(ctx->mem, ctx->n, min, max, 0); + if (!ctx->n) + return REG_ESPACE; + } + + nbranch = tre_ast_new_catenation(ctx->mem, nbranch, ctx->n); + if ((ere && *s == '|') || + (ere && *s == ')' && depth) || + (!ere && *s == '\\' && s[1] == ')') || + /* extension: treat \| as alternation in BRE */ + (!ere && *s == '\\' && s[1] == '|') || + !*s) { + /* extension: empty branch is unspecified (), (|a), (a|) + here they are not rejected but match on empty string */ + int c = *s; + nunion = tre_ast_new_union(ctx->mem, nunion, nbranch); + nbranch = 0; + + if (c == '\\' && s[1] == '|') { + s+=2; + ctx->start = s; + } else if (c == '|') { + s++; + ctx->start = s; + } else { + if (c == '\\') { + if (!depth) return REG_EPAREN; + s+=2; + } else if (c == ')') + s++; + depth--; + err = marksub(ctx, nunion, tre_stack_pop_int(stack)); + if (err != REG_OK) + return err; + if (!c && depth<0) { + ctx->submatch_id = subid; + return REG_OK; + } + if (!c || depth<0) + return REG_EPAREN; + nbranch = tre_stack_pop_voidptr(stack); + nunion = tre_stack_pop_voidptr(stack); + goto parse_iter; + } + } + } +} + + +/*********************************************************************** + from tre-compile.c +***********************************************************************/ + + +/* + TODO: + - Fix tre_ast_to_tnfa() to recurse using a stack instead of recursive + function calls. +*/ + +/* + Algorithms to setup tags so that submatch addressing can be done. +*/ + + +/* Inserts a catenation node to the root of the tree given in `node'. + As the left child a new tag with number `tag_id' to `node' is added, + and the right child is the old root. */ +static reg_errcode_t +tre_add_tag_left(tre_mem_t mem, tre_ast_node_t *node, int tag_id) +{ + tre_catenation_t *c; + + c = tre_mem_alloc(mem, sizeof(*c)); + if (c == NULL) + return REG_ESPACE; + c->left = tre_ast_new_literal(mem, TAG, tag_id, -1); + if (c->left == NULL) + return REG_ESPACE; + c->right = tre_mem_alloc(mem, sizeof(tre_ast_node_t)); + if (c->right == NULL) + return REG_ESPACE; + + c->right->obj = node->obj; + c->right->type = node->type; + c->right->nullable = -1; + c->right->submatch_id = -1; + c->right->firstpos = NULL; + c->right->lastpos = NULL; + c->right->num_tags = 0; + c->right->num_submatches = 0; + node->obj = c; + node->type = CATENATION; + return REG_OK; +} + +/* Inserts a catenation node to the root of the tree given in `node'. + As the right child a new tag with number `tag_id' to `node' is added, + and the left child is the old root. */ +static reg_errcode_t +tre_add_tag_right(tre_mem_t mem, tre_ast_node_t *node, int tag_id) +{ + tre_catenation_t *c; + + c = tre_mem_alloc(mem, sizeof(*c)); + if (c == NULL) + return REG_ESPACE; + c->right = tre_ast_new_literal(mem, TAG, tag_id, -1); + if (c->right == NULL) + return REG_ESPACE; + c->left = tre_mem_alloc(mem, sizeof(tre_ast_node_t)); + if (c->left == NULL) + return REG_ESPACE; + + c->left->obj = node->obj; + c->left->type = node->type; + c->left->nullable = -1; + c->left->submatch_id = -1; + c->left->firstpos = NULL; + c->left->lastpos = NULL; + c->left->num_tags = 0; + c->left->num_submatches = 0; + node->obj = c; + node->type = CATENATION; + return REG_OK; +} + +typedef enum { + ADDTAGS_RECURSE, + ADDTAGS_AFTER_ITERATION, + ADDTAGS_AFTER_UNION_LEFT, + ADDTAGS_AFTER_UNION_RIGHT, + ADDTAGS_AFTER_CAT_LEFT, + ADDTAGS_AFTER_CAT_RIGHT, + ADDTAGS_SET_SUBMATCH_END +} tre_addtags_symbol_t; + + +typedef struct { + int tag; + int next_tag; +} tre_tag_states_t; + + +/* Go through `regset' and set submatch data for submatches that are + using this tag. */ +static void +tre_purge_regset(int *regset, tre_tnfa_t *tnfa, int tag) +{ + int i; + + for (i = 0; regset[i] >= 0; i++) + { + int id = regset[i] / 2; + int start = !(regset[i] % 2); + if (start) + tnfa->submatch_data[id].so_tag = tag; + else + tnfa->submatch_data[id].eo_tag = tag; + } + regset[0] = -1; +} + + +/* Adds tags to appropriate locations in the parse tree in `tree', so that + subexpressions marked for submatch addressing can be traced. */ +static reg_errcode_t +tre_add_tags(tre_mem_t mem, tre_stack_t *stack, tre_ast_node_t *tree, + tre_tnfa_t *tnfa) +{ + reg_errcode_t status = REG_OK; + tre_addtags_symbol_t symbol; + tre_ast_node_t *node = tree; /* Tree node we are currently looking at. */ + int bottom = tre_stack_num_objects(stack); + /* True for first pass (counting number of needed tags) */ + int first_pass = (mem == NULL || tnfa == NULL); + int *regset, *orig_regset; + int num_tags = 0; /* Total number of tags. */ + int num_minimals = 0; /* Number of special minimal tags. */ + int tag = 0; /* The tag that is to be added next. */ + int next_tag = 1; /* Next tag to use after this one. */ + int *parents; /* Stack of submatches the current submatch is + contained in. */ + int minimal_tag = -1; /* Tag that marks the beginning of a minimal match. */ + tre_tag_states_t *saved_states; + + tre_tag_direction_t direction = TRE_TAG_MINIMIZE; + if (!first_pass) + { + tnfa->end_tag = 0; + tnfa->minimal_tags[0] = -1; + } + + regset = xmalloc(sizeof(*regset) * ((tnfa->num_submatches + 1) * 2)); + if (regset == NULL) + return REG_ESPACE; + regset[0] = -1; + orig_regset = regset; + + parents = xmalloc(sizeof(*parents) * (tnfa->num_submatches + 1)); + if (parents == NULL) + { + xfree(regset); + return REG_ESPACE; + } + parents[0] = -1; + + saved_states = xmalloc(sizeof(*saved_states) * (tnfa->num_submatches + 1)); + if (saved_states == NULL) + { + xfree(regset); + xfree(parents); + return REG_ESPACE; + } + else + { + unsigned int i; + for (i = 0; i <= tnfa->num_submatches; i++) + saved_states[i].tag = -1; + } + + STACK_PUSH(stack, voidptr, node); + STACK_PUSH(stack, int, ADDTAGS_RECURSE); + + while (tre_stack_num_objects(stack) > bottom) + { + if (status != REG_OK) + break; + + symbol = (tre_addtags_symbol_t)tre_stack_pop_int(stack); + switch (symbol) + { + + case ADDTAGS_SET_SUBMATCH_END: + { + int id = tre_stack_pop_int(stack); + int i; + + /* Add end of this submatch to regset. */ + for (i = 0; regset[i] >= 0; i++); + regset[i] = id * 2 + 1; + regset[i + 1] = -1; + + /* Pop this submatch from the parents stack. */ + for (i = 0; parents[i] >= 0; i++); + parents[i - 1] = -1; + break; + } + + case ADDTAGS_RECURSE: + node = tre_stack_pop_voidptr(stack); + + if (node->submatch_id >= 0) + { + int id = node->submatch_id; + int i; + + + /* Add start of this submatch to regset. */ + for (i = 0; regset[i] >= 0; i++); + regset[i] = id * 2; + regset[i + 1] = -1; + + if (!first_pass) + { + for (i = 0; parents[i] >= 0; i++); + tnfa->submatch_data[id].parents = NULL; + if (i > 0) + { + int *p = xmalloc(sizeof(*p) * (i + 1)); + if (p == NULL) + { + status = REG_ESPACE; + break; + } + assert(tnfa->submatch_data[id].parents == NULL); + tnfa->submatch_data[id].parents = p; + for (i = 0; parents[i] >= 0; i++) + p[i] = parents[i]; + p[i] = -1; + } + } + + /* Add end of this submatch to regset after processing this + node. */ + STACK_PUSHX(stack, int, node->submatch_id); + STACK_PUSHX(stack, int, ADDTAGS_SET_SUBMATCH_END); + } + + switch (node->type) + { + case LITERAL: + { + tre_literal_t *lit = node->obj; + + if (!IS_SPECIAL(lit) || IS_BACKREF(lit)) + { + int i; + if (regset[0] >= 0) + { + /* Regset is not empty, so add a tag before the + literal or backref. */ + if (!first_pass) + { + status = tre_add_tag_left(mem, node, tag); + tnfa->tag_directions[tag] = direction; + if (minimal_tag >= 0) + { + for (i = 0; tnfa->minimal_tags[i] >= 0; i++); + tnfa->minimal_tags[i] = tag; + tnfa->minimal_tags[i + 1] = minimal_tag; + tnfa->minimal_tags[i + 2] = -1; + minimal_tag = -1; + num_minimals++; + } + tre_purge_regset(regset, tnfa, tag); + } + else + { + node->num_tags = 1; + } + + regset[0] = -1; + tag = next_tag; + num_tags++; + next_tag++; + } + } + else + { + assert(!IS_TAG(lit)); + } + break; + } + case CATENATION: + { + tre_catenation_t *cat = node->obj; + tre_ast_node_t *left = cat->left; + tre_ast_node_t *right = cat->right; + int reserved_tag = -1; + + + /* After processing right child. */ + STACK_PUSHX(stack, voidptr, node); + STACK_PUSHX(stack, int, ADDTAGS_AFTER_CAT_RIGHT); + + /* Process right child. */ + STACK_PUSHX(stack, voidptr, right); + STACK_PUSHX(stack, int, ADDTAGS_RECURSE); + + /* After processing left child. */ + STACK_PUSHX(stack, int, next_tag + left->num_tags); + if (left->num_tags > 0 && right->num_tags > 0) + { + /* Reserve the next tag to the right child. */ + reserved_tag = next_tag; + next_tag++; + } + STACK_PUSHX(stack, int, reserved_tag); + STACK_PUSHX(stack, int, ADDTAGS_AFTER_CAT_LEFT); + + /* Process left child. */ + STACK_PUSHX(stack, voidptr, left); + STACK_PUSHX(stack, int, ADDTAGS_RECURSE); + + } + break; + case ITERATION: + { + tre_iteration_t *iter = node->obj; + + if (first_pass) + { + STACK_PUSHX(stack, int, regset[0] >= 0 || iter->minimal); + } + else + { + STACK_PUSHX(stack, int, tag); + STACK_PUSHX(stack, int, iter->minimal); + } + STACK_PUSHX(stack, voidptr, node); + STACK_PUSHX(stack, int, ADDTAGS_AFTER_ITERATION); + + STACK_PUSHX(stack, voidptr, iter->arg); + STACK_PUSHX(stack, int, ADDTAGS_RECURSE); + + /* Regset is not empty, so add a tag here. */ + if (regset[0] >= 0 || iter->minimal) + { + if (!first_pass) + { + int i; + status = tre_add_tag_left(mem, node, tag); + if (iter->minimal) + tnfa->tag_directions[tag] = TRE_TAG_MAXIMIZE; + else + tnfa->tag_directions[tag] = direction; + if (minimal_tag >= 0) + { + for (i = 0; tnfa->minimal_tags[i] >= 0; i++); + tnfa->minimal_tags[i] = tag; + tnfa->minimal_tags[i + 1] = minimal_tag; + tnfa->minimal_tags[i + 2] = -1; + minimal_tag = -1; + num_minimals++; + } + tre_purge_regset(regset, tnfa, tag); + } + + regset[0] = -1; + tag = next_tag; + num_tags++; + next_tag++; + } + direction = TRE_TAG_MINIMIZE; + } + break; + case UNION: + { + tre_union_t *uni = node->obj; + tre_ast_node_t *left = uni->left; + tre_ast_node_t *right = uni->right; + int left_tag; + int right_tag; + + if (regset[0] >= 0) + { + left_tag = next_tag; + right_tag = next_tag + 1; + } + else + { + left_tag = tag; + right_tag = next_tag; + } + + /* After processing right child. */ + STACK_PUSHX(stack, int, right_tag); + STACK_PUSHX(stack, int, left_tag); + STACK_PUSHX(stack, voidptr, regset); + STACK_PUSHX(stack, int, regset[0] >= 0); + STACK_PUSHX(stack, voidptr, node); + STACK_PUSHX(stack, voidptr, right); + STACK_PUSHX(stack, voidptr, left); + STACK_PUSHX(stack, int, ADDTAGS_AFTER_UNION_RIGHT); + + /* Process right child. */ + STACK_PUSHX(stack, voidptr, right); + STACK_PUSHX(stack, int, ADDTAGS_RECURSE); + + /* After processing left child. */ + STACK_PUSHX(stack, int, ADDTAGS_AFTER_UNION_LEFT); + + /* Process left child. */ + STACK_PUSHX(stack, voidptr, left); + STACK_PUSHX(stack, int, ADDTAGS_RECURSE); + + /* Regset is not empty, so add a tag here. */ + if (regset[0] >= 0) + { + if (!first_pass) + { + int i; + status = tre_add_tag_left(mem, node, tag); + tnfa->tag_directions[tag] = direction; + if (minimal_tag >= 0) + { + for (i = 0; tnfa->minimal_tags[i] >= 0; i++); + tnfa->minimal_tags[i] = tag; + tnfa->minimal_tags[i + 1] = minimal_tag; + tnfa->minimal_tags[i + 2] = -1; + minimal_tag = -1; + num_minimals++; + } + tre_purge_regset(regset, tnfa, tag); + } + + regset[0] = -1; + tag = next_tag; + num_tags++; + next_tag++; + } + + if (node->num_submatches > 0) + { + /* The next two tags are reserved for markers. */ + next_tag++; + tag = next_tag; + next_tag++; + } + + break; + } + } + + if (node->submatch_id >= 0) + { + int i; + /* Push this submatch on the parents stack. */ + for (i = 0; parents[i] >= 0; i++); + parents[i] = node->submatch_id; + parents[i + 1] = -1; + } + + break; /* end case: ADDTAGS_RECURSE */ + + case ADDTAGS_AFTER_ITERATION: + { + int minimal = 0; + int enter_tag; + node = tre_stack_pop_voidptr(stack); + if (first_pass) + { + node->num_tags = ((tre_iteration_t *)node->obj)->arg->num_tags + + tre_stack_pop_int(stack); + minimal_tag = -1; + } + else + { + minimal = tre_stack_pop_int(stack); + enter_tag = tre_stack_pop_int(stack); + if (minimal) + minimal_tag = enter_tag; + } + + if (!first_pass) + { + if (minimal) + direction = TRE_TAG_MINIMIZE; + else + direction = TRE_TAG_MAXIMIZE; + } + break; + } + + case ADDTAGS_AFTER_CAT_LEFT: + { + int new_tag = tre_stack_pop_int(stack); + next_tag = tre_stack_pop_int(stack); + if (new_tag >= 0) + { + tag = new_tag; + } + break; + } + + case ADDTAGS_AFTER_CAT_RIGHT: + node = tre_stack_pop_voidptr(stack); + if (first_pass) + node->num_tags = ((tre_catenation_t *)node->obj)->left->num_tags + + ((tre_catenation_t *)node->obj)->right->num_tags; + break; + + case ADDTAGS_AFTER_UNION_LEFT: + /* Lift the bottom of the `regset' array so that when processing + the right operand the items currently in the array are + invisible. The original bottom was saved at ADDTAGS_UNION and + will be restored at ADDTAGS_AFTER_UNION_RIGHT below. */ + while (*regset >= 0) + regset++; + break; + + case ADDTAGS_AFTER_UNION_RIGHT: + { + int added_tags, tag_left, tag_right; + tre_ast_node_t *left = tre_stack_pop_voidptr(stack); + tre_ast_node_t *right = tre_stack_pop_voidptr(stack); + node = tre_stack_pop_voidptr(stack); + added_tags = tre_stack_pop_int(stack); + if (first_pass) + { + node->num_tags = ((tre_union_t *)node->obj)->left->num_tags + + ((tre_union_t *)node->obj)->right->num_tags + added_tags + + ((node->num_submatches > 0) ? 2 : 0); + } + regset = tre_stack_pop_voidptr(stack); + tag_left = tre_stack_pop_int(stack); + tag_right = tre_stack_pop_int(stack); + + /* Add tags after both children, the left child gets a smaller + tag than the right child. This guarantees that we prefer + the left child over the right child. */ + /* XXX - This is not always necessary (if the children have + tags which must be seen for every match of that child). */ + /* XXX - Check if this is the only place where tre_add_tag_right + is used. If so, use tre_add_tag_left (putting the tag before + the child as opposed after the child) and throw away + tre_add_tag_right. */ + if (node->num_submatches > 0) + { + if (!first_pass) + { + status = tre_add_tag_right(mem, left, tag_left); + tnfa->tag_directions[tag_left] = TRE_TAG_MAXIMIZE; + if (status == REG_OK) + status = tre_add_tag_right(mem, right, tag_right); + tnfa->tag_directions[tag_right] = TRE_TAG_MAXIMIZE; + } + num_tags += 2; + } + direction = TRE_TAG_MAXIMIZE; + break; + } + + default: + assert(0); + break; + + } /* end switch(symbol) */ + } /* end while(tre_stack_num_objects(stack) > bottom) */ + + if (!first_pass) + tre_purge_regset(regset, tnfa, tag); + + if (!first_pass && minimal_tag >= 0) + { + int i; + for (i = 0; tnfa->minimal_tags[i] >= 0; i++); + tnfa->minimal_tags[i] = tag; + tnfa->minimal_tags[i + 1] = minimal_tag; + tnfa->minimal_tags[i + 2] = -1; + minimal_tag = -1; + num_minimals++; + } + + assert(tree->num_tags == num_tags); + tnfa->end_tag = num_tags; + tnfa->num_tags = num_tags; + tnfa->num_minimals = num_minimals; + xfree(orig_regset); + xfree(parents); + xfree(saved_states); + return status; +} + + + +/* + AST to TNFA compilation routines. +*/ + +typedef enum { + COPY_RECURSE, + COPY_SET_RESULT_PTR +} tre_copyast_symbol_t; + +/* Flags for tre_copy_ast(). */ +#define COPY_REMOVE_TAGS 1 +#define COPY_MAXIMIZE_FIRST_TAG 2 + +static reg_errcode_t +tre_copy_ast(tre_mem_t mem, tre_stack_t *stack, tre_ast_node_t *ast, + int flags, int *pos_add, tre_tag_direction_t *tag_directions, + tre_ast_node_t **copy, int *max_pos) +{ + reg_errcode_t status = REG_OK; + int bottom = tre_stack_num_objects(stack); + int num_copied = 0; + int first_tag = 1; + tre_ast_node_t **result = copy; + tre_copyast_symbol_t symbol; + + STACK_PUSH(stack, voidptr, ast); + STACK_PUSH(stack, int, COPY_RECURSE); + + while (status == REG_OK && tre_stack_num_objects(stack) > bottom) + { + tre_ast_node_t *node; + if (status != REG_OK) + break; + + symbol = (tre_copyast_symbol_t)tre_stack_pop_int(stack); + switch (symbol) + { + case COPY_SET_RESULT_PTR: + result = tre_stack_pop_voidptr(stack); + break; + case COPY_RECURSE: + node = tre_stack_pop_voidptr(stack); + switch (node->type) + { + case LITERAL: + { + tre_literal_t *lit = node->obj; + int pos = lit->position; + int min = lit->code_min; + int max = lit->code_max; + if (!IS_SPECIAL(lit) || IS_BACKREF(lit)) + { + /* XXX - e.g. [ab] has only one position but two + nodes, so we are creating holes in the state space + here. Not fatal, just wastes memory. */ + pos += *pos_add; + num_copied++; + } + else if (IS_TAG(lit) && (flags & COPY_REMOVE_TAGS)) + { + /* Change this tag to empty. */ + min = EMPTY; + max = pos = -1; + } + else if (IS_TAG(lit) && (flags & COPY_MAXIMIZE_FIRST_TAG) + && first_tag) + { + /* Maximize the first tag. */ + tag_directions[max] = TRE_TAG_MAXIMIZE; + first_tag = 0; + } + *result = tre_ast_new_literal(mem, min, max, pos); + if (*result == NULL) + status = REG_ESPACE; + else { + tre_literal_t *p = (*result)->obj; + p->class = lit->class; + p->neg_classes = lit->neg_classes; + } + + if (pos > *max_pos) + *max_pos = pos; + break; + } + case UNION: + { + tre_union_t *uni = node->obj; + tre_union_t *tmp; + *result = tre_ast_new_union(mem, uni->left, uni->right); + if (*result == NULL) + { + status = REG_ESPACE; + break; + } + tmp = (*result)->obj; + result = &tmp->left; + STACK_PUSHX(stack, voidptr, uni->right); + STACK_PUSHX(stack, int, COPY_RECURSE); + STACK_PUSHX(stack, voidptr, &tmp->right); + STACK_PUSHX(stack, int, COPY_SET_RESULT_PTR); + STACK_PUSHX(stack, voidptr, uni->left); + STACK_PUSHX(stack, int, COPY_RECURSE); + break; + } + case CATENATION: + { + tre_catenation_t *cat = node->obj; + tre_catenation_t *tmp; + *result = tre_ast_new_catenation(mem, cat->left, cat->right); + if (*result == NULL) + { + status = REG_ESPACE; + break; + } + tmp = (*result)->obj; + tmp->left = NULL; + tmp->right = NULL; + result = &tmp->left; + + STACK_PUSHX(stack, voidptr, cat->right); + STACK_PUSHX(stack, int, COPY_RECURSE); + STACK_PUSHX(stack, voidptr, &tmp->right); + STACK_PUSHX(stack, int, COPY_SET_RESULT_PTR); + STACK_PUSHX(stack, voidptr, cat->left); + STACK_PUSHX(stack, int, COPY_RECURSE); + break; + } + case ITERATION: + { + tre_iteration_t *iter = node->obj; + STACK_PUSHX(stack, voidptr, iter->arg); + STACK_PUSHX(stack, int, COPY_RECURSE); + *result = tre_ast_new_iter(mem, iter->arg, iter->min, + iter->max, iter->minimal); + if (*result == NULL) + { + status = REG_ESPACE; + break; + } + iter = (*result)->obj; + result = &iter->arg; + break; + } + default: + assert(0); + break; + } + break; + } + } + *pos_add += num_copied; + return status; +} + +typedef enum { + EXPAND_RECURSE, + EXPAND_AFTER_ITER +} tre_expand_ast_symbol_t; + +/* Expands each iteration node that has a finite nonzero minimum or maximum + iteration count to a catenated sequence of copies of the node. */ +static reg_errcode_t +tre_expand_ast(tre_mem_t mem, tre_stack_t *stack, tre_ast_node_t *ast, + int *position, tre_tag_direction_t *tag_directions) +{ + reg_errcode_t status = REG_OK; + int bottom = tre_stack_num_objects(stack); + int pos_add = 0; + int pos_add_total = 0; + int max_pos = 0; + int iter_depth = 0; + + STACK_PUSHR(stack, voidptr, ast); + STACK_PUSHR(stack, int, EXPAND_RECURSE); + while (status == REG_OK && tre_stack_num_objects(stack) > bottom) + { + tre_ast_node_t *node; + tre_expand_ast_symbol_t symbol; + + if (status != REG_OK) + break; + + symbol = (tre_expand_ast_symbol_t)tre_stack_pop_int(stack); + node = tre_stack_pop_voidptr(stack); + switch (symbol) + { + case EXPAND_RECURSE: + switch (node->type) + { + case LITERAL: + { + tre_literal_t *lit= node->obj; + if (!IS_SPECIAL(lit) || IS_BACKREF(lit)) + { + lit->position += pos_add; + if (lit->position > max_pos) + max_pos = lit->position; + } + break; + } + case UNION: + { + tre_union_t *uni = node->obj; + STACK_PUSHX(stack, voidptr, uni->right); + STACK_PUSHX(stack, int, EXPAND_RECURSE); + STACK_PUSHX(stack, voidptr, uni->left); + STACK_PUSHX(stack, int, EXPAND_RECURSE); + break; + } + case CATENATION: + { + tre_catenation_t *cat = node->obj; + STACK_PUSHX(stack, voidptr, cat->right); + STACK_PUSHX(stack, int, EXPAND_RECURSE); + STACK_PUSHX(stack, voidptr, cat->left); + STACK_PUSHX(stack, int, EXPAND_RECURSE); + break; + } + case ITERATION: + { + tre_iteration_t *iter = node->obj; + STACK_PUSHX(stack, int, pos_add); + STACK_PUSHX(stack, voidptr, node); + STACK_PUSHX(stack, int, EXPAND_AFTER_ITER); + STACK_PUSHX(stack, voidptr, iter->arg); + STACK_PUSHX(stack, int, EXPAND_RECURSE); + /* If we are going to expand this node at EXPAND_AFTER_ITER + then don't increase the `pos' fields of the nodes now, it + will get done when expanding. */ + if (iter->min > 1 || iter->max > 1) + pos_add = 0; + iter_depth++; + break; + } + default: + assert(0); + break; + } + break; + case EXPAND_AFTER_ITER: + { + tre_iteration_t *iter = node->obj; + int pos_add_last; + pos_add = tre_stack_pop_int(stack); + pos_add_last = pos_add; + if (iter->min > 1 || iter->max > 1) + { + tre_ast_node_t *seq1 = NULL, *seq2 = NULL; + int j; + int pos_add_save = pos_add; + + /* Create a catenated sequence of copies of the node. */ + for (j = 0; j < iter->min; j++) + { + tre_ast_node_t *copy; + /* Remove tags from all but the last copy. */ + int flags = ((j + 1 < iter->min) + ? COPY_REMOVE_TAGS + : COPY_MAXIMIZE_FIRST_TAG); + pos_add_save = pos_add; + status = tre_copy_ast(mem, stack, iter->arg, flags, + &pos_add, tag_directions, ©, + &max_pos); + if (status != REG_OK) + return status; + if (seq1 != NULL) + seq1 = tre_ast_new_catenation(mem, seq1, copy); + else + seq1 = copy; + if (seq1 == NULL) + return REG_ESPACE; + } + + if (iter->max == -1) + { + /* No upper limit. */ + pos_add_save = pos_add; + status = tre_copy_ast(mem, stack, iter->arg, 0, + &pos_add, NULL, &seq2, &max_pos); + if (status != REG_OK) + return status; + seq2 = tre_ast_new_iter(mem, seq2, 0, -1, 0); + if (seq2 == NULL) + return REG_ESPACE; + } + else + { + for (j = iter->min; j < iter->max; j++) + { + tre_ast_node_t *tmp, *copy; + pos_add_save = pos_add; + status = tre_copy_ast(mem, stack, iter->arg, 0, + &pos_add, NULL, ©, &max_pos); + if (status != REG_OK) + return status; + if (seq2 != NULL) + seq2 = tre_ast_new_catenation(mem, copy, seq2); + else + seq2 = copy; + if (seq2 == NULL) + return REG_ESPACE; + tmp = tre_ast_new_literal(mem, EMPTY, -1, -1); + if (tmp == NULL) + return REG_ESPACE; + seq2 = tre_ast_new_union(mem, tmp, seq2); + if (seq2 == NULL) + return REG_ESPACE; + } + } + + pos_add = pos_add_save; + if (seq1 == NULL) + seq1 = seq2; + else if (seq2 != NULL) + seq1 = tre_ast_new_catenation(mem, seq1, seq2); + if (seq1 == NULL) + return REG_ESPACE; + node->obj = seq1->obj; + node->type = seq1->type; + } + + iter_depth--; + pos_add_total += pos_add - pos_add_last; + if (iter_depth == 0) + pos_add = pos_add_total; + + break; + } + default: + assert(0); + break; + } + } + + *position += pos_add_total; + + /* `max_pos' should never be larger than `*position' if the above + code works, but just an extra safeguard let's make sure + `*position' is set large enough so enough memory will be + allocated for the transition table. */ + if (max_pos > *position) + *position = max_pos; + + return status; +} + +static tre_pos_and_tags_t * +tre_set_empty(tre_mem_t mem) +{ + tre_pos_and_tags_t *new_set; + + new_set = tre_mem_calloc(mem, sizeof(*new_set)); + if (new_set == NULL) + return NULL; + + new_set[0].position = -1; + new_set[0].code_min = -1; + new_set[0].code_max = -1; + + return new_set; +} + +static tre_pos_and_tags_t * +tre_set_one(tre_mem_t mem, int position, int code_min, int code_max, + tre_ctype_t class, tre_ctype_t *neg_classes, int backref) +{ + tre_pos_and_tags_t *new_set; + + new_set = tre_mem_calloc(mem, sizeof(*new_set) * 2); + if (new_set == NULL) + return NULL; + + new_set[0].position = position; + new_set[0].code_min = code_min; + new_set[0].code_max = code_max; + new_set[0].class = class; + new_set[0].neg_classes = neg_classes; + new_set[0].backref = backref; + new_set[1].position = -1; + new_set[1].code_min = -1; + new_set[1].code_max = -1; + + return new_set; +} + +static tre_pos_and_tags_t * +tre_set_union(tre_mem_t mem, tre_pos_and_tags_t *set1, tre_pos_and_tags_t *set2, + int *tags, int assertions) +{ + int s1, s2, i, j; + tre_pos_and_tags_t *new_set; + int *new_tags; + int num_tags; + + for (num_tags = 0; tags != NULL && tags[num_tags] >= 0; num_tags++); + for (s1 = 0; set1[s1].position >= 0; s1++); + for (s2 = 0; set2[s2].position >= 0; s2++); + new_set = tre_mem_calloc(mem, sizeof(*new_set) * (s1 + s2 + 1)); + if (!new_set ) + return NULL; + + for (s1 = 0; set1[s1].position >= 0; s1++) + { + new_set[s1].position = set1[s1].position; + new_set[s1].code_min = set1[s1].code_min; + new_set[s1].code_max = set1[s1].code_max; + new_set[s1].assertions = set1[s1].assertions | assertions; + new_set[s1].class = set1[s1].class; + new_set[s1].neg_classes = set1[s1].neg_classes; + new_set[s1].backref = set1[s1].backref; + if (set1[s1].tags == NULL && tags == NULL) + new_set[s1].tags = NULL; + else + { + for (i = 0; set1[s1].tags != NULL && set1[s1].tags[i] >= 0; i++); + new_tags = tre_mem_alloc(mem, (sizeof(*new_tags) + * (i + num_tags + 1))); + if (new_tags == NULL) + return NULL; + for (j = 0; j < i; j++) + new_tags[j] = set1[s1].tags[j]; + for (i = 0; i < num_tags; i++) + new_tags[j + i] = tags[i]; + new_tags[j + i] = -1; + new_set[s1].tags = new_tags; + } + } + + for (s2 = 0; set2[s2].position >= 0; s2++) + { + new_set[s1 + s2].position = set2[s2].position; + new_set[s1 + s2].code_min = set2[s2].code_min; + new_set[s1 + s2].code_max = set2[s2].code_max; + /* XXX - why not | assertions here as well? */ + new_set[s1 + s2].assertions = set2[s2].assertions; + new_set[s1 + s2].class = set2[s2].class; + new_set[s1 + s2].neg_classes = set2[s2].neg_classes; + new_set[s1 + s2].backref = set2[s2].backref; + if (set2[s2].tags == NULL) + new_set[s1 + s2].tags = NULL; + else + { + for (i = 0; set2[s2].tags[i] >= 0; i++); + new_tags = tre_mem_alloc(mem, sizeof(*new_tags) * (i + 1)); + if (new_tags == NULL) + return NULL; + for (j = 0; j < i; j++) + new_tags[j] = set2[s2].tags[j]; + new_tags[j] = -1; + new_set[s1 + s2].tags = new_tags; + } + } + new_set[s1 + s2].position = -1; + return new_set; +} + +/* Finds the empty path through `node' which is the one that should be + taken according to POSIX.2 rules, and adds the tags on that path to + `tags'. `tags' may be NULL. If `num_tags_seen' is not NULL, it is + set to the number of tags seen on the path. */ +static reg_errcode_t +tre_match_empty(tre_stack_t *stack, tre_ast_node_t *node, int *tags, + int *assertions, int *num_tags_seen) +{ + tre_literal_t *lit; + tre_union_t *uni; + tre_catenation_t *cat; + tre_iteration_t *iter; + int i; + int bottom = tre_stack_num_objects(stack); + reg_errcode_t status = REG_OK; + if (num_tags_seen) + *num_tags_seen = 0; + + status = tre_stack_push_voidptr(stack, node); + + /* Walk through the tree recursively. */ + while (status == REG_OK && tre_stack_num_objects(stack) > bottom) + { + node = tre_stack_pop_voidptr(stack); + + switch (node->type) + { + case LITERAL: + lit = (tre_literal_t *)node->obj; + switch (lit->code_min) + { + case TAG: + if (lit->code_max >= 0) + { + if (tags != NULL) + { + /* Add the tag to `tags'. */ + for (i = 0; tags[i] >= 0; i++) + if (tags[i] == lit->code_max) + break; + if (tags[i] < 0) + { + tags[i] = lit->code_max; + tags[i + 1] = -1; + } + } + if (num_tags_seen) + (*num_tags_seen)++; + } + break; + case ASSERTION: + assert(lit->code_max >= 1 + || lit->code_max <= ASSERT_LAST); + if (assertions != NULL) + *assertions |= lit->code_max; + break; + case EMPTY: + break; + default: + assert(0); + break; + } + break; + + case UNION: + /* Subexpressions starting earlier take priority over ones + starting later, so we prefer the left subexpression over the + right subexpression. */ + uni = (tre_union_t *)node->obj; + if (uni->left->nullable) + STACK_PUSHX(stack, voidptr, uni->left) + else if (uni->right->nullable) + STACK_PUSHX(stack, voidptr, uni->right) + else + assert(0); + break; + + case CATENATION: + /* The path must go through both children. */ + cat = (tre_catenation_t *)node->obj; + assert(cat->left->nullable); + assert(cat->right->nullable); + STACK_PUSHX(stack, voidptr, cat->left); + STACK_PUSHX(stack, voidptr, cat->right); + break; + + case ITERATION: + /* A match with an empty string is preferred over no match at + all, so we go through the argument if possible. */ + iter = (tre_iteration_t *)node->obj; + if (iter->arg->nullable) + STACK_PUSHX(stack, voidptr, iter->arg); + break; + + default: + assert(0); + break; + } + } + + return status; +} + + +typedef enum { + NFL_RECURSE, + NFL_POST_UNION, + NFL_POST_CATENATION, + NFL_POST_ITERATION +} tre_nfl_stack_symbol_t; + + +/* Computes and fills in the fields `nullable', `firstpos', and `lastpos' for + the nodes of the AST `tree'. */ +static reg_errcode_t +tre_compute_nfl(tre_mem_t mem, tre_stack_t *stack, tre_ast_node_t *tree) +{ + int bottom = tre_stack_num_objects(stack); + + STACK_PUSHR(stack, voidptr, tree); + STACK_PUSHR(stack, int, NFL_RECURSE); + + while (tre_stack_num_objects(stack) > bottom) + { + tre_nfl_stack_symbol_t symbol; + tre_ast_node_t *node; + + symbol = (tre_nfl_stack_symbol_t)tre_stack_pop_int(stack); + node = tre_stack_pop_voidptr(stack); + switch (symbol) + { + case NFL_RECURSE: + switch (node->type) + { + case LITERAL: + { + tre_literal_t *lit = (tre_literal_t *)node->obj; + if (IS_BACKREF(lit)) + { + /* Back references: nullable = false, firstpos = {i}, + lastpos = {i}. */ + node->nullable = 0; + node->firstpos = tre_set_one(mem, lit->position, 0, + TRE_CHAR_MAX, 0, NULL, -1); + if (!node->firstpos) + return REG_ESPACE; + node->lastpos = tre_set_one(mem, lit->position, 0, + TRE_CHAR_MAX, 0, NULL, + (int)lit->code_max); + if (!node->lastpos) + return REG_ESPACE; + } + else if (lit->code_min < 0) + { + /* Tags, empty strings, params, and zero width assertions: + nullable = true, firstpos = {}, and lastpos = {}. */ + node->nullable = 1; + node->firstpos = tre_set_empty(mem); + if (!node->firstpos) + return REG_ESPACE; + node->lastpos = tre_set_empty(mem); + if (!node->lastpos) + return REG_ESPACE; + } + else + { + /* Literal at position i: nullable = false, firstpos = {i}, + lastpos = {i}. */ + node->nullable = 0; + node->firstpos = + tre_set_one(mem, lit->position, (int)lit->code_min, + (int)lit->code_max, 0, NULL, -1); + if (!node->firstpos) + return REG_ESPACE; + node->lastpos = tre_set_one(mem, lit->position, + (int)lit->code_min, + (int)lit->code_max, + lit->class, lit->neg_classes, + -1); + if (!node->lastpos) + return REG_ESPACE; + } + break; + } + + case UNION: + /* Compute the attributes for the two subtrees, and after that + for this node. */ + STACK_PUSHR(stack, voidptr, node); + STACK_PUSHR(stack, int, NFL_POST_UNION); + STACK_PUSHR(stack, voidptr, ((tre_union_t *)node->obj)->right); + STACK_PUSHR(stack, int, NFL_RECURSE); + STACK_PUSHR(stack, voidptr, ((tre_union_t *)node->obj)->left); + STACK_PUSHR(stack, int, NFL_RECURSE); + break; + + case CATENATION: + /* Compute the attributes for the two subtrees, and after that + for this node. */ + STACK_PUSHR(stack, voidptr, node); + STACK_PUSHR(stack, int, NFL_POST_CATENATION); + STACK_PUSHR(stack, voidptr, ((tre_catenation_t *)node->obj)->right); + STACK_PUSHR(stack, int, NFL_RECURSE); + STACK_PUSHR(stack, voidptr, ((tre_catenation_t *)node->obj)->left); + STACK_PUSHR(stack, int, NFL_RECURSE); + break; + + case ITERATION: + /* Compute the attributes for the subtree, and after that for + this node. */ + STACK_PUSHR(stack, voidptr, node); + STACK_PUSHR(stack, int, NFL_POST_ITERATION); + STACK_PUSHR(stack, voidptr, ((tre_iteration_t *)node->obj)->arg); + STACK_PUSHR(stack, int, NFL_RECURSE); + break; + } + break; /* end case: NFL_RECURSE */ + + case NFL_POST_UNION: + { + tre_union_t *uni = (tre_union_t *)node->obj; + node->nullable = uni->left->nullable || uni->right->nullable; + node->firstpos = tre_set_union(mem, uni->left->firstpos, + uni->right->firstpos, NULL, 0); + if (!node->firstpos) + return REG_ESPACE; + node->lastpos = tre_set_union(mem, uni->left->lastpos, + uni->right->lastpos, NULL, 0); + if (!node->lastpos) + return REG_ESPACE; + break; + } + + case NFL_POST_ITERATION: + { + tre_iteration_t *iter = (tre_iteration_t *)node->obj; + + if (iter->min == 0 || iter->arg->nullable) + node->nullable = 1; + else + node->nullable = 0; + node->firstpos = iter->arg->firstpos; + node->lastpos = iter->arg->lastpos; + break; + } + + case NFL_POST_CATENATION: + { + int num_tags, *tags, assertions; + reg_errcode_t status; + tre_catenation_t *cat = node->obj; + node->nullable = cat->left->nullable && cat->right->nullable; + + /* Compute firstpos. */ + if (cat->left->nullable) + { + /* The left side matches the empty string. Make a first pass + with tre_match_empty() to get the number of tags and + parameters. */ + status = tre_match_empty(stack, cat->left, + NULL, NULL, &num_tags); + if (status != REG_OK) + return status; + /* Allocate arrays for the tags and parameters. */ + tags = xmalloc(sizeof(*tags) * (num_tags + 1)); + if (!tags) + return REG_ESPACE; + tags[0] = -1; + assertions = 0; + /* Second pass with tre_mach_empty() to get the list of + tags and parameters. */ + status = tre_match_empty(stack, cat->left, tags, + &assertions, NULL); + if (status != REG_OK) + { + xfree(tags); + return status; + } + node->firstpos = + tre_set_union(mem, cat->right->firstpos, cat->left->firstpos, + tags, assertions); + xfree(tags); + if (!node->firstpos) + return REG_ESPACE; + } + else + { + node->firstpos = cat->left->firstpos; + } + + /* Compute lastpos. */ + if (cat->right->nullable) + { + /* The right side matches the empty string. Make a first pass + with tre_match_empty() to get the number of tags and + parameters. */ + status = tre_match_empty(stack, cat->right, + NULL, NULL, &num_tags); + if (status != REG_OK) + return status; + /* Allocate arrays for the tags and parameters. */ + tags = xmalloc(sizeof(int) * (num_tags + 1)); + if (!tags) + return REG_ESPACE; + tags[0] = -1; + assertions = 0; + /* Second pass with tre_mach_empty() to get the list of + tags and parameters. */ + status = tre_match_empty(stack, cat->right, tags, + &assertions, NULL); + if (status != REG_OK) + { + xfree(tags); + return status; + } + node->lastpos = + tre_set_union(mem, cat->left->lastpos, cat->right->lastpos, + tags, assertions); + xfree(tags); + if (!node->lastpos) + return REG_ESPACE; + } + else + { + node->lastpos = cat->right->lastpos; + } + break; + } + + default: + assert(0); + break; + } + } + + return REG_OK; +} + + +/* Adds a transition from each position in `p1' to each position in `p2'. */ +static reg_errcode_t +tre_make_trans(tre_pos_and_tags_t *p1, tre_pos_and_tags_t *p2, + tre_tnfa_transition_t *transitions, + int *counts, int *offs) +{ + tre_pos_and_tags_t *orig_p2 = p2; + tre_tnfa_transition_t *trans; + int i, j, k, l, dup, prev_p2_pos; + + if (transitions != NULL) + while (p1->position >= 0) + { + p2 = orig_p2; + prev_p2_pos = -1; + while (p2->position >= 0) + { + /* Optimization: if this position was already handled, skip it. */ + if (p2->position == prev_p2_pos) + { + p2++; + continue; + } + prev_p2_pos = p2->position; + /* Set `trans' to point to the next unused transition from + position `p1->position'. */ + trans = transitions + offs[p1->position]; + while (trans->state != NULL) + { +#if 0 + /* If we find a previous transition from `p1->position' to + `p2->position', it is overwritten. This can happen only + if there are nested loops in the regexp, like in "((a)*)*". + In POSIX.2 repetition using the outer loop is always + preferred over using the inner loop. Therefore the + transition for the inner loop is useless and can be thrown + away. */ + /* XXX - The same position is used for all nodes in a bracket + expression, so this optimization cannot be used (it will + break bracket expressions) unless I figure out a way to + detect it here. */ + if (trans->state_id == p2->position) + { + break; + } +#endif + trans++; + } + + if (trans->state == NULL) + (trans + 1)->state = NULL; + /* Use the character ranges, assertions, etc. from `p1' for + the transition from `p1' to `p2'. */ + trans->code_min = p1->code_min; + trans->code_max = p1->code_max; + trans->state = transitions + offs[p2->position]; + trans->state_id = p2->position; + trans->assertions = p1->assertions | p2->assertions + | (p1->class ? ASSERT_CHAR_CLASS : 0) + | (p1->neg_classes != NULL ? ASSERT_CHAR_CLASS_NEG : 0); + if (p1->backref >= 0) + { + assert((trans->assertions & ASSERT_CHAR_CLASS) == 0); + assert(p2->backref < 0); + trans->u.backref = p1->backref; + trans->assertions |= ASSERT_BACKREF; + } + else + trans->u.class = p1->class; + if (p1->neg_classes != NULL) + { + for (i = 0; p1->neg_classes[i] != (tre_ctype_t)0; i++); + trans->neg_classes = + xmalloc(sizeof(*trans->neg_classes) * (i + 1)); + if (trans->neg_classes == NULL) + return REG_ESPACE; + for (i = 0; p1->neg_classes[i] != (tre_ctype_t)0; i++) + trans->neg_classes[i] = p1->neg_classes[i]; + trans->neg_classes[i] = (tre_ctype_t)0; + } + else + trans->neg_classes = NULL; + + /* Find out how many tags this transition has. */ + i = 0; + if (p1->tags != NULL) + while(p1->tags[i] >= 0) + i++; + j = 0; + if (p2->tags != NULL) + while(p2->tags[j] >= 0) + j++; + + /* If we are overwriting a transition, free the old tag array. */ + if (trans->tags != NULL) + xfree(trans->tags); + trans->tags = NULL; + + /* If there were any tags, allocate an array and fill it. */ + if (i + j > 0) + { + trans->tags = xmalloc(sizeof(*trans->tags) * (i + j + 1)); + if (!trans->tags) + return REG_ESPACE; + i = 0; + if (p1->tags != NULL) + while(p1->tags[i] >= 0) + { + trans->tags[i] = p1->tags[i]; + i++; + } + l = i; + j = 0; + if (p2->tags != NULL) + while (p2->tags[j] >= 0) + { + /* Don't add duplicates. */ + dup = 0; + for (k = 0; k < i; k++) + if (trans->tags[k] == p2->tags[j]) + { + dup = 1; + break; + } + if (!dup) + trans->tags[l++] = p2->tags[j]; + j++; + } + trans->tags[l] = -1; + } + + p2++; + } + p1++; + } + else + /* Compute a maximum limit for the number of transitions leaving + from each state. */ + while (p1->position >= 0) + { + p2 = orig_p2; + while (p2->position >= 0) + { + counts[p1->position]++; + p2++; + } + p1++; + } + return REG_OK; +} + +/* Converts the syntax tree to a TNFA. All the transitions in the TNFA are + labelled with one character range (there are no transitions on empty + strings). The TNFA takes O(n^2) space in the worst case, `n' is size of + the regexp. */ +static reg_errcode_t +tre_ast_to_tnfa(tre_ast_node_t *node, tre_tnfa_transition_t *transitions, + int *counts, int *offs) +{ + tre_union_t *uni; + tre_catenation_t *cat; + tre_iteration_t *iter; + reg_errcode_t errcode = REG_OK; + + /* XXX - recurse using a stack!. */ + switch (node->type) + { + case LITERAL: + break; + case UNION: + uni = (tre_union_t *)node->obj; + errcode = tre_ast_to_tnfa(uni->left, transitions, counts, offs); + if (errcode != REG_OK) + return errcode; + errcode = tre_ast_to_tnfa(uni->right, transitions, counts, offs); + break; + + case CATENATION: + cat = (tre_catenation_t *)node->obj; + /* Add a transition from each position in cat->left->lastpos + to each position in cat->right->firstpos. */ + errcode = tre_make_trans(cat->left->lastpos, cat->right->firstpos, + transitions, counts, offs); + if (errcode != REG_OK) + return errcode; + errcode = tre_ast_to_tnfa(cat->left, transitions, counts, offs); + if (errcode != REG_OK) + return errcode; + errcode = tre_ast_to_tnfa(cat->right, transitions, counts, offs); + break; + + case ITERATION: + iter = (tre_iteration_t *)node->obj; + assert(iter->max == -1 || iter->max == 1); + + if (iter->max == -1) + { + assert(iter->min == 0 || iter->min == 1); + /* Add a transition from each last position in the iterated + expression to each first position. */ + errcode = tre_make_trans(iter->arg->lastpos, iter->arg->firstpos, + transitions, counts, offs); + if (errcode != REG_OK) + return errcode; + } + errcode = tre_ast_to_tnfa(iter->arg, transitions, counts, offs); + break; + } + return errcode; +} + + +#define ERROR_EXIT(err) \ + do \ + { \ + errcode = err; \ + if (/*CONSTCOND*/1) \ + goto error_exit; \ + } \ + while (/*CONSTCOND*/0) + + +int +regcomp(regex_t *restrict preg, const char *restrict regex, int cflags) +{ + tre_stack_t *stack; + tre_ast_node_t *tree, *tmp_ast_l, *tmp_ast_r; + tre_pos_and_tags_t *p; + int *counts = NULL, *offs = NULL; + int i, add = 0; + tre_tnfa_transition_t *transitions, *initial; + tre_tnfa_t *tnfa = NULL; + tre_submatch_data_t *submatch_data; + tre_tag_direction_t *tag_directions = NULL; + reg_errcode_t errcode; + tre_mem_t mem; + + /* Parse context. */ + tre_parse_ctx_t parse_ctx; + + /* Allocate a stack used throughout the compilation process for various + purposes. */ + stack = tre_stack_new(512, 1024000, 128); + if (!stack) + return REG_ESPACE; + /* Allocate a fast memory allocator. */ + mem = tre_mem_new(); + if (!mem) + { + tre_stack_destroy(stack); + return REG_ESPACE; + } + + /* Parse the regexp. */ + memset(&parse_ctx, 0, sizeof(parse_ctx)); + parse_ctx.mem = mem; + parse_ctx.stack = stack; + parse_ctx.start = regex; + parse_ctx.cflags = cflags; + parse_ctx.max_backref = -1; + errcode = tre_parse(&parse_ctx); + if (errcode != REG_OK) + ERROR_EXIT(errcode); + preg->re_nsub = parse_ctx.submatch_id - 1; + tree = parse_ctx.n; + +#ifdef TRE_DEBUG + tre_ast_print(tree); +#endif /* TRE_DEBUG */ + + /* Referring to nonexistent subexpressions is illegal. */ + if (parse_ctx.max_backref > (int)preg->re_nsub) + ERROR_EXIT(REG_ESUBREG); + + /* Allocate the TNFA struct. */ + tnfa = xcalloc(1, sizeof(tre_tnfa_t)); + if (tnfa == NULL) + ERROR_EXIT(REG_ESPACE); + tnfa->have_backrefs = parse_ctx.max_backref >= 0; + tnfa->have_approx = 0; + tnfa->num_submatches = parse_ctx.submatch_id; + + /* Set up tags for submatch addressing. If REG_NOSUB is set and the + regexp does not have back references, this can be skipped. */ + if (tnfa->have_backrefs || !(cflags & REG_NOSUB)) + { + + /* Figure out how many tags we will need. */ + errcode = tre_add_tags(NULL, stack, tree, tnfa); + if (errcode != REG_OK) + ERROR_EXIT(errcode); + + if (tnfa->num_tags > 0) + { + tag_directions = xmalloc(sizeof(*tag_directions) + * (tnfa->num_tags + 1)); + if (tag_directions == NULL) + ERROR_EXIT(REG_ESPACE); + tnfa->tag_directions = tag_directions; + memset(tag_directions, -1, + sizeof(*tag_directions) * (tnfa->num_tags + 1)); + } + tnfa->minimal_tags = xcalloc((unsigned)tnfa->num_tags * 2 + 1, + sizeof(*tnfa->minimal_tags)); + if (tnfa->minimal_tags == NULL) + ERROR_EXIT(REG_ESPACE); + + submatch_data = xcalloc((unsigned)parse_ctx.submatch_id, + sizeof(*submatch_data)); + if (submatch_data == NULL) + ERROR_EXIT(REG_ESPACE); + tnfa->submatch_data = submatch_data; + + errcode = tre_add_tags(mem, stack, tree, tnfa); + if (errcode != REG_OK) + ERROR_EXIT(errcode); + + } + + /* Expand iteration nodes. */ + errcode = tre_expand_ast(mem, stack, tree, &parse_ctx.position, + tag_directions); + if (errcode != REG_OK) + ERROR_EXIT(errcode); + + /* Add a dummy node for the final state. + XXX - For certain patterns this dummy node can be optimized away, + for example "a*" or "ab*". Figure out a simple way to detect + this possibility. */ + tmp_ast_l = tree; + tmp_ast_r = tre_ast_new_literal(mem, 0, 0, parse_ctx.position++); + if (tmp_ast_r == NULL) + ERROR_EXIT(REG_ESPACE); + + tree = tre_ast_new_catenation(mem, tmp_ast_l, tmp_ast_r); + if (tree == NULL) + ERROR_EXIT(REG_ESPACE); + + errcode = tre_compute_nfl(mem, stack, tree); + if (errcode != REG_OK) + ERROR_EXIT(errcode); + + counts = xmalloc(sizeof(int) * parse_ctx.position); + if (counts == NULL) + ERROR_EXIT(REG_ESPACE); + + offs = xmalloc(sizeof(int) * parse_ctx.position); + if (offs == NULL) + ERROR_EXIT(REG_ESPACE); + + for (i = 0; i < parse_ctx.position; i++) + counts[i] = 0; + tre_ast_to_tnfa(tree, NULL, counts, NULL); + + add = 0; + for (i = 0; i < parse_ctx.position; i++) + { + offs[i] = add; + add += counts[i] + 1; + counts[i] = 0; + } + transitions = xcalloc((unsigned)add + 1, sizeof(*transitions)); + if (transitions == NULL) + ERROR_EXIT(REG_ESPACE); + tnfa->transitions = transitions; + tnfa->num_transitions = add; + + errcode = tre_ast_to_tnfa(tree, transitions, counts, offs); + if (errcode != REG_OK) + ERROR_EXIT(errcode); + + tnfa->firstpos_chars = NULL; + + p = tree->firstpos; + i = 0; + while (p->position >= 0) + { + i++; + p++; + } + + initial = xcalloc((unsigned)i + 1, sizeof(tre_tnfa_transition_t)); + if (initial == NULL) + ERROR_EXIT(REG_ESPACE); + tnfa->initial = initial; + + i = 0; + for (p = tree->firstpos; p->position >= 0; p++) + { + initial[i].state = transitions + offs[p->position]; + initial[i].state_id = p->position; + initial[i].tags = NULL; + /* Copy the arrays p->tags, and p->params, they are allocated + from a tre_mem object. */ + if (p->tags) + { + int j; + for (j = 0; p->tags[j] >= 0; j++); + initial[i].tags = xmalloc(sizeof(*p->tags) * (j + 1)); + if (!initial[i].tags) + ERROR_EXIT(REG_ESPACE); + memcpy(initial[i].tags, p->tags, sizeof(*p->tags) * (j + 1)); + } + initial[i].assertions = p->assertions; + i++; + } + initial[i].state = NULL; + + tnfa->num_transitions = add; + tnfa->final = transitions + offs[tree->lastpos[0].position]; + tnfa->num_states = parse_ctx.position; + tnfa->cflags = cflags; + + tre_mem_destroy(mem); + tre_stack_destroy(stack); + xfree(counts); + xfree(offs); + + preg->TRE_REGEX_T_FIELD = (void *)tnfa; + return REG_OK; + + error_exit: + /* Free everything that was allocated and return the error code. */ + tre_mem_destroy(mem); + if (stack != NULL) + tre_stack_destroy(stack); + if (counts != NULL) + xfree(counts); + if (offs != NULL) + xfree(offs); + preg->TRE_REGEX_T_FIELD = (void *)tnfa; + regfree(preg); + return errcode; +} + + + + +void +regfree(regex_t *preg) +{ + tre_tnfa_t *tnfa; + unsigned int i; + tre_tnfa_transition_t *trans; + + tnfa = (void *)preg->TRE_REGEX_T_FIELD; + if (!tnfa) + return; + + for (i = 0; i < tnfa->num_transitions; i++) + if (tnfa->transitions[i].state) + { + if (tnfa->transitions[i].tags) + xfree(tnfa->transitions[i].tags); + if (tnfa->transitions[i].neg_classes) + xfree(tnfa->transitions[i].neg_classes); + } + if (tnfa->transitions) + xfree(tnfa->transitions); + + if (tnfa->initial) + { + for (trans = tnfa->initial; trans->state; trans++) + { + if (trans->tags) + xfree(trans->tags); + } + xfree(tnfa->initial); + } + + if (tnfa->submatch_data) + { + for (i = 0; i < tnfa->num_submatches; i++) + if (tnfa->submatch_data[i].parents) + xfree(tnfa->submatch_data[i].parents); + xfree(tnfa->submatch_data); + } + + if (tnfa->tag_directions) + xfree(tnfa->tag_directions); + if (tnfa->firstpos_chars) + xfree(tnfa->firstpos_chars); + if (tnfa->minimal_tags) + xfree(tnfa->minimal_tags); + xfree(tnfa); +} \ No newline at end of file diff --git a/lib/mlibc/options/posix/musl-generic-regex/regerror.c b/lib/mlibc/options/posix/musl-generic-regex/regerror.c new file mode 100644 index 0000000..41e9a36 --- /dev/null +++ b/lib/mlibc/options/posix/musl-generic-regex/regerror.c @@ -0,0 +1,37 @@ +#include +#include +#include +// #include "locale_impl.h" + +/* Error message strings for error codes listed in `regex.h'. This list + needs to be in sync with the codes listed there, naturally. */ + +/* Converted to single string by Rich Felker to remove the need for + * data relocations at runtime, 27 Feb 2006. */ + +static const char messages[] = { + "No error\0" + "No match\0" + "Invalid regexp\0" + "Unknown collating element\0" + "Unknown character class name\0" + "Trailing backslash\0" + "Invalid back reference\0" + "Missing ']'\0" + "Missing ')'\0" + "Missing '}'\0" + "Invalid contents of {}\0" + "Invalid character range\0" + "Out of memory\0" + "Repetition not preceded by valid expression\0" + "\0Unknown error" +}; + +size_t regerror(int e, const regex_t *restrict preg, char *restrict buf, size_t size) +{ + const char *s; + for (s=messages; e && *s; e--, s+=strlen(s)+1); + if (!*s) s++; + // s = LCTRANS_CUR(s); + return 1+snprintf(buf, size, "%s", s); +} diff --git a/lib/mlibc/options/posix/musl-generic-regex/regexec.c b/lib/mlibc/options/posix/musl-generic-regex/regexec.c new file mode 100644 index 0000000..1a169ab --- /dev/null +++ b/lib/mlibc/options/posix/musl-generic-regex/regexec.c @@ -0,0 +1,1028 @@ +/* + regexec.c - TRE POSIX compatible matching functions (and more). + + Copyright (c) 2001-2009 Ville Laurikari + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +#include +#include +#include +#include +#include +#include + +#include + +#include "tre.h" + +#include + +static void +tre_fill_pmatch(size_t nmatch, regmatch_t pmatch[], int cflags, + const tre_tnfa_t *tnfa, regoff_t *tags, regoff_t match_eo); + +/*********************************************************************** + from tre-match-utils.h +***********************************************************************/ + +#define GET_NEXT_WCHAR() do { \ + prev_c = next_c; pos += pos_add_next; \ + if ((pos_add_next = mbtowc(&next_c, str_byte, MB_LEN_MAX)) <= 0) { \ + if (pos_add_next < 0) { ret = REG_NOMATCH; goto error_exit; } \ + else pos_add_next++; \ + } \ + str_byte += pos_add_next; \ + } while (0) + +#define IS_WORD_CHAR(c) ((c) == L'_' || tre_isalnum(c)) + +#define CHECK_ASSERTIONS(assertions) \ + (((assertions & ASSERT_AT_BOL) \ + && (pos > 0 || reg_notbol) \ + && (prev_c != L'\n' || !reg_newline)) \ + || ((assertions & ASSERT_AT_EOL) \ + && (next_c != L'\0' || reg_noteol) \ + && (next_c != L'\n' || !reg_newline)) \ + || ((assertions & ASSERT_AT_BOW) \ + && (IS_WORD_CHAR(prev_c) || !IS_WORD_CHAR(next_c))) \ + || ((assertions & ASSERT_AT_EOW) \ + && (!IS_WORD_CHAR(prev_c) || IS_WORD_CHAR(next_c))) \ + || ((assertions & ASSERT_AT_WB) \ + && (pos != 0 && next_c != L'\0' \ + && IS_WORD_CHAR(prev_c) == IS_WORD_CHAR(next_c))) \ + || ((assertions & ASSERT_AT_WB_NEG) \ + && (pos == 0 || next_c == L'\0' \ + || IS_WORD_CHAR(prev_c) != IS_WORD_CHAR(next_c)))) + +#define CHECK_CHAR_CLASSES(trans_i, tnfa, eflags) \ + (((trans_i->assertions & ASSERT_CHAR_CLASS) \ + && !(tnfa->cflags & REG_ICASE) \ + && !tre_isctype((tre_cint_t)prev_c, trans_i->u.class)) \ + || ((trans_i->assertions & ASSERT_CHAR_CLASS) \ + && (tnfa->cflags & REG_ICASE) \ + && !tre_isctype(tre_tolower((tre_cint_t)prev_c),trans_i->u.class) \ + && !tre_isctype(tre_toupper((tre_cint_t)prev_c),trans_i->u.class)) \ + || ((trans_i->assertions & ASSERT_CHAR_CLASS_NEG) \ + && tre_neg_char_classes_match(trans_i->neg_classes,(tre_cint_t)prev_c,\ + tnfa->cflags & REG_ICASE))) + + + + +/* Returns 1 if `t1' wins `t2', 0 otherwise. */ +static int +tre_tag_order(int num_tags, tre_tag_direction_t *tag_directions, + regoff_t *t1, regoff_t *t2) +{ + int i; + for (i = 0; i < num_tags; i++) + { + if (tag_directions[i] == TRE_TAG_MINIMIZE) + { + if (t1[i] < t2[i]) + return 1; + if (t1[i] > t2[i]) + return 0; + } + else + { + if (t1[i] > t2[i]) + return 1; + if (t1[i] < t2[i]) + return 0; + } + } + /* assert(0);*/ + return 0; +} + +static int +tre_neg_char_classes_match(tre_ctype_t *classes, tre_cint_t wc, int icase) +{ + while (*classes != (tre_ctype_t)0) + if ((!icase && tre_isctype(wc, *classes)) + || (icase && (tre_isctype(tre_toupper(wc), *classes) + || tre_isctype(tre_tolower(wc), *classes)))) + return 1; /* Match. */ + else + classes++; + return 0; /* No match. */ +} + + +/*********************************************************************** + from tre-match-parallel.c +***********************************************************************/ + +/* + This algorithm searches for matches basically by reading characters + in the searched string one by one, starting at the beginning. All + matching paths in the TNFA are traversed in parallel. When two or + more paths reach the same state, exactly one is chosen according to + tag ordering rules; if returning submatches is not required it does + not matter which path is chosen. + + The worst case time required for finding the leftmost and longest + match, or determining that there is no match, is always linearly + dependent on the length of the text being searched. + + This algorithm cannot handle TNFAs with back referencing nodes. + See `tre-match-backtrack.c'. +*/ + +typedef struct { + tre_tnfa_transition_t *state; + regoff_t *tags; +} tre_tnfa_reach_t; + +typedef struct { + regoff_t pos; + regoff_t **tags; +} tre_reach_pos_t; + + +static reg_errcode_t +tre_tnfa_run_parallel(const tre_tnfa_t *tnfa, const void *string, + regoff_t *match_tags, int eflags, + regoff_t *match_end_ofs) +{ + /* State variables required by GET_NEXT_WCHAR. */ + tre_char_t prev_c = 0, next_c = 0; + const char *str_byte = string; + regoff_t pos = -1; + regoff_t pos_add_next = 1; +#ifdef TRE_MBSTATE + mbstate_t mbstate; +#endif /* TRE_MBSTATE */ + int reg_notbol = eflags & REG_NOTBOL; + int reg_noteol = eflags & REG_NOTEOL; + int reg_newline = tnfa->cflags & REG_NEWLINE; + reg_errcode_t ret; + + char *buf; + tre_tnfa_transition_t *trans_i; + tre_tnfa_reach_t *reach, *reach_next, *reach_i, *reach_next_i; + tre_reach_pos_t *reach_pos; + int *tag_i; + int num_tags, i; + + regoff_t match_eo = -1; /* end offset of match (-1 if no match found yet) */ + int new_match = 0; + regoff_t *tmp_tags = NULL; + regoff_t *tmp_iptr; + +#ifdef TRE_MBSTATE + memset(&mbstate, '\0', sizeof(mbstate)); +#endif /* TRE_MBSTATE */ + + if (!match_tags) + num_tags = 0; + else + num_tags = tnfa->num_tags; + + /* Allocate memory for temporary data required for matching. This needs to + be done for every matching operation to be thread safe. This allocates + everything in a single large block with calloc(). */ + { + size_t tbytes, rbytes, pbytes, xbytes, total_bytes; + char *tmp_buf; + + /* Ensure that tbytes and xbytes*num_states cannot overflow, and that + * they don't contribute more than 1/8 of SIZE_MAX to total_bytes. */ + if (num_tags > SIZE_MAX/(8 * sizeof(regoff_t) * tnfa->num_states)) + return REG_ESPACE; + + /* Likewise check rbytes. */ + if (tnfa->num_states+1 > SIZE_MAX/(8 * sizeof(*reach_next))) + return REG_ESPACE; + + /* Likewise check pbytes. */ + if (tnfa->num_states > SIZE_MAX/(8 * sizeof(*reach_pos))) + return REG_ESPACE; + + /* Compute the length of the block we need. */ + tbytes = sizeof(*tmp_tags) * num_tags; + rbytes = sizeof(*reach_next) * (tnfa->num_states + 1); + pbytes = sizeof(*reach_pos) * tnfa->num_states; + xbytes = sizeof(regoff_t) * num_tags; + total_bytes = + (sizeof(long) - 1) * 4 /* for alignment paddings */ + + (rbytes + xbytes * tnfa->num_states) * 2 + tbytes + pbytes; + + /* Allocate the memory. */ + buf = calloc(total_bytes, 1); + if (buf == NULL) + return REG_ESPACE; + + /* Get the various pointers within tmp_buf (properly aligned). */ + tmp_tags = (void *)buf; + tmp_buf = buf + tbytes; + tmp_buf += ALIGN(tmp_buf, long); + reach_next = (void *)tmp_buf; + tmp_buf += rbytes; + tmp_buf += ALIGN(tmp_buf, long); + reach = (void *)tmp_buf; + tmp_buf += rbytes; + tmp_buf += ALIGN(tmp_buf, long); + reach_pos = (void *)tmp_buf; + tmp_buf += pbytes; + tmp_buf += ALIGN(tmp_buf, long); + for (i = 0; i < tnfa->num_states; i++) + { + reach[i].tags = (void *)tmp_buf; + tmp_buf += xbytes; + reach_next[i].tags = (void *)tmp_buf; + tmp_buf += xbytes; + } + } + + for (i = 0; i < tnfa->num_states; i++) + reach_pos[i].pos = -1; + + GET_NEXT_WCHAR(); + pos = 0; + + reach_next_i = reach_next; + while (1) + { + /* If no match found yet, add the initial states to `reach_next'. */ + if (match_eo < 0) + { + trans_i = tnfa->initial; + while (trans_i->state != NULL) + { + if (reach_pos[trans_i->state_id].pos < pos) + { + if (trans_i->assertions + && CHECK_ASSERTIONS(trans_i->assertions)) + { + trans_i++; + continue; + } + + reach_next_i->state = trans_i->state; + for (i = 0; i < num_tags; i++) + reach_next_i->tags[i] = -1; + tag_i = trans_i->tags; + if (tag_i) + while (*tag_i >= 0) + { + if (*tag_i < num_tags) + reach_next_i->tags[*tag_i] = pos; + tag_i++; + } + if (reach_next_i->state == tnfa->final) + { + match_eo = pos; + new_match = 1; + for (i = 0; i < num_tags; i++) + match_tags[i] = reach_next_i->tags[i]; + } + reach_pos[trans_i->state_id].pos = pos; + reach_pos[trans_i->state_id].tags = &reach_next_i->tags; + reach_next_i++; + } + trans_i++; + } + reach_next_i->state = NULL; + } + else + { + if (num_tags == 0 || reach_next_i == reach_next) + /* We have found a match. */ + break; + } + + /* Check for end of string. */ + if (!next_c) break; + + GET_NEXT_WCHAR(); + + /* Swap `reach' and `reach_next'. */ + reach_i = reach; + reach = reach_next; + reach_next = reach_i; + + /* For each state in `reach', weed out states that don't fulfill the + minimal matching conditions. */ + if (tnfa->num_minimals && new_match) + { + new_match = 0; + reach_next_i = reach_next; + for (reach_i = reach; reach_i->state; reach_i++) + { + int skip = 0; + for (i = 0; tnfa->minimal_tags[i] >= 0; i += 2) + { + int end = tnfa->minimal_tags[i]; + int start = tnfa->minimal_tags[i + 1]; + if (end >= num_tags) + { + skip = 1; + break; + } + else if (reach_i->tags[start] == match_tags[start] + && reach_i->tags[end] < match_tags[end]) + { + skip = 1; + break; + } + } + if (!skip) + { + reach_next_i->state = reach_i->state; + tmp_iptr = reach_next_i->tags; + reach_next_i->tags = reach_i->tags; + reach_i->tags = tmp_iptr; + reach_next_i++; + } + } + reach_next_i->state = NULL; + + /* Swap `reach' and `reach_next'. */ + reach_i = reach; + reach = reach_next; + reach_next = reach_i; + } + + /* For each state in `reach' see if there is a transition leaving with + the current input symbol to a state not yet in `reach_next', and + add the destination states to `reach_next'. */ + reach_next_i = reach_next; + for (reach_i = reach; reach_i->state; reach_i++) + { + for (trans_i = reach_i->state; trans_i->state; trans_i++) + { + /* Does this transition match the input symbol? */ + if (trans_i->code_min <= (tre_cint_t)prev_c && + trans_i->code_max >= (tre_cint_t)prev_c) + { + if (trans_i->assertions + && (CHECK_ASSERTIONS(trans_i->assertions) + || CHECK_CHAR_CLASSES(trans_i, tnfa, eflags))) + { + continue; + } + + /* Compute the tags after this transition. */ + for (i = 0; i < num_tags; i++) + tmp_tags[i] = reach_i->tags[i]; + tag_i = trans_i->tags; + if (tag_i != NULL) + while (*tag_i >= 0) + { + if (*tag_i < num_tags) + tmp_tags[*tag_i] = pos; + tag_i++; + } + + if (reach_pos[trans_i->state_id].pos < pos) + { + /* Found an unvisited node. */ + reach_next_i->state = trans_i->state; + tmp_iptr = reach_next_i->tags; + reach_next_i->tags = tmp_tags; + tmp_tags = tmp_iptr; + reach_pos[trans_i->state_id].pos = pos; + reach_pos[trans_i->state_id].tags = &reach_next_i->tags; + + if (reach_next_i->state == tnfa->final + && (match_eo == -1 + || (num_tags > 0 + && reach_next_i->tags[0] <= match_tags[0]))) + { + match_eo = pos; + new_match = 1; + for (i = 0; i < num_tags; i++) + match_tags[i] = reach_next_i->tags[i]; + } + reach_next_i++; + + } + else + { + assert(reach_pos[trans_i->state_id].pos == pos); + /* Another path has also reached this state. We choose + the winner by examining the tag values for both + paths. */ + if (tre_tag_order(num_tags, tnfa->tag_directions, + tmp_tags, + *reach_pos[trans_i->state_id].tags)) + { + /* The new path wins. */ + tmp_iptr = *reach_pos[trans_i->state_id].tags; + *reach_pos[trans_i->state_id].tags = tmp_tags; + if (trans_i->state == tnfa->final) + { + match_eo = pos; + new_match = 1; + for (i = 0; i < num_tags; i++) + match_tags[i] = tmp_tags[i]; + } + tmp_tags = tmp_iptr; + } + } + } + } + } + reach_next_i->state = NULL; + } + + *match_end_ofs = match_eo; + ret = match_eo >= 0 ? REG_OK : REG_NOMATCH; +error_exit: + xfree(buf); + return ret; +} + + + +/*********************************************************************** + from tre-match-backtrack.c +***********************************************************************/ + +/* + This matcher is for regexps that use back referencing. Regexp matching + with back referencing is an NP-complete problem on the number of back + references. The easiest way to match them is to use a backtracking + routine which basically goes through all possible paths in the TNFA + and chooses the one which results in the best (leftmost and longest) + match. This can be spectacularly expensive and may run out of stack + space, but there really is no better known generic algorithm. Quoting + Henry Spencer from comp.compilers: + + + POSIX.2 REs require longest match, which is really exciting to + implement since the obsolete ("basic") variant also includes + \. I haven't found a better way of tackling this than doing + a preliminary match using a DFA (or simulation) on a modified RE + that just replicates subREs for \, and then doing a + backtracking match to determine whether the subRE matches were + right. This can be rather slow, but I console myself with the + thought that people who use \ deserve very slow execution. + (Pun unintentional but very appropriate.) + +*/ + +typedef struct { + regoff_t pos; + const char *str_byte; + tre_tnfa_transition_t *state; + int state_id; + int next_c; + regoff_t *tags; +#ifdef TRE_MBSTATE + mbstate_t mbstate; +#endif /* TRE_MBSTATE */ +} tre_backtrack_item_t; + +typedef struct tre_backtrack_struct { + tre_backtrack_item_t item; + struct tre_backtrack_struct *prev; + struct tre_backtrack_struct *next; +} *tre_backtrack_t; + +#ifdef TRE_MBSTATE +#define BT_STACK_MBSTATE_IN stack->item.mbstate = (mbstate) +#define BT_STACK_MBSTATE_OUT (mbstate) = stack->item.mbstate +#else /* !TRE_MBSTATE */ +#define BT_STACK_MBSTATE_IN +#define BT_STACK_MBSTATE_OUT +#endif /* !TRE_MBSTATE */ + +#define tre_bt_mem_new tre_mem_new +#define tre_bt_mem_alloc tre_mem_alloc +#define tre_bt_mem_destroy tre_mem_destroy + + +#define BT_STACK_PUSH(_pos, _str_byte, _str_wide, _state, _state_id, _next_c, _tags, _mbstate) \ + do \ + { \ + int i; \ + if (!stack->next) \ + { \ + tre_backtrack_t s; \ + s = tre_bt_mem_alloc(mem, sizeof(*s)); \ + if (!s) \ + { \ + tre_bt_mem_destroy(mem); \ + if (tags) \ + xfree(tags); \ + if (pmatch) \ + xfree(pmatch); \ + if (states_seen) \ + xfree(states_seen); \ + return REG_ESPACE; \ + } \ + s->prev = stack; \ + s->next = NULL; \ + s->item.tags = tre_bt_mem_alloc(mem, \ + sizeof(*tags) * tnfa->num_tags); \ + if (!s->item.tags) \ + { \ + tre_bt_mem_destroy(mem); \ + if (tags) \ + xfree(tags); \ + if (pmatch) \ + xfree(pmatch); \ + if (states_seen) \ + xfree(states_seen); \ + return REG_ESPACE; \ + } \ + stack->next = s; \ + stack = s; \ + } \ + else \ + stack = stack->next; \ + stack->item.pos = (_pos); \ + stack->item.str_byte = (_str_byte); \ + stack->item.state = (_state); \ + stack->item.state_id = (_state_id); \ + stack->item.next_c = (_next_c); \ + for (i = 0; i < tnfa->num_tags; i++) \ + stack->item.tags[i] = (_tags)[i]; \ + BT_STACK_MBSTATE_IN; \ + } \ + while (0) + +#define BT_STACK_POP() \ + do \ + { \ + int i; \ + assert(stack->prev); \ + pos = stack->item.pos; \ + str_byte = stack->item.str_byte; \ + state = stack->item.state; \ + next_c = stack->item.next_c; \ + for (i = 0; i < tnfa->num_tags; i++) \ + tags[i] = stack->item.tags[i]; \ + BT_STACK_MBSTATE_OUT; \ + stack = stack->prev; \ + } \ + while (0) + +#undef MIN +#define MIN(a, b) ((a) <= (b) ? (a) : (b)) + +static reg_errcode_t +tre_tnfa_run_backtrack(const tre_tnfa_t *tnfa, const void *string, + regoff_t *match_tags, int eflags, regoff_t *match_end_ofs) +{ + /* State variables required by GET_NEXT_WCHAR. */ + tre_char_t prev_c = 0, next_c = 0; + const char *str_byte = string; + regoff_t pos = 0; + regoff_t pos_add_next = 1; +#ifdef TRE_MBSTATE + mbstate_t mbstate; +#endif /* TRE_MBSTATE */ + int reg_notbol = eflags & REG_NOTBOL; + int reg_noteol = eflags & REG_NOTEOL; + int reg_newline = tnfa->cflags & REG_NEWLINE; + + /* These are used to remember the necessary values of the above + variables to return to the position where the current search + started from. */ + int next_c_start; + const char *str_byte_start; + regoff_t pos_start = -1; +#ifdef TRE_MBSTATE + mbstate_t mbstate_start; +#endif /* TRE_MBSTATE */ + + /* End offset of best match so far, or -1 if no match found yet. */ + regoff_t match_eo = -1; + /* Tag arrays. */ + int *next_tags; + regoff_t *tags = NULL; + /* Current TNFA state. */ + tre_tnfa_transition_t *state; + int *states_seen = NULL; + + /* Memory allocator to for allocating the backtracking stack. */ + tre_mem_t mem = tre_bt_mem_new(); + + /* The backtracking stack. */ + tre_backtrack_t stack; + + tre_tnfa_transition_t *trans_i; + regmatch_t *pmatch = NULL; + int ret; + +#ifdef TRE_MBSTATE + memset(&mbstate, '\0', sizeof(mbstate)); +#endif /* TRE_MBSTATE */ + + if (!mem) + return REG_ESPACE; + stack = tre_bt_mem_alloc(mem, sizeof(*stack)); + if (!stack) + { + ret = REG_ESPACE; + goto error_exit; + } + stack->prev = NULL; + stack->next = NULL; + + if (tnfa->num_tags) + { + tags = xmalloc(sizeof(*tags) * tnfa->num_tags); + if (!tags) + { + ret = REG_ESPACE; + goto error_exit; + } + } + if (tnfa->num_submatches) + { + pmatch = xmalloc(sizeof(*pmatch) * tnfa->num_submatches); + if (!pmatch) + { + ret = REG_ESPACE; + goto error_exit; + } + } + if (tnfa->num_states) + { + states_seen = xmalloc(sizeof(*states_seen) * tnfa->num_states); + if (!states_seen) + { + ret = REG_ESPACE; + goto error_exit; + } + } + + retry: + { + int i; + for (i = 0; i < tnfa->num_tags; i++) + { + tags[i] = -1; + if (match_tags) + match_tags[i] = -1; + } + for (i = 0; i < tnfa->num_states; i++) + states_seen[i] = 0; + } + + state = NULL; + pos = pos_start; + GET_NEXT_WCHAR(); + pos_start = pos; + next_c_start = next_c; + str_byte_start = str_byte; +#ifdef TRE_MBSTATE + mbstate_start = mbstate; +#endif /* TRE_MBSTATE */ + + /* Handle initial states. */ + next_tags = NULL; + for (trans_i = tnfa->initial; trans_i->state; trans_i++) + { + if (trans_i->assertions && CHECK_ASSERTIONS(trans_i->assertions)) + { + continue; + } + if (state == NULL) + { + /* Start from this state. */ + state = trans_i->state; + next_tags = trans_i->tags; + } + else + { + /* Backtrack to this state. */ + BT_STACK_PUSH(pos, str_byte, 0, trans_i->state, + trans_i->state_id, next_c, tags, mbstate); + { + int *tmp = trans_i->tags; + if (tmp) + while (*tmp >= 0) + stack->item.tags[*tmp++] = pos; + } + } + } + + if (next_tags) + for (; *next_tags >= 0; next_tags++) + tags[*next_tags] = pos; + + + if (state == NULL) + goto backtrack; + + while (1) + { + tre_tnfa_transition_t *next_state; + int empty_br_match; + + if (state == tnfa->final) + { + if (match_eo < pos + || (match_eo == pos + && match_tags + && tre_tag_order(tnfa->num_tags, tnfa->tag_directions, + tags, match_tags))) + { + int i; + /* This match wins the previous match. */ + match_eo = pos; + if (match_tags) + for (i = 0; i < tnfa->num_tags; i++) + match_tags[i] = tags[i]; + } + /* Our TNFAs never have transitions leaving from the final state, + so we jump right to backtracking. */ + goto backtrack; + } + + /* Go to the next character in the input string. */ + empty_br_match = 0; + trans_i = state; + if (trans_i->state && trans_i->assertions & ASSERT_BACKREF) + { + /* This is a back reference state. All transitions leaving from + this state have the same back reference "assertion". Instead + of reading the next character, we match the back reference. */ + regoff_t so, eo; + int bt = trans_i->u.backref; + regoff_t bt_len; + int result; + + /* Get the substring we need to match against. Remember to + turn off REG_NOSUB temporarily. */ + tre_fill_pmatch(bt + 1, pmatch, tnfa->cflags & ~REG_NOSUB, + tnfa, tags, pos); + so = pmatch[bt].rm_so; + eo = pmatch[bt].rm_eo; + bt_len = eo - so; + + result = strncmp((const char*)string + so, str_byte - 1, + (size_t)bt_len); + + if (result == 0) + { + /* Back reference matched. Check for infinite loop. */ + if (bt_len == 0) + empty_br_match = 1; + if (empty_br_match && states_seen[trans_i->state_id]) + { + goto backtrack; + } + + states_seen[trans_i->state_id] = empty_br_match; + + /* Advance in input string and resync `prev_c', `next_c' + and pos. */ + str_byte += bt_len - 1; + pos += bt_len - 1; + GET_NEXT_WCHAR(); + } + else + { + goto backtrack; + } + } + else + { + /* Check for end of string. */ + if (next_c == L'\0') + goto backtrack; + + /* Read the next character. */ + GET_NEXT_WCHAR(); + } + + next_state = NULL; + for (trans_i = state; trans_i->state; trans_i++) + { + if (trans_i->code_min <= (tre_cint_t)prev_c + && trans_i->code_max >= (tre_cint_t)prev_c) + { + if (trans_i->assertions + && (CHECK_ASSERTIONS(trans_i->assertions) + || CHECK_CHAR_CLASSES(trans_i, tnfa, eflags))) + { + continue; + } + + if (next_state == NULL) + { + /* First matching transition. */ + next_state = trans_i->state; + next_tags = trans_i->tags; + } + else + { + /* Second matching transition. We may need to backtrack here + to take this transition instead of the first one, so we + push this transition in the backtracking stack so we can + jump back here if needed. */ + BT_STACK_PUSH(pos, str_byte, 0, trans_i->state, + trans_i->state_id, next_c, tags, mbstate); + { + int *tmp; + for (tmp = trans_i->tags; tmp && *tmp >= 0; tmp++) + stack->item.tags[*tmp] = pos; + } +#if 0 /* XXX - it's important not to look at all transitions here to keep + the stack small! */ + break; +#endif + } + } + } + + if (next_state != NULL) + { + /* Matching transitions were found. Take the first one. */ + state = next_state; + + /* Update the tag values. */ + if (next_tags) + while (*next_tags >= 0) + tags[*next_tags++] = pos; + } + else + { + backtrack: + /* A matching transition was not found. Try to backtrack. */ + if (stack->prev) + { + if (stack->item.state->assertions & ASSERT_BACKREF) + { + states_seen[stack->item.state_id] = 0; + } + + BT_STACK_POP(); + } + else if (match_eo < 0) + { + /* Try starting from a later position in the input string. */ + /* Check for end of string. */ + if (next_c == L'\0') + { + break; + } + next_c = next_c_start; +#ifdef TRE_MBSTATE + mbstate = mbstate_start; +#endif /* TRE_MBSTATE */ + str_byte = str_byte_start; + goto retry; + } + else + { + break; + } + } + } + + ret = match_eo >= 0 ? REG_OK : REG_NOMATCH; + *match_end_ofs = match_eo; + + error_exit: + tre_bt_mem_destroy(mem); +#ifndef TRE_USE_ALLOCA + if (tags) + xfree(tags); + if (pmatch) + xfree(pmatch); + if (states_seen) + xfree(states_seen); +#endif /* !TRE_USE_ALLOCA */ + + return ret; +} + +/*********************************************************************** + from regexec.c +***********************************************************************/ + +/* Fills the POSIX.2 regmatch_t array according to the TNFA tag and match + endpoint values. */ +static void +tre_fill_pmatch(size_t nmatch, regmatch_t pmatch[], int cflags, + const tre_tnfa_t *tnfa, regoff_t *tags, regoff_t match_eo) +{ + tre_submatch_data_t *submatch_data; + unsigned int i, j; + int *parents; + + i = 0; + if (match_eo >= 0 && !(cflags & REG_NOSUB)) + { + /* Construct submatch offsets from the tags. */ + submatch_data = tnfa->submatch_data; + while (i < tnfa->num_submatches && i < nmatch) + { + if (submatch_data[i].so_tag == tnfa->end_tag) + pmatch[i].rm_so = match_eo; + else + pmatch[i].rm_so = tags[submatch_data[i].so_tag]; + + if (submatch_data[i].eo_tag == tnfa->end_tag) + pmatch[i].rm_eo = match_eo; + else + pmatch[i].rm_eo = tags[submatch_data[i].eo_tag]; + + /* If either of the endpoints were not used, this submatch + was not part of the match. */ + if (pmatch[i].rm_so == -1 || pmatch[i].rm_eo == -1) + pmatch[i].rm_so = pmatch[i].rm_eo = -1; + + i++; + } + /* Reset all submatches that are not within all of their parent + submatches. */ + i = 0; + while (i < tnfa->num_submatches && i < nmatch) + { + if (pmatch[i].rm_eo == -1) + assert(pmatch[i].rm_so == -1); + assert(pmatch[i].rm_so <= pmatch[i].rm_eo); + + parents = submatch_data[i].parents; + if (parents != NULL) + for (j = 0; parents[j] >= 0; j++) + { + if (pmatch[i].rm_so < pmatch[parents[j]].rm_so + || pmatch[i].rm_eo > pmatch[parents[j]].rm_eo) + pmatch[i].rm_so = pmatch[i].rm_eo = -1; + } + i++; + } + } + + while (i < nmatch) + { + pmatch[i].rm_so = -1; + pmatch[i].rm_eo = -1; + i++; + } +} + + +/* + Wrapper functions for POSIX compatible regexp matching. +*/ + +int +regexec(const regex_t *restrict preg, const char *restrict string, + size_t nmatch, regmatch_t pmatch[restrict], int eflags) +{ + tre_tnfa_t *tnfa = (void *)preg->TRE_REGEX_T_FIELD; + reg_errcode_t status; + regoff_t *tags = NULL, eo; + if (tnfa->cflags & REG_NOSUB) nmatch = 0; + if (tnfa->num_tags > 0 && nmatch > 0) + { + tags = xmalloc(sizeof(*tags) * tnfa->num_tags); + if (tags == NULL) + return REG_ESPACE; + } + + /* Dispatch to the appropriate matcher. */ + if (tnfa->have_backrefs) + { + /* The regex has back references, use the backtracking matcher. */ + status = tre_tnfa_run_backtrack(tnfa, string, tags, eflags, &eo); + } + else + { + /* Exact matching, no back references, use the parallel matcher. */ + status = tre_tnfa_run_parallel(tnfa, string, tags, eflags, &eo); + } + + if (status == REG_OK) + /* A match was found, so fill the submatch registers. */ + tre_fill_pmatch(nmatch, pmatch, tnfa->cflags, tnfa, tags, eo); + if (tags) + xfree(tags); + return status; +} \ No newline at end of file diff --git a/lib/mlibc/options/posix/musl-generic-regex/tre-mem.c b/lib/mlibc/options/posix/musl-generic-regex/tre-mem.c new file mode 100644 index 0000000..a3df685 --- /dev/null +++ b/lib/mlibc/options/posix/musl-generic-regex/tre-mem.c @@ -0,0 +1,158 @@ +/* + tre-mem.c - TRE memory allocator + + Copyright (c) 2001-2009 Ville Laurikari + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +/* + This memory allocator is for allocating small memory blocks efficiently + in terms of memory overhead and execution speed. The allocated blocks + cannot be freed individually, only all at once. There can be multiple + allocators, though. +*/ + +#include +#include + +#include "tre.h" + +/* + This memory allocator is for allocating small memory blocks efficiently + in terms of memory overhead and execution speed. The allocated blocks + cannot be freed individually, only all at once. There can be multiple + allocators, though. +*/ + +/* Returns a new memory allocator or NULL if out of memory. */ +tre_mem_t +tre_mem_new_impl(int provided, void *provided_block) +{ + tre_mem_t mem; + if (provided) + { + mem = provided_block; + memset(mem, 0, sizeof(*mem)); + } + else + mem = xcalloc(1, sizeof(*mem)); + if (mem == NULL) + return NULL; + return mem; +} + + +/* Frees the memory allocator and all memory allocated with it. */ +void +tre_mem_destroy(tre_mem_t mem) +{ + tre_list_t *tmp, *l = mem->blocks; + + while (l != NULL) + { + xfree(l->data); + tmp = l->next; + xfree(l); + l = tmp; + } + xfree(mem); +} + + +/* Allocates a block of `size' bytes from `mem'. Returns a pointer to the + allocated block or NULL if an underlying malloc() failed. */ +void * +tre_mem_alloc_impl(tre_mem_t mem, int provided, void *provided_block, + int zero, size_t size) +{ + void *ptr; + + if (mem->failed) + { + return NULL; + } + + if (mem->n < size) + { + /* We need more memory than is available in the current block. + Allocate a new block. */ + tre_list_t *l; + if (provided) + { + if (provided_block == NULL) + { + mem->failed = 1; + return NULL; + } + mem->ptr = provided_block; + mem->n = TRE_MEM_BLOCK_SIZE; + } + else + { + int block_size; + if (size * 8 > TRE_MEM_BLOCK_SIZE) + block_size = size * 8; + else + block_size = TRE_MEM_BLOCK_SIZE; + l = xmalloc(sizeof(*l)); + if (l == NULL) + { + mem->failed = 1; + return NULL; + } + l->data = xmalloc(block_size); + if (l->data == NULL) + { + xfree(l); + mem->failed = 1; + return NULL; + } + l->next = NULL; + if (mem->current != NULL) + mem->current->next = l; + if (mem->blocks == NULL) + mem->blocks = l; + mem->current = l; + mem->ptr = l->data; + mem->n = block_size; + } + } + + /* Make sure the next pointer will be aligned. */ + size += ALIGN(mem->ptr + size, long); + + /* Allocate from current block. */ + ptr = mem->ptr; + mem->ptr += size; + mem->n -= size; + + /* Set to zero if needed. */ + if (zero) + memset(ptr, 0, size); + + return ptr; +} \ No newline at end of file diff --git a/lib/mlibc/options/posix/musl-generic-regex/tre.h b/lib/mlibc/options/posix/musl-generic-regex/tre.h new file mode 100644 index 0000000..5891f75 --- /dev/null +++ b/lib/mlibc/options/posix/musl-generic-regex/tre.h @@ -0,0 +1,241 @@ +// Taken from musl tre.h +/* + tre-internal.h - TRE internal definitions + + Copyright (c) 2001-2009 Ville Laurikari + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +#include +#include +#include + +#define hidden __attribute__((__visibility__("hidden"))) + +// TODO: These should probably go in limits.h +#define CHARCLASS_NAME_MAX 14 +#define RE_DUP_MAX 255 + +#undef TRE_MBSTATE + +#define NDEBUG + +#define TRE_REGEX_T_FIELD __opaque +typedef int reg_errcode_t; + +typedef wchar_t tre_char_t; + +#define DPRINT(msg) do { } while(0) + +#define elementsof(x) ( sizeof(x) / sizeof(x[0]) ) + +#define tre_mbrtowc(pwc, s, n, ps) (mbtowc((pwc), (s), (n))) + +/* Wide characters. */ +typedef wint_t tre_cint_t; +#define TRE_CHAR_MAX 0x10ffff + +#define tre_isalnum iswalnum +#define tre_isalpha iswalpha +#define tre_isblank iswblank +#define tre_iscntrl iswcntrl +#define tre_isdigit iswdigit +#define tre_isgraph iswgraph +#define tre_islower iswlower +#define tre_isprint iswprint +#define tre_ispunct iswpunct +#define tre_isspace iswspace +#define tre_isupper iswupper +#define tre_isxdigit iswxdigit + +#define tre_tolower towlower +#define tre_toupper towupper +#define tre_strlen wcslen + +/* Use system provided iswctype() and wctype(). */ +typedef wctype_t tre_ctype_t; +#define tre_isctype iswctype +#define tre_ctype wctype + +/* Returns number of bytes to add to (char *)ptr to make it + properly aligned for the type. */ +#define ALIGN(ptr, type) \ + ((((long)ptr) % sizeof(type)) \ + ? (sizeof(type) - (((long)ptr) % sizeof(type))) \ + : 0) + +#undef MAX +#undef MIN +#define MAX(a, b) (((a) >= (b)) ? (a) : (b)) +#define MIN(a, b) (((a) <= (b)) ? (a) : (b)) + +/* TNFA transition type. A TNFA state is an array of transitions, + the terminator is a transition with NULL `state'. */ +typedef struct tnfa_transition tre_tnfa_transition_t; + +struct tnfa_transition { + /* Range of accepted characters. */ + tre_cint_t code_min; + tre_cint_t code_max; + /* Pointer to the destination state. */ + tre_tnfa_transition_t *state; + /* ID number of the destination state. */ + int state_id; + /* -1 terminated array of tags (or NULL). */ + int *tags; + /* Assertion bitmap. */ + int assertions; + /* Assertion parameters. */ + union { + /* Character class assertion. */ + tre_ctype_t class; + /* Back reference assertion. */ + int backref; + } u; + /* Negative character class assertions. */ + tre_ctype_t *neg_classes; +}; + + +/* Assertions. */ +#define ASSERT_AT_BOL 1 /* Beginning of line. */ +#define ASSERT_AT_EOL 2 /* End of line. */ +#define ASSERT_CHAR_CLASS 4 /* Character class in `class'. */ +#define ASSERT_CHAR_CLASS_NEG 8 /* Character classes in `neg_classes'. */ +#define ASSERT_AT_BOW 16 /* Beginning of word. */ +#define ASSERT_AT_EOW 32 /* End of word. */ +#define ASSERT_AT_WB 64 /* Word boundary. */ +#define ASSERT_AT_WB_NEG 128 /* Not a word boundary. */ +#define ASSERT_BACKREF 256 /* A back reference in `backref'. */ +#define ASSERT_LAST 256 + +/* Tag directions. */ +typedef enum { + TRE_TAG_MINIMIZE = 0, + TRE_TAG_MAXIMIZE = 1 +} tre_tag_direction_t; + +/* Instructions to compute submatch register values from tag values + after a successful match. */ +struct tre_submatch_data { + /* Tag that gives the value for rm_so (submatch start offset). */ + int so_tag; + /* Tag that gives the value for rm_eo (submatch end offset). */ + int eo_tag; + /* List of submatches this submatch is contained in. */ + int *parents; +}; + +typedef struct tre_submatch_data tre_submatch_data_t; + + +/* TNFA definition. */ +typedef struct tnfa tre_tnfa_t; + +struct tnfa { + tre_tnfa_transition_t *transitions; + unsigned int num_transitions; + tre_tnfa_transition_t *initial; + tre_tnfa_transition_t *final; + tre_submatch_data_t *submatch_data; + char *firstpos_chars; + int first_char; + unsigned int num_submatches; + tre_tag_direction_t *tag_directions; + int *minimal_tags; + int num_tags; + int num_minimals; + int end_tag; + int num_states; + int cflags; + int have_backrefs; + int have_approx; +}; + +/* from tre-mem.h: */ + +#define TRE_MEM_BLOCK_SIZE 1024 + +typedef struct tre_list { + void *data; + struct tre_list *next; +} tre_list_t; + +typedef struct tre_mem_struct { + tre_list_t *blocks; + tre_list_t *current; + char *ptr; + size_t n; + int failed; + void **provided; +} *tre_mem_t; + +#ifndef __MLIBC_ABI_ONLY + +#define tre_mem_new_impl __tre_mem_new_impl +#define tre_mem_alloc_impl __tre_mem_alloc_impl +#define tre_mem_destroy __tre_mem_destroy + +hidden tre_mem_t tre_mem_new_impl(int provided, void *provided_block); +hidden void *tre_mem_alloc_impl(tre_mem_t mem, int provided, void *provided_block, + int zero, size_t size); + +/* Returns a new memory allocator or NULL if out of memory. */ +#define tre_mem_new() tre_mem_new_impl(0, NULL) + +/* Allocates a block of `size' bytes from `mem'. Returns a pointer to the + allocated block or NULL if an underlying malloc() failed. */ +#define tre_mem_alloc(mem, size) tre_mem_alloc_impl(mem, 0, NULL, 0, size) + +/* Allocates a block of `size' bytes from `mem'. Returns a pointer to the + allocated block or NULL if an underlying malloc() failed. The memory + is set to zero. */ +#define tre_mem_calloc(mem, size) tre_mem_alloc_impl(mem, 0, NULL, 1, size) + +#ifdef TRE_USE_ALLOCA +/* alloca() versions. Like above, but memory is allocated with alloca() + instead of malloc(). */ + +#define tre_mem_newa() \ + tre_mem_new_impl(1, alloca(sizeof(struct tre_mem_struct))) + +#define tre_mem_alloca(mem, size) \ + ((mem)->n >= (size) \ + ? tre_mem_alloc_impl((mem), 1, NULL, 0, (size)) \ + : tre_mem_alloc_impl((mem), 1, alloca(TRE_MEM_BLOCK_SIZE), 0, (size))) +#endif /* TRE_USE_ALLOCA */ + + +/* Frees the memory allocator and all memory allocated with it. */ +hidden void tre_mem_destroy(tre_mem_t mem); + +#define xmalloc malloc +#define xcalloc calloc +#define xfree free +#define xrealloc realloc + +#endif /* !__MLIBC_ABI_ONLY */ diff --git a/lib/mlibc/options/rtdl/aarch64/elf.hpp b/lib/mlibc/options/rtdl/aarch64/elf.hpp new file mode 100644 index 0000000..802d1a2 --- /dev/null +++ b/lib/mlibc/options/rtdl/aarch64/elf.hpp @@ -0,0 +1,37 @@ +#pragma once + +#include + +#define ELF_CLASS ELFCLASS64 +#define ELF_MACHINE EM_AARCH64 + +using elf_ehdr = Elf64_Ehdr; +using elf_phdr = Elf64_Phdr; +using elf_dyn = Elf64_Dyn; +using elf_rel = Elf64_Rel; +using elf_rela = Elf64_Rela; +using elf_relr = Elf64_Relr; +using elf_sym = Elf64_Sym; +using elf_addr = Elf64_Addr; + +using elf_info = Elf64_Xword; +using elf_addend = Elf64_Sxword; + +#define ELF_R_SYM ELF64_R_SYM +#define ELF_R_TYPE ELF64_R_TYPE +#define ELF_ST_BIND ELF64_ST_BIND + +#define R_NONE R_AARCH64_NONE +#define R_JUMP_SLOT R_AARCH64_JUMP_SLOT +#define R_ABSOLUTE R_AARCH64_ABS64 +#define R_GLOB_DAT R_AARCH64_GLOB_DAT +#define R_RELATIVE R_AARCH64_RELATIVE +#define R_IRELATIVE R_AARCH64_IRELATIVE +// #define R_OFFSET +#define R_COPY R_AARCH64_COPY +#define R_TLS_DTPMOD R_AARCH64_TLS_DTPMOD +#define R_TLS_DTPREL R_AARCH64_TLS_DTPREL +#define R_TLS_TPREL R_AARCH64_TLS_TPREL +#define R_TLSDESC R_AARCH64_TLSDESC + +#define TP_TCB_OFFSET (16) diff --git a/lib/mlibc/options/rtdl/aarch64/entry.S b/lib/mlibc/options/rtdl/aarch64/entry.S new file mode 100644 index 0000000..b22af53 --- /dev/null +++ b/lib/mlibc/options/rtdl/aarch64/entry.S @@ -0,0 +1,11 @@ + +.global _start +_start: + bl relocateSelf + + mov x0, sp + bl interpreterMain + + br x0 +.section .note.GNU-stack,"",%progbits + diff --git a/lib/mlibc/options/rtdl/aarch64/runtime.S b/lib/mlibc/options/rtdl/aarch64/runtime.S new file mode 100644 index 0000000..c3e2cff --- /dev/null +++ b/lib/mlibc/options/rtdl/aarch64/runtime.S @@ -0,0 +1,62 @@ + +.global __mlibcTlsdescStatic +.hidden __mlibcTlsdescStatic +.type __mlibcTlsdescStatic,@function +__mlibcTlsdescStatic: + ldr x0, [x0, #8] + ret + +// This function depends on the Tcb layout, since it pulls out the dtv pointer +// out of the thread control block +.global __mlibcTlsdescDynamic +.hidden __mlibcTlsdescDynamic +.type __mlibcTlsdescDynamic,@function +__mlibcTlsdescDynamic: + stp x1, x2, [sp, #-16]! + ldr x0, [x0, #8] + ldp x1, x2, [x0] // tlsIndex, addend + mrs x0, tpidr_el0 // tp + ldr x0, [x0, #-104] // tp->dtvPointers + ldr x0, [x0, x1, lsl 3] // [tlsIndex] + add x0, x0, x2 // + addend + mrs x1, tpidr_el0 // tp + sub x0, x0, x1 // result - tp + ldp x1, x2, [sp], #16 + ret + +.global pltRelocateStub +pltRelocateStub: + // we need to save / restore all registers than can hold function arguments + // we do not need to save callee-saved registers as they will not be trashed by lazyRelocate + // TODO: save floating point argument registers + + stp x0, x1, [sp, #-16]! + + // pointer to PLT entry + ldr x1, [sp, #24] + ldr x0, [x16] + sub x1, x1, x0 + asr x0, x0, #3 + + // pointer GOT + sub x0, x16, #8 // &PLTGOT[1] + + stp x2, x3, [sp, #-16]! + stp x4, x5, [sp, #-16]! + stp x6, x7, [sp, #-16]! + stp x8, x30, [sp, #-16]! + + bl lazyRelocate + mov x9, x0 + + ldp x8, x30, [sp], #16 + ldp x6, x7, [sp], #16 + ldp x4, x5, [sp], #16 + ldp x2, x1, [sp], #16 + + ldp x0, x1, [sp], #16 + add sp, sp, #16 + br x9 + +.section .note.GNU-stack,"",%progbits + diff --git a/lib/mlibc/options/rtdl/generic/linker.cpp b/lib/mlibc/options/rtdl/generic/linker.cpp new file mode 100644 index 0000000..a519c35 --- /dev/null +++ b/lib/mlibc/options/rtdl/generic/linker.cpp @@ -0,0 +1,1872 @@ +#include +#include +#include + +// keep a list of optional generic relocation types +enum { + R_OFFSET = (uintptr_t) -1, +}; + + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "elf.hpp" +#include "linker.hpp" + +#if !MLIBC_MMAP_ALLOCATE_DSO +uintptr_t libraryBase = 0x41000000; +#endif + +constexpr bool verbose = false; +constexpr bool stillSlightlyVerbose = false; +constexpr bool logBaseAddresses = false; +constexpr bool logRpath = false; +constexpr bool logLdPath = false; +constexpr bool eagerBinding = true; + +#if defined(__x86_64__) || defined(__i386__) +constexpr inline bool tlsAboveTp = false; +#elif defined(__aarch64__) +constexpr inline bool tlsAboveTp = true; +#elif defined(__riscv) +constexpr inline bool tlsAboveTp = true; +#else +# error Unknown architecture +#endif + +extern DebugInterface globalDebugInterface; +extern uintptr_t __stack_chk_guard; + +extern frg::manual_box> libraryPaths; +extern frg::manual_box> preloads; + +#if MLIBC_STATIC_BUILD +extern "C" size_t __init_array_start[]; +extern "C" size_t __init_array_end[]; +extern "C" size_t __preinit_array_start[]; +extern "C" size_t __preinit_array_end[]; +#endif + +size_t tlsMaxAlignment = 16; + +// This is the global "resolution timestamp" (RTS) counter. +// It is incremented each time __dlapi_open() (i.e. dlopen()) is called. +// Each DSO stores its objectRts (i.e. RTS at the time the object was loaded). +// DSOs in the global scope also store a globalRts (i.e. RTS at the time the +// object became global). This mechanism is used to determine which +// part of the global scope is considered for symbol resolution. +uint64_t rtsCounter = 2; + +bool trySeek(int fd, int64_t offset) { + off_t noff; + return mlibc::sys_seek(fd, offset, SEEK_SET, &noff) == 0; +} + +bool tryReadExactly(int fd, void *data, size_t length) { + size_t offset = 0; + while(offset < length) { + ssize_t chunk; + if(mlibc::sys_read(fd, reinterpret_cast(data) + offset, + length - offset, &chunk)) + return false; + __ensure(chunk > 0); + offset += chunk; + } + __ensure(offset == length); + return true; +} + +void closeOrDie(int fd) { + if(mlibc::sys_close(fd)) + __ensure(!"sys_close() failed"); +} + +uintptr_t alignUp(uintptr_t address, size_t align) { + return (address + align - 1) & ~(align - 1); +} + +// -------------------------------------------------------- +// ObjectRepository +// -------------------------------------------------------- + +ObjectRepository::ObjectRepository() +: loadedObjects{getAllocator()}, + _nameMap{frg::hash{}, getAllocator()} {} + +SharedObject *ObjectRepository::injectObjectFromDts(frg::string_view name, + frg::string path, uintptr_t base_address, + elf_dyn *dynamic, uint64_t rts) { + __ensure(!findLoadedObject(name)); + + auto object = frg::construct(getAllocator(), + name.data(), std::move(path), false, globalScope.get(), rts); + object->baseAddress = base_address; + object->dynamic = dynamic; + _parseDynamic(object); + + _addLoadedObject(object); + _discoverDependencies(object, globalScope.get(), rts); + + return object; +} + +SharedObject *ObjectRepository::injectObjectFromPhdrs(frg::string_view name, + frg::string path, void *phdr_pointer, + size_t phdr_entry_size, size_t num_phdrs, void *entry_pointer, + uint64_t rts) { + __ensure(!findLoadedObject(name)); + + auto object = frg::construct(getAllocator(), + name.data(), std::move(path), true, globalScope.get(), rts); + _fetchFromPhdrs(object, phdr_pointer, phdr_entry_size, num_phdrs, entry_pointer); + _parseDynamic(object); + + _addLoadedObject(object); + _discoverDependencies(object, globalScope.get(), rts); + + return object; +} + +SharedObject *ObjectRepository::injectStaticObject(frg::string_view name, + frg::string path, void *phdr_pointer, + size_t phdr_entry_size, size_t num_phdrs, void *entry_pointer, + uint64_t rts) { + __ensure(!findLoadedObject(name)); + auto object = frg::construct(getAllocator(), + name.data(), std::move(path), true, globalScope.get(), rts); + _fetchFromPhdrs(object, phdr_pointer, phdr_entry_size, num_phdrs, entry_pointer); + +#if MLIBC_STATIC_BUILD + object->initArray = reinterpret_cast(__init_array_start); + object->initArraySize = static_cast((uintptr_t)__init_array_end - + (uintptr_t)__init_array_start); + object->preInitArray = reinterpret_cast(__preinit_array_start); + object->preInitArraySize = static_cast((uintptr_t)__preinit_array_end - + (uintptr_t)__preinit_array_start); +#endif + + _addLoadedObject(object); + + return object; +} + +frg::expected ObjectRepository::requestObjectWithName(frg::string_view name, + SharedObject *origin, Scope *localScope, bool createScope, uint64_t rts) { + if (auto obj = findLoadedObject(name)) + return obj; + + auto tryToOpen = [&] (const char *path) { + int fd; + if(auto x = mlibc::sys_open(path, O_RDONLY, 0, &fd); x) { + return -1; + } + return fd; + }; + + // TODO(arsen): this process can probably undergo heavy optimization, by + // preprocessing the rpath only once on parse + auto processRpath = [&] (frg::string_view path) { + frg::string sPath { getAllocator() }; + if (path.starts_with("$ORIGIN")) { + frg::string_view dirname = origin->path; + auto lastsl = dirname.find_last('/'); + if (lastsl != size_t(-1)) { + dirname = dirname.sub_string(0, lastsl); + } else { + dirname = "."; + } + sPath = frg::string{ getAllocator(), dirname }; + sPath += path.sub_string(7, path.size() - 7); + } else { + sPath = frg::string{ getAllocator(), path }; + } + if (sPath[sPath.size() - 1] != '/') { + sPath += '/'; + } + sPath += name; + if (logRpath) + mlibc::infoLogger() << "rtdl: trying in rpath " << sPath << frg::endlog; + int fd = tryToOpen(sPath.data()); + if (logRpath && fd >= 0) + mlibc::infoLogger() << "rtdl: found in rpath" << frg::endlog; + return frg::tuple { fd, std::move(sPath) }; + }; + + frg::string chosenPath { getAllocator() }; + int fd = -1; + if (origin && origin->runPath) { + size_t start = 0; + size_t idx = 0; + frg::string_view rpath { origin->runPath }; + auto next = [&] () { + idx = rpath.find_first(':', start); + if (idx == (size_t)-1) + idx = rpath.size(); + }; + for (next(); idx < rpath.size(); next()) { + auto path = rpath.sub_string(start, idx - start); + start = idx + 1; + auto [fd_, fullPath] = processRpath(path); + if (fd_ != -1) { + fd = fd_; + chosenPath = std::move(fullPath); + break; + } + } + if (fd == -1) { + auto path = rpath.sub_string(start, rpath.size() - start); + auto [fd_, fullPath] = processRpath(path); + if (fd_ != -1) { + fd = fd_; + chosenPath = std::move(fullPath); + } + } + } else if (logRpath) { + mlibc::infoLogger() << "rtdl: no rpath set for object" << frg::endlog; + } + + for(size_t i = 0; i < libraryPaths->size() && fd == -1; i++) { + auto ldPath = (*libraryPaths)[i]; + auto path = frg::string{getAllocator(), ldPath} + '/' + name; + if(logLdPath) + mlibc::infoLogger() << "rtdl: Trying to load " << name << " from ldpath " << ldPath << "/" << frg::endlog; + fd = tryToOpen(path.data()); + if(fd >= 0) { + chosenPath = std::move(path); + break; + } + } + if(fd == -1) + return LinkerError::notFound; + + if (createScope) { + __ensure(localScope == nullptr); + + // TODO: Free this when the scope is no longer needed. + localScope = frg::construct(getAllocator()); + } + + __ensure(localScope != nullptr); + + auto object = frg::construct(getAllocator(), + name.data(), std::move(chosenPath), false, localScope, rts); + + auto result = _fetchFromFile(object, fd); + closeOrDie(fd); + if(!result) { + frg::destruct(getAllocator(), object); + return result.error(); + } + + _parseDynamic(object); + + _addLoadedObject(object); + _discoverDependencies(object, localScope, rts); + + return object; +} + +frg::expected ObjectRepository::requestObjectAtPath(frg::string_view path, + Scope *localScope, bool createScope, uint64_t rts) { + // TODO: Support SONAME correctly. + auto lastSlash = path.find_last('/') + 1; + auto name = path; + if (!lastSlash) { + name = name.sub_string(lastSlash, path.size() - lastSlash); + } + if (auto obj = findLoadedObject(name)) + return obj; + + if (createScope) { + __ensure(localScope == nullptr); + + // TODO: Free this when the scope is no longer needed. + localScope = frg::construct(getAllocator()); + } + + __ensure(localScope != nullptr); + + auto object = frg::construct(getAllocator(), + name.data(), path.data(), false, localScope, rts); + + frg::string no_prefix(getAllocator(), path); + + int fd; + if(mlibc::sys_open((no_prefix + '\0').data(), O_RDONLY, 0, &fd)) { + frg::destruct(getAllocator(), object); + return LinkerError::notFound; + } + auto result = _fetchFromFile(object, fd); + closeOrDie(fd); + if(!result) { + frg::destruct(getAllocator(), object); + return result.error(); + } + + _parseDynamic(object); + + _addLoadedObject(object); + _discoverDependencies(object, localScope, rts); + + return object; +} + +SharedObject *ObjectRepository::findCaller(void *addr) { + uintptr_t target = reinterpret_cast(addr); + + for (auto [name, object] : _nameMap) { + // Search all PT_LOAD segments for the specified address. + for(size_t j = 0; j < object->phdrCount; j++) { + auto phdr = (elf_phdr *)((uintptr_t)object->phdrPointer + j * object->phdrEntrySize); + if (phdr->p_type == PT_LOAD) { + uintptr_t start = object->baseAddress + phdr->p_vaddr; + uintptr_t end = start + phdr->p_memsz; + if (start <= target && target < end) + return object; + } + } + } + + return nullptr; +} + +SharedObject *ObjectRepository::findLoadedObject(frg::string_view name) { + auto it = _nameMap.get(name); + if (it) + return *it; + + for (auto object : loadedObjects) { + // See if any object has a matching SONAME. + if (object->soName && name == object->soName) + return object; + } + + // TODO: We should also look at the device and inode here as a fallback. + return nullptr; +} + +// -------------------------------------------------------- +// ObjectRepository: Fetching methods. +// -------------------------------------------------------- + +void ObjectRepository::_fetchFromPhdrs(SharedObject *object, void *phdr_pointer, + size_t phdr_entry_size, size_t phdr_count, void *entry_pointer) { + __ensure(object->isMainObject); + object->phdrPointer = phdr_pointer; + object->phdrEntrySize = phdr_entry_size; + object->phdrCount = phdr_count; + if(verbose) + mlibc::infoLogger() << "rtdl: Loading " << object->name << frg::endlog; + + // Note: the entry pointer is absolute and not relative to the base address. + object->entry = entry_pointer; + + frg::optional dynamic_offset; + frg::optional tls_offset; + + // segments are already mapped, so we just have to find the dynamic section + for(size_t i = 0; i < phdr_count; i++) { + auto phdr = (elf_phdr *)((uintptr_t)phdr_pointer + i * phdr_entry_size); + switch(phdr->p_type) { + case PT_PHDR: + // Determine the executable's base address (in the PIE case) by comparing + // the PHDR segment's load address against it's address in the ELF file. + object->baseAddress = reinterpret_cast(phdr_pointer) - phdr->p_vaddr; + if(verbose) + mlibc::infoLogger() << "rtdl: Executable is loaded at " + << (void *)object->baseAddress << frg::endlog; + break; + case PT_DYNAMIC: + dynamic_offset = phdr->p_vaddr; + break; + case PT_TLS: { + object->tlsSegmentSize = phdr->p_memsz; + object->tlsAlignment = phdr->p_align; + object->tlsImageSize = phdr->p_filesz; + tls_offset = phdr->p_vaddr; + break; + case PT_INTERP: + object->interpreterPath = frg::string{ + (char*)(object->baseAddress + phdr->p_vaddr), + getAllocator() + }; + } break; + default: + //FIXME warn about unknown phdrs + break; + } + } + + if(dynamic_offset) + object->dynamic = (elf_dyn *)(object->baseAddress + *dynamic_offset); + if(tls_offset) + object->tlsImagePtr = (void *)(object->baseAddress + *tls_offset); +} + + +frg::expected ObjectRepository::_fetchFromFile(SharedObject *object, int fd) { + __ensure(!object->isMainObject); + + // read the elf file header + elf_ehdr ehdr; + if(!tryReadExactly(fd, &ehdr, sizeof(elf_ehdr))) + return LinkerError::fileTooShort; + + if(ehdr.e_ident[0] != 0x7F + || ehdr.e_ident[1] != 'E' + || ehdr.e_ident[2] != 'L' + || ehdr.e_ident[3] != 'F') + return LinkerError::notElf; + + if((ehdr.e_type != ET_EXEC && ehdr.e_type != ET_DYN) + || ehdr.e_machine != ELF_MACHINE + || ehdr.e_ident[EI_CLASS] != ELF_CLASS) + return LinkerError::wrongElfType; + + // read the elf program headers + auto phdr_buffer = (char *)getAllocator().allocate(ehdr.e_phnum * ehdr.e_phentsize); + if(!phdr_buffer) + return LinkerError::outOfMemory; + + if(!trySeek(fd, ehdr.e_phoff)) { + getAllocator().deallocate(phdr_buffer, ehdr.e_phnum * ehdr.e_phentsize); + return LinkerError::invalidProgramHeader; + } + if(!tryReadExactly(fd, phdr_buffer, ehdr.e_phnum * ehdr.e_phentsize)) { + getAllocator().deallocate(phdr_buffer, ehdr.e_phnum * ehdr.e_phentsize); + return LinkerError::invalidProgramHeader; + } + + object->phdrPointer = phdr_buffer; + object->phdrCount = ehdr.e_phnum; + object->phdrEntrySize = ehdr.e_phentsize; + + // Allocate virtual address space for the DSO. + constexpr size_t hugeSize = 0x200000; + + uintptr_t highest_address = 0; + for(int i = 0; i < ehdr.e_phnum; i++) { + auto phdr = (elf_phdr *)(phdr_buffer + i * ehdr.e_phentsize); + + if(phdr->p_type != PT_LOAD) + continue; + + auto limit = phdr->p_vaddr + phdr->p_memsz; + if(limit > highest_address) + highest_address = limit; + } + + __ensure(!(object->baseAddress & (hugeSize - 1))); + + highest_address = (highest_address + mlibc::page_size - 1) & ~(mlibc::page_size - 1); + +#if MLIBC_MMAP_ALLOCATE_DSO + void *mappedAddr = nullptr; + + if (mlibc::sys_vm_map(nullptr, + highest_address - object->baseAddress, PROT_NONE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0, &mappedAddr)) { + mlibc::infoLogger() << "sys_vm_map failed when allocating address space for DSO \"" + << object->name << "\"" + << ", base " << (void *)object->baseAddress + << ", requested " << (highest_address - object->baseAddress) << " bytes" + << frg::endlog; + getAllocator().deallocate(phdr_buffer, ehdr.e_phnum * ehdr.e_phentsize); + return LinkerError::outOfMemory; + } + + object->baseAddress = reinterpret_cast(mappedAddr); +#else + object->baseAddress = libraryBase; + libraryBase += (highest_address + (hugeSize - 1)) & ~(hugeSize - 1); +#endif + + if(verbose || logBaseAddresses) + mlibc::infoLogger() << "rtdl: Loading " << object->name + << " at " << (void *)object->baseAddress << frg::endlog; + + // Load all segments. + constexpr size_t pageSize = 0x1000; + for(int i = 0; i < ehdr.e_phnum; i++) { + auto phdr = (elf_phdr *)(phdr_buffer + i * ehdr.e_phentsize); + + if(phdr->p_type == PT_LOAD) { + size_t misalign = phdr->p_vaddr & (pageSize - 1); + __ensure(phdr->p_memsz > 0); + __ensure(phdr->p_memsz >= phdr->p_filesz); + + // If the following condition is violated, we cannot use mmap() the segment; + // however, GCC only generates ELF files that satisfy this. + __ensure(misalign == (phdr->p_offset & (pageSize - 1))); + + auto map_address = object->baseAddress + phdr->p_vaddr - misalign; + auto backed_map_size = (phdr->p_filesz + misalign + pageSize - 1) & ~(pageSize - 1); + auto total_map_size = (phdr->p_memsz + misalign + pageSize - 1) & ~(pageSize - 1); + + int prot = 0; + if(phdr->p_flags & PF_R) + prot |= PROT_READ; + if(phdr->p_flags & PF_W) + prot |= PROT_WRITE; + if(phdr->p_flags & PF_X) + prot |= PROT_EXEC; + + #if MLIBC_MAP_DSO_SEGMENTS + void *map_pointer; + if(mlibc::sys_vm_map(reinterpret_cast(map_address), + backed_map_size, prot | PROT_WRITE, + MAP_PRIVATE | MAP_FIXED, fd, phdr->p_offset - misalign, &map_pointer)) + __ensure(!"sys_vm_map failed"); + if(total_map_size > backed_map_size) + if(mlibc::sys_vm_map(reinterpret_cast(map_address + backed_map_size), + total_map_size - backed_map_size, prot | PROT_WRITE, + MAP_PRIVATE | MAP_FIXED | MAP_ANONYMOUS, -1, 0, &map_pointer)) + __ensure(!"sys_vm_map failed"); + + if(mlibc::sys_vm_readahead) + if(mlibc::sys_vm_readahead(reinterpret_cast(map_address), + backed_map_size)) + mlibc::infoLogger() << "mlibc: sys_vm_readahead() failed in ld.so" + << frg::endlog; + + // Clear the trailing area at the end of the backed mapping. + // We do not clear the leading area; programs are not supposed to access it. + memset(reinterpret_cast(map_address + misalign + phdr->p_filesz), + 0, phdr->p_memsz - phdr->p_filesz); + #else + (void)backed_map_size; + + void *map_pointer; + if(mlibc::sys_vm_map(reinterpret_cast(map_address), + total_map_size, prot | PROT_WRITE, + MAP_PRIVATE | MAP_FIXED | MAP_ANONYMOUS, -1, 0, &map_pointer)) + __ensure(!"sys_vm_map failed"); + + __ensure(trySeek(fd, phdr->p_offset)); + __ensure(tryReadExactly(fd, reinterpret_cast(map_address) + misalign, + phdr->p_filesz)); + #endif + // Take care of removing superfluous permissions. + if(mlibc::sys_vm_protect && ((prot & PROT_WRITE) == 0)) + if(mlibc::sys_vm_protect(map_pointer, total_map_size, prot)) + mlibc::infoLogger() << "mlibc: sys_vm_protect() failed in ld.so" << frg::endlog; + }else if(phdr->p_type == PT_TLS) { + object->tlsSegmentSize = phdr->p_memsz; + object->tlsAlignment = phdr->p_align; + object->tlsImageSize = phdr->p_filesz; + object->tlsImagePtr = (void *)(object->baseAddress + phdr->p_vaddr); + }else if(phdr->p_type == PT_DYNAMIC) { + object->dynamic = (elf_dyn *)(object->baseAddress + phdr->p_vaddr); + }else if(phdr->p_type == PT_INTERP + || phdr->p_type == PT_PHDR + || phdr->p_type == PT_NOTE + || phdr->p_type == PT_RISCV_ATTRIBUTES + || phdr->p_type == PT_GNU_EH_FRAME + || phdr->p_type == PT_GNU_RELRO + || phdr->p_type == PT_GNU_STACK + || phdr->p_type == PT_GNU_PROPERTY) { + // ignore the phdr + }else{ + mlibc::panicLogger() << "Unexpected PHDR type 0x" + << frg::hex_fmt(phdr->p_type) << " in DSO " << object->name << frg::endlog; + } + } + + return frg::success; +} + +// -------------------------------------------------------- +// ObjectRepository: Parsing methods. +// -------------------------------------------------------- + +void ObjectRepository::_parseDynamic(SharedObject *object) { + if(!object->dynamic) + mlibc::infoLogger() << "ldso: Object '" << object->name + << "' does not have a dynamic section" << frg::endlog; + __ensure(object->dynamic); + + // Fix up these offsets to addresses after the loop, since the + // addresses depend on the value of DT_STRTAB. + frg::optional runpath_offset; + /* If true, ignore the RPATH. */ + bool runpath_found = false; + frg::optional soname_offset; + + for(size_t i = 0; object->dynamic[i].d_tag != DT_NULL; i++) { + elf_dyn *dynamic = &object->dynamic[i]; + switch(dynamic->d_tag) { + // handle hash table, symbol table and string table + case DT_HASH: + object->hashStyle = HashStyle::systemV; + object->hashTableOffset = dynamic->d_un.d_ptr; + break; + case DT_GNU_HASH: + object->hashStyle = HashStyle::gnu; + object->hashTableOffset = dynamic->d_un.d_ptr; + break; + case DT_STRTAB: + object->stringTableOffset = dynamic->d_un.d_ptr; + break; + case DT_STRSZ: + break; // we don't need the size of the string table + case DT_SYMTAB: + object->symbolTableOffset = dynamic->d_un.d_ptr; + break; + case DT_SYMENT: + __ensure(dynamic->d_un.d_val == sizeof(elf_sym)); + break; + // handle lazy relocation table + case DT_PLTGOT: + object->globalOffsetTable = (void **)(object->baseAddress + + dynamic->d_un.d_ptr); + break; + case DT_JMPREL: + object->lazyRelocTableOffset = dynamic->d_un.d_ptr; + break; + case DT_PLTRELSZ: + object->lazyTableSize = dynamic->d_un.d_val; + break; + case DT_PLTREL: + if(dynamic->d_un.d_val == DT_RELA) { + object->lazyExplicitAddend = true; + }else{ + __ensure(dynamic->d_un.d_val == DT_REL); + object->lazyExplicitAddend = false; + } + break; + // TODO: Implement this correctly! + case DT_SYMBOLIC: + object->symbolicResolution = true; + break; + case DT_BIND_NOW: + object->eagerBinding = true; + break; + case DT_FLAGS: { + if(dynamic->d_un.d_val & DF_SYMBOLIC) + object->symbolicResolution = true; + if(dynamic->d_un.d_val & DF_STATIC_TLS) + object->haveStaticTls = true; + if(dynamic->d_un.d_val & DF_BIND_NOW) + object->eagerBinding = true; + + auto ignored = DF_BIND_NOW | DF_SYMBOLIC | DF_STATIC_TLS; +#ifdef __riscv + // Work around https://sourceware.org/bugzilla/show_bug.cgi?id=24673. + ignored |= DF_TEXTREL; +#else + if(dynamic->d_un.d_val & DF_TEXTREL) + mlibc::panicLogger() << "\e[31mrtdl: DF_TEXTREL is unimplemented" << frg::endlog; +#endif + if(dynamic->d_un.d_val & ~ignored) + mlibc::infoLogger() << "\e[31mrtdl: DT_FLAGS(" << frg::hex_fmt{dynamic->d_un.d_val & ~ignored} + << ") is not implemented correctly!\e[39m" + << frg::endlog; + } break; + case DT_FLAGS_1: + if(dynamic->d_un.d_val & DF_1_NOW) + object->eagerBinding = true; + // The DF_1_PIE flag is informational only. It is used by e.g file(1). + // The DF_1_NODELETE flag has a similar effect to RTLD_NODELETE, both of which we + // ignore because we don't implement dlclose(). + if(dynamic->d_un.d_val & ~(DF_1_NOW | DF_1_PIE | DF_1_NODELETE)) + mlibc::infoLogger() << "\e[31mrtdl: DT_FLAGS_1(" << frg::hex_fmt{dynamic->d_un.d_val} + << ") is not implemented correctly!\e[39m" + << frg::endlog; + break; + case DT_RPATH: + if (runpath_found) { + /* Ignore RPATH if RUNPATH was present. */ + break; + } + [[fallthrough]]; + case DT_RUNPATH: + runpath_found = dynamic->d_tag == DT_RUNPATH; + runpath_offset = dynamic->d_un.d_val; + break; + case DT_INIT: + if(dynamic->d_un.d_ptr != 0) + object->initPtr = (InitFuncPtr)(object->baseAddress + dynamic->d_un.d_ptr); + break; + case DT_INIT_ARRAY: + if(dynamic->d_un.d_ptr != 0) + object->initArray = (InitFuncPtr *)(object->baseAddress + dynamic->d_un.d_ptr); + break; + case DT_INIT_ARRAYSZ: + object->initArraySize = dynamic->d_un.d_val; + break; + case DT_PREINIT_ARRAY: + if(dynamic->d_un.d_ptr != 0) { + // Only the main object is allowed pre-initializers. + __ensure(object->isMainObject); + object->preInitArray = (InitFuncPtr *)(object->baseAddress + dynamic->d_un.d_ptr); + } + break; + case DT_PREINIT_ARRAYSZ: + // Only the main object is allowed pre-initializers. + __ensure(object->isMainObject); + object->preInitArraySize = dynamic->d_un.d_val; + break; + case DT_DEBUG: +#if ELF_CLASS == ELFCLASS32 + dynamic->d_un.d_val = reinterpret_cast(&globalDebugInterface); +#elif ELF_CLASS == ELFCLASS64 + dynamic->d_un.d_val = reinterpret_cast(&globalDebugInterface); +#endif + break; + case DT_SONAME: + soname_offset = dynamic->d_un.d_val; + break; + // ignore unimportant tags + case DT_NEEDED: // we handle this later + case DT_FINI: case DT_FINI_ARRAY: case DT_FINI_ARRAYSZ: + case DT_RELA: case DT_RELASZ: case DT_RELAENT: case DT_RELACOUNT: + case DT_REL: case DT_RELSZ: case DT_RELENT: case DT_RELCOUNT: + case DT_RELR: case DT_RELRSZ: case DT_RELRENT: + case DT_VERSYM: + case DT_VERDEF: case DT_VERDEFNUM: + case DT_VERNEED: case DT_VERNEEDNUM: +#ifdef __riscv + case DT_TEXTREL: // Work around https://sourceware.org/bugzilla/show_bug.cgi?id=24673. +#endif + break; + case DT_TLSDESC_PLT: case DT_TLSDESC_GOT: + break; + default: + // Ignore unknown entries in the os-specific area as we don't use them. + if(dynamic->d_tag < DT_LOOS || dynamic->d_tag > DT_HIOS) { + mlibc::panicLogger() << "Unexpected dynamic entry " + << (void *)dynamic->d_tag << " in object" << frg::endlog; + } + } + } + + if(runpath_offset) { + object->runPath = reinterpret_cast(object->baseAddress + + object->stringTableOffset + *runpath_offset); + } + if(soname_offset) { + object->soName = reinterpret_cast(object->baseAddress + + object->stringTableOffset + *soname_offset); + } +} + +void ObjectRepository::_discoverDependencies(SharedObject *object, + Scope *localScope, uint64_t rts) { + if(object->isMainObject) { + for(auto preload : *preloads) { + frg::expected libraryResult; + if (preload.find_first('/') == size_t(-1)) { + libraryResult = requestObjectWithName(preload, object, globalScope.get(), false, 1); + } else { + libraryResult = requestObjectAtPath(preload, globalScope.get(), false, 1); + } + if(!libraryResult) + mlibc::panicLogger() << "rtdl: Could not load preload " << preload << frg::endlog; + + if(verbose) + mlibc::infoLogger() << "rtdl: Preloading " << preload << frg::endlog; + + object->dependencies.push_back(libraryResult.value()); + } + } + + // Load required dynamic libraries. + for(size_t i = 0; object->dynamic[i].d_tag != DT_NULL; i++) { + elf_dyn *dynamic = &object->dynamic[i]; + if(dynamic->d_tag != DT_NEEDED) + continue; + + const char *library_str = (const char *)(object->baseAddress + + object->stringTableOffset + dynamic->d_un.d_val); + + auto library = requestObjectWithName(frg::string_view{library_str}, + object, localScope, false, rts); + if(!library) + mlibc::panicLogger() << "Could not satisfy dependency " << library_str << frg::endlog; + object->dependencies.push(library.value()); + } +} + +void ObjectRepository::_addLoadedObject(SharedObject *object) { + _nameMap.insert(object->name, object); + loadedObjects.push_back(object); +} + +// -------------------------------------------------------- +// SharedObject +// -------------------------------------------------------- + +SharedObject::SharedObject(const char *name, frg::string path, + bool is_main_object, Scope *local_scope, uint64_t object_rts) + : name(name, getAllocator()), path(std::move(path)), + interpreterPath(getAllocator()), soName(nullptr), + isMainObject(is_main_object), objectRts(object_rts), inLinkMap(false), + baseAddress(0), localScope(local_scope), dynamic(nullptr), + globalOffsetTable(nullptr), entry(nullptr), tlsSegmentSize(0), + tlsAlignment(0), tlsImageSize(0), tlsImagePtr(nullptr), + tlsInitialized(false), hashTableOffset(0), symbolTableOffset(0), + stringTableOffset(0), lazyRelocTableOffset(0), lazyTableSize(0), + lazyExplicitAddend(false), symbolicResolution(false), + eagerBinding(false), haveStaticTls(false), + dependencies(getAllocator()), tlsModel(TlsModel::null), + tlsOffset(0), globalRts(0), wasLinked(false), + scheduledForInit(false), onInitStack(false), + wasInitialized(false) { } + +SharedObject::SharedObject(const char *name, const char *path, + bool is_main_object, Scope *localScope, uint64_t object_rts) + : SharedObject(name, + frg::string { path, getAllocator() }, + is_main_object, localScope, object_rts) {} + +void processLateRelocation(Relocation rel) { + // resolve the symbol if there is a symbol + frg::optional p; + if(rel.symbol_index()) { + auto symbol = (elf_sym *)(rel.object()->baseAddress + rel.object()->symbolTableOffset + + rel.symbol_index() * sizeof(elf_sym)); + ObjectSymbol r(rel.object(), symbol); + + p = Scope::resolveGlobalOrLocal(*globalScope, rel.object()->localScope, + r.getString(), rel.object()->objectRts, Scope::resolveCopy); + } + + switch(rel.type()) { + case R_COPY: + __ensure(p); + memcpy(rel.destination(), (void *)p->virtualAddress(), p->symbol()->st_size); + break; + +// TODO: R_IRELATIVE also exists on other architectures but will likely need a different implementation. +#if defined(__x86_64__) || defined(__i386__) + case R_IRELATIVE: { + uintptr_t addr = rel.object()->baseAddress + rel.addend_rel(); + auto* fn = reinterpret_cast(addr); + rel.relocate(fn()); + } break; +#elif defined(__aarch64__) + case R_IRELATIVE: { + uintptr_t addr = rel.object()->baseAddress + rel.addend_rel(); + auto* fn = reinterpret_cast(addr); + // TODO: the function should get passed AT_HWCAP value. + rel.relocate(fn(0)); + } break; +#endif + + default: + break; + } +} + +void processLateRelocations(SharedObject *object) { + frg::optional rel_offset; + frg::optional rel_length; + + frg::optional rela_offset; + frg::optional rela_length; + + for(size_t i = 0; object->dynamic[i].d_tag != DT_NULL; i++) { + elf_dyn *dynamic = &object->dynamic[i]; + + switch(dynamic->d_tag) { + case DT_REL: + rel_offset = dynamic->d_un.d_ptr; + break; + case DT_RELSZ: + rel_length = dynamic->d_un.d_val; + break; + case DT_RELENT: + __ensure(dynamic->d_un.d_val == sizeof(elf_rel)); + break; + case DT_RELA: + rela_offset = dynamic->d_un.d_ptr; + break; + case DT_RELASZ: + rela_length = dynamic->d_un.d_val; + break; + case DT_RELAENT: + __ensure(dynamic->d_un.d_val == sizeof(elf_rela)); + break; + } + } + + if(rela_offset && rela_length) { + for(size_t offset = 0; offset < *rela_length; offset += sizeof(elf_rela)) { + auto reloc = (elf_rela *)(object->baseAddress + *rela_offset + offset); + auto r = Relocation(object, reloc); + processLateRelocation(r); + } + } else if(rel_offset && rel_length) { + for(size_t offset = 0; offset < *rel_length; offset += sizeof(elf_rel)) { + auto reloc = (elf_rel *)(object->baseAddress + *rel_offset + offset); + auto r = Relocation(object, reloc); + processLateRelocation(r); + } + }else{ + __ensure(!rela_offset && !rela_length); + __ensure(!rel_offset && !rel_length); + } +} + +void doInitialize(SharedObject *object) { + __ensure(object->wasLinked); + __ensure(!object->wasInitialized); + + // if the object has dependencies we initialize them first + for(size_t i = 0; i < object->dependencies.size(); i++) + __ensure(object->dependencies[i]->wasInitialized); + + if(verbose) + mlibc::infoLogger() << "rtdl: Initialize " << object->name << frg::endlog; + + if(verbose) + mlibc::infoLogger() << "rtdl: Running DT_INIT function" << frg::endlog; + if(object->initPtr != nullptr) + object->initPtr(); + + if(verbose) + mlibc::infoLogger() << "rtdl: Running DT_INIT_ARRAY functions" << frg::endlog; + __ensure((object->initArraySize % sizeof(InitFuncPtr)) == 0); + for(size_t i = 0; i < object->initArraySize / sizeof(InitFuncPtr); i++) + object->initArray[i](); + + if(verbose) + mlibc::infoLogger() << "rtdl: Object initialization complete" << frg::endlog; + object->wasInitialized = true; +} + +// -------------------------------------------------------- +// RuntimeTlsMap +// -------------------------------------------------------- + +RuntimeTlsMap::RuntimeTlsMap() +: initialPtr{0}, initialLimit{0}, indices{getAllocator()} { } + +void initTlsObjects(Tcb *tcb, const frg::vector &objects, bool checkInitialized) { + // Initialize TLS segments that follow the static model. + for(auto object : objects) { + if(object->tlsModel == TlsModel::initial) { + if(checkInitialized && object->tlsInitialized) + continue; + + char *tcb_ptr = reinterpret_cast(tcb); + auto tls_ptr = tcb_ptr + object->tlsOffset; + memset(tls_ptr, 0, object->tlsSegmentSize); + memcpy(tls_ptr, object->tlsImagePtr, object->tlsImageSize); + + if (verbose) { + mlibc::infoLogger() << "rtdl: wrote tls image at " << (void *)tls_ptr + << ", size = 0x" << frg::hex_fmt{object->tlsSegmentSize} << frg::endlog; + } + + if (checkInitialized) + object->tlsInitialized = true; + } + } +} + +Tcb *allocateTcb() { + size_t tlsInitialSize = runtimeTlsMap->initialLimit; + + // To make sure that both the TCB and TLS data are sufficiently aligned, allocate + // slightly more than necessary and adjust alignment afterwards. + size_t alignOverhead = frg::max(alignof(Tcb), tlsMaxAlignment); + size_t allocSize = tlsInitialSize + sizeof(Tcb) + alignOverhead; + auto allocation = reinterpret_cast(getAllocator().allocate(allocSize)); + memset(reinterpret_cast(allocation), 0, allocSize); + + uintptr_t tlsAddress, tcbAddress; + if constexpr (tlsAboveTp) { + // Here we must satisfy two requirements of the TCB and the TLS data: + // 1. One should follow the other immediately in memory. We do this so that + // we can simply add or subtract sizeof(Tcb) to obtain the address of the other. + // 2. Both should be sufficiently aligned. + // To do this, we will fix whichever address has stricter alignment requirements, and + // derive the other from it. + if (tlsMaxAlignment > alignof(Tcb)) { + tlsAddress = alignUp(allocation + sizeof(Tcb), tlsMaxAlignment); + tcbAddress = tlsAddress - sizeof(Tcb); + } else { + tcbAddress = alignUp(allocation, alignof(Tcb)); + tlsAddress = tcbAddress + sizeof(Tcb); + } + __ensure((tlsAddress & (tlsMaxAlignment - 1)) == 0); + __ensure(tlsAddress == tcbAddress + sizeof(Tcb)); + } else { + // The TCB should be aligned such that the preceding blocks are aligned too. + tcbAddress = alignUp(allocation + tlsInitialSize, alignOverhead); + tlsAddress = tcbAddress - tlsInitialSize; + } + __ensure((tcbAddress & (alignof(Tcb) - 1)) == 0); + + if (verbose) { + mlibc::infoLogger() << "rtdl: tcb allocated at " << (void *)tcbAddress + << ", size = 0x" << frg::hex_fmt{sizeof(Tcb)} << frg::endlog; + mlibc::infoLogger() << "rtdl: tls allocated at " << (void *)tlsAddress + << ", size = 0x" << frg::hex_fmt{tlsInitialSize} << frg::endlog; + } + + Tcb *tcb_ptr = new ((char *)tcbAddress) Tcb; + tcb_ptr->selfPointer = tcb_ptr; + + tcb_ptr->stackCanary = __stack_chk_guard; + tcb_ptr->cancelBits = tcbCancelEnableBit; + tcb_ptr->didExit = 0; + tcb_ptr->isJoinable = 1; + memset(&tcb_ptr->returnValue, 0, sizeof(tcb_ptr->returnValue)); + tcb_ptr->localKeys = frg::construct>(getAllocator()); + tcb_ptr->dtvSize = runtimeTlsMap->indices.size(); + tcb_ptr->dtvPointers = frg::construct_n(getAllocator(), runtimeTlsMap->indices.size()); + memset(tcb_ptr->dtvPointers, 0, sizeof(void *) * runtimeTlsMap->indices.size()); + for(size_t i = 0; i < runtimeTlsMap->indices.size(); ++i) { + auto object = runtimeTlsMap->indices[i]; + if(object->tlsModel != TlsModel::initial) + continue; + tcb_ptr->dtvPointers[i] = reinterpret_cast(tcb_ptr) + object->tlsOffset; + } + + return tcb_ptr; +} + +void *accessDtv(SharedObject *object) { + Tcb *tcb_ptr = mlibc::get_current_tcb(); + + // We might need to reallocate the DTV. + if(object->tlsIndex >= tcb_ptr->dtvSize) { + // TODO: need to protect runtimeTlsMap against concurrent access. + auto ndtv = frg::construct_n(getAllocator(), runtimeTlsMap->indices.size()); + memset(ndtv, 0, sizeof(void *) * runtimeTlsMap->indices.size()); + memcpy(ndtv, tcb_ptr->dtvPointers, sizeof(void *) * tcb_ptr->dtvSize); + frg::destruct_n(getAllocator(), tcb_ptr->dtvPointers, tcb_ptr->dtvSize); + tcb_ptr->dtvSize = runtimeTlsMap->indices.size(); + tcb_ptr->dtvPointers = ndtv; + } + + // We might need to fill in a new DTV entry. + if(!tcb_ptr->dtvPointers[object->tlsIndex]) { + __ensure(object->tlsModel == TlsModel::dynamic); + + auto buffer = getAllocator().allocate(object->tlsSegmentSize); + __ensure(!(reinterpret_cast(buffer) & (object->tlsAlignment - 1))); + memset(buffer, 0, object->tlsSegmentSize); + memcpy(buffer, object->tlsImagePtr, object->tlsImageSize); + tcb_ptr->dtvPointers[object->tlsIndex] = buffer; + + if (verbose) { + mlibc::infoLogger() << "rtdl: accessDtv wrote tls image at " << buffer + << ", size = 0x" << frg::hex_fmt{object->tlsSegmentSize} << frg::endlog; + } + } + + return (void *)((char *)tcb_ptr->dtvPointers[object->tlsIndex] + TLS_DTV_OFFSET); +} + +void *tryAccessDtv(SharedObject *object) { + Tcb *tcb_ptr = mlibc::get_current_tcb(); + + if (object->tlsIndex >= tcb_ptr->dtvSize) + return nullptr; + if (!tcb_ptr->dtvPointers[object->tlsIndex]) + return nullptr; + + return (void *)((char *)tcb_ptr->dtvPointers[object->tlsIndex] + TLS_DTV_OFFSET); +} + +// -------------------------------------------------------- +// ObjectSymbol +// -------------------------------------------------------- + +ObjectSymbol::ObjectSymbol(SharedObject *object, const elf_sym *symbol) +: _object(object), _symbol(symbol) { } + +const char *ObjectSymbol::getString() { + __ensure(_symbol->st_name != 0); + return (const char *)(_object->baseAddress + + _object->stringTableOffset + _symbol->st_name); +} + +uintptr_t ObjectSymbol::virtualAddress() { + auto bind = ELF_ST_BIND(_symbol->st_info); + __ensure(bind == STB_GLOBAL || bind == STB_WEAK || bind == STB_GNU_UNIQUE); + __ensure(_symbol->st_shndx != SHN_UNDEF); + return _object->baseAddress + _symbol->st_value; +} + +// -------------------------------------------------------- +// Scope +// -------------------------------------------------------- + +uint32_t elf64Hash(frg::string_view string) { + uint32_t h = 0, g; + + for(size_t i = 0; i < string.size(); ++i) { + h = (h << 4) + (uint32_t)string[i]; + g = h & 0xF0000000; + if(g) + h ^= g >> 24; + h &= 0x0FFFFFFF; + } + + return h; +} + +uint32_t gnuHash(frg::string_view string) { + uint32_t h = 5381; + for(size_t i = 0; i < string.size(); ++i) + h = (h << 5) + h + string[i]; + return h; +} + +// TODO: move this to some namespace or class? +frg::optional resolveInObject(SharedObject *object, frg::string_view string) { + // Checks if the symbol can be used to satisfy the dependency. + auto eligible = [&] (ObjectSymbol cand) { + if(cand.symbol()->st_shndx == SHN_UNDEF) + return false; + + auto bind = ELF_ST_BIND(cand.symbol()->st_info); + if(bind != STB_GLOBAL && bind != STB_WEAK && bind != STB_GNU_UNIQUE) + return false; + + return true; + }; + + if (object->hashStyle == HashStyle::systemV) { + auto hash_table = (Elf64_Word *)(object->baseAddress + object->hashTableOffset); + Elf64_Word num_buckets = hash_table[0]; + auto bucket = elf64Hash(string) % num_buckets; + + auto index = hash_table[2 + bucket]; + while(index != 0) { + ObjectSymbol cand{object, (elf_sym *)(object->baseAddress + + object->symbolTableOffset + index * sizeof(elf_sym))}; + if(eligible(cand) && frg::string_view{cand.getString()} == string) + return cand; + + index = hash_table[2 + num_buckets + index]; + } + + return frg::optional{}; + }else{ + __ensure(object->hashStyle == HashStyle::gnu); + + struct GnuTable { + uint32_t nBuckets; + uint32_t symbolOffset; + uint32_t bloomSize; + uint32_t bloomShift; + }; + + auto hash_table = reinterpret_cast(object->baseAddress + + object->hashTableOffset); + auto buckets = reinterpret_cast(object->baseAddress + + object->hashTableOffset + sizeof(GnuTable) + + hash_table->bloomSize * sizeof(elf_addr)); + auto chains = reinterpret_cast(object->baseAddress + + object->hashTableOffset + sizeof(GnuTable) + + hash_table->bloomSize * sizeof(elf_addr) + + hash_table->nBuckets * sizeof(uint32_t)); + + // TODO: Use the bloom filter. + + // The symbols of a given bucket are contiguous in the table. + auto hash = gnuHash(string); + auto index = buckets[hash % hash_table->nBuckets]; + + if(!index) + return frg::optional{}; + + while(true) { + // chains[] contains an array of hashes, parallel to the symbol table. + auto chash = chains[index - hash_table->symbolOffset]; + if ((chash & ~1) == (hash & ~1)) { + ObjectSymbol cand{object, (elf_sym *)(object->baseAddress + + object->symbolTableOffset + index * sizeof(elf_sym))}; + if(eligible(cand) && frg::string_view{cand.getString()} == string) + return cand; + } + + // If we hit the end of the chain, the symbol is not present. + if(chash & 1) + return frg::optional{}; + index++; + } + } +} + +frg::optional Scope::_resolveNext(frg::string_view string, + SharedObject *target) { + // Skip objects until we find the target, and only look for symbols after that. + size_t i; + for (i = 0; i < _objects.size(); i++) { + if (_objects[i] == target) + break; + } + + if (i == _objects.size()) { + mlibc::infoLogger() << "rtdl: object passed to Scope::resolveAfter was not found" << frg::endlog; + return frg::optional(); + } + + for (i = i + 1; i < _objects.size(); i++) { + if(_objects[i]->isMainObject) + continue; + + frg::optional p = resolveInObject(_objects[i], string); + if(p) + return p; + } + + return frg::optional(); +} + +Scope::Scope(bool isGlobal) +: isGlobal{isGlobal}, _objects(getAllocator()) { } + +void Scope::appendObject(SharedObject *object) { + // Don't insert duplicates. + for (auto obj : _objects) { + if (obj == object) + return; + } + + _objects.push(object); +} + +frg::optional Scope::resolveGlobalOrLocal(Scope &globalScope, + Scope *localScope, frg::string_view string, uint64_t skipRts, ResolveFlags flags) { + auto sym = globalScope.resolveSymbol(string, skipRts, flags | skipGlobalAfterRts); + if(!sym && localScope) + sym = localScope->resolveSymbol(string, skipRts, flags | skipGlobalAfterRts); + return sym; +} + +frg::optional Scope::resolveGlobalOrLocalNext(Scope &globalScope, + Scope *localScope, frg::string_view string, SharedObject *origin) { + auto sym = globalScope._resolveNext(string, origin); + if(!sym && localScope) { + sym = localScope->_resolveNext(string, origin); + } + return sym; +} + +// TODO: let this return uintptr_t +frg::optional Scope::resolveSymbol(frg::string_view string, + uint64_t skipRts, ResolveFlags flags) { + for (auto object : _objects) { + if((flags & resolveCopy) && object->isMainObject) + continue; + if((flags & skipGlobalAfterRts) && object->globalRts > skipRts) { + // globalRts should be monotone increasing for objects in the global scope, + // so as an optimization we can break early here. + // TODO: If we implement DT_SYMBOLIC, this assumption fails. + if(isGlobal) + break; + else + continue; + } + + frg::optional p = resolveInObject(object, string); + if(p) + return p; + } + + return frg::optional(); +} + +// -------------------------------------------------------- +// Loader +// -------------------------------------------------------- + +Loader::Loader(Scope *scope, SharedObject *mainExecutable, bool is_initial_link, uint64_t rts) +: _mainExecutable{mainExecutable}, _loadScope{scope}, _isInitialLink{is_initial_link}, + _linkRts{rts}, _linkBfs{getAllocator()}, _initQueue{getAllocator()} { } + +void Loader::_buildLinkBfs(SharedObject *root) { + __ensure(_linkBfs.size() == 0); + + struct Token {}; + using Set = frg::hash_map, MemoryAllocator>; + Set set{frg::hash{}, getAllocator()}; + _linkBfs.push(root); + + // Loop over indices (not iterators) here: We are adding elements in the loop! + for(size_t i = 0; i < _linkBfs.size(); i++) { + auto current = _linkBfs[i]; + + // At this point the object is loaded and we can fill in its debug struct, + // the linked list fields will be filled later. + current->linkMap.base = current->baseAddress; + current->linkMap.name = current->path.data(); + current->linkMap.dynv = current->dynamic; + + __ensure((current->tlsAlignment & (current->tlsAlignment - 1)) == 0); + + if (_isInitialLink && current->tlsAlignment > tlsMaxAlignment) { + tlsMaxAlignment = current->tlsAlignment; + } + + for (auto dep : current->dependencies) { + if (!set.get(dep)) { + set.insert(dep, Token{}); + _linkBfs.push(dep); + } + } + } +} + +void Loader::linkObjects(SharedObject *root) { + _buildLinkBfs(root); + _buildTlsMaps(); + + // Promote objects to the desired scope. + for(auto object : _linkBfs) { + if (object->globalRts == 0 && _loadScope->isGlobal) + object->globalRts = _linkRts; + + _loadScope->appendObject(object); + } + + // Process regular relocations. + for(auto object : _linkBfs) { + // Some objects have already been linked before. + if(object->objectRts < _linkRts) + continue; + + if(object->dynamic == nullptr) + continue; + + if(verbose) + mlibc::infoLogger() << "rtdl: Linking " << object->name << frg::endlog; + + __ensure(!object->wasLinked); + + // TODO: Support this. + if(object->symbolicResolution) + mlibc::infoLogger() << "\e[31mrtdl: DT_SYMBOLIC is not implemented correctly!\e[39m" + << frg::endlog; + + _processStaticRelocations(object); + _processLazyRelocations(object); + } + + // Process copy relocations. + for(auto object : _linkBfs) { + if(!object->isMainObject) + continue; + + // Some objects have already been linked before. + if(object->objectRts < _linkRts) + continue; + + if(object->dynamic == nullptr) + continue; + + processLateRelocations(object); + } + + for(auto object : _linkBfs) { + object->wasLinked = true; + + if(object->inLinkMap) + continue; + + auto linkMap = reinterpret_cast(globalDebugInterface.head); + + object->linkMap.prev = linkMap; + object->linkMap.next = linkMap->next; + if(linkMap->next) + linkMap->next->prev = &(object->linkMap); + linkMap->next = &(object->linkMap); + object->inLinkMap = true; + } +} + +void Loader::_buildTlsMaps() { + if(_isInitialLink) { + __ensure(runtimeTlsMap->initialPtr == 0); + __ensure(runtimeTlsMap->initialLimit == 0); + + __ensure(!_linkBfs.empty()); + __ensure(_linkBfs.front()->isMainObject); + + for(auto object : _linkBfs) { + __ensure(object->tlsModel == TlsModel::null); + + if(object->tlsSegmentSize == 0) + continue; + + // Allocate an index for the object. + object->tlsIndex = runtimeTlsMap->indices.size(); + runtimeTlsMap->indices.push_back(object); + + object->tlsModel = TlsModel::initial; + + if constexpr (tlsAboveTp) { + // As per the comment in allocateTcb(), we may simply add sizeof(Tcb) to + // reach the TLS data. + object->tlsOffset = runtimeTlsMap->initialPtr + sizeof(Tcb); + runtimeTlsMap->initialPtr += object->tlsSegmentSize; + + size_t misalign = runtimeTlsMap->initialPtr & (object->tlsAlignment - 1); + if(misalign) + runtimeTlsMap->initialPtr += object->tlsAlignment - misalign; + } else { + runtimeTlsMap->initialPtr += object->tlsSegmentSize; + + size_t misalign = runtimeTlsMap->initialPtr & (object->tlsAlignment - 1); + if(misalign) + runtimeTlsMap->initialPtr += object->tlsAlignment - misalign; + + object->tlsOffset = -runtimeTlsMap->initialPtr; + } + + if(verbose) + mlibc::infoLogger() << "rtdl: TLS of " << object->name + << " mapped to 0x" << frg::hex_fmt{object->tlsOffset} + << ", size: " << object->tlsSegmentSize + << ", alignment: " << object->tlsAlignment << frg::endlog; + } + + // Reserve some additional space for future libraries. + runtimeTlsMap->initialLimit = runtimeTlsMap->initialPtr + 64; + }else{ + for(auto object : _linkBfs) { + if(object->tlsModel != TlsModel::null) + continue; + if(object->tlsSegmentSize == 0) + continue; + + // Allocate an index for the object. + object->tlsIndex = runtimeTlsMap->indices.size(); + runtimeTlsMap->indices.push_back(object); + + // There are some libraries (e.g. Mesa) that require static TLS even though + // they expect to be dynamically loaded. + if(object->haveStaticTls) { + auto ptr = runtimeTlsMap->initialPtr + object->tlsSegmentSize; + size_t misalign = ptr & (object->tlsAlignment - 1); + if(misalign) + ptr += object->tlsAlignment - misalign; + + if(ptr > runtimeTlsMap->initialLimit) + mlibc::panicLogger() << "rtdl: Static TLS space exhausted while while" + " allocating TLS for " << object->name << frg::endlog; + + object->tlsModel = TlsModel::initial; + + if constexpr (tlsAboveTp) { + size_t tcbSize = ((sizeof(Tcb) + tlsMaxAlignment - 1) & ~(tlsMaxAlignment - 1)); + + object->tlsOffset = runtimeTlsMap->initialPtr + tcbSize; + runtimeTlsMap->initialPtr = ptr; + } else { + runtimeTlsMap->initialPtr = ptr; + object->tlsOffset = -runtimeTlsMap->initialPtr; + } + + if(verbose) + mlibc::infoLogger() << "rtdl: TLS of " << object->name + << " mapped to 0x" << frg::hex_fmt{object->tlsOffset} + << ", size: " << object->tlsSegmentSize + << ", alignment: " << object->tlsAlignment << frg::endlog; + }else{ + object->tlsModel = TlsModel::dynamic; + } + } + } +} + +void Loader::initObjects() { + initTlsObjects(mlibc::get_current_tcb(), _linkBfs, true); + + if (_mainExecutable && _mainExecutable->preInitArray) { + if (verbose) + mlibc::infoLogger() << "rtdl: Running DT_PREINIT_ARRAY functions" << frg::endlog; + + __ensure(_mainExecutable->isMainObject); + __ensure(!_mainExecutable->wasInitialized); + __ensure((_mainExecutable->preInitArraySize % sizeof(InitFuncPtr)) == 0); + for(size_t i = 0; i < _mainExecutable->preInitArraySize / sizeof(InitFuncPtr); i++) + _mainExecutable->preInitArray[i](); + } + + // Convert the breadth-first representation to a depth-first post-order representation, + // so that every object is initialized *after* its dependencies. + for(auto object : _linkBfs) { + if(!object->scheduledForInit) + _scheduleInit(object); + } + + for(auto object : _initQueue) { + if(!object->wasInitialized) + doInitialize(object); + } +} + +// TODO: Use an explicit vector to reduce stack usage to O(1)? +void Loader::_scheduleInit(SharedObject *object) { + // Here we detect cyclic dependencies. + __ensure(!object->onInitStack); + object->onInitStack = true; + + __ensure(!object->scheduledForInit); + object->scheduledForInit = true; + + for(size_t i = 0; i < object->dependencies.size(); i++) { + if(!object->dependencies[i]->scheduledForInit) + _scheduleInit(object->dependencies[i]); + } + + _initQueue.push(object); + object->onInitStack = false; +} + +void Loader::_processRelocations(Relocation &rel) { + // copy and irelative relocations have to be performed after all other relocations + if(rel.type() == R_COPY || rel.type() == R_IRELATIVE) + return; + + // resolve the symbol if there is a symbol + frg::optional p; + if(rel.symbol_index()) { + auto symbol = (elf_sym *)(rel.object()->baseAddress + rel.object()->symbolTableOffset + + rel.symbol_index() * sizeof(elf_sym)); + ObjectSymbol r(rel.object(), symbol); + + p = Scope::resolveGlobalOrLocal(*globalScope, rel.object()->localScope, + r.getString(), rel.object()->objectRts, 0); + if(!p) { + if(ELF_ST_BIND(symbol->st_info) != STB_WEAK) + mlibc::panicLogger() << "Unresolved load-time symbol " + << r.getString() << " in object " << rel.object()->name << frg::endlog; + + if(verbose) + mlibc::infoLogger() << "rtdl: Unresolved weak load-time symbol " + << r.getString() << " in object " << rel.object()->name << frg::endlog; + } + } + + switch(rel.type()) { + case R_NONE: + break; + + case R_JUMP_SLOT: { + __ensure(!rel.addend_norel()); + uintptr_t symbol_addr = p ? p->virtualAddress() : 0; + rel.relocate(symbol_addr); + } break; + +#if !defined(__riscv) + // on some architectures, R_GLOB_DAT can be defined to other relocations + case R_GLOB_DAT: { + __ensure(rel.symbol_index()); + uintptr_t symbol_addr = p ? p->virtualAddress() : 0; + rel.relocate(symbol_addr + rel.addend_norel()); + } break; +#endif + + case R_ABSOLUTE: { + __ensure(rel.symbol_index()); + uintptr_t symbol_addr = p ? p->virtualAddress() : 0; + rel.relocate(symbol_addr + rel.addend_rel()); + } break; + + case R_RELATIVE: { + __ensure(!rel.symbol_index()); + rel.relocate(rel.object()->baseAddress + rel.addend_rel()); + } break; + + // DTPMOD and DTPREL are dynamic TLS relocations (for __tls_get_addr()). + // TPOFF is a relocation to the initial TLS model. + case R_TLS_DTPMOD: { + // sets the first `sizeof(uintptr_t)` bytes of `struct __abi_tls_entry` + // this means that we can just use the `SharedObject *` to resolve whatever we need + __ensure(!rel.addend_rel()); + if(rel.symbol_index()) { + __ensure(p); + rel.relocate(elf_addr(p->object())); + }else{ + if(stillSlightlyVerbose) + mlibc::infoLogger() << "rtdl: Warning: TLS_DTPMOD64 with no symbol in object " + << rel.object()->name << frg::endlog; + rel.relocate(elf_addr(rel.object())); + } + } break; + case R_TLS_DTPREL: { + __ensure(rel.symbol_index()); + __ensure(p); + rel.relocate(p->symbol()->st_value + rel.addend_rel() - TLS_DTV_OFFSET); + } break; + case R_TLS_TPREL: { + uintptr_t off = rel.addend_rel(); + uintptr_t tls_offset = 0; + + if(rel.symbol_index()) { + __ensure(p); + if(p->object()->tlsModel != TlsModel::initial) + mlibc::panicLogger() << "rtdl: In object " << rel.object()->name + << ": Static TLS relocation to symbol " << p->getString() + << " in dynamically loaded object " + << p->object()->name << frg::endlog; + off += p->symbol()->st_value; + tls_offset = p->object()->tlsOffset; + }else{ + if(stillSlightlyVerbose) + mlibc::infoLogger() << "rtdl: Warning: TPOFF64 with no symbol" + " in object " << rel.object()->name << frg::endlog; + if(rel.object()->tlsModel != TlsModel::initial) + mlibc::panicLogger() << "rtdl: In object " << rel.object()->name + << ": Static TLS relocation to dynamically loaded object " + << rel.object()->name << frg::endlog; + tls_offset = rel.object()->tlsOffset; + } + + if constexpr (tlsAboveTp) { + off += tls_offset - sizeof(Tcb); + } else { + off += tls_offset; + } + + rel.relocate(off); + } break; + default: + mlibc::panicLogger() << "Unexpected relocation type " + << (void *) rel.type() << frg::endlog; + } +} + +void Loader::_processStaticRelocations(SharedObject *object) { + frg::optional rela_offset; + frg::optional rela_length; + + frg::optional rel_offset; + frg::optional rel_length; + + frg::optional relr_offset; + frg::optional relr_length; + + for(size_t i = 0; object->dynamic[i].d_tag != DT_NULL; i++) { + elf_dyn *dynamic = &object->dynamic[i]; + + switch(dynamic->d_tag) { + case DT_RELA: + rela_offset = dynamic->d_un.d_ptr; + break; + case DT_RELASZ: + rela_length = dynamic->d_un.d_val; + break; + case DT_RELAENT: + __ensure(dynamic->d_un.d_val == sizeof(elf_rela)); + break; + case DT_REL: + rel_offset = dynamic->d_un.d_ptr; + break; + case DT_RELSZ: + rel_length = dynamic->d_un.d_val; + break; + case DT_RELENT: + __ensure(dynamic->d_un.d_val == sizeof(elf_rel)); + break; + case DT_RELR: + relr_offset = dynamic->d_un.d_ptr; + break; + case DT_RELRSZ: + relr_length = dynamic->d_un.d_val; + break; + case DT_RELRENT: + __ensure(dynamic->d_un.d_val == sizeof(elf_relr)); + break; + } + } + + if(rela_offset && rela_length) { + __ensure(!rel_offset && !rel_length); + + for(size_t offset = 0; offset < *rela_length; offset += sizeof(elf_rela)) { + auto reloc = (elf_rela *)(object->baseAddress + *rela_offset + offset); + auto r = Relocation(object, reloc); + + _processRelocations(r); + } + }else if(rel_offset && rel_length) { + __ensure(!rela_offset && !rela_length); + + for(size_t offset = 0; offset < *rel_length; offset += sizeof(elf_rel)) { + auto reloc = (elf_rel *)(object->baseAddress + *rel_offset + offset); + auto r = Relocation(object, reloc); + + _processRelocations(r); + } + } + + if(relr_offset && relr_length) { + elf_addr *addr = nullptr; + + for(size_t offset = 0; offset < *relr_length; offset += sizeof(elf_relr)) { + auto entry = *(elf_relr *)(object->baseAddress + *relr_offset + offset); + + // Even entry indicates the beginning address. + if(!(entry & 1)) { + addr = (elf_addr *)(object->baseAddress + entry); + __ensure(addr); + *addr++ += object->baseAddress; + }else { + // Odd entry indicates entry is a bitmap of the subsequent locations to be relocated. + for(int i = 0; entry; ++i) { + if(entry & 1) { + addr[i] += object->baseAddress; + } + entry >>= 1; + } + + // Each entry describes at max 63 (on 64bit) or 31 (on 32bit) subsequent locations. + addr += CHAR_BIT * sizeof(elf_relr) - 1; + } + } + } +} + +// TODO: TLSDESC relocations aren't aarch64 specific +#ifdef __aarch64__ +extern "C" void *__mlibcTlsdescStatic(void *); +extern "C" void *__mlibcTlsdescDynamic(void *); +#endif + +void Loader::_processLazyRelocations(SharedObject *object) { + if(object->globalOffsetTable == nullptr) { + __ensure(object->lazyRelocTableOffset == 0); + return; + } + object->globalOffsetTable[1] = object; + object->globalOffsetTable[2] = (void *)&pltRelocateStub; + + if(!object->lazyTableSize) + return; + + // adjust the addresses of JUMP_SLOT relocations + __ensure(object->lazyExplicitAddend.has_value()); + size_t rel_size = (*object->lazyExplicitAddend) ? sizeof(elf_rela) : sizeof(elf_rel); + + for(size_t offset = 0; offset < object->lazyTableSize; offset += rel_size) { + elf_info type; + elf_info symbol_index; + + uintptr_t rel_addr; + uintptr_t addend [[maybe_unused]] = 0; + + if(*object->lazyExplicitAddend) { + auto reloc = (elf_rela *)(object->baseAddress + object->lazyRelocTableOffset + offset); + type = ELF_R_TYPE(reloc->r_info); + symbol_index = ELF_R_SYM(reloc->r_info); + rel_addr = object->baseAddress + reloc->r_offset; + addend = reloc->r_addend; + } else { + auto reloc = (elf_rel *)(object->baseAddress + object->lazyRelocTableOffset + offset); + type = ELF_R_TYPE(reloc->r_info); + symbol_index = ELF_R_SYM(reloc->r_info); + rel_addr = object->baseAddress + reloc->r_offset; + } + + switch (type) { + case R_JUMP_SLOT: + if(eagerBinding) { + auto symbol = (elf_sym *)(object->baseAddress + object->symbolTableOffset + + symbol_index * sizeof(elf_sym)); + ObjectSymbol r(object, symbol); + auto p = Scope::resolveGlobalOrLocal(*globalScope, object->localScope, r.getString(), object->objectRts, 0); + + if(!p) { + if(ELF_ST_BIND(symbol->st_info) != STB_WEAK) + mlibc::panicLogger() << "rtdl: Unresolved JUMP_SLOT symbol " + << r.getString() << " in object " << object->name << frg::endlog; + + if(verbose) + mlibc::infoLogger() << "rtdl: Unresolved weak JUMP_SLOT symbol " + << r.getString() << " in object " << object->name << frg::endlog; + *((uintptr_t *)rel_addr) = 0; + }else{ + *((uintptr_t *)rel_addr) = p->virtualAddress(); + } + }else{ + *((uintptr_t *)rel_addr) += object->baseAddress; + } + break; +#if defined(__x86_64__) + case R_X86_64_IRELATIVE: { + auto ptr = object->baseAddress + addend; + auto target = reinterpret_cast(ptr)(); + *((uintptr_t *)rel_addr) = target; + break; + } +#endif +// TODO: TLSDESC relocations aren't aarch64 specific +#if defined(__aarch64__) + case R_AARCH64_TLSDESC: { + size_t symValue = 0; + SharedObject *target = nullptr; + + if (symbol_index) { + auto symbol = (elf_sym *)(object->baseAddress + object->symbolTableOffset + + symbol_index * sizeof(elf_sym)); + ObjectSymbol r(object, symbol); + auto p = Scope::resolveGlobalOrLocal(*globalScope, object->localScope, r.getString(), object->objectRts, 0); + + if (!p) { + __ensure(ELF_ST_BIND(symbol->st_info) != STB_WEAK); + mlibc::panicLogger() << "rtdl: Unresolved TLSDESC for symbol " + << r.getString() << " in object " << object->name << frg::endlog; + } else { + target = p->object(); + if (p->symbol()) + symValue = p->symbol()->st_value; + } + } else { + target = object; + } + + __ensure(target); + + if (target->tlsModel == TlsModel::initial) { + ((uint64_t *)rel_addr)[0] = reinterpret_cast(&__mlibcTlsdescStatic); + // TODO: guard the subtraction of TCB size with `if constexpr (tlsAboveTp)` + // for the arch-generic case + __ensure(tlsAboveTp == true); + ((uint64_t *)rel_addr)[1] = symValue + target->tlsOffset + addend - sizeof(Tcb); + } else { + struct TlsdescData { + uintptr_t tlsIndex; + uintptr_t addend; + }; + + // Access DTV for object to force the entry to be allocated and initialized + accessDtv(target); + + __ensure(target->tlsIndex < mlibc::get_current_tcb()->dtvSize); + + // TODO: We should free this when the DSO gets destroyed + auto data = frg::construct(getAllocator()); + data->tlsIndex = target->tlsIndex; + data->addend = symValue + addend; + + ((uint64_t *)rel_addr)[0] = reinterpret_cast(&__mlibcTlsdescDynamic); + ((uint64_t *)rel_addr)[1] = reinterpret_cast(data); + } + } break; +#endif + default: + mlibc::panicLogger() << "unimplemented lazy relocation type " << type << frg::endlog; + break; + } + } +} + diff --git a/lib/mlibc/options/rtdl/generic/linker.hpp b/lib/mlibc/options/rtdl/generic/linker.hpp new file mode 100644 index 0000000..ad84ca9 --- /dev/null +++ b/lib/mlibc/options/rtdl/generic/linker.hpp @@ -0,0 +1,402 @@ + +#include +#include +#include +#include +#include +#include +#include + +#include "elf.hpp" + +struct ObjectRepository; +struct Scope; +struct Loader; +struct SharedObject; + +extern uint64_t rtsCounter; + +enum class TlsModel { + null, + initial, + dynamic +}; + +enum class LinkerError { + success, + notFound, + fileTooShort, + notElf, + wrongElfType, + outOfMemory, + invalidProgramHeader +}; + +// -------------------------------------------------------- +// ObjectRepository +// -------------------------------------------------------- + +struct ObjectRepository { + ObjectRepository(); + + ObjectRepository(const ObjectRepository &) = delete; + + ObjectRepository &operator= (const ObjectRepository &) = delete; + + // This is primarily used to create a SharedObject for the RTDL itself. + SharedObject *injectObjectFromDts(frg::string_view name, + frg::string path, + uintptr_t base_address, elf_dyn *dynamic, uint64_t rts); + + // This is used to create a SharedObject for the executable that we want to link. + SharedObject *injectObjectFromPhdrs(frg::string_view name, + frg::string path, void *phdr_pointer, + size_t phdr_entry_size, size_t num_phdrs, void *entry_pointer, + uint64_t rts); + + SharedObject *injectStaticObject(frg::string_view name, + frg::string path, void *phdr_pointer, + size_t phdr_entry_size, size_t num_phdrs, void *entry_pointer, + uint64_t rts); + + frg::expected requestObjectWithName(frg::string_view name, + SharedObject *origin, Scope *localScope, bool createScope, uint64_t rts); + + frg::expected requestObjectAtPath(frg::string_view path, + Scope *localScope, bool createScope, uint64_t rts); + + SharedObject *findCaller(void *address); + + SharedObject *findLoadedObject(frg::string_view name); + + // Used by dl_iterate_phdr: stores objects in the order they are loaded. + frg::vector loadedObjects; + +private: + void _fetchFromPhdrs(SharedObject *object, void *phdr_pointer, + size_t phdr_entry_size, size_t num_phdrs, void *entry_pointer); + + frg::expected _fetchFromFile(SharedObject *object, int fd); + + void _parseDynamic(SharedObject *object); + + void _discoverDependencies(SharedObject *object, Scope *localScope, uint64_t rts); + + void _addLoadedObject(SharedObject *object); + + frg::hash_map, MemoryAllocator> _nameMap; +}; + +// -------------------------------------------------------- +// SharedObject +// -------------------------------------------------------- + +enum class HashStyle { + none, + systemV, + gnu +}; + +using InitFuncPtr = void (*)(); + +// The ABI of this struct is fixed by GDB +struct DebugInterface { + int ver; + void *head; + void (*brk)(void); + int state; + void *base; +}; + +// The ABI of this struct is fixed by GDB +struct LinkMap { + uintptr_t base = 0; + const char *name = nullptr; + elf_dyn *dynv = nullptr; + LinkMap *next = nullptr, *prev = nullptr; +}; + +struct SharedObject { + // path is copied + SharedObject(const char *name, frg::string path, + bool is_main_object, Scope *localScope, uint64_t object_rts); + + SharedObject(const char *name, const char *path, bool is_main_object, + Scope *localScope, uint64_t object_rts); + + frg::string name; + frg::string path; + frg::string interpreterPath; + const char *soName; + bool isMainObject; + uint64_t objectRts; + + // link map for debugging + LinkMap linkMap; + bool inLinkMap; + + // base address this shared object was loaded to + uintptr_t baseAddress; + + Scope *localScope; + + // pointers to the dynamic table, GOT and entry point + elf_dyn *dynamic = nullptr; + void **globalOffsetTable; + void *entry; + + // object initialization information + InitFuncPtr initPtr = nullptr; + InitFuncPtr *initArray = nullptr; + InitFuncPtr *preInitArray = nullptr; + size_t initArraySize = 0; + size_t preInitArraySize = 0; + + + // TODO: read this from the PHDR + size_t tlsSegmentSize, tlsAlignment, tlsImageSize; + void *tlsImagePtr; + bool tlsInitialized; + + // symbol and string table of this shared object + HashStyle hashStyle = HashStyle::none; + uintptr_t hashTableOffset; + uintptr_t symbolTableOffset; + uintptr_t stringTableOffset; + + const char *runPath = nullptr; + + // save the lazy JUMP_SLOT relocation table + uintptr_t lazyRelocTableOffset; + size_t lazyTableSize; + frg::optional lazyExplicitAddend; + + bool symbolicResolution; + bool eagerBinding; + bool haveStaticTls; + + // vector of dependencies + frg::vector dependencies; + + TlsModel tlsModel; + size_t tlsIndex; + size_t tlsOffset; + + uint64_t globalRts; + bool wasLinked; + + bool scheduledForInit; + bool onInitStack; + bool wasInitialized; + + // PHDR related stuff, we only set these for the main executable + void *phdrPointer = nullptr; + size_t phdrEntrySize = 0; + size_t phdrCount = 0; +}; + +struct Relocation { + Relocation(SharedObject *object, elf_rela *r) + : object_{object}, type_{Addend::Explicit} { + offset_ = r->r_offset; + info_ = r->r_info; + addend_ = r->r_addend; + } + + Relocation(SharedObject *object, elf_rel *r) + : object_{object}, type_{Addend::Implicit} { + offset_ = r->r_offset; + info_ = r->r_info; + } + + SharedObject *object() { + return object_; + } + + elf_info type() const { + return ELF_R_TYPE(info_); + } + + elf_info symbol_index() const { + return ELF_R_SYM(info_); + } + + elf_addr addend_rel() { + switch(type_) { + case Addend::Explicit: + return addend_; + case Addend::Implicit: { + auto ptr = reinterpret_cast(object_->baseAddress + offset_); + return *ptr; + } + } + __builtin_unreachable(); + } + + elf_addr addend_norel() { + switch(type_) { + case Addend::Explicit: + return addend_; + case Addend::Implicit: + return 0; + } + __builtin_unreachable(); + } + + void *destination() { + return reinterpret_cast(object_->baseAddress + offset_); + } + + void relocate(elf_addr addr) { + auto ptr = destination(); + memcpy(ptr, &addr, sizeof(addr)); + } + +private: + enum class Addend { + Implicit, + Explicit + }; + + SharedObject *object_; + Addend type_; + + elf_addr offset_; + elf_info info_; + elf_addend addend_ = 0; +}; + +void processCopyRelocations(SharedObject *object); + +// -------------------------------------------------------- +// RuntimeTlsMap +// -------------------------------------------------------- + +struct RuntimeTlsMap { + RuntimeTlsMap(); + + // Amount of initialLimit that has already been allocated. + size_t initialPtr; + + // Size of the inital TLS segment. + size_t initialLimit; + + // TLS indices. + frg::vector indices; +}; + +extern frg::manual_box runtimeTlsMap; + +Tcb *allocateTcb(); +void initTlsObjects(Tcb *tcb, const frg::vector &objects, bool checkInitialized); +void *accessDtv(SharedObject *object); +// Tries to access the DTV, if not allocated, or object doesn't have +// PT_TLS, return nullptr. +void *tryAccessDtv(SharedObject *object); + +// -------------------------------------------------------- +// ObjectSymbol +// -------------------------------------------------------- + +struct ObjectSymbol { + ObjectSymbol(SharedObject *object, const elf_sym *symbol); + + SharedObject *object() { + return _object; + } + + const elf_sym *symbol() { + return _symbol; + } + + const char *getString(); + + uintptr_t virtualAddress(); + +private: + SharedObject *_object; + const elf_sym *_symbol; +}; + +frg::optional resolveInObject(SharedObject *object, frg::string_view string); + +// -------------------------------------------------------- +// Scope +// -------------------------------------------------------- + +struct Scope { + using ResolveFlags = uint32_t; + static inline constexpr ResolveFlags resolveCopy = 1; + static inline constexpr ResolveFlags skipGlobalAfterRts = 1 << 1; + + static frg::optional resolveGlobalOrLocal(Scope &globalScope, + Scope *localScope, frg::string_view string, uint64_t skipRts, ResolveFlags flags); + static frg::optional resolveGlobalOrLocalNext(Scope &globalScope, + Scope *localScope, frg::string_view string, SharedObject *origin); + + Scope(bool isGlobal = false); + + void appendObject(SharedObject *object); + + frg::optional resolveSymbol(frg::string_view string, uint64_t skipRts, ResolveFlags flags); + + bool isGlobal; + +private: + frg::optional _resolveNext(frg::string_view string, SharedObject *target); +public: // TODO: Make this private again. (Was made public for __dlapi_reverse()). + frg::vector _objects; +}; + +extern frg::manual_box globalScope; + +// -------------------------------------------------------- +// Loader +// -------------------------------------------------------- + +class Loader { +public: + Loader(Scope *scope, SharedObject *mainExecutable, bool is_initial_link, uint64_t rts); + +public: + void linkObjects(SharedObject *root); + +private: + void _buildLinkBfs(SharedObject *root); + void _buildTlsMaps(); + + void _processStaticRelocations(SharedObject *object); + void _processLazyRelocations(SharedObject *object); + + void _processRelocations(Relocation &rel); + +public: + void initObjects(); + +private: + void _scheduleInit(SharedObject *object); + +private: + SharedObject *_mainExecutable; + Scope *_loadScope; + bool _isInitialLink; + uint64_t _linkRts; + + frg::vector _linkBfs; + + frg::vector _initQueue; +}; + +// -------------------------------------------------------- +// Namespace scope functions +// -------------------------------------------------------- + +extern "C" void pltRelocateStub() __attribute__((__visibility__("hidden"))); + +// -------------------------------------------------------- +// RTDL interface +// -------------------------------------------------------- + +void *rtdl_auxvector(); + diff --git a/lib/mlibc/options/rtdl/generic/main.cpp b/lib/mlibc/options/rtdl/generic/main.cpp new file mode 100644 index 0000000..3cff1e4 --- /dev/null +++ b/lib/mlibc/options/rtdl/generic/main.cpp @@ -0,0 +1,844 @@ + +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "elf.hpp" +#include "linker.hpp" + +#if __MLIBC_POSIX_OPTION +#include +#endif + +#define HIDDEN __attribute__((__visibility__("hidden"))) +#define EXPORT __attribute__((__visibility__("default"))) + +static constexpr bool logEntryExit = false; +static constexpr bool logStartup = false; +static constexpr bool logDlCalls = false; + +#ifndef MLIBC_STATIC_BUILD +extern HIDDEN void *_GLOBAL_OFFSET_TABLE_[]; +extern HIDDEN elf_dyn _DYNAMIC[]; +#endif + +namespace mlibc { + // Declared in options/internal/mlibc/tcb.hpp. + bool tcb_available_flag = false; +} + +mlibc::RtdlConfig rtdlConfig; + +bool ldShowAuxv = false; + +uintptr_t *entryStack; +frg::manual_box initialRepository; +frg::manual_box globalScope; + +frg::manual_box runtimeTlsMap; + +// We use a small vector of size 4 to avoid memory allocation for the default library paths +frg::manual_box> libraryPaths; + +frg::manual_box> preloads; + +static SharedObject *executableSO; +extern HIDDEN char __ehdr_start[]; + +// Global debug interface variable +DebugInterface globalDebugInterface; + +#ifndef MLIBC_STATIC_BUILD + +// Use a PC-relative instruction sequence to find our runtime load address. +uintptr_t getLdsoBase() { +#if defined(__x86_64__) || defined(__i386__) || defined(__aarch64__) + // On x86_64, the first GOT entry holds the link-time address of _DYNAMIC. + // TODO: This isn't guaranteed on AArch64, so this might fail with some linkers. + auto linktime_dynamic = reinterpret_cast(_GLOBAL_OFFSET_TABLE_[0]); + auto runtime_dynamic = reinterpret_cast(_DYNAMIC); + return runtime_dynamic - linktime_dynamic; +#elif defined(__riscv) + return reinterpret_cast(&__ehdr_start); +#endif +} + +// Relocates the dynamic linker (i.e. this DSO) itself. +// Assumptions: +// - There are no references to external symbols. +// Note that this code is fragile in the sense that it must not contain relocations itself. +// TODO: Use tooling to verify this at compile time. +extern "C" void relocateSelf() { + size_t rela_offset = 0; + size_t rela_size = 0; + size_t rel_offset = 0; + size_t rel_size = 0; + size_t relr_offset = 0; + size_t relr_size = 0; + for(size_t i = 0; _DYNAMIC[i].d_tag != DT_NULL; i++) { + auto ent = &_DYNAMIC[i]; + switch(ent->d_tag) { + case DT_REL: rel_offset = ent->d_un.d_ptr; break; + case DT_RELSZ: rel_size = ent->d_un.d_val; break; + case DT_RELA: rela_offset = ent->d_un.d_ptr; break; + case DT_RELASZ: rela_size = ent->d_un.d_val; break; + case DT_RELR: relr_offset = ent->d_un.d_ptr; break; + case DT_RELRSZ: relr_size = ent->d_un.d_val; break; + } + } + + auto ldso_base = getLdsoBase(); + + __ensure((rel_offset != 0) ^ (rela_offset != 0)); + + for(size_t disp = 0; disp < rela_size; disp += sizeof(elf_rela)) { + auto reloc = reinterpret_cast(ldso_base + rela_offset + disp); + + auto type = ELF_R_TYPE(reloc->r_info); + if(ELF_R_SYM(reloc->r_info)) + __builtin_trap(); + + auto p = reinterpret_cast(ldso_base + reloc->r_offset); + switch(type) { + case R_RELATIVE: + *p = ldso_base + reloc->r_addend; + break; + default: + __builtin_trap(); + } + } + + for(size_t disp = 0; disp < rel_size; disp += sizeof(elf_rel)) { + auto reloc = reinterpret_cast(ldso_base + rel_offset + disp); + + auto type = ELF_R_TYPE(reloc->r_info); + if(ELF_R_SYM(reloc->r_info)) + __builtin_trap(); + + auto p = reinterpret_cast(ldso_base + reloc->r_offset); + switch(type) { + case R_RELATIVE: + *p += ldso_base; + break; + default: + __builtin_trap(); + } + } + + elf_addr *addr = nullptr; + for(size_t disp = 0; disp < relr_size; disp += sizeof(elf_relr)) { + auto entry = *(elf_relr *)(ldso_base + relr_offset + disp); + + // Even entry indicates the beginning address. + if(!(entry & 1)) { + addr = (elf_addr *)(ldso_base + entry); + __ensure(addr); + *addr++ += ldso_base; + }else { + // Odd entry indicates entry is a bitmap of the subsequent locations to be relocated. + for(int i = 0; entry; ++i) { + if(entry & 1) { + addr[i] += ldso_base; + } + entry >>= 1; + } + + // Each entry describes at max 63 (on 64bit) or 31 (on 32bit) subsequent locations. + addr += CHAR_BIT * sizeof(elf_relr) - 1; + } + } +} +#endif + +extern "C" void *lazyRelocate(SharedObject *object, unsigned int rel_index) { + __ensure(object->lazyExplicitAddend); + auto reloc = (elf_rela *)(object->baseAddress + object->lazyRelocTableOffset + + rel_index * sizeof(elf_rela)); + auto type = ELF_R_TYPE(reloc->r_info); + auto symbol_index = ELF_R_SYM(reloc->r_info); + + __ensure(type == R_X86_64_JUMP_SLOT); + __ensure(ELF_CLASS == ELFCLASS64); + + auto symbol = (elf_sym *)(object->baseAddress + object->symbolTableOffset + + symbol_index * sizeof(elf_sym)); + ObjectSymbol r(object, symbol); + auto p = Scope::resolveGlobalOrLocal(*globalScope, object->localScope, r.getString(), object->objectRts, 0); + if(!p) + mlibc::panicLogger() << "Unresolved JUMP_SLOT symbol" << frg::endlog; + + //mlibc::infoLogger() << "Lazy relocation to " << symbol_str + // << " resolved to " << pointer << frg::endlog; + + *(uint64_t *)(object->baseAddress + reloc->r_offset) = p->virtualAddress(); + return (void *)p->virtualAddress(); +} + +extern "C" [[ gnu::visibility("default") ]] void *__rtdl_allocateTcb() { + auto tcb = allocateTcb(); + initTlsObjects(tcb, globalScope->_objects, false); + return tcb; +} + +extern "C" { + [[ gnu::visibility("hidden") ]] void dl_debug_state() { + // This function is used to signal changes in the debugging link map, + // GDB just sets a breakpoint on this function and we can call it + // everytime we update the link map. We don't need to implement + // anything besides defining and calling it. + } +} + +extern "C" [[gnu::alias("dl_debug_state"), gnu::visibility("default")]] void _dl_debug_state() noexcept; + +// This symbol can be used by GDB to find the global interface structure +[[ gnu::visibility("default") ]] DebugInterface *_dl_debug_addr = &globalDebugInterface; + +static frg::vector parseList(frg::string_view paths, frg::string_view separators) { + frg::vector list{getAllocator()}; + + size_t p = 0; + while(p < paths.size()) { + size_t s; // Offset of next colon or end of string. + if(size_t cs = paths.find_first_of(separators, p); cs != size_t(-1)) { + s = cs; + }else{ + s = paths.size(); + } + + auto path = paths.sub_string(p, s - p); + p = s + 1; + + if(path.size() == 0) + continue; + + if(path.ends_with("/")) { + size_t i = path.size() - 1; + while(i > 0 && path[i] == '/') + i--; + path = path.sub_string(0, i + 1); + } + + if(path == "/") + path = ""; + + list.push_back(path); + } + + return list; +} + +extern "C" void *interpreterMain(uintptr_t *entry_stack) { + if(logEntryExit) + mlibc::infoLogger() << "Entering ld.so" << frg::endlog; + entryStack = entry_stack; + runtimeTlsMap.initialize(); + libraryPaths.initialize(getAllocator()); + preloads.initialize(getAllocator()); + + void *phdr_pointer = 0; + size_t phdr_entry_size = 0; + size_t phdr_count = 0; + void *entry_pointer = 0; + void *stack_entropy = nullptr; + + const char *execfn = "(executable)"; + +#ifndef MLIBC_STATIC_BUILD + using ctor_fn = void(*)(void); + + ctor_fn *ldso_ctors = nullptr; + size_t num_ldso_ctors = 0; + + auto ldso_base = getLdsoBase(); + if(logStartup) { + mlibc::infoLogger() << "ldso: Own base address is: 0x" + << frg::hex_fmt(ldso_base) << frg::endlog; + mlibc::infoLogger() << "ldso: Own dynamic section is at: " << _DYNAMIC << frg::endlog; + } + +#ifdef __x86_64__ + // These entries are reserved on x86_64. + // TODO: Use a fake PLT stub that reports an error message? + _GLOBAL_OFFSET_TABLE_[1] = 0; + _GLOBAL_OFFSET_TABLE_[2] = 0; +#endif + + // Validate our own dynamic section. + // Here, we make sure that the dynamic linker does not need relocations itself. + uintptr_t strtab_offset = 0; + uintptr_t soname_str = 0; + for(size_t i = 0; _DYNAMIC[i].d_tag != DT_NULL; i++) { + auto ent = &_DYNAMIC[i]; + switch(ent->d_tag) { + case DT_STRTAB: strtab_offset = ent->d_un.d_ptr; break; + case DT_SONAME: soname_str = ent->d_un.d_val; break; + case DT_INIT_ARRAY: ldso_ctors = reinterpret_cast(ent->d_un.d_ptr + ldso_base); break; + case DT_INIT_ARRAYSZ: num_ldso_ctors = ent->d_un.d_val / sizeof(ctor_fn); break; + case DT_HASH: + case DT_GNU_HASH: + case DT_STRSZ: + case DT_SYMTAB: + case DT_SYMENT: + case DT_RELA: + case DT_RELASZ: + case DT_RELAENT: + case DT_RELACOUNT: + case DT_DEBUG: + case DT_REL: + case DT_RELSZ: + case DT_RELENT: + case DT_RELCOUNT: + case DT_RELR: + case DT_RELRSZ: + case DT_RELRENT: + continue; + default: + __ensure(!"Unexpected dynamic entry in program interpreter"); + } + } + __ensure(strtab_offset); + __ensure(soname_str); + + // Find the auxiliary vector by skipping args and environment. + auto aux = entryStack; + aux += *aux + 1; // First, we skip argc and all args. + __ensure(!*aux); + aux++; + while(*aux) { // Loop through the environment. + auto env = reinterpret_cast(*aux); + frg::string_view view{env}; + size_t s = view.find_first('='); + + if(s == size_t(-1)) + mlibc::panicLogger() << "rtdl: environment '" << env << "' is missing a '='" << frg::endlog; + + auto name = view.sub_string(0, s); + auto value = const_cast(view.data() + s + 1); + + if(name == "LD_SHOW_AUXV" && *value && *value != '0') { + ldShowAuxv = true; + }else if(name == "LD_LIBRARY_PATH" && *value) { + for(auto path : parseList(value, ":;")) + libraryPaths->push_back(path); + }else if(name == "LD_PRELOAD" && *value) { + *preloads = parseList(value, " :"); + } + + aux++; + } + aux++; + + // Add default library paths + libraryPaths->push_back("/lib"); + libraryPaths->push_back("/lib64"); + libraryPaths->push_back("/usr/lib"); + libraryPaths->push_back("/usr/lib64"); + + // Parse the actual vector. + while(true) { + auto value = aux + 1; + if(!(*aux)) + break; + + if(ldShowAuxv) { + switch(*aux) { + case AT_PHDR: mlibc::infoLogger() << "AT_PHDR: 0x" << frg::hex_fmt{*value} << frg::endlog; break; + case AT_PHENT: mlibc::infoLogger() << "AT_PHENT: " << *value << frg::endlog; break; + case AT_PHNUM: mlibc::infoLogger() << "AT_PHNUM: " << *value << frg::endlog; break; + case AT_ENTRY: mlibc::infoLogger() << "AT_ENTRY: 0x" << frg::hex_fmt{*value} << frg::endlog; break; + case AT_PAGESZ: mlibc::infoLogger() << "AT_PAGESZ: " << *value << frg::endlog; break; + case AT_BASE: mlibc::infoLogger() << "AT_BASE: 0x" << frg::hex_fmt{*value} << frg::endlog; break; + case AT_FLAGS: mlibc::infoLogger() << "AT_FLAGS: 0x" << frg::hex_fmt{*value} << frg::endlog; break; + case AT_NOTELF: mlibc::infoLogger() << "AT_NOTELF: " << frg::hex_fmt{*value} << frg::endlog; break; + case AT_UID: mlibc::infoLogger() << "AT_UID: " << *value << frg::endlog; break; + case AT_EUID: mlibc::infoLogger() << "AT_EUID: " << *value << frg::endlog; break; + case AT_GID: mlibc::infoLogger() << "AT_GID: " << *value << frg::endlog; break; + case AT_EGID: mlibc::infoLogger() << "AT_EGID: " << *value << frg::endlog; break; +#ifdef AT_PLATFORM + case AT_PLATFORM: mlibc::infoLogger() << "AT_PLATFORM: " << reinterpret_cast(*value) << frg::endlog; break; +#endif +#ifdef AT_HWCAP + case AT_HWCAP: mlibc::infoLogger() << "AT_HWCAP: " << frg::hex_fmt{*value} << frg::endlog; break; +#endif +#ifdef AT_CLKTCK + case AT_CLKTCK: mlibc::infoLogger() << "AT_CLKTCK: " << *value << frg::endlog; break; +#endif +#ifdef AT_FPUCW + case AT_FPUCW: mlibc::infoLogger() << "AT_FPUCW: " << frg::hex_fmt{*value} << frg::endlog; break; +#endif +#ifdef AT_SECURE + case AT_SECURE: mlibc::infoLogger() << "AT_SECURE: " << *value << frg::endlog; break; +#endif +#ifdef AT_RANDOM + case AT_RANDOM: mlibc::infoLogger() << "AT_RANDOM: 0x" << frg::hex_fmt{*value} << frg::endlog; break; +#endif +#ifdef AT_EXECFN + case AT_EXECFN: mlibc::infoLogger() << "AT_EXECFN: " << reinterpret_cast(*value) << frg::endlog; break; +#endif +#ifdef AT_SYSINFO_EHDR + case AT_SYSINFO_EHDR: mlibc::infoLogger() << "AT_SYSINFO_EHDR: 0x" << frg::hex_fmt{*value} << frg::endlog; break; +#endif + } + } + + // TODO: Whitelist auxiliary vector entries here? + switch(*aux) { + case AT_PHDR: phdr_pointer = reinterpret_cast(*value); break; + case AT_PHENT: phdr_entry_size = *value; break; + case AT_PHNUM: phdr_count = *value; break; + case AT_ENTRY: entry_pointer = reinterpret_cast(*value); break; + case AT_EXECFN: execfn = reinterpret_cast(*value); break; + case AT_RANDOM: stack_entropy = reinterpret_cast(*value); break; + case AT_SECURE: rtdlConfig.secureRequired = reinterpret_cast(*value); break; + } + + aux += 2; + } + globalDebugInterface.base = reinterpret_cast(ldso_base); + +// This is here because libgcc will add a global constructor on glibc Linux +// (which is what it believes we are due to the aarch64-linux-gnu toolchain) +// in order to check if LSE atomics are supported. +// +// This is not necessary on a custom Linux toolchain and is purely an artifact of +// using the host toolchain. +#if defined(__aarch64__) && defined(__gnu_linux__) + for (size_t i = 0; i < num_ldso_ctors; i++) { + if(logStartup) + mlibc::infoLogger() << "ldso: Running own constructor at " + << reinterpret_cast(ldso_ctors[i]) + << frg::endlog; + ldso_ctors[i](); + } +#else + if (num_ldso_ctors > 0) { + mlibc::panicLogger() << "ldso: Found unexpected own global constructor(s), init_array starts at: " + << ldso_ctors + << frg::endlog; + } +#endif + +#else + auto ehdr = reinterpret_cast(__ehdr_start); + phdr_pointer = reinterpret_cast((uintptr_t)ehdr->e_phoff + (uintptr_t)ehdr); + phdr_entry_size = ehdr->e_phentsize; + phdr_count = ehdr->e_phnum; + entry_pointer = reinterpret_cast(ehdr->e_entry); +#endif + __ensure(phdr_pointer); + __ensure(entry_pointer); + + if(logStartup) + mlibc::infoLogger() << "ldso: Executable PHDRs are at " << phdr_pointer + << frg::endlog; + + // perform the initial dynamic linking + initialRepository.initialize(); + + globalScope.initialize(true); + + // Add the dynamic linker, as well as the exectuable to the repository. +#ifndef MLIBC_STATIC_BUILD + auto ldso_soname = reinterpret_cast(ldso_base + strtab_offset + soname_str); + auto ldso = initialRepository->injectObjectFromDts(ldso_soname, + frg::string { getAllocator() }, + ldso_base, _DYNAMIC, 1); + ldso->phdrPointer = phdr_pointer; + ldso->phdrCount = phdr_count; + ldso->phdrEntrySize = phdr_entry_size; + + // TODO: support non-zero base addresses? + executableSO = initialRepository->injectObjectFromPhdrs(execfn, + frg::string { execfn, getAllocator() }, + phdr_pointer, phdr_entry_size, phdr_count, entry_pointer, 1); + + // We can't initialise the ldso object after the executable SO, + // so we have to set the ldso path after loading both. + ldso->path = executableSO->interpreterPath; + +#else + executableSO = initialRepository->injectStaticObject(execfn, + frg::string{ execfn, getAllocator() }, + phdr_pointer, phdr_entry_size, phdr_count, entry_pointer, 1); + globalDebugInterface.base = (void*)executableSO->baseAddress; +#endif + + globalDebugInterface.head = &executableSO->linkMap; + executableSO->inLinkMap = true; + Loader linker{globalScope.get(), executableSO, true, 1}; + linker.linkObjects(executableSO); + + mlibc::initStackGuard(stack_entropy); + + auto tcb = allocateTcb(); + if(mlibc::sys_tcb_set(tcb)) + __ensure(!"sys_tcb_set() failed"); + tcb->tid = mlibc::this_tid(); + mlibc::tcb_available_flag = true; + + globalDebugInterface.ver = 1; + globalDebugInterface.brk = &dl_debug_state; + globalDebugInterface.state = 0; + dl_debug_state(); + + linker.initObjects(); + + if(logEntryExit) + mlibc::infoLogger() << "Leaving ld.so, jump to " + << (void *)executableSO->entry << frg::endlog; + return executableSO->entry; +} + +const char *lastError; + +extern "C" [[ gnu::visibility("default") ]] uintptr_t *__dlapi_entrystack() { + return entryStack; +} + +extern "C" [[ gnu::visibility("default") ]] +const char *__dlapi_error() { + auto error = lastError; + lastError = nullptr; + return error; +} + +extern "C" [[ gnu::visibility("default") ]] +void *__dlapi_get_tls(struct __abi_tls_entry *entry) { + return reinterpret_cast(accessDtv(entry->object)) + entry->offset; +} + +extern "C" [[ gnu::visibility("default") ]] +const mlibc::RtdlConfig &__dlapi_get_config() { + return rtdlConfig; +} + +#if __MLIBC_POSIX_OPTION + +extern "C" [[ gnu::visibility("default") ]] +void *__dlapi_open(const char *file, int flags, void *returnAddress) { + if (logDlCalls) + mlibc::infoLogger() << "rtdl: __dlapi_open(" << (file ? file : "nullptr") << ")" << frg::endlog; + + if (flags & RTLD_DEEPBIND) + mlibc::infoLogger() << "rtdl: dlopen(RTLD_DEEPBIND) is unsupported" << frg::endlog; + + if(!file) + return executableSO; + + // TODO: Thread-safety! + auto rts = rtsCounter++; + + SharedObject *object; + if (flags & RTLD_NOLOAD) { + object = initialRepository->findLoadedObject(file); + if (object && object->globalRts == 0 && (flags & RTLD_GLOBAL)) { + // The object was opened with RTLD_LOCAL, but we are called with RTLD_NOLOAD | RTLD_GLOBAL. + // According to the man page, we should promote to the global scope here. + object->globalRts = rts; + globalScope->appendObject(object); + } + } else { + bool isGlobal = flags & RTLD_GLOBAL; + Scope *newScope = isGlobal ? globalScope.get() : nullptr; + + frg::expected objectResult; + if (frg::string_view{file}.find_first('/') == size_t(-1)) { + // In order to know which RUNPATH / RPATH to process, we must find the calling object. + SharedObject *origin = initialRepository->findCaller(returnAddress); + if (!origin) { + mlibc::panicLogger() << "rtdl: unable to determine calling object of dlopen " + << "(ra = " << returnAddress << ")" << frg::endlog; + } + + objectResult = initialRepository->requestObjectWithName(file, origin, newScope, !isGlobal, rts); + } else { + objectResult = initialRepository->requestObjectAtPath(file, newScope, !isGlobal, rts); + } + + if(!objectResult) { + switch (objectResult.error()) { + case LinkerError::success: + __builtin_unreachable(); + case LinkerError::notFound: + lastError = "Cannot locate requested DSO"; + break; + case LinkerError::fileTooShort: + lastError = "File too short"; + break; + case LinkerError::notElf: + lastError = "File is not an ELF file"; + break; + case LinkerError::wrongElfType: + lastError = "File has wrong ELF type"; + break; + case LinkerError::outOfMemory: + lastError = "Out of memory"; + break; + case LinkerError::invalidProgramHeader: + lastError = "File has invalid program header"; + break; + } + return nullptr; + } + object = objectResult.value(); + + Loader linker{object->localScope, nullptr, false, rts}; + linker.linkObjects(object); + linker.initObjects(); + } + + dl_debug_state(); + + return object; +} + +extern "C" [[ gnu::visibility("default") ]] +void *__dlapi_resolve(void *handle, const char *string, void *returnAddress) { + if (logDlCalls) { + const char *name; + bool quote = false; + if (handle == RTLD_DEFAULT) { + name = "RTLD_DEFAULT"; + } else if (handle == RTLD_NEXT) { + name = "RTLD_NEXT"; + } else { + name = ((SharedObject *)handle)->name.data(); + quote = true; + } + + mlibc::infoLogger() << "rtdl: __dlapi_resolve(" << (quote ? "\"" : "") << name + << (quote ? "\"" : "") << ", \"" << string << "\")" << frg::endlog; + } + + frg::optional target; + + if (handle == RTLD_DEFAULT) { + target = globalScope->resolveSymbol(string, 0, 0); + } else if (handle == RTLD_NEXT) { + SharedObject *origin = initialRepository->findCaller(returnAddress); + if (!origin) { + mlibc::panicLogger() << "rtdl: unable to determine calling object of dlsym " + << "(ra = " << returnAddress << ")" << frg::endlog; + } + + target = Scope::resolveGlobalOrLocalNext(*globalScope, origin->localScope, string, origin); + } else { + // POSIX does not unambiguously state how dlsym() is supposed to work; it just + // states that "The symbol resolution algorithm used shall be dependency order + // as described in dlopen()". + // + // Linux libc's lookup the symbol in the given DSO and all of its dependencies + // in breadth-first order. That is also what we implement here. + // + // Note that this *differs* from the algorithm that is used for relocations + // (since the algorithm used for relocations takes (i) the global scope, + // and (ii) the local scope of the DSO into account (which can contain more objects + // than just the dependencies of the DSO, if the DSO was loaded as a dependency + // of a dlopen()ed DSO). + + frg::vector queue{getAllocator()}; + + struct Token { }; + frg::hash_map< + SharedObject *, Token, + frg::hash, MemoryAllocator + > visited{frg::hash{}, getAllocator()}; + + auto root = reinterpret_cast(handle); + visited.insert(root, Token{}); + queue.push_back(root); + + for(size_t i = 0; i < queue.size(); i++) { + auto current = queue[i]; + + target = resolveInObject(current, string); + if(target) + break; + + for(auto dep : current->dependencies) { + if(visited.get(dep)) + continue; + visited.insert(dep, Token{}); + queue.push_back(dep); + } + } + } + + if (!target) { + if (logDlCalls) + mlibc::infoLogger() << "rtdl: could not resolve \"" << string << "\"" << frg::endlog; + + lastError = "Cannot resolve requested symbol"; + return nullptr; + } + return reinterpret_cast(target->virtualAddress()); +} + +struct __dlapi_symbol { + const char *file; + void *base; + const char *symbol; + void *address; +}; + +extern "C" [[ gnu::visibility("default") ]] +int __dlapi_reverse(const void *ptr, __dlapi_symbol *info) { + if (logDlCalls) + mlibc::infoLogger() << "rtdl: __dlapi_reverse(" << ptr << ")" << frg::endlog; + + for(size_t i = 0; i < initialRepository->loadedObjects.size(); i++) { + auto object = initialRepository->loadedObjects[i]; + + auto eligible = [&] (ObjectSymbol cand) { + if(cand.symbol()->st_shndx == SHN_UNDEF) + return false; + + auto bind = ELF_ST_BIND(cand.symbol()->st_info); + if(bind != STB_GLOBAL && bind != STB_WEAK) + return false; + + return true; + }; + + auto hash_table = (Elf64_Word *)(object->baseAddress + object->hashTableOffset); + auto num_symbols = hash_table[1]; + for(size_t i = 0; i < num_symbols; i++) { + ObjectSymbol cand{object, (elf_sym *)(object->baseAddress + + object->symbolTableOffset + i * sizeof(elf_sym))}; + if(eligible(cand) && cand.virtualAddress() == reinterpret_cast(ptr)) { + if (logDlCalls) + mlibc::infoLogger() << "rtdl: Found symbol " << cand.getString() << " in object " + << object->path << frg::endlog; + + info->file = object->path.data(); + info->base = reinterpret_cast(object->baseAddress); + info->symbol = cand.getString(); + info->address = reinterpret_cast(cand.virtualAddress()); + return 0; + } + } + } + + // Not found, find the DSO it should be in. + for(size_t i = 0; i < initialRepository->loadedObjects.size(); i++) { + auto object = initialRepository->loadedObjects[i]; + + for(size_t j = 0; j < object->phdrCount; j++) { + auto phdr = (elf_phdr *)((uintptr_t)object->phdrPointer + j * object->phdrEntrySize); + if(phdr->p_type != PT_LOAD) { + continue; + } + uintptr_t start = object->baseAddress + phdr->p_vaddr; + uintptr_t end = start + phdr->p_memsz; + if(reinterpret_cast(ptr) >= start && reinterpret_cast(ptr) < end) { + mlibc::infoLogger() << "rtdl: Found DSO " << object->path << frg::endlog; + info->file = object->path.data(); + info->base = reinterpret_cast(object->baseAddress); + info->symbol = nullptr; + info->address = 0; + return 0; + } + } + } + + if (logDlCalls) + mlibc::infoLogger() << "rtdl: Could not find symbol in __dlapi_reverse()" << frg::endlog; + + return -1; +} + +extern "C" [[ gnu::visibility("default") ]] +int __dlapi_close(void *) { + if (logDlCalls) + mlibc::infoLogger() << "mlibc: dlclose() is a no-op" << frg::endlog; + return 0; +} + +#endif + +extern "C" [[ gnu::visibility("default") ]] +int __dlapi_iterate_phdr(int (*callback)(struct dl_phdr_info *, size_t, void*), void *data) { + int last_return = 0; + for (auto object : initialRepository->loadedObjects) { + struct dl_phdr_info info; + info.dlpi_addr = object->baseAddress; + info.dlpi_name = object->name.data(); + + if(object->isMainObject) { + info.dlpi_name = ""; + } else { + info.dlpi_name = object->name.data(); + } + info.dlpi_phdr = static_cast(object->phdrPointer); + info.dlpi_phnum = object->phdrCount; + info.dlpi_adds = rtsCounter; + info.dlpi_subs = 0; // TODO(geert): implement dlclose(). + if (object->tlsModel != TlsModel::null) + info.dlpi_tls_modid = object->tlsIndex; + else + info.dlpi_tls_modid = 0; + info.dlpi_tls_data = tryAccessDtv(object); + + last_return = callback(&info, sizeof(struct dl_phdr_info), data); + if(last_return) + return last_return; + } + + return last_return; +} + +extern "C" [[ gnu::visibility("default") ]] +void __dlapi_enter(uintptr_t *entry_stack) { +#if MLIBC_STATIC_BUILD + interpreterMain(entry_stack); +#else + (void)entry_stack; +#endif +} + +// XXX(qookie): +// This is here because libgcc will call into __getauxval on glibc Linux +// (which is what it believes we are due to the aarch64-linux-gnu toolchain) +// in order to find AT_HWCAP to discover if LSE atomics are supported. +// +// This is not necessary on a custom Linux toolchain and is purely an artifact of +// using the host toolchain. + +// __gnu_linux__ is the define checked by libgcc +#if defined(__aarch64__) && defined(__gnu_linux__) && !defined(MLIBC_STATIC_BUILD) + +extern "C" unsigned long __getauxval(unsigned long type) { + // Find the auxiliary vector by skipping args and environment. + auto aux = entryStack; + aux += *aux + 1; // Skip argc and all arguments + __ensure(!*aux); + aux++; + while(*aux) // Now, we skip the environment. + aux++; + aux++; + + // Parse the auxiliary vector. + while(true) { + auto value = aux + 1; + if(*aux == AT_NULL) { + return 0; + }else if(*aux == type) { + return *value; + } + aux += 2; + } +} + +#endif diff --git a/lib/mlibc/options/rtdl/include/mlibc/rtdl-abi.hpp b/lib/mlibc/options/rtdl/include/mlibc/rtdl-abi.hpp new file mode 100644 index 0000000..135b461 --- /dev/null +++ b/lib/mlibc/options/rtdl/include/mlibc/rtdl-abi.hpp @@ -0,0 +1,28 @@ +#ifndef MLIBC_RTDL_ABI +#define MLIBC_RTDL_ABI + +#include + +#if defined(__x86_64__) || defined(__aarch64__) || defined(__i386__) || defined(__riscv) + +struct __abi_tls_entry { + struct SharedObject *object; + size_t offset; +}; +static_assert(sizeof(__abi_tls_entry) == sizeof(size_t) * 2, "Bad __abi_tls_entry size"); + +extern "C" void *__dlapi_get_tls(struct __abi_tls_entry *); + +#else +#error "Missing architecture specific code." +#endif + +#if defined(__riscv) +constexpr inline unsigned long TLS_DTV_OFFSET = 0x800; +#elif defined(__x86_64__) || defined(__i386__) || defined(__aarch64__) +constexpr inline unsigned long TLS_DTV_OFFSET = 0; +#else +#error "Missing architecture specific code." +#endif + +#endif // MLIBC_RTDL_ABI diff --git a/lib/mlibc/options/rtdl/include/mlibc/rtdl-config.hpp b/lib/mlibc/options/rtdl/include/mlibc/rtdl-config.hpp new file mode 100644 index 0000000..4838880 --- /dev/null +++ b/lib/mlibc/options/rtdl/include/mlibc/rtdl-config.hpp @@ -0,0 +1,24 @@ +#ifndef MLIBC_RTDL_CONFIG +#define MLIBC_RTDL_CONFIG + +namespace mlibc { + +struct RtdlConfig { + bool secureRequired; +}; + +} + +extern "C" const mlibc::RtdlConfig &__dlapi_get_config(); + +#ifndef MLIBC_BUILDING_RTDL +namespace mlibc { + +inline const RtdlConfig &rtdlConfig() { + return __dlapi_get_config(); +} + +} +#endif + +#endif // MLIBC_RTDL_CONFIG diff --git a/lib/mlibc/options/rtdl/include/mlibc/rtdl-sysdeps.hpp b/lib/mlibc/options/rtdl/include/mlibc/rtdl-sysdeps.hpp new file mode 100644 index 0000000..c35271c --- /dev/null +++ b/lib/mlibc/options/rtdl/include/mlibc/rtdl-sysdeps.hpp @@ -0,0 +1,12 @@ +#ifndef MLIBC_RTDL_SYSDEPS +#define MLIBC_RTDL_SYSDEPS + +namespace [[gnu::visibility("hidden")]] mlibc { + +int sys_tcb_set(void *pointer); + +[[gnu::weak]] int sys_vm_readahead(void *pointer, size_t size); + +} // namespace mlibc + +#endif // MLIBC_RTDL_SYSDEPS diff --git a/lib/mlibc/options/rtdl/riscv64/elf.hpp b/lib/mlibc/options/rtdl/riscv64/elf.hpp new file mode 100644 index 0000000..5d7039a --- /dev/null +++ b/lib/mlibc/options/rtdl/riscv64/elf.hpp @@ -0,0 +1,37 @@ +#pragma once + +#include + +#define ELF_CLASS ELFCLASS64 +#define ELF_MACHINE EM_RISCV + +using elf_ehdr = Elf64_Ehdr; +using elf_phdr = Elf64_Phdr; +using elf_dyn = Elf64_Dyn; +using elf_rel = Elf64_Rel; +using elf_rela = Elf64_Rela; +using elf_relr = Elf64_Relr; +using elf_sym = Elf64_Sym; +using elf_addr = Elf64_Addr; + +using elf_info = Elf64_Xword; +using elf_addend = Elf64_Sxword; + +#define ELF_R_SYM ELF64_R_SYM +#define ELF_R_TYPE ELF64_R_TYPE +#define ELF_ST_BIND ELF64_ST_BIND + +#define R_NONE R_RISCV_NONE +#define R_JUMP_SLOT R_RISCV_JUMP_SLOT +#define R_ABSOLUTE R_RISCV_64 +#define R_GLOB_DAT R_RISCV_64 +#define R_RELATIVE R_RISCV_RELATIVE +#define R_IRELATIVE R_RISCV_IRELATIVE +// #define R_OFFSET +#define R_COPY R_RISCV_COPY +#define R_TLS_DTPMOD R_RISCV_TLS_DTPMOD64 +#define R_TLS_DTPREL R_RISCV_TLS_DTPREL64 +#define R_TLS_TPREL R_RISCV_TLS_TPREL64 +#define R_TLSDESC R_RISCV_TLSDESC + +#define TP_TCB_OFFSET 0 diff --git a/lib/mlibc/options/rtdl/riscv64/entry.S b/lib/mlibc/options/rtdl/riscv64/entry.S new file mode 100644 index 0000000..b7cf854 --- /dev/null +++ b/lib/mlibc/options/rtdl/riscv64/entry.S @@ -0,0 +1,11 @@ +.global _start +_start: + call relocateSelf + + mv a0, sp + call interpreterMain + + jr a0 + +.section .note.GNU-stack,"",%progbits + diff --git a/lib/mlibc/options/rtdl/riscv64/runtime.S b/lib/mlibc/options/rtdl/riscv64/runtime.S new file mode 100644 index 0000000..5128fd3 --- /dev/null +++ b/lib/mlibc/options/rtdl/riscv64/runtime.S @@ -0,0 +1,5 @@ +.global pltRelocateStub +pltRelocateStub: + unimp // TODO +.section .note.GNU-stack,"",%progbits + diff --git a/lib/mlibc/options/rtdl/x86/elf.hpp b/lib/mlibc/options/rtdl/x86/elf.hpp new file mode 100644 index 0000000..95800aa --- /dev/null +++ b/lib/mlibc/options/rtdl/x86/elf.hpp @@ -0,0 +1,37 @@ +#pragma once + +#include + +#define ELF_CLASS ELFCLASS32 +#define ELF_MACHINE EM_386 + +using elf_ehdr = Elf32_Ehdr; +using elf_phdr = Elf32_Phdr; +using elf_dyn = Elf32_Dyn; +using elf_rel = Elf32_Rel; +using elf_rela = Elf32_Rela; +using elf_relr = Elf32_Relr; +using elf_sym = Elf32_Sym; +using elf_addr = Elf32_Addr; + +using elf_info = Elf32_Word; +using elf_addend = Elf32_Sword; + +#define ELF_R_SYM ELF32_R_SYM +#define ELF_R_TYPE ELF32_R_TYPE +#define ELF_ST_BIND ELF32_ST_BIND + +#define R_NONE R_386_NONE +#define R_JUMP_SLOT R_386_JMP_SLOT +#define R_ABSOLUTE R_386_32 +#define R_GLOB_DAT R_386_GLOB_DAT +#define R_RELATIVE R_386_RELATIVE +#define R_IRELATIVE R_386_IRELATIVE +#define R_OFFSET R_386_PC32 +#define R_COPY R_386_COPY +#define R_TLS_DTPMOD R_386_TLS_DTPMOD32 +#define R_TLS_DTPREL R_386_TLS_DTPOFF32 +#define R_TLS_TPREL R_386_TLS_TPOFF +#define R_TLSDESC R_386_TLS_DESC + +#define TP_TCB_OFFSET 0 diff --git a/lib/mlibc/options/rtdl/x86/entry.S b/lib/mlibc/options/rtdl/x86/entry.S new file mode 100644 index 0000000..963185b --- /dev/null +++ b/lib/mlibc/options/rtdl/x86/entry.S @@ -0,0 +1,10 @@ +.global _start +_start: + call relocateSelf + + push %esp + call interpreterMain + + jmp *%eax + +.section .note.GNU-stack,"",%progbits diff --git a/lib/mlibc/options/rtdl/x86/runtime.S b/lib/mlibc/options/rtdl/x86/runtime.S new file mode 100755 index 0000000..40a175f --- /dev/null +++ b/lib/mlibc/options/rtdl/x86/runtime.S @@ -0,0 +1,9 @@ +.global pltRelocateStub +# save / restore all registers that can hold function parameters +pltRelocateStub: + # we need to save / restore all registers than can hold function arguments + # we do not need to save callee-saved registers as they will not be trashed by lazyRelocate + # TODO: save floating point argument registers + ud2 + +.section .note.GNU-stack,"",%progbits diff --git a/lib/mlibc/options/rtdl/x86_64/elf.hpp b/lib/mlibc/options/rtdl/x86_64/elf.hpp new file mode 100644 index 0000000..2a80644 --- /dev/null +++ b/lib/mlibc/options/rtdl/x86_64/elf.hpp @@ -0,0 +1,37 @@ +#pragma once + +#include + +#define ELF_CLASS ELFCLASS64 +#define ELF_MACHINE EM_X86_64 + +using elf_ehdr = Elf64_Ehdr; +using elf_phdr = Elf64_Phdr; +using elf_dyn = Elf64_Dyn; +using elf_rel = Elf64_Rel; +using elf_rela = Elf64_Rela; +using elf_relr = Elf64_Relr; +using elf_sym = Elf64_Sym; +using elf_addr = Elf64_Addr; + +using elf_info = Elf64_Xword; +using elf_addend = Elf64_Sxword; + +#define ELF_R_SYM ELF64_R_SYM +#define ELF_R_TYPE ELF64_R_TYPE +#define ELF_ST_BIND ELF64_ST_BIND + +#define R_NONE R_X86_64_NONE +#define R_JUMP_SLOT R_X86_64_JUMP_SLOT +#define R_ABSOLUTE R_X86_64_64 +#define R_GLOB_DAT R_X86_64_GLOB_DAT +#define R_RELATIVE R_X86_64_RELATIVE +#define R_IRELATIVE R_X86_64_IRELATIVE +// #define R_OFFSET +#define R_COPY R_X86_64_COPY +#define R_TLS_DTPMOD R_X86_64_DTPMOD64 +#define R_TLS_DTPREL R_X86_64_DTPOFF64 +#define R_TLS_TPREL R_X86_64_TPOFF64 +#define R_TLSDESC R_X86_64_TLSDESC + +#define TP_TCB_OFFSET 0 diff --git a/lib/mlibc/options/rtdl/x86_64/entry.S b/lib/mlibc/options/rtdl/x86_64/entry.S new file mode 100644 index 0000000..ea64111 --- /dev/null +++ b/lib/mlibc/options/rtdl/x86_64/entry.S @@ -0,0 +1,11 @@ + +.global _start +_start: + call relocateSelf + + mov %rsp, %rdi + call interpreterMain + + jmp *%rax +.section .note.GNU-stack,"",%progbits + diff --git a/lib/mlibc/options/rtdl/x86_64/runtime.S b/lib/mlibc/options/rtdl/x86_64/runtime.S new file mode 100644 index 0000000..d8593c4 --- /dev/null +++ b/lib/mlibc/options/rtdl/x86_64/runtime.S @@ -0,0 +1,36 @@ + +.global pltRelocateStub +pltRelocateStub: + # we need to save / restore all registers than can hold function arguments + # we do not need to save callee-saved registers as they will not be trashed by lazyRelocate + # TODO: save floating point argument registers + + push %rsi + push %rdi + mov 16(%rsp), %rdi + mov 24(%rsp), %rsi + + push %rax + push %rcx + push %rdx + push %r8 + push %r9 + push %r10 + + call lazyRelocate + mov %rax, %r11 + + pop %r10 + pop %r9 + pop %r8 + pop %rdx + pop %rcx + pop %rax + + pop %rdi + pop %rsi + add $16, %rsp + jmp *%r11 + +.section .note.GNU-stack,"",%progbits + diff --git a/lib/mlibc/scripts/abi-link.sh b/lib/mlibc/scripts/abi-link.sh new file mode 100755 index 0000000..fdd0a5c --- /dev/null +++ b/lib/mlibc/scripts/abi-link.sh @@ -0,0 +1,12 @@ +#!/bin/bash +# USAGE: put files and ports in the arrays below and export the abi you want to use + + +declare -a files=() +declare -a ports=() + +for file in "${files[@]}"; do + for port in "${ports[@]}"; do + ln -rsiv abis/$abi/$file sysdeps/$port/include/abi-bits/$file + done +done diff --git a/lib/mlibc/scripts/check-options-header-include.sh b/lib/mlibc/scripts/check-options-header-include.sh new file mode 100644 index 0000000..7f951c8 --- /dev/null +++ b/lib/mlibc/scripts/check-options-header-include.sh @@ -0,0 +1,18 @@ +#!/bin/bash + +shopt -s lastpipe + +errors_found=0 + +find . -wholename '*include/*.h' -print0 | while read -rd $'\0' file; do + uses=$(grep -c -E "__MLIBC_(ANSI|BSD|POSIX|LINUX|INTL|ICONV|GLIBC|CRYPT)_OPTION" "$file") + if [ "$uses" -ne 0 ]; then + does_include=$(grep -c "#include " "$file") + if [ "$does_include" -eq 0 ]; then + echo "'$file' does not include mlibc-config.h while it does use mlibc option macros" + errors_found+=1 + fi + fi +done + +exit $errors_found diff --git a/lib/mlibc/scripts/hdoc.toml.in b/lib/mlibc/scripts/hdoc.toml.in new file mode 100644 index 0000000..eb51611 --- /dev/null +++ b/lib/mlibc/scripts/hdoc.toml.in @@ -0,0 +1,15 @@ +[project] +name = "mlibc" +use_system_includes = false +git_repo_url = "https://github.com/managarm/mlibc/" +git_default_branch = "master" + +[ignore] +paths = [ + "options/ansi/musl-generic-math/" +] + +[paths] +input_dir = "@source_root@" +output_dir = "@build_root@/docs/" +compile_commands = "@build_root@/compile_commands.json" diff --git a/lib/mlibc/sysdeps/aero/crt-x86_64/crt0.S b/lib/mlibc/sysdeps/aero/crt-x86_64/crt0.S new file mode 100644 index 0000000..62298e3 --- /dev/null +++ b/lib/mlibc/sysdeps/aero/crt-x86_64/crt0.S @@ -0,0 +1,10 @@ +.section .text + +.global _start +_start: + mov $main, %rdi + call __mlibc_entry + +.size _start, . - _start +.section .note.GNU-stack,"",%progbits + diff --git a/lib/mlibc/sysdeps/aero/generic/aero.cpp b/lib/mlibc/sysdeps/aero/generic/aero.cpp new file mode 100644 index 0000000..e6bd277 --- /dev/null +++ b/lib/mlibc/sysdeps/aero/generic/aero.cpp @@ -0,0 +1,360 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define ARCH_SET_GS 0x1001 +#define ARCH_SET_FS 0x1002 +#define ARCH_GET_FS 0x1003 +#define ARCH_GET_GS 0x1004 + +struct Slice { + void *ptr; + uint64_t len; +}; + +/// Helper function to construct a slice vector from the provided argument +/// array. A slice basically consists of a pointer to the data and the length of +/// it. +/// +/// ## Examples +/// ```cc +/// auto slice = create_slice({ "hello", "world" }); +/// ``` +/// +/// The `slice` will look like the following: +/// +/// ```cc +/// vector( +/// Slice { .ptr: hello_ptr, .size: hello_size }, +/// Slice { .ptr: world_ptr, .size: world_size } +/// ) +/// ``` +static frg::vector create_slice(char *const arg[]) { + if (arg == nullptr) { + return frg::vector{getAllocator()}; + } + + // Find out the length of arg: + size_t len = 0; + + while (arg[len] != nullptr) { + len += 1; + } + + frg::vector params{getAllocator()}; + params.resize(len); + + // Construct the slice vector: + for (size_t i = 0; i < len; ++i) { + params[i].ptr = (void *)arg[i]; + params[i].len = strlen(arg[i]); + } + + return params; +} + +namespace mlibc { +int sys_uname(struct utsname *buf) { + auto result = syscall(SYS_UNAME, buf); + + if (result < 0) { + return -result; + } + + return result; +} + +int sys_futex_wait(int *pointer, int expected, const struct timespec *time) { + // auto result = syscall(SYS_FUTEX_WAIT, pointer, expected, time); + // + // if (result < 0) { + // return -result; + // } + // + return 0; +} + +int sys_futex_wake(int *pointer) { + // auto result = syscall(SYS_FUTEX_WAKE, pointer); + // + // if (result < 0) { + // return -result; + // } + // + return 0; +} + +int sys_tcb_set(void *pointer) { + auto result = syscall(SYS_ARCH_PRCTL, ARCH_SET_FS, (uint64_t)pointer); + + if (result < 0) { + return -result; + } + + return 0; +} + +int sys_vm_map(void *hint, size_t size, int prot, int flags, int fd, + off_t offset, void **window) { + auto result = syscall(SYS_MMAP, hint, size, prot, flags, fd, offset); + + if (result < 0) { + return -result; + } + + *window = (void *)result; + return 0; +} + +int sys_vm_unmap(void *address, size_t size) { + return syscall(SYS_MUNMAP, address, size); +} + +int sys_vm_protect(void *pointer, size_t size, int prot) { + auto res = syscall(SYS_MPROTECT, pointer, size, prot); + if (res < 0) + return -res; + + return 0; +} + +int sys_anon_allocate(size_t size, void **pointer) { + return sys_vm_map(nullptr, size, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0, pointer); +} + +int sys_anon_free(void *pointer, size_t size) { + return sys_vm_unmap(pointer, size); +} + +void sys_libc_panic() { + mlibc::infoLogger() << "libc_panic: panicked at 'unknown'" << frg::endlog; + __ensure(!syscall(SYS_BACKTRACE)); + + sys_exit(1); +} + +void sys_libc_log(const char *msg) { syscall(SYS_LOG, msg, strlen(msg)); } + +void sys_exit(int status) { + syscall(SYS_EXIT, status); + + __builtin_unreachable(); +} + +#ifndef MLIBC_BUILDING_RTDL + +pid_t sys_getpid() { + auto result = syscall(SYS_GETPID); + __ensure(result >= 0); + + return result; +} + +pid_t sys_getppid() { + auto result = syscall(SYS_GETPPID); + __ensure(result != 0); + + return result; +} + +int sys_kill(int pid, int sig) { + auto result = syscall(SYS_KILL, pid, sig); + + if (result < 0) { + return -result; + } + + return 0; +} + +int sys_clock_get(int clock, time_t *secs, long *nanos) { + struct timespec ts; + auto result = syscall(SYS_GETTIME, clock, &ts); + + if (result < 0) { + return -result; + } + + *secs = ts.tv_sec; + *nanos = ts.tv_nsec; + + return 0; +} + +int sys_getcwd(char *buffer, size_t size) { + auto result = syscall(SYS_GETCWD, buffer, size); + + if (result < 0) { + return -result; + } + + return 0; +} + +int sys_chdir(const char *path) { + auto result = syscall(SYS_CHDIR, path, strlen(path)); + + if (result < 0) { + return -result; + } + + return 0; +} + +int sys_gethostname(char *buffer, size_t bufsize) { + auto result = syscall(SYS_GETHOSTNAME, buffer, bufsize); + + if (result < 0) { + return -result; + } + + return 0; +} + +int sys_sleep(time_t *sec, long *nanosec) { + struct timespec ts = {.tv_sec = *sec, .tv_nsec = *nanosec}; + + auto result = syscall(SYS_SLEEP, &ts); + + if (result < 0) { + return -result; + } + + return 0; +} + +pid_t sys_getpgid(pid_t pid, pid_t *pgid) { + auto ret = syscall(SYS_GETPGID, pid); + if(int e = sc_error(ret); e) + return e; + *pgid = ret; + return 0; +} + +int sys_setpgid(pid_t pid, pid_t pgid) { + auto ret = syscall(SYS_SETPGID, pid, pgid); + if(int e = sc_error(ret); e) + return e; + return 0; +} + +uid_t sys_getuid() { + mlibc::infoLogger() << "mlibc: sys_setuid is a stub" << frg::endlog; + return 0; +} + +uid_t sys_geteuid() { + mlibc::infoLogger() << "mlibc: sys_seteuid is a stub" << frg::endlog; + return 0; +} + +int sys_setsid(pid_t *sid) { + auto ret = syscall(SYS_SETSID); + if(int e = sc_error(ret); e) + return e; + *sid = ret; + return 0; +} + +int sys_seteuid(uid_t euid) UNIMPLEMENTED("sys_seteuid") + + gid_t sys_getgid() { + mlibc::infoLogger() << "mlibc: sys_setgid is a stub" << frg::endlog; + return 0; +} + +gid_t sys_getegid() { + mlibc::infoLogger() << "mlibc: sys_getegid is a stub" << frg::endlog; + return 0; +} + +int sys_setgid(gid_t gid) { + mlibc::infoLogger() << "mlibc: sys_setgid is a stub" << frg::endlog; + return 0; +} + +int sys_setegid(gid_t egid) { + mlibc::infoLogger() << "mlibc: sys_setegid is a stub" << frg::endlog; + return 0; +} + +void sys_yield() { + mlibc::infoLogger() << "mlibc: sys_yield is a stub" << frg::endlog; + __ensure(!syscall(SYS_BACKTRACE)); +} + +int sys_clone(void *tcb, pid_t *tid_out, void *stack) { + auto result = syscall(SYS_CLONE, (uintptr_t)__mlibc_start_thread, stack); + + if (result < 0) { + return -result; + } + + *tid_out = (pid_t)result; + return 0; +} + +void sys_thread_exit() UNIMPLEMENTED("sys_thread_exit") + + int sys_waitpid(pid_t pid, int *status, int flags, struct rusage *ru, + pid_t *ret_pid) { + if (ru) { + mlibc::infoLogger() + << "mlibc: struct rusage in sys_waitpid is unsupported" + << frg::endlog; + return ENOSYS; + } + + auto result = syscall(SYS_WAITPID, pid, status, flags); + + if (result < 0) { + return -result; + } + + *ret_pid = result; + return 0; +} + +int sys_fork(pid_t *child) { + auto result = syscall(SYS_FORK); + + if (result < 0) { + return -result; + } + + *child = result; + return 0; +} + +int sys_execve(const char *path, char *const argv[], char *const envp[]) { + auto envv_slice = create_slice(envp); + auto argv_slice = create_slice(argv); + + auto path_ptr = (uintptr_t)path; + auto path_len = strlen(path); + + auto result = + syscall(SYS_EXEC, path_ptr, path_len, argv_slice.data(), + argv_slice.size(), envv_slice.data(), envv_slice.size()); + + if (result < 0) { + return -result; + } + + __builtin_unreachable(); +} + +// int sys_getentropy(void *buffer, size_t length) +// UNIMPLEMENTED("sys_getentropy") + +#endif +} // namespace mlibc diff --git a/lib/mlibc/sysdeps/aero/generic/entry.cpp b/lib/mlibc/sysdeps/aero/generic/entry.cpp new file mode 100644 index 0000000..77d6ed5 --- /dev/null +++ b/lib/mlibc/sysdeps/aero/generic/entry.cpp @@ -0,0 +1,36 @@ +#include +#include +#include +#include + +// defined by the POSIX library +void __mlibc_initLocale(); + +extern "C" uintptr_t *__dlapi_entrystack(); + +extern char **environ; +static mlibc::exec_stack_data __mlibc_stack_data; + +struct LibraryGuard { + LibraryGuard(); +}; + +static LibraryGuard guard; + +LibraryGuard::LibraryGuard() { + __mlibc_initLocale(); + + // Parse the exec() stack. + mlibc::parse_exec_stack(__dlapi_entrystack(), &__mlibc_stack_data); + mlibc::set_startup_data(__mlibc_stack_data.argc, __mlibc_stack_data.argv, + __mlibc_stack_data.envp); +} + +extern "C" void __mlibc_entry(int (*main_fn)(int argc, char *argv[], + char *env[])) { + // TODO: call __dlapi_enter, otherwise static builds will break (see Linux + // sysdeps) + auto result = + main_fn(__mlibc_stack_data.argc, __mlibc_stack_data.argv, environ); + exit(result); +} diff --git a/lib/mlibc/sysdeps/aero/generic/filesystem.cpp b/lib/mlibc/sysdeps/aero/generic/filesystem.cpp new file mode 100644 index 0000000..049f4c0 --- /dev/null +++ b/lib/mlibc/sysdeps/aero/generic/filesystem.cpp @@ -0,0 +1,472 @@ +#include "mlibc/fsfd_target.hpp" +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include +#include + +namespace mlibc { +int sys_write(int fd, const void *buffer, size_t count, ssize_t *written) { + auto result = syscall(SYS_WRITE, fd, buffer, count); + + if (result < 0) { + return -result; + } + + *written = result; + return 0; +} + +int sys_read(int fd, void *buf, size_t count, ssize_t *bytes_read) { + auto result = syscall(SYS_READ, fd, buf, count); + + if (result < 0) { + *bytes_read = 0; + return -result; + } + + *bytes_read = result; + return 0; +} + +// clang-format off +int sys_pwrite(int fd, const void *buffer, size_t count, off_t off, + ssize_t *written) UNIMPLEMENTED("sys_pwrite") + +// clang-format off +int sys_pread(int fd, void *buf, size_t count, + off_t off, ssize_t *bytes_read) UNIMPLEMENTED("sys_pread") + +int sys_seek(int fd, off_t offset, int whence, off_t *new_offset) { + auto result = syscall(SYS_SEEK, fd, offset, whence); + + if (result < 0) { + return -result; + } + + *new_offset = result; + return 0; +} + +int sys_open(const char *filename, int flags, mode_t mode, int *fd) { + auto result = syscall(SYS_OPEN, 0, filename, strlen(filename), flags); + + if (result < 0) { + return -result; + } + + *fd = result; + return 0; +} + +int sys_close(int fd) { + auto result = syscall(SYS_CLOSE, fd); + + if (result < 0) { + return -result; + } + + return 0; +} + +int sys_access(const char *filename, int mode) { + auto result = + syscall(SYS_ACCESS, AT_FDCWD, filename, strlen(filename), mode, 0); + + if (result < 0) { + return -result; + } + + return 0; +} + +int sys_stat(fsfd_target fsfdt, int fd, const char *path, int flags, + struct stat *statbuf) { + switch (fsfdt) { + case fsfd_target::path: + fd = AT_FDCWD; + break; + case fsfd_target::fd: + flags |= AT_EMPTY_PATH; + + case fsfd_target::fd_path: + break; + + default: + __ensure(!"Invalid fsfd_target"); + __builtin_unreachable(); + } + + auto ret = syscall(SYS_FSTAT, fd, path, strlen(path), flags, statbuf); + if(int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_ioctl(int fd, unsigned long request, void *arg, int *result) { + auto sys_res = syscall(SYS_IOCTL, fd, request, arg); + + if (sys_res < 0) { + return -sys_res; + } + + if (result) + *result = sys_res; + return 0; +} + +int sys_isatty(int fd) { + // NOTE: The easiest way to check if a file descriptor is a TTY is to + // do an ioctl of TIOCGWINSZ on it and see if it succeeds :^) + struct winsize ws; + int result; + + if (!sys_ioctl(fd, TIOCGWINSZ, &ws, &result)) { + return 0; + } + + return ENOTTY; +} + +int sys_tcgetattr(int fd, struct termios *attr) { + int result; + + if (int e = sys_ioctl(fd, TCGETS, (void *)attr, &result); e) + return e; + + return 0; +} + +int sys_tcsetattr(int fd, int optional_action, const struct termios *attr) { + int req; + + switch (optional_action) { + case TCSANOW: req = TCSETS; break; + case TCSADRAIN: req = TCSETSW; break; + case TCSAFLUSH: req = TCSETSF; break; + default: return EINVAL; + } + + if (int e = sys_ioctl(fd, req, (void *)attr, NULL); e) + return e; + + return 0; +} + +int sys_mkdir(const char *path, mode_t) { + auto result = syscall(SYS_MKDIR, path, strlen(path)); + + if (result < 0) { + return -result; + } + + return 0; +} + +int sys_link(const char *srcpath, const char *destpath) { + auto result = + syscall(SYS_LINK, srcpath, strlen(srcpath), destpath, strlen(destpath)); + + if (result < 0) { + return -result; + } + + return 0; +} + +int sys_rmdir(const char *path) { + return sys_unlinkat(AT_FDCWD, path, AT_REMOVEDIR); +} + +int sys_unlinkat(int fd, const char *path, int flags) { + auto ret = syscall(SYS_UNLINK, fd, path, strlen(path), flags); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +struct aero_dir_entry { + size_t inode; + size_t offset; + size_t reclen; + size_t filetyp; + char name[]; +} __attribute__((__packed__)); + +int sys_read_entries(int handle, void *buffer, size_t max_size, + size_t *bytes_read) { + auto result = syscall(SYS_GETDENTS, handle, buffer, max_size); + + // Check if we got an error. + if (result < 0) { + *bytes_read = 0; + return -result; + } + + // Nothing to read. + if (result == 0) { + *bytes_read = 0; + return 0; + } + + auto entry = (struct aero_dir_entry *)buffer; + + struct dirent dirent = { + .d_ino = static_cast(entry->inode), + .d_off = static_cast(entry->offset), + .d_reclen = static_cast(entry->reclen), + .d_type = static_cast(entry->filetyp), + }; + + // The reclen is the size of the dirent struct, plus the size of the name. + auto name_size = entry->reclen - sizeof(struct aero_dir_entry); + __ensure(name_size < 255); + + memcpy(&dirent.d_name, entry->name, name_size); + *bytes_read = entry->reclen; + + memcpy(buffer, &dirent, sizeof(struct dirent)); + return 0; +} + +int sys_open_dir(const char *path, int *handle) { + return sys_open(path, O_DIRECTORY, 0, handle); +} + +int sys_rename(const char *path, const char *new_path) { + auto result = + syscall(SYS_RENAME, path, strlen(path), new_path, strlen(new_path)); + + if (result < 0) { + return -result; + } + + return 0; +} + +int sys_readlink(const char *path, void *buffer, size_t max_size, + ssize_t *length) { + auto result = syscall(SYS_READ_LINK, path, strlen(path), buffer, max_size); + + if (result < 0) { + return -result; + } + + *length = result; + return 0; +} + +int sys_dup(int fd, int flags, int *newfd) { + auto result = syscall(SYS_DUP, fd, flags); + + if (result < 0) { + return -result; + } + + *newfd = result; + return 0; +} + +int sys_dup2(int fd, int flags, int newfd) { + auto result = syscall(SYS_DUP2, fd, newfd, flags); + + if (result < 0) { + return -result; + } + + return 0; +} + +int sys_fcntl(int fd, int request, va_list args, int *result_value) { + auto result = syscall(SYS_FCNTL, fd, request, va_arg(args, uint64_t)); + + if (result < 0) { + return -result; + } + + *result_value = result; + return 0; +} + +// int sys_chmod(const char *pathname, mode_t mode) UNIMPLEMENTED("sys_chmod") + +int sys_pipe(int *fds, int flags) { + auto result = syscall(SYS_PIPE, fds, flags); + + if (result < 0) { + return -result; + } + + return 0; +} + +// epoll API syscalls: +int sys_epoll_create(int flags, int *fd) { + auto result = syscall(SYS_EPOLL_CREATE, flags); + + if (result < 0) { + return -result; + } + + *fd = result; + return 0; +} + +int sys_epoll_ctl(int epfd, int mode, int fd, struct epoll_event *ev) { + auto result = syscall(SYS_EPOLL_CTL, epfd, mode, fd, ev); + + if (result < 0) { + return -result; + } + + return 0; +} + +int sys_epoll_pwait(int epfd, struct epoll_event *ev, int n, int timeout, + const sigset_t *sigmask, int *raised) { + auto result = syscall(SYS_EPOLL_PWAIT, epfd, ev, n, timeout, sigmask); + + if (result < 0) { + return -result; + } + + *raised = result; + return 0; +} + +int sys_eventfd_create(unsigned int initval, int flags, int *fd) { + auto result = syscall(SYS_EVENT_FD, initval, flags); + + if (result < 0) { + return -result; + } + + *fd = result; + return 0; +} + +int sys_ppoll(struct pollfd *fds, int nfds, const struct timespec *timeout, + const sigset_t *sigmask, int *num_events) { + auto result = syscall(SYS_POLL, fds, nfds, timeout, sigmask); + + if (result < 0) { + return -result; + } + + *num_events = result; + return 0; +} + +int sys_poll(struct pollfd *fds, nfds_t count, int timeout, int *num_events) { + struct timespec ts; + ts.tv_sec = timeout / 1000; + ts.tv_nsec = (timeout % 1000) * 1000000; + + return sys_ppoll(fds, count, &ts, NULL, num_events); +} + +#ifndef MLIBC_BUILDING_RTDL +#include +int sys_ptsname(int fd, char *buffer, size_t length) { + int index; + if (int e = sys_ioctl(fd, TIOCGPTN, &index, NULL); e) + return e; + if ((size_t)snprintf(buffer, length, "/dev/pts/%d", index) >= length) { + return ERANGE; + } + return 0; +} + +int sys_pselect(int num_fds, fd_set *read_set, fd_set *write_set, + fd_set *except_set, const struct timespec *timeout, + const sigset_t *sigmask, int *num_events) { + int fd = epoll_create1(0); + if (fd == -1) + return -1; + + for (int k = 0; k < FD_SETSIZE; k++) { + struct epoll_event ev; + memset(&ev, 0, sizeof(struct epoll_event)); + + if (read_set && FD_ISSET(k, read_set)) + ev.events |= EPOLLIN; + if (write_set && FD_ISSET(k, write_set)) + ev.events |= EPOLLOUT; + if (except_set && FD_ISSET(k, except_set)) + ev.events |= EPOLLPRI; + + if (!ev.events) + continue; + + ev.data.u32 = k; + if (epoll_ctl(fd, EPOLL_CTL_ADD, k, &ev)) + return -1; + } + + struct epoll_event evnts[16]; + int n = epoll_pwait( + fd, evnts, 16, + timeout ? (timeout->tv_sec * 1000 + timeout->tv_nsec / 100) : -1, + sigmask); + + if (n == -1) + return -1; + + fd_set res_read_set; + fd_set res_write_set; + fd_set res_except_set; + FD_ZERO(&res_read_set); + FD_ZERO(&res_write_set); + FD_ZERO(&res_except_set); + + int m = 0; + + for (int i = 0; i < n; i++) { + int k = evnts[i].data.u32; + + if (read_set && FD_ISSET(k, read_set) && + evnts[i].events & (EPOLLIN | EPOLLERR | EPOLLHUP)) { + FD_SET(k, &res_read_set); + m++; + } + + if (write_set && FD_ISSET(k, write_set) && + evnts[i].events & (EPOLLOUT | EPOLLERR | EPOLLHUP)) { + FD_SET(k, &res_write_set); + m++; + } + + if (except_set && FD_ISSET(k, except_set) && + evnts[i].events & EPOLLPRI) { + FD_SET(k, &res_except_set); + m++; + } + } + + if (close(fd)) + __ensure("mlibc::pselect: close() failed on epoll file"); + + if (read_set) + memcpy(read_set, &res_read_set, sizeof(fd_set)); + + if (write_set) + memcpy(write_set, &res_write_set, sizeof(fd_set)); + + if (except_set) + memcpy(except_set, &res_except_set, sizeof(fd_set)); + + *num_events = m; + return 0; +} +#endif // #ifndef MLIBC_BUILDING_RTDL +} // namespace mlibc diff --git a/lib/mlibc/sysdeps/aero/generic/signals.S b/lib/mlibc/sysdeps/aero/generic/signals.S new file mode 100644 index 0000000..62dee9b --- /dev/null +++ b/lib/mlibc/sysdeps/aero/generic/signals.S @@ -0,0 +1,9 @@ +.section .text +.global __mlibc_signal_restore + +__mlibc_signal_restore: + mov $39, %rax + syscall + ud2 +.section .note.GNU-stack,"",%progbits + diff --git a/lib/mlibc/sysdeps/aero/generic/signals.cpp b/lib/mlibc/sysdeps/aero/generic/signals.cpp new file mode 100644 index 0000000..a6f69ff --- /dev/null +++ b/lib/mlibc/sysdeps/aero/generic/signals.cpp @@ -0,0 +1,53 @@ +#include +#include + +#include +#include + +#define LOG_SIGACTION_INSTALL 0 + +extern "C" void __mlibc_signal_restore(); // defined in `signals.S` + +namespace mlibc { +int sys_sigaction(int how, const struct sigaction *__restrict action, + struct sigaction *__restrict old_action) { +#if LOG_SIGACTION_INSTALL + mlibc::infoLogger() << "sys_sigaction: signal " << how << frg::endlog; + mlibc::infoLogger() << "sys_sigaction: size: " << sizeof(*action) + << frg::endlog; + + if (action != NULL) { + mlibc::infoLogger() << "sys_sigaction: handler " + << (int64_t)action->sa_handler << frg::endlog; + mlibc::infoLogger() << "sys_sigaction: action " + << (int64_t)action->sa_sigaction << frg::endlog; + mlibc::infoLogger() << "sys_sigaction: flags " + << (int64_t)action->sa_flags << frg::endlog; + } + + mlibc::infoLogger() << frg::endlog; +#endif + + auto sigreturn = (sc_word_t)__mlibc_signal_restore; + + auto res = syscall(SYS_SIGACTION, how, (sc_word_t)action, sigreturn, + (sc_word_t)old_action); + + if (res < 0) { + return -res; + } + + return 0; +} + +int sys_sigprocmask(int how, const sigset_t *__restrict set, + sigset_t *__restrict retrieve) { + auto result = syscall(SYS_SIGPROCMASK, how, set, retrieve); + + if (result < 0) { + return -result; + } + + return 0; +} +} // namespace mlibc \ No newline at end of file diff --git a/lib/mlibc/sysdeps/aero/generic/sockets.cpp b/lib/mlibc/sysdeps/aero/generic/sockets.cpp new file mode 100644 index 0000000..0cce3c0 --- /dev/null +++ b/lib/mlibc/sysdeps/aero/generic/sockets.cpp @@ -0,0 +1,250 @@ +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +namespace { + +int fcntl_helper(int fd, int request, int *result, ...) { + va_list args; + va_start(args, result); + if(!mlibc::sys_fcntl) { + return ENOSYS; + } + int ret = mlibc::sys_fcntl(fd, request, args, result); + va_end(args); + return ret; +} + +} + +namespace mlibc { +int sys_socket(int family, int type, int protocol, int *fd) { + auto result = syscall(SYS_SOCKET, family, type, protocol); + + if (result < 0) { + return -result; + } + + *fd = result; + return 0; +} + +int sys_bind(int fd, const struct sockaddr *addr_ptr, socklen_t addr_length) { + auto result = syscall(SYS_BIND, fd, addr_ptr, (sc_word_t)addr_length); + + if (result < 0) { + return -result; + } + + return 0; +} + +int sys_connect(int fd, const struct sockaddr *addr_ptr, + socklen_t addr_length) { + auto result = syscall(SYS_CONNECT, fd, addr_ptr, (sc_word_t)addr_length); + + if (result < 0) { + return -result; + } + + return 0; +} + +int sys_listen(int fd, int backlog) { + auto result = syscall(SYS_LISTEN, fd, backlog); + + if (result < 0) { + return -result; + } + + return 0; +} + +int sys_accept(int sockfd, int *newfd, struct sockaddr *addr_ptr, + socklen_t *addr_length, int flags) { + auto result = syscall(SYS_ACCEPT, sockfd, addr_ptr, addr_length); + + if (result < 0) { + return -result; + } + + *newfd = result; + + if(flags & SOCK_NONBLOCK) { + int fcntl_ret = 0; + fcntl_helper(*newfd, F_GETFL, &fcntl_ret); + fcntl_helper(*newfd, F_SETFL, &fcntl_ret, fcntl_ret | O_NONBLOCK); + } + + if(flags & SOCK_CLOEXEC) { + int fcntl_ret = 0; + fcntl_helper(*newfd, F_GETFD, &fcntl_ret); + fcntl_helper(*newfd, F_SETFD, &fcntl_ret, fcntl_ret | FD_CLOEXEC); + } + + return 0; +} + +int sys_msg_send(int fd, const struct msghdr *hdr, int flags, ssize_t *length) { + auto result = syscall(SYS_SOCK_SEND, fd, hdr, flags); + if (result < 0) + return -result; + + *length = result; + return 0; +} + +int sys_msg_recv(int sockfd, struct msghdr *msg_hdr, int flags, + ssize_t *length) { + auto result = syscall(SYS_SOCK_RECV, sockfd, msg_hdr, flags); + + if (result < 0) { + return -result; + } + + *length = result; + return 0; +} + +int sys_socketpair(int domain, int type_and_flags, int proto, int *fds) { + auto result = syscall(SYS_SOCKET_PAIR, domain, type_and_flags, proto, fds); + + if (result < 0) { + return -result; + } + + return 0; +} + +int sys_getsockopt(int fd, int layer, int number, void *__restrict buffer, + socklen_t *__restrict size) { + (void)fd; + (void)size; + if (layer == SOL_SOCKET && number == SO_PEERCRED) { + mlibc::infoLogger() << "\e[31mmlibc: getsockopt() call with SOL_SOCKET " + "and SO_PEERCRED is unimplemented\e[39m" + << frg::endlog; + *(int *)buffer = 0; + return 0; + } else if (layer == SOL_SOCKET && number == SO_SNDBUF) { + mlibc::infoLogger() << "\e[31mmlibc: getsockopt() call with SOL_SOCKET " + "and SO_SNDBUF is unimplemented\e[39m" + << frg::endlog; + *(int *)buffer = 4096; + return 0; + } else if (layer == SOL_SOCKET && number == SO_TYPE) { + mlibc::infoLogger() + << "\e[31mmlibc: getsockopt() call with SOL_SOCKET and SO_TYPE is " + "unimplemented, hardcoding SOCK_STREAM\e[39m" + << frg::endlog; + *(int *)buffer = SOCK_STREAM; + return 0; + } else if (layer == SOL_SOCKET && number == SO_ERROR) { + mlibc::infoLogger() + << "\e[31mmlibc: getsockopt() call with SOL_SOCKET and SO_ERROR is " + "unimplemented, hardcoding 0\e[39m" + << frg::endlog; + *(int *)buffer = 0; + return 0; + } else if (layer == SOL_SOCKET && number == SO_KEEPALIVE) { + mlibc::infoLogger() + << "\e[31mmlibc: getsockopt() call with SOL_SOCKET and " + "SO_KEEPALIVE is unimplemented, hardcoding 0\e[39m" + << frg::endlog; + *(int *)buffer = 0; + return 0; + } else { + mlibc::panicLogger() + << "\e[31mmlibc: Unexpected getsockopt() call, layer: " << layer + << " number: " << number << "\e[39m" << frg::endlog; + __builtin_unreachable(); + } + + return 0; +} + +int sys_setsockopt(int fd, int layer, int number, const void *buffer, + socklen_t size) { + (void)fd; + (void)buffer; + (void)size; + + if (layer == SOL_SOCKET && number == SO_PASSCRED) { + mlibc::infoLogger() << "\e[31mmlibc: setsockopt(SO_PASSCRED) is not " + "implemented correctly\e[39m" + << frg::endlog; + return 0; + } else if (layer == SOL_SOCKET && number == SO_ATTACH_FILTER) { + mlibc::infoLogger() << "\e[31mmlibc: setsockopt(SO_ATTACH_FILTER) is " + "not implemented correctly\e[39m" + << frg::endlog; + return 0; + } else if (layer == SOL_SOCKET && number == SO_RCVBUFFORCE) { + mlibc::infoLogger() << "\e[31mmlibc: setsockopt(SO_RCVBUFFORCE) is not " + "implemented correctly\e[39m" + << frg::endlog; + return 0; + } else if (layer == SOL_SOCKET && number == SO_SNDBUF) { + mlibc::infoLogger() << "\e[31mmlibc: setsockopt() call with SOL_SOCKET " + "and SO_SNDBUF is unimplemented\e[39m" + << frg::endlog; + return 0; + } else if (layer == SOL_SOCKET && number == SO_KEEPALIVE) { + mlibc::infoLogger() << "\e[31mmlibc: setsockopt() call with SOL_SOCKET " + "and SO_KEEPALIVE is unimplemented\e[39m" + << frg::endlog; + return 0; + } else if (layer == SOL_SOCKET && number == SO_REUSEADDR) { + mlibc::infoLogger() << "\e[31mmlibc: setsockopt() call with SOL_SOCKET " + "and SO_REUSEADDR is unimplemented\e[39m" + << frg::endlog; + return 0; + } else if (layer == AF_NETLINK && number == SO_ACCEPTCONN) { + mlibc::infoLogger() << "\e[31mmlibc: setsockopt() call with AF_NETLINK " + "and SO_ACCEPTCONN is unimplemented\e[39m" + << frg::endlog; + return 0; + } else { + mlibc::infoLogger() + << "\e[31mmlibc: Unexpected setsockopt() call, layer: " << layer + << " number: " << number << "\e[39m" << frg::endlog; + return 0; + } +} + +int sys_shutdown(int sockfd, int how) { + auto ret = syscall(SYS_SOCK_SHUTDOWN, sockfd, how); + if(int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_if_nametoindex(const char *name, unsigned int *ret) { + int fd = 0; + int r = sys_socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, AF_UNSPEC, &fd); + + if (r) + return r; + + struct ifreq ifr; + strncpy(ifr.ifr_name, name, sizeof ifr.ifr_name); + + r = sys_ioctl(fd, SIOCGIFINDEX, &ifr, NULL); + close(fd); + + if (r) + return r; + + *ret = ifr.ifr_ifindex; + return 0; +} +} // namespace mlibc diff --git a/lib/mlibc/sysdeps/aero/generic/thread.cpp b/lib/mlibc/sysdeps/aero/generic/thread.cpp new file mode 100644 index 0000000..bc9a449 --- /dev/null +++ b/lib/mlibc/sysdeps/aero/generic/thread.cpp @@ -0,0 +1,55 @@ +#include +#include + +#include +#include + +#include + +#include +#include + +extern "C" void __mlibc_enter_thread(void *entry, void *user_arg, Tcb *tcb) { + // Wait until our parent sets up the TID: + while (!__atomic_load_n(&tcb->tid, __ATOMIC_RELAXED)) + mlibc::sys_futex_wait(&tcb->tid, 0, nullptr); + + if (mlibc::sys_tcb_set(tcb)) + __ensure(!"sys_tcb_set() failed"); + + tcb->invokeThreadFunc(entry, user_arg); + + auto self = reinterpret_cast(tcb); + + __atomic_store_n(&self->didExit, 1, __ATOMIC_RELEASE); + mlibc::sys_futex_wake(&self->didExit); + + mlibc::sys_thread_exit(); +} + +namespace mlibc { + +static constexpr size_t default_stacksize = 0x1000000; + +int sys_prepare_stack(void **stack, void *entry, void *user_arg, void *tcb, + size_t *stack_size, size_t *guard_size, void **stack_base) { + if (!*stack_size) + *stack_size = default_stacksize; + *guard_size = 0; + + if (*stack) { + *stack_base = *stack; + } else { + *stack_base = mmap(nullptr, *stack_size, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + } + + uintptr_t *sp = reinterpret_cast(reinterpret_cast(*stack_base) + *stack_size); + + *--sp = reinterpret_cast(tcb); + *--sp = reinterpret_cast(user_arg); + *--sp = reinterpret_cast(entry); + *stack = reinterpret_cast(sp); + return 0; +} +} // namespace mlibc diff --git a/lib/mlibc/sysdeps/aero/generic/thread_entry.S b/lib/mlibc/sysdeps/aero/generic/thread_entry.S new file mode 100644 index 0000000..498fda3 --- /dev/null +++ b/lib/mlibc/sysdeps/aero/generic/thread_entry.S @@ -0,0 +1,10 @@ +.section .text +.global __mlibc_start_thread + +__mlibc_start_thread: + pop %rdi + pop %rsi + pop %rdx + call __mlibc_enter_thread +.section .note.GNU-stack,"",%progbits + diff --git a/lib/mlibc/sysdeps/aero/generic/time.cpp b/lib/mlibc/sysdeps/aero/generic/time.cpp new file mode 100644 index 0000000..c995148 --- /dev/null +++ b/lib/mlibc/sysdeps/aero/generic/time.cpp @@ -0,0 +1,25 @@ +#include +#include + +namespace mlibc { +int sys_setitimer(int which, const struct itimerval *new_value, + struct itimerval *old_value) { + auto result = syscall(SYS_SETITIMER, which, new_value, old_value); + + if (result < 0) { + return -result; + } + + return 0; +} + +int sys_getitimer(int which, struct itimerval *curr_value) { + auto result = syscall(SYS_GETITIMER, which, curr_value); + + if (result < 0) { + return -result; + } + + return 0; +} +} // namespace mlibc \ No newline at end of file diff --git a/lib/mlibc/sysdeps/aero/include/abi-bits/access.h b/lib/mlibc/sysdeps/aero/include/abi-bits/access.h new file mode 120000 index 0000000..171f75f --- /dev/null +++ b/lib/mlibc/sysdeps/aero/include/abi-bits/access.h @@ -0,0 +1 @@ +../../../../abis/mlibc/access.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/aero/include/abi-bits/auxv.h b/lib/mlibc/sysdeps/aero/include/abi-bits/auxv.h new file mode 120000 index 0000000..86157e8 --- /dev/null +++ b/lib/mlibc/sysdeps/aero/include/abi-bits/auxv.h @@ -0,0 +1 @@ +../../../../abis/aero/auxv.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/aero/include/abi-bits/blkcnt_t.h b/lib/mlibc/sysdeps/aero/include/abi-bits/blkcnt_t.h new file mode 120000 index 0000000..e9d9f1b --- /dev/null +++ b/lib/mlibc/sysdeps/aero/include/abi-bits/blkcnt_t.h @@ -0,0 +1 @@ +../../../../abis/mlibc/blkcnt_t.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/aero/include/abi-bits/blksize_t.h b/lib/mlibc/sysdeps/aero/include/abi-bits/blksize_t.h new file mode 120000 index 0000000..c6dfb6e --- /dev/null +++ b/lib/mlibc/sysdeps/aero/include/abi-bits/blksize_t.h @@ -0,0 +1 @@ +../../../../abis/mlibc/blksize_t.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/aero/include/abi-bits/clockid_t.h b/lib/mlibc/sysdeps/aero/include/abi-bits/clockid_t.h new file mode 120000 index 0000000..71f37bb --- /dev/null +++ b/lib/mlibc/sysdeps/aero/include/abi-bits/clockid_t.h @@ -0,0 +1 @@ +../../../../abis/mlibc/clockid_t.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/aero/include/abi-bits/dev_t.h b/lib/mlibc/sysdeps/aero/include/abi-bits/dev_t.h new file mode 120000 index 0000000..0c1143b --- /dev/null +++ b/lib/mlibc/sysdeps/aero/include/abi-bits/dev_t.h @@ -0,0 +1 @@ +../../../../abis/mlibc/dev_t.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/aero/include/abi-bits/epoll.h b/lib/mlibc/sysdeps/aero/include/abi-bits/epoll.h new file mode 120000 index 0000000..9efc3a0 --- /dev/null +++ b/lib/mlibc/sysdeps/aero/include/abi-bits/epoll.h @@ -0,0 +1 @@ +../../../../abis/mlibc/epoll.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/aero/include/abi-bits/errno.h b/lib/mlibc/sysdeps/aero/include/abi-bits/errno.h new file mode 120000 index 0000000..589859f --- /dev/null +++ b/lib/mlibc/sysdeps/aero/include/abi-bits/errno.h @@ -0,0 +1 @@ +../../../../abis/mlibc/errno.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/aero/include/abi-bits/fcntl.h b/lib/mlibc/sysdeps/aero/include/abi-bits/fcntl.h new file mode 120000 index 0000000..ea5323a --- /dev/null +++ b/lib/mlibc/sysdeps/aero/include/abi-bits/fcntl.h @@ -0,0 +1 @@ +../../../../abis/mlibc/fcntl.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/aero/include/abi-bits/fsblkcnt_t.h b/lib/mlibc/sysdeps/aero/include/abi-bits/fsblkcnt_t.h new file mode 120000 index 0000000..898dfb2 --- /dev/null +++ b/lib/mlibc/sysdeps/aero/include/abi-bits/fsblkcnt_t.h @@ -0,0 +1 @@ +../../../../abis/linux/fsblkcnt_t.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/aero/include/abi-bits/fsfilcnt_t.h b/lib/mlibc/sysdeps/aero/include/abi-bits/fsfilcnt_t.h new file mode 120000 index 0000000..791755c --- /dev/null +++ b/lib/mlibc/sysdeps/aero/include/abi-bits/fsfilcnt_t.h @@ -0,0 +1 @@ +../../../../abis/linux/fsfilcnt_t.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/aero/include/abi-bits/gid_t.h b/lib/mlibc/sysdeps/aero/include/abi-bits/gid_t.h new file mode 120000 index 0000000..6a77218 --- /dev/null +++ b/lib/mlibc/sysdeps/aero/include/abi-bits/gid_t.h @@ -0,0 +1 @@ +../../../../abis/mlibc/gid_t.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/aero/include/abi-bits/in.h b/lib/mlibc/sysdeps/aero/include/abi-bits/in.h new file mode 120000 index 0000000..b58c683 --- /dev/null +++ b/lib/mlibc/sysdeps/aero/include/abi-bits/in.h @@ -0,0 +1 @@ +../../../../abis/mlibc/in.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/aero/include/abi-bits/ino_t.h b/lib/mlibc/sysdeps/aero/include/abi-bits/ino_t.h new file mode 120000 index 0000000..10d644e --- /dev/null +++ b/lib/mlibc/sysdeps/aero/include/abi-bits/ino_t.h @@ -0,0 +1 @@ +../../../../abis/mlibc/ino_t.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/aero/include/abi-bits/inotify.h b/lib/mlibc/sysdeps/aero/include/abi-bits/inotify.h new file mode 120000 index 0000000..3f19ef6 --- /dev/null +++ b/lib/mlibc/sysdeps/aero/include/abi-bits/inotify.h @@ -0,0 +1 @@ +../../../../abis/mlibc/inotify.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/aero/include/abi-bits/ioctls.h b/lib/mlibc/sysdeps/aero/include/abi-bits/ioctls.h new file mode 120000 index 0000000..595106b --- /dev/null +++ b/lib/mlibc/sysdeps/aero/include/abi-bits/ioctls.h @@ -0,0 +1 @@ +../../../../abis/linux/ioctls.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/aero/include/abi-bits/limits.h b/lib/mlibc/sysdeps/aero/include/abi-bits/limits.h new file mode 120000 index 0000000..1aa5894 --- /dev/null +++ b/lib/mlibc/sysdeps/aero/include/abi-bits/limits.h @@ -0,0 +1 @@ +../../../../abis/mlibc/limits.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/aero/include/abi-bits/mode_t.h b/lib/mlibc/sysdeps/aero/include/abi-bits/mode_t.h new file mode 120000 index 0000000..29d7733 --- /dev/null +++ b/lib/mlibc/sysdeps/aero/include/abi-bits/mode_t.h @@ -0,0 +1 @@ +../../../../abis/mlibc/mode_t.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/aero/include/abi-bits/mqueue.h b/lib/mlibc/sysdeps/aero/include/abi-bits/mqueue.h new file mode 120000 index 0000000..fa87b07 --- /dev/null +++ b/lib/mlibc/sysdeps/aero/include/abi-bits/mqueue.h @@ -0,0 +1 @@ +../../../../abis/linux/mqueue.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/aero/include/abi-bits/msg.h b/lib/mlibc/sysdeps/aero/include/abi-bits/msg.h new file mode 120000 index 0000000..f402b49 --- /dev/null +++ b/lib/mlibc/sysdeps/aero/include/abi-bits/msg.h @@ -0,0 +1 @@ +../../../../abis/linux/msg.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/aero/include/abi-bits/nlink_t.h b/lib/mlibc/sysdeps/aero/include/abi-bits/nlink_t.h new file mode 120000 index 0000000..7618c27 --- /dev/null +++ b/lib/mlibc/sysdeps/aero/include/abi-bits/nlink_t.h @@ -0,0 +1 @@ +../../../../abis/mlibc/nlink_t.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/aero/include/abi-bits/packet.h b/lib/mlibc/sysdeps/aero/include/abi-bits/packet.h new file mode 120000 index 0000000..47067e2 --- /dev/null +++ b/lib/mlibc/sysdeps/aero/include/abi-bits/packet.h @@ -0,0 +1 @@ +../../../../abis/mlibc/packet.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/aero/include/abi-bits/pid_t.h b/lib/mlibc/sysdeps/aero/include/abi-bits/pid_t.h new file mode 120000 index 0000000..3fd26a7 --- /dev/null +++ b/lib/mlibc/sysdeps/aero/include/abi-bits/pid_t.h @@ -0,0 +1 @@ +../../../../abis/mlibc/pid_t.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/aero/include/abi-bits/poll.h b/lib/mlibc/sysdeps/aero/include/abi-bits/poll.h new file mode 120000 index 0000000..ab989c7 --- /dev/null +++ b/lib/mlibc/sysdeps/aero/include/abi-bits/poll.h @@ -0,0 +1 @@ +../../../../abis/mlibc/poll.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/aero/include/abi-bits/ptrace.h b/lib/mlibc/sysdeps/aero/include/abi-bits/ptrace.h new file mode 120000 index 0000000..f391fb7 --- /dev/null +++ b/lib/mlibc/sysdeps/aero/include/abi-bits/ptrace.h @@ -0,0 +1 @@ +../../../../abis/mlibc/ptrace.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/aero/include/abi-bits/reboot.h b/lib/mlibc/sysdeps/aero/include/abi-bits/reboot.h new file mode 120000 index 0000000..77013a4 --- /dev/null +++ b/lib/mlibc/sysdeps/aero/include/abi-bits/reboot.h @@ -0,0 +1 @@ +../../../../abis/linux/reboot.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/aero/include/abi-bits/resource.h b/lib/mlibc/sysdeps/aero/include/abi-bits/resource.h new file mode 120000 index 0000000..3e59c75 --- /dev/null +++ b/lib/mlibc/sysdeps/aero/include/abi-bits/resource.h @@ -0,0 +1 @@ +../../../../abis/mlibc/resource.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/aero/include/abi-bits/seek-whence.h b/lib/mlibc/sysdeps/aero/include/abi-bits/seek-whence.h new file mode 120000 index 0000000..3bd41ef --- /dev/null +++ b/lib/mlibc/sysdeps/aero/include/abi-bits/seek-whence.h @@ -0,0 +1 @@ +../../../../abis/mlibc/seek-whence.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/aero/include/abi-bits/shm.h b/lib/mlibc/sysdeps/aero/include/abi-bits/shm.h new file mode 120000 index 0000000..067d8c4 --- /dev/null +++ b/lib/mlibc/sysdeps/aero/include/abi-bits/shm.h @@ -0,0 +1 @@ +../../../../abis/linux/shm.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/aero/include/abi-bits/signal.h b/lib/mlibc/sysdeps/aero/include/abi-bits/signal.h new file mode 120000 index 0000000..4dcb0b7 --- /dev/null +++ b/lib/mlibc/sysdeps/aero/include/abi-bits/signal.h @@ -0,0 +1 @@ +../../../../abis/linux/signal.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/aero/include/abi-bits/socket.h b/lib/mlibc/sysdeps/aero/include/abi-bits/socket.h new file mode 120000 index 0000000..0e1d6be --- /dev/null +++ b/lib/mlibc/sysdeps/aero/include/abi-bits/socket.h @@ -0,0 +1 @@ +../../../../abis/mlibc/socket.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/aero/include/abi-bits/socklen_t.h b/lib/mlibc/sysdeps/aero/include/abi-bits/socklen_t.h new file mode 120000 index 0000000..41f3b11 --- /dev/null +++ b/lib/mlibc/sysdeps/aero/include/abi-bits/socklen_t.h @@ -0,0 +1 @@ +../../../../abis/linux/socklen_t.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/aero/include/abi-bits/stat.h b/lib/mlibc/sysdeps/aero/include/abi-bits/stat.h new file mode 120000 index 0000000..82642c3 --- /dev/null +++ b/lib/mlibc/sysdeps/aero/include/abi-bits/stat.h @@ -0,0 +1 @@ +../../../../abis/mlibc/stat.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/aero/include/abi-bits/statfs.h b/lib/mlibc/sysdeps/aero/include/abi-bits/statfs.h new file mode 120000 index 0000000..e3d202f --- /dev/null +++ b/lib/mlibc/sysdeps/aero/include/abi-bits/statfs.h @@ -0,0 +1 @@ +../../../../abis/linux/statfs.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/aero/include/abi-bits/statvfs.h b/lib/mlibc/sysdeps/aero/include/abi-bits/statvfs.h new file mode 120000 index 0000000..1fc80c2 --- /dev/null +++ b/lib/mlibc/sysdeps/aero/include/abi-bits/statvfs.h @@ -0,0 +1 @@ +../../../../abis/linux/statvfs.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/aero/include/abi-bits/suseconds_t.h b/lib/mlibc/sysdeps/aero/include/abi-bits/suseconds_t.h new file mode 120000 index 0000000..9ed6597 --- /dev/null +++ b/lib/mlibc/sysdeps/aero/include/abi-bits/suseconds_t.h @@ -0,0 +1 @@ +../../../../abis/linux/suseconds_t.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/aero/include/abi-bits/termios.h b/lib/mlibc/sysdeps/aero/include/abi-bits/termios.h new file mode 120000 index 0000000..ee8f0b0 --- /dev/null +++ b/lib/mlibc/sysdeps/aero/include/abi-bits/termios.h @@ -0,0 +1 @@ +../../../../abis/linux/termios.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/aero/include/abi-bits/time.h b/lib/mlibc/sysdeps/aero/include/abi-bits/time.h new file mode 120000 index 0000000..97f3d52 --- /dev/null +++ b/lib/mlibc/sysdeps/aero/include/abi-bits/time.h @@ -0,0 +1 @@ +../../../../abis/mlibc/time.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/aero/include/abi-bits/uid_t.h b/lib/mlibc/sysdeps/aero/include/abi-bits/uid_t.h new file mode 120000 index 0000000..1113eba --- /dev/null +++ b/lib/mlibc/sysdeps/aero/include/abi-bits/uid_t.h @@ -0,0 +1 @@ +../../../../abis/mlibc/uid_t.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/aero/include/abi-bits/utsname.h b/lib/mlibc/sysdeps/aero/include/abi-bits/utsname.h new file mode 120000 index 0000000..b285754 --- /dev/null +++ b/lib/mlibc/sysdeps/aero/include/abi-bits/utsname.h @@ -0,0 +1 @@ +../../../../abis/linux/utsname.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/aero/include/abi-bits/vm-flags.h b/lib/mlibc/sysdeps/aero/include/abi-bits/vm-flags.h new file mode 120000 index 0000000..f1a985e --- /dev/null +++ b/lib/mlibc/sysdeps/aero/include/abi-bits/vm-flags.h @@ -0,0 +1 @@ +../../../../abis/mlibc/vm-flags.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/aero/include/abi-bits/wait.h b/lib/mlibc/sysdeps/aero/include/abi-bits/wait.h new file mode 120000 index 0000000..feb2840 --- /dev/null +++ b/lib/mlibc/sysdeps/aero/include/abi-bits/wait.h @@ -0,0 +1 @@ +../../../../abis/linux/wait.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/aero/include/abi-bits/xattr.h b/lib/mlibc/sysdeps/aero/include/abi-bits/xattr.h new file mode 120000 index 0000000..66412d7 --- /dev/null +++ b/lib/mlibc/sysdeps/aero/include/abi-bits/xattr.h @@ -0,0 +1 @@ +../../../../abis/linux/xattr.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/aero/include/aero/syscall.h b/lib/mlibc/sysdeps/aero/include/aero/syscall.h new file mode 100644 index 0000000..3f36e4d --- /dev/null +++ b/lib/mlibc/sysdeps/aero/include/aero/syscall.h @@ -0,0 +1,231 @@ +#ifndef SYSCALL_H +#define SYSCALL_H + +#include +#include + +#define SYS_READ 0 +#define SYS_WRITE 1 +#define SYS_OPEN 2 +#define SYS_CLOSE 3 +#define SYS_SHUTDOWN 4 +#define SYS_EXIT 5 +#define SYS_FORK 6 +#define SYS_REBOOT 7 +#define SYS_MMAP 8 +#define SYS_MUNMAP 9 +#define SYS_ARCH_PRCTL 10 +#define SYS_GETDENTS 11 +#define SYS_GETCWD 12 +#define SYS_CHDIR 13 +#define SYS_MKDIR 14 +#define SYS_MKDIR_AT 15 +#define SYS_RMDIR 16 +#define SYS_EXEC 17 +#define SYS_LOG 18 +#define SYS_UNAME 19 +#define SYS_WAITPID 20 +#define SYS_IOCTL 21 +#define SYS_GETPID 22 +#define SYS_SOCKET 23 +#define SYS_CONNECT 24 +#define SYS_BIND 25 +#define SYS_LISTEN 26 +#define SYS_ACCEPT 27 +#define SYS_SEEK 28 +#define SYS_GETTID 29 +#define SYS_GETTIME 30 +#define SYS_SLEEP 31 +#define SYS_ACCESS 32 +#define SYS_PIPE 33 +#define SYS_UNLINK 34 +#define SYS_GETHOSTNAME 35 +#define SYS_SETHOSTNAME 36 +#define SYS_INFO 37 +#define SYS_CLONE 38 +#define SYS_SIGRETURN 39 +#define SYS_SIGACTION 40 +#define SYS_SIGPROCMASK 41 +#define SYS_DUP 42 +#define SYS_FCNTL 43 +#define SYS_DUP2 44 +#define SYS_IPC_SEND 45 +#define SYS_IPC_RECV 46 +#define SYS_DISCOVER_ROOT 47 +#define SYS_BECOME_ROOT 48 +#define SYS_STAT 49 +#define SYS_FSTAT 50 +#define SYS_READ_LINK 51 +#define SYS_EPOLL_CREATE 52 +#define SYS_EPOLL_PWAIT 53 +#define SYS_EPOLL_CTL 54 +#define SYS_EVENT_FD 55 +#define SYS_KILL 56 +#define SYS_FUTEX_WAIT 57 +#define SYS_FUTEX_WAKE 58 +#define SYS_LINK 59 +#define SYS_BACKTRACE 60 +#define SYS_POLL 61 +#define SYS_EXIT_THREAD 62 +#define SYS_SOCK_RECV 63 +#define SYS_SETITIMER 64 +#define SYS_GETITIMER 65 +#define SYS_GETPPID 66 +#define SYS_SOCKET_PAIR 67 +#define SYS_RENAME 68 +#define SYS_MPROTECT 69 +#define SYS_SOCK_SEND 70 +#define SYS_TRACE 71 +#define SYS_SETPGID 72 +#define SYS_SETSID 73 +#define SYS_GETPGID 74 +#define SYS_SOCK_SHUTDOWN 75 + +// Invalid syscall used to trigger a log error in the kernel (as a hint) +// so, that we can implement the syscall in the kernel. +#define UNIMPLEMENTED(FUNCTION_NAME) \ + { \ + sys_libc_log("Unimplemented syscall: " FUNCTION_NAME); \ + sys_exit(1); \ + __builtin_unreachable(); \ + } + +extern "C" { +using sc_word_t = long; + +static sc_word_t syscall0(int sc) { + sc_word_t ret; + asm volatile("syscall" : "=a"(ret) : "a"(sc) : "rcx", "r11", "memory"); + return ret; +} + +static sc_word_t syscall1(int sc, sc_word_t arg1) { + sc_word_t ret; + asm volatile("syscall" + : "=a"(ret) + : "a"(sc), "D"(arg1) + : "rcx", "r11", "memory"); + return ret; +} + +static sc_word_t syscall2(int sc, sc_word_t arg1, sc_word_t arg2) { + sc_word_t ret; + asm volatile("syscall" + : "=a"(ret) + : "a"(sc), "D"(arg1), "S"(arg2) + : "rcx", "r11", "memory"); + return ret; +} + +static sc_word_t syscall3(int sc, sc_word_t arg1, sc_word_t arg2, + sc_word_t arg3) { + sc_word_t ret; + asm volatile("syscall" + : "=a"(ret) + : "a"(sc), "D"(arg1), "S"(arg2), "d"(arg3) + : "rcx", "r11", "memory"); + return ret; +} + +static sc_word_t syscall4(int sc, sc_word_t arg1, sc_word_t arg2, + sc_word_t arg3, sc_word_t arg4) { + sc_word_t ret; + + register sc_word_t arg4_reg asm("r10") = arg4; + + asm volatile("syscall" + : "=a"(ret) + : "a"(sc), "D"(arg1), "S"(arg2), "d"(arg3), "r"(arg4_reg) + : "rcx", "r11", "memory"); + return ret; +} + +static sc_word_t syscall5(int sc, sc_word_t arg1, sc_word_t arg2, + sc_word_t arg3, sc_word_t arg4, sc_word_t arg5) { + sc_word_t ret; + + register sc_word_t arg4_reg asm("r10") = arg4; + register sc_word_t arg5_reg asm("r8") = arg5; + + asm volatile("syscall" + : "=a"(ret) + : "a"(sc), "D"(arg1), "S"(arg2), "d"(arg3), "r"(arg4_reg), + "r"(arg5_reg) + : "rcx", "r11", "memory"); + return ret; +} + +static sc_word_t syscall6(int sc, sc_word_t arg1, sc_word_t arg2, + sc_word_t arg3, sc_word_t arg4, sc_word_t arg5, + sc_word_t arg6) { + sc_word_t ret; + + register sc_word_t arg4_reg asm("r10") = arg4; + register sc_word_t arg5_reg asm("r8") = arg5; + register sc_word_t arg6_reg asm("r9") = arg6; + + asm volatile("syscall" + : "=a"(ret) + : "a"(sc), "D"(arg1), "S"(arg2), "d"(arg3), "r"(arg4_reg), + "r"(arg5_reg), "r"(arg6_reg) + : "rcx", "r11", "memory"); + return ret; +} +} // extern "C" + +// Cast to the argument type of the extern "C" functions. +__attribute__((__always_inline__)) inline sc_word_t sc_cast(long x) { return x; } +__attribute__((__always_inline__)) inline sc_word_t sc_cast(const void *x) { + return reinterpret_cast(x); +} + +// C++ wrappers for the extern "C" functions. +__attribute__((__always_inline__)) static inline long _syscall(int call) { + return syscall0(call); +} + +__attribute__((__always_inline__)) static inline long _syscall(int call, + sc_word_t arg0) { + return syscall1(call, arg0); +} + +__attribute__((__always_inline__)) static inline long +_syscall(int call, sc_word_t arg0, sc_word_t arg1) { + return syscall2(call, arg0, arg1); +} + +__attribute__((__always_inline__)) static inline long +_syscall(int call, sc_word_t arg0, sc_word_t arg1, sc_word_t arg2) { + return syscall3(call, arg0, arg1, arg2); +} + +__attribute__((__always_inline__)) static inline long +_syscall(int call, sc_word_t arg0, sc_word_t arg1, sc_word_t arg2, + sc_word_t arg3) { + return syscall4(call, arg0, arg1, arg2, arg3); +} + +__attribute__((__always_inline__)) static inline long +_syscall(int call, sc_word_t arg0, sc_word_t arg1, sc_word_t arg2, + sc_word_t arg3, sc_word_t arg4) { + return syscall5(call, arg0, arg1, arg2, arg3, arg4); +} + +__attribute__((__always_inline__)) static inline long +_syscall(int call, sc_word_t arg0, sc_word_t arg1, sc_word_t arg2, + sc_word_t arg3, sc_word_t arg4, sc_word_t arg5) { + return syscall6(call, arg0, arg1, arg2, arg3, arg4, arg5); +} + +template +__attribute__((__always_inline__)) static inline long syscall(sc_word_t call, + T... args) { + return _syscall(call, sc_cast(args)...); +} + +inline int sc_error(long ret) { + if (ret < 0) + return -ret; + return 0; +} +#endif // SYSCALL_H diff --git a/lib/mlibc/sysdeps/aero/include/mlibc/thread-entry.hpp b/lib/mlibc/sysdeps/aero/include/mlibc/thread-entry.hpp new file mode 100644 index 0000000..a241479 --- /dev/null +++ b/lib/mlibc/sysdeps/aero/include/mlibc/thread-entry.hpp @@ -0,0 +1,11 @@ +#pragma once + +#include + +extern "C" void __mlibc_start_thread(void); +extern "C" void __mlibc_enter_thread(void *entry, void *user_arg, Tcb *tcb); + +namespace mlibc { +int prepare_stack(void **stack, void *entry, void *user_arg, void *tcb, size_t *stack_size, + size_t *guard_size); +} // namespace mlibc diff --git a/lib/mlibc/sysdeps/aero/meson.build b/lib/mlibc/sysdeps/aero/meson.build new file mode 100644 index 0000000..20cf6cf --- /dev/null +++ b/lib/mlibc/sysdeps/aero/meson.build @@ -0,0 +1,85 @@ +rtdl_dso_sources += files( + 'generic/aero.cpp', + 'generic/filesystem.cpp', +) + +libc_sources += files( + 'generic/aero.cpp', + 'generic/entry.cpp', + 'generic/thread_entry.S', + 'generic/thread.cpp', + 'generic/filesystem.cpp', + 'generic/sockets.cpp', + 'generic/signals.cpp', + 'generic/time.cpp', +) + +if not no_headers + install_headers( + 'include/abi-bits/auxv.h', + 'include/abi-bits/seek-whence.h', + 'include/abi-bits/vm-flags.h', + 'include/abi-bits/errno.h', + 'include/abi-bits/fcntl.h', + 'include/abi-bits/in.h', + 'include/abi-bits/resource.h', + 'include/abi-bits/signal.h', + 'include/abi-bits/stat.h', + 'include/abi-bits/socket.h', + 'include/abi-bits/termios.h', + 'include/abi-bits/time.h', + 'include/abi-bits/blkcnt_t.h', + 'include/abi-bits/blksize_t.h', + 'include/abi-bits/dev_t.h', + 'include/abi-bits/gid_t.h', + 'include/abi-bits/ino_t.h', + 'include/abi-bits/mode_t.h', + 'include/abi-bits/nlink_t.h', + 'include/abi-bits/pid_t.h', + 'include/abi-bits/uid_t.h', + 'include/abi-bits/access.h', + 'include/abi-bits/wait.h', + 'include/abi-bits/limits.h', + 'include/abi-bits/utsname.h', + 'include/abi-bits/ptrace.h', + 'include/abi-bits/poll.h', + 'include/abi-bits/epoll.h', + 'include/abi-bits/packet.h', + 'include/abi-bits/inotify.h', + 'include/abi-bits/clockid_t.h', + 'include/abi-bits/shm.h', + 'include/abi-bits/mqueue.h', + 'include/abi-bits/suseconds_t.h', + 'include/abi-bits/fsfilcnt_t.h', + 'include/abi-bits/fsblkcnt_t.h', + 'include/abi-bits/socklen_t.h', + 'include/abi-bits/statfs.h', + 'include/abi-bits/statvfs.h', + 'include/abi-bits/ioctls.h', + 'include/abi-bits/xattr.h', + 'include/abi-bits/msg.h', + subdir: 'abi-bits', + follow_symlinks: true + ) + install_headers( + 'include/aero/syscall.h', + subdir: 'aero' + ) +endif + +if not headers_only + crt = custom_target('crt0', + build_by_default: true, + command: c_compiler.cmd_array() + ['-c', '-o', '@OUTPUT@', '@INPUT@'], + input: 'crt-x86_64/crt0.S', + output: 'crt0.o', + install: true, + install_dir: get_option('libdir') + ) +endif + +if host_machine.cpu_family() == 'x86_64' + libc_sources += files('generic/signals.S') +else + error('Unknown architecture') +endif diff --git a/lib/mlibc/sysdeps/dripos/crt-x86_64/crt1.S b/lib/mlibc/sysdeps/dripos/crt-x86_64/crt1.S new file mode 100644 index 0000000..18d109e --- /dev/null +++ b/lib/mlibc/sysdeps/dripos/crt-x86_64/crt1.S @@ -0,0 +1,9 @@ + +.section .text +.global _start +_start: + mov $main, %rdi + call __mlibc_entry + +.section .note.GNU-stack,"",%progbits + diff --git a/lib/mlibc/sysdeps/dripos/generic/entry.cpp b/lib/mlibc/sysdeps/dripos/generic/entry.cpp new file mode 100644 index 0000000..2b8b914 --- /dev/null +++ b/lib/mlibc/sysdeps/dripos/generic/entry.cpp @@ -0,0 +1,35 @@ + +#include +#include +#include +#include + +// defined by the POSIX library +void __mlibc_initLocale(); + +extern "C" uintptr_t *__dlapi_entrystack(); + +extern char **environ; +static mlibc::exec_stack_data __mlibc_stack_data; + +struct LibraryGuard { + LibraryGuard(); +}; + +static LibraryGuard guard; + +LibraryGuard::LibraryGuard() { + __mlibc_initLocale(); + + // Parse the exec() stack. + mlibc::parse_exec_stack(__dlapi_entrystack(), &__mlibc_stack_data); + mlibc::set_startup_data(__mlibc_stack_data.argc, __mlibc_stack_data.argv, + __mlibc_stack_data.envp); +} + +extern "C" void __mlibc_entry(int (*main_fn)(int argc, char *argv[], char *env[])) { + // TODO: call __dlapi_enter, otherwise static builds will break (see Linux sysdeps) + auto result = main_fn(__mlibc_stack_data.argc, __mlibc_stack_data.argv, environ); + exit(result); +} + diff --git a/lib/mlibc/sysdeps/dripos/generic/generic.cpp b/lib/mlibc/sysdeps/dripos/generic/generic.cpp new file mode 100644 index 0000000..89203c3 --- /dev/null +++ b/lib/mlibc/sysdeps/dripos/generic/generic.cpp @@ -0,0 +1,298 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +namespace mlibc { + +void sys_libc_log(const char *message) { + unsigned long res; + asm volatile ("syscall" : "=a"(res) + : "a"(50), "D"(message) + : "rcx", "r11", "rdx"); +} + +void sys_libc_panic() { + mlibc::infoLogger() << "\e[31mmlibc: panic!" << frg::endlog; + asm volatile ("syscall" : + : "a"(12), "D"(1) + : "rcx", "r11", "rdx"); +} + +int sys_tcb_set(void *pointer) { + int res; + asm volatile ("syscall" : "=a"(res) + : "a"(300), "D"(pointer) + : "rcx", "r11", "rdx"); + return res; +} + +int sys_anon_allocate(size_t size, void **pointer) { + void *ret; + int sys_errno; + + asm volatile ("syscall" + : "=a"(ret), "=d"(sys_errno) + : "a"(9), "D"(0), "S"(size) + : "rcx", "r11"); + + if (!ret) + return sys_errno; + + *pointer = ret; + return 0; +} + +int sys_anon_free(void *pointer, size_t size) { + int unused_return; + int sys_errno; + + asm volatile ("syscall" + : "=a"(unused_return), "=d"(sys_errno) + : "a"(11), "D"(pointer), "S"(size) + : "rcx", "r11"); + + if (unused_return) + return sys_errno; + + return 0; +} + +#ifndef MLIBC_BUILDING_RTDL +void sys_exit(int status) { + asm volatile ("syscall" : + : "a"(12), "D"(status) + : "rcx", "r11", "rdx"); +} +#endif + +#ifndef MLIBC_BUILDING_RTDL +int sys_clock_get(int clock, time_t *secs, long *nanos) { + return 0; +} +#endif + +int sys_open(const char *path, int flags, mode_t mode, int *fd) { + int ret; + int sys_errno; + + asm volatile ("syscall" + : "=a"(ret), "=d"(sys_errno) + : "a"(2), "D"(path), "S"(flags), "d"(0) + : "rcx", "r11"); + + if (ret == -1) + return sys_errno; + + *fd = ret; + return 0; +} + +int sys_close(int fd) { + int ret; + int sys_errno; + + asm volatile ("syscall" + : "=a"(ret), "=d"(sys_errno) + : "a"(3), "D"(fd) + : "rcx", "r11"); + + if (ret == -1) + return sys_errno; + + return 0; +} + +int sys_read(int fd, void *buf, size_t count, ssize_t *bytes_read) { + ssize_t ret; + int sys_errno; + + asm volatile ("syscall" + : "=a"(ret), "=d"(sys_errno) + : "a"(0), "D"(fd), "S"(buf), "d"(count) + : "rcx", "r11"); + + if (ret == -1) + return sys_errno; + + *bytes_read = ret; + return 0; +} + +#ifndef MLIBC_BUILDING_RTDL +int sys_write(int fd, const void *buf, size_t count, ssize_t *bytes_written) { + ssize_t ret; + int sys_errno; + + asm volatile ("syscall" + : "=a"(ret), "=d"(sys_errno) + : "a"(1), "D"(fd), "S"(buf), "d"(count) + : "rcx", "r11"); + + if (ret == -1) + return sys_errno; + + *bytes_written = ret; + return 0; +} +#endif + + +int sys_seek(int fd, off_t offset, int whence, off_t *new_offset) { + off_t ret; + int sys_errno; + + asm volatile ("syscall" + : "=a"(ret), "=d"(sys_errno) + : "a"(8), "D"(fd), "S"(offset), "d"(whence) + : "rcx", "r11"); + + if (ret == -1) + return sys_errno; + + *new_offset = ret; + return 0; +} + +int sys_vm_map(void *hint, size_t size, int prot, int flags, + int fd, off_t offset, void **window) { + __ensure(flags & MAP_ANONYMOUS); + void *ret; + int sys_errno; + + // mlibc::infoLogger() << "calling sys_vm_map with size: " << size << frg::endlog; + + asm volatile ("syscall" + : "=a"(ret), "=d"(sys_errno) + : "a"(9), "D"(hint), "S"(size) + : "rcx", "r11"); + + if (!ret) + return sys_errno; + + *window = ret; + + return 0; +} + +int sys_vm_unmap(void *pointer, size_t size) { + return sys_anon_free(pointer, size); +} + +int sys_futex_wait(int *pointer, int expected, const struct timespec *time) { + uint64_t err; + asm volatile ("syscall" + : "=d"(err) + : "a"(66), "D"(pointer), "S"(expected) + : "rcx", "r11"); + + if (err) { + return -1; + } + + return 0; +} + +int sys_futex_wake(int *pointer) { + uint64_t err; + asm volatile ("syscall" + : "=d"(err) + : "a"(65), "D"(pointer) + : "rcx", "r11"); + + if (err) { + return -1; + } + + return 0; +} + +// All remaining functions are disabled in ldso. +#ifndef MLIBC_BUILDING_RTDL + +int sys_clone(void *tcb, pid_t *tid_out, void *stack) { + int tid; + + asm volatile ("syscall" + : "=a"(tid) + : "a"(67), "D"(__mlibc_start_thread), "S"(stack), "d"(tcb) + : "rcx", "r11"); + + if (tid_out) + *tid_out = tid; + + return 0; +} + +void sys_thread_exit() { + asm volatile ("syscall" + : + : "a"(68) + : "rcx", "r11"); + __builtin_trap(); +} + +int sys_sleep(time_t *secs, long *nanos) { + long ms = (*nanos / 1000000) + (*secs * 1000); + asm volatile ("syscall" + : + : "a"(6), "D"(ms) + : "rcx", "r11"); + *secs = 0; + *nanos = 0; + return 0; +} + +int sys_fork(pid_t *child) { + pid_t ret; + int sys_errno; + + asm volatile ("syscall" + : "=a"(ret), "=d"(sys_errno) + : "a"(57) + : "rcx", "r11"); + + if (ret == -1) + return sys_errno; + + *child = ret; + return 0; +} + +int sys_execve(const char *path, char *const argv[], char *const envp[]) { + int ret; + int sys_errno; + + asm volatile ("syscall" + : "=a"(ret), "=d"(sys_errno) + : "a"(59), "D"(path), "S"(argv), "d"(envp) + : "rcx", "r11"); + + if (sys_errno != 0) + return sys_errno; + + return 0; +} + +pid_t sys_getpid() { + pid_t pid; + asm volatile ("syscall" : "=a"(pid) + : "a"(5) + : "rcx", "r11", "rdx"); + return pid; +} +pid_t sys_getppid() { + pid_t ppid; + asm volatile ("syscall" : "=a"(ppid) + : "a"(14) + : "rcx", "r11", "rdx"); + return ppid; +} + +#endif // MLIBC_BUILDING_RTDL + +} // namespace mlibc diff --git a/lib/mlibc/sysdeps/dripos/generic/thread.cpp b/lib/mlibc/sysdeps/dripos/generic/thread.cpp new file mode 100644 index 0000000..42cd758 --- /dev/null +++ b/lib/mlibc/sysdeps/dripos/generic/thread.cpp @@ -0,0 +1,53 @@ +#include +#include +#include +#include +#include +#include +#include + +extern "C" void __mlibc_enter_thread(void *entry, void *user_arg, Tcb *tcb) { + // Wait until our parent sets up the TID. + while(!__atomic_load_n(&tcb->tid, __ATOMIC_RELAXED)) + mlibc::sys_futex_wait(&tcb->tid, 0, nullptr); + + if(mlibc::sys_tcb_set(tcb)) + __ensure(!"sys_tcb_set() failed"); + + tcb->invokeThreadFunc(entry, user_arg); + + auto self = reinterpret_cast(tcb); + + __atomic_store_n(&self->didExit, 1, __ATOMIC_RELEASE); + mlibc::sys_futex_wake(&self->didExit); + + mlibc::sys_thread_exit(); +} + +namespace mlibc { + +static constexpr size_t default_stacksize = 0x200000; + +int sys_prepare_stack(void **stack, void *entry, void *user_arg, void *tcb, size_t *stack_size, size_t *guard_size, void **stack_base) { + if (!*stack_size) + *stack_size = default_stacksize; + *guard_size = 0; + + if (*stack) { + *stack_base = *stack; + } else { + *stack_base = mmap(nullptr, *stack_size, + PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + } + + uintptr_t *sp = reinterpret_cast(reinterpret_cast(*stack_base) + *stack_size); + + *--sp = reinterpret_cast(tcb); + *--sp = reinterpret_cast(user_arg); + *--sp = reinterpret_cast(entry); + *stack = reinterpret_cast(sp); + return 0; +} + +} //namespace mlibc diff --git a/lib/mlibc/sysdeps/dripos/generic/thread_entry.S b/lib/mlibc/sysdeps/dripos/generic/thread_entry.S new file mode 100644 index 0000000..51e703b --- /dev/null +++ b/lib/mlibc/sysdeps/dripos/generic/thread_entry.S @@ -0,0 +1,11 @@ + +.section .text +.global __mlibc_start_thread +__mlibc_start_thread: + pop %rdi + pop %rsi + pop %rdx + call __mlibc_enter_thread + +.section .note.GNU-stack,"",%progbits + diff --git a/lib/mlibc/sysdeps/dripos/include/abi-bits/access.h b/lib/mlibc/sysdeps/dripos/include/abi-bits/access.h new file mode 120000 index 0000000..171f75f --- /dev/null +++ b/lib/mlibc/sysdeps/dripos/include/abi-bits/access.h @@ -0,0 +1 @@ +../../../../abis/mlibc/access.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/dripos/include/abi-bits/auxv.h b/lib/mlibc/sysdeps/dripos/include/abi-bits/auxv.h new file mode 120000 index 0000000..866c8bb --- /dev/null +++ b/lib/mlibc/sysdeps/dripos/include/abi-bits/auxv.h @@ -0,0 +1 @@ +../../../../abis/dripos/auxv.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/dripos/include/abi-bits/blkcnt_t.h b/lib/mlibc/sysdeps/dripos/include/abi-bits/blkcnt_t.h new file mode 120000 index 0000000..e9d9f1b --- /dev/null +++ b/lib/mlibc/sysdeps/dripos/include/abi-bits/blkcnt_t.h @@ -0,0 +1 @@ +../../../../abis/mlibc/blkcnt_t.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/dripos/include/abi-bits/blksize_t.h b/lib/mlibc/sysdeps/dripos/include/abi-bits/blksize_t.h new file mode 120000 index 0000000..c6dfb6e --- /dev/null +++ b/lib/mlibc/sysdeps/dripos/include/abi-bits/blksize_t.h @@ -0,0 +1 @@ +../../../../abis/mlibc/blksize_t.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/dripos/include/abi-bits/clockid_t.h b/lib/mlibc/sysdeps/dripos/include/abi-bits/clockid_t.h new file mode 120000 index 0000000..71f37bb --- /dev/null +++ b/lib/mlibc/sysdeps/dripos/include/abi-bits/clockid_t.h @@ -0,0 +1 @@ +../../../../abis/mlibc/clockid_t.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/dripos/include/abi-bits/dev_t.h b/lib/mlibc/sysdeps/dripos/include/abi-bits/dev_t.h new file mode 120000 index 0000000..0c1143b --- /dev/null +++ b/lib/mlibc/sysdeps/dripos/include/abi-bits/dev_t.h @@ -0,0 +1 @@ +../../../../abis/mlibc/dev_t.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/dripos/include/abi-bits/epoll.h b/lib/mlibc/sysdeps/dripos/include/abi-bits/epoll.h new file mode 120000 index 0000000..9efc3a0 --- /dev/null +++ b/lib/mlibc/sysdeps/dripos/include/abi-bits/epoll.h @@ -0,0 +1 @@ +../../../../abis/mlibc/epoll.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/dripos/include/abi-bits/errno.h b/lib/mlibc/sysdeps/dripos/include/abi-bits/errno.h new file mode 120000 index 0000000..2a2ab26 --- /dev/null +++ b/lib/mlibc/sysdeps/dripos/include/abi-bits/errno.h @@ -0,0 +1 @@ +../../../../abis/dripos/errno.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/dripos/include/abi-bits/fcntl.h b/lib/mlibc/sysdeps/dripos/include/abi-bits/fcntl.h new file mode 120000 index 0000000..ea5323a --- /dev/null +++ b/lib/mlibc/sysdeps/dripos/include/abi-bits/fcntl.h @@ -0,0 +1 @@ +../../../../abis/mlibc/fcntl.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/dripos/include/abi-bits/fsblkcnt_t.h b/lib/mlibc/sysdeps/dripos/include/abi-bits/fsblkcnt_t.h new file mode 120000 index 0000000..898dfb2 --- /dev/null +++ b/lib/mlibc/sysdeps/dripos/include/abi-bits/fsblkcnt_t.h @@ -0,0 +1 @@ +../../../../abis/linux/fsblkcnt_t.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/dripos/include/abi-bits/fsfilcnt_t.h b/lib/mlibc/sysdeps/dripos/include/abi-bits/fsfilcnt_t.h new file mode 120000 index 0000000..791755c --- /dev/null +++ b/lib/mlibc/sysdeps/dripos/include/abi-bits/fsfilcnt_t.h @@ -0,0 +1 @@ +../../../../abis/linux/fsfilcnt_t.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/dripos/include/abi-bits/gid_t.h b/lib/mlibc/sysdeps/dripos/include/abi-bits/gid_t.h new file mode 120000 index 0000000..6a77218 --- /dev/null +++ b/lib/mlibc/sysdeps/dripos/include/abi-bits/gid_t.h @@ -0,0 +1 @@ +../../../../abis/mlibc/gid_t.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/dripos/include/abi-bits/in.h b/lib/mlibc/sysdeps/dripos/include/abi-bits/in.h new file mode 120000 index 0000000..b58c683 --- /dev/null +++ b/lib/mlibc/sysdeps/dripos/include/abi-bits/in.h @@ -0,0 +1 @@ +../../../../abis/mlibc/in.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/dripos/include/abi-bits/ino_t.h b/lib/mlibc/sysdeps/dripos/include/abi-bits/ino_t.h new file mode 120000 index 0000000..10d644e --- /dev/null +++ b/lib/mlibc/sysdeps/dripos/include/abi-bits/ino_t.h @@ -0,0 +1 @@ +../../../../abis/mlibc/ino_t.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/dripos/include/abi-bits/inotify.h b/lib/mlibc/sysdeps/dripos/include/abi-bits/inotify.h new file mode 120000 index 0000000..3f19ef6 --- /dev/null +++ b/lib/mlibc/sysdeps/dripos/include/abi-bits/inotify.h @@ -0,0 +1 @@ +../../../../abis/mlibc/inotify.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/dripos/include/abi-bits/ioctls.h b/lib/mlibc/sysdeps/dripos/include/abi-bits/ioctls.h new file mode 120000 index 0000000..595106b --- /dev/null +++ b/lib/mlibc/sysdeps/dripos/include/abi-bits/ioctls.h @@ -0,0 +1 @@ +../../../../abis/linux/ioctls.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/dripos/include/abi-bits/limits.h b/lib/mlibc/sysdeps/dripos/include/abi-bits/limits.h new file mode 120000 index 0000000..1aa5894 --- /dev/null +++ b/lib/mlibc/sysdeps/dripos/include/abi-bits/limits.h @@ -0,0 +1 @@ +../../../../abis/mlibc/limits.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/dripos/include/abi-bits/mode_t.h b/lib/mlibc/sysdeps/dripos/include/abi-bits/mode_t.h new file mode 120000 index 0000000..29d7733 --- /dev/null +++ b/lib/mlibc/sysdeps/dripos/include/abi-bits/mode_t.h @@ -0,0 +1 @@ +../../../../abis/mlibc/mode_t.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/dripos/include/abi-bits/mqueue.h b/lib/mlibc/sysdeps/dripos/include/abi-bits/mqueue.h new file mode 120000 index 0000000..fa87b07 --- /dev/null +++ b/lib/mlibc/sysdeps/dripos/include/abi-bits/mqueue.h @@ -0,0 +1 @@ +../../../../abis/linux/mqueue.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/dripos/include/abi-bits/msg.h b/lib/mlibc/sysdeps/dripos/include/abi-bits/msg.h new file mode 120000 index 0000000..f402b49 --- /dev/null +++ b/lib/mlibc/sysdeps/dripos/include/abi-bits/msg.h @@ -0,0 +1 @@ +../../../../abis/linux/msg.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/dripos/include/abi-bits/nlink_t.h b/lib/mlibc/sysdeps/dripos/include/abi-bits/nlink_t.h new file mode 120000 index 0000000..7618c27 --- /dev/null +++ b/lib/mlibc/sysdeps/dripos/include/abi-bits/nlink_t.h @@ -0,0 +1 @@ +../../../../abis/mlibc/nlink_t.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/dripos/include/abi-bits/packet.h b/lib/mlibc/sysdeps/dripos/include/abi-bits/packet.h new file mode 120000 index 0000000..47067e2 --- /dev/null +++ b/lib/mlibc/sysdeps/dripos/include/abi-bits/packet.h @@ -0,0 +1 @@ +../../../../abis/mlibc/packet.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/dripos/include/abi-bits/pid_t.h b/lib/mlibc/sysdeps/dripos/include/abi-bits/pid_t.h new file mode 120000 index 0000000..3fd26a7 --- /dev/null +++ b/lib/mlibc/sysdeps/dripos/include/abi-bits/pid_t.h @@ -0,0 +1 @@ +../../../../abis/mlibc/pid_t.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/dripos/include/abi-bits/poll.h b/lib/mlibc/sysdeps/dripos/include/abi-bits/poll.h new file mode 120000 index 0000000..ab989c7 --- /dev/null +++ b/lib/mlibc/sysdeps/dripos/include/abi-bits/poll.h @@ -0,0 +1 @@ +../../../../abis/mlibc/poll.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/dripos/include/abi-bits/ptrace.h b/lib/mlibc/sysdeps/dripos/include/abi-bits/ptrace.h new file mode 120000 index 0000000..f391fb7 --- /dev/null +++ b/lib/mlibc/sysdeps/dripos/include/abi-bits/ptrace.h @@ -0,0 +1 @@ +../../../../abis/mlibc/ptrace.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/dripos/include/abi-bits/resource.h b/lib/mlibc/sysdeps/dripos/include/abi-bits/resource.h new file mode 120000 index 0000000..3e59c75 --- /dev/null +++ b/lib/mlibc/sysdeps/dripos/include/abi-bits/resource.h @@ -0,0 +1 @@ +../../../../abis/mlibc/resource.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/dripos/include/abi-bits/seek-whence.h b/lib/mlibc/sysdeps/dripos/include/abi-bits/seek-whence.h new file mode 120000 index 0000000..3bd41ef --- /dev/null +++ b/lib/mlibc/sysdeps/dripos/include/abi-bits/seek-whence.h @@ -0,0 +1 @@ +../../../../abis/mlibc/seek-whence.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/dripos/include/abi-bits/shm.h b/lib/mlibc/sysdeps/dripos/include/abi-bits/shm.h new file mode 120000 index 0000000..067d8c4 --- /dev/null +++ b/lib/mlibc/sysdeps/dripos/include/abi-bits/shm.h @@ -0,0 +1 @@ +../../../../abis/linux/shm.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/dripos/include/abi-bits/signal.h b/lib/mlibc/sysdeps/dripos/include/abi-bits/signal.h new file mode 120000 index 0000000..b20e511 --- /dev/null +++ b/lib/mlibc/sysdeps/dripos/include/abi-bits/signal.h @@ -0,0 +1 @@ +../../../../abis/mlibc/signal.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/dripos/include/abi-bits/socket.h b/lib/mlibc/sysdeps/dripos/include/abi-bits/socket.h new file mode 120000 index 0000000..0e1d6be --- /dev/null +++ b/lib/mlibc/sysdeps/dripos/include/abi-bits/socket.h @@ -0,0 +1 @@ +../../../../abis/mlibc/socket.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/dripos/include/abi-bits/socklen_t.h b/lib/mlibc/sysdeps/dripos/include/abi-bits/socklen_t.h new file mode 120000 index 0000000..41f3b11 --- /dev/null +++ b/lib/mlibc/sysdeps/dripos/include/abi-bits/socklen_t.h @@ -0,0 +1 @@ +../../../../abis/linux/socklen_t.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/dripos/include/abi-bits/stat.h b/lib/mlibc/sysdeps/dripos/include/abi-bits/stat.h new file mode 120000 index 0000000..82642c3 --- /dev/null +++ b/lib/mlibc/sysdeps/dripos/include/abi-bits/stat.h @@ -0,0 +1 @@ +../../../../abis/mlibc/stat.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/dripos/include/abi-bits/statfs.h b/lib/mlibc/sysdeps/dripos/include/abi-bits/statfs.h new file mode 120000 index 0000000..e3d202f --- /dev/null +++ b/lib/mlibc/sysdeps/dripos/include/abi-bits/statfs.h @@ -0,0 +1 @@ +../../../../abis/linux/statfs.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/dripos/include/abi-bits/statvfs.h b/lib/mlibc/sysdeps/dripos/include/abi-bits/statvfs.h new file mode 120000 index 0000000..1fc80c2 --- /dev/null +++ b/lib/mlibc/sysdeps/dripos/include/abi-bits/statvfs.h @@ -0,0 +1 @@ +../../../../abis/linux/statvfs.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/dripos/include/abi-bits/suseconds_t.h b/lib/mlibc/sysdeps/dripos/include/abi-bits/suseconds_t.h new file mode 120000 index 0000000..9ed6597 --- /dev/null +++ b/lib/mlibc/sysdeps/dripos/include/abi-bits/suseconds_t.h @@ -0,0 +1 @@ +../../../../abis/linux/suseconds_t.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/dripos/include/abi-bits/termios.h b/lib/mlibc/sysdeps/dripos/include/abi-bits/termios.h new file mode 120000 index 0000000..cfcfe76 --- /dev/null +++ b/lib/mlibc/sysdeps/dripos/include/abi-bits/termios.h @@ -0,0 +1 @@ +../../../../abis/mlibc/termios.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/dripos/include/abi-bits/time.h b/lib/mlibc/sysdeps/dripos/include/abi-bits/time.h new file mode 120000 index 0000000..2a02625 --- /dev/null +++ b/lib/mlibc/sysdeps/dripos/include/abi-bits/time.h @@ -0,0 +1 @@ +../../../../abis/linux/time.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/dripos/include/abi-bits/uid_t.h b/lib/mlibc/sysdeps/dripos/include/abi-bits/uid_t.h new file mode 120000 index 0000000..1113eba --- /dev/null +++ b/lib/mlibc/sysdeps/dripos/include/abi-bits/uid_t.h @@ -0,0 +1 @@ +../../../../abis/mlibc/uid_t.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/dripos/include/abi-bits/utsname.h b/lib/mlibc/sysdeps/dripos/include/abi-bits/utsname.h new file mode 120000 index 0000000..17b993f --- /dev/null +++ b/lib/mlibc/sysdeps/dripos/include/abi-bits/utsname.h @@ -0,0 +1 @@ +../../../../abis/mlibc/utsname.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/dripos/include/abi-bits/vm-flags.h b/lib/mlibc/sysdeps/dripos/include/abi-bits/vm-flags.h new file mode 120000 index 0000000..f1a985e --- /dev/null +++ b/lib/mlibc/sysdeps/dripos/include/abi-bits/vm-flags.h @@ -0,0 +1 @@ +../../../../abis/mlibc/vm-flags.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/dripos/include/abi-bits/wait.h b/lib/mlibc/sysdeps/dripos/include/abi-bits/wait.h new file mode 120000 index 0000000..6d911c7 --- /dev/null +++ b/lib/mlibc/sysdeps/dripos/include/abi-bits/wait.h @@ -0,0 +1 @@ +../../../../abis/mlibc/wait.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/dripos/include/abi-bits/xattr.h b/lib/mlibc/sysdeps/dripos/include/abi-bits/xattr.h new file mode 120000 index 0000000..66412d7 --- /dev/null +++ b/lib/mlibc/sysdeps/dripos/include/abi-bits/xattr.h @@ -0,0 +1 @@ +../../../../abis/linux/xattr.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/dripos/include/mlibc/thread-entry.hpp b/lib/mlibc/sysdeps/dripos/include/mlibc/thread-entry.hpp new file mode 100644 index 0000000..2dd88a6 --- /dev/null +++ b/lib/mlibc/sysdeps/dripos/include/mlibc/thread-entry.hpp @@ -0,0 +1,10 @@ +#pragma once + +#include + +extern "C" void __mlibc_start_thread(void); +extern "C" void __mlibc_enter_thread(void *entry, void *user_arg, Tcb *tcb); + +namespace mlibc { + void *prepare_stack(void *entry, void *user_arg, void *tcb); +} diff --git a/lib/mlibc/sysdeps/dripos/meson.build b/lib/mlibc/sysdeps/dripos/meson.build new file mode 100644 index 0000000..afecf25 --- /dev/null +++ b/lib/mlibc/sysdeps/dripos/meson.build @@ -0,0 +1,71 @@ + +rtdl_sources += files( + 'generic/generic.cpp' +) + +libc_sources += files( + 'generic/entry.cpp', + 'generic/generic.cpp', + 'generic/thread.cpp', + 'generic/thread_entry.S' +) + +if not no_headers + install_headers( + 'include/abi-bits/auxv.h', + 'include/abi-bits/seek-whence.h', + 'include/abi-bits/vm-flags.h', + 'include/abi-bits/errno.h', + 'include/abi-bits/fcntl.h', + 'include/abi-bits/in.h', + 'include/abi-bits/resource.h', + 'include/abi-bits/stat.h', + 'include/abi-bits/signal.h', + 'include/abi-bits/socket.h', + 'include/abi-bits/termios.h', + 'include/abi-bits/blkcnt_t.h', + 'include/abi-bits/blksize_t.h', + 'include/abi-bits/dev_t.h', + 'include/abi-bits/gid_t.h', + 'include/abi-bits/ino_t.h', + 'include/abi-bits/mode_t.h', + 'include/abi-bits/nlink_t.h', + 'include/abi-bits/pid_t.h', + 'include/abi-bits/uid_t.h', + 'include/abi-bits/access.h', + 'include/abi-bits/wait.h', + 'include/abi-bits/limits.h', + 'include/abi-bits/utsname.h', + 'include/abi-bits/ptrace.h', + 'include/abi-bits/poll.h', + 'include/abi-bits/epoll.h', + 'include/abi-bits/packet.h', + 'include/abi-bits/inotify.h', + 'include/abi-bits/clockid_t.h', + 'include/abi-bits/shm.h', + 'include/abi-bits/mqueue.h', + 'include/abi-bits/suseconds_t.h', + 'include/abi-bits/fsfilcnt_t.h', + 'include/abi-bits/fsblkcnt_t.h', + 'include/abi-bits/socklen_t.h', + 'include/abi-bits/statfs.h', + 'include/abi-bits/statvfs.h', + 'include/abi-bits/ioctls.h', + 'include/abi-bits/xattr.h', + 'include/abi-bits/msg.h', + subdir: 'abi-bits', + follow_symlinks: true + ) +endif + +if not headers_only + crt = custom_target('crt1', + build_by_default: true, + command: c_compiler.cmd_array() + ['-c', '-o', '@OUTPUT@', '@INPUT@'], + input: 'crt-x86_64/crt1.S', + output: 'crt1.o', + install: true, + install_dir: get_option('libdir') + ) +endif + diff --git a/lib/mlibc/sysdeps/hyra/crt-x86_64/crt0.S b/lib/mlibc/sysdeps/hyra/crt-x86_64/crt0.S new file mode 100644 index 0000000..57f0dd1 --- /dev/null +++ b/lib/mlibc/sysdeps/hyra/crt-x86_64/crt0.S @@ -0,0 +1,9 @@ +.section .text + +.global _start +_start: + mov $main, %rdi + call __mlibc_entry + +.size _start, . - _start +.section .note.GNU-stack,"",%progbits diff --git a/lib/mlibc/sysdeps/hyra/generic/entry.cpp b/lib/mlibc/sysdeps/hyra/generic/entry.cpp new file mode 100644 index 0000000..d5129af --- /dev/null +++ b/lib/mlibc/sysdeps/hyra/generic/entry.cpp @@ -0,0 +1,35 @@ +#include +#include +#include +#include + +// defined by the POSIX library +void __mlibc_initLocale(); + +extern "C" uintptr_t *__dlapi_entrystack(); + +extern char **environ; +static mlibc::exec_stack_data __mlibc_stack_data; + +struct LibraryGuard { + LibraryGuard(); +}; + +static LibraryGuard guard; + +LibraryGuard::LibraryGuard() { + __mlibc_initLocale(); + + // Parse the exec() stack. + mlibc::parse_exec_stack(__dlapi_entrystack(), &__mlibc_stack_data); + mlibc::set_startup_data(__mlibc_stack_data.argc, __mlibc_stack_data.argv, + __mlibc_stack_data.envp); +} + +extern "C" void __mlibc_entry(int (*main_fn)(int argc, char *argv[], + char *env[])) { + // TODO: call __dlapi_enter, otherwise static builds will break (see Linux + // sysdeps) + auto result = main_fn(__mlibc_stack_data.argc, __mlibc_stack_data.argv, environ); + exit(result); +} diff --git a/lib/mlibc/sysdeps/hyra/generic/hyra.cpp b/lib/mlibc/sysdeps/hyra/generic/hyra.cpp new file mode 100644 index 0000000..fb555b9 --- /dev/null +++ b/lib/mlibc/sysdeps/hyra/generic/hyra.cpp @@ -0,0 +1,121 @@ +#include +#include +#include + +namespace mlibc { +void sys_libc_log(const char *msg) { + __syscall(0, (uintptr_t)msg); +} + +int sys_anon_allocate(size_t size, void **pointer) { + (void)size; + (void)pointer; + while (1); +} + +void sys_libc_panic() { + sys_libc_log("\n** MLIBC PANIC **\n"); + while (1); +} + +int sys_tcb_set(void *pointer) { + (void)pointer; + + while (1); +} + +void sys_exit(int status) { +} + +void sys_seek(int fd, off_t offset, int whence, off_t *new_offset) { + (void)fd; + (void)offset; + (void)whence; + (void)new_offset; + + while (1); +} + +int sys_vm_map(void *hint, size_t size, int prot, int flags, int fd, + off_t offset, void **window) { + (void)hint; + (void)size; + (void)prot; + (void)flags; + (void)fd; + (void)offset; + (void)window; + + while (1); +} + +int sys_vm_unmap(void *address, size_t size) { + (void)address; + (void)size; + + while (1); +} + +int sys_anon_free(void *pointer, size_t size) { + (void)pointer; + (void)size; + + while (1); +} + +int sys_clock_get(int clock, time_t *secs, long *nanos) { + (void)clock; + (void)secs; + (void)nanos; + + while (1); +} + +int sys_futex_wait(int *pointer, int expected, const struct timespec *time) { + (void)pointer; + (void)expected; + (void)time; + + return 0; +} + +int sys_futex_wake(int *pointer) { + (void)pointer; + + return 0; +} + +int sys_open(const char *filename, int flags, mode_t mode, int *fd) { + (void)filename; + (void)flags; + (void)mode; + (void)fd; + + while (1); +} + +int sys_read(int fd, void *buf, size_t count, ssize_t *bytes_read) { + (void)fd; + (void)buf; + (void)count; + (void)bytes_read; + + while (1); +} + +int sys_write(int fd, const void *buffer, size_t count, ssize_t *written) { + (void)fd; + (void)buffer; + (void)count; + (void)written; + + while (1); +} + +int sys_close(int fd) { + (void)fd; + + while (1); +} + +} diff --git a/lib/mlibc/sysdeps/hyra/include/abi-bits/access.h b/lib/mlibc/sysdeps/hyra/include/abi-bits/access.h new file mode 120000 index 0000000..cb83931 --- /dev/null +++ b/lib/mlibc/sysdeps/hyra/include/abi-bits/access.h @@ -0,0 +1 @@ +../../../../abis/linux/access.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/hyra/include/abi-bits/auxv.h b/lib/mlibc/sysdeps/hyra/include/abi-bits/auxv.h new file mode 120000 index 0000000..6959fac --- /dev/null +++ b/lib/mlibc/sysdeps/hyra/include/abi-bits/auxv.h @@ -0,0 +1 @@ +../../../../abis/hyra/auxv.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/hyra/include/abi-bits/blkcnt_t.h b/lib/mlibc/sysdeps/hyra/include/abi-bits/blkcnt_t.h new file mode 120000 index 0000000..0b0ec27 --- /dev/null +++ b/lib/mlibc/sysdeps/hyra/include/abi-bits/blkcnt_t.h @@ -0,0 +1 @@ +../../../../abis/linux/blkcnt_t.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/hyra/include/abi-bits/blksize_t.h b/lib/mlibc/sysdeps/hyra/include/abi-bits/blksize_t.h new file mode 120000 index 0000000..7dc8d7c --- /dev/null +++ b/lib/mlibc/sysdeps/hyra/include/abi-bits/blksize_t.h @@ -0,0 +1 @@ +../../../../abis/linux/blksize_t.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/hyra/include/abi-bits/clockid_t.h b/lib/mlibc/sysdeps/hyra/include/abi-bits/clockid_t.h new file mode 120000 index 0000000..6a42da5 --- /dev/null +++ b/lib/mlibc/sysdeps/hyra/include/abi-bits/clockid_t.h @@ -0,0 +1 @@ +../../../../abis/linux/clockid_t.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/hyra/include/abi-bits/dev_t.h b/lib/mlibc/sysdeps/hyra/include/abi-bits/dev_t.h new file mode 120000 index 0000000..bca881e --- /dev/null +++ b/lib/mlibc/sysdeps/hyra/include/abi-bits/dev_t.h @@ -0,0 +1 @@ +../../../../abis/linux/dev_t.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/hyra/include/abi-bits/epoll.h b/lib/mlibc/sysdeps/hyra/include/abi-bits/epoll.h new file mode 120000 index 0000000..eb4b76d --- /dev/null +++ b/lib/mlibc/sysdeps/hyra/include/abi-bits/epoll.h @@ -0,0 +1 @@ +../../../../abis/linux/epoll.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/hyra/include/abi-bits/errno.h b/lib/mlibc/sysdeps/hyra/include/abi-bits/errno.h new file mode 120000 index 0000000..6e507de --- /dev/null +++ b/lib/mlibc/sysdeps/hyra/include/abi-bits/errno.h @@ -0,0 +1 @@ +../../../../abis/linux/errno.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/hyra/include/abi-bits/fcntl.h b/lib/mlibc/sysdeps/hyra/include/abi-bits/fcntl.h new file mode 120000 index 0000000..463e2c9 --- /dev/null +++ b/lib/mlibc/sysdeps/hyra/include/abi-bits/fcntl.h @@ -0,0 +1 @@ +../../../../abis/linux/fcntl.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/hyra/include/abi-bits/fsblkcnt_t.h b/lib/mlibc/sysdeps/hyra/include/abi-bits/fsblkcnt_t.h new file mode 120000 index 0000000..898dfb2 --- /dev/null +++ b/lib/mlibc/sysdeps/hyra/include/abi-bits/fsblkcnt_t.h @@ -0,0 +1 @@ +../../../../abis/linux/fsblkcnt_t.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/hyra/include/abi-bits/fsfilcnt_t.h b/lib/mlibc/sysdeps/hyra/include/abi-bits/fsfilcnt_t.h new file mode 120000 index 0000000..791755c --- /dev/null +++ b/lib/mlibc/sysdeps/hyra/include/abi-bits/fsfilcnt_t.h @@ -0,0 +1 @@ +../../../../abis/linux/fsfilcnt_t.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/hyra/include/abi-bits/gid_t.h b/lib/mlibc/sysdeps/hyra/include/abi-bits/gid_t.h new file mode 120000 index 0000000..abce6d6 --- /dev/null +++ b/lib/mlibc/sysdeps/hyra/include/abi-bits/gid_t.h @@ -0,0 +1 @@ +../../../../abis/linux/gid_t.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/hyra/include/abi-bits/in.h b/lib/mlibc/sysdeps/hyra/include/abi-bits/in.h new file mode 120000 index 0000000..418d1d5 --- /dev/null +++ b/lib/mlibc/sysdeps/hyra/include/abi-bits/in.h @@ -0,0 +1 @@ +../../../../abis/linux/in.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/hyra/include/abi-bits/ino_t.h b/lib/mlibc/sysdeps/hyra/include/abi-bits/ino_t.h new file mode 120000 index 0000000..4c20aca --- /dev/null +++ b/lib/mlibc/sysdeps/hyra/include/abi-bits/ino_t.h @@ -0,0 +1 @@ +../../../../abis/linux/ino_t.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/hyra/include/abi-bits/inotify.h b/lib/mlibc/sysdeps/hyra/include/abi-bits/inotify.h new file mode 120000 index 0000000..b5cb282 --- /dev/null +++ b/lib/mlibc/sysdeps/hyra/include/abi-bits/inotify.h @@ -0,0 +1 @@ +../../../../abis/linux/inotify.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/hyra/include/abi-bits/ioctls.h b/lib/mlibc/sysdeps/hyra/include/abi-bits/ioctls.h new file mode 120000 index 0000000..595106b --- /dev/null +++ b/lib/mlibc/sysdeps/hyra/include/abi-bits/ioctls.h @@ -0,0 +1 @@ +../../../../abis/linux/ioctls.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/hyra/include/abi-bits/limits.h b/lib/mlibc/sysdeps/hyra/include/abi-bits/limits.h new file mode 120000 index 0000000..6c88db2 --- /dev/null +++ b/lib/mlibc/sysdeps/hyra/include/abi-bits/limits.h @@ -0,0 +1 @@ +../../../../abis/linux/limits.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/hyra/include/abi-bits/mode_t.h b/lib/mlibc/sysdeps/hyra/include/abi-bits/mode_t.h new file mode 120000 index 0000000..5d78fdf --- /dev/null +++ b/lib/mlibc/sysdeps/hyra/include/abi-bits/mode_t.h @@ -0,0 +1 @@ +../../../../abis/linux/mode_t.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/hyra/include/abi-bits/mqueue.h b/lib/mlibc/sysdeps/hyra/include/abi-bits/mqueue.h new file mode 120000 index 0000000..fa87b07 --- /dev/null +++ b/lib/mlibc/sysdeps/hyra/include/abi-bits/mqueue.h @@ -0,0 +1 @@ +../../../../abis/linux/mqueue.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/hyra/include/abi-bits/msg.h b/lib/mlibc/sysdeps/hyra/include/abi-bits/msg.h new file mode 120000 index 0000000..f402b49 --- /dev/null +++ b/lib/mlibc/sysdeps/hyra/include/abi-bits/msg.h @@ -0,0 +1 @@ +../../../../abis/linux/msg.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/hyra/include/abi-bits/nlink_t.h b/lib/mlibc/sysdeps/hyra/include/abi-bits/nlink_t.h new file mode 120000 index 0000000..bb3b625 --- /dev/null +++ b/lib/mlibc/sysdeps/hyra/include/abi-bits/nlink_t.h @@ -0,0 +1 @@ +../../../../abis/linux/nlink_t.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/hyra/include/abi-bits/packet.h b/lib/mlibc/sysdeps/hyra/include/abi-bits/packet.h new file mode 120000 index 0000000..998ef1a --- /dev/null +++ b/lib/mlibc/sysdeps/hyra/include/abi-bits/packet.h @@ -0,0 +1 @@ +../../../../abis/linux/packet.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/hyra/include/abi-bits/pid_t.h b/lib/mlibc/sysdeps/hyra/include/abi-bits/pid_t.h new file mode 120000 index 0000000..baa90f6 --- /dev/null +++ b/lib/mlibc/sysdeps/hyra/include/abi-bits/pid_t.h @@ -0,0 +1 @@ +../../../../abis/linux/pid_t.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/hyra/include/abi-bits/poll.h b/lib/mlibc/sysdeps/hyra/include/abi-bits/poll.h new file mode 120000 index 0000000..8ea6a0a --- /dev/null +++ b/lib/mlibc/sysdeps/hyra/include/abi-bits/poll.h @@ -0,0 +1 @@ +../../../../abis/linux/poll.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/hyra/include/abi-bits/ptrace.h b/lib/mlibc/sysdeps/hyra/include/abi-bits/ptrace.h new file mode 120000 index 0000000..b2517b2 --- /dev/null +++ b/lib/mlibc/sysdeps/hyra/include/abi-bits/ptrace.h @@ -0,0 +1 @@ +../../../../abis/linux/ptrace.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/hyra/include/abi-bits/reboot.h b/lib/mlibc/sysdeps/hyra/include/abi-bits/reboot.h new file mode 120000 index 0000000..77013a4 --- /dev/null +++ b/lib/mlibc/sysdeps/hyra/include/abi-bits/reboot.h @@ -0,0 +1 @@ +../../../../abis/linux/reboot.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/hyra/include/abi-bits/resource.h b/lib/mlibc/sysdeps/hyra/include/abi-bits/resource.h new file mode 120000 index 0000000..88d7402 --- /dev/null +++ b/lib/mlibc/sysdeps/hyra/include/abi-bits/resource.h @@ -0,0 +1 @@ +../../../../abis/linux/resource.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/hyra/include/abi-bits/seek-whence.h b/lib/mlibc/sysdeps/hyra/include/abi-bits/seek-whence.h new file mode 120000 index 0000000..df7bccf --- /dev/null +++ b/lib/mlibc/sysdeps/hyra/include/abi-bits/seek-whence.h @@ -0,0 +1 @@ +../../../../abis/linux/seek-whence.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/hyra/include/abi-bits/shm.h b/lib/mlibc/sysdeps/hyra/include/abi-bits/shm.h new file mode 120000 index 0000000..067d8c4 --- /dev/null +++ b/lib/mlibc/sysdeps/hyra/include/abi-bits/shm.h @@ -0,0 +1 @@ +../../../../abis/linux/shm.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/hyra/include/abi-bits/signal.h b/lib/mlibc/sysdeps/hyra/include/abi-bits/signal.h new file mode 120000 index 0000000..4dcb0b7 --- /dev/null +++ b/lib/mlibc/sysdeps/hyra/include/abi-bits/signal.h @@ -0,0 +1 @@ +../../../../abis/linux/signal.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/hyra/include/abi-bits/socket.h b/lib/mlibc/sysdeps/hyra/include/abi-bits/socket.h new file mode 120000 index 0000000..f1dc016 --- /dev/null +++ b/lib/mlibc/sysdeps/hyra/include/abi-bits/socket.h @@ -0,0 +1 @@ +../../../../abis/linux/socket.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/hyra/include/abi-bits/socklen_t.h b/lib/mlibc/sysdeps/hyra/include/abi-bits/socklen_t.h new file mode 120000 index 0000000..41f3b11 --- /dev/null +++ b/lib/mlibc/sysdeps/hyra/include/abi-bits/socklen_t.h @@ -0,0 +1 @@ +../../../../abis/linux/socklen_t.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/hyra/include/abi-bits/stat.h b/lib/mlibc/sysdeps/hyra/include/abi-bits/stat.h new file mode 120000 index 0000000..1f63b41 --- /dev/null +++ b/lib/mlibc/sysdeps/hyra/include/abi-bits/stat.h @@ -0,0 +1 @@ +../../../../abis/linux/stat.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/hyra/include/abi-bits/statfs.h b/lib/mlibc/sysdeps/hyra/include/abi-bits/statfs.h new file mode 120000 index 0000000..e3d202f --- /dev/null +++ b/lib/mlibc/sysdeps/hyra/include/abi-bits/statfs.h @@ -0,0 +1 @@ +../../../../abis/linux/statfs.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/hyra/include/abi-bits/statvfs.h b/lib/mlibc/sysdeps/hyra/include/abi-bits/statvfs.h new file mode 120000 index 0000000..1fc80c2 --- /dev/null +++ b/lib/mlibc/sysdeps/hyra/include/abi-bits/statvfs.h @@ -0,0 +1 @@ +../../../../abis/linux/statvfs.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/hyra/include/abi-bits/suseconds_t.h b/lib/mlibc/sysdeps/hyra/include/abi-bits/suseconds_t.h new file mode 120000 index 0000000..9ed6597 --- /dev/null +++ b/lib/mlibc/sysdeps/hyra/include/abi-bits/suseconds_t.h @@ -0,0 +1 @@ +../../../../abis/linux/suseconds_t.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/hyra/include/abi-bits/termios.h b/lib/mlibc/sysdeps/hyra/include/abi-bits/termios.h new file mode 120000 index 0000000..ee8f0b0 --- /dev/null +++ b/lib/mlibc/sysdeps/hyra/include/abi-bits/termios.h @@ -0,0 +1 @@ +../../../../abis/linux/termios.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/hyra/include/abi-bits/time.h b/lib/mlibc/sysdeps/hyra/include/abi-bits/time.h new file mode 120000 index 0000000..2a02625 --- /dev/null +++ b/lib/mlibc/sysdeps/hyra/include/abi-bits/time.h @@ -0,0 +1 @@ +../../../../abis/linux/time.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/hyra/include/abi-bits/uid_t.h b/lib/mlibc/sysdeps/hyra/include/abi-bits/uid_t.h new file mode 120000 index 0000000..b306777 --- /dev/null +++ b/lib/mlibc/sysdeps/hyra/include/abi-bits/uid_t.h @@ -0,0 +1 @@ +../../../../abis/linux/uid_t.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/hyra/include/abi-bits/utsname.h b/lib/mlibc/sysdeps/hyra/include/abi-bits/utsname.h new file mode 120000 index 0000000..b285754 --- /dev/null +++ b/lib/mlibc/sysdeps/hyra/include/abi-bits/utsname.h @@ -0,0 +1 @@ +../../../../abis/linux/utsname.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/hyra/include/abi-bits/vm-flags.h b/lib/mlibc/sysdeps/hyra/include/abi-bits/vm-flags.h new file mode 120000 index 0000000..bbe258c --- /dev/null +++ b/lib/mlibc/sysdeps/hyra/include/abi-bits/vm-flags.h @@ -0,0 +1 @@ +../../../../abis/linux/vm-flags.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/hyra/include/abi-bits/vt.h b/lib/mlibc/sysdeps/hyra/include/abi-bits/vt.h new file mode 120000 index 0000000..5798a4a --- /dev/null +++ b/lib/mlibc/sysdeps/hyra/include/abi-bits/vt.h @@ -0,0 +1 @@ +../../../../abis/linux/vt.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/hyra/include/abi-bits/wait.h b/lib/mlibc/sysdeps/hyra/include/abi-bits/wait.h new file mode 120000 index 0000000..feb2840 --- /dev/null +++ b/lib/mlibc/sysdeps/hyra/include/abi-bits/wait.h @@ -0,0 +1 @@ +../../../../abis/linux/wait.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/hyra/include/abi-bits/xattr.h b/lib/mlibc/sysdeps/hyra/include/abi-bits/xattr.h new file mode 120000 index 0000000..66412d7 --- /dev/null +++ b/lib/mlibc/sysdeps/hyra/include/abi-bits/xattr.h @@ -0,0 +1 @@ +../../../../abis/linux/xattr.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/hyra/include/hyra/syscall.h b/lib/mlibc/sysdeps/hyra/include/hyra/syscall.h new file mode 100644 index 0000000..f38a59b --- /dev/null +++ b/lib/mlibc/sysdeps/hyra/include/hyra/syscall.h @@ -0,0 +1,55 @@ +#ifndef _HYRA_SYSCALL_H_ +#define _HYRA_SYSCALL_H_ + +#define SYS_debug 0 +#define SYS_exit 1 + +__attribute__((__always_inline__)) +static inline long syscall0() { + volatile long ret; + asm volatile("int $0x80" : "=a"(ret)); + return ret; +} + +__attribute__((__always_inline__)) +static inline long syscall1(uint64_t code, uint64_t arg0) { + volatile long ret; + asm volatile("int $0x80" + : "=a"(ret) + : "a"(code), + "D"(arg0) : "memory"); + return ret; +} + +__attribute__((__always_inline__)) +static inline long syscall2(uint64_t code, uint64_t arg0, uint64_t arg1) { + volatile long ret; + asm volatile("int $0x80" + : "=a"(ret) + : "a"(code), + "D"(arg0), + "S"(arg1) + : "memory"); + return ret; +} + +__attribute__((__always_inline__)) +static inline long syscall3(uint64_t code, uint64_t arg0, uint64_t arg1, uint64_t arg2) { + volatile long ret; + asm volatile("int $0x80" + : "=a"(ret) + : "a"(code), + "D"(arg0), + "S"(arg1), + "d"(arg2) + : "memory"); + return ret; +} + +#define _GET_SYSCALL(a0, a1, a2, a3, name, ...) name + +#define __syscall(...) \ + _GET_SYSCALL(__VA_ARGS__, syscall3, syscall2, syscall1, \ + syscall0)(__VA_ARGS__) + +#endif /* !_HYRA_SYSCALL_H_ */ diff --git a/lib/mlibc/sysdeps/hyra/meson.build b/lib/mlibc/sysdeps/hyra/meson.build new file mode 100644 index 0000000..80136db --- /dev/null +++ b/lib/mlibc/sysdeps/hyra/meson.build @@ -0,0 +1,69 @@ +rtdl_dso_sources += files( + 'generic/hyra.cpp' +) + +libc_sources += files( + 'generic/entry.cpp', + 'generic/hyra.cpp', +) + +if not no_headers + install_headers( + 'include/abi-bits/auxv.h', + 'include/abi-bits/seek-whence.h', + 'include/abi-bits/vm-flags.h', + 'include/abi-bits/errno.h', + 'include/abi-bits/fcntl.h', + 'include/abi-bits/in.h', + 'include/abi-bits/resource.h', + 'include/abi-bits/signal.h', + 'include/abi-bits/stat.h', + 'include/abi-bits/socket.h', + 'include/abi-bits/termios.h', + 'include/abi-bits/time.h', + 'include/abi-bits/blkcnt_t.h', + 'include/abi-bits/blksize_t.h', + 'include/abi-bits/dev_t.h', + 'include/abi-bits/gid_t.h', + 'include/abi-bits/ino_t.h', + 'include/abi-bits/mode_t.h', + 'include/abi-bits/nlink_t.h', + 'include/abi-bits/pid_t.h', + 'include/abi-bits/uid_t.h', + 'include/abi-bits/access.h', + 'include/abi-bits/wait.h', + 'include/abi-bits/limits.h', + 'include/abi-bits/utsname.h', + 'include/abi-bits/ptrace.h', + 'include/abi-bits/poll.h', + 'include/abi-bits/epoll.h', + 'include/abi-bits/packet.h', + 'include/abi-bits/inotify.h', + 'include/abi-bits/clockid_t.h', + 'include/abi-bits/shm.h', + 'include/abi-bits/mqueue.h', + subdir: 'abi-bits', + follow_symlinks: true + ) + install_headers( + 'include/hyra/syscall.h', + subdir: 'hyra' + ) +endif + +if not headers_only + crt = custom_target('crt0', + build_by_default: true, + command: c_compiler.cmd_array() + ['-c', '-o', '@OUTPUT@', '@INPUT@'], + input: 'crt-x86_64/crt0.S', + output: 'crt0.o', + install: true, + install_dir: get_option('libdir') + ) +endif + +if host_machine.cpu_family() == 'x86_64' + # libc_sources += files('generic/signals.S') +else + error('Unknown architecture') +endif diff --git a/lib/mlibc/sysdeps/ironclad/crt-x86_64/crt0.S b/lib/mlibc/sysdeps/ironclad/crt-x86_64/crt0.S new file mode 100644 index 0000000..18d109e --- /dev/null +++ b/lib/mlibc/sysdeps/ironclad/crt-x86_64/crt0.S @@ -0,0 +1,9 @@ + +.section .text +.global _start +_start: + mov $main, %rdi + call __mlibc_entry + +.section .note.GNU-stack,"",%progbits + diff --git a/lib/mlibc/sysdeps/ironclad/crt-x86_64/crti.S b/lib/mlibc/sysdeps/ironclad/crt-x86_64/crti.S new file mode 100644 index 0000000..911b078 --- /dev/null +++ b/lib/mlibc/sysdeps/ironclad/crt-x86_64/crti.S @@ -0,0 +1,11 @@ +.section .init +.global _init +_init: + push %rax + +.section .fini +.global _fini +_fini: + push %rax +.section .note.GNU-stack,"",%progbits + diff --git a/lib/mlibc/sysdeps/ironclad/crt-x86_64/crtn.S b/lib/mlibc/sysdeps/ironclad/crt-x86_64/crtn.S new file mode 100644 index 0000000..0187e50 --- /dev/null +++ b/lib/mlibc/sysdeps/ironclad/crt-x86_64/crtn.S @@ -0,0 +1,9 @@ +.section .init + pop %rax + ret + +.section .fini + pop %rax + ret +.section .note.GNU-stack,"",%progbits + diff --git a/lib/mlibc/sysdeps/ironclad/generic/entry.cpp b/lib/mlibc/sysdeps/ironclad/generic/entry.cpp new file mode 100644 index 0000000..2b8b914 --- /dev/null +++ b/lib/mlibc/sysdeps/ironclad/generic/entry.cpp @@ -0,0 +1,35 @@ + +#include +#include +#include +#include + +// defined by the POSIX library +void __mlibc_initLocale(); + +extern "C" uintptr_t *__dlapi_entrystack(); + +extern char **environ; +static mlibc::exec_stack_data __mlibc_stack_data; + +struct LibraryGuard { + LibraryGuard(); +}; + +static LibraryGuard guard; + +LibraryGuard::LibraryGuard() { + __mlibc_initLocale(); + + // Parse the exec() stack. + mlibc::parse_exec_stack(__dlapi_entrystack(), &__mlibc_stack_data); + mlibc::set_startup_data(__mlibc_stack_data.argc, __mlibc_stack_data.argv, + __mlibc_stack_data.envp); +} + +extern "C" void __mlibc_entry(int (*main_fn)(int argc, char *argv[], char *env[])) { + // TODO: call __dlapi_enter, otherwise static builds will break (see Linux sysdeps) + auto result = main_fn(__mlibc_stack_data.argc, __mlibc_stack_data.argv, environ); + exit(result); +} + diff --git a/lib/mlibc/sysdeps/ironclad/generic/generic.cpp b/lib/mlibc/sysdeps/ironclad/generic/generic.cpp new file mode 100644 index 0000000..3d15365 --- /dev/null +++ b/lib/mlibc/sysdeps/ironclad/generic/generic.cpp @@ -0,0 +1,1266 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace mlibc { + +void sys_libc_log(const char *message) { + ssize_t unused; + char new_line = '\n'; + sys_write(2, message, strlen(message), &unused); + sys_write(2, &new_line, 1, &unused); +} + +void sys_libc_panic() { + ssize_t unused; + char const *message = "mlibc panicked unrecoverably\n"; + sys_write(2, message, strlen(message), &unused); + sys_exit(1); +} + +void sys_exit(int status) { + int ret, errno; + SYSCALL1(SYSCALL_EXIT, status); + __builtin_unreachable(); +} + +int sys_tcb_set(void *pointer) { + int ret, errno; + SYSCALL2(SYSCALL_ARCH_PRCTL, 1, pointer); + return errno; +} + +int sys_thread_getname(void *tcb, char *name, size_t size) { + int ret, errno; + auto t = reinterpret_cast(tcb); + SYSCALL3(SYSCALL_GETTIDID, t->tid, name, size); + return errno; +} + +int sys_thread_setname(void *tcb, const char *name) { + int ret, errno; + size_t len = strlen(name); + auto t = reinterpret_cast(tcb); + SYSCALL3(SYSCALL_SETTIDID, t->tid, name, len); + return errno; +} + +int sys_open(const char *path, int flags, mode_t mode, int *fd) { + return sys_openat(AT_FDCWD, path, flags, mode, fd); +} + +int sys_openat(int dirfd, const char *path, int flags, mode_t mode, int *fd) { + int ret, errno; + + int path_len = strlen (path); + SYSCALL4(SYSCALL_OPEN, dirfd, path, path_len, flags); + if (ret != -1 && (flags & O_EXCL)) { + SYSCALL1(SYSCALL_CLOSE, ret); + return EEXIST; + } + + if (ret == -1 && (flags & O_CREAT)) { + SYSCALL5(SYSCALL_MAKENODE, AT_FDCWD, path, path_len, mode, 0); + if (ret == -1) { + return errno; + } + SYSCALL4(SYSCALL_OPEN, AT_FDCWD, path, path_len, flags); + } else if (ret != -1 && (flags & O_TRUNC)) { + // If the file cannot be truncated, dont sweat it, some software + // depends on some things being truncate-able that ironclad does not + // allow. For example, some devices. + sys_ftruncate(ret, 0); + } else if (ret != -1 && (flags & O_DIRECTORY)) { + struct stat st; + sys_stat(fsfd_target::fd, ret, NULL, 0, &st); + if (!S_ISDIR (st.st_mode)) { + ret = -1; + errno = ENOTDIR; + } + } + + *fd = ret; + return errno; +} + +int sys_open_dir(const char *path, int *handle) { + return sys_open(path, O_RDONLY | O_DIRECTORY, 0660, handle); +} + +int sys_read_entries(int handle, void *buffer, size_t max_size, size_t *bytes_read) { + size_t ret; + int errno; + SYSCALL3(SYSCALL_GETDENTS, handle, buffer, max_size); + if (errno != 0) { + return errno; + } else { + *bytes_read = ret; + return 0; + } +} + +void sys_thread_exit() { + int ret, errno; + SYSCALL0(SYSCALL_EXIT_THREAD); + __builtin_unreachable(); +} + +int sys_close(int fd) { + int ret, errno; + SYSCALL1(SYSCALL_CLOSE, fd); + return errno; +} + +void sys_sync() { + int ret, errno; + SYSCALL0(SYSCALL_SYNC); + if (ret != 0) { + sys_libc_log("mlibc: sync failed"); + } +} + +int sys_fsync(int fd) { + int ret, errno; + SYSCALL2(SYSCALL_FSYNC, fd, 0); + return errno; +} + +int sys_fdatasync(int fd) { + int ret, errno; + SYSCALL2(SYSCALL_FSYNC, fd, 1); + return errno; +} + +int sys_read(int fd, void *buf, size_t count, ssize_t *bytes_read) { + ssize_t ret; + int errno; + SYSCALL3(SYSCALL_READ, fd, buf, count); + *bytes_read = ret; + return errno; +} + +int sys_write(int fd, const void *buf, size_t count, ssize_t *bytes_written) { + ssize_t ret; + int errno; + SYSCALL3(SYSCALL_WRITE, fd, buf, count); + *bytes_written = ret; + return errno; +} + +int sys_pread(int fd, void *buf, size_t n, off_t off, ssize_t *bytes_read) { + ssize_t ret; + int errno; + SYSCALL4(SYSCALL_PREAD, fd, buf, n, off); + *bytes_read = ret; + return errno; +} + +int sys_pwrite(int fd, const void *buf, size_t n, off_t off, ssize_t *bytes_written) { + ssize_t ret; + int errno; + SYSCALL4(SYSCALL_WRITE, fd, buf, n, off); + *bytes_written = ret; + return errno; +} + +int sys_seek(int fd, off_t offset, int whence, off_t *new_offset) { + ssize_t ret; + int errno; + SYSCALL3(SYSCALL_SEEK, fd, offset, whence); + *new_offset = ret; + return errno; +} + +int sys_ftruncate (int fd, size_t size) { + int ret, errno; + SYSCALL2(SYSCALL_TRUNCATE, fd, size); + return errno; +} + +int sys_flock(int fd, int options) { + // XXX: Shouldnt this use F_SETLKW and F_SETLK only when LOCK_NB ? + struct flock lock; + lock.l_whence = SEEK_SET; + lock.l_start = 0; + lock.l_len = (off_t)((uint64_t)-1); + lock.l_pid = sys_getpid(); + + switch (options & ~(LOCK_NB)) { + case LOCK_SH: + lock.l_type = F_RDLCK; + break; + case LOCK_EX: + lock.l_type = F_WRLCK; + break; + case LOCK_UN: + lock.l_type = F_UNLCK; + break; + default: + return -1; + } + + int ret, errno; + SYSCALL3(SYSCALL_FCNTL, fd, F_SETLK, &lock); + return errno; +} + +int sys_getpriority(int which, id_t who, int *value) { + int ret, errno; + SYSCALL2(SYSCALL_GETPRIO, which, who); + *value = ret; + return errno; +} + +int sys_setpriority(int which, id_t who, int value) { + int ret, errno; + SYSCALL3(SYSCALL_SETPRIO, which, who, value); + return errno; +} + +int sys_getrusage(int scope, struct rusage *usage) { + int ret, errno; + SYSCALL2(SYSCALL_GETRUSAGE, scope, usage); + + // Ironclad returns nanoseconds instead of microseconds for usage, so we + // have to compensate for that. + usage->ru_utime.tv_usec = usage->ru_utime.tv_usec / 1000; + usage->ru_stime.tv_usec = usage->ru_stime.tv_usec / 1000; + + return errno; +} + +int sys_anon_allocate(size_t size, void **pointer) { + return sys_vm_map(NULL, size, PROT_READ | PROT_WRITE, MAP_ANON, 0, 0, pointer); +} + +int sys_anon_free(void *pointer, size_t size) { + return sys_vm_unmap(pointer, size); +} + +int sys_vm_map(void *hint, size_t size, int prot, int flags, int fd, off_t offset, void **window) { + void *ret; + int errno; + SYSCALL6(SYSCALL_MMAP, hint, size, prot, flags, fd, offset); + *window = ret; + return errno; +} + +int sys_getsockopt(int fd, int layer, int number, void *__restrict buffer, socklen_t *__restrict size) { + int ret, errno; + SYSCALL5(SYSCALL_GETSOCKOPT, fd, layer, number, buffer, size); + return errno; +} + +int sys_setsockopt(int fd, int layer, int number, const void *buffer, socklen_t size) { + int ret, errno; + SYSCALL5(SYSCALL_SETSOCKOPT, fd, layer, number, buffer, size); + return errno; +} + +int sys_vm_unmap(void *pointer, size_t size) { + int ret; + int errno; + SYSCALL2(SYSCALL_MUNMAP, pointer, size); + if (ret != 0) { + return errno; + } else { + return 0; + } +} + +int sys_getcwd(char *buf, size_t size) { + buf[0] = '/'; + buf[1] = '\0'; + return 0; +} + +int sys_vm_protect(void *pointer, size_t size, int prot) { + int ret; + int errno; + SYSCALL3(SYSCALL_MPROTECT, pointer, size, prot); + if (ret != 0) { + return errno; + } + return 0; +} + +int sys_getsid(pid_t pid, pid_t *sid) { + // STUB. + return 0; +} + +pid_t sys_getpid() { + pid_t ret; + int errno; + SYSCALL0(SYSCALL_GETPID); + return ret; +} + +pid_t sys_getppid() { + pid_t ret; + int errno; + SYSCALL0(SYSCALL_GETPPID); + return ret; +} + +int sys_getgroups(size_t size, const gid_t *list, int *retval) { + int ret, errno; + SYSCALL2(SYSCALL_GETGROUPS, size, list); + *retval = ret; + return errno; +} + +int sys_setgroups(size_t size, const gid_t *list) { + int ret, errno; + SYSCALL2(SYSCALL_SETGROUPS, size, list); + return errno; +} + +int sys_sigaction(int signum, const struct sigaction *act, struct sigaction *oldact) { + return 0; +} + +int sys_ptrace(long req, pid_t pid, void *addr, void *data, long *out) { + int ret, errno; + SYSCALL4(SYSCALL_PTRACE, req, pid, addr, data); + *out = (long)ret; + return errno; +} + +int sys_fcntl(int fd, int request, va_list args, int *result) { + int ret, errno; + SYSCALL3(SYSCALL_FCNTL, fd, request, va_arg(args, uint64_t)); + *result = ret; + return errno; +} + +int sys_sigprocmask(int how, const sigset_t *__restrict set, sigset_t *__restrict retrieve) { + return 0; +} + +int sys_isatty(int fd) { + struct termios t; + if (sys_tcgetattr(fd, &t) == 0) { + return 0; + } else { + return ENOTTY; + } +} + +int sys_getpgid(pid_t pid, pid_t *pgid) { + (void)pid; + // FIXME: Stub needed by mlibc. + *pgid = 0; + return 0; +} + +int sys_execve(const char *path, char *const argv[], char *const envp[]) { + int ret, errno, argv_len, envp_len; + for (argv_len = 0; argv[argv_len] != NULL; argv_len++); + for (envp_len = 0; envp[envp_len] != NULL; envp_len++); + + size_t path_len = strlen (path); + SYSCALL6(SYSCALL_EXEC, path, path_len, argv, argv_len, envp, envp_len); + + if (ret == -1) { + return errno; + } + + return 0; +} + +int sys_fork(pid_t *child) { + pid_t ret; + int errno; + + SYSCALL6(SYSCALL_CLONE, 0, 0, 0, 0, 0, 1); + + if (ret == -1) { + return errno; + } + + if (child != NULL) { + *child = ret; + } + + return 0; +} + +int sys_getrlimit(int resource, struct rlimit *limit) { + uint64_t ret, errno; + SYSCALL1(SYSCALL_GETRLIMIT, resource); + limit->rlim_cur = ret; + limit->rlim_max = ret; + return errno; +} + +int sys_setrlimit(int resource, const struct rlimit *limit) { + int ret, errno; + SYSCALL2(SYSCALL_SETRLIMIT, resource, limit->rlim_cur); + return errno; +} + +int sys_waitpid(pid_t pid, int *status, int flags, struct rusage *ru, pid_t *ret_pid) { + pid_t ret; + int errno; + + if(ru) { + mlibc::infoLogger() << "mlibc: struct rusage in sys_waitpid is unsupported" << frg::endlog; + return ENOSYS; + } + + SYSCALL3(SYSCALL_WAIT, pid, status, flags); + + if (ret == -1) { + return errno; + } + + *ret_pid = ret; + return errno; +} + +int sys_uname(struct utsname *buf) { + int ret, errno; + + SYSCALL3(SYSCALL_SYSCONF, 10, buf, sizeof(struct utsname)); + + if (ret == -1) { + return errno; + } + + return 0; +} + + + +int sys_setpgid(pid_t pid, pid_t pgid) { + (void)pid; + (void)pgid; + return 0; +} + +int sys_ttyname(int fd, char *buff, size_t size) { + int ret, errno; + SYSCALL3(SYSCALL_TTYNAME, fd, buff, size); + return errno; +} + +int sys_sethostname(const char *buff, size_t size) { + int ret, errno; + + SYSCALL2(SYSCALL_SETHOSTNAME, buff, size); + + if (ret == -1) { + return errno; + } + + return 0; +} + +int sys_chdir(const char *buff) { + int ret, errno; + + size_t buff_len = strlen(buff); + SYSCALL4(SYSCALL_OPEN, AT_FDCWD, buff, buff_len, O_RDONLY); + if (ret == -1) { + return ENOENT; + } + + SYSCALL1(SYSCALL_CHDIR, ret); + + if (ret == -1) { + return errno; + } + + return 0; +} + +int sys_fchdir(int fd) { + int ret, errno; + + SYSCALL1(SYSCALL_CHDIR, fd); + + if (ret == -1) { + return errno; + } + + return 0; +} + +int sys_ioctl(int fd, unsigned long request, void *arg, int *result) { + int ret, errno; + + if (request == TIOCGPGRP) { + *result = 0; + return 0; + } else if (request == TIOCSPGRP) { + return 0; + } + + SYSCALL3(SYSCALL_IOCTL, fd, request, arg); + + if (ret == -1) { + return errno; + } + + *result = ret; + return 0; +} + +void sys_yield(void) { + int ret, errno; + SYSCALL0(SYSCALL_SCHED_YIELD); +} + +int sys_kill(int pid, int sig) { + int ret, errno; + if (sig == SIGKILL) { + SYSCALL1(SYSCALL_ACTUALLY_KILL, pid); + } else { + SYSCALL2(SYSCALL_SEND_SIGNAL, pid, sig); + } + + return errno; +} + +int sys_dup(int fd, int flags, int *newfd) { + int ret, errno; + if (flags & O_CLOEXEC) { + SYSCALL3(SYSCALL_FCNTL, fd, F_DUPFD_CLOEXEC, 0); + } else { + SYSCALL3(SYSCALL_FCNTL, fd, F_DUPFD, 0); + } + *newfd = ret; + return errno; +} + +int sys_dup2(int fd, int flags, int newfd) { + int ret = sys_close(newfd); + if (ret != 0 && ret != EBADFD) { + return EBADFD; + } + + int errno; + if (flags & O_CLOEXEC) { + SYSCALL3(SYSCALL_FCNTL, fd, F_DUPFD_CLOEXEC, newfd); + } else { + SYSCALL3(SYSCALL_FCNTL, fd, F_DUPFD, newfd); + } + + if (ret != -1 && ret != newfd) { + return EBADFD; + } else { + return errno; + } +} + +int sys_tcgetattr(int fd, struct termios *attr) { + int ret; + + if (int r = sys_ioctl(fd, TCGETS, attr, &ret) != 0) { + return r; + } + + return 0; +} + +int sys_tcsetattr(int fd, int optional_action, const struct termios *attr) { + int ret; + + switch (optional_action) { + case TCSANOW: + optional_action = TCSETS; break; + case TCSADRAIN: + optional_action = TCSETSW; break; + case TCSAFLUSH: + optional_action = TCSETSF; break; + default: + __ensure(!"Unsupported tcsetattr"); + } + + if (int r = sys_ioctl(fd, optional_action, (void *)attr, &ret) != 0) { + return r; + } + + return 0; +} + +int sys_tcflow(int fd, int action) { + int ret; + return sys_ioctl(fd, TCXONC, &action, &ret); +} + +int sys_tcflush(int fd, int action) { + int ret; + return sys_ioctl(fd, TCFLSH, &action, &ret); +} + +int sys_access(const char *path, int mode) { + int ret, errno; + size_t len = strlen(path); + SYSCALL5(SYSCALL_ACCESS, AT_FDCWD, path, len, mode, 0); + return errno; +} + +int sys_faccessat(int dirfd, const char *pathname, int mode, int flags) { + int ret, errno; + size_t len = strlen(pathname); + SYSCALL5(SYSCALL_ACCESS, dirfd, pathname, len, mode, flags); + return errno; +} + +struct futex_item { + uint64_t addr; + uint32_t expected; + uint32_t flags; +}; + +int sys_futex_wait(int *pointer, int expected, const struct timespec *time) { + int ret, errno; + struct futex_item item = {.addr = (uint64_t)pointer, .expected = expected, .flags = 0}; + if (time == NULL) { + struct timespec t = {(time_t)-1, (time_t)-1}; + SYSCALL4(SYSCALL_FUTEX, 0b01, &item, 1, &t); + } else { + SYSCALL4(SYSCALL_FUTEX, 0b01, &item, 1, time); + } + return errno; +} + +int sys_futex_wake(int *pointer) { + int ret, errno; + struct futex_item item = {.addr = (uint64_t)pointer, .expected = 0, .flags = 0}; + struct timespec t = {(time_t)-1, (time_t)-1}; + SYSCALL4(SYSCALL_FUTEX, 0b10, &item, 1, &t); + return errno; +} + +int sys_pipe(int *fds, int flags) { + int ret, errno; + SYSCALL2(SYSCALL_PIPE, fds, flags); + return errno; +} + +int sys_getentropy(void *buffer, size_t length) { + ssize_t ret; + int errno; + SYSCALL2(SYSCALL_GETRANDOM, buffer, length); + return errno; +} + +int sys_mkdir(const char *path, mode_t mode) { + return sys_mkdirat(AT_FDCWD, path, mode); +} + +int sys_mkdirat(int dirfd, const char *path, mode_t mode) { + int ret, errno; + size_t path_len = strlen (path); + SYSCALL5(SYSCALL_MAKENODE, dirfd, path, path_len, S_IFDIR | mode, 0); + return errno; +} + +int sys_rmdir(const char* path){ + int ret, errno; + size_t path_len = strlen (path); + SYSCALL3(SYSCALL_UNLINK, AT_FDCWD, path, path_len); + return errno; +} + +int sys_unlinkat(int fd, const char *path, int flags) { + int ret, errno; + size_t path_len = strlen (path); + SYSCALL3(SYSCALL_UNLINK, fd, path, path_len); + return errno; +} + +int sys_link(const char* srcpath, const char* destpath) { + int ret, errno; + size_t src_len = strlen (srcpath); + size_t dst_len = strlen (destpath); + SYSCALL6(SYSCALL_LINK, AT_FDCWD, srcpath, src_len, AT_FDCWD, destpath, dst_len); + return errno; +} + +int sys_socket(int domain, int type, int protocol, int *fd) { + int ret, errno; + SYSCALL3(SYSCALL_SOCKET, domain, type, protocol); + if (ret != -1) { + *fd = ret; + return 0; + } else { + return errno; + } +} + +uid_t sys_getuid() { + uint64_t ret, errno; + SYSCALL0(SYSCALL_GETUID); + return (uid_t)ret; +} + +uid_t sys_geteuid() { + uint64_t ret, errno; + SYSCALL0(SYSCALL_GETEUID); + return (uid_t)ret; +} + +int sys_setuid(uid_t uid) { + int ret, errno; + SYSCALL2(SYSCALL_SETUIDS, uid, uid); + return ret; +} + +int sys_seteuid(uid_t euid) { + int ret, errno; + SYSCALL2(SYSCALL_SETUIDS, ((uint64_t)-1), euid); + return ret; +} + +int sys_setreuid(uid_t ruid, uid_t euid) { + int ret, errno; + SYSCALL2(SYSCALL_SETUIDS, ruid, euid); + return ret; +} + +gid_t sys_getgid() { + uint64_t ret, errno; + SYSCALL0(SYSCALL_GETGID); + return (gid_t)ret; +} + +gid_t sys_getegid() { + return sys_getgid(); +} + +int sys_setgid(gid_t gid) { + int ret, errno; + SYSCALL2(SYSCALL_SETGIDS, gid, gid); + return ret; +} + +int sys_setegid(gid_t egid) { + int ret, errno; + SYSCALL2(SYSCALL_SETGIDS, ((uint64_t)-1), egid); + return ret; +} + +int sys_setregid(gid_t rgid, gid_t egid) { + int ret, errno; + SYSCALL2(SYSCALL_SETGIDS, rgid, egid); + return ret; +} + +int sys_setsid(pid_t *sid) { + return 0; +} + +#ifndef MLIBC_BUILDING_RTDL + +extern "C" void __mlibc_thread_entry(); + +int sys_clone(void *tcb, pid_t *tid_out, void *stack) { + int ret, errno; + SYSCALL6(SYSCALL_CLONE, (uintptr_t)__mlibc_thread_entry, 0, stack, 0b10, tcb, 1); + + if (ret == -1) { + return errno; + } + + *tid_out = (pid_t)ret; + return 0; +} + +int sys_prepare_stack(void **stack, void *entry, void *arg, void *tcb, size_t *stack_size, size_t *guard_size) { + // TODO guard + + mlibc::infoLogger() << "mlibc: sys_prepare_stack() does not setup a guard!" << frg::endlog; + + *guard_size = 0; + *stack_size = *stack_size ? *stack_size : 0x400000; + + if (!*stack) { + *stack = (void *)((char *)mmap(NULL, *stack_size, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0) + *stack_size); + if (*stack == MAP_FAILED) { + return errno; + } + } + + void **stack_it = (void **)*stack; + + *--stack_it = arg; + *--stack_it = tcb; + *--stack_it = entry; + + *stack = (void *)stack_it; + + return 0; +} + +int sys_clock_getres(int clock, time_t *secs, long *nanos) { + struct timespec time; + int ret, errno; + SYSCALL3(SYSCALL_CLOCK, 0, clock, &time); + *secs = time.tv_sec; + *nanos = time.tv_nsec; + return errno; +} + +int sys_clock_get(int clock, time_t *secs, long *nanos) { + struct timespec time; + int ret, errno; + SYSCALL3(SYSCALL_CLOCK, 1, clock, &time); + *secs = time.tv_sec; + *nanos = time.tv_nsec; + return errno; +} + +int sys_clock_set(int clock, time_t secs, long nanos) { + struct timespec time = {.tv_sec = secs, .tv_nsec = nanos }; + int ret, errno; + SYSCALL3(SYSCALL_CLOCK, 2, clock, &time); + return errno; +} + +int sys_bind(int fd, const struct sockaddr *addr_ptr, socklen_t addrlen) { + int ret, errno; + SYSCALL3(SYSCALL_BIND, fd, addr_ptr, addrlen); + return errno; +} + +int sys_connect(int fd, const struct sockaddr *addr_ptr, socklen_t addrlen) { + int ret, errno; + SYSCALL3(SYSCALL_CONNECT, fd, addr_ptr, addrlen); + return errno; +} + +int sys_listen(int fd, int backlog) { + int ret, errno; + SYSCALL2(SYSCALL_LISTEN, fd, backlog); + return errno; +} + +int sys_accept(int fd, int *newfd, struct sockaddr *addr_ptr, socklen_t *addr_length, int flags) { + int ret, errno; + SYSCALL4(SYSCALL_ACCEPT, fd, addr_ptr, addr_length, flags); + *newfd = ret; + return errno; +} + + +int sys_sockname(int fd, struct sockaddr *addr_ptr, socklen_t max_addr_length, socklen_t *actual_length) { + int ret, errno; + SYSCALL3(SYSCALL_GETSOCKNAME, fd, addr_ptr, &max_addr_length); + *actual_length = max_addr_length; + return errno; +} + +int sys_peername(int fd, struct sockaddr *addr_ptr, socklen_t max_addr_length, socklen_t *actual_length) { + int ret, errno; + SYSCALL3(SYSCALL_GETPEERNAME, fd, addr_ptr, &max_addr_length); + *actual_length = max_addr_length; + return errno; +} + +int sys_shutdown(int sockfd, int how) { + int ret, errno; + SYSCALL2(SYSCALL_SHUTDOWN, sockfd, how); + return errno; +} + +int sys_setitimer(int which, const struct itimerval *new_value, struct itimerval *old_value) { + return ENOSYS; +} + +int sys_msg_recv(int fd, struct msghdr *hdr, int flags, ssize_t *length) { + if (hdr->msg_control != NULL) { + // mlibc::infoLogger() << "mlibc: recv() msg_control not supported!" << frg::endlog; + } + + int ret; + size_t count = 0; + int errno; + + for (int i = 0; i < hdr->msg_iovlen; i++) { + SYSCALL6(SYSCALL_RECVFROM, fd, hdr->msg_iov->iov_base, hdr->msg_iov->iov_len, + hdr->msg_flags, hdr->msg_name, hdr->msg_namelen); + if (ret == -1) { + return errno; + } + count += ret; + } + + *length = count; + return 0; +} + +int sys_msg_send(int fd, const struct msghdr *hdr, int flags, ssize_t *length) { + if (hdr->msg_control != NULL) { + // mlibc::infoLogger() << "mlibc: recv() msg_control not supported!" << frg::endlog; + } + + int ret; + size_t count = 0; + int errno; + + for (int i = 0; i < hdr->msg_iovlen; i++) { + SYSCALL6(SYSCALL_SENDTO, fd, hdr->msg_iov->iov_base, hdr->msg_iov->iov_len, + hdr->msg_flags, hdr->msg_name, hdr->msg_namelen); + if (ret == -1) { + return errno; + } + count += ret; + } + + *length = count; + return 0; +} + + +int sys_ppoll(struct pollfd *fds, int nfds, const struct timespec *timeout, const sigset_t *sigmask, int *num_events) { + // XXX: Ironclad has no sigprogmask so this is basically a weird ppoll poll + // chimeral abomination. + int ret, errno; + if (timeout == NULL) { + struct timespec t = {.tv_sec = (time_t)-1, .tv_nsec = (time_t)-1}; + SYSCALL3(SYSCALL_POLL, fds, nfds, &t); + } else { + SYSCALL3(SYSCALL_POLL, fds, nfds, timeout); + } + if (ret == -1) { + return errno; + } + + *num_events = ret; + return errno; +} + +int sys_poll(struct pollfd *fds, nfds_t count, int timeout, int *num_events) { + struct timespec ts; + ts.tv_sec = timeout / 1000; + ts.tv_nsec = (timeout % 1000) * 1000000; + return sys_ppoll(fds, count, timeout == -1 ? NULL : &ts, NULL, num_events); +} + +int sys_pselect(int nfds, fd_set *read_set, fd_set *write_set, + fd_set *except_set, const struct timespec *timeout, + const sigset_t *sigmask, int *num_events) { + struct pollfd *fds = (struct pollfd *)calloc(nfds, sizeof(struct pollfd)); + if (fds == NULL) { + return ENOMEM; + } + + for (int i = 0; i < nfds; i++) { + struct pollfd *fd = &fds[i]; + + if (read_set && FD_ISSET(i, read_set)) { + fd->events |= POLLIN; + } + if (write_set && FD_ISSET(i, write_set)) { + fd->events |= POLLOUT; + } + if (except_set && FD_ISSET(i, except_set)) { + fd->events |= POLLPRI; + } + + if (!fd->events) { + fd->fd = -1; + continue; + } + fd->fd = i; + } + + int ret = sys_ppoll(fds, nfds, timeout, sigmask, num_events); + if (ret != 0) { + free(fds); + return ret; + } + + fd_set res_read_set, res_write_set, res_except_set; + FD_ZERO(&res_read_set); + FD_ZERO(&res_write_set); + FD_ZERO(&res_except_set); + + for (int i = 0; i < nfds; i++) { + struct pollfd *fd = &fds[i]; + + if (read_set && FD_ISSET(i, read_set) && (fd->revents & (POLLIN | POLLERR | POLLHUP)) != 0) { + FD_SET(i, &res_read_set); + } + if (write_set && FD_ISSET(i, write_set) && (fd->revents & (POLLOUT | POLLERR | POLLHUP)) != 0) { + FD_SET(i, &res_write_set); + } + if (except_set && FD_ISSET(i, except_set) && (fd->revents & POLLPRI) != 0) { + FD_SET(i, &res_except_set); + } + } + + free(fds); + if (read_set) { + *read_set = res_read_set; + } + if (write_set) { + *write_set = res_write_set; + } + if (except_set) { + *except_set = res_except_set; + } + + return 0; +} + +int sys_sleep(time_t *secs, long *nanos) { + struct timespec time = {.tv_sec = *secs, .tv_nsec = *nanos}; + struct timespec rem = {.tv_sec = 0, .tv_nsec = 0}; + + int ret, errno; + SYSCALL4(SYSCALL_CLOCK_NANOSLEEP, CLOCK_MONOTONIC, 0, &time, &rem); + *secs = rem.tv_sec; + *nanos = rem.tv_nsec; + return errno; +} + +int sys_gethostname(char *buffer, size_t bufsize) { + struct utsname buf; + if (uname(&buf)) { + return -1; + } + + strncpy(buffer, buf.nodename, bufsize); + return 0; +} + +int sys_utimensat(int dirfd, const char *pathname, const struct timespec times[2], int flags) { + int ret, errno; + if (pathname == NULL) { + pathname = ""; + flags |= AT_EMPTY_PATH; + } + + size_t path_len = strlen (pathname); + if (times == NULL) { + time_t secs; + long nsec; + ret = sys_clock_get(CLOCK_REALTIME, &secs, &nsec); + if (ret) { + return ret; + } + struct timespec times2[2] = {0, 0}; + times2[0].tv_sec = secs; + times2[0].tv_nsec = nsec; + times2[1].tv_sec = secs; + times2[1].tv_nsec = nsec; + SYSCALL5(SYSCALL_UTIMES, dirfd, pathname, path_len, ×2[0], flags); + } else { + SYSCALL5(SYSCALL_UTIMES, dirfd, pathname, path_len, times, flags); + } + + return errno; +} + +int sys_sysconf(int num, long *rret) { + long ret, errno; + SYSCALL3(SYSCALL_SYSCONF, num, 0, 0); + *rret = ret; + return errno; +} + +int sys_stat(fsfd_target fsfdt, int fd, const char *path, int flags, struct stat *statbuf) { + int ret, errno; + (void)flags; + + switch (fsfdt) { + case fsfd_target::fd: { + SYSCALL5(SYSCALL_STAT, fd, "", 0, statbuf, AT_EMPTY_PATH); + break; + } + case fsfd_target::path: { + size_t len = strlen(path); + SYSCALL5(SYSCALL_STAT, AT_FDCWD, path, len, statbuf, flags); + break; + } + case fsfd_target::fd_path: { + size_t len = strlen(path); + SYSCALL5(SYSCALL_STAT, fd, path, len, statbuf, flags); + break; + } + default: { + __ensure(!"stat: Invalid fsfdt"); + __builtin_unreachable(); + } + } + + return errno; +} + +int sys_chmod(const char *pathname, mode_t mode) { + int ret, errno; + size_t len = strlen(pathname); + SYSCALL5(SYSCALL_FCHMOD, AT_FDCWD, pathname, len, mode, 0); + return errno; +} + +int sys_fchmodat(int fd, const char *pathname, mode_t mode, int flags) { + int ret, errno; + size_t len = strlen(pathname); + SYSCALL5(SYSCALL_FCHMOD, fd, pathname, len, mode, flags); + return errno; +} + +int sys_fchmod(int fd, mode_t mode) { + int ret, errno; + SYSCALL5(SYSCALL_FCHMOD, fd, "", 0, mode, AT_EMPTY_PATH); + return errno; +} + +int sys_chown(const char *pathname, uid_t uid, gid_t gid) { + int ret, errno; + size_t len = strlen(pathname); + SYSCALL6(SYSCALL_FCHOWN, AT_FDCWD, pathname, len, uid, gid, 0); + return errno; +} + +int sys_fchownat(int fd, const char *pathname, uid_t uid, gid_t gid, int flags) { + int ret, errno; + size_t len = strlen(pathname); + SYSCALL6(SYSCALL_FCHOWN, fd, pathname, len, uid, gid, flags); + return errno; +} + +int sys_fchown(int fd, uid_t uid, gid_t gid) { + int ret, errno; + SYSCALL6(SYSCALL_FCHOWN, fd, "", 0, uid, gid, AT_EMPTY_PATH); + return errno; +} + +int sys_umask(mode_t mode, mode_t *old) { + mode_t ret; + int errno; + SYSCALL1(SYSCALL_UMASK, mode); + *old = (mode_t)ret; + return errno; +} + +int sys_fadvise(int fd, off_t offset, off_t length, int advice) { + int ret, errno; + SYSCALL4(SYSCALL_FADVISE, fd, offset, length, advice); + return errno; +} + +int sys_readlink(const char *path, void *buffer, size_t max_size, ssize_t *length) { + ssize_t ret; + int errno; + size_t path_len = strlen(path); + SYSCALL5(SYSCALL_READLINK, AT_FDCWD, path, path_len, buffer, max_size); + if (ret == -1) { + return errno; + } else { + *length = ret; + return 0; + } +} + +int sys_rename(const char *path, const char *new_path) { + int ret; + int errno; + size_t old_len = strlen(path); + size_t new_len = strlen(new_path); + SYSCALL7(SYSCALL_RENAME, AT_FDCWD, path, old_len, AT_FDCWD, new_path, new_len, 0); + return errno; +} + +int sys_renameat(int olddirfd, const char *old_path, int newdirfd, const char *new_path) { + int ret; + int errno; + size_t old_len = strlen(old_path); + size_t new_len = strlen(new_path); + SYSCALL7(SYSCALL_RENAME, olddirfd, old_path, old_len, newdirfd, new_path, new_len, 0); + return errno; +} + +int sys_mknodat(int dirfd, const char *path, mode_t mode, dev_t dev) { + int ret; + int errno; + size_t len = strlen(path); + SYSCALL5(SYSCALL_MAKENODE, dirfd, path, len, mode, dev); + return errno; +} + +#define SC_LIST_MOUNTS 9 +struct mountinfo { + uint32_t type; + uint32_t flags; + char source[20]; + uint32_t source_length; + char location[20]; + uint32_t location_length; + uint64_t block_size; + uint64_t fragment_size; + uint64_t size_in_fragments; + uint64_t free_blocks; + uint64_t free_blocks_user; + uint64_t inode_count; + uint64_t free_inodes; + uint64_t free_inodes_user; + uint64_t max_filename; +}; + +#include + +int sys_fstatvfs(int fd, struct statvfs *out) { + return sys_statvfs("/", out); +} + +int sys_statvfs(const char *path, struct statvfs *out) { + long ret, errno; + struct mountinfo *buffer = (mountinfo *)malloc(5 * sizeof(struct mountinfo)); + SYSCALL3(SYSCALL_SYSCONF, SC_LIST_MOUNTS, buffer, 5 * sizeof(struct mountinfo)); + if (errno) { + free(buffer); + return errno; + } else if (ret > 5) { + free(buffer); + return 1; + } + + for (int i = 0; i < ret; i++) { + if (!strncmp(path, buffer[i].location, buffer[i].location_length)) { + out->f_bsize = buffer[i].block_size; + out->f_frsize = buffer[i].fragment_size; + out->f_blocks = buffer[i].size_in_fragments; + out->f_bfree = buffer[i].free_blocks; + out->f_bavail = buffer[i].free_blocks_user; + out->f_files = buffer[i].inode_count; + out->f_ffree = buffer[i].free_inodes; + out->f_favail = buffer[i].free_inodes_user; + out->f_fsid = 0; + out->f_flag = buffer[i].flags; + out->f_namemax = buffer[i].max_filename; + if (buffer[i].type == MNT_EXT) { + strcpy(out->f_basetype, "ext"); + } else { + strcpy(out->f_basetype, "fat"); + } + return 0; + } + } + + return EINVAL; +} +#endif +} // namespace mlibc diff --git a/lib/mlibc/sysdeps/ironclad/generic/mac.cpp b/lib/mlibc/sysdeps/ironclad/generic/mac.cpp new file mode 100644 index 0000000..12b63d8 --- /dev/null +++ b/lib/mlibc/sysdeps/ironclad/generic/mac.cpp @@ -0,0 +1,32 @@ +#include +#include +#include +#include + +extern "C" { + +unsigned long get_mac_capabilities(void) { + int ret; + SYSCALL0(SYSCALL_GET_MAC_CAPABILITIES); + return ret; +} + +int set_mac_capabilities(unsigned long request) { + int ret; + SYSCALL1(SYSCALL_SET_MAC_CAPABILITIES, request); + return ret; +} + +int add_mac_permissions(const char *path, int flags) { + int ret; + SYSCALL3(SYSCALL_ADD_MAC_PERMISSIONS, path, strlen(path), flags); + return ret; +} + +int set_mac_enforcement(unsigned long enforcement) { + int ret; + SYSCALL1(SYSCALL_SET_MAC_ENFORCEMENT, enforcement); + return ret; +} + +} diff --git a/lib/mlibc/sysdeps/ironclad/generic/mntent.cpp b/lib/mlibc/sysdeps/ironclad/generic/mntent.cpp new file mode 100644 index 0000000..d064af3 --- /dev/null +++ b/lib/mlibc/sysdeps/ironclad/generic/mntent.cpp @@ -0,0 +1,97 @@ +#include +#include +#include +#include +#include +#include + +namespace { + +char *internal_buf; +size_t internal_bufsize; + +} + +#define SENTINEL (char *)&internal_buf + +FILE *setmntent(const char *name, const char *mode) { + return fopen(name, mode); +} + +struct mntent *getmntent(FILE *f) { + static struct mntent mnt; + return getmntent_r(f, &mnt, SENTINEL, 0); +} + +int addmntent(FILE *f, const struct mntent *mnt) { + if(fseek(f, 0, SEEK_END)) { + return 1; + } + return fprintf(f, "%s\t%s\t%s\t%s\t%d\t%d\n", + mnt->mnt_fsname, mnt->mnt_dir, mnt->mnt_type, mnt->mnt_opts, + mnt->mnt_freq, mnt->mnt_passno) < 0; +} + +int endmntent(FILE *f) { + if(f) { + fclose(f); + } + return 1; +} + +char *hasmntopt(const struct mntent *mnt, const char *opt) { + return strstr(mnt->mnt_opts, opt); +} + +/* Adapted from musl */ +struct mntent *getmntent_r(FILE *f, struct mntent *mnt, char *linebuf, int buflen) { + int n[8]; + bool use_internal = (linebuf == SENTINEL); + int len; + size_t i; + + mnt->mnt_freq = 0; + mnt->mnt_passno = 0; + + do { + if(use_internal) { + getline(&internal_buf, &internal_bufsize, f); + linebuf = internal_buf; + } else { + fgets(linebuf, buflen, f); + } + if(feof(f) || ferror(f)) { + return 0; + } + if(!strchr(linebuf, '\n')) { + fscanf(f, "%*[^\n]%*[\n]"); + errno = ERANGE; + return 0; + } + + len = strlen(linebuf); + if(len > INT_MAX) { + continue; + } + + for(i = 0; i < sizeof n / sizeof *n; i++) { + n[i] = len; + } + + sscanf(linebuf, " %n%*s%n %n%*s%n %n%*s%n %n%*s%n %d %d", + n, n + 1, n + 2, n + 3, n + 4, n + 5, n + 6, n + 7, + &mnt->mnt_freq, &mnt->mnt_passno); + } while(linebuf[n[0]] == '#' || n[1] == len); + + linebuf[n[1]] = 0; + linebuf[n[3]] = 0; + linebuf[n[5]] = 0; + linebuf[n[7]] = 0; + + mnt->mnt_fsname = linebuf + n[0]; + mnt->mnt_dir = linebuf + n[2]; + mnt->mnt_type = linebuf + n[4]; + mnt->mnt_opts = linebuf + n[6]; + + return mnt; +} diff --git a/lib/mlibc/sysdeps/ironclad/generic/mount.cpp b/lib/mlibc/sysdeps/ironclad/generic/mount.cpp new file mode 100644 index 0000000..feb6e4c --- /dev/null +++ b/lib/mlibc/sysdeps/ironclad/generic/mount.cpp @@ -0,0 +1,20 @@ +#include +#include +#include +#include +#include + +int mount(const char *source, const char *target, int type, int flags) { + int ret; + size_t source_len = strlen(source); + size_t target_len = strlen(target); + SYSCALL6(SYSCALL_MOUNT, source, source_len, target, target_len, type, flags); + return ret; +} + +int umount(const char *target, int flags) { + int ret; + size_t target_len = strlen(target); + SYSCALL3(SYSCALL_UMOUNT, target, target_len, flags); + return ret; +} diff --git a/lib/mlibc/sysdeps/ironclad/generic/ptrace.cpp b/lib/mlibc/sysdeps/ironclad/generic/ptrace.cpp new file mode 100644 index 0000000..58a8dd2 --- /dev/null +++ b/lib/mlibc/sysdeps/ironclad/generic/ptrace.cpp @@ -0,0 +1,9 @@ +#include +#include +#include + +int ptrace(int request, pid_t pid, void *addr, void *data) { + int ret; + SYSCALL4(SYSCALL_PTRACE, request, pid, addr, data); + return ret; +} diff --git a/lib/mlibc/sysdeps/ironclad/generic/pty.cpp b/lib/mlibc/sysdeps/ironclad/generic/pty.cpp new file mode 100644 index 0000000..1626e4b --- /dev/null +++ b/lib/mlibc/sysdeps/ironclad/generic/pty.cpp @@ -0,0 +1,41 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int openpty(int *mfd, int *sfd, char *name, const struct termios *ios, const struct winsize *win) { + int ret; + int fds[2]; + SYSCALL1(SYSCALL_OPENPTY, fds); + if (errno) { + return -1; + } + *mfd = fds[0]; + *sfd = fds[1]; + + if (name != NULL) { + ret = ttyname_r(*mfd, name, (size_t)-1); + if (ret) { + return -1; + } + } + if (ios != NULL) { + ret = tcsetattr(*mfd, TCSANOW, ios); + if (ret) { + return -1; + } + } + if (win != NULL) { + ret = ioctl(*mfd, TIOCGWINSZ, win); + if (ret) { + return -1; + } + } + return ret; +} diff --git a/lib/mlibc/sysdeps/ironclad/generic/reboot.cpp b/lib/mlibc/sysdeps/ironclad/generic/reboot.cpp new file mode 100644 index 0000000..45e8f03 --- /dev/null +++ b/lib/mlibc/sysdeps/ironclad/generic/reboot.cpp @@ -0,0 +1,9 @@ +#include +#include +#include + +int reboot(int what) { + int ret, errno; + SYSCALL2(SYSCALL_REBOOT, what, 0); + return ret; +} diff --git a/lib/mlibc/sysdeps/ironclad/generic/sched2.cpp b/lib/mlibc/sysdeps/ironclad/generic/sched2.cpp new file mode 100644 index 0000000..9699517 --- /dev/null +++ b/lib/mlibc/sysdeps/ironclad/generic/sched2.cpp @@ -0,0 +1,20 @@ +#include +#include +#include +#include + +extern "C" { + +int get_thread_sched(void) { + return 0; +} + +int set_thread_sched(int flags) { + return 0; +} + +int set_deadlines(int runtime, int period) { + return 0; +} + +} diff --git a/lib/mlibc/sysdeps/ironclad/generic/thread.S b/lib/mlibc/sysdeps/ironclad/generic/thread.S new file mode 100644 index 0000000..47ab6a9 --- /dev/null +++ b/lib/mlibc/sysdeps/ironclad/generic/thread.S @@ -0,0 +1,9 @@ +.section .text +.global __mlibc_thread_entry +__mlibc_thread_entry: + pop %rdi + pop %rsi + pop %rdx + call __mlibc_thread_trampoline + +.section .note.GNU-stack,"",%progbits diff --git a/lib/mlibc/sysdeps/ironclad/generic/thread.cpp b/lib/mlibc/sysdeps/ironclad/generic/thread.cpp new file mode 100644 index 0000000..1b2f040 --- /dev/null +++ b/lib/mlibc/sysdeps/ironclad/generic/thread.cpp @@ -0,0 +1,54 @@ +#include +#include +#include +#include +#include +#include + +extern "C" void __mlibc_thread_trampoline(void *(*fn)(void *), Tcb *tcb, void *arg) { + while (__atomic_load_n(&tcb->tid, __ATOMIC_RELAXED) == 0) { + mlibc::sys_futex_wait(&tcb->tid, 0, nullptr); + } + + tcb->invokeThreadFunc(reinterpret_cast(fn), arg); + + __atomic_store_n(&tcb->didExit, 1, __ATOMIC_RELEASE); + mlibc::sys_futex_wake(&tcb->didExit); + + mlibc::sys_thread_exit(); +} + +#define DEFAULT_STACK 0x20000 + +namespace mlibc { + int sys_prepare_stack(void **stack, void *entry, void *arg, void *tcb, size_t *stack_size, size_t *guard_size, void **stack_base) { + // TODO guard + + mlibc::infoLogger() << "mlibc: sys_prepare_stack() does not setup a guard!" << frg::endlog; + + *guard_size = 0; + + *stack_size = *stack_size ? *stack_size : DEFAULT_STACK; + + if (!*stack) { + *stack_base = mmap(NULL, *stack_size, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); + if (*stack_base == MAP_FAILED) { + return errno; + } + } else { + *stack_base = *stack; + } + + *stack = (void *)((char *)*stack_base + *stack_size); + + void **stack_it = (void **)*stack; + + *--stack_it = arg; + *--stack_it = tcb; + *--stack_it = entry; + + *stack = (void *)stack_it; + + return 0; + } +} diff --git a/lib/mlibc/sysdeps/ironclad/generic/utmpx.cpp b/lib/mlibc/sysdeps/ironclad/generic/utmpx.cpp new file mode 100644 index 0000000..ec74e22 --- /dev/null +++ b/lib/mlibc/sysdeps/ironclad/generic/utmpx.cpp @@ -0,0 +1,76 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int utmpx_file = -1; + +void updwtmpx(const char *, const struct utmpx *) { + // Empty as musl does +} + +void endutxent(void) { + if (utmpx_file >= 0) { + close(utmpx_file); + } +} + +void setutxent(void) { + if (utmpx_file < 0) { + utmpx_file = open(UTMPX_FILE, O_RDWR | O_CREAT, 0755); + } else { + lseek(utmpx_file, 0, SEEK_SET); + } +} + +struct utmpx returned; + +struct utmpx *getutxent(void) { + if (utmpx_file < 0) { + setutxent(); + if (utmpx_file < 0) { + return NULL; + } + } + + if (read(utmpx_file, &returned, sizeof(struct utmpx)) != sizeof(struct utmpx)) { + return NULL; + } + + return &returned; +} + +struct utmpx *pututxline(const struct utmpx *added) { + if (utmpx_file < 0) { + setutxent(); + if (utmpx_file < 0) { + return NULL; + } + } + + lseek(utmpx_file, 0, SEEK_END); + if (write(utmpx_file, added, sizeof(struct utmpx)) != sizeof(struct utmpx)) { + return NULL; + } + + return (struct utmpx *)added; +} + +int utmpxname(const char *path) { + if (utmpx_file > 0) { + close(utmpx_file); + } + + utmpx_file = open(path, O_RDWR | O_CREAT, 0755); + if (utmpx_file > 0) { + lseek(utmpx_file, 0, SEEK_END); + return 1; + } else { + return 0; + } +} diff --git a/lib/mlibc/sysdeps/ironclad/include/abi-bits/access.h b/lib/mlibc/sysdeps/ironclad/include/abi-bits/access.h new file mode 120000 index 0000000..8f0556a --- /dev/null +++ b/lib/mlibc/sysdeps/ironclad/include/abi-bits/access.h @@ -0,0 +1 @@ +../../../../abis/ironclad/access.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/ironclad/include/abi-bits/auxv.h b/lib/mlibc/sysdeps/ironclad/include/abi-bits/auxv.h new file mode 120000 index 0000000..f9be899 --- /dev/null +++ b/lib/mlibc/sysdeps/ironclad/include/abi-bits/auxv.h @@ -0,0 +1 @@ +../../../../abis/ironclad/auxv.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/ironclad/include/abi-bits/blkcnt_t.h b/lib/mlibc/sysdeps/ironclad/include/abi-bits/blkcnt_t.h new file mode 120000 index 0000000..02c7cf3 --- /dev/null +++ b/lib/mlibc/sysdeps/ironclad/include/abi-bits/blkcnt_t.h @@ -0,0 +1 @@ +../../../../abis/ironclad/blkcnt_t.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/ironclad/include/abi-bits/blksize_t.h b/lib/mlibc/sysdeps/ironclad/include/abi-bits/blksize_t.h new file mode 120000 index 0000000..1745393 --- /dev/null +++ b/lib/mlibc/sysdeps/ironclad/include/abi-bits/blksize_t.h @@ -0,0 +1 @@ +../../../../abis/ironclad/blksize_t.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/ironclad/include/abi-bits/clockid_t.h b/lib/mlibc/sysdeps/ironclad/include/abi-bits/clockid_t.h new file mode 120000 index 0000000..b05d507 --- /dev/null +++ b/lib/mlibc/sysdeps/ironclad/include/abi-bits/clockid_t.h @@ -0,0 +1 @@ +../../../../abis/ironclad/clockid_t.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/ironclad/include/abi-bits/dev_t.h b/lib/mlibc/sysdeps/ironclad/include/abi-bits/dev_t.h new file mode 120000 index 0000000..e403f5b --- /dev/null +++ b/lib/mlibc/sysdeps/ironclad/include/abi-bits/dev_t.h @@ -0,0 +1 @@ +../../../../abis/ironclad/dev_t.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/ironclad/include/abi-bits/epoll.h b/lib/mlibc/sysdeps/ironclad/include/abi-bits/epoll.h new file mode 120000 index 0000000..0364554 --- /dev/null +++ b/lib/mlibc/sysdeps/ironclad/include/abi-bits/epoll.h @@ -0,0 +1 @@ +../../../../abis/ironclad/epoll.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/ironclad/include/abi-bits/errno.h b/lib/mlibc/sysdeps/ironclad/include/abi-bits/errno.h new file mode 120000 index 0000000..ec9b8f6 --- /dev/null +++ b/lib/mlibc/sysdeps/ironclad/include/abi-bits/errno.h @@ -0,0 +1 @@ +../../../../abis/ironclad/errno.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/ironclad/include/abi-bits/fcntl.h b/lib/mlibc/sysdeps/ironclad/include/abi-bits/fcntl.h new file mode 120000 index 0000000..c60789c --- /dev/null +++ b/lib/mlibc/sysdeps/ironclad/include/abi-bits/fcntl.h @@ -0,0 +1 @@ +../../../../abis/ironclad/fcntl.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/ironclad/include/abi-bits/fsblkcnt_t.h b/lib/mlibc/sysdeps/ironclad/include/abi-bits/fsblkcnt_t.h new file mode 120000 index 0000000..c5e0d6a --- /dev/null +++ b/lib/mlibc/sysdeps/ironclad/include/abi-bits/fsblkcnt_t.h @@ -0,0 +1 @@ +../../../../abis/ironclad/fsblkcnt_t.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/ironclad/include/abi-bits/fsfilcnt_t.h b/lib/mlibc/sysdeps/ironclad/include/abi-bits/fsfilcnt_t.h new file mode 120000 index 0000000..b8925b8 --- /dev/null +++ b/lib/mlibc/sysdeps/ironclad/include/abi-bits/fsfilcnt_t.h @@ -0,0 +1 @@ +../../../../abis/ironclad/fsfilcnt_t.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/ironclad/include/abi-bits/gid_t.h b/lib/mlibc/sysdeps/ironclad/include/abi-bits/gid_t.h new file mode 120000 index 0000000..1ee9676 --- /dev/null +++ b/lib/mlibc/sysdeps/ironclad/include/abi-bits/gid_t.h @@ -0,0 +1 @@ +../../../../abis/ironclad/gid_t.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/ironclad/include/abi-bits/in.h b/lib/mlibc/sysdeps/ironclad/include/abi-bits/in.h new file mode 120000 index 0000000..e10e010 --- /dev/null +++ b/lib/mlibc/sysdeps/ironclad/include/abi-bits/in.h @@ -0,0 +1 @@ +../../../../abis/ironclad/in.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/ironclad/include/abi-bits/ino_t.h b/lib/mlibc/sysdeps/ironclad/include/abi-bits/ino_t.h new file mode 120000 index 0000000..8da8d60 --- /dev/null +++ b/lib/mlibc/sysdeps/ironclad/include/abi-bits/ino_t.h @@ -0,0 +1 @@ +../../../../abis/ironclad/ino_t.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/ironclad/include/abi-bits/inotify.h b/lib/mlibc/sysdeps/ironclad/include/abi-bits/inotify.h new file mode 120000 index 0000000..95578b0 --- /dev/null +++ b/lib/mlibc/sysdeps/ironclad/include/abi-bits/inotify.h @@ -0,0 +1 @@ +../../../../abis/ironclad/inotify.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/ironclad/include/abi-bits/ioctls.h b/lib/mlibc/sysdeps/ironclad/include/abi-bits/ioctls.h new file mode 120000 index 0000000..d532c47 --- /dev/null +++ b/lib/mlibc/sysdeps/ironclad/include/abi-bits/ioctls.h @@ -0,0 +1 @@ +../../../../abis/ironclad/ioctls.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/ironclad/include/abi-bits/limits.h b/lib/mlibc/sysdeps/ironclad/include/abi-bits/limits.h new file mode 120000 index 0000000..9f4938c --- /dev/null +++ b/lib/mlibc/sysdeps/ironclad/include/abi-bits/limits.h @@ -0,0 +1 @@ +../../../../abis/ironclad/limits.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/ironclad/include/abi-bits/mode_t.h b/lib/mlibc/sysdeps/ironclad/include/abi-bits/mode_t.h new file mode 120000 index 0000000..47764b7 --- /dev/null +++ b/lib/mlibc/sysdeps/ironclad/include/abi-bits/mode_t.h @@ -0,0 +1 @@ +../../../../abis/ironclad/mode_t.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/ironclad/include/abi-bits/mqueue.h b/lib/mlibc/sysdeps/ironclad/include/abi-bits/mqueue.h new file mode 120000 index 0000000..394c37d --- /dev/null +++ b/lib/mlibc/sysdeps/ironclad/include/abi-bits/mqueue.h @@ -0,0 +1 @@ +../../../../abis/ironclad/mqueue.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/ironclad/include/abi-bits/msg.h b/lib/mlibc/sysdeps/ironclad/include/abi-bits/msg.h new file mode 120000 index 0000000..7c59866 --- /dev/null +++ b/lib/mlibc/sysdeps/ironclad/include/abi-bits/msg.h @@ -0,0 +1 @@ +../../../../abis/ironclad/msg.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/ironclad/include/abi-bits/nlink_t.h b/lib/mlibc/sysdeps/ironclad/include/abi-bits/nlink_t.h new file mode 120000 index 0000000..a5c8e25 --- /dev/null +++ b/lib/mlibc/sysdeps/ironclad/include/abi-bits/nlink_t.h @@ -0,0 +1 @@ +../../../../abis/ironclad/nlink_t.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/ironclad/include/abi-bits/packet.h b/lib/mlibc/sysdeps/ironclad/include/abi-bits/packet.h new file mode 120000 index 0000000..5a7a333 --- /dev/null +++ b/lib/mlibc/sysdeps/ironclad/include/abi-bits/packet.h @@ -0,0 +1 @@ +../../../../abis/ironclad/packet.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/ironclad/include/abi-bits/pid_t.h b/lib/mlibc/sysdeps/ironclad/include/abi-bits/pid_t.h new file mode 120000 index 0000000..36e4068 --- /dev/null +++ b/lib/mlibc/sysdeps/ironclad/include/abi-bits/pid_t.h @@ -0,0 +1 @@ +../../../../abis/ironclad/pid_t.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/ironclad/include/abi-bits/poll.h b/lib/mlibc/sysdeps/ironclad/include/abi-bits/poll.h new file mode 120000 index 0000000..156ddd9 --- /dev/null +++ b/lib/mlibc/sysdeps/ironclad/include/abi-bits/poll.h @@ -0,0 +1 @@ +../../../../abis/ironclad/poll.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/ironclad/include/abi-bits/ptrace.h b/lib/mlibc/sysdeps/ironclad/include/abi-bits/ptrace.h new file mode 120000 index 0000000..1260bf7 --- /dev/null +++ b/lib/mlibc/sysdeps/ironclad/include/abi-bits/ptrace.h @@ -0,0 +1 @@ +../../../../abis/ironclad/ptrace.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/ironclad/include/abi-bits/reboot.h b/lib/mlibc/sysdeps/ironclad/include/abi-bits/reboot.h new file mode 120000 index 0000000..23c9af3 --- /dev/null +++ b/lib/mlibc/sysdeps/ironclad/include/abi-bits/reboot.h @@ -0,0 +1 @@ +../../../../abis/ironclad/reboot.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/ironclad/include/abi-bits/resource.h b/lib/mlibc/sysdeps/ironclad/include/abi-bits/resource.h new file mode 120000 index 0000000..e950420 --- /dev/null +++ b/lib/mlibc/sysdeps/ironclad/include/abi-bits/resource.h @@ -0,0 +1 @@ +../../../../abis/ironclad/resource.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/ironclad/include/abi-bits/seek-whence.h b/lib/mlibc/sysdeps/ironclad/include/abi-bits/seek-whence.h new file mode 120000 index 0000000..fbd0a8f --- /dev/null +++ b/lib/mlibc/sysdeps/ironclad/include/abi-bits/seek-whence.h @@ -0,0 +1 @@ +../../../../abis/ironclad/seek-whence.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/ironclad/include/abi-bits/shm.h b/lib/mlibc/sysdeps/ironclad/include/abi-bits/shm.h new file mode 120000 index 0000000..f20c4fc --- /dev/null +++ b/lib/mlibc/sysdeps/ironclad/include/abi-bits/shm.h @@ -0,0 +1 @@ +../../../../abis/ironclad/shm.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/ironclad/include/abi-bits/signal.h b/lib/mlibc/sysdeps/ironclad/include/abi-bits/signal.h new file mode 120000 index 0000000..ae8aa10 --- /dev/null +++ b/lib/mlibc/sysdeps/ironclad/include/abi-bits/signal.h @@ -0,0 +1 @@ +../../../../abis/ironclad/signal.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/ironclad/include/abi-bits/socket.h b/lib/mlibc/sysdeps/ironclad/include/abi-bits/socket.h new file mode 120000 index 0000000..5ddea1c --- /dev/null +++ b/lib/mlibc/sysdeps/ironclad/include/abi-bits/socket.h @@ -0,0 +1 @@ +../../../../abis/ironclad/socket.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/ironclad/include/abi-bits/socklen_t.h b/lib/mlibc/sysdeps/ironclad/include/abi-bits/socklen_t.h new file mode 120000 index 0000000..7db34a4 --- /dev/null +++ b/lib/mlibc/sysdeps/ironclad/include/abi-bits/socklen_t.h @@ -0,0 +1 @@ +../../../../abis/ironclad/socklen_t.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/ironclad/include/abi-bits/stat.h b/lib/mlibc/sysdeps/ironclad/include/abi-bits/stat.h new file mode 120000 index 0000000..a307c32 --- /dev/null +++ b/lib/mlibc/sysdeps/ironclad/include/abi-bits/stat.h @@ -0,0 +1 @@ +../../../../abis/ironclad/stat.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/ironclad/include/abi-bits/statfs.h b/lib/mlibc/sysdeps/ironclad/include/abi-bits/statfs.h new file mode 120000 index 0000000..bc1f622 --- /dev/null +++ b/lib/mlibc/sysdeps/ironclad/include/abi-bits/statfs.h @@ -0,0 +1 @@ +../../../../abis/ironclad/statfs.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/ironclad/include/abi-bits/statvfs.h b/lib/mlibc/sysdeps/ironclad/include/abi-bits/statvfs.h new file mode 120000 index 0000000..e0b90f0 --- /dev/null +++ b/lib/mlibc/sysdeps/ironclad/include/abi-bits/statvfs.h @@ -0,0 +1 @@ +../../../../abis/ironclad/statvfs.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/ironclad/include/abi-bits/suseconds_t.h b/lib/mlibc/sysdeps/ironclad/include/abi-bits/suseconds_t.h new file mode 120000 index 0000000..88197dd --- /dev/null +++ b/lib/mlibc/sysdeps/ironclad/include/abi-bits/suseconds_t.h @@ -0,0 +1 @@ +../../../../abis/ironclad/suseconds_t.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/ironclad/include/abi-bits/termios.h b/lib/mlibc/sysdeps/ironclad/include/abi-bits/termios.h new file mode 120000 index 0000000..a6bacb3 --- /dev/null +++ b/lib/mlibc/sysdeps/ironclad/include/abi-bits/termios.h @@ -0,0 +1 @@ +../../../../abis/ironclad/termios.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/ironclad/include/abi-bits/time.h b/lib/mlibc/sysdeps/ironclad/include/abi-bits/time.h new file mode 120000 index 0000000..fa8e486 --- /dev/null +++ b/lib/mlibc/sysdeps/ironclad/include/abi-bits/time.h @@ -0,0 +1 @@ +../../../../abis/ironclad/time.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/ironclad/include/abi-bits/uid_t.h b/lib/mlibc/sysdeps/ironclad/include/abi-bits/uid_t.h new file mode 120000 index 0000000..1aebbe3 --- /dev/null +++ b/lib/mlibc/sysdeps/ironclad/include/abi-bits/uid_t.h @@ -0,0 +1 @@ +../../../../abis/ironclad/uid_t.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/ironclad/include/abi-bits/utsname.h b/lib/mlibc/sysdeps/ironclad/include/abi-bits/utsname.h new file mode 120000 index 0000000..0a5dbc8 --- /dev/null +++ b/lib/mlibc/sysdeps/ironclad/include/abi-bits/utsname.h @@ -0,0 +1 @@ +../../../../abis/ironclad/utsname.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/ironclad/include/abi-bits/vm-flags.h b/lib/mlibc/sysdeps/ironclad/include/abi-bits/vm-flags.h new file mode 120000 index 0000000..6dc4788 --- /dev/null +++ b/lib/mlibc/sysdeps/ironclad/include/abi-bits/vm-flags.h @@ -0,0 +1 @@ +../../../../abis/ironclad/vm-flags.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/ironclad/include/abi-bits/wait.h b/lib/mlibc/sysdeps/ironclad/include/abi-bits/wait.h new file mode 120000 index 0000000..a87457d --- /dev/null +++ b/lib/mlibc/sysdeps/ironclad/include/abi-bits/wait.h @@ -0,0 +1 @@ +../../../../abis/ironclad/wait.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/ironclad/include/abi-bits/xattr.h b/lib/mlibc/sysdeps/ironclad/include/abi-bits/xattr.h new file mode 120000 index 0000000..99e5aa3 --- /dev/null +++ b/lib/mlibc/sysdeps/ironclad/include/abi-bits/xattr.h @@ -0,0 +1 @@ +../../../../abis/ironclad/xattr.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/ironclad/include/asm/ioctls.h b/lib/mlibc/sysdeps/ironclad/include/asm/ioctls.h new file mode 100644 index 0000000..aa9f0b4 --- /dev/null +++ b/lib/mlibc/sysdeps/ironclad/include/asm/ioctls.h @@ -0,0 +1,102 @@ +#ifndef _ASM_IOCTLS_H +#define _ASM_IOCTLS_H + +// List of all the IOCTLs supported, for further explanation on the meanings +// please refer to documentation. If you did not get any, good luck! +// Some IOCTL codes may be the same, in which case the device they are used in +// gives them meaning. Cross-device IOCTLs have more distinct values. + +#define PS2MOUSE_2_1_SCALING 1 +#define PS2MOUSE_1_1_SCALING 2 +#define PS2MOUSE_SET_RES 3 +#define PS2MOUSE_SET_SAMPLE_RATE 4 +#define RTC_RD_TIME 1 +#define RTC_SET_TIME 2 +#define FIOQSIZE 0x5460 +#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 TCGETS2 3 +#define TCSETS2 3 +#define TCSETSW2 3 +#define TCSETSF2 3 +#define TIOCGRS485 0x542E +#define TIOCSRS485 0x542F +#define TIOCGPTN 3 +#define TIOCSPTLCK 3 +#define TIOCGDEV 3 +#define TCGETX 0x5432 +#define TCSETX 0x5433 +#define TCSETXF 0x5434 +#define TCSETXW 0x5435 +#define TIOCSIG 0x36 +#define TIOCVHANGUP 0x5437 +#define TIOCGPKT 3 +#define TIOCGPTLCK 3 +#define TIOCGEXCL 3 +#define TIOCGPTPEER 3 +#define TIOCGISO7816 3 +#define TIOCSISO7816 3 +#define FIONCLEX 0x5450 +#define FIOCLEX 0x5451 +#define FIOASYNC 0x5452 +#define TIOCSERCONFIG 0x5453 +#define TIOCSERGWILD 0x5454 +#define TIOCSERSWILD 0x5455 +#define TIOCGLCKTRMIOS 0x5456 +#define TIOCSLCKTRMIOS 0x5457 +#define TIOCSERGSTRUCT 0x5458 +#define TIOCSERGETLSR 0x5459 +#define TIOCSERGETMULTI 0x545A +#define TIOCSERSETMULTI 0x545B +#define TIOCMIWAIT 0x545C +#define TIOCGICOUNT 0x545D +#define TIOCPKT_DATA 0 +#define TIOCPKT_FLUSHREAD 1 +#define TIOCPKT_FLUSHWRITE 2 +#define TIOCPKT_STOP 4 +#define TIOCPKT_START 8 +#define TIOCPKT_NOSTOP 16 +#define TIOCPKT_DOSTOP 32 +#define TIOCPKT_IOCTL 64 +#define TIOCSER_TEMT 0x01 + +#endif /* _ASM_IOCTLS_H */ diff --git a/lib/mlibc/sysdeps/ironclad/include/linux/fb.h b/lib/mlibc/sysdeps/ironclad/include/linux/fb.h new file mode 100644 index 0000000..563ce82 --- /dev/null +++ b/lib/mlibc/sysdeps/ironclad/include/linux/fb.h @@ -0,0 +1,397 @@ +#ifndef _SYS_FB_H +#define _SYS_FB_H + +#include + +/* Definitions of frame buffers */ + +#define FB_MAX 32 /* sufficient for now */ + +/* ioctls + 0x46 is 'F' */ +#define FBIOGET_VSCREENINFO 0x4600 +#define FBIOPUT_VSCREENINFO 0x4601 +#define FBIOGET_FSCREENINFO 0x4602 +#define FBIOGETCMAP 0x4604 +#define FBIOPUTCMAP 0x4605 +#define FBIOPAN_DISPLAY 0x4606 +#define FBIO_CURSOR _IOWR('F', 0x08, struct fb_cursor) +/* 0x4607-0x460B are defined below */ +/* #define FBIOGET_MONITORSPEC 0x460C */ +/* #define FBIOPUT_MONITORSPEC 0x460D */ +/* #define FBIOSWITCH_MONIBIT 0x460E */ +#define FBIOGET_CON2FBMAP 0x460F +#define FBIOPUT_CON2FBMAP 0x4610 +#define FBIOBLANK 0x4611 /* arg: 0 or vesa level + 1 */ +#define FBIOGET_VBLANK _IOR('F', 0x12, struct fb_vblank) +#define FBIO_ALLOC 0x4613 +#define FBIO_FREE 0x4614 +#define FBIOGET_GLYPH 0x4615 +#define FBIOGET_HWCINFO 0x4616 +#define FBIOPUT_MODEINFO 0x4617 +#define FBIOGET_DISPINFO 0x4618 + +#define FB_TYPE_PACKED_PIXELS 0 /* Packed Pixels */ +#define FB_TYPE_PLANES 1 /* Non interleaved planes */ +#define FB_TYPE_INTERLEAVED_PLANES 2 /* Interleaved planes */ +#define FB_TYPE_TEXT 3 /* Text/attributes */ +#define FB_TYPE_VGA_PLANES 4 /* EGA/VGA planes */ +#define FB_TYPE_FOURCC 5 /* Type identified by a V4L2 FOURCC */ + +#define FB_AUX_TEXT_MDA 0 /* Monochrome text */ +#define FB_AUX_TEXT_CGA 1 /* CGA/EGA/VGA Color text */ +#define FB_AUX_TEXT_S3_MMIO 2 /* S3 MMIO fasttext */ +#define FB_AUX_TEXT_MGA_STEP16 3 /* MGA Millenium I: text, attr, 14 reserved bytes */ +#define FB_AUX_TEXT_MGA_STEP8 4 /* other MGAs: text, attr, 6 reserved bytes */ +#define FB_AUX_TEXT_SVGA_GROUP 8 /* 8-15: SVGA tileblit compatible modes */ +#define FB_AUX_TEXT_SVGA_MASK 7 /* lower three bits says step */ +#define FB_AUX_TEXT_SVGA_STEP2 8 /* SVGA text mode: text, attr */ +#define FB_AUX_TEXT_SVGA_STEP4 9 /* SVGA text mode: text, attr, 2 reserved bytes */ +#define FB_AUX_TEXT_SVGA_STEP8 10 /* SVGA text mode: text, attr, 6 reserved bytes */ +#define FB_AUX_TEXT_SVGA_STEP16 11 /* SVGA text mode: text, attr, 14 reserved bytes */ +#define FB_AUX_TEXT_SVGA_LAST 15 /* reserved up to 15 */ + +#define FB_AUX_VGA_PLANES_VGA4 0 /* 16 color planes (EGA/VGA) */ +#define FB_AUX_VGA_PLANES_CFB4 1 /* CFB4 in planes (VGA) */ +#define FB_AUX_VGA_PLANES_CFB8 2 /* CFB8 in planes (VGA) */ + +#define FB_VISUAL_MONO01 0 /* Monochr. 1=Black 0=White */ +#define FB_VISUAL_MONO10 1 /* Monochr. 1=White 0=Black */ +#define FB_VISUAL_TRUECOLOR 2 /* True color */ +#define FB_VISUAL_PSEUDOCOLOR 3 /* Pseudo color (like atari) */ +#define FB_VISUAL_DIRECTCOLOR 4 /* Direct color */ +#define FB_VISUAL_STATIC_PSEUDOCOLOR 5 /* Pseudo color readonly */ +#define FB_VISUAL_FOURCC 6 /* Visual identified by a V4L2 FOURCC */ + +#define FB_ACCEL_NONE 0 /* no hardware accelerator */ +#define FB_ACCEL_ATARIBLITT 1 /* Atari Blitter */ +#define FB_ACCEL_AMIGABLITT 2 /* Amiga Blitter */ +#define FB_ACCEL_S3_TRIO64 3 /* Cybervision64 (S3 Trio64) */ +#define FB_ACCEL_NCR_77C32BLT 4 /* RetinaZ3 (NCR 77C32BLT) */ +#define FB_ACCEL_S3_VIRGE 5 /* Cybervision64/3D (S3 ViRGE) */ +#define FB_ACCEL_ATI_MACH64GX 6 /* ATI Mach 64GX family */ +#define FB_ACCEL_DEC_TGA 7 /* DEC 21030 TGA */ +#define FB_ACCEL_ATI_MACH64CT 8 /* ATI Mach 64CT family */ +#define FB_ACCEL_ATI_MACH64VT 9 /* ATI Mach 64CT family VT class */ +#define FB_ACCEL_ATI_MACH64GT 10 /* ATI Mach 64CT family GT class */ +#define FB_ACCEL_SUN_CREATOR 11 /* Sun Creator/Creator3D */ +#define FB_ACCEL_SUN_CGSIX 12 /* Sun cg6 */ +#define FB_ACCEL_SUN_LEO 13 /* Sun leo/zx */ +#define FB_ACCEL_IMS_TWINTURBO 14 /* IMS Twin Turbo */ +#define FB_ACCEL_3DLABS_PERMEDIA2 15 /* 3Dlabs Permedia 2 */ +#define FB_ACCEL_MATROX_MGA2064W 16 /* Matrox MGA2064W (Millenium) */ +#define FB_ACCEL_MATROX_MGA1064SG 17 /* Matrox MGA1064SG (Mystique) */ +#define FB_ACCEL_MATROX_MGA2164W 18 /* Matrox MGA2164W (Millenium II) */ +#define FB_ACCEL_MATROX_MGA2164W_AGP 19 /* Matrox MGA2164W (Millenium II) */ +#define FB_ACCEL_MATROX_MGAG100 20 /* Matrox G100 (Productiva G100) */ +#define FB_ACCEL_MATROX_MGAG200 21 /* Matrox G200 (Myst, Mill, ...) */ +#define FB_ACCEL_SUN_CG14 22 /* Sun cgfourteen */ +#define FB_ACCEL_SUN_BWTWO 23 /* Sun bwtwo */ +#define FB_ACCEL_SUN_CGTHREE 24 /* Sun cgthree */ +#define FB_ACCEL_SUN_TCX 25 /* Sun tcx */ +#define FB_ACCEL_MATROX_MGAG400 26 /* Matrox G400 */ +#define FB_ACCEL_NV3 27 /* nVidia RIVA 128 */ +#define FB_ACCEL_NV4 28 /* nVidia RIVA TNT */ +#define FB_ACCEL_NV5 29 /* nVidia RIVA TNT2 */ +#define FB_ACCEL_CT_6555x 30 /* C&T 6555x */ +#define FB_ACCEL_3DFX_BANSHEE 31 /* 3Dfx Banshee */ +#define FB_ACCEL_ATI_RAGE128 32 /* ATI Rage128 family */ +#define FB_ACCEL_IGS_CYBER2000 33 /* CyberPro 2000 */ +#define FB_ACCEL_IGS_CYBER2010 34 /* CyberPro 2010 */ +#define FB_ACCEL_IGS_CYBER5000 35 /* CyberPro 5000 */ +#define FB_ACCEL_SIS_GLAMOUR 36 /* SiS 300/630/540 */ +#define FB_ACCEL_3DLABS_PERMEDIA3 37 /* 3Dlabs Permedia 3 */ +#define FB_ACCEL_ATI_RADEON 38 /* ATI Radeon family */ +#define FB_ACCEL_I810 39 /* Intel 810/815 */ +#define FB_ACCEL_SIS_GLAMOUR_2 40 /* SiS 315, 650, 740 */ +#define FB_ACCEL_SIS_XABRE 41 /* SiS 330 ("Xabre") */ +#define FB_ACCEL_I830 42 /* Intel 830M/845G/85x/865G */ +#define FB_ACCEL_NV_10 43 /* nVidia Arch 10 */ +#define FB_ACCEL_NV_20 44 /* nVidia Arch 20 */ +#define FB_ACCEL_NV_30 45 /* nVidia Arch 30 */ +#define FB_ACCEL_NV_40 46 /* nVidia Arch 40 */ +#define FB_ACCEL_XGI_VOLARI_V 47 /* XGI Volari V3XT, V5, V8 */ +#define FB_ACCEL_XGI_VOLARI_Z 48 /* XGI Volari Z7 */ +#define FB_ACCEL_OMAP1610 49 /* TI OMAP16xx */ +#define FB_ACCEL_TRIDENT_TGUI 50 /* Trident TGUI */ +#define FB_ACCEL_TRIDENT_3DIMAGE 51 /* Trident 3DImage */ +#define FB_ACCEL_TRIDENT_BLADE3D 52 /* Trident Blade3D */ +#define FB_ACCEL_TRIDENT_BLADEXP 53 /* Trident BladeXP */ +#define FB_ACCEL_CIRRUS_ALPINE 53 /* Cirrus Logic 543x/544x/5480 */ +#define FB_ACCEL_NEOMAGIC_NM2070 90 /* NeoMagic NM2070 */ +#define FB_ACCEL_NEOMAGIC_NM2090 91 /* NeoMagic NM2090 */ +#define FB_ACCEL_NEOMAGIC_NM2093 92 /* NeoMagic NM2093 */ +#define FB_ACCEL_NEOMAGIC_NM2097 93 /* NeoMagic NM2097 */ +#define FB_ACCEL_NEOMAGIC_NM2160 94 /* NeoMagic NM2160 */ +#define FB_ACCEL_NEOMAGIC_NM2200 95 /* NeoMagic NM2200 */ +#define FB_ACCEL_NEOMAGIC_NM2230 96 /* NeoMagic NM2230 */ +#define FB_ACCEL_NEOMAGIC_NM2360 97 /* NeoMagic NM2360 */ +#define FB_ACCEL_NEOMAGIC_NM2380 98 /* NeoMagic NM2380 */ +#define FB_ACCEL_PXA3XX 99 /* PXA3xx */ + +#define FB_ACCEL_SAVAGE4 0x80 /* S3 Savage4 */ +#define FB_ACCEL_SAVAGE3D 0x81 /* S3 Savage3D */ +#define FB_ACCEL_SAVAGE3D_MV 0x82 /* S3 Savage3D-MV */ +#define FB_ACCEL_SAVAGE2000 0x83 /* S3 Savage2000 */ +#define FB_ACCEL_SAVAGE_MX_MV 0x84 /* S3 Savage/MX-MV */ +#define FB_ACCEL_SAVAGE_MX 0x85 /* S3 Savage/MX */ +#define FB_ACCEL_SAVAGE_IX_MV 0x86 /* S3 Savage/IX-MV */ +#define FB_ACCEL_SAVAGE_IX 0x87 /* S3 Savage/IX */ +#define FB_ACCEL_PROSAVAGE_PM 0x88 /* S3 ProSavage PM133 */ +#define FB_ACCEL_PROSAVAGE_KM 0x89 /* S3 ProSavage KM133 */ +#define FB_ACCEL_S3TWISTER_P 0x8a /* S3 Twister */ +#define FB_ACCEL_S3TWISTER_K 0x8b /* S3 TwisterK */ +#define FB_ACCEL_SUPERSAVAGE 0x8c /* S3 Supersavage */ +#define FB_ACCEL_PROSAVAGE_DDR 0x8d /* S3 ProSavage DDR */ +#define FB_ACCEL_PROSAVAGE_DDRK 0x8e /* S3 ProSavage DDR-K */ + +#define FB_ACCEL_PUV3_UNIGFX 0xa0 /* PKUnity-v3 Unigfx */ + +#define FB_CAP_FOURCC 1 /* Device supports FOURCC-based formats */ + +struct fb_fix_screeninfo { + char id[16]; /* identification string eg "TT Builtin" */ + unsigned long smem_start; /* Start of frame buffer mem */ + /* (physical address) */ + uint32_t smem_len; /* Length of frame buffer mem */ + uint32_t type; /* see FB_TYPE_* */ + uint32_t type_aux; /* Interleave for interleaved Planes */ + uint32_t visual; /* see FB_VISUAL_* */ + uint16_t xpanstep; /* zero if no hardware panning */ + uint16_t ypanstep; /* zero if no hardware panning */ + uint16_t ywrapstep; /* zero if no hardware ywrap */ + uint32_t line_length; /* length of a line in bytes */ + unsigned long mmio_start; /* Start of Memory Mapped I/O */ + /* (physical address) */ + uint32_t mmio_len; /* Length of Memory Mapped I/O */ + uint32_t accel; /* Indicate to driver which */ + /* specific chip/card we have */ + uint16_t capabilities; /* see FB_CAP_* */ + uint16_t reserved[2]; /* Reserved for future compatibility */ +}; + +/* Interpretation of offset for color fields: All offsets are from the right, + * inside a "pixel" value, which is exactly 'bits_per_pixel' wide (means: you + * can use the offset as right argument to <<). A pixel afterwards is a bit + * stream and is written to video memory as that unmodified. + * + * For pseudocolor: offset and length should be the same for all color + * components. Offset specifies the position of the least significant bit + * of the palette index in a pixel value. Length indicates the number + * of available palette entries (i.e. # of entries = 1 << length). + */ +struct fb_bitfield { + uint32_t offset; /* beginning of bitfield */ + uint32_t length; /* length of bitfield */ + uint32_t msb_right; /* != 0 : Most significant bit is */ + /* right */ +}; + +#define FB_NONSTD_HAM 1 /* Hold-And-Modify (HAM) */ +#define FB_NONSTD_REV_PIX_IN_B 2 /* order of pixels in each byte is reversed */ + +#define FB_ACTIVATE_NOW 0 /* set values immediately (or vbl)*/ +#define FB_ACTIVATE_NXTOPEN 1 /* activate on next open */ +#define FB_ACTIVATE_TEST 2 /* don't set, round up impossible */ +#define FB_ACTIVATE_MASK 15 + /* values */ +#define FB_ACTIVATE_VBL 16 /* activate values on next vbl */ +#define FB_CHANGE_CMAP_VBL 32 /* change colormap on vbl */ +#define FB_ACTIVATE_ALL 64 /* change all VCs on this fb */ +#define FB_ACTIVATE_FORCE 128 /* force apply even when no change*/ +#define FB_ACTIVATE_INV_MODE 256 /* invalidate videomode */ +#define FB_ACTIVATE_KD_TEXT 512 /* for KDSET vt ioctl */ + +#define FB_ACCELF_TEXT 1 /* (OBSOLETE) see fb_info.flags and vc_mode */ + +#define FB_SYNC_HOR_HIGH_ACT 1 /* horizontal sync high active */ +#define FB_SYNC_VERT_HIGH_ACT 2 /* vertical sync high active */ +#define FB_SYNC_EXT 4 /* external sync */ +#define FB_SYNC_COMP_HIGH_ACT 8 /* composite sync high active */ +#define FB_SYNC_BROADCAST 16 /* broadcast video timings */ + /* vtotal = 144d/288n/576i => PAL */ + /* vtotal = 121d/242n/484i => NTSC */ +#define FB_SYNC_ON_GREEN 32 /* sync on green */ + +#define FB_VMODE_NONINTERLACED 0 /* non interlaced */ +#define FB_VMODE_INTERLACED 1 /* interlaced */ +#define FB_VMODE_DOUBLE 2 /* double scan */ +#define FB_VMODE_ODD_FLD_FIRST 4 /* interlaced: top line first */ +#define FB_VMODE_MASK 255 + +#define FB_VMODE_YWRAP 256 /* ywrap instead of panning */ +#define FB_VMODE_SMOOTH_XPAN 512 /* smooth xpan possible (internally used) */ +#define FB_VMODE_CONUPDATE 512 /* don't update x/yoffset */ + +/* + * Display rotation support + */ +#define FB_ROTATE_UR 0 +#define FB_ROTATE_CW 1 +#define FB_ROTATE_UD 2 +#define FB_ROTATE_CCW 3 + +#define PICOS2KHZ(a) (1000000000UL/(a)) +#define KHZ2PICOS(a) (1000000000UL/(a)) + +struct fb_var_screeninfo { + uint32_t xres; /* visible resolution */ + uint32_t yres; + uint32_t xres_virtual; /* virtual resolution */ + uint32_t yres_virtual; + uint32_t xoffset; /* offset from virtual to visible */ + uint32_t yoffset; /* resolution */ + + uint32_t bits_per_pixel; /* guess what */ + uint32_t grayscale; /* 0 = color, 1 = grayscale, */ + /* >1 = FOURCC */ + struct fb_bitfield red; /* bitfield in fb mem if true color, */ + struct fb_bitfield green; /* else only length is significant */ + struct fb_bitfield blue; + struct fb_bitfield transp; /* transparency */ + + uint32_t nonstd; /* != 0 Non standard pixel format */ + + uint32_t activate; /* see FB_ACTIVATE_* */ + + uint32_t height; /* height of picture in mm */ + uint32_t width; /* width of picture in mm */ + + uint32_t accel_flags; /* (OBSOLETE) see fb_info.flags */ + + /* Timing: All values in pixclocks, except pixclock (of course) */ + uint32_t pixclock; /* pixel clock in ps (pico seconds) */ + uint32_t left_margin; /* time from sync to picture */ + uint32_t right_margin; /* time from picture to sync */ + uint32_t upper_margin; /* time from sync to picture */ + uint32_t lower_margin; + uint32_t hsync_len; /* length of horizontal sync */ + uint32_t vsync_len; /* length of vertical sync */ + uint32_t sync; /* see FB_SYNC_* */ + uint32_t vmode; /* see FB_VMODE_* */ + uint32_t rotate; /* angle we rotate counter clockwise */ + uint32_t colorspace; /* colorspace for FOURCC-based modes */ + uint32_t reserved[4]; /* Reserved for future compatibility */ +}; + +struct fb_cmap { + uint32_t start; /* First entry */ + uint32_t len; /* Number of entries */ + uint16_t *red; /* Red values */ + uint16_t *green; + uint16_t *blue; + uint16_t *transp; /* transparency, can be NULL */ +}; + +struct fb_con2fbmap { + uint32_t console; + uint32_t framebuffer; +}; + +/* VESA Blanking Levels */ +#define VESA_NO_BLANKING 0 +#define VESA_VSYNC_SUSPEND 1 +#define VESA_HSYNC_SUSPEND 2 +#define VESA_POWERDOWN 3 + + +enum { + /* screen: unblanked, hsync: on, vsync: on */ + FB_BLANK_UNBLANK = VESA_NO_BLANKING, + + /* screen: blanked, hsync: on, vsync: on */ + FB_BLANK_NORMAL = VESA_NO_BLANKING + 1, + + /* screen: blanked, hsync: on, vsync: off */ + FB_BLANK_VSYNC_SUSPEND = VESA_VSYNC_SUSPEND + 1, + + /* screen: blanked, hsync: off, vsync: on */ + FB_BLANK_HSYNC_SUSPEND = VESA_HSYNC_SUSPEND + 1, + + /* screen: blanked, hsync: off, vsync: off */ + FB_BLANK_POWERDOWN = VESA_POWERDOWN + 1 +}; + +#define FB_VBLANK_VBLANKING 0x001 /* currently in a vertical blank */ +#define FB_VBLANK_HBLANKING 0x002 /* currently in a horizontal blank */ +#define FB_VBLANK_HAVE_VBLANK 0x004 /* vertical blanks can be detected */ +#define FB_VBLANK_HAVE_HBLANK 0x008 /* horizontal blanks can be detected */ +#define FB_VBLANK_HAVE_COUNT 0x010 /* global retrace counter is available */ +#define FB_VBLANK_HAVE_VCOUNT 0x020 /* the vcount field is valid */ +#define FB_VBLANK_HAVE_HCOUNT 0x040 /* the hcount field is valid */ +#define FB_VBLANK_VSYNCING 0x080 /* currently in a vsync */ +#define FB_VBLANK_HAVE_VSYNC 0x100 /* verical syncs can be detected */ + +struct fb_vblank { + uint32_t flags; /* FB_VBLANK flags */ + uint32_t count; /* counter of retraces since boot */ + uint32_t vcount; /* current scanline position */ + uint32_t hcount; /* current scandot position */ + uint32_t reserved[4]; /* reserved for future compatibility */ +}; + +/* Internal HW accel */ +#define ROP_COPY 0 +#define ROP_XOR 1 + +struct fb_copyarea { + uint32_t dx; + uint32_t dy; + uint32_t width; + uint32_t height; + uint32_t sx; + uint32_t sy; +}; + +struct fb_fillrect { + uint32_t dx; /* screen-relative */ + uint32_t dy; + uint32_t width; + uint32_t height; + uint32_t color; + uint32_t rop; +}; + +struct fb_image { + uint32_t dx; /* Where to place image */ + uint32_t dy; + uint32_t width; /* Size of image */ + uint32_t height; + uint32_t fg_color; /* Only used when a mono bitmap */ + uint32_t bg_color; + uint8_t depth; /* Depth of the image */ + const char *data; /* Pointer to image data */ + struct fb_cmap cmap; /* color map info */ +}; + +/* + * hardware cursor control + */ + +#define FB_CUR_SETIMAGE 0x01 +#define FB_CUR_SETPOS 0x02 +#define FB_CUR_SETHOT 0x04 +#define FB_CUR_SETCMAP 0x08 +#define FB_CUR_SETSHAPE 0x10 +#define FB_CUR_SETSIZE 0x20 +#define FB_CUR_SETALL 0xFF + +struct fbcurpos { + uint16_t x, y; +}; + +struct fb_cursor { + uint16_t set; /* what to set */ + uint16_t enable; /* cursor on/off */ + uint16_t rop; /* bitop operation */ + const char *mask; /* cursor mask bits */ + struct fbcurpos hot; /* cursor hot spot */ + struct fb_image image; /* Cursor image */ +}; + +/* Settings for the generic backlight code */ +#define FB_BACKLIGHT_LEVELS 128 +#define FB_BACKLIGHT_MAX 0xFF + + +#endif /* _SYS_FB_H */ diff --git a/lib/mlibc/sysdeps/ironclad/include/mntent.h b/lib/mlibc/sysdeps/ironclad/include/mntent.h new file mode 100644 index 0000000..e5e49e7 --- /dev/null +++ b/lib/mlibc/sysdeps/ironclad/include/mntent.h @@ -0,0 +1,46 @@ +#ifndef _MNTENT_H +#define _MNTENT_H + +#include + +// TODO: Refer to _PATH_MOUNTED +#define MOUNTED "/etc/mtab" + +/* Generic mount options */ +#define MNTOPT_DEFAULTS "defaults" /* Use all default options. */ +#define MNTOPT_RO "ro" /* Read only. */ +#define MNTOPT_RW "rw" /* Read/write. */ +#define MNTOPT_SUID "suid" /* Set uid allowed. */ +#define MNTOPT_NOSUID "nosuid" /* No set uid allowed. */ +#define MNTOPT_NOAUTO "noauto" /* Do not auto mount. */ + +#ifdef __cplusplus +extern "C" { +#endif + +struct mntent { + char *mnt_fsname; + char *mnt_dir; + char *mnt_type; + char *mnt_opts; + int mnt_freq; + int mnt_passno; +}; + +FILE *setmntent(const char *, const char *); + +struct mntent *getmntent(FILE *); + +int addmntent(FILE *, const struct mntent *); + +int endmntent(FILE *); + +char *hasmntopt(const struct mntent *, const char *); + +struct mntent *getmntent_r(FILE *, struct mntent *, char *, int); + +#ifdef __cplusplus +} +#endif + +#endif // _MNTENT_H diff --git a/lib/mlibc/sysdeps/ironclad/include/pty.h b/lib/mlibc/sysdeps/ironclad/include/pty.h new file mode 100644 index 0000000..0468b46 --- /dev/null +++ b/lib/mlibc/sysdeps/ironclad/include/pty.h @@ -0,0 +1,16 @@ +#ifndef _PTY_H +#define _PTY_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +int openpty(int *mfd, int *sfd, char *name, const struct termios *ios, const struct winsize *win); + +#ifdef __cplusplus +} +#endif + +#endif // _PTY_H diff --git a/lib/mlibc/sysdeps/ironclad/include/sys/ironclad_devices.h b/lib/mlibc/sysdeps/ironclad/include/sys/ironclad_devices.h new file mode 100644 index 0000000..74f47f8 --- /dev/null +++ b/lib/mlibc/sysdeps/ironclad/include/sys/ironclad_devices.h @@ -0,0 +1,44 @@ +#ifndef _SYS_IRONCLAD_DEVICES_H +#define _SYS_IRONCLAD_DEVICES_H + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define PS2MOUSE_2_1_SCALING 1 +#define PS2MOUSE_1_1_SCALING 2 +#define PS2MOUSE_SET_RES 3 +#define PS2MOUSE_SET_SAMPLE_RATE 4 + +struct ironclad_mouse_data { + int x_variation; + int y_variation; + bool is_left; + bool is_right; +}; + +#define RTC_RD_TIME 1 +#define RTC_SET_TIME 2 + +struct rtc_time { + int tm_sec; + int tm_min; + int tm_hour; + int tm_mday; + int tm_mon; + int tm_year; + int tm_wday; /* unused */ + int tm_yday; /* unused */ + int tm_isdst; /* unused */ +}; + +#ifdef __cplusplus +} +#endif + +#endif // _SYS_IRONCLAD_DEVICES_H diff --git a/lib/mlibc/sysdeps/ironclad/include/sys/mac.h b/lib/mlibc/sysdeps/ironclad/include/sys/mac.h new file mode 100644 index 0000000..d4cf76d --- /dev/null +++ b/lib/mlibc/sysdeps/ironclad/include/sys/mac.h @@ -0,0 +1,46 @@ +#ifndef _SYS_MAC_H +#define _SYS_MAC_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define MAC_CAP_SCHED 0b00000000001 +#define MAC_CAP_SPAWN 0b00000000010 +#define MAC_CAP_ENTROPY 0b00000000100 +#define MAC_CAP_SYS_MEM 0b00000001000 +#define MAC_CAP_USE_NET 0b00000010000 +#define MAC_CAP_SYS_NET 0b00000100000 +#define MAC_CAP_SYS_MNT 0b00001000000 +#define MAC_CAP_SYS_PWR 0b00010000000 +#define MAC_CAP_PTRACE 0b00100000000 +#define MAC_CAP_SETUID 0b01000000000 +#define MAC_CAP_SYS_MAC 0b10000000000 +#define MAC_CAP_CLOCK 0b100000000000 +#define MAC_CAP_SIGNALALL 0b1000000000000 +unsigned long get_mac_capabilities(void); +int set_mac_capabilities(unsigned long request); + +#define MAC_PERM_CONTENTS 0b0000001 +#define MAC_PERM_READ 0b0000010 +#define MAC_PERM_WRITE 0b0000100 +#define MAC_PERM_EXEC 0b0001000 +#define MAC_PERM_APPEND 0b0010000 +#define MAC_PERM_FLOCK 0b0100000 +#define MAC_PERM_DEV 0b1000000 +int add_mac_permissions(const char *path, int flags); + +#define MAC_DENY 0b001 +#define MAC_DENY_AND_SCREAM 0b010 +#define MAC_KILL 0b100 +int set_mac_enforcement(unsigned long enforcement); + +#ifdef __cplusplus +} +#endif + +#endif // _SYS_MAC_H diff --git a/lib/mlibc/sysdeps/ironclad/include/sys/mount.h b/lib/mlibc/sysdeps/ironclad/include/sys/mount.h new file mode 100644 index 0000000..51263fa --- /dev/null +++ b/lib/mlibc/sysdeps/ironclad/include/sys/mount.h @@ -0,0 +1,24 @@ +#ifndef _SYS_MOUNT_H +#define _SYS_MOUNT_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define MNT_EXT 1 +#define MNT_FAT 2 + +#define MS_RDONLY 0b001 +#define MS_REMOUNT 0b010 +#define MS_RELATIME 0b100 + +#define MNT_FORCE 1 + +int mount(const char *source, const char *target, int type, int flags); +int umount(const char *target, int flags); + +#ifdef __cplusplus +} +#endif + +#endif // _SYS_MOUNT_H diff --git a/lib/mlibc/sysdeps/ironclad/include/sys/ptrace.h b/lib/mlibc/sysdeps/ironclad/include/sys/ptrace.h new file mode 100644 index 0000000..3993753 --- /dev/null +++ b/lib/mlibc/sysdeps/ironclad/include/sys/ptrace.h @@ -0,0 +1,23 @@ +#ifndef _SYS_PTRACE_H +#define _SYS_PTRACE_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define PTRACE_ATTACH 1 +#define PTRACE_DETACH 2 +#define PTRACE_CONT 3 +#define PTRACE_SYSCALL 4 +#define PTRACE_GETREGS 5 +int ptrace(int request, pid_t pid, void *addr, void *data); + +#ifdef __cplusplus +} +#endif + +#endif // _SYS_PTRACE_H diff --git a/lib/mlibc/sysdeps/ironclad/include/sys/reboot.h b/lib/mlibc/sysdeps/ironclad/include/sys/reboot.h new file mode 100644 index 0000000..c2dbbf2 --- /dev/null +++ b/lib/mlibc/sysdeps/ironclad/include/sys/reboot.h @@ -0,0 +1,16 @@ +#ifndef _SYS_REBOOT_H +#define _SYS_REBOOT_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +int reboot(int arg); + +#ifdef __cplusplus +} +#endif + +#endif // _SYS_REBOOT_H diff --git a/lib/mlibc/sysdeps/ironclad/include/sys/sched2.h b/lib/mlibc/sysdeps/ironclad/include/sys/sched2.h new file mode 100644 index 0000000..caeb86a --- /dev/null +++ b/lib/mlibc/sysdeps/ironclad/include/sys/sched2.h @@ -0,0 +1,24 @@ +#ifndef _SYS_SCHED2_H +#define _SYS_SCHED2_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define THREAD_RT 0b0001 +#define THREAD_MONO 0b0010 +#define THREAD_MLOCK 0b0100 +#define THREAD_BANNED 0b1000 +int get_thread_sched(void); +int set_thread_sched(int flags); +int set_deadlines(int runtime, int period); + +#ifdef __cplusplus +} +#endif + +#endif // _SYS_SCHED2_H diff --git a/lib/mlibc/sysdeps/ironclad/include/sys/syscall.h b/lib/mlibc/sysdeps/ironclad/include/sys/syscall.h new file mode 100644 index 0000000..01ab016 --- /dev/null +++ b/lib/mlibc/sysdeps/ironclad/include/sys/syscall.h @@ -0,0 +1,187 @@ +#ifndef _SYS_SYSCALL_H +#define _SYS_SYSCALL_H + +#include + +#define SYSCALL0(NUM) ({ \ + asm volatile ("syscall" \ + : "=a"(ret), "=d"(errno) \ + : "a"(NUM) \ + : "rcx", "r11", "memory"); \ +}) + +#define SYSCALL1(NUM, ARG0) ({ \ + asm volatile ("syscall" \ + : "=a"(ret), "=d"(errno) \ + : "a"(NUM), "D"(ARG0) \ + : "rcx", "r11", "memory"); \ +}) + +#define SYSCALL2(NUM, ARG0, ARG1) ({ \ + asm volatile ("syscall" \ + : "=a"(ret), "=d"(errno) \ + : "a"(NUM), "D"(ARG0), "S"(ARG1) \ + : "rcx", "r11", "memory"); \ +}) + +#define SYSCALL3(NUM, ARG0, ARG1, ARG2) ({ \ + asm volatile ("syscall" \ + : "=a"(ret), "=d"(errno) \ + : "a"(NUM), "D"(ARG0), "S"(ARG1), "d"(ARG2) \ + : "rcx", "r11", "memory"); \ +}) + +#define SYSCALL4(NUM, ARG0, ARG1, ARG2, ARG3) ({ \ + register __typeof(ARG3) arg_r12 asm("r12") = ARG3; \ + asm volatile ("syscall" \ + : "=a"(ret), "=d"(errno) \ + : "a"(NUM), "D"(ARG0), "S"(ARG1), "d"(ARG2), \ + "r"(arg_r12) \ + : "rcx", "r11", "memory"); \ +}) + +#define SYSCALL5(NUM, ARG0, ARG1, ARG2, ARG3, ARG4) ({ \ + register __typeof(ARG3) arg_r12 asm("r12") = ARG3; \ + register __typeof(ARG4) arg_r8 asm("r8") = ARG4; \ + asm volatile ("syscall" \ + : "=a"(ret), "=d"(errno) \ + : "a"(NUM), "D"(ARG0), "S"(ARG1), "d"(ARG2), \ + "r"(arg_r12), "r"(arg_r8) \ + : "rcx", "r11", "memory"); \ +}) + +#define SYSCALL6(NUM, ARG0, ARG1, ARG2, ARG3, ARG4, ARG5) ({ \ + register __typeof(ARG3) arg_r12 asm("r12") = ARG3; \ + register __typeof(ARG4) arg_r8 asm("r8") = ARG4; \ + register __typeof(ARG5) arg_r9 asm("r9") = ARG5; \ + asm volatile ("syscall" \ + : "=a"(ret), "=d"(errno) \ + : "a"(NUM), "D"(ARG0), "S"(ARG1), "d"(ARG2), \ + "r"(arg_r12), "r"(arg_r8), "r"(arg_r9) \ + : "rcx", "r11", "memory"); \ +}) + +#define SYSCALL6(NUM, ARG0, ARG1, ARG2, ARG3, ARG4, ARG5) ({ \ + register __typeof(ARG3) arg_r12 asm("r12") = ARG3; \ + register __typeof(ARG4) arg_r8 asm("r8") = ARG4; \ + register __typeof(ARG5) arg_r9 asm("r9") = ARG5; \ + asm volatile ("syscall" \ + : "=a"(ret), "=d"(errno) \ + : "a"(NUM), "D"(ARG0), "S"(ARG1), "d"(ARG2), \ + "r"(arg_r12), "r"(arg_r8), "r"(arg_r9) \ + : "rcx", "r11", "memory"); \ +}) + +#define SYSCALL7(NUM, ARG0, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6) ({ \ + register __typeof(ARG3) arg_r12 asm("r12") = ARG3; \ + register __typeof(ARG4) arg_r8 asm("r8") = ARG4; \ + register __typeof(ARG5) arg_r9 asm("r9") = ARG5; \ + register __typeof(ARG6) arg_r10 asm("r10") = ARG6; \ + asm volatile ("syscall" \ + : "=a"(ret), "=d"(errno) \ + : "a"(NUM), "D"(ARG0), "S"(ARG1), "d"(ARG2), \ + "r"(arg_r12), "r"(arg_r8), "r"(arg_r9), "r"(arg_r10) \ + : "rcx", "r11", "memory"); \ +}) + +#define SYSCALL_EXIT 0 +#define SYSCALL_ARCH_PRCTL 1 +#define SYSCALL_OPEN 2 +#define SYSCALL_CLOSE 3 +#define SYSCALL_READ 4 +#define SYSCALL_WRITE 5 +#define SYSCALL_SEEK 6 +#define SYSCALL_MMAP 7 +#define SYSCALL_MUNMAP 8 +#define SYSCALL_GETPID 9 +#define SYSCALL_GETPPID 10 +#define SYSCALL_EXEC 11 +#define SYSCALL_CLONE 12 +#define SYSCALL_WAIT 13 +#define SYSCALL_SOCKET 14 +#define SYSCALL_SETHOSTNAME 15 +#define SYSCALL_UNLINK 16 +#define SYSCALL_STAT 17 +#define SYSCALL_GETCWD 18 +#define SYSCALL_CHDIR 19 +#define SYSCALL_IOCTL 20 +#define SYSCALL_SCHED_YIELD 21 +#define SYSCALL_DELETE_TCLUSTER 22 +#define SYSCALL_PIPE 23 +#define SYSCALL_GETUID 24 +#define SYSCALL_RENAME 25 +#define SYSCALL_SYSCONF 26 +#define SYSCALL_SPAWN 27 +#define SYSCALL_GETTID 28 +#define SYSCALL_MANAGE_TCLUSTER 29 +#define SYSCALL_FCNTL 30 +#define SYSCALL_EXIT_THREAD 31 +#define SYSCALL_GETRANDOM 32 +#define SYSCALL_MPROTECT 33 +#define SYSCALL_SYNC 34 +#define SYSCALL_SET_MAC_CAPABILITIES 35 +#define SYSCALL_GET_MAC_CAPABILITIES 36 +#define SYSCALL_ADD_MAC_PERMISSIONS 37 +#define SYSCALL_SET_MAC_ENFORCEMENT 38 +#define SYSCALL_MOUNT 39 +#define SYSCALL_UMOUNT 40 +#define SYSCALL_READLINK 41 +#define SYSCALL_GETDENTS 42 +#define SYSCALL_MAKENODE 43 +#define SYSCALL_TRUNCATE 44 +#define SYSCALL_BIND 45 +#define SYSCALL_SYMLINK 46 +#define SYSCALL_CONNECT 47 +#define SYSCALL_OPENPTY 48 +#define SYSCALL_FSYNC 49 +#define SYSCALL_LINK 50 +#define SYSCALL_PTRACE 51 +#define SYSCALL_LISTEN 52 +#define SYSCALL_ACCEPT 53 +#define SYSCALL_GETRLIMIT 54 +#define SYSCALL_SETRLIMIT 55 +#define SYSCALL_ACCESS 56 +#define SYSCALL_POLL 57 +#define SYSCALL_GETEUID 58 +#define SYSCALL_SETUIDS 59 +#define SYSCALL_FCHMOD 60 +#define SYSCALL_UMASK 61 +#define SYSCALL_REBOOT 62 +#define SYSCALL_FCHOWN 63 +#define SYSCALL_PREAD 64 +#define SYSCALL_PWRITE 65 +#define SYSCALL_GETSOCKNAME 66 +#define SYSCALL_GETPEERNAME 67 +#define SYSCALL_SHUTDOWN 68 +#define SYSCALL_FUTEX 69 +#define SYSCALL_CLOCK 70 +#define SYSCALL_CLOCK_NANOSLEEP 71 +#define SYSCALL_GETRUSAGE 72 +#define SYSCALL_RECVFROM 73 +#define SYSCALL_SENDTO 74 +#define SYSCALL_CONFIG_NETINTER 75 +#define SYSCALL_UTIMES 76 +#define SYSCALL_CREATE_TCLUSTER 77 +#define SYSCALL_SWITCH_TCLUSTER 78 +#define SYSCALL_ACTUALLY_KILL 79 +#define SYSCALL_SIGNALPOST 80 +#define SYSCALL_SEND_SIGNAL 81 +#define SYSCALL_GETPRIO 82 +#define SYSCALL_SETPRIO 83 +#define SYSCALL_GETGID 84 +#define SYSCALL_GETEGID 85 +#define SYSCALL_SETGIDS 86 +#define SYSCALL_GETGROUPS 87 +#define SYSCALL_SETGROUPS 88 +#define SYSCALL_TTYNAME 89 +#define SYSCALL_FADVISE 90 +#define SYSCALL_SHMAT 91 +#define SYSCALL_SHMCTL 92 +#define SYSCALL_SHMDT 93 +#define SYSCALL_SHMGET 94 +#define SYSCALL_GETSOCKOPT 95 +#define SYSCALL_SETSOCKOPT 96 +#define SYSCALL_GETTIDID 97 +#define SYSCALL_SETTIDID 98 + +#endif // _SYS_SYSCALL_H diff --git a/lib/mlibc/sysdeps/ironclad/include/utmpx.h b/lib/mlibc/sysdeps/ironclad/include/utmpx.h new file mode 100644 index 0000000..2d7d3e1 --- /dev/null +++ b/lib/mlibc/sysdeps/ironclad/include/utmpx.h @@ -0,0 +1,63 @@ + +#ifndef _UTMPX_H +#define _UTMPX_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +#define UTMPX_FILE "/var/run/utmp" +#define WTMPX_FILE "/var/run/wtmp" + +// Struct definition taken from musl +struct utmpx { + short ut_type; + short __ut_pad1; + pid_t ut_pid; + char ut_line[32]; + char ut_id[4]; + char ut_user[32]; + char ut_host[256]; + struct { + short __e_termination; + short __e_exit; + } ut_exit; + int ut_session, __ut_pad2; + struct timeval ut_tv; + unsigned ut_addr_v6[4]; + char __unused[20]; +}; + +#ifndef __MLIBC_ABI_ONLY + +void updwtmpx(const char *, const struct utmpx *); +int utmpxname(const char *); +struct utmpx *pututxline(const struct utmpx *); +struct utmpx *getutxent(void); +void setutxent(void); +void endutxent(void); + +#endif /* !__MLIBC_ABI_ONLY */ + +#define EMPTY 0 +#define RUN_LVL 1 +#define BOOT_TIME 2 +#define NEW_TIME 3 +#define OLD_TIME 4 +#define INIT_PROCESS 5 +#define LOGIN_PROCESS 6 +#define USER_PROCESS 7 +#define DEAD_PROCESS 8 + +#define __UT_HOSTSIZE 256 +#define __UT_NAMESIZE 32 +#define __UT_LINESIZE 32 + +#ifdef __cplusplus +} +#endif + +#endif // _UTMPX_H diff --git a/lib/mlibc/sysdeps/ironclad/meson.build b/lib/mlibc/sysdeps/ironclad/meson.build new file mode 100644 index 0000000..a23203c --- /dev/null +++ b/lib/mlibc/sysdeps/ironclad/meson.build @@ -0,0 +1,125 @@ + +rtdl_sources += files( + 'generic/generic.cpp' +) + +libc_sources += files( + 'generic/entry.cpp', + 'generic/ptrace.cpp', + 'generic/generic.cpp', + 'generic/mntent.cpp', + 'generic/mount.cpp', + 'generic/reboot.cpp', + 'generic/pty.cpp', + 'generic/thread.cpp', + 'generic/mac.cpp', + 'generic/sched2.cpp', + 'generic/thread.S', + 'generic/utmpx.cpp' +) + +if not no_headers + install_headers( + 'include/abi-bits/access.h', + 'include/abi-bits/auxv.h', + 'include/abi-bits/seek-whence.h', + 'include/abi-bits/vm-flags.h', + 'include/abi-bits/errno.h', + 'include/abi-bits/fcntl.h', + 'include/abi-bits/in.h', + 'include/abi-bits/reboot.h', + 'include/abi-bits/resource.h', + 'include/abi-bits/stat.h', + 'include/abi-bits/signal.h', + 'include/abi-bits/socket.h', + 'include/abi-bits/termios.h', + 'include/abi-bits/time.h', + 'include/abi-bits/blkcnt_t.h', + 'include/abi-bits/blksize_t.h', + 'include/abi-bits/dev_t.h', + 'include/abi-bits/gid_t.h', + 'include/abi-bits/ino_t.h', + 'include/abi-bits/mode_t.h', + 'include/abi-bits/nlink_t.h', + 'include/abi-bits/pid_t.h', + 'include/abi-bits/uid_t.h', + 'include/abi-bits/wait.h', + 'include/abi-bits/limits.h', + 'include/abi-bits/utsname.h', + 'include/abi-bits/ptrace.h', + 'include/abi-bits/poll.h', + 'include/abi-bits/epoll.h', + 'include/abi-bits/packet.h', + 'include/abi-bits/inotify.h', + 'include/abi-bits/clockid_t.h', + 'include/abi-bits/shm.h', + 'include/abi-bits/mqueue.h', + 'include/abi-bits/suseconds_t.h', + 'include/abi-bits/fsfilcnt_t.h', + 'include/abi-bits/fsblkcnt_t.h', + 'include/abi-bits/socklen_t.h', + 'include/abi-bits/statfs.h', + 'include/abi-bits/statvfs.h', + 'include/abi-bits/ioctls.h', + 'include/abi-bits/xattr.h', + 'include/abi-bits/msg.h', + subdir: 'abi-bits', + follow_symlinks: true + ) + install_headers( + 'include/sys/sched2.h', + 'include/sys/ironclad_devices.h', + 'include/sys/mac.h', + 'include/sys/syscall.h', + 'include/sys/reboot.h', + 'include/sys/mount.h', + 'include/sys/ptrace.h', + subdir: 'sys' + ) + + install_headers( + 'include/asm/ioctls.h', + subdir: 'asm' + ) + + install_headers( + 'include/linux/fb.h', + subdir: 'linux' + ) + + install_headers( + 'include/mntent.h', + 'include/pty.h', + 'include/utmpx.h' + ) +endif + +if not headers_only + crt = custom_target('crt0', + build_by_default: true, + command: c_compiler.cmd_array() + ['-c', '-o', '@OUTPUT@', '@INPUT@'], + input: 'crt-x86_64/crt0.S', + output: 'crt0.o', + install: true, + install_dir: get_option('libdir') + ) + + custom_target('crti', + build_by_default: true, + command: c_compiler.cmd_array() + ['-c', '-o', '@OUTPUT@', '@INPUT@'], + input: 'crt-x86_64/crti.S', + output: 'crti.o', + install: true, + install_dir: get_option('libdir') + ) + + custom_target('crtn', + build_by_default: true, + command: c_compiler.cmd_array() + ['-c', '-o', '@OUTPUT@', '@INPUT@'], + input: 'crt-x86_64/crtn.S', + output: 'crtn.o', + install: true, + install_dir: get_option('libdir') + ) +endif + diff --git a/lib/mlibc/sysdeps/keyronex/generic/entry.cpp b/lib/mlibc/sysdeps/keyronex/generic/entry.cpp new file mode 100644 index 0000000..ff15c62 --- /dev/null +++ b/lib/mlibc/sysdeps/keyronex/generic/entry.cpp @@ -0,0 +1,108 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +// defined by the POSIX library +void __mlibc_initLocale(); + +extern "C" uintptr_t *__dlapi_entrystack(); + +extern char **environ; +static mlibc::exec_stack_data __mlibc_stack_data; + +struct LibraryGuard { + LibraryGuard(); +}; + +static LibraryGuard guard; + +LibraryGuard::LibraryGuard() +{ + __mlibc_initLocale(); + + // Parse the exec() stack. + mlibc::parse_exec_stack(__dlapi_entrystack(), &__mlibc_stack_data); + mlibc::set_startup_data(__mlibc_stack_data.argc, + __mlibc_stack_data.argv, __mlibc_stack_data.envp); +} + +namespace mlibc { +int +sys_sigentry(void *sigentry) +{ + uintptr_t ret = syscall1(kPXSysSigEntry, (uintptr_t)sigentry, NULL); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +[[noreturn]] int +sys_sigreturn(ucontext_t *context) +{ + syscall1(kPXSysSigReturn, (uintptr_t)context, NULL); + __builtin_unreachable(); +} +} + +static void +do_stacktrace(ucontext_t *ctx) +{ + size_t *base_ptr = (size_t *)ctx->uc_mcontext.gregs[REG_RBP]; + + mlibc::infoLogger() << "Stacktrace:" << frg::endlog; + mlibc::infoLogger() << " [" << (void *)ctx->uc_mcontext.gregs[REG_RIP] + << "]" << frg::endlog; + for (;;) { + size_t old_bp = base_ptr[0]; + size_t ret_addr = base_ptr[1]; + if (!ret_addr) + break; + mlibc::infoLogger() + << " [" << (void *)ret_addr << "]" << frg::endlog; + if (!old_bp) + break; + base_ptr = (size_t *)old_bp; + } +} + +static void +__mlibc_sigentry(int which, siginfo_t *siginfo, void *handler, + bool is_sigaction, ucontext_t *ret_context) +{ + if ((uintptr_t)handler == (uintptr_t)SIG_DFL) { + mlibc::infoLogger() + << "mlibc: Unhandled signal " << which << frg::endlog; + do_stacktrace(ret_context); + mlibc::sys_exit(128 + which); + } else if ((uintptr_t)handler == (uintptr_t)SIG_IGN) { + /* epsilon */ + } else { + if (is_sigaction) + ((void (*)(int, siginfo_t *, void *))handler)(which, + siginfo, ret_context); + else + ((void (*)(int))handler)(which); + } + + mlibc::sys_sigreturn(ret_context); + + __builtin_unreachable(); +} + +extern "C" void +__mlibc_entry(int (*main_fn)(int argc, char *argv[], char *env[])) +{ + /* communicate the signal handler entry point to the kernel */ + mlibc::sys_sigentry((void *)__mlibc_sigentry); + + // TODO: call __dlapi_enter, otherwise static builds will break (see + // Linux sysdeps) + auto result = main_fn(__mlibc_stack_data.argc, __mlibc_stack_data.argv, + environ); + exit(result); +} diff --git a/lib/mlibc/sysdeps/keyronex/generic/generic.cpp b/lib/mlibc/sysdeps/keyronex/generic/generic.cpp new file mode 100644 index 0000000..a3e77fb --- /dev/null +++ b/lib/mlibc/sysdeps/keyronex/generic/generic.cpp @@ -0,0 +1,753 @@ +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define STUB_ONLY \ + { \ + __ensure(!"STUB_ONLY function was called"); \ + __builtin_unreachable(); \ + } + +namespace mlibc { + +void +sys_libc_log(const char *message) +{ + syscall1(kPXSysDebug, (uintptr_t)message, NULL); +} + +void +sys_libc_panic() +{ + sys_libc_log("\nMLIBC PANIC\n"); + for (;;) + ; + STUB_ONLY +} + +void +sys_exit(int status) +{ + syscall1(kPXSysExit, status, NULL); + mlibc::panicLogger() << "sys_exit() returned!" << frg::endlog; + __builtin_unreachable(); +} + +#ifndef MLIBC_BUILDING_RTDL +int +sys_tcgetattr(int fd, struct termios *attr) +{ + int ret; + + if (int r = sys_ioctl(fd, TCGETS, attr, &ret) != 0) { + return r; + } + + return 0; +} + +int +sys_tcsetattr(int fd, int optional_action, const struct termios *attr) +{ + int ret; + + switch (optional_action) { + case TCSANOW: + optional_action = TCSETS; + break; + case TCSADRAIN: + optional_action = TCSETSW; + break; + case TCSAFLUSH: + optional_action = TCSETSF; + break; + default: + __ensure(!"Unsupported tcsetattr"); + } + + if (int r = sys_ioctl(fd, optional_action, (void *)attr, &ret) != 0) { + return r; + } + + return 0; +} +#endif + +int +sys_tcb_set(void *pointer) +{ + return syscall1(kPXSysSetFSBase, (uintptr_t)pointer, NULL); +} + +int +sys_ppoll(struct pollfd *fds, int nfds, const struct timespec *timeout, + const sigset_t *sigmask, int *num_events) +{ + uintptr_t ret = syscall4(kPXSysPPoll, (uintptr_t)fds, (uintptr_t)nfds, + (uintptr_t)timeout, (uintptr_t)sigmask, NULL); + if (int e = sc_error(ret); e) + return e; + *num_events = (ssize_t)ret; + return 0; +} + +int +sys_poll(struct pollfd *fds, nfds_t count, int timeout, int *num_events) +{ + struct timespec ts; + ts.tv_sec = timeout / 1000; + ts.tv_nsec = (timeout % 1000) * 1000000; + return sys_ppoll(fds, count, timeout < 0 ? NULL : &ts, NULL, + num_events); +} + +#ifndef MLIBC_BUILDING_RTDL +int +sys_pselect(int nfds, fd_set *read_set, fd_set *write_set, fd_set *except_set, + const struct timespec *timeout, const sigset_t *sigmask, int *num_events) +{ + struct pollfd *fds = (struct pollfd *)malloc( + nfds * sizeof(struct pollfd)); + + for (int i = 0; i < nfds; i++) { + struct pollfd *fd = &fds[i]; + memset(fd, 0, sizeof(struct pollfd)); + + if (read_set && FD_ISSET(i, read_set)) + fd->events |= POLLIN; // TODO: Additional events. + if (write_set && FD_ISSET(i, write_set)) + fd->events |= POLLOUT; // TODO: Additional events. + if (except_set && FD_ISSET(i, except_set)) + fd->events |= POLLPRI; + + if (!fd->events) { + fd->fd = -1; + continue; + } + + fd->fd = i; + } + + int e = sys_ppoll(fds, nfds, timeout, sigmask, num_events); + + if (e != 0) { + free(fds); + return e; + } + + fd_set res_read_set; + fd_set res_write_set; + fd_set res_except_set; + FD_ZERO(&res_read_set); + FD_ZERO(&res_write_set); + FD_ZERO(&res_except_set); + + for (int i = 0; i < nfds; i++) { + struct pollfd *fd = &fds[i]; + + if (read_set && FD_ISSET(i, read_set) && + fd->revents & (POLLIN | POLLERR | POLLHUP)) { + FD_SET(i, &res_read_set); + } + + if (write_set && FD_ISSET(i, write_set) && + fd->revents & (POLLOUT | POLLERR | POLLHUP)) { + FD_SET(i, &res_write_set); + } + + if (except_set && FD_ISSET(i, except_set) && + fd->revents & POLLPRI) { + FD_SET(i, &res_except_set); + } + } + + free(fds); + + if (read_set) + memcpy(read_set, &res_read_set, sizeof(fd_set)); + if (write_set) + memcpy(write_set, &res_write_set, sizeof(fd_set)); + if (except_set) + memcpy(except_set, &res_except_set, sizeof(fd_set)); + + return 0; +} +#endif + +int +sys_fcntl(int fd, int request, va_list args, int *result) +{ + auto ret = syscall3(kPXSysFCntl, fd, request, va_arg(args, uint64_t), + NULL); + if (int e = sc_error(ret); e) + return e; + *result = ret; + return 0; +} + +int +sys_futex_wait(int *pointer, int expected, const struct timespec *time) +{ + auto ret = syscall3(kPXSysFutexWait, (uintptr_t)pointer, expected, + (uintptr_t)time, NULL); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int +sys_futex_wake(int *pointer) +{ + auto ret = syscall1(kPXSysFutexWake, (uintptr_t)pointer, NULL); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +#ifndef MLIBC_BUILDING_RTDL +int +sys_ioctl(int fd, unsigned long request, void *arg, int *result) +{ + uintptr_t r = syscall3(kPXSysIOCtl, fd, request, (uintptr_t)arg, NULL); + if (int e = sc_error(r); e) + return e; + *result = r; + return 0; +} +#endif + +int +sys_isatty(int fd) +{ + uintptr_t ret = syscall1(kPXSysIsATTY, fd, NULL); + if (int e = sc_error(ret); e) { + return e; + } + return 0; +} + +#ifndef MLIBC_BUILDING_RTDL +int +sys_getcwd(char *buffer, size_t size) +{ + uintptr_t ret = syscall2(kPXSysGetCWD, (uintptr_t)buffer, size, NULL); + if (int e = sc_error(ret); e) { + return e; + } + return 0; +} +#endif + +int +sys_dup(int fd, int flags, int *newfd) +{ + uintptr_t ret = syscall2(kPXSysDup, fd, flags, NULL); + if (int e = sc_error(ret); e) { + return e; + } + *newfd = ret; + return 0; +} + +int +sys_dup2(int fd, int flags, int newfd) +{ + uintptr_t ret = syscall3(kPXSysDup3, fd, newfd, flags, NULL); + if (int e = sc_error(ret); e) { + return e; + } + return 0; +} + +int +sys_openat(int dirfd, const char *path, int flags, mode_t mode, int *fd) +{ + uintptr_t r = syscall4(kPXSysOpenAt, dirfd, (uintptr_t)path, + (uintptr_t)flags, (uintptr_t)mode, NULL); + if (int e = sc_error(r); e) + return e; + *fd = (int)r; + return 0; +} + +int +sys_open(const char *path, int flags, mode_t mode, int *fd) +{ + return sys_openat(AT_FDCWD, path, flags, mode, fd); +} + +int +sys_open_dir(const char *path, int *handle) +{ + return sys_open(path, O_DIRECTORY, 0, handle); +} + +int +sys_read_entries(int fd, void *buffer, size_t max_size, size_t *bytes_read) +{ + uintptr_t r = syscall3(kPXSysReadDir, fd, (uintptr_t)buffer, max_size, + NULL); + + if (int e = sc_error(r); e) + return e; + + *bytes_read = r; + return 0; +} + +int +sys_close(int fd) +{ + return (int)syscall1(kPXSysClose, fd, NULL); +} + +int +sys_link(const char *old_path, const char *new_path) +{ + uintptr_t ret = syscall2(kPXSysLink, (uintptr_t)old_path, + (uintptr_t)new_path, NULL); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int +sys_seek(int fd, off_t offset, int whence, off_t *new_offset) +{ + uintptr_t ret = syscall3(kPXSysSeek, fd, offset, whence, NULL); + if (int e = sc_error(ret); e) + return e; + *new_offset = (ssize_t)ret; + return 0; +} + +int +sys_read(int fd, void *buf, size_t count, ssize_t *bytes_read) +{ + uintptr_t ret = syscall3(kPXSysRead, fd, (uintptr_t)buf, + (uintptr_t)count, NULL); + if (int e = sc_error(ret); e) + return e; + *bytes_read = (ssize_t)ret; + return 0; +} + +int +sys_write(int fd, const void *buf, size_t count, ssize_t *bytes_written) +{ + uintptr_t ret = syscall3(kPXSysWrite, fd, (uintptr_t)buf, + (uintptr_t)count, NULL); + if (int e = sc_error(ret); e) + return e; + *bytes_written = (ssize_t)ret; + return 0; +} + +int +sys_readlink(const char *path, void *buffer, size_t max_size, ssize_t *length) +{ + uintptr_t ret = syscall3(kPXSysReadLink, (uintptr_t)path, + (uintptr_t)buffer, (uintptr_t)max_size, NULL); + if (int e = sc_error(ret); e) + return e; + *length = (ssize_t)ret; + return 0; +} + +int +sys_pipe(int *fds, int flags) +{ + uintptr_t ret = syscall2(kPXSysPipe, (uintptr_t)fds, flags, NULL); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int +sys_unlinkat(int fd, const char *path, int flags) +{ + uintptr_t ret = syscall3(kPXSysUnlinkAt, fd, (uintptr_t)path, flags, + NULL); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int +sys_vm_map(void *hint, size_t size, int prot, int flags, int fd, off_t offset, + void **window) +{ + uintptr_t r = syscall6(kPXSysMmap, (uintptr_t)hint, size, prot, flags, + fd, offset, NULL); + if (int e = sc_error(r); e) + return e; + *window = (void *)r; + return 0; +} + +int +sys_vm_unmap(void *pointer, size_t size) +{ + uintptr_t r = syscall2(kPXSysMunmap, (uintptr_t)pointer, size, NULL); + if (int e = sc_error(r); e) + return e; + return 0; +} + +int +sys_vm_protect(void *pointer, size_t size, int prot) +{ + + mlibc::infoLogger() << "mlibc: sys_vm_protect(" << pointer << ", " + << size << ", " << prot << "); stub!\n" + << frg::endlog; + return 0; +} + +int +sys_anon_allocate(size_t size, void **pointer) +{ + return sys_vm_map(NULL, size, PROT_EXEC | PROT_READ | PROT_WRITE, + MAP_ANONYMOUS, -1, 0, pointer); +} + +int +sys_anon_free(void *pointer, size_t size) +{ + return sys_vm_unmap(pointer, size); +} + +pid_t +sys_getpid() +{ + return syscall0(kPXSysGetPID, NULL); +} + +pid_t +sys_getppid() +{ + return syscall0(kPXSysGetPPID, NULL); +} + +uid_t +sys_getuid() +{ + return 0; +} + +uid_t +sys_geteuid() +{ + return 0; +} + +gid_t +sys_getgid() +{ + return 0; +} + +int +sys_getsid(pid_t pid, pid_t *sid) +{ + auto ret = syscall1(kPXSysGetSID, pid, NULL); + if (int e = sc_error(ret); e) + return e; + *sid = (pid_t)(ret); + return 0; +} + +int +sys_setgid(gid_t gid) +{ + (void)gid; + return 0; +} + +int +sys_getpgid(pid_t pid, pid_t *out) +{ + auto ret = syscall1(kPXSysGetPGID, pid, NULL); + if (int e = sc_error(ret); e) + return e; + *out = (pid_t)(ret); + return 0; +} + +int +sys_setpgid(pid_t pid, pid_t pgid) +{ + auto ret = syscall2(kPXSysSetPGID, pid, pgid, NULL); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int +sys_setsid(pid_t *sid) +{ + auto ret = syscall0(kPXSysSetSID, NULL); + if (int e = sc_error(ret); e) + return e; + *sid = (pid_t)ret; + return 0; +} + +gid_t +sys_getegid() +{ + mlibc::infoLogger() << "mlibc: " << __func__ << " is a stub!\n" + << frg::endlog; + return 0; +} + +pid_t +sys_gettid() +{ + return syscall0(kPXSysGetTID, NULL); +} + +int +sys_clock_get(int clock, time_t *secs, long *nanos) +{ + auto ret = syscall1(kPXSysClockGet, clock, NULL); + *secs = ret / 1000000000; + *nanos = ret % 1000000000; + return 0; +} + +int +sys_stat(fsfd_target fsfdt, int fd, const char *path, int flags, + struct stat *statbuf) +{ + uintptr_t r; + enum posix_stat_kind kind; + + switch (fsfdt) { + case fsfd_target::fd: + kind = kPXStatKindFD; + break; + + case fsfd_target::path: + kind = kPXStatKindCWD; + break; + case fsfd_target::fd_path: + kind = kPXStatKindAt; + break; + + default: + __ensure(!"stat: Invalid fsfdt"); + __builtin_unreachable(); + } + + r = syscall5(kPXSysStat, kind, fd, (uintptr_t)path, flags, + (uintptr_t)statbuf, NULL); + if (int e = sc_error(r); e) + return e; + return 0; +} + +int +sys_statfs(const char *path, struct statfs *buf) +{ + uintptr_t ret = syscall2(kPXSysStatFS, (uintptr_t)path, (uintptr_t)buf, + NULL); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int +sys_statvfs(const char *path, struct statvfs *buf) +{ + struct statfs sb; + uintptr_t ret = syscall2(kPXSysStatFS, (uintptr_t)path, (uintptr_t)&sb, + NULL); + if (int e = sc_error(ret); e) + return e; + + buf->f_bsize = sb.f_bsize; + buf->f_frsize = sb.f_frsize; + buf->f_blocks = sb.f_blocks; + buf->f_bfree = sb.f_bfree; + buf->f_bavail = sb.f_bavail; + + buf->f_files = sb.f_files; + buf->f_ffree = sb.f_ffree; + buf->f_favail = sb.f_ffree; + + buf->f_fsid = sb.f_fsid.__val[1] | (uint64_t)sb.f_fsid.__val[0] << 32; + buf->f_flag = sb.f_flags; + buf->f_namemax = sb.f_namelen; + + return 0; +} + +int +sys_faccessat(int dirfd, const char *pathname, int mode, int flags) +{ + (void)flags; + struct stat buf; + if (int r = sys_stat(dirfd == AT_FDCWD ? fsfd_target::path : + fsfd_target::fd_path, + dirfd, pathname, mode & AT_SYMLINK_FOLLOW, &buf)) { + return r; + } + return 0; +} + +int +sys_access(const char *path, int mode) +{ + return sys_faccessat(AT_FDCWD, path, mode, 0); +} + +int +sys_fork(pid_t *child) +{ + uintptr_t ret = syscall0(kPXSysFork, NULL); + if (int e = sc_error(ret); e) + return e; + *child = (int)ret; + return 0; +} + +int +sys_execve(const char *path, char *const argv[], char *const envp[]) +{ + uintptr_t ret = syscall3(kPXSysExecVE, (uintptr_t)path, (uintptr_t)argv, + (uintptr_t)envp, NULL); + if (int e = sc_error(ret); e) + return e; + mlibc::panicLogger() << "execve returned! " << ret << frg::endlog; + __builtin_unreachable(); +} + +int +sys_waitpid(pid_t pid, int *status, int flags, struct rusage *ru, + pid_t *ret_pid) +{ + (void)ru; + + uintptr_t ret = syscall3(kPXSysWaitPID, pid, (uintptr_t)status, flags, + NULL); + if (int e = sc_error(ret); e) + return e; + *ret_pid = (pid_t)ret; + return 0; +} + +#ifndef MLIBC_BUILDING_RTDL +int +sys_sleep(time_t *sec, long *nanosec) +{ + auto ret = syscall1(kPXSysSleep, *sec * 1000000000 + *nanosec, NULL); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int +sys_uname(struct utsname *buf) +{ + uintptr_t ret = syscall1(kPXSysUTSName, (uintptr_t)buf, NULL); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int +sys_gethostname(char *buf, size_t bufsize) +{ + struct utsname uname_buf; + if (auto e = sys_uname(&uname_buf); e) + return e; + + auto node_len = strlen(uname_buf.nodename); + if (node_len >= bufsize) + return ENAMETOOLONG; + + memcpy(buf, uname_buf.nodename, node_len); + buf[node_len] = '\0'; + return 0; +} + +int +sys_fsync(int) +{ + mlibc::infoLogger() << "mlibc: fsync is a stub" << frg::endlog; + return 0; +} + +int +sys_getentropy(void *buffer, size_t length) +{ + /* todo: improve lmao */ + mlibc::infoLogger() << "mlibc: getentropy is a stub" << frg::endlog; + memset(buffer, 123, length); + return 0; +} +#endif + +int +sys_mkdir(const char *path, mode_t mode) +{ + return sys_mkdirat(AT_FDCWD, path, mode); +} + +int +sys_mkdirat(int dirfd, const char *path, mode_t mode) +{ + uintptr_t ret = syscall3(kPXSysMkDirAt, dirfd, (uintptr_t)path, mode, + NULL); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int +sys_chdir(const char *path) +{ + uintptr_t ret = syscall1(kPXSysChDir, (uintptr_t)path, NULL); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int +sys_umask(mode_t mode, mode_t *old) +{ + uintptr_t ret = syscall1(kPXSysUMask, mode, NULL); + if (int e = sc_error(ret); e) + return e; + *old = (mode_t)ret; + return 0; +} + +int +sys_rename(const char *old_path, const char *new_path) +{ + return sys_renameat(AT_FDCWD, old_path, AT_FDCWD, new_path); +} + +int +sys_renameat(int old_dirfd, const char *old_path, int new_dirfd, + const char *new_path) +{ + auto ret = syscall4(kPXSysRenameAt, old_dirfd, (uintptr_t)old_path, + new_dirfd, (uintptr_t)new_path, NULL); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +} // namespace mlibc diff --git a/lib/mlibc/sysdeps/keyronex/generic/linux.cpp b/lib/mlibc/sysdeps/keyronex/generic/linux.cpp new file mode 100644 index 0000000..9b4a4c7 --- /dev/null +++ b/lib/mlibc/sysdeps/keyronex/generic/linux.cpp @@ -0,0 +1,41 @@ +#include + +#include +#include +#include +#include +#include + +namespace mlibc { + +int +sys_epoll_pwait(int epfd, struct epoll_event *ev, int n, int timeout, + const sigset_t *sigmask, int *raised) +{ + uintptr_t ret = syscall5(kPXSysEPollWait, epfd, (uintptr_t)ev, n, + timeout, (uintptr_t)sigmask, NULL); + if (int e = sc_error(ret); e) + return e; + *raised = ret; + return 0; +} + +int +sys_epoll_create(int flags, int *fd) +{ + uintptr_t ret = syscall1(kPXSysEPollCreate, flags, NULL); + if (int e = sc_error(ret); e) + return e; + *fd = ret; + return 0; +} + +int +sys_epoll_ctl(int epfd, int mode, int fd, struct epoll_event *ev) +{ + uintptr_t ret = syscall4(kPXSysEPollCtl, epfd, mode, fd, (uintptr_t)ev, + NULL); + return sc_error(ret); +} + +} \ No newline at end of file diff --git a/lib/mlibc/sysdeps/keyronex/generic/signal.cpp b/lib/mlibc/sysdeps/keyronex/generic/signal.cpp new file mode 100644 index 0000000..ead3dee --- /dev/null +++ b/lib/mlibc/sysdeps/keyronex/generic/signal.cpp @@ -0,0 +1,66 @@ +#include + +#include +#include +#include +#include + +namespace mlibc { + +int +sys_sigprocmask(int how, const sigset_t *__restrict set, + sigset_t *__restrict retrieve) +{ + auto ret = syscall3(kPXSysSigMask, how, (uintptr_t)set, + (uintptr_t)retrieve, NULL); + if (int e = sc_error(ret); e) { + return e; + } + + return 0; +} + +int +sys_sigaction(int signal, const struct sigaction *__restrict action, + struct sigaction *__restrict oldAction) +{ + auto ret = syscall3(kPXSysSigAction, signal, (uintptr_t)action, + (uintptr_t)oldAction, NULL); + if (int e = sc_error(ret); e) { + return e; + } + + return 0; +} + +int +sys_kill(int pid, int signal) +{ + if (signal == 0) { + mlibc::infoLogger() << "Sending signal 0! Allowing" << frg::endlog; + return 0; + } + + auto ret = syscall2(kPXSysSigSend, pid, signal, NULL); + if (int e = sc_error(ret); e) { + return e; + } + + return 0; +} + +int +sys_sigsuspend(const sigset_t *set) +{ + auto ret = syscall1(kPXSysSigSuspend, (uintptr_t)set, NULL); + if (int e = sc_error(ret); e) { + return e; + } + + mlibc::panicLogger() + << "Unexpected zero return from sigsuspend()" << frg::endlog; + + return 0; +} + +} \ No newline at end of file diff --git a/lib/mlibc/sysdeps/keyronex/generic/socket.cpp b/lib/mlibc/sysdeps/keyronex/generic/socket.cpp new file mode 100644 index 0000000..c6453bf --- /dev/null +++ b/lib/mlibc/sysdeps/keyronex/generic/socket.cpp @@ -0,0 +1,119 @@ +#include + +#include +#include +#include +#include + +#define log_unimplemented() \ + mlibc::infoLogger() << "mlibc: " << __PRETTY_FUNCTION__ \ + << " is a stub!" << frg::endlog; + +namespace mlibc { + +int +sys_socket(int family, int type, int protocol, int *fd) +{ + auto ret = syscall3(kPXSysSocket, family, type, protocol, NULL); + if (int e = sc_error(ret); e) + return e; + *fd = ret; + return 0; +} + +int +sys_bind(int fd, const struct sockaddr *addr, socklen_t addrlen) +{ + auto ret = syscall3(kPXSysBind, fd, (uintptr_t)addr, addrlen, NULL); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int +sys_connect(int fd, const struct sockaddr *addr, socklen_t addrlen) +{ + auto ret = syscall3(kPXSysConnect, fd, (uintptr_t)addr, addrlen, NULL); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int +sys_listen(int fd, int backlog) +{ + auto ret = syscall2(kPXSysListen, fd, backlog, NULL); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int +sys_accept(int fd, int *newfd, struct sockaddr *addr, socklen_t *addrlen, + int flags) +{ + auto ret = syscall4(kPXSysAccept, fd, (uintptr_t)addr, + (uintptr_t)addrlen, flags, NULL); + if (int e = sc_error(ret); e) + return e; + *newfd = ret; + return 0; +} + +int +sys_msg_send(int fd, const struct msghdr *msg, int flags, ssize_t *length) +{ + auto ret = syscall3(kPXSysSendMsg, fd, (uintptr_t)msg, flags, NULL); + if (int e = sc_error(ret); e) + return e; + *length = ret; + return 0; +} + +int +sys_msg_recv(int fd, struct msghdr *msg, int flags, ssize_t *length) +{ + auto ret = syscall3(kPXSysRecvMsg, fd, (uintptr_t)msg, flags, NULL); + if (int e = sc_error(ret); e) + return e; + *length = ret; + return 0; +} + +int +sys_socketpair(int domain, int type_and_flags, int proto, int *fds) +{ + auto ret = syscall4(kPXSysSocketPair, domain, type_and_flags, proto, + (uintptr_t)fds, NULL); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int +sys_getsockopt(int fd, int layer, int number, void *__restrict buffer, + socklen_t *__restrict size) +{ + (void)fd; + (void)layer; + (void)number; + (void)buffer; + (void)size; + log_unimplemented(); + return ENOSYS; +} + +int +sys_setsockopt(int fd, int layer, int number, const void *buffer, + socklen_t size) +{ + (void)fd; + (void)layer; + (void)number; + (void)buffer; + (void)size; + log_unimplemented(); + return ENOSYS; +} + +} diff --git a/lib/mlibc/sysdeps/keyronex/generic/thread.S b/lib/mlibc/sysdeps/keyronex/generic/thread.S new file mode 100644 index 0000000..47ab6a9 --- /dev/null +++ b/lib/mlibc/sysdeps/keyronex/generic/thread.S @@ -0,0 +1,9 @@ +.section .text +.global __mlibc_thread_entry +__mlibc_thread_entry: + pop %rdi + pop %rsi + pop %rdx + call __mlibc_thread_trampoline + +.section .note.GNU-stack,"",%progbits diff --git a/lib/mlibc/sysdeps/keyronex/generic/thread.cpp b/lib/mlibc/sysdeps/keyronex/generic/thread.cpp new file mode 100644 index 0000000..cafb74a --- /dev/null +++ b/lib/mlibc/sysdeps/keyronex/generic/thread.cpp @@ -0,0 +1,80 @@ +#include +#include +#include +#include +#include +#include +#include + +extern "C" void __mlibc_thread_trampoline(void *(*fn)(void *), Tcb *tcb, void *arg) { + if (mlibc::sys_tcb_set(tcb)) { + __ensure(!"failed to set tcb for new thread"); + } + + while (__atomic_load_n(&tcb->tid, __ATOMIC_RELAXED) == 0) { + mlibc::sys_futex_wait(&tcb->tid, 0, nullptr); + } + + tcb->invokeThreadFunc(reinterpret_cast(fn), arg); + + __atomic_store_n(&tcb->didExit, 1, __ATOMIC_RELEASE); + mlibc::sys_futex_wake(&tcb->didExit); + + mlibc::sys_thread_exit(); +} + +#define DEFAULT_STACK 0x400000 + +namespace mlibc { + +extern "C" void __mlibc_thread_entry(); + + int sys_clone(void *tcb, pid_t *tid_out, void *stack) { + (void)tcb; + + auto ret = syscall2(kPXSysForkThread, (uintptr_t)__mlibc_thread_entry, (uintptr_t)stack, NULL); + if (int e = sc_error(ret); e) + return e; + + *tid_out = ret; + return 0; + } + + int sys_prepare_stack(void **stack, void *entry, void *arg, void *tcb, size_t *stack_size, size_t *guard_size, void **stack_base) { + // TODO guard + + mlibc::infoLogger() << "mlibc: sys_prepare_stack() does not setup a guard!" << frg::endlog; + + *guard_size = 0; + + *stack_size = *stack_size ? *stack_size : DEFAULT_STACK; + + if (!*stack) { + *stack_base = mmap(NULL, *stack_size, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); + if (*stack_base == MAP_FAILED) { + return errno; + } + } else { + *stack_base = *stack; + } + + *stack = (void *)((char *)*stack_base + *stack_size); + + void **stack_it = (void **)*stack; + + *--stack_it = arg; + *--stack_it = tcb; + *--stack_it = entry; + + *stack = (void *)stack_it; + + return 0; + } + + void sys_thread_exit() { + mlibc::panicLogger() << "mlibc: sys_thread_exit unimplemented!" << frg::endlog; + __builtin_unreachable(); + } + + +} diff --git a/lib/mlibc/sysdeps/keyronex/include/abi-bits/access.h b/lib/mlibc/sysdeps/keyronex/include/abi-bits/access.h new file mode 120000 index 0000000..cb83931 --- /dev/null +++ b/lib/mlibc/sysdeps/keyronex/include/abi-bits/access.h @@ -0,0 +1 @@ +../../../../abis/linux/access.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/keyronex/include/abi-bits/auxv.h b/lib/mlibc/sysdeps/keyronex/include/abi-bits/auxv.h new file mode 120000 index 0000000..c43f878 --- /dev/null +++ b/lib/mlibc/sysdeps/keyronex/include/abi-bits/auxv.h @@ -0,0 +1 @@ +../../../../abis/linux/auxv.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/keyronex/include/abi-bits/blkcnt_t.h b/lib/mlibc/sysdeps/keyronex/include/abi-bits/blkcnt_t.h new file mode 120000 index 0000000..0b0ec27 --- /dev/null +++ b/lib/mlibc/sysdeps/keyronex/include/abi-bits/blkcnt_t.h @@ -0,0 +1 @@ +../../../../abis/linux/blkcnt_t.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/keyronex/include/abi-bits/blksize_t.h b/lib/mlibc/sysdeps/keyronex/include/abi-bits/blksize_t.h new file mode 120000 index 0000000..7dc8d7c --- /dev/null +++ b/lib/mlibc/sysdeps/keyronex/include/abi-bits/blksize_t.h @@ -0,0 +1 @@ +../../../../abis/linux/blksize_t.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/keyronex/include/abi-bits/clockid_t.h b/lib/mlibc/sysdeps/keyronex/include/abi-bits/clockid_t.h new file mode 120000 index 0000000..6a42da5 --- /dev/null +++ b/lib/mlibc/sysdeps/keyronex/include/abi-bits/clockid_t.h @@ -0,0 +1 @@ +../../../../abis/linux/clockid_t.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/keyronex/include/abi-bits/dev_t.h b/lib/mlibc/sysdeps/keyronex/include/abi-bits/dev_t.h new file mode 120000 index 0000000..bca881e --- /dev/null +++ b/lib/mlibc/sysdeps/keyronex/include/abi-bits/dev_t.h @@ -0,0 +1 @@ +../../../../abis/linux/dev_t.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/keyronex/include/abi-bits/epoll.h b/lib/mlibc/sysdeps/keyronex/include/abi-bits/epoll.h new file mode 120000 index 0000000..eb4b76d --- /dev/null +++ b/lib/mlibc/sysdeps/keyronex/include/abi-bits/epoll.h @@ -0,0 +1 @@ +../../../../abis/linux/epoll.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/keyronex/include/abi-bits/errno.h b/lib/mlibc/sysdeps/keyronex/include/abi-bits/errno.h new file mode 120000 index 0000000..6e507de --- /dev/null +++ b/lib/mlibc/sysdeps/keyronex/include/abi-bits/errno.h @@ -0,0 +1 @@ +../../../../abis/linux/errno.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/keyronex/include/abi-bits/fcntl.h b/lib/mlibc/sysdeps/keyronex/include/abi-bits/fcntl.h new file mode 120000 index 0000000..463e2c9 --- /dev/null +++ b/lib/mlibc/sysdeps/keyronex/include/abi-bits/fcntl.h @@ -0,0 +1 @@ +../../../../abis/linux/fcntl.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/keyronex/include/abi-bits/fsblkcnt_t.h b/lib/mlibc/sysdeps/keyronex/include/abi-bits/fsblkcnt_t.h new file mode 120000 index 0000000..898dfb2 --- /dev/null +++ b/lib/mlibc/sysdeps/keyronex/include/abi-bits/fsblkcnt_t.h @@ -0,0 +1 @@ +../../../../abis/linux/fsblkcnt_t.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/keyronex/include/abi-bits/fsfilcnt_t.h b/lib/mlibc/sysdeps/keyronex/include/abi-bits/fsfilcnt_t.h new file mode 120000 index 0000000..791755c --- /dev/null +++ b/lib/mlibc/sysdeps/keyronex/include/abi-bits/fsfilcnt_t.h @@ -0,0 +1 @@ +../../../../abis/linux/fsfilcnt_t.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/keyronex/include/abi-bits/gid_t.h b/lib/mlibc/sysdeps/keyronex/include/abi-bits/gid_t.h new file mode 120000 index 0000000..abce6d6 --- /dev/null +++ b/lib/mlibc/sysdeps/keyronex/include/abi-bits/gid_t.h @@ -0,0 +1 @@ +../../../../abis/linux/gid_t.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/keyronex/include/abi-bits/in.h b/lib/mlibc/sysdeps/keyronex/include/abi-bits/in.h new file mode 120000 index 0000000..418d1d5 --- /dev/null +++ b/lib/mlibc/sysdeps/keyronex/include/abi-bits/in.h @@ -0,0 +1 @@ +../../../../abis/linux/in.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/keyronex/include/abi-bits/ino_t.h b/lib/mlibc/sysdeps/keyronex/include/abi-bits/ino_t.h new file mode 120000 index 0000000..4c20aca --- /dev/null +++ b/lib/mlibc/sysdeps/keyronex/include/abi-bits/ino_t.h @@ -0,0 +1 @@ +../../../../abis/linux/ino_t.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/keyronex/include/abi-bits/inotify.h b/lib/mlibc/sysdeps/keyronex/include/abi-bits/inotify.h new file mode 120000 index 0000000..b5cb282 --- /dev/null +++ b/lib/mlibc/sysdeps/keyronex/include/abi-bits/inotify.h @@ -0,0 +1 @@ +../../../../abis/linux/inotify.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/keyronex/include/abi-bits/ioctls.h b/lib/mlibc/sysdeps/keyronex/include/abi-bits/ioctls.h new file mode 120000 index 0000000..595106b --- /dev/null +++ b/lib/mlibc/sysdeps/keyronex/include/abi-bits/ioctls.h @@ -0,0 +1 @@ +../../../../abis/linux/ioctls.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/keyronex/include/abi-bits/limits.h b/lib/mlibc/sysdeps/keyronex/include/abi-bits/limits.h new file mode 120000 index 0000000..6c88db2 --- /dev/null +++ b/lib/mlibc/sysdeps/keyronex/include/abi-bits/limits.h @@ -0,0 +1 @@ +../../../../abis/linux/limits.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/keyronex/include/abi-bits/mode_t.h b/lib/mlibc/sysdeps/keyronex/include/abi-bits/mode_t.h new file mode 120000 index 0000000..5d78fdf --- /dev/null +++ b/lib/mlibc/sysdeps/keyronex/include/abi-bits/mode_t.h @@ -0,0 +1 @@ +../../../../abis/linux/mode_t.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/keyronex/include/abi-bits/mqueue.h b/lib/mlibc/sysdeps/keyronex/include/abi-bits/mqueue.h new file mode 120000 index 0000000..fa87b07 --- /dev/null +++ b/lib/mlibc/sysdeps/keyronex/include/abi-bits/mqueue.h @@ -0,0 +1 @@ +../../../../abis/linux/mqueue.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/keyronex/include/abi-bits/msg.h b/lib/mlibc/sysdeps/keyronex/include/abi-bits/msg.h new file mode 120000 index 0000000..f402b49 --- /dev/null +++ b/lib/mlibc/sysdeps/keyronex/include/abi-bits/msg.h @@ -0,0 +1 @@ +../../../../abis/linux/msg.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/keyronex/include/abi-bits/nlink_t.h b/lib/mlibc/sysdeps/keyronex/include/abi-bits/nlink_t.h new file mode 120000 index 0000000..bb3b625 --- /dev/null +++ b/lib/mlibc/sysdeps/keyronex/include/abi-bits/nlink_t.h @@ -0,0 +1 @@ +../../../../abis/linux/nlink_t.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/keyronex/include/abi-bits/packet.h b/lib/mlibc/sysdeps/keyronex/include/abi-bits/packet.h new file mode 120000 index 0000000..998ef1a --- /dev/null +++ b/lib/mlibc/sysdeps/keyronex/include/abi-bits/packet.h @@ -0,0 +1 @@ +../../../../abis/linux/packet.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/keyronex/include/abi-bits/pid_t.h b/lib/mlibc/sysdeps/keyronex/include/abi-bits/pid_t.h new file mode 120000 index 0000000..baa90f6 --- /dev/null +++ b/lib/mlibc/sysdeps/keyronex/include/abi-bits/pid_t.h @@ -0,0 +1 @@ +../../../../abis/linux/pid_t.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/keyronex/include/abi-bits/poll.h b/lib/mlibc/sysdeps/keyronex/include/abi-bits/poll.h new file mode 120000 index 0000000..8ea6a0a --- /dev/null +++ b/lib/mlibc/sysdeps/keyronex/include/abi-bits/poll.h @@ -0,0 +1 @@ +../../../../abis/linux/poll.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/keyronex/include/abi-bits/ptrace.h b/lib/mlibc/sysdeps/keyronex/include/abi-bits/ptrace.h new file mode 120000 index 0000000..b2517b2 --- /dev/null +++ b/lib/mlibc/sysdeps/keyronex/include/abi-bits/ptrace.h @@ -0,0 +1 @@ +../../../../abis/linux/ptrace.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/keyronex/include/abi-bits/reboot.h b/lib/mlibc/sysdeps/keyronex/include/abi-bits/reboot.h new file mode 120000 index 0000000..77013a4 --- /dev/null +++ b/lib/mlibc/sysdeps/keyronex/include/abi-bits/reboot.h @@ -0,0 +1 @@ +../../../../abis/linux/reboot.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/keyronex/include/abi-bits/resource.h b/lib/mlibc/sysdeps/keyronex/include/abi-bits/resource.h new file mode 120000 index 0000000..88d7402 --- /dev/null +++ b/lib/mlibc/sysdeps/keyronex/include/abi-bits/resource.h @@ -0,0 +1 @@ +../../../../abis/linux/resource.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/keyronex/include/abi-bits/seek-whence.h b/lib/mlibc/sysdeps/keyronex/include/abi-bits/seek-whence.h new file mode 120000 index 0000000..df7bccf --- /dev/null +++ b/lib/mlibc/sysdeps/keyronex/include/abi-bits/seek-whence.h @@ -0,0 +1 @@ +../../../../abis/linux/seek-whence.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/keyronex/include/abi-bits/shm.h b/lib/mlibc/sysdeps/keyronex/include/abi-bits/shm.h new file mode 120000 index 0000000..067d8c4 --- /dev/null +++ b/lib/mlibc/sysdeps/keyronex/include/abi-bits/shm.h @@ -0,0 +1 @@ +../../../../abis/linux/shm.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/keyronex/include/abi-bits/signal.h b/lib/mlibc/sysdeps/keyronex/include/abi-bits/signal.h new file mode 120000 index 0000000..4dcb0b7 --- /dev/null +++ b/lib/mlibc/sysdeps/keyronex/include/abi-bits/signal.h @@ -0,0 +1 @@ +../../../../abis/linux/signal.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/keyronex/include/abi-bits/socket.h b/lib/mlibc/sysdeps/keyronex/include/abi-bits/socket.h new file mode 120000 index 0000000..f1dc016 --- /dev/null +++ b/lib/mlibc/sysdeps/keyronex/include/abi-bits/socket.h @@ -0,0 +1 @@ +../../../../abis/linux/socket.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/keyronex/include/abi-bits/socklen_t.h b/lib/mlibc/sysdeps/keyronex/include/abi-bits/socklen_t.h new file mode 120000 index 0000000..41f3b11 --- /dev/null +++ b/lib/mlibc/sysdeps/keyronex/include/abi-bits/socklen_t.h @@ -0,0 +1 @@ +../../../../abis/linux/socklen_t.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/keyronex/include/abi-bits/stat.h b/lib/mlibc/sysdeps/keyronex/include/abi-bits/stat.h new file mode 120000 index 0000000..1f63b41 --- /dev/null +++ b/lib/mlibc/sysdeps/keyronex/include/abi-bits/stat.h @@ -0,0 +1 @@ +../../../../abis/linux/stat.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/keyronex/include/abi-bits/statfs.h b/lib/mlibc/sysdeps/keyronex/include/abi-bits/statfs.h new file mode 120000 index 0000000..e3d202f --- /dev/null +++ b/lib/mlibc/sysdeps/keyronex/include/abi-bits/statfs.h @@ -0,0 +1 @@ +../../../../abis/linux/statfs.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/keyronex/include/abi-bits/statvfs.h b/lib/mlibc/sysdeps/keyronex/include/abi-bits/statvfs.h new file mode 120000 index 0000000..1fc80c2 --- /dev/null +++ b/lib/mlibc/sysdeps/keyronex/include/abi-bits/statvfs.h @@ -0,0 +1 @@ +../../../../abis/linux/statvfs.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/keyronex/include/abi-bits/suseconds_t.h b/lib/mlibc/sysdeps/keyronex/include/abi-bits/suseconds_t.h new file mode 120000 index 0000000..9ed6597 --- /dev/null +++ b/lib/mlibc/sysdeps/keyronex/include/abi-bits/suseconds_t.h @@ -0,0 +1 @@ +../../../../abis/linux/suseconds_t.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/keyronex/include/abi-bits/termios.h b/lib/mlibc/sysdeps/keyronex/include/abi-bits/termios.h new file mode 120000 index 0000000..ee8f0b0 --- /dev/null +++ b/lib/mlibc/sysdeps/keyronex/include/abi-bits/termios.h @@ -0,0 +1 @@ +../../../../abis/linux/termios.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/keyronex/include/abi-bits/time.h b/lib/mlibc/sysdeps/keyronex/include/abi-bits/time.h new file mode 120000 index 0000000..2a02625 --- /dev/null +++ b/lib/mlibc/sysdeps/keyronex/include/abi-bits/time.h @@ -0,0 +1 @@ +../../../../abis/linux/time.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/keyronex/include/abi-bits/uid_t.h b/lib/mlibc/sysdeps/keyronex/include/abi-bits/uid_t.h new file mode 120000 index 0000000..b306777 --- /dev/null +++ b/lib/mlibc/sysdeps/keyronex/include/abi-bits/uid_t.h @@ -0,0 +1 @@ +../../../../abis/linux/uid_t.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/keyronex/include/abi-bits/utsname.h b/lib/mlibc/sysdeps/keyronex/include/abi-bits/utsname.h new file mode 120000 index 0000000..b285754 --- /dev/null +++ b/lib/mlibc/sysdeps/keyronex/include/abi-bits/utsname.h @@ -0,0 +1 @@ +../../../../abis/linux/utsname.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/keyronex/include/abi-bits/vm-flags.h b/lib/mlibc/sysdeps/keyronex/include/abi-bits/vm-flags.h new file mode 120000 index 0000000..bbe258c --- /dev/null +++ b/lib/mlibc/sysdeps/keyronex/include/abi-bits/vm-flags.h @@ -0,0 +1 @@ +../../../../abis/linux/vm-flags.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/keyronex/include/abi-bits/wait.h b/lib/mlibc/sysdeps/keyronex/include/abi-bits/wait.h new file mode 120000 index 0000000..feb2840 --- /dev/null +++ b/lib/mlibc/sysdeps/keyronex/include/abi-bits/wait.h @@ -0,0 +1 @@ +../../../../abis/linux/wait.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/keyronex/include/abi-bits/xattr.h b/lib/mlibc/sysdeps/keyronex/include/abi-bits/xattr.h new file mode 120000 index 0000000..66412d7 --- /dev/null +++ b/lib/mlibc/sysdeps/keyronex/include/abi-bits/xattr.h @@ -0,0 +1 @@ +../../../../abis/linux/xattr.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/keyronex/include/keyronex/syscall.h b/lib/mlibc/sysdeps/keyronex/include/keyronex/syscall.h new file mode 100644 index 0000000..9cbafd0 --- /dev/null +++ b/lib/mlibc/sysdeps/keyronex/include/keyronex/syscall.h @@ -0,0 +1,213 @@ +#ifndef _KEYRONEX__SYSCALL_H +#define _KEYRONEX__SYSCALL_H + +#include + +enum posix_syscall { + /*! debug print */ + kPXSysDebug, + kPXSysMmap, + kPXSysMunmap, + + kPXSysIOCtl, + kPXSysOpenAt, + kPXSysClose, + kPXSysRead, + kPXSysReadLink, + kPXSysWrite, + kPXSysSeek, + kPXSysPPoll, + kPXSysIsATTY, + kPXSysReadDir, + kPXSysStat, + kPXSysUnlinkAt, + kPXSysGetCWD, + kPXSysPipe, + kPXSysDup, + kPXSysDup3, + kPXSysLink, + kPXSysChDir, + kPXSysUMask, + kPXSysMkDirAt, + kPXSysRenameAt, + kPXSysStatFS, + kPXSysFCntl, + + kPXSysSetFSBase, + kPXSysExecVE, + kPXSysExit, + kPXSysFork, + kPXSysWaitPID, + kPXSysGetPID, + kPXSysGetPPID, + kPXSysGetPGID, + kPXSysSetPGID, + kPXSysGetSID, + kPXSysSetSID, + kPXSysGetTID, + + kPXSysSigAction, + kPXSysSigMask, + kPXSysSigSend, + kPXSysSigSuspend, + kPXSysSigTimedWait, + + kPXSysSocket, + kPXSysBind, + kPXSysConnect, + kPXSysListen, + kPXSysAccept, + kPXSysSendMsg, + kPXSysRecvMsg, + kPXSysSocketPair, + kPXSysGetSockOpt, + kPXSysSetSockOpt, + + kPXSysEPollCreate, + kPXSysEPollCtl, + kPXSysEPollWait, + + kPXSysSleep, + kPXSysUTSName, + kPXSysClockGet, + + kPXSysForkThread, + kPXSysFutexWait, + kPXSysFutexWake, + + /*! register signal entry function */ + kPXSysSigEntry, + /*! return from a signal */ + kPXSysSigReturn, +}; + +enum posix_stat_kind { + kPXStatKindFD, + kPXStatKindAt, + kPXStatKindCWD, +}; + +#if defined(__x86_64__) +static inline uintptr_t +syscall0(uintptr_t num, uintptr_t *out) +{ + uintptr_t ret, ret2; + asm volatile("int $0x80" : "=a"(ret), "=D"(ret2) : "a"(num) : "memory"); + if (out) + *out = ret2; + return ret; +} + +static inline uintptr_t +syscall1(uintptr_t num, uintptr_t arg1, uintptr_t *out) +{ + uintptr_t ret, ret2; + asm volatile("int $0x80" + : "=a"(ret), "=D"(ret2) + : "a"(num), "D"(arg1) + : "memory"); + if (out) + *out = ret2; + return ret; +} + +static inline uintptr_t +syscall2(uintptr_t num, uintptr_t arg1, uintptr_t arg2, uintptr_t *out) +{ + uintptr_t ret, ret2; + + asm volatile("int $0x80" + : "=a"(ret), "=D"(ret2) + : "a"(num), "D"(arg1), "S"(arg2) + : "memory"); + + if (out) + *out = ret2; + + return ret; +} + +static inline uintptr_t +syscall3(intptr_t num, uintptr_t arg1, uintptr_t arg2, uintptr_t arg3, + uintptr_t *out) +{ + uintptr_t ret, ret2; + + asm volatile("int $0x80" + : "=a"(ret), "=D"(ret2) + : "a"(num), "D"(arg1), "S"(arg2), "d"(arg3) + : "memory"); + + if (out) + *out = ret2; + + return ret; +} + +static inline uintptr_t +syscall4(intptr_t num, uintptr_t arg1, uintptr_t arg2, uintptr_t arg3, + uintptr_t arg4, uintptr_t *out) +{ + register uintptr_t r10 asm("r10") = arg4; + uintptr_t ret, ret2; + + asm volatile("int $0x80" + : "=a"(ret), "=D"(ret2) + : "a"(num), "D"(arg1), "S"(arg2), "d"(arg3), "r"(r10) + : "memory"); + + if (out) + *out = ret2; + + return ret; +} + +static inline uintptr_t +syscall5(uintptr_t num, uintptr_t arg1, uintptr_t arg2, uintptr_t arg3, + uintptr_t arg4, uintptr_t arg5, uintptr_t *out) +{ + register uintptr_t r10 asm("r10") = arg4, r8 asm("r8") = arg5; + uintptr_t ret, ret2; + + asm volatile("int $0x80" + : "=a"(ret), "=D"(ret2) + : "a"(num), "D"(arg1), "S"(arg2), "d"(arg3), "r"(r10), + "r"(r8) + : "memory"); + + if (out) + *out = ret2; + + return ret; +} + +static inline uintptr_t +syscall6(uintptr_t num, uintptr_t arg1, uintptr_t arg2, uintptr_t arg3, + uintptr_t arg4, uintptr_t arg5, uintptr_t arg6, uintptr_t *out) +{ + register uintptr_t r10 asm("r10") = arg4, r8 asm("r8") = arg5, + r9 asm("r9") = arg6; + uintptr_t ret, ret2; + + asm volatile("int $0x80" + : "=a"(ret), "=D"(ret2) + : "a"(num), "D"(arg1), "S"(arg2), "d"(arg3), "r"(r10), + "r"(r8), "r"(r9) + : "memory"); + + if (out) + *out = ret2; + + return ret; +} + +static inline int +sc_error(uintptr_t ret) +{ + if (ret > -4096UL) + return -ret; + return 0; +} +#endif + +#endif diff --git a/lib/mlibc/sysdeps/keyronex/meson.build b/lib/mlibc/sysdeps/keyronex/meson.build new file mode 100644 index 0000000..42de7a8 --- /dev/null +++ b/lib/mlibc/sysdeps/keyronex/meson.build @@ -0,0 +1,98 @@ + +rtdl_sources += files( + 'generic/generic.cpp' +) + +libc_sources += files( + 'generic/entry.cpp', + 'generic/generic.cpp', + 'generic/linux.cpp', + 'generic/signal.cpp', + 'generic/socket.cpp', + 'generic/thread.cpp', + 'generic/thread.S' +) + +if not no_headers + install_headers( + 'include/abi-bits/auxv.h', + 'include/abi-bits/seek-whence.h', + 'include/abi-bits/vm-flags.h', + 'include/abi-bits/errno.h', + 'include/abi-bits/fcntl.h', + 'include/abi-bits/in.h', + 'include/abi-bits/reboot.h', + 'include/abi-bits/resource.h', + 'include/abi-bits/stat.h', + 'include/abi-bits/signal.h', + 'include/abi-bits/socket.h', + 'include/abi-bits/termios.h', + 'include/abi-bits/time.h', + 'include/abi-bits/blkcnt_t.h', + 'include/abi-bits/blksize_t.h', + 'include/abi-bits/dev_t.h', + 'include/abi-bits/gid_t.h', + 'include/abi-bits/ino_t.h', + 'include/abi-bits/mode_t.h', + 'include/abi-bits/nlink_t.h', + 'include/abi-bits/pid_t.h', + 'include/abi-bits/uid_t.h', + 'include/abi-bits/access.h', + 'include/abi-bits/wait.h', + 'include/abi-bits/limits.h', + 'include/abi-bits/utsname.h', + 'include/abi-bits/ptrace.h', + 'include/abi-bits/poll.h', + 'include/abi-bits/epoll.h', + 'include/abi-bits/packet.h', + 'include/abi-bits/inotify.h', + 'include/abi-bits/clockid_t.h', + 'include/abi-bits/shm.h', + 'include/abi-bits/mqueue.h', + 'include/abi-bits/suseconds_t.h', + 'include/abi-bits/fsfilcnt_t.h', + 'include/abi-bits/fsblkcnt_t.h', + 'include/abi-bits/socklen_t.h', + 'include/abi-bits/statfs.h', + 'include/abi-bits/statvfs.h', + 'include/abi-bits/ioctls.h', + 'include/abi-bits/xattr.h', + subdir: 'abi-bits', + follow_symlinks: true + ) + + install_headers( + 'include/keyronex/syscall.h', + subdir: 'keyronex', + ) +endif + +if not headers_only + crt = custom_target('crt0', + build_by_default: true, + command: c_compiler.cmd_array() + ['-c', '-o', '@OUTPUT@', '@INPUT@'], + input: host_machine.cpu_family() / 'crt-src/crt0.S', + output: 'crt0.o', + install: true, + install_dir: get_option('libdir') + ) + + custom_target('crti', + build_by_default: true, + command: c_compiler.cmd_array() + ['-c', '-o', '@OUTPUT@', '@INPUT@'], + input: host_machine.cpu_family() / 'crt-src/crti.S', + output: 'crti.o', + install: true, + install_dir: get_option('libdir') + ) + + custom_target('crtn', + build_by_default: true, + command: c_compiler.cmd_array() + ['-c', '-o', '@OUTPUT@', '@INPUT@'], + input: host_machine.cpu_family() / 'crt-src/crtn.S', + output: 'crtn.o', + install: true, + install_dir: get_option('libdir') + ) +endif + diff --git a/lib/mlibc/sysdeps/keyronex/x86_64/crt-src/crt0.S b/lib/mlibc/sysdeps/keyronex/x86_64/crt-src/crt0.S new file mode 100644 index 0000000..d16a46f --- /dev/null +++ b/lib/mlibc/sysdeps/keyronex/x86_64/crt-src/crt0.S @@ -0,0 +1,7 @@ +.section .text +.global _start +_start: + mov $main, %rdi + call __mlibc_entry +.section .note.GNU-stack,"",%progbits + diff --git a/lib/mlibc/sysdeps/keyronex/x86_64/crt-src/crti.S b/lib/mlibc/sysdeps/keyronex/x86_64/crt-src/crti.S new file mode 100644 index 0000000..911b078 --- /dev/null +++ b/lib/mlibc/sysdeps/keyronex/x86_64/crt-src/crti.S @@ -0,0 +1,11 @@ +.section .init +.global _init +_init: + push %rax + +.section .fini +.global _fini +_fini: + push %rax +.section .note.GNU-stack,"",%progbits + diff --git a/lib/mlibc/sysdeps/keyronex/x86_64/crt-src/crtn.S b/lib/mlibc/sysdeps/keyronex/x86_64/crt-src/crtn.S new file mode 100644 index 0000000..0187e50 --- /dev/null +++ b/lib/mlibc/sysdeps/keyronex/x86_64/crt-src/crtn.S @@ -0,0 +1,9 @@ +.section .init + pop %rax + ret + +.section .fini + pop %rax + ret +.section .note.GNU-stack,"",%progbits + diff --git a/lib/mlibc/sysdeps/lemon/crt-x86_64/crt0.S b/lib/mlibc/sysdeps/lemon/crt-x86_64/crt0.S new file mode 100755 index 0000000..62298e3 --- /dev/null +++ b/lib/mlibc/sysdeps/lemon/crt-x86_64/crt0.S @@ -0,0 +1,10 @@ +.section .text + +.global _start +_start: + mov $main, %rdi + call __mlibc_entry + +.size _start, . - _start +.section .note.GNU-stack,"",%progbits + diff --git a/lib/mlibc/sysdeps/lemon/generic/entry.cpp b/lib/mlibc/sysdeps/lemon/generic/entry.cpp new file mode 100644 index 0000000..f4cf144 --- /dev/null +++ b/lib/mlibc/sysdeps/lemon/generic/entry.cpp @@ -0,0 +1,33 @@ +#include +#include +#include +#include + +// defined by the POSIX library +void __mlibc_initLocale(); + +extern "C" uintptr_t *__dlapi_entrystack(); + +extern char **environ; +static mlibc::exec_stack_data __mlibc_stack_data; + +struct LibraryGuard { + LibraryGuard(); +}; + +static LibraryGuard guard; + +LibraryGuard::LibraryGuard() { + __mlibc_initLocale(); + + // Parse the exec() stack. + mlibc::parse_exec_stack(__dlapi_entrystack(), &__mlibc_stack_data); + mlibc::set_startup_data(__mlibc_stack_data.argc, __mlibc_stack_data.argv, + __mlibc_stack_data.envp); +} + +extern "C" void __mlibc_entry(int (*main_fn)(int argc, char *argv[], char *env[])) { + // TODO: call __dlapi_enter, otherwise static builds will break (see Linux sysdeps) + auto result = main_fn(__mlibc_stack_data.argc, __mlibc_stack_data.argv, environ); + exit(result); +} diff --git a/lib/mlibc/sysdeps/lemon/generic/filesystem.cpp b/lib/mlibc/sysdeps/lemon/generic/filesystem.cpp new file mode 100755 index 0000000..4a7d780 --- /dev/null +++ b/lib/mlibc/sysdeps/lemon/generic/filesystem.cpp @@ -0,0 +1,406 @@ +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +namespace mlibc{ + +typedef struct { + dev_t st_dev; + ino_t st_ino; + mode_t st_mode; + nlink_t st_nlink; + uid_t st_uid; + uid_t st_gid; + dev_t st_rdev; + off_t st_size; + int64_t st_blksize; + int64_t st_blocks; +} lemon_stat_t; + +int sys_write(int fd, const void* buffer, size_t count, ssize_t* written){ + long ret = syscall(SYS_WRITE, fd, (uintptr_t)buffer, count); + + if(ret < 0) + return -ret; + + *written = ret; + return 0; +} + +int sys_read(int fd, void *buf, size_t count, ssize_t *bytes_read) { + long ret = syscall(SYS_READ, fd, (uintptr_t)buf, count); + + if(ret < 0){ + *bytes_read = 0; + return -ret; + } + + *bytes_read = ret; + return 0; +} + +int sys_pwrite(int fd, const void* buffer, size_t count, off_t off, ssize_t* written){ + int ret = syscall(SYS_PWRITE, fd, (uintptr_t)buffer, count, 0, off); + + + if(ret < 0){ + return -ret; + } + + *written = ret; + return 0; +} + +int sys_pread(int fd, void *buf, size_t count, off_t off, ssize_t *bytes_read) { + int ret = syscall(SYS_PREAD, fd, (uintptr_t)buf, count, 0, off); + + if(ret < 0){ + return -ret; + } + + *bytes_read = ret; + return 0; +} + +int sys_seek(int fd, off_t offset, int whence, off_t *new_offset) { + long ret = syscall(SYS_LSEEK, fd, offset, whence); + + if(ret < 0){ + return -ret; + } + + *new_offset = ret; + return 0; +} + + +int sys_open(const char* filename, int flags, mode_t mode, int* fd){ + long ret = syscall(SYS_OPEN, (uintptr_t)filename, flags); + + if(ret < 0) + return -ret; + + *fd = ret; + + return 0; +} + +int sys_close(int fd){ + syscall(SYS_CLOSE, fd); + return 0; +} + +int sys_access(const char* filename, int mode){ + int fd; + if(int e = sys_open(filename, O_RDONLY, 0, &fd)){ + return e; + } + + sys_close(fd); + return 0; +} + +int sys_stat(fsfd_target fsfdt, int fd, const char *path, int flags, struct stat *statbuf){ + long ret = 0; + + lemon_stat_t lemonStat; + switch(fsfdt){ + case fsfd_target::fd: + ret = syscall(SYS_FSTAT, &lemonStat, fd); + break; + case fsfd_target::path: + ret = syscall(SYS_STAT, &lemonStat, path); + break; + default: + mlibc::infoLogger() << "mlibc warning: sys_stat: unsupported fsfd target" << frg::endlog; + return EINVAL; + } + + statbuf->st_dev = lemonStat.st_dev; + statbuf->st_ino = lemonStat.st_ino; + statbuf->st_mode = lemonStat.st_mode; + statbuf->st_nlink = lemonStat.st_nlink; + statbuf->st_uid = lemonStat.st_uid; + statbuf->st_gid = lemonStat.st_gid; + statbuf->st_rdev = lemonStat.st_rdev; + statbuf->st_size = lemonStat.st_size; + statbuf->st_blksize = lemonStat.st_blksize; + statbuf->st_blocks = lemonStat.st_blocks; + + return -ret; +} + +int sys_ioctl(int fd, unsigned long request, void *arg, int *result){ + long ret = syscall(SYS_IOCTL, fd, request, arg, result); + + if(ret < 0) + return -ret; + + return 0; +} + +#ifndef MLIBC_BUILDING_RTDL + +int sys_poll(struct pollfd *fds, nfds_t count, int timeout, int *num_events){ + long ret = syscall(SYS_POLL, fds, count, timeout); + + if(ret < 0){ + return -ret; + } + + *num_events = ret; + + return 0; +} + +int sys_mkdir(const char* path, mode_t){ + long ret = syscall(SYS_MKDIR, path); + + if(ret < 0){ + return -ret; + } + + return 0; +} + +int sys_rmdir(const char* path){ + long ret = syscall(SYS_RMDIR, path); + + if(ret < 0){ + return -ret; + } + + return 0; +} + +int sys_link(const char* srcpath, const char* destpath){ + long ret = syscall(SYS_LINK, srcpath, destpath); + + if(ret < 0){ + return -ret; + } + + return 0; +} + +int sys_unlinkat(int fd, const char *path, int flags) { + long ret = syscall(SYS_UNLINK, fd, path, flags); + + if(ret < 0) { + return -ret; + } + + return 0; +} + +typedef struct lemon_dirent { + uint32_t inode; // Inode number + uint32_t type; + char name[NAME_MAX]; // Filename +} lemon_dirent_t; + +int sys_read_entries(int handle, void *buffer, size_t max_size, size_t *bytes_read){ + lemon_dirent_t lemonDirent; + long ret = syscall(SYS_READDIR_NEXT, handle, &lemonDirent); + + if(!ret){ + *bytes_read = 0; + return 0; + } else if(ret > 0){ + dirent* dir = (dirent*)buffer; + strcpy(dir->d_name, lemonDirent.name); + dir->d_ino = lemonDirent.inode; + dir->d_off = 0; + dir->d_reclen = sizeof(dirent); + dir->d_type = lemonDirent.type; + + *bytes_read = sizeof(dirent); + return 0; + } else { + return -ret; + } +} + +int sys_open_dir(const char* path, int* handle){ + return sys_open(path, O_DIRECTORY, 0, handle); +} + +int sys_rename(const char* path, const char* new_path){ + return -syscall(SYS_RENAME, path, new_path); +} + +int sys_readlink(const char *path, void *buffer, size_t max_size, ssize_t *length){ + long ret = syscall(SYS_READLINK, path, buffer, max_size); + if(ret < 0){ + return -ret; + } + + *length = ret; + return 0; +} + +int sys_dup(int fd, int flags, int* newfd){ + int ret = syscall(SYS_DUP, fd, flags, -1); + if(ret < 0){ + return -ret; + } + + *newfd = ret; + return 0; +} + +int sys_dup2(int fd, int flags, int newfd){ + int ret = syscall(SYS_DUP, fd, flags, newfd); + if(ret < 0){ + return -ret; + } + + return 0; +} + +int sys_fcntl(int fd, int request, va_list args, int* result){ + if(request == F_DUPFD){ + return sys_dup(fd, 0, result); + } else if (request == F_DUPFD_CLOEXEC) { + return sys_dup(fd, O_CLOEXEC, result); + } else if(request == F_GETFD){ + *result = 0; + return 0; + } else if(request == F_SETFD){ + if(va_arg(args, int) & FD_CLOEXEC) { + return sys_ioctl(fd, FIOCLEX, NULL, result); + } else { + return sys_ioctl(fd, FIONCLEX, NULL, result); + } + } else if(request == F_GETFL){ + int ret = syscall(SYS_GET_FILE_STATUS_FLAGS, fd); + if(ret < 0){ + return -ret; + } + + *result = ret; + return 0; + } else if(request == F_SETFL){ + int ret = syscall(SYS_SET_FILE_STATUS_FLAGS, fd, va_arg(args, int)); + return -ret; + } else { + infoLogger() << "mlibc: sys_fcntl unsupported request (" << request << ")" << frg::endlog; + return EINVAL; + } +} + +int sys_pselect(int nfds, fd_set* readfds, fd_set* writefds, + fd_set *exceptfds, const struct timespec* timeout, const sigset_t* sigmask, int *num_events){ + int ret = syscall(SYS_SELECT, nfds, readfds, writefds, exceptfds, timeout); + if(ret < 0){ + return -ret; + } + + *num_events = ret; + return 0; +} + +int sys_chmod(const char *pathname, mode_t mode){ + int ret = syscall(SYS_CHMOD, pathname, mode); + + if(ret < 0){ + return -ret; + } + + return 0; +} + +int sys_pipe(int *fds, int flags){ + return -syscall(SYS_PIPE, fds, flags); +} + +int sys_epoll_create(int flags, int *fd) { + int ret = syscall(SYS_EPOLL_CREATE, flags); + + if(ret < 0){ + return -ret; + } + + *fd = ret; + + return 0; +} + +int sys_epoll_ctl(int epfd, int mode, int fd, struct epoll_event *ev) { + int ret = syscall(SYS_EPOLL_CTL, epfd, mode, fd, ev); + + if(ret < 0) { + return -ret; + } + + return 0; +} + +int sys_epoll_pwait(int epfd, struct epoll_event *ev, int n, + int timeout, const sigset_t *sigmask, int *raised) { + int ret = syscall(SYS_EPOLL_WAIT, epfd, ev, n, timeout, sigmask); + + if(ret < 0) { + return -ret; + } + + *raised = ret; + + return 0; +} + +int sys_ttyname(int tty, char *buf, size_t size) { + char path[PATH_MAX] = {"/dev/pts/"}; + + struct stat stat; + if(int e = sys_stat(fsfd_target::fd, tty, nullptr, 0, &stat)) { + return e; + } + + if(!S_ISCHR(stat.st_mode)) { + return ENOTTY; // Not a char device, isn't a tty + } + + if(sys_isatty(tty)) { + return ENOTTY; + } + + // Look for tty in /dev/pts + int ptDir = open("/dev/pts", O_DIRECTORY); + __ensure(ptDir >= 0); + + struct dirent dirent; + size_t direntBytesRead; + while(!sys_read_entries(ptDir, &dirent, sizeof(dirent), &direntBytesRead) && direntBytesRead) { + // Compare the inodes + if(dirent.d_ino == stat.st_ino) { + __ensure(strlen(path) + strlen(dirent.d_name) < PATH_MAX); + strcat(path, dirent.d_name); + + strncpy(buf, path, size); + return 0; + } + } + + // Could not find corresponding TTY in /dev/pts + return ENODEV; +} + +int sys_fchdir(int fd) { + return syscall(SYS_FCHDIR, fd); +} +#endif + +} diff --git a/lib/mlibc/sysdeps/lemon/generic/lemon.cpp b/lib/mlibc/sysdeps/lemon/generic/lemon.cpp new file mode 100644 index 0000000..8f15ff1 --- /dev/null +++ b/lib/mlibc/sysdeps/lemon/generic/lemon.cpp @@ -0,0 +1,199 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace mlibc{ + +int sys_futex_tid(){ + return syscall(SYS_GETTID); +} + +int sys_futex_wait(int *pointer, int expected, const struct timespec *time){ + return syscall(SYS_FUTEX_WAIT, pointer, expected); +} + +int sys_futex_wake(int *pointer) { + return syscall(SYS_FUTEX_WAKE, pointer); +} + +int sys_tcb_set(void* pointer){ + syscall(SYS_SET_FS_BASE, (uintptr_t)pointer); + return 0; +} + +int sys_vm_map(void *hint, size_t size, int prot, int flags, int fd, off_t offset, void **window) { + __ensure(flags & MAP_ANONYMOUS); + + return syscall(SYS_MMAP, (uintptr_t)window, (size + 0xFFF) & ~static_cast(0xFFF), (uintptr_t)hint, flags); +} + +int sys_vm_unmap(void* address, size_t size) { + __ensure(!(size & 0xFFF)); + + long ret = syscall(SYS_MUNMAP, (uintptr_t)address, (size + 0xFFF) & ~static_cast(0xFFF)); + + return ret; +} + +int sys_anon_allocate(size_t size, void **pointer) { + return sys_vm_map(nullptr, size, PROT_READ | PROT_WRITE, MAP_ANONYMOUS, -1, 0, pointer); +} + +int sys_anon_free(void *pointer, size_t size) { + return sys_vm_unmap(pointer, size); +} + +void sys_libc_panic(){ + sys_libc_log("libc panic!"); + __builtin_trap(); + for(;;); +} + +void sys_libc_log(const char* msg){ + syscall(0, (uintptr_t)msg); +} + +#ifndef MLIBC_BUILDING_RTDL + +void sys_exit(int status){ + syscall(SYS_EXIT, status); + + __builtin_unreachable(); +} + +pid_t sys_getpid(){ + uint64_t _pid; + syscall(SYS_GETPID, (uintptr_t)&_pid); + + pid_t pid = _pid; + return pid; +} + +pid_t sys_getppid(){ + return syscall(SYS_GETPPID); +} + +int sys_clock_get(int clock, time_t *secs, long *nanos) { + syscall(SYS_UPTIME, nanos); + + *secs = (*nanos) / 1000000000; + *nanos = (*nanos) - (*secs) * 1000000000; + + return 0; +} + +int sys_getcwd(char *buffer, size_t size){ + return syscall(SYS_GET_CWD, buffer, size); +} + +int sys_chdir(const char *path){ + syscall(SYS_CHDIR, path); + return 0; +} + +int sys_sleep(time_t* sec, long* nanosec){ + syscall(SYS_NANO_SLEEP, (*sec) * 1000000000 + (*nanosec)); + return 0; +} + +uid_t sys_getuid(){ + return syscall(SYS_GETUID); +} + +uid_t sys_geteuid(){ + return syscall(SYS_GETEUID); +} + +int sys_setuid(uid_t uid){ + return -syscall(SYS_SETUID, uid); +} + +int sys_seteuid(uid_t euid){ + return -syscall(SYS_SETEUID, euid); +} + +gid_t sys_getgid(){ + return syscall(SYS_GETGID); +} + +gid_t sys_getegid(){ + return syscall(SYS_GETEGID); +} + +int sys_setgid(gid_t gid){ + mlibc::infoLogger() << "mlibc: sys_setgid is a stub" << frg::endlog; + return 0; +} + +int sys_setegid(gid_t egid){ + mlibc::infoLogger() << "mlibc: sys_setegid is a stub" << frg::endlog; + return 0; +} + +void sys_yield(){ + syscall(SYS_YIELD); +} + +int sys_clone(void *tcb, pid_t *tid_out, void *stack){ + pid_t tid = syscall(SYS_SPAWN_THREAD, __mlibc_start_thread, stack); + + if(tid < 0){ + errno = tid; + return -1; + } + + *tid_out = tid; + + return 0; +} + +void sys_thread_exit(){ + syscall(SYS_EXIT_THREAD); + + __builtin_unreachable(); +} + +int sys_waitpid(pid_t pid, int *status, int flags, struct rusage *ru, pid_t *ret_pid){ + if(ru) { + mlibc::infoLogger() << "mlibc: struct rusage in sys_waitpid is unsupported" << frg::endlog; + return ENOSYS; + } + + pid_t ret = syscall(SYS_WAIT_PID, pid, status, flags); + + if(ret < 0){ + return -ret; + } + + *ret_pid = ret; + + return 0; +} + +int sys_fork(pid_t *child){ + long pid = syscall(SYS_FORK, 0); + if(pid < 0){ + errno = pid; + return -1; + } + + *child = pid; + return 0; +} + +int sys_execve(const char *path, char *const argv[], char *const envp[]){ + return -syscall(SYS_EXECVE, path, argv, envp); +} + +int sys_getentropy(void *buffer, size_t length){ + return -syscall(SYS_GETENTROPY, buffer, length); +} +#endif + +} diff --git a/lib/mlibc/sysdeps/lemon/generic/pty.cpp b/lib/mlibc/sysdeps/lemon/generic/pty.cpp new file mode 100644 index 0000000..794f74f --- /dev/null +++ b/lib/mlibc/sysdeps/lemon/generic/pty.cpp @@ -0,0 +1,63 @@ +#include +#include + +#include + +#include +#include +#include + +#include + +namespace mlibc { + +int sys_isatty(int fd) { + struct winsize ws; + long ret = sys_ioctl(fd, TIOCGWINSZ, &ws, 0); + + if(!ret) return 0; + + return ENOTTY; +} + +int sys_tcgetattr(int fd, struct termios *attr) { + if(int e = sys_isatty(fd)) + return e; + + int ret; + sys_ioctl(fd, TCGETS, attr, &ret); + + if(ret) + return -ret; + + return 0; +} + +int sys_tcsetattr(int fd, int optional_action, const struct termios *attr) { + if(int e = sys_isatty(fd)) + return e; + + if(optional_action){ + mlibc::infoLogger() << "mlibc warning: sys_tcsetattr ignores optional_action" << frg::endlog; + } + + int ret; + sys_ioctl(fd, TCSETS, const_cast(attr), &ret); + + if(ret) + return -ret; + + return 0; +} + +int sys_ptsname(int fd, char *buffer, size_t length) { + int index; + if(int e = sys_ioctl(fd, TIOCGPTN, &index, NULL); e) + return e; + if((size_t)snprintf(buffer, length, "/dev/pts/%d", index) >= length) { + return ERANGE; + } + return 0; +} + +} diff --git a/lib/mlibc/sysdeps/lemon/generic/signals.cpp b/lib/mlibc/sysdeps/lemon/generic/signals.cpp new file mode 100644 index 0000000..46b4714 --- /dev/null +++ b/lib/mlibc/sysdeps/lemon/generic/signals.cpp @@ -0,0 +1,38 @@ +#include + +#include + +#include + +namespace mlibc{ + +int sys_sigprocmask(int how, const sigset_t *__restrict set, + sigset_t *__restrict retrieve){ + int ret = syscall(SYS_SIGPROCMASK, how, set, retrieve); + if(ret < 0){ + return -ret; + } + + return 0; +} + +int sys_sigaction(int signal, const struct sigaction *__restrict action, + struct sigaction *__restrict oldAction) { + int ret = syscall(SYS_SIGNAL_ACTION, signal, action, oldAction); + if(ret < 0){ + return -ret; + } + + return 0; +} + +int sys_kill(int pid, int signal){ + int ret = syscall(SYS_KILL, pid, signal); + if(ret < 0){ + return -ret; + } + + return 0; +} + +} \ No newline at end of file diff --git a/lib/mlibc/sysdeps/lemon/generic/sockets.cpp b/lib/mlibc/sysdeps/lemon/generic/sockets.cpp new file mode 100755 index 0000000..7244218 --- /dev/null +++ b/lib/mlibc/sysdeps/lemon/generic/sockets.cpp @@ -0,0 +1,132 @@ +#include + +#include +#include +#include + +#include + +namespace { + +int fcntl_helper(int fd, int request, int *result, ...) { + va_list args; + va_start(args, result); + if(!mlibc::sys_fcntl) { + return ENOSYS; + } + int ret = mlibc::sys_fcntl(fd, request, args, result); + va_end(args); + return ret; +} + +} + +namespace mlibc{ + +int sys_socket(int domain, int type, int protocol, int *fd){ + long ret = syscall(SYS_SOCKET, domain, type, protocol); + + if(ret < 0){ + return -ret; + } + + *fd = ret; + + return 0; +} + +int sys_bind(int sockfd, const struct sockaddr *addr_ptr, socklen_t addrlen){ + return syscall(SYS_BIND, sockfd, addr_ptr, addrlen); +} + +int sys_connect(int sockfd, const struct sockaddr *addr_ptr, socklen_t addrlen){ + return syscall(SYS_CONNECT, sockfd, addr_ptr, addrlen); +} + +int sys_accept(int fd, int *newfd, struct sockaddr *addr_ptr, socklen_t *addr_length, int flags){ + long ret = syscall(SYS_ACCEPT, fd); + + if(ret < 0){ + return -ret; + } + + *newfd = ret; + + if(flags & SOCK_NONBLOCK) { + int fcntl_ret = 0; + fcntl_helper(*newfd, F_GETFL, &fcntl_ret); + fcntl_helper(*newfd, F_SETFL, &fcntl_ret, fcntl_ret | O_NONBLOCK); + } + + if(flags & SOCK_CLOEXEC) { + int fcntl_ret = 0; + fcntl_helper(*newfd, F_GETFD, &fcntl_ret); + fcntl_helper(*newfd, F_SETFD, &fcntl_ret, fcntl_ret | FD_CLOEXEC); + } + + return 0; +} + +int sys_listen(int fd, int backlog){ + return syscall(SYS_LISTEN, fd, backlog); +} + +int sys_msg_recv(int sockfd, struct msghdr *hdr, int flags, ssize_t *length){ + long ret = syscall(SYS_RECVMSG, sockfd, hdr, flags); + + if(ret < 0){ + return -ret; + } + + *length = ret; + + return 0; +} + +int sys_msg_send(int sockfd, const struct msghdr *hdr, int flags, ssize_t *length){ + long ret = syscall(SYS_SENDMSG, sockfd, hdr, flags); + + if(ret < 0){ + return -ret; + } + + *length = ret; + + return 0; +} + +int sys_setsockopt(int fd, int layer, int number, const void *buffer, socklen_t size){ + long ret = syscall(SYS_SET_SOCKET_OPTIONS, fd, layer, number, buffer, size); + + if(ret < 0){ + return -ret; + } + + return 0; +} + +int sys_getsockopt(int fd, int layer, int number, void *__restrict buffer, socklen_t *__restrict size){ + long ret = syscall(SYS_GET_SOCKET_OPTIONS, fd, layer, number, buffer, size); + + if(ret < 0){ + return -ret; + } + + return 0; +} + +int sys_socketpair(int domain, int type_and_flags, int proto, int *fds){ + return -syscall(SYS_SOCKETPAIR, domain, type_and_flags, proto, fds); +} + +int sys_sockname(int fd, struct sockaddr *addr_ptr, socklen_t max_addr_length, + socklen_t *actual_length) { + return -syscall(SYS_SOCKNAME, fd, addr_ptr, max_addr_length); +} + +int sys_peername(int fd, struct sockaddr *addr_ptr, socklen_t max_addr_length, + socklen_t *actual_length) { + return -syscall(SYS_PEERNAME, fd, addr_ptr, max_addr_length); +} + +} diff --git a/lib/mlibc/sysdeps/lemon/generic/thread.cpp b/lib/mlibc/sysdeps/lemon/generic/thread.cpp new file mode 100644 index 0000000..42cd758 --- /dev/null +++ b/lib/mlibc/sysdeps/lemon/generic/thread.cpp @@ -0,0 +1,53 @@ +#include +#include +#include +#include +#include +#include +#include + +extern "C" void __mlibc_enter_thread(void *entry, void *user_arg, Tcb *tcb) { + // Wait until our parent sets up the TID. + while(!__atomic_load_n(&tcb->tid, __ATOMIC_RELAXED)) + mlibc::sys_futex_wait(&tcb->tid, 0, nullptr); + + if(mlibc::sys_tcb_set(tcb)) + __ensure(!"sys_tcb_set() failed"); + + tcb->invokeThreadFunc(entry, user_arg); + + auto self = reinterpret_cast(tcb); + + __atomic_store_n(&self->didExit, 1, __ATOMIC_RELEASE); + mlibc::sys_futex_wake(&self->didExit); + + mlibc::sys_thread_exit(); +} + +namespace mlibc { + +static constexpr size_t default_stacksize = 0x200000; + +int sys_prepare_stack(void **stack, void *entry, void *user_arg, void *tcb, size_t *stack_size, size_t *guard_size, void **stack_base) { + if (!*stack_size) + *stack_size = default_stacksize; + *guard_size = 0; + + if (*stack) { + *stack_base = *stack; + } else { + *stack_base = mmap(nullptr, *stack_size, + PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + } + + uintptr_t *sp = reinterpret_cast(reinterpret_cast(*stack_base) + *stack_size); + + *--sp = reinterpret_cast(tcb); + *--sp = reinterpret_cast(user_arg); + *--sp = reinterpret_cast(entry); + *stack = reinterpret_cast(sp); + return 0; +} + +} //namespace mlibc diff --git a/lib/mlibc/sysdeps/lemon/generic/thread_entry.S b/lib/mlibc/sysdeps/lemon/generic/thread_entry.S new file mode 100644 index 0000000..51e703b --- /dev/null +++ b/lib/mlibc/sysdeps/lemon/generic/thread_entry.S @@ -0,0 +1,11 @@ + +.section .text +.global __mlibc_start_thread +__mlibc_start_thread: + pop %rdi + pop %rsi + pop %rdx + call __mlibc_enter_thread + +.section .note.GNU-stack,"",%progbits + diff --git a/lib/mlibc/sysdeps/lemon/include/abi-bits/access.h b/lib/mlibc/sysdeps/lemon/include/abi-bits/access.h new file mode 120000 index 0000000..171f75f --- /dev/null +++ b/lib/mlibc/sysdeps/lemon/include/abi-bits/access.h @@ -0,0 +1 @@ +../../../../abis/mlibc/access.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/lemon/include/abi-bits/auxv.h b/lib/mlibc/sysdeps/lemon/include/abi-bits/auxv.h new file mode 120000 index 0000000..0f14415 --- /dev/null +++ b/lib/mlibc/sysdeps/lemon/include/abi-bits/auxv.h @@ -0,0 +1 @@ +../../../../abis/lemon/auxv.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/lemon/include/abi-bits/blkcnt_t.h b/lib/mlibc/sysdeps/lemon/include/abi-bits/blkcnt_t.h new file mode 120000 index 0000000..e9d9f1b --- /dev/null +++ b/lib/mlibc/sysdeps/lemon/include/abi-bits/blkcnt_t.h @@ -0,0 +1 @@ +../../../../abis/mlibc/blkcnt_t.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/lemon/include/abi-bits/blksize_t.h b/lib/mlibc/sysdeps/lemon/include/abi-bits/blksize_t.h new file mode 120000 index 0000000..c6dfb6e --- /dev/null +++ b/lib/mlibc/sysdeps/lemon/include/abi-bits/blksize_t.h @@ -0,0 +1 @@ +../../../../abis/mlibc/blksize_t.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/lemon/include/abi-bits/clockid_t.h b/lib/mlibc/sysdeps/lemon/include/abi-bits/clockid_t.h new file mode 120000 index 0000000..71f37bb --- /dev/null +++ b/lib/mlibc/sysdeps/lemon/include/abi-bits/clockid_t.h @@ -0,0 +1 @@ +../../../../abis/mlibc/clockid_t.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/lemon/include/abi-bits/dev_t.h b/lib/mlibc/sysdeps/lemon/include/abi-bits/dev_t.h new file mode 120000 index 0000000..0c1143b --- /dev/null +++ b/lib/mlibc/sysdeps/lemon/include/abi-bits/dev_t.h @@ -0,0 +1 @@ +../../../../abis/mlibc/dev_t.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/lemon/include/abi-bits/epoll.h b/lib/mlibc/sysdeps/lemon/include/abi-bits/epoll.h new file mode 120000 index 0000000..9efc3a0 --- /dev/null +++ b/lib/mlibc/sysdeps/lemon/include/abi-bits/epoll.h @@ -0,0 +1 @@ +../../../../abis/mlibc/epoll.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/lemon/include/abi-bits/errno.h b/lib/mlibc/sysdeps/lemon/include/abi-bits/errno.h new file mode 120000 index 0000000..589859f --- /dev/null +++ b/lib/mlibc/sysdeps/lemon/include/abi-bits/errno.h @@ -0,0 +1 @@ +../../../../abis/mlibc/errno.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/lemon/include/abi-bits/fcntl.h b/lib/mlibc/sysdeps/lemon/include/abi-bits/fcntl.h new file mode 120000 index 0000000..ea5323a --- /dev/null +++ b/lib/mlibc/sysdeps/lemon/include/abi-bits/fcntl.h @@ -0,0 +1 @@ +../../../../abis/mlibc/fcntl.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/lemon/include/abi-bits/fsblkcnt_t.h b/lib/mlibc/sysdeps/lemon/include/abi-bits/fsblkcnt_t.h new file mode 120000 index 0000000..898dfb2 --- /dev/null +++ b/lib/mlibc/sysdeps/lemon/include/abi-bits/fsblkcnt_t.h @@ -0,0 +1 @@ +../../../../abis/linux/fsblkcnt_t.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/lemon/include/abi-bits/fsfilcnt_t.h b/lib/mlibc/sysdeps/lemon/include/abi-bits/fsfilcnt_t.h new file mode 120000 index 0000000..791755c --- /dev/null +++ b/lib/mlibc/sysdeps/lemon/include/abi-bits/fsfilcnt_t.h @@ -0,0 +1 @@ +../../../../abis/linux/fsfilcnt_t.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/lemon/include/abi-bits/gid_t.h b/lib/mlibc/sysdeps/lemon/include/abi-bits/gid_t.h new file mode 120000 index 0000000..6a77218 --- /dev/null +++ b/lib/mlibc/sysdeps/lemon/include/abi-bits/gid_t.h @@ -0,0 +1 @@ +../../../../abis/mlibc/gid_t.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/lemon/include/abi-bits/in.h b/lib/mlibc/sysdeps/lemon/include/abi-bits/in.h new file mode 120000 index 0000000..b58c683 --- /dev/null +++ b/lib/mlibc/sysdeps/lemon/include/abi-bits/in.h @@ -0,0 +1 @@ +../../../../abis/mlibc/in.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/lemon/include/abi-bits/ino_t.h b/lib/mlibc/sysdeps/lemon/include/abi-bits/ino_t.h new file mode 120000 index 0000000..10d644e --- /dev/null +++ b/lib/mlibc/sysdeps/lemon/include/abi-bits/ino_t.h @@ -0,0 +1 @@ +../../../../abis/mlibc/ino_t.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/lemon/include/abi-bits/inotify.h b/lib/mlibc/sysdeps/lemon/include/abi-bits/inotify.h new file mode 120000 index 0000000..3f19ef6 --- /dev/null +++ b/lib/mlibc/sysdeps/lemon/include/abi-bits/inotify.h @@ -0,0 +1 @@ +../../../../abis/mlibc/inotify.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/lemon/include/abi-bits/ioctls.h b/lib/mlibc/sysdeps/lemon/include/abi-bits/ioctls.h new file mode 120000 index 0000000..595106b --- /dev/null +++ b/lib/mlibc/sysdeps/lemon/include/abi-bits/ioctls.h @@ -0,0 +1 @@ +../../../../abis/linux/ioctls.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/lemon/include/abi-bits/limits.h b/lib/mlibc/sysdeps/lemon/include/abi-bits/limits.h new file mode 120000 index 0000000..1aa5894 --- /dev/null +++ b/lib/mlibc/sysdeps/lemon/include/abi-bits/limits.h @@ -0,0 +1 @@ +../../../../abis/mlibc/limits.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/lemon/include/abi-bits/mode_t.h b/lib/mlibc/sysdeps/lemon/include/abi-bits/mode_t.h new file mode 120000 index 0000000..29d7733 --- /dev/null +++ b/lib/mlibc/sysdeps/lemon/include/abi-bits/mode_t.h @@ -0,0 +1 @@ +../../../../abis/mlibc/mode_t.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/lemon/include/abi-bits/mqueue.h b/lib/mlibc/sysdeps/lemon/include/abi-bits/mqueue.h new file mode 120000 index 0000000..fa87b07 --- /dev/null +++ b/lib/mlibc/sysdeps/lemon/include/abi-bits/mqueue.h @@ -0,0 +1 @@ +../../../../abis/linux/mqueue.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/lemon/include/abi-bits/msg.h b/lib/mlibc/sysdeps/lemon/include/abi-bits/msg.h new file mode 120000 index 0000000..f402b49 --- /dev/null +++ b/lib/mlibc/sysdeps/lemon/include/abi-bits/msg.h @@ -0,0 +1 @@ +../../../../abis/linux/msg.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/lemon/include/abi-bits/nlink_t.h b/lib/mlibc/sysdeps/lemon/include/abi-bits/nlink_t.h new file mode 120000 index 0000000..7618c27 --- /dev/null +++ b/lib/mlibc/sysdeps/lemon/include/abi-bits/nlink_t.h @@ -0,0 +1 @@ +../../../../abis/mlibc/nlink_t.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/lemon/include/abi-bits/packet.h b/lib/mlibc/sysdeps/lemon/include/abi-bits/packet.h new file mode 120000 index 0000000..47067e2 --- /dev/null +++ b/lib/mlibc/sysdeps/lemon/include/abi-bits/packet.h @@ -0,0 +1 @@ +../../../../abis/mlibc/packet.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/lemon/include/abi-bits/pid_t.h b/lib/mlibc/sysdeps/lemon/include/abi-bits/pid_t.h new file mode 120000 index 0000000..3fd26a7 --- /dev/null +++ b/lib/mlibc/sysdeps/lemon/include/abi-bits/pid_t.h @@ -0,0 +1 @@ +../../../../abis/mlibc/pid_t.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/lemon/include/abi-bits/poll.h b/lib/mlibc/sysdeps/lemon/include/abi-bits/poll.h new file mode 120000 index 0000000..ab989c7 --- /dev/null +++ b/lib/mlibc/sysdeps/lemon/include/abi-bits/poll.h @@ -0,0 +1 @@ +../../../../abis/mlibc/poll.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/lemon/include/abi-bits/ptrace.h b/lib/mlibc/sysdeps/lemon/include/abi-bits/ptrace.h new file mode 120000 index 0000000..f391fb7 --- /dev/null +++ b/lib/mlibc/sysdeps/lemon/include/abi-bits/ptrace.h @@ -0,0 +1 @@ +../../../../abis/mlibc/ptrace.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/lemon/include/abi-bits/reboot.h b/lib/mlibc/sysdeps/lemon/include/abi-bits/reboot.h new file mode 120000 index 0000000..77013a4 --- /dev/null +++ b/lib/mlibc/sysdeps/lemon/include/abi-bits/reboot.h @@ -0,0 +1 @@ +../../../../abis/linux/reboot.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/lemon/include/abi-bits/resource.h b/lib/mlibc/sysdeps/lemon/include/abi-bits/resource.h new file mode 120000 index 0000000..3e59c75 --- /dev/null +++ b/lib/mlibc/sysdeps/lemon/include/abi-bits/resource.h @@ -0,0 +1 @@ +../../../../abis/mlibc/resource.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/lemon/include/abi-bits/seek-whence.h b/lib/mlibc/sysdeps/lemon/include/abi-bits/seek-whence.h new file mode 120000 index 0000000..df7bccf --- /dev/null +++ b/lib/mlibc/sysdeps/lemon/include/abi-bits/seek-whence.h @@ -0,0 +1 @@ +../../../../abis/linux/seek-whence.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/lemon/include/abi-bits/shm.h b/lib/mlibc/sysdeps/lemon/include/abi-bits/shm.h new file mode 120000 index 0000000..067d8c4 --- /dev/null +++ b/lib/mlibc/sysdeps/lemon/include/abi-bits/shm.h @@ -0,0 +1 @@ +../../../../abis/linux/shm.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/lemon/include/abi-bits/signal.h b/lib/mlibc/sysdeps/lemon/include/abi-bits/signal.h new file mode 120000 index 0000000..4dcb0b7 --- /dev/null +++ b/lib/mlibc/sysdeps/lemon/include/abi-bits/signal.h @@ -0,0 +1 @@ +../../../../abis/linux/signal.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/lemon/include/abi-bits/socket.h b/lib/mlibc/sysdeps/lemon/include/abi-bits/socket.h new file mode 120000 index 0000000..f1dc016 --- /dev/null +++ b/lib/mlibc/sysdeps/lemon/include/abi-bits/socket.h @@ -0,0 +1 @@ +../../../../abis/linux/socket.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/lemon/include/abi-bits/socklen_t.h b/lib/mlibc/sysdeps/lemon/include/abi-bits/socklen_t.h new file mode 120000 index 0000000..41f3b11 --- /dev/null +++ b/lib/mlibc/sysdeps/lemon/include/abi-bits/socklen_t.h @@ -0,0 +1 @@ +../../../../abis/linux/socklen_t.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/lemon/include/abi-bits/stat.h b/lib/mlibc/sysdeps/lemon/include/abi-bits/stat.h new file mode 120000 index 0000000..82642c3 --- /dev/null +++ b/lib/mlibc/sysdeps/lemon/include/abi-bits/stat.h @@ -0,0 +1 @@ +../../../../abis/mlibc/stat.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/lemon/include/abi-bits/statfs.h b/lib/mlibc/sysdeps/lemon/include/abi-bits/statfs.h new file mode 120000 index 0000000..e3d202f --- /dev/null +++ b/lib/mlibc/sysdeps/lemon/include/abi-bits/statfs.h @@ -0,0 +1 @@ +../../../../abis/linux/statfs.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/lemon/include/abi-bits/statvfs.h b/lib/mlibc/sysdeps/lemon/include/abi-bits/statvfs.h new file mode 120000 index 0000000..1fc80c2 --- /dev/null +++ b/lib/mlibc/sysdeps/lemon/include/abi-bits/statvfs.h @@ -0,0 +1 @@ +../../../../abis/linux/statvfs.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/lemon/include/abi-bits/suseconds_t.h b/lib/mlibc/sysdeps/lemon/include/abi-bits/suseconds_t.h new file mode 120000 index 0000000..9ed6597 --- /dev/null +++ b/lib/mlibc/sysdeps/lemon/include/abi-bits/suseconds_t.h @@ -0,0 +1 @@ +../../../../abis/linux/suseconds_t.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/lemon/include/abi-bits/termios.h b/lib/mlibc/sysdeps/lemon/include/abi-bits/termios.h new file mode 120000 index 0000000..ee8f0b0 --- /dev/null +++ b/lib/mlibc/sysdeps/lemon/include/abi-bits/termios.h @@ -0,0 +1 @@ +../../../../abis/linux/termios.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/lemon/include/abi-bits/time.h b/lib/mlibc/sysdeps/lemon/include/abi-bits/time.h new file mode 120000 index 0000000..97f3d52 --- /dev/null +++ b/lib/mlibc/sysdeps/lemon/include/abi-bits/time.h @@ -0,0 +1 @@ +../../../../abis/mlibc/time.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/lemon/include/abi-bits/uid_t.h b/lib/mlibc/sysdeps/lemon/include/abi-bits/uid_t.h new file mode 120000 index 0000000..1113eba --- /dev/null +++ b/lib/mlibc/sysdeps/lemon/include/abi-bits/uid_t.h @@ -0,0 +1 @@ +../../../../abis/mlibc/uid_t.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/lemon/include/abi-bits/utsname.h b/lib/mlibc/sysdeps/lemon/include/abi-bits/utsname.h new file mode 120000 index 0000000..17b993f --- /dev/null +++ b/lib/mlibc/sysdeps/lemon/include/abi-bits/utsname.h @@ -0,0 +1 @@ +../../../../abis/mlibc/utsname.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/lemon/include/abi-bits/vm-flags.h b/lib/mlibc/sysdeps/lemon/include/abi-bits/vm-flags.h new file mode 120000 index 0000000..f1a985e --- /dev/null +++ b/lib/mlibc/sysdeps/lemon/include/abi-bits/vm-flags.h @@ -0,0 +1 @@ +../../../../abis/mlibc/vm-flags.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/lemon/include/abi-bits/wait.h b/lib/mlibc/sysdeps/lemon/include/abi-bits/wait.h new file mode 120000 index 0000000..feb2840 --- /dev/null +++ b/lib/mlibc/sysdeps/lemon/include/abi-bits/wait.h @@ -0,0 +1 @@ +../../../../abis/linux/wait.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/lemon/include/abi-bits/xattr.h b/lib/mlibc/sysdeps/lemon/include/abi-bits/xattr.h new file mode 120000 index 0000000..66412d7 --- /dev/null +++ b/lib/mlibc/sysdeps/lemon/include/abi-bits/xattr.h @@ -0,0 +1 @@ +../../../../abis/linux/xattr.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/lemon/include/lemon/syscall.h b/lib/mlibc/sysdeps/lemon/include/lemon/syscall.h new file mode 100755 index 0000000..98db45d --- /dev/null +++ b/lib/mlibc/sysdeps/lemon/include/lemon/syscall.h @@ -0,0 +1,194 @@ +#ifndef SYSCALL_H +#define SYSCALL_H + +#include + +#define SYS_EXIT 1 +#define SYS_EXEC 2 +#define SYS_READ 3 +#define SYS_WRITE 4 +#define SYS_OPEN 5 +#define SYS_CLOSE 6 +#define SYS_SLEEP 7 +#define SYS_CREATE 8 +#define SYS_LINK 9 +#define SYS_UNLINK 10 +#define SYS_EXECVE 11 +#define SYS_CHDIR 12 +#define SYS_TIME 13 +#define SYS_MAP_FB 14 +#define SYS_GETTID 15 +#define SYS_CHMOD 16 +#define SYS_FSTAT 17 +#define SYS_STAT 18 +#define SYS_LSEEK 19 +#define SYS_GETPID 20 +#define SYS_MOUNT 21 +#define SYS_MKDIR 22 +#define SYS_RMDIR 23 +#define SYS_RENAME 24 +#define SYS_YIELD 25 +#define SYS_READDIR_NEXT 26 +#define SYS_SEND_MESSAGE 28 +#define SYS_RECEIVE_MESSAGE 29 +#define SYS_UPTIME 30 +#define SYS_GET_VIDEO_MODE 31 +#define SYS_UNAME 32 +#define SYS_READDIR 33 +#define SYS_SET_FS_BASE 34 +#define SYS_MMAP 35 +#define SYS_GET_CWD 37 +#define SYS_WAIT_PID 38 +#define SYS_NANO_SLEEP 39 +#define SYS_PREAD 40 +#define SYS_PWRITE 41 +#define SYS_IOCTL 42 +#define SYS_INFO 43 +#define SYS_MUNMAP 44 +#define SYS_CREATE_SHARED_MEMORY 45 +#define SYS_MAP_SHARED_MEMORY 46 +#define SYS_UNMAP_SHARED_MEMORY 47 +#define SYS_DESTROY_SHARED_MEMORY 48 +#define SYS_SOCKET 49 +#define SYS_BIND 50 +#define SYS_LISTEN 51 +#define SYS_ACCEPT 52 +#define SYS_CONNECT 53 +#define SYS_SEND 54 +#define SYS_SENDTO 55 +#define SYS_RECEIVE 56 +#define SYS_RECEIVEFROM 57 +#define SYS_GETUID 58 +#define SYS_SETUID 59 +#define SYS_POLL 60 +#define SYS_SENDMSG 61 +#define SYS_RECVMSG 62 +#define SYS_GETEUID 63 +#define SYS_SETEUID 64 +#define SYS_GET_PROCESS_INFO 65 +#define SYS_GET_NEXT_PROCESS_INFO 66 +#define SYS_READLINK 67 +#define SYS_SPAWN_THREAD 68 +#define SYS_EXIT_THREAD 69 +#define SYS_FUTEX_WAKE 70 +#define SYS_FUTEX_WAIT 71 +#define SYS_DUP 72 +#define SYS_GET_FILE_STATUS_FLAGS 73 +#define SYS_SET_FILE_STATUS_FLAGS 74 +#define SYS_SELECT 75 +#define SYS_CREATE_SERVICE 76 +#define SYS_CREATE_INTERFACE 77 +#define SYS_INTERFACE_ACCEPT 78 +#define SYS_INTERFACE_CONNECT 79 +#define SYS_ENDPOINT_QUEUE 80 +#define SYS_ENDPOINT_DEQUEUE 81 +#define SYS_ENDPOINT_CALL 82 +#define SYS_ENDPOINT_INFO 83 +#define SYS_KERNELOBJECT_WAIT_ONE 84 +#define SYS_KERNELOBJECT_WAIT 85 +#define SYS_KERNELOBJECT_DESTROY 86 +#define SYS_SET_SOCKET_OPTIONS 87 +#define SYS_GET_SOCKET_OPTIONS 88 +#define SYS_DEVICE_MANAGEMENT 89 +#define SYS_INTERRUPT_THREAD 90 +#define SYS_LOAD_KERNEL_MODULE 91 +#define SYS_UNLOAD_KERNEL_MODULE 92 +#define SYS_FORK 93 +#define SYS_GETGID 94 +#define SYS_GETEGID 95 +#define SYS_GETPPID 96 +#define SYS_PIPE 97 +#define SYS_GETENTROPY 98 +#define SYS_SOCKETPAIR 99 +#define SYS_PEERNAME 100 +#define SYS_SOCKNAME 101 +#define SYS_SIGNAL_ACTION 102 +#define SYS_SIGPROCMASK 103 +#define SYS_KILL 104 +#define SYS_SIGNAL_RETURN 105 +#define SYS_ALARM 106 +#define SYS_GET_RESOURCE_LIMIT 107 +#define SYS_EPOLL_CREATE 108 +#define SYS_EPOLL_CTL 109 +#define SYS_EPOLL_WAIT 110 +#define SYS_FCHDIR 111 + +#ifdef __cplusplus +extern "C"{ +#endif + +__attribute__((__always_inline__)) +static inline long syscalln0(uint64_t call) { + volatile long ret; + asm volatile("int $0x69" : "=a"(ret) : "a"(call)); + return ret; +} + +__attribute__((__always_inline__)) +static long syscalln1(uint64_t call, uint64_t arg0) { + volatile long ret; + asm volatile("int $0x69" : "=a"(ret) : "a"(call), "D"(arg0) : "memory"); + return ret; +} + +__attribute__((__always_inline__)) +static long syscalln2(uint64_t call, uint64_t arg0, uint64_t arg1) { + volatile long ret; + asm volatile("int $0x69" : "=a"(ret) : "a"(call), "D"(arg0), "S"(arg1) : "memory"); + return ret; +} + +__attribute__((__always_inline__)) +static long syscalln3(uint64_t call, uint64_t arg0, uint64_t arg1, uint64_t arg2) { + volatile long ret; + asm volatile("int $0x69" : "=a"(ret) : "a"(call), "D"(arg0), "S"(arg1), "d"(arg2) : "memory"); + return ret; +} + +__attribute__((__always_inline__)) +static long syscalln4(uint64_t call, uint64_t arg0, uint64_t arg1, uint64_t arg2, uint64_t arg3) { + volatile long ret; + register uint64_t arg3r asm("r10") = arg3; // put arg3 in r10 + asm volatile("int $0x69" : "=a"(ret) : "a"(call), "D"(arg0), "S"(arg1), "d"(arg2), "r"(arg3r) : "memory"); + return ret; +} + +__attribute__((__always_inline__)) +static long syscalln5(uint64_t call, uint64_t arg0, uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t arg4) { + volatile long ret; + register uint64_t arg3r asm("r10") = arg3; // put arg3 in r10 + register uint64_t arg4r asm("r9") = arg4; // put arg4 in r9 + asm volatile("int $0x69" : "=a"(ret) : "a"(call), "D"(arg0), "S"(arg1), "d"(arg2), "r"(arg3r), "r"(arg4r) : "memory"); + return ret; +} + +__attribute__((__always_inline__)) +static long syscalln6(uint64_t call, uint64_t arg0, uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t arg4, uint64_t arg5) { + volatile long ret; + register uint64_t arg3r asm("r10") = arg3; // put arg3 in r10 + register uint64_t arg4r asm("r9") = arg4; // put arg4 in r9 + register uint64_t arg5r asm("r8") = arg5; // put arg5 in r8 + asm volatile("int $0x69" : "=a"(ret) : "a"(call), "D"(arg0), "S"(arg1), "d"(arg2), "r"(arg3r), "r"(arg4r), "r"(arg5r) : "memory"); + return ret; +} + +#ifdef __cplusplus +} + __attribute__((__always_inline__)) static inline long _syscall(uint64_t call) { return syscalln0(call); } + __attribute__((__always_inline__)) static inline long _syscall(uint64_t call, uint64_t arg0) { return syscalln1(call, arg0); } + __attribute__((__always_inline__)) static inline long _syscall(uint64_t call, uint64_t arg0, uint64_t arg1) { return syscalln2(call, arg0, arg1); } + __attribute__((__always_inline__)) static inline long _syscall(uint64_t call, uint64_t arg0, uint64_t arg1, uint64_t arg2) { return syscalln3(call, arg0, arg1, arg2); } + __attribute__((__always_inline__)) static inline long _syscall(uint64_t call, uint64_t arg0, uint64_t arg1, uint64_t arg2, uint64_t arg3) { return syscalln4(call, arg0, arg1, arg2, arg3); } + __attribute__((__always_inline__)) static inline long _syscall(uint64_t call, uint64_t arg0, uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t arg4) { return syscalln5(call, arg0, arg1, arg2, arg3, arg4); } + __attribute__((__always_inline__)) static inline long _syscall(uint64_t call, uint64_t arg0, uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t arg4, uint64_t arg5) { return syscalln6(call, arg0, arg1, arg2, arg3, arg4, arg5); } + + template + __attribute__((__always_inline__)) static inline long syscall(uint64_t call, T... args){ + return _syscall(call, (uint64_t)(args)...); + } +#else + #define GET_SYSCALL(a0, a1, a2, a3, a4, a5, a6, name, ...) name + #define syscall(...) GET_SYSCALL(__VA_ARGS__, syscalln6, syscalln5, syscalln4, syscalln3, syscalln2, syscalln1, syscalln0)(__VA_ARGS__) +#endif + +#endif diff --git a/lib/mlibc/sysdeps/lemon/include/mlibc/thread-entry.hpp b/lib/mlibc/sysdeps/lemon/include/mlibc/thread-entry.hpp new file mode 100644 index 0000000..2dd88a6 --- /dev/null +++ b/lib/mlibc/sysdeps/lemon/include/mlibc/thread-entry.hpp @@ -0,0 +1,10 @@ +#pragma once + +#include + +extern "C" void __mlibc_start_thread(void); +extern "C" void __mlibc_enter_thread(void *entry, void *user_arg, Tcb *tcb); + +namespace mlibc { + void *prepare_stack(void *entry, void *user_arg, void *tcb); +} diff --git a/lib/mlibc/sysdeps/lemon/meson.build b/lib/mlibc/sysdeps/lemon/meson.build new file mode 100644 index 0000000..8704b71 --- /dev/null +++ b/lib/mlibc/sysdeps/lemon/meson.build @@ -0,0 +1,81 @@ + +rtdl_sources += files( + 'generic/filesystem.cpp', + 'generic/lemon.cpp', +) + +libc_sources += files( + 'generic/entry.cpp', + 'generic/filesystem.cpp', + 'generic/lemon.cpp', + 'generic/pty.cpp', + 'generic/signals.cpp', + 'generic/sockets.cpp', + 'generic/thread_entry.S', + 'generic/thread.cpp' +) + +if not no_headers + install_headers( + 'include/abi-bits/auxv.h', + 'include/abi-bits/seek-whence.h', + 'include/abi-bits/vm-flags.h', + 'include/abi-bits/errno.h', + 'include/abi-bits/fcntl.h', + 'include/abi-bits/in.h', + 'include/abi-bits/resource.h', + 'include/abi-bits/signal.h', + 'include/abi-bits/stat.h', + 'include/abi-bits/socket.h', + 'include/abi-bits/termios.h', + 'include/abi-bits/time.h', + 'include/abi-bits/blkcnt_t.h', + 'include/abi-bits/blksize_t.h', + 'include/abi-bits/dev_t.h', + 'include/abi-bits/gid_t.h', + 'include/abi-bits/ino_t.h', + 'include/abi-bits/mode_t.h', + 'include/abi-bits/nlink_t.h', + 'include/abi-bits/pid_t.h', + 'include/abi-bits/uid_t.h', + 'include/abi-bits/access.h', + 'include/abi-bits/wait.h', + 'include/abi-bits/limits.h', + 'include/abi-bits/utsname.h', + 'include/abi-bits/ptrace.h', + 'include/abi-bits/poll.h', + 'include/abi-bits/epoll.h', + 'include/abi-bits/packet.h', + 'include/abi-bits/inotify.h', + 'include/abi-bits/clockid_t.h', + 'include/abi-bits/shm.h', + 'include/abi-bits/mqueue.h', + 'include/abi-bits/suseconds_t.h', + 'include/abi-bits/fsfilcnt_t.h', + 'include/abi-bits/fsblkcnt_t.h', + 'include/abi-bits/socklen_t.h', + 'include/abi-bits/statfs.h', + 'include/abi-bits/statvfs.h', + 'include/abi-bits/ioctls.h', + 'include/abi-bits/xattr.h', + 'include/abi-bits/msg.h', + subdir: 'abi-bits', + follow_symlinks: true + ) + install_headers( + 'include/lemon/syscall.h', + subdir: 'lemon' + ) +endif + +if not headers_only + crt = custom_target('crt0', + build_by_default: true, + command: c_compiler.cmd_array() + ['-c', '-o', '@OUTPUT@', '@INPUT@'], + input: 'crt-x86_64/crt0.S', + output: 'crt0.o', + install: true, + install_dir: get_option('libdir') + ) +endif + diff --git a/lib/mlibc/sysdeps/linux/aarch64/arch-syscall.cpp b/lib/mlibc/sysdeps/linux/aarch64/arch-syscall.cpp new file mode 100644 index 0000000..b178538 --- /dev/null +++ b/lib/mlibc/sysdeps/linux/aarch64/arch-syscall.cpp @@ -0,0 +1,117 @@ +#include +#include + +using sc_word_t = __sc_word_t; + +sc_word_t __do_syscall0(long sc) { + register int sc_reg asm("x8") = sc; + register sc_word_t ret asm("x0"); + asm volatile ("svc 0" : "=r"(ret) : "r"(sc_reg) : "memory"); + return ret; +} + +sc_word_t __do_syscall1(long sc, + sc_word_t arg1) { + register int sc_reg asm("x8") = sc; + register sc_word_t arg1_reg asm("x0") = arg1; + register sc_word_t ret asm("x0"); + asm volatile ("svc 0" : "=r"(ret) : + "r"(sc_reg), + "r"(arg1_reg) + : "memory"); + return ret; +} + +sc_word_t __do_syscall2(long sc, + sc_word_t arg1, sc_word_t arg2) { + register int sc_reg asm("x8") = sc; + register sc_word_t arg1_reg asm("x0") = arg1; + register sc_word_t arg2_reg asm("x1") = arg2; + register sc_word_t ret asm("x0"); + asm volatile ("svc 0" : "=r"(ret) : + "r"(sc_reg), + "r"(arg1_reg), + "r"(arg2_reg) + : "memory"); + return ret; +} + +sc_word_t __do_syscall3(long sc, + sc_word_t arg1, sc_word_t arg2, sc_word_t arg3) { + register int sc_reg asm("x8") = sc; + register sc_word_t arg1_reg asm("x0") = arg1; + register sc_word_t arg2_reg asm("x1") = arg2; + register sc_word_t arg3_reg asm("x2") = arg3; + register sc_word_t ret asm("x0"); + asm volatile ("svc 0" : "=r"(ret) : + "r"(sc_reg), + "r"(arg1_reg), + "r"(arg2_reg), + "r"(arg3_reg) + : "memory"); + return ret; +} + +sc_word_t __do_syscall4(long sc, + sc_word_t arg1, sc_word_t arg2, sc_word_t arg3, + sc_word_t arg4) { + register int sc_reg asm("x8") = sc; + register sc_word_t arg1_reg asm("x0") = arg1; + register sc_word_t arg2_reg asm("x1") = arg2; + register sc_word_t arg3_reg asm("x2") = arg3; + register sc_word_t arg4_reg asm("x3") = arg4; + register sc_word_t ret asm("x0"); + asm volatile ("svc 0" : "=r"(ret) : + "r"(sc_reg), + "r"(arg1_reg), + "r"(arg2_reg), + "r"(arg3_reg), + "r"(arg4_reg) + : "memory"); + return ret; +} + +sc_word_t __do_syscall5(long sc, + sc_word_t arg1, sc_word_t arg2, sc_word_t arg3, + sc_word_t arg4, sc_word_t arg5) { + register int sc_reg asm("x8") = sc; + register sc_word_t arg1_reg asm("x0") = arg1; + register sc_word_t arg2_reg asm("x1") = arg2; + register sc_word_t arg3_reg asm("x2") = arg3; + register sc_word_t arg4_reg asm("x3") = arg4; + register sc_word_t arg5_reg asm("x4") = arg5; + register sc_word_t ret asm("x0"); + asm volatile ("svc 0" : "=r"(ret) : + "r"(sc_reg), + "r"(arg1_reg), + "r"(arg2_reg), + "r"(arg3_reg), + "r"(arg4_reg), + "r"(arg5_reg) + : "memory"); + return ret; +} + +sc_word_t __do_syscall6(long sc, + sc_word_t arg1, sc_word_t arg2, sc_word_t arg3, + sc_word_t arg4, sc_word_t arg5, sc_word_t arg6) { + register int sc_reg asm("x8") = sc; + register sc_word_t arg1_reg asm("x0") = arg1; + register sc_word_t arg2_reg asm("x1") = arg2; + register sc_word_t arg3_reg asm("x2") = arg3; + register sc_word_t arg4_reg asm("x3") = arg4; + register sc_word_t arg5_reg asm("x4") = arg5; + register sc_word_t arg6_reg asm("x5") = arg6; + register sc_word_t ret asm("x0"); + asm volatile ("svc 0" : "=r"(ret) : + "r"(sc_reg), + "r"(arg1_reg), + "r"(arg2_reg), + "r"(arg3_reg), + "r"(arg4_reg), + "r"(arg5_reg), + "r"(arg6_reg) + : "memory" + ); + return ret; +} diff --git a/lib/mlibc/sysdeps/linux/aarch64/cp_syscall.S b/lib/mlibc/sysdeps/linux/aarch64/cp_syscall.S new file mode 100644 index 0000000..98690c7 --- /dev/null +++ b/lib/mlibc/sysdeps/linux/aarch64/cp_syscall.S @@ -0,0 +1,31 @@ +.section .text +.global __mlibc_do_asm_cp_syscall +.global __mlibc_syscall_begin +.global __mlibc_syscall_end +.type __mlibc_do_asm_cp_syscall, "function" +__mlibc_do_asm_cp_syscall: + mov x8, x0 + mov x0, x1 + mov x1, x2 + mov x2, x3 + mov x3, x4 + mov x4, x5 + mov x5, x6 + + mrs x7, tpidr_el0 + ldr w7, [x7, #-80] // Tcb::cancelBits. See asserts in tcb.hpp. +__mlibc_syscall_begin: + // tcbCancelEnableBit && tcbCancelTriggerBit + mov x9, #((1 << 0) | (1 << 2)) + and x7, x7, x9 + cmp x7, x9 + b.eq cancel + svc 0 +__mlibc_syscall_end: + ret + +cancel: + bl __mlibc_do_cancel + brk #0 +.section .note.GNU-stack,"",%progbits + diff --git a/lib/mlibc/sysdeps/linux/aarch64/crt-src/Scrt1.S b/lib/mlibc/sysdeps/linux/aarch64/crt-src/Scrt1.S new file mode 100644 index 0000000..547499e --- /dev/null +++ b/lib/mlibc/sysdeps/linux/aarch64/crt-src/Scrt1.S @@ -0,0 +1,11 @@ +.section .text +.global _start +_start: + mov x0, sp + adr x1, main + + bl __mlibc_entry + brk #0 + +.section .note.GNU-stack,"",%progbits + diff --git a/lib/mlibc/sysdeps/linux/aarch64/crt-src/crt1.S b/lib/mlibc/sysdeps/linux/aarch64/crt-src/crt1.S new file mode 100644 index 0000000..6550612 --- /dev/null +++ b/lib/mlibc/sysdeps/linux/aarch64/crt-src/crt1.S @@ -0,0 +1,9 @@ +.section .text +.global _start +_start: + mov x0, sp + adrp x1, main + add x1, x1, :lo12:main + bl __mlibc_entry +.section .note.GNU-stack,"",%progbits + diff --git a/lib/mlibc/sysdeps/linux/aarch64/crt-src/crti.S b/lib/mlibc/sysdeps/linux/aarch64/crt-src/crti.S new file mode 100644 index 0000000..0f5ca0f --- /dev/null +++ b/lib/mlibc/sysdeps/linux/aarch64/crt-src/crti.S @@ -0,0 +1,13 @@ +.section .init +.global _init +_init: + stp x29, x30, [sp, -16]! + mov x29, sp + +.section .fini +.global _fini +_fini: + stp x29, x30, [sp, -16]! + mov x29, sp +.section .note.GNU-stack,"",%progbits + diff --git a/lib/mlibc/sysdeps/linux/aarch64/crt-src/crtn.S b/lib/mlibc/sysdeps/linux/aarch64/crt-src/crtn.S new file mode 100644 index 0000000..cd95321 --- /dev/null +++ b/lib/mlibc/sysdeps/linux/aarch64/crt-src/crtn.S @@ -0,0 +1,9 @@ +.section .init + ldp x29, x30, [sp], #16 + ret + +.section .fini + ldp x29, x30, [sp], #16 + ret +.section .note.GNU-stack,"",%progbits + diff --git a/lib/mlibc/sysdeps/linux/aarch64/signals.S b/lib/mlibc/sysdeps/linux/aarch64/signals.S new file mode 100644 index 0000000..923d8d7 --- /dev/null +++ b/lib/mlibc/sysdeps/linux/aarch64/signals.S @@ -0,0 +1,12 @@ +.section .text + +.global __mlibc_signal_restore +.type __mlibc_signal_restore, @function +__mlibc_signal_restore: +.global __mlibc_signal_restore_rt +.type __mlibc_signal_restore_rt, @function +__mlibc_signal_restore_rt: + mov x8,#139 // SYS_rt_sigreturn + svc 0 +.section .note.GNU-stack,"",%progbits + diff --git a/lib/mlibc/sysdeps/linux/aarch64/syscallnos.h b/lib/mlibc/sysdeps/linux/aarch64/syscallnos.h new file mode 100644 index 0000000..9df2598 --- /dev/null +++ b/lib/mlibc/sysdeps/linux/aarch64/syscallnos.h @@ -0,0 +1,313 @@ +#ifndef __MLIBC_SYSCALLNOS_h +#define __MLIBC_SYSCALLNOS_h +/* This file is autogenerated. Don't bother. */ +/* Generator script: sysdeps/linux/update-syscall-list.py. */ +#define __NR_io_setup 0 +#define __NR_io_destroy 1 +#define __NR_io_submit 2 +#define __NR_io_cancel 3 +#define __NR_io_getevents 4 +#define __NR_setxattr 5 +#define __NR_lsetxattr 6 +#define __NR_fsetxattr 7 +#define __NR_getxattr 8 +#define __NR_lgetxattr 9 +#define __NR_fgetxattr 10 +#define __NR_listxattr 11 +#define __NR_llistxattr 12 +#define __NR_flistxattr 13 +#define __NR_removexattr 14 +#define __NR_lremovexattr 15 +#define __NR_fremovexattr 16 +#define __NR_getcwd 17 +#define __NR_lookup_dcookie 18 +#define __NR_eventfd2 19 +#define __NR_epoll_create1 20 +#define __NR_epoll_ctl 21 +#define __NR_epoll_pwait 22 +#define __NR_dup 23 +#define __NR_dup3 24 +#define __NR_fcntl 25 +#define __NR_inotify_init1 26 +#define __NR_inotify_add_watch 27 +#define __NR_inotify_rm_watch 28 +#define __NR_ioctl 29 +#define __NR_ioprio_set 30 +#define __NR_ioprio_get 31 +#define __NR_flock 32 +#define __NR_mknodat 33 +#define __NR_mkdirat 34 +#define __NR_unlinkat 35 +#define __NR_symlinkat 36 +#define __NR_linkat 37 +#define __NR_renameat 38 +#define __NR_umount2 39 +#define __NR_mount 40 +#define __NR_pivot_root 41 +#define __NR_nfsservctl 42 +#define __NR_statfs 43 +#define __NR_fstatfs 44 +#define __NR_truncate 45 +#define __NR_ftruncate 46 +#define __NR_fallocate 47 +#define __NR_faccessat 48 +#define __NR_chdir 49 +#define __NR_fchdir 50 +#define __NR_chroot 51 +#define __NR_fchmod 52 +#define __NR_fchmodat 53 +#define __NR_fchownat 54 +#define __NR_fchown 55 +#define __NR_openat 56 +#define __NR_close 57 +#define __NR_vhangup 58 +#define __NR_pipe2 59 +#define __NR_quotactl 60 +#define __NR_getdents64 61 +#define __NR_lseek 62 +#define __NR_read 63 +#define __NR_write 64 +#define __NR_readv 65 +#define __NR_writev 66 +#define __NR_pread64 67 +#define __NR_pwrite64 68 +#define __NR_preadv 69 +#define __NR_pwritev 70 +#define __NR_sendfile 71 +#define __NR_pselect6 72 +#define __NR_ppoll 73 +#define __NR_signalfd4 74 +#define __NR_vmsplice 75 +#define __NR_splice 76 +#define __NR_tee 77 +#define __NR_readlinkat 78 +#define __NR_newfstatat 79 +#define __NR_fstat 80 +#define __NR_sync 81 +#define __NR_fsync 82 +#define __NR_fdatasync 83 +#define __NR_sync_file_range 84 +#define __NR_timerfd_create 85 +#define __NR_timerfd_settime 86 +#define __NR_timerfd_gettime 87 +#define __NR_utimensat 88 +#define __NR_acct 89 +#define __NR_capget 90 +#define __NR_capset 91 +#define __NR_personality 92 +#define __NR_exit 93 +#define __NR_exit_group 94 +#define __NR_waitid 95 +#define __NR_set_tid_address 96 +#define __NR_unshare 97 +#define __NR_futex 98 +#define __NR_set_robust_list 99 +#define __NR_get_robust_list 100 +#define __NR_nanosleep 101 +#define __NR_getitimer 102 +#define __NR_setitimer 103 +#define __NR_kexec_load 104 +#define __NR_init_module 105 +#define __NR_delete_module 106 +#define __NR_timer_create 107 +#define __NR_timer_gettime 108 +#define __NR_timer_getoverrun 109 +#define __NR_timer_settime 110 +#define __NR_timer_delete 111 +#define __NR_clock_settime 112 +#define __NR_clock_gettime 113 +#define __NR_clock_getres 114 +#define __NR_clock_nanosleep 115 +#define __NR_syslog 116 +#define __NR_ptrace 117 +#define __NR_sched_setparam 118 +#define __NR_sched_setscheduler 119 +#define __NR_sched_getscheduler 120 +#define __NR_sched_getparam 121 +#define __NR_sched_setaffinity 122 +#define __NR_sched_getaffinity 123 +#define __NR_sched_yield 124 +#define __NR_sched_get_priority_max 125 +#define __NR_sched_get_priority_min 126 +#define __NR_sched_rr_get_interval 127 +#define __NR_restart_syscall 128 +#define __NR_kill 129 +#define __NR_tkill 130 +#define __NR_tgkill 131 +#define __NR_sigaltstack 132 +#define __NR_rt_sigsuspend 133 +#define __NR_rt_sigaction 134 +#define __NR_rt_sigprocmask 135 +#define __NR_rt_sigpending 136 +#define __NR_rt_sigtimedwait 137 +#define __NR_rt_sigqueueinfo 138 +#define __NR_rt_sigreturn 139 +#define __NR_setpriority 140 +#define __NR_getpriority 141 +#define __NR_reboot 142 +#define __NR_setregid 143 +#define __NR_setgid 144 +#define __NR_setreuid 145 +#define __NR_setuid 146 +#define __NR_setresuid 147 +#define __NR_getresuid 148 +#define __NR_setresgid 149 +#define __NR_getresgid 150 +#define __NR_setfsuid 151 +#define __NR_setfsgid 152 +#define __NR_times 153 +#define __NR_setpgid 154 +#define __NR_getpgid 155 +#define __NR_getsid 156 +#define __NR_setsid 157 +#define __NR_getgroups 158 +#define __NR_setgroups 159 +#define __NR_uname 160 +#define __NR_sethostname 161 +#define __NR_setdomainname 162 +#define __NR_getrlimit 163 +#define __NR_setrlimit 164 +#define __NR_getrusage 165 +#define __NR_umask 166 +#define __NR_prctl 167 +#define __NR_getcpu 168 +#define __NR_gettimeofday 169 +#define __NR_settimeofday 170 +#define __NR_adjtimex 171 +#define __NR_getpid 172 +#define __NR_getppid 173 +#define __NR_getuid 174 +#define __NR_geteuid 175 +#define __NR_getgid 176 +#define __NR_getegid 177 +#define __NR_gettid 178 +#define __NR_sysinfo 179 +#define __NR_mq_open 180 +#define __NR_mq_unlink 181 +#define __NR_mq_timedsend 182 +#define __NR_mq_timedreceive 183 +#define __NR_mq_notify 184 +#define __NR_mq_getsetattr 185 +#define __NR_msgget 186 +#define __NR_msgctl 187 +#define __NR_msgrcv 188 +#define __NR_msgsnd 189 +#define __NR_semget 190 +#define __NR_semctl 191 +#define __NR_semtimedop 192 +#define __NR_semop 193 +#define __NR_shmget 194 +#define __NR_shmctl 195 +#define __NR_shmat 196 +#define __NR_shmdt 197 +#define __NR_socket 198 +#define __NR_socketpair 199 +#define __NR_bind 200 +#define __NR_listen 201 +#define __NR_accept 202 +#define __NR_connect 203 +#define __NR_getsockname 204 +#define __NR_getpeername 205 +#define __NR_sendto 206 +#define __NR_recvfrom 207 +#define __NR_setsockopt 208 +#define __NR_getsockopt 209 +#define __NR_shutdown 210 +#define __NR_sendmsg 211 +#define __NR_recvmsg 212 +#define __NR_readahead 213 +#define __NR_brk 214 +#define __NR_munmap 215 +#define __NR_mremap 216 +#define __NR_add_key 217 +#define __NR_request_key 218 +#define __NR_keyctl 219 +#define __NR_clone 220 +#define __NR_execve 221 +#define __NR_mmap 222 +#define __NR_fadvise64 223 +#define __NR_swapon 224 +#define __NR_swapoff 225 +#define __NR_mprotect 226 +#define __NR_msync 227 +#define __NR_mlock 228 +#define __NR_munlock 229 +#define __NR_mlockall 230 +#define __NR_munlockall 231 +#define __NR_mincore 232 +#define __NR_madvise 233 +#define __NR_remap_file_pages 234 +#define __NR_mbind 235 +#define __NR_get_mempolicy 236 +#define __NR_set_mempolicy 237 +#define __NR_migrate_pages 238 +#define __NR_move_pages 239 +#define __NR_rt_tgsigqueueinfo 240 +#define __NR_perf_event_open 241 +#define __NR_accept4 242 +#define __NR_recvmmsg 243 +#define __NR_arch_specific_syscall 244 +#define __NR_wait4 260 +#define __NR_prlimit64 261 +#define __NR_fanotify_init 262 +#define __NR_fanotify_mark 263 +#define __NR_name_to_handle_at 264 +#define __NR_open_by_handle_at 265 +#define __NR_clock_adjtime 266 +#define __NR_syncfs 267 +#define __NR_setns 268 +#define __NR_sendmmsg 269 +#define __NR_process_vm_readv 270 +#define __NR_process_vm_writev 271 +#define __NR_kcmp 272 +#define __NR_finit_module 273 +#define __NR_sched_setattr 274 +#define __NR_sched_getattr 275 +#define __NR_renameat2 276 +#define __NR_seccomp 277 +#define __NR_getrandom 278 +#define __NR_memfd_create 279 +#define __NR_bpf 280 +#define __NR_execveat 281 +#define __NR_userfaultfd 282 +#define __NR_membarrier 283 +#define __NR_mlock2 284 +#define __NR_copy_file_range 285 +#define __NR_preadv2 286 +#define __NR_pwritev2 287 +#define __NR_pkey_mprotect 288 +#define __NR_pkey_alloc 289 +#define __NR_pkey_free 290 +#define __NR_statx 291 +#define __NR_io_pgetevents 292 +#define __NR_rseq 293 +#define __NR_kexec_file_load 294 +#define __NR_pidfd_send_signal 424 +#define __NR_io_uring_setup 425 +#define __NR_io_uring_enter 426 +#define __NR_io_uring_register 427 +#define __NR_open_tree 428 +#define __NR_move_mount 429 +#define __NR_fsopen 430 +#define __NR_fsconfig 431 +#define __NR_fsmount 432 +#define __NR_fspick 433 +#define __NR_pidfd_open 434 +#define __NR_clone3 435 +#define __NR_close_range 436 +#define __NR_openat2 437 +#define __NR_pidfd_getfd 438 +#define __NR_faccessat2 439 +#define __NR_process_madvise 440 +#define __NR_epoll_pwait2 441 +#define __NR_mount_setattr 442 +#define __NR_quotactl_fd 443 +#define __NR_landlock_create_ruleset 444 +#define __NR_landlock_add_rule 445 +#define __NR_landlock_restrict_self 446 +#define __NR_memfd_secret 447 +#define __NR_process_mrelease 448 +#define __NR_futex_waitv 449 +#define __NR_set_mempolicy_home_node 450 +#define __NR_syscalls 451 +#endif /* __MLIBC_SYSCALLNOS_h */ diff --git a/lib/mlibc/sysdeps/linux/aarch64/thread_entry.S b/lib/mlibc/sysdeps/linux/aarch64/thread_entry.S new file mode 100644 index 0000000..a47a048 --- /dev/null +++ b/lib/mlibc/sysdeps/linux/aarch64/thread_entry.S @@ -0,0 +1,27 @@ +.section .text +.global __mlibc_spawn_thread +.type __mlibc_spawn_thread, "function" +__mlibc_spawn_thread: + // __mlibc_spawn_thread(flags, stack, pid_out, child_tid, tls) + // x0, x1, x2, x3, x4 + // syscall(NR_clone, flags, stack, ptid, tls, ctid) + // x8, x0, x1, x2, x3, x4 + + // Swap x3 <-> x4 + mov x5, x4 + mov x4, x3 + mov x3, x5 + + mov x8, 220 // NR_clone + svc 0 + cbnz x0, .parent + + ldp x0, x1, [sp], #16 + + bl __mlibc_enter_thread + brk #0 + +.parent: + ret +.section .note.GNU-stack,"",%progbits + diff --git a/lib/mlibc/sysdeps/linux/generic/cxx-syscall.hpp b/lib/mlibc/sysdeps/linux/generic/cxx-syscall.hpp new file mode 100644 index 0000000..aa7d17c --- /dev/null +++ b/lib/mlibc/sysdeps/linux/generic/cxx-syscall.hpp @@ -0,0 +1,118 @@ +#pragma once + +#include +#include +#include +#include +#include + +#include +#include + +using sc_word_t = __sc_word_t; + +extern "C" { + extern sc_word_t __mlibc_do_asm_cp_syscall(int sc, sc_word_t arg1, sc_word_t arg2, + sc_word_t arg3, sc_word_t arg4, sc_word_t arg5, sc_word_t arg6); + + extern void __mlibc_do_cancel(); +} + +namespace mlibc { + // C++ wrappers for the extern "C" functions. + inline sc_word_t do_nargs_syscall(int sc) { + return __do_syscall0(sc); + } + inline sc_word_t do_nargs_syscall(int sc, sc_word_t arg1) { + return __do_syscall1(sc, arg1); + } + inline sc_word_t do_nargs_syscall(int sc, sc_word_t arg1, sc_word_t arg2) { + return __do_syscall2(sc, arg1, arg2); + } + inline sc_word_t do_nargs_syscall(int sc, sc_word_t arg1, sc_word_t arg2, sc_word_t arg3) { + return __do_syscall3(sc, arg1, arg2, arg3); + } + inline sc_word_t do_nargs_syscall(int sc, sc_word_t arg1, sc_word_t arg2, sc_word_t arg3, + sc_word_t arg4) { + return __do_syscall4(sc, arg1, arg2, arg3, arg4); + } + inline sc_word_t do_nargs_syscall(int sc, sc_word_t arg1, sc_word_t arg2, sc_word_t arg3, + sc_word_t arg4, sc_word_t arg5) { + return __do_syscall5(sc, arg1, arg2, arg3, arg4, arg5); + } + inline sc_word_t do_nargs_syscall(int sc, sc_word_t arg1, sc_word_t arg2, sc_word_t arg3, + sc_word_t arg4, sc_word_t arg5, sc_word_t arg6) { + return __do_syscall6(sc, arg1, arg2, arg3, arg4, arg5, arg6); + } + + inline sc_word_t do_nargs_cp_syscall(int sc, sc_word_t arg1) { + return __mlibc_do_asm_cp_syscall(sc, arg1, 0, 0, 0, 0, 0); + } + inline sc_word_t do_nargs_cp_syscall(int sc, sc_word_t arg1, sc_word_t arg2) { + return __mlibc_do_asm_cp_syscall(sc, arg1, arg2, 0, 0, 0, 0); + } + inline sc_word_t do_nargs_cp_syscall(int sc, sc_word_t arg1, sc_word_t arg2, + sc_word_t arg3) { + return __mlibc_do_asm_cp_syscall(sc, arg1, arg2, arg3, 0, 0, 0); + } + inline sc_word_t do_nargs_cp_syscall(int sc, sc_word_t arg1, sc_word_t arg2, sc_word_t arg3, + sc_word_t arg4) { + return __mlibc_do_asm_cp_syscall(sc, arg1, arg2, arg3, arg4, 0, 0); + } + inline sc_word_t do_nargs_cp_syscall(int sc, sc_word_t arg1, sc_word_t arg2, sc_word_t arg3, + sc_word_t arg4, sc_word_t arg5) { + return __mlibc_do_asm_cp_syscall(sc, arg1, arg2, arg3, arg4, arg5, 0); + } + inline sc_word_t do_nargs_cp_syscall(int sc, sc_word_t arg1, sc_word_t arg2, sc_word_t arg3, + sc_word_t arg4, sc_word_t arg5, sc_word_t arg6) { + return __mlibc_do_asm_cp_syscall(sc, arg1, arg2, arg3, arg4, arg5, arg6); + } + + // Type-safe syscall result type. + enum class sc_result_t : sc_word_t { }; + + // Cast to the argument type of the extern "C" functions. + inline sc_word_t sc_cast(long x) { return x; } + inline sc_word_t sc_cast(const void *x) { return reinterpret_cast(x); } + + template + sc_result_t do_syscall(int sc, T... args) { + return static_cast(do_nargs_syscall(sc, sc_cast(args)...)); + } + + inline int sc_error(sc_result_t ret) { + auto v = static_cast(ret); + if(static_cast(v) > -4096UL) + return -v; + return 0; + } + + template + sc_result_t do_cp_syscall(int sc, T... args) { +#if __MLIBC_POSIX_OPTION && !MLIBC_BUILDING_RTDL + auto result = static_cast(do_nargs_cp_syscall(sc, sc_cast(args)...)); + if (int e = sc_error(result); e) { + auto tcb = reinterpret_cast(get_current_tcb()); + if (tcb_cancelled(tcb->cancelBits) && e == EINTR) { + __mlibc_do_cancel(); + __builtin_unreachable(); + } + } + return result; +#else + return do_syscall(sc, std::forward(args)...); +#endif // __MLIBC_POSIX_OPTION || !MLIBC_BUILDING_RTDL + } + // Cast from the syscall result type. + template + T sc_int_result(sc_result_t ret) { + auto v = static_cast(ret); + return v; + } + + template + T *sc_ptr_result(sc_result_t ret) { + auto v = static_cast(ret); + return reinterpret_cast(v); + } +} diff --git a/lib/mlibc/sysdeps/linux/generic/entry.cpp b/lib/mlibc/sysdeps/linux/generic/entry.cpp new file mode 100644 index 0000000..aa049ce --- /dev/null +++ b/lib/mlibc/sysdeps/linux/generic/entry.cpp @@ -0,0 +1,38 @@ +#include +#include +#include +#include +#include + +// defined by the POSIX library +void __mlibc_initLocale(); + +extern "C" uintptr_t *__dlapi_entrystack(); +extern "C" void __dlapi_enter(uintptr_t *); + +extern char **environ; +static mlibc::exec_stack_data __mlibc_stack_data; + +size_t __hwcap; + +struct LibraryGuard { + LibraryGuard(); +}; + +static LibraryGuard guard; + +LibraryGuard::LibraryGuard() { + __mlibc_initLocale(); + + // Parse the exec() stack. + mlibc::parse_exec_stack(__dlapi_entrystack(), &__mlibc_stack_data); + mlibc::set_startup_data(__mlibc_stack_data.argc, __mlibc_stack_data.argv, + __mlibc_stack_data.envp); +} + +extern "C" void __mlibc_entry(uintptr_t *entry_stack, int (*main_fn)(int argc, char *argv[], char *env[])) { + __dlapi_enter(entry_stack); + __hwcap = getauxval(AT_HWCAP); + auto result = main_fn(__mlibc_stack_data.argc, __mlibc_stack_data.argv, environ); + exit(result); +} diff --git a/lib/mlibc/sysdeps/linux/generic/sysdeps.cpp b/lib/mlibc/sysdeps/linux/generic/sysdeps.cpp new file mode 100644 index 0000000..bc33a9e --- /dev/null +++ b/lib/mlibc/sysdeps/linux/generic/sysdeps.cpp @@ -0,0 +1,2002 @@ +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "cxx-syscall.hpp" + +#define STUB_ONLY { __ensure(!"STUB_ONLY function was called"); __builtin_unreachable(); } +#define UNUSED(x) (void)(x); + +#ifndef MLIBC_BUILDING_RTDL +extern "C" long __do_syscall_ret(unsigned long ret) { + if(ret > -4096UL) { + errno = -ret; + return -1; + } + return ret; +} +#endif + +namespace mlibc { + +void sys_libc_log(const char *message) { + size_t n = 0; + while(message[n]) + n++; + do_syscall(SYS_write, 2, message, n); + char lf = '\n'; + do_syscall(SYS_write, 2, &lf, 1); +} + +void sys_libc_panic() { + __builtin_trap(); +} + +#if defined(__i386__) + +struct user_desc { + unsigned int entry_number; + unsigned long base_addr; + unsigned int limit; + unsigned int seg_32bit: 1; + unsigned int contents: 2; + unsigned int read_exec_only: 1; + unsigned int limit_in_pages: 1; + unsigned int seg_not_present: 1; + unsigned int useable: 1; +}; + +#endif + +int sys_tcb_set(void *pointer) { +#if defined(__x86_64__) + auto ret = do_syscall(SYS_arch_prctl, 0x1002 /* ARCH_SET_FS */, pointer); + if(int e = sc_error(ret); e) + return e; +#elif defined(__i386__) + struct user_desc desc = { + .entry_number = static_cast(-1), + .base_addr = uintptr_t(pointer), + .limit = 0xfffff, + .seg_32bit = 1, + .contents = 0, + .read_exec_only = 0, + .limit_in_pages = 1, + .seg_not_present = 0, + .useable = 1, + }; + auto ret = do_syscall(SYS_set_thread_area, &desc); + __ensure(!sc_error(ret)); + asm volatile ("movw %w0, %%gs" : : "q"(desc.entry_number * 8 + 3) :); +#elif defined(__riscv) + uintptr_t thread_data = reinterpret_cast(pointer) + sizeof(Tcb); + asm volatile ("mv tp, %0" :: "r"(thread_data)); +#elif defined (__aarch64__) + uintptr_t thread_data = reinterpret_cast(pointer) + sizeof(Tcb) - 0x10; + asm volatile ("msr tpidr_el0, %0" :: "r"(thread_data)); +#else +#error "Missing architecture specific code." +#endif + return 0; +} + +int sys_anon_allocate(size_t size, void **pointer) { + return sys_vm_map(nullptr, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, + -1, 0, pointer); +} +int sys_anon_free(void *pointer, size_t size) { + return sys_vm_unmap(pointer, size); +} + +int sys_fadvise(int fd, off_t offset, off_t length, int advice) { + auto ret = do_syscall(SYS_fadvise64, fd, offset, length, advice); + if(int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_open(const char *path, int flags, mode_t mode, int *fd) { + auto ret = do_cp_syscall(SYS_openat, AT_FDCWD, path, flags, mode); + if(int e = sc_error(ret); e) + return e; + *fd = sc_int_result(ret); + return 0; +} + +int sys_openat(int dirfd, const char *path, int flags, mode_t mode, int *fd) { + auto ret = do_syscall(SYS_openat, dirfd, path, flags, mode); + if (int e = sc_error(ret); e) + return e; + *fd = sc_int_result(ret); + return 0; +} + +int sys_close(int fd) { + auto ret = do_cp_syscall(SYS_close, fd); + if(int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_dup2(int fd, int flags, int newfd) { + auto ret = do_cp_syscall(SYS_dup3, fd, newfd, flags); + if(int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_read(int fd, void *buffer, size_t size, ssize_t *bytes_read) { + auto ret = do_cp_syscall(SYS_read, fd, buffer, size); + if(int e = sc_error(ret); e) + return e; + *bytes_read = sc_int_result(ret); + return 0; +} + +int sys_readv(int fd, const struct iovec *iovs, int iovc, ssize_t *bytes_read) { + auto ret = do_cp_syscall(SYS_readv, fd, iovs, iovc); + if(int e = sc_error(ret); e) + return e; + *bytes_read = sc_int_result(ret); + return 0; +} + +int sys_write(int fd, const void *buffer, size_t size, ssize_t *bytes_written) { + auto ret = do_cp_syscall(SYS_write, fd, buffer, size); + if(int e = sc_error(ret); e) + return e; + if(bytes_written) + *bytes_written = sc_int_result(ret); + return 0; +} + +int sys_seek(int fd, off_t offset, int whence, off_t *new_offset) { + auto ret = do_syscall(SYS_lseek, fd, offset, whence); + if(int e = sc_error(ret); e) + return e; + *new_offset = sc_int_result(ret); + return 0; +} + +int sys_chmod(const char *pathname, mode_t mode) { + auto ret = do_cp_syscall(SYS_fchmodat, AT_FDCWD, pathname, mode); + if(int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_fchmod(int fd, mode_t mode) { + auto ret = do_cp_syscall(SYS_fchmod, fd, mode); + if(int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_fchmodat(int fd, const char *pathname, mode_t mode, int flags) { + auto ret = do_cp_syscall(SYS_fchmodat, fd, pathname, mode, flags); + if(int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_fchownat(int dirfd, const char *pathname, uid_t owner, gid_t group, int flags) { + auto ret = do_cp_syscall(SYS_fchownat, dirfd, pathname, owner, group, flags); + if(int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_utimensat(int dirfd, const char *pathname, const struct timespec times[2], int flags) { + auto ret = do_cp_syscall(SYS_utimensat, dirfd, pathname, times, flags); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_vm_map(void *hint, size_t size, int prot, int flags, + int fd, off_t offset, void **window) { + if(offset % 4096) + return EINVAL; + if(size >= PTRDIFF_MAX) + return ENOMEM; +#if defined(SYS_mmap2) + auto ret = do_syscall(SYS_mmap2, hint, size, prot, flags, fd, offset/4096); +#else + auto ret = do_syscall(SYS_mmap, hint, size, prot, flags, fd, offset); +#endif + // TODO: musl fixes up EPERM errors from the kernel. + if(int e = sc_error(ret); e) + return e; + *window = sc_ptr_result(ret); + return 0; +} + +int sys_vm_unmap(void *pointer, size_t size) { + auto ret = do_syscall(SYS_munmap, pointer, size); + if(int e = sc_error(ret); e) + return e; + return 0; +} + +// All remaining functions are disabled in ldso. +#ifndef MLIBC_BUILDING_RTDL + +int sys_clock_get(int clock, time_t *secs, long *nanos) { + struct timespec tp = {}; + auto ret = do_syscall(SYS_clock_gettime, clock, &tp); + if (int e = sc_error(ret); e) + return e; + *secs = tp.tv_sec; + *nanos = tp.tv_nsec; + return 0; +} + +int sys_clock_getres(int clock, time_t *secs, long *nanos) { + struct timespec tp = {}; + auto ret = do_syscall(SYS_clock_getres, clock, &tp); + if (int e = sc_error(ret); e) + return e; + *secs = tp.tv_sec; + *nanos = tp.tv_nsec; + return 0; +} + +int sys_stat(fsfd_target fsfdt, int fd, const char *path, int flags, struct stat *statbuf) { + if (fsfdt == fsfd_target::path) + fd = AT_FDCWD; + else if (fsfdt == fsfd_target::fd) + flags |= AT_EMPTY_PATH; + else + __ensure(fsfdt == fsfd_target::fd_path); + +#if defined(SYS_newfstatat) + auto ret = do_cp_syscall(SYS_newfstatat, fd, path, statbuf, flags); +#else + auto ret = do_cp_syscall(SYS_fstatat64, fd, path, statbuf, flags); +#endif + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_statfs(const char *path, struct statfs *buf) { + auto ret = do_cp_syscall(SYS_statfs, path, buf); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_fstatfs(int fd, struct statfs *buf) { + auto ret = do_cp_syscall(SYS_fstatfs, fd, buf); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +extern "C" void __mlibc_signal_restore(void); +extern "C" void __mlibc_signal_restore_rt(void); + +int sys_sigaction(int signum, const struct sigaction *act, + struct sigaction *oldact) { + struct ksigaction { + void (*handler)(int); + unsigned long flags; + void (*restorer)(void); + sigset_t mask; + }; + + struct ksigaction kernel_act, kernel_oldact; + if (act) { + kernel_act.handler = act->sa_handler; + kernel_act.flags = act->sa_flags | SA_RESTORER; + kernel_act.restorer = (act->sa_flags & SA_SIGINFO) ? __mlibc_signal_restore_rt : __mlibc_signal_restore; + kernel_act.mask = act->sa_mask; + } + + static_assert(sizeof(sigset_t) == 8); + + auto ret = do_syscall(SYS_rt_sigaction, signum, act ? + &kernel_act : NULL, oldact ? + &kernel_oldact : NULL, sizeof(sigset_t)); + if (int e = sc_error(ret); e) + return e; + + if (oldact) { + oldact->sa_handler = kernel_oldact.handler; + oldact->sa_flags = kernel_oldact.flags; + oldact->sa_restorer = kernel_oldact.restorer; + oldact->sa_mask = kernel_oldact.mask; + } + return 0; +} + +int sys_socket(int domain, int type, int protocol, int *fd) { + auto ret = do_syscall(SYS_socket, domain, type, protocol); + if (int e = sc_error(ret); e) + return e; + *fd = sc_int_result(ret); + return 0; +} + +int sys_msg_send(int sockfd, const struct msghdr *msg, int flags, ssize_t *length) { + auto ret = do_cp_syscall(SYS_sendmsg, sockfd, msg, flags); + if (int e = sc_error(ret); e) + return e; + *length = sc_int_result(ret); + return 0; +} + +ssize_t sys_sendto(int fd, const void *buffer, size_t size, int flags, const struct sockaddr *sock_addr, socklen_t addr_length, ssize_t *length) { + auto ret = do_cp_syscall(SYS_sendto, fd, buffer, size, flags, sock_addr, addr_length); + if(int e = sc_error(ret); e) { + return e; + } + *length = sc_int_result(ret); + return 0; +} + +ssize_t sys_recvfrom(int fd, void *buffer, size_t size, int flags, struct sockaddr *sock_addr, socklen_t *addr_length, ssize_t *length) { + auto ret = do_cp_syscall(SYS_recvfrom, fd, buffer, size, flags, sock_addr, addr_length); + if(int e = sc_error(ret); e) { + return e; + } + *length = sc_int_result(ret); + return 0; +} + +int sys_msg_recv(int sockfd, struct msghdr *msg, int flags, ssize_t *length) { + auto ret = do_cp_syscall(SYS_recvmsg, sockfd, msg, flags); + if (int e = sc_error(ret); e) + return e; + *length = sc_int_result(ret); + return 0; +} + +int sys_fcntl(int fd, int cmd, va_list args, int *result) { + auto arg = va_arg(args, unsigned long); + // TODO: the api for linux differs for each command so fcntl()s might fail with -EINVAL + // we should implement all the different fcntl()s + // TODO(geert): only some fcntl()s can fail with -EINTR, making do_cp_syscall useless + // on most fcntls(). Another reason to handle different fcntl()s seperately. + auto ret = do_cp_syscall(SYS_fcntl, fd, cmd, arg); + if (int e = sc_error(ret); e) + return e; + *result = sc_int_result(ret); + return 0; +} + +int sys_getcwd(char *buf, size_t size) { + auto ret = do_syscall(SYS_getcwd, buf, size); + if (int e = sc_error(ret); e) { + return e; + } + return 0; +} + +int sys_unlinkat(int dfd, const char *path, int flags) { + auto ret = do_syscall(SYS_unlinkat, dfd, path, flags); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_sleep(time_t *secs, long *nanos) { + struct timespec req = { + .tv_sec = *secs, + .tv_nsec = *nanos + }; + struct timespec rem = {}; + + auto ret = do_cp_syscall(SYS_nanosleep, &req, &rem); + if (int e = sc_error(ret); e) + return e; + + *secs = rem.tv_sec; + *nanos = rem.tv_nsec; + return 0; +} + +int sys_isatty(int fd) { + unsigned short winsizeHack[4]; + auto ret = do_syscall(SYS_ioctl, fd, 0x5413 /* TIOCGWINSZ */, &winsizeHack); + if (int e = sc_error(ret); e) + return e; + auto res = sc_int_result(ret); + if(!res) return 0; + return 1; +} + +#if __MLIBC_POSIX_OPTION + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int sys_ioctl(int fd, unsigned long request, void *arg, int *result) { + auto ret = do_syscall(SYS_ioctl, fd, request, arg); + if (int e = sc_error(ret); e) + return e; + if (result) + *result = sc_int_result(ret); + return 0; +} + +int sys_connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen) { + auto ret = do_cp_syscall(SYS_connect, sockfd, addr, addrlen); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_pselect(int nfds, fd_set *readfds, fd_set *writefds, + fd_set *exceptfds, const struct timespec *timeout, const sigset_t *sigmask, int *num_events) { + // The Linux kernel really wants 7 arguments, even tho this is not supported + // To fix that issue, they use a struct as the last argument. + // See the man page of pselect and the glibc source code + struct { + sigset_t ss; + size_t ss_len; + } data; + data.ss = (uintptr_t)sigmask; + data.ss_len = NSIG / 8; + + auto ret = do_cp_syscall(SYS_pselect6, nfds, readfds, writefds, + exceptfds, timeout, &data); + if (int e = sc_error(ret); e) + return e; + *num_events = sc_int_result(ret); + return 0; +} + +int sys_pipe(int *fds, int flags) { + if(flags) { + auto ret = do_syscall(SYS_pipe2, fds, flags); + if (int e = sc_error(ret); e) + return e; + return 0; + } else { + auto ret = do_syscall(SYS_pipe2, fds, 0); + if (int e = sc_error(ret); e) + return e; + return 0; + } +} + +int sys_fork(pid_t *child) { + auto ret = do_syscall(SYS_clone, SIGCHLD, 0); + if (int e = sc_error(ret); e) + return e; + *child = sc_int_result(ret); + return 0; +} + +int sys_waitpid(pid_t pid, int *status, int flags, struct rusage *ru, pid_t *ret_pid) { + auto ret = do_syscall(SYS_wait4, pid, status, flags, ru); + if (int e = sc_error(ret); e) + return e; + *ret_pid = sc_int_result(ret); + return 0; +} + +int sys_execve(const char *path, char *const argv[], char *const envp[]) { + auto ret = do_syscall(SYS_execve, path, argv, envp); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_sigprocmask(int how, const sigset_t *set, sigset_t *old) { + auto ret = do_syscall(SYS_rt_sigprocmask, how, set, old, NSIG / 8); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_setresuid(uid_t ruid, uid_t euid, uid_t suid) { + auto ret = do_syscall(SYS_setresuid, ruid, euid, suid); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_setresgid(gid_t rgid, gid_t egid, gid_t sgid) { + auto ret = do_syscall(SYS_setresgid, rgid, egid, sgid); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_getresuid(uid_t *ruid, uid_t *euid, uid_t *suid) { + auto ret = do_syscall(SYS_getresuid, &ruid, &euid, &suid); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid) { + auto ret = do_syscall(SYS_getresgid, &rgid, &egid, &sgid); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_setreuid(uid_t ruid, uid_t euid) { + auto ret = do_syscall(SYS_setreuid, ruid, euid); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_setregid(gid_t rgid, gid_t egid) { + auto ret = do_syscall(SYS_setregid, rgid, egid); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_sysinfo(struct sysinfo *info) { + auto ret = do_syscall(SYS_sysinfo, info); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +void sys_yield() { + do_syscall(SYS_sched_yield); +} + +int sys_clone(void *tcb, pid_t *pid_out, void *stack) { + unsigned long flags = CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND + | CLONE_THREAD | CLONE_SYSVSEM | CLONE_SETTLS + | CLONE_PARENT_SETTID; + +#if defined(__riscv) + // TP should point to the address immediately after the TCB. + // TODO: We should change the sysdep so that we don't need to do this. + auto tls = reinterpret_cast(tcb) + sizeof(Tcb); + tcb = reinterpret_cast(tls); +#elif defined(__aarch64__) + // TP should point to the address 16 bytes before the end of the TCB. + // TODO: We should change the sysdep so that we don't need to do this. + auto tp = reinterpret_cast(tcb) + sizeof(Tcb) - 0x10; + tcb = reinterpret_cast(tp); +#elif defined(__i386__) + /* get the entry number, as we don't request a new one here */ + uint32_t gs; + asm volatile("movw %%gs, %w0" : "=q"(gs)); + + auto user_desc = reinterpret_cast(getAllocator().allocate(sizeof(struct user_desc))); + + user_desc->entry_number = (gs & 0xffff) >> 3; + user_desc->base_addr = uintptr_t(tcb); + user_desc->limit = 0xfffff; + user_desc->seg_32bit = 1; + user_desc->contents = 0; + user_desc->read_exec_only = 0; + user_desc->limit_in_pages = 1; + user_desc->seg_not_present = 0; + user_desc->useable = 1; + + tcb = reinterpret_cast(user_desc); +#endif + + auto ret = __mlibc_spawn_thread(flags, stack, pid_out, NULL, tcb); + if (ret < 0) + return ret; + + return 0; +} + +extern "C" const char __mlibc_syscall_begin[1]; +extern "C" const char __mlibc_syscall_end[1]; + +#if defined(__riscv) +// Disable UBSan here to work around qemu-user misaligning ucontext_t. +// https://github.com/qemu/qemu/blob/2bf40d0841b942e7ba12953d515e62a436f0af84/linux-user/riscv/signal.c#L68-L69 +[[gnu::no_sanitize("undefined")]] +#endif +int sys_before_cancellable_syscall(ucontext_t *uct) { +#if defined(__x86_64__) + auto pc = reinterpret_cast(uct->uc_mcontext.gregs[REG_RIP]); +#elif defined(__i386__) + auto pc = reinterpret_cast(uct->uc_mcontext.gregs[REG_EIP]); +#elif defined(__riscv) + auto pc = reinterpret_cast(uct->uc_mcontext.gregs[REG_PC]); +#elif defined(__aarch64__) + auto pc = reinterpret_cast(uct->uc_mcontext.pc); +#else +#error "Missing architecture specific code." +#endif + if (pc < __mlibc_syscall_begin || pc > __mlibc_syscall_end) + return 0; + return 1; +} + +int sys_tgkill(int tgid, int tid, int sig) { + auto ret = do_syscall(SYS_tgkill, tgid, tid, sig); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_tcgetattr(int fd, struct termios *attr) { + auto ret = do_syscall(SYS_ioctl, fd, TCGETS, attr); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_tcsetattr(int fd, int optional_action, const struct termios *attr) { + int req; + + switch (optional_action) { + case TCSANOW: req = TCSETS; break; + case TCSADRAIN: req = TCSETSW; break; + case TCSAFLUSH: req = TCSETSF; break; + default: return EINVAL; + } + + auto ret = do_syscall(SYS_ioctl, fd, req, attr); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_tcflush(int fd, int queue) { + auto ret = do_syscall(SYS_ioctl, fd, TCFLSH, queue); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_tcdrain(int fd) { + auto ret = do_syscall(SYS_ioctl, fd, TCSBRK, 1); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_tcflow(int fd, int action) { + auto ret = do_syscall(SYS_ioctl, fd, TCXONC, action); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_access(const char *path, int mode) { + auto ret = do_syscall(SYS_faccessat, AT_FDCWD, path, mode, 0); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_faccessat(int dirfd, const char *pathname, int mode, int flags) { + auto ret = do_syscall(SYS_faccessat, dirfd, pathname, mode, flags); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_accept(int fd, int *newfd, struct sockaddr *addr_ptr, socklen_t *addr_length, int flags) { + auto ret = do_syscall(SYS_accept4, fd, addr_ptr, addr_length, flags); + if (int e = sc_error(ret); e) + return e; + *newfd = sc_int_result(ret); + return 0; +} + +int sys_bind(int fd, const struct sockaddr *addr_ptr, socklen_t addr_length) { + auto ret = do_syscall(SYS_bind, fd, addr_ptr, addr_length, 0, 0, 0); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_setsockopt(int fd, int layer, int number, const void *buffer, socklen_t size) { + auto ret = do_syscall(SYS_setsockopt, fd, layer, number, buffer, size, 0); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_sockname(int fd, struct sockaddr *addr_ptr, socklen_t max_addr_length, + socklen_t *actual_length) { + auto ret = do_syscall(SYS_getsockname, fd, addr_ptr, &max_addr_length); + if (int e = sc_error(ret); e) + return e; + *actual_length = max_addr_length; + return 0; +} + +int sys_peername(int fd, struct sockaddr *addr_ptr, socklen_t max_addr_length, + socklen_t *actual_length) { + auto ret = do_syscall(SYS_getpeername, fd, addr_ptr, &max_addr_length); + if (int e = sc_error(ret); e) + return e; + *actual_length = max_addr_length; + return 0; +} + +int sys_listen(int fd, int backlog) { + auto ret = do_syscall(SYS_listen, fd, backlog, 0, 0, 0, 0); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_shutdown(int sockfd, int how) { + auto ret = do_syscall(SYS_shutdown, sockfd, how); + if (int e = sc_error(ret); e) { + return e; + } + return 0; +} + +int sys_getpriority(int which, id_t who, int *value) { + auto ret = do_syscall(SYS_getpriority, which, who); + if (int e = sc_error(ret); e) { + return e; + } + *value = 20 - sc_int_result(ret); + return 0; +} + +int sys_setpriority(int which, id_t who, int prio) { + auto ret = do_syscall(SYS_setpriority, which, who, prio); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_setitimer(int which, const struct itimerval *new_value, struct itimerval *old_value) { + auto ret = do_syscall(SYS_setitimer, which, new_value, old_value); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +/* Linux' uapi does some weird union stuff in place of `sigev_tid`, which we conveniently ignore */ +struct linux_uapi_sigevent { + union sigval sigev_value; + int sigev_signo; + int sigev_notify; + int sigev_tid; +}; + +int sys_timer_create(clockid_t clk, struct sigevent *__restrict evp, timer_t *__restrict res) { + struct linux_uapi_sigevent ksev; + struct linux_uapi_sigevent *ksevp = 0; + int timer_id; + + switch(evp ? evp->sigev_notify : SIGEV_SIGNAL) { + case SIGEV_NONE: + case SIGEV_SIGNAL: { + if(evp) { + ksev.sigev_value = evp->sigev_value; + ksev.sigev_signo = evp->sigev_signo; + ksev.sigev_notify = evp->sigev_notify; + ksev.sigev_tid = 0; + ksevp = &ksev; + } + + auto ret = do_syscall(SYS_timer_create, clk, ksevp, &timer_id); + if (int e = sc_error(ret); e) { + return e; + } + *res = (void *) (intptr_t) timer_id; + break; + } + case SIGEV_THREAD: + __ensure(!"sys_timer_create with evp->sigev_notify == SIGEV_THREAD is unimplemented"); + [[fallthrough]]; + default: + return EINVAL; + } + + return 0; +} + +int sys_timer_settime(timer_t t, int flags, const struct itimerspec *__restrict val, struct itimerspec *__restrict old) { + auto ret = do_syscall(SYS_timer_settime, t, flags, val, old); + if (int e = sc_error(ret); e) { + return e; + } + return 0; +} + +int sys_timer_delete(timer_t t) { + __ensure((intptr_t) t >= 0); + auto ret = do_syscall(SYS_timer_delete, t); + if (int e = sc_error(ret); e) { + return e; + } + return 0; +} + +int sys_ptrace(long req, pid_t pid, void *addr, void *data, long *out) { + auto ret = do_syscall(SYS_ptrace, req, pid, addr, data); + if (int e = sc_error(ret); e) + return e; + *out = sc_int_result(ret); + return 0; +} + +int sys_open_dir(const char *path, int *fd) { + return sys_open(path, O_DIRECTORY, 0, fd); +} + +int sys_read_entries(int handle, void *buffer, size_t max_size, size_t *bytes_read) { + auto ret = do_syscall(SYS_getdents64, handle, buffer, max_size); + if(int e = sc_error(ret); e) + return e; + *bytes_read = sc_int_result(ret); + return 0; +} + +int sys_prctl(int op, va_list ap, int *out) { + unsigned long x[4]; + for(int i = 0; i < 4; i++) + x[i] = va_arg(ap, unsigned long); + + auto ret = do_syscall(SYS_prctl, op, x[0], x[1], x[2], x[3]); + if (int e = sc_error(ret); e) + return e; + *out = sc_int_result(ret); + return 0; +} + +int sys_uname(struct utsname *buf) { + auto ret = do_syscall(SYS_uname, buf); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_gethostname(char *buf, size_t bufsize) { + struct utsname uname_buf; + if (auto e = sys_uname(&uname_buf); e) + return e; + + auto node_len = strlen(uname_buf.nodename); + if (node_len >= bufsize) + return ENAMETOOLONG; + + memcpy(buf, uname_buf.nodename, node_len); + buf[node_len] = '\0'; + return 0; +} + +int sys_pread(int fd, void *buf, size_t n, off_t off, ssize_t *bytes_read) { + auto ret = do_syscall(SYS_pread64, fd, buf, n, off); + if (int e = sc_error(ret); e) + return e; + *bytes_read = sc_int_result(ret); + return 0; +} + +int sys_pwrite(int fd, const void *buf, size_t n, off_t off, ssize_t *bytes_written) { + auto ret = do_syscall(SYS_pwrite64, fd, buf, n, off); + if (int e = sc_error(ret); e) + return e; + *bytes_written = sc_int_result(ret); + return 0; +} + +int sys_poll(struct pollfd *fds, nfds_t count, int timeout, int *num_events) { + struct timespec tm; + tm.tv_sec = timeout / 1000; + tm.tv_nsec = timeout % 1000 * 1000000; + auto ret = do_syscall(SYS_ppoll, fds, count, timeout >= 0 ? &tm : nullptr, 0, NSIG / 8); + if (int e = sc_error(ret); e) + return e; + *num_events = sc_int_result(ret); + return 0; +} + +int sys_getrusage(int scope, struct rusage *usage) { + auto ret = do_syscall(SYS_getrusage, scope, usage); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_madvise(void *addr, size_t length, int advice) { + auto ret = do_syscall(SYS_madvise, addr, length, advice); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_msync(void *addr, size_t length, int flags) { + auto ret = do_syscall(SYS_msync, addr, length, flags); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_swapon(const char *path, int flags) { + auto ret = do_syscall(SYS_swapon, path, flags); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_swapoff(const char *path) { + auto ret = do_syscall(SYS_swapoff, path); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_getaffinity(pid_t pid, size_t cpusetsize, cpu_set_t *mask) { + auto ret = do_syscall(SYS_sched_getaffinity, pid, cpusetsize, mask); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_mount(const char *source, const char *target, + const char *fstype, unsigned long flags, const void *data) { + auto ret = do_syscall(SYS_mount, source, target, fstype, flags, data); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_umount2(const char *target, int flags) { + auto ret = do_syscall(SYS_umount2, target, flags); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_sethostname(const char *buffer, size_t bufsize) { + auto ret = do_syscall(SYS_sethostname, buffer, bufsize); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_epoll_create(int flags, int *fd) { + auto ret = do_syscall(SYS_epoll_create1, flags); + if (int e = sc_error(ret); e) + return e; + *fd = sc_int_result(ret); + return 0; +} + +int sys_epoll_ctl(int epfd, int mode, int fd, struct epoll_event *ev) { + auto ret = do_syscall(SYS_epoll_ctl, epfd, mode, fd, ev); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_epoll_pwait(int epfd, struct epoll_event *ev, int n, int timeout, const sigset_t *sigmask, int *raised) { + auto ret = do_syscall(SYS_epoll_pwait, epfd, ev, n, timeout, sigmask, NSIG / 8); + if (int e = sc_error(ret); e) + return e; + *raised = sc_int_result(ret); + return 0; +} + +int sys_eventfd_create(unsigned int initval, int flags, int *fd) { + auto ret = do_syscall(SYS_eventfd2, initval, flags); + if (int e = sc_error(ret); e) + return e; + *fd = sc_int_result(ret); + return 0; +} + +int sys_signalfd_create(const sigset_t *masks, int flags, int *fd) { + auto ret = do_syscall(SYS_signalfd4, *fd, masks, sizeof(sigset_t), flags); + if (int e = sc_error(ret); e) + return e; + *fd = sc_int_result(ret); + return 0; +} + +int sys_timerfd_create(int clockid, int flags, int *fd) { + auto ret = do_syscall(SYS_timerfd_create, clockid, flags); + if (int e = sc_error(ret); e) + return e; + *fd = sc_int_result(ret); + return 0; +} + +int sys_timerfd_settime(int fd, int flags, const struct itimerspec *value, struct itimerspec *oldvalue) { + auto ret = do_syscall(SYS_timerfd_settime, fd, flags, value, oldvalue); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_inotify_create(int flags, int *fd) { + auto ret = do_syscall(SYS_inotify_init1, flags); + if (int e = sc_error(ret); e) + return e; + *fd = sc_int_result(ret); + return 0; +} + +int sys_init_module(void *module, unsigned long length, const char *args) { + auto ret = do_syscall(SYS_init_module, module, length, args); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_delete_module(const char *name, unsigned flags) { + auto ret = do_syscall(SYS_delete_module, name, flags); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_klogctl(int type, char *bufp, int len, int *out) { + auto ret = do_syscall(SYS_syslog, type, bufp, len); + if (int e = sc_error(ret); e) + return e; + *out = sc_int_result(ret); + return 0; +} + +int sys_getcpu(int *cpu) { + auto ret = do_syscall(SYS_getcpu, cpu, NULL, NULL); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_socketpair(int domain, int type_and_flags, int proto, int *fds) { + auto ret = do_syscall(SYS_socketpair, domain, type_and_flags, proto, fds, 0, 0); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_getsockopt(int fd, int layer, int number, void *__restrict buffer, socklen_t *__restrict size) { + auto ret = do_syscall(SYS_getsockopt, fd, layer, number, buffer, size, 0); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_inotify_add_watch(int ifd, const char *path, uint32_t mask, int *wd) { + auto ret = do_syscall(SYS_inotify_add_watch, ifd, path, mask); + if (int e = sc_error(ret); e) + return e; + *wd = sc_int_result(ret); + return 0; +} + +int sys_inotify_rm_watch(int ifd, int wd) { + auto ret = do_syscall(SYS_inotify_rm_watch, ifd, wd); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_ttyname(int fd, char *buf, size_t size) { + if (!isatty(fd)) + return errno; + + char *procname; + if(int e = asprintf(&procname, "/proc/self/fd/%i", fd); e) + return ENOMEM; + __ensure(procname); + + ssize_t l = readlink(procname, buf, size); + free(procname); + + if (l < 0) + return errno; + else if ((size_t)l >= size) + return ERANGE; + + buf[l] = '\0'; + struct stat st1; + struct stat st2; + + if (stat(buf, &st1) || fstat(fd, &st2)) + return errno; + if (st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino) + return ENODEV; + + return 0; +} + +int sys_pause() { +#ifdef SYS_pause + auto ret = do_syscall(SYS_pause); +#else + auto ret = do_syscall(SYS_ppoll, 0, 0, 0, 0); +#endif + if (int e = sc_error(ret); e) + return e; + return EINTR; +} + +int sys_mlockall(int flags) { + auto ret = do_syscall(SYS_mlockall, flags); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_get_min_priority(int policy, int *out) { + auto ret = do_syscall(SYS_sched_get_priority_min, policy); + if (int e = sc_error(ret); e) + return e; + *out = sc_int_result(ret); + + return 0; +} + +int sys_getschedparam(void *tcb, int *policy, struct sched_param *param) { + auto t = reinterpret_cast(tcb); + + if(!t->tid) { + return ESRCH; + } + + auto ret_param = do_syscall(SYS_sched_getparam, t->tid, param); + if (int e = sc_error(ret_param); e) + return e; + + auto ret_sched = do_syscall(SYS_sched_getscheduler, t->tid, param); + if (int e = sc_error(ret_sched); e) + return e; + *policy = sc_int_result(ret_sched); + + return 0; +} + +int sys_setschedparam(void *tcb, int policy, const struct sched_param *param) { + auto t = reinterpret_cast(tcb); + + if(!t->tid) { + return ESRCH; + } + + auto ret = do_syscall(SYS_sched_setscheduler, t->tid, policy, param); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_if_indextoname(unsigned int index, char *name) { + int fd = 0; + int r = sys_socket(AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, AF_UNSPEC, &fd); + + if(r) + return r; + + struct ifreq ifr; + ifr.ifr_ifindex = index; + + int ret = sys_ioctl(fd, SIOCGIFNAME, &ifr, NULL); + close(fd); + + if(ret) { + if(ret == ENODEV) + return ENXIO; + return ret; + } + + strncpy(name, ifr.ifr_name, IF_NAMESIZE); + + return 0; +} + +int sys_if_nametoindex(const char *name, unsigned int *ret) { + int fd = 0; + int r = sys_socket(AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, AF_UNSPEC, &fd); + + if(r) + return r; + + struct ifreq ifr; + strncpy(ifr.ifr_name, name, sizeof ifr.ifr_name); + + r = sys_ioctl(fd, SIOCGIFINDEX, &ifr, NULL); + close(fd); + + if(r) { + return r; + } + + *ret = ifr.ifr_ifindex; + + return 0; +} + +int sys_ptsname(int fd, char *buffer, size_t length) { + int index; + if(int e = sys_ioctl(fd, TIOCGPTN, &index, NULL); e) + return e; + if((size_t)snprintf(buffer, length, "/dev/pts/%d", index) >= length) { + return ERANGE; + } + return 0; +} + +int sys_unlockpt(int fd) { + int unlock = 0; + + if(int e = sys_ioctl(fd, TIOCSPTLCK, &unlock, NULL); e) + return e; + + return 0; +} + +int sys_thread_setname(void *tcb, const char *name) { + if(strlen(name) > 15) { + return ERANGE; + } + + auto t = reinterpret_cast(tcb); + char *path; + int cs = 0; + + if(asprintf(&path, "/proc/self/task/%d/comm", t->tid) < 0) { + return ENOMEM; + } + + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs); + + int fd; + if(int e = sys_open(path, O_WRONLY, 0, &fd); e) { + return e; + } + + if(int e = sys_write(fd, name, strlen(name) + 1, NULL)) { + return e; + } + + sys_close(fd); + + pthread_setcancelstate(cs, 0); + + return 0; +} + +int sys_thread_getname(void *tcb, char *name, size_t size) { + auto t = reinterpret_cast(tcb); + char *path; + int cs = 0; + ssize_t real_size = 0; + + if(asprintf(&path, "/proc/self/task/%d/comm", t->tid) < 0) { + return ENOMEM; + } + + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs); + + int fd; + if(int e = sys_open(path, O_RDONLY | O_CLOEXEC, 0, &fd); e) { + return e; + } + + if(int e = sys_read(fd, name, size, &real_size)) { + return e; + } + + name[real_size - 1] = 0; + sys_close(fd); + + pthread_setcancelstate(cs, 0); + + if(static_cast(size) <= real_size) { + return ERANGE; + } + + return 0; +} + +int sys_mlock(const void *addr, size_t length) { + auto ret = do_syscall(SYS_mlock, addr, length); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_munlock(const void *addr, size_t length) { + auto ret = do_syscall(SYS_munlock, addr, length); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_munlockall(void) { + auto ret = do_syscall(SYS_munlockall); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_mincore(void *addr, size_t length, unsigned char *vec) { + auto ret = do_syscall(SYS_mincore, addr, length, vec); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_memfd_create(const char *name, int flags, int *fd) { + auto ret = do_syscall(SYS_memfd_create, name, flags); + if (int e = sc_error(ret); e) + return e; + *fd = sc_int_result(ret); + return 0; +} + +int sys_fallocate(int fd, off_t offset, size_t size) { + auto ret = do_syscall(SYS_fallocate, fd, 0, offset, size); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_flock(int fd, int options) { + auto ret = do_syscall(SYS_flock, fd, options); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_seteuid(uid_t euid) { + return sys_setresuid(-1, euid, -1); +} + +int sys_vm_remap(void *pointer, size_t size, size_t new_size, void **window) { + auto ret = do_syscall(SYS_mremap, pointer, size, new_size, MREMAP_MAYMOVE); + // TODO: musl fixes up EPERM errors from the kernel. + if(int e = sc_error(ret); e) + return e; + *window = sc_ptr_result(ret); + return 0; +} + +int sys_link(const char *old_path, const char *new_path) { +#ifdef SYS_link + auto ret = do_syscall(SYS_link, old_path, new_path); + if (int e = sc_error(ret); e) + return e; + return 0; +#else + auto ret = do_syscall(SYS_linkat, AT_FDCWD, old_path, AT_FDCWD, new_path, 0); + if (int e = sc_error(ret); e) + return e; + return 0; +#endif +} + +// Inspired by musl (src/stat/statvfs.c:28 fixup function) +static void statfs_to_statvfs(struct statfs *from, struct statvfs *to) { + *to = { + .f_bsize = from->f_bsize, + .f_frsize = from->f_frsize ? from->f_frsize : from->f_bsize, + .f_blocks = from->f_blocks, + .f_bfree = from->f_bfree, + .f_bavail = from->f_bavail, + .f_files = from->f_files, + .f_ffree = from->f_ffree, + .f_favail = from->f_ffree, + .f_fsid = (unsigned long) from->f_fsid.__val[0], + .f_flag = from->f_flags, + .f_namemax = from->f_namelen, + }; +} + +int sys_statvfs(const char *path, struct statvfs *out) { + struct statfs buf; + if(auto ret = sys_statfs(path, &buf); ret != 0) { + return ret; + } + statfs_to_statvfs(&buf, out); + return 0; +} + +int sys_fstatvfs(int fd, struct statvfs *out) { + struct statfs buf; + if(auto ret = sys_fstatfs(fd, &buf); ret != 0) { + return ret; + } + statfs_to_statvfs(&buf, out); + return 0; +} + +int sys_sysconf(int num, long *ret) { + switch(num) { + case _SC_OPEN_MAX: { + struct rlimit ru; + if(int e = sys_getrlimit(RLIMIT_NOFILE, &ru); e) { + return e; + } + *ret = (ru.rlim_cur == RLIM_INFINITY) ? -1 : ru.rlim_cur; + break; + } + case _SC_NPROCESSORS_ONLN: { + cpu_set_t set; + CPU_ZERO(&set); + if(int e = sys_getaffinity(0, sizeof(set), &set); e) { + return e; + } + *ret = CPU_COUNT(&set); + break; + } + case _SC_PHYS_PAGES: { + struct sysinfo info; + if(int e = sys_sysinfo(&info); e) { + return e; + } + unsigned unit = (info.mem_unit) ? info.mem_unit : 1; + *ret = std::min(long((info.totalram * unit) / PAGE_SIZE), LONG_MAX); + break; + } + case _SC_CHILD_MAX: { + struct rlimit ru; + if(int e = sys_getrlimit(RLIMIT_NPROC, &ru); e) { + return e; + } + *ret = (ru.rlim_cur == RLIM_INFINITY) ? -1 : ru.rlim_cur; + break; + } + case _SC_LINE_MAX: { + *ret = -1; + break; + } + default: { + return EINVAL; + } + } + + return 0; +} + +int sys_semget(key_t key, int n, int fl, int *id) { + auto ret = do_syscall(SYS_semget, key, n, fl); + if(int e = sc_error(ret); e) + return e; + *id = sc_int_result(ret); + return 0; +} + +int sys_semctl(int semid, int semnum, int cmd, void *semun, int *out) { + auto ret = do_syscall(SYS_semctl, semid, semnum, cmd | IPC_64, semun); + if(int e = sc_error(ret); e) + return e; + *out = sc_int_result(ret); + return 0; +} + +int sys_waitid(idtype_t idtype, id_t id, siginfo_t *info, int options) { + auto ret = do_syscall(SYS_waitid, idtype, id, info, options, 0); + if(int e = sc_error(ret); e) + return e; + return sc_int_result(ret); +} + +#endif // __MLIBC_POSIX_OPTION + +#if __MLIBC_LINUX_OPTION + +#include + +int sys_reboot(int cmd) { + auto ret = do_syscall(SYS_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, cmd, nullptr); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +#endif // __MLIBC_LINUX_OPTION + +int sys_times(struct tms *tms, clock_t *out) { + auto ret = do_syscall(SYS_times, tms); + if (int e = sc_error(ret); e) + return e; + *out = sc_int_result(ret); + return 0; +} + +pid_t sys_getpid() { + auto ret = do_syscall(SYS_getpid); + // getpid() always succeeds. + return sc_int_result(ret); +} + +pid_t sys_gettid() { + auto ret = do_syscall(SYS_gettid); + // gettid() always succeeds. + return sc_int_result(ret); +} + +uid_t sys_getuid() { + auto ret = do_syscall(SYS_getuid); + // getuid() always succeeds. + return sc_int_result(ret); +} + +uid_t sys_geteuid() { + auto ret = do_syscall(SYS_geteuid); + // geteuid() always succeeds. + return sc_int_result(ret); +} + +gid_t sys_getgid() { + auto ret = do_syscall(SYS_getgid); + // getgid() always succeeds. + return sc_int_result(ret); +} + +gid_t sys_getegid() { + auto ret = do_syscall(SYS_getegid); + // getegid() always succeeds. + return sc_int_result(ret); +} + +int sys_kill(int pid, int sig) { + auto ret = do_syscall(SYS_kill, pid, sig); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_vm_protect(void *pointer, size_t size, int prot) { + auto ret = do_syscall(SYS_mprotect, pointer, size, prot); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +void sys_thread_exit() { + do_syscall(SYS_exit, 0); + __builtin_trap(); +} + +void sys_exit(int status) { + do_syscall(SYS_exit_group, status); + __builtin_trap(); +} + +#endif // MLIBC_BUILDING_RTDL + +#define FUTEX_WAIT 0 +#define FUTEX_WAKE 1 + +int sys_futex_tid() { + auto ret = do_syscall(SYS_gettid); + // gettid() always succeeds. + return sc_int_result(ret); +} + +int sys_futex_wait(int *pointer, int expected, const struct timespec *time) { + auto ret = do_cp_syscall(SYS_futex, pointer, FUTEX_WAIT, expected, time); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_futex_wake(int *pointer) { + auto ret = do_syscall(SYS_futex, pointer, FUTEX_WAKE, INT_MAX); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_sigsuspend(const sigset_t *set) { + auto ret = do_syscall(SYS_rt_sigsuspend, set, NSIG / 8); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_sigaltstack(const stack_t *ss, stack_t *oss) { + auto ret = do_syscall(SYS_sigaltstack, ss, oss); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_mkdir(const char *path, mode_t mode) { + auto ret = do_syscall(SYS_mkdirat, AT_FDCWD, path, mode); + if (int e = sc_error(ret); e) + return e; + return 0; +} + + +int sys_mkdirat(int dirfd, const char *path, mode_t mode) { + auto ret = do_syscall(SYS_mkdirat, dirfd, path, mode); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_mknodat(int dirfd, const char *path, int mode, int dev) { + auto ret = do_syscall(SYS_mknodat, dirfd, path, mode, dev); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_mkfifoat(int dirfd, const char *path, int mode) { + return sys_mknodat(dirfd, path, mode | S_IFIFO, 0); +} + +int sys_symlink(const char *target_path, const char *link_path) { + auto ret = do_syscall(SYS_symlinkat, target_path, AT_FDCWD, link_path); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_symlinkat(const char *target_path, int dirfd, const char *link_path) { + auto ret = do_syscall(SYS_symlinkat, target_path, dirfd, link_path); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_umask(mode_t mode, mode_t *old) { + auto ret = do_syscall(SYS_umask, mode); + if (int e = sc_error(ret); e) + return e; + *old = sc_int_result(ret); + return 0; +} + +int sys_chdir(const char *path) { + auto ret = do_syscall(SYS_chdir, path); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_fchdir(int fd) { + auto ret = do_syscall(SYS_fchdir, fd); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_rename(const char *old_path, const char *new_path) { + return sys_renameat(AT_FDCWD, old_path, AT_FDCWD, new_path); +} + +int sys_renameat(int old_dirfd, const char *old_path, int new_dirfd, const char *new_path) { +#ifdef SYS_renameat2 + auto ret = do_syscall(SYS_renameat2, old_dirfd, old_path, new_dirfd, new_path, 0); +#else + auto ret = do_syscall(SYS_renameat, old_dirfd, old_path, new_dirfd, new_path); +#endif /* defined(SYS_renameat2) */ + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_rmdir(const char *path) { + auto ret = do_syscall(SYS_unlinkat, AT_FDCWD, path, AT_REMOVEDIR); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_ftruncate(int fd, size_t size) { + auto ret = do_syscall(SYS_ftruncate, fd, size); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_readlink(const char *path, void *buf, size_t bufsiz, ssize_t *len) { + auto ret = do_syscall(SYS_readlinkat, AT_FDCWD, path, buf, bufsiz); + if (int e = sc_error(ret); e) + return e; + *len = sc_int_result(ret); + return 0; +} + +int sys_getrlimit(int resource, struct rlimit *limit) { + auto ret = do_syscall(SYS_getrlimit, resource, limit); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_setrlimit(int resource, const struct rlimit *limit) { + auto ret = do_syscall(SYS_setrlimit, resource, limit); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +pid_t sys_getppid() { + auto ret = do_syscall(SYS_getppid); + // getppid() always succeeds. + return sc_int_result(ret); +} + +int sys_setpgid(pid_t pid, pid_t pgid) { + auto ret = do_syscall(SYS_setpgid, pid, pgid); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_getsid(pid_t pid, pid_t *sid) { + auto ret = do_syscall(SYS_getsid, pid); + if (int e = sc_error(ret); e) + return e; + *sid = sc_int_result(ret); + return 0; +} + +int sys_setsid(pid_t *sid) { + auto ret = do_syscall(SYS_setsid); + if (int e = sc_error(ret); e) + return e; + *sid = sc_int_result(ret); + return 0; +} + +int sys_setuid(uid_t uid) { + auto ret = do_syscall(SYS_setuid, uid); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_setgid(gid_t gid) { + auto ret = do_syscall(SYS_setgid, gid); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_getpgid(pid_t pid, pid_t *out) { + auto ret = do_syscall(SYS_getpgid, pid); + if (int e = sc_error(ret); e) + return e; + *out = sc_int_result(ret); + return 0; +} + +int sys_getgroups(size_t size, const gid_t *list, int *retval) { + auto ret = do_syscall(SYS_getgroups, size, list); + if (int e = sc_error(ret); e) + return e; + *retval = sc_int_result(ret); + return 0; +} + +int sys_dup(int fd, int flags, int *newfd) { + __ensure(!flags); + auto ret = do_cp_syscall(SYS_dup, fd); + if (int e = sc_error(ret); e) + return e; + *newfd = sc_int_result(ret); + return 0; +} + +void sys_sync() { + do_syscall(SYS_sync); +} + +int sys_fsync(int fd) { + auto ret = do_syscall(SYS_fsync, fd); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_fdatasync(int fd) { + auto ret = do_syscall(SYS_fdatasync, fd); + if (int e = sc_error(ret); e) + return e; + return 0; +} + +int sys_getrandom(void *buffer, size_t length, int flags, ssize_t *bytes_written) { + auto ret = do_syscall(SYS_getrandom, buffer, length, flags); + if (int e = sc_error(ret); e) + return e; + *bytes_written = sc_int_result(ret); + return 0; +} + +int sys_getentropy(void *buffer, size_t length) { + ssize_t written; + return sys_getrandom(buffer, length, 0, &written); +} + +int sys_setxattr(const char *path, const char *name, const void *val, + size_t size, int flags) { + auto ret = do_syscall(SYS_setxattr, path, name, val, size, flags); + return sc_error(ret); +} + +int sys_lsetxattr(const char *path, const char *name, const void *val, + size_t size, int flags) { + auto ret = do_syscall(SYS_lsetxattr, path, name, val, size, flags); + return sc_error(ret); +} + +int sys_fsetxattr(int fd, const char *name, const void *val, + size_t size, int flags) { + auto ret = do_syscall(SYS_fsetxattr, fd, name, val, size, flags); + return sc_error(ret); +} + +int sys_getxattr(const char *path, const char *name, void *val, size_t size, + ssize_t *nread) { + auto ret = do_syscall(SYS_getxattr, path, name, val, size); + if (int e = sc_error(ret); e) { + return e; + } + + *nread = sc_int_result(ret); + return 0; +} + +int sys_lgetxattr(const char *path, const char *name, void *val, size_t size, + ssize_t *nread) { + auto ret = do_syscall(SYS_lgetxattr, path, name, val, size); + if (int e = sc_error(ret); e) { + return e; + } + + *nread = sc_int_result(ret); + return 0; +} + +int sys_fgetxattr(int fd, const char *name, void *val, size_t size, + ssize_t *nread) { + auto ret = do_syscall(SYS_fgetxattr, fd, name, val, size); + if (int e = sc_error(ret); e) { + return e; + } + + *nread = sc_int_result(ret); + return 0; +} + +int sys_removexattr(const char *path, const char *name) { + auto ret = do_syscall(SYS_removexattr, path, name); + return sc_error(ret); +} + +int sys_lremovexattr(const char *path, const char *name) { + auto ret = do_syscall(SYS_lremovexattr, path, name); + return sc_error(ret); +} + +int sys_fremovexattr(int fd, const char *name) { + auto ret = do_syscall(SYS_fremovexattr, fd, name); + return sc_error(ret); +} + +int sys_listxattr(const char *path, char *list, size_t size, ssize_t *nread) { + auto ret = do_syscall(SYS_listxattr, path, list, size); + if (int e = sc_error(ret); e) { + return e; + } + + *nread = sc_int_result(ret); + return 0; +} + +int sys_llistxattr(const char *path, char *list, size_t size, ssize_t *nread) { + auto ret = do_syscall(SYS_llistxattr, path, list, size); + if (int e = sc_error(ret); e) { + return e; + } + + *nread = sc_int_result(ret); + return 0; +} + +int sys_flistxattr(int fd, char *list, size_t size, ssize_t *nread) { + auto ret = do_syscall(SYS_flistxattr, fd, list, size); + if (int e = sc_error(ret); e) { + return e; + } + + *nread = sc_int_result(ret); + return 0; +} + +int sys_sigtimedwait(const sigset_t *__restrict set, siginfo_t *__restrict info, const struct timespec *__restrict timeout, int *out_signal) { + auto ret = do_syscall(SYS_rt_sigtimedwait, set, info, timeout, NSIG / 8); + + if (int e = sc_error(ret); e) + return e; + + *out_signal = sc_int_result(ret); + + return 0; +} + +#if __MLIBC_BSD_OPTION +int sys_brk(void **out) { + auto ret = do_syscall(SYS_brk, 0); + if(int e = sc_error(ret); e) { + return e; + } + + *out = (void *) sc_int_result(ret); + return 0; +} +#endif // __MLIBC_BSD_OPTION + +#if __MLIBC_GLIBC_OPTION + +int sys_personality(unsigned long persona, int *out) { + auto ret = do_syscall(SYS_personality, persona); + + if(int e = sc_error(ret); e) { + return e; + } + + *out = sc_int_result(ret); + return 0; +} + +int sys_ioperm(unsigned long int from, unsigned long int num, int turn_on) { +#if defined(SYS_ioperm) + auto ret = do_syscall(SYS_ioperm, from, num, turn_on); + + if(int e = sc_error(ret); e) { + return e; + } + + return 0; +#else + (void) from; + (void) num; + (void) turn_on; + return ENOSYS; +#endif +} + +int sys_iopl(int level) { +#if defined(SYS_iopl) + auto ret = do_syscall(SYS_iopl, level); + + if(int e = sc_error(ret); e) { + return e; + } + + return 0; +#else + (void) level; + return ENOSYS; +#endif +} + +#endif // __MLIBC_GLIBC_OPTION + +} // namespace mlibc diff --git a/lib/mlibc/sysdeps/linux/generic/thread.cpp b/lib/mlibc/sysdeps/linux/generic/thread.cpp new file mode 100644 index 0000000..e413e4f --- /dev/null +++ b/lib/mlibc/sysdeps/linux/generic/thread.cpp @@ -0,0 +1,60 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +extern "C" void __mlibc_enter_thread(void *entry, void *user_arg) { + // The linux kernel already sets the TCB in sys_clone(). + auto tcb = mlibc::get_current_tcb(); + + // Wait until our parent sets up the TID. + while(!__atomic_load_n(&tcb->tid, __ATOMIC_RELAXED)) + mlibc::sys_futex_wait(&tcb->tid, 0, nullptr); + + tcb->invokeThreadFunc(entry, user_arg); + + __atomic_store_n(&tcb->didExit, 1, __ATOMIC_RELEASE); + mlibc::sys_futex_wake(&tcb->didExit); + + mlibc::sys_thread_exit(); +} + +namespace mlibc { + +static constexpr size_t default_stacksize = 0x200000; + +int sys_prepare_stack(void **stack, void *entry, void *user_arg, void *tcb, size_t *stack_size, size_t *guard_size, void **stack_base) { + (void)tcb; + if (!*stack_size) + *stack_size = default_stacksize; + + uintptr_t map; + if (*stack) { + map = reinterpret_cast(*stack); + *guard_size = 0; + } else { + map = reinterpret_cast( + mmap(nullptr, *stack_size + *guard_size, + PROT_NONE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0) + ); + if (reinterpret_cast(map) == MAP_FAILED) + return EAGAIN; + int ret = mprotect(reinterpret_cast(map + *guard_size), *stack_size, + PROT_READ | PROT_WRITE); + if(ret) + return EAGAIN; + } + + *stack_base = reinterpret_cast(map); + auto sp = reinterpret_cast(map + *guard_size + *stack_size); + *--sp = reinterpret_cast(user_arg); + *--sp = reinterpret_cast(entry); + *stack = reinterpret_cast(sp); + return 0; +} +} // namespace mlibc diff --git a/lib/mlibc/sysdeps/linux/include-internal/linux/unistd.h b/lib/mlibc/sysdeps/linux/include-internal/linux/unistd.h new file mode 100644 index 0000000..6a8020e --- /dev/null +++ b/lib/mlibc/sysdeps/linux/include-internal/linux/unistd.h @@ -0,0 +1,2 @@ +/* stub header not present in practice, redirects to our internal syscallnos */ +#include diff --git a/lib/mlibc/sysdeps/linux/include/abi-bits/access.h b/lib/mlibc/sysdeps/linux/include/abi-bits/access.h new file mode 120000 index 0000000..cb83931 --- /dev/null +++ b/lib/mlibc/sysdeps/linux/include/abi-bits/access.h @@ -0,0 +1 @@ +../../../../abis/linux/access.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/linux/include/abi-bits/auxv.h b/lib/mlibc/sysdeps/linux/include/abi-bits/auxv.h new file mode 120000 index 0000000..c43f878 --- /dev/null +++ b/lib/mlibc/sysdeps/linux/include/abi-bits/auxv.h @@ -0,0 +1 @@ +../../../../abis/linux/auxv.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/linux/include/abi-bits/blkcnt_t.h b/lib/mlibc/sysdeps/linux/include/abi-bits/blkcnt_t.h new file mode 120000 index 0000000..0b0ec27 --- /dev/null +++ b/lib/mlibc/sysdeps/linux/include/abi-bits/blkcnt_t.h @@ -0,0 +1 @@ +../../../../abis/linux/blkcnt_t.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/linux/include/abi-bits/blksize_t.h b/lib/mlibc/sysdeps/linux/include/abi-bits/blksize_t.h new file mode 120000 index 0000000..7dc8d7c --- /dev/null +++ b/lib/mlibc/sysdeps/linux/include/abi-bits/blksize_t.h @@ -0,0 +1 @@ +../../../../abis/linux/blksize_t.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/linux/include/abi-bits/clockid_t.h b/lib/mlibc/sysdeps/linux/include/abi-bits/clockid_t.h new file mode 120000 index 0000000..6a42da5 --- /dev/null +++ b/lib/mlibc/sysdeps/linux/include/abi-bits/clockid_t.h @@ -0,0 +1 @@ +../../../../abis/linux/clockid_t.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/linux/include/abi-bits/dev_t.h b/lib/mlibc/sysdeps/linux/include/abi-bits/dev_t.h new file mode 120000 index 0000000..bca881e --- /dev/null +++ b/lib/mlibc/sysdeps/linux/include/abi-bits/dev_t.h @@ -0,0 +1 @@ +../../../../abis/linux/dev_t.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/linux/include/abi-bits/epoll.h b/lib/mlibc/sysdeps/linux/include/abi-bits/epoll.h new file mode 120000 index 0000000..eb4b76d --- /dev/null +++ b/lib/mlibc/sysdeps/linux/include/abi-bits/epoll.h @@ -0,0 +1 @@ +../../../../abis/linux/epoll.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/linux/include/abi-bits/errno.h b/lib/mlibc/sysdeps/linux/include/abi-bits/errno.h new file mode 120000 index 0000000..6e507de --- /dev/null +++ b/lib/mlibc/sysdeps/linux/include/abi-bits/errno.h @@ -0,0 +1 @@ +../../../../abis/linux/errno.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/linux/include/abi-bits/fcntl.h b/lib/mlibc/sysdeps/linux/include/abi-bits/fcntl.h new file mode 120000 index 0000000..463e2c9 --- /dev/null +++ b/lib/mlibc/sysdeps/linux/include/abi-bits/fcntl.h @@ -0,0 +1 @@ +../../../../abis/linux/fcntl.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/linux/include/abi-bits/fsblkcnt_t.h b/lib/mlibc/sysdeps/linux/include/abi-bits/fsblkcnt_t.h new file mode 120000 index 0000000..898dfb2 --- /dev/null +++ b/lib/mlibc/sysdeps/linux/include/abi-bits/fsblkcnt_t.h @@ -0,0 +1 @@ +../../../../abis/linux/fsblkcnt_t.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/linux/include/abi-bits/fsfilcnt_t.h b/lib/mlibc/sysdeps/linux/include/abi-bits/fsfilcnt_t.h new file mode 120000 index 0000000..791755c --- /dev/null +++ b/lib/mlibc/sysdeps/linux/include/abi-bits/fsfilcnt_t.h @@ -0,0 +1 @@ +../../../../abis/linux/fsfilcnt_t.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/linux/include/abi-bits/gid_t.h b/lib/mlibc/sysdeps/linux/include/abi-bits/gid_t.h new file mode 120000 index 0000000..abce6d6 --- /dev/null +++ b/lib/mlibc/sysdeps/linux/include/abi-bits/gid_t.h @@ -0,0 +1 @@ +../../../../abis/linux/gid_t.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/linux/include/abi-bits/in.h b/lib/mlibc/sysdeps/linux/include/abi-bits/in.h new file mode 120000 index 0000000..418d1d5 --- /dev/null +++ b/lib/mlibc/sysdeps/linux/include/abi-bits/in.h @@ -0,0 +1 @@ +../../../../abis/linux/in.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/linux/include/abi-bits/ino_t.h b/lib/mlibc/sysdeps/linux/include/abi-bits/ino_t.h new file mode 120000 index 0000000..4c20aca --- /dev/null +++ b/lib/mlibc/sysdeps/linux/include/abi-bits/ino_t.h @@ -0,0 +1 @@ +../../../../abis/linux/ino_t.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/linux/include/abi-bits/inotify.h b/lib/mlibc/sysdeps/linux/include/abi-bits/inotify.h new file mode 120000 index 0000000..b5cb282 --- /dev/null +++ b/lib/mlibc/sysdeps/linux/include/abi-bits/inotify.h @@ -0,0 +1 @@ +../../../../abis/linux/inotify.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/linux/include/abi-bits/ioctls.h b/lib/mlibc/sysdeps/linux/include/abi-bits/ioctls.h new file mode 120000 index 0000000..595106b --- /dev/null +++ b/lib/mlibc/sysdeps/linux/include/abi-bits/ioctls.h @@ -0,0 +1 @@ +../../../../abis/linux/ioctls.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/linux/include/abi-bits/limits.h b/lib/mlibc/sysdeps/linux/include/abi-bits/limits.h new file mode 120000 index 0000000..6c88db2 --- /dev/null +++ b/lib/mlibc/sysdeps/linux/include/abi-bits/limits.h @@ -0,0 +1 @@ +../../../../abis/linux/limits.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/linux/include/abi-bits/mode_t.h b/lib/mlibc/sysdeps/linux/include/abi-bits/mode_t.h new file mode 120000 index 0000000..5d78fdf --- /dev/null +++ b/lib/mlibc/sysdeps/linux/include/abi-bits/mode_t.h @@ -0,0 +1 @@ +../../../../abis/linux/mode_t.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/linux/include/abi-bits/mqueue.h b/lib/mlibc/sysdeps/linux/include/abi-bits/mqueue.h new file mode 120000 index 0000000..fa87b07 --- /dev/null +++ b/lib/mlibc/sysdeps/linux/include/abi-bits/mqueue.h @@ -0,0 +1 @@ +../../../../abis/linux/mqueue.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/linux/include/abi-bits/msg.h b/lib/mlibc/sysdeps/linux/include/abi-bits/msg.h new file mode 120000 index 0000000..f402b49 --- /dev/null +++ b/lib/mlibc/sysdeps/linux/include/abi-bits/msg.h @@ -0,0 +1 @@ +../../../../abis/linux/msg.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/linux/include/abi-bits/nlink_t.h b/lib/mlibc/sysdeps/linux/include/abi-bits/nlink_t.h new file mode 120000 index 0000000..bb3b625 --- /dev/null +++ b/lib/mlibc/sysdeps/linux/include/abi-bits/nlink_t.h @@ -0,0 +1 @@ +../../../../abis/linux/nlink_t.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/linux/include/abi-bits/packet.h b/lib/mlibc/sysdeps/linux/include/abi-bits/packet.h new file mode 120000 index 0000000..998ef1a --- /dev/null +++ b/lib/mlibc/sysdeps/linux/include/abi-bits/packet.h @@ -0,0 +1 @@ +../../../../abis/linux/packet.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/linux/include/abi-bits/pid_t.h b/lib/mlibc/sysdeps/linux/include/abi-bits/pid_t.h new file mode 120000 index 0000000..baa90f6 --- /dev/null +++ b/lib/mlibc/sysdeps/linux/include/abi-bits/pid_t.h @@ -0,0 +1 @@ +../../../../abis/linux/pid_t.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/linux/include/abi-bits/poll.h b/lib/mlibc/sysdeps/linux/include/abi-bits/poll.h new file mode 120000 index 0000000..8ea6a0a --- /dev/null +++ b/lib/mlibc/sysdeps/linux/include/abi-bits/poll.h @@ -0,0 +1 @@ +../../../../abis/linux/poll.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/linux/include/abi-bits/ptrace.h b/lib/mlibc/sysdeps/linux/include/abi-bits/ptrace.h new file mode 120000 index 0000000..b2517b2 --- /dev/null +++ b/lib/mlibc/sysdeps/linux/include/abi-bits/ptrace.h @@ -0,0 +1 @@ +../../../../abis/linux/ptrace.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/linux/include/abi-bits/reboot.h b/lib/mlibc/sysdeps/linux/include/abi-bits/reboot.h new file mode 120000 index 0000000..77013a4 --- /dev/null +++ b/lib/mlibc/sysdeps/linux/include/abi-bits/reboot.h @@ -0,0 +1 @@ +../../../../abis/linux/reboot.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/linux/include/abi-bits/resource.h b/lib/mlibc/sysdeps/linux/include/abi-bits/resource.h new file mode 120000 index 0000000..88d7402 --- /dev/null +++ b/lib/mlibc/sysdeps/linux/include/abi-bits/resource.h @@ -0,0 +1 @@ +../../../../abis/linux/resource.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/linux/include/abi-bits/seek-whence.h b/lib/mlibc/sysdeps/linux/include/abi-bits/seek-whence.h new file mode 120000 index 0000000..df7bccf --- /dev/null +++ b/lib/mlibc/sysdeps/linux/include/abi-bits/seek-whence.h @@ -0,0 +1 @@ +../../../../abis/linux/seek-whence.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/linux/include/abi-bits/shm.h b/lib/mlibc/sysdeps/linux/include/abi-bits/shm.h new file mode 120000 index 0000000..067d8c4 --- /dev/null +++ b/lib/mlibc/sysdeps/linux/include/abi-bits/shm.h @@ -0,0 +1 @@ +../../../../abis/linux/shm.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/linux/include/abi-bits/signal.h b/lib/mlibc/sysdeps/linux/include/abi-bits/signal.h new file mode 120000 index 0000000..4dcb0b7 --- /dev/null +++ b/lib/mlibc/sysdeps/linux/include/abi-bits/signal.h @@ -0,0 +1 @@ +../../../../abis/linux/signal.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/linux/include/abi-bits/socket.h b/lib/mlibc/sysdeps/linux/include/abi-bits/socket.h new file mode 120000 index 0000000..f1dc016 --- /dev/null +++ b/lib/mlibc/sysdeps/linux/include/abi-bits/socket.h @@ -0,0 +1 @@ +../../../../abis/linux/socket.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/linux/include/abi-bits/socklen_t.h b/lib/mlibc/sysdeps/linux/include/abi-bits/socklen_t.h new file mode 120000 index 0000000..41f3b11 --- /dev/null +++ b/lib/mlibc/sysdeps/linux/include/abi-bits/socklen_t.h @@ -0,0 +1 @@ +../../../../abis/linux/socklen_t.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/linux/include/abi-bits/stat.h b/lib/mlibc/sysdeps/linux/include/abi-bits/stat.h new file mode 120000 index 0000000..1f63b41 --- /dev/null +++ b/lib/mlibc/sysdeps/linux/include/abi-bits/stat.h @@ -0,0 +1 @@ +../../../../abis/linux/stat.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/linux/include/abi-bits/statfs.h b/lib/mlibc/sysdeps/linux/include/abi-bits/statfs.h new file mode 120000 index 0000000..e3d202f --- /dev/null +++ b/lib/mlibc/sysdeps/linux/include/abi-bits/statfs.h @@ -0,0 +1 @@ +../../../../abis/linux/statfs.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/linux/include/abi-bits/statvfs.h b/lib/mlibc/sysdeps/linux/include/abi-bits/statvfs.h new file mode 120000 index 0000000..1fc80c2 --- /dev/null +++ b/lib/mlibc/sysdeps/linux/include/abi-bits/statvfs.h @@ -0,0 +1 @@ +../../../../abis/linux/statvfs.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/linux/include/abi-bits/suseconds_t.h b/lib/mlibc/sysdeps/linux/include/abi-bits/suseconds_t.h new file mode 120000 index 0000000..9ed6597 --- /dev/null +++ b/lib/mlibc/sysdeps/linux/include/abi-bits/suseconds_t.h @@ -0,0 +1 @@ +../../../../abis/linux/suseconds_t.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/linux/include/abi-bits/termios.h b/lib/mlibc/sysdeps/linux/include/abi-bits/termios.h new file mode 120000 index 0000000..ee8f0b0 --- /dev/null +++ b/lib/mlibc/sysdeps/linux/include/abi-bits/termios.h @@ -0,0 +1 @@ +../../../../abis/linux/termios.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/linux/include/abi-bits/time.h b/lib/mlibc/sysdeps/linux/include/abi-bits/time.h new file mode 120000 index 0000000..2a02625 --- /dev/null +++ b/lib/mlibc/sysdeps/linux/include/abi-bits/time.h @@ -0,0 +1 @@ +../../../../abis/linux/time.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/linux/include/abi-bits/uid_t.h b/lib/mlibc/sysdeps/linux/include/abi-bits/uid_t.h new file mode 120000 index 0000000..b306777 --- /dev/null +++ b/lib/mlibc/sysdeps/linux/include/abi-bits/uid_t.h @@ -0,0 +1 @@ +../../../../abis/linux/uid_t.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/linux/include/abi-bits/utsname.h b/lib/mlibc/sysdeps/linux/include/abi-bits/utsname.h new file mode 120000 index 0000000..b285754 --- /dev/null +++ b/lib/mlibc/sysdeps/linux/include/abi-bits/utsname.h @@ -0,0 +1 @@ +../../../../abis/linux/utsname.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/linux/include/abi-bits/vm-flags.h b/lib/mlibc/sysdeps/linux/include/abi-bits/vm-flags.h new file mode 120000 index 0000000..bbe258c --- /dev/null +++ b/lib/mlibc/sysdeps/linux/include/abi-bits/vm-flags.h @@ -0,0 +1 @@ +../../../../abis/linux/vm-flags.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/linux/include/abi-bits/vt.h b/lib/mlibc/sysdeps/linux/include/abi-bits/vt.h new file mode 120000 index 0000000..5798a4a --- /dev/null +++ b/lib/mlibc/sysdeps/linux/include/abi-bits/vt.h @@ -0,0 +1 @@ +../../../../abis/linux/vt.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/linux/include/abi-bits/wait.h b/lib/mlibc/sysdeps/linux/include/abi-bits/wait.h new file mode 120000 index 0000000..feb2840 --- /dev/null +++ b/lib/mlibc/sysdeps/linux/include/abi-bits/wait.h @@ -0,0 +1 @@ +../../../../abis/linux/wait.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/linux/include/abi-bits/xattr.h b/lib/mlibc/sysdeps/linux/include/abi-bits/xattr.h new file mode 120000 index 0000000..66412d7 --- /dev/null +++ b/lib/mlibc/sysdeps/linux/include/abi-bits/xattr.h @@ -0,0 +1 @@ +../../../../abis/linux/xattr.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/linux/include/bits/syscall.h b/lib/mlibc/sysdeps/linux/include/bits/syscall.h new file mode 100644 index 0000000..3023a3b --- /dev/null +++ b/lib/mlibc/sysdeps/linux/include/bits/syscall.h @@ -0,0 +1,90 @@ +#ifndef _MLIBC_SYSCALL_H +#define _MLIBC_SYSCALL_H + +#ifdef __cplusplus +extern "C" { +#endif + +typedef long __sc_word_t; + +/* These functions are implemented in arch-syscall.cpp. */ +__sc_word_t __do_syscall0(long); +__sc_word_t __do_syscall1(long, __sc_word_t); +__sc_word_t __do_syscall2(long, __sc_word_t, __sc_word_t); +__sc_word_t __do_syscall3(long, __sc_word_t, __sc_word_t, __sc_word_t); +__sc_word_t __do_syscall4(long, __sc_word_t, __sc_word_t, __sc_word_t, __sc_word_t); +__sc_word_t __do_syscall5(long, __sc_word_t, __sc_word_t, __sc_word_t, __sc_word_t, + __sc_word_t); +__sc_word_t __do_syscall6(long, __sc_word_t, __sc_word_t, __sc_word_t, __sc_word_t, + __sc_word_t, __sc_word_t); +__sc_word_t __do_syscall7(long, __sc_word_t, __sc_word_t, __sc_word_t, __sc_word_t, + __sc_word_t, __sc_word_t, __sc_word_t); +long __do_syscall_ret(unsigned long); + +#ifdef __cplusplus +extern "C++" { + +/* Defining a syscall as a macro is more problematic in C++, since there's a high chance of + * a name collision e.g foo.syscall() or foo::syscall. + */ +template +long syscall(long n) { + return __do_syscall_ret(__do_syscall0(n)); +} +template +long syscall(long n, Arg0 a0) { + return __do_syscall_ret(__do_syscall1(n, (long)a0)); +} +template +long syscall(long n, Arg0 a0, Arg1 a1) { + return __do_syscall_ret(__do_syscall2(n, (long)a0, (long)a1)); +} +template +long syscall(long n, Arg0 a0, Arg1 a1, Arg2 a2) { + return __do_syscall_ret(__do_syscall3(n, (long)a0, (long)a1, (long)a2)); +} +template +long syscall(long n, Arg0 a0, Arg1 a1, Arg2 a2, Arg3 a3) { + return __do_syscall_ret(__do_syscall4(n, (long)a0, (long)a1, (long)a2, (long)a3)); +} +template +long syscall(long n, Arg0 a0, Arg1 a1, Arg2 a2, Arg3 a3, Arg4 a4) { + return __do_syscall_ret(__do_syscall5(n, (long)a0, (long)a1, (long)a2, (long)a3, (long)a4)); +} +template +long syscall(long n, Arg0 a0, Arg1 a1, Arg2 a2, Arg3 a3, Arg4 a4, Arg5 a5) { + return __do_syscall_ret(__do_syscall6(n, (long)a0, (long)a1, (long)a2, (long)a3, (long)a4, (long)a5)); +} +template +long syscall(long n, Arg0 a0, Arg1 a1, Arg2 a2, Arg3 a3, Arg4 a4, Arg5 a5, Arg6 a6) { + return __do_syscall_ret(__do_syscall7(n, (long)a0, (long)a1, (long)a2, (long)a3, (long)a4, (long)a5, (long)a6)); +} + +} /* extern C++ */ +#else + +/* These syscall macros were copied from musl. */ +#define __scc(x) ((__sc_word_t)(x)) +#define __syscall0(n) __do_syscall0(n) +#define __syscall1(n,a) __do_syscall1(n,__scc(a)) +#define __syscall2(n,a,b) __do_syscall2(n,__scc(a),__scc(b)) +#define __syscall3(n,a,b,c) __do_syscall3(n,__scc(a),__scc(b),__scc(c)) +#define __syscall4(n,a,b,c,d) __do_syscall4(n,__scc(a),__scc(b),__scc(c),__scc(d)) +#define __syscall5(n,a,b,c,d,e) __do_syscall5(n,__scc(a),__scc(b),__scc(c),__scc(d),__scc(e)) +#define __syscall6(n,a,b,c,d,e,f) __do_syscall6(n,__scc(a),__scc(b),__scc(c),__scc(d),__scc(e),__scc(f)) +#define __syscall7(n,a,b,c,d,e,f,g) __do_syscall7(n,__scc(a),__scc(b),__scc(c),__scc(d),__scc(e),__scc(f),__scc(g)) +#define __SYSCALL_NARGS_X(a,b,c,d,e,f,g,h,n,...) n +#define __SYSCALL_NARGS(...) __SYSCALL_NARGS_X(__VA_ARGS__,7,6,5,4,3,2,1,0,) +#define __SYSCALL_CONCAT_X(a,b) a##b +#define __SYSCALL_CONCAT(a,b) __SYSCALL_CONCAT_X(a,b) +#define __SYSCALL_DISP(b,...) __SYSCALL_CONCAT(b,__SYSCALL_NARGS(__VA_ARGS__))(__VA_ARGS__) +#define __syscall(...) __SYSCALL_DISP(__syscall,__VA_ARGS__) +#define syscall(...) __do_syscall_ret(__syscall(__VA_ARGS__)) + +#endif + +#ifdef __cplusplus +} +#endif + +#endif // _MLIBC_SYSCALL_H diff --git a/lib/mlibc/sysdeps/linux/include/bits/syscall_aliases.h b/lib/mlibc/sysdeps/linux/include/bits/syscall_aliases.h new file mode 100644 index 0000000..b929efc --- /dev/null +++ b/lib/mlibc/sysdeps/linux/include/bits/syscall_aliases.h @@ -0,0 +1,1823 @@ +#ifndef __MLIBC_SYSCALL_ALIAS_BIT +#define __MLIBC_SYSCALL_ALIAS_BIT +/* This file is autogenerated. Don't bother. */ +/* Generator script: sysdeps/linux/update-syscall-list.py. */ +#ifdef __NR__llseek +# define SYS__llseek __NR__llseek +#endif +#ifdef __NR__newselect +# define SYS__newselect __NR__newselect +#endif +#ifdef __NR__sysctl +# define SYS__sysctl __NR__sysctl +#endif +#ifdef __NR_accept +# define SYS_accept __NR_accept +#endif +#ifdef __NR_accept4 +# define SYS_accept4 __NR_accept4 +#endif +#ifdef __NR_access +# define SYS_access __NR_access +#endif +#ifdef __NR_acct +# define SYS_acct __NR_acct +#endif +#ifdef __NR_add_key +# define SYS_add_key __NR_add_key +#endif +#ifdef __NR_adjtimex +# define SYS_adjtimex __NR_adjtimex +#endif +#ifdef __NR_alarm +# define SYS_alarm __NR_alarm +#endif +#ifdef __NR_arc_gettls +# define SYS_arc_gettls __NR_arc_gettls +#endif +#ifdef __NR_arc_settls +# define SYS_arc_settls __NR_arc_settls +#endif +#ifdef __NR_arc_usr_cmpxchg +# define SYS_arc_usr_cmpxchg __NR_arc_usr_cmpxchg +#endif +#ifdef __NR_arch_prctl +# define SYS_arch_prctl __NR_arch_prctl +#endif +#ifdef __NR_arch_specific_syscall +# define SYS_arch_specific_syscall __NR_arch_specific_syscall +#endif +#ifdef __NR_arm_fadvise64_64 +# define SYS_arm_fadvise64_64 __NR_arm_fadvise64_64 +#endif +#ifdef __NR_atomic_barrier +# define SYS_atomic_barrier __NR_atomic_barrier +#endif +#ifdef __NR_atomic_cmpxchg_32 +# define SYS_atomic_cmpxchg_32 __NR_atomic_cmpxchg_32 +#endif +#ifdef __NR_bdflush +# define SYS_bdflush __NR_bdflush +#endif +#ifdef __NR_bind +# define SYS_bind __NR_bind +#endif +#ifdef __NR_bpf +# define SYS_bpf __NR_bpf +#endif +#ifdef __NR_brk +# define SYS_brk __NR_brk +#endif +#ifdef __NR_cachectl +# define SYS_cachectl __NR_cachectl +#endif +#ifdef __NR_cacheflush +# define SYS_cacheflush __NR_cacheflush +#endif +#ifdef __NR_capget +# define SYS_capget __NR_capget +#endif +#ifdef __NR_capset +# define SYS_capset __NR_capset +#endif +#ifdef __NR_chdir +# define SYS_chdir __NR_chdir +#endif +#ifdef __NR_chmod +# define SYS_chmod __NR_chmod +#endif +#ifdef __NR_chown +# define SYS_chown __NR_chown +#endif +#ifdef __NR_chown32 +# define SYS_chown32 __NR_chown32 +#endif +#ifdef __NR_chroot +# define SYS_chroot __NR_chroot +#endif +#ifdef __NR_clock_adjtime +# define SYS_clock_adjtime __NR_clock_adjtime +#endif +#ifdef __NR_clock_adjtime64 +# define SYS_clock_adjtime64 __NR_clock_adjtime64 +#endif +#ifdef __NR_clock_getres +# define SYS_clock_getres __NR_clock_getres +#endif +#ifdef __NR_clock_getres_time64 +# define SYS_clock_getres_time64 __NR_clock_getres_time64 +#endif +#ifdef __NR_clock_gettime +# define SYS_clock_gettime __NR_clock_gettime +#endif +#ifdef __NR_clock_gettime64 +# define SYS_clock_gettime64 __NR_clock_gettime64 +#endif +#ifdef __NR_clock_nanosleep +# define SYS_clock_nanosleep __NR_clock_nanosleep +#endif +#ifdef __NR_clock_nanosleep_time64 +# define SYS_clock_nanosleep_time64 __NR_clock_nanosleep_time64 +#endif +#ifdef __NR_clock_settime +# define SYS_clock_settime __NR_clock_settime +#endif +#ifdef __NR_clock_settime64 +# define SYS_clock_settime64 __NR_clock_settime64 +#endif +#ifdef __NR_clone +# define SYS_clone __NR_clone +#endif +#ifdef __NR_clone2 +# define SYS_clone2 __NR_clone2 +#endif +#ifdef __NR_clone3 +# define SYS_clone3 __NR_clone3 +#endif +#ifdef __NR_close +# define SYS_close __NR_close +#endif +#ifdef __NR_close_range +# define SYS_close_range __NR_close_range +#endif +#ifdef __NR_connect +# define SYS_connect __NR_connect +#endif +#ifdef __NR_copy_file_range +# define SYS_copy_file_range __NR_copy_file_range +#endif +#ifdef __NR_creat +# define SYS_creat __NR_creat +#endif +#ifdef __NR_create_module +# define SYS_create_module __NR_create_module +#endif +#ifdef __NR_delete_module +# define SYS_delete_module __NR_delete_module +#endif +#ifdef __NR_dipc +# define SYS_dipc __NR_dipc +#endif +#ifdef __NR_dup +# define SYS_dup __NR_dup +#endif +#ifdef __NR_dup2 +# define SYS_dup2 __NR_dup2 +#endif +#ifdef __NR_dup3 +# define SYS_dup3 __NR_dup3 +#endif +#ifdef __NR_epoll_create +# define SYS_epoll_create __NR_epoll_create +#endif +#ifdef __NR_epoll_create1 +# define SYS_epoll_create1 __NR_epoll_create1 +#endif +#ifdef __NR_epoll_ctl +# define SYS_epoll_ctl __NR_epoll_ctl +#endif +#ifdef __NR_epoll_ctl_old +# define SYS_epoll_ctl_old __NR_epoll_ctl_old +#endif +#ifdef __NR_epoll_pwait +# define SYS_epoll_pwait __NR_epoll_pwait +#endif +#ifdef __NR_epoll_pwait2 +# define SYS_epoll_pwait2 __NR_epoll_pwait2 +#endif +#ifdef __NR_epoll_wait +# define SYS_epoll_wait __NR_epoll_wait +#endif +#ifdef __NR_epoll_wait_old +# define SYS_epoll_wait_old __NR_epoll_wait_old +#endif +#ifdef __NR_eventfd +# define SYS_eventfd __NR_eventfd +#endif +#ifdef __NR_eventfd2 +# define SYS_eventfd2 __NR_eventfd2 +#endif +#ifdef __NR_exec_with_loader +# define SYS_exec_with_loader __NR_exec_with_loader +#endif +#ifdef __NR_execv +# define SYS_execv __NR_execv +#endif +#ifdef __NR_execve +# define SYS_execve __NR_execve +#endif +#ifdef __NR_execveat +# define SYS_execveat __NR_execveat +#endif +#ifdef __NR_exit +# define SYS_exit __NR_exit +#endif +#ifdef __NR_exit_group +# define SYS_exit_group __NR_exit_group +#endif +#ifdef __NR_faccessat +# define SYS_faccessat __NR_faccessat +#endif +#ifdef __NR_faccessat2 +# define SYS_faccessat2 __NR_faccessat2 +#endif +#ifdef __NR_fadvise64 +# define SYS_fadvise64 __NR_fadvise64 +#endif +#ifdef __NR_fadvise64_64 +# define SYS_fadvise64_64 __NR_fadvise64_64 +#endif +#ifdef __NR_fallocate +# define SYS_fallocate __NR_fallocate +#endif +#ifdef __NR_fanotify_init +# define SYS_fanotify_init __NR_fanotify_init +#endif +#ifdef __NR_fanotify_mark +# define SYS_fanotify_mark __NR_fanotify_mark +#endif +#ifdef __NR_fchdir +# define SYS_fchdir __NR_fchdir +#endif +#ifdef __NR_fchmod +# define SYS_fchmod __NR_fchmod +#endif +#ifdef __NR_fchmodat +# define SYS_fchmodat __NR_fchmodat +#endif +#ifdef __NR_fchown +# define SYS_fchown __NR_fchown +#endif +#ifdef __NR_fchown32 +# define SYS_fchown32 __NR_fchown32 +#endif +#ifdef __NR_fchownat +# define SYS_fchownat __NR_fchownat +#endif +#ifdef __NR_fcntl +# define SYS_fcntl __NR_fcntl +#endif +#ifdef __NR_fcntl64 +# define SYS_fcntl64 __NR_fcntl64 +#endif +#ifdef __NR_fdatasync +# define SYS_fdatasync __NR_fdatasync +#endif +#ifdef __NR_fgetxattr +# define SYS_fgetxattr __NR_fgetxattr +#endif +#ifdef __NR_finit_module +# define SYS_finit_module __NR_finit_module +#endif +#ifdef __NR_flistxattr +# define SYS_flistxattr __NR_flistxattr +#endif +#ifdef __NR_flock +# define SYS_flock __NR_flock +#endif +#ifdef __NR_fork +# define SYS_fork __NR_fork +#endif +#ifdef __NR_fremovexattr +# define SYS_fremovexattr __NR_fremovexattr +#endif +#ifdef __NR_fsconfig +# define SYS_fsconfig __NR_fsconfig +#endif +#ifdef __NR_fsetxattr +# define SYS_fsetxattr __NR_fsetxattr +#endif +#ifdef __NR_fsmount +# define SYS_fsmount __NR_fsmount +#endif +#ifdef __NR_fsopen +# define SYS_fsopen __NR_fsopen +#endif +#ifdef __NR_fspick +# define SYS_fspick __NR_fspick +#endif +#ifdef __NR_fstat +# define SYS_fstat __NR_fstat +#endif +#ifdef __NR_fstat64 +# define SYS_fstat64 __NR_fstat64 +#endif +#ifdef __NR_fstatat64 +# define SYS_fstatat64 __NR_fstatat64 +#endif +#ifdef __NR_fstatfs +# define SYS_fstatfs __NR_fstatfs +#endif +#ifdef __NR_fstatfs64 +# define SYS_fstatfs64 __NR_fstatfs64 +#endif +#ifdef __NR_fsync +# define SYS_fsync __NR_fsync +#endif +#ifdef __NR_ftruncate +# define SYS_ftruncate __NR_ftruncate +#endif +#ifdef __NR_ftruncate64 +# define SYS_ftruncate64 __NR_ftruncate64 +#endif +#ifdef __NR_futex +# define SYS_futex __NR_futex +#endif +#ifdef __NR_futex_time64 +# define SYS_futex_time64 __NR_futex_time64 +#endif +#ifdef __NR_futex_waitv +# define SYS_futex_waitv __NR_futex_waitv +#endif +#ifdef __NR_futimesat +# define SYS_futimesat __NR_futimesat +#endif +#ifdef __NR_get_kernel_syms +# define SYS_get_kernel_syms __NR_get_kernel_syms +#endif +#ifdef __NR_get_mempolicy +# define SYS_get_mempolicy __NR_get_mempolicy +#endif +#ifdef __NR_get_robust_list +# define SYS_get_robust_list __NR_get_robust_list +#endif +#ifdef __NR_get_thread_area +# define SYS_get_thread_area __NR_get_thread_area +#endif +#ifdef __NR_getcpu +# define SYS_getcpu __NR_getcpu +#endif +#ifdef __NR_getcwd +# define SYS_getcwd __NR_getcwd +#endif +#ifdef __NR_getdents +# define SYS_getdents __NR_getdents +#endif +#ifdef __NR_getdents64 +# define SYS_getdents64 __NR_getdents64 +#endif +#ifdef __NR_getdomainname +# define SYS_getdomainname __NR_getdomainname +#endif +#ifdef __NR_getdtablesize +# define SYS_getdtablesize __NR_getdtablesize +#endif +#ifdef __NR_getegid +# define SYS_getegid __NR_getegid +#endif +#ifdef __NR_getegid32 +# define SYS_getegid32 __NR_getegid32 +#endif +#ifdef __NR_geteuid +# define SYS_geteuid __NR_geteuid +#endif +#ifdef __NR_geteuid32 +# define SYS_geteuid32 __NR_geteuid32 +#endif +#ifdef __NR_getgid +# define SYS_getgid __NR_getgid +#endif +#ifdef __NR_getgid32 +# define SYS_getgid32 __NR_getgid32 +#endif +#ifdef __NR_getgroups +# define SYS_getgroups __NR_getgroups +#endif +#ifdef __NR_getgroups32 +# define SYS_getgroups32 __NR_getgroups32 +#endif +#ifdef __NR_gethostname +# define SYS_gethostname __NR_gethostname +#endif +#ifdef __NR_getitimer +# define SYS_getitimer __NR_getitimer +#endif +#ifdef __NR_getpagesize +# define SYS_getpagesize __NR_getpagesize +#endif +#ifdef __NR_getpeername +# define SYS_getpeername __NR_getpeername +#endif +#ifdef __NR_getpgid +# define SYS_getpgid __NR_getpgid +#endif +#ifdef __NR_getpgrp +# define SYS_getpgrp __NR_getpgrp +#endif +#ifdef __NR_getpid +# define SYS_getpid __NR_getpid +#endif +#ifdef __NR_getpmsg +# define SYS_getpmsg __NR_getpmsg +#endif +#ifdef __NR_getppid +# define SYS_getppid __NR_getppid +#endif +#ifdef __NR_getpriority +# define SYS_getpriority __NR_getpriority +#endif +#ifdef __NR_getrandom +# define SYS_getrandom __NR_getrandom +#endif +#ifdef __NR_getresgid +# define SYS_getresgid __NR_getresgid +#endif +#ifdef __NR_getresgid32 +# define SYS_getresgid32 __NR_getresgid32 +#endif +#ifdef __NR_getresuid +# define SYS_getresuid __NR_getresuid +#endif +#ifdef __NR_getresuid32 +# define SYS_getresuid32 __NR_getresuid32 +#endif +#ifdef __NR_getrlimit +# define SYS_getrlimit __NR_getrlimit +#endif +#ifdef __NR_getrusage +# define SYS_getrusage __NR_getrusage +#endif +#ifdef __NR_getsid +# define SYS_getsid __NR_getsid +#endif +#ifdef __NR_getsockname +# define SYS_getsockname __NR_getsockname +#endif +#ifdef __NR_getsockopt +# define SYS_getsockopt __NR_getsockopt +#endif +#ifdef __NR_gettid +# define SYS_gettid __NR_gettid +#endif +#ifdef __NR_gettimeofday +# define SYS_gettimeofday __NR_gettimeofday +#endif +#ifdef __NR_getuid +# define SYS_getuid __NR_getuid +#endif +#ifdef __NR_getuid32 +# define SYS_getuid32 __NR_getuid32 +#endif +#ifdef __NR_getunwind +# define SYS_getunwind __NR_getunwind +#endif +#ifdef __NR_getxattr +# define SYS_getxattr __NR_getxattr +#endif +#ifdef __NR_getxgid +# define SYS_getxgid __NR_getxgid +#endif +#ifdef __NR_getxpid +# define SYS_getxpid __NR_getxpid +#endif +#ifdef __NR_getxuid +# define SYS_getxuid __NR_getxuid +#endif +#ifdef __NR_idle +# define SYS_idle __NR_idle +#endif +#ifdef __NR_init_module +# define SYS_init_module __NR_init_module +#endif +#ifdef __NR_inotify_add_watch +# define SYS_inotify_add_watch __NR_inotify_add_watch +#endif +#ifdef __NR_inotify_init +# define SYS_inotify_init __NR_inotify_init +#endif +#ifdef __NR_inotify_init1 +# define SYS_inotify_init1 __NR_inotify_init1 +#endif +#ifdef __NR_inotify_rm_watch +# define SYS_inotify_rm_watch __NR_inotify_rm_watch +#endif +#ifdef __NR_io_cancel +# define SYS_io_cancel __NR_io_cancel +#endif +#ifdef __NR_io_destroy +# define SYS_io_destroy __NR_io_destroy +#endif +#ifdef __NR_io_getevents +# define SYS_io_getevents __NR_io_getevents +#endif +#ifdef __NR_io_pgetevents +# define SYS_io_pgetevents __NR_io_pgetevents +#endif +#ifdef __NR_io_pgetevents_time64 +# define SYS_io_pgetevents_time64 __NR_io_pgetevents_time64 +#endif +#ifdef __NR_io_setup +# define SYS_io_setup __NR_io_setup +#endif +#ifdef __NR_io_submit +# define SYS_io_submit __NR_io_submit +#endif +#ifdef __NR_io_uring_enter +# define SYS_io_uring_enter __NR_io_uring_enter +#endif +#ifdef __NR_io_uring_register +# define SYS_io_uring_register __NR_io_uring_register +#endif +#ifdef __NR_io_uring_setup +# define SYS_io_uring_setup __NR_io_uring_setup +#endif +#ifdef __NR_ioctl +# define SYS_ioctl __NR_ioctl +#endif +#ifdef __NR_ioperm +# define SYS_ioperm __NR_ioperm +#endif +#ifdef __NR_iopl +# define SYS_iopl __NR_iopl +#endif +#ifdef __NR_ioprio_get +# define SYS_ioprio_get __NR_ioprio_get +#endif +#ifdef __NR_ioprio_set +# define SYS_ioprio_set __NR_ioprio_set +#endif +#ifdef __NR_ipc +# define SYS_ipc __NR_ipc +#endif +#ifdef __NR_kcmp +# define SYS_kcmp __NR_kcmp +#endif +#ifdef __NR_kern_features +# define SYS_kern_features __NR_kern_features +#endif +#ifdef __NR_kexec_file_load +# define SYS_kexec_file_load __NR_kexec_file_load +#endif +#ifdef __NR_kexec_load +# define SYS_kexec_load __NR_kexec_load +#endif +#ifdef __NR_keyctl +# define SYS_keyctl __NR_keyctl +#endif +#ifdef __NR_kill +# define SYS_kill __NR_kill +#endif +#ifdef __NR_landlock_add_rule +# define SYS_landlock_add_rule __NR_landlock_add_rule +#endif +#ifdef __NR_landlock_create_ruleset +# define SYS_landlock_create_ruleset __NR_landlock_create_ruleset +#endif +#ifdef __NR_landlock_restrict_self +# define SYS_landlock_restrict_self __NR_landlock_restrict_self +#endif +#ifdef __NR_lchown +# define SYS_lchown __NR_lchown +#endif +#ifdef __NR_lchown32 +# define SYS_lchown32 __NR_lchown32 +#endif +#ifdef __NR_lgetxattr +# define SYS_lgetxattr __NR_lgetxattr +#endif +#ifdef __NR_link +# define SYS_link __NR_link +#endif +#ifdef __NR_linkat +# define SYS_linkat __NR_linkat +#endif +#ifdef __NR_listen +# define SYS_listen __NR_listen +#endif +#ifdef __NR_listxattr +# define SYS_listxattr __NR_listxattr +#endif +#ifdef __NR_llistxattr +# define SYS_llistxattr __NR_llistxattr +#endif +#ifdef __NR_llseek +# define SYS_llseek __NR_llseek +#endif +#ifdef __NR_lookup_dcookie +# define SYS_lookup_dcookie __NR_lookup_dcookie +#endif +#ifdef __NR_lremovexattr +# define SYS_lremovexattr __NR_lremovexattr +#endif +#ifdef __NR_lseek +# define SYS_lseek __NR_lseek +#endif +#ifdef __NR_lsetxattr +# define SYS_lsetxattr __NR_lsetxattr +#endif +#ifdef __NR_lstat +# define SYS_lstat __NR_lstat +#endif +#ifdef __NR_lstat64 +# define SYS_lstat64 __NR_lstat64 +#endif +#ifdef __NR_madvise +# define SYS_madvise __NR_madvise +#endif +#ifdef __NR_mbind +# define SYS_mbind __NR_mbind +#endif +#ifdef __NR_membarrier +# define SYS_membarrier __NR_membarrier +#endif +#ifdef __NR_memfd_create +# define SYS_memfd_create __NR_memfd_create +#endif +#ifdef __NR_memfd_secret +# define SYS_memfd_secret __NR_memfd_secret +#endif +#ifdef __NR_memory_ordering +# define SYS_memory_ordering __NR_memory_ordering +#endif +#ifdef __NR_migrate_pages +# define SYS_migrate_pages __NR_migrate_pages +#endif +#ifdef __NR_mincore +# define SYS_mincore __NR_mincore +#endif +#ifdef __NR_mkdir +# define SYS_mkdir __NR_mkdir +#endif +#ifdef __NR_mkdirat +# define SYS_mkdirat __NR_mkdirat +#endif +#ifdef __NR_mknod +# define SYS_mknod __NR_mknod +#endif +#ifdef __NR_mknodat +# define SYS_mknodat __NR_mknodat +#endif +#ifdef __NR_mlock +# define SYS_mlock __NR_mlock +#endif +#ifdef __NR_mlock2 +# define SYS_mlock2 __NR_mlock2 +#endif +#ifdef __NR_mlockall +# define SYS_mlockall __NR_mlockall +#endif +#ifdef __NR_mmap +# define SYS_mmap __NR_mmap +#endif +#ifdef __NR_mmap2 +# define SYS_mmap2 __NR_mmap2 +#endif +#ifdef __NR_modify_ldt +# define SYS_modify_ldt __NR_modify_ldt +#endif +#ifdef __NR_mount +# define SYS_mount __NR_mount +#endif +#ifdef __NR_mount_setattr +# define SYS_mount_setattr __NR_mount_setattr +#endif +#ifdef __NR_move_mount +# define SYS_move_mount __NR_move_mount +#endif +#ifdef __NR_move_pages +# define SYS_move_pages __NR_move_pages +#endif +#ifdef __NR_mprotect +# define SYS_mprotect __NR_mprotect +#endif +#ifdef __NR_mq_getsetattr +# define SYS_mq_getsetattr __NR_mq_getsetattr +#endif +#ifdef __NR_mq_notify +# define SYS_mq_notify __NR_mq_notify +#endif +#ifdef __NR_mq_open +# define SYS_mq_open __NR_mq_open +#endif +#ifdef __NR_mq_timedreceive +# define SYS_mq_timedreceive __NR_mq_timedreceive +#endif +#ifdef __NR_mq_timedreceive_time64 +# define SYS_mq_timedreceive_time64 __NR_mq_timedreceive_time64 +#endif +#ifdef __NR_mq_timedsend +# define SYS_mq_timedsend __NR_mq_timedsend +#endif +#ifdef __NR_mq_timedsend_time64 +# define SYS_mq_timedsend_time64 __NR_mq_timedsend_time64 +#endif +#ifdef __NR_mq_unlink +# define SYS_mq_unlink __NR_mq_unlink +#endif +#ifdef __NR_mremap +# define SYS_mremap __NR_mremap +#endif +#ifdef __NR_msgctl +# define SYS_msgctl __NR_msgctl +#endif +#ifdef __NR_msgget +# define SYS_msgget __NR_msgget +#endif +#ifdef __NR_msgrcv +# define SYS_msgrcv __NR_msgrcv +#endif +#ifdef __NR_msgsnd +# define SYS_msgsnd __NR_msgsnd +#endif +#ifdef __NR_msync +# define SYS_msync __NR_msync +#endif +#ifdef __NR_multiplexer +# define SYS_multiplexer __NR_multiplexer +#endif +#ifdef __NR_munlock +# define SYS_munlock __NR_munlock +#endif +#ifdef __NR_munlockall +# define SYS_munlockall __NR_munlockall +#endif +#ifdef __NR_munmap +# define SYS_munmap __NR_munmap +#endif +#ifdef __NR_name_to_handle_at +# define SYS_name_to_handle_at __NR_name_to_handle_at +#endif +#ifdef __NR_nanosleep +# define SYS_nanosleep __NR_nanosleep +#endif +#ifdef __NR_newfstatat +# define SYS_newfstatat __NR_newfstatat +#endif +#ifdef __NR_nfsservctl +# define SYS_nfsservctl __NR_nfsservctl +#endif +#ifdef __NR_nice +# define SYS_nice __NR_nice +#endif +#ifdef __NR_old_adjtimex +# define SYS_old_adjtimex __NR_old_adjtimex +#endif +#ifdef __NR_old_getpagesize +# define SYS_old_getpagesize __NR_old_getpagesize +#endif +#ifdef __NR_oldfstat +# define SYS_oldfstat __NR_oldfstat +#endif +#ifdef __NR_oldlstat +# define SYS_oldlstat __NR_oldlstat +#endif +#ifdef __NR_oldolduname +# define SYS_oldolduname __NR_oldolduname +#endif +#ifdef __NR_oldstat +# define SYS_oldstat __NR_oldstat +#endif +#ifdef __NR_oldumount +# define SYS_oldumount __NR_oldumount +#endif +#ifdef __NR_olduname +# define SYS_olduname __NR_olduname +#endif +#ifdef __NR_open +# define SYS_open __NR_open +#endif +#ifdef __NR_open_by_handle_at +# define SYS_open_by_handle_at __NR_open_by_handle_at +#endif +#ifdef __NR_open_tree +# define SYS_open_tree __NR_open_tree +#endif +#ifdef __NR_openat +# define SYS_openat __NR_openat +#endif +#ifdef __NR_openat2 +# define SYS_openat2 __NR_openat2 +#endif +#ifdef __NR_or1k_atomic +# define SYS_or1k_atomic __NR_or1k_atomic +#endif +#ifdef __NR_osf_adjtime +# define SYS_osf_adjtime __NR_osf_adjtime +#endif +#ifdef __NR_osf_afs_syscall +# define SYS_osf_afs_syscall __NR_osf_afs_syscall +#endif +#ifdef __NR_osf_alt_plock +# define SYS_osf_alt_plock __NR_osf_alt_plock +#endif +#ifdef __NR_osf_alt_setsid +# define SYS_osf_alt_setsid __NR_osf_alt_setsid +#endif +#ifdef __NR_osf_alt_sigpending +# define SYS_osf_alt_sigpending __NR_osf_alt_sigpending +#endif +#ifdef __NR_osf_asynch_daemon +# define SYS_osf_asynch_daemon __NR_osf_asynch_daemon +#endif +#ifdef __NR_osf_audcntl +# define SYS_osf_audcntl __NR_osf_audcntl +#endif +#ifdef __NR_osf_audgen +# define SYS_osf_audgen __NR_osf_audgen +#endif +#ifdef __NR_osf_chflags +# define SYS_osf_chflags __NR_osf_chflags +#endif +#ifdef __NR_osf_execve +# define SYS_osf_execve __NR_osf_execve +#endif +#ifdef __NR_osf_exportfs +# define SYS_osf_exportfs __NR_osf_exportfs +#endif +#ifdef __NR_osf_fchflags +# define SYS_osf_fchflags __NR_osf_fchflags +#endif +#ifdef __NR_osf_fdatasync +# define SYS_osf_fdatasync __NR_osf_fdatasync +#endif +#ifdef __NR_osf_fpathconf +# define SYS_osf_fpathconf __NR_osf_fpathconf +#endif +#ifdef __NR_osf_fstat +# define SYS_osf_fstat __NR_osf_fstat +#endif +#ifdef __NR_osf_fstatfs +# define SYS_osf_fstatfs __NR_osf_fstatfs +#endif +#ifdef __NR_osf_fstatfs64 +# define SYS_osf_fstatfs64 __NR_osf_fstatfs64 +#endif +#ifdef __NR_osf_fuser +# define SYS_osf_fuser __NR_osf_fuser +#endif +#ifdef __NR_osf_getaddressconf +# define SYS_osf_getaddressconf __NR_osf_getaddressconf +#endif +#ifdef __NR_osf_getdirentries +# define SYS_osf_getdirentries __NR_osf_getdirentries +#endif +#ifdef __NR_osf_getdomainname +# define SYS_osf_getdomainname __NR_osf_getdomainname +#endif +#ifdef __NR_osf_getfh +# define SYS_osf_getfh __NR_osf_getfh +#endif +#ifdef __NR_osf_getfsstat +# define SYS_osf_getfsstat __NR_osf_getfsstat +#endif +#ifdef __NR_osf_gethostid +# define SYS_osf_gethostid __NR_osf_gethostid +#endif +#ifdef __NR_osf_getitimer +# define SYS_osf_getitimer __NR_osf_getitimer +#endif +#ifdef __NR_osf_getlogin +# define SYS_osf_getlogin __NR_osf_getlogin +#endif +#ifdef __NR_osf_getmnt +# define SYS_osf_getmnt __NR_osf_getmnt +#endif +#ifdef __NR_osf_getrusage +# define SYS_osf_getrusage __NR_osf_getrusage +#endif +#ifdef __NR_osf_getsysinfo +# define SYS_osf_getsysinfo __NR_osf_getsysinfo +#endif +#ifdef __NR_osf_gettimeofday +# define SYS_osf_gettimeofday __NR_osf_gettimeofday +#endif +#ifdef __NR_osf_kloadcall +# define SYS_osf_kloadcall __NR_osf_kloadcall +#endif +#ifdef __NR_osf_kmodcall +# define SYS_osf_kmodcall __NR_osf_kmodcall +#endif +#ifdef __NR_osf_lstat +# define SYS_osf_lstat __NR_osf_lstat +#endif +#ifdef __NR_osf_memcntl +# define SYS_osf_memcntl __NR_osf_memcntl +#endif +#ifdef __NR_osf_mincore +# define SYS_osf_mincore __NR_osf_mincore +#endif +#ifdef __NR_osf_mount +# define SYS_osf_mount __NR_osf_mount +#endif +#ifdef __NR_osf_mremap +# define SYS_osf_mremap __NR_osf_mremap +#endif +#ifdef __NR_osf_msfs_syscall +# define SYS_osf_msfs_syscall __NR_osf_msfs_syscall +#endif +#ifdef __NR_osf_msleep +# define SYS_osf_msleep __NR_osf_msleep +#endif +#ifdef __NR_osf_mvalid +# define SYS_osf_mvalid __NR_osf_mvalid +#endif +#ifdef __NR_osf_mwakeup +# define SYS_osf_mwakeup __NR_osf_mwakeup +#endif +#ifdef __NR_osf_naccept +# define SYS_osf_naccept __NR_osf_naccept +#endif +#ifdef __NR_osf_nfssvc +# define SYS_osf_nfssvc __NR_osf_nfssvc +#endif +#ifdef __NR_osf_ngetpeername +# define SYS_osf_ngetpeername __NR_osf_ngetpeername +#endif +#ifdef __NR_osf_ngetsockname +# define SYS_osf_ngetsockname __NR_osf_ngetsockname +#endif +#ifdef __NR_osf_nrecvfrom +# define SYS_osf_nrecvfrom __NR_osf_nrecvfrom +#endif +#ifdef __NR_osf_nrecvmsg +# define SYS_osf_nrecvmsg __NR_osf_nrecvmsg +#endif +#ifdef __NR_osf_nsendmsg +# define SYS_osf_nsendmsg __NR_osf_nsendmsg +#endif +#ifdef __NR_osf_ntp_adjtime +# define SYS_osf_ntp_adjtime __NR_osf_ntp_adjtime +#endif +#ifdef __NR_osf_ntp_gettime +# define SYS_osf_ntp_gettime __NR_osf_ntp_gettime +#endif +#ifdef __NR_osf_old_creat +# define SYS_osf_old_creat __NR_osf_old_creat +#endif +#ifdef __NR_osf_old_fstat +# define SYS_osf_old_fstat __NR_osf_old_fstat +#endif +#ifdef __NR_osf_old_getpgrp +# define SYS_osf_old_getpgrp __NR_osf_old_getpgrp +#endif +#ifdef __NR_osf_old_killpg +# define SYS_osf_old_killpg __NR_osf_old_killpg +#endif +#ifdef __NR_osf_old_lstat +# define SYS_osf_old_lstat __NR_osf_old_lstat +#endif +#ifdef __NR_osf_old_open +# define SYS_osf_old_open __NR_osf_old_open +#endif +#ifdef __NR_osf_old_sigaction +# define SYS_osf_old_sigaction __NR_osf_old_sigaction +#endif +#ifdef __NR_osf_old_sigblock +# define SYS_osf_old_sigblock __NR_osf_old_sigblock +#endif +#ifdef __NR_osf_old_sigreturn +# define SYS_osf_old_sigreturn __NR_osf_old_sigreturn +#endif +#ifdef __NR_osf_old_sigsetmask +# define SYS_osf_old_sigsetmask __NR_osf_old_sigsetmask +#endif +#ifdef __NR_osf_old_sigvec +# define SYS_osf_old_sigvec __NR_osf_old_sigvec +#endif +#ifdef __NR_osf_old_stat +# define SYS_osf_old_stat __NR_osf_old_stat +#endif +#ifdef __NR_osf_old_vadvise +# define SYS_osf_old_vadvise __NR_osf_old_vadvise +#endif +#ifdef __NR_osf_old_vtrace +# define SYS_osf_old_vtrace __NR_osf_old_vtrace +#endif +#ifdef __NR_osf_old_wait +# define SYS_osf_old_wait __NR_osf_old_wait +#endif +#ifdef __NR_osf_oldquota +# define SYS_osf_oldquota __NR_osf_oldquota +#endif +#ifdef __NR_osf_pathconf +# define SYS_osf_pathconf __NR_osf_pathconf +#endif +#ifdef __NR_osf_pid_block +# define SYS_osf_pid_block __NR_osf_pid_block +#endif +#ifdef __NR_osf_pid_unblock +# define SYS_osf_pid_unblock __NR_osf_pid_unblock +#endif +#ifdef __NR_osf_plock +# define SYS_osf_plock __NR_osf_plock +#endif +#ifdef __NR_osf_priocntlset +# define SYS_osf_priocntlset __NR_osf_priocntlset +#endif +#ifdef __NR_osf_profil +# define SYS_osf_profil __NR_osf_profil +#endif +#ifdef __NR_osf_proplist_syscall +# define SYS_osf_proplist_syscall __NR_osf_proplist_syscall +#endif +#ifdef __NR_osf_reboot +# define SYS_osf_reboot __NR_osf_reboot +#endif +#ifdef __NR_osf_revoke +# define SYS_osf_revoke __NR_osf_revoke +#endif +#ifdef __NR_osf_sbrk +# define SYS_osf_sbrk __NR_osf_sbrk +#endif +#ifdef __NR_osf_security +# define SYS_osf_security __NR_osf_security +#endif +#ifdef __NR_osf_select +# define SYS_osf_select __NR_osf_select +#endif +#ifdef __NR_osf_set_program_attributes +# define SYS_osf_set_program_attributes __NR_osf_set_program_attributes +#endif +#ifdef __NR_osf_set_speculative +# define SYS_osf_set_speculative __NR_osf_set_speculative +#endif +#ifdef __NR_osf_sethostid +# define SYS_osf_sethostid __NR_osf_sethostid +#endif +#ifdef __NR_osf_setitimer +# define SYS_osf_setitimer __NR_osf_setitimer +#endif +#ifdef __NR_osf_setlogin +# define SYS_osf_setlogin __NR_osf_setlogin +#endif +#ifdef __NR_osf_setsysinfo +# define SYS_osf_setsysinfo __NR_osf_setsysinfo +#endif +#ifdef __NR_osf_settimeofday +# define SYS_osf_settimeofday __NR_osf_settimeofday +#endif +#ifdef __NR_osf_shmat +# define SYS_osf_shmat __NR_osf_shmat +#endif +#ifdef __NR_osf_signal +# define SYS_osf_signal __NR_osf_signal +#endif +#ifdef __NR_osf_sigprocmask +# define SYS_osf_sigprocmask __NR_osf_sigprocmask +#endif +#ifdef __NR_osf_sigsendset +# define SYS_osf_sigsendset __NR_osf_sigsendset +#endif +#ifdef __NR_osf_sigstack +# define SYS_osf_sigstack __NR_osf_sigstack +#endif +#ifdef __NR_osf_sigwaitprim +# define SYS_osf_sigwaitprim __NR_osf_sigwaitprim +#endif +#ifdef __NR_osf_sstk +# define SYS_osf_sstk __NR_osf_sstk +#endif +#ifdef __NR_osf_stat +# define SYS_osf_stat __NR_osf_stat +#endif +#ifdef __NR_osf_statfs +# define SYS_osf_statfs __NR_osf_statfs +#endif +#ifdef __NR_osf_statfs64 +# define SYS_osf_statfs64 __NR_osf_statfs64 +#endif +#ifdef __NR_osf_subsys_info +# define SYS_osf_subsys_info __NR_osf_subsys_info +#endif +#ifdef __NR_osf_swapctl +# define SYS_osf_swapctl __NR_osf_swapctl +#endif +#ifdef __NR_osf_swapon +# define SYS_osf_swapon __NR_osf_swapon +#endif +#ifdef __NR_osf_syscall +# define SYS_osf_syscall __NR_osf_syscall +#endif +#ifdef __NR_osf_sysinfo +# define SYS_osf_sysinfo __NR_osf_sysinfo +#endif +#ifdef __NR_osf_table +# define SYS_osf_table __NR_osf_table +#endif +#ifdef __NR_osf_uadmin +# define SYS_osf_uadmin __NR_osf_uadmin +#endif +#ifdef __NR_osf_usleep_thread +# define SYS_osf_usleep_thread __NR_osf_usleep_thread +#endif +#ifdef __NR_osf_uswitch +# define SYS_osf_uswitch __NR_osf_uswitch +#endif +#ifdef __NR_osf_utc_adjtime +# define SYS_osf_utc_adjtime __NR_osf_utc_adjtime +#endif +#ifdef __NR_osf_utc_gettime +# define SYS_osf_utc_gettime __NR_osf_utc_gettime +#endif +#ifdef __NR_osf_utimes +# define SYS_osf_utimes __NR_osf_utimes +#endif +#ifdef __NR_osf_utsname +# define SYS_osf_utsname __NR_osf_utsname +#endif +#ifdef __NR_osf_wait4 +# define SYS_osf_wait4 __NR_osf_wait4 +#endif +#ifdef __NR_osf_waitid +# define SYS_osf_waitid __NR_osf_waitid +#endif +#ifdef __NR_pause +# define SYS_pause __NR_pause +#endif +#ifdef __NR_pciconfig_iobase +# define SYS_pciconfig_iobase __NR_pciconfig_iobase +#endif +#ifdef __NR_pciconfig_read +# define SYS_pciconfig_read __NR_pciconfig_read +#endif +#ifdef __NR_pciconfig_write +# define SYS_pciconfig_write __NR_pciconfig_write +#endif +#ifdef __NR_perf_event_open +# define SYS_perf_event_open __NR_perf_event_open +#endif +#ifdef __NR_perfctr +# define SYS_perfctr __NR_perfctr +#endif +#ifdef __NR_perfmonctl +# define SYS_perfmonctl __NR_perfmonctl +#endif +#ifdef __NR_personality +# define SYS_personality __NR_personality +#endif +#ifdef __NR_pidfd_getfd +# define SYS_pidfd_getfd __NR_pidfd_getfd +#endif +#ifdef __NR_pidfd_open +# define SYS_pidfd_open __NR_pidfd_open +#endif +#ifdef __NR_pidfd_send_signal +# define SYS_pidfd_send_signal __NR_pidfd_send_signal +#endif +#ifdef __NR_pipe +# define SYS_pipe __NR_pipe +#endif +#ifdef __NR_pipe2 +# define SYS_pipe2 __NR_pipe2 +#endif +#ifdef __NR_pivot_root +# define SYS_pivot_root __NR_pivot_root +#endif +#ifdef __NR_pkey_alloc +# define SYS_pkey_alloc __NR_pkey_alloc +#endif +#ifdef __NR_pkey_free +# define SYS_pkey_free __NR_pkey_free +#endif +#ifdef __NR_pkey_mprotect +# define SYS_pkey_mprotect __NR_pkey_mprotect +#endif +#ifdef __NR_poll +# define SYS_poll __NR_poll +#endif +#ifdef __NR_ppoll +# define SYS_ppoll __NR_ppoll +#endif +#ifdef __NR_ppoll_time64 +# define SYS_ppoll_time64 __NR_ppoll_time64 +#endif +#ifdef __NR_prctl +# define SYS_prctl __NR_prctl +#endif +#ifdef __NR_pread64 +# define SYS_pread64 __NR_pread64 +#endif +#ifdef __NR_preadv +# define SYS_preadv __NR_preadv +#endif +#ifdef __NR_preadv2 +# define SYS_preadv2 __NR_preadv2 +#endif +#ifdef __NR_prlimit64 +# define SYS_prlimit64 __NR_prlimit64 +#endif +#ifdef __NR_process_madvise +# define SYS_process_madvise __NR_process_madvise +#endif +#ifdef __NR_process_mrelease +# define SYS_process_mrelease __NR_process_mrelease +#endif +#ifdef __NR_process_vm_readv +# define SYS_process_vm_readv __NR_process_vm_readv +#endif +#ifdef __NR_process_vm_writev +# define SYS_process_vm_writev __NR_process_vm_writev +#endif +#ifdef __NR_pselect6 +# define SYS_pselect6 __NR_pselect6 +#endif +#ifdef __NR_pselect6_time64 +# define SYS_pselect6_time64 __NR_pselect6_time64 +#endif +#ifdef __NR_ptrace +# define SYS_ptrace __NR_ptrace +#endif +#ifdef __NR_pwrite64 +# define SYS_pwrite64 __NR_pwrite64 +#endif +#ifdef __NR_pwritev +# define SYS_pwritev __NR_pwritev +#endif +#ifdef __NR_pwritev2 +# define SYS_pwritev2 __NR_pwritev2 +#endif +#ifdef __NR_query_module +# define SYS_query_module __NR_query_module +#endif +#ifdef __NR_quotactl +# define SYS_quotactl __NR_quotactl +#endif +#ifdef __NR_quotactl_fd +# define SYS_quotactl_fd __NR_quotactl_fd +#endif +#ifdef __NR_read +# define SYS_read __NR_read +#endif +#ifdef __NR_readahead +# define SYS_readahead __NR_readahead +#endif +#ifdef __NR_readdir +# define SYS_readdir __NR_readdir +#endif +#ifdef __NR_readlink +# define SYS_readlink __NR_readlink +#endif +#ifdef __NR_readlinkat +# define SYS_readlinkat __NR_readlinkat +#endif +#ifdef __NR_readv +# define SYS_readv __NR_readv +#endif +#ifdef __NR_reboot +# define SYS_reboot __NR_reboot +#endif +#ifdef __NR_recv +# define SYS_recv __NR_recv +#endif +#ifdef __NR_recvfrom +# define SYS_recvfrom __NR_recvfrom +#endif +#ifdef __NR_recvmmsg +# define SYS_recvmmsg __NR_recvmmsg +#endif +#ifdef __NR_recvmmsg_time64 +# define SYS_recvmmsg_time64 __NR_recvmmsg_time64 +#endif +#ifdef __NR_recvmsg +# define SYS_recvmsg __NR_recvmsg +#endif +#ifdef __NR_remap_file_pages +# define SYS_remap_file_pages __NR_remap_file_pages +#endif +#ifdef __NR_removexattr +# define SYS_removexattr __NR_removexattr +#endif +#ifdef __NR_rename +# define SYS_rename __NR_rename +#endif +#ifdef __NR_renameat +# define SYS_renameat __NR_renameat +#endif +#ifdef __NR_renameat2 +# define SYS_renameat2 __NR_renameat2 +#endif +#ifdef __NR_request_key +# define SYS_request_key __NR_request_key +#endif +#ifdef __NR_restart_syscall +# define SYS_restart_syscall __NR_restart_syscall +#endif +#ifdef __NR_riscv_flush_icache +# define SYS_riscv_flush_icache __NR_riscv_flush_icache +#endif +#ifdef __NR_riscv_hwprobe +# define SYS_riscv_hwprobe __NR_riscv_hwprobe +#endif +#ifdef __NR_rmdir +# define SYS_rmdir __NR_rmdir +#endif +#ifdef __NR_rseq +# define SYS_rseq __NR_rseq +#endif +#ifdef __NR_rt_sigaction +# define SYS_rt_sigaction __NR_rt_sigaction +#endif +#ifdef __NR_rt_sigpending +# define SYS_rt_sigpending __NR_rt_sigpending +#endif +#ifdef __NR_rt_sigprocmask +# define SYS_rt_sigprocmask __NR_rt_sigprocmask +#endif +#ifdef __NR_rt_sigqueueinfo +# define SYS_rt_sigqueueinfo __NR_rt_sigqueueinfo +#endif +#ifdef __NR_rt_sigreturn +# define SYS_rt_sigreturn __NR_rt_sigreturn +#endif +#ifdef __NR_rt_sigsuspend +# define SYS_rt_sigsuspend __NR_rt_sigsuspend +#endif +#ifdef __NR_rt_sigtimedwait +# define SYS_rt_sigtimedwait __NR_rt_sigtimedwait +#endif +#ifdef __NR_rt_sigtimedwait_time64 +# define SYS_rt_sigtimedwait_time64 __NR_rt_sigtimedwait_time64 +#endif +#ifdef __NR_rt_tgsigqueueinfo +# define SYS_rt_tgsigqueueinfo __NR_rt_tgsigqueueinfo +#endif +#ifdef __NR_rtas +# define SYS_rtas __NR_rtas +#endif +#ifdef __NR_s390_guarded_storage +# define SYS_s390_guarded_storage __NR_s390_guarded_storage +#endif +#ifdef __NR_s390_pci_mmio_read +# define SYS_s390_pci_mmio_read __NR_s390_pci_mmio_read +#endif +#ifdef __NR_s390_pci_mmio_write +# define SYS_s390_pci_mmio_write __NR_s390_pci_mmio_write +#endif +#ifdef __NR_s390_runtime_instr +# define SYS_s390_runtime_instr __NR_s390_runtime_instr +#endif +#ifdef __NR_s390_sthyi +# define SYS_s390_sthyi __NR_s390_sthyi +#endif +#ifdef __NR_sched_get_affinity +# define SYS_sched_get_affinity __NR_sched_get_affinity +#endif +#ifdef __NR_sched_get_priority_max +# define SYS_sched_get_priority_max __NR_sched_get_priority_max +#endif +#ifdef __NR_sched_get_priority_min +# define SYS_sched_get_priority_min __NR_sched_get_priority_min +#endif +#ifdef __NR_sched_getaffinity +# define SYS_sched_getaffinity __NR_sched_getaffinity +#endif +#ifdef __NR_sched_getattr +# define SYS_sched_getattr __NR_sched_getattr +#endif +#ifdef __NR_sched_getparam +# define SYS_sched_getparam __NR_sched_getparam +#endif +#ifdef __NR_sched_getscheduler +# define SYS_sched_getscheduler __NR_sched_getscheduler +#endif +#ifdef __NR_sched_rr_get_interval +# define SYS_sched_rr_get_interval __NR_sched_rr_get_interval +#endif +#ifdef __NR_sched_rr_get_interval_time64 +# define SYS_sched_rr_get_interval_time64 __NR_sched_rr_get_interval_time64 +#endif +#ifdef __NR_sched_set_affinity +# define SYS_sched_set_affinity __NR_sched_set_affinity +#endif +#ifdef __NR_sched_setaffinity +# define SYS_sched_setaffinity __NR_sched_setaffinity +#endif +#ifdef __NR_sched_setattr +# define SYS_sched_setattr __NR_sched_setattr +#endif +#ifdef __NR_sched_setparam +# define SYS_sched_setparam __NR_sched_setparam +#endif +#ifdef __NR_sched_setscheduler +# define SYS_sched_setscheduler __NR_sched_setscheduler +#endif +#ifdef __NR_sched_yield +# define SYS_sched_yield __NR_sched_yield +#endif +#ifdef __NR_seccomp +# define SYS_seccomp __NR_seccomp +#endif +#ifdef __NR_select +# define SYS_select __NR_select +#endif +#ifdef __NR_semctl +# define SYS_semctl __NR_semctl +#endif +#ifdef __NR_semget +# define SYS_semget __NR_semget +#endif +#ifdef __NR_semop +# define SYS_semop __NR_semop +#endif +#ifdef __NR_semtimedop +# define SYS_semtimedop __NR_semtimedop +#endif +#ifdef __NR_semtimedop_time64 +# define SYS_semtimedop_time64 __NR_semtimedop_time64 +#endif +#ifdef __NR_send +# define SYS_send __NR_send +#endif +#ifdef __NR_sendfile +# define SYS_sendfile __NR_sendfile +#endif +#ifdef __NR_sendfile64 +# define SYS_sendfile64 __NR_sendfile64 +#endif +#ifdef __NR_sendmmsg +# define SYS_sendmmsg __NR_sendmmsg +#endif +#ifdef __NR_sendmsg +# define SYS_sendmsg __NR_sendmsg +#endif +#ifdef __NR_sendto +# define SYS_sendto __NR_sendto +#endif +#ifdef __NR_set_mempolicy +# define SYS_set_mempolicy __NR_set_mempolicy +#endif +#ifdef __NR_set_mempolicy_home_node +# define SYS_set_mempolicy_home_node __NR_set_mempolicy_home_node +#endif +#ifdef __NR_set_robust_list +# define SYS_set_robust_list __NR_set_robust_list +#endif +#ifdef __NR_set_thread_area +# define SYS_set_thread_area __NR_set_thread_area +#endif +#ifdef __NR_set_tid_address +# define SYS_set_tid_address __NR_set_tid_address +#endif +#ifdef __NR_setdomainname +# define SYS_setdomainname __NR_setdomainname +#endif +#ifdef __NR_setfsgid +# define SYS_setfsgid __NR_setfsgid +#endif +#ifdef __NR_setfsgid32 +# define SYS_setfsgid32 __NR_setfsgid32 +#endif +#ifdef __NR_setfsuid +# define SYS_setfsuid __NR_setfsuid +#endif +#ifdef __NR_setfsuid32 +# define SYS_setfsuid32 __NR_setfsuid32 +#endif +#ifdef __NR_setgid +# define SYS_setgid __NR_setgid +#endif +#ifdef __NR_setgid32 +# define SYS_setgid32 __NR_setgid32 +#endif +#ifdef __NR_setgroups +# define SYS_setgroups __NR_setgroups +#endif +#ifdef __NR_setgroups32 +# define SYS_setgroups32 __NR_setgroups32 +#endif +#ifdef __NR_sethae +# define SYS_sethae __NR_sethae +#endif +#ifdef __NR_sethostname +# define SYS_sethostname __NR_sethostname +#endif +#ifdef __NR_setitimer +# define SYS_setitimer __NR_setitimer +#endif +#ifdef __NR_setns +# define SYS_setns __NR_setns +#endif +#ifdef __NR_setpgid +# define SYS_setpgid __NR_setpgid +#endif +#ifdef __NR_setpgrp +# define SYS_setpgrp __NR_setpgrp +#endif +#ifdef __NR_setpriority +# define SYS_setpriority __NR_setpriority +#endif +#ifdef __NR_setregid +# define SYS_setregid __NR_setregid +#endif +#ifdef __NR_setregid32 +# define SYS_setregid32 __NR_setregid32 +#endif +#ifdef __NR_setresgid +# define SYS_setresgid __NR_setresgid +#endif +#ifdef __NR_setresgid32 +# define SYS_setresgid32 __NR_setresgid32 +#endif +#ifdef __NR_setresuid +# define SYS_setresuid __NR_setresuid +#endif +#ifdef __NR_setresuid32 +# define SYS_setresuid32 __NR_setresuid32 +#endif +#ifdef __NR_setreuid +# define SYS_setreuid __NR_setreuid +#endif +#ifdef __NR_setreuid32 +# define SYS_setreuid32 __NR_setreuid32 +#endif +#ifdef __NR_setrlimit +# define SYS_setrlimit __NR_setrlimit +#endif +#ifdef __NR_setsid +# define SYS_setsid __NR_setsid +#endif +#ifdef __NR_setsockopt +# define SYS_setsockopt __NR_setsockopt +#endif +#ifdef __NR_settimeofday +# define SYS_settimeofday __NR_settimeofday +#endif +#ifdef __NR_setuid +# define SYS_setuid __NR_setuid +#endif +#ifdef __NR_setuid32 +# define SYS_setuid32 __NR_setuid32 +#endif +#ifdef __NR_setxattr +# define SYS_setxattr __NR_setxattr +#endif +#ifdef __NR_sgetmask +# define SYS_sgetmask __NR_sgetmask +#endif +#ifdef __NR_shmat +# define SYS_shmat __NR_shmat +#endif +#ifdef __NR_shmctl +# define SYS_shmctl __NR_shmctl +#endif +#ifdef __NR_shmdt +# define SYS_shmdt __NR_shmdt +#endif +#ifdef __NR_shmget +# define SYS_shmget __NR_shmget +#endif +#ifdef __NR_shutdown +# define SYS_shutdown __NR_shutdown +#endif +#ifdef __NR_sigaction +# define SYS_sigaction __NR_sigaction +#endif +#ifdef __NR_sigaltstack +# define SYS_sigaltstack __NR_sigaltstack +#endif +#ifdef __NR_signal +# define SYS_signal __NR_signal +#endif +#ifdef __NR_signalfd +# define SYS_signalfd __NR_signalfd +#endif +#ifdef __NR_signalfd4 +# define SYS_signalfd4 __NR_signalfd4 +#endif +#ifdef __NR_sigpending +# define SYS_sigpending __NR_sigpending +#endif +#ifdef __NR_sigprocmask +# define SYS_sigprocmask __NR_sigprocmask +#endif +#ifdef __NR_sigreturn +# define SYS_sigreturn __NR_sigreturn +#endif +#ifdef __NR_sigsuspend +# define SYS_sigsuspend __NR_sigsuspend +#endif +#ifdef __NR_socket +# define SYS_socket __NR_socket +#endif +#ifdef __NR_socketcall +# define SYS_socketcall __NR_socketcall +#endif +#ifdef __NR_socketpair +# define SYS_socketpair __NR_socketpair +#endif +#ifdef __NR_spill +# define SYS_spill __NR_spill +#endif +#ifdef __NR_splice +# define SYS_splice __NR_splice +#endif +#ifdef __NR_spu_create +# define SYS_spu_create __NR_spu_create +#endif +#ifdef __NR_spu_run +# define SYS_spu_run __NR_spu_run +#endif +#ifdef __NR_ssetmask +# define SYS_ssetmask __NR_ssetmask +#endif +#ifdef __NR_stat +# define SYS_stat __NR_stat +#endif +#ifdef __NR_stat64 +# define SYS_stat64 __NR_stat64 +#endif +#ifdef __NR_statfs +# define SYS_statfs __NR_statfs +#endif +#ifdef __NR_statfs64 +# define SYS_statfs64 __NR_statfs64 +#endif +#ifdef __NR_statx +# define SYS_statx __NR_statx +#endif +#ifdef __NR_stime +# define SYS_stime __NR_stime +#endif +#ifdef __NR_subpage_prot +# define SYS_subpage_prot __NR_subpage_prot +#endif +#ifdef __NR_swapcontext +# define SYS_swapcontext __NR_swapcontext +#endif +#ifdef __NR_swapoff +# define SYS_swapoff __NR_swapoff +#endif +#ifdef __NR_swapon +# define SYS_swapon __NR_swapon +#endif +#ifdef __NR_switch_endian +# define SYS_switch_endian __NR_switch_endian +#endif +#ifdef __NR_symlink +# define SYS_symlink __NR_symlink +#endif +#ifdef __NR_symlinkat +# define SYS_symlinkat __NR_symlinkat +#endif +#ifdef __NR_sync +# define SYS_sync __NR_sync +#endif +#ifdef __NR_sync_file_range +# define SYS_sync_file_range __NR_sync_file_range +#endif +#ifdef __NR_sync_file_range2 +# define SYS_sync_file_range2 __NR_sync_file_range2 +#endif +#ifdef __NR_syncfs +# define SYS_syncfs __NR_syncfs +#endif +#ifdef __NR_sys_debug_setcontext +# define SYS_sys_debug_setcontext __NR_sys_debug_setcontext +#endif +#ifdef __NR_syscall +# define SYS_syscall __NR_syscall +#endif +#ifdef __NR_syscalls +# define SYS_syscalls __NR_syscalls +#endif +#ifdef __NR_sysfs +# define SYS_sysfs __NR_sysfs +#endif +#ifdef __NR_sysinfo +# define SYS_sysinfo __NR_sysinfo +#endif +#ifdef __NR_syslog +# define SYS_syslog __NR_syslog +#endif +#ifdef __NR_sysmips +# define SYS_sysmips __NR_sysmips +#endif +#ifdef __NR_tee +# define SYS_tee __NR_tee +#endif +#ifdef __NR_tgkill +# define SYS_tgkill __NR_tgkill +#endif +#ifdef __NR_time +# define SYS_time __NR_time +#endif +#ifdef __NR_timer_create +# define SYS_timer_create __NR_timer_create +#endif +#ifdef __NR_timer_delete +# define SYS_timer_delete __NR_timer_delete +#endif +#ifdef __NR_timer_getoverrun +# define SYS_timer_getoverrun __NR_timer_getoverrun +#endif +#ifdef __NR_timer_gettime +# define SYS_timer_gettime __NR_timer_gettime +#endif +#ifdef __NR_timer_gettime64 +# define SYS_timer_gettime64 __NR_timer_gettime64 +#endif +#ifdef __NR_timer_settime +# define SYS_timer_settime __NR_timer_settime +#endif +#ifdef __NR_timer_settime64 +# define SYS_timer_settime64 __NR_timer_settime64 +#endif +#ifdef __NR_timerfd +# define SYS_timerfd __NR_timerfd +#endif +#ifdef __NR_timerfd_create +# define SYS_timerfd_create __NR_timerfd_create +#endif +#ifdef __NR_timerfd_gettime +# define SYS_timerfd_gettime __NR_timerfd_gettime +#endif +#ifdef __NR_timerfd_gettime64 +# define SYS_timerfd_gettime64 __NR_timerfd_gettime64 +#endif +#ifdef __NR_timerfd_settime +# define SYS_timerfd_settime __NR_timerfd_settime +#endif +#ifdef __NR_timerfd_settime64 +# define SYS_timerfd_settime64 __NR_timerfd_settime64 +#endif +#ifdef __NR_times +# define SYS_times __NR_times +#endif +#ifdef __NR_tkill +# define SYS_tkill __NR_tkill +#endif +#ifdef __NR_truncate +# define SYS_truncate __NR_truncate +#endif +#ifdef __NR_truncate64 +# define SYS_truncate64 __NR_truncate64 +#endif +#ifdef __NR_ugetrlimit +# define SYS_ugetrlimit __NR_ugetrlimit +#endif +#ifdef __NR_umask +# define SYS_umask __NR_umask +#endif +#ifdef __NR_umount +# define SYS_umount __NR_umount +#endif +#ifdef __NR_umount2 +# define SYS_umount2 __NR_umount2 +#endif +#ifdef __NR_uname +# define SYS_uname __NR_uname +#endif +#ifdef __NR_unlink +# define SYS_unlink __NR_unlink +#endif +#ifdef __NR_unlinkat +# define SYS_unlinkat __NR_unlinkat +#endif +#ifdef __NR_unshare +# define SYS_unshare __NR_unshare +#endif +#ifdef __NR_uselib +# define SYS_uselib __NR_uselib +#endif +#ifdef __NR_userfaultfd +# define SYS_userfaultfd __NR_userfaultfd +#endif +#ifdef __NR_ustat +# define SYS_ustat __NR_ustat +#endif +#ifdef __NR_utime +# define SYS_utime __NR_utime +#endif +#ifdef __NR_utimensat +# define SYS_utimensat __NR_utimensat +#endif +#ifdef __NR_utimensat_time64 +# define SYS_utimensat_time64 __NR_utimensat_time64 +#endif +#ifdef __NR_utimes +# define SYS_utimes __NR_utimes +#endif +#ifdef __NR_utrap_install +# define SYS_utrap_install __NR_utrap_install +#endif +#ifdef __NR_vfork +# define SYS_vfork __NR_vfork +#endif +#ifdef __NR_vhangup +# define SYS_vhangup __NR_vhangup +#endif +#ifdef __NR_vm86 +# define SYS_vm86 __NR_vm86 +#endif +#ifdef __NR_vm86old +# define SYS_vm86old __NR_vm86old +#endif +#ifdef __NR_vmsplice +# define SYS_vmsplice __NR_vmsplice +#endif +#ifdef __NR_wait4 +# define SYS_wait4 __NR_wait4 +#endif +#ifdef __NR_waitid +# define SYS_waitid __NR_waitid +#endif +#ifdef __NR_waitpid +# define SYS_waitpid __NR_waitpid +#endif +#ifdef __NR_write +# define SYS_write __NR_write +#endif +#ifdef __NR_writev +# define SYS_writev __NR_writev +#endif +#endif /* __MLIBC_SYSCALL_ALIAS_BIT */ diff --git a/lib/mlibc/sysdeps/linux/include/mlibc/thread-entry.hpp b/lib/mlibc/sysdeps/linux/include/mlibc/thread-entry.hpp new file mode 100644 index 0000000..a20cab5 --- /dev/null +++ b/lib/mlibc/sysdeps/linux/include/mlibc/thread-entry.hpp @@ -0,0 +1,12 @@ +#ifndef MLIBC_THREAD_ENTRY + +#include + +extern "C" int __mlibc_spawn_thread(int flags, void *stack, void *pid_out, void *child_tid, void *tcb); +extern "C" void __mlibc_enter_thread(void *entry, void *user_arg); + +namespace mlibc { + void *prepare_stack(void *entry, void *user_arg); +} + +#endif // MLIBC_THREAD_ENTRY diff --git a/lib/mlibc/sysdeps/linux/include/sys/syscall.h b/lib/mlibc/sysdeps/linux/include/sys/syscall.h new file mode 100644 index 0000000..2084103 --- /dev/null +++ b/lib/mlibc/sysdeps/linux/include/sys/syscall.h @@ -0,0 +1,12 @@ +#ifndef _SYS_SYSCALL_H +#define _SYS_SYSCALL_H + +/* On GNU/Linux, this header provides includes __NR_-prefixed syscall numbers, + * and their SYS_ aliases. We defer to kernel headers for the numbers + * (linux-headers, or an autogenerated stub while building), and an + * autogenerated file containing SYS_ defines. + */ +#include +#include + +#endif // _SYS_SYSCALL_H diff --git a/lib/mlibc/sysdeps/linux/include/syscall.h b/lib/mlibc/sysdeps/linux/include/syscall.h new file mode 100644 index 0000000..4c30578 --- /dev/null +++ b/lib/mlibc/sysdeps/linux/include/syscall.h @@ -0,0 +1 @@ +#include diff --git a/lib/mlibc/sysdeps/linux/meson.build b/lib/mlibc/sysdeps/linux/meson.build new file mode 100644 index 0000000..0809237 --- /dev/null +++ b/lib/mlibc/sysdeps/linux/meson.build @@ -0,0 +1,143 @@ +rtdl_dso_sources += files( + host_machine.cpu_family() / 'arch-syscall.cpp', + 'generic/sysdeps.cpp', +) + +linux_include_dirs = [ + include_directories(host_machine.cpu_family()), + include_directories('include-internal/'), +] + +rtdl_include_dirs += linux_include_dirs +libc_include_dirs += linux_include_dirs +libc_sources += files( + host_machine.cpu_family() / 'signals.S', + host_machine.cpu_family() / 'arch-syscall.cpp', + 'generic/entry.cpp', + 'generic/sysdeps.cpp', +) + +if not disable_posix_option + libc_sources += files( + 'generic/thread.cpp', + host_machine.cpu_family() / 'cp_syscall.S', + host_machine.cpu_family() / 'thread_entry.S' + ) +endif + +if not no_headers + install_headers( + 'include/abi-bits/auxv.h', + 'include/abi-bits/seek-whence.h', + 'include/abi-bits/vm-flags.h', + 'include/abi-bits/errno.h', + 'include/abi-bits/fcntl.h', + 'include/abi-bits/in.h', + 'include/abi-bits/stat.h', + 'include/abi-bits/signal.h', + 'include/abi-bits/reboot.h', + 'include/abi-bits/resource.h', + 'include/abi-bits/socket.h', + 'include/abi-bits/termios.h', + 'include/abi-bits/time.h', + 'include/abi-bits/blkcnt_t.h', + 'include/abi-bits/blksize_t.h', + 'include/abi-bits/dev_t.h', + 'include/abi-bits/gid_t.h', + 'include/abi-bits/ino_t.h', + 'include/abi-bits/mode_t.h', + 'include/abi-bits/nlink_t.h', + 'include/abi-bits/pid_t.h', + 'include/abi-bits/uid_t.h', + 'include/abi-bits/access.h', + 'include/abi-bits/wait.h', + 'include/abi-bits/limits.h', + 'include/abi-bits/utsname.h', + 'include/abi-bits/ptrace.h', + 'include/abi-bits/vt.h', + 'include/abi-bits/ptrace.h', + 'include/abi-bits/poll.h', + 'include/abi-bits/epoll.h', + 'include/abi-bits/packet.h', + 'include/abi-bits/inotify.h', + 'include/abi-bits/clockid_t.h', + 'include/abi-bits/shm.h', + 'include/abi-bits/mqueue.h', + 'include/abi-bits/suseconds_t.h', + 'include/abi-bits/fsfilcnt_t.h', + 'include/abi-bits/fsblkcnt_t.h', + 'include/abi-bits/socklen_t.h', + 'include/abi-bits/statfs.h', + 'include/abi-bits/statvfs.h', + 'include/abi-bits/ioctls.h', + 'include/abi-bits/xattr.h', + 'include/abi-bits/msg.h', + subdir: 'abi-bits', + follow_symlinks: true + ) + + install_headers('include/syscall.h') + install_headers('include/sys/syscall.h', subdir: 'sys') + install_headers( + 'include/bits/syscall.h', + 'include/bits/syscall_aliases.h', + subdir: 'bits' + ) +endif + +if not headers_only + crt = custom_target('crt1', + build_by_default: true, + command: c_compiler.cmd_array() + ['-c', '-o', '@OUTPUT@', '@INPUT@'], + input: host_machine.cpu_family() / 'crt-src/crt1.S', + output: 'crt1.o', + install: true, + install_dir: get_option('libdir') + ) + + crt_pie = custom_target('Scrt1', + build_by_default: true, + command: c_compiler.cmd_array() + ['-fPIE', '-c', '-o', '@OUTPUT@', '@INPUT@'], + input: host_machine.cpu_family() / 'crt-src/Scrt1.S', + output: 'Scrt1.o', + install: true, + install_dir: get_option('libdir') + ) + + custom_target('crti', + build_by_default: true, + command: c_compiler.cmd_array() + ['-c', '-o', '@OUTPUT@', '@INPUT@'], + input: host_machine.cpu_family() / 'crt-src/crti.S', + output: 'crti.o', + install: true, + install_dir: get_option('libdir') + ) + + custom_target('crtn', + build_by_default: true, + command: c_compiler.cmd_array() + ['-c', '-o', '@OUTPUT@', '@INPUT@'], + input: host_machine.cpu_family() / 'crt-src/crtn.S', + output: 'crtn.o', + install: true, + install_dir: get_option('libdir') + ) + + wrapper_conf = configuration_data() + wrapper_conf.set('LIBDIR', get_option('libdir')) + wrapper_conf.set('PREFIX', get_option('prefix')) + specs = configure_file(input: 'mlibc-gcc.specs.in', + output: 'mlibc-gcc.specs', + configuration: wrapper_conf) + + wrapper_script = configure_file(input: 'mlibc-gcc.in', + output: 'mlibc-gcc', + configuration: wrapper_conf) + + install_data(specs, + install_dir: get_option('libdir') + ) + + install_data(wrapper_script, + install_dir: get_option('bindir') + ) +endif diff --git a/lib/mlibc/sysdeps/linux/mlibc-gcc.in b/lib/mlibc/sysdeps/linux/mlibc-gcc.in new file mode 100755 index 0000000..6236bd6 --- /dev/null +++ b/lib/mlibc/sysdeps/linux/mlibc-gcc.in @@ -0,0 +1,2 @@ +#!/bin/sh +exec "${REALGCC:-gcc}" "$@" -specs "@PREFIX@/@LIBDIR@/mlibc-gcc.specs" diff --git a/lib/mlibc/sysdeps/linux/mlibc-gcc.specs.in b/lib/mlibc/sysdeps/linux/mlibc-gcc.specs.in new file mode 100644 index 0000000..4304c4d --- /dev/null +++ b/lib/mlibc/sysdeps/linux/mlibc-gcc.specs.in @@ -0,0 +1,32 @@ +%rename cpp_options old_cpp_options + +*cpp_options: +-nostdinc -isystem @PREFIX@/include -isystem include%s %(old_cpp_options) + +*cc1: +%(cc1_cpu) -nostdinc -isystem @PREFIX@/include -isystem include%s + +*link_libgcc: +-L@PREFIX@/@LIBDIR@ -L .%s + +*libgcc: +libgcc.a%s %:if-exists(libgcc_eh.a%s) + +*startfile: +%{!shared: @PREFIX@/@LIBDIR@/Scrt1.o} @PREFIX@/@LIBDIR@/crti.o crtbeginS.o%s + +*endfile: +crtendS.o%s @PREFIX@/@LIBDIR@/crtn.o + +*link: +-dynamic-linker @PREFIX@/@LIBDIR@/ld.so -rpath @PREFIX@/@LIBDIR@ -nostdlib %{shared:-shared} %{static:-static} %{rdynamic:-export-dynamic} + +*esp_link: + + +*esp_options: + + +*esp_cpp_options: + + diff --git a/lib/mlibc/sysdeps/linux/riscv64/arch-syscall.cpp b/lib/mlibc/sysdeps/linux/riscv64/arch-syscall.cpp new file mode 100644 index 0000000..18ac6b0 --- /dev/null +++ b/lib/mlibc/sysdeps/linux/riscv64/arch-syscall.cpp @@ -0,0 +1,117 @@ +#include +#include + +using sc_word_t = __sc_word_t; + +sc_word_t __do_syscall0(long sc) { + register int sc_reg asm("a7") = sc; + register sc_word_t ret asm("a0"); + asm volatile ("ecall" : "=r"(ret) : "r"(sc_reg) : "memory", "a1"); + return ret; +} + +sc_word_t __do_syscall1(long sc, + sc_word_t arg1) { + register int sc_reg asm("a7") = sc; + register sc_word_t arg1_reg asm("a0") = arg1; + register sc_word_t ret asm("a0"); + asm volatile ("ecall" : "=r"(ret) : + "r"(sc_reg), + "r"(arg1_reg) + : "memory", "a1"); + return ret; +} + +sc_word_t __do_syscall2(long sc, + sc_word_t arg1, sc_word_t arg2) { + register int sc_reg asm("a7") = sc; + register sc_word_t arg1_reg asm("a0") = arg1; + register sc_word_t arg2_reg asm("a1") = arg2; + register sc_word_t ret asm("a0"); + asm volatile ("ecall" : "=r"(ret) : + "r"(sc_reg), + "r"(arg1_reg), + "r"(arg2_reg) + : "memory"); + return ret; +} + +sc_word_t __do_syscall3(long sc, + sc_word_t arg1, sc_word_t arg2, sc_word_t arg3) { + register int sc_reg asm("a7") = sc; + register sc_word_t arg1_reg asm("a0") = arg1; + register sc_word_t arg2_reg asm("a1") = arg2; + register sc_word_t arg3_reg asm("a2") = arg3; + register sc_word_t ret asm("a0"); + asm volatile ("ecall" : "=r"(ret) : + "r"(sc_reg), + "r"(arg1_reg), + "r"(arg2_reg), + "r"(arg3_reg) + : "memory"); + return ret; +} + +sc_word_t __do_syscall4(long sc, + sc_word_t arg1, sc_word_t arg2, sc_word_t arg3, + sc_word_t arg4) { + register int sc_reg asm("a7") = sc; + register sc_word_t arg1_reg asm("a0") = arg1; + register sc_word_t arg2_reg asm("a1") = arg2; + register sc_word_t arg3_reg asm("a2") = arg3; + register sc_word_t arg4_reg asm("a3") = arg4; + register sc_word_t ret asm("a0"); + asm volatile ("ecall" : "=r"(ret) : + "r"(sc_reg), + "r"(arg1_reg), + "r"(arg2_reg), + "r"(arg3_reg), + "r"(arg4_reg) + : "memory"); + return ret; +} + +sc_word_t __do_syscall5(long sc, + sc_word_t arg1, sc_word_t arg2, sc_word_t arg3, + sc_word_t arg4, sc_word_t arg5) { + register int sc_reg asm("a7") = sc; + register sc_word_t arg1_reg asm("a0") = arg1; + register sc_word_t arg2_reg asm("a1") = arg2; + register sc_word_t arg3_reg asm("a2") = arg3; + register sc_word_t arg4_reg asm("a3") = arg4; + register sc_word_t arg5_reg asm("a4") = arg5; + register sc_word_t ret asm("a0"); + asm volatile ("ecall" : "=r"(ret) : + "r"(sc_reg), + "r"(arg1_reg), + "r"(arg2_reg), + "r"(arg3_reg), + "r"(arg4_reg), + "r"(arg5_reg) + : "memory"); + return ret; +} + +sc_word_t __do_syscall6(long sc, + sc_word_t arg1, sc_word_t arg2, sc_word_t arg3, + sc_word_t arg4, sc_word_t arg5, sc_word_t arg6) { + register int sc_reg asm("a7") = sc; + register sc_word_t arg1_reg asm("a0") = arg1; + register sc_word_t arg2_reg asm("a1") = arg2; + register sc_word_t arg3_reg asm("a2") = arg3; + register sc_word_t arg4_reg asm("a3") = arg4; + register sc_word_t arg5_reg asm("a4") = arg5; + register sc_word_t arg6_reg asm("a5") = arg6; + register sc_word_t ret asm("a0"); + asm volatile ("ecall" : "=r"(ret) : + "r"(sc_reg), + "r"(arg1_reg), + "r"(arg2_reg), + "r"(arg3_reg), + "r"(arg4_reg), + "r"(arg5_reg), + "r"(arg6_reg) + : "memory" + ); + return ret; +} diff --git a/lib/mlibc/sysdeps/linux/riscv64/cp_syscall.S b/lib/mlibc/sysdeps/linux/riscv64/cp_syscall.S new file mode 100644 index 0000000..8d3175d --- /dev/null +++ b/lib/mlibc/sysdeps/linux/riscv64/cp_syscall.S @@ -0,0 +1,30 @@ +.section .text +.global __mlibc_do_asm_cp_syscall +.global __mlibc_syscall_begin +.global __mlibc_syscall_end +.type __mlibc_do_asm_cp_syscall, "function" +__mlibc_do_asm_cp_syscall: + sd a7, -8(sp) + mv a7, a0 + mv a0, a1 + mv a1, a2 + mv a2, a3 + mv a3, a4 + mv a4, a5 + mv a5, a6 + ld a6, -8(sp) // a7 + lw t0, -96(tp) // Tcb::cancelBits. See asserts in tcb.hpp. +__mlibc_syscall_begin: + // tcbCancelEnableBit && tcbCancelTriggerBit + li t1, (1 << 0) | (1 << 2) + and t0, t0, t1 + beq t0, t1, cancel + ecall +__mlibc_syscall_end: + ret + +cancel: + call __mlibc_do_cancel + unimp +.section .note.GNU-stack,"",%progbits + diff --git a/lib/mlibc/sysdeps/linux/riscv64/crt-src/Scrt1.S b/lib/mlibc/sysdeps/linux/riscv64/crt-src/Scrt1.S new file mode 100644 index 0000000..9ee8625 --- /dev/null +++ b/lib/mlibc/sysdeps/linux/riscv64/crt-src/Scrt1.S @@ -0,0 +1,18 @@ +.section .text +.global _start +_start: + .weak __global_pointer$ + .hidden __global_pointer$ + .option push + .option norelax + lla gp, __global_pointer$ + .option pop + + mv a0, sp + la a1, main + call __mlibc_entry@plt + unimp + + +.section .note.GNU-stack,"",%progbits + diff --git a/lib/mlibc/sysdeps/linux/riscv64/crt-src/crt1.S b/lib/mlibc/sysdeps/linux/riscv64/crt-src/crt1.S new file mode 100644 index 0000000..16c79d6 --- /dev/null +++ b/lib/mlibc/sysdeps/linux/riscv64/crt-src/crt1.S @@ -0,0 +1,15 @@ +.section .text +.global _start +_start: + .weak __global_pointer$ + .hidden __global_pointer$ + .option push + .option norelax + lla gp, __global_pointer$ + .option pop + + mv a0, sp + la a1, main + call __mlibc_entry +.section .note.GNU-stack,"",%progbits + diff --git a/lib/mlibc/sysdeps/linux/riscv64/crt-src/crti.S b/lib/mlibc/sysdeps/linux/riscv64/crt-src/crti.S new file mode 100644 index 0000000..69f23ea --- /dev/null +++ b/lib/mlibc/sysdeps/linux/riscv64/crt-src/crti.S @@ -0,0 +1,11 @@ +.section .init +.global _init +_init: + unimp + +.section .fini +.global _fini +_fini: + unimp +.section .note.GNU-stack,"",%progbits + diff --git a/lib/mlibc/sysdeps/linux/riscv64/crt-src/crtn.S b/lib/mlibc/sysdeps/linux/riscv64/crt-src/crtn.S new file mode 100644 index 0000000..525efd6 --- /dev/null +++ b/lib/mlibc/sysdeps/linux/riscv64/crt-src/crtn.S @@ -0,0 +1,7 @@ +.section .init + unimp + +.section .fini + unimp +.section .note.GNU-stack,"",%progbits + diff --git a/lib/mlibc/sysdeps/linux/riscv64/signals.S b/lib/mlibc/sysdeps/linux/riscv64/signals.S new file mode 100644 index 0000000..7769043 --- /dev/null +++ b/lib/mlibc/sysdeps/linux/riscv64/signals.S @@ -0,0 +1,12 @@ +.section .text + +.global __mlibc_signal_restore +.type __mlibc_signal_restore, @function +__mlibc_signal_restore: +.global __mlibc_signal_restore_rt +.type __mlibc_signal_restore_rt, @function +__mlibc_signal_restore_rt: + li a7, 139 + ecall +.section .note.GNU-stack,"",%progbits + diff --git a/lib/mlibc/sysdeps/linux/riscv64/syscallnos.h b/lib/mlibc/sysdeps/linux/riscv64/syscallnos.h new file mode 100644 index 0000000..a5a11bb --- /dev/null +++ b/lib/mlibc/sysdeps/linux/riscv64/syscallnos.h @@ -0,0 +1,314 @@ +#ifndef __MLIBC_SYSCALLNOS_h +#define __MLIBC_SYSCALLNOS_h +/* This file is autogenerated. Don't bother. */ +/* Generator script: sysdeps/linux/update-syscall-list.py. */ +#define __NR_io_setup 0 +#define __NR_io_destroy 1 +#define __NR_io_submit 2 +#define __NR_io_cancel 3 +#define __NR_io_getevents 4 +#define __NR_setxattr 5 +#define __NR_lsetxattr 6 +#define __NR_fsetxattr 7 +#define __NR_getxattr 8 +#define __NR_lgetxattr 9 +#define __NR_fgetxattr 10 +#define __NR_listxattr 11 +#define __NR_llistxattr 12 +#define __NR_flistxattr 13 +#define __NR_removexattr 14 +#define __NR_lremovexattr 15 +#define __NR_fremovexattr 16 +#define __NR_getcwd 17 +#define __NR_lookup_dcookie 18 +#define __NR_eventfd2 19 +#define __NR_epoll_create1 20 +#define __NR_epoll_ctl 21 +#define __NR_epoll_pwait 22 +#define __NR_dup 23 +#define __NR_dup3 24 +#define __NR_fcntl 25 +#define __NR_inotify_init1 26 +#define __NR_inotify_add_watch 27 +#define __NR_inotify_rm_watch 28 +#define __NR_ioctl 29 +#define __NR_ioprio_set 30 +#define __NR_ioprio_get 31 +#define __NR_flock 32 +#define __NR_mknodat 33 +#define __NR_mkdirat 34 +#define __NR_unlinkat 35 +#define __NR_symlinkat 36 +#define __NR_linkat 37 +#define __NR_umount2 39 +#define __NR_mount 40 +#define __NR_pivot_root 41 +#define __NR_nfsservctl 42 +#define __NR_statfs 43 +#define __NR_fstatfs 44 +#define __NR_truncate 45 +#define __NR_ftruncate 46 +#define __NR_fallocate 47 +#define __NR_faccessat 48 +#define __NR_chdir 49 +#define __NR_fchdir 50 +#define __NR_chroot 51 +#define __NR_fchmod 52 +#define __NR_fchmodat 53 +#define __NR_fchownat 54 +#define __NR_fchown 55 +#define __NR_openat 56 +#define __NR_close 57 +#define __NR_vhangup 58 +#define __NR_pipe2 59 +#define __NR_quotactl 60 +#define __NR_getdents64 61 +#define __NR_lseek 62 +#define __NR_read 63 +#define __NR_write 64 +#define __NR_readv 65 +#define __NR_writev 66 +#define __NR_pread64 67 +#define __NR_pwrite64 68 +#define __NR_preadv 69 +#define __NR_pwritev 70 +#define __NR_sendfile 71 +#define __NR_pselect6 72 +#define __NR_ppoll 73 +#define __NR_signalfd4 74 +#define __NR_vmsplice 75 +#define __NR_splice 76 +#define __NR_tee 77 +#define __NR_readlinkat 78 +#define __NR_newfstatat 79 +#define __NR_fstat 80 +#define __NR_sync 81 +#define __NR_fsync 82 +#define __NR_fdatasync 83 +#define __NR_sync_file_range 84 +#define __NR_timerfd_create 85 +#define __NR_timerfd_settime 86 +#define __NR_timerfd_gettime 87 +#define __NR_utimensat 88 +#define __NR_acct 89 +#define __NR_capget 90 +#define __NR_capset 91 +#define __NR_personality 92 +#define __NR_exit 93 +#define __NR_exit_group 94 +#define __NR_waitid 95 +#define __NR_set_tid_address 96 +#define __NR_unshare 97 +#define __NR_futex 98 +#define __NR_set_robust_list 99 +#define __NR_get_robust_list 100 +#define __NR_nanosleep 101 +#define __NR_getitimer 102 +#define __NR_setitimer 103 +#define __NR_kexec_load 104 +#define __NR_init_module 105 +#define __NR_delete_module 106 +#define __NR_timer_create 107 +#define __NR_timer_gettime 108 +#define __NR_timer_getoverrun 109 +#define __NR_timer_settime 110 +#define __NR_timer_delete 111 +#define __NR_clock_settime 112 +#define __NR_clock_gettime 113 +#define __NR_clock_getres 114 +#define __NR_clock_nanosleep 115 +#define __NR_syslog 116 +#define __NR_ptrace 117 +#define __NR_sched_setparam 118 +#define __NR_sched_setscheduler 119 +#define __NR_sched_getscheduler 120 +#define __NR_sched_getparam 121 +#define __NR_sched_setaffinity 122 +#define __NR_sched_getaffinity 123 +#define __NR_sched_yield 124 +#define __NR_sched_get_priority_max 125 +#define __NR_sched_get_priority_min 126 +#define __NR_sched_rr_get_interval 127 +#define __NR_restart_syscall 128 +#define __NR_kill 129 +#define __NR_tkill 130 +#define __NR_tgkill 131 +#define __NR_sigaltstack 132 +#define __NR_rt_sigsuspend 133 +#define __NR_rt_sigaction 134 +#define __NR_rt_sigprocmask 135 +#define __NR_rt_sigpending 136 +#define __NR_rt_sigtimedwait 137 +#define __NR_rt_sigqueueinfo 138 +#define __NR_rt_sigreturn 139 +#define __NR_setpriority 140 +#define __NR_getpriority 141 +#define __NR_reboot 142 +#define __NR_setregid 143 +#define __NR_setgid 144 +#define __NR_setreuid 145 +#define __NR_setuid 146 +#define __NR_setresuid 147 +#define __NR_getresuid 148 +#define __NR_setresgid 149 +#define __NR_getresgid 150 +#define __NR_setfsuid 151 +#define __NR_setfsgid 152 +#define __NR_times 153 +#define __NR_setpgid 154 +#define __NR_getpgid 155 +#define __NR_getsid 156 +#define __NR_setsid 157 +#define __NR_getgroups 158 +#define __NR_setgroups 159 +#define __NR_uname 160 +#define __NR_sethostname 161 +#define __NR_setdomainname 162 +#define __NR_getrlimit 163 +#define __NR_setrlimit 164 +#define __NR_getrusage 165 +#define __NR_umask 166 +#define __NR_prctl 167 +#define __NR_getcpu 168 +#define __NR_gettimeofday 169 +#define __NR_settimeofday 170 +#define __NR_adjtimex 171 +#define __NR_getpid 172 +#define __NR_getppid 173 +#define __NR_getuid 174 +#define __NR_geteuid 175 +#define __NR_getgid 176 +#define __NR_getegid 177 +#define __NR_gettid 178 +#define __NR_sysinfo 179 +#define __NR_mq_open 180 +#define __NR_mq_unlink 181 +#define __NR_mq_timedsend 182 +#define __NR_mq_timedreceive 183 +#define __NR_mq_notify 184 +#define __NR_mq_getsetattr 185 +#define __NR_msgget 186 +#define __NR_msgctl 187 +#define __NR_msgrcv 188 +#define __NR_msgsnd 189 +#define __NR_semget 190 +#define __NR_semctl 191 +#define __NR_semtimedop 192 +#define __NR_semop 193 +#define __NR_shmget 194 +#define __NR_shmctl 195 +#define __NR_shmat 196 +#define __NR_shmdt 197 +#define __NR_socket 198 +#define __NR_socketpair 199 +#define __NR_bind 200 +#define __NR_listen 201 +#define __NR_accept 202 +#define __NR_connect 203 +#define __NR_getsockname 204 +#define __NR_getpeername 205 +#define __NR_sendto 206 +#define __NR_recvfrom 207 +#define __NR_setsockopt 208 +#define __NR_getsockopt 209 +#define __NR_shutdown 210 +#define __NR_sendmsg 211 +#define __NR_recvmsg 212 +#define __NR_readahead 213 +#define __NR_brk 214 +#define __NR_munmap 215 +#define __NR_mremap 216 +#define __NR_add_key 217 +#define __NR_request_key 218 +#define __NR_keyctl 219 +#define __NR_clone 220 +#define __NR_execve 221 +#define __NR_mmap 222 +#define __NR_fadvise64 223 +#define __NR_swapon 224 +#define __NR_swapoff 225 +#define __NR_mprotect 226 +#define __NR_msync 227 +#define __NR_mlock 228 +#define __NR_munlock 229 +#define __NR_mlockall 230 +#define __NR_munlockall 231 +#define __NR_mincore 232 +#define __NR_madvise 233 +#define __NR_remap_file_pages 234 +#define __NR_mbind 235 +#define __NR_get_mempolicy 236 +#define __NR_set_mempolicy 237 +#define __NR_migrate_pages 238 +#define __NR_move_pages 239 +#define __NR_rt_tgsigqueueinfo 240 +#define __NR_perf_event_open 241 +#define __NR_accept4 242 +#define __NR_recvmmsg 243 +#define __NR_arch_specific_syscall 244 +#define __NR_riscv_hwprobe 258 +#define __NR_riscv_flush_icache 259 +#define __NR_wait4 260 +#define __NR_prlimit64 261 +#define __NR_fanotify_init 262 +#define __NR_fanotify_mark 263 +#define __NR_name_to_handle_at 264 +#define __NR_open_by_handle_at 265 +#define __NR_clock_adjtime 266 +#define __NR_syncfs 267 +#define __NR_setns 268 +#define __NR_sendmmsg 269 +#define __NR_process_vm_readv 270 +#define __NR_process_vm_writev 271 +#define __NR_kcmp 272 +#define __NR_finit_module 273 +#define __NR_sched_setattr 274 +#define __NR_sched_getattr 275 +#define __NR_renameat2 276 +#define __NR_seccomp 277 +#define __NR_getrandom 278 +#define __NR_memfd_create 279 +#define __NR_bpf 280 +#define __NR_execveat 281 +#define __NR_userfaultfd 282 +#define __NR_membarrier 283 +#define __NR_mlock2 284 +#define __NR_copy_file_range 285 +#define __NR_preadv2 286 +#define __NR_pwritev2 287 +#define __NR_pkey_mprotect 288 +#define __NR_pkey_alloc 289 +#define __NR_pkey_free 290 +#define __NR_statx 291 +#define __NR_io_pgetevents 292 +#define __NR_rseq 293 +#define __NR_kexec_file_load 294 +#define __NR_pidfd_send_signal 424 +#define __NR_io_uring_setup 425 +#define __NR_io_uring_enter 426 +#define __NR_io_uring_register 427 +#define __NR_open_tree 428 +#define __NR_move_mount 429 +#define __NR_fsopen 430 +#define __NR_fsconfig 431 +#define __NR_fsmount 432 +#define __NR_fspick 433 +#define __NR_pidfd_open 434 +#define __NR_clone3 435 +#define __NR_close_range 436 +#define __NR_openat2 437 +#define __NR_pidfd_getfd 438 +#define __NR_faccessat2 439 +#define __NR_process_madvise 440 +#define __NR_epoll_pwait2 441 +#define __NR_mount_setattr 442 +#define __NR_quotactl_fd 443 +#define __NR_landlock_create_ruleset 444 +#define __NR_landlock_add_rule 445 +#define __NR_landlock_restrict_self 446 +#define __NR_memfd_secret 447 +#define __NR_process_mrelease 448 +#define __NR_futex_waitv 449 +#define __NR_set_mempolicy_home_node 450 +#define __NR_syscalls 451 +#endif /* __MLIBC_SYSCALLNOS_h */ diff --git a/lib/mlibc/sysdeps/linux/riscv64/thread_entry.S b/lib/mlibc/sysdeps/linux/riscv64/thread_entry.S new file mode 100644 index 0000000..fe170fa --- /dev/null +++ b/lib/mlibc/sysdeps/linux/riscv64/thread_entry.S @@ -0,0 +1,29 @@ +.section .text +.global __mlibc_spawn_thread +.type __mlibc_spawn_thread, "function" +__mlibc_spawn_thread: + // __mlibc_spawn_thread(flags, stack, pid_out, child_tid, tls) + // a0, a1, a2, a3, a4 + // syscall(NR_clone, flags, stack, ptid, tls, ctid) + // a7, a0, a1, a2, a3, a4 + + // Swap a3 <-> a4 + mv a5, a4 + mv a4, a3 + mv a3, a5 + + li a7, 220 // NR_clone + ecall + bnez a0, .parent + + ld a0, 0(sp) + ld a1, 8(sp) + addi sp, sp, 8 + andi sp, sp, -16 + call __mlibc_enter_thread + unimp + +.parent: + ret +.section .note.GNU-stack,"",%progbits + diff --git a/lib/mlibc/sysdeps/linux/update-syscall-list.py b/lib/mlibc/sysdeps/linux/update-syscall-list.py new file mode 100755 index 0000000..58825f7 --- /dev/null +++ b/lib/mlibc/sysdeps/linux/update-syscall-list.py @@ -0,0 +1,332 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: MIT + +import argparse +import hashlib +import io +import json +import logging +import os +import os.path as path +import pathlib +import subprocess +import tarfile +import tempfile +import urllib.request as urr +from dataclasses import dataclass + +KERNEL_RELEASES = "https://www.kernel.org/releases.json" +NR_PREFIX = "__NR_" +logging.basicConfig(level=logging.DEBUG) +LOGGER = logging.getLogger(__name__) + +# ADD NEW ARCHITECTURES HERE: these should match directory names in Linuxes arch/ +# directory or the second element of one of the harnesses below +WANTED_ARCHES = ["riscv64", "x86_64", "arm64", "i386"] +# How to translate from Linux arch directory names to gnutools architecture fields +LINUX_GNU_TRANSLATION = { + "arm64": "aarch64", + "i386": "x86", +} + +argp = argparse.ArgumentParser() +argp.add_argument("kver", help="Kernel version to download", default="latest") + + +@dataclass +class Kernel: + version: str + srchash: str + srcdir: pathlib.Path + + +@dataclass +class Context: + dirpath: pathlib.Path + + +def run(args: list[str], **kwargs): + LOGGER.debug("running %s", args) + subprocess.check_call(args, **kwargs) + + +def collect(args: list[str], **kwargs): + LOGGER.debug("running %s (kw: %s)", args, kwargs) + kwargs.setdefault("text", True) + return subprocess.check_output(args, **kwargs) + + +def fetch_kernel(ctx: Context, kver: str) -> Kernel: + LOGGER.debug("fetching %s", KERNEL_RELEASES) + with urr.urlopen(KERNEL_RELEASES) as f: + if f.status != 200: + LOGGER.error("meta fetch failed: %s", f) + raise RuntimeError("failed to get kernel meta") + metadata = json.load(f) + + if kver == "latest": + kver = metadata["latest_stable"]["version"] + + LOGGER.debug("figured out kernel version: %s", kver) + + for rel in metadata["releases"]: + if rel["version"] == kver: + kernel_release = rel + break + else: + raise RuntimeError("failed to find kver " + kver) + + kurl = kernel_release["source"] + LOGGER.debug("kernel src url: %s", kurl) + source_path = ctx.dirpath / ("source.tar" + path.splitext(kurl)[1]) + + with urr.urlopen(kurl) as f, open(source_path, "wb") as g: + if f.status != 200: + LOGGER.error("ksrc fetch failed: %s", f) + raise RuntimeError("failed to get kernel source") + + hasher = hashlib.blake2b() + while buf := f.read(16 * 1024): + hasher.update(buf) + g.write(buf) + + srchash = hasher.hexdigest() + srcpath = ctx.dirpath / "src" + + with tarfile.open(source_path) as srctar: + memb: tarfile.TarInfo + for memb in srctar: + if not memb.name.startswith("linux-"): + raise RuntimeError( + "malformed tar member in %s (%s): %s has bad prefix".format( + kurl, srchash, memb.name + ) + ) + memb.name = "./" + memb.name[memb.name.find("/") + 1 :] + srctar.extract(memb, path=srcpath) + + return Kernel( + version=kver, + srchash=srchash, + srcdir=srcpath, + ) + + +def run_harness(ctx: Context, kernel: Kernel, harness: (str, str)) -> dict[str, int]: + LOGGER.debug("running harness %s", harness) + (archdir, arch, defines) = harness + flags = [f"-D{x}" for x in defines] + archout = ctx.dirpath / "headers" / archdir + if not archout.exists(): + run( + [ + "make", + "-sC", + kernel.srcdir, + f"ARCH={archdir}", + f"O={archout}", + "headers_install", + ] + ) + + hdrdir = archout / "usr/include" + callset = set() + for x in collect( + ["gcc", "-E", "-dM", "-I", hdrdir, *flags, "-"], input="#include " + ).splitlines(): + x = x.split(maxsplit=2) + if len(x) < 2 or x[0] != "#define": + # skip invalid lines + continue + + defname = x[1] + if not defname.startswith(NR_PREFIX): + # not a syscall + continue + + defname = defname[len(NR_PREFIX) :] + + if ( + "SYSCALL" in defname + or defname.startswith("available") + or defname.startswith("reserved") + or defname.startswith("unused") + ): + continue + + # dead syscalls + if defname in [ + "Linux", + "afs_syscall", + "break", + "ftime", + "gtty", + "lock", + "mpx", + "oldwait4", + "prof", + "profil", + "putpmsg", + "security", + "stty", + "tuxcall", + "ulimit", + "vserver", + "arm_sync_file_range", + "utimesat", + "ni_syscall", + "xtensa", + ]: + continue + callset.add(defname) + + # alright, we have the set of all syscalls, time to produce their numbers + syscall_dumper = """ +/* my sincerest apologies */ +#include +""" + + for x in defines: + syscall_dumper += "#define {}\n".format(x.replace("=", " ")) + + syscall_dumper += """ +#include + +int main() { + puts("{"); + """ + + comma = "" + for x in callset: + syscall_dumper += 'printf("{comma}\\"{sc}\\": %d\\n", {pfx}{sc});\n '.format( + sc=x, comma=comma, pfx=NR_PREFIX + ) + comma = "," + + syscall_dumper += """ + puts("}"); +} +""" + + dumper = archout / "dumper" + with tempfile.NamedTemporaryFile(suffix=".c") as src: + src.write(syscall_dumper.encode()) + run(["gcc", "-o", dumper, "-I", hdrdir, src.name]) + return json.loads(collect([dumper])) + + +def main(ctx: Context): + args = argp.parse_args() + kernel = fetch_kernel(ctx, args.kver) + + LOGGER.info("got kernel version %s (%s)", kernel.version, kernel.srchash) + + archlist = os.listdir(kernel.srcdir / "arch") + archlist.remove("Kconfig") + archlist.remove("um") + + # harnesses converted from + # https://github.com/hrw/syscalls-table/blob/c638834d9b5d71bb40a555755ea07735cace58f2/do_all_tables.sh + # (arch_dirname, archname, list[defines]) + harnesses: (str, str, list[str]) + harnesses = [ + (arch,) + x + for arch in archlist + if not arch.startswith(".") + for x in { + # arch specific overrides + # format: (archname, list[defines]), gets prefixed with archdir outside + "arm": [ + ("armoabi", []), + ("arm", ["__ARM_EABI_"]), + ], + "loongarch": [ + ("loongarch64", ["_LOONGARCH_SZLONG=64"]), + ], + "mips": [ + ("mipso32", ["_MIPS_SIM=_MIPS_SIM_ABI32"]), + ("mips64n32", ["_MIPS_SIM=_MIPS_SIM_NABI32"]), + ("mips64", ["_MIPS_SIM=_MIPS_SIM_ABI64"]), + ], + "powerpc": [ + ("powerpc", []), + ("powerpc64", []), + ], + "riscv": [ + ("riscv32", ["__SIZEOF_POINTER__=4"]), + ("riscv64", ["__LP64__"]), + ], + "s390": [ + ("s390", []), + ("s390x", []), + ], + "sparc": [ + ("sparc", ["__32bit_syscall_numbers__"]), + ("sparc64", ["__arch64__"]), + ], + "tile": [ + ("tile", []), + ("tile64", ["__LP64__", "__tilegx__"]), + ], + "x86": [ + ("i386", ["__i386__"]), + ("x32", ["__ILP32__"]), + ("x86_64", ["__LP64__"]), + ], + }.get(arch, [(arch, [])]) + ] + + syscall_set = set() + + for x in harnesses: + syscalls = run_harness(ctx, kernel, x) + syscall_set |= syscalls.keys() + + wanted_arch = x[1] + if wanted_arch not in WANTED_ARCHES: + continue + + wanted_arch = LINUX_GNU_TRANSLATION.get(wanted_arch, wanted_arch) + + pathlib.Path(wanted_arch).mkdir(exist_ok=True) + + with open(wanted_arch + "/syscallnos.h", "w") as f: + print("#ifndef __MLIBC_SYSCALLNOS_h", file=f) + print("#define __MLIBC_SYSCALLNOS_h", file=f) + print("/* This file is autogenerated. Don't bother. */", file=f) + print( + "/* Generator script: sysdeps/linux/update-syscall-list.py. */", file=f + ) + + for name, num in sorted(syscalls.items(), key=lambda x: x[1]): + print("#define {p}{sc} {n}".format(p=NR_PREFIX, sc=name, n=num), file=f) + + print("#endif /* __MLIBC_SYSCALLNOS_h */", file=f) + + with open("include/bits/syscall_aliases.h", "w") as f: + print("#ifndef __MLIBC_SYSCALL_ALIAS_BIT", file=f) + print("#define __MLIBC_SYSCALL_ALIAS_BIT", file=f) + print("/* This file is autogenerated. Don't bother. */", file=f) + print("/* Generator script: sysdeps/linux/update-syscall-list.py. */", file=f) + + for x in sorted(list(syscall_set)): + print( + f"""\ +#ifdef\t{NR_PREFIX}{x} +#\tdefine SYS_{x} {NR_PREFIX}{x} +#endif +""", + end="", + file=f, + ) + + print("#endif /* __MLIBC_SYSCALL_ALIAS_BIT */", file=f) + + +if __name__ == "__main__": + with tempfile.TemporaryDirectory() as td: + main( + Context( + dirpath=pathlib.Path(td), + ) + ) diff --git a/lib/mlibc/sysdeps/linux/x86/arch-syscall.cpp b/lib/mlibc/sysdeps/linux/x86/arch-syscall.cpp new file mode 100644 index 0000000..35fc8aa --- /dev/null +++ b/lib/mlibc/sysdeps/linux/x86/arch-syscall.cpp @@ -0,0 +1,90 @@ +#include +#include + +using sc_word_t = __sc_word_t; + +// Note: ebx is used for PIC (it holds a reference to the GOT), so we can't clobber it with gcc apparently, +// and also need to make sure to restore it after a syscall + +sc_word_t __do_syscall0(long sc) { + sc_word_t ret; + asm volatile("int $0x80" : "=a"(ret) : "a"(sc) : "memory"); + return ret; +} + +sc_word_t __do_syscall1(long sc, sc_word_t arg1) { + sc_word_t ret; + asm volatile("xchg %%ebx, %%edi;" + "int $0x80;" + "xchg %%edi, %%ebx;" + : "=a"(ret) + : "a"(sc), "D"(arg1) + : "memory"); + return ret; +} + +sc_word_t __do_syscall2(long sc, sc_word_t arg1, sc_word_t arg2) { + sc_word_t ret; + asm volatile("xchg %%ebx, %%edi;" + "int $0x80;" + "xchg %%edi, %%ebx;" + : "=a"(ret) + : "a"(sc), "D"(arg1), "c"(arg2) + : "memory"); + return ret; +} + +sc_word_t __do_syscall3(long sc, sc_word_t arg1, sc_word_t arg2, sc_word_t arg3) { + sc_word_t ret; + asm volatile("xchg %%ebx, %%edi;" + "int $0x80;" + "xchg %%edi, %%ebx;" + : "=a"(ret) + : "a"(sc), "D"(arg1), "c"(arg2), "d"(arg3) + : "memory"); + return ret; +} + +sc_word_t __do_syscall4(long sc, sc_word_t arg1, sc_word_t arg2, sc_word_t arg3, sc_word_t arg4) { + sc_word_t ret; + asm volatile("xchg %%ebx, %%edi;" + "int $0x80;" + "xchg %%edi, %%ebx;" + : "=a"(ret) + : "a"(sc), "D"(arg1), "c"(arg2), "d"(arg3), "S"(arg4) + : "memory"); + return ret; +} + +sc_word_t __do_syscall5(long sc, sc_word_t arg1, sc_word_t arg2, sc_word_t arg3, sc_word_t arg4, + sc_word_t arg5) { + sc_word_t ret; + asm volatile("pushl %2;" + "push %%ebx;" + "mov 4(%%esp), %%ebx;" + "int $0x80;" + "pop %%ebx;" + "add $4, %%esp;" + : "=a"(ret) + : "a"(sc), "g"(arg1), "c"(arg2), "d"(arg3), "S"(arg4), "D"(arg5) + : "memory"); + return ret; +} + +sc_word_t __do_syscall6(long sc, sc_word_t arg1, sc_word_t arg2, sc_word_t arg3, sc_word_t arg4, + sc_word_t arg5, sc_word_t arg6) { + sc_word_t ret; + sc_word_t a1a6[2] = { arg1, arg6 }; + asm volatile ("pushl %1;" + "push %%ebx;" + "push %%ebp;" + "mov 8(%%esp),%%ebx;" + "mov 4(%%ebx),%%ebp;" + "mov (%%ebx),%%ebx;" + "int $0x80;" + "pop %%ebp;" + "pop %%ebx;" + "add $4,%%esp;" + : "=a"(ret) : "g"(&a1a6), "a"(sc), "c"(arg2), "d"(arg3), "S"(arg4), "D"(arg5) : "memory"); + return ret; +} diff --git a/lib/mlibc/sysdeps/linux/x86/cp_syscall.S b/lib/mlibc/sysdeps/linux/x86/cp_syscall.S new file mode 100644 index 0000000..b89e1f4 --- /dev/null +++ b/lib/mlibc/sysdeps/linux/x86/cp_syscall.S @@ -0,0 +1,42 @@ + +.section .text +.global __mlibc_do_asm_cp_syscall +.global __mlibc_syscall_begin +.global __mlibc_syscall_end +.type __mlibc_do_asm_cp_syscall, "function" +__mlibc_do_asm_cp_syscall: + push %ebx + push %esi + push %edi + push %ebp + ; mov 16(%esp), %eax + mov 24(%esp), %ebx + mov 28(%esp), %ecx + mov 32(%esp), %edx + mov 36(%esp), %esi + mov 40(%esp), %edi + mov 44(%esp), %ebp + mov %gs:0x18, %al +__mlibc_syscall_begin: + /* tcbCancelEnableBit && tcbCancelTriggerBit */ + and $((1 << 0) | (1 << 2)), %al + cmp $((1 << 0) | (1 << 2)), %al + je cancel + mov 20(%esp), %eax + int $0x80 +__mlibc_syscall_end: + pop %ebp + pop %edi + pop %esi + pop %ebx + ret + +cancel: + pop %ebp + pop %edi + pop %esi + pop %ebx + call __mlibc_do_cancel@PLT + hlt + +.section .note.GNU-stack,"",%progbits diff --git a/lib/mlibc/sysdeps/linux/x86/crt-src/Scrt1.S b/lib/mlibc/sysdeps/linux/x86/crt-src/Scrt1.S new file mode 100644 index 0000000..a62b127 --- /dev/null +++ b/lib/mlibc/sysdeps/linux/x86/crt-src/Scrt1.S @@ -0,0 +1,29 @@ +.section .text + +.type __stack_chk_fail_local, %function +.weak __stack_chk_fail_local +__stack_chk_fail_local: + call __stack_chk_fail@plt + +.global _start + +.type _start, %function +.type main, %function +.type __mlibc_entry, %function + +.cfi_startproc +_start: +.cfi_undefined eip + xor %ebp, %ebp + mov %esp, %edi + call 1f + +1: + pop %ebx + addl $_GLOBAL_OFFSET_TABLE_+[.-1b], %ebx + push main@GOT(%ebx) + push %edi + call __mlibc_entry@plt +.cfi_endproc + +.section .note.GNU-stack,"",%progbits diff --git a/lib/mlibc/sysdeps/linux/x86/crt-src/crt1.S b/lib/mlibc/sysdeps/linux/x86/crt-src/crt1.S new file mode 100644 index 0000000..ed45da3 --- /dev/null +++ b/lib/mlibc/sysdeps/linux/x86/crt-src/crt1.S @@ -0,0 +1,18 @@ +.section .text +.global _start + +.type _start, %function +.type main, %function +.type __mlibc_entry, %function + +.cfi_startproc +_start: +.cfi_undefined eip + xor %ebp, %ebp + mov %esp, %ecx + push $main + push %ecx + call __mlibc_entry +.cfi_endproc + +.section .note.GNU-stack,"",%progbits diff --git a/lib/mlibc/sysdeps/linux/x86/crt-src/crti.S b/lib/mlibc/sysdeps/linux/x86/crt-src/crti.S new file mode 100644 index 0000000..e232557 --- /dev/null +++ b/lib/mlibc/sysdeps/linux/x86/crt-src/crti.S @@ -0,0 +1,11 @@ +.section .init +.global _init +_init: + pushl %eax + +.section .fini +.global _fini +_fini: + pushl %eax + +.section .note.GNU-stack,"",%progbits diff --git a/lib/mlibc/sysdeps/linux/x86/crt-src/crtn.S b/lib/mlibc/sysdeps/linux/x86/crt-src/crtn.S new file mode 100644 index 0000000..d890289 --- /dev/null +++ b/lib/mlibc/sysdeps/linux/x86/crt-src/crtn.S @@ -0,0 +1,9 @@ +.section .init + popl %eax + ret + +.section .fini + popl %eax + ret + +.section .note.GNU-stack,"",%progbits diff --git a/lib/mlibc/sysdeps/linux/x86/signals.S b/lib/mlibc/sysdeps/linux/x86/signals.S new file mode 100644 index 0000000..8127ee4 --- /dev/null +++ b/lib/mlibc/sysdeps/linux/x86/signals.S @@ -0,0 +1,18 @@ +.section .text + +.global __mlibc_signal_restore +.type __mlibc_signal_restore, @function +__mlibc_signal_restore: + popl %eax + mov $119, %eax + int $0x80 + ud2 + +.global __mlibc_signal_restore_rt +.type __mlibc_signal_restore_rt, @function +__mlibc_signal_restore_rt: + mov $173, %eax + int $0x80 + ud2 + +.section .note.GNU-stack,"",%progbits diff --git a/lib/mlibc/sysdeps/linux/x86/syscallnos.h b/lib/mlibc/sysdeps/linux/x86/syscallnos.h new file mode 100644 index 0000000..f75eb0a --- /dev/null +++ b/lib/mlibc/sysdeps/linux/x86/syscallnos.h @@ -0,0 +1,433 @@ +#ifndef __MLIBC_SYSCALLNOS_h +#define __MLIBC_SYSCALLNOS_h +/* This file is autogenerated. Don't bother. */ +/* Generator script: sysdeps/linux/update-syscall-list.py. */ +#define __NR_restart_syscall 0 +#define __NR_exit 1 +#define __NR_fork 2 +#define __NR_read 3 +#define __NR_write 4 +#define __NR_open 5 +#define __NR_close 6 +#define __NR_waitpid 7 +#define __NR_creat 8 +#define __NR_link 9 +#define __NR_unlink 10 +#define __NR_execve 11 +#define __NR_chdir 12 +#define __NR_time 13 +#define __NR_mknod 14 +#define __NR_chmod 15 +#define __NR_lchown 16 +#define __NR_oldstat 18 +#define __NR_lseek 19 +#define __NR_getpid 20 +#define __NR_mount 21 +#define __NR_umount 22 +#define __NR_setuid 23 +#define __NR_getuid 24 +#define __NR_stime 25 +#define __NR_ptrace 26 +#define __NR_alarm 27 +#define __NR_oldfstat 28 +#define __NR_pause 29 +#define __NR_utime 30 +#define __NR_access 33 +#define __NR_nice 34 +#define __NR_sync 36 +#define __NR_kill 37 +#define __NR_rename 38 +#define __NR_mkdir 39 +#define __NR_rmdir 40 +#define __NR_dup 41 +#define __NR_pipe 42 +#define __NR_times 43 +#define __NR_brk 45 +#define __NR_setgid 46 +#define __NR_getgid 47 +#define __NR_signal 48 +#define __NR_geteuid 49 +#define __NR_getegid 50 +#define __NR_acct 51 +#define __NR_umount2 52 +#define __NR_ioctl 54 +#define __NR_fcntl 55 +#define __NR_setpgid 57 +#define __NR_oldolduname 59 +#define __NR_umask 60 +#define __NR_chroot 61 +#define __NR_ustat 62 +#define __NR_dup2 63 +#define __NR_getppid 64 +#define __NR_getpgrp 65 +#define __NR_setsid 66 +#define __NR_sigaction 67 +#define __NR_sgetmask 68 +#define __NR_ssetmask 69 +#define __NR_setreuid 70 +#define __NR_setregid 71 +#define __NR_sigsuspend 72 +#define __NR_sigpending 73 +#define __NR_sethostname 74 +#define __NR_setrlimit 75 +#define __NR_getrlimit 76 +#define __NR_getrusage 77 +#define __NR_gettimeofday 78 +#define __NR_settimeofday 79 +#define __NR_getgroups 80 +#define __NR_setgroups 81 +#define __NR_select 82 +#define __NR_symlink 83 +#define __NR_oldlstat 84 +#define __NR_readlink 85 +#define __NR_uselib 86 +#define __NR_swapon 87 +#define __NR_reboot 88 +#define __NR_readdir 89 +#define __NR_mmap 90 +#define __NR_munmap 91 +#define __NR_truncate 92 +#define __NR_ftruncate 93 +#define __NR_fchmod 94 +#define __NR_fchown 95 +#define __NR_getpriority 96 +#define __NR_setpriority 97 +#define __NR_statfs 99 +#define __NR_fstatfs 100 +#define __NR_ioperm 101 +#define __NR_socketcall 102 +#define __NR_syslog 103 +#define __NR_setitimer 104 +#define __NR_getitimer 105 +#define __NR_stat 106 +#define __NR_lstat 107 +#define __NR_fstat 108 +#define __NR_olduname 109 +#define __NR_iopl 110 +#define __NR_vhangup 111 +#define __NR_idle 112 +#define __NR_vm86old 113 +#define __NR_wait4 114 +#define __NR_swapoff 115 +#define __NR_sysinfo 116 +#define __NR_ipc 117 +#define __NR_fsync 118 +#define __NR_sigreturn 119 +#define __NR_clone 120 +#define __NR_setdomainname 121 +#define __NR_uname 122 +#define __NR_modify_ldt 123 +#define __NR_adjtimex 124 +#define __NR_mprotect 125 +#define __NR_sigprocmask 126 +#define __NR_create_module 127 +#define __NR_init_module 128 +#define __NR_delete_module 129 +#define __NR_get_kernel_syms 130 +#define __NR_quotactl 131 +#define __NR_getpgid 132 +#define __NR_fchdir 133 +#define __NR_bdflush 134 +#define __NR_sysfs 135 +#define __NR_personality 136 +#define __NR_setfsuid 138 +#define __NR_setfsgid 139 +#define __NR__llseek 140 +#define __NR_getdents 141 +#define __NR__newselect 142 +#define __NR_flock 143 +#define __NR_msync 144 +#define __NR_readv 145 +#define __NR_writev 146 +#define __NR_getsid 147 +#define __NR_fdatasync 148 +#define __NR__sysctl 149 +#define __NR_mlock 150 +#define __NR_munlock 151 +#define __NR_mlockall 152 +#define __NR_munlockall 153 +#define __NR_sched_setparam 154 +#define __NR_sched_getparam 155 +#define __NR_sched_setscheduler 156 +#define __NR_sched_getscheduler 157 +#define __NR_sched_yield 158 +#define __NR_sched_get_priority_max 159 +#define __NR_sched_get_priority_min 160 +#define __NR_sched_rr_get_interval 161 +#define __NR_nanosleep 162 +#define __NR_mremap 163 +#define __NR_setresuid 164 +#define __NR_getresuid 165 +#define __NR_vm86 166 +#define __NR_query_module 167 +#define __NR_poll 168 +#define __NR_nfsservctl 169 +#define __NR_setresgid 170 +#define __NR_getresgid 171 +#define __NR_prctl 172 +#define __NR_rt_sigreturn 173 +#define __NR_rt_sigaction 174 +#define __NR_rt_sigprocmask 175 +#define __NR_rt_sigpending 176 +#define __NR_rt_sigtimedwait 177 +#define __NR_rt_sigqueueinfo 178 +#define __NR_rt_sigsuspend 179 +#define __NR_pread64 180 +#define __NR_pwrite64 181 +#define __NR_chown 182 +#define __NR_getcwd 183 +#define __NR_capget 184 +#define __NR_capset 185 +#define __NR_sigaltstack 186 +#define __NR_sendfile 187 +#define __NR_getpmsg 188 +#define __NR_vfork 190 +#define __NR_ugetrlimit 191 +#define __NR_mmap2 192 +#define __NR_truncate64 193 +#define __NR_ftruncate64 194 +#define __NR_stat64 195 +#define __NR_lstat64 196 +#define __NR_fstat64 197 +#define __NR_lchown32 198 +#define __NR_getuid32 199 +#define __NR_getgid32 200 +#define __NR_geteuid32 201 +#define __NR_getegid32 202 +#define __NR_setreuid32 203 +#define __NR_setregid32 204 +#define __NR_getgroups32 205 +#define __NR_setgroups32 206 +#define __NR_fchown32 207 +#define __NR_setresuid32 208 +#define __NR_getresuid32 209 +#define __NR_setresgid32 210 +#define __NR_getresgid32 211 +#define __NR_chown32 212 +#define __NR_setuid32 213 +#define __NR_setgid32 214 +#define __NR_setfsuid32 215 +#define __NR_setfsgid32 216 +#define __NR_pivot_root 217 +#define __NR_mincore 218 +#define __NR_madvise 219 +#define __NR_getdents64 220 +#define __NR_fcntl64 221 +#define __NR_gettid 224 +#define __NR_readahead 225 +#define __NR_setxattr 226 +#define __NR_lsetxattr 227 +#define __NR_fsetxattr 228 +#define __NR_getxattr 229 +#define __NR_lgetxattr 230 +#define __NR_fgetxattr 231 +#define __NR_listxattr 232 +#define __NR_llistxattr 233 +#define __NR_flistxattr 234 +#define __NR_removexattr 235 +#define __NR_lremovexattr 236 +#define __NR_fremovexattr 237 +#define __NR_tkill 238 +#define __NR_sendfile64 239 +#define __NR_futex 240 +#define __NR_sched_setaffinity 241 +#define __NR_sched_getaffinity 242 +#define __NR_set_thread_area 243 +#define __NR_get_thread_area 244 +#define __NR_io_setup 245 +#define __NR_io_destroy 246 +#define __NR_io_getevents 247 +#define __NR_io_submit 248 +#define __NR_io_cancel 249 +#define __NR_fadvise64 250 +#define __NR_exit_group 252 +#define __NR_lookup_dcookie 253 +#define __NR_epoll_create 254 +#define __NR_epoll_ctl 255 +#define __NR_epoll_wait 256 +#define __NR_remap_file_pages 257 +#define __NR_set_tid_address 258 +#define __NR_timer_create 259 +#define __NR_timer_settime 260 +#define __NR_timer_gettime 261 +#define __NR_timer_getoverrun 262 +#define __NR_timer_delete 263 +#define __NR_clock_settime 264 +#define __NR_clock_gettime 265 +#define __NR_clock_getres 266 +#define __NR_clock_nanosleep 267 +#define __NR_statfs64 268 +#define __NR_fstatfs64 269 +#define __NR_tgkill 270 +#define __NR_utimes 271 +#define __NR_fadvise64_64 272 +#define __NR_mbind 274 +#define __NR_get_mempolicy 275 +#define __NR_set_mempolicy 276 +#define __NR_mq_open 277 +#define __NR_mq_unlink 278 +#define __NR_mq_timedsend 279 +#define __NR_mq_timedreceive 280 +#define __NR_mq_notify 281 +#define __NR_mq_getsetattr 282 +#define __NR_kexec_load 283 +#define __NR_waitid 284 +#define __NR_add_key 286 +#define __NR_request_key 287 +#define __NR_keyctl 288 +#define __NR_ioprio_set 289 +#define __NR_ioprio_get 290 +#define __NR_inotify_init 291 +#define __NR_inotify_add_watch 292 +#define __NR_inotify_rm_watch 293 +#define __NR_migrate_pages 294 +#define __NR_openat 295 +#define __NR_mkdirat 296 +#define __NR_mknodat 297 +#define __NR_fchownat 298 +#define __NR_futimesat 299 +#define __NR_fstatat64 300 +#define __NR_unlinkat 301 +#define __NR_renameat 302 +#define __NR_linkat 303 +#define __NR_symlinkat 304 +#define __NR_readlinkat 305 +#define __NR_fchmodat 306 +#define __NR_faccessat 307 +#define __NR_pselect6 308 +#define __NR_ppoll 309 +#define __NR_unshare 310 +#define __NR_set_robust_list 311 +#define __NR_get_robust_list 312 +#define __NR_splice 313 +#define __NR_sync_file_range 314 +#define __NR_tee 315 +#define __NR_vmsplice 316 +#define __NR_move_pages 317 +#define __NR_getcpu 318 +#define __NR_epoll_pwait 319 +#define __NR_utimensat 320 +#define __NR_signalfd 321 +#define __NR_timerfd_create 322 +#define __NR_eventfd 323 +#define __NR_fallocate 324 +#define __NR_timerfd_settime 325 +#define __NR_timerfd_gettime 326 +#define __NR_signalfd4 327 +#define __NR_eventfd2 328 +#define __NR_epoll_create1 329 +#define __NR_dup3 330 +#define __NR_pipe2 331 +#define __NR_inotify_init1 332 +#define __NR_preadv 333 +#define __NR_pwritev 334 +#define __NR_rt_tgsigqueueinfo 335 +#define __NR_perf_event_open 336 +#define __NR_recvmmsg 337 +#define __NR_fanotify_init 338 +#define __NR_fanotify_mark 339 +#define __NR_prlimit64 340 +#define __NR_name_to_handle_at 341 +#define __NR_open_by_handle_at 342 +#define __NR_clock_adjtime 343 +#define __NR_syncfs 344 +#define __NR_sendmmsg 345 +#define __NR_setns 346 +#define __NR_process_vm_readv 347 +#define __NR_process_vm_writev 348 +#define __NR_kcmp 349 +#define __NR_finit_module 350 +#define __NR_sched_setattr 351 +#define __NR_sched_getattr 352 +#define __NR_renameat2 353 +#define __NR_seccomp 354 +#define __NR_getrandom 355 +#define __NR_memfd_create 356 +#define __NR_bpf 357 +#define __NR_execveat 358 +#define __NR_socket 359 +#define __NR_socketpair 360 +#define __NR_bind 361 +#define __NR_connect 362 +#define __NR_listen 363 +#define __NR_accept4 364 +#define __NR_getsockopt 365 +#define __NR_setsockopt 366 +#define __NR_getsockname 367 +#define __NR_getpeername 368 +#define __NR_sendto 369 +#define __NR_sendmsg 370 +#define __NR_recvfrom 371 +#define __NR_recvmsg 372 +#define __NR_shutdown 373 +#define __NR_userfaultfd 374 +#define __NR_membarrier 375 +#define __NR_mlock2 376 +#define __NR_copy_file_range 377 +#define __NR_preadv2 378 +#define __NR_pwritev2 379 +#define __NR_pkey_mprotect 380 +#define __NR_pkey_alloc 381 +#define __NR_pkey_free 382 +#define __NR_statx 383 +#define __NR_arch_prctl 384 +#define __NR_io_pgetevents 385 +#define __NR_rseq 386 +#define __NR_semget 393 +#define __NR_semctl 394 +#define __NR_shmget 395 +#define __NR_shmctl 396 +#define __NR_shmat 397 +#define __NR_shmdt 398 +#define __NR_msgget 399 +#define __NR_msgsnd 400 +#define __NR_msgrcv 401 +#define __NR_msgctl 402 +#define __NR_clock_gettime64 403 +#define __NR_clock_settime64 404 +#define __NR_clock_adjtime64 405 +#define __NR_clock_getres_time64 406 +#define __NR_clock_nanosleep_time64 407 +#define __NR_timer_gettime64 408 +#define __NR_timer_settime64 409 +#define __NR_timerfd_gettime64 410 +#define __NR_timerfd_settime64 411 +#define __NR_utimensat_time64 412 +#define __NR_pselect6_time64 413 +#define __NR_ppoll_time64 414 +#define __NR_io_pgetevents_time64 416 +#define __NR_recvmmsg_time64 417 +#define __NR_mq_timedsend_time64 418 +#define __NR_mq_timedreceive_time64 419 +#define __NR_semtimedop_time64 420 +#define __NR_rt_sigtimedwait_time64 421 +#define __NR_futex_time64 422 +#define __NR_sched_rr_get_interval_time64 423 +#define __NR_pidfd_send_signal 424 +#define __NR_io_uring_setup 425 +#define __NR_io_uring_enter 426 +#define __NR_io_uring_register 427 +#define __NR_open_tree 428 +#define __NR_move_mount 429 +#define __NR_fsopen 430 +#define __NR_fsconfig 431 +#define __NR_fsmount 432 +#define __NR_fspick 433 +#define __NR_pidfd_open 434 +#define __NR_clone3 435 +#define __NR_close_range 436 +#define __NR_openat2 437 +#define __NR_pidfd_getfd 438 +#define __NR_faccessat2 439 +#define __NR_process_madvise 440 +#define __NR_epoll_pwait2 441 +#define __NR_mount_setattr 442 +#define __NR_quotactl_fd 443 +#define __NR_landlock_create_ruleset 444 +#define __NR_landlock_add_rule 445 +#define __NR_landlock_restrict_self 446 +#define __NR_memfd_secret 447 +#define __NR_process_mrelease 448 +#define __NR_futex_waitv 449 +#define __NR_set_mempolicy_home_node 450 +#endif /* __MLIBC_SYSCALLNOS_h */ diff --git a/lib/mlibc/sysdeps/linux/x86/thread_entry.S b/lib/mlibc/sysdeps/linux/x86/thread_entry.S new file mode 100644 index 0000000..031a6aa --- /dev/null +++ b/lib/mlibc/sysdeps/linux/x86/thread_entry.S @@ -0,0 +1,61 @@ +#define FLAGS 4 +#define STACK FLAGS+4 +#define PTID STACK+4 +#define CTID PTID+4 +#define TLS CTID+4 + +.section .text +.global __mlibc_spawn_thread +.type __mlibc_spawn_thread, "function" +.cfi_startproc +__mlibc_spawn_thread: + push %ebx + .cfi_adjust_cfa_offset 4 + .cfi_rel_offset ebx, 0 + push %esi + .cfi_adjust_cfa_offset 4 + .cfi_rel_offset esi, 0 + push %edi + .cfi_adjust_cfa_offset 4 + .cfi_rel_offset edi, 0 + + xor %eax, %eax + mov 12+FLAGS(%esp), %ebx + mov 12+STACK(%esp), %ecx + mov 12+PTID(%esp), %edx + /* On x86-32 tls and child_tid have to be reversed */ + mov 12+TLS(%esp), %esi + mov 12+CTID(%esp), %edi + mov $120, %al + + int $0x80 + + test %eax, %eax + jnz .parent_exit + + xor %ebp, %ebp + .cfi_undefined %eip + .cfi_undefined %ebp + + call 1f +1: + pop %ebx + addl $_GLOBAL_OFFSET_TABLE_+[.-1b], %ebx + + call __mlibc_enter_thread@plt + hlt + +.parent_exit: + pop %edi + .cfi_adjust_cfa_offset -4 + .cfi_restore edi + pop %esi + .cfi_adjust_cfa_offset -4 + .cfi_restore esi + pop %ebx + .cfi_adjust_cfa_offset -4 + .cfi_restore ebx + ret +.cfi_endproc + +.section .note.GNU-stack,"",%progbits diff --git a/lib/mlibc/sysdeps/linux/x86_64/arch-syscall.cpp b/lib/mlibc/sysdeps/linux/x86_64/arch-syscall.cpp new file mode 100644 index 0000000..d2ebbe7 --- /dev/null +++ b/lib/mlibc/sysdeps/linux/x86_64/arch-syscall.cpp @@ -0,0 +1,78 @@ +#include +#include + +using sc_word_t = __sc_word_t; + +sc_word_t __do_syscall0(long sc) { + sc_word_t ret; + asm volatile ("syscall" : "=a"(ret) + : "a"(sc) + : "rcx", "r11", "memory"); + return ret; +} + +sc_word_t __do_syscall1(long sc, + sc_word_t arg1) { + sc_word_t ret; + asm volatile ("syscall" : "=a"(ret) + : "a"(sc), "D"(arg1) + : "rcx", "r11", "memory"); + return ret; +} + +sc_word_t __do_syscall2(long sc, + sc_word_t arg1, sc_word_t arg2) { + sc_word_t ret; + asm volatile ("syscall" : "=a"(ret) + : "a"(sc), "D"(arg1), "S"(arg2) + : "rcx", "r11", "memory"); + return ret; +} + +sc_word_t __do_syscall3(long sc, + sc_word_t arg1, sc_word_t arg2, sc_word_t arg3) { + sc_word_t ret; + asm volatile ("syscall" : "=a"(ret) + : "a"(sc), "D"(arg1), "S"(arg2), "d"(arg3) + : "rcx", "r11", "memory"); + return ret; +} + +sc_word_t __do_syscall4(long sc, + sc_word_t arg1, sc_word_t arg2, sc_word_t arg3, + sc_word_t arg4) { + sc_word_t ret; + register sc_word_t arg4_reg asm("r10") = arg4; + asm volatile ("syscall" : "=a"(ret) + : "a"(sc), "D"(arg1), "S"(arg2), "d"(arg3), + "r"(arg4_reg) + : "rcx", "r11", "memory"); + return ret; +} + +sc_word_t __do_syscall5(long sc, + sc_word_t arg1, sc_word_t arg2, sc_word_t arg3, + sc_word_t arg4, sc_word_t arg5) { + sc_word_t ret; + register sc_word_t arg4_reg asm("r10") = arg4; + register sc_word_t arg5_reg asm("r8") = arg5; + asm volatile ("syscall" : "=a"(ret) + : "a"(sc), "D"(arg1), "S"(arg2), "d"(arg3), + "r"(arg4_reg), "r"(arg5_reg) + : "rcx", "r11", "memory"); + return ret; +} + +sc_word_t __do_syscall6(long sc, + sc_word_t arg1, sc_word_t arg2, sc_word_t arg3, + sc_word_t arg4, sc_word_t arg5, sc_word_t arg6) { + sc_word_t ret; + register sc_word_t arg4_reg asm("r10") = arg4; + register sc_word_t arg5_reg asm("r8") = arg5; + register sc_word_t arg6_reg asm("r9") = arg6; + asm volatile ("syscall" : "=a"(ret) + : "a"(sc), "D"(arg1), "S"(arg2), "d"(arg3), + "r"(arg4_reg), "r"(arg5_reg), "r"(arg6_reg) + : "rcx", "r11", "memory"); + return ret; +} diff --git a/lib/mlibc/sysdeps/linux/x86_64/cp_syscall.S b/lib/mlibc/sysdeps/linux/x86_64/cp_syscall.S new file mode 100644 index 0000000..5db1f1d --- /dev/null +++ b/lib/mlibc/sysdeps/linux/x86_64/cp_syscall.S @@ -0,0 +1,29 @@ + +.section .text +.global __mlibc_do_asm_cp_syscall +.global __mlibc_syscall_begin +.global __mlibc_syscall_end +.type __mlibc_do_asm_cp_syscall, "function" +__mlibc_do_asm_cp_syscall: + mov %rdi, %rax + mov %rsi, %rdi + mov %rdx, %rsi + mov %rcx, %rdx + mov %r8, %r10 + mov %r9, %r8 + mov 8(%rsp), %r9 + mov %fs:0x30, %r11 +__mlibc_syscall_begin: + /* tcbCancelEnableBit && tcbCancelTriggerBit */ + and $((1 << 0) | (1 << 2)), %r11 + cmp $((1 << 0) | (1 << 2)), %r11 + je cancel + syscall +__mlibc_syscall_end: + ret + +cancel: + call __mlibc_do_cancel + hlt +.section .note.GNU-stack,"",%progbits + diff --git a/lib/mlibc/sysdeps/linux/x86_64/crt-src/Scrt1.S b/lib/mlibc/sysdeps/linux/x86_64/crt-src/Scrt1.S new file mode 100644 index 0000000..d0e8213 --- /dev/null +++ b/lib/mlibc/sysdeps/linux/x86_64/crt-src/Scrt1.S @@ -0,0 +1,8 @@ +.section .text +.global _start +_start: + mov %rsp, %rdi + lea main(%rip), %rsi + call __mlibc_entry +.section .note.GNU-stack,"",%progbits + diff --git a/lib/mlibc/sysdeps/linux/x86_64/crt-src/crt1.S b/lib/mlibc/sysdeps/linux/x86_64/crt-src/crt1.S new file mode 100644 index 0000000..9b77ee7 --- /dev/null +++ b/lib/mlibc/sysdeps/linux/x86_64/crt-src/crt1.S @@ -0,0 +1,8 @@ +.section .text +.global _start +_start: + mov %rsp, %rdi + mov $main, %rsi + call __mlibc_entry +.section .note.GNU-stack,"",%progbits + diff --git a/lib/mlibc/sysdeps/linux/x86_64/crt-src/crti.S b/lib/mlibc/sysdeps/linux/x86_64/crt-src/crti.S new file mode 100644 index 0000000..911b078 --- /dev/null +++ b/lib/mlibc/sysdeps/linux/x86_64/crt-src/crti.S @@ -0,0 +1,11 @@ +.section .init +.global _init +_init: + push %rax + +.section .fini +.global _fini +_fini: + push %rax +.section .note.GNU-stack,"",%progbits + diff --git a/lib/mlibc/sysdeps/linux/x86_64/crt-src/crtn.S b/lib/mlibc/sysdeps/linux/x86_64/crt-src/crtn.S new file mode 100644 index 0000000..0187e50 --- /dev/null +++ b/lib/mlibc/sysdeps/linux/x86_64/crt-src/crtn.S @@ -0,0 +1,9 @@ +.section .init + pop %rax + ret + +.section .fini + pop %rax + ret +.section .note.GNU-stack,"",%progbits + diff --git a/lib/mlibc/sysdeps/linux/x86_64/signals.S b/lib/mlibc/sysdeps/linux/x86_64/signals.S new file mode 100644 index 0000000..09b4387 --- /dev/null +++ b/lib/mlibc/sysdeps/linux/x86_64/signals.S @@ -0,0 +1,14 @@ + +.section .text + +.global __mlibc_signal_restore +.type __mlibc_signal_restore, @function +__mlibc_signal_restore: +.global __mlibc_signal_restore_rt +.type __mlibc_signal_restore_rt, @function +__mlibc_signal_restore_rt: + mov $15, %rax + syscall + ud2 +.section .note.GNU-stack,"",%progbits + diff --git a/lib/mlibc/sysdeps/linux/x86_64/syscallnos.h b/lib/mlibc/sysdeps/linux/x86_64/syscallnos.h new file mode 100644 index 0000000..6c07e69 --- /dev/null +++ b/lib/mlibc/sysdeps/linux/x86_64/syscallnos.h @@ -0,0 +1,362 @@ +#ifndef __MLIBC_SYSCALLNOS_h +#define __MLIBC_SYSCALLNOS_h +/* This file is autogenerated. Don't bother. */ +/* Generator script: sysdeps/linux/update-syscall-list.py. */ +#define __NR_read 0 +#define __NR_write 1 +#define __NR_open 2 +#define __NR_close 3 +#define __NR_stat 4 +#define __NR_fstat 5 +#define __NR_lstat 6 +#define __NR_poll 7 +#define __NR_lseek 8 +#define __NR_mmap 9 +#define __NR_mprotect 10 +#define __NR_munmap 11 +#define __NR_brk 12 +#define __NR_rt_sigaction 13 +#define __NR_rt_sigprocmask 14 +#define __NR_rt_sigreturn 15 +#define __NR_ioctl 16 +#define __NR_pread64 17 +#define __NR_pwrite64 18 +#define __NR_readv 19 +#define __NR_writev 20 +#define __NR_access 21 +#define __NR_pipe 22 +#define __NR_select 23 +#define __NR_sched_yield 24 +#define __NR_mremap 25 +#define __NR_msync 26 +#define __NR_mincore 27 +#define __NR_madvise 28 +#define __NR_shmget 29 +#define __NR_shmat 30 +#define __NR_shmctl 31 +#define __NR_dup 32 +#define __NR_dup2 33 +#define __NR_pause 34 +#define __NR_nanosleep 35 +#define __NR_getitimer 36 +#define __NR_alarm 37 +#define __NR_setitimer 38 +#define __NR_getpid 39 +#define __NR_sendfile 40 +#define __NR_socket 41 +#define __NR_connect 42 +#define __NR_accept 43 +#define __NR_sendto 44 +#define __NR_recvfrom 45 +#define __NR_sendmsg 46 +#define __NR_recvmsg 47 +#define __NR_shutdown 48 +#define __NR_bind 49 +#define __NR_listen 50 +#define __NR_getsockname 51 +#define __NR_getpeername 52 +#define __NR_socketpair 53 +#define __NR_setsockopt 54 +#define __NR_getsockopt 55 +#define __NR_clone 56 +#define __NR_fork 57 +#define __NR_vfork 58 +#define __NR_execve 59 +#define __NR_exit 60 +#define __NR_wait4 61 +#define __NR_kill 62 +#define __NR_uname 63 +#define __NR_semget 64 +#define __NR_semop 65 +#define __NR_semctl 66 +#define __NR_shmdt 67 +#define __NR_msgget 68 +#define __NR_msgsnd 69 +#define __NR_msgrcv 70 +#define __NR_msgctl 71 +#define __NR_fcntl 72 +#define __NR_flock 73 +#define __NR_fsync 74 +#define __NR_fdatasync 75 +#define __NR_truncate 76 +#define __NR_ftruncate 77 +#define __NR_getdents 78 +#define __NR_getcwd 79 +#define __NR_chdir 80 +#define __NR_fchdir 81 +#define __NR_rename 82 +#define __NR_mkdir 83 +#define __NR_rmdir 84 +#define __NR_creat 85 +#define __NR_link 86 +#define __NR_unlink 87 +#define __NR_symlink 88 +#define __NR_readlink 89 +#define __NR_chmod 90 +#define __NR_fchmod 91 +#define __NR_chown 92 +#define __NR_fchown 93 +#define __NR_lchown 94 +#define __NR_umask 95 +#define __NR_gettimeofday 96 +#define __NR_getrlimit 97 +#define __NR_getrusage 98 +#define __NR_sysinfo 99 +#define __NR_times 100 +#define __NR_ptrace 101 +#define __NR_getuid 102 +#define __NR_syslog 103 +#define __NR_getgid 104 +#define __NR_setuid 105 +#define __NR_setgid 106 +#define __NR_geteuid 107 +#define __NR_getegid 108 +#define __NR_setpgid 109 +#define __NR_getppid 110 +#define __NR_getpgrp 111 +#define __NR_setsid 112 +#define __NR_setreuid 113 +#define __NR_setregid 114 +#define __NR_getgroups 115 +#define __NR_setgroups 116 +#define __NR_setresuid 117 +#define __NR_getresuid 118 +#define __NR_setresgid 119 +#define __NR_getresgid 120 +#define __NR_getpgid 121 +#define __NR_setfsuid 122 +#define __NR_setfsgid 123 +#define __NR_getsid 124 +#define __NR_capget 125 +#define __NR_capset 126 +#define __NR_rt_sigpending 127 +#define __NR_rt_sigtimedwait 128 +#define __NR_rt_sigqueueinfo 129 +#define __NR_rt_sigsuspend 130 +#define __NR_sigaltstack 131 +#define __NR_utime 132 +#define __NR_mknod 133 +#define __NR_uselib 134 +#define __NR_personality 135 +#define __NR_ustat 136 +#define __NR_statfs 137 +#define __NR_fstatfs 138 +#define __NR_sysfs 139 +#define __NR_getpriority 140 +#define __NR_setpriority 141 +#define __NR_sched_setparam 142 +#define __NR_sched_getparam 143 +#define __NR_sched_setscheduler 144 +#define __NR_sched_getscheduler 145 +#define __NR_sched_get_priority_max 146 +#define __NR_sched_get_priority_min 147 +#define __NR_sched_rr_get_interval 148 +#define __NR_mlock 149 +#define __NR_munlock 150 +#define __NR_mlockall 151 +#define __NR_munlockall 152 +#define __NR_vhangup 153 +#define __NR_modify_ldt 154 +#define __NR_pivot_root 155 +#define __NR__sysctl 156 +#define __NR_prctl 157 +#define __NR_arch_prctl 158 +#define __NR_adjtimex 159 +#define __NR_setrlimit 160 +#define __NR_chroot 161 +#define __NR_sync 162 +#define __NR_acct 163 +#define __NR_settimeofday 164 +#define __NR_mount 165 +#define __NR_umount2 166 +#define __NR_swapon 167 +#define __NR_swapoff 168 +#define __NR_reboot 169 +#define __NR_sethostname 170 +#define __NR_setdomainname 171 +#define __NR_iopl 172 +#define __NR_ioperm 173 +#define __NR_create_module 174 +#define __NR_init_module 175 +#define __NR_delete_module 176 +#define __NR_get_kernel_syms 177 +#define __NR_query_module 178 +#define __NR_quotactl 179 +#define __NR_nfsservctl 180 +#define __NR_getpmsg 181 +#define __NR_gettid 186 +#define __NR_readahead 187 +#define __NR_setxattr 188 +#define __NR_lsetxattr 189 +#define __NR_fsetxattr 190 +#define __NR_getxattr 191 +#define __NR_lgetxattr 192 +#define __NR_fgetxattr 193 +#define __NR_listxattr 194 +#define __NR_llistxattr 195 +#define __NR_flistxattr 196 +#define __NR_removexattr 197 +#define __NR_lremovexattr 198 +#define __NR_fremovexattr 199 +#define __NR_tkill 200 +#define __NR_time 201 +#define __NR_futex 202 +#define __NR_sched_setaffinity 203 +#define __NR_sched_getaffinity 204 +#define __NR_set_thread_area 205 +#define __NR_io_setup 206 +#define __NR_io_destroy 207 +#define __NR_io_getevents 208 +#define __NR_io_submit 209 +#define __NR_io_cancel 210 +#define __NR_get_thread_area 211 +#define __NR_lookup_dcookie 212 +#define __NR_epoll_create 213 +#define __NR_epoll_ctl_old 214 +#define __NR_epoll_wait_old 215 +#define __NR_remap_file_pages 216 +#define __NR_getdents64 217 +#define __NR_set_tid_address 218 +#define __NR_restart_syscall 219 +#define __NR_semtimedop 220 +#define __NR_fadvise64 221 +#define __NR_timer_create 222 +#define __NR_timer_settime 223 +#define __NR_timer_gettime 224 +#define __NR_timer_getoverrun 225 +#define __NR_timer_delete 226 +#define __NR_clock_settime 227 +#define __NR_clock_gettime 228 +#define __NR_clock_getres 229 +#define __NR_clock_nanosleep 230 +#define __NR_exit_group 231 +#define __NR_epoll_wait 232 +#define __NR_epoll_ctl 233 +#define __NR_tgkill 234 +#define __NR_utimes 235 +#define __NR_mbind 237 +#define __NR_set_mempolicy 238 +#define __NR_get_mempolicy 239 +#define __NR_mq_open 240 +#define __NR_mq_unlink 241 +#define __NR_mq_timedsend 242 +#define __NR_mq_timedreceive 243 +#define __NR_mq_notify 244 +#define __NR_mq_getsetattr 245 +#define __NR_kexec_load 246 +#define __NR_waitid 247 +#define __NR_add_key 248 +#define __NR_request_key 249 +#define __NR_keyctl 250 +#define __NR_ioprio_set 251 +#define __NR_ioprio_get 252 +#define __NR_inotify_init 253 +#define __NR_inotify_add_watch 254 +#define __NR_inotify_rm_watch 255 +#define __NR_migrate_pages 256 +#define __NR_openat 257 +#define __NR_mkdirat 258 +#define __NR_mknodat 259 +#define __NR_fchownat 260 +#define __NR_futimesat 261 +#define __NR_newfstatat 262 +#define __NR_unlinkat 263 +#define __NR_renameat 264 +#define __NR_linkat 265 +#define __NR_symlinkat 266 +#define __NR_readlinkat 267 +#define __NR_fchmodat 268 +#define __NR_faccessat 269 +#define __NR_pselect6 270 +#define __NR_ppoll 271 +#define __NR_unshare 272 +#define __NR_set_robust_list 273 +#define __NR_get_robust_list 274 +#define __NR_splice 275 +#define __NR_tee 276 +#define __NR_sync_file_range 277 +#define __NR_vmsplice 278 +#define __NR_move_pages 279 +#define __NR_utimensat 280 +#define __NR_epoll_pwait 281 +#define __NR_signalfd 282 +#define __NR_timerfd_create 283 +#define __NR_eventfd 284 +#define __NR_fallocate 285 +#define __NR_timerfd_settime 286 +#define __NR_timerfd_gettime 287 +#define __NR_accept4 288 +#define __NR_signalfd4 289 +#define __NR_eventfd2 290 +#define __NR_epoll_create1 291 +#define __NR_dup3 292 +#define __NR_pipe2 293 +#define __NR_inotify_init1 294 +#define __NR_preadv 295 +#define __NR_pwritev 296 +#define __NR_rt_tgsigqueueinfo 297 +#define __NR_perf_event_open 298 +#define __NR_recvmmsg 299 +#define __NR_fanotify_init 300 +#define __NR_fanotify_mark 301 +#define __NR_prlimit64 302 +#define __NR_name_to_handle_at 303 +#define __NR_open_by_handle_at 304 +#define __NR_clock_adjtime 305 +#define __NR_syncfs 306 +#define __NR_sendmmsg 307 +#define __NR_setns 308 +#define __NR_getcpu 309 +#define __NR_process_vm_readv 310 +#define __NR_process_vm_writev 311 +#define __NR_kcmp 312 +#define __NR_finit_module 313 +#define __NR_sched_setattr 314 +#define __NR_sched_getattr 315 +#define __NR_renameat2 316 +#define __NR_seccomp 317 +#define __NR_getrandom 318 +#define __NR_memfd_create 319 +#define __NR_kexec_file_load 320 +#define __NR_bpf 321 +#define __NR_execveat 322 +#define __NR_userfaultfd 323 +#define __NR_membarrier 324 +#define __NR_mlock2 325 +#define __NR_copy_file_range 326 +#define __NR_preadv2 327 +#define __NR_pwritev2 328 +#define __NR_pkey_mprotect 329 +#define __NR_pkey_alloc 330 +#define __NR_pkey_free 331 +#define __NR_statx 332 +#define __NR_io_pgetevents 333 +#define __NR_rseq 334 +#define __NR_pidfd_send_signal 424 +#define __NR_io_uring_setup 425 +#define __NR_io_uring_enter 426 +#define __NR_io_uring_register 427 +#define __NR_open_tree 428 +#define __NR_move_mount 429 +#define __NR_fsopen 430 +#define __NR_fsconfig 431 +#define __NR_fsmount 432 +#define __NR_fspick 433 +#define __NR_pidfd_open 434 +#define __NR_clone3 435 +#define __NR_close_range 436 +#define __NR_openat2 437 +#define __NR_pidfd_getfd 438 +#define __NR_faccessat2 439 +#define __NR_process_madvise 440 +#define __NR_epoll_pwait2 441 +#define __NR_mount_setattr 442 +#define __NR_quotactl_fd 443 +#define __NR_landlock_create_ruleset 444 +#define __NR_landlock_add_rule 445 +#define __NR_landlock_restrict_self 446 +#define __NR_memfd_secret 447 +#define __NR_process_mrelease 448 +#define __NR_futex_waitv 449 +#define __NR_set_mempolicy_home_node 450 +#endif /* __MLIBC_SYSCALLNOS_h */ diff --git a/lib/mlibc/sysdeps/linux/x86_64/thread_entry.S b/lib/mlibc/sysdeps/linux/x86_64/thread_entry.S new file mode 100644 index 0000000..954c6dd --- /dev/null +++ b/lib/mlibc/sysdeps/linux/x86_64/thread_entry.S @@ -0,0 +1,23 @@ + +.section .text +.global __mlibc_spawn_thread +.type __mlibc_spawn_thread, "function" +__mlibc_spawn_thread: + xor %eax, %eax + /* The rest of the args are already in the right registers, + * only need to fixup rcx to r10 + */ + mov %rcx, %r10 + mov $56, %al + syscall + test %eax, %eax + jnz 1f + xor %ebp, %ebp + pop %rdi + pop %rsi + call __mlibc_enter_thread + hlt +1: + ret +.section .note.GNU-stack,"",%progbits + diff --git a/lib/mlibc/sysdeps/lyre/generic/entry.cpp b/lib/mlibc/sysdeps/lyre/generic/entry.cpp new file mode 100644 index 0000000..4fb0179 --- /dev/null +++ b/lib/mlibc/sysdeps/lyre/generic/entry.cpp @@ -0,0 +1,120 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +// defined by the POSIX library +void __mlibc_initLocale(); + +extern "C" uintptr_t *__dlapi_entrystack(); + +extern char **environ; +static mlibc::exec_stack_data __mlibc_stack_data; + +struct LibraryGuard { + LibraryGuard(); +}; + +static LibraryGuard guard; + +LibraryGuard::LibraryGuard() { + __mlibc_initLocale(); + + // Parse the exec() stack. + mlibc::parse_exec_stack(__dlapi_entrystack(), &__mlibc_stack_data); + mlibc::set_startup_data(__mlibc_stack_data.argc, __mlibc_stack_data.argv, + __mlibc_stack_data.envp); +} + +struct GPRState { + uint64_t ds; + uint64_t es; + uint64_t rax; + uint64_t rbx; + uint64_t rcx; + uint64_t rdx; + uint64_t rsi; + uint64_t rdi; + uint64_t rbp; + uint64_t r8; + uint64_t r9; + uint64_t r10; + uint64_t r11; + uint64_t r12; + uint64_t r13; + uint64_t r14; + uint64_t r15; + uint64_t err; + uint64_t rip; + uint64_t cs; + uint64_t rflags; + uint64_t rsp; + uint64_t ss; +}; + +namespace mlibc { + int sys_sigentry(void *sigentry) { + __syscall_ret ret = __syscall(27, sigentry); + if (ret.errno != 0) + return ret.errno; + return 0; + } + + [[noreturn]] int sys_sigreturn(void *context, sigset_t old_mask) { + __syscall(30, context, old_mask); + __builtin_unreachable(); + } +} + +static void __mlibc_sigentry(int which, siginfo_t *siginfo, + void (*sa)(int, siginfo_t *, void *), + GPRState *ret_context, sigset_t prev_mask) { + +/* + size_t *base_ptr = (size_t *)ret_context->rbp; + + mlibc::infoLogger() << "Stacktrace:" << frg::endlog; + mlibc::infoLogger() << " [" << (void *)ret_context->rip << "]" << frg::endlog; + for (;;) { + size_t old_bp = base_ptr[0]; + size_t ret_addr = base_ptr[1]; + if (!ret_addr) + break; + size_t off; + mlibc::infoLogger() << " [" << (void *)ret_addr << "]" << frg::endlog; + if (!old_bp) + break; + base_ptr = (size_t *)old_bp; + } +*/ + + switch ((uintptr_t)sa) { + // DFL + case (uintptr_t)(-2): + mlibc::infoLogger() << "mlibc: Unhandled signal " << which << frg::endlog; + mlibc::sys_exit(128 + which); + // IGN + case (uintptr_t)(-3): + break; + default: + sa(which, siginfo, NULL); + break; + } + + mlibc::sys_sigreturn(ret_context, prev_mask); + + __builtin_unreachable(); +} + +extern "C" void __mlibc_entry(int (*main_fn)(int argc, char *argv[], char *env[])) { + //mlibc::sys_sigentry((void *)__mlibc_sigentry); + + // TODO: call __dlapi_enter, otherwise static builds will break (see Linux sysdeps) + auto result = main_fn(__mlibc_stack_data.argc, __mlibc_stack_data.argv, environ); + exit(result); +} + diff --git a/lib/mlibc/sysdeps/lyre/generic/generic.cpp b/lib/mlibc/sysdeps/lyre/generic/generic.cpp new file mode 100644 index 0000000..549e9f0 --- /dev/null +++ b/lib/mlibc/sysdeps/lyre/generic/generic.cpp @@ -0,0 +1,860 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define STRINGIFY_(X) #X +#define STRINGIFY(X) STRINGIFY_(X) +#define STUB_ONLY { \ + sys_libc_log("STUB_ONLY function on line " STRINGIFY(__LINE__) " was called"); \ + sys_libc_panic(); \ +} + +namespace { + +int fcntl_helper(int fd, int request, int *result, ...) { + va_list args; + va_start(args, result); + if(!mlibc::sys_fcntl) { + return ENOSYS; + } + int ret = mlibc::sys_fcntl(fd, request, args, result); + va_end(args); + return ret; +} + +} + +namespace mlibc { + +void sys_libc_log(const char *message) { + __syscall(SYS_debug, message); +} + +void sys_libc_panic() { + sys_libc_log("\nMLIBC PANIC\n"); + sys_exit(1); + __builtin_unreachable(); +} + +void sys_exit(int status) { + __syscall(SYS_exit, status); + __builtin_unreachable(); +} + +#ifndef MLIBC_BUILDING_RTDL + +[[noreturn]] void sys_thread_exit() { + __syscall(SYS_exit_thread); + __builtin_unreachable(); +} + +extern "C" void __mlibc_thread_entry(); + +int sys_clone(void *tcb, pid_t *pid_out, void *stack) { + (void)tcb; + + __syscall_ret ret = __syscall(SYS_new_thread, (uintptr_t)__mlibc_thread_entry, (uintptr_t)stack); + int ret_value = (int)ret.ret; + if (ret_value == -1) { + return ret.errno; + } + + *pid_out = ret_value; + return 0; +} + +int sys_kill(pid_t, int) STUB_ONLY + +int sys_tcgetattr(int fd, struct termios *attr) { + int ret; + if (int r = sys_ioctl(fd, TCGETS, attr, &ret) != 0) { + return r; + } + return 0; +} + +int sys_tcsetattr(int fd, int optional_action, const struct termios *attr) { + int ret; + switch (optional_action) { + case TCSANOW: + optional_action = TCSETS; break; + case TCSADRAIN: + optional_action = TCSETSW; break; + case TCSAFLUSH: + optional_action = TCSETSF; break; + default: + __ensure(!"Unsupported tcsetattr"); + } + + if (int r = sys_ioctl(fd, optional_action, (void *)attr, &ret) != 0) { + return r; + } + + return 0; +} + +#endif + +int sys_tcb_set(void *pointer) { + __syscall(SYS_set_fs_base, pointer); + return 0; +} + +#ifndef MLIBC_BUILDING_RTDL + +int sys_ppoll(struct pollfd *fds, int nfds, const struct timespec *timeout, const sigset_t *sigmask, int *num_events) { + __syscall_ret ret = __syscall(SYS_ppoll, fds, nfds, timeout, sigmask); + int ret_value = (int)ret.ret; + + if (ret_value == -1) + return ret.errno; + + *num_events = ret_value; + return 0; +} + +int sys_poll(struct pollfd *fds, nfds_t count, int timeout, int *num_events) { + struct timespec ts; + ts.tv_sec = timeout / 1000; + ts.tv_nsec = (timeout % 1000) * 1000000; + return sys_ppoll(fds, count, timeout < 0 ? NULL : &ts, NULL, num_events); +} + +int sys_epoll_pwait(int, struct epoll_event *, int, + int, const sigset_t *, int *) STUB_ONLY + +int sys_epoll_create(int, int *) STUB_ONLY + +int sys_epoll_ctl(int, int, int, struct epoll_event *) STUB_ONLY + +int sys_pselect(int nfds, fd_set *read_set, fd_set *write_set, + fd_set *except_set, const struct timespec *timeout, + const sigset_t *sigmask, int *num_events) { + struct pollfd *fds = (struct pollfd *)calloc(nfds, sizeof(struct pollfd)); + if (fds == NULL) { + return ENOMEM; + } + + for (int i = 0; i < nfds; i++) { + struct pollfd *fd = &fds[i]; + + if (read_set && FD_ISSET(i, read_set)) { + fd->events |= POLLIN; + } + if (write_set && FD_ISSET(i, write_set)) { + fd->events |= POLLOUT; + } + if (except_set && FD_ISSET(i, except_set)) { + fd->events |= POLLPRI; + } + + if (!fd->events) { + fd->fd = -1; + continue; + } + fd->fd = i; + } + + int ret = sys_ppoll(fds, nfds, timeout, sigmask, num_events); + if (ret != 0) { + free(fds); + return ret; + } + + fd_set res_read_set, res_write_set, res_except_set; + FD_ZERO(&res_read_set); + FD_ZERO(&res_write_set); + FD_ZERO(&res_except_set); + + for (int i = 0; i < nfds; i++) { + struct pollfd *fd = &fds[i]; + + if (read_set && FD_ISSET(i, read_set) && (fd->revents & (POLLIN | POLLERR | POLLHUP)) != 0) { + FD_SET(i, &res_read_set); + } + if (write_set && FD_ISSET(i, write_set) && (fd->revents & (POLLOUT | POLLERR | POLLHUP)) != 0) { + FD_SET(i, &res_write_set); + } + if (except_set && FD_ISSET(i, except_set) && (fd->revents & POLLPRI) != 0) { + FD_SET(i, &res_except_set); + } + } + + free(fds); + if (read_set) { + *read_set = res_read_set; + } + if (write_set) { + *write_set = res_write_set; + } + if (except_set) { + *except_set = res_except_set; + } + + return 0; +} + +#endif + +int sys_futex_wait(int *pointer, int expected, const struct timespec *time) { + __syscall_ret ret = __syscall(SYS_futex_wait, pointer, expected, time); + + if ((int)ret.ret == -1) + return ret.errno; + + return 0; +} + +int sys_futex_wake(int *pointer) { + __syscall_ret ret = __syscall(SYS_futex_wake, pointer); + + if ((int)ret.ret == -1) + return ret.errno; + + int num_woken = ret.ret; + + __ensure(num_woken >= 0 && num_woken <= 1); + return num_woken; +} + +#ifndef MLIBC_BUILDING_RTDL + +int sys_timerfd_create(int, int *) STUB_ONLY + +int sys_ioctl(int fd, unsigned long request, void *arg, int *result) { + __syscall_ret ret = __syscall(SYS_ioctl, fd, request, arg); + + if ((int)ret.ret == -1) + return ret.errno; + + *result = (int)ret.ret; + return 0; +} + +int sys_isatty(int fd) { + struct winsize ws; + int ret; + + if (!sys_ioctl(fd, TIOCGWINSZ, &ws, &ret)) + return 0; + + return ENOTTY; +} + +int sys_getcwd(char *buffer, size_t size) { + __syscall_ret ret = __syscall(SYS_getcwd, buffer, size); + + if ((int)ret.ret == -1) + return ret.errno; + + return 0; +} + +#endif + +int sys_openat(int dirfd, const char *path, int flags, mode_t mode, int *fd) { + __syscall_ret ret = __syscall(SYS_openat, dirfd, path, flags, mode); + + if ((int)ret.ret == -1) + return ret.errno; + + *fd = (int)ret.ret; + return 0; +} + +int sys_open(const char *path, int flags, mode_t mode, int *fd) { + return sys_openat(AT_FDCWD, path, flags, mode, fd); +} + +#ifndef MLIBC_BUILDING_RTDL + +int sys_open_dir(const char *path, int *handle) { + return sys_openat(AT_FDCWD, path, O_DIRECTORY, 0, handle); +} + +struct ReadDirState { + size_t offset; + size_t capacity; + void *buffer; +}; + +static frg::hash_map, MemoryAllocator> open_dirs{frg::hash{}, getAllocator()}; + +static ReadDirState *get_dir_state(int fdnum) { + ReadDirState *result; + if (auto value = open_dirs.get(fdnum)) { + result = *value; + } else { + result = (ReadDirState *)malloc(sizeof(ReadDirState)); + result->offset = 0; + result->capacity = 1024; + result->buffer = malloc(result->capacity); + open_dirs.insert(fdnum, result); + } + return result; +} + +int sys_read_entries(int fdnum, void *buffer, size_t max_size, size_t *bytes_read) { + ReadDirState *state = get_dir_state(fdnum); + +retry: + __syscall_ret ret = __syscall(SYS_readdir, fdnum, state->buffer, &state->capacity); + if ((int)ret.ret == -1) { + if (ret.errno == ENOBUFS) { + state->buffer = realloc(state->buffer, state->capacity); + goto retry; + } else { + return ret.errno; + } + } + + size_t offset = 0; + while (offset < max_size) { + struct dirent *ent = (struct dirent *)((char *)state->buffer + state->offset); + if (ent->d_reclen == 0) { + break; + } + + if (offset + ent->d_reclen >= max_size) { + break; + } + + memcpy((char *)buffer + offset, ent, ent->d_reclen); + offset += ent->d_reclen; + state->offset += ent->d_reclen; + } + + *bytes_read = offset; + return 0; +} + +#endif + +int sys_close(int fd) { + __syscall_ret ret = __syscall(SYS_close, fd); + if ((int)ret.ret == -1) { + return ret.errno; + } +#ifndef MLIBC_BUILDING_RTDL + open_dirs.remove(fd); +#endif + return 0; +} + +int sys_seek(int fd, off_t offset, int whence, off_t *new_offset) { + __syscall_ret ret = __syscall(SYS_seek, fd, offset, whence); + off_t ret_value = (off_t)ret.ret; + if (ret_value == -1) { + return ret.errno; + } + *new_offset = ret_value; + return 0; +} + +int sys_read(int fd, void *buf, size_t count, ssize_t *bytes_read) { + __syscall_ret ret = __syscall(SYS_read, fd, buf, count); + ssize_t ret_value = (ssize_t)ret.ret; + if (ret_value == -1) { + return ret.errno; + } + *bytes_read = ret_value; + return 0; +} + +#ifndef MLIBC_BUILDING_RTDL + +int sys_write(int fd, const void *buf, size_t count, ssize_t *bytes_written) { + __syscall_ret ret = __syscall(SYS_write, fd, buf, count); + ssize_t ret_value = (ssize_t)ret.ret; + if (ret_value == -1) { + return ret.errno; + } + *bytes_written = ret_value; + return 0; +} + +int sys_readlink(const char *path, void *data, size_t max_size, ssize_t *length) { + __syscall_ret ret = __syscall(SYS_readlinkat, AT_FDCWD, path, data, max_size); + ssize_t ret_value = (ssize_t)ret.ret; + if (ret_value == -1) { + return ret.errno; + } + *length = ret_value; + return 0; +} + +int sys_link(const char *old_path, const char *new_path) { + return sys_linkat(AT_FDCWD, old_path, AT_FDCWD, new_path, 0); +} + +int sys_linkat(int olddirfd, const char *old_path, int newdirfd, const char *new_path, int flags) { + __syscall_ret ret = __syscall(SYS_linkat, olddirfd, old_path, newdirfd, new_path, flags); + if ((int)ret.ret == -1) { + return ret.errno; + } + return 0; +} + +int sys_unlinkat(int fd, const char *path, int flags) { + __syscall_ret ret = __syscall(SYS_unlinkat, fd, path, flags); + if ((int)ret.ret == -1) { + return ret.errno; + } + return 0; +} + +int sys_fchmodat(int fd, const char *pathname, mode_t mode, int flags) { + __syscall_ret ret = __syscall(SYS_fchmodat, fd, pathname, mode, flags); + if ((int)ret.ret == -1) { + return ret.errno; + } + return 0; +} + +int sys_fchmod(int fd, mode_t mode) { + return sys_fchmodat(fd, "", mode, AT_EMPTY_PATH); +} + +int sys_chmod(const char *pathname, mode_t mode) { + return sys_fchmodat(AT_FDCWD, pathname, mode, 0); +} + +int sys_rmdir(const char *) STUB_ONLY + +#endif + +int sys_vm_map(void *hint, size_t size, int prot, int flags, + int fd, off_t offset, void **window) { + __syscall_ret ret = __syscall(SYS_mmap, hint, size, (uint64_t)prot << 32 | flags, fd, offset); + void *ret_value = (void *)ret.ret; + if (ret_value == MAP_FAILED) { + return ret.errno; + } + *window = ret_value; + return 0; +} + +int sys_vm_unmap(void *pointer, size_t size) { + __syscall_ret ret = __syscall(SYS_unmmap, pointer, size); + if ((int)ret.ret == -1) { + return ret.errno; + } + return 0; +} + +#ifndef MLIBC_BUILDING_RTDL + +int sys_vm_protect(void *pointer, size_t size, int prot) { + __syscall_ret ret = __syscall(SYS_mprotect, pointer, size, prot); + if ((int)ret.ret == -1) { + return ret.errno; + } + return 0; +} + +#endif + +int sys_anon_allocate(size_t size, void **pointer) { + return sys_vm_map(NULL, size, PROT_READ | PROT_WRITE, MAP_ANONYMOUS, -1, 0, pointer); +} + +int sys_anon_free(void *pointer, size_t size) { + return sys_vm_unmap(pointer, size); +} + +#ifndef MLIBC_BUILDING_RTDL + +pid_t sys_getpid() { + __syscall_ret ret = __syscall(SYS_getpid); + return (pid_t)ret.ret; +} + +pid_t sys_getppid() { + return 0; +} + +uid_t sys_getuid() { + return 0; +} + +uid_t sys_geteuid() { + return 0; +} + +gid_t sys_getgid() { + return 0; +} + +int sys_setgid(gid_t) { + return 0; +} + +int sys_getpgid(pid_t, pid_t *) { + return 0; +} + +gid_t sys_getegid() { + return 0; +} + +int sys_setpgid(pid_t, pid_t) { + return 0; +} + +int sys_ttyname(int, char *, size_t) { + return ENOSYS; +} + +int sys_clock_get(int clock, time_t *secs, long *nanos) { + struct timespec buf; + __syscall_ret ret = __syscall(SYS_getclock, clock, &buf); + if ((int)ret.ret == -1) { + return ret.errno; + } + *secs = buf.tv_sec; + *nanos = buf.tv_nsec; + return 0; +} + +int sys_stat(fsfd_target fsfdt, int fd, const char *path, int flags, struct stat *statbuf) { + __syscall_ret ret; + switch (fsfdt) { + case fsfd_target::fd: + ret = __syscall(SYS_stat, fd, "", flags | AT_EMPTY_PATH, statbuf); + break; + case fsfd_target::path: + ret = __syscall(SYS_stat, AT_FDCWD, path, flags, statbuf); + break; + case fsfd_target::fd_path: + ret = __syscall(SYS_stat, fd, path, flags, statbuf); + break; + default: + __ensure(!"sys_stat: Invalid fsfdt"); + __builtin_unreachable(); + } + if ((int)ret.ret == -1) { + return ret.errno; + } + return 0; +} + +int sys_faccessat(int dirfd, const char *pathname, int mode, int flags) { + (void)flags; + struct stat buf; + if (int r = sys_stat(fsfd_target::fd_path, dirfd, pathname, mode & AT_SYMLINK_FOLLOW, &buf)) { + return r; + } + return 0; +} + +int sys_access(const char *path, int mode) { + return sys_faccessat(AT_FDCWD, path, mode, 0); +} + +int sys_pipe(int *fds, int flags) { + __syscall_ret ret = __syscall(SYS_pipe, fds, flags); + if ((int)ret.ret == -1) { + return ret.errno; + } + return 0; +} + +int sys_chdir(const char *path) { + __syscall_ret ret = __syscall(SYS_chdir, path); + if ((int)ret.ret == -1) { + return ret.errno; + } + return 0; +} + +int sys_mkdir(const char *path, mode_t mode) { + return sys_mkdirat(AT_FDCWD, path, mode); +} + +int sys_mkdirat(int dirfd, const char *path, mode_t mode) { + __syscall_ret ret = __syscall(SYS_mkdirat, dirfd, path, mode); + if ((int)ret.ret == -1) { + return ret.errno; + } + return 0; +} + +int sys_socket(int domain, int type_and_flags, int proto, int *fd) { + __syscall_ret ret = __syscall(SYS_socket, domain, type_and_flags, proto); + int ret_value = (int)ret.ret; + if (ret_value == -1) { + return ret.errno; + } + *fd = ret_value; + return 0; +} + +int sys_socketpair(int domain, int type_and_flags, int proto, int *fds) { + __syscall_ret ret = __syscall(SYS_socketpair, domain, type_and_flags, proto, fds); + int ret_value = (int)ret.ret; + if (ret_value == -1) { + return ret.errno; + } + return 0; +} + +int sys_bind(int fd, const struct sockaddr *addr_ptr, socklen_t addr_length) { + __syscall_ret ret = __syscall(SYS_bind, fd, addr_ptr, addr_length); + if ((int)ret.ret == -1) { + return ret.errno; + } + return 0; +} + +int sys_connect(int fd, const struct sockaddr *addr_ptr, socklen_t addr_length) { + __syscall_ret ret = __syscall(SYS_connect, fd, addr_ptr, addr_length); + if ((int)ret.ret == -1) { + return ret.errno; + } + return 0; +} + +int sys_accept(int fd, int *newfd, struct sockaddr *addr_ptr, socklen_t *addr_length, int flags) { + __syscall_ret ret = __syscall(SYS_accept, fd, addr_ptr, addr_length); + int ret_value = (int)ret.ret; + if (ret_value == -1) { + return ret.errno; + } + *newfd = ret_value; + + if(flags & SOCK_NONBLOCK) { + int fcntl_ret = 0; + fcntl_helper(*newfd, F_GETFL, &fcntl_ret); + fcntl_helper(*newfd, F_SETFL, &fcntl_ret, fcntl_ret | O_NONBLOCK); + } + + if(flags & SOCK_CLOEXEC) { + int fcntl_ret = 0; + fcntl_helper(*newfd, F_GETFD, &fcntl_ret); + fcntl_helper(*newfd, F_SETFD, &fcntl_ret, fcntl_ret | FD_CLOEXEC); + } + + return 0; +} + +int sys_getsockopt(int fd, int layer, int number, void *__restrict buffer, socklen_t *__restrict size) { + __syscall_ret ret = __syscall(SYS_getsockopt, fd, layer, number, buffer, size); + ssize_t ret_value = (ssize_t)ret.ret; + if (ret_value == -1) { + return ret.errno; + } + return 0; +} + +int sys_setsockopt(int fd, int layer, int number, const void *buffer, socklen_t size) { + __syscall_ret ret = __syscall(SYS_setsockopt, fd, layer, number, buffer, size); + ssize_t ret_value = (ssize_t)ret.ret; + if (ret_value == -1) { + return ret.errno; + } + return 0; +} + +int sys_msg_recv(int sockfd, struct msghdr *hdr, int flags, ssize_t *length) { + __syscall_ret ret = __syscall(SYS_recvmsg, sockfd, hdr, flags); + ssize_t ret_value = (ssize_t)ret.ret; + if (ret_value == -1) { + return ret.errno; + } + *length = ret_value; + return 0; +} + +int sys_msg_send(int sockfd, const struct msghdr *hdr, int flags, ssize_t *length) { + __syscall_ret ret = __syscall(SYS_sendmsg, sockfd, hdr, flags); + ssize_t ret_value = (ssize_t)ret.ret; + if (ret_value == -1) { + return ret.errno; + } + *length = ret_value; + return 0; +} + +int sys_peername(int fd, struct sockaddr *addr_ptr, socklen_t max_addr_length, socklen_t *actual_length) { + __syscall_ret ret = __syscall(SYS_getpeername, fd, addr_ptr, &max_addr_length); + if ((int)ret.ret == -1) { + return ret.errno; + } + *actual_length = max_addr_length; + return 0; +} + +int sys_sockname(int fd, struct sockaddr *addr_ptr, socklen_t max_addr_length, socklen_t *actual_length) { + __syscall_ret ret = __syscall(SYS_getsockname, fd, addr_ptr, &max_addr_length); + if ((int)ret.ret == -1) { + return ret.errno; + } + *actual_length = max_addr_length; + return 0; +} + +int sys_listen(int fd, int backlog) { + __syscall_ret ret = __syscall(SYS_listen, fd, backlog); + if ((int)ret.ret == -1) { + return ret.errno; + } + return 0; +} + +int sys_inotify_create(int, int *) { + mlibc::infoLogger() << "mlibc: sys_inotify_create() is unimplemented" << frg::endlog; + return ENOSYS; +} + +int sys_fork(pid_t *child) { + __syscall_ret ret = __syscall(SYS_fork); + pid_t ret_value = (pid_t)ret.ret; + if (ret_value == -1) { + return ret.errno; + } + *child = ret_value; + return 0; +} + +int sys_execve(const char *path, char *const argv[], char *const envp[]) { + __syscall_ret ret = __syscall(SYS_exec, path, argv, envp); + return ret.errno; +} + +int sys_fcntl(int fd, int request, va_list args, int *result) { + __syscall_ret ret = __syscall(SYS_fcntl, fd, request, va_arg(args, uint64_t)); + int ret_value = (int)ret.ret; + if (ret_value == -1) { + return ret.errno; + } + *result = ret_value; + return 0; +} + +int sys_dup(int fd, int flags, int *newfd) { + (void)flags; + __syscall_ret ret = __syscall(SYS_fcntl, fd, F_DUPFD, 0); + int ret_value = (int)ret.ret; + if (ret_value == -1) { + return ret.errno; + } + *newfd = ret_value; + return 0; +} + +int sys_dup2(int fd, int flags, int newfd) { + __syscall_ret ret = __syscall(SYS_dup3, fd, newfd, flags); + if ((int)ret.ret == -1) { + return ret.errno; + } + return 0; +} + +int sys_sigprocmask(int, const sigset_t *__restrict, sigset_t *__restrict) { + mlibc::infoLogger() << "mlibc: sys_sigprocmask() is a stub" << frg::endlog; + return 0; +} + +int sys_sigaction(int, const struct sigaction *, struct sigaction *) { + mlibc::infoLogger() << "mlibc: sys_sigaction() is a stub" << frg::endlog; + return 0; +} + +int sys_signalfd_create(sigset_t, int, int *) STUB_ONLY + +int sys_waitpid(pid_t pid, int *status, int flags, struct rusage *ru, pid_t *ret_pid) { + if (ru != NULL) { + mlibc::infoLogger() << "mlibc: struct rusage in sys_waitpid is unsupported" << frg::endlog; + return ENOSYS; + } +again: + __syscall_ret ret = __syscall(SYS_waitpid, pid, status, flags); + pid_t ret_value = (pid_t)ret.ret; + if (ret_value == -1) { + if (ret.errno == EINTR) { + goto again; + } + return ret.errno; + } + *ret_pid = ret_value; + return 0; +} + +int sys_getgroups(size_t, const gid_t *, int *) { + mlibc::infoLogger() << "mlibc: sys_getgroups() is unimplemented" << frg::endlog; + return ENOSYS; +} + +int sys_mount(const char *, const char *, const char *, unsigned long, const void *) STUB_ONLY + +int sys_umount2(const char *, int) STUB_ONLY + +int sys_gethostname(char *buffer, size_t bufsize) { + struct utsname utsname; + if (int err = sys_uname(&utsname)) { + return err; + } + if (strlen(utsname.nodename) >= bufsize) { + return ENAMETOOLONG; + } + strncpy(buffer, utsname.nodename, bufsize); + return 0; +} + +int sys_sethostname(const char *, size_t) STUB_ONLY + +int sys_sleep(time_t *secs, long *nanos) { + struct timespec time = {.tv_sec = *secs, .tv_nsec = *nanos}; + struct timespec rem = {.tv_sec = 0, .tv_nsec = 0}; + __syscall_ret ret = __syscall(SYS_sleep, &time, &rem); + if ((int)ret.ret == -1) { + return ret.errno; + } + *secs = rem.tv_sec; + *nanos = rem.tv_nsec; + return 0; +} + +int sys_getitimer(int, struct itimerval *) { + mlibc::infoLogger() << "mlibc: sys_getitimer() is unimplemented" << frg::endlog; + return ENOSYS; +} + +int sys_setitimer(int, const struct itimerval *, struct itimerval *) { + mlibc::infoLogger() << "mlibc: sys_setitimer() is unimplemented" << frg::endlog; + return ENOSYS; +} + +int sys_umask(mode_t mode, mode_t *old) { + __syscall_ret ret = __syscall(SYS_umask, mode); + *old = (mode_t)ret.ret; + return 0; +} + +int sys_uname(struct utsname *buf) { + __syscall_ret ret = __syscall(SYS_uname, buf); + if ((int)ret.ret == -1) { + return ret.errno; + } + return 0; +} + +int sys_fsync(int) { + mlibc::infoLogger() << "sys_fsync is a stub" << frg::endlog; + return 0; +} + +#endif + +} // namespace mlibc diff --git a/lib/mlibc/sysdeps/lyre/generic/mntent.cpp b/lib/mlibc/sysdeps/lyre/generic/mntent.cpp new file mode 100644 index 0000000..d064af3 --- /dev/null +++ b/lib/mlibc/sysdeps/lyre/generic/mntent.cpp @@ -0,0 +1,97 @@ +#include +#include +#include +#include +#include +#include + +namespace { + +char *internal_buf; +size_t internal_bufsize; + +} + +#define SENTINEL (char *)&internal_buf + +FILE *setmntent(const char *name, const char *mode) { + return fopen(name, mode); +} + +struct mntent *getmntent(FILE *f) { + static struct mntent mnt; + return getmntent_r(f, &mnt, SENTINEL, 0); +} + +int addmntent(FILE *f, const struct mntent *mnt) { + if(fseek(f, 0, SEEK_END)) { + return 1; + } + return fprintf(f, "%s\t%s\t%s\t%s\t%d\t%d\n", + mnt->mnt_fsname, mnt->mnt_dir, mnt->mnt_type, mnt->mnt_opts, + mnt->mnt_freq, mnt->mnt_passno) < 0; +} + +int endmntent(FILE *f) { + if(f) { + fclose(f); + } + return 1; +} + +char *hasmntopt(const struct mntent *mnt, const char *opt) { + return strstr(mnt->mnt_opts, opt); +} + +/* Adapted from musl */ +struct mntent *getmntent_r(FILE *f, struct mntent *mnt, char *linebuf, int buflen) { + int n[8]; + bool use_internal = (linebuf == SENTINEL); + int len; + size_t i; + + mnt->mnt_freq = 0; + mnt->mnt_passno = 0; + + do { + if(use_internal) { + getline(&internal_buf, &internal_bufsize, f); + linebuf = internal_buf; + } else { + fgets(linebuf, buflen, f); + } + if(feof(f) || ferror(f)) { + return 0; + } + if(!strchr(linebuf, '\n')) { + fscanf(f, "%*[^\n]%*[\n]"); + errno = ERANGE; + return 0; + } + + len = strlen(linebuf); + if(len > INT_MAX) { + continue; + } + + for(i = 0; i < sizeof n / sizeof *n; i++) { + n[i] = len; + } + + sscanf(linebuf, " %n%*s%n %n%*s%n %n%*s%n %n%*s%n %d %d", + n, n + 1, n + 2, n + 3, n + 4, n + 5, n + 6, n + 7, + &mnt->mnt_freq, &mnt->mnt_passno); + } while(linebuf[n[0]] == '#' || n[1] == len); + + linebuf[n[1]] = 0; + linebuf[n[3]] = 0; + linebuf[n[5]] = 0; + linebuf[n[7]] = 0; + + mnt->mnt_fsname = linebuf + n[0]; + mnt->mnt_dir = linebuf + n[2]; + mnt->mnt_type = linebuf + n[4]; + mnt->mnt_opts = linebuf + n[6]; + + return mnt; +} diff --git a/lib/mlibc/sysdeps/lyre/generic/mount.cpp b/lib/mlibc/sysdeps/lyre/generic/mount.cpp new file mode 100644 index 0000000..f10254d --- /dev/null +++ b/lib/mlibc/sysdeps/lyre/generic/mount.cpp @@ -0,0 +1,16 @@ +#include +#include +#include + +int mount(const char *source, const char *target, + const char *fstype, unsigned long flags, const void *data) { + return 0; +} + +int umount(const char *target) { + return umount2(target, 0); +} + +int umount2(const char *target, int flags) { + return 0; +} diff --git a/lib/mlibc/sysdeps/lyre/generic/reboot.cpp b/lib/mlibc/sysdeps/lyre/generic/reboot.cpp new file mode 100644 index 0000000..7c86ffd --- /dev/null +++ b/lib/mlibc/sysdeps/lyre/generic/reboot.cpp @@ -0,0 +1,7 @@ +#include +#include +#include + +int reboot(int what) { + return 0; +} diff --git a/lib/mlibc/sysdeps/lyre/generic/thread.S b/lib/mlibc/sysdeps/lyre/generic/thread.S new file mode 100644 index 0000000..47ab6a9 --- /dev/null +++ b/lib/mlibc/sysdeps/lyre/generic/thread.S @@ -0,0 +1,9 @@ +.section .text +.global __mlibc_thread_entry +__mlibc_thread_entry: + pop %rdi + pop %rsi + pop %rdx + call __mlibc_thread_trampoline + +.section .note.GNU-stack,"",%progbits diff --git a/lib/mlibc/sysdeps/lyre/generic/thread.cpp b/lib/mlibc/sysdeps/lyre/generic/thread.cpp new file mode 100644 index 0000000..5186e1f --- /dev/null +++ b/lib/mlibc/sysdeps/lyre/generic/thread.cpp @@ -0,0 +1,58 @@ +#include +#include +#include +#include +#include +#include + +extern "C" void __mlibc_thread_trampoline(void *(*fn)(void *), Tcb *tcb, void *arg) { + if (mlibc::sys_tcb_set(tcb)) { + __ensure(!"failed to set tcb for new thread"); + } + + while (__atomic_load_n(&tcb->tid, __ATOMIC_RELAXED) == 0) { + mlibc::sys_futex_wait(&tcb->tid, 0, nullptr); + } + + tcb->invokeThreadFunc(reinterpret_cast(fn), arg); + + __atomic_store_n(&tcb->didExit, 1, __ATOMIC_RELEASE); + mlibc::sys_futex_wake(&tcb->didExit); + + mlibc::sys_thread_exit(); +} + +#define DEFAULT_STACK 0x400000 + +namespace mlibc { + int sys_prepare_stack(void **stack, void *entry, void *arg, void *tcb, size_t *stack_size, size_t *guard_size, void **stack_base) { + // TODO guard + + mlibc::infoLogger() << "mlibc: sys_prepare_stack() does not setup a guard!" << frg::endlog; + + *guard_size = 0; + + *stack_size = *stack_size ? *stack_size : DEFAULT_STACK; + + if (!*stack) { + *stack_base = mmap(NULL, *stack_size, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); + if (*stack_base == MAP_FAILED) { + return errno; + } + } else { + *stack_base = *stack; + } + + *stack = (void *)((char *)*stack_base + *stack_size); + + void **stack_it = (void **)*stack; + + *--stack_it = arg; + *--stack_it = tcb; + *--stack_it = entry; + + *stack = (void *)stack_it; + + return 0; + } +} diff --git a/lib/mlibc/sysdeps/lyre/include/abi-bits/access.h b/lib/mlibc/sysdeps/lyre/include/abi-bits/access.h new file mode 120000 index 0000000..cb83931 --- /dev/null +++ b/lib/mlibc/sysdeps/lyre/include/abi-bits/access.h @@ -0,0 +1 @@ +../../../../abis/linux/access.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/lyre/include/abi-bits/auxv.h b/lib/mlibc/sysdeps/lyre/include/abi-bits/auxv.h new file mode 120000 index 0000000..c43f878 --- /dev/null +++ b/lib/mlibc/sysdeps/lyre/include/abi-bits/auxv.h @@ -0,0 +1 @@ +../../../../abis/linux/auxv.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/lyre/include/abi-bits/blkcnt_t.h b/lib/mlibc/sysdeps/lyre/include/abi-bits/blkcnt_t.h new file mode 120000 index 0000000..0b0ec27 --- /dev/null +++ b/lib/mlibc/sysdeps/lyre/include/abi-bits/blkcnt_t.h @@ -0,0 +1 @@ +../../../../abis/linux/blkcnt_t.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/lyre/include/abi-bits/blksize_t.h b/lib/mlibc/sysdeps/lyre/include/abi-bits/blksize_t.h new file mode 120000 index 0000000..7dc8d7c --- /dev/null +++ b/lib/mlibc/sysdeps/lyre/include/abi-bits/blksize_t.h @@ -0,0 +1 @@ +../../../../abis/linux/blksize_t.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/lyre/include/abi-bits/clockid_t.h b/lib/mlibc/sysdeps/lyre/include/abi-bits/clockid_t.h new file mode 120000 index 0000000..6a42da5 --- /dev/null +++ b/lib/mlibc/sysdeps/lyre/include/abi-bits/clockid_t.h @@ -0,0 +1 @@ +../../../../abis/linux/clockid_t.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/lyre/include/abi-bits/dev_t.h b/lib/mlibc/sysdeps/lyre/include/abi-bits/dev_t.h new file mode 120000 index 0000000..bca881e --- /dev/null +++ b/lib/mlibc/sysdeps/lyre/include/abi-bits/dev_t.h @@ -0,0 +1 @@ +../../../../abis/linux/dev_t.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/lyre/include/abi-bits/epoll.h b/lib/mlibc/sysdeps/lyre/include/abi-bits/epoll.h new file mode 120000 index 0000000..eb4b76d --- /dev/null +++ b/lib/mlibc/sysdeps/lyre/include/abi-bits/epoll.h @@ -0,0 +1 @@ +../../../../abis/linux/epoll.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/lyre/include/abi-bits/errno.h b/lib/mlibc/sysdeps/lyre/include/abi-bits/errno.h new file mode 120000 index 0000000..6e507de --- /dev/null +++ b/lib/mlibc/sysdeps/lyre/include/abi-bits/errno.h @@ -0,0 +1 @@ +../../../../abis/linux/errno.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/lyre/include/abi-bits/fcntl.h b/lib/mlibc/sysdeps/lyre/include/abi-bits/fcntl.h new file mode 120000 index 0000000..463e2c9 --- /dev/null +++ b/lib/mlibc/sysdeps/lyre/include/abi-bits/fcntl.h @@ -0,0 +1 @@ +../../../../abis/linux/fcntl.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/lyre/include/abi-bits/fsblkcnt_t.h b/lib/mlibc/sysdeps/lyre/include/abi-bits/fsblkcnt_t.h new file mode 120000 index 0000000..898dfb2 --- /dev/null +++ b/lib/mlibc/sysdeps/lyre/include/abi-bits/fsblkcnt_t.h @@ -0,0 +1 @@ +../../../../abis/linux/fsblkcnt_t.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/lyre/include/abi-bits/fsfilcnt_t.h b/lib/mlibc/sysdeps/lyre/include/abi-bits/fsfilcnt_t.h new file mode 120000 index 0000000..791755c --- /dev/null +++ b/lib/mlibc/sysdeps/lyre/include/abi-bits/fsfilcnt_t.h @@ -0,0 +1 @@ +../../../../abis/linux/fsfilcnt_t.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/lyre/include/abi-bits/gid_t.h b/lib/mlibc/sysdeps/lyre/include/abi-bits/gid_t.h new file mode 120000 index 0000000..abce6d6 --- /dev/null +++ b/lib/mlibc/sysdeps/lyre/include/abi-bits/gid_t.h @@ -0,0 +1 @@ +../../../../abis/linux/gid_t.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/lyre/include/abi-bits/in.h b/lib/mlibc/sysdeps/lyre/include/abi-bits/in.h new file mode 120000 index 0000000..418d1d5 --- /dev/null +++ b/lib/mlibc/sysdeps/lyre/include/abi-bits/in.h @@ -0,0 +1 @@ +../../../../abis/linux/in.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/lyre/include/abi-bits/ino_t.h b/lib/mlibc/sysdeps/lyre/include/abi-bits/ino_t.h new file mode 120000 index 0000000..4c20aca --- /dev/null +++ b/lib/mlibc/sysdeps/lyre/include/abi-bits/ino_t.h @@ -0,0 +1 @@ +../../../../abis/linux/ino_t.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/lyre/include/abi-bits/inotify.h b/lib/mlibc/sysdeps/lyre/include/abi-bits/inotify.h new file mode 120000 index 0000000..b5cb282 --- /dev/null +++ b/lib/mlibc/sysdeps/lyre/include/abi-bits/inotify.h @@ -0,0 +1 @@ +../../../../abis/linux/inotify.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/lyre/include/abi-bits/ioctls.h b/lib/mlibc/sysdeps/lyre/include/abi-bits/ioctls.h new file mode 120000 index 0000000..595106b --- /dev/null +++ b/lib/mlibc/sysdeps/lyre/include/abi-bits/ioctls.h @@ -0,0 +1 @@ +../../../../abis/linux/ioctls.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/lyre/include/abi-bits/limits.h b/lib/mlibc/sysdeps/lyre/include/abi-bits/limits.h new file mode 120000 index 0000000..6c88db2 --- /dev/null +++ b/lib/mlibc/sysdeps/lyre/include/abi-bits/limits.h @@ -0,0 +1 @@ +../../../../abis/linux/limits.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/lyre/include/abi-bits/mode_t.h b/lib/mlibc/sysdeps/lyre/include/abi-bits/mode_t.h new file mode 120000 index 0000000..5d78fdf --- /dev/null +++ b/lib/mlibc/sysdeps/lyre/include/abi-bits/mode_t.h @@ -0,0 +1 @@ +../../../../abis/linux/mode_t.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/lyre/include/abi-bits/mqueue.h b/lib/mlibc/sysdeps/lyre/include/abi-bits/mqueue.h new file mode 120000 index 0000000..fa87b07 --- /dev/null +++ b/lib/mlibc/sysdeps/lyre/include/abi-bits/mqueue.h @@ -0,0 +1 @@ +../../../../abis/linux/mqueue.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/lyre/include/abi-bits/msg.h b/lib/mlibc/sysdeps/lyre/include/abi-bits/msg.h new file mode 120000 index 0000000..f402b49 --- /dev/null +++ b/lib/mlibc/sysdeps/lyre/include/abi-bits/msg.h @@ -0,0 +1 @@ +../../../../abis/linux/msg.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/lyre/include/abi-bits/nlink_t.h b/lib/mlibc/sysdeps/lyre/include/abi-bits/nlink_t.h new file mode 120000 index 0000000..bb3b625 --- /dev/null +++ b/lib/mlibc/sysdeps/lyre/include/abi-bits/nlink_t.h @@ -0,0 +1 @@ +../../../../abis/linux/nlink_t.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/lyre/include/abi-bits/packet.h b/lib/mlibc/sysdeps/lyre/include/abi-bits/packet.h new file mode 120000 index 0000000..998ef1a --- /dev/null +++ b/lib/mlibc/sysdeps/lyre/include/abi-bits/packet.h @@ -0,0 +1 @@ +../../../../abis/linux/packet.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/lyre/include/abi-bits/pid_t.h b/lib/mlibc/sysdeps/lyre/include/abi-bits/pid_t.h new file mode 120000 index 0000000..baa90f6 --- /dev/null +++ b/lib/mlibc/sysdeps/lyre/include/abi-bits/pid_t.h @@ -0,0 +1 @@ +../../../../abis/linux/pid_t.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/lyre/include/abi-bits/poll.h b/lib/mlibc/sysdeps/lyre/include/abi-bits/poll.h new file mode 120000 index 0000000..8ea6a0a --- /dev/null +++ b/lib/mlibc/sysdeps/lyre/include/abi-bits/poll.h @@ -0,0 +1 @@ +../../../../abis/linux/poll.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/lyre/include/abi-bits/ptrace.h b/lib/mlibc/sysdeps/lyre/include/abi-bits/ptrace.h new file mode 120000 index 0000000..b2517b2 --- /dev/null +++ b/lib/mlibc/sysdeps/lyre/include/abi-bits/ptrace.h @@ -0,0 +1 @@ +../../../../abis/linux/ptrace.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/lyre/include/abi-bits/reboot.h b/lib/mlibc/sysdeps/lyre/include/abi-bits/reboot.h new file mode 120000 index 0000000..77013a4 --- /dev/null +++ b/lib/mlibc/sysdeps/lyre/include/abi-bits/reboot.h @@ -0,0 +1 @@ +../../../../abis/linux/reboot.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/lyre/include/abi-bits/resource.h b/lib/mlibc/sysdeps/lyre/include/abi-bits/resource.h new file mode 120000 index 0000000..88d7402 --- /dev/null +++ b/lib/mlibc/sysdeps/lyre/include/abi-bits/resource.h @@ -0,0 +1 @@ +../../../../abis/linux/resource.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/lyre/include/abi-bits/seek-whence.h b/lib/mlibc/sysdeps/lyre/include/abi-bits/seek-whence.h new file mode 120000 index 0000000..df7bccf --- /dev/null +++ b/lib/mlibc/sysdeps/lyre/include/abi-bits/seek-whence.h @@ -0,0 +1 @@ +../../../../abis/linux/seek-whence.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/lyre/include/abi-bits/shm.h b/lib/mlibc/sysdeps/lyre/include/abi-bits/shm.h new file mode 120000 index 0000000..067d8c4 --- /dev/null +++ b/lib/mlibc/sysdeps/lyre/include/abi-bits/shm.h @@ -0,0 +1 @@ +../../../../abis/linux/shm.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/lyre/include/abi-bits/signal.h b/lib/mlibc/sysdeps/lyre/include/abi-bits/signal.h new file mode 120000 index 0000000..4dcb0b7 --- /dev/null +++ b/lib/mlibc/sysdeps/lyre/include/abi-bits/signal.h @@ -0,0 +1 @@ +../../../../abis/linux/signal.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/lyre/include/abi-bits/socket.h b/lib/mlibc/sysdeps/lyre/include/abi-bits/socket.h new file mode 120000 index 0000000..f1dc016 --- /dev/null +++ b/lib/mlibc/sysdeps/lyre/include/abi-bits/socket.h @@ -0,0 +1 @@ +../../../../abis/linux/socket.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/lyre/include/abi-bits/socklen_t.h b/lib/mlibc/sysdeps/lyre/include/abi-bits/socklen_t.h new file mode 120000 index 0000000..41f3b11 --- /dev/null +++ b/lib/mlibc/sysdeps/lyre/include/abi-bits/socklen_t.h @@ -0,0 +1 @@ +../../../../abis/linux/socklen_t.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/lyre/include/abi-bits/stat.h b/lib/mlibc/sysdeps/lyre/include/abi-bits/stat.h new file mode 120000 index 0000000..1f63b41 --- /dev/null +++ b/lib/mlibc/sysdeps/lyre/include/abi-bits/stat.h @@ -0,0 +1 @@ +../../../../abis/linux/stat.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/lyre/include/abi-bits/statfs.h b/lib/mlibc/sysdeps/lyre/include/abi-bits/statfs.h new file mode 120000 index 0000000..e3d202f --- /dev/null +++ b/lib/mlibc/sysdeps/lyre/include/abi-bits/statfs.h @@ -0,0 +1 @@ +../../../../abis/linux/statfs.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/lyre/include/abi-bits/statvfs.h b/lib/mlibc/sysdeps/lyre/include/abi-bits/statvfs.h new file mode 120000 index 0000000..d0bdd40 --- /dev/null +++ b/lib/mlibc/sysdeps/lyre/include/abi-bits/statvfs.h @@ -0,0 +1 @@ +../../../../abis/lyre/statvfs.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/lyre/include/abi-bits/suseconds_t.h b/lib/mlibc/sysdeps/lyre/include/abi-bits/suseconds_t.h new file mode 120000 index 0000000..9ed6597 --- /dev/null +++ b/lib/mlibc/sysdeps/lyre/include/abi-bits/suseconds_t.h @@ -0,0 +1 @@ +../../../../abis/linux/suseconds_t.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/lyre/include/abi-bits/termios.h b/lib/mlibc/sysdeps/lyre/include/abi-bits/termios.h new file mode 120000 index 0000000..ee8f0b0 --- /dev/null +++ b/lib/mlibc/sysdeps/lyre/include/abi-bits/termios.h @@ -0,0 +1 @@ +../../../../abis/linux/termios.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/lyre/include/abi-bits/time.h b/lib/mlibc/sysdeps/lyre/include/abi-bits/time.h new file mode 120000 index 0000000..2a02625 --- /dev/null +++ b/lib/mlibc/sysdeps/lyre/include/abi-bits/time.h @@ -0,0 +1 @@ +../../../../abis/linux/time.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/lyre/include/abi-bits/uid_t.h b/lib/mlibc/sysdeps/lyre/include/abi-bits/uid_t.h new file mode 120000 index 0000000..b306777 --- /dev/null +++ b/lib/mlibc/sysdeps/lyre/include/abi-bits/uid_t.h @@ -0,0 +1 @@ +../../../../abis/linux/uid_t.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/lyre/include/abi-bits/utsname.h b/lib/mlibc/sysdeps/lyre/include/abi-bits/utsname.h new file mode 120000 index 0000000..b285754 --- /dev/null +++ b/lib/mlibc/sysdeps/lyre/include/abi-bits/utsname.h @@ -0,0 +1 @@ +../../../../abis/linux/utsname.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/lyre/include/abi-bits/vm-flags.h b/lib/mlibc/sysdeps/lyre/include/abi-bits/vm-flags.h new file mode 120000 index 0000000..bbe258c --- /dev/null +++ b/lib/mlibc/sysdeps/lyre/include/abi-bits/vm-flags.h @@ -0,0 +1 @@ +../../../../abis/linux/vm-flags.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/lyre/include/abi-bits/wait.h b/lib/mlibc/sysdeps/lyre/include/abi-bits/wait.h new file mode 120000 index 0000000..feb2840 --- /dev/null +++ b/lib/mlibc/sysdeps/lyre/include/abi-bits/wait.h @@ -0,0 +1 @@ +../../../../abis/linux/wait.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/lyre/include/abi-bits/xattr.h b/lib/mlibc/sysdeps/lyre/include/abi-bits/xattr.h new file mode 120000 index 0000000..66412d7 --- /dev/null +++ b/lib/mlibc/sysdeps/lyre/include/abi-bits/xattr.h @@ -0,0 +1 @@ +../../../../abis/linux/xattr.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/lyre/include/asm/ioctl.h b/lib/mlibc/sysdeps/lyre/include/asm/ioctl.h new file mode 100644 index 0000000..8cbb364 --- /dev/null +++ b/lib/mlibc/sysdeps/lyre/include/asm/ioctl.h @@ -0,0 +1,105 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +#ifndef _ASM_GENERIC_IOCTL_H +#define _ASM_GENERIC_IOCTL_H + +/* ioctl command encoding: 32 bits total, command in lower 16 bits, + * size of the parameter structure in the lower 14 bits of the + * upper 16 bits. + * Encoding the size of the parameter structure in the ioctl request + * is useful for catching programs compiled with old versions + * and to avoid overwriting user space outside the user buffer area. + * The highest 2 bits are reserved for indicating the ``access mode''. + * NOTE: This limits the max parameter size to 16kB -1 ! + */ + +/* + * The following is for compatibility across the various Linux + * platforms. The generic ioctl numbering scheme doesn't really enforce + * a type field. De facto, however, the top 8 bits of the lower 16 + * bits are indeed used as a type field, so we might just as well make + * this explicit here. Please be sure to use the decoding macros + * below from now on. + */ +#define _IOC_NRBITS 8 +#define _IOC_TYPEBITS 8 + +/* + * Let any architecture override either of the following before + * including this file. + */ + +#ifndef _IOC_SIZEBITS +# define _IOC_SIZEBITS 14 +#endif + +#ifndef _IOC_DIRBITS +# define _IOC_DIRBITS 2 +#endif + +#define _IOC_NRMASK ((1 << _IOC_NRBITS)-1) +#define _IOC_TYPEMASK ((1 << _IOC_TYPEBITS)-1) +#define _IOC_SIZEMASK ((1 << _IOC_SIZEBITS)-1) +#define _IOC_DIRMASK ((1 << _IOC_DIRBITS)-1) + +#define _IOC_NRSHIFT 0 +#define _IOC_TYPESHIFT (_IOC_NRSHIFT+_IOC_NRBITS) +#define _IOC_SIZESHIFT (_IOC_TYPESHIFT+_IOC_TYPEBITS) +#define _IOC_DIRSHIFT (_IOC_SIZESHIFT+_IOC_SIZEBITS) + +/* + * Direction bits, which any architecture can choose to override + * before including this file. + * + * NOTE: _IOC_WRITE means userland is writing and kernel is + * reading. _IOC_READ means userland is reading and kernel is writing. + */ + +#ifndef _IOC_NONE +# define _IOC_NONE 0U +#endif + +#ifndef _IOC_WRITE +# define _IOC_WRITE 1U +#endif + +#ifndef _IOC_READ +# define _IOC_READ 2U +#endif + +#define _IOC(dir,type,nr,size) \ + (((dir) << _IOC_DIRSHIFT) | \ + ((type) << _IOC_TYPESHIFT) | \ + ((nr) << _IOC_NRSHIFT) | \ + ((size) << _IOC_SIZESHIFT)) + +#define _IOC_TYPECHECK(t) (sizeof(t)) + +/* + * Used to create numbers. + * + * NOTE: _IOW means userland is writing and kernel is reading. _IOR + * means userland is reading and kernel is writing. + */ +#define _IO(type,nr) _IOC(_IOC_NONE,(type),(nr),0) +#define _IOR(type,nr,size) _IOC(_IOC_READ,(type),(nr),(_IOC_TYPECHECK(size))) +#define _IOW(type,nr,size) _IOC(_IOC_WRITE,(type),(nr),(_IOC_TYPECHECK(size))) +#define _IOWR(type,nr,size) _IOC(_IOC_READ|_IOC_WRITE,(type),(nr),(_IOC_TYPECHECK(size))) +#define _IOR_BAD(type,nr,size) _IOC(_IOC_READ,(type),(nr),sizeof(size)) +#define _IOW_BAD(type,nr,size) _IOC(_IOC_WRITE,(type),(nr),sizeof(size)) +#define _IOWR_BAD(type,nr,size) _IOC(_IOC_READ|_IOC_WRITE,(type),(nr),sizeof(size)) + +/* used to decode ioctl numbers.. */ +#define _IOC_DIR(nr) (((nr) >> _IOC_DIRSHIFT) & _IOC_DIRMASK) +#define _IOC_TYPE(nr) (((nr) >> _IOC_TYPESHIFT) & _IOC_TYPEMASK) +#define _IOC_NR(nr) (((nr) >> _IOC_NRSHIFT) & _IOC_NRMASK) +#define _IOC_SIZE(nr) (((nr) >> _IOC_SIZESHIFT) & _IOC_SIZEMASK) + +/* ...and for the drivers/sound files... */ + +#define IOC_IN (_IOC_WRITE << _IOC_DIRSHIFT) +#define IOC_OUT (_IOC_READ << _IOC_DIRSHIFT) +#define IOC_INOUT ((_IOC_WRITE|_IOC_READ) << _IOC_DIRSHIFT) +#define IOCSIZE_MASK (_IOC_SIZEMASK << _IOC_SIZESHIFT) +#define IOCSIZE_SHIFT (_IOC_SIZESHIFT) + +#endif /* _ASM_GENERIC_IOCTL_H */ diff --git a/lib/mlibc/sysdeps/lyre/include/asm/ioctls.h b/lib/mlibc/sysdeps/lyre/include/asm/ioctls.h new file mode 100644 index 0000000..bdbba9b --- /dev/null +++ b/lib/mlibc/sysdeps/lyre/include/asm/ioctls.h @@ -0,0 +1,121 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +#ifndef __ASM_GENERIC_IOCTLS_H +#define __ASM_GENERIC_IOCTLS_H + +#include + +/* + * These are the most common definitions for tty ioctl numbers. + * Most of them do not use the recommended _IOC(), but there is + * probably some source code out there hardcoding the number, + * so we might as well use them for all new platforms. + * + * The architectures that use different values here typically + * try to be compatible with some Unix variants for the same + * architecture. + */ + +/* 0x54 is just a magic number to make these relatively unique ('T') */ + +#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 /* Needed for POSIX tcsendbreak() */ +#define TIOCSBRK 0x5427 /* BSD compatibility */ +#define TIOCCBRK 0x5428 /* BSD compatibility */ +#define TIOCGSID 0x5429 /* Return the session ID of FD */ +#define TCGETS2 _IOR('T', 0x2A, struct termios2) +#define TCSETS2 _IOW('T', 0x2B, struct termios2) +#define TCSETSW2 _IOW('T', 0x2C, struct termios2) +#define TCSETSF2 _IOW('T', 0x2D, struct termios2) +#define TIOCGRS485 0x542E +#ifndef TIOCSRS485 +#define TIOCSRS485 0x542F +#endif +#define TIOCGPTN _IOR('T', 0x30, unsigned int) /* Get Pty Number (of pty-mux device) */ +#define TIOCSPTLCK _IOW('T', 0x31, int) /* Lock/unlock Pty */ +#define TIOCGDEV _IOR('T', 0x32, unsigned int) /* Get primary device node of /dev/console */ +#define TCGETX 0x5432 /* SYS5 TCGETX compatibility */ +#define TCSETX 0x5433 +#define TCSETXF 0x5434 +#define TCSETXW 0x5435 +#define TIOCSIG _IOW('T', 0x36, int) /* pty: generate signal */ +#define TIOCVHANGUP 0x5437 +#define TIOCGPKT _IOR('T', 0x38, int) /* Get packet mode state */ +#define TIOCGPTLCK _IOR('T', 0x39, int) /* Get Pty lock state */ +#define TIOCGEXCL _IOR('T', 0x40, int) /* Get exclusive mode state */ +#define TIOCGPTPEER _IO('T', 0x41) /* Safely open the slave */ +#define TIOCGISO7816 _IOR('T', 0x42, struct serial_iso7816) +#define TIOCSISO7816 _IOWR('T', 0x43, struct serial_iso7816) + +#define FIONCLEX 0x5450 +#define FIOCLEX 0x5451 +#define FIOASYNC 0x5452 +#define TIOCSERCONFIG 0x5453 +#define TIOCSERGWILD 0x5454 +#define TIOCSERSWILD 0x5455 +#define TIOCGLCKTRMIOS 0x5456 +#define TIOCSLCKTRMIOS 0x5457 +#define TIOCSERGSTRUCT 0x5458 /* For debugging only */ +#define TIOCSERGETLSR 0x5459 /* Get line status register */ +#define TIOCSERGETMULTI 0x545A /* Get multiport config */ +#define TIOCSERSETMULTI 0x545B /* Set multiport config */ + +#define TIOCMIWAIT 0x545C /* wait for a change on serial input line(s) */ +#define TIOCGICOUNT 0x545D /* read serial port __inline__ interrupt counts */ + +/* + * Some arches already define FIOQSIZE due to a historical + * conflict with a Hayes modem-specific ioctl value. + */ +#ifndef FIOQSIZE +# define FIOQSIZE 0x5460 +#endif + +/* Used for packet mode */ +#define TIOCPKT_DATA 0 +#define TIOCPKT_FLUSHREAD 1 +#define TIOCPKT_FLUSHWRITE 2 +#define TIOCPKT_STOP 4 +#define TIOCPKT_START 8 +#define TIOCPKT_NOSTOP 16 +#define TIOCPKT_DOSTOP 32 +#define TIOCPKT_IOCTL 64 + +#define TIOCSER_TEMT 0x01 /* Transmitter physically empty */ + +#endif /* __ASM_GENERIC_IOCTLS_H */ diff --git a/lib/mlibc/sysdeps/lyre/include/linux/fb.h b/lib/mlibc/sysdeps/lyre/include/linux/fb.h new file mode 100644 index 0000000..d5e6d88 --- /dev/null +++ b/lib/mlibc/sysdeps/lyre/include/linux/fb.h @@ -0,0 +1,400 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +#ifndef _LINUX_FB_H +#define _LINUX_FB_H + +#include +#include + +/* Definitions of frame buffers */ + +#define FB_MAX 32 /* sufficient for now */ + +/* ioctls + 0x46 is 'F' */ +#define FBIOGET_VSCREENINFO 0x4600 +#define FBIOPUT_VSCREENINFO 0x4601 +#define FBIOGET_FSCREENINFO 0x4602 +#define FBIOGETCMAP 0x4604 +#define FBIOPUTCMAP 0x4605 +#define FBIOPAN_DISPLAY 0x4606 +#define FBIO_CURSOR _IOWR('F', 0x08, struct fb_cursor) +/* 0x4607-0x460B are defined below */ +/* #define FBIOGET_MONITORSPEC 0x460C */ +/* #define FBIOPUT_MONITORSPEC 0x460D */ +/* #define FBIOSWITCH_MONIBIT 0x460E */ +#define FBIOGET_CON2FBMAP 0x460F +#define FBIOPUT_CON2FBMAP 0x4610 +#define FBIOBLANK 0x4611 /* arg: 0 or vesa level + 1 */ +#define FBIOGET_VBLANK _IOR('F', 0x12, struct fb_vblank) +#define FBIO_ALLOC 0x4613 +#define FBIO_FREE 0x4614 +#define FBIOGET_GLYPH 0x4615 +#define FBIOGET_HWCINFO 0x4616 +#define FBIOPUT_MODEINFO 0x4617 +#define FBIOGET_DISPINFO 0x4618 +#define FBIO_WAITFORVSYNC _IOW('F', 0x20, uint32_t) + +#define FB_TYPE_PACKED_PIXELS 0 /* Packed Pixels */ +#define FB_TYPE_PLANES 1 /* Non interleaved planes */ +#define FB_TYPE_INTERLEAVED_PLANES 2 /* Interleaved planes */ +#define FB_TYPE_TEXT 3 /* Text/attributes */ +#define FB_TYPE_VGA_PLANES 4 /* EGA/VGA planes */ +#define FB_TYPE_FOURCC 5 /* Type identified by a V4L2 FOURCC */ + +#define FB_AUX_TEXT_MDA 0 /* Monochrome text */ +#define FB_AUX_TEXT_CGA 1 /* CGA/EGA/VGA Color text */ +#define FB_AUX_TEXT_S3_MMIO 2 /* S3 MMIO fasttext */ +#define FB_AUX_TEXT_MGA_STEP16 3 /* MGA Millenium I: text, attr, 14 reserved bytes */ +#define FB_AUX_TEXT_MGA_STEP8 4 /* other MGAs: text, attr, 6 reserved bytes */ +#define FB_AUX_TEXT_SVGA_GROUP 8 /* 8-15: SVGA tileblit compatible modes */ +#define FB_AUX_TEXT_SVGA_MASK 7 /* lower three bits says step */ +#define FB_AUX_TEXT_SVGA_STEP2 8 /* SVGA text mode: text, attr */ +#define FB_AUX_TEXT_SVGA_STEP4 9 /* SVGA text mode: text, attr, 2 reserved bytes */ +#define FB_AUX_TEXT_SVGA_STEP8 10 /* SVGA text mode: text, attr, 6 reserved bytes */ +#define FB_AUX_TEXT_SVGA_STEP16 11 /* SVGA text mode: text, attr, 14 reserved bytes */ +#define FB_AUX_TEXT_SVGA_LAST 15 /* reserved up to 15 */ + +#define FB_AUX_VGA_PLANES_VGA4 0 /* 16 color planes (EGA/VGA) */ +#define FB_AUX_VGA_PLANES_CFB4 1 /* CFB4 in planes (VGA) */ +#define FB_AUX_VGA_PLANES_CFB8 2 /* CFB8 in planes (VGA) */ + +#define FB_VISUAL_MONO01 0 /* Monochr. 1=Black 0=White */ +#define FB_VISUAL_MONO10 1 /* Monochr. 1=White 0=Black */ +#define FB_VISUAL_TRUECOLOR 2 /* True color */ +#define FB_VISUAL_PSEUDOCOLOR 3 /* Pseudo color (like atari) */ +#define FB_VISUAL_DIRECTCOLOR 4 /* Direct color */ +#define FB_VISUAL_STATIC_PSEUDOCOLOR 5 /* Pseudo color readonly */ +#define FB_VISUAL_FOURCC 6 /* Visual identified by a V4L2 FOURCC */ + +#define FB_ACCEL_NONE 0 /* no hardware accelerator */ +#define FB_ACCEL_ATARIBLITT 1 /* Atari Blitter */ +#define FB_ACCEL_AMIGABLITT 2 /* Amiga Blitter */ +#define FB_ACCEL_S3_TRIO64 3 /* Cybervision64 (S3 Trio64) */ +#define FB_ACCEL_NCR_77C32BLT 4 /* RetinaZ3 (NCR 77C32BLT) */ +#define FB_ACCEL_S3_VIRGE 5 /* Cybervision64/3D (S3 ViRGE) */ +#define FB_ACCEL_ATI_MACH64GX 6 /* ATI Mach 64GX family */ +#define FB_ACCEL_DEC_TGA 7 /* DEC 21030 TGA */ +#define FB_ACCEL_ATI_MACH64CT 8 /* ATI Mach 64CT family */ +#define FB_ACCEL_ATI_MACH64VT 9 /* ATI Mach 64CT family VT class */ +#define FB_ACCEL_ATI_MACH64GT 10 /* ATI Mach 64CT family GT class */ +#define FB_ACCEL_SUN_CREATOR 11 /* Sun Creator/Creator3D */ +#define FB_ACCEL_SUN_CGSIX 12 /* Sun cg6 */ +#define FB_ACCEL_SUN_LEO 13 /* Sun leo/zx */ +#define FB_ACCEL_IMS_TWINTURBO 14 /* IMS Twin Turbo */ +#define FB_ACCEL_3DLABS_PERMEDIA2 15 /* 3Dlabs Permedia 2 */ +#define FB_ACCEL_MATROX_MGA2064W 16 /* Matrox MGA2064W (Millenium) */ +#define FB_ACCEL_MATROX_MGA1064SG 17 /* Matrox MGA1064SG (Mystique) */ +#define FB_ACCEL_MATROX_MGA2164W 18 /* Matrox MGA2164W (Millenium II) */ +#define FB_ACCEL_MATROX_MGA2164W_AGP 19 /* Matrox MGA2164W (Millenium II) */ +#define FB_ACCEL_MATROX_MGAG100 20 /* Matrox G100 (Productiva G100) */ +#define FB_ACCEL_MATROX_MGAG200 21 /* Matrox G200 (Myst, Mill, ...) */ +#define FB_ACCEL_SUN_CG14 22 /* Sun cgfourteen */ +#define FB_ACCEL_SUN_BWTWO 23 /* Sun bwtwo */ +#define FB_ACCEL_SUN_CGTHREE 24 /* Sun cgthree */ +#define FB_ACCEL_SUN_TCX 25 /* Sun tcx */ +#define FB_ACCEL_MATROX_MGAG400 26 /* Matrox G400 */ +#define FB_ACCEL_NV3 27 /* nVidia RIVA 128 */ +#define FB_ACCEL_NV4 28 /* nVidia RIVA TNT */ +#define FB_ACCEL_NV5 29 /* nVidia RIVA TNT2 */ +#define FB_ACCEL_CT_6555x 30 /* C&T 6555x */ +#define FB_ACCEL_3DFX_BANSHEE 31 /* 3Dfx Banshee */ +#define FB_ACCEL_ATI_RAGE128 32 /* ATI Rage128 family */ +#define FB_ACCEL_IGS_CYBER2000 33 /* CyberPro 2000 */ +#define FB_ACCEL_IGS_CYBER2010 34 /* CyberPro 2010 */ +#define FB_ACCEL_IGS_CYBER5000 35 /* CyberPro 5000 */ +#define FB_ACCEL_SIS_GLAMOUR 36 /* SiS 300/630/540 */ +#define FB_ACCEL_3DLABS_PERMEDIA3 37 /* 3Dlabs Permedia 3 */ +#define FB_ACCEL_ATI_RADEON 38 /* ATI Radeon family */ +#define FB_ACCEL_I810 39 /* Intel 810/815 */ +#define FB_ACCEL_SIS_GLAMOUR_2 40 /* SiS 315, 650, 740 */ +#define FB_ACCEL_SIS_XABRE 41 /* SiS 330 ("Xabre") */ +#define FB_ACCEL_I830 42 /* Intel 830M/845G/85x/865G */ +#define FB_ACCEL_NV_10 43 /* nVidia Arch 10 */ +#define FB_ACCEL_NV_20 44 /* nVidia Arch 20 */ +#define FB_ACCEL_NV_30 45 /* nVidia Arch 30 */ +#define FB_ACCEL_NV_40 46 /* nVidia Arch 40 */ +#define FB_ACCEL_XGI_VOLARI_V 47 /* XGI Volari V3XT, V5, V8 */ +#define FB_ACCEL_XGI_VOLARI_Z 48 /* XGI Volari Z7 */ +#define FB_ACCEL_OMAP1610 49 /* TI OMAP16xx */ +#define FB_ACCEL_TRIDENT_TGUI 50 /* Trident TGUI */ +#define FB_ACCEL_TRIDENT_3DIMAGE 51 /* Trident 3DImage */ +#define FB_ACCEL_TRIDENT_BLADE3D 52 /* Trident Blade3D */ +#define FB_ACCEL_TRIDENT_BLADEXP 53 /* Trident BladeXP */ +#define FB_ACCEL_CIRRUS_ALPINE 53 /* Cirrus Logic 543x/544x/5480 */ +#define FB_ACCEL_NEOMAGIC_NM2070 90 /* NeoMagic NM2070 */ +#define FB_ACCEL_NEOMAGIC_NM2090 91 /* NeoMagic NM2090 */ +#define FB_ACCEL_NEOMAGIC_NM2093 92 /* NeoMagic NM2093 */ +#define FB_ACCEL_NEOMAGIC_NM2097 93 /* NeoMagic NM2097 */ +#define FB_ACCEL_NEOMAGIC_NM2160 94 /* NeoMagic NM2160 */ +#define FB_ACCEL_NEOMAGIC_NM2200 95 /* NeoMagic NM2200 */ +#define FB_ACCEL_NEOMAGIC_NM2230 96 /* NeoMagic NM2230 */ +#define FB_ACCEL_NEOMAGIC_NM2360 97 /* NeoMagic NM2360 */ +#define FB_ACCEL_NEOMAGIC_NM2380 98 /* NeoMagic NM2380 */ +#define FB_ACCEL_PXA3XX 99 /* PXA3xx */ + +#define FB_ACCEL_SAVAGE4 0x80 /* S3 Savage4 */ +#define FB_ACCEL_SAVAGE3D 0x81 /* S3 Savage3D */ +#define FB_ACCEL_SAVAGE3D_MV 0x82 /* S3 Savage3D-MV */ +#define FB_ACCEL_SAVAGE2000 0x83 /* S3 Savage2000 */ +#define FB_ACCEL_SAVAGE_MX_MV 0x84 /* S3 Savage/MX-MV */ +#define FB_ACCEL_SAVAGE_MX 0x85 /* S3 Savage/MX */ +#define FB_ACCEL_SAVAGE_IX_MV 0x86 /* S3 Savage/IX-MV */ +#define FB_ACCEL_SAVAGE_IX 0x87 /* S3 Savage/IX */ +#define FB_ACCEL_PROSAVAGE_PM 0x88 /* S3 ProSavage PM133 */ +#define FB_ACCEL_PROSAVAGE_KM 0x89 /* S3 ProSavage KM133 */ +#define FB_ACCEL_S3TWISTER_P 0x8a /* S3 Twister */ +#define FB_ACCEL_S3TWISTER_K 0x8b /* S3 TwisterK */ +#define FB_ACCEL_SUPERSAVAGE 0x8c /* S3 Supersavage */ +#define FB_ACCEL_PROSAVAGE_DDR 0x8d /* S3 ProSavage DDR */ +#define FB_ACCEL_PROSAVAGE_DDRK 0x8e /* S3 ProSavage DDR-K */ + +#define FB_ACCEL_PUV3_UNIGFX 0xa0 /* PKUnity-v3 Unigfx */ + +#define FB_CAP_FOURCC 1 /* Device supports FOURCC-based formats */ + +struct fb_fix_screeninfo { + char id[16]; /* identification string eg "TT Builtin" */ + unsigned long smem_start; /* Start of frame buffer mem */ + /* (physical address) */ + uint32_t smem_len; /* Length of frame buffer mem */ + uint32_t type; /* see FB_TYPE_* */ + uint32_t type_aux; /* Interleave for interleaved Planes */ + uint32_t visual; /* see FB_VISUAL_* */ + uint16_t xpanstep; /* zero if no hardware panning */ + uint16_t ypanstep; /* zero if no hardware panning */ + uint16_t ywrapstep; /* zero if no hardware ywrap */ + uint32_t line_length; /* length of a line in bytes */ + unsigned long mmio_start; /* Start of Memory Mapped I/O */ + /* (physical address) */ + uint32_t mmio_len; /* Length of Memory Mapped I/O */ + uint32_t accel; /* Indicate to driver which */ + /* specific chip/card we have */ + uint16_t capabilities; /* see FB_CAP_* */ + uint16_t reserved[2]; /* Reserved for future compatibility */ +}; + +/* Interpretation of offset for color fields: All offsets are from the right, + * inside a "pixel" value, which is exactly 'bits_per_pixel' wide (means: you + * can use the offset as right argument to <<). A pixel afterwards is a bit + * stream and is written to video memory as that unmodified. + * + * For pseudocolor: offset and length should be the same for all color + * components. Offset specifies the position of the least significant bit + * of the palette index in a pixel value. Length indicates the number + * of available palette entries (i.e. # of entries = 1 << length). + */ +struct fb_bitfield { + uint32_t offset; /* beginning of bitfield */ + uint32_t length; /* length of bitfield */ + uint32_t msb_right; /* != 0 : Most significant bit is */ + /* right */ +}; + +#define FB_NONSTD_HAM 1 /* Hold-And-Modify (HAM) */ +#define FB_NONSTD_REV_PIX_IN_B 2 /* order of pixels in each byte is reversed */ + +#define FB_ACTIVATE_NOW 0 /* set values immediately (or vbl)*/ +#define FB_ACTIVATE_NXTOPEN 1 /* activate on next open */ +#define FB_ACTIVATE_TEST 2 /* don't set, round up impossible */ +#define FB_ACTIVATE_MASK 15 + /* values */ +#define FB_ACTIVATE_VBL 16 /* activate values on next vbl */ +#define FB_CHANGE_CMAP_VBL 32 /* change colormap on vbl */ +#define FB_ACTIVATE_ALL 64 /* change all VCs on this fb */ +#define FB_ACTIVATE_FORCE 128 /* force apply even when no change*/ +#define FB_ACTIVATE_INV_MODE 256 /* invalidate videomode */ +#define FB_ACTIVATE_KD_TEXT 512 /* for KDSET vt ioctl */ + +#define FB_ACCELF_TEXT 1 /* (OBSOLETE) see fb_info.flags and vc_mode */ + +#define FB_SYNC_HOR_HIGH_ACT 1 /* horizontal sync high active */ +#define FB_SYNC_VERT_HIGH_ACT 2 /* vertical sync high active */ +#define FB_SYNC_EXT 4 /* external sync */ +#define FB_SYNC_COMP_HIGH_ACT 8 /* composite sync high active */ +#define FB_SYNC_BROADCAST 16 /* broadcast video timings */ + /* vtotal = 144d/288n/576i => PAL */ + /* vtotal = 121d/242n/484i => NTSC */ +#define FB_SYNC_ON_GREEN 32 /* sync on green */ + +#define FB_VMODE_NONINTERLACED 0 /* non interlaced */ +#define FB_VMODE_INTERLACED 1 /* interlaced */ +#define FB_VMODE_DOUBLE 2 /* double scan */ +#define FB_VMODE_ODD_FLD_FIRST 4 /* interlaced: top line first */ +#define FB_VMODE_MASK 255 + +#define FB_VMODE_YWRAP 256 /* ywrap instead of panning */ +#define FB_VMODE_SMOOTH_XPAN 512 /* smooth xpan possible (internally used) */ +#define FB_VMODE_CONUPDATE 512 /* don't update x/yoffset */ + +/* + * Display rotation support + */ +#define FB_ROTATE_UR 0 +#define FB_ROTATE_CW 1 +#define FB_ROTATE_UD 2 +#define FB_ROTATE_CCW 3 + +#define PICOS2KHZ(a) (1000000000UL/(a)) +#define KHZ2PICOS(a) (1000000000UL/(a)) + +struct fb_var_screeninfo { + uint32_t xres; /* visible resolution */ + uint32_t yres; + uint32_t xres_virtual; /* virtual resolution */ + uint32_t yres_virtual; + uint32_t xoffset; /* offset from virtual to visible */ + uint32_t yoffset; /* resolution */ + + uint32_t bits_per_pixel; /* guess what */ + uint32_t grayscale; /* 0 = color, 1 = grayscale, */ + /* >1 = FOURCC */ + struct fb_bitfield red; /* bitfield in fb mem if true color, */ + struct fb_bitfield green; /* else only length is significant */ + struct fb_bitfield blue; + struct fb_bitfield transp; /* transparency */ + + uint32_t nonstd; /* != 0 Non standard pixel format */ + + uint32_t activate; /* see FB_ACTIVATE_* */ + + uint32_t height; /* height of picture in mm */ + uint32_t width; /* width of picture in mm */ + + uint32_t accel_flags; /* (OBSOLETE) see fb_info.flags */ + + /* Timing: All values in pixclocks, except pixclock (of course) */ + uint32_t pixclock; /* pixel clock in ps (pico seconds) */ + uint32_t left_margin; /* time from sync to picture */ + uint32_t right_margin; /* time from picture to sync */ + uint32_t upper_margin; /* time from sync to picture */ + uint32_t lower_margin; + uint32_t hsync_len; /* length of horizontal sync */ + uint32_t vsync_len; /* length of vertical sync */ + uint32_t sync; /* see FB_SYNC_* */ + uint32_t vmode; /* see FB_VMODE_* */ + uint32_t rotate; /* angle we rotate counter clockwise */ + uint32_t colorspace; /* colorspace for FOURCC-based modes */ + uint32_t reserved[4]; /* Reserved for future compatibility */ +}; + +struct fb_cmap { + uint32_t start; /* First entry */ + uint32_t len; /* Number of entries */ + uint16_t *red; /* Red values */ + uint16_t *green; + uint16_t *blue; + uint16_t *transp; /* transparency, can be NULL */ +}; + +struct fb_con2fbmap { + uint32_t console; + uint32_t framebuffer; +}; + +/* VESA Blanking Levels */ +#define VESA_NO_BLANKING 0 +#define VESA_VSYNC_SUSPEND 1 +#define VESA_HSYNC_SUSPEND 2 +#define VESA_POWERDOWN 3 + + +enum { + /* screen: unblanked, hsync: on, vsync: on */ + FB_BLANK_UNBLANK = VESA_NO_BLANKING, + + /* screen: blanked, hsync: on, vsync: on */ + FB_BLANK_NORMAL = VESA_NO_BLANKING + 1, + + /* screen: blanked, hsync: on, vsync: off */ + FB_BLANK_VSYNC_SUSPEND = VESA_VSYNC_SUSPEND + 1, + + /* screen: blanked, hsync: off, vsync: on */ + FB_BLANK_HSYNC_SUSPEND = VESA_HSYNC_SUSPEND + 1, + + /* screen: blanked, hsync: off, vsync: off */ + FB_BLANK_POWERDOWN = VESA_POWERDOWN + 1 +}; + +#define FB_VBLANK_VBLANKING 0x001 /* currently in a vertical blank */ +#define FB_VBLANK_HBLANKING 0x002 /* currently in a horizontal blank */ +#define FB_VBLANK_HAVE_VBLANK 0x004 /* vertical blanks can be detected */ +#define FB_VBLANK_HAVE_HBLANK 0x008 /* horizontal blanks can be detected */ +#define FB_VBLANK_HAVE_COUNT 0x010 /* global retrace counter is available */ +#define FB_VBLANK_HAVE_VCOUNT 0x020 /* the vcount field is valid */ +#define FB_VBLANK_HAVE_HCOUNT 0x040 /* the hcount field is valid */ +#define FB_VBLANK_VSYNCING 0x080 /* currently in a vsync */ +#define FB_VBLANK_HAVE_VSYNC 0x100 /* verical syncs can be detected */ + +struct fb_vblank { + uint32_t flags; /* FB_VBLANK flags */ + uint32_t count; /* counter of retraces since boot */ + uint32_t vcount; /* current scanline position */ + uint32_t hcount; /* current scandot position */ + uint32_t reserved[4]; /* reserved for future compatibility */ +}; + +/* Internal HW accel */ +#define ROP_COPY 0 +#define ROP_XOR 1 + +struct fb_copyarea { + uint32_t dx; + uint32_t dy; + uint32_t width; + uint32_t height; + uint32_t sx; + uint32_t sy; +}; + +struct fb_fillrect { + uint32_t dx; /* screen-relative */ + uint32_t dy; + uint32_t width; + uint32_t height; + uint32_t color; + uint32_t rop; +}; + +struct fb_image { + uint32_t dx; /* Where to place image */ + uint32_t dy; + uint32_t width; /* Size of image */ + uint32_t height; + uint32_t fg_color; /* Only used when a mono bitmap */ + uint32_t bg_color; + uint8_t depth; /* Depth of the image */ + const char *data; /* Pointer to image data */ + struct fb_cmap cmap; /* color map info */ +}; + +/* + * hardware cursor control + */ + +#define FB_CUR_SETIMAGE 0x01 +#define FB_CUR_SETPOS 0x02 +#define FB_CUR_SETHOT 0x04 +#define FB_CUR_SETCMAP 0x08 +#define FB_CUR_SETSHAPE 0x10 +#define FB_CUR_SETSIZE 0x20 +#define FB_CUR_SETALL 0xFF + +struct fbcurpos { + uint16_t x, y; +}; + +struct fb_cursor { + uint16_t set; /* what to set */ + uint16_t enable; /* cursor on/off */ + uint16_t rop; /* bitop operation */ + const char *mask; /* cursor mask bits */ + struct fbcurpos hot; /* cursor hot spot */ + struct fb_image image; /* Cursor image */ +}; + +/* Settings for the generic backlight code */ +#define FB_BACKLIGHT_LEVELS 128 +#define FB_BACKLIGHT_MAX 0xFF + + +#endif /* _LINUX_FB_H */ diff --git a/lib/mlibc/sysdeps/lyre/include/lyre/sockios.h b/lib/mlibc/sysdeps/lyre/include/lyre/sockios.h new file mode 100644 index 0000000..9c5a318 --- /dev/null +++ b/lib/mlibc/sysdeps/lyre/include/lyre/sockios.h @@ -0,0 +1,25 @@ +#ifndef _LYRE__SOCKIOS_H +#define _LYRE__SOCKIOS_H + +#include + +#define SIOCINQ FIONREAD +#define SIOCOUTQ TIOCOUTQ + +#define SIOCGIFNAME 0x8910 /* get interface name */ +#define SIOCGIFFLAGS 0x8911 /* get flags */ +#define SIOCSIFFLAGS 0x8912 /* set flags */ +#define SIOCGIFADDR 0x8913 /* get interface ip */ +#define SIOCSIFADDR 0x8914 /* set interface ip */ +#define SIOCGIFNETMASK 0x8915 /* set netmask */ +#define SIOCSIFNETMASK 0x8916 /* get netmask */ +#define SIOCGIFMTU 0x8917 /* get mtu */ +#define SIOCSIFMTU 0x8918 /* set mtu */ +#define SIOCSIFNAME 0x8919 /* set interface name */ +#define SIOCSIFHWADDR 0x891a /* set mac address */ +#define SIOCGIFHWADDR 0x891b /* get mac address */ +#define SIOCGIFINDEX 0x891c /* get interface index */ +#define SIOCGIFGATEWAY 0x891d /* get gateway ip */ +#define SIOCSIFGATEWAY 0x891e /* set gateway ip */ + +#endif diff --git a/lib/mlibc/sysdeps/lyre/include/lyre/syscall.h b/lib/mlibc/sysdeps/lyre/include/lyre/syscall.h new file mode 100644 index 0000000..531b869 --- /dev/null +++ b/lib/mlibc/sysdeps/lyre/include/lyre/syscall.h @@ -0,0 +1,113 @@ +#ifndef _LYRE__SYSCALL_H +#define _LYRE__SYSCALL_H + +#include + +#define SYS_debug 0 +#define SYS_mmap 1 +#define SYS_openat 2 +#define SYS_close 3 +#define SYS_read 4 +#define SYS_write 5 +#define SYS_seek 6 +#define SYS_set_fs_base 7 +#define SYS_set_gs_base 8 +#define SYS_stat 9 +#define SYS_fcntl 10 +#define SYS_dup3 11 +#define SYS_ioctl 12 +#define SYS_fork 13 +#define SYS_exec 14 +#define SYS_getpid 15 +#define SYS_waitpid 16 +#define SYS_exit 17 +#define SYS_getcwd 18 +#define SYS_chdir 19 +#define SYS_unmmap 20 +#define SYS_pipe 21 +#define SYS_readlinkat 22 +#define SYS_linkat 23 +#define SYS_unlinkat 24 +#define SYS_readdir 25 +#define SYS_uname 26 +#define SYS_futex_wait 27 +#define SYS_futex_wake 28 +#define SYS_mkdirat 29 +#define SYS_fchmodat 30 +#define SYS_sleep 31 +#define SYS_ppoll 32 +#define SYS_umask 33 +#define SYS_mprotect 34 +#define SYS_getclock 35 +#define SYS_socket 36 +#define SYS_bind 37 +#define SYS_connect 38 +#define SYS_listen 39 +#define SYS_accept 40 +#define SYS_getpeername 41 +#define SYS_recvmsg 42 +#define SYS_new_thread 43 +#define SYS_exit_thread 44 +#define SYS_sendmsg 45 +#define SYS_socketpair 46 +#define SYS_getsockopt 47 +#define SYS_setsockopt 48 +#define SYS_getsockname 49 + +struct __syscall_ret { + uint64_t ret; + uint64_t errno; +}; + +#define __SYSCALL_EXPAND(...) \ + struct __syscall_ret ret; \ + asm volatile ( \ + "mov %%rsp, %%r10\n\t" \ + "lea 1f(%%rip), %%r11\n\t" \ + "sysenter\n\t" \ + "1:" \ + : "=a"(ret.ret), "=b"(ret.errno) __VA_ARGS__ \ + "r10", "r11", "memory" \ + ); \ + return ret + +static inline struct __syscall_ret __syscall5(int number, uint64_t a, uint64_t b, uint64_t c, uint64_t d, uint64_t e) { + register uint64_t r8 asm("%r8") = d; + register uint64_t r9 asm("%r9") = e; + __SYSCALL_EXPAND(, "+d"(b), "+c"(c) : "D"(number), "S"(a), "r"(r8), "r"(r9) :); +} + +static inline struct __syscall_ret __syscall4(int number, uint64_t a, uint64_t b, uint64_t c, uint64_t d) { + register uint64_t r8 asm("%r8") = d; + __SYSCALL_EXPAND(, "+d"(b), "+c"(c) : "D"(number), "S"(a), "r"(r8) :); +} + +static inline struct __syscall_ret __syscall3(int number, uint64_t a, uint64_t b, uint64_t c) { + __SYSCALL_EXPAND(, "+d"(b), "+c"(c) : "D"(number), "S"(a) :); +} + +static inline struct __syscall_ret __syscall2(int number, uint64_t a, uint64_t b) { + __SYSCALL_EXPAND(, "+d"(b) : "D"(number), "S"(a) : "rcx", ); +} + +static inline struct __syscall_ret __syscall1(int number, uint64_t a) { + __SYSCALL_EXPAND( : "D"(number), "S"(a) : "rcx", "rdx", ); +} + +static inline struct __syscall_ret __syscall0(int number) { + __SYSCALL_EXPAND( : "D"(number) : "rcx", "rdx", ); +} + +#define __SYSCALL_NARGS_SEQ(_0,_1,_2,_3,_4,_5,_6,_7,N,...) N +#define __SYSCALL_NARGS(...) __SYSCALL_NARGS_SEQ(__VA_ARGS__, 7, 6, 5, 4, 3, 2, 1, 0) + +#define __SYSCALL_CONCAT1(X, Y) X##Y +#define __SYSCALL_CONCAT(X, Y) __SYSCALL_CONCAT1(X, Y) + +#define __syscall(...) ({ \ + struct __syscall_ret (*__SYSCALL_f)(int, ...); \ + __SYSCALL_f = (struct __syscall_ret (*)(int, ...))__SYSCALL_CONCAT(__syscall, __SYSCALL_NARGS(__VA_ARGS__)); \ + __SYSCALL_f(__VA_ARGS__); \ +}) + +#endif diff --git a/lib/mlibc/sysdeps/lyre/include/mntent.h b/lib/mlibc/sysdeps/lyre/include/mntent.h new file mode 100644 index 0000000..bafd289 --- /dev/null +++ b/lib/mlibc/sysdeps/lyre/include/mntent.h @@ -0,0 +1,50 @@ +#ifndef _MNTENT_H +#define _MNTENT_H + +#include + +// TODO: Refer to _PATH_MOUNTED +#define MOUNTED "/etc/mtab" + +/* Generic mount options */ +#define MNTOPT_DEFAULTS "defaults" /* Use all default options. */ +#define MNTOPT_RO "ro" /* Read only. */ +#define MNTOPT_RW "rw" /* Read/write. */ +#define MNTOPT_SUID "suid" /* Set uid allowed. */ +#define MNTOPT_NOSUID "nosuid" /* No set uid allowed. */ +#define MNTOPT_NOAUTO "noauto" /* Do not auto mount. */ + +#ifdef __cplusplus +extern "C" { +#endif + +struct mntent { + char *mnt_fsname; + char *mnt_dir; + char *mnt_type; + char *mnt_opts; + int mnt_freq; + int mnt_passno; +}; + +#ifndef __MLIBC_ABI_ONLY + +FILE *setmntent(const char *, const char *); + +struct mntent *getmntent(FILE *); + +int addmntent(FILE *, const struct mntent *); + +int endmntent(FILE *); + +char *hasmntopt(const struct mntent *, const char *); + +struct mntent *getmntent_r(FILE *, struct mntent *, char *, int); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif // _MNTENT_H diff --git a/lib/mlibc/sysdeps/lyre/include/sys/mount.h b/lib/mlibc/sysdeps/lyre/include/sys/mount.h new file mode 100644 index 0000000..b19f3d7 --- /dev/null +++ b/lib/mlibc/sysdeps/lyre/include/sys/mount.h @@ -0,0 +1,54 @@ +#ifndef _SYS_MOUNT_H +#define _SYS_MOUNT_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define MS_RDONLY 1 +#define MS_NOSUID 2 +#define MS_NODEV 4 +#define MS_NOEXEC 8 +#define MS_SYNCHRONOUS 16 +#define MS_REMOUNT 32 +#define MS_MANDLOCK 64 +#define MS_DIRSYNC 128 +#define MS_NOSYMFOLLOW 256 +#define MS_NOATIME 1024 +#define MS_NODIRATIME 2048 +#define MS_BIND 4096 +#define MS_MOVE 8192 +#define MS_REC 16384 +#define MS_SILENT 32768 +#define MS_POSIXACL (1 << 16) +#define MS_UNBINDABLE (1 << 17) +#define MS_PRIVATE (1 << 18) +#define MS_SLAVE (1 << 19) +#define MS_SHARED (1 << 20) +#define MS_RELATIME (1 << 21) +#define MS_KERNMOUNT (1 << 22) +#define MS_I_VERSION (1 << 23) +#define MS_STRICTATIME (1 << 24) +#define MS_LAZYTIME (1 << 25) +#define MS_NOREMOTELOCK (1 << 27) +#define MS_NOSEC (1 << 28) +#define MS_BORN (1 << 29) +#define MS_ACTIVE (1 << 30) +#define MS_NOUSER (1 << 31) + +#define MNT_FORCE 1 + +#ifndef __MLIBC_ABI_ONLY + +int mount(const char *source, const char *target, + const char *fstype, unsigned long flags, const void *data); +int umount(const char *target); +int umount2(const char *target, int flags); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif // _SYS_MOUNT_H diff --git a/lib/mlibc/sysdeps/lyre/include/sys/reboot.h b/lib/mlibc/sysdeps/lyre/include/sys/reboot.h new file mode 100644 index 0000000..6c4e495 --- /dev/null +++ b/lib/mlibc/sysdeps/lyre/include/sys/reboot.h @@ -0,0 +1,20 @@ +#ifndef MLIBC_SYS_REBOOT_H +#define MLIBC_SYS_REBOOT_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MLIBC_ABI_ONLY + +int reboot(int arg); + +#endif /* !__MLIBC_ABI_ONLY */ + +#ifdef __cplusplus +} +#endif + +#endif // MLIBC_SYS_REBOOT_H diff --git a/lib/mlibc/sysdeps/lyre/include/sys/sysmacros.h b/lib/mlibc/sysdeps/lyre/include/sys/sysmacros.h new file mode 100644 index 0000000..2d696e3 --- /dev/null +++ b/lib/mlibc/sysdeps/lyre/include/sys/sysmacros.h @@ -0,0 +1,33 @@ +#ifndef _SYS_SYSMACROS_H +#define _SYS_SYSMACROS_H + +#ifdef __cplusplus +extern "C" { +#endif + +static unsigned int __mlibc_dev_major( + unsigned long long int __dev) { + return ((__dev >> 8) & 0xfff) | ((unsigned int)(__dev >> 32) & ~0xfff); +} + +static unsigned int __mlibc_dev_minor( + unsigned long long int __dev) { + return (__dev & 0xff) | ((unsigned int)(__dev >> 12) & ~0xff); +} + +static unsigned long long int __mlibc_dev_makedev( + unsigned int __major, unsigned int __minor) { + return ((__minor & 0xff) | ((__major & 0xfff) << 8) + | (((unsigned long long int)(__minor & ~0xff)) << 12) + | (((unsigned long long int)(__major & ~0xfff)) << 32)); +} + +#define major(dev) __mlibc_dev_major(dev) +#define minor(dev) __mlibc_dev_minor(dev) +#define makedev(major, minor) __mlibc_dev_makedev(major, minor) + +#ifdef __cplusplus +} +#endif + +#endif // _SYS_SYSMACROS_H diff --git a/lib/mlibc/sysdeps/lyre/meson.build b/lib/mlibc/sysdeps/lyre/meson.build new file mode 100644 index 0000000..56ed19a --- /dev/null +++ b/lib/mlibc/sysdeps/lyre/meson.build @@ -0,0 +1,122 @@ + +rtdl_sources += files( + 'generic/generic.cpp' +) + +libc_sources += files( + 'generic/entry.cpp', + 'generic/generic.cpp', + 'generic/mntent.cpp', + 'generic/mount.cpp', + 'generic/reboot.cpp', + 'generic/thread.cpp', + 'generic/thread.S' +) + +if not no_headers + install_headers( + 'include/abi-bits/auxv.h', + 'include/abi-bits/seek-whence.h', + 'include/abi-bits/vm-flags.h', + 'include/abi-bits/errno.h', + 'include/abi-bits/fcntl.h', + 'include/abi-bits/in.h', + 'include/abi-bits/reboot.h', + 'include/abi-bits/resource.h', + 'include/abi-bits/stat.h', + 'include/abi-bits/signal.h', + 'include/abi-bits/socket.h', + 'include/abi-bits/termios.h', + 'include/abi-bits/time.h', + 'include/abi-bits/blkcnt_t.h', + 'include/abi-bits/blksize_t.h', + 'include/abi-bits/dev_t.h', + 'include/abi-bits/gid_t.h', + 'include/abi-bits/ino_t.h', + 'include/abi-bits/mode_t.h', + 'include/abi-bits/nlink_t.h', + 'include/abi-bits/pid_t.h', + 'include/abi-bits/uid_t.h', + 'include/abi-bits/access.h', + 'include/abi-bits/wait.h', + 'include/abi-bits/limits.h', + 'include/abi-bits/utsname.h', + 'include/abi-bits/ptrace.h', + 'include/abi-bits/poll.h', + 'include/abi-bits/epoll.h', + 'include/abi-bits/packet.h', + 'include/abi-bits/inotify.h', + 'include/abi-bits/clockid_t.h', + 'include/abi-bits/shm.h', + 'include/abi-bits/mqueue.h', + 'include/abi-bits/suseconds_t.h', + 'include/abi-bits/fsfilcnt_t.h', + 'include/abi-bits/fsblkcnt_t.h', + 'include/abi-bits/socklen_t.h', + 'include/abi-bits/statfs.h', + 'include/abi-bits/statvfs.h', + 'include/abi-bits/ioctls.h', + 'include/abi-bits/xattr.h', + 'include/abi-bits/msg.h', + subdir: 'abi-bits', + follow_symlinks: true + ) + + install_headers( + 'include/asm/ioctl.h', + 'include/asm/ioctls.h', + subdir: 'asm', + ) + + install_headers( + 'include/linux/fb.h', + subdir: 'linux', + ) + + install_headers( + 'include/sys/reboot.h', + 'include/sys/mount.h', + 'include/sys/sysmacros.h', + subdir: 'sys', + ) + + install_headers( + 'include/lyre/syscall.h', + 'include/lyre/sockios.h', + subdir: 'lyre', + ) + + install_headers( + 'include/mntent.h', + ) +endif + +if not headers_only + crt = custom_target('crt0', + build_by_default: true, + command: c_compiler.cmd_array() + ['-c', '-o', '@OUTPUT@', '@INPUT@'], + input: host_machine.cpu_family() / 'crt-src/crt0.S', + output: 'crt0.o', + install: true, + install_dir: get_option('libdir') + ) + + custom_target('crti', + build_by_default: true, + command: c_compiler.cmd_array() + ['-c', '-o', '@OUTPUT@', '@INPUT@'], + input: host_machine.cpu_family() / 'crt-src/crti.S', + output: 'crti.o', + install: true, + install_dir: get_option('libdir') + ) + + custom_target('crtn', + build_by_default: true, + command: c_compiler.cmd_array() + ['-c', '-o', '@OUTPUT@', '@INPUT@'], + input: host_machine.cpu_family() / 'crt-src/crtn.S', + output: 'crtn.o', + install: true, + install_dir: get_option('libdir') + ) +endif + diff --git a/lib/mlibc/sysdeps/lyre/x86_64/crt-src/crt0.S b/lib/mlibc/sysdeps/lyre/x86_64/crt-src/crt0.S new file mode 100644 index 0000000..d16a46f --- /dev/null +++ b/lib/mlibc/sysdeps/lyre/x86_64/crt-src/crt0.S @@ -0,0 +1,7 @@ +.section .text +.global _start +_start: + mov $main, %rdi + call __mlibc_entry +.section .note.GNU-stack,"",%progbits + diff --git a/lib/mlibc/sysdeps/lyre/x86_64/crt-src/crti.S b/lib/mlibc/sysdeps/lyre/x86_64/crt-src/crti.S new file mode 100644 index 0000000..911b078 --- /dev/null +++ b/lib/mlibc/sysdeps/lyre/x86_64/crt-src/crti.S @@ -0,0 +1,11 @@ +.section .init +.global _init +_init: + push %rax + +.section .fini +.global _fini +_fini: + push %rax +.section .note.GNU-stack,"",%progbits + diff --git a/lib/mlibc/sysdeps/lyre/x86_64/crt-src/crtn.S b/lib/mlibc/sysdeps/lyre/x86_64/crt-src/crtn.S new file mode 100644 index 0000000..0187e50 --- /dev/null +++ b/lib/mlibc/sysdeps/lyre/x86_64/crt-src/crtn.S @@ -0,0 +1,9 @@ +.section .init + pop %rax + ret + +.section .fini + pop %rax + ret +.section .note.GNU-stack,"",%progbits + diff --git a/lib/mlibc/sysdeps/managarm/aarch64/crt-src/Scrt1.S b/lib/mlibc/sysdeps/managarm/aarch64/crt-src/Scrt1.S new file mode 100644 index 0000000..3e56608 --- /dev/null +++ b/lib/mlibc/sysdeps/managarm/aarch64/crt-src/Scrt1.S @@ -0,0 +1,10 @@ +.section .text +.global _start +_start: + mov x0, sp + adr x1, main + + bl __mlibc_entry + brk #0 + +.section .note.GNU-stack,"",%progbits diff --git a/lib/mlibc/sysdeps/managarm/aarch64/crt-src/crt0.S b/lib/mlibc/sysdeps/managarm/aarch64/crt-src/crt0.S new file mode 100644 index 0000000..5e59593 --- /dev/null +++ b/lib/mlibc/sysdeps/managarm/aarch64/crt-src/crt0.S @@ -0,0 +1,11 @@ + +.section .text +.global _start +_start: + mov x0, sp + adrp x1, main + add x1, x1, :lo12:main + bl __mlibc_entry + +.section .note.GNU-stack,"",%progbits + diff --git a/lib/mlibc/sysdeps/managarm/aarch64/crt-src/crti.S b/lib/mlibc/sysdeps/managarm/aarch64/crt-src/crti.S new file mode 100644 index 0000000..4307dfb --- /dev/null +++ b/lib/mlibc/sysdeps/managarm/aarch64/crt-src/crti.S @@ -0,0 +1,15 @@ + .ident "aarch64-managarm-mlibc crti" + + .section .init + .global _init +_init: + stp x29, x30, [sp, -16]! + mov x29, sp + + .section .fini + .global _fini +_fini: + stp x29, x30, [sp, -16]! + mov x29, sp + + .section .note.GNU-stack,"",%progbits diff --git a/lib/mlibc/sysdeps/managarm/aarch64/crt-src/crtn.S b/lib/mlibc/sysdeps/managarm/aarch64/crt-src/crtn.S new file mode 100644 index 0000000..005d870 --- /dev/null +++ b/lib/mlibc/sysdeps/managarm/aarch64/crt-src/crtn.S @@ -0,0 +1,11 @@ + .ident "aarch64-managarm-mlibc crtn" + + .section .init + ldp x29, x30, [sp], #16 + ret + + .section .fini + ldp x29, x30, [sp], #16 + ret + + .section .note.GNU-stack,"",%progbits diff --git a/lib/mlibc/sysdeps/managarm/aarch64/signals.S b/lib/mlibc/sysdeps/managarm/aarch64/signals.S new file mode 100644 index 0000000..044767d --- /dev/null +++ b/lib/mlibc/sysdeps/managarm/aarch64/signals.S @@ -0,0 +1,10 @@ + +.section .text +.global __mlibc_signal_restore +__mlibc_signal_restore: + ldr x0, =0x80000006 + svc 0 + brk #1 + +.section .note.GNU-stack,"",%progbits + diff --git a/lib/mlibc/sysdeps/managarm/aarch64/thread.cpp b/lib/mlibc/sysdeps/managarm/aarch64/thread.cpp new file mode 100644 index 0000000..88f1bf3 --- /dev/null +++ b/lib/mlibc/sysdeps/managarm/aarch64/thread.cpp @@ -0,0 +1,56 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +extern "C" void __mlibc_enter_thread(void *entry, void *user_arg, Tcb *tcb) { + // Wait until our parent sets up the TID. + while(!__atomic_load_n(&tcb->tid, __ATOMIC_RELAXED)) + mlibc::sys_futex_wait(&tcb->tid, 0, nullptr); + + if(mlibc::sys_tcb_set(tcb)) + __ensure(!"sys_tcb_set() failed"); + + tcb->invokeThreadFunc(entry, user_arg); + + auto self = reinterpret_cast(tcb); + + __atomic_store_n(&self->didExit, 1, __ATOMIC_RELEASE); + mlibc::sys_futex_wake(&self->didExit); + + mlibc::sys_thread_exit(); +} + +namespace mlibc { + +static constexpr size_t default_stacksize = 0x200000; + +int sys_prepare_stack(void **stack, void *entry, void *user_arg, void *tcb, size_t *stack_size, size_t *guard_size, void **stack_base) { + if (!*stack_size) + *stack_size = default_stacksize; + *guard_size = 0; + + if (*stack) { + *stack_base = *stack; + } else { + *stack_base = mmap(nullptr, *stack_size, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if(*stack_base == MAP_FAILED) { + return errno; + } + } + + uintptr_t *sp = reinterpret_cast(reinterpret_cast(*stack_base) + *stack_size); + + *--sp = reinterpret_cast(tcb); + *--sp = reinterpret_cast(user_arg); + *--sp = reinterpret_cast(entry); + *stack = reinterpret_cast(sp); + return 0; +} + +} //namespace mlibc diff --git a/lib/mlibc/sysdeps/managarm/aarch64/thread_entry.S b/lib/mlibc/sysdeps/managarm/aarch64/thread_entry.S new file mode 100644 index 0000000..4cfcb4c --- /dev/null +++ b/lib/mlibc/sysdeps/managarm/aarch64/thread_entry.S @@ -0,0 +1,11 @@ + +.section .text +.global __mlibc_start_thread +__mlibc_start_thread: + ldp x0, x1, [sp] + ldr x2, [sp, #16] + add sp, sp, #24 + bl __mlibc_enter_thread + +.section .note.GNU-stack,"",%progbits + diff --git a/lib/mlibc/sysdeps/managarm/generic/drm.cpp b/lib/mlibc/sysdeps/managarm/generic/drm.cpp new file mode 100644 index 0000000..805c366 --- /dev/null +++ b/lib/mlibc/sysdeps/managarm/generic/drm.cpp @@ -0,0 +1,1176 @@ +#include +#include + +#include +#include +#include +#include +#include + +#include + +namespace mlibc { + +int ioctl_drm(int fd, unsigned long request, void *arg, int *result, HelHandle handle) { + managarm::fs::IoctlRequest ioctl_req(getSysdepsAllocator()); + + switch(request) { + case DRM_IOCTL_VERSION: { + auto param = reinterpret_cast(arg); + + managarm::fs::GenericIoctlRequest req(getSysdepsAllocator()); + req.set_command(request); + + auto [offer, send_ioctl_req, send_req, recv_resp] = exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(ioctl_req, getSysdepsAllocator()), + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline()) + ); + HEL_CHECK(offer.error()); + HEL_CHECK(send_ioctl_req.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::fs::GenericIoctlReply resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + __ensure(resp.error() == managarm::fs::Errors::SUCCESS); + + param->version_major = resp.drm_version_major(); + param->version_minor = resp.drm_version_minor(); + param->version_patchlevel = resp.drm_version_patchlevel(); + + if(param->name) + memcpy(param->name, resp.drm_driver_name().data(), frg::min(param->name_len, + resp.drm_driver_name().size())); + if(param->date) + memcpy(param->date, resp.drm_driver_date().data(), frg::min(param->date_len, + resp.drm_driver_date().size())); + if(param->desc) + memcpy(param->desc, resp.drm_driver_desc().data(), frg::min(param->desc_len, + resp.drm_driver_desc().size())); + + param->name_len = resp.drm_driver_name().size(); + param->date_len = resp.drm_driver_date().size(); + param->desc_len = resp.drm_driver_desc().size(); + + *result = resp.result(); + return 0; + } + case DRM_IOCTL_GET_CAP: { + auto param = reinterpret_cast(arg); + + managarm::fs::GenericIoctlRequest req(getSysdepsAllocator()); + req.set_command(request); + req.set_drm_capability(param->capability); + + auto [offer, send_ioctl_req, send_req, recv_resp] = exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(ioctl_req, getSysdepsAllocator()), + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline()) + ); + HEL_CHECK(offer.error()); + HEL_CHECK(send_ioctl_req.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::fs::GenericIoctlReply resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + + if(resp.error() == managarm::fs::Errors::ILLEGAL_ARGUMENT) { + return EINVAL; + }else{ + __ensure(resp.error() == managarm::fs::Errors::SUCCESS); + + param->value = resp.drm_value(); + *result = resp.result(); + return 0; + } + } + case DRM_IOCTL_SET_CLIENT_CAP: { + auto param = reinterpret_cast(arg); + mlibc::infoLogger() << "\e[35mmlibc: DRM_IOCTL_SET_CLIENT_CAP(" << param->capability << ") ignores its value\e[39m" << frg::endlog; + + managarm::fs::GenericIoctlRequest req(getSysdepsAllocator()); + req.set_command(request); + req.set_drm_capability(param->capability); + + auto [offer, send_ioctl_req, send_req, recv_resp] = exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(ioctl_req, getSysdepsAllocator()), + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline()) + ); + HEL_CHECK(offer.error()); + HEL_CHECK(send_ioctl_req.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::fs::GenericIoctlReply resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + + if(resp.error() == managarm::fs::Errors::ILLEGAL_ARGUMENT) { + return EINVAL; + }else{ + __ensure(resp.error() == managarm::fs::Errors::SUCCESS); + + param->value = resp.drm_value(); + *result = resp.result(); + return 0; + } + } + case DRM_IOCTL_GET_MAGIC: { + auto param = reinterpret_cast(arg); + mlibc::infoLogger() << "\e[31mmlibc: DRM_IOCTL_GET_MAGIC is not implemented correctly\e[39m" + << frg::endlog; + param->magic = 1; + *result = 0; + return 0; + } + case DRM_IOCTL_AUTH_MAGIC: { + mlibc::infoLogger() << "\e[31mmlibc: DRM_IOCTL_AUTH_MAGIC is not implemented correctly\e[39m" + << frg::endlog; + *result = 0; + return 0; + } + case DRM_IOCTL_SET_MASTER: { + mlibc::infoLogger() << "\e[31mmlibc: DRM_IOCTL_SET_MASTER is not implemented correctly\e[39m" + << frg::endlog; + *result = 0; + return 0; + } + case DRM_IOCTL_DROP_MASTER: { + mlibc::infoLogger() << "\e[31mmlibc: DRM_IOCTL_DROP_MASTER is not implemented correctly\e[39m" + << frg::endlog; + *result = 0; + return 0; + } + case DRM_IOCTL_MODE_GETRESOURCES: { + auto param = reinterpret_cast(arg); + + managarm::fs::GenericIoctlRequest req(getSysdepsAllocator()); + req.set_command(request); + + auto [offer, send_ioctl_req, send_req, recv_resp] = exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(ioctl_req, getSysdepsAllocator()), + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline()) + ); + HEL_CHECK(offer.error()); + HEL_CHECK(send_ioctl_req.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + if(recv_resp.error() == kHelErrDismissed) { + return EINVAL; + } + + managarm::fs::GenericIoctlReply resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + + __ensure(resp.error() == managarm::fs::Errors::SUCCESS); + + for(size_t i = 0; i < resp.drm_fb_ids_size(); i++) { + if(i >= param->count_fbs) + break; + auto dest = reinterpret_cast(param->fb_id_ptr); + dest[i] = resp.drm_fb_ids(i); + } + param->count_fbs = resp.drm_fb_ids_size(); + + for(size_t i = 0; i < resp.drm_crtc_ids_size(); i++) { + if(i >= param->count_crtcs) + break; + auto dest = reinterpret_cast(param->crtc_id_ptr); + dest[i] = resp.drm_crtc_ids(i); + } + param->count_crtcs = resp.drm_crtc_ids_size(); + + for(size_t i = 0; i < resp.drm_connector_ids_size(); i++) { + if(i >= param->count_connectors) + break; + auto dest = reinterpret_cast(param->connector_id_ptr); + dest[i] = resp.drm_connector_ids(i); + } + param->count_connectors = resp.drm_connector_ids_size(); + + for(size_t i = 0; i < resp.drm_encoder_ids_size(); i++) { + if(i >= param->count_encoders) + continue; + auto dest = reinterpret_cast(param->encoder_id_ptr); + dest[i] = resp.drm_encoder_ids(i); + } + param->count_encoders = resp.drm_encoder_ids_size(); + + param->min_width = resp.drm_min_width(); + param->max_width = resp.drm_max_width(); + param->min_height = resp.drm_min_height(); + param->max_height = resp.drm_max_height(); + + *result = resp.result(); + return 0; + } + case DRM_IOCTL_MODE_GETCONNECTOR: { + auto param = reinterpret_cast(arg); + + managarm::fs::GenericIoctlRequest req(getSysdepsAllocator()); + req.set_command(request); + req.set_drm_connector_id(param->connector_id); + req.set_drm_max_modes(param->count_modes); + + auto [offer, send_ioctl_req, send_req, recv_resp, recv_list] = exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(ioctl_req, getSysdepsAllocator()), + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline(), + helix_ng::recvBuffer(reinterpret_cast(param->modes_ptr), param->count_modes * sizeof(drm_mode_modeinfo)) + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_ioctl_req.error()); + HEL_CHECK(send_req.error()); + if(recv_resp.error() == kHelErrDismissed) + return EINVAL; + + HEL_CHECK(recv_resp.error()); + HEL_CHECK(recv_list.error()); + + managarm::fs::GenericIoctlReply resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + __ensure(resp.error() == managarm::fs::Errors::SUCCESS); + + for(size_t i = 0; i < resp.drm_encoders_size(); i++) { + if(i >= param->count_encoders) + continue; + auto dest = reinterpret_cast(param->encoders_ptr); + dest[i] = resp.drm_encoders(i); + } + + param->encoder_id = resp.drm_encoder_id(); + param->connector_type = resp.drm_connector_type(); + param->connector_type_id = resp.drm_connector_type_id(); + param->connection = resp.drm_connection(); + param->mm_width = resp.drm_mm_width(); + param->mm_height = resp.drm_mm_height(); + param->subpixel = resp.drm_subpixel(); + param->pad = 0; + param->count_encoders = resp.drm_encoders_size(); + param->count_modes = resp.drm_num_modes(); + + if(param->props_ptr) { + auto id_ptr = reinterpret_cast(param->props_ptr); + auto val_ptr = reinterpret_cast(param->prop_values_ptr); + + for(size_t i = 0; i < frg::min(static_cast(param->count_props), resp.drm_obj_property_ids_size()); i++) { + id_ptr[i] = resp.drm_obj_property_ids(i); + val_ptr[i] = resp.drm_obj_property_values(i); + } + } + + param->count_props = resp.drm_obj_property_ids_size(); + + *result = resp.result(); + return 0; + } + case DRM_IOCTL_MODE_GETPROPERTY: { + auto param = reinterpret_cast(arg); + + managarm::fs::GenericIoctlRequest req(getSysdepsAllocator()); + req.set_command(request); + req.set_drm_property_id(param->prop_id); + + auto [offer, send_ioctl_req, send_req, recv_resp] = exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(ioctl_req, getSysdepsAllocator()), + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline()) + ); + HEL_CHECK(offer.error()); + HEL_CHECK(send_ioctl_req.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::fs::GenericIoctlReply resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + + if(resp.error() != managarm::fs::Errors::SUCCESS) { + mlibc::infoLogger() << "\e[31mmlibc: DRM_IOCTL_MODE_GETPROPERTY(" << param->prop_id << ") error " << (int) resp.error() << "\e[39m" + << frg::endlog; + *result = 0; + return EINVAL; + } + + memcpy(param->name, resp.drm_property_name().data(), resp.drm_property_name().size()); + param->count_values = resp.drm_property_vals_size(); + param->flags = resp.drm_property_flags(); + + for(size_t i = 0; i < param->count_values && i < resp.drm_property_vals_size() && param->values_ptr; i++) { + auto dest = reinterpret_cast(param->values_ptr); + dest[i] = resp.drm_property_vals(i); + } + + __ensure(resp.drm_enum_name_size() == resp.drm_enum_value_size()); + + for(size_t i = 0; i < param->count_enum_blobs && i < resp.drm_enum_name_size() && i < resp.drm_enum_value_size(); i++) { + auto dest = reinterpret_cast(param->enum_blob_ptr); + dest[i].value = resp.drm_enum_value(i); + strncpy(dest[i].name, resp.drm_enum_name(i).data(), DRM_PROP_NAME_LEN); + } + + param->count_enum_blobs = resp.drm_enum_name_size(); + + *result = 0; + return 0; + } + case DRM_IOCTL_MODE_SETPROPERTY: { + auto param = reinterpret_cast(arg); + + managarm::fs::GenericIoctlRequest req(getSysdepsAllocator()); + req.set_command(request); + req.set_drm_property_id(param->prop_id); + req.set_drm_property_value(param->value); + req.set_drm_obj_id(param->connector_id); + + auto [offer, send_ioctl_req, send_req, recv_resp] = exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(ioctl_req, getSysdepsAllocator()), + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline()) + ); + HEL_CHECK(offer.error()); + HEL_CHECK(send_ioctl_req.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::fs::GenericIoctlReply resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + + if(resp.error() != managarm::fs::Errors::SUCCESS) { + mlibc::infoLogger() << "\e[31mmlibc: DRM_IOCTL_MODE_SETPROPERTY(" << param->prop_id << ") error " << (int) resp.error() << "\e[39m" + << frg::endlog; + *result = 0; + return EINVAL; + } + + *result = resp.result(); + return 0; + } + case DRM_IOCTL_MODE_GETPROPBLOB: { + auto param = reinterpret_cast(arg); + + managarm::fs::GenericIoctlRequest req(getSysdepsAllocator()); + req.set_command(request); + req.set_drm_blob_id(param->blob_id); + + auto [offer, send_ioctl_req, send_req, recv_resp] = exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(ioctl_req, getSysdepsAllocator()), + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline()) + ); + HEL_CHECK(offer.error()); + HEL_CHECK(send_ioctl_req.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::fs::GenericIoctlReply resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + + if(resp.error() != managarm::fs::Errors::SUCCESS) { + mlibc::infoLogger() << "\e[31mmlibc: DRM_IOCTL_MODE_GETPROPBLOB(" << param->blob_id << ") error " << (int) resp.error() << "\e[39m" + << frg::endlog; + *result = 0; + return EINVAL; + } + + uint8_t *dest = reinterpret_cast(param->data); + for(size_t i = 0; i < resp.drm_property_blob_size(); i++) { + if(i >= param->length) { + continue; + } + + dest[i] = resp.drm_property_blob(i); + } + + param->length = resp.drm_property_blob_size(); + + *result = 0; + return 0; + } + case DRM_IOCTL_MODE_GETPLANE: { + auto param = reinterpret_cast(arg); + + managarm::fs::GenericIoctlRequest req(getSysdepsAllocator()); + req.set_command(request); + req.set_drm_plane_id(param->plane_id); + + auto [offer, send_ioctl_req, send_req, recv_resp] = exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(ioctl_req, getSysdepsAllocator()), + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline()) + ); + HEL_CHECK(offer.error()); + HEL_CHECK(send_ioctl_req.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::fs::GenericIoctlReply resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + __ensure(resp.error() == managarm::fs::Errors::SUCCESS); + + param->crtc_id = resp.drm_crtc_id(); + param->fb_id = resp.drm_fb_id(); + param->possible_crtcs = resp.drm_possible_crtcs(); + param->gamma_size = resp.drm_gamma_size(); + + // FIXME: this should be passed as a buffer with helix, but this has no bounded max size? + for(size_t i = 0; i < resp.drm_format_type_size(); i++) { + if(i >= param->count_format_types) { + break; + } + auto dest = reinterpret_cast(param->format_type_ptr); + dest[i] = resp.drm_format_type(i); + } + + param->count_format_types = resp.drm_format_type_size(); + + *result = resp.result(); + return 0; + } + case DRM_IOCTL_MODE_GETPLANERESOURCES: { + auto param = reinterpret_cast(arg); + + managarm::fs::GenericIoctlRequest req(getSysdepsAllocator()); + req.set_command(request); + + frg::string ser(getSysdepsAllocator()); + req.SerializeToString(&ser); + + auto [offer, send_ioctl_req, send_req, recv_resp] = exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(ioctl_req, getSysdepsAllocator()), + helix_ng::sendBuffer(ser.data(), ser.size()), + helix_ng::recvInline()) + ); + HEL_CHECK(offer.error()); + HEL_CHECK(send_ioctl_req.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::fs::GenericIoctlReply resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + __ensure(resp.error() == managarm::fs::Errors::SUCCESS); + + // FIXME: send this via a helix_ng buffer + for(size_t i = 0; i < resp.drm_plane_res_size(); i++) { + if(i >= param->count_planes) { + continue; + } + auto dest = reinterpret_cast(param->plane_id_ptr); + dest[i] = resp.drm_plane_res(i); + } + + param->count_planes = resp.drm_plane_res_size(); + + *result = resp.result(); + + return 0; + } + case DRM_IOCTL_MODE_GETENCODER: { + auto param = reinterpret_cast(arg); + + managarm::fs::GenericIoctlRequest req(getSysdepsAllocator()); + req.set_command(request); + req.set_drm_encoder_id(param->encoder_id); + + auto [offer, send_ioctl_req, send_req, recv_resp] = exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(ioctl_req, getSysdepsAllocator()), + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline()) + ); + HEL_CHECK(offer.error()); + HEL_CHECK(send_ioctl_req.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::fs::GenericIoctlReply resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + __ensure(resp.error() == managarm::fs::Errors::SUCCESS); + + param->encoder_type = resp.drm_encoder_type(); + param->crtc_id = resp.drm_crtc_id(); + param->possible_crtcs = resp.drm_possible_crtcs(); + param->possible_clones = resp.drm_possible_clones(); + + *result = resp.result(); + return 0; + } + case DRM_IOCTL_MODE_CREATE_DUMB: { + auto param = reinterpret_cast(arg); + + managarm::fs::GenericIoctlRequest req(getSysdepsAllocator()); + req.set_command(request); + + req.set_drm_width(param->width); + req.set_drm_height(param->height); + req.set_drm_bpp(param->bpp); + req.set_drm_flags(param->flags); + + auto [offer, send_ioctl_req, send_req, recv_resp] = exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(ioctl_req, getSysdepsAllocator()), + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline()) + ); + HEL_CHECK(offer.error()); + HEL_CHECK(send_ioctl_req.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::fs::GenericIoctlReply resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + __ensure(resp.error() == managarm::fs::Errors::SUCCESS); + + param->handle = resp.drm_handle(); + param->pitch = resp.drm_pitch(); + param->size = resp.drm_size(); + + *result = resp.result(); + return 0; + } + case DRM_IOCTL_MODE_ADDFB: { + auto param = reinterpret_cast(arg); + + managarm::fs::GenericIoctlRequest req(getSysdepsAllocator()); + req.set_command(request); + + req.set_drm_width(param->width); + req.set_drm_height(param->height); + req.set_drm_pitch(param->pitch); + req.set_drm_bpp(param->bpp); + req.set_drm_depth(param->depth); + req.set_drm_handle(param->handle); + + auto [offer, send_ioctl_req, send_req, recv_resp] = exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(ioctl_req, getSysdepsAllocator()), + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline()) + ); + HEL_CHECK(offer.error()); + HEL_CHECK(send_ioctl_req.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::fs::GenericIoctlReply resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + __ensure(resp.error() == managarm::fs::Errors::SUCCESS); + + param->fb_id = resp.drm_fb_id(); + + *result = resp.result(); + return 0; + } + case DRM_IOCTL_MODE_GETFB2: { + auto param = reinterpret_cast(arg); + + managarm::fs::GenericIoctlRequest req(getSysdepsAllocator()); + req.set_command(DRM_IOCTL_MODE_GETFB2); + req.set_drm_fb_id(param->fb_id); + + auto [offer, send_ioctl_req, send_req, recv_resp] = exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(ioctl_req, getSysdepsAllocator()), + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline()) + ); + HEL_CHECK(offer.error()); + HEL_CHECK(send_ioctl_req.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::fs::GenericIoctlReply resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + __ensure(resp.error() == managarm::fs::Errors::SUCCESS); + + param->width = resp.drm_width(); + param->height = resp.drm_height(); + param->pixel_format = resp.pixel_format(); + param->modifier[0] = resp.modifier(); + memcpy(param->handles, resp.drm_handles().data(), sizeof(uint32_t) * resp.drm_handles_size()); + memcpy(param->pitches, resp.drm_pitches().data(), sizeof(uint32_t) * resp.drm_pitches_size()); + memcpy(param->offsets, resp.drm_offsets().data(), sizeof(uint32_t) * resp.drm_offsets_size()); + + *result = resp.result(); + return 0; + } + case DRM_IOCTL_MODE_ADDFB2: { + auto param = reinterpret_cast(arg); + + __ensure(!param->flags || param->flags == DRM_MODE_FB_MODIFIERS); + __ensure(!param->modifier[0] || param->modifier[0] == DRM_FORMAT_MOD_INVALID); + __ensure(!param->offsets[0]); + + managarm::fs::GenericIoctlRequest req(getSysdepsAllocator()); + req.set_command(DRM_IOCTL_MODE_ADDFB2); + + req.set_drm_width(param->width); + req.set_drm_height(param->height); + req.set_drm_pitch(param->pitches[0]); + req.set_drm_fourcc(param->pixel_format); + req.set_drm_handle(param->handles[0]); + + auto [offer, send_ioctl_req, send_req, recv_resp] = exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(ioctl_req, getSysdepsAllocator()), + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline()) + ); + HEL_CHECK(offer.error()); + HEL_CHECK(send_ioctl_req.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::fs::GenericIoctlReply resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + __ensure(resp.error() == managarm::fs::Errors::SUCCESS); + + param->fb_id = resp.drm_fb_id(); + + *result = resp.result(); + return 0; + } + case DRM_IOCTL_MODE_RMFB: { + auto param = reinterpret_cast(arg); + + managarm::fs::GenericIoctlRequest req(getSysdepsAllocator()); + req.set_command(request); + + req.set_drm_fb_id(*param); + + auto [offer, send_ioctl_req, send_req, recv_resp] = exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(ioctl_req, getSysdepsAllocator()), + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline()) + ); + HEL_CHECK(offer.error()); + HEL_CHECK(send_ioctl_req.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::fs::GenericIoctlReply resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + __ensure(resp.error() == managarm::fs::Errors::SUCCESS); + + *result = resp.result(); + return 0; + } + case DRM_IOCTL_MODE_MAP_DUMB: { + auto param = reinterpret_cast(arg); + + managarm::fs::GenericIoctlRequest req(getSysdepsAllocator()); + req.set_command(request); + + req.set_drm_handle(param->handle); + + auto [offer, send_ioctl_req, send_req, recv_resp] = exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(ioctl_req, getSysdepsAllocator()), + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline()) + ); + HEL_CHECK(offer.error()); + HEL_CHECK(send_ioctl_req.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::fs::GenericIoctlReply resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + __ensure(resp.error() == managarm::fs::Errors::SUCCESS); + + param->offset = resp.drm_offset(); + + *result = resp.result(); + return 0; + } + case DRM_IOCTL_MODE_GETCRTC: { + auto param = reinterpret_cast(arg); + + managarm::fs::GenericIoctlRequest req(getSysdepsAllocator()); + req.set_command(request); + req.set_drm_crtc_id(param->crtc_id); + + auto [offer, send_ioctl_req, send_req, recv_resp, recv_data] = exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(ioctl_req, getSysdepsAllocator()), + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline(), + helix_ng::recvBuffer(¶m->mode, sizeof(drm_mode_modeinfo))) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_ioctl_req.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + HEL_CHECK(recv_data.error()); + + managarm::fs::GenericIoctlReply resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + __ensure(resp.error() == managarm::fs::Errors::SUCCESS); + + param->fb_id = resp.drm_fb_id(); + param->x = resp.drm_x(); + param->y = resp.drm_y(); + param->gamma_size = resp.drm_gamma_size(); + param->mode_valid = resp.drm_mode_valid(); + + *result = resp.result(); + return 0; + } + case DRM_IOCTL_MODE_SETCRTC: { + auto param = reinterpret_cast(arg); + + managarm::fs::GenericIoctlRequest req(getSysdepsAllocator()); + req.set_command(request); + + for(size_t i = 0; i < param->count_connectors; i++) { + auto dest = reinterpret_cast(param->set_connectors_ptr); + req.add_drm_connector_ids(dest[i]); + } + req.set_drm_x(param->x); + req.set_drm_y(param->y); + req.set_drm_crtc_id(param->crtc_id); + req.set_drm_fb_id(param->fb_id); + req.set_drm_mode_valid(param->mode_valid); + + auto [offer, send_ioctl_req, send_req, send_mode, recv_resp] = exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(ioctl_req, getSysdepsAllocator()), + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::sendBuffer(¶m->mode, sizeof(drm_mode_modeinfo)), + helix_ng::recvInline()) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_ioctl_req.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(send_mode.error()); + HEL_CHECK(recv_resp.error()); + + managarm::fs::GenericIoctlReply resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + __ensure(resp.error() == managarm::fs::Errors::SUCCESS); + + *result = resp.result(); + return 0; + } + case DRM_IOCTL_MODE_OBJ_GETPROPERTIES: { + auto param = reinterpret_cast(arg); + + managarm::fs::GenericIoctlRequest req(getSysdepsAllocator()); + req.set_command(request); + + req.set_drm_count_props(param->count_props); + req.set_drm_obj_id(param->obj_id); + req.set_drm_obj_type(param->obj_type); + + auto [offer, send_ioctl_req, send_req, recv_resp] = exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(ioctl_req, getSysdepsAllocator()), + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline()) + ); + HEL_CHECK(offer.error()); + HEL_CHECK(send_ioctl_req.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::fs::GenericIoctlReply resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + __ensure(resp.error() == managarm::fs::Errors::SUCCESS); + + auto props = reinterpret_cast(param->props_ptr); + auto prop_vals = reinterpret_cast(param->prop_values_ptr); + + for(size_t i = 0; i < resp.drm_obj_property_ids_size(); i++) { + if(i >= param->count_props) { + break; + } + props[i] = resp.drm_obj_property_ids(i); + prop_vals[i] = resp.drm_obj_property_values(i); + } + + param->count_props = resp.drm_obj_property_ids_size(); + + *result = resp.result(); + return 0; + } + case DRM_IOCTL_MODE_PAGE_FLIP: { + auto param = reinterpret_cast(arg); + + managarm::fs::GenericIoctlRequest req(getSysdepsAllocator()); + req.set_command(request); + + __ensure(!(param->flags & ~DRM_MODE_PAGE_FLIP_EVENT)); + req.set_drm_crtc_id(param->crtc_id); + req.set_drm_fb_id(param->fb_id); + req.set_drm_cookie(param->user_data); + + auto [offer, send_ioctl_req, send_req, recv_resp] = exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(ioctl_req, getSysdepsAllocator()), + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline()) + ); + HEL_CHECK(offer.error()); + HEL_CHECK(send_ioctl_req.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::fs::GenericIoctlReply resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + __ensure(resp.error() == managarm::fs::Errors::SUCCESS); + + *result = resp.result(); + return 0; + } + case DRM_IOCTL_MODE_DIRTYFB: { + auto param = reinterpret_cast(arg); + + managarm::fs::GenericIoctlRequest req(getSysdepsAllocator()); + req.set_command(request); + + req.set_drm_fb_id(param->fb_id); + req.set_drm_flags(param->flags); + req.set_drm_color(param->color); + for(size_t i = 0; i < param->num_clips; i++) { + auto dest = reinterpret_cast(param->clips_ptr); + managarm::fs::Rect clip(getSysdepsAllocator()); + clip.set_x1(dest->x1); + clip.set_y1(dest->y1); + clip.set_x2(dest->x2); + clip.set_y2(dest->y2); + req.add_drm_clips(std::move(clip)); + } + + auto [offer, send_ioctl_req, send_req, recv_resp] = exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(ioctl_req, getSysdepsAllocator()), + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline()) + ); + HEL_CHECK(offer.error()); + HEL_CHECK(send_ioctl_req.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::fs::GenericIoctlReply resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + + if(resp.error() == managarm::fs::Errors::ILLEGAL_ARGUMENT) { + return EINVAL; + }else{ + __ensure(resp.error() == managarm::fs::Errors::SUCCESS); + *result = resp.result(); + return 0; + } + } + case DRM_IOCTL_MODE_CURSOR: { + auto param = reinterpret_cast(arg); + + managarm::fs::GenericIoctlRequest req(getSysdepsAllocator()); + req.set_command(request); + + req.set_drm_flags(param->flags); + req.set_drm_crtc_id(param->crtc_id); + + if (param->flags == DRM_MODE_CURSOR_MOVE) { + req.set_drm_x(param->x); + req.set_drm_y(param->y); + } else if (param->flags == DRM_MODE_CURSOR_BO) { + req.set_drm_width(param->width); + req.set_drm_height(param->height); + req.set_drm_handle(param->handle); + } else { + mlibc::infoLogger() << "\e[35mmlibc: invalid flags in DRM_IOCTL_MODE_CURSOR\e[39m" << frg::endlog; + return EINVAL; + } + + auto [offer, send_ioctl_req, send_req, recv_resp] = exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(ioctl_req, getSysdepsAllocator()), + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline()) + ); + HEL_CHECK(offer.error()); + HEL_CHECK(send_ioctl_req.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::fs::GenericIoctlReply resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + + if (resp.error() == managarm::fs::Errors::NO_BACKING_DEVICE) { + return ENXIO; + }else if (resp.error() == managarm::fs::Errors::ILLEGAL_ARGUMENT) { + return EINVAL; + }else{ + *result = resp.result(); + return 0; + } + } + case DRM_IOCTL_MODE_DESTROY_DUMB: { + auto param = reinterpret_cast(arg); + + managarm::fs::GenericIoctlRequest req(getSysdepsAllocator()); + req.set_command(request); + + req.set_drm_handle(param->handle); + + auto [offer, send_ioctl_req, send_req, recv_resp] = exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(ioctl_req, getSysdepsAllocator()), + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline()) + ); + HEL_CHECK(offer.error()); + HEL_CHECK(send_ioctl_req.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::fs::GenericIoctlReply resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + + *result = resp.result(); + return 0; + } + case DRM_IOCTL_MODE_CREATEPROPBLOB: { + auto param = reinterpret_cast(arg); + + managarm::fs::GenericIoctlRequest req(getSysdepsAllocator()); + req.set_command(request); + req.set_drm_blob_size(param->length); + + auto [offer, send_ioctl_req, send_req, blob_req, recv_resp] = exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(ioctl_req, getSysdepsAllocator()), + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::sendBuffer(reinterpret_cast(param->data), param->length), + helix_ng::recvInline()) + ); + HEL_CHECK(offer.error()); + HEL_CHECK(send_ioctl_req.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(blob_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::fs::GenericIoctlReply resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + __ensure(resp.error() == managarm::fs::Errors::SUCCESS); + + param->blob_id = resp.drm_blob_id(); + + *result = resp.result(); + return 0; + } + case DRM_IOCTL_MODE_DESTROYPROPBLOB: { + auto param = reinterpret_cast(arg); + + managarm::fs::GenericIoctlRequest req(getSysdepsAllocator()); + req.set_command(request); + req.set_drm_blob_id(param->blob_id); + + auto [offer, send_ioctl_req, send_req, recv_resp] = exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(ioctl_req, getSysdepsAllocator()), + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline()) + ); + HEL_CHECK(offer.error()); + HEL_CHECK(send_ioctl_req.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::fs::GenericIoctlReply resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + __ensure(resp.error() == managarm::fs::Errors::SUCCESS); + + *result = resp.result(); + return 0; + } + case DRM_IOCTL_MODE_ATOMIC: { + auto param = reinterpret_cast(arg); + + managarm::fs::GenericIoctlRequest req(getSysdepsAllocator()); + req.set_command(request); + req.set_drm_flags(param->flags); + req.set_drm_cookie(param->user_data); + + size_t prop_count = 0; + auto objs_ptr = reinterpret_cast(param->objs_ptr); + auto count_props_ptr = reinterpret_cast(param->count_props_ptr); + auto props_ptr = reinterpret_cast(param->props_ptr); + auto prop_values_ptr = reinterpret_cast(param->prop_values_ptr); + + for(size_t i = 0; i < param->count_objs; i++) { + /* list of modeobjs and their property count */ + req.add_drm_obj_ids(objs_ptr[i]); + req.add_drm_prop_counts(count_props_ptr[i]); + prop_count += count_props_ptr[i]; + } + + for(size_t i = 0; i < prop_count; i++) { + /* array of property IDs */ + req.add_drm_props(props_ptr[i]); + /* array of property values */ + req.add_drm_prop_values(prop_values_ptr[i]); + } + + auto [offer, send_ioctl_req, send_req, recv_resp] = exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(ioctl_req, getSysdepsAllocator()), + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline()) + ); + HEL_CHECK(offer.error()); + HEL_CHECK(send_ioctl_req.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::fs::GenericIoctlReply resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + + *result = resp.result(); + return 0; + } + case DRM_IOCTL_MODE_LIST_LESSEES: { + mlibc::infoLogger() << "\e[35mmlibc: DRM_IOCTL_MODE_LIST_LESSEES" + " is not implemented correctly\e[39m" << frg::endlog; + return EINVAL; + } + case DRM_IOCTL_MODE_SETGAMMA: { + mlibc::infoLogger() << "\e[35mmlibc: DRM_IOCTL_MODE_SETGAMMA" + " is not implemented correctly\e[39m" << frg::endlog; + return 0; + } + case DRM_IOCTL_MODE_CREATE_LEASE: { + auto param = reinterpret_cast(arg); + + mlibc::infoLogger() << "\e[35mmlibc: DRM_IOCTL_MODE_CREATE_LEASE" + " is a noop\e[39m" << frg::endlog; + param->lessee_id = 1; + param->fd = fd; + *result = 0; + return 0; + } + case DRM_IOCTL_GEM_CLOSE: { + mlibc::infoLogger() << "\e[35mmlibc: DRM_IOCTL_GEM_CLOSE" + " is a noop\e[39m" << frg::endlog; + return 0; + } + case DRM_IOCTL_PRIME_HANDLE_TO_FD: { + auto param = reinterpret_cast(arg); + + managarm::fs::GenericIoctlRequest req(getSysdepsAllocator()); + req.set_command(request); + req.set_drm_prime_handle(param->handle); + req.set_drm_flags(param->flags); + + auto [offer, send_ioctl_req, send_req, send_creds, recv_resp] = exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(ioctl_req, getSysdepsAllocator()), + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::imbueCredentials(), + helix_ng::recvInline()) + ); + HEL_CHECK(offer.error()); + HEL_CHECK(send_ioctl_req.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(send_creds.error()); + HEL_CHECK(recv_resp.error()); + + managarm::fs::GenericIoctlReply resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + __ensure(resp.error() == managarm::fs::Errors::SUCCESS); + + param->fd = resp.drm_prime_fd(); + *result = resp.result(); + return 0; + } + case DRM_IOCTL_PRIME_FD_TO_HANDLE: { + auto param = reinterpret_cast(arg); + + managarm::fs::GenericIoctlRequest req(getSysdepsAllocator()); + req.set_command(request); + req.set_drm_flags(param->flags); + + auto [offer, send_ioctl_req, send_req, send_creds, recv_resp] = exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(ioctl_req, getSysdepsAllocator()), + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::imbueCredentials(getHandleForFd(param->fd)), + helix_ng::recvInline()) + ); + HEL_CHECK(offer.error()); + HEL_CHECK(send_ioctl_req.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(send_creds.error()); + HEL_CHECK(recv_resp.error()); + + managarm::fs::GenericIoctlReply resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if(resp.error() == managarm::fs::Errors::FILE_NOT_FOUND) { + return EBADF; + } else { + __ensure(resp.error() == managarm::fs::Errors::SUCCESS); + } + + param->handle = resp.drm_prime_handle(); + *result = resp.result(); + return 0; + } + } + + mlibc::infoLogger() << "mlibc: Unexpected DRM ioctl with" + << ", number: 0x" << frg::hex_fmt(_IOC_NR(request)) + << " (raw request: " << frg::hex_fmt(request) << ")" << frg::endlog; + __ensure(!"Illegal ioctl request"); + __builtin_unreachable(); +} + +} //namespace mlibc diff --git a/lib/mlibc/sysdeps/managarm/generic/ensure.cpp b/lib/mlibc/sysdeps/managarm/generic/ensure.cpp new file mode 100644 index 0000000..ab0d84f --- /dev/null +++ b/lib/mlibc/sysdeps/managarm/generic/ensure.cpp @@ -0,0 +1,38 @@ + +#include +#include +#include + +#include +#include +#include + +#include +#include + +void __frigg_assert_fail(const char *assertion, const char *file, unsigned int line, + const char *function) { + mlibc::panicLogger() << "In function " << function + << ", file " << file << ":" << line << "\n" + << "__ensure(" << assertion << ") failed" << frg::endlog; +} + +namespace mlibc { + void sys_libc_log(const char *message) { + // This implementation is inherently signal-safe. + size_t n = 0; + while(message[n]) + n++; + HEL_CHECK(helLog(message, n)); + } + + void sys_libc_panic() { + // This implementation is inherently signal-safe. + const char *message = "mlibc: Panic!"; + size_t n = 0; + while(message[n]) + n++; + helPanic(message, n); + } +} + diff --git a/lib/mlibc/sysdeps/managarm/generic/entry.cpp b/lib/mlibc/sysdeps/managarm/generic/entry.cpp new file mode 100644 index 0000000..3ff28d2 --- /dev/null +++ b/lib/mlibc/sysdeps/managarm/generic/entry.cpp @@ -0,0 +1,132 @@ +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +// defined by the POSIX library +void __mlibc_initLocale(); + +extern "C" uintptr_t *__dlapi_entrystack(); +extern "C" void __dlapi_enter(uintptr_t *); + +// declared in posix-pipe.hpp +thread_local Queue globalQueue; + +// TODO: clock tracker page and file table don't need to be thread-local! +thread_local HelHandle __mlibc_posix_lane; +thread_local void *__mlibc_clk_tracker_page; + +namespace { + thread_local unsigned __mlibc_gsf_nesting; + thread_local void *__mlibc_cached_thread_page; + thread_local HelHandle *cachedFileTable; + + // This construction is a bit weird: Even though the variables above + // are thread_local we still protect their initialization with a pthread_once_t + // (instead of using a C++ constructor). + // We do this in order to able to clear the pthread_once_t after a fork. + thread_local pthread_once_t has_cached_infos = PTHREAD_ONCE_INIT; + + void actuallyCacheInfos() { + posix::ManagarmProcessData data; + HEL_CHECK(helSyscall1(kHelCallSuper + posix::superGetProcessData, reinterpret_cast(&data))); + + __mlibc_posix_lane = data.posixLane; + __mlibc_cached_thread_page = data.threadPage; + cachedFileTable = data.fileTable; + __mlibc_clk_tracker_page = data.clockTrackerPage; + } +} + +SignalGuard::SignalGuard() { + pthread_once(&has_cached_infos, &actuallyCacheInfos); + if(!__mlibc_cached_thread_page) + return; + auto p = reinterpret_cast(__mlibc_cached_thread_page); + if(!__mlibc_gsf_nesting) + __atomic_store_n(p, 1, __ATOMIC_RELAXED); + __mlibc_gsf_nesting++; +} + +SignalGuard::~SignalGuard() { + pthread_once(&has_cached_infos, &actuallyCacheInfos); + if(!__mlibc_cached_thread_page) + return; + auto p = reinterpret_cast(__mlibc_cached_thread_page); + __ensure(__mlibc_gsf_nesting > 0); + __mlibc_gsf_nesting--; + if(!__mlibc_gsf_nesting) { + unsigned int result = __atomic_exchange_n(p, 0, __ATOMIC_RELAXED); + if(result == 2) { + HEL_CHECK(helSyscall0(kHelCallSuper + posix::superSigRaise)); + }else{ + __ensure(result == 1); + } + } +} + +MemoryAllocator &getSysdepsAllocator() { + // use frg::eternal to prevent a call to __cxa_atexit(). + // this is necessary because __cxa_atexit() call this function. + static frg::eternal virtualAllocator; + static frg::eternal heap{virtualAllocator.get()}; + static frg::eternal singleton{&heap.get()}; + return singleton.get(); +} + +HelHandle getPosixLane() { + cacheFileTable(); + return __mlibc_posix_lane; +} + +HelHandle *cacheFileTable() { + // TODO: Make sure that this is signal-safe (it is called e.g. by sys_clock_get()). + pthread_once(&has_cached_infos, &actuallyCacheInfos); + return cachedFileTable; +} + +HelHandle getHandleForFd(int fd) { + if (fd >= 512) + return 0; + + return cacheFileTable()[fd]; +} + +void clearCachedInfos() { + has_cached_infos = PTHREAD_ONCE_INIT; +} + +struct LibraryGuard { + LibraryGuard(); +}; + +static LibraryGuard guard; + +extern char **environ; +static mlibc::exec_stack_data __mlibc_stack_data; + +LibraryGuard::LibraryGuard() { + __mlibc_initLocale(); + + // Parse the exec() stack. + mlibc::parse_exec_stack(__dlapi_entrystack(), &__mlibc_stack_data); + mlibc::set_startup_data(__mlibc_stack_data.argc, __mlibc_stack_data.argv, + __mlibc_stack_data.envp); +} + +extern "C" void __mlibc_entry(uintptr_t *entry_stack, int (*main_fn)(int argc, char *argv[], char *env[])) { + __dlapi_enter(entry_stack); + auto result = main_fn(__mlibc_stack_data.argc, __mlibc_stack_data.argv, environ); + exit(result); +} diff --git a/lib/mlibc/sysdeps/managarm/generic/file.cpp b/lib/mlibc/sysdeps/managarm/generic/file.cpp new file mode 100644 index 0000000..1f5cba6 --- /dev/null +++ b/lib/mlibc/sysdeps/managarm/generic/file.cpp @@ -0,0 +1,2526 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +HelHandle __mlibc_getPassthrough(int fd) { + auto handle = getHandleForFd(fd); + __ensure(handle); + return handle; +} + +namespace mlibc { + +int sys_chdir(const char *path) { + SignalGuard sguard; + + managarm::posix::CntRequest req(getSysdepsAllocator()); + req.set_request_type(managarm::posix::CntReqType::CHDIR); + req.set_path(frg::string(getSysdepsAllocator(), path)); + + auto [offer, send_req, recv_resp] = exchangeMsgsSync(getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::posix::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if(resp.error() == managarm::posix::Errors::FILE_NOT_FOUND) { + return ENOENT; + }else{ + __ensure(resp.error() == managarm::posix::Errors::SUCCESS); + return 0; + } +} + +int sys_fchdir(int fd) { + SignalGuard sguard; + + managarm::posix::CntRequest req(getSysdepsAllocator()); + req.set_request_type(managarm::posix::CntReqType::FCHDIR); + req.set_fd(fd); + + auto [offer, send_req, recv_resp] = exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline()) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::posix::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + __ensure(resp.error() == managarm::posix::Errors::SUCCESS); + return 0; +} + +int sys_chroot(const char *path) { + SignalGuard sguard; + + managarm::posix::CntRequest req(getSysdepsAllocator()); + req.set_request_type(managarm::posix::CntReqType::CHROOT); + req.set_path(frg::string(getSysdepsAllocator(), path)); + + auto [offer, send_req, recv_resp] = exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline()) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::posix::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + __ensure(resp.error() == managarm::posix::Errors::SUCCESS); + return 0; +} + +int sys_mkdir(const char *path, mode_t mode) { + return sys_mkdirat(AT_FDCWD, path, mode); +} + +int sys_mkdirat(int dirfd, const char *path, mode_t mode) { + (void)mode; + SignalGuard sguard; + + managarm::posix::MkdirAtRequest req(getSysdepsAllocator()); + req.set_fd(dirfd); + req.set_path(frg::string(getSysdepsAllocator(), path)); + + auto [offer, send_head, send_tail, recv_resp] = + exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadTail(req, getSysdepsAllocator()), + helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_head.error()); + HEL_CHECK(send_tail.error()); + HEL_CHECK(recv_resp.error()); + + managarm::posix::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if(resp.error() == managarm::posix::Errors::ALREADY_EXISTS) { + return EEXIST; + } else if(resp.error() == managarm::posix::Errors::ILLEGAL_ARGUMENTS) { + return EINVAL; + }else if(resp.error() == managarm::posix::Errors::BAD_FD) { + return EBADF; + }else if(resp.error() == managarm::posix::Errors::FILE_NOT_FOUND) { + return ENOENT; + }else if(resp.error() == managarm::posix::Errors::NOT_A_DIRECTORY) { + return ENOTDIR; + }else{ + __ensure(resp.error() == managarm::posix::Errors::SUCCESS); + return 0; + } +} + +int sys_symlink(const char *target_path, const char *link_path) { + return sys_symlinkat(target_path, AT_FDCWD, link_path); +} + +int sys_symlinkat(const char *target_path, int dirfd, const char *link_path) { + SignalGuard sguard; + + managarm::posix::SymlinkAtRequest req(getSysdepsAllocator()); + req.set_fd(dirfd); + req.set_path(frg::string(getSysdepsAllocator(), link_path)); + req.set_target_path(frg::string(getSysdepsAllocator(), target_path)); + + auto [offer, send_head, send_tail, recv_resp] = + exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadTail(req, getSysdepsAllocator()), + helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_head.error()); + HEL_CHECK(send_tail.error()); + HEL_CHECK(recv_resp.error()); + + managarm::posix::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if(resp.error() == managarm::posix::Errors::FILE_NOT_FOUND) { + return ENOENT; + }else if(resp.error() == managarm::posix::Errors::ILLEGAL_ARGUMENTS) { + return EINVAL; + }else if(resp.error() == managarm::posix::Errors::BAD_FD) { + return EBADF; + }else if(resp.error() == managarm::posix::Errors::NOT_A_DIRECTORY) { + return ENOTDIR; + }else{ + __ensure(resp.error() == managarm::posix::Errors::SUCCESS); + return 0; + } +} + +int sys_link(const char *old_path, const char *new_path) { + return sys_linkat(AT_FDCWD, old_path, AT_FDCWD, new_path, 0); +} + +int sys_linkat(int olddirfd, const char *old_path, int newdirfd, const char *new_path, int flags) { + SignalGuard sguard; + + managarm::posix::LinkAtRequest req(getSysdepsAllocator()); + req.set_path(frg::string(getSysdepsAllocator(), old_path)); + req.set_target_path(frg::string(getSysdepsAllocator(), new_path)); + req.set_fd(olddirfd); + req.set_newfd(newdirfd); + req.set_flags(flags); + + auto [offer, send_head, send_tail, recv_resp] = + exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadTail(req, getSysdepsAllocator()), + helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_head.error()); + HEL_CHECK(send_tail.error()); + HEL_CHECK(recv_resp.error()); + + managarm::posix::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if(resp.error() == managarm::posix::Errors::FILE_NOT_FOUND) { + return ENOENT; + }else if(resp.error() == managarm::posix::Errors::ILLEGAL_ARGUMENTS) { + return EINVAL; + }else if(resp.error() == managarm::posix::Errors::BAD_FD) { + return EBADF; + }else{ + __ensure(resp.error() == managarm::posix::Errors::SUCCESS); + return 0; + } +} + +int sys_rename(const char *path, const char *new_path) { + return sys_renameat(AT_FDCWD, path, AT_FDCWD, new_path); +} + +int sys_renameat(int olddirfd, const char *old_path, int newdirfd, const char *new_path) { + SignalGuard sguard; + + managarm::posix::RenameAtRequest req(getSysdepsAllocator()); + req.set_path(frg::string(getSysdepsAllocator(), old_path)); + req.set_target_path(frg::string(getSysdepsAllocator(), new_path)); + req.set_fd(olddirfd); + req.set_newfd(newdirfd); + + auto [offer, send_head, send_tail, recv_resp] = + exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadTail(req, getSysdepsAllocator()), + helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_head.error()); + HEL_CHECK(send_tail.error()); + HEL_CHECK(recv_resp.error()); + + managarm::posix::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if(resp.error() == managarm::posix::Errors::FILE_NOT_FOUND) { + return ENOENT; + }else{ + __ensure(resp.error() == managarm::posix::Errors::SUCCESS); + return 0; + } +} + +} //namespace mlibc + +namespace mlibc { + +int sys_fcntl(int fd, int request, va_list args, int *result) { + SignalGuard sguard; + if(request == F_DUPFD) { + int newfd; + if(int e = sys_dup(fd, 0, &newfd); e) + return e; + *result = newfd; + return 0; + }else if(request == F_DUPFD_CLOEXEC) { + int newfd; + if(int e = sys_dup(fd, O_CLOEXEC, &newfd); e) + return e; + *result = newfd; + return 0; + }else if(request == F_GETFD) { + managarm::posix::CntRequest req(getSysdepsAllocator()); + req.set_request_type(managarm::posix::CntReqType::FD_GET_FLAGS); + req.set_fd(fd); + + auto [offer, send_req, recv_resp] = exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline()) + ); + HEL_CHECK(offer.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::posix::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if(resp.error() == managarm::posix::Errors::NO_SUCH_FD) + return EBADF; + __ensure(resp.error() == managarm::posix::Errors::SUCCESS); + *result = resp.flags(); + return 0; + }else if(request == F_SETFD) { + managarm::posix::CntRequest req(getSysdepsAllocator()); + req.set_request_type(managarm::posix::CntReqType::FD_SET_FLAGS); + req.set_fd(fd); + req.set_flags(va_arg(args, int)); + + auto [offer, send_req, recv_resp] = exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline()) + ); + HEL_CHECK(offer.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::posix::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if(resp.error() == managarm::posix::Errors::NO_SUCH_FD) + return EBADF; + else if(resp.error() == managarm::posix::Errors::ILLEGAL_ARGUMENTS) + return EINVAL; + __ensure(resp.error() == managarm::posix::Errors::SUCCESS); + *result = static_cast(resp.error()); + return 0; + }else if(request == F_GETFL) { + SignalGuard sguard; + + auto handle = getHandleForFd(fd); + if (!handle) + return EBADF; + + managarm::fs::CntRequest req(getSysdepsAllocator()); + req.set_req_type(managarm::fs::CntReqType::PT_GET_FILE_FLAGS); + req.set_fd(fd); + + auto [offer, send_req, recv_resp] = exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline()) + ); + HEL_CHECK(offer.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::fs::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if(resp.error() == managarm::fs::Errors::ILLEGAL_OPERATION_TARGET) { + mlibc::infoLogger() << "\e[31mmlibc: fcntl(F_GETFL) unimplemented for this file\e[39m" << frg::endlog; + return EINVAL; + } + __ensure(resp.error() == managarm::fs::Errors::SUCCESS); + *result = resp.flags(); + return 0; + }else if(request == F_SETFL) { + SignalGuard sguard; + + auto handle = getHandleForFd(fd); + if (!handle) + return EBADF; + + managarm::fs::CntRequest req(getSysdepsAllocator()); + req.set_req_type(managarm::fs::CntReqType::PT_SET_FILE_FLAGS); + req.set_fd(fd); + req.set_flags(va_arg(args, int)); + + auto [offer, send_req, recv_resp] = exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline()) + ); + HEL_CHECK(offer.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::fs::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if(resp.error() == managarm::fs::Errors::ILLEGAL_OPERATION_TARGET) { + mlibc::infoLogger() << "\e[31mmlibc: fcntl(F_SETFL) unimplemented for this file\e[39m" << frg::endlog; + return EINVAL; + } + __ensure(resp.error() == managarm::fs::Errors::SUCCESS); + *result = 0; + return 0; + }else if(request == F_SETLK) { + mlibc::infoLogger() << "\e[31mmlibc: F_SETLK\e[39m" << frg::endlog; + return 0; + }else if(request == F_SETLKW) { + mlibc::infoLogger() << "\e[31mmlibc: F_SETLKW\e[39m" << frg::endlog; + return 0; + }else if(request == F_GETLK) { + struct flock *lock = va_arg(args, struct flock *); + lock->l_type = F_UNLCK; + mlibc::infoLogger() << "\e[31mmlibc: F_GETLK is stubbed!\e[39m" << frg::endlog; + return 0; + }else if(request == F_ADD_SEALS) { + auto seals = va_arg(args, int); + auto handle = getHandleForFd(fd); + if (!handle) + return EBADF; + + managarm::fs::CntRequest req(getSysdepsAllocator()); + req.set_req_type(managarm::fs::CntReqType::PT_ADD_SEALS); + req.set_fd(fd); + req.set_seals(seals); + + auto [offer, send_req, recv_resp] = exchangeMsgsSync(handle, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::RecvInline() + )); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::fs::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if(resp.error() == managarm::fs::Errors::ILLEGAL_OPERATION_TARGET) { + mlibc::infoLogger() << "\e[31mmlibc: fcntl(F_ADD_SEALS) unimplemented for this file\e[39m" << frg::endlog; + return EINVAL; + } else if(resp.error() == managarm::fs::Errors::INSUFFICIENT_PERMISSIONS) { + return EPERM; + } + __ensure(resp.error() == managarm::fs::Errors::SUCCESS); + + *result = resp.seals(); + return 0; + }else if(request == F_GET_SEALS) { + auto handle = getHandleForFd(fd); + if (!handle) + return EBADF; + + managarm::fs::CntRequest req(getSysdepsAllocator()); + req.set_req_type(managarm::fs::CntReqType::PT_GET_SEALS); + req.set_fd(fd); + + auto [offer, send_req, recv_resp] = exchangeMsgsSync(handle, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::RecvInline() + )); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::fs::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if(resp.error() == managarm::fs::Errors::ILLEGAL_OPERATION_TARGET) { + mlibc::infoLogger() << "\e[31mmlibc: fcntl(F_GET_SEALS) unimplemented for this file\e[39m" << frg::endlog; + return EINVAL; + } + __ensure(resp.error() == managarm::fs::Errors::SUCCESS); + *result = resp.seals(); + return 0; + }else{ + mlibc::infoLogger() << "\e[31mmlibc: Unexpected fcntl() request: " + << request << "\e[39m" << frg::endlog; + return EINVAL; + } +} + +int sys_open_dir(const char *path, int *handle) { + return sys_open(path, 0, 0, handle); +} + +int sys_read_entries(int fd, void *buffer, size_t max_size, size_t *bytes_read) { + SignalGuard sguard; + auto handle = getHandleForFd(fd); + if (!handle) + return EBADF; + + managarm::fs::CntRequest req(getSysdepsAllocator()); + req.set_req_type(managarm::fs::CntReqType::PT_READ_ENTRIES); + + auto [offer, send_req, recv_resp] = exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline()) + ); + HEL_CHECK(offer.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::fs::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if(resp.error() == managarm::fs::Errors::END_OF_FILE) { + *bytes_read = 0; + return 0; + }else{ + __ensure(resp.error() == managarm::fs::Errors::SUCCESS); + __ensure(max_size > sizeof(struct dirent)); + auto ent = new (buffer) struct dirent; + memset(ent, 0, sizeof(struct dirent)); + memcpy(ent->d_name, resp.path().data(), resp.path().size()); + ent->d_reclen = sizeof(struct dirent); + *bytes_read = sizeof(struct dirent); + return 0; + } +} + +int sys_ttyname(int fd, char *buf, size_t size) { + SignalGuard sguard; + + managarm::posix::CntRequest req(getSysdepsAllocator()); + req.set_request_type(managarm::posix::CntReqType::TTY_NAME); + req.set_fd(fd); + + auto [offer, send_req, recv_resp] = exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline()) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::posix::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if(resp.error() == managarm::posix::Errors::BAD_FD) { + return EBADF; + }else if(resp.error() == managarm::posix::Errors::NOT_A_TTY) { + return ENOTTY; + }else{ + __ensure(resp.error() == managarm::posix::Errors::SUCCESS); + __ensure(size >= resp.path().size() + 1); + memcpy(buf, resp.path().data(), size); + buf[resp.path().size()] = '\0'; + return 0; + } +} + +int sys_fdatasync(int) { + mlibc::infoLogger() << "\e[35mmlibc: fdatasync() is a no-op\e[39m" + << frg::endlog; + return 0; +} + +int sys_getcwd(char *buffer, size_t size) { + SignalGuard sguard; + + managarm::posix::CntRequest req(getSysdepsAllocator()); + req.set_request_type(managarm::posix::CntReqType::GETCWD); + req.set_size(size); + + auto [offer, send_req, recv_resp, recv_path] = exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline(), + helix_ng::recvBuffer(buffer, size)) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + HEL_CHECK(recv_path.error()); + + managarm::posix::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + __ensure(resp.error() == managarm::posix::Errors::SUCCESS); + if(static_cast(resp.size()) >= size) + return ERANGE; + return 0; +} + +int sys_vm_map(void *hint, size_t size, int prot, int flags, int fd, off_t offset, void **window) { + SignalGuard sguard; + + managarm::posix::VmMapRequest req(getSysdepsAllocator()); + req.set_address_hint(reinterpret_cast(hint)); + req.set_size(size); + req.set_mode(prot); + req.set_flags(flags); + req.set_fd(fd); + req.set_rel_offset(offset); + + auto [offer, sendReq, recvResp] = exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(sendReq.error()); + HEL_CHECK(recvResp.error()); + + managarm::posix::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recvResp.data(), recvResp.length()); + if(resp.error() == managarm::posix::Errors::ALREADY_EXISTS) { + return EEXIST; + }else if(resp.error() == managarm::posix::Errors::NO_MEMORY) { + return EFAULT; + }else if(resp.error() == managarm::posix::Errors::ILLEGAL_ARGUMENTS) { + return EINVAL; + }else { + __ensure(resp.error() == managarm::posix::Errors::SUCCESS); + *window = reinterpret_cast(resp.offset()); + } + + return 0; +} + +int sys_vm_remap(void *pointer, size_t size, size_t new_size, void **window) { + SignalGuard sguard; + + managarm::posix::CntRequest req(getSysdepsAllocator()); + req.set_request_type(managarm::posix::CntReqType::VM_REMAP); + req.set_address(reinterpret_cast(pointer)); + req.set_size(size); + req.set_new_size(new_size); + + auto [offer, send_req, recv_resp] = exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline()) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::posix::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + __ensure(resp.error() == managarm::posix::Errors::SUCCESS); + *window = reinterpret_cast(resp.offset()); + return 0; +} + +int sys_vm_protect(void *pointer, size_t size, int prot) { + SignalGuard sguard; + + managarm::posix::CntRequest req(getSysdepsAllocator()); + req.set_request_type(managarm::posix::CntReqType::VM_PROTECT); + req.set_address(reinterpret_cast(pointer)); + req.set_size(size); + req.set_mode(prot); + + auto [offer, send_req, recv_resp] = exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline()) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::posix::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + __ensure(resp.error() == managarm::posix::Errors::SUCCESS); + return 0; +} + +int sys_vm_unmap(void *pointer, size_t size) { + SignalGuard sguard; + + managarm::posix::CntRequest req(getSysdepsAllocator()); + req.set_request_type(managarm::posix::CntReqType::VM_UNMAP); + req.set_address(reinterpret_cast(pointer)); + req.set_size(size); + + auto [offer, send_req, recv_resp] = exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline()) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::posix::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + __ensure(resp.error() == managarm::posix::Errors::SUCCESS); + return 0; +} + +int sys_setsid(pid_t *sid) { + SignalGuard sguard; + + managarm::posix::CntRequest req(getSysdepsAllocator()); + req.set_request_type(managarm::posix::CntReqType::SETSID); + + auto [offer, send_req, recv_resp] = exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline()) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::posix::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if(resp.error() == managarm::posix::Errors::ACCESS_DENIED) { + *sid = -1; + return EPERM; + } + __ensure(resp.error() == managarm::posix::Errors::SUCCESS); + *sid = resp.sid(); + return 0; +} + +int sys_tcgetattr(int fd, struct termios *attr) { + int result; + if(int e = sys_ioctl(fd, TCGETS, attr, &result); e) + return e; + return 0; +} + +int sys_tcsetattr(int fd, int when, const struct termios *attr) { + if(when < TCSANOW || when > TCSAFLUSH) + return EINVAL; + + if(int e = sys_ioctl(fd, TCSETS, const_cast(attr), nullptr); e) + return e; + return 0; +} + +int sys_tcdrain(int) { + mlibc::infoLogger() << "\e[35mmlibc: tcdrain() is a stub\e[39m" << frg::endlog; + return 0; +} + +int sys_socket(int domain, int type_and_flags, int proto, int *fd) { + constexpr int type_mask = int(0xF); + constexpr int flags_mask = ~int(0xF); + __ensure(!((type_and_flags & flags_mask) & ~(SOCK_CLOEXEC | SOCK_NONBLOCK))); + + SignalGuard sguard; + + managarm::posix::SocketRequest req(getSysdepsAllocator()); + req.set_domain(domain); + req.set_socktype(type_and_flags & type_mask); + req.set_protocol(proto); + req.set_flags(type_and_flags & flags_mask); + + auto [offer, sendReq, recvResp] = exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(sendReq.error()); + HEL_CHECK(recvResp.error()); + + managarm::posix::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recvResp.data(), recvResp.length()); + if(resp.error() == managarm::posix::Errors::ILLEGAL_ARGUMENTS) { + return EAFNOSUPPORT; + } else { + __ensure(resp.error() == managarm::posix::Errors::SUCCESS); + *fd = resp.fd(); + return 0; + } +} + +int sys_pipe(int *fds, int flags) { + SignalGuard sguard; + + managarm::posix::CntRequest req(getSysdepsAllocator()); + req.set_request_type(managarm::posix::CntReqType::PIPE_CREATE); + req.set_flags(flags); + + auto [offer, send_req, recv_resp] = exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline()) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::posix::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + __ensure(resp.error() == managarm::posix::Errors::SUCCESS); + __ensure(resp.fds_size() == 2); + fds[0] = resp.fds(0); + fds[1] = resp.fds(1); + return 0; +} + +int sys_socketpair(int domain, int type_and_flags, int proto, int *fds) { + constexpr int type_mask = int(0xF); + constexpr int flags_mask = ~int(0xF); + __ensure(!((type_and_flags & flags_mask) & ~(SOCK_CLOEXEC | SOCK_NONBLOCK))); + + SignalGuard sguard; + + managarm::posix::SockpairRequest req(getSysdepsAllocator()); + req.set_domain(domain); + req.set_socktype(type_and_flags & type_mask); + req.set_protocol(proto); + req.set_flags(type_and_flags & flags_mask); + + auto [offer, sendReq, recvResp] = exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(sendReq.error()); + HEL_CHECK(recvResp.error()); + + managarm::posix::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recvResp.data(), recvResp.length()); + if(resp.error() == managarm::posix::Errors::PROTOCOL_NOT_SUPPORTED) { + return EPROTONOSUPPORT; + } else { + __ensure(resp.error() == managarm::posix::Errors::SUCCESS); + } + __ensure(resp.fds_size() == 2); + fds[0] = resp.fds(0); + fds[1] = resp.fds(1); + return 0; +} + +int sys_msg_send(int sockfd, const struct msghdr *hdr, int flags, ssize_t *length) { + frg::vector sglist{getSysdepsAllocator()}; + auto handle = getHandleForFd(sockfd); + if (!handle) + return EBADF; + + size_t overall_size = 0; + for(int i = 0; i < hdr->msg_iovlen; i++) { + HelSgItem item{ + .buffer = hdr->msg_iov[i].iov_base, + .length = hdr->msg_iov[i].iov_len, + }; + sglist.push_back(item); + overall_size += hdr->msg_iov[i].iov_len; + } + + SignalGuard sguard; + + managarm::fs::SendMsgRequest req(getSysdepsAllocator()); + req.set_flags(flags); + req.set_size(overall_size); + + for(auto cmsg = CMSG_FIRSTHDR(hdr); cmsg; cmsg = CMSG_NXTHDR(hdr, cmsg)) { + __ensure(cmsg->cmsg_level == SOL_SOCKET); + if(cmsg->cmsg_type == SCM_CREDENTIALS) { + mlibc::infoLogger() << "mlibc: SCM_CREDENTIALS requested but we don't handle that yet!" << frg::endlog; + return EINVAL; + } + __ensure(cmsg->cmsg_type == SCM_RIGHTS); + __ensure(cmsg->cmsg_len >= sizeof(struct cmsghdr)); + + size_t size = cmsg->cmsg_len - CMSG_ALIGN(sizeof(struct cmsghdr)); + __ensure(!(size % sizeof(int))); + for(size_t off = 0; off < size; off += sizeof(int)) { + int fd; + memcpy(&fd, CMSG_DATA(cmsg) + off, sizeof(int)); + req.add_fds(fd); + } + } + + auto [offer, send_head, send_tail, send_data, imbue_creds, send_addr, recv_resp] = exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBragiHeadTail(req, getSysdepsAllocator()), + helix_ng::sendBufferSg(sglist.data(), hdr->msg_iovlen), + helix_ng::imbueCredentials(), + helix_ng::sendBuffer(hdr->msg_name, hdr->msg_namelen), + helix_ng::recvInline()) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_head.error()); + HEL_CHECK(send_tail.error()); + HEL_CHECK(send_data.error()); + HEL_CHECK(imbue_creds.error()); + HEL_CHECK(send_addr.error()); + HEL_CHECK(recv_resp.error()); + + managarm::fs::SendMsgReply resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + + if(resp.error() == managarm::fs::Errors::BROKEN_PIPE) { + return EPIPE; + }else if(resp.error() == managarm::fs::Errors::NOT_CONNECTED) { + return ENOTCONN; + }else if(resp.error() == managarm::fs::Errors::WOULD_BLOCK) { + return EAGAIN; + }else if(resp.error() == managarm::fs::Errors::HOST_UNREACHABLE) { + return EHOSTUNREACH; + }else if(resp.error() == managarm::fs::Errors::ACCESS_DENIED) { + return EACCES; + }else if(resp.error() == managarm::fs::Errors::NETWORK_UNREACHABLE) { + return ENETUNREACH; + }else if(resp.error() == managarm::fs::Errors::DESTINATION_ADDRESS_REQUIRED) { + return EDESTADDRREQ; + }else if(resp.error() == managarm::fs::Errors::ADDRESS_NOT_AVAILABLE) { + return EADDRNOTAVAIL; + }else if(resp.error() == managarm::fs::Errors::ILLEGAL_ARGUMENT) { + return EINVAL; + }else if(resp.error() == managarm::fs::Errors::AF_NOT_SUPPORTED) { + return EAFNOSUPPORT; + }else if(resp.error() == managarm::fs::Errors::MESSAGE_TOO_LARGE) { + return EMSGSIZE; + }else{ + __ensure(resp.error() == managarm::fs::Errors::SUCCESS); + *length = resp.size(); + return 0; + } +} + +int sys_msg_recv(int sockfd, struct msghdr *hdr, int flags, ssize_t *length) { + if(!hdr->msg_iovlen) { + return EMSGSIZE; + } + + auto handle = getHandleForFd(sockfd); + if (!handle) + return EBADF; + + SignalGuard sguard; + + managarm::fs::RecvMsgRequest req(getSysdepsAllocator()); + req.set_flags(flags); + req.set_size(hdr->msg_iov[0].iov_len); + req.set_addr_size(hdr->msg_namelen); + req.set_ctrl_size(hdr->msg_controllen); + + auto [offer, send_req, imbue_creds, recv_resp, recv_addr, recv_data, recv_ctrl] = exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::imbueCredentials(), + helix_ng::recvInline(), + helix_ng::recvBuffer(hdr->msg_name, hdr->msg_namelen), + helix_ng::recvBuffer(hdr->msg_iov[0].iov_base, hdr->msg_iov[0].iov_len), + helix_ng::recvBuffer(hdr->msg_control, hdr->msg_controllen)) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(imbue_creds.error()); + HEL_CHECK(recv_resp.error()); + + managarm::fs::RecvMsgReply resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + + if(resp.error() == managarm::fs::Errors::WOULD_BLOCK) { + return EAGAIN; + }else{ + __ensure(resp.error() == managarm::fs::Errors::SUCCESS); + HEL_CHECK(recv_addr.error()); + HEL_CHECK(recv_data.error()); + HEL_CHECK(recv_ctrl.error()); + + hdr->msg_namelen = resp.addr_size(); + hdr->msg_controllen = recv_ctrl.actualLength(); + hdr->msg_flags = resp.flags(); + *length = resp.ret_val(); + return 0; + } +} + +int sys_pselect(int, fd_set *read_set, fd_set *write_set, + fd_set *except_set, const struct timespec *timeout, + const sigset_t *sigmask, int *num_events) { + // TODO: Do not keep errors from epoll (?). + int fd = epoll_create1(0); + if(fd == -1) + return -1; + + for(int k = 0; k < FD_SETSIZE; k++) { + struct epoll_event ev; + memset(&ev, 0, sizeof(struct epoll_event)); + + if(read_set && FD_ISSET(k, read_set)) + ev.events |= EPOLLIN; // TODO: Additional events. + if(write_set && FD_ISSET(k, write_set)) + ev.events |= EPOLLOUT; // TODO: Additional events. + if(except_set && FD_ISSET(k, except_set)) + ev.events |= EPOLLPRI; + + if(!ev.events) + continue; + ev.data.u32 = k; + + if(epoll_ctl(fd, EPOLL_CTL_ADD, k, &ev)) + return -1; + } + + struct epoll_event evnts[16]; + int n = epoll_pwait(fd, evnts, 16, + timeout ? (timeout->tv_sec * 1000 + timeout->tv_nsec / 100) : -1, sigmask); + if(n == -1) + return -1; + + fd_set res_read_set; + fd_set res_write_set; + fd_set res_except_set; + FD_ZERO(&res_read_set); + FD_ZERO(&res_write_set); + FD_ZERO(&res_except_set); + int m = 0; + + for(int i = 0; i < n; i++) { + int k = evnts[i].data.u32; + + if(read_set && FD_ISSET(k, read_set) + && evnts[i].events & (EPOLLIN | EPOLLERR | EPOLLHUP)) { + FD_SET(k, &res_read_set); + m++; + } + + if(write_set && FD_ISSET(k, write_set) + && evnts[i].events & (EPOLLOUT | EPOLLERR | EPOLLHUP)) { + FD_SET(k, &res_write_set); + m++; + } + + if(except_set && FD_ISSET(k, except_set) + && evnts[i].events & EPOLLPRI) { + FD_SET(k, &res_except_set); + m++; + } + } + + if(close(fd)) + __ensure("close() failed on epoll file"); + + if(read_set) + memcpy(read_set, &res_read_set, sizeof(fd_set)); + if(write_set) + memcpy(write_set, &res_write_set, sizeof(fd_set)); + if(except_set) + memcpy(except_set, &res_except_set, sizeof(fd_set)); + + *num_events = m; + return 0; +} + +int sys_poll(struct pollfd *fds, nfds_t count, int timeout, int *num_events) { + __ensure(timeout >= 0 || timeout == -1); // TODO: Report errors correctly. + + SignalGuard sguard; + + managarm::posix::CntRequest req(getSysdepsAllocator()); + req.set_request_type(managarm::posix::CntReqType::EPOLL_CALL); + req.set_timeout(timeout > 0 ? int64_t{timeout} * 1000000 : timeout); + + for(nfds_t i = 0; i < count; i++) { + req.add_fds(fds[i].fd); + req.add_events(fds[i].events); + } + + auto [offer, send_req, recv_resp] = exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline()) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::posix::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if(resp.error() == managarm::posix::Errors::ILLEGAL_ARGUMENTS) { + return EINVAL; + } else { + __ensure(resp.error() == managarm::posix::Errors::SUCCESS); + __ensure(resp.events_size() == count); + + int m = 0; + for(nfds_t i = 0; i < count; i++) { + if(resp.events(i)) + m++; + fds[i].revents = resp.events(i); + } + + *num_events = m; + return 0; + } +} + +int sys_epoll_create(int flags, int *fd) { + // Some applications assume EPOLL_CLOEXEC and O_CLOEXEC to be the same. + // They are on linux, but not yet on managarm. + __ensure(!(flags & ~(EPOLL_CLOEXEC | O_CLOEXEC))); + + SignalGuard sguard; + + uint32_t proto_flags = 0; + if(flags & EPOLL_CLOEXEC || flags & O_CLOEXEC) + proto_flags |= managarm::posix::OpenFlags::OF_CLOEXEC; + + managarm::posix::CntRequest req(getSysdepsAllocator()); + req.set_request_type(managarm::posix::CntReqType::EPOLL_CREATE); + req.set_flags(proto_flags); + + auto [offer, send_req, recv_resp] = exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline()) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::posix::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + __ensure(resp.error() == managarm::posix::Errors::SUCCESS); + *fd = resp.fd(); + return 0; +} + +int sys_epoll_ctl(int epfd, int mode, int fd, struct epoll_event *ev) { + SignalGuard sguard; + + managarm::posix::CntRequest req(getSysdepsAllocator()); + if(mode == EPOLL_CTL_ADD) { + __ensure(ev); + req.set_request_type(managarm::posix::CntReqType::EPOLL_ADD); + req.set_flags(ev->events); + req.set_cookie(ev->data.u64); + }else if(mode == EPOLL_CTL_MOD) { + __ensure(ev); + req.set_request_type(managarm::posix::CntReqType::EPOLL_MODIFY); + req.set_flags(ev->events); + req.set_cookie(ev->data.u64); + }else if(mode == EPOLL_CTL_DEL) { + req.set_request_type(managarm::posix::CntReqType::EPOLL_DELETE); + }else{ + mlibc::panicLogger() << "\e[31mmlibc: Illegal epoll_ctl() mode\e[39m" << frg::endlog; + } + req.set_fd(epfd); + req.set_newfd(fd); + + auto [offer, send_req, recv_resp] = exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline()) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::posix::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if(resp.error() == managarm::posix::Errors::BAD_FD) { + return EBADF; + } else if(resp.error() == managarm::posix::Errors::ALREADY_EXISTS) { + return EEXIST; + } else if(resp.error() == managarm::posix::Errors::FILE_NOT_FOUND) { + return ENOENT; + } else { + __ensure(resp.error() == managarm::posix::Errors::SUCCESS); + return 0; + } + return 0; +} + +int sys_epoll_pwait(int epfd, struct epoll_event *ev, int n, + int timeout, const sigset_t *sigmask, int *raised) { + __ensure(timeout >= 0 || timeout == -1); // TODO: Report errors correctly. + + SignalGuard sguard; + + managarm::posix::CntRequest req(getSysdepsAllocator()); + req.set_request_type(managarm::posix::CntReqType::EPOLL_WAIT); + req.set_fd(epfd); + req.set_size(n); + req.set_timeout(timeout > 0 ? int64_t{timeout} * 1000000 : timeout); + if(sigmask != NULL) { + req.set_sigmask((long int)*sigmask); + req.set_sigmask_needed(true); + } else { + req.set_sigmask_needed(false); + } + + auto [offer, send_req, recv_resp, recv_data] = exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline(), + helix_ng::recvBuffer(ev, n * sizeof(struct epoll_event))) + ); + HEL_CHECK(offer.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + HEL_CHECK(recv_data.error()); + + managarm::posix::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if(resp.error() == managarm::posix::Errors::BAD_FD) { + return EBADF; + } + __ensure(resp.error() == managarm::posix::Errors::SUCCESS); + __ensure(!(recv_data.actualLength() % sizeof(struct epoll_event))); + *raised = recv_data.actualLength() / sizeof(struct epoll_event); + return 0; +} + +int sys_timerfd_create(int clockid, int flags, int *fd) { + (void) clockid; + SignalGuard sguard; + + managarm::posix::CntRequest req(getSysdepsAllocator()); + req.set_request_type(managarm::posix::CntReqType::TIMERFD_CREATE); + req.set_flags(flags); + + auto [offer, send_req, recv_resp] = exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline()) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::posix::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + __ensure(resp.error() == managarm::posix::Errors::SUCCESS); + *fd = resp.fd(); + return 0; +} + +int sys_timerfd_settime(int fd, int, + const struct itimerspec *value, struct itimerspec *oldvalue) { + __ensure(!oldvalue); + SignalGuard sguard; + + managarm::posix::CntRequest req(getSysdepsAllocator()); + req.set_request_type(managarm::posix::CntReqType::TIMERFD_SETTIME); + req.set_fd(fd); + req.set_time_secs(value->it_value.tv_sec); + req.set_time_nanos(value->it_value.tv_nsec); + req.set_interval_secs(value->it_interval.tv_sec); + req.set_interval_nanos(value->it_interval.tv_nsec); + + auto [offer, send_req, recv_resp] = exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline()) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::posix::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + __ensure(resp.error() == managarm::posix::Errors::SUCCESS); + return 0; +} + +int sys_signalfd_create(const sigset_t *masks, int flags, int *fd) { + __ensure(!(flags & ~(SFD_CLOEXEC | SFD_NONBLOCK))); + + uint32_t proto_flags = 0; + if(flags & SFD_CLOEXEC) + proto_flags |= managarm::posix::OpenFlags::OF_CLOEXEC; + if(flags & SFD_NONBLOCK) + proto_flags |= managarm::posix::OpenFlags::OF_NONBLOCK; + + SignalGuard sguard; + + managarm::posix::CntRequest req(getSysdepsAllocator()); + req.set_request_type(managarm::posix::CntReqType::SIGNALFD_CREATE); + req.set_flags(proto_flags); + req.set_sigset(*masks); + + auto [offer, send_req, recv_resp] = exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline()) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::posix::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + __ensure(resp.error() == managarm::posix::Errors::SUCCESS); + *fd = resp.fd(); + return 0; +} + +int sys_inotify_create(int flags, int *fd) { + __ensure(!(flags & ~(IN_CLOEXEC | IN_NONBLOCK))); + + SignalGuard sguard; + + uint32_t proto_flags = 0; + if(flags & IN_CLOEXEC) + proto_flags |= managarm::posix::OpenFlags::OF_CLOEXEC; + if(flags & IN_NONBLOCK) + proto_flags |= managarm::posix::OpenFlags::OF_NONBLOCK; + + managarm::posix::InotifyCreateRequest req(getSysdepsAllocator()); + req.set_flags(proto_flags); + + auto [offer, sendReq, recvResp] = exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(sendReq.error()); + HEL_CHECK(recvResp.error()); + + managarm::posix::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recvResp.data(), recvResp.length()); + __ensure(resp.error() == managarm::posix::Errors::SUCCESS); + *fd = resp.fd(); + return 0; +} + +int sys_inotify_add_watch(int ifd, const char *path, uint32_t mask, int *wd) { + SignalGuard sguard; + + managarm::posix::InotifyAddRequest req(getSysdepsAllocator()); + req.set_fd(ifd); + req.set_path(frg::string(getSysdepsAllocator(), path)); + req.set_flags(mask); + + auto [offer, send_head, send_tail, recv_resp] = + exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadTail(req, getSysdepsAllocator()), + helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_head.error()); + HEL_CHECK(send_tail.error()); + HEL_CHECK(recv_resp.error()); + + managarm::posix::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if(resp.error() == managarm::posix::Errors::FILE_NOT_FOUND) { + return ENOENT; + }else if(resp.error() == managarm::posix::Errors::BAD_FD) { + return EBADF; + }else{ + __ensure(resp.error() == managarm::posix::Errors::SUCCESS); + *wd = resp.wd(); + return 0; + } +} + +int sys_eventfd_create(unsigned int initval, int flags, int *fd) { + SignalGuard sguard; + + uint32_t proto_flags = 0; + if (flags & EFD_NONBLOCK) proto_flags |= managarm::posix::OpenFlags::OF_NONBLOCK; + if (flags & EFD_CLOEXEC) proto_flags |= managarm::posix::OpenFlags::OF_CLOEXEC; + if (flags & EFD_SEMAPHORE) + return ENOSYS; + + managarm::posix::EventfdCreateRequest req(getSysdepsAllocator()); + req.set_flags(proto_flags); + req.set_initval(initval); + + auto [offer, sendReq, recvResp] = exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(sendReq.error()); + HEL_CHECK(recvResp.error()); + + managarm::posix::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recvResp.data(), recvResp.length()); + __ensure(resp.error() == managarm::posix::Errors::SUCCESS); + *fd = resp.fd(); + return 0; +} + +int sys_open(const char *path, int flags, mode_t mode, int *fd) { + return sys_openat(AT_FDCWD, path, flags, mode, fd); +} + +int sys_openat(int dirfd, const char *path, int flags, mode_t mode, int *fd) { + SignalGuard sguard; + + // We do not support O_TMPFILE. + if(flags & O_TMPFILE) + return EOPNOTSUPP; + + uint32_t proto_flags = 0; + if(flags & O_APPEND) + proto_flags |= managarm::posix::OpenFlags::OF_APPEND; + if(flags & O_CREAT) + proto_flags |= managarm::posix::OpenFlags::OF_CREATE; + if(flags & O_EXCL) + proto_flags |= managarm::posix::OpenFlags::OF_EXCLUSIVE; + if(flags & O_NONBLOCK) + proto_flags |= managarm::posix::OpenFlags::OF_NONBLOCK; + if(flags & O_TRUNC) + proto_flags |= managarm::posix::OpenFlags::OF_TRUNC; + + if(flags & O_CLOEXEC) + proto_flags |= managarm::posix::OpenFlags::OF_CLOEXEC; + if(flags & O_NOCTTY) + proto_flags |= managarm::posix::OpenFlags::OF_NOCTTY; + + if(flags & O_RDONLY) + proto_flags |= managarm::posix::OpenFlags::OF_RDONLY; + else if(flags & O_WRONLY) + proto_flags |= managarm::posix::OpenFlags::OF_WRONLY; + else if(flags & O_RDWR) + proto_flags |= managarm::posix::OpenFlags::OF_RDWR; + else if(flags & O_PATH) + proto_flags |= managarm::posix::OpenFlags::OF_PATH; + + managarm::posix::OpenAtRequest req(getSysdepsAllocator()); + req.set_fd(dirfd); + req.set_path(frg::string(getSysdepsAllocator(), path)); + req.set_flags(proto_flags); + req.set_mode(mode); + + auto [offer, sendHead, sendTail, recvResp] = exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadTail(req, getSysdepsAllocator()), + helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(sendHead.error()); + HEL_CHECK(sendTail.error()); + HEL_CHECK(recvResp.error()); + + managarm::posix::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recvResp.data(), recvResp.length()); + if(resp.error() == managarm::posix::Errors::FILE_NOT_FOUND) { + return ENOENT; + }else if(resp.error() == managarm::posix::Errors::ALREADY_EXISTS) { + return EEXIST; + }else if(resp.error() == managarm::posix::Errors::NOT_A_DIRECTORY) { + return ENOTDIR; + }else if(resp.error() == managarm::posix::Errors::ILLEGAL_OPERATION_TARGET) { + mlibc::infoLogger() << "\e[31mmlibc: openat unimplemented for this file " << path << "\e[39m" << frg::endlog; + return EINVAL; + }else if(resp.error() == managarm::posix::Errors::NO_BACKING_DEVICE) { + return ENXIO; + }else if(resp.error() == managarm::posix::Errors::IS_DIRECTORY) { + return EISDIR; + }else if(resp.error() == managarm::posix::Errors::ILLEGAL_ARGUMENTS) { + return EINVAL; + }else{ + __ensure(resp.error() == managarm::posix::Errors::SUCCESS); + *fd = resp.fd(); + return 0; + } +} + +int sys_mkfifoat(int dirfd, const char *path, mode_t mode) { + SignalGuard sguard; + + managarm::posix::MkfifoAtRequest req(getSysdepsAllocator()); + req.set_fd(dirfd); + req.set_path(frg::string(getSysdepsAllocator(), path)); + req.set_mode(mode); + + auto [offer, send_head, send_tail, recv_resp] = + exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadTail(req, getSysdepsAllocator()), + helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_head.error()); + HEL_CHECK(send_tail.error()); + HEL_CHECK(recv_resp.error()); + + managarm::posix::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if(resp.error() == managarm::posix::Errors::FILE_NOT_FOUND) { + return ENOENT; + }else if(resp.error() == managarm::posix::Errors::ALREADY_EXISTS) { + return EEXIST; + }else if(resp.error() == managarm::posix::Errors::BAD_FD) { + return EBADF; + }else if(resp.error() == managarm::posix::Errors::ILLEGAL_ARGUMENTS) { + return EINVAL; + }else if(resp.error() == managarm::posix::Errors::INTERNAL_ERROR) { + return EIEIO; + }else{ + __ensure(resp.error() == managarm::posix::Errors::SUCCESS); + return 0; + } +} + +int sys_mknodat(int dirfd, const char *path, int mode, int dev) { + SignalGuard sguard; + + managarm::posix::MknodAtRequest req(getSysdepsAllocator()); + req.set_dirfd(dirfd); + req.set_path(frg::string(getSysdepsAllocator(), path)); + req.set_mode(mode); + req.set_device(dev); + + auto [offer, send_head, send_tail, recv_resp] = + exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadTail(req, getSysdepsAllocator()), + helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_head.error()); + HEL_CHECK(send_tail.error()); + HEL_CHECK(recv_resp.error()); + + managarm::posix::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if(resp.error() == managarm::posix::Errors::FILE_NOT_FOUND) { + return ENOENT; + }else if(resp.error() == managarm::posix::Errors::ALREADY_EXISTS) { + return EEXIST; + }else if(resp.error() == managarm::posix::Errors::BAD_FD) { + return EBADF; + }else if(resp.error() == managarm::posix::Errors::ILLEGAL_ARGUMENTS) { + return EINVAL; + }else{ + __ensure(resp.error() == managarm::posix::Errors::SUCCESS); + return 0; + } +} + +int sys_read(int fd, void *data, size_t max_size, ssize_t *bytes_read) { + SignalGuard sguard; + + auto handle = getHandleForFd(fd); + if (!handle) + return EBADF; + + managarm::fs::CntRequest req(getSysdepsAllocator()); + req.set_req_type(managarm::fs::CntReqType::READ); + req.set_fd(fd); + req.set_size(max_size); + + frg::string ser(getSysdepsAllocator()); + req.SerializeToString(&ser); + + auto [offer, send_req, imbue_creds, recv_resp, recv_data] = + exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBuffer(ser.data(), ser.size()), + helix_ng::imbueCredentials(), + helix_ng::recvInline(), + helix_ng::recvBuffer(data, max_size) + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(imbue_creds.error()); + HEL_CHECK(recv_resp.error()); + + managarm::fs::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); +/* if(resp.error() == managarm::fs::Errors::NO_SUCH_FD) { + return EBADF; + }else*/ + if(resp.error() == managarm::fs::Errors::ILLEGAL_ARGUMENT) { + return EINVAL; + }else if(resp.error() == managarm::fs::Errors::WOULD_BLOCK) { + return EAGAIN; + }else if(resp.error() == managarm::fs::Errors::END_OF_FILE) { + *bytes_read = 0; + return 0; + }else{ + __ensure(resp.error() == managarm::fs::Errors::SUCCESS); + HEL_CHECK(recv_data.error()); + *bytes_read = recv_data.actualLength(); + return 0; + } +} + +int sys_readv(int fd, const struct iovec *iovs, int iovc, ssize_t *bytes_read) { + for(int i = 0; i < iovc; i++) { + ssize_t intermed = 0; + + if(int e = sys_read(fd, iovs[i].iov_base, iovs[i].iov_len, &intermed); e) + return e; + else if(intermed == 0) + break; + + *bytes_read += intermed; + } + + return 0; +} + +int sys_write(int fd, const void *data, size_t size, ssize_t *bytes_written) { + SignalGuard sguard; + + auto handle = getHandleForFd(fd); + if (!handle) + return EBADF; + + managarm::fs::CntRequest req(getSysdepsAllocator()); + req.set_req_type(managarm::fs::CntReqType::WRITE); + req.set_fd(fd); + req.set_size(size); + + auto [offer, send_req, imbue_creds, send_data, recv_resp] = exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::imbueCredentials(), + helix_ng::sendBuffer(data, size), + helix_ng::recvInline()) + ); + HEL_CHECK(offer.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(imbue_creds.error()); + HEL_CHECK(send_data.error()); + HEL_CHECK(recv_resp.error()); + + managarm::fs::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + + // TODO: implement NO_SUCH_FD +/* if(resp.error() == managarm::fs::Errors::NO_SUCH_FD) { + return EBADF; + }else*/ if(resp.error() == managarm::fs::Errors::ILLEGAL_OPERATION_TARGET) { + return EINVAL; // FD does not support writes. + }else if(resp.error() == managarm::fs::Errors::NO_SPACE_LEFT) { + return ENOSPC; + }else if(resp.error() == managarm::fs::Errors::WOULD_BLOCK) { + return EAGAIN; + }else if(resp.error() == managarm::fs::Errors::NOT_CONNECTED) { + return ENOTCONN; + }else{ + __ensure(resp.error() == managarm::fs::Errors::SUCCESS); + if(bytes_written) { + *bytes_written = resp.size(); + } + return 0; + } +} + +int sys_pread(int fd, void *buf, size_t n, off_t off, ssize_t *bytes_read) { + SignalGuard sguard; + + auto handle = getHandleForFd(fd); + if (!handle) + return EBADF; + + managarm::fs::CntRequest req(getSysdepsAllocator()); + req.set_req_type(managarm::fs::CntReqType::PT_PREAD); + req.set_fd(fd); + req.set_size(n); + req.set_offset(off); + + auto [offer, send_req, imbue_creds, recv_resp, recv_data] = exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::imbueCredentials(), + helix_ng::recvInline(), + helix_ng::recvBuffer(buf, n)) + ); + HEL_CHECK(offer.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(imbue_creds.error()); + HEL_CHECK(recv_resp.error()); + + managarm::fs::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); +/* if(resp.error() == managarm::fs::Errors::NO_SUCH_FD) { + return EBADF; + }else*/ + if(resp.error() == managarm::fs::Errors::ILLEGAL_ARGUMENT) { + return EINVAL; + }else if(resp.error() == managarm::fs::Errors::WOULD_BLOCK) { + return EAGAIN; + }else if(resp.error() == managarm::fs::Errors::END_OF_FILE) { + *bytes_read = 0; + return 0; + }else{ + __ensure(resp.error() == managarm::fs::Errors::SUCCESS); + HEL_CHECK(recv_data.error()); + *bytes_read = recv_data.actualLength(); + return 0; + } +} + +int sys_pwrite(int fd, const void *buf, size_t n, off_t off, ssize_t *bytes_written) { + SignalGuard sguard; + + auto handle = getHandleForFd(fd); + if (!handle) + return EBADF; + + managarm::fs::CntRequest req(getSysdepsAllocator()); + req.set_req_type(managarm::fs::CntReqType::PT_PWRITE); + req.set_fd(fd); + req.set_size(n); + req.set_offset(off); + + frg::string ser(getSysdepsAllocator()); + req.SerializeToString(&ser); + + auto [offer, send_head, imbue_creds, to_write, recv_resp] = exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::imbueCredentials(), + helix_ng::sendBuffer(buf, n), + helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_head.error()); + HEL_CHECK(imbue_creds.error()); + HEL_CHECK(to_write.error()); + HEL_CHECK(recv_resp.error()); + + managarm::fs::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if(resp.error() == managarm::fs::Errors::ILLEGAL_ARGUMENT) { + return EINVAL; + }else if(resp.error() == managarm::fs::Errors::WOULD_BLOCK) { + return EAGAIN; + }else if(resp.error() == managarm::fs::Errors::NO_SPACE_LEFT) { + return ENOSPC; + }else if(resp.error() == managarm::fs::Errors::SEEK_ON_PIPE) { + return ESPIPE; + }else if(resp.error() == managarm::fs::Errors::ILLEGAL_OPERATION_TARGET) { + return EINVAL; + }else{ + __ensure(resp.error() == managarm::fs::Errors::SUCCESS); + *bytes_written = n; + return 0; + } +} + +int sys_seek(int fd, off_t offset, int whence, off_t *new_offset) { + SignalGuard sguard; + + auto handle = getHandleForFd(fd); + if(!handle) + return EBADF; + + managarm::fs::CntRequest req(getSysdepsAllocator()); + req.set_fd(fd); + req.set_rel_offset(offset); + + if(whence == SEEK_SET) { + req.set_req_type(managarm::fs::CntReqType::SEEK_ABS); + }else if(whence == SEEK_CUR) { + req.set_req_type(managarm::fs::CntReqType::SEEK_REL); + }else if(whence == SEEK_END) { + req.set_req_type(managarm::fs::CntReqType::SEEK_EOF); + }else{ + return EINVAL; + } + + frg::string ser(getSysdepsAllocator()); + req.SerializeToString(&ser); + + auto [offer, send_req, recv_resp] = exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBuffer(ser.data(), ser.size()), + helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::fs::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if(resp.error() == managarm::fs::Errors::SEEK_ON_PIPE) { + return ESPIPE; + } else if(resp.error() == managarm::fs::Errors::ILLEGAL_ARGUMENT) { + return EINVAL; + } else { + __ensure(resp.error() == managarm::fs::Errors::SUCCESS); + *new_offset = resp.offset(); + return 0; + } +} + + +int sys_close(int fd) { + SignalGuard sguard; + + managarm::posix::CloseRequest req(getSysdepsAllocator()); + req.set_fd(fd); + + auto [offer, sendReq, recvResp] = exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(sendReq.error()); + HEL_CHECK(recvResp.error()); + + managarm::posix::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recvResp.data(), recvResp.length()); + + if(resp.error() == managarm::posix::Errors::NO_SUCH_FD) { + return EBADF; + }else if(resp.error() == managarm::posix::Errors::SUCCESS) { + return 0; + }else{ + __ensure(!"Unexpected error"); + __builtin_unreachable(); + } +} + +int sys_dup(int fd, int flags, int *newfd) { + SignalGuard sguard; + + __ensure(!(flags & ~(O_CLOEXEC))); + + uint32_t proto_flags = 0; + if(flags & O_CLOEXEC) + proto_flags |= managarm::posix::OpenFlags::OF_CLOEXEC; + + managarm::posix::CntRequest req(getSysdepsAllocator()); + req.set_request_type(managarm::posix::CntReqType::DUP); + req.set_fd(fd); + req.set_flags(proto_flags); + + auto [offer, send_req, recv_resp] = exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline()) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::posix::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if (resp.error() == managarm::posix::Errors::BAD_FD) { + return EBADF; + } else if (resp.error() == managarm::posix::Errors::ILLEGAL_ARGUMENTS) { + return EINVAL; + } else { + __ensure(resp.error() == managarm::posix::Errors::SUCCESS); + } + + *newfd = resp.fd(); + return 0; +} + +int sys_dup2(int fd, int flags, int newfd) { + SignalGuard sguard; + + managarm::posix::CntRequest req(getSysdepsAllocator()); + req.set_request_type(managarm::posix::CntReqType::DUP2); + req.set_fd(fd); + req.set_newfd(newfd); + req.set_flags(flags); + + auto [offer, send_req, recv_resp] = exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline()) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::posix::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + + if (resp.error() == managarm::posix::Errors::BAD_FD) { + return EBADF; + } else if (resp.error() == managarm::posix::Errors::ILLEGAL_ARGUMENTS) { + return EINVAL; + } else { + __ensure(resp.error() == managarm::posix::Errors::SUCCESS); + } + + return 0; +} + +int sys_stat(fsfd_target fsfdt, int fd, const char *path, int flags, struct stat *result) { + SignalGuard sguard; + + managarm::posix::FstatAtRequest req(getSysdepsAllocator()); + if (fsfdt == fsfd_target::path) { + req.set_fd(AT_FDCWD); + req.set_path(frg::string(getSysdepsAllocator(), path)); + } else if (fsfdt == fsfd_target::fd) { + flags |= AT_EMPTY_PATH; + req.set_fd(fd); + } else { + __ensure(fsfdt == fsfd_target::fd_path); + req.set_fd(fd); + req.set_path(frg::string(getSysdepsAllocator(), path)); + } + + if (flags & ~(AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH)) { + return EINVAL; + } + + if (!(flags & AT_EMPTY_PATH) && (!path || !strlen(path))) { + return ENOENT; + } + + req.set_flags(flags); + + auto [offer, send_head, send_tail, recv_resp] = + exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadTail(req, getSysdepsAllocator()), + helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_head.error()); + HEL_CHECK(send_tail.error()); + HEL_CHECK(recv_resp.error()); + + managarm::posix::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if(resp.error() == managarm::posix::Errors::FILE_NOT_FOUND) { + return ENOENT; + }else if(resp.error() == managarm::posix::Errors::BAD_FD) { + return EBADF; + }else if(resp.error() == managarm::posix::Errors::NOT_A_DIRECTORY) { + return ENOTDIR; + }else{ + __ensure(resp.error() == managarm::posix::Errors::SUCCESS); + memset(result, 0, sizeof(struct stat)); + + switch(resp.file_type()) { + case managarm::posix::FileType::FT_REGULAR: + result->st_mode = S_IFREG; break; + case managarm::posix::FileType::FT_DIRECTORY: + result->st_mode = S_IFDIR; break; + case managarm::posix::FileType::FT_SYMLINK: + result->st_mode = S_IFLNK; break; + case managarm::posix::FileType::FT_CHAR_DEVICE: + result->st_mode = S_IFCHR; break; + case managarm::posix::FileType::FT_BLOCK_DEVICE: + result->st_mode = S_IFBLK; break; + case managarm::posix::FileType::FT_SOCKET: + result->st_mode = S_IFSOCK; break; + case managarm::posix::FileType::FT_FIFO: + result->st_mode = S_IFIFO; break; + default: + __ensure(!resp.file_type()); + } + + result->st_dev = 1; + result->st_ino = resp.fs_inode(); + result->st_mode |= resp.mode(); + result->st_nlink = resp.num_links(); + result->st_uid = resp.uid(); + result->st_gid = resp.gid(); + result->st_rdev = resp.ref_devnum(); + result->st_size = resp.file_size(); + result->st_atim.tv_sec = resp.atime_secs(); + result->st_atim.tv_nsec = resp.atime_nanos(); + result->st_mtim.tv_sec = resp.mtime_secs(); + result->st_mtim.tv_nsec = resp.mtime_nanos(); + result->st_ctim.tv_sec = resp.ctime_secs(); + result->st_ctim.tv_nsec = resp.ctime_nanos(); + result->st_blksize = 4096; + result->st_blocks = resp.file_size() / 512 + 1; + return 0; + } +} + +int sys_readlink(const char *path, void *data, size_t max_size, ssize_t *length) { + SignalGuard sguard; + + managarm::posix::CntRequest req(getSysdepsAllocator()); + req.set_request_type(managarm::posix::CntReqType::READLINK); + req.set_path(frg::string(getSysdepsAllocator(), path)); + + auto [offer, send_req, recv_resp, recv_data] = exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline(), + helix_ng::recvBuffer(data, max_size)) + ); + HEL_CHECK(offer.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::posix::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if(resp.error() == managarm::posix::Errors::FILE_NOT_FOUND) { + return ENOENT; + }else if(resp.error() == managarm::posix::Errors::ILLEGAL_ARGUMENTS) { + return EINVAL; + }else{ + __ensure(resp.error() == managarm::posix::Errors::SUCCESS); + *length = recv_data.actualLength(); + return 0; + } +} + +int sys_rmdir(const char *path) { + SignalGuard sguard; + + managarm::posix::RmdirRequest req(getSysdepsAllocator()); + req.set_path(frg::string(getSysdepsAllocator(), path)); + + auto [offer, send_head, send_tail, recv_resp] = + exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadTail(req, getSysdepsAllocator()), + helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_head.error()); + HEL_CHECK(send_tail.error()); + HEL_CHECK(recv_resp.error()); + + managarm::posix::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if(resp.error() == managarm::posix::Errors::FILE_NOT_FOUND) { + return ENOENT; + }else{ + __ensure(resp.error() == managarm::posix::Errors::SUCCESS); + return 0; + } +} + +int sys_ftruncate(int fd, size_t size) { + SignalGuard sguard; + + auto handle = getHandleForFd(fd); + if (!handle) + return EBADF; + + managarm::fs::CntRequest req(getSysdepsAllocator()); + req.set_req_type(managarm::fs::CntReqType::PT_TRUNCATE); + req.set_size(size); + + auto [offer, send_req, recv_resp] = exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline()) + ); + HEL_CHECK(offer.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::fs::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if(resp.error() == managarm::fs::Errors::ILLEGAL_OPERATION_TARGET) { + return EINVAL; + } else { + __ensure(resp.error() == managarm::fs::Errors::SUCCESS); + return 0; + } +} + +int sys_fallocate(int fd, off_t offset, size_t size) { + SignalGuard sguard; + + auto handle = getHandleForFd(fd); + if (!handle) + return EBADF; + + managarm::fs::CntRequest req(getSysdepsAllocator()); + req.set_req_type(managarm::fs::CntReqType::PT_FALLOCATE); + req.set_rel_offset(offset); + req.set_size(size); + + auto [offer, send_req, recv_resp] = exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline()) + ); + HEL_CHECK(offer.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::fs::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if(resp.error() == managarm::fs::Errors::ILLEGAL_OPERATION_TARGET) { + return EINVAL; + }else if(resp.error() == managarm::fs::Errors::INSUFFICIENT_PERMISSIONS) { + return EPERM; + }else if(resp.error() == managarm::fs::Errors::ILLEGAL_ARGUMENT) { + return EINVAL; + }else{ + __ensure(resp.error() == managarm::fs::Errors::SUCCESS); + return 0; + } + return 0; +} + +int sys_unlinkat(int fd, const char *path, int flags) { + SignalGuard sguard; + + managarm::posix::UnlinkAtRequest req(getSysdepsAllocator()); + req.set_fd(fd); + req.set_path(frg::string(getSysdepsAllocator(), path)); + req.set_flags(flags); + + auto [offer, send_head, send_tail, recv_resp] = + exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadTail(req, getSysdepsAllocator()), + helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_head.error()); + HEL_CHECK(send_tail.error()); + HEL_CHECK(recv_resp.error()); + + managarm::posix::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if(resp.error() == managarm::posix::Errors::FILE_NOT_FOUND) { + return ENOENT; + }else if(resp.error() == managarm::posix::Errors::RESOURCE_IN_USE) { + return EBUSY; + }else if(resp.error() == managarm::posix::Errors::IS_DIRECTORY) { + return EISDIR; + }else{ + __ensure(resp.error() == managarm::posix::Errors::SUCCESS); + return 0; + } +} + +int sys_access(const char *path, int mode) { + return sys_faccessat(AT_FDCWD, path, mode, 0); +} + +int sys_faccessat(int dirfd, const char *pathname, int, int flags) { + SignalGuard sguard; + + managarm::posix::AccessAtRequest req(getSysdepsAllocator()); + req.set_path(frg::string(getSysdepsAllocator(), pathname)); + req.set_fd(dirfd); + req.set_flags(flags); + + auto [offer, send_head, send_tail, recv_resp] = + exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadTail(req, getSysdepsAllocator()), + helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_head.error()); + HEL_CHECK(send_tail.error()); + HEL_CHECK(recv_resp.error()); + + managarm::posix::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if(resp.error() == managarm::posix::Errors::FILE_NOT_FOUND) { + return ENOENT; + }else if(resp.error() == managarm::posix::Errors::NO_SUCH_FD) { + return EBADF; + }else if(resp.error() == managarm::posix::Errors::ILLEGAL_ARGUMENTS) { + return EINVAL; + }else{ + __ensure(resp.error() == managarm::posix::Errors::SUCCESS); + return 0; + } +} + +int sys_flock(int fd, int opts) { + SignalGuard sguard; + + managarm::fs::CntRequest req(getSysdepsAllocator()); + req.set_req_type(managarm::fs::CntReqType::FLOCK); + req.set_fd(fd); + req.set_flock_flags(opts); + auto handle = getHandleForFd(fd); + if(!handle) { + return EBADF; + } + + auto [offer, send_req, recv_resp] = exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline()) + ); + HEL_CHECK(offer.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::posix::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if(resp.error() == managarm::posix::Errors::WOULD_BLOCK) { + return EWOULDBLOCK; + }else if(resp.error() == managarm::posix::Errors::ILLEGAL_ARGUMENTS) { + return EINVAL; + } else { + __ensure(resp.error() == managarm::posix::Errors::SUCCESS); + return 0; + } +} + +int sys_isatty(int fd) { + SignalGuard sguard; + + managarm::posix::IsTtyRequest req(getSysdepsAllocator()); + req.set_fd(fd); + + auto [offer, sendReq, recvResp] = exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(sendReq.error()); + HEL_CHECK(recvResp.error()); + + managarm::posix::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recvResp.data(), recvResp.length()); + if(resp.error() == managarm::posix::Errors::NO_SUCH_FD) { + return EBADF; + }else{ + __ensure(resp.error() == managarm::posix::Errors::SUCCESS); + if(resp.mode()) + return 0; + return ENOTTY; + } +} + +int sys_chmod(const char *pathname, mode_t mode) { + return sys_fchmodat(AT_FDCWD, pathname, mode, 0); +} + +int sys_fchmod(int fd, mode_t mode) { + return sys_fchmodat(fd, "", mode, AT_EMPTY_PATH); +} + +int sys_fchmodat(int fd, const char *pathname, mode_t mode, int flags) { + SignalGuard sguard; + + managarm::posix::FchmodAtRequest req(getSysdepsAllocator()); + req.set_fd(fd); + req.set_path(frg::string(getSysdepsAllocator(), pathname)); + req.set_mode(mode); + req.set_flags(flags); + + auto [offer, send_head, send_tail, recv_resp] = + exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadTail(req, getSysdepsAllocator()), + helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_head.error()); + HEL_CHECK(send_tail.error()); + HEL_CHECK(recv_resp.error()); + + managarm::posix::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if(resp.error() == managarm::posix::Errors::FILE_NOT_FOUND) { + return ENOENT; + }else if(resp.error() == managarm::posix::Errors::NO_SUCH_FD) { + return EBADF; + }else if(resp.error() == managarm::posix::Errors::ILLEGAL_ARGUMENTS) { + return EINVAL; + }else if(resp.error() == managarm::posix::Errors::NOT_SUPPORTED) { + return ENOTSUP; + }else{ + __ensure(resp.error() == managarm::posix::Errors::SUCCESS); + return 0; + } +} + +int sys_fchownat(int dirfd, const char *pathname, uid_t owner, gid_t group, int flags) { + (void)dirfd; + (void)pathname; + (void)owner; + (void)group; + (void)flags; + mlibc::infoLogger() << "mlibc: sys_fchownat is a stub!" << frg::endlog; + return 0; +} + +int sys_umask(mode_t mode, mode_t *old) { + (void)mode; + mlibc::infoLogger() << "mlibc: sys_umask is a stub, hardcoding 022!" << frg::endlog; + *old = 022; + return 0; +} + +int sys_utimensat(int dirfd, const char *pathname, const struct timespec times[2], int flags) { + SignalGuard sguard; + + managarm::posix::UtimensAtRequest req(getSysdepsAllocator()); + req.set_fd(dirfd); + if(pathname != nullptr) + req.set_path(frg::string(getSysdepsAllocator(), pathname)); + if(times) { + req.set_atimeSec(times[0].tv_sec); + req.set_atimeNsec(times[0].tv_nsec); + req.set_mtimeSec(times[1].tv_sec); + req.set_mtimeNsec(times[1].tv_nsec); + } else { + req.set_atimeSec(UTIME_NOW); + req.set_atimeNsec(UTIME_NOW); + req.set_mtimeSec(UTIME_NOW); + req.set_mtimeNsec(UTIME_NOW); + } + req.set_flags(flags); + + auto [offer, send_head, send_tail, recv_resp] = + exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadTail(req, getSysdepsAllocator()), + helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_head.error()); + HEL_CHECK(send_tail.error()); + HEL_CHECK(recv_resp.error()); + + managarm::posix::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if(resp.error() == managarm::posix::Errors::FILE_NOT_FOUND) { + return ENOENT; + }else if(resp.error() == managarm::posix::Errors::NO_SUCH_FD) { + return EBADF; + }else if(resp.error() == managarm::posix::Errors::ILLEGAL_ARGUMENTS) { + return EINVAL; + }else if(resp.error() == managarm::posix::Errors::NOT_SUPPORTED) { + return ENOTSUP; + }else{ + __ensure(resp.error() == managarm::posix::Errors::SUCCESS); + return 0; + } +} + +int sys_getentropy(void *buffer, size_t length) { + SignalGuard sguard; + auto p = reinterpret_cast(buffer); + size_t n = 0; + + while(n < length) { + size_t chunk; + HEL_CHECK(helGetRandomBytes(p + n, length - n, &chunk)); + n+= chunk; + } + + return 0; +} + +int sys_gethostname(char *buffer, size_t bufsize) { + SignalGuard sguard; + mlibc::infoLogger() << "mlibc: gethostname always returns managarm" << frg::endlog; + char name[10] = "managarm\0"; + if(bufsize < 10) + return ENAMETOOLONG; + strncpy(buffer, name, 10); + return 0; +} + +int sys_fsync(int) { + mlibc::infoLogger() << "mlibc: fsync is a stub" << frg::endlog; + return 0; +} + +int sys_memfd_create(const char *name, int flags, int *fd) { + SignalGuard sguard; + + managarm::posix::MemFdCreateRequest req(getSysdepsAllocator()); + req.set_name(frg::string(getSysdepsAllocator(), name)); + req.set_flags(flags); + + auto [offer, send_head, send_tail, recv_resp] = + exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadTail(req, getSysdepsAllocator()), + helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_head.error()); + HEL_CHECK(send_tail.error()); + HEL_CHECK(recv_resp.error()); + + managarm::posix::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if(resp.error() == managarm::posix::Errors::ILLEGAL_ARGUMENTS) { + return EINVAL; + } + + *fd = resp.fd(); + + __ensure(resp.error() == managarm::posix::Errors::SUCCESS); + return 0; +} + +int sys_uname(struct utsname *buf) { + __ensure(buf); + mlibc::infoLogger() << "\e[31mmlibc: uname() returns static information\e[39m" << frg::endlog; + strcpy(buf->sysname, "Managarm"); + strcpy(buf->nodename, "managarm"); + strcpy(buf->release, "0.0.1-rolling"); + strcpy(buf->version, "Managarm is not Managram"); +#if defined(__x86_64__) + strcpy(buf->machine, "x86_64"); +#elif defined (__aarch64__) + strcpy(buf->machine, "aarch64"); +#else +# error Unknown architecture +#endif + + return 0; +} + +int sys_madvise(void *, size_t, int) { + mlibc::infoLogger() << "mlibc: sys_madvise is a stub!" << frg::endlog; + return 0; +} + +int sys_ptsname(int fd, char *buffer, size_t length) { + int index; + if(int e = sys_ioctl(fd, TIOCGPTN, &index, NULL); e) + return e; + if((size_t)snprintf(buffer, length, "/dev/pts/%d", index) >= length) { + return ERANGE; + } + return 0; +} + +int sys_unlockpt(int fd) { + int unlock = 0; + + if(int e = sys_ioctl(fd, TIOCSPTLCK, &unlock, NULL); e) + return e; + + return 0; +} + +} //namespace mlibc + diff --git a/lib/mlibc/sysdeps/managarm/generic/fork-exec.cpp b/lib/mlibc/sysdeps/managarm/generic/fork-exec.cpp new file mode 100644 index 0000000..8da0e1e --- /dev/null +++ b/lib/mlibc/sysdeps/managarm/generic/fork-exec.cpp @@ -0,0 +1,744 @@ + +// for _Exit() +#include + +#include +#include + +// for fork() and execve() +#include +// for sched_yield() +#include +#include +// for getrusage() +#include +// for waitpid() +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace mlibc { + +int sys_futex_tid() { + HelWord tid = 0; + HEL_CHECK(helSyscall0_1(kHelCallSuper + posix::superGetTid, + &tid)); + + return tid; +} + +int sys_futex_wait(int *pointer, int expected, const struct timespec *time) { + // This implementation is inherently signal-safe. + if(time) { + if(helFutexWait(pointer, expected, time->tv_nsec + time->tv_sec * 1000000000)) + return -1; + return 0; + } + if(helFutexWait(pointer, expected, -1)) + return -1; + return 0; +} + +int sys_futex_wake(int *pointer) { + // This implementation is inherently signal-safe. + if(helFutexWake(pointer)) + return -1; + return 0; +} + +int sys_waitpid(pid_t pid, int *status, int flags, struct rusage *ru, pid_t *ret_pid) { + if(ru) { + mlibc::infoLogger() << "mlibc: struct rusage in sys_waitpid is unsupported" << frg::endlog; + return ENOSYS; + } + + SignalGuard sguard; + + managarm::posix::CntRequest req(getSysdepsAllocator()); + req.set_request_type(managarm::posix::CntReqType::WAIT); + req.set_pid(pid); + req.set_flags(flags); + + auto [offer, send_head, recv_resp] = + exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_head.error()); + HEL_CHECK(recv_resp.error()); + + managarm::posix::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if(resp.error() == managarm::posix::Errors::ILLEGAL_ARGUMENTS) { + return EINVAL; + } + __ensure(resp.error() == managarm::posix::Errors::SUCCESS); + if(status) + *status = resp.mode(); + *ret_pid = resp.pid(); + return 0; +} + +int sys_waitid(idtype_t idtype, id_t id, siginfo_t *info, int options) { + SignalGuard sguard; + + managarm::posix::WaitIdRequest req(getSysdepsAllocator()); + + req.set_idtype(idtype); + req.set_id(id); + req.set_flags(options); + + auto [offer, send_head, recv_resp] = + exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_head.error()); + HEL_CHECK(recv_resp.error()); + + managarm::posix::WaitIdResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if(resp.error() == managarm::posix::Errors::ILLEGAL_ARGUMENTS) { + return EINVAL; + } + __ensure(resp.error() == managarm::posix::Errors::SUCCESS); + info->si_pid = resp.pid(); + info->si_uid = resp.uid(); + info->si_signo = SIGCHLD; + info->si_status = resp.sig_status(); + info->si_code = resp.sig_code(); + return 0; +} + +void sys_exit(int status) { + // This implementation is inherently signal-safe. + HEL_CHECK(helSyscall1(kHelCallSuper + posix::superExit, status)); + __builtin_trap(); +} + +void sys_yield() { + // This implementation is inherently signal-safe. + HEL_CHECK(helYield()); +} + +int sys_sleep(time_t *secs, long *nanos) { + SignalGuard sguard; + globalQueue.trim(); + + uint64_t now; + HEL_CHECK(helGetClock(&now)); + + uint64_t async_id; + HEL_CHECK(helSubmitAwaitClock(now + uint64_t(*secs) * 1000000000 + uint64_t(*nanos), + globalQueue.getQueue(), 0, &async_id)); + + auto element = globalQueue.dequeueSingle(); + auto result = parseSimple(element); + HEL_CHECK(result->error); + + *secs = 0; + *nanos = 0; + + return 0; +} + +int sys_fork(pid_t *child) { + // This implementation is inherently signal-safe. + int res; + + sigset_t full_sigset; + res = sigfillset(&full_sigset); + __ensure(!res); + + sigset_t former_sigset; + res = sigprocmask(SIG_SETMASK, &full_sigset, &former_sigset); + __ensure(!res); + + HelWord out; + HEL_CHECK(helSyscall0_1(kHelCallSuper + posix::superFork, &out)); + *child = out; + + if(!out) { + clearCachedInfos(); + globalQueue.recreateQueue(); + } + + res = sigprocmask(SIG_SETMASK, &former_sigset, nullptr); + __ensure(!res); + + return 0; +} + +int sys_execve(const char *path, char *const argv[], char *const envp[]) { + // TODO: Make this function signal-safe! + frg::string args_area(getSysdepsAllocator()); + for(auto it = argv; *it; ++it) + args_area += frg::string_view{*it, strlen(*it) + 1}; + + frg::string env_area(getSysdepsAllocator()); + for(auto it = envp; *it; ++it) + env_area += frg::string_view{*it, strlen(*it) + 1}; + + uintptr_t out; + + HEL_CHECK(helSyscall6_1(kHelCallSuper + posix::superExecve, + reinterpret_cast(path), + strlen(path), + reinterpret_cast(args_area.data()), + args_area.size(), + reinterpret_cast(env_area.data()), + env_area.size(), + &out)); + + return out; +} + +gid_t sys_getgid() { + SignalGuard sguard; + + managarm::posix::GetGidRequest req(getSysdepsAllocator()); + + auto [offer, send_head, recv_resp] = + exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_head.error()); + HEL_CHECK(recv_resp.error()); + + managarm::posix::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + __ensure(resp.error() == managarm::posix::Errors::SUCCESS); + return resp.uid(); +} + +int sys_setgid(gid_t gid) { + SignalGuard sguard; + + managarm::posix::SetGidRequest req(getSysdepsAllocator()); + + req.set_uid(gid); + + auto [offer, send_head, recv_resp] = + exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_head.error()); + HEL_CHECK(recv_resp.error()); + + managarm::posix::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if(resp.error() == managarm::posix::Errors::ACCESS_DENIED) { + return EPERM; + }else if(resp.error() == managarm::posix::Errors::ILLEGAL_ARGUMENTS) { + return EINVAL; + }else{ + __ensure(resp.error() == managarm::posix::Errors::SUCCESS); + return 0; + } +} + +gid_t sys_getegid() { + SignalGuard sguard; + + managarm::posix::GetEgidRequest req(getSysdepsAllocator()); + + auto [offer, send_head, recv_resp] = + exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_head.error()); + HEL_CHECK(recv_resp.error()); + + managarm::posix::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + __ensure(resp.error() == managarm::posix::Errors::SUCCESS); + return resp.uid(); +} + +int sys_setegid(gid_t egid) { + SignalGuard sguard; + + managarm::posix::SetEgidRequest req(getSysdepsAllocator()); + + req.set_uid(egid); + + auto [offer, send_head, recv_resp] = + exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_head.error()); + HEL_CHECK(recv_resp.error()); + + managarm::posix::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if(resp.error() == managarm::posix::Errors::ACCESS_DENIED) { + return EPERM; + }else if(resp.error() == managarm::posix::Errors::ILLEGAL_ARGUMENTS) { + return EINVAL; + }else{ + __ensure(resp.error() == managarm::posix::Errors::SUCCESS); + return 0; + } +} + +uid_t sys_getuid() { + SignalGuard sguard; + + managarm::posix::GetUidRequest req(getSysdepsAllocator()); + + auto [offer, send_head, recv_resp] = + exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_head.error()); + HEL_CHECK(recv_resp.error()); + + managarm::posix::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + __ensure(resp.error() == managarm::posix::Errors::SUCCESS); + return resp.uid(); +} + +int sys_setuid(uid_t uid) { + SignalGuard sguard; + + managarm::posix::SetUidRequest req(getSysdepsAllocator()); + + req.set_uid(uid); + + auto [offer, send_head, recv_resp] = + exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_head.error()); + HEL_CHECK(recv_resp.error()); + + managarm::posix::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if(resp.error() == managarm::posix::Errors::ACCESS_DENIED) { + return EPERM; + }else if(resp.error() == managarm::posix::Errors::ILLEGAL_ARGUMENTS) { + return EINVAL; + }else{ + __ensure(resp.error() == managarm::posix::Errors::SUCCESS); + return 0; + } +} + +uid_t sys_geteuid() { + SignalGuard sguard; + + managarm::posix::GetEuidRequest req(getSysdepsAllocator()); + + auto [offer, send_head, recv_resp] = + exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_head.error()); + HEL_CHECK(recv_resp.error()); + + managarm::posix::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + __ensure(resp.error() == managarm::posix::Errors::SUCCESS); + return resp.uid(); +} + +int sys_seteuid(uid_t euid) { + SignalGuard sguard; + + managarm::posix::SetEuidRequest req(getSysdepsAllocator()); + + req.set_uid(euid); + + auto [offer, send_head, recv_resp] = + exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_head.error()); + HEL_CHECK(recv_resp.error()); + + managarm::posix::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if(resp.error() == managarm::posix::Errors::ACCESS_DENIED) { + return EPERM; + }else if(resp.error() == managarm::posix::Errors::ILLEGAL_ARGUMENTS) { + return EINVAL; + }else{ + __ensure(resp.error() == managarm::posix::Errors::SUCCESS); + return 0; + } +} + +pid_t sys_gettid() { + // TODO: use an actual gettid syscall. + return sys_getpid(); +} + +pid_t sys_getpid() { + SignalGuard sguard; + + managarm::posix::GetPidRequest req(getSysdepsAllocator()); + + auto [offer, send_head, recv_resp] = + exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_head.error()); + HEL_CHECK(recv_resp.error()); + + managarm::posix::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + __ensure(resp.error() == managarm::posix::Errors::SUCCESS); + return resp.pid(); +} + +pid_t sys_getppid() { + SignalGuard sguard; + + managarm::posix::GetPpidRequest req(getSysdepsAllocator()); + + auto [offer, send_head, recv_resp] = + exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_head.error()); + HEL_CHECK(recv_resp.error()); + + managarm::posix::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + __ensure(resp.error() == managarm::posix::Errors::SUCCESS); + return resp.pid(); +} + +int sys_getsid(pid_t pid, pid_t *sid) { + SignalGuard sguard; + + managarm::posix::GetSidRequest req(getSysdepsAllocator()); + req.set_pid(pid); + + auto [offer, send_head, recv_resp] = + exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_head.error()); + HEL_CHECK(recv_resp.error()); + + managarm::posix::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if(resp.error() == managarm::posix::Errors::NO_SUCH_RESOURCE) { + *sid = 0; + return ESRCH; + } else { + __ensure(resp.error() == managarm::posix::Errors::SUCCESS); + *sid = resp.pid(); + return 0; + } +} + +int sys_getpgid(pid_t pid, pid_t *pgid) { + SignalGuard sguard; + + managarm::posix::GetPgidRequest req(getSysdepsAllocator()); + req.set_pid(pid); + + auto [offer, send_head, recv_resp] = + exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_head.error()); + HEL_CHECK(recv_resp.error()); + + managarm::posix::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if(resp.error() == managarm::posix::Errors::NO_SUCH_RESOURCE) { + *pgid = 0; + return ESRCH; + } else { + __ensure(resp.error() == managarm::posix::Errors::SUCCESS); + *pgid = resp.pid(); + return 0; + } +} + +int sys_setpgid(pid_t pid, pid_t pgid) { + SignalGuard sguard; + + managarm::posix::SetPgidRequest req(getSysdepsAllocator()); + + req.set_pid(pid); + req.set_pgid(pgid); + + auto [offer, send_head, recv_resp] = + exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_head.error()); + HEL_CHECK(recv_resp.error()); + + managarm::posix::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if(resp.error() == managarm::posix::Errors::INSUFFICIENT_PERMISSION) { + return EPERM; + }else if(resp.error() == managarm::posix::Errors::NO_SUCH_RESOURCE) { + return ESRCH; + }else if(resp.error() == managarm::posix::Errors::ACCESS_DENIED) { + return EACCES; + }else{ + __ensure(resp.error() == managarm::posix::Errors::SUCCESS); + return 0; + } +} + +int sys_getrusage(int scope, struct rusage *usage) { + memset(usage, 0, sizeof(struct rusage)); + + SignalGuard sguard; + + managarm::posix::CntRequest req(getSysdepsAllocator()); + req.set_request_type(managarm::posix::CntReqType::GET_RESOURCE_USAGE); + req.set_mode(scope); + + auto [offer, send_head, recv_resp] = + exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_head.error()); + HEL_CHECK(recv_resp.error()); + + managarm::posix::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + __ensure(resp.error() == managarm::posix::Errors::SUCCESS); + + usage->ru_utime.tv_sec = resp.ru_user_time() / 1'000'000'000; + usage->ru_utime.tv_usec = (resp.ru_user_time() % 1'000'000'000) / 1'000; + + return 0; +} + +int sys_getschedparam(void *tcb, int *policy, struct sched_param *param) { + if(tcb != mlibc::get_current_tcb()) { + return ESRCH; + } + + *policy = SCHED_OTHER; + int prio = 0; + // TODO(no92): use helGetPriority(kHelThisThread) here + mlibc::infoLogger() << "\e[31mlibc: sys_getschedparam always returns priority 0\e[39m" << frg::endlog; + param->sched_priority = prio; + + return 0; +} + +int sys_setschedparam(void *tcb, int policy, const struct sched_param *param) { + if(tcb != mlibc::get_current_tcb()) { + return ESRCH; + } + + if(policy != SCHED_OTHER) { + return EINVAL; + } + + HEL_CHECK(helSetPriority(kHelThisThread, param->sched_priority)); + + return 0; +} + +int sys_clone(void *tcb, pid_t *pid_out, void *stack) { + HelWord pid = 0; + HEL_CHECK(helSyscall2_1(kHelCallSuper + posix::superClone, + reinterpret_cast(__mlibc_start_thread), + reinterpret_cast(stack), + &pid)); + + if (pid_out) + *pid_out = pid; + + return 0; +} + +int sys_tcb_set(void *pointer) { +#if defined(__aarch64__) + uintptr_t addr = reinterpret_cast(pointer); + addr += sizeof(Tcb) - 0x10; + asm volatile ("msr tpidr_el0, %0" :: "r"(addr)); +#else + HEL_CHECK(helWriteFsBase(pointer)); +#endif + return 0; +} + +void sys_thread_exit() { + // This implementation is inherently signal-safe. + HEL_CHECK(helSyscall1(kHelCallSuper + posix::superExit, 0)); + __builtin_trap(); +} + +int sys_thread_setname(void *tcb, const char *name) { + if(strlen(name) > 15) { + return ERANGE; + } + + auto t = reinterpret_cast(tcb); + char *path; + int cs = 0; + + if(asprintf(&path, "/proc/self/task/%d/comm", t->tid) < 0) { + return ENOMEM; + } + + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs); + + int fd; + if(int e = sys_open(path, O_WRONLY, 0, &fd); e) { + return e; + } + + if(int e = sys_write(fd, name, strlen(name) + 1, NULL)) { + return e; + } + + sys_close(fd); + + pthread_setcancelstate(cs, 0); + + return 0; +} + +int sys_thread_getname(void *tcb, char *name, size_t size) { + auto t = reinterpret_cast(tcb); + char *path; + int cs = 0; + ssize_t real_size = 0; + + if(asprintf(&path, "/proc/self/task/%d/comm", t->tid) < 0) { + return ENOMEM; + } + + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs); + + int fd; + if(int e = sys_open(path, O_RDONLY | O_CLOEXEC, 0, &fd); e) { + return e; + } + + if(int e = sys_read(fd, name, size, &real_size)) { + return e; + } + + name[real_size - 1] = 0; + sys_close(fd); + + pthread_setcancelstate(cs, 0); + + if(static_cast(size) <= real_size) { + return ERANGE; + } + + return 0; +} + + +} //namespace mlibc + diff --git a/lib/mlibc/sysdeps/managarm/generic/ioctl.cpp b/lib/mlibc/sysdeps/managarm/generic/ioctl.cpp new file mode 100644 index 0000000..384c09e --- /dev/null +++ b/lib/mlibc/sysdeps/managarm/generic/ioctl.cpp @@ -0,0 +1,708 @@ +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +namespace mlibc { + +static constexpr bool logIoctls = false; + +int ioctl_drm(int fd, unsigned long request, void *arg, int *result, HelHandle handle); + +int sys_ioctl(int fd, unsigned long request, void *arg, int *result) { + if(logIoctls) + mlibc::infoLogger() << "mlibc: ioctl with" + << " type: 0x" << frg::hex_fmt(_IOC_TYPE(request)) + << ", number: 0x" << frg::hex_fmt(_IOC_NR(request)) + << " (raw request: " << frg::hex_fmt(request) << ")" + << " on fd " << fd << frg::endlog; + + SignalGuard sguard; + auto handle = getHandleForFd(fd); + if(!handle) + return EBADF; + + if(_IOC_TYPE(request) == 'd') { + return ioctl_drm(fd, request, arg, result, handle); + } + + managarm::fs::IoctlRequest ioctl_req(getSysdepsAllocator()); + + switch(request) { + case FIONBIO: { + auto mode = reinterpret_cast(arg); + int flags = fcntl(fd, F_GETFL, 0); + if(*mode) { + fcntl(fd, F_SETFL, flags | O_NONBLOCK); + }else{ + fcntl(fd, F_SETFL, flags & ~O_NONBLOCK); + } + return 0; + } + case FIONREAD: { + auto argp = reinterpret_cast(arg); + + auto handle = getHandleForFd(fd); + if (!handle) + return EBADF; + + if(!argp) + return EINVAL; + + managarm::fs::GenericIoctlRequest req(getSysdepsAllocator()); + req.set_command(FIONREAD); + + auto [offer, send_ioctl_req, send_req, recv_resp] = + exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(ioctl_req, getSysdepsAllocator()), + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_ioctl_req.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::fs::GenericIoctlReply resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if(resp.error() == managarm::fs::Errors::NOT_CONNECTED) { + return ENOTCONN; + } else { + __ensure(resp.error() == managarm::fs::Errors::SUCCESS); + + *argp = resp.fionread_count(); + + return 0; + } + } + case FIOCLEX: { + managarm::posix::IoctlFioclexRequest req(getSysdepsAllocator()); + req.set_fd(fd); + + auto [offer, sendReq, recvResp] = exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(sendReq.error()); + if(recvResp.error() == kHelErrDismissed) + return EINVAL; + HEL_CHECK(recvResp.error()); + + managarm::posix::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recvResp.data(), recvResp.length()); + __ensure(resp.error() == managarm::posix::Errors::SUCCESS); + return 0; + } + case TCGETS: { + auto param = reinterpret_cast(arg); + + managarm::fs::GenericIoctlRequest req(getSysdepsAllocator()); + req.set_command(request); + + auto [offer, send_ioctl_req, send_req, recv_resp, recv_attrs] = exchangeMsgsSync(handle, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(ioctl_req, getSysdepsAllocator()), + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline(), + helix_ng::recvBuffer(param, sizeof(struct termios)) + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_ioctl_req.error()); + if(send_req.error() == kHelErrDismissed) + return EINVAL; + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + HEL_CHECK(recv_attrs.error()); + + managarm::fs::GenericIoctlReply resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + __ensure(resp.error() == managarm::fs::Errors::SUCCESS); + __ensure(recv_attrs.actualLength() == sizeof(struct termios)); + *result = resp.result(); + return 0; + } + case TCSETS: { + auto param = reinterpret_cast(arg); + + managarm::fs::GenericIoctlRequest req(getSysdepsAllocator()); + req.set_command(request); + + auto [offer, send_ioctl_req, send_req, send_attrs, recv_resp] = exchangeMsgsSync(handle, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(ioctl_req, getSysdepsAllocator()), + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::sendBuffer(param, sizeof(struct termios)), + helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_ioctl_req.error()); + if(send_req.error() == kHelErrDismissed) + return EINVAL; + HEL_CHECK(send_req.error()); + HEL_CHECK(send_attrs.error()); + HEL_CHECK(recv_resp.error()); + + managarm::fs::GenericIoctlReply resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + __ensure(resp.error() == managarm::fs::Errors::SUCCESS); + if(result) + *result = resp.result(); + return 0; + } + case TIOCSCTTY: { + managarm::fs::GenericIoctlRequest req(getSysdepsAllocator()); + req.set_command(request); + + auto [offer, send_ioctl_req, send_req, imbue_creds, recv_resp] = exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(ioctl_req, getSysdepsAllocator()), + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::imbueCredentials(), + helix_ng::recvInline()) + ); + + HEL_CHECK(offer.error()); + if(send_req.error() == kHelErrDismissed) + return EINVAL; + HEL_CHECK(send_ioctl_req.error()); + HEL_CHECK(imbue_creds.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::fs::GenericIoctlReply resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + + if(resp.error() == managarm::fs::Errors::ILLEGAL_ARGUMENT) { + return EINVAL; + }else if(resp.error() == managarm::fs::Errors::INSUFFICIENT_PERMISSIONS) { + return EPERM; + } + __ensure(resp.error() == managarm::fs::Errors::SUCCESS); + *result = resp.result(); + return 0; + } + case TIOCGWINSZ: { + auto param = reinterpret_cast(arg); + + managarm::fs::GenericIoctlRequest req(getSysdepsAllocator()); + req.set_command(request); + + auto [offer, send_ioctl_req, send_req, recv_resp] = exchangeMsgsSync(handle, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(ioctl_req, getSysdepsAllocator()), + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_ioctl_req.error()); + if(send_req.error() == kHelErrDismissed) + return EINVAL; + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::fs::GenericIoctlReply resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if(resp.error() == managarm::fs::Errors::ILLEGAL_OPERATION_TARGET) + return EINVAL; + __ensure(resp.error() == managarm::fs::Errors::SUCCESS); + + *result = resp.result(); + param->ws_col = resp.pts_width(); + param->ws_row = resp.pts_height(); + param->ws_xpixel = resp.pts_pixel_width(); + param->ws_ypixel = resp.pts_pixel_height(); + return 0; + } + case TIOCSWINSZ: { + auto param = reinterpret_cast(arg); + + managarm::fs::GenericIoctlRequest req(getSysdepsAllocator()); + req.set_command(request); + req.set_pts_width(param->ws_col); + req.set_pts_height(param->ws_row); + req.set_pts_pixel_width(param->ws_xpixel); + req.set_pts_pixel_height(param->ws_ypixel); + + auto [offer, send_ioctl_req, send_req, recv_resp] = exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(ioctl_req, getSysdepsAllocator()), + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline()) + ); + HEL_CHECK(offer.error()); + HEL_CHECK(send_ioctl_req.error()); + if(send_req.error() == kHelErrDismissed) + return EINVAL; + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::fs::GenericIoctlReply resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + __ensure(resp.error() == managarm::fs::Errors::SUCCESS); + + *result = resp.result(); + return 0; + } + case TIOCGPTN: { + auto param = reinterpret_cast(arg); + + managarm::fs::GenericIoctlRequest req(getSysdepsAllocator()); + req.set_command(request); + + auto [offer, send_ioctl_req, send_req, recv_resp] = exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(ioctl_req, getSysdepsAllocator()), + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline()) + ); + HEL_CHECK(offer.error()); + HEL_CHECK(send_ioctl_req.error()); + if(send_req.error() == kHelErrDismissed) + return EINVAL; + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::fs::GenericIoctlReply resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + __ensure(resp.error() == managarm::fs::Errors::SUCCESS); + *param = resp.pts_index(); + if(result) + *result = resp.result(); + return 0; + } + case TIOCGPGRP: { + managarm::fs::GenericIoctlRequest req(getSysdepsAllocator()); + req.set_command(request); + + frg::string ser(getSysdepsAllocator()); + req.SerializeToString(&ser); + + auto [offer, send_ioctl_req, send_req, imbue_creds, recv_resp] = + exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(ioctl_req, getSysdepsAllocator()), + helix_ng::sendBuffer(ser.data(), ser.size()), + helix_ng::imbueCredentials(), + helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_ioctl_req.error()); + if(send_req.error()) + return EINVAL; + HEL_CHECK(send_req.error()); + HEL_CHECK(imbue_creds.error()); + HEL_CHECK(recv_resp.error()); + + managarm::fs::GenericIoctlReply resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if(resp.error() == managarm::fs::Errors::NOT_A_TERMINAL) { + return ENOTTY; + } + __ensure(resp.error() == managarm::fs::Errors::SUCCESS); + *result = resp.result(); + *static_cast(arg) = resp.pid(); + return 0; + } + case TIOCSPGRP: { + auto param = reinterpret_cast(arg); + + managarm::fs::GenericIoctlRequest req(getSysdepsAllocator()); + req.set_command(request); + req.set_pgid(*param); + + frg::string ser(getSysdepsAllocator()); + req.SerializeToString(&ser); + + auto [offer, send_ioctl_req, send_req, imbue_creds, recv_resp] = + exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(ioctl_req, getSysdepsAllocator()), + helix_ng::sendBuffer(ser.data(), ser.size()), + helix_ng::imbueCredentials(), + helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_ioctl_req.error()); + if(send_req.error() == kHelErrDismissed) + return EINVAL; + HEL_CHECK(send_req.error()); + HEL_CHECK(imbue_creds.error()); + HEL_CHECK(recv_resp.error()); + + managarm::fs::GenericIoctlReply resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if(resp.error() == managarm::fs::Errors::INSUFFICIENT_PERMISSIONS) { + return EPERM; + } else if(resp.error() == managarm::fs::Errors::ILLEGAL_ARGUMENT) { + return EINVAL; + } + __ensure(resp.error() == managarm::fs::Errors::SUCCESS); + *result = resp.result(); + return 0; + } + case TIOCGSID: { + managarm::fs::GenericIoctlRequest req(getSysdepsAllocator()); + req.set_command(request); + + frg::string ser(getSysdepsAllocator()); + req.SerializeToString(&ser); + + auto [offer, send_ioctl_req, send_req, imbue_creds, recv_resp] = + exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(ioctl_req, getSysdepsAllocator()), + helix_ng::sendBuffer(ser.data(), ser.size()), + helix_ng::imbueCredentials(), + helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + if(send_ioctl_req.error()) + return EINVAL; + HEL_CHECK(send_ioctl_req.error()); + if(send_req.error()) + return EINVAL; + HEL_CHECK(send_req.error()); + if(imbue_creds.error() == kHelErrDismissed) + return EINVAL; + HEL_CHECK(imbue_creds.error()); + HEL_CHECK(recv_resp.error()); + + managarm::fs::GenericIoctlReply resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if(resp.error() == managarm::fs::Errors::NOT_A_TERMINAL) { + return ENOTTY; + } + __ensure(resp.error() == managarm::fs::Errors::SUCCESS); + *result = resp.result(); + *static_cast(arg) = resp.pid(); + return 0; + } + case CDROM_GET_CAPABILITY: { + managarm::fs::GenericIoctlRequest req(getSysdepsAllocator()); + req.set_command(request); + + frg::string ser(getSysdepsAllocator()); + req.SerializeToString(&ser); + + auto [offer, send_ioctl_req, send_req, recv_resp] = + exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(ioctl_req, getSysdepsAllocator()), + helix_ng::sendBuffer(ser.data(), ser.size()), + helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + if(send_ioctl_req.error()) + return EINVAL; + HEL_CHECK(send_ioctl_req.error()); + if(send_req.error()) + return EINVAL; + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::fs::GenericIoctlReply resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if(resp.error() == managarm::fs::Errors::NOT_A_TERMINAL) { + return ENOTTY; + } + __ensure(resp.error() == managarm::fs::Errors::SUCCESS); + *result = resp.result(); + return 0; + } + } // end of switch() + + + if(_IOC_TYPE(request) == 'E' + && _IOC_NR(request) == _IOC_NR(EVIOCGVERSION)) { + *reinterpret_cast(arg) = 0x010001; // should be EV_VERSION + *result = 0; + return 0; + }else if(_IOC_TYPE(request) == 'E' + && _IOC_NR(request) == _IOC_NR(EVIOCGID)) { + memset(arg, 0, sizeof(struct input_id)); + *result = 0; + return 0; + }else if(_IOC_TYPE(request) == 'E' + && _IOC_NR(request) == _IOC_NR(EVIOCGNAME(0))) { + const char *s = "Managarm generic evdev"; + auto chunk = frg::min(_IOC_SIZE(request), strlen(s) + 1); + memcpy(arg, s, chunk); + *result = chunk; + return 0; + }else if(_IOC_TYPE(request) == 'E' + && _IOC_NR(request) == _IOC_NR(EVIOCGPHYS(0))) { + // Returns the sysfs path of the device. + const char *s = "input0"; + auto chunk = frg::min(_IOC_SIZE(request), strlen(s) + 1); + memcpy(arg, s, chunk); + *result = chunk; + return 0; + }else if(_IOC_TYPE(request) == 'E' + && _IOC_NR(request) == _IOC_NR(EVIOCGUNIQ(0))) { + // Returns a unique ID for the device. + const char *s = "0"; + auto chunk = frg::min(_IOC_SIZE(request), strlen(s) + 1); + memcpy(arg, s, chunk); + *result = chunk; + return 0; + }else if(_IOC_TYPE(request) == 'E' + && _IOC_NR(request) == _IOC_NR(EVIOCGPROP(0))) { + // Returns a bitmask of properties of the device. + auto size = _IOC_SIZE(request); + memset(arg, 0, size); + *result = size; + return 0; + }else if(_IOC_TYPE(request) == 'E' + && _IOC_NR(request) == _IOC_NR(EVIOCGKEY(0))) { + // Returns the current key state. + auto size = _IOC_SIZE(request); + memset(arg, 0, size); + *result = size; + return 0; + }else if(_IOC_TYPE(request) == 'E' + && _IOC_NR(request) == _IOC_NR(EVIOCGLED(0))) { + // Returns the current LED state. + auto size = _IOC_SIZE(request); + memset(arg, 0, size); + *result = size; + return 0; + }else if(_IOC_TYPE(request) == 'E' + && _IOC_NR(request) == _IOC_NR(EVIOCGSW(0))) { + auto size = _IOC_SIZE(request); + memset(arg, 0, size); + *result = size; + return 0; + }else if(_IOC_TYPE(request) == 'E' + && _IOC_NR(request) >= _IOC_NR(EVIOCGBIT(0, 0)) + && _IOC_NR(request) <= _IOC_NR(EVIOCGBIT(EV_MAX, 0))) { + // Returns a bitmask of capabilities of the device. + // If type is zero, return a mask of supported types. + // As EV_SYN is zero, this implies that it is impossible + // to get the mask of supported synthetic events. + auto type = _IOC_NR(request) - _IOC_NR(EVIOCGBIT(0, 0)); + if(!type) { + // TODO: Check with the Linux ABI if we have to do this. + memset(arg, 0, _IOC_SIZE(request)); + + managarm::fs::GenericIoctlRequest req(getSysdepsAllocator()); + req.set_command(EVIOCGBIT(0, 0)); + req.set_size(_IOC_SIZE(request)); + + auto [offer, send_ioctl_req, send_req, recv_resp, recv_data] = exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(ioctl_req, getSysdepsAllocator()), + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline(), + helix_ng::recvBuffer(arg, _IOC_SIZE(request))) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_ioctl_req.error()); + if(send_req.error() == kHelErrDismissed) + return EINVAL; + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + HEL_CHECK(recv_data.error()); + + managarm::fs::GenericIoctlReply resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + __ensure(resp.error() == managarm::fs::Errors::SUCCESS); + *result = recv_data.actualLength(); + return 0; + }else{ + // TODO: Check with the Linux ABI if we have to do this. + memset(arg, 0, _IOC_SIZE(request)); + + managarm::fs::GenericIoctlRequest req(getSysdepsAllocator()); + req.set_command(EVIOCGBIT(1, 0)); + req.set_input_type(type); + req.set_size(_IOC_SIZE(request)); + + auto [offer, send_ioctl_req, send_req, recv_resp, recv_data] = exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(ioctl_req, getSysdepsAllocator()), + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline(), + helix_ng::recvBuffer(arg, _IOC_SIZE(request))) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_ioctl_req.error()); + if(send_req.error() == kHelErrDismissed) + return EINVAL; + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + HEL_CHECK(recv_data.error()); + + managarm::fs::GenericIoctlReply resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + __ensure(resp.error() == managarm::fs::Errors::SUCCESS); + *result = recv_data.actualLength(); + return 0; + } + }else if(_IOC_TYPE(request) == 'E' + && _IOC_NR(request) == _IOC_NR(EVIOCSCLOCKID)) { + auto param = reinterpret_cast(arg); + + managarm::fs::GenericIoctlRequest req(getSysdepsAllocator()); + req.set_command(request); + req.set_input_clock(*param); + + auto [offer, send_ioctl_req, send_req, recv_resp] = exchangeMsgsSync(handle, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(ioctl_req, getSysdepsAllocator()), + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_ioctl_req.error()); + if(send_req.error() == kHelErrDismissed) + return EINVAL; + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::fs::GenericIoctlReply resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + __ensure(resp.error() == managarm::fs::Errors::SUCCESS); + *result = resp.result(); + return 0; + }else if(_IOC_TYPE(request) == 'E' + && _IOC_NR(request) >= _IOC_NR(EVIOCGABS(0)) + && _IOC_NR(request) <= _IOC_NR(EVIOCGABS(ABS_MAX))) { + auto param = reinterpret_cast(arg); + + auto type = _IOC_NR(request) - _IOC_NR(EVIOCGABS(0)); + managarm::fs::GenericIoctlRequest req(getSysdepsAllocator()); + req.set_command(EVIOCGABS(0)); + req.set_input_type(type); + + auto [offer, send_ioctl_req, send_req, recv_resp] = exchangeMsgsSync(handle, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(ioctl_req, getSysdepsAllocator()), + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_ioctl_req.error()); + if(send_req.error() == kHelErrDismissed) + return EINVAL; + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::fs::GenericIoctlReply resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + __ensure(resp.error() == managarm::fs::Errors::SUCCESS); + + param->value = resp.input_value(); + param->minimum = resp.input_min(); + param->maximum = resp.input_max(); + param->fuzz = resp.input_fuzz(); + param->flat = resp.input_flat(); + param->resolution = resp.input_resolution(); + + *result = resp.result(); + return 0; + }else if(request == KDSETMODE) { + auto param = reinterpret_cast(arg); + mlibc::infoLogger() << "\e[35mmlibc: KD_SETMODE(" << frg::hex_fmt(param) << ") is a no-op" << frg::endlog; + + *result = 0; + return 0; + }else if(request == KDGETMODE) { + auto param = reinterpret_cast(arg); + mlibc::infoLogger() << "\e[35mmlibc: KD_GETMODE is a no-op" << frg::endlog; + *param = 0; + + *result = 0; + return 0; + }else if(request == KDSKBMODE) { + auto param = reinterpret_cast(arg); + mlibc::infoLogger() << "\e[35mmlibc: KD_SKBMODE(" << frg::hex_fmt(param) << ") is a no-op" << frg::endlog; + + *result = 0; + return 0; + }else if(request == VT_SETMODE) { + // auto param = reinterpret_cast(arg); + mlibc::infoLogger() << "\e[35mmlibc: VT_SETMODE is a no-op" << frg::endlog; + + *result = 0; + return 0; + }else if(request == VT_GETSTATE) { + auto param = reinterpret_cast(arg); + + param->v_active = 0; + param->v_signal = 0; + param->v_state = 0; + + mlibc::infoLogger() << "\e[35mmlibc: VT_GETSTATE is a no-op" << frg::endlog; + + *result = 0; + return 0; + }else if(request == VT_ACTIVATE || request == VT_WAITACTIVE) { + mlibc::infoLogger() << "\e[35mmlibc: VT_ACTIVATE/VT_WAITACTIVE are no-ops" << frg::endlog; + *result = 0; + return 0; + }else if(request == TIOCSPTLCK) { + mlibc::infoLogger() << "\e[35mmlibc: TIOCSPTLCK is a no-op" << frg::endlog; + if(result) + *result = 0; + return 0; + } + + mlibc::infoLogger() << "mlibc: Unexpected ioctl with" + << " type: 0x" << frg::hex_fmt(_IOC_TYPE(request)) + << ", number: 0x" << frg::hex_fmt(_IOC_NR(request)) + << " (raw request: " << frg::hex_fmt(request) << ")" << frg::endlog; + __ensure(!"Illegal ioctl request"); + __builtin_unreachable(); +} + +} //namespace mlibc diff --git a/lib/mlibc/sysdeps/managarm/generic/memory.cpp b/lib/mlibc/sysdeps/managarm/generic/memory.cpp new file mode 100644 index 0000000..91e47af --- /dev/null +++ b/lib/mlibc/sysdeps/managarm/generic/memory.cpp @@ -0,0 +1,30 @@ + +#include + +#include +#include +#include +#include + +#include +#include + +namespace mlibc { + +int sys_anon_allocate(size_t size, void **pointer) { + // This implementation is inherently signal-safe. + __ensure(!(size & 0xFFF)); + HelWord out; + HEL_CHECK(helSyscall1_1(kHelCallSuper + posix::superAnonAllocate, size, &out)); + *pointer = reinterpret_cast(out); + return 0; +} + +int sys_anon_free(void *pointer, size_t size) { + // This implementation is inherently signal-safe. + HEL_CHECK(helSyscall2(kHelCallSuper + posix::superAnonDeallocate, (HelWord)pointer, size)); + return 0; +} + +} //namespace mlibc + diff --git a/lib/mlibc/sysdeps/managarm/generic/mount.cpp b/lib/mlibc/sysdeps/managarm/generic/mount.cpp new file mode 100644 index 0000000..5677b20 --- /dev/null +++ b/lib/mlibc/sysdeps/managarm/generic/mount.cpp @@ -0,0 +1,44 @@ +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +namespace mlibc { + +int sys_mount(const char *source, const char *target, + const char *fstype, unsigned long, const void *) { + SignalGuard sguard; + + managarm::posix::MountRequest req(getSysdepsAllocator()); + req.set_path(frg::string(getSysdepsAllocator(), source)); + req.set_target_path(frg::string(getSysdepsAllocator(), target)); + req.set_fs_type(frg::string(getSysdepsAllocator(), fstype)); + + auto [offer, send_head, send_tail, recv_resp] = + exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadTail(req, getSysdepsAllocator()), + helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_head.error()); + HEL_CHECK(send_tail.error()); + HEL_CHECK(recv_resp.error()); + + auto resp = *bragi::parse_head_only(recv_resp, getSysdepsAllocator()); + if(resp.error() == managarm::posix::Errors::FILE_NOT_FOUND) + return ENOENT; + __ensure(resp.error() == managarm::posix::Errors::SUCCESS); + return 0; +} + +} //namespace mlibc diff --git a/lib/mlibc/sysdeps/managarm/generic/net.cpp b/lib/mlibc/sysdeps/managarm/generic/net.cpp new file mode 100644 index 0000000..63f2d0c --- /dev/null +++ b/lib/mlibc/sysdeps/managarm/generic/net.cpp @@ -0,0 +1,57 @@ +#include +#include +#include +#include +#include +#include + +namespace mlibc { + +int sys_if_indextoname(unsigned int index, char *name) { + int fd = 0; + int r = sys_socket(AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, AF_UNSPEC, &fd); + + if(r) + return r; + + struct ifreq ifr; + ifr.ifr_ifindex = index; + + int res = 0; + int ret = sys_ioctl(fd, SIOCGIFNAME, &ifr, &res); + close(fd); + + if(ret) { + if(ret == ENODEV) + return ENXIO; + return ret; + } + + strncpy(name, ifr.ifr_name, IF_NAMESIZE); + + return 0; +} + +int sys_if_nametoindex(const char *name, unsigned int *ret) { + int fd = 0; + int r = sys_socket(AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, AF_UNSPEC, &fd); + + if(r) + return r; + + struct ifreq ifr; + strncpy(ifr.ifr_name, name, sizeof ifr.ifr_name); + + int res = 0; + r = sys_ioctl(fd, SIOCGIFINDEX, &ifr, &res); + close(fd); + + if(r) + return r; + + *ret = ifr.ifr_ifindex; + + return 0; +} + +} //namespace mlibc diff --git a/lib/mlibc/sysdeps/managarm/generic/sched.cpp b/lib/mlibc/sysdeps/managarm/generic/sched.cpp new file mode 100644 index 0000000..bce8db8 --- /dev/null +++ b/lib/mlibc/sysdeps/managarm/generic/sched.cpp @@ -0,0 +1,102 @@ +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +namespace mlibc { + +int sys_getaffinity(pid_t pid, size_t cpusetsize, cpu_set_t *mask) { + return sys_getthreadaffinity(pid, cpusetsize, mask); +} + +int sys_getthreadaffinity(pid_t tid, size_t cpusetsize, cpu_set_t *mask) { + SignalGuard sguard; + + managarm::posix::GetAffinityRequest req(getSysdepsAllocator()); + + req.set_pid(tid); + req.set_size(cpusetsize); + + auto [offer, send_head, recv_resp, recv_data] = + exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline(), + helix_ng::recvBuffer(mask, cpusetsize) + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_head.error()); + HEL_CHECK(recv_resp.error()); + + managarm::posix::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + + if(resp.error() == managarm::posix::Errors::ILLEGAL_ARGUMENTS) { + return EINVAL; + } else if(resp.error() != managarm::posix::Errors::SUCCESS) { + mlibc::infoLogger() << "mlibc: got unexpected error from posix in sys_getaffinity!" << frg::endlog; + return EIEIO; + } + HEL_CHECK(recv_data.error()); + + return 0; +} + +int sys_setaffinity(pid_t pid, size_t cpusetsize, const cpu_set_t *mask) { + return sys_setthreadaffinity(pid, cpusetsize, mask); +} + +int sys_setthreadaffinity(pid_t tid, size_t cpusetsize, const cpu_set_t *mask) { + SignalGuard sguard; + + frg::vector affinity_mask(getSysdepsAllocator()); + affinity_mask.resize(cpusetsize); + memcpy(affinity_mask.data(), mask, cpusetsize); + managarm::posix::SetAffinityRequest req(getSysdepsAllocator()); + + req.set_pid(tid); + req.set_mask(affinity_mask); + + auto [offer, send_head, send_tail, recv_resp] = + exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadTail(req, getSysdepsAllocator()), + helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_head.error()); + HEL_CHECK(send_tail.error()); + HEL_CHECK(recv_resp.error()); + + managarm::posix::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + + if(resp.error() == managarm::posix::Errors::ILLEGAL_ARGUMENTS) { + return EINVAL; + } else if(resp.error() != managarm::posix::Errors::SUCCESS) { + mlibc::infoLogger() << "mlibc: got unexpected error from posix in sys_getaffinity!" << frg::endlog; + return EIEIO; + } + + return 0; +} + +int sys_getcpu(int *cpu) { + HEL_CHECK(helGetCurrentCpu(cpu)); + return 0; +} + +} diff --git a/lib/mlibc/sysdeps/managarm/generic/signals.cpp b/lib/mlibc/sysdeps/managarm/generic/signals.cpp new file mode 100644 index 0000000..486f3d4 --- /dev/null +++ b/lib/mlibc/sysdeps/managarm/generic/signals.cpp @@ -0,0 +1,139 @@ +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include + +extern "C" void __mlibc_signal_restore(); + +namespace mlibc { + +int sys_sigprocmask(int how, const sigset_t *set, sigset_t *retrieve) { + // This implementation is inherently signal-safe. + uint64_t former, unused; + if(set) { + HEL_CHECK(helSyscall2_2(kHelObserveSuperCall + posix::superSigMask, how, *set, &former, &unused)); + }else{ + HEL_CHECK(helSyscall2_2(kHelObserveSuperCall + posix::superSigMask, 0, 0, &former, &unused)); + } + if(retrieve) + *retrieve = former; + return 0; +} + +int sys_sigaction(int number, const struct sigaction *__restrict action, + struct sigaction *__restrict saved_action) { + SignalGuard sguard; + + // TODO: Respect restorer. __ensure(!(action->sa_flags & SA_RESTORER)); + + managarm::posix::CntRequest req(getSysdepsAllocator()); + req.set_request_type(managarm::posix::CntReqType::SIG_ACTION); + req.set_sig_number(number); + if(action) { + req.set_mode(1); + req.set_flags(action->sa_flags); + req.set_sig_mask(action->sa_mask); + if(action->sa_flags & SA_SIGINFO) { + req.set_sig_handler(reinterpret_cast(action->sa_sigaction)); + }else{ + req.set_sig_handler(reinterpret_cast(action->sa_handler)); + } + req.set_sig_restorer(reinterpret_cast(&__mlibc_signal_restore)); + } else { + req.set_mode(0); + } + + auto [offer, send_req, recv_resp] = exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline()) + ); + HEL_CHECK(offer.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::posix::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + + if(resp.error() == managarm::posix::Errors::ILLEGAL_REQUEST) { + // This is only returned for servers, not for normal userspace. + return ENOSYS; + }else if(resp.error() == managarm::posix::Errors::ILLEGAL_ARGUMENTS) { + return EINVAL; + } + __ensure(resp.error() == managarm::posix::Errors::SUCCESS); + + if(saved_action) { + saved_action->sa_flags = resp.flags(); + saved_action->sa_mask = resp.sig_mask(); + if(resp.flags() & SA_SIGINFO) { + saved_action->sa_sigaction = + reinterpret_cast(resp.sig_handler()); + }else{ + saved_action->sa_handler = reinterpret_cast(resp.sig_handler()); + } + // TODO: saved_action->sa_restorer = resp.sig_restorer; + } + return 0; +} + +int sys_kill(int pid, int number) { + // This implementation is inherently signal-safe. + HEL_CHECK(helSyscall2(kHelObserveSuperCall + posix::superSigKill, pid, number)); + return 0; +} + +int sys_tgkill(int, int tid, int number) { + return sys_kill(tid, number); +} + +int sys_sigaltstack(const stack_t *ss, stack_t *oss) { + HelWord out; + + // This implementation is inherently signal-safe. + HEL_CHECK(helSyscall2_1(kHelObserveSuperCall + posix::superSigAltStack, + reinterpret_cast(ss), + reinterpret_cast(oss), + &out)); + + return out; +} + +int sys_sigsuspend(const sigset_t *set) { + //SignalGuard sguard; + uint64_t former, seq, unused; + + HEL_CHECK(helSyscall2_2(kHelObserveSuperCall + posix::superSigMask, SIG_SETMASK, *set, &former, &seq)); + HEL_CHECK(helSyscall1(kHelObserveSuperCall + posix::superSigSuspend, seq)); + HEL_CHECK(helSyscall2_2(kHelObserveSuperCall + posix::superSigMask, SIG_SETMASK, former, &unused, &unused)); + + return EINTR; +} + +int sys_sigpending(sigset_t *set) { + uint64_t pendingMask; + + HEL_CHECK(helSyscall0_1(kHelObserveSuperCall + posix::superSigGetPending, &pendingMask)); + *set = pendingMask; + + return 0; +} + +} //namespace mlibc diff --git a/lib/mlibc/sysdeps/managarm/generic/socket.cpp b/lib/mlibc/sysdeps/managarm/generic/socket.cpp new file mode 100644 index 0000000..5bdc1fc --- /dev/null +++ b/lib/mlibc/sysdeps/managarm/generic/socket.cpp @@ -0,0 +1,423 @@ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +namespace { + +int fcntl_helper(int fd, int request, int *result, ...) { + va_list args; + va_start(args, result); + if(!mlibc::sys_fcntl) { + return ENOSYS; + } + int ret = mlibc::sys_fcntl(fd, request, args, result); + va_end(args); + return ret; +} + +} + +namespace mlibc { + +int sys_accept(int fd, int *newfd, struct sockaddr *addr_ptr, socklen_t *addr_length, int flags) { + SignalGuard sguard; + + managarm::posix::AcceptRequest req(getSysdepsAllocator()); + req.set_fd(fd); + + auto [offer, sendReq, recvResp] = exchangeMsgsSync( + getPosixLane(), + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(sendReq.error()); + HEL_CHECK(recvResp.error()); + + managarm::posix::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recvResp.data(), recvResp.length()); + if(resp.error() == managarm::posix::Errors::WOULD_BLOCK) { + return EWOULDBLOCK; + }else{ + __ensure(resp.error() == managarm::posix::Errors::SUCCESS); + *newfd = resp.fd(); + } + + if(addr_ptr && addr_length) { + if(int e = mlibc::sys_peername(*newfd, addr_ptr, *addr_length, addr_length); e) { + errno = e; + return -1; + } + } + + if(flags & SOCK_NONBLOCK) { + int fcntl_ret = 0; + fcntl_helper(*newfd, F_GETFL, &fcntl_ret); + fcntl_helper(*newfd, F_SETFL, &fcntl_ret, fcntl_ret | O_NONBLOCK); + } + + if(flags & SOCK_CLOEXEC) { + int fcntl_ret = 0; + fcntl_helper(*newfd, F_GETFD, &fcntl_ret); + fcntl_helper(*newfd, F_SETFD, &fcntl_ret, fcntl_ret | FD_CLOEXEC); + } + + return 0; +} + +int sys_bind(int fd, const struct sockaddr *addr_ptr, socklen_t addr_length) { + SignalGuard sguard; + auto handle = getHandleForFd(fd); + if (!handle) + return EBADF; + + managarm::fs::CntRequest req(getSysdepsAllocator()); + req.set_req_type(managarm::fs::CntReqType::PT_BIND); + + auto [offer, send_req, send_creds, send_buf, recv_resp] = exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::imbueCredentials(), + helix_ng::sendBuffer(addr_ptr, addr_length), + helix_ng::recvInline()) + ); + HEL_CHECK(offer.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(send_creds.error()); + HEL_CHECK(send_buf.error()); + HEL_CHECK(recv_resp.error()); + + managarm::fs::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if(resp.error() == managarm::fs::Errors::FILE_NOT_FOUND) { + return ENOENT; + } else if(resp.error() == managarm::fs::Errors::ADDRESS_IN_USE) { + return EADDRINUSE; + } else if(resp.error() == managarm::fs::Errors::ALREADY_EXISTS) { + return EINVAL; + } else if(resp.error() == managarm::fs::Errors::ILLEGAL_OPERATION_TARGET) { + return EINVAL; + } else if(resp.error() == managarm::fs::Errors::ILLEGAL_ARGUMENT) { + return EINVAL; + } else if(resp.error() == managarm::fs::Errors::ACCESS_DENIED) { + return EACCES; + } else if(resp.error() == managarm::fs::Errors::ADDRESS_NOT_AVAILABLE) { + return EADDRNOTAVAIL; + } + __ensure(resp.error() == managarm::fs::Errors::SUCCESS); + return 0; +} + +int sys_connect(int fd, const struct sockaddr *addr_ptr, socklen_t addr_length) { + SignalGuard sguard; + + auto handle = getHandleForFd(fd); + if (!handle) + return EBADF; + + managarm::fs::CntRequest req(getSysdepsAllocator()); + req.set_req_type(managarm::fs::CntReqType::PT_CONNECT); + + frg::string ser(getSysdepsAllocator()); + req.SerializeToString(&ser); + + auto [offer, send_req, imbue_creds, send_addr, recv_resp] = + exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBuffer(ser.data(), ser.size()), + helix_ng::imbueCredentials(), + helix_ng::sendBuffer(const_cast(addr_ptr), addr_length), + helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(imbue_creds.error()); + HEL_CHECK(send_addr.error()); + HEL_CHECK(recv_resp.error()); + + managarm::fs::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if(resp.error() == managarm::fs::Errors::FILE_NOT_FOUND) { + return ENOENT; + } else if(resp.error() == managarm::fs::Errors::ILLEGAL_ARGUMENT) { + return EINVAL; + } + + __ensure(resp.error() == managarm::fs::Errors::SUCCESS); + return 0; +} + +int sys_sockname(int fd, struct sockaddr *addr_ptr, socklen_t max_addr_length, + socklen_t *actual_length) { + SignalGuard sguard; + + auto handle = getHandleForFd(fd); + if (!handle) + return EBADF; + + managarm::fs::CntRequest req(getSysdepsAllocator()); + req.set_req_type(managarm::fs::CntReqType::PT_SOCKNAME); + req.set_fd(fd); + req.set_size(max_addr_length); + + auto [offer, send_req, recv_resp, recv_addr] = exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline(), + helix_ng::recvBuffer(addr_ptr, max_addr_length)) + ); + HEL_CHECK(offer.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::fs::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + if(resp.error() == managarm::fs::Errors::ILLEGAL_OPERATION_TARGET) { + return ENOTSOCK; + } + __ensure(resp.error() == managarm::fs::Errors::SUCCESS); + HEL_CHECK(recv_addr.error()); + *actual_length = resp.file_size(); + return 0; +} + +int sys_peername(int fd, struct sockaddr *addr_ptr, socklen_t max_addr_length, + socklen_t *actual_length) { + SignalGuard sguard; + + auto handle = getHandleForFd(fd); + if (!handle) + return EBADF; + + managarm::fs::CntRequest req(getSysdepsAllocator()); + req.set_req_type(managarm::fs::CntReqType::PT_PEERNAME); + req.set_fd(fd); + req.set_size(max_addr_length); + + frg::string ser(getSysdepsAllocator()); + req.SerializeToString(&ser); + + auto [offer, sendReq, recvResp, recvData] = exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBuffer(ser.data(), ser.size()), + helix_ng::recvInline(), + helix_ng::recvBuffer(addr_ptr, max_addr_length) + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(sendReq.error()); + if(recvResp.error() == kHelErrDismissed) + return ENOTSOCK; + HEL_CHECK(recvResp.error()); + HEL_CHECK(recvData.error()); + + managarm::fs::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recvResp.data(), recvResp.length()); + if(resp.error() == managarm::fs::Errors::ILLEGAL_OPERATION_TARGET) { + return ENOTSOCK; + }else if(resp.error() == managarm::fs::Errors::NOT_CONNECTED) { + return ENOTCONN; + }else{ + __ensure(resp.error() == managarm::fs::Errors::SUCCESS); + *actual_length = resp.file_size(); + return 0; + } +} + +int sys_getsockopt(int fd, int layer, int number, + void *__restrict buffer, socklen_t *__restrict size) { + SignalGuard sguard; + + if(layer == SOL_SOCKET && number == SO_PEERCRED) { + if(*size != sizeof(struct ucred)) + return EINVAL; + + auto handle = getHandleForFd(fd); + if (!handle) + return EBADF; + + managarm::fs::CntRequest req(getSysdepsAllocator()); + req.set_req_type(managarm::fs::CntReqType::PT_GET_OPTION); + req.set_command(SO_PEERCRED); + + auto [offer, send_req, recv_resp] = exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline()) + ); + HEL_CHECK(offer.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::fs::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + __ensure(resp.error() == managarm::fs::Errors::SUCCESS); + + struct ucred creds; + creds.pid = resp.pid(); + creds.uid = resp.uid(); + creds.gid = resp.gid(); + memcpy(buffer, &creds, sizeof(struct ucred)); + return 0; + }else if(layer == SOL_SOCKET && number == SO_SNDBUF) { + mlibc::infoLogger() << "\e[31mmlibc: getsockopt() call with SOL_SOCKET and SO_SNDBUF is unimplemented\e[39m" << frg::endlog; + *(int *)buffer = 4096; + return 0; + }else if(layer == SOL_SOCKET && number == SO_TYPE) { + mlibc::infoLogger() << "\e[31mmlibc: getsockopt() call with SOL_SOCKET and SO_TYPE is unimplemented, hardcoding SOCK_STREAM\e[39m" << frg::endlog; + *(int *)buffer = SOCK_STREAM; + return 0; + }else if(layer == SOL_SOCKET && number == SO_ERROR) { + mlibc::infoLogger() << "\e[31mmlibc: getsockopt() call with SOL_SOCKET and SO_ERROR is unimplemented, hardcoding 0\e[39m" << frg::endlog; + *(int *)buffer = 0; + return 0; + }else if(layer == SOL_SOCKET && number == SO_KEEPALIVE) { + mlibc::infoLogger() << "\e[31mmlibc: getsockopt() call with SOL_SOCKET and SO_KEEPALIVE is unimplemented, hardcoding 0\e[39m" << frg::endlog; + *(int *)buffer = 0; + return 0; + }else if(layer == SOL_SOCKET && number == SO_LINGER) { + mlibc::infoLogger() << "\e[31mmlibc: getsockopt() call with SOL_SOCKET and SO_LINGER is unimplemented, hardcoding 0\e[39m" << frg::endlog; + *(int *)buffer = 0; + return 0; + }else{ + mlibc::panicLogger() << "\e[31mmlibc: Unexpected getsockopt() call, layer: " << layer << " number: " << number << "\e[39m" << frg::endlog; + __builtin_unreachable(); + } +} + +int sys_setsockopt(int fd, int layer, int number, + const void *buffer, socklen_t size) { + SignalGuard sguard; + + if(layer == SOL_SOCKET && number == SO_PASSCRED) { + int value; + __ensure(size == sizeof(int)); + memcpy(&value, buffer, sizeof(int)); + + auto handle = getHandleForFd(fd); + if (!handle) + return EBADF; + + managarm::fs::CntRequest req(getSysdepsAllocator()); + req.set_req_type(managarm::fs::CntReqType::PT_SET_OPTION); + req.set_command(SO_PASSCRED); + req.set_value(value); + + auto [offer, send_req, recv_resp] = exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), + helix_ng::recvInline()) + ); + HEL_CHECK(offer.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::fs::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + __ensure(resp.error() == managarm::fs::Errors::SUCCESS); + return 0; + }else if(layer == SOL_SOCKET && number == SO_ATTACH_FILTER) { + mlibc::infoLogger() << "\e[31mmlibc: setsockopt(SO_ATTACH_FILTER) is not implemented" + " correctly\e[39m" << frg::endlog; + return 0; + }else if(layer == SOL_SOCKET && number == SO_RCVBUFFORCE) { + mlibc::infoLogger() << "\e[31mmlibc: setsockopt(SO_RCVBUFFORCE) is not implemented" + " correctly\e[39m" << frg::endlog; + return 0; + }else if(layer == SOL_SOCKET && number == SO_SNDBUF) { + mlibc::infoLogger() << "\e[31mmlibc: setsockopt() call with SOL_SOCKET and SO_SNDBUF is unimplemented\e[39m" << frg::endlog; + return 0; + }else if(layer == SOL_SOCKET && number == SO_KEEPALIVE) { + mlibc::infoLogger() << "\e[31mmlibc: setsockopt() call with SOL_SOCKET and SO_KEEPALIVE is unimplemented\e[39m" << frg::endlog; + return 0; + }else if(layer == SOL_SOCKET && number == SO_REUSEADDR) { + mlibc::infoLogger() << "\e[31mmlibc: setsockopt() call with SOL_SOCKET and SO_REUSEADDR is unimplemented\e[39m" << frg::endlog; + return 0; + }else if(layer == SOL_SOCKET && number == SO_REUSEPORT) { + mlibc::infoLogger() << "\e[31mmlibc: setsockopt() call with SOL_SOCKET and SO_REUSEPORT is unimplemented\e[39m" << frg::endlog; + return 0; + }else if(layer == SOL_SOCKET && number == SO_RCVBUF) { + mlibc::infoLogger() << "\e[31mmlibc: setsockopt() call with SOL_SOCKET and SO_RCVBUF is unimplemented\e[39m" << frg::endlog; + return 0; + }else if(layer == IPPROTO_TCP && number == TCP_NODELAY) { + mlibc::infoLogger() << "\e[31mmlibc: setsockopt() call with IPPROTO_TCP and TCP_NODELAY is unimplemented\e[39m" << frg::endlog; + return 0; + }else if(layer == SOL_SOCKET && number == SO_ACCEPTCONN) { + mlibc::infoLogger() << "\e[31mmlibc: setsockopt() call with SOL_SOCKET and SO_ACCEPTCONN is unimplemented\e[39m" << frg::endlog; + return 0; + }else if(layer == IPPROTO_TCP && number == TCP_KEEPIDLE) { + mlibc::infoLogger() << "\e[31mmlibc: setsockopt() call with IPPROTO_TCP and TCP_KEEPIDLE is unimplemented\e[39m" << frg::endlog; + return 0; + }else if(layer == SOL_NETLINK && number == NETLINK_EXT_ACK) { + mlibc::infoLogger() << "\e[31mmlibc: setsockopt() call with SOL_NETLINK and NETLINK_EXT_ACK is unimplemented\e[39m" << frg::endlog; + return 0; + }else if(layer == SOL_NETLINK && number == NETLINK_GET_STRICT_CHK) { + mlibc::infoLogger() << "\e[31mmlibc: setsockopt() call with SOL_NETLINK and NETLINK_EXT_ACK is unimplemented\e[39m" << frg::endlog; + return 0; + }else if(layer == IPPROTO_TCP && number == TCP_KEEPINTVL) { + mlibc::infoLogger() << "\e[31mmlibc: setsockopt() call with IPPROTO_TCP and TCP_KEEPINTVL is unimplemented\e[39m" << frg::endlog; + return 0; + }else if(layer == IPPROTO_TCP && number == TCP_KEEPCNT) { + mlibc::infoLogger() << "\e[31mmlibc: setsockopt() call with IPPROTO_TCP and TCP_KEEPCNT is unimplemented\e[39m" << frg::endlog; + return 0; + }else{ + mlibc::panicLogger() << "\e[31mmlibc: Unexpected setsockopt() call, layer: " << layer << " number: " << number << "\e[39m" << frg::endlog; + __builtin_unreachable(); + } +} + +int sys_listen(int fd, int) { + SignalGuard sguard; + + auto handle = getHandleForFd(fd); + if (!handle) + return EBADF; + + managarm::fs::CntRequest req(getSysdepsAllocator()); + req.set_req_type(managarm::fs::CntReqType::PT_LISTEN); + + frg::string ser(getSysdepsAllocator()); + req.SerializeToString(&ser); + + auto [offer, send_req, recv_resp] = exchangeMsgsSync( + handle, + helix_ng::offer( + helix_ng::sendBuffer(ser.data(), ser.size()), + helix_ng::recvInline() + ) + ); + + HEL_CHECK(offer.error()); + HEL_CHECK(send_req.error()); + HEL_CHECK(recv_resp.error()); + + managarm::fs::SvrResponse resp(getSysdepsAllocator()); + resp.ParseFromArray(recv_resp.data(), recv_resp.length()); + __ensure(resp.error() == managarm::fs::Errors::SUCCESS); + return 0; +} + +} //namespace mlibc diff --git a/lib/mlibc/sysdeps/managarm/generic/time.cpp b/lib/mlibc/sysdeps/managarm/generic/time.cpp new file mode 100644 index 0000000..468a738 --- /dev/null +++ b/lib/mlibc/sysdeps/managarm/generic/time.cpp @@ -0,0 +1,81 @@ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +struct TrackerPage { + uint64_t seqlock; + int32_t state; + int32_t padding; + int64_t refClock; + int64_t baseRealtime; +}; + +extern thread_local TrackerPage *__mlibc_clk_tracker_page; + +namespace mlibc { + +int sys_clock_get(int clock, time_t *secs, long *nanos) { + // This implementation is inherently signal-safe. + if(clock == CLOCK_MONOTONIC || clock == CLOCK_MONOTONIC_RAW || clock == CLOCK_MONOTONIC_COARSE) { + uint64_t tick; + HEL_CHECK(helGetClock(&tick)); + *secs = tick / 1000000000; + *nanos = tick % 1000000000; + }else if(clock == CLOCK_REALTIME) { + cacheFileTable(); + + // Start the seqlock read. + auto seqlock = __atomic_load_n(&__mlibc_clk_tracker_page->seqlock, __ATOMIC_ACQUIRE); + __ensure(!(seqlock & 1)); + + // Perform the actual loads. + auto ref = __atomic_load_n(&__mlibc_clk_tracker_page->refClock, __ATOMIC_RELAXED); + auto base = __atomic_load_n(&__mlibc_clk_tracker_page->baseRealtime, __ATOMIC_RELAXED); + + // Finish the seqlock read. + __atomic_thread_fence(__ATOMIC_ACQUIRE); + __ensure(__atomic_load_n(&__mlibc_clk_tracker_page->seqlock, __ATOMIC_RELAXED) == seqlock); + + // Calculate the current time. + uint64_t tick; + HEL_CHECK(helGetClock(&tick)); + __ensure(tick >= (uint64_t)__mlibc_clk_tracker_page->refClock); // TODO: Respect the seqlock! + tick -= ref; + tick += base; + *secs = tick / 1000000000; + *nanos = tick % 1000000000; + }else if(clock == CLOCK_PROCESS_CPUTIME_ID) { + mlibc::infoLogger() << "\e[31mmlibc: clock_gettime does not support the CPU time clocks" + "\e[39m" << frg::endlog; + *secs = 0; + *nanos = 0; + }else if(clock == CLOCK_BOOTTIME) { + mlibc::infoLogger() << "\e[31mmlibc: clock_gettime does not support CLOCK_BOOTTIME" + "\e[39m" << frg::endlog; + *secs = 0; + *nanos = 0; + }else{ + mlibc::panicLogger() << "mlibc: Unexpected clock " << clock << frg::endlog; + } + return 0; +} + +int sys_clock_getres(int clock, time_t *secs, long *nanos) { + (void)clock; + (void)secs; + (void)nanos; + mlibc::infoLogger() << "mlibc: clock_getres is a stub" << frg::endlog; + return 0; +} + +} //namespace mlibc + diff --git a/lib/mlibc/sysdeps/managarm/include/abi-bits/access.h b/lib/mlibc/sysdeps/managarm/include/abi-bits/access.h new file mode 120000 index 0000000..cb83931 --- /dev/null +++ b/lib/mlibc/sysdeps/managarm/include/abi-bits/access.h @@ -0,0 +1 @@ +../../../../abis/linux/access.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/managarm/include/abi-bits/auxv.h b/lib/mlibc/sysdeps/managarm/include/abi-bits/auxv.h new file mode 120000 index 0000000..e760d62 --- /dev/null +++ b/lib/mlibc/sysdeps/managarm/include/abi-bits/auxv.h @@ -0,0 +1 @@ +../../../../abis/managarm/auxv.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/managarm/include/abi-bits/blkcnt_t.h b/lib/mlibc/sysdeps/managarm/include/abi-bits/blkcnt_t.h new file mode 120000 index 0000000..0b0ec27 --- /dev/null +++ b/lib/mlibc/sysdeps/managarm/include/abi-bits/blkcnt_t.h @@ -0,0 +1 @@ +../../../../abis/linux/blkcnt_t.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/managarm/include/abi-bits/blksize_t.h b/lib/mlibc/sysdeps/managarm/include/abi-bits/blksize_t.h new file mode 120000 index 0000000..7dc8d7c --- /dev/null +++ b/lib/mlibc/sysdeps/managarm/include/abi-bits/blksize_t.h @@ -0,0 +1 @@ +../../../../abis/linux/blksize_t.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/managarm/include/abi-bits/clockid_t.h b/lib/mlibc/sysdeps/managarm/include/abi-bits/clockid_t.h new file mode 120000 index 0000000..6a42da5 --- /dev/null +++ b/lib/mlibc/sysdeps/managarm/include/abi-bits/clockid_t.h @@ -0,0 +1 @@ +../../../../abis/linux/clockid_t.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/managarm/include/abi-bits/dev_t.h b/lib/mlibc/sysdeps/managarm/include/abi-bits/dev_t.h new file mode 120000 index 0000000..bca881e --- /dev/null +++ b/lib/mlibc/sysdeps/managarm/include/abi-bits/dev_t.h @@ -0,0 +1 @@ +../../../../abis/linux/dev_t.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/managarm/include/abi-bits/epoll.h b/lib/mlibc/sysdeps/managarm/include/abi-bits/epoll.h new file mode 120000 index 0000000..eb4b76d --- /dev/null +++ b/lib/mlibc/sysdeps/managarm/include/abi-bits/epoll.h @@ -0,0 +1 @@ +../../../../abis/linux/epoll.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/managarm/include/abi-bits/errno.h b/lib/mlibc/sysdeps/managarm/include/abi-bits/errno.h new file mode 120000 index 0000000..6e507de --- /dev/null +++ b/lib/mlibc/sysdeps/managarm/include/abi-bits/errno.h @@ -0,0 +1 @@ +../../../../abis/linux/errno.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/managarm/include/abi-bits/fcntl.h b/lib/mlibc/sysdeps/managarm/include/abi-bits/fcntl.h new file mode 120000 index 0000000..463e2c9 --- /dev/null +++ b/lib/mlibc/sysdeps/managarm/include/abi-bits/fcntl.h @@ -0,0 +1 @@ +../../../../abis/linux/fcntl.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/managarm/include/abi-bits/fsblkcnt_t.h b/lib/mlibc/sysdeps/managarm/include/abi-bits/fsblkcnt_t.h new file mode 120000 index 0000000..898dfb2 --- /dev/null +++ b/lib/mlibc/sysdeps/managarm/include/abi-bits/fsblkcnt_t.h @@ -0,0 +1 @@ +../../../../abis/linux/fsblkcnt_t.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/managarm/include/abi-bits/fsfilcnt_t.h b/lib/mlibc/sysdeps/managarm/include/abi-bits/fsfilcnt_t.h new file mode 120000 index 0000000..791755c --- /dev/null +++ b/lib/mlibc/sysdeps/managarm/include/abi-bits/fsfilcnt_t.h @@ -0,0 +1 @@ +../../../../abis/linux/fsfilcnt_t.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/managarm/include/abi-bits/gid_t.h b/lib/mlibc/sysdeps/managarm/include/abi-bits/gid_t.h new file mode 120000 index 0000000..abce6d6 --- /dev/null +++ b/lib/mlibc/sysdeps/managarm/include/abi-bits/gid_t.h @@ -0,0 +1 @@ +../../../../abis/linux/gid_t.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/managarm/include/abi-bits/in.h b/lib/mlibc/sysdeps/managarm/include/abi-bits/in.h new file mode 120000 index 0000000..418d1d5 --- /dev/null +++ b/lib/mlibc/sysdeps/managarm/include/abi-bits/in.h @@ -0,0 +1 @@ +../../../../abis/linux/in.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/managarm/include/abi-bits/ino_t.h b/lib/mlibc/sysdeps/managarm/include/abi-bits/ino_t.h new file mode 120000 index 0000000..4c20aca --- /dev/null +++ b/lib/mlibc/sysdeps/managarm/include/abi-bits/ino_t.h @@ -0,0 +1 @@ +../../../../abis/linux/ino_t.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/managarm/include/abi-bits/inotify.h b/lib/mlibc/sysdeps/managarm/include/abi-bits/inotify.h new file mode 120000 index 0000000..b5cb282 --- /dev/null +++ b/lib/mlibc/sysdeps/managarm/include/abi-bits/inotify.h @@ -0,0 +1 @@ +../../../../abis/linux/inotify.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/managarm/include/abi-bits/ioctls.h b/lib/mlibc/sysdeps/managarm/include/abi-bits/ioctls.h new file mode 120000 index 0000000..595106b --- /dev/null +++ b/lib/mlibc/sysdeps/managarm/include/abi-bits/ioctls.h @@ -0,0 +1 @@ +../../../../abis/linux/ioctls.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/managarm/include/abi-bits/limits.h b/lib/mlibc/sysdeps/managarm/include/abi-bits/limits.h new file mode 120000 index 0000000..6c88db2 --- /dev/null +++ b/lib/mlibc/sysdeps/managarm/include/abi-bits/limits.h @@ -0,0 +1 @@ +../../../../abis/linux/limits.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/managarm/include/abi-bits/mode_t.h b/lib/mlibc/sysdeps/managarm/include/abi-bits/mode_t.h new file mode 120000 index 0000000..5d78fdf --- /dev/null +++ b/lib/mlibc/sysdeps/managarm/include/abi-bits/mode_t.h @@ -0,0 +1 @@ +../../../../abis/linux/mode_t.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/managarm/include/abi-bits/mqueue.h b/lib/mlibc/sysdeps/managarm/include/abi-bits/mqueue.h new file mode 120000 index 0000000..fa87b07 --- /dev/null +++ b/lib/mlibc/sysdeps/managarm/include/abi-bits/mqueue.h @@ -0,0 +1 @@ +../../../../abis/linux/mqueue.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/managarm/include/abi-bits/msg.h b/lib/mlibc/sysdeps/managarm/include/abi-bits/msg.h new file mode 120000 index 0000000..f402b49 --- /dev/null +++ b/lib/mlibc/sysdeps/managarm/include/abi-bits/msg.h @@ -0,0 +1 @@ +../../../../abis/linux/msg.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/managarm/include/abi-bits/nlink_t.h b/lib/mlibc/sysdeps/managarm/include/abi-bits/nlink_t.h new file mode 120000 index 0000000..bb3b625 --- /dev/null +++ b/lib/mlibc/sysdeps/managarm/include/abi-bits/nlink_t.h @@ -0,0 +1 @@ +../../../../abis/linux/nlink_t.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/managarm/include/abi-bits/packet.h b/lib/mlibc/sysdeps/managarm/include/abi-bits/packet.h new file mode 120000 index 0000000..998ef1a --- /dev/null +++ b/lib/mlibc/sysdeps/managarm/include/abi-bits/packet.h @@ -0,0 +1 @@ +../../../../abis/linux/packet.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/managarm/include/abi-bits/pid_t.h b/lib/mlibc/sysdeps/managarm/include/abi-bits/pid_t.h new file mode 120000 index 0000000..baa90f6 --- /dev/null +++ b/lib/mlibc/sysdeps/managarm/include/abi-bits/pid_t.h @@ -0,0 +1 @@ +../../../../abis/linux/pid_t.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/managarm/include/abi-bits/poll.h b/lib/mlibc/sysdeps/managarm/include/abi-bits/poll.h new file mode 120000 index 0000000..8ea6a0a --- /dev/null +++ b/lib/mlibc/sysdeps/managarm/include/abi-bits/poll.h @@ -0,0 +1 @@ +../../../../abis/linux/poll.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/managarm/include/abi-bits/ptrace.h b/lib/mlibc/sysdeps/managarm/include/abi-bits/ptrace.h new file mode 120000 index 0000000..b2517b2 --- /dev/null +++ b/lib/mlibc/sysdeps/managarm/include/abi-bits/ptrace.h @@ -0,0 +1 @@ +../../../../abis/linux/ptrace.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/managarm/include/abi-bits/reboot.h b/lib/mlibc/sysdeps/managarm/include/abi-bits/reboot.h new file mode 120000 index 0000000..77013a4 --- /dev/null +++ b/lib/mlibc/sysdeps/managarm/include/abi-bits/reboot.h @@ -0,0 +1 @@ +../../../../abis/linux/reboot.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/managarm/include/abi-bits/resource.h b/lib/mlibc/sysdeps/managarm/include/abi-bits/resource.h new file mode 120000 index 0000000..88d7402 --- /dev/null +++ b/lib/mlibc/sysdeps/managarm/include/abi-bits/resource.h @@ -0,0 +1 @@ +../../../../abis/linux/resource.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/managarm/include/abi-bits/seek-whence.h b/lib/mlibc/sysdeps/managarm/include/abi-bits/seek-whence.h new file mode 120000 index 0000000..df7bccf --- /dev/null +++ b/lib/mlibc/sysdeps/managarm/include/abi-bits/seek-whence.h @@ -0,0 +1 @@ +../../../../abis/linux/seek-whence.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/managarm/include/abi-bits/shm.h b/lib/mlibc/sysdeps/managarm/include/abi-bits/shm.h new file mode 120000 index 0000000..067d8c4 --- /dev/null +++ b/lib/mlibc/sysdeps/managarm/include/abi-bits/shm.h @@ -0,0 +1 @@ +../../../../abis/linux/shm.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/managarm/include/abi-bits/signal.h b/lib/mlibc/sysdeps/managarm/include/abi-bits/signal.h new file mode 120000 index 0000000..4dcb0b7 --- /dev/null +++ b/lib/mlibc/sysdeps/managarm/include/abi-bits/signal.h @@ -0,0 +1 @@ +../../../../abis/linux/signal.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/managarm/include/abi-bits/socket.h b/lib/mlibc/sysdeps/managarm/include/abi-bits/socket.h new file mode 120000 index 0000000..f1dc016 --- /dev/null +++ b/lib/mlibc/sysdeps/managarm/include/abi-bits/socket.h @@ -0,0 +1 @@ +../../../../abis/linux/socket.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/managarm/include/abi-bits/socklen_t.h b/lib/mlibc/sysdeps/managarm/include/abi-bits/socklen_t.h new file mode 120000 index 0000000..41f3b11 --- /dev/null +++ b/lib/mlibc/sysdeps/managarm/include/abi-bits/socklen_t.h @@ -0,0 +1 @@ +../../../../abis/linux/socklen_t.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/managarm/include/abi-bits/stat.h b/lib/mlibc/sysdeps/managarm/include/abi-bits/stat.h new file mode 120000 index 0000000..1f63b41 --- /dev/null +++ b/lib/mlibc/sysdeps/managarm/include/abi-bits/stat.h @@ -0,0 +1 @@ +../../../../abis/linux/stat.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/managarm/include/abi-bits/statfs.h b/lib/mlibc/sysdeps/managarm/include/abi-bits/statfs.h new file mode 120000 index 0000000..e3d202f --- /dev/null +++ b/lib/mlibc/sysdeps/managarm/include/abi-bits/statfs.h @@ -0,0 +1 @@ +../../../../abis/linux/statfs.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/managarm/include/abi-bits/statvfs.h b/lib/mlibc/sysdeps/managarm/include/abi-bits/statvfs.h new file mode 120000 index 0000000..1fc80c2 --- /dev/null +++ b/lib/mlibc/sysdeps/managarm/include/abi-bits/statvfs.h @@ -0,0 +1 @@ +../../../../abis/linux/statvfs.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/managarm/include/abi-bits/suseconds_t.h b/lib/mlibc/sysdeps/managarm/include/abi-bits/suseconds_t.h new file mode 120000 index 0000000..9ed6597 --- /dev/null +++ b/lib/mlibc/sysdeps/managarm/include/abi-bits/suseconds_t.h @@ -0,0 +1 @@ +../../../../abis/linux/suseconds_t.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/managarm/include/abi-bits/termios.h b/lib/mlibc/sysdeps/managarm/include/abi-bits/termios.h new file mode 120000 index 0000000..ee8f0b0 --- /dev/null +++ b/lib/mlibc/sysdeps/managarm/include/abi-bits/termios.h @@ -0,0 +1 @@ +../../../../abis/linux/termios.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/managarm/include/abi-bits/time.h b/lib/mlibc/sysdeps/managarm/include/abi-bits/time.h new file mode 120000 index 0000000..2a02625 --- /dev/null +++ b/lib/mlibc/sysdeps/managarm/include/abi-bits/time.h @@ -0,0 +1 @@ +../../../../abis/linux/time.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/managarm/include/abi-bits/uid_t.h b/lib/mlibc/sysdeps/managarm/include/abi-bits/uid_t.h new file mode 120000 index 0000000..b306777 --- /dev/null +++ b/lib/mlibc/sysdeps/managarm/include/abi-bits/uid_t.h @@ -0,0 +1 @@ +../../../../abis/linux/uid_t.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/managarm/include/abi-bits/utsname.h b/lib/mlibc/sysdeps/managarm/include/abi-bits/utsname.h new file mode 120000 index 0000000..b285754 --- /dev/null +++ b/lib/mlibc/sysdeps/managarm/include/abi-bits/utsname.h @@ -0,0 +1 @@ +../../../../abis/linux/utsname.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/managarm/include/abi-bits/vm-flags.h b/lib/mlibc/sysdeps/managarm/include/abi-bits/vm-flags.h new file mode 120000 index 0000000..bbe258c --- /dev/null +++ b/lib/mlibc/sysdeps/managarm/include/abi-bits/vm-flags.h @@ -0,0 +1 @@ +../../../../abis/linux/vm-flags.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/managarm/include/abi-bits/vt.h b/lib/mlibc/sysdeps/managarm/include/abi-bits/vt.h new file mode 120000 index 0000000..5798a4a --- /dev/null +++ b/lib/mlibc/sysdeps/managarm/include/abi-bits/vt.h @@ -0,0 +1 @@ +../../../../abis/linux/vt.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/managarm/include/abi-bits/wait.h b/lib/mlibc/sysdeps/managarm/include/abi-bits/wait.h new file mode 120000 index 0000000..feb2840 --- /dev/null +++ b/lib/mlibc/sysdeps/managarm/include/abi-bits/wait.h @@ -0,0 +1 @@ +../../../../abis/linux/wait.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/managarm/include/abi-bits/xattr.h b/lib/mlibc/sysdeps/managarm/include/abi-bits/xattr.h new file mode 120000 index 0000000..66412d7 --- /dev/null +++ b/lib/mlibc/sysdeps/managarm/include/abi-bits/xattr.h @@ -0,0 +1 @@ +../../../../abis/linux/xattr.h \ No newline at end of file diff --git a/lib/mlibc/sysdeps/managarm/include/mlibc/posix-pipe.hpp b/lib/mlibc/sysdeps/managarm/include/mlibc/posix-pipe.hpp new file mode 100644 index 0000000..4bcf1cb --- /dev/null +++ b/lib/mlibc/sysdeps/managarm/include/mlibc/posix-pipe.hpp @@ -0,0 +1,300 @@ +#ifndef MLIBC_POSIX_PIPE +#define MLIBC_POSIX_PIPE + +#include +#include +#include +#include + +#include +#include + +struct SignalGuard { + SignalGuard(); + + SignalGuard(const SignalGuard &) = delete; + + ~SignalGuard(); + + SignalGuard &operator= (const SignalGuard &) = delete; +}; + +// We need an allocator for message structs in sysdeps functions; the "normal" mlibc +// allocator cannot be used, as the sysdeps function might be called from a signal. +MemoryAllocator &getSysdepsAllocator(); + +struct Queue; + +struct ElementHandle { + friend void swap(ElementHandle &u, ElementHandle &v) { + using std::swap; + swap(u._queue, v._queue); + swap(u._n, v._n); + swap(u._data, v._data); + } + + ElementHandle() + : _queue{nullptr}, _n{-1}, _data{nullptr} { } + + ElementHandle(Queue *queue, int n, void *data) + : _queue{queue}, _n{n}, _data{data} { } + + ElementHandle(const ElementHandle &other); + + ElementHandle(ElementHandle &&other) + : ElementHandle{} { + swap(*this, other); + } + + ~ElementHandle(); + + ElementHandle &operator= (ElementHandle other) { + swap(*this, other); + return *this; + } + + void *data() { + return _data; + } + + void advance(size_t size) { + _data = reinterpret_cast(_data) + size; + } + +private: + Queue *_queue; + int _n; + void *_data; +}; + +struct Queue { + Queue() + : _handle{kHelNullHandle} { + // We do not need to protect those allocations against signals as this constructor + // is only called during library initialization. + _chunks[0] = reinterpret_cast(getSysdepsAllocator().allocate(sizeof(HelChunk) + 4096)); + _chunks[1] = reinterpret_cast(getSysdepsAllocator().allocate(sizeof(HelChunk) + 4096)); + + recreateQueue(); + } + + Queue(const Queue &) = delete; + + Queue &operator= (const Queue &) = delete; + + void recreateQueue() { + // Reset the internal queue state. + _retrieveIndex = 0; + _nextIndex = 0; + _lastProgress = 0; + + // Setup the queue header. + HelQueueParameters params { + .flags = 0, + .ringShift = 1, + .numChunks = 2, + .chunkSize = 4096 + }; + HEL_CHECK(helCreateQueue(¶ms, &_handle)); + + auto chunksOffset = (sizeof(HelQueue) + (sizeof(int) << 1) + 63) & ~size_t(63); + auto reservedPerChunk = (sizeof(HelChunk) + params.chunkSize + 63) & ~size_t(63); + auto overallSize = chunksOffset + params.numChunks * reservedPerChunk; + + void *mapping; + HEL_CHECK(helMapMemory(_handle, kHelNullHandle, nullptr, + 0, (overallSize + 0xFFF) & ~size_t(0xFFF), + kHelMapProtRead | kHelMapProtWrite, &mapping)); + + _queue = reinterpret_cast(mapping); + auto chunksPtr = reinterpret_cast(mapping) + chunksOffset; + for(unsigned int i = 0; i < 2; ++i) + _chunks[i] = reinterpret_cast(chunksPtr + i * reservedPerChunk); + + // Reset and enqueue the chunks. + _chunks[0]->progressFutex = 0; + _chunks[1]->progressFutex = 0; + _refCount[0] = 1; + _refCount[1] = 1; + + _queue->indexQueue[0] = 0; + _queue->indexQueue[1] = 1; + _queue->headFutex = 0; + _nextIndex = 2; + _wakeHeadFutex(); + } + + HelHandle getQueue() { + return _handle; + } + + void trim() { } + + ElementHandle dequeueSingle() { + while(true) { + __ensure(_retrieveIndex != _nextIndex); + + bool done; + _waitProgressFutex(&done); + + auto n = _numberOf(_retrieveIndex); + __ensure(_refCount[n]); + + if(done) { + retire(n); + + _lastProgress = 0; + _retrieveIndex = ((_retrieveIndex + 1) & kHelHeadMask); + continue; + } + + // Dequeue the next element. + auto ptr = (char *)_chunks[n] + sizeof(HelChunk) + _lastProgress; + auto element = reinterpret_cast(ptr); + _lastProgress += sizeof(HelElement) + element->length; + _refCount[n]++; + return ElementHandle{this, n, ptr + sizeof(HelElement)}; + } + } + + void retire(int n) { + __ensure(_refCount[n]); + if(_refCount[n]-- > 1) + return; + + // Reset and enqueue the chunk again. + _chunks[n]->progressFutex = 0; + _refCount[n] = 1; + + _queue->indexQueue[_nextIndex & 1] = n; + _nextIndex = ((_nextIndex + 1) & kHelHeadMask); + _wakeHeadFutex(); + } + + void reference(int n) { + _refCount[n]++; + } + +private: + int _numberOf(int index) { + return _queue->indexQueue[index & 1]; + } + + HelChunk *_retrieveChunk() { + return _chunks[_numberOf(_retrieveIndex)]; + } + + void _wakeHeadFutex() { + auto futex = __atomic_exchange_n(&_queue->headFutex, _nextIndex, __ATOMIC_RELEASE); + if(futex & kHelHeadWaiters) + HEL_CHECK(helFutexWake(&_queue->headFutex)); + } + + void _waitProgressFutex(bool *done) { + while(true) { + auto futex = __atomic_load_n(&_retrieveChunk()->progressFutex, __ATOMIC_ACQUIRE); + __ensure(!(futex & ~(kHelProgressMask | kHelProgressWaiters | kHelProgressDone))); + do { + if(_lastProgress != (futex & kHelProgressMask)) { + *done = false; + return; + }else if(futex & kHelProgressDone) { + *done = true; + return; + } + + if(futex & kHelProgressWaiters) + break; // Waiters bit is already set (in a previous iteration). + } while(!__atomic_compare_exchange_n(&_retrieveChunk()->progressFutex, &futex, + _lastProgress | kHelProgressWaiters, + false, __ATOMIC_ACQUIRE, __ATOMIC_ACQUIRE)); + + HEL_CHECK(helFutexWait(&_retrieveChunk()->progressFutex, + _lastProgress | kHelProgressWaiters, -1)); + } + } + +private: + HelHandle _handle; + HelQueue *_queue; + HelChunk *_chunks[2]; + + // Index of the chunk that we are currently retrieving/inserting next. + int _retrieveIndex; + int _nextIndex; + + // Progress into the current chunk. + int _lastProgress; + + // Number of ElementHandle objects alive. + int _refCount[2]; +}; + +inline ElementHandle::~ElementHandle() { + if(_queue) + _queue->retire(_n); +} + +inline ElementHandle::ElementHandle(const ElementHandle &other) { + _queue = other._queue; + _n = other._n; + _data = other._data; + + _queue->reference(_n); +} + + +inline HelSimpleResult *parseSimple(ElementHandle &element) { + auto result = reinterpret_cast(element.data()); + element.advance(sizeof(HelSimpleResult)); + return result; +} + +inline HelInlineResult *parseInline(ElementHandle &element) { + auto result = reinterpret_cast(element.data()); + element.advance(sizeof(HelInlineResult) + ((result->length + 7) & ~size_t(7))); + return result; +} + +inline HelLengthResult *parseLength(ElementHandle &element) { + auto result = reinterpret_cast(element.data()); + element.advance(sizeof(HelLengthResult)); + return result; +} + +inline HelHandleResult *parseHandle(ElementHandle &element) { + auto result = reinterpret_cast(element.data()); + element.advance(sizeof(HelHandleResult)); + return result; +} + +HelHandle getPosixLane(); +HelHandle *cacheFileTable(); +HelHandle getHandleForFd(int fd); +void clearCachedInfos(); + +extern thread_local Queue globalQueue; + +// This include is here because it needs ElementHandle to be declared +#include + +template +auto exchangeMsgsSync(HelHandle descriptor, Args &&...args) { + auto results = helix_ng::createResultsTuple(args...); + auto actions = helix_ng::chainActionArrays(args...); + + HEL_CHECK(helSubmitAsync(descriptor, actions.data(), + actions.size(), globalQueue.getQueue(), 0, 0)); + + auto element = globalQueue.dequeueSingle(); + void *ptr = element.data(); + + [&](std::index_sequence) { + (results.template get

().parse(ptr, element), ...); + } (std::make_index_sequence>{}); + + return results; +} + + +#endif // MLIBC_POSIX_PIPE diff --git a/lib/mlibc/sysdeps/managarm/include/mlibc/thread-entry.hpp b/lib/mlibc/sysdeps/managarm/include/mlibc/thread-entry.hpp new file mode 100644 index 0000000..2dd88a6 --- /dev/null +++ b/lib/mlibc/sysdeps/managarm/include/mlibc/thread-entry.hpp @@ -0,0 +1,10 @@ +#pragma once + +#include + +extern "C" void __mlibc_start_thread(void); +extern "C" void __mlibc_enter_thread(void *entry, void *user_arg, Tcb *tcb); + +namespace mlibc { + void *prepare_stack(void *entry, void *user_arg, void *tcb); +} diff --git a/lib/mlibc/sysdeps/managarm/meson.build b/lib/mlibc/sysdeps/managarm/meson.build new file mode 100644 index 0000000..3b85e30 --- /dev/null +++ b/lib/mlibc/sysdeps/managarm/meson.build @@ -0,0 +1,145 @@ + +bragi = find_program('bragi') + +bragi_gen = generator(bragi, arguments: [ + '-l', 'frigg', + '--protobuf', + '@INPUT@', + '@OUTPUT@' + ], + output: '@BASENAME@.frigg_bragi.hpp') + +fs_bragi = bragi_gen.process('../../subprojects/managarm/protocols/fs/fs.bragi') +posix_bragi = bragi_gen.process('../../subprojects/managarm/protocols/posix/posix.bragi') + +managarm_incl = include_directories( + '../../subprojects/managarm/protocols/posix/include', + '../../subprojects/managarm/hel/include', + '../../subprojects/bragi/include') + +rtdl_include_dirs += managarm_incl +rtdl_sources += files( + 'generic/ensure.cpp', + 'generic/memory.cpp', + 'rtdl-generic/support.cpp', +) +rtdl_sources += [ + fs_bragi, + posix_bragi, +] + +libc_include_dirs += include_directories('../../../ports/libdrm/include') +libc_include_dirs += managarm_incl + +libc_sources += files( + 'generic/drm.cpp', + 'generic/ensure.cpp', + 'generic/entry.cpp', + 'generic/file.cpp', + 'generic/fork-exec.cpp', + 'generic/ioctl.cpp', + 'generic/memory.cpp', + 'generic/mount.cpp', + 'generic/net.cpp', + 'generic/sched.cpp', + 'generic/signals.cpp', + 'generic/socket.cpp', + 'generic/time.cpp' +) +libc_sources += [ + fs_bragi, + posix_bragi, +] + +if host_machine.cpu_family() == 'aarch64' + libc_sources += files( + 'aarch64/signals.S', + 'aarch64/thread_entry.S', + 'aarch64/thread.cpp' + ) +elif host_machine.cpu_family() == 'x86_64' + libc_sources += files( + 'x86_64/signals.S', + 'x86_64/thread_entry.S', + 'x86_64/thread.cpp' + ) +else + error('Unknown architecture') +endif + +if not no_headers + install_headers( + 'include/abi-bits/access.h', + 'include/abi-bits/auxv.h', + 'include/abi-bits/seek-whence.h', + 'include/abi-bits/vm-flags.h', + 'include/abi-bits/errno.h', + 'include/abi-bits/fcntl.h', + 'include/abi-bits/in.h', + 'include/abi-bits/stat.h', + 'include/abi-bits/signal.h', + 'include/abi-bits/reboot.h', + 'include/abi-bits/resource.h', + 'include/abi-bits/socket.h', + 'include/abi-bits/termios.h', + 'include/abi-bits/time.h', + 'include/abi-bits/blkcnt_t.h', + 'include/abi-bits/blksize_t.h', + 'include/abi-bits/dev_t.h', + 'include/abi-bits/gid_t.h', + 'include/abi-bits/ino_t.h', + 'include/abi-bits/mode_t.h', + 'include/abi-bits/nlink_t.h', + 'include/abi-bits/pid_t.h', + 'include/abi-bits/uid_t.h', + 'include/abi-bits/wait.h', + 'include/abi-bits/limits.h', + 'include/abi-bits/utsname.h', + 'include/abi-bits/ptrace.h', + 'include/abi-bits/poll.h', + 'include/abi-bits/epoll.h', + 'include/abi-bits/packet.h', + 'include/abi-bits/inotify.h', + 'include/abi-bits/clockid_t.h', + 'include/abi-bits/shm.h', + 'include/abi-bits/mqueue.h', + 'include/abi-bits/suseconds_t.h', + 'include/abi-bits/fsfilcnt_t.h', + 'include/abi-bits/fsblkcnt_t.h', + 'include/abi-bits/socklen_t.h', + 'include/abi-bits/statfs.h', + 'include/abi-bits/statvfs.h', + 'include/abi-bits/ioctls.h', + 'include/abi-bits/xattr.h', + 'include/abi-bits/msg.h', + 'include/abi-bits/vt.h', + subdir: 'abi-bits', + follow_symlinks: true + ) +endif + +if not headers_only + crtstuff = ['crt0'] + if host_machine.cpu_family() in ['x86_64', 'aarch64'] + crtstuff += [ + 'Scrt1', + 'crti', + 'crtn' + ] + endif + foreach crtthing : crtstuff + crtf = crtthing + '.S' + crt_src = files(host_machine.cpu_family() / 'crt-src' / crtf) + crt = custom_target( + crtthing, + build_by_default: true, + command: c_compiler.cmd_array() + ['-c', '-o', '@OUTPUT@', '@INPUT@'], + input: crt_src, + output: crtthing + '.o', + install: true, + install_dir: get_option('libdir') + ) + endforeach + +endif + diff --git a/lib/mlibc/sysdeps/managarm/rtdl-generic/support.cpp b/lib/mlibc/sysdeps/managarm/rtdl-generic/support.cpp new file mode 100644 index 0000000..ee8ecbb --- /dev/null +++ b/lib/mlibc/sysdeps/managarm/rtdl-generic/support.cpp @@ -0,0 +1,444 @@ +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +// -------------------------------------------------------- +// POSIX I/O functions. +// -------------------------------------------------------- + +HelHandle posixLane; +HelHandle *fileTable; + +void cacheFileTable() { + if(fileTable) + return; + + posix::ManagarmProcessData data; + HEL_CHECK(helSyscall1(kHelCallSuper + posix::superGetProcessData, reinterpret_cast(&data))); + posixLane = data.posixLane; + fileTable = data.fileTable; +} + +template +T load(void *ptr) { + T result; + memcpy(&result, ptr, sizeof(T)); + return result; +} + +// This Queue implementation is more simplistic than the ones in mlibc and helix. +// In fact, we only manage a single chunk; this minimizes the memory usage of the queue. +struct Queue { + Queue() + : _handle{kHelNullHandle}, _lastProgress(0) { + HelQueueParameters params { + .flags = 0, + .ringShift = 0, + .numChunks = 1, + .chunkSize = 4096 + }; + HEL_CHECK(helCreateQueue(¶ms, &_handle)); + + auto chunksOffset = (sizeof(HelQueue) + (sizeof(int) << 0) + 63) & ~size_t(63); + auto reservedPerChunk = (sizeof(HelChunk) + params.chunkSize + 63) & ~size_t(63); + auto overallSize = chunksOffset + params.numChunks * reservedPerChunk; + + void *mapping; + HEL_CHECK(helMapMemory(_handle, kHelNullHandle, nullptr, + 0, (overallSize + 0xFFF) & ~size_t(0xFFF), + kHelMapProtRead | kHelMapProtWrite, &mapping)); + + _queue = reinterpret_cast(mapping); + _chunk = reinterpret_cast( + reinterpret_cast(mapping) + chunksOffset); + + // Reset and enqueue the first chunk. + _chunk->progressFutex = 0; + + _queue->indexQueue[0] = 0; + _queue->headFutex = 1; + _nextIndex = 1; + _wakeHeadFutex(); + } + + Queue(const Queue &) = delete; + + Queue &operator= (const Queue &) = delete; + + HelHandle getHandle() { + return _handle; + } + + void *dequeueSingle() { + while(true) { + bool done; + _waitProgressFutex(&done); + if(done) { + // Reset and enqueue the chunk again. + _chunk->progressFutex = 0; + + _queue->indexQueue[0] = 0; + _nextIndex = ((_nextIndex + 1) & kHelHeadMask); + _wakeHeadFutex(); + + _lastProgress = 0; + continue; + } + + // Dequeue the next element. + auto ptr = (char *)_chunk + sizeof(HelChunk) + _lastProgress; + auto element = load(ptr); + _lastProgress += sizeof(HelElement) + element.length; + return ptr + sizeof(HelElement); + } + } + +private: + void _wakeHeadFutex() { + auto futex = __atomic_exchange_n(&_queue->headFutex, _nextIndex, __ATOMIC_RELEASE); + if(futex & kHelHeadWaiters) + HEL_CHECK(helFutexWake(&_queue->headFutex)); + } + + void _waitProgressFutex(bool *done) { + while(true) { + auto futex = __atomic_load_n(&_chunk->progressFutex, __ATOMIC_ACQUIRE); + __ensure(!(futex & ~(kHelProgressMask | kHelProgressWaiters | kHelProgressDone))); + do { + if(_lastProgress != (futex & kHelProgressMask)) { + *done = false; + return; + }else if(futex & kHelProgressDone) { + *done = true; + return; + } + + if(futex & kHelProgressWaiters) + break; // Waiters bit is already set (in a previous iteration). + } while(!__atomic_compare_exchange_n(&_chunk->progressFutex, &futex, + _lastProgress | kHelProgressWaiters, + false, __ATOMIC_ACQUIRE, __ATOMIC_ACQUIRE)); + + HEL_CHECK(helFutexWait(&_chunk->progressFutex, + _lastProgress | kHelProgressWaiters, -1)); + } + } + +private: + HelHandle _handle; + HelQueue *_queue; + HelChunk *_chunk; + int _nextIndex; + int _lastProgress; +}; + +frg::manual_box globalQueue; + +HelSimpleResult *parseSimple(void *&element) { + auto result = reinterpret_cast(element); + element = (char *)element + sizeof(HelSimpleResult); + return result; +} + +HelInlineResult *parseInline(void *&element) { + auto result = reinterpret_cast(element); + element = (char *)element + sizeof(HelInlineResult) + + ((result->length + 7) & ~size_t(7)); + return result; +} + +HelLengthResult *parseLength(void *&element) { + auto result = reinterpret_cast(element); + element = (char *)element + sizeof(HelLengthResult); + return result; +} + +HelHandleResult *parseHandle(void *&element) { + auto result = reinterpret_cast(element); + element = (char *)element + sizeof(HelHandleResult); + return result; +} + +namespace mlibc { + +int sys_tcb_set(void *pointer) { +#if defined(__aarch64__) + asm volatile ("msr tpidr_el0, %0" :: "r"(pointer)); +#else + HEL_CHECK(helWriteFsBase(pointer)); +#endif + return 0; +} + +int sys_open(const char *path, int flags, mode_t mode, int *fd) { + cacheFileTable(); + HelAction actions[4]; + + managarm::posix::OpenAtRequest req(getAllocator()); + req.set_fd(AT_FDCWD); + req.set_flags(flags); + req.set_mode(mode); + req.set_path(frg::string(getAllocator(), path)); + + if(!globalQueue.valid()) + globalQueue.initialize(); + + frg::string head(getAllocator()); + frg::string tail(getAllocator()); + head.resize(req.size_of_head()); + tail.resize(req.size_of_tail()); + bragi::limited_writer headWriter{head.data(), head.size()}; + bragi::limited_writer tailWriter{tail.data(), tail.size()}; + auto headOk = req.encode_head(headWriter); + auto tailOk = req.encode_tail(tailWriter); + __ensure(headOk); + __ensure(tailOk); + + actions[0].type = kHelActionOffer; + actions[0].flags = kHelItemAncillary; + actions[1].type = kHelActionSendFromBuffer; + actions[1].flags = kHelItemChain; + actions[1].buffer = head.data(); + actions[1].length = head.size(); + actions[2].type = kHelActionSendFromBuffer; + actions[2].flags = kHelItemChain; + actions[2].buffer = tail.data(); + actions[2].length = tail.size(); + actions[3].type = kHelActionRecvInline; + actions[3].flags = 0; + HEL_CHECK(helSubmitAsync(posixLane, actions, 4, globalQueue->getHandle(), 0, 0)); + + auto element = globalQueue->dequeueSingle(); + auto offer = parseHandle(element); + auto send_head = parseSimple(element); + auto send_tail = parseSimple(element); + auto recv_resp = parseInline(element); + HEL_CHECK(offer->error); + HEL_CHECK(send_head->error); + HEL_CHECK(send_tail->error); + HEL_CHECK(recv_resp->error); + + managarm::posix::SvrResponse resp(getAllocator()); + resp.ParseFromArray(recv_resp->data, recv_resp->length); + + if(resp.error() == managarm::posix::Errors::FILE_NOT_FOUND) + return -1; + __ensure(resp.error() == managarm::posix::Errors::SUCCESS); + *fd = resp.fd(); + return 0; +} + +int sys_seek(int fd, off_t offset, int whence, off_t *new_offset) { + __ensure(whence == SEEK_SET); + + cacheFileTable(); + auto lane = fileTable[fd]; + HelAction actions[3]; + + managarm::fs::CntRequest req(getAllocator()); + req.set_req_type(managarm::fs::CntReqType::SEEK_ABS); + req.set_rel_offset(offset); + + if(!globalQueue.valid()) + globalQueue.initialize(); + + frg::string ser(getAllocator()); + req.SerializeToString(&ser); + actions[0].type = kHelActionOffer; + actions[0].flags = kHelItemAncillary; + actions[1].type = kHelActionSendFromBuffer; + actions[1].flags = kHelItemChain; + actions[1].buffer = ser.data(); + actions[1].length = ser.size(); + actions[2].type = kHelActionRecvInline; + actions[2].flags = 0; + HEL_CHECK(helSubmitAsync(lane, actions, 3, globalQueue->getHandle(), 0, 0)); + + auto element = globalQueue->dequeueSingle(); + auto offer = parseHandle(element); + auto send_req = parseSimple(element); + auto recv_resp = parseInline(element); + HEL_CHECK(offer->error); + HEL_CHECK(send_req->error); + HEL_CHECK(recv_resp->error); + + managarm::fs::SvrResponse resp(getAllocator()); + resp.ParseFromArray(recv_resp->data, recv_resp->length); + __ensure(resp.error() == managarm::fs::Errors::SUCCESS); + *new_offset = offset; + return 0; +} + +int sys_read(int fd, void *data, size_t length, ssize_t *bytes_read) { + cacheFileTable(); + auto lane = fileTable[fd]; + HelAction actions[5]; + + managarm::fs::CntRequest req(getAllocator()); + req.set_req_type(managarm::fs::CntReqType::READ); + req.set_size(length); + + if(!globalQueue.valid()) + globalQueue.initialize(); + + frg::string ser(getAllocator()); + req.SerializeToString(&ser); + actions[0].type = kHelActionOffer; + actions[0].flags = kHelItemAncillary; + actions[1].type = kHelActionSendFromBuffer; + actions[1].flags = kHelItemChain; + actions[1].buffer = ser.data(); + actions[1].length = ser.size(); + actions[2].type = kHelActionImbueCredentials; + actions[2].handle = kHelThisThread; + actions[2].flags = kHelItemChain; + actions[3].type = kHelActionRecvInline; + actions[3].flags = kHelItemChain; + actions[4].type = kHelActionRecvToBuffer; + actions[4].flags = 0; + actions[4].buffer = data; + actions[4].length = length; + HEL_CHECK(helSubmitAsync(lane, actions, 5, globalQueue->getHandle(), 0, 0)); + + auto element = globalQueue->dequeueSingle(); + auto offer = parseHandle(element); + auto send_req = parseSimple(element); + auto imbue_creds = parseSimple(element); + auto recv_resp = parseInline(element); + auto recv_data = parseLength(element); + HEL_CHECK(offer->error); + HEL_CHECK(send_req->error); + HEL_CHECK(imbue_creds->error); + HEL_CHECK(recv_resp->error); + HEL_CHECK(recv_data->error); + + managarm::fs::SvrResponse resp(getAllocator()); + resp.ParseFromArray(recv_resp->data, recv_resp->length); + __ensure(resp.error() == managarm::fs::Errors::SUCCESS); + *bytes_read = recv_data->length; + return 0; +} + +int sys_vm_map(void *hint, size_t size, int prot, int flags, int fd, off_t offset, void **window) { + cacheFileTable(); + HelAction actions[3]; + + managarm::posix::VmMapRequest req(getAllocator()); + req.set_address_hint(reinterpret_cast(hint)); + req.set_size(size); + req.set_mode(prot); + req.set_flags(flags); + req.set_fd(fd); + req.set_rel_offset(offset); + + if(!globalQueue.valid()) + globalQueue.initialize(); + + frg::string ser(getAllocator()); + req.SerializeToString(&ser); + actions[0].type = kHelActionOffer; + actions[0].flags = kHelItemAncillary; + actions[1].type = kHelActionSendFromBuffer; + actions[1].flags = kHelItemChain; + actions[1].buffer = ser.data(); + actions[1].length = ser.size(); + actions[2].type = kHelActionRecvInline; + actions[2].flags = 0; + HEL_CHECK(helSubmitAsync(posixLane, actions, 3, + globalQueue->getHandle(), 0, 0)); + + auto element = globalQueue->dequeueSingle(); + auto offer = parseHandle(element); + auto send_req = parseSimple(element); + auto recv_resp = parseInline(element); + + HEL_CHECK(offer->error); + HEL_CHECK(send_req->error); + HEL_CHECK(recv_resp->error); + + managarm::posix::SvrResponse resp(getAllocator()); + resp.ParseFromArray(recv_resp->data, recv_resp->length); + __ensure(resp.error() == managarm::posix::Errors::SUCCESS); + *window = reinterpret_cast(resp.offset()); + return 0; +} + +int sys_close(int fd) { + cacheFileTable(); + HelAction actions[3]; + + managarm::posix::CloseRequest req(getAllocator()); + req.set_fd(fd); + + if(!globalQueue.valid()) + globalQueue.initialize(); + + frg::string ser(getAllocator()); + req.SerializeToString(&ser); + actions[0].type = kHelActionOffer; + actions[0].flags = kHelItemAncillary; + actions[1].type = kHelActionSendFromBuffer; + actions[1].flags = kHelItemChain; + actions[1].buffer = ser.data(); + actions[1].length = ser.size(); + actions[2].type = kHelActionRecvInline; + actions[2].flags = 0; + HEL_CHECK(helSubmitAsync(posixLane, actions, 3, globalQueue->getHandle(), 0, 0)); + + auto element = globalQueue->dequeueSingle(); + auto offer = parseHandle(element); + auto send_req = parseSimple(element); + auto recv_resp = parseInline(element); + HEL_CHECK(offer->error); + HEL_CHECK(send_req->error); + HEL_CHECK(recv_resp->error); + + managarm::posix::SvrResponse resp(getAllocator()); + resp.ParseFromArray(recv_resp->data, recv_resp->length); + __ensure(resp.error() == managarm::posix::Errors::SUCCESS); + return 0; +} + +int sys_futex_tid() { + HelWord tid = 0; + HEL_CHECK(helSyscall0_1(kHelCallSuper + posix::superGetTid, + &tid)); + + return tid; +} + +int sys_futex_wait(int *pointer, int expected, const struct timespec *time) { + // This implementation is inherently signal-safe. + if(time) { + if(helFutexWait(pointer, expected, time->tv_nsec + time->tv_sec * 1000000000)) + return -1; + return 0; + } + if(helFutexWait(pointer, expected, -1)) + return -1; + return 0; +} + +int sys_futex_wake(int *pointer) { + // This implementation is inherently signal-safe. + if(helFutexWake(pointer)) + return -1; + return 0; +} + + +} // namespace mlibc diff --git a/lib/mlibc/sysdeps/managarm/x86_64/crt-src/Scrt1.S b/lib/mlibc/sysdeps/managarm/x86_64/crt-src/Scrt1.S new file mode 100644 index 0000000..d0e8213 --- /dev/null +++ b/lib/mlibc/sysdeps/managarm/x86_64/crt-src/Scrt1.S @@ -0,0 +1,8 @@ +.section .text +.global _start +_start: + mov %rsp, %rdi + lea main(%rip), %rsi + call __mlibc_entry +.section .note.GNU-stack,"",%progbits + diff --git a/lib/mlibc/sysdeps/managarm/x86_64/crt-src/crt0.S b/lib/mlibc/sysdeps/managarm/x86_64/crt-src/crt0.S new file mode 100644 index 0000000..6afb421 --- /dev/null +++ b/lib/mlibc/sysdeps/managarm/x86_64/crt-src/crt0.S @@ -0,0 +1,10 @@ + +.section .text +.global _start +_start: + mov %rsp, %rdi + mov $main, %rsi + call __mlibc_entry + +.section .note.GNU-stack,"",%progbits + diff --git a/lib/mlibc/sysdeps/managarm/x86_64/crt-src/crti.S b/lib/mlibc/sysdeps/managarm/x86_64/crt-src/crti.S new file mode 100644 index 0000000..1ca20f2 --- /dev/null +++ b/lib/mlibc/sysdeps/managarm/x86_64/crt-src/crti.S @@ -0,0 +1,15 @@ + .ident "x86_64-managarm-mlibc crti" + + .section .init + .globl _init + .type _init,@function +_init: + push %rax + + .section .fini + .globl _fini + .type _fini,@function +_fini: + push %rax + +.section .note.GNU-stack,"",%progbits diff --git a/lib/mlibc/sysdeps/managarm/x86_64/crt-src/crtn.S b/lib/mlibc/sysdeps/managarm/x86_64/crt-src/crtn.S new file mode 100644 index 0000000..fdb309e --- /dev/null +++ b/lib/mlibc/sysdeps/managarm/x86_64/crt-src/crtn.S @@ -0,0 +1,11 @@ +.ident "x86_64-managarm-mlibc crtn" + +.section .init + pop %rax + ret + +.section .fini + pop %rax + ret + +.section .note.GNU-stack,"",%progbits diff --git a/lib/mlibc/sysdeps/managarm/x86_64/signals.S b/lib/mlibc/sysdeps/managarm/x86_64/signals.S new file mode 100644 index 0000000..33ac4a3 --- /dev/null +++ b/lib/mlibc/sysdeps/managarm/x86_64/signals.S @@ -0,0 +1,10 @@ + +.section .text +.global __mlibc_signal_restore +__mlibc_signal_restore: + mov $0x80000006, %rdi + syscall + ud2 + +.section .note.GNU-stack,"",%progbits + diff --git a/lib/mlibc/sysdeps/managarm/x86_64/thread.cpp b/lib/mlibc/sysdeps/managarm/x86_64/thread.cpp new file mode 100644 index 0000000..88f1bf3 --- /dev/null +++ b/lib/mlibc/sysdeps/managarm/x86_64/thread.cpp @@ -0,0 +1,56 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +extern "C" void __mlibc_enter_thread(void *entry, void *user_arg, Tcb *tcb) { + // Wait until our parent sets up the TID. + while(!__atomic_load_n(&tcb->tid, __ATOMIC_RELAXED)) + mlibc::sys_futex_wait(&tcb->tid, 0, nullptr); + + if(mlibc::sys_tcb_set(tcb)) + __ensure(!"sys_tcb_set() failed"); + + tcb->invokeThreadFunc(entry, user_arg); + + auto self = reinterpret_cast(tcb); + + __atomic_store_n(&self->didExit, 1, __ATOMIC_RELEASE); + mlibc::sys_futex_wake(&self->didExit); + + mlibc::sys_thread_exit(); +} + +namespace mlibc { + +static constexpr size_t default_stacksize = 0x200000; + +int sys_prepare_stack(void **stack, void *entry, void *user_arg, void *tcb, size_t *stack_size, size_t *guard_size, void **stack_base) { + if (!*stack_size) + *stack_size = default_stacksize; + *guard_size = 0; + + if (*stack) { + *stack_base = *stack; + } else { + *stack_base = mmap(nullptr, *stack_size, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if(*stack_base == MAP_FAILED) { + return errno; + } + } + + uintptr_t *sp = reinterpret_cast(reinterpret_cast(*stack_base) + *stack_size); + + *--sp = reinterpret_cast(tcb); + *--sp = reinterpret_cast(user_arg); + *--sp = reinterpret_cast(entry); + *stack = reinterpret_cast(sp); + return 0; +} + +} //namespace mlibc diff --git a/lib/mlibc/sysdeps/managarm/x86_64/thread_entry.S b/lib/mlibc/sysdeps/managarm/x86_64/thread_entry.S new file mode 100644 index 0000000..51e703b --- /dev/null +++ b/lib/mlibc/sysdeps/managarm/x86_64/thread_entry.S @@ -0,0 +1,11 @@ + +.section .text +.global __mlibc_start_thread +__mlibc_start_thread: + pop %rdi + pop %rsi + pop %rdx + call __mlibc_enter_thread + +.section .note.GNU-stack,"",%progbits + diff --git a/lib/mlibc/test.c b/lib/mlibc/test.c new file mode 100644 index 0000000..a0ccfeb --- /dev/null +++ b/lib/mlibc/test.c @@ -0,0 +1,7 @@ +#include + +int +main(void) +{ + return 0; +} diff --git a/lib/mlibc/tests/ansi/abs.c b/lib/mlibc/tests/ansi/abs.c new file mode 100644 index 0000000..492040c --- /dev/null +++ b/lib/mlibc/tests/ansi/abs.c @@ -0,0 +1,16 @@ +#include +#include +#include + +int main(){ + assert(abs(-10) == 10); + assert(abs(2021) == 2021); + + assert(labs(-256) == 256); + assert(labs(10034890) == 10034890); + + assert(llabs(-0x2deadbeef) == 0x2deadbeef); + assert(llabs(49238706947) == 49238706947); + + return 0; +} \ No newline at end of file diff --git a/lib/mlibc/tests/ansi/alloc.c b/lib/mlibc/tests/ansi/alloc.c new file mode 100644 index 0000000..c6ce870 --- /dev/null +++ b/lib/mlibc/tests/ansi/alloc.c @@ -0,0 +1,37 @@ +#include +#include +#include +#include + +int main() { + void *p; + + p = aligned_alloc(sizeof(void *), sizeof(void *)); + assert(p != NULL && (uintptr_t)p % sizeof(void *) == 0); + free(p); + + p = aligned_alloc(256, 256); + assert(p != NULL && (uintptr_t)p % 256 == 0); + free(p); + + // small alignments are okay + p = aligned_alloc(1, 8); + assert(p != NULL); + free(p); + p = aligned_alloc(1, 1); + assert(p != NULL); + free(p); + + // It seems that glibc doesn't report error in these cases. +#if !(defined(USE_HOST_LIBC) && defined(__GLIBC__)) + // size % align must be 0 + p = aligned_alloc(256, 1); + assert(errno == EINVAL); + assert(p == NULL); + + // align must be a 'valid alignment supported by the implementation' + p = aligned_alloc(3, 1); + assert(errno == EINVAL); + assert(p == NULL); +#endif +} diff --git a/lib/mlibc/tests/ansi/calloc.c b/lib/mlibc/tests/ansi/calloc.c new file mode 100644 index 0000000..6cfc87d --- /dev/null +++ b/lib/mlibc/tests/ansi/calloc.c @@ -0,0 +1,20 @@ +#include +#include +#include +#include +#include + +int main() { + errno = 0; + void *ptr = calloc((SIZE_MAX / 2) + 2, 2); + assert(!ptr); + assert(errno); + + errno = 0; + ptr = calloc(sizeof(size_t), 10); + assert(ptr); + for(size_t i = 0; i < 10; i++) { + size_t *p = ptr; + assert(!p[i]); + } +} diff --git a/lib/mlibc/tests/ansi/creal-cimag.c b/lib/mlibc/tests/ansi/creal-cimag.c new file mode 100644 index 0000000..fc70aa3 --- /dev/null +++ b/lib/mlibc/tests/ansi/creal-cimag.c @@ -0,0 +1,37 @@ +#include +#include +#include + +// FIXME: We should create a proper floating point facility +// in order for other functions to be tested properly + +#define APPROXIMATELY_EQUAL(calculated, expected) fabs((calculated) - (expected)) <= 0.0000005 +#define APPROXIMATELY_EQUALF(calculated, expected) fabsf((calculated) - (expected)) <= 0.0000005f +#define APPROXIMATELY_EQUALL(calculated, expected) fabsl((calculated) - (expected)) <= 0.0000005L + +#define IS_COMPLEX_NUMBER(Z) \ + _Generic((Z), \ + double complex: 1, \ + float complex: 1, \ + long double complex: 1, \ + default: 0 \ + ) + +int main() { + assert(IS_COMPLEX_NUMBER(CMPLX(5.2, 4.3))); + double complex cz = CMPLX(5.2, 4.3); + assert(APPROXIMATELY_EQUAL(creal(cz), 5.2)); + assert(APPROXIMATELY_EQUAL(cimag(cz), 4.3)); + + assert(IS_COMPLEX_NUMBER(CMPLXF(1.2f, 2.5f))); + float complex czf = CMPLXF(1.2f, 2.5f); + assert(APPROXIMATELY_EQUALF(crealf(czf), 1.2f)); + assert(APPROXIMATELY_EQUALF(cimagf(czf), 2.5f)); + + assert(IS_COMPLEX_NUMBER(CMPLXL(0.1L, 123.54L))); + long double complex czl = CMPLXL(0.1L, 123.54L); + assert(APPROXIMATELY_EQUALL(creall(czl), 0.1L)); + assert(APPROXIMATELY_EQUALL(cimagl(czl), 123.54L)); + + return 0; +} \ No newline at end of file diff --git a/lib/mlibc/tests/ansi/fenv.c b/lib/mlibc/tests/ansi/fenv.c new file mode 100644 index 0000000..629a5cb --- /dev/null +++ b/lib/mlibc/tests/ansi/fenv.c @@ -0,0 +1,91 @@ +#include +#include +#include +#include +#include + +#define NO_OPTIMIZE(x) asm volatile("" :: "r,m" (x) : "memory") + +static void div_by_zero() { + volatile float zero = 0.0f; + NO_OPTIMIZE(69.0f / zero); +} + +static bool float_cmp(float a, float b) { + return a == b || fabs(a - b) < (fabs(a) + fabs(b)) * FLT_EPSILON; +} + +static void test_rounding(float expectation1, float expectation2) { + float x; + volatile float f = 1.968750f; + volatile float m = 0x1.0p23f; + + NO_OPTIMIZE(x = f + m); + assert(float_cmp(expectation1, x)); + NO_OPTIMIZE(x = x - m); + assert(x == expectation2); +} + +void test0() { + // test whether the divide-by-zero exception is raised + feclearexcept(FE_ALL_EXCEPT); + assert(fetestexcept(FE_ALL_EXCEPT) == 0); + + div_by_zero(); + int raised = fetestexcept(FE_DIVBYZERO); + assert((raised & FE_DIVBYZERO)); +} + +void test1() { + // test various rounding modes + feclearexcept(FE_DIVBYZERO); + assert(fetestexcept(FE_ALL_EXCEPT) == 0); + + fesetround(FE_UPWARD); + assert(fegetround() == FE_UPWARD); + test_rounding(8388610.0f, 2.0f); + + fesetround(FE_DOWNWARD); + assert(fegetround() == FE_DOWNWARD); + test_rounding(8388609.0f, 1.0f); + + fesetround(FE_TONEAREST); + assert(fegetround() == FE_TONEAREST); + test_rounding(8388610.0f, 2.0f); + + fesetround(FE_TOWARDZERO); + assert(fegetround() == FE_TOWARDZERO); + test_rounding(8388609.0f, 1.0f); +} + +void test2() { + // test feraiseexcept + feclearexcept(FE_ALL_EXCEPT); + assert(fetestexcept(FE_ALL_EXCEPT) == 0); + assert(feraiseexcept(FE_DIVBYZERO | FE_OVERFLOW) == 0); + assert(fetestexcept(FE_ALL_EXCEPT) == (FE_DIVBYZERO | FE_OVERFLOW)); +} + +void test3() { + // test fe{get,set}env + feclearexcept(FE_ALL_EXCEPT); + assert(fetestexcept(FE_ALL_EXCEPT) == 0); + assert(feraiseexcept(FE_OVERFLOW) == 0); + + fenv_t state; + assert(fegetenv(&state) == 0); + assert(fetestexcept(FE_ALL_EXCEPT) == FE_OVERFLOW); + + div_by_zero(); + assert(fetestexcept(FE_ALL_EXCEPT) == (FE_DIVBYZERO | FE_OVERFLOW)); + + assert(fesetenv(&state) == 0); + assert(fetestexcept(FE_ALL_EXCEPT) == FE_OVERFLOW); +} + +int main() { + test0(); + test1(); + test2(); + test3(); +} diff --git a/lib/mlibc/tests/ansi/fopen.c b/lib/mlibc/tests/ansi/fopen.c new file mode 100644 index 0000000..f4818b2 --- /dev/null +++ b/lib/mlibc/tests/ansi/fopen.c @@ -0,0 +1,59 @@ +#include +#include +#include + +#ifdef USE_HOST_LIBC +#define TEST_FILE "fopen-host-libc.tmp" +#else +#define TEST_FILE "fopen.tmp" +#endif + +int main() { + FILE *file; + char str[] = "mlibc fopen test"; + char str2[] = " mlibc appending"; + char completestr[] = "mlibc fopen test mlibc appending"; + char buffer[100]; + char buffer2[100]; + + // Clear all the buffers to zero. + memset(buffer, 0, sizeof(buffer)); + memset(buffer2, 0, sizeof(buffer2)); + + // Open the file for writing. + file = fopen(TEST_FILE, "w"); + assert(file); + + // Write string minus null terminator, flush and close. + fwrite(str, 1, sizeof(str) - 1, file); + fflush(file); + fclose(file); + + // Open the file for reading. + file = fopen(TEST_FILE, "r"); + assert(file); + + // Verify that we read back the written string and close the file. + assert(fread(buffer, 1, sizeof(str) - 1, file)); + assert(!strcmp(buffer, str)); + fclose(file); + + // Open the file in appending mode, append string 2 (minus the null terminator) to the file, flush and close. + file = fopen(TEST_FILE, "a"); + fwrite(str2, 1, sizeof(str2) - 1, file); + fflush(file); + fclose(file); + + // Open the file for reading again, verify the contents, close the file and return. + file = fopen(TEST_FILE, "r"); + assert(fread(buffer2, 1, sizeof(completestr) - 1, file)); + assert(!strcmp(buffer2, completestr)); + fclose(file); + + // Check that stdout, stdin and stderr can be closed by the application (issue #12). + fclose(stdout); + fclose(stdin); + fclose(stderr); + + return 0; +} diff --git a/lib/mlibc/tests/ansi/freopen.c b/lib/mlibc/tests/ansi/freopen.c new file mode 100644 index 0000000..c91577f --- /dev/null +++ b/lib/mlibc/tests/ansi/freopen.c @@ -0,0 +1,49 @@ +#include +#include +#include + +#ifdef USE_HOST_LIBC +#define TEST_FILE "freopen-host-libc.tmp" +#else +#define TEST_FILE "freopen.tmp" +#endif + +int main() { + FILE *file = fopen(TEST_FILE, "w"); + assert(file); + + assert(freopen("/dev/null", "w", file)); + + char str[] = "mlibc freopen test"; + fwrite(str, 1, sizeof(str) - 1, file); + fflush(file); + fclose(file); + + file = fopen(TEST_FILE, "r"); + assert(file); + + char buf[sizeof(str)]; + memset(buf, 0, sizeof(buf)); + int ret = fread(buf, 1, sizeof(buf) - 1, file); + fprintf(stderr, "ret %d\n", ret); + assert(ret == 0); + fclose(file); + + file = fopen("/dev/null", "w"); + assert(file); + + assert(freopen(TEST_FILE, "w", file)); + fwrite(str, 1, sizeof(str) - 1, file); + fflush(file); + fclose(file); + + memset(buf, 0, sizeof(buf)); + file = fopen(TEST_FILE, "r"); + assert(fread(buf, 1, sizeof(buf) - 1, file)); + + fprintf(stderr, "buffer content '%s'\n", buf); + assert(!strcmp(buf, "mlibc freopen test")); + fclose(file); + + return 0; +} diff --git a/lib/mlibc/tests/ansi/locale.c b/lib/mlibc/tests/ansi/locale.c new file mode 100644 index 0000000..056298b --- /dev/null +++ b/lib/mlibc/tests/ansi/locale.c @@ -0,0 +1,17 @@ +#include +#include +#include +#include + +int main() { + wchar_t c = 0xC9; + unsigned char buf[sizeof(wchar_t)] = { 0 }; + setlocale(LC_ALL, ""); + if (sprintf(buf, "%lc", c) < 0) + return -1; + + assert(buf[0] == 0xc3 && buf[1] == 0x89 + && buf[2] == '\0' && buf[3] == '\0'); + + return 0; +} diff --git a/lib/mlibc/tests/ansi/longjmp.c b/lib/mlibc/tests/ansi/longjmp.c new file mode 100644 index 0000000..9f9c1ed --- /dev/null +++ b/lib/mlibc/tests/ansi/longjmp.c @@ -0,0 +1,29 @@ +#include +#include +#include +#include + +jmp_buf buf; + +noreturn void do_jump(int arg) { + longjmp(buf, 2 * arg); +} + +int main(void) { + volatile int times_called = 0; + + if (setjmp(buf) != 8) { + do_jump(++times_called); + } + + assert(times_called == 4); + + times_called = 0; + int ret = setjmp(buf); + assert(ret == times_called); + + if (!ret) { + times_called = 1; + longjmp(buf, 0); + } +} diff --git a/lib/mlibc/tests/ansi/mbrtoc32.c b/lib/mlibc/tests/ansi/mbrtoc32.c new file mode 100644 index 0000000..781bc71 --- /dev/null +++ b/lib/mlibc/tests/ansi/mbrtoc32.c @@ -0,0 +1,53 @@ +#include +#include +#include +#include +#include +#include + +struct { + size_t ret; + char32_t c32; + uint8_t bytes[4]; +} expected_results[] = { + {1, 0x7A, {0x7A, 0, 0, 0}}, + {2, 0xDF, {0xC3, 0x9F, 0, 0}}, + {3, 0x6C34, {0xE6, 0xB0, 0xB4, 0}}, + {4, 0x1F34C, {0xF0, 0x9F, 0x8D, 0x8C}}, +}; + +int main() { + setlocale(LC_ALL, "en_US.utf8"); + + size_t ret = 0; + + char *str = "z\u00df\u6c34\U0001F34C"; + + fprintf(stderr, "string: '%s'\n", str); + + mbstate_t state = {}; + char32_t c32; + size_t loop = 0; + while((ret = mbrtoc32(&c32, str, strlen(str), &state))) { + assert(ret != (size_t)-3); + if(ret == (size_t)-1) + break; + if(ret == (size_t)-2) + break; + + fprintf(stderr, "Next UTF-32 char: 0x%x obtained from %zu bytes [", c32, ret); + for(size_t n = 0; n < ret; ++n) { + fprintf(stderr, " 0x%02x ", (uint8_t) str[n]); + } + fprintf(stderr, "]\n"); + + assert(ret == expected_results[loop].ret); + assert(c32 == expected_results[loop].c32); + for(size_t n = 0; n < ret; ++n) { + assert((uint8_t) str[n] == expected_results[loop].bytes[n]); + } + + str += ret; + loop++; + } +} diff --git a/lib/mlibc/tests/ansi/memmem.c b/lib/mlibc/tests/ansi/memmem.c new file mode 100644 index 0000000..8de558f --- /dev/null +++ b/lib/mlibc/tests/ansi/memmem.c @@ -0,0 +1,22 @@ +#include +#include + +int main() { + char *haystack = "abc123\0x45"; + + char *needle1 = "abc"; + void *rv = memmem(haystack, strlen(haystack), needle1, strlen(needle1)); + assert(rv == haystack); + + char *needle2 = "123"; + rv = memmem(haystack, strlen(haystack), needle2, strlen(needle2)); + assert(rv == haystack + 3); + + char *needle3 = "1234"; + rv = memmem(haystack, strlen(haystack), needle3, strlen(needle3)); + assert(rv == NULL); + + char *needle4 = "23\0x45"; + rv = memmem(haystack, 10, needle4, 6); + assert(rv == haystack + 4); +} diff --git a/lib/mlibc/tests/ansi/qsort.c b/lib/mlibc/tests/ansi/qsort.c new file mode 100644 index 0000000..bb48a23 --- /dev/null +++ b/lib/mlibc/tests/ansi/qsort.c @@ -0,0 +1,31 @@ +#include +#include +#include +#include + +static const char *arr[] = { "xyz", "abc", "ghi", "def" }; + +static const size_t magic = 0xDEADBEEF; + +static int cmpstringp(const void *p1, const void *p2, void *ctx) { + /* The actual arguments to this function are "pointers to + * pointers to char", but strcmp(3) arguments are "pointers + * to char", hence the following cast plus dereference. */ + assert(*(size_t *) ctx == magic); + return strcmp(*(const char **) p1, *(const char **) p2); +} + +int main() { + qsort_r(&arr[0], sizeof(arr) / sizeof(*arr), sizeof(char *), cmpstringp, (void *) &magic); + + assert(!strcmp(arr[0], "abc")); + assert(!strcmp(arr[1], "def")); + assert(!strcmp(arr[2], "ghi")); + assert(!strcmp(arr[3], "xyz")); + + for(size_t i = 0; i < sizeof(arr) / sizeof(*arr); i++) { + fprintf(stderr, "%s\n", arr[i]); + } + + return 0; +} diff --git a/lib/mlibc/tests/ansi/snprintf.c b/lib/mlibc/tests/ansi/snprintf.c new file mode 100644 index 0000000..82e4640 --- /dev/null +++ b/lib/mlibc/tests/ansi/snprintf.c @@ -0,0 +1,23 @@ +#include +#include +#include + +int main() { + char buffer[10]; + int ret = snprintf(buffer, 10, "%d", 123456789); + assert(strncmp("123456789", buffer, 10) == 0); + assert(ret == 9); + + // We deliberately induce a warning here. +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wformat-truncation" + ret = snprintf(buffer, 10, "%d", 1234567890); + assert(strncmp("123456789", buffer, 10) == 0); + assert(ret == 10); +#pragma GCC diagnostic pop + + // mlibc issue #118. + ret = snprintf(NULL, 0, "%d", 123456789); + assert(ret == 9); + return 0; +} diff --git a/lib/mlibc/tests/ansi/sprintf.c b/lib/mlibc/tests/ansi/sprintf.c new file mode 100644 index 0000000..fd9398c --- /dev/null +++ b/lib/mlibc/tests/ansi/sprintf.c @@ -0,0 +1,191 @@ +#include +#include +#include +#include + +int main() { + char buf[11] = { 0 }; + sprintf(buf, "%d", 12); + assert(!strcmp(buf, "12")); + sprintf(buf, "%f", 3.14); + assert(!strcmp(buf, "3.140000")); + + // Test %c right padding. + sprintf(buf, "%-2c", 'a'); + assert(!strcmp(buf, "a ")); + + // Test %c left padding. + sprintf(buf, "%2c", 'a'); + assert(!strcmp(buf, " a")); + + // Test %d right padding - mlibc issue #58. + sprintf(buf, "%-2d", 1); + assert(!strcmp(buf, "1 ")); + sprintf(buf, "%-2.2d", 1); + assert(!strcmp(buf, "01")); + sprintf(buf, "%-3.2d", 1); + assert(!strcmp(buf, "01 ")); + sprintf(buf, "%-3.2d", 12); + assert(!strcmp(buf, "12 ")); + sprintf(buf, "%-3.2d", 123); + assert(!strcmp(buf, "123")); + sprintf(buf, "%-3.2u", 12); + assert(!strcmp(buf, "12 ")); + + // Test %d left padding. + sprintf(buf, "%2d", 1); + assert(!strcmp(buf, " 1")); + sprintf(buf, "%3.2d", 1); + assert(!strcmp(buf, " 01")); + sprintf(buf, "%3.2d", 12); + assert(!strcmp(buf, " 12")); + sprintf(buf, "%3.2d", 123); + assert(!strcmp(buf, "123")); + sprintf(buf, "%3.2u", 12); + assert(!strcmp(buf, " 12")); + + // Test %f padding. + // TODO: Test printing of huge numbers (larger than 2^64) + sprintf(buf, "%2.f", 1.2); + assert(!strcmp(buf, " 1")); + sprintf(buf, "%2.f", 12.3); + assert(!strcmp(buf, "12")); + sprintf(buf, "%5.2f", 1.0); + assert(!strcmp(buf, " 1.00")); + sprintf(buf, "%.1f", -4.0); + assert(!strcmp(buf, "-4.0")); + sprintf(buf, "%-3.f", 8.0); + assert(!strcmp(buf, "8 ")); + sprintf(buf, "%4f", INFINITY); + assert(!strcmp(buf, " inf") || !strcmp(buf, "infinity")); + sprintf(buf, "%4f", NAN); + assert(!strcmp(buf, " nan")); + sprintf(buf, "%4F", INFINITY); + assert(!strcmp(buf, " INF") || !strcmp(buf, "INFINITY")); + sprintf(buf, "%4F", NAN); + assert(!strcmp(buf, " NAN")); + sprintf(buf, "%05.2f", 1.0); + assert(!strcmp(buf, "01.00")); + sprintf(buf, "%09f", INFINITY); // 0 ignored when padding infs + assert(!strcmp(buf, " inf") || !strcmp(buf, " infinity")); + // TODO: We don't yet round properly + // sprintf(buf, "%5.2f", 1.2); + // assert(!strcmp(buf, " 1.20")); + // sprintf(buf, "%5.2f", 1.23); + // assert(!strcmp(buf, " 1.23")); + // sprintf(buf, "%5.2f", 1.234); + // assert(!strcmp(buf, " 1.23")); + // sprintf(buf, "%5.2f", 12.345); + // assert(!strcmp(buf, "12.35")); + // sprintf(buf, "%-5.2f", 1.2); + // assert(!strcmp(buf, "1.20 ")); + + // Test '+' and ' ' flags - mlibc issue #229. + // Disable -Wformat here since we deliberately induce some warnings. +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wformat" + sprintf(buf, "%+d", 12); + assert(!strcmp(buf, "+12")); + sprintf(buf, "% d", 12); + assert(!strcmp(buf, " 12")); + sprintf(buf, "% +d", 12); + assert(!strcmp(buf, "+12")); + sprintf(buf, "%+ d", 12); + assert(!strcmp(buf, "+12")); + sprintf(buf, "%+d", -12); + assert(!strcmp(buf, "-12")); + sprintf(buf, "% d", -12); + assert(!strcmp(buf, "-12")); + sprintf(buf, "% +d", -12); + assert(!strcmp(buf, "-12")); + sprintf(buf, "%+ d", -12); + assert(!strcmp(buf, "-12")); +#pragma GCC diagnostic pop + + // Test '#' flag. + // TODO: Test with a, A, e, E, f, F, g, G conversions. + sprintf(buf, "%#x", 12); + assert(!strcmp(buf, "0xc")); + sprintf(buf, "%#X", 12); + assert(!strcmp(buf, "0XC")); + sprintf(buf, "%#o", 12); + assert(!strcmp(buf, "014")); + sprintf(buf, "%#x", 0); + assert(!strcmp(buf, "0")); + sprintf(buf, "%#X", 0); + assert(!strcmp(buf, "0")); + sprintf(buf, "%#o", 0); + assert(!strcmp(buf, "0")); + + // Test 'd' with different size mods to see + // if they work + sprintf(buf, "%d", 12); + assert(!strcmp(buf, "12")); + sprintf(buf, "%ld", 12L); + assert(!strcmp(buf, "12")); + sprintf(buf, "%lld", 12LL); + assert(!strcmp(buf, "12")); + sprintf(buf, "%zd", (size_t)12); + assert(!strcmp(buf, "12")); + sprintf(buf, "%hd", 12); + assert(!strcmp(buf, "12")); + sprintf(buf, "%hhd", 12); + assert(!strcmp(buf, "12")); + + // Test 'x' with different size mods to see + // if they work + sprintf(buf, "%x", 12); + assert(!strcmp(buf, "c")); + sprintf(buf, "%lx", 12L); + assert(!strcmp(buf, "c")); + sprintf(buf, "%llx", 12LL); + assert(!strcmp(buf, "c")); + sprintf(buf, "%zx", (size_t)12); + assert(!strcmp(buf, "c")); + sprintf(buf, "%hx", 12); + assert(!strcmp(buf, "c")); + sprintf(buf, "%hhx", 12); + assert(!strcmp(buf, "c")); + + // Test 'X' with different size mods to see + // if they work + sprintf(buf, "%X", 12); + assert(!strcmp(buf, "C")); + sprintf(buf, "%lX", 12L); + assert(!strcmp(buf, "C")); + sprintf(buf, "%llX", 12LL); + assert(!strcmp(buf, "C")); + sprintf(buf, "%zX", (size_t)12); + assert(!strcmp(buf, "C")); + sprintf(buf, "%hX", 12); + assert(!strcmp(buf, "C")); + sprintf(buf, "%hhX", 12); + assert(!strcmp(buf, "C")); + + // Test 'o' with different size mods to see + // if they work + sprintf(buf, "%o", 12); + assert(!strcmp(buf, "14")); + sprintf(buf, "%lo", 12L); + assert(!strcmp(buf, "14")); + sprintf(buf, "%llo", 12LL); + assert(!strcmp(buf, "14")); + sprintf(buf, "%zo", (size_t)12); + assert(!strcmp(buf, "14")); + sprintf(buf, "%ho", 12); + assert(!strcmp(buf, "14")); + sprintf(buf, "%hho", 12); + assert(!strcmp(buf, "14")); + + // Test %n$ syntax. + sprintf(buf, "%1$d", 12); + assert(!strcmp(buf, "12")); + sprintf(buf, "%1$d %1$d", 12); + assert(!strcmp(buf, "12 12")); + sprintf(buf, "%1$d %2$d %1$d", 12, 14); + assert(!strcmp(buf, "12 14 12")); + sprintf(buf, "%1$d %2$s %2$s", 12, "foo"); + assert(!strcmp(buf, "12 foo foo")); + + return 0; +} diff --git a/lib/mlibc/tests/ansi/sscanf.c b/lib/mlibc/tests/ansi/sscanf.c new file mode 100644 index 0000000..f3a881f --- /dev/null +++ b/lib/mlibc/tests/ansi/sscanf.c @@ -0,0 +1,143 @@ +#include +#include +#include + +struct format_test_cases { + const char *format; + const char *data; + int expected_int; + enum { + T_INT, + T_UINT, + T_CHAR, + T_NONE, + } type; + int ret; +} formats[] = { + {"%i", "0x420", 0x420, T_INT, 1}, + {"%i", "0420", 0420, T_INT, 1}, + {"%i", "420", 420, T_INT, 1}, + {"%i", "-420", -420, T_INT, 1}, + {"%d", "-12345", -12345, T_INT, 1}, + {"%u", "69", 69, T_UINT, 1}, + {"%u", "0420", 420, T_UINT, 1}, + {"%o", "0420", 0420, T_UINT, 1}, + {"%x", "0xCB7", 0xCB7, T_UINT, 1}, + {"%%", "%", 0, T_NONE, 0}, + {"%c", " I am not a fan of this solution.", ' ', T_CHAR, 1}, + {" %c", " CBT (capybara therapy)", 'C', T_CHAR, 1}, +}; + +#pragma GCC diagnostic ignored "-Wformat-security" + +static void test_matrix() { + for(size_t i = 0; i < (sizeof(formats) / sizeof(*formats)); i++) { + struct format_test_cases *f = &formats[i]; + int ret = -1; + int data_int; + unsigned int data_uint; + char data_char; + + switch(f->type) { + case T_INT: { + ret = sscanf(f->data, f->format, &data_int); + assert(data_int == f->expected_int); + break; + } + case T_UINT: { + ret = sscanf(f->data, f->format, &data_uint); + assert(data_uint == (unsigned int) f->expected_int); + break; + } + case T_CHAR: { + ret = sscanf(f->data, f->format, &data_char); + assert(data_char == (unsigned char) f->expected_int); + break; + } + case T_NONE: { + ret = sscanf(f->data, f->format); + break; + } + + } + + assert(ret == f->ret); + } +} + +int main() { + { + int x = 0; + char buf[] = "12345"; + sscanf(buf, "%d", &x); + assert(x == 12345); + } + + { + char c; + int n1; + int n2; + char buf[] = "z$ 7 5 440";; + int count = sscanf(buf, "%*c%c %d %*d %d", &c, &n1, &n2); + assert(count == 3); + assert(c == '$'); + assert(n1 == 7); + assert(n2 == 440); + } + + { + // From dsda-doom + char buf[] = "process_priority 0\n"; + char def[80], strparm[128]; + memset(def, '!', 80); + memset(strparm, '!', 128); + sscanf(buf, "%s %[^\n]\n", def, strparm); + assert(!strcmp(def, "process_priority")); + assert(!strcmp(strparm, "0")); + } + + { + char buf[] = "fffff100"; + unsigned long y = 0; + sscanf(buf, "%lx", &y); + assert(y == 0xfffff100); + } + +#if !defined(__i386__) + { + char buf[] = "fffffffff100"; + unsigned long y = 0; + sscanf(buf, "%lx", &y); + assert(y == 0xfffffffff100); + } +#endif + + { + char buf[] = "410dc000"; + unsigned long y = 0; + sscanf(buf, "%lx", &y); + assert(y == 0x410dc000); + } + + { + // From webkitgtk + char buf[] = "MemTotal: 16299664 kB\n"; + char token[51] = {0}; + size_t amount = 0; + int ret = sscanf(buf, "%50s%zukB", token, &amount); + assert(ret == 2); + assert(!strcmp(token, "MemTotal:")); + assert(amount == 16299664); + } + + { + char buf[] = "SIGINT"; + int sig; + int ret = sscanf(buf, "%d", &sig); + assert(!ret); + } + + test_matrix(); + + return 0; +} diff --git a/lib/mlibc/tests/ansi/strchr.c b/lib/mlibc/tests/ansi/strchr.c new file mode 100644 index 0000000..a80a1f9 --- /dev/null +++ b/lib/mlibc/tests/ansi/strchr.c @@ -0,0 +1,20 @@ +#include +#include +#include + +int main() { + char str[] = "This is a sample string"; + char *pch; + // The character 's' is at position 4, 7, 11 and 18 + pch = strchr(str, 's'); + assert(pch - str + 1 == 4); + pch = strchr(pch + 1, 's'); + assert(pch - str + 1 == 7); + pch = strchr(pch + 1, 's'); + assert(pch - str + 1 == 11); + pch = strchr(pch + 1, 's'); + assert(pch - str + 1 == 18); + pch = strchr(pch + 1, 's'); + assert(pch == NULL); + return 0; +} diff --git a/lib/mlibc/tests/ansi/strftime.c b/lib/mlibc/tests/ansi/strftime.c new file mode 100644 index 0000000..69ec642 --- /dev/null +++ b/lib/mlibc/tests/ansi/strftime.c @@ -0,0 +1,48 @@ +#include +#include +#include +#include +#include + +int main() { + // Date representation depends on locale, here only C is tested. + // Maybe consider testing more locales? + if (setlocale (LC_ALL, "C") == NULL) { + fputs("strftime testcase could not set locale, errors may be expected!", stderr); + } + + char timebuf[16]; + char result[16] = " 8"; + struct tm tm; + tm.tm_sec = 0; + tm.tm_min = 17; + tm.tm_hour = 17; + tm.tm_mday = 8; + tm.tm_mon = 2; + tm.tm_year = 121; + tm.tm_wday = 2; + tm.tm_yday = 39; + strftime(timebuf, sizeof(timebuf), "%e", &tm); + assert(!strcmp(timebuf, result)); + + memset(timebuf, 0, sizeof(timebuf)); + strftime(timebuf, sizeof(timebuf), "%x", &tm); + assert(!strcmp(timebuf, "03/08/21")); + + memset(timebuf, 0, sizeof(timebuf)); + strftime(timebuf, sizeof(timebuf), "%X", &tm); + assert(!strcmp(timebuf, "17:17:00")); + + memset(timebuf, 0, sizeof(timebuf)); + strftime(timebuf, sizeof(timebuf), "%a %A", &tm); + assert(!strcmp(timebuf, "Tue Tuesday")); + + memset(timebuf, 0, sizeof(timebuf)); + strftime(timebuf, sizeof(timebuf), "%b %B %h", &tm); + assert(!strcmp(timebuf, "Mar March Mar")); + + memset(timebuf, 0, sizeof(timebuf)); + assert(!strftime(timebuf, sizeof(timebuf), "%a %A %a %A %b %B %h", &tm)); + + return 0; +} diff --git a/lib/mlibc/tests/ansi/strrchr.c b/lib/mlibc/tests/ansi/strrchr.c new file mode 100644 index 0000000..2de9821 --- /dev/null +++ b/lib/mlibc/tests/ansi/strrchr.c @@ -0,0 +1,11 @@ +#include +#include + +int main() { + char str[] = "This is a sample string"; + char *pch; + pch = strrchr(str, 's'); + // The last occurence of 's' is at position 18 + assert(pch - str + 1 == 18); + return 0; +} diff --git a/lib/mlibc/tests/ansi/strtof.c b/lib/mlibc/tests/ansi/strtof.c new file mode 100644 index 0000000..a13af90 --- /dev/null +++ b/lib/mlibc/tests/ansi/strtof.c @@ -0,0 +1,83 @@ +#include +#include +#include +#include + +#define FLT_RANGE 0.000001f +#define DBL_RANGE 0.000001 +#define LDBL_RANGE 0.000001 + +#define DO_TEST(str, value, off, func, range) ({ \ + char s[] = (str); \ + char *pEnd = NULL; \ + __typeof(func(s, &pEnd)) result = func(s, &pEnd); \ + assert(result >= (value) - (range)); \ + assert(result <= (value) + (range)); \ + assert(pEnd == (off == -1 ? s + strlen(s) : s + off)); }) + +#define DO_TEST_SUCCESS_FUNC(str, success_func, off, func) ({ \ + char s[] = (str); \ + char *pEnd = NULL; \ + assert(success_func(func(s, &pEnd))); \ + assert(pEnd == (off == -1 ? s + strlen(s) : s + off)); }) + +int main () { + DO_TEST("0", 0.0f, -1, strtof, FLT_RANGE); + DO_TEST("0.12", 0.12f, -1, strtof, FLT_RANGE); + DO_TEST("12", 12.0f, -1, strtof, FLT_RANGE); + DO_TEST("12.13", 12.13f, -1, strtof, FLT_RANGE); + DO_TEST("10.0e1", 100.0f, -1, strtof, FLT_RANGE); + DO_TEST("10.0e10", 100000000000.0f, -1, strtof, FLT_RANGE); + DO_TEST("100.0e-1", 10.0f, -1, strtof, FLT_RANGE); + DO_TEST("0x0", 0.0f, -1, strtof, FLT_RANGE); + DO_TEST("0x0.12", 0.0703125f, -1, strtof, FLT_RANGE); + DO_TEST("0x12", 18.0f, -1, strtof, FLT_RANGE); + DO_TEST("0x12.13", 18.07421875f, -1, strtof, FLT_RANGE); + DO_TEST("0x10.0p1", 32.0f, -1, strtof, FLT_RANGE); + DO_TEST("0x10.0p10", 16384.0f, -1, strtof, FLT_RANGE); + DO_TEST("0x100.0p-1", 128.0f, -1, strtof, FLT_RANGE); + DO_TEST_SUCCESS_FUNC("NAN", isnan, -1, strtof); + DO_TEST_SUCCESS_FUNC("nan", isnan, -1, strtof); + DO_TEST_SUCCESS_FUNC("INF", isinf, -1, strtof); + DO_TEST_SUCCESS_FUNC("INFINITY", isinf, -1, strtof); + + DO_TEST("0", 0.0, -1, strtod, DBL_RANGE); + DO_TEST("0.12", 0.12, -1, strtod, DBL_RANGE); + DO_TEST("12", 12.0, -1, strtod, DBL_RANGE); + DO_TEST("12.13", 12.13, -1, strtod, DBL_RANGE); + DO_TEST("10.0e1", 100.0, -1, strtod, DBL_RANGE); + DO_TEST("10.0e10", 100000000000.0, -1, strtod, DBL_RANGE); + DO_TEST("100.0e-1", 10.0, -1, strtod, DBL_RANGE); + DO_TEST("0x0", 0.0, -1, strtod, DBL_RANGE); + DO_TEST("0x0.12", 0.0703125, -1, strtod, DBL_RANGE); + DO_TEST("0x12", 18.0, -1, strtod, DBL_RANGE); + DO_TEST("0x12.13", 18.07421875, -1, strtod, DBL_RANGE); + DO_TEST("0x10.0p1", 32.0, -1, strtod, DBL_RANGE); + DO_TEST("0x10.0p10", 16384.0, -1, strtod, DBL_RANGE); + DO_TEST("0x100.0p-1", 128.0, -1, strtod, DBL_RANGE); + DO_TEST_SUCCESS_FUNC("NAN", isnan, -1, strtod); + DO_TEST_SUCCESS_FUNC("nan", isnan, -1, strtod); + DO_TEST_SUCCESS_FUNC("INF", isinf, -1, strtod); + DO_TEST_SUCCESS_FUNC("INFINITY", isinf, -1, strtod); + + DO_TEST("0", 0.0, -1, strtold, LDBL_RANGE); + DO_TEST("0.12", 0.12, -1, strtold, LDBL_RANGE); + DO_TEST("12", 12.0, -1, strtold, LDBL_RANGE); + DO_TEST("12.13", 12.13, -1, strtold, LDBL_RANGE); + DO_TEST("10.0e1", 100.0, -1, strtold, LDBL_RANGE); + DO_TEST("10.0e10", 100000000000.0, -1, strtold, LDBL_RANGE); + DO_TEST("100.0e-1", 10.0, -1, strtold, LDBL_RANGE); + DO_TEST("0x0", 0.0, -1, strtold, LDBL_RANGE); + DO_TEST("0x0.12", 0.0703125, -1, strtold, LDBL_RANGE); + DO_TEST("0x12", 18.0, -1, strtold, LDBL_RANGE); + DO_TEST("0x12.13", 18.07421875, -1, strtold, LDBL_RANGE); + DO_TEST("0x10.0p1", 32.0, -1, strtold, LDBL_RANGE); + DO_TEST("0x10.0p10", 16384.0, -1, strtold, LDBL_RANGE); + DO_TEST("0x100.0p-1", 128.0, -1, strtold, LDBL_RANGE); + DO_TEST_SUCCESS_FUNC("NAN", isnan, -1, strtold); + DO_TEST_SUCCESS_FUNC("nan", isnan, -1, strtold); + DO_TEST_SUCCESS_FUNC("INF", isinf, -1, strtold); + DO_TEST_SUCCESS_FUNC("INFINITY", isinf, -1, strtold); + + return 0; +} diff --git a/lib/mlibc/tests/ansi/strtol.c b/lib/mlibc/tests/ansi/strtol.c new file mode 100644 index 0000000..823cb4a --- /dev/null +++ b/lib/mlibc/tests/ansi/strtol.c @@ -0,0 +1,140 @@ +#include +#include +#include +#include +#include +#include +#include + +#define DO_TEST(str, value, off, func, base) ({ \ + char s[] = (str); \ + char *pEnd = NULL; \ + errno = 0; \ + assert(func(s, &pEnd, base) == (value)); \ + assert(errno == 0); \ + assert(pEnd == (off == -1 ? s + strlen(s) : s + off)); }) + +#define DO_ERR_TEST(str, value, err, func, base) ({ \ + char s[] = (str); \ + char *pEnd = NULL; \ + errno = 0; \ + assert(func(s, &pEnd, base) == (value)); \ + assert(errno == err); \ + assert(pEnd == (err == ERANGE ? s + strlen(s) : s)); }) + +#define DO_TESTL(str, value, off, func, base) ({ \ + wchar_t s[] = (str); \ + wchar_t *pEnd = NULL; \ + errno = 0; \ + assert(func(s, &pEnd, base) == (value)); \ + assert(errno == 0); \ + assert(pEnd == (off == -1 ? s + wcslen(s) : s + off)); }) + +#define DO_ERR_TESTL(str, value, err, func, base) ({ \ + wchar_t s[] = (str); \ + wchar_t *pEnd = NULL; \ + errno = 0; \ + assert(func(s, &pEnd, base) == (value)); \ + assert(errno == err); \ + assert(pEnd == (err == ERANGE ? s + wcslen(s) : s)); }) + +int main () { + // A few generic checks. + DO_TEST("0", 0, -1, strtol, 0); + DO_TEST("0", 0, -1, strtol, 10); + DO_TEST("2001", 2001, -1, strtol, 10); + DO_TEST("+2001", 2001, -1, strtol, 10); + DO_TEST("60c0c0", 0x60c0c0, -1, strtol, 16); + DO_TEST("-1101110100110100100000", -3624224, -1, strtol, 2); + DO_TEST("0x6fffff", 0x6fffff, -1, strtol, 0); + DO_TEST("0666", 0666, -1, strtol, 0); + DO_TEST("0xzzz", 0, 1, strtol, 0); + DO_TEST("0yzzz", 0, 1, strtol, 0); + DO_TEST("00xzz", 0, 2, strtol, 0); + DO_ERR_TEST("", 0, 0, strtol, 10); + DO_ERR_TEST("asd", 0, 0, strtol, 10); + DO_ERR_TEST("999999999999999999999999999", LONG_MAX, ERANGE, strtol, 10); + DO_ERR_TEST("-999999999999999999999999999", LONG_MIN, ERANGE, strtol, 10); + + // strtol +#if defined(__i386__) + DO_TEST("-2147483648", LONG_MIN, -1, strtol, 10); + DO_TEST("2147483647", LONG_MAX, -1, strtol, 10); + DO_ERR_TEST("-2147483649", LONG_MIN, ERANGE, strtol, 10); + DO_ERR_TEST("2147483648", LONG_MAX, ERANGE, strtol, 10); +#else + DO_TEST("-9223372036854775808", LONG_MIN, -1, strtol, 10); + DO_TEST("9223372036854775807", LONG_MAX, -1, strtol, 10); + DO_ERR_TEST("9223372036854775808", LONG_MAX, ERANGE, strtol, 10); + DO_ERR_TEST("-9223372036854775809", LONG_MIN, ERANGE, strtol, 10); +#endif + + // wcstol +#if defined(__i386__) + DO_TESTL(L"-2147483648", LONG_MIN, -1, wcstol, 10); + DO_TESTL(L"2147483647", LONG_MAX, -1, wcstol, 10); + DO_ERR_TESTL(L"2147483648", LONG_MAX, ERANGE, wcstol, 10); + DO_ERR_TESTL(L"-2147483649", LONG_MIN, ERANGE, wcstol, 10); +#else + DO_TESTL(L"-9223372036854775808", LONG_MIN, -1, wcstol, 10); + DO_TESTL(L"9223372036854775807", LONG_MAX, -1, wcstol, 10); + DO_ERR_TESTL(L"9223372036854775808", LONG_MAX, ERANGE, wcstol, 10); + DO_ERR_TESTL(L"-9223372036854775809", LONG_MIN, ERANGE, wcstol, 10); +#endif + + // strtoll + DO_TEST("-9223372036854775808", LLONG_MIN, -1, strtoll, 10); + DO_TEST("9223372036854775807", LLONG_MAX, -1, strtoll, 10); + DO_ERR_TEST("9223372036854775808", LLONG_MAX, ERANGE, strtoll, 10); + DO_ERR_TEST("-9223372036854775809", LLONG_MIN, ERANGE, strtoll, 10); + // wcstoll + DO_TESTL(L"-9223372036854775808", LLONG_MIN, -1, wcstoll, 10); + DO_TESTL(L"9223372036854775807", LLONG_MAX, -1, wcstoll, 10); + DO_ERR_TESTL(L"9223372036854775808", LLONG_MAX, ERANGE, wcstoll, 10); + DO_ERR_TESTL(L"-9223372036854775809", LLONG_MIN, ERANGE, wcstoll, 10); + + // strtoul +#if defined(__i386__) + DO_TEST("-1", -(1UL), -1, strtoul, 10); + DO_TEST("2147483647", LONG_MAX, -1, strtoul, 10); + DO_TEST("4294967295", ULONG_MAX, -1, strtoul, 10); + DO_TEST("-4294967295", 1UL, -1, strtoul, 10); + DO_ERR_TEST("4294967296", ULONG_MAX, ERANGE, strtoul, 10); +#else + DO_TEST("-1", -(1UL), -1, strtoul, 10); + DO_TEST("9223372036854775807", LONG_MAX, -1, strtoul, 10); + DO_TEST("18446744073709551615", ULONG_MAX, -1, strtoul, 10); + DO_TEST("-18446744073709551615", 1UL, -1, strtoul, 10); + DO_ERR_TEST("18446744073709551616", ULONG_MAX, ERANGE, strtoul, 10); +#endif + + // wcstoul +#if defined(__i386__) + DO_TESTL(L"-1", -(1UL), -1, wcstoul, 10); + DO_TESTL(L"2147483647", LONG_MAX, -1, wcstoul, 10); + DO_TESTL(L"4294967295", ULONG_MAX, -1, wcstoul, 10); + DO_TESTL(L"-4294967295", 1UL, -1, wcstoul, 10); + DO_ERR_TESTL(L"4294967296", ULONG_MAX, ERANGE, wcstoul, 10); +#else + DO_TESTL(L"-1", -(1UL), -1, wcstoul, 10); + DO_TESTL(L"9223372036854775807", LONG_MAX, -1, wcstoul, 10); + DO_TESTL(L"18446744073709551615", ULONG_MAX, -1, wcstoul, 10); + DO_TESTL(L"-18446744073709551615", 1UL, -1, wcstoul, 10); + DO_ERR_TESTL(L"18446744073709551616", ULONG_MAX, ERANGE, wcstoul, 10); +#endif + + // strtoull + DO_TEST("-1", -(1ULL), -1, strtoull, 10); + DO_TEST("9223372036854775807", LLONG_MAX, -1, strtoull, 10); + DO_TEST("18446744073709551615", ULLONG_MAX, -1, strtoull, 10); + DO_TEST("-18446744073709551615", 1ULL, -1, strtoull, 10); + DO_ERR_TEST("18446744073709551616", ULLONG_MAX, ERANGE, strtoull, 10); + // wcstoull + DO_TESTL(L"-1", -(1ULL), -1, wcstoull, 10); + DO_TESTL(L"9223372036854775807", LLONG_MAX, -1, wcstoull, 10); + DO_TESTL(L"18446744073709551615", ULLONG_MAX, -1, wcstoull, 10); + DO_TESTL(L"-18446744073709551615", 1ULL, -1, wcstoull, 10); + DO_ERR_TESTL(L"18446744073709551616", ULLONG_MAX, ERANGE, wcstoull, 10); + + return 0; +} diff --git a/lib/mlibc/tests/ansi/strverscmp.c b/lib/mlibc/tests/ansi/strverscmp.c new file mode 100644 index 0000000..d6501a1 --- /dev/null +++ b/lib/mlibc/tests/ansi/strverscmp.c @@ -0,0 +1,16 @@ +#include +#include +#include + +int main() { + int res; + + res = strverscmp("jan1", "jan10"); + assert(res < 0); + + res = strverscmp("jan11", "jan10"); + assert(res > 0); + + res = strverscmp("jan1", "jan1"); + assert(res == 0); +} diff --git a/lib/mlibc/tests/ansi/strxfrm.c b/lib/mlibc/tests/ansi/strxfrm.c new file mode 100644 index 0000000..07a4082 --- /dev/null +++ b/lib/mlibc/tests/ansi/strxfrm.c @@ -0,0 +1,14 @@ +#include +#include +#include + +int main() { + setlocale(LC_ALL, "C"); + + const char *buf = "cbtteststring"; + char dest[14]; + size_t ret = strxfrm(dest, buf, strlen(buf) + 1); + assert(ret == 13); + int cmp = strncmp(dest, buf, 13); + assert(!cmp); +} diff --git a/lib/mlibc/tests/ansi/timegm.c b/lib/mlibc/tests/ansi/timegm.c new file mode 100644 index 0000000..f5af03e --- /dev/null +++ b/lib/mlibc/tests/ansi/timegm.c @@ -0,0 +1,45 @@ +#include +#include +#include + +int main() { + struct tm soon = {}; + soon.tm_sec = 0; + soon.tm_min = 0; + soon.tm_hour = 0; + soon.tm_mday = 1; + soon.tm_mon = 0; + soon.tm_year = 70; + time_t result; + time_t expected_result = 0; + // This should be epoch. + result = timegm(&soon); + printf("epoch: %ld\n", result); + assert(result == expected_result); + + soon.tm_sec = 12; + soon.tm_min = 8; + soon.tm_hour = 16; + soon.tm_mday = 17; + soon.tm_mon = 4; + soon.tm_year = 122; + expected_result = 1652803692; + result = timegm(&soon); + // On my host, this returned 1652803692, verify this. + printf("epoch: %ld\n", result); + assert(result == expected_result); + + soon.tm_sec = 45; + soon.tm_min = 42; + soon.tm_hour = 17; + soon.tm_mday = 16; + soon.tm_mon = 8; + soon.tm_year = 69; + expected_result = -9181035; + result = timegm(&soon); + // On my host, this returned -9181035, verify this. + printf("epoch: %ld\n", result); + assert(result == expected_result); + + return 0; +} diff --git a/lib/mlibc/tests/ansi/ungetc.c b/lib/mlibc/tests/ansi/ungetc.c new file mode 100644 index 0000000..8773c6d --- /dev/null +++ b/lib/mlibc/tests/ansi/ungetc.c @@ -0,0 +1,74 @@ +#include +#include + +#ifdef USE_HOST_LIBC +#define TEST_FILE "ungetc-host-libc.tmp" +#else +#define TEST_FILE "ungetc.tmp" +#endif + +void test(int buffering) { + FILE *f = fopen(TEST_FILE, "w"); + for(int c = '0'; c <= '9'; c++) { + fputc(c, f); + } + fclose(f); + + f = fopen(TEST_FILE, "r"); + if (!buffering) { + setbuf(f, NULL); + } + + assert(ungetc('x', f) == 'x'); + assert(fgetc(f) == 'x'); + + // Test pushing back the same character + for (int c = '0'; c <= '9'; c++) { + assert(fgetc(f) == c); + assert(ungetc(c, f) == c); + assert(fgetc(f) == c); + } + assert(fgetc(f) == EOF); + assert(ungetc(EOF, f) == EOF); + + // Even though the spec does not guarantee it, we should be able to + // ungetc more than one character. + assert(ungetc('x', f) == 'x'); + assert(ungetc('y', f) == 'y'); + assert(fgetc(f) == 'y'); + assert(fgetc(f) == 'x'); + + // Seeking should discard the effects of ungetc. + assert(ungetc('x', f) == 'x'); + rewind(f); + + // Test pushing back a different character + for (int c = '0'; c <= '9'; c++) { + assert(fgetc(f) == c); + assert(ungetc(c - '0' + 'a', f) == c - '0' + 'a'); + assert(fgetc(f) == c - '0' + 'a'); + } + +#ifndef USE_HOST_LIBC + // Too many ungetcs should fail. + int eof = 0; + for (int i = 0; i < 100; i++) { + if (ungetc('x', f) == EOF) { + eof = 1; + break; + } + } + assert(eof); +#endif + + fclose(f); + + // TODO: Test with other operations, like fread. +} + +int main() { + fprintf(stderr, "with buffering...\n"); + test(1); + fprintf(stderr, "without buffering...\n"); + test(0); +} diff --git a/lib/mlibc/tests/ansi/utf8.c b/lib/mlibc/tests/ansi/utf8.c new file mode 100644 index 0000000..18b0d5a --- /dev/null +++ b/lib/mlibc/tests/ansi/utf8.c @@ -0,0 +1,63 @@ +#include +#include +#include +#include +#include +#include +#include + +#if UINTPTR_MAX == UINT64_MAX +#define WCHAR_SPEC "" +#else +#define WCHAR_SPEC "l" +#endif + +#define EXPECT(func) ({ \ + if(res != expected_ret) { \ + printf(#func " decoded %d bytes (expected %d bytes), at %s:%d\n", \ + res, expected_ret, __FILE__, line); \ + fflush(stdout); \ + abort(); \ + } \ + if(wc != expected) { \ + printf(#func " output cp %" WCHAR_SPEC "x (expected cp %" WCHAR_SPEC "x), at %s:%d\n", wc, \ + expected, __FILE__, line); \ + fflush(stdout); \ + abort(); \ + } \ + }) + +void verify_decode(const char *input, wchar_t expected, int line) { + wchar_t wc; + int bytes = *input ? strlen(input) : 1; + int expected_ret = *input ? strlen(input) : 0; + + // Check mbrtowc(). + mbstate_t state; + memset(&state, 0, sizeof(state)); + assert(mbrtowc(NULL, NULL, -1, &state) == 0); + int res = mbrtowc(&wc, input, bytes, &state); + EXPECT("mbrtowc"); + res = mbrtowc(NULL, input, bytes, &state); + EXPECT("mbrtowc (pwc == NULL)"); + + // Check mbtowc(). + assert(mbtowc(NULL, NULL, -1) == 0); + res = mbtowc(&wc, input, bytes); + EXPECT("mbtowc"); + res = mbtowc(NULL, input, bytes); + EXPECT("mbtowc (pwc == NULL)"); +} + +int main() { + setlocale(LC_ALL, "C.UTF-8"); + +#define verify_decode(in, out) verify_decode(in, out, __LINE__) + verify_decode("\x24", 0x24); + verify_decode("\xC2\xA2", 0xA2); + verify_decode("\xE0\xA4\xB9", 0x939); + verify_decode("\xE2\x82\xAC", 0x20AC); + verify_decode("\xED\x95\x9C", 0xD55C); + verify_decode("\xF0\x90\x8D\x88", 0x10348); + verify_decode("", L'\0'); +} diff --git a/lib/mlibc/tests/ansi/wcsdup.c b/lib/mlibc/tests/ansi/wcsdup.c new file mode 100644 index 0000000..564b77e --- /dev/null +++ b/lib/mlibc/tests/ansi/wcsdup.c @@ -0,0 +1,11 @@ +#include +#include +#include +#include + +int main() { + wchar_t *wide_string = L"test string\n"; + wchar_t *dup_string = wcsdup(wide_string); + assert(!memcmp(wide_string, dup_string, (wcslen(wide_string) + 1) * sizeof(wchar_t))); + free(dup_string); +} diff --git a/lib/mlibc/tests/ansi/wcsncasecmp.c b/lib/mlibc/tests/ansi/wcsncasecmp.c new file mode 100644 index 0000000..fcbe98f --- /dev/null +++ b/lib/mlibc/tests/ansi/wcsncasecmp.c @@ -0,0 +1,11 @@ +#include +#include + +int main() { + assert(!wcsncasecmp(L"foo", L"foo", 3)); + assert(!wcsncasecmp(L"foo", L"FOO", 3)); + assert(!wcsncasecmp(L"fooa", L"FOOB", 3)); + assert(wcsncasecmp(L"foo", L"bar", 3)); + assert(!wcsncasecmp(L"fooa", L"FOOA", 4)); + assert(!wcsncasecmp(L"123abc", L"123AbC", 6)); +} diff --git a/lib/mlibc/tests/ansi/wcsrtombs.c b/lib/mlibc/tests/ansi/wcsrtombs.c new file mode 100644 index 0000000..80df257 --- /dev/null +++ b/lib/mlibc/tests/ansi/wcsrtombs.c @@ -0,0 +1,12 @@ +#include +#include +#include +#include + +int main() { + const wchar_t str[] = L"wcsrtombs"; + const wchar_t *p = str; + int ret = wcsrtombs(NULL, &p, 343245234, NULL); + assert(ret == 9); + return 0; +} diff --git a/lib/mlibc/tests/ansi/wmemcmp.c b/lib/mlibc/tests/ansi/wmemcmp.c new file mode 100644 index 0000000..74de9bd --- /dev/null +++ b/lib/mlibc/tests/ansi/wmemcmp.c @@ -0,0 +1,19 @@ +#include +#include +#include + +int main(void){ + wchar_t *ws1 = calloc(10, sizeof(wchar_t)); + wchar_t *ws2 = calloc(10, sizeof(wchar_t)); + + mbstowcs(ws1, "Test 1", 10); + mbstowcs(ws2, "Tester 2", 10); + + assert(wmemcmp(ws1, ws2, 10) < 0); + assert(wmemcmp(ws2, ws1, 10) > 0); + assert(wmemcmp(ws2, ws2, 10) == 0); + + free(ws1); + free(ws2); + return 0; +} diff --git a/lib/mlibc/tests/bsd/ns_get_put.c b/lib/mlibc/tests/bsd/ns_get_put.c new file mode 100644 index 0000000..d64bb2a --- /dev/null +++ b/lib/mlibc/tests/bsd/ns_get_put.c @@ -0,0 +1,21 @@ +#include +#include +#include +#include +#include + +int main() { + uint8_t *buf = malloc(256); + uint16_t original16 = 4891; + uint32_t original32 = 4861984; + memset(buf, 0x0, sizeof(*buf)); + ns_put16(original16, buf); + uint16_t result16 = ns_get16(buf); + assert(result16 == original16); + memset(buf, 0x0, sizeof(*buf)); + ns_put32(original32, buf); + uint32_t result32 = ns_get32(buf); + assert(result32 == original32); + free(buf); + return 0; +} diff --git a/lib/mlibc/tests/bsd/reallocarray.c b/lib/mlibc/tests/bsd/reallocarray.c new file mode 100644 index 0000000..905d68d --- /dev/null +++ b/lib/mlibc/tests/bsd/reallocarray.c @@ -0,0 +1,7 @@ +#include + +int main() { + void *ret = reallocarray(NULL, 69, 0xCB7); + free(ret); + return !ret; +} diff --git a/lib/mlibc/tests/bsd/sbrk.c b/lib/mlibc/tests/bsd/sbrk.c new file mode 100644 index 0000000..88b0407 --- /dev/null +++ b/lib/mlibc/tests/bsd/sbrk.c @@ -0,0 +1,9 @@ +#include +#include +#include + +int main() { + void *ret = sbrk(0); + assert(ret != (void *) -1); + assert(ret); +} diff --git a/lib/mlibc/tests/bsd/strl.c b/lib/mlibc/tests/bsd/strl.c new file mode 100644 index 0000000..a502850 --- /dev/null +++ b/lib/mlibc/tests/bsd/strl.c @@ -0,0 +1,56 @@ +#include +#include + +int main() { + char buf[256]; + + /* Test copy to 0-sized buffer . */ + memset(buf, 0, sizeof(buf)); + assert(strlcpy(buf, "xyz", 0) == 3); + assert(strcmp(buf, "") == 0); + + /* Test normal copy. */ + memset(buf, 0, sizeof(buf)); + assert(strlcpy(buf, "xyz", sizeof(buf)) == 3); + assert(strcmp(buf, "xyz") == 0); + + /* Test truncated copy. */ + memset(buf, 0, sizeof(buf)); + assert(strlcpy(buf, "abcdefabcdef", 10) == 12); + assert(strcmp(buf, "abcdefabc") == 0); + + /* Test concat to 0-sized buffer. */ + memset(buf, 0, sizeof(buf)); + assert(strlcat(buf, "abc", 0) == 3); + assert(strcmp(buf, "") == 0); + + /* Test concat to full buffer. */ + memset(buf, 0, sizeof(buf)); + assert(strlcat(buf, "abcde", 6) == 5); + assert(strcmp(buf, "abcde") == 0); + assert(strlcat(buf, "xyz", 5) == 8); + assert(strcmp(buf, "abcde") == 0); + + /* Test normal concat. */ + memset(buf, 0, sizeof(buf)); + assert(strlcat(buf, "abc", sizeof(buf)) == 3); + assert(strcmp(buf, "abc") == 0); + assert(strlcat(buf, "xyz", sizeof(buf)) == 6); + assert(strcmp(buf, "abcxyz") == 0); + + /* Test truncated concat. */ + memset(buf, 0, sizeof(buf)); + assert(strlcat(buf, "abcabc", 10) == 6); + assert(strcmp(buf, "abcabc") == 0); + assert(strlcat(buf, "xyzxyz", 10) == 12); + assert(strcmp(buf, "abcabcxyz") == 0); + + /* Test truncated concat w/ truncated dst. */ + memset(buf, 0, sizeof(buf)); + assert(strlcat(buf, "abcabc", 10) == 6); + assert(strcmp(buf, "abcabc") == 0); + assert(strlcat(buf, "xyz", 4) == 7); + assert(strcmp(buf, "abcabc") == 0); + + return 0; +} diff --git a/lib/mlibc/tests/glibc/error.c b/lib/mlibc/tests/glibc/error.c new file mode 100644 index 0000000..2ae752a --- /dev/null +++ b/lib/mlibc/tests/glibc/error.c @@ -0,0 +1,6 @@ +#include +#include + +int main() { + error(0, EINVAL, "test: %s", "error"); +} diff --git a/lib/mlibc/tests/glibc/error.py b/lib/mlibc/tests/glibc/error.py new file mode 100644 index 0000000..3833974 --- /dev/null +++ b/lib/mlibc/tests/glibc/error.py @@ -0,0 +1,11 @@ +import subprocess +import sys +import os +from pyexpect import expect + +wrapper = os.getenv("MESON_EXE_WRAPPER") +wrapper = [x for x in (wrapper,) if x] + +output = subprocess.check_output(wrapper + [sys.argv[1]], stderr=subprocess.STDOUT) + +expect(bytes(sys.argv[1], 'utf-8') + b': test: error: Invalid argument (EINVAL)\n').to_equal(output) diff --git a/lib/mlibc/tests/glibc/error_at_line.c b/lib/mlibc/tests/glibc/error_at_line.c new file mode 100644 index 0000000..257ddd2 --- /dev/null +++ b/lib/mlibc/tests/glibc/error_at_line.c @@ -0,0 +1,6 @@ +#include +#include + +int main() { + error_at_line(0, EINVAL, "error_at_line", 5, "test: %s", "error"); +} diff --git a/lib/mlibc/tests/glibc/error_at_line.py b/lib/mlibc/tests/glibc/error_at_line.py new file mode 100644 index 0000000..7499e05 --- /dev/null +++ b/lib/mlibc/tests/glibc/error_at_line.py @@ -0,0 +1,11 @@ +import subprocess +import sys +import os +from pyexpect import expect + +wrapper = os.getenv("MESON_EXE_WRAPPER") +wrapper = [x for x in (wrapper,) if x] + +output = subprocess.check_output(wrapper + [sys.argv[1]], stderr=subprocess.STDOUT) + +expect(bytes(sys.argv[1], 'utf-8') + b':error_at_line:5: test: error: Invalid argument (EINVAL)\n').to_equal(output) diff --git a/lib/mlibc/tests/glibc/error_expect_fail.c b/lib/mlibc/tests/glibc/error_expect_fail.c new file mode 100644 index 0000000..17f0907 --- /dev/null +++ b/lib/mlibc/tests/glibc/error_expect_fail.c @@ -0,0 +1,6 @@ +#include +#include + +int main() { + error(1, EINVAL, "test error #1"); +} diff --git a/lib/mlibc/tests/glibc/error_message_count.c b/lib/mlibc/tests/glibc/error_message_count.c new file mode 100644 index 0000000..c2c694a --- /dev/null +++ b/lib/mlibc/tests/glibc/error_message_count.c @@ -0,0 +1,11 @@ +#include +#include +#include + +int main() { + assert(error_message_count == 0); + error(0, EINVAL, "test error #1"); + assert(error_message_count == 1); + error_at_line(0, EINVAL, __FILE__, __LINE__, "test error #2"); + assert(error_message_count == 2); +} diff --git a/lib/mlibc/tests/glibc/error_one_per_line.c b/lib/mlibc/tests/glibc/error_one_per_line.c new file mode 100644 index 0000000..98721ec --- /dev/null +++ b/lib/mlibc/tests/glibc/error_one_per_line.c @@ -0,0 +1,13 @@ +#include +#include +#include + +int main() { + assert(error_one_per_line == 0); + assert(error_message_count == 0); + error_one_per_line = 1; + error_at_line(0, EINVAL, __FILE__, 0, "test error #1"); + assert(error_message_count == 1); + error_at_line(0, EINVAL, __FILE__, 0, "test error #2"); + assert(error_message_count == 1); +} diff --git a/lib/mlibc/tests/glibc/error_print_progname.c b/lib/mlibc/tests/glibc/error_print_progname.c new file mode 100644 index 0000000..8840cb2 --- /dev/null +++ b/lib/mlibc/tests/glibc/error_print_progname.c @@ -0,0 +1,19 @@ +#include +#include +#include +#include +#include + +bool ran = false; + +void test_progname(void) { + ran = true; + fprintf(stderr, "progname test"); +} + +int main() { + assert(error_print_progname == NULL); + error_print_progname = &test_progname; + error(0, EINVAL, "test error #1"); + assert(ran == true); +} diff --git a/lib/mlibc/tests/glibc/ffsl-ffsll.c b/lib/mlibc/tests/glibc/ffsl-ffsll.c new file mode 100644 index 0000000..ed70ad6 --- /dev/null +++ b/lib/mlibc/tests/glibc/ffsl-ffsll.c @@ -0,0 +1,36 @@ +#include +#include +#include +#include + +int main(void){ + // ffsl + assert(ffsl(0x8000) == 16); + assert(ffsl(0) == 0); +#if UINTPTR_MAX == UINT64_MAX + assert(ffsl(LLONG_MAX - 1) == 2); + assert(ffsl(LLONG_MAX) == 1); +#endif + assert(ffsl(LONG_MIN) == (long)(sizeof(long) * CHAR_BIT)); + assert(ffsl(LONG_MIN + 1) == 1); + + for (int i = 1; i < 0x1000; i++) { + assert(ffsl(i) - 1 == __builtin_ctz(i)); + } + + // ffsll + assert(ffsll(0x8000) == 16); + assert(ffsll(0) == 0); +#if UINTPTR_MAX == UINT64_MAX + assert(ffsll(LLONG_MAX - 1) == 2); + assert(ffsll(LLONG_MAX) == 1); +#endif + assert(ffsll(LLONG_MIN) == (long long)(sizeof(long long) * CHAR_BIT)); + assert(ffsll(LLONG_MIN + 1) == 1); + + for (int i = 1; i < 0x1000; i++) { + assert(ffsll(i) - 1 == __builtin_ctz(i)); + } + + return 0; +} diff --git a/lib/mlibc/tests/glibc/getopt.c b/lib/mlibc/tests/glibc/getopt.c new file mode 100644 index 0000000..a0e27bb --- /dev/null +++ b/lib/mlibc/tests/glibc/getopt.c @@ -0,0 +1,288 @@ +#include +#include +#include +#include +#include +#include +#include + +#define COUNT_OF(x) ((sizeof(x)/sizeof(0[x])) / ((size_t)(!(sizeof(x) % sizeof(0[x]))))) +#define dump(x) fprintf(stderr, "getopt c '%c' (%d), optind %d ('%s'), optarg '%s', optopt '%c' (%d)\n", \ + (x), (x), optind, (size_t)optind >= COUNT_OF(test_argv) ? "out of range" : test_argv[optind], optarg, optopt, optopt); + +void test1() { + const char *shortopts = "b:cdef"; + + const struct option longopts[] = { + {"foo", required_argument, NULL, 'f'}, + {NULL, no_argument, NULL, 0} + }; + + int test_argc = 7; + + char *test_argv[] = { + "dummy", + "--foo", + "abc", + "-b", + "abc", + "abc", + "abc" + }; + + optind = 0; + int c = getopt_long(test_argc, test_argv, shortopts, longopts, NULL); + dump(c) + assert(c == 'f'); + + c = getopt_long(test_argc, test_argv, shortopts, longopts, NULL); + dump(c) + assert(optarg && !strcmp(optarg, "abc")); + assert(c == 'b'); + + c = getopt_long(test_argc, test_argv, shortopts, longopts, NULL); + dump(c); + assert(c == -1); + assert(optarg == NULL); + + // we have 2 non-option arguments + assert((optind + 2) == test_argc); +} + +void test2() { + const struct option longopts[] = { + {"foo", required_argument, NULL, 'f'}, + {NULL, no_argument, NULL, 0} + }; + + char *test_argv[] = { + "dummy", + "-c", + }; + + fputs("Situation: we pass a non-existant short option in argv\n", stderr); + + optind = 0; + int c = getopt_long(COUNT_OF(test_argv), test_argv, "ab:", longopts, NULL); + // Exprected result: return '?', optopt is set to the offender + assert(c == '?'); + assert(optopt == 'c'); + + fputs("Situation: we pass a non-existant short option in argv, while passing a leading colon in optstring\n", stderr); + optind = 0; + + c = getopt_long(COUNT_OF(test_argv), test_argv, ":ab:", longopts, NULL); + // Exprected result: return '?', optopt is set to the offender + assert(c == '?'); + assert(optopt == 'c'); + + fputs("Situation: we omit the required arg to a short option\n", stderr); + optind = 0; + + c = getopt_long(COUNT_OF(test_argv), test_argv, "ab:c:", longopts, NULL); + // Exprected result: return '?', optopt is set to the offender + assert(c == '?'); + assert(optopt == 'c'); + + fputs("Situation: we omit the required arg to a short option, while passing a leading colon in optstring\n", stderr); + optind = 0; + + c = getopt_long(COUNT_OF(test_argv), test_argv, ":ab:c:", longopts, NULL); + // Exprected result: return ':', optopt is set to the offender + assert(c == ':'); + assert(optopt == 'c'); +} + +void test3() { + const struct option longopts[] = { + {"foo", required_argument, NULL, 'f'}, + {NULL, no_argument, NULL, 0} + }; + + char *test_argv[] = { + "dummy", + "-cmanagarm", + }; + + fputs("Situation: we pass a concatenated argument to a short option\n", stderr); + + optind = 0; + int c = getopt_long(COUNT_OF(test_argv), test_argv, "ab:c:", longopts, NULL); + dump(c); + // Exprected result: + assert(c == 'c'); + assert(!strcmp(optarg, "managarm")); +} + +void test4() { + const struct option longopts[] = { + {"foo", required_argument, NULL, 'f'}, + {NULL, no_argument, NULL, 0} + }; + + char *test_argv[] = { + "dummy", + "-acmanagarm", + }; + + fputs("Situation: we pass concatenated short options to getopt\n", stderr); + + optind = 0; + int c = getopt_long(COUNT_OF(test_argv), test_argv, "ab:c:", longopts, NULL); + assert(c == 'a'); + + c = getopt_long(COUNT_OF(test_argv), test_argv, "ab:c:", longopts, NULL); + // Exprected result: + assert(c == 'c'); + assert(!strcmp(optarg, "managarm")); +} + +void test5() { + const struct option longopts[] = { + {"foo", required_argument, NULL, 'f'}, + {NULL, no_argument, NULL, 0} + }; + + char *test_argv[] = { + "su", + "-", + "managarm", + 0 + }; + + int test_argc = 3; + + fputs("Situation: testing `su - managarm`\n", stderr); + + optind = 0; + int c = getopt_long(test_argc, test_argv, "ab:", longopts, NULL); + dump(c); + assert(c == -1); + + if (optind < test_argc && !strcmp(test_argv[optind], "-")) { + ++optind; + } + + assert(optind < test_argc); + assert(!strcmp(test_argv[optind++], "managarm")); + assert(optind == test_argc); +} + +void test6() { + char *test_argv[] = { + "telescope", + "gemini://electrode.codes", + "-S", + 0 + }; + + int test_argc = 3; + optind = 0; + + const struct option longopts[] = { + {"colors", no_argument, NULL, 'C'}, + {"colours", no_argument, NULL, 'C'}, + {"help", no_argument, NULL, 'h'}, + {"safe", no_argument, NULL, 'S'}, + {"version", no_argument, NULL, 'v'}, + {NULL, 0, NULL, 0}, + }; + + int c = getopt_long(test_argc, test_argv, "Cc:hnST:v", longopts, NULL); + dump(c); + assert(c == 'S'); + assert(optind == 3); + assert(!optarg); +} + +void test7() { + int c; + + static const struct option options[] = { + { "debug", no_argument, NULL, 'd' }, + { "help", no_argument, NULL, 'h' }, + { "version", no_argument, NULL, 'V' }, + {} + }; + const char *command; + + char *test_argv[] = { + "udevadm", + "hwdb", + "--update", + 0 + }; + + int test_argc = 3; + setenv("POSIXLY_CORRECT", "1", 1); + optind = 0; + + while ((c = getopt_long(test_argc, test_argv, "+dhV", options, NULL)) >= 0) { + switch (c) { + case 'd': + break; + case 'h': + break; + case 'V': + break; + default: + break; + } + } + + dump(c); + command = test_argv[optind]; + assert(command); + assert(!strcmp(command, "hwdb")); +} + +void test8() { + const char *shortopts = "b:cde"; + + int foo = false; + int bar = false; + + const struct option longopts[] = { + {"foo", required_argument, &foo, 'x'}, + {"bar", required_argument, &bar, 'y'}, + {NULL, no_argument, NULL, 0} + }; + + int test_argc = 6; + + char *test_argv[] = { + "dummy", + "-foo", + "abc", + "-bar=def", + "ghi", + "jkl" + }; + + #ifdef __GLIBC__ + optind = 0; + #else + optreset = 1; + #endif + optopt = 0; + int c = getopt_long_only(test_argc, test_argv, shortopts, longopts, NULL); + dump(c); + assert(foo && !c); + assert(optind == 3); + + c = getopt_long_only(test_argc, test_argv, shortopts, longopts, NULL); + dump(c); + assert(bar && !c); + assert(optind == 4); +} + +int main() { + test1(); + test2(); + test3(); + test4(); + test5(); + test6(); + test7(); + test8(); +} diff --git a/lib/mlibc/tests/glibc/gnu-basename.c b/lib/mlibc/tests/glibc/gnu-basename.c new file mode 100644 index 0000000..9566532 --- /dev/null +++ b/lib/mlibc/tests/glibc/gnu-basename.c @@ -0,0 +1,13 @@ +#define _GNU_SOURCE +#include +#include + +#define test_string(x, expectval) assert(strcmp(basename(x), expectval) == 0) + +int main() { + test_string("/usr/lib", "lib"); + test_string("/usr/", ""); + test_string("/", ""); + test_string(".", "."); + test_string("..", ".."); +} diff --git a/lib/mlibc/tests/glibc/linux-syscall.c b/lib/mlibc/tests/glibc/linux-syscall.c new file mode 100644 index 0000000..2760df4 --- /dev/null +++ b/lib/mlibc/tests/glibc/linux-syscall.c @@ -0,0 +1,14 @@ +#include +#include +#include +#include +#include + +int main() { + char *data = "hello mlibc\n"; + long ret = syscall(SYS_write, 1, data, strlen(data)); + assert(ret == (long)strlen(data)); + + syscall(SYS_exit, 0); + abort(); +} diff --git a/lib/mlibc/tests/linux/cpuset.c b/lib/mlibc/tests/linux/cpuset.c new file mode 100644 index 0000000..3f55732 --- /dev/null +++ b/lib/mlibc/tests/linux/cpuset.c @@ -0,0 +1,27 @@ +#include +#include +#include + +#define SET_SIZE 15 + +int main() { + cpu_set_t *set = CPU_ALLOC(SET_SIZE); + size_t setsize = CPU_ALLOC_SIZE(SET_SIZE); + + CPU_ZERO_S(setsize, set); + + assert(!CPU_ISSET_S(11, setsize, set)); + + CPU_SET_S(11, setsize, set); + assert(CPU_ISSET_S(11, setsize, set)); + assert(CPU_COUNT_S(setsize, set) == 1); + + assert(!CPU_ISSET_S(CPU_SETSIZE - 1, setsize, set)); + + CPU_CLR_S(11, setsize, set); + assert(!CPU_ISSET_S(11, setsize, set)); + + CPU_FREE(set); + + return 0; +} diff --git a/lib/mlibc/tests/linux/malloc-usable-size.c b/lib/mlibc/tests/linux/malloc-usable-size.c new file mode 100644 index 0000000..3bb0394 --- /dev/null +++ b/lib/mlibc/tests/linux/malloc-usable-size.c @@ -0,0 +1,13 @@ +#include +#include +#include +#include + +int main() { + void *p1 = malloc(1023); + fprintf(stderr, "size: %zu\n", malloc_usable_size(p1)); + assert(malloc_usable_size(p1) >= 1023); + free(p1); + + return 0; +} diff --git a/lib/mlibc/tests/linux/pthread_attr.c b/lib/mlibc/tests/linux/pthread_attr.c new file mode 100644 index 0000000..4c1907c --- /dev/null +++ b/lib/mlibc/tests/linux/pthread_attr.c @@ -0,0 +1,90 @@ +#include +#include +#include +#include +#include + +static void test_affinity() { + pthread_attr_t attr; + cpu_set_t set = {0}; + assert(!pthread_attr_init(&attr)); + assert(!pthread_attr_setaffinity_np(&attr, 1, &set)); + + cpu_set_t other_set = {0}; + assert(!pthread_attr_getaffinity_np(&attr, 1, &set)); + + assert(!memcmp(&set, &other_set, sizeof(cpu_set_t))); + + pthread_attr_destroy(&attr); +} + +#if !defined(USE_HOST_LIBC) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 32) +static void test_sigmask() { + pthread_attr_t attr; + sigset_t set; + sigemptyset(&set); + sigaddset(&set, SIGUSR1); +#ifndef USE_HOST_LIBC + sigaddset(&set, SIGCANCEL); +#endif + + assert(!pthread_attr_init(&attr)); + assert(!pthread_attr_setsigmask_np(&attr, &set)); + + sigset_t other_set; + sigemptyset(&other_set); + + assert(!pthread_attr_getsigmask_np(&attr, &other_set)); + + assert(sigismember(&other_set, SIGUSR1)); +#ifndef USE_HOST_LIBC + // Test whether internal signals get filtered properly. + assert(!sigismember(&other_set, SIGCANCEL)); +#endif + + pthread_attr_destroy(&attr); +} + +static void *getattr_worker(void *arg) { + (void)arg; + return NULL; +} + +static void test_getattrnp() { + pthread_attr_t attr; + size_t stacksize = PTHREAD_STACK_MIN; + assert(!pthread_attr_init(&attr)); + assert(!pthread_attr_setstacksize(&attr, stacksize)); + + pthread_t thread; + assert(!pthread_create(&thread, &attr, getattr_worker, NULL)); + assert(!pthread_getattr_np(thread, &attr)); + size_t other_stacksize; + assert(!pthread_attr_getstacksize(&attr, &other_stacksize)); + assert(other_stacksize == stacksize); + assert(!pthread_join(thread, NULL)); + + pthread_t own_thread = pthread_self(); + void *stack; + assert(!pthread_getattr_np(own_thread, &attr)); + assert(!pthread_attr_getstack(&attr, &stack, &other_stacksize)); + assert(stack); + assert(other_stacksize); + // Check that we can read from the highest byte returned. + // pthread_getattr_np() should return the lowest byte + // of the stack. + printf("highest byte: %hhu\n", *(char *)(stack + other_stacksize - 1)); + + pthread_attr_destroy(&attr); +} +#endif // !defined(USE_HOST_LIBC) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 32) + +int main() { + test_affinity(); +#if !defined(USE_HOST_LIBC) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 32) + test_sigmask(); + test_getattrnp(); +#endif + + return 0; +} diff --git a/lib/mlibc/tests/linux/pthread_setname_np.c b/lib/mlibc/tests/linux/pthread_setname_np.c new file mode 100644 index 0000000..95c95c9 --- /dev/null +++ b/lib/mlibc/tests/linux/pthread_setname_np.c @@ -0,0 +1,33 @@ +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#include +#include +#include +#include + +int main() { + int ret = pthread_setname_np(pthread_self(), "mlibc-test-123"); + assert(!ret); + + char buf[16]; + ret = pthread_getname_np(pthread_self(), buf, 16); + assert(!ret); + assert(!strcmp("mlibc-test-123", buf)); + + ret = pthread_setname_np(pthread_self(), "mlibc-test-123-too-long"); + assert(ret == ERANGE); + + ret = pthread_getname_np(pthread_self(), buf, 1); + assert(ret == ERANGE); + + ret = pthread_getname_np(pthread_self(), buf, 15); + assert(ret == ERANGE); + + ret = pthread_getname_np(pthread_self(), buf, 16); + assert(!ret); + assert(!strcmp("mlibc-test-123", buf)); + + return 0; +} diff --git a/lib/mlibc/tests/linux/xattr.c b/lib/mlibc/tests/linux/xattr.c new file mode 100644 index 0000000..c6dd152 --- /dev/null +++ b/lib/mlibc/tests/linux/xattr.c @@ -0,0 +1,80 @@ +#include +#include +#include +#include +#include +#include + +#define assert_perror(x) \ + ({ \ + int res = (x); \ + if (res < 0) { \ + perror(#x); \ + return 1; \ + } \ + res; \ + }) + +#define soft_assert(x, m) \ + ({ \ + if (!(x)) { \ + fprintf(stderr, "cond \"%s\" failed: %s\n", #x, m); \ + return 1; \ + } \ + }) + +void remove_tmp(const char (*fname)[]) { + unlink(&(*fname)[0]); +} +#define _cleanup_file_ __attribute__((cleanup(remove_tmp))) + +int main(void) { + int ret; + char buf[32] = { 0 }; + _cleanup_file_ char filename[] = "xattr_test.XXXXXX"; + _cleanup_file_ char filename2[] = "xattr_test.XXXXXX.2"; + + int tmpfile = assert_perror(mkstemp(filename)); + memcpy(filename2, filename, sizeof(filename) - 1); + assert_perror(symlink(filename, filename2)); + + assert_perror(setxattr(filename, "user.T1", "ABC", 3, XATTR_CREATE)); + assert_perror(fsetxattr(tmpfile, "user.T2", "DEF", 3, XATTR_CREATE)); + + // for testing remove + assert_perror(fsetxattr(tmpfile, "user.T3", "DEF", 3, XATTR_CREATE)); + + if ((ret = getxattr(filename, "user.T1", buf, 3)) != 3) { + if (ret < 0) { + perror("getxattr"); + return 1; + } + + soft_assert(memcmp(buf, "ABC", 3) == 0, "xattr read wrong"); + } + + ret = lgetxattr(filename2, "user.T1", buf, 3); + soft_assert(ret < 0 && errno == ENODATA, "lgetxattr deref'd"); + + if ((ret = fgetxattr(tmpfile, "user.T3", buf, 3)) != 3) { + if (ret < 0) { + perror("fgetxattr"); + return 1; + } + + soft_assert(memcmp(buf, "DEF", 3) == 0, "xattr read wrong"); + } + + assert_perror(removexattr(filename, "user.T2")); + assert_perror(fremovexattr(tmpfile, "user.T3")); + + ret = assert_perror(listxattr(filename, buf, sizeof(buf) - 1)); + soft_assert(memmem(buf, ret, "user.T1", 7), "user.T1 not found"); + soft_assert(!memmem(buf, ret, "user.T2", 7), "user.T2 found"); + soft_assert(!memmem(buf, ret, "user.T3", 7), "user.T3 found"); + + ret = assert_perror(flistxattr(tmpfile, buf, sizeof(buf) - 1)); + soft_assert(memmem(buf, ret, "user.T1", 7), "user.T1 not found"); + soft_assert(!memmem(buf, ret, "user.T2", 7), "user.T2 found"); + soft_assert(!memmem(buf, ret, "user.T3", 7), "user.T3 found"); +} diff --git a/lib/mlibc/tests/meson.build b/lib/mlibc/tests/meson.build new file mode 100644 index 0000000..b7d65ca --- /dev/null +++ b/lib/mlibc/tests/meson.build @@ -0,0 +1,261 @@ +timeout_sec = 10 + +all_test_cases = [ + 'ansi/alloc', + 'ansi/sscanf', + 'ansi/sprintf', + 'ansi/snprintf', + 'ansi/utf8', + 'ansi/strtol', + 'ansi/strtof', + 'ansi/abs', + 'ansi/longjmp', + 'ansi/mbrtoc32', + 'ansi/strverscmp', + 'ansi/strftime', + 'ansi/strchr', + 'ansi/strrchr', + 'ansi/wcsrtombs', + 'ansi/wmemcmp', + 'ansi/timegm', + 'ansi/ungetc', + 'ansi/wcsdup', + 'ansi/wcsncasecmp', + 'ansi/fopen', + 'ansi/memmem', + 'ansi/creal-cimag', + 'ansi/fenv', + 'ansi/qsort', + 'ansi/freopen', + 'ansi/strxfrm', + 'ansi/calloc', + 'bsd/ns_get_put', + 'bsd/reallocarray', + 'bsd/strl', + 'bsd/sbrk', + 'posix/inet_ntop', + 'posix/inet_pton', + 'posix/access', + 'posix/pthread_barrier', + 'posix/pthread_rwlock', + 'posix/pthread_cond', + 'posix/pthread_create', + 'posix/pthread_cancel', + 'posix/pthread_atfork', + 'posix/pthread_cleanup', + 'posix/pthread_kill', + 'posix/pthread_mutex', + 'posix/pthread_key', + 'posix/pthread_thread_local', + 'posix/pthread_attr', + 'posix/pthread_schedparam', + 'posix/pwd', + 'posix/fdopen', + 'posix/fopencookie', + 'posix/fmemopen', + 'posix/getaddrinfo', + 'posix/getdelim', + 'posix/getnameinfo', + 'posix/getservbyname', + 'posix/getservbyport', + 'posix/grp', + 'posix/dprintf', + 'posix/posix_memalign', + 'posix/posix_spawn', + 'posix/index', + 'posix/rindex', + 'posix/search', + 'posix/open_memstream', + 'posix/popen', + 'posix/system', # This test should be in the ANSI tests, but it depends on sys/wait.h + 'posix/sigsuspend', + 'posix/sigaltstack', + 'posix/time', + 'posix/realpath', + 'posix/ffs', + 'posix/getcwd', + 'posix/memrchr', + 'posix/wordexp', + 'posix/rlimits', + 'posix/accept4', + 'posix/setpriority', + 'posix/alarm', + 'posix/abort', # This test should be in the ANSI tests, but it depends on sigaction + 'posix/timer', + 'posix/vfork', + 'posix/wcwidth', + 'posix/pause', + 'posix/flockfile', + 'posix/basename', + 'posix/regex', + 'posix/sigtimedwait', + 'posix/if_indextoname', + 'posix/readv-writev', + 'posix/posix-timer', + 'posix/strdupa', + 'posix/mkstemp', + 'posix/waitid', + 'glibc/getopt', + 'glibc/ffsl-ffsll', + 'glibc/error_message_count', + 'glibc/error_one_per_line', + 'glibc/error_print_progname', + 'glibc/error_expect_fail', + 'glibc/error', + 'glibc/error_at_line', + 'linux/xattr', + 'linux/pthread_setname_np', + 'linux/pthread_attr', + 'linux/cpuset', + 'linux/malloc-usable-size', +] + +if host_machine.system() == 'linux' + all_test_cases += 'glibc/linux-syscall' +endif + +fail_test_cases = [ + 'posix/abort', + 'glibc/error_expect_fail', +] + +wrapped_test_cases = [ + 'glibc/error', + 'glibc/error_at_line', +] + +host_libc_excluded_test_cases = [ + 'bsd/strl', # These functions do not exist on Linux. +] +host_libc_noasan_test_cases = [ + 'posix/pthread_cancel', + 'posix/pthread_attr', # does some stack overflowing to check stack size + 'posix/posix_memalign', + 'posix/search', # requires tdelete (#351) + 'ansi/calloc', # does some overflowing + 'linux/pthread_attr', # encounters memory leaks +] + +extra_cflags_test_cases = { + 'ansi/calloc': ['-Wno-alloc-size-larger-than'], +} + +test_sources = [] +test_link_args = [] +test_c_args = [] +use_pie = false + +test_c_args = [] +test_link_args = [] + +# Our ubsan implementation can't be used by the tests themselves, +# since it is internal to libc.so and ld.so. +test_override_options = ['b_sanitize=none'] + +if library_type == 'static' + libc_dep = declare_dependency( + include_directories: libc_include_dirs, + link_with: libc_static, + dependencies: [libc_deps, rtlib_deps] + ) + use_pie = false + test_c_args += '-no-pie' + test_link_args += ['-no-pie', '-static'] + test_sources += [ + '../options/internal' / host_machine.cpu_family() / 'mlibc_crtbegin.S', + '../options/internal' / host_machine.cpu_family() / 'mlibc_crtend.S', + crt, + ] +else + libc_dep = declare_dependency( + include_directories: libc_include_dirs, + link_with: libc_shared, + dependencies: [libc_deps, rtlib_deps] + ) + test_link_args += ['-Wl,--dynamic-linker=' + meson.build_root() + '/ld.so'] + + if host_machine.system() in ['linux'] + use_pie = true + test_sources += crt_pie + else + use_pie = false + test_sources += crt + + # Meson doesn't set these for us (issue #4651). + test_c_args += '-no-pie' + test_link_args += '-no-pie' + endif + + # Add the rtdl tests. + if not disable_posix_option + subdir('rtdl') + endif +endif + +py = import('python').find_installation('python3') + +foreach test_name : all_test_cases + test_subdir = test_name.split('/')[0] + test_short_name = test_name.split('/')[1] + test_exec_name = test_name.replace('/', '-') + + if test_subdir == 'ansi' and disable_ansi_option + continue + elif test_subdir == 'bsd' and disable_bsd_option + continue + elif test_subdir == 'glibc' and disable_glibc_option + continue + elif test_subdir == 'posix' and disable_posix_option + continue + elif test_subdir == 'linux' and disable_linux_option + continue + endif + + should_fail = fail_test_cases.contains(test_name) + exec = executable(test_exec_name, [test_name + '.c', test_sources], + dependencies: libc_dep, + build_rpath: meson.build_root(), + override_options: test_override_options, + c_args: test_c_args, + link_args: test_link_args, + pie: use_pie, + ) + + if wrapped_test_cases.contains(test_name) + test(test_short_name, + py, + suite: test_subdir, + should_fail: should_fail, + args: [ + meson.source_root() + '/tests/' + test_name + '.py', + exec + ], + timeout: timeout_sec, + ) + else + test(test_short_name, exec, suite: test_subdir, should_fail: should_fail, timeout: timeout_sec) + endif + + if build_tests_host_libc and not host_libc_excluded_test_cases.contains(test_name) + if test_name in host_libc_noasan_test_cases + host_libc_sanitize_options = 'b_sanitize=undefined' + else + host_libc_sanitize_options = 'b_sanitize=address,undefined' + endif + + if test_name in extra_cflags_test_cases + extra_cflags = extra_cflags_test_cases[test_name] + else + extra_cflags = [] + endif + + exec = executable('host-libc-' + test_exec_name, test_name + '.c', + build_rpath: meson.build_root(), + override_options: host_libc_sanitize_options, + c_args: ['-D_GNU_SOURCE', '-DUSE_HOST_LIBC', '-pthread', extra_cflags], + link_args: ['-lresolv', '-ldl', '-pthread', '-lm', '-lrt'], + native: true, + ) + test(test_short_name, exec, suite: ['host-libc', test_subdir], should_fail: should_fail, timeout: timeout_sec) + endif +endforeach diff --git a/lib/mlibc/tests/posix/abort.c b/lib/mlibc/tests/posix/abort.c new file mode 100644 index 0000000..5f7bb7d --- /dev/null +++ b/lib/mlibc/tests/posix/abort.c @@ -0,0 +1,21 @@ +#include +#include +#include + +void handler(int sig, siginfo_t *info, void *ctx) { + (void)sig; + (void)info; + (void)ctx; +} + +int main() { + struct sigaction sa; + sa.sa_sigaction = handler; + sa.sa_flags = SA_SIGINFO; + sigemptyset(&sa.sa_mask); + + int ret = sigaction(SIGABRT, &sa, NULL); + assert(!ret); + + abort(); +} diff --git a/lib/mlibc/tests/posix/accept4.c b/lib/mlibc/tests/posix/accept4.c new file mode 100644 index 0000000..ba593ee --- /dev/null +++ b/lib/mlibc/tests/posix/accept4.c @@ -0,0 +1,123 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef USE_HOST_LIBC +#define TEST_PORT 31337 +#else +#define TEST_PORT 42069 +#endif + +static struct sockaddr_in connect_addr, accept_addr; +static int listen_fd; + +int permutations[] = { + 0, + SOCK_CLOEXEC, + SOCK_NONBLOCK, + SOCK_CLOEXEC | SOCK_NONBLOCK, +}; + +static bool run_test(int flags) +{ + int connect_fd; + int fd_flags, access; + socklen_t addrlen; + + connect_fd = socket(AF_INET, SOCK_STREAM, 0); + connect(connect_fd, (struct sockaddr *)&connect_addr, sizeof(connect_addr)); + addrlen = sizeof(accept_addr); + + int accept_fd = accept4(listen_fd, (struct sockaddr *)&accept_addr, &addrlen, flags); + + if(accept_fd == -1) { + fprintf(stderr, "accept4 failed: %s\n", strerror(errno)); + goto cleanup; + } + + fd_flags = fcntl(accept_fd, F_GETFD); + if(!(!!(fd_flags & FD_CLOEXEC) == !!(flags & SOCK_CLOEXEC))) { + fprintf(stderr, "CLOEXEC mismatch, got %d instead of %d\n", !!(fd_flags & FD_CLOEXEC), !!(flags & SOCK_CLOEXEC)); + goto cleanup; + } + + access = fcntl(accept_fd, F_GETFL); + if(!(!!(access & O_NONBLOCK) == !!(flags & SOCK_NONBLOCK))) { + fprintf(stderr, "NONBLOCK flag mismatch, %d vs %d\n", !!(access & O_NONBLOCK), !!(flags & SOCK_NONBLOCK)); + goto cleanup; + } + + close(accept_fd); + close(connect_fd); + + fprintf(stderr, "tested CLOEXEC %d, NONBLOCK %d\n", !!(flags & SOCK_CLOEXEC), !!(flags & SOCK_NONBLOCK)); + return true; + +cleanup: + close(accept_fd); + close(connect_fd); + return false; +} + +static int socket_setup(void) +{ + struct sockaddr_in addr; + int reuseaddr; + + memset(&addr, 0, sizeof(struct sockaddr_in)); + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = htonl(INADDR_ANY); + addr.sin_port = htons(TEST_PORT); + + int socket_fd = socket(AF_INET, SOCK_STREAM, 0); + + if(socket_fd == -1) { + fprintf(stderr, "socket failed: %s\n", strerror(errno)); + exit(1); + } + + reuseaddr = 1; + int ret = setsockopt(socket_fd, SOL_SOCKET, SO_REUSEADDR, &reuseaddr, sizeof(reuseaddr)); + + if(ret == -1) { + fprintf(stderr, "setsockopt failed: %s\n", strerror(errno)); + exit(1); + } + + ret = bind(socket_fd, (struct sockaddr *)&addr, sizeof(struct sockaddr_in)); + + if(ret == -1) { + fprintf(stderr, "bind failed: %s\n", strerror(errno)); + exit(1); + } + + ret = listen(socket_fd, 5); + + if(ret == -1) { + fprintf(stderr, "listen failed: %s\n", strerror(errno)); + exit(1); + } + + return socket_fd; +} + +int main() { + memset(&connect_addr, 0, sizeof(connect_addr)); + connect_addr.sin_family = AF_INET; + connect_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + connect_addr.sin_port = htons(TEST_PORT); + + for(size_t i = 0; i < 4; i++) { + listen_fd = socket_setup(); + if(!run_test(permutations[i])) { + exit(1); + } + close(listen_fd); + } +} diff --git a/lib/mlibc/tests/posix/access.c b/lib/mlibc/tests/posix/access.c new file mode 100644 index 0000000..e0c9f45 --- /dev/null +++ b/lib/mlibc/tests/posix/access.c @@ -0,0 +1,30 @@ +#include +#include +#include +#include +#include + +#ifdef USE_HOST_LIBC +#define TEST_FILE "access-host-libc.tmp" +#else +#define TEST_FILE "access.tmp" +#endif + +int main() { + // Make sure that it wasn't created by a previous test run + unlink(TEST_FILE); + + assert(access(TEST_FILE, F_OK) == -1); + assert(access(TEST_FILE, W_OK) == -1); + assert(access(TEST_FILE, R_OK) == -1); + assert(access(TEST_FILE, X_OK) == -1); + + close(open(TEST_FILE, O_CREAT | O_RDWR, 0666)); + + assert(access(TEST_FILE, F_OK) == 0); + assert(access(TEST_FILE, W_OK) == 0); + assert(access(TEST_FILE, R_OK) == 0); + assert(access(TEST_FILE, X_OK) == -1); + + unlink(TEST_FILE); +} diff --git a/lib/mlibc/tests/posix/alarm.c b/lib/mlibc/tests/posix/alarm.c new file mode 100644 index 0000000..b8a43e3 --- /dev/null +++ b/lib/mlibc/tests/posix/alarm.c @@ -0,0 +1,34 @@ +#include +#include +#include +#include +#include +#include + +static volatile int alarms_fired = 0; + +static void sigalrm_handler(int signal) { + if(signal == SIGALRM) + alarms_fired++; +} + +int main() { + signal(SIGALRM, sigalrm_handler); + + alarms_fired = 0; + + unsigned int ret = alarm(10); + assert(!ret); + + sleep(1); + + ret = alarm(1); + assert(ret == 9); + + sleep(2); + + if(alarms_fired != 1) { + fprintf(stderr, "alarm handler fired %u times instead of 1\n", alarms_fired); + exit(1); + } +} diff --git a/lib/mlibc/tests/posix/basename.c b/lib/mlibc/tests/posix/basename.c new file mode 100644 index 0000000..260bf90 --- /dev/null +++ b/lib/mlibc/tests/posix/basename.c @@ -0,0 +1,17 @@ +#include +#include +#include + +int main() { + /* intentionally a macro: basename modifies its argument */ +#define test_string(x, expectval) do { \ + char str[] = x; \ + assert(strcmp(basename(str), expectval) == 0); \ + } while (0) + + test_string("/usr/lib", "lib"); + test_string("/usr/", "usr"); + test_string("/", "/"); + test_string(".", "."); + test_string("..", ".."); +} diff --git a/lib/mlibc/tests/posix/dprintf.c b/lib/mlibc/tests/posix/dprintf.c new file mode 100644 index 0000000..4746edb --- /dev/null +++ b/lib/mlibc/tests/posix/dprintf.c @@ -0,0 +1,39 @@ +#include +#include +#include +#include +#include + +#ifdef USE_HOST_LIBC +#define TEST_FILE "dprintf-host-libc.tmp" +#else +#define TEST_FILE "dprintf.tmp" +#endif + +int main() { + int fd = open(TEST_FILE, O_RDWR | O_CREAT, 0666); + assert(fd > -1); + + int ret = dprintf(fd, "aaa"); + assert(ret == 3); + + // Check if we can read back the same things. + // Also checks to see if the fd is still open, + // which is issue #199. + + off_t seek = lseek(fd, 0, SEEK_SET); + assert(seek == 0); + + char buf[3]; + ssize_t num_read = read(fd, buf, 3); + + assert(num_read == 3); + assert(buf[0] == 'a' + && buf[1] == 'a' + && buf[2] == 'a'); + + // All the tests pass, now we can unlink the file. + ret = unlink(TEST_FILE); + assert(ret == 0); + return 0; +} diff --git a/lib/mlibc/tests/posix/fdopen.c b/lib/mlibc/tests/posix/fdopen.c new file mode 100644 index 0000000..1066bfb --- /dev/null +++ b/lib/mlibc/tests/posix/fdopen.c @@ -0,0 +1,37 @@ +#include +#include +#include +#include +#include + +#define TEST_FILE "fdopen.tmp" + +int main() { + int fd = open(TEST_FILE, O_CREAT | O_RDWR, 0666); + assert(fd >= 0); + + char *str = "mlibc fdopen test"; + assert(write(fd, str, strlen(str))); + + // Seek to the beginning, then reopen with fdopen in append mode. + lseek(fd, 0, SEEK_SET); + FILE *file = fdopen(fd, "a"); + assert(file); + + // Append and close. + str = " appended"; + fwrite(str, strlen(str), 1, file); + fflush(file); + fclose(file); + + // Open it again and check that the append succeeded. + fd = open(TEST_FILE, O_RDONLY); + assert(fd >= 0); + file = fdopen(fd, "r"); + assert(file); + str = "mlibc fdopen test appended"; + char buf[100] = {0}; + assert(fread(buf, 1, strlen(str), file)); + assert(!strcmp(buf, str)); + fclose(file); +} diff --git a/lib/mlibc/tests/posix/ffs.c b/lib/mlibc/tests/posix/ffs.c new file mode 100644 index 0000000..3f7ba84 --- /dev/null +++ b/lib/mlibc/tests/posix/ffs.c @@ -0,0 +1,18 @@ +#include +#include +#include + +int main(void){ + assert(ffs(0x8000) == 16); + assert(ffs(0) == 0); + assert(ffs(INT_MAX - 1) == 2); + assert(ffs(INT_MAX) == 1); + assert(ffs(INT_MIN) == (int)(sizeof(int) * CHAR_BIT)); + assert(ffs(INT_MIN + 1) == 1); + + for (int i = 1; i < 0x1000; i++) { + assert(ffs(i) - 1 == __builtin_ctz(i)); + } + + return 0; +} diff --git a/lib/mlibc/tests/posix/flockfile.c b/lib/mlibc/tests/posix/flockfile.c new file mode 100644 index 0000000..982311e --- /dev/null +++ b/lib/mlibc/tests/posix/flockfile.c @@ -0,0 +1,35 @@ +#include +#include +#include +#include +#include + +static void *worker(void *arg) { + (void)arg; + flockfile(stdout); + fputs_unlocked("hello from worker", stdout); + funlockfile(stdout); + return NULL; +} + +int main() { + // Check that recursive locking works. + assert(!ftrylockfile(stdout)); + flockfile(stdout); + flockfile(stdout); + funlockfile(stdout); + funlockfile(stdout); + funlockfile(stdout); + + assert(!ftrylockfile(stdout)); + + pthread_t thread; + int ret = pthread_create(&thread, NULL, &worker, NULL); + assert(!ret); + + sleep(1); + funlockfile(stdout); + + assert(!pthread_join(thread, NULL)); + return 0; +} diff --git a/lib/mlibc/tests/posix/fmemopen.c b/lib/mlibc/tests/posix/fmemopen.c new file mode 100644 index 0000000..4d5046e --- /dev/null +++ b/lib/mlibc/tests/posix/fmemopen.c @@ -0,0 +1,150 @@ +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#include +#include +#include +#include +#include + +#define BUFFER0_SIZE 0x1000 +#define BUFFER1 "Hello world" +#define BUFFER1_SIZE (sizeof(BUFFER1)) + +int main() { + // test seek with mode "r" + FILE *f = fmemopen(NULL, BUFFER0_SIZE, "r"); + assert(f); + + int ret = fseek(f, 0, SEEK_END); + assert(!ret); + long pos = ftell(f); + fprintf(stderr, "pos = %ld\n", pos); + // Despite the fact that this is correct behavior (see below), + // this sometimes fails on glibc; newlib seems to get this wrong, too. + // to quote what posix says about it: + // > The stream shall also maintain the size of the current buffer contents; + // > use of fseek() or fseeko() on the stream with SEEK_END shall seek relative to this size. + // > For modes r and r+ the size shall be set to the value given by the size argument. +#if !defined(__GLIBC__) + assert(pos == BUFFER0_SIZE); +#endif + + fclose(f); + + // test seek with mode "w" + f = fmemopen(NULL, BUFFER0_SIZE, "w"); + assert(f); + + ret = fseek(f, 0, SEEK_END); + assert(!ret); + pos = ftell(f); + assert(pos == 0); + + fclose(f); + + // test seek with mode "a" and a NULL buffer + f = fmemopen(NULL, BUFFER0_SIZE, "a"); + assert(f); + + ret = fseek(f, 0, SEEK_END); + assert(!ret); + pos = ftell(f); + assert(pos == 0); + + fclose(f); + + // test seek with mode "a" and a buffer containing a '\0' + f = fmemopen(BUFFER1, BUFFER1_SIZE + 2, "a"); + assert(f); + + pos = ftell(f); + assert(pos == (long) (BUFFER1_SIZE - 1)); + + ret = fseek(f, 0, SEEK_SET); + assert(!ret); + pos = ftell(f); + assert(!pos); + + ret = fseek(f, 0, SEEK_END); + assert(!ret); + pos = ftell(f); + assert(pos == (long) (BUFFER1_SIZE - 1)); + + fclose(f); + + // test seek with mode "a" and a buffer not containing a '\0' + f = fmemopen(BUFFER1, BUFFER1_SIZE - 2, "a"); + assert(f); + + ret = fseek(f, 0, SEEK_END); + assert(!ret); + pos = ftell(f); + assert(pos == (long) (BUFFER1_SIZE - 2)); + + fclose(f); + + f = fmemopen(BUFFER1, BUFFER1_SIZE, "r"); + assert(f); + + ret = fseek(f, 0, SEEK_SET); + assert(!ret); + + char buf[BUFFER1_SIZE]; + int read = fread(buf, 1, BUFFER1_SIZE - 2, f); + assert(read == BUFFER1_SIZE - 2); + assert(!strncmp(BUFFER1, buf, BUFFER1_SIZE - 2)); + + fseek(f, 0, SEEK_END); + + read = fread(buf, 1, 2, f); + assert(read == 0); + assert(feof(f)); + + fclose(f); + + // Open a buffer for read+write + char *buf1 = strdup(BUFFER1); + f = fmemopen(buf1, BUFFER1_SIZE, "w+"); + assert(f); + assert(strlen(BUFFER1) == BUFFER1_SIZE - 1); + + // seek to somewhere in the middle of the buffer + fseek(f, BUFFER1_SIZE - 5, SEEK_SET); + // write as much data to it as possible + read = fwrite(BUFFER1, 1, 9, f); + rewind(f); + + // seek the the same position in the middle of the buffer + ret = fseek(f, BUFFER1_SIZE - 5, SEEK_SET); + assert(!ret); + memset(buf, 0, BUFFER1_SIZE); + // read what we just wrote + read = fread(buf, 1, 5, f); + // check that the write got correctly truncated + fprintf(stderr, "buf '%s' (%zu)\n", buf, strlen(buf)); + assert(!strncmp(BUFFER1, buf, 4) && strlen(buf) == 4); + + fclose(f); + free(buf1); + + char *buf2 = strdup(BUFFER1); + f = fmemopen(buf2, 0, "r"); + assert(f || errno == EINVAL); + + if(f) { + memset(buf, 0, BUFFER1_SIZE); + read = fread(buf, 10, 1, f); + assert(!read); + rewind(f); + + read = fwrite(BUFFER1, 1, 12, f); + assert(read == 0); + + fclose(f); + } + free(buf2); + + return 0; +} diff --git a/lib/mlibc/tests/posix/fopencookie.c b/lib/mlibc/tests/posix/fopencookie.c new file mode 100644 index 0000000..4325038 --- /dev/null +++ b/lib/mlibc/tests/posix/fopencookie.c @@ -0,0 +1,69 @@ +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#include +#include +#include + +struct testcookie { + bool read; + bool write; + bool seek; + bool close; +}; + +ssize_t cookie_read(void *c, char *buf, size_t size) { + (void) buf; + struct testcookie *cookie = c; + cookie->read = true; + return size; +} + +ssize_t cookie_write(void *c, const char *buf, size_t size) { + (void) buf; + struct testcookie *cookie = c; + cookie->write = true; + return size; +} + +int cookie_seek(void *c, off64_t *offset, int whence) { + (void) offset; + (void) whence; + struct testcookie *cookie = c; + cookie->seek = true; + return 0; +} + +int cookie_close(void *c) { + struct testcookie *cookie = c; + cookie->close = true; + return 0; +} + +int main() { + struct testcookie cookie = { false, false, false, false }; + + cookie_io_functions_t funcs = { + .read = cookie_read, + .write = cookie_write, + .seek = cookie_seek, + .close = cookie_close, + }; + + FILE *stream = fopencookie(&cookie, "w+", funcs); + assert(stream); + + unsigned char buf[1]; + int ret = fread(buf, 1, 1, stream); + assert(ret == 1); + ret = fwrite(buf, 1, 1, stream); + assert(ret == 1); + ret = fseek(stream, 0, SEEK_SET); + assert(!ret); + + ret = fclose(stream); + assert(!ret); + + assert(cookie.read && cookie.write && cookie.seek && cookie.close); +} diff --git a/lib/mlibc/tests/posix/getaddrinfo.c b/lib/mlibc/tests/posix/getaddrinfo.c new file mode 100644 index 0000000..d52c93f --- /dev/null +++ b/lib/mlibc/tests/posix/getaddrinfo.c @@ -0,0 +1,52 @@ +#include +#include +#include +#include +#include +#include + +int main() { + struct addrinfo *res = NULL; + struct addrinfo hints = {0}; + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_TCP; + + int ret = getaddrinfo(NULL, "443", &hints, &res); + assert(ret == 0); + + struct sockaddr_in *addr = (struct sockaddr_in*)(res[0].ai_addr); + assert(addr->sin_port == htons(443)); + assert(res[0].ai_socktype == SOCK_STREAM); + assert(res[0].ai_protocol == IPPROTO_TCP); + + freeaddrinfo(res); + res = NULL; + + /* check we can resolve any domain */ + ret = getaddrinfo("example.net", NULL, &hints, &res); + assert(ret == 0); + + freeaddrinfo(res); + res = NULL; + + hints.ai_flags = AI_NUMERICHOST; + ret = getaddrinfo("10.10.10.10", NULL, &hints, &res); + assert(ret == 0); + + addr = (struct sockaddr_in*)res[0].ai_addr; + assert((addr->sin_addr.s_addr & 0xFF) == 10); + assert(((addr->sin_addr.s_addr >> 8) & 0xFF) == 10); + assert(((addr->sin_addr.s_addr >> 16) & 0xFF) == 10); + assert(((addr->sin_addr.s_addr >> 24) & 0xFF) == 10); + + freeaddrinfo(res); + res = NULL; + + ret = getaddrinfo("example.net", NULL, &hints, &res); + assert(ret == EAI_NONAME); + + freeaddrinfo(res); + + return 0; +} diff --git a/lib/mlibc/tests/posix/getcwd.c b/lib/mlibc/tests/posix/getcwd.c new file mode 100644 index 0000000..f3ba8da --- /dev/null +++ b/lib/mlibc/tests/posix/getcwd.c @@ -0,0 +1,22 @@ +#include +#include +#include +#include +#include + +int main() { + char buf[PATH_MAX]; + char *ret = getcwd(buf, PATH_MAX); + + assert(ret); + assert((strlen(ret) == strlen(buf)) && strlen(ret)); + assert(!strcmp(ret, buf)); + + char *ret2 = getcwd(NULL, 0); + assert(ret2); + assert(strlen(ret2)); + assert(!strcmp(ret, ret2)); + free(ret2); + + return 0; +} diff --git a/lib/mlibc/tests/posix/getdelim.c b/lib/mlibc/tests/posix/getdelim.c new file mode 100644 index 0000000..bc43ef6 --- /dev/null +++ b/lib/mlibc/tests/posix/getdelim.c @@ -0,0 +1,90 @@ +#include +#include +#include +#include +#include + +#ifdef USE_HOST_LIBC +#define TEST_FILE "getdelim-host-libc.tmp" +#else +#define TEST_FILE "getdelim.tmp" +#endif + +int main(void) { + FILE *fp; + char *line = NULL; + size_t len = 0; + ssize_t read; + + // We have to open the file for writing and then reading separately, + // as mlibc doesn't allow us to do both at the same time (yet). + fp = fopen(TEST_FILE, "w"); + assert(fp); + fputs("foo\nbar\nbaz\nquux\n", fp); + fclose(fp); + + fp = fopen(TEST_FILE, "r"); + assert(fp); + while ((read = getline(&line, &len, fp)) != -1) { + printf("read line of length %zd, capacity %zu\n", read, len); + } + assert(!ferror(fp)); + free(line); + fclose(fp); + + size_t nchars = 10000; + fp = fopen(TEST_FILE, "w"); + assert(fp); + for (size_t i = 0; i < nchars; i++) + fputc('a', fp); + fputc('b', fp); + fclose(fp); + + line = NULL; + len = 0; + fp = fopen(TEST_FILE, "r"); + assert(fp); + while ((read = getdelim(&line, &len, 'b', fp)) != -1) { + printf("read line of length %zd, capacity %zu\n", read, len); + assert((size_t)read == nchars + 1); + } + + assert(len > nchars + 1); + assert(!ferror(fp)); + assert(feof(fp)); + + assert(getdelim(&line, &len, 'b', fp) == -1); + assert(feof(fp)); + + free(line); + fclose(fp); + + fp = fopen(TEST_FILE, "w"); + assert(fp); + assert(fwrite("1234ef\0f", 1, 8, fp) == 8); + fclose(fp); + + fp = fopen(TEST_FILE, "r"); + assert(fp); + + /* test with line = NULL and large len */ + line = NULL; + len = (size_t) ~0; + assert(getdelim(&line, &len, 'e', fp) == 5); + assert(!memcmp(line, "1234e", 6)); + assert(5 < len); + + /* test handling of internal nulls */ + assert(getdelim(&line, &len, 'e', fp) == 3); + assert(!memcmp(line, "f\0f", 4)); + assert(3 < len); + + /* test handling of EOF */ + assert(getdelim(&line, &len, 'e', fp) == -1); + + free(line); + fclose(fp); + + // Delete the file + unlink(TEST_FILE); +} diff --git a/lib/mlibc/tests/posix/getnameinfo.c b/lib/mlibc/tests/posix/getnameinfo.c new file mode 100644 index 0000000..d22a0eb --- /dev/null +++ b/lib/mlibc/tests/posix/getnameinfo.c @@ -0,0 +1,22 @@ +#include +#include +#include +#include +#include + +int main() { + struct sockaddr_in addr; + addr.sin_family = AF_INET; + assert(inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr)); + + char host[64]; + assert(!getnameinfo((struct sockaddr*)&addr, sizeof(addr), host, + sizeof(host), NULL, 0, 0)); + + assert(inet_pton(AF_INET, "8.8.8.8", &addr.sin_addr)); + + assert(!getnameinfo((struct sockaddr*)&addr, sizeof(addr), host, + sizeof(host), NULL, 0, 0)); + assert(!strcmp(host, "dns.google")); + return 0; +} diff --git a/lib/mlibc/tests/posix/getservbyname.c b/lib/mlibc/tests/posix/getservbyname.c new file mode 100644 index 0000000..8c51710 --- /dev/null +++ b/lib/mlibc/tests/posix/getservbyname.c @@ -0,0 +1,27 @@ +#include +#include +#include +#include + +int main() { + struct servent *ret = getservbyname("http", "tcp"); + assert(ret); + assert(!strcmp("http", ret->s_name)); + assert(ret->s_port == htons(80)); + assert(!strcmp("tcp", ret->s_proto)); + + ret = getservbyname("http", NULL); + assert(ret); + assert(!strcmp("http", ret->s_name)); + assert(ret->s_port == htons(80)); + assert(!strcmp("tcp", ret->s_proto)); + + ret = getservbyname("babel", "udp"); + assert(ret); + ret = getservbyname("babel", "tcp"); + assert(!ret); + + ret = getservbyname("", NULL); + assert(!ret); + return 0; +} diff --git a/lib/mlibc/tests/posix/getservbyport.c b/lib/mlibc/tests/posix/getservbyport.c new file mode 100644 index 0000000..f522d71 --- /dev/null +++ b/lib/mlibc/tests/posix/getservbyport.c @@ -0,0 +1,28 @@ +#include +#include +#include +#include +#include + +int main() { + struct servent *ret = getservbyport(htons(80), "tcp"); + assert(ret); + assert(!strcmp("http", ret->s_name)); + assert(ret->s_port == htons(80)); + assert(!strcmp("tcp", ret->s_proto)); + + ret = getservbyport(htons(80), NULL); + assert(ret); + assert(!strcmp("http", ret->s_name)); + assert(ret->s_port == htons(80)); + assert(!strcmp("tcp", ret->s_proto)); + + ret = getservbyport(htons(6696), "udp"); + assert(ret); + ret = getservbyport(htons(6696), "tcp"); + assert(!ret); + + ret = getservbyport(htons(0), NULL); + assert(!ret); + return 0; +} diff --git a/lib/mlibc/tests/posix/grp.c b/lib/mlibc/tests/posix/grp.c new file mode 100644 index 0000000..3d334fe --- /dev/null +++ b/lib/mlibc/tests/posix/grp.c @@ -0,0 +1,110 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +void check_root_group(struct group *grp) { + assert(grp); + + printf("group name: %s\n", grp->gr_name); + fflush(stdout); + + assert(grp->gr_gid == 0); + assert(!strcmp(grp->gr_name, "root")); + + // Depending on your system, the root group may or may not contain the root user. + if (grp->gr_mem[0] != NULL) { + bool found = false; + for (size_t i = 0; grp->gr_mem[i] != NULL; i++) { + printf("group member: %s\n", grp->gr_mem[i]); + fflush(stdout); + + if (!strcmp(grp->gr_mem[i], "root")) { + found = true; + break; + } + } + assert(found); + } +} + +int main() +{ + struct group grp, *result = NULL; + char *buf; + size_t bufsize; + int s; + bool password = false; + + bufsize = sysconf(_SC_GETGR_R_SIZE_MAX); + assert(bufsize > 0 && bufsize < 0x100000); + + buf = malloc(bufsize); + assert(buf); + + s = getgrnam_r("root", &grp, buf, bufsize, &result); + assert(!s); + check_root_group(result); + + s = getgrgid_r(0, &grp, buf, bufsize, &result); + assert(!s); + check_root_group(result); + + result = getgrnam("root"); + check_root_group(result); + + result = getgrgid(0); + check_root_group(result); + + result = getgrnam("this_group_doesnt_exist"); + assert(!result); +#ifndef USE_HOST_LIBC + // This is not guaranteed. + assert(errno == ESRCH); +#endif + + s = getgrnam_r("this_group_doesnt_exist", &grp, buf, bufsize, &result); + assert(!result); +#ifndef USE_HOST_LIBC + // This is not guaranteed. + assert(s == ESRCH); +#endif + + errno = 0; + setgrent(); + assert(errno == 0); + + result = getgrent(); + assert(result); + grp.gr_name = strdup(result->gr_name); + if(result->gr_passwd) { + password = true; + } + grp.gr_passwd = strdup(result->gr_passwd); + grp.gr_gid = result->gr_gid; + assert(grp.gr_name); + if(password) + assert(grp.gr_passwd); + + assert(grp.gr_name); + if(password) + assert(grp.gr_passwd); + + endgrent(); + + result = getgrent(); + assert(result); + assert(strcmp(result->gr_name, grp.gr_name) == 0); + if(password) + assert(strcmp(result->gr_passwd, grp.gr_passwd) == 0); + assert(result->gr_gid == grp.gr_gid); + + free(grp.gr_name); + if(password) + free(grp.gr_passwd); + free(buf); +} diff --git a/lib/mlibc/tests/posix/if_indextoname.c b/lib/mlibc/tests/posix/if_indextoname.c new file mode 100644 index 0000000..15dc12a --- /dev/null +++ b/lib/mlibc/tests/posix/if_indextoname.c @@ -0,0 +1,11 @@ +#include +#include +#include + +int main() { + char name[IF_NAMESIZE]; + + assert(name == if_indextoname(1, name)); + printf("test: name '%s'\n", name); + assert(1 == if_nametoindex(name)); +} diff --git a/lib/mlibc/tests/posix/index.c b/lib/mlibc/tests/posix/index.c new file mode 100644 index 0000000..63be75d --- /dev/null +++ b/lib/mlibc/tests/posix/index.c @@ -0,0 +1,20 @@ +#include +#include +#include + +int main() { + char str[] = "This is a sample string"; + char *pch; + // The character 's' is at position 4, 7, 11 and 18 + pch = index(str, 's'); + assert(pch - str + 1 == 4); + pch = index(pch + 1, 's'); + assert(pch - str + 1 == 7); + pch = index(pch + 1, 's'); + assert(pch - str + 1 == 11); + pch = index(pch + 1, 's'); + assert(pch - str + 1 == 18); + pch = index(pch + 1, 's'); + assert(pch == NULL); + return 0; +} diff --git a/lib/mlibc/tests/posix/inet_ntop.c b/lib/mlibc/tests/posix/inet_ntop.c new file mode 100644 index 0000000..feca26c --- /dev/null +++ b/lib/mlibc/tests/posix/inet_ntop.c @@ -0,0 +1,30 @@ +#include +#include +#include +#include + +int main() { + struct in_addr addr; + addr.s_addr = (1 << 24) | + (1 << 16) | (1 << 8) | 1; + char buf[INET_ADDRSTRLEN]; + assert(inet_ntop(AF_INET, &addr, buf, INET_ADDRSTRLEN) != NULL); + assert(strncmp("1.1.1.1", buf, INET_ADDRSTRLEN) == 0); + + struct in6_addr addr2 = { .s6_addr = {0x20, 0x1, 0xd, 0xb8, 0, 0, 0, 0, 0, 0x1, 0, 0, 0, 0, 0, 0x1} }; + char buf2[INET6_ADDRSTRLEN]; + assert(inet_ntop(AF_INET6, &addr2, buf2, INET6_ADDRSTRLEN) != NULL); + assert(strncmp("2001:db8::1:0:0:1", buf2, INET6_ADDRSTRLEN) == 0); + + struct in6_addr addr3 = { .s6_addr = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1} }; + char buf3[INET6_ADDRSTRLEN]; + assert(inet_ntop(AF_INET6, &addr3, buf3, INET6_ADDRSTRLEN) != NULL); + assert(strncmp("::1", buf3, INET6_ADDRSTRLEN) == 0); + + struct in6_addr addr4 = { .s6_addr = {0x20, 0x1, 0xd, 0xb8, 00, 00, 00, 0x1, 00, 0x1, 00, 0x1, 00, 0x1, 00, 0x1} }; + char buf4[INET6_ADDRSTRLEN]; + assert(inet_ntop(AF_INET6, &addr4, buf4, INET6_ADDRSTRLEN) != NULL); + assert(strncmp("2001:db8:0:1:1:1:1:1", buf4, INET6_ADDRSTRLEN) == 0); + + return 0; +} diff --git a/lib/mlibc/tests/posix/inet_pton.c b/lib/mlibc/tests/posix/inet_pton.c new file mode 100644 index 0000000..6c0f342 --- /dev/null +++ b/lib/mlibc/tests/posix/inet_pton.c @@ -0,0 +1,16 @@ +#include +#include + +int main() { + struct in_addr addr; + assert(inet_pton(AF_INET, "1.1.1.1", &addr)); + assert((addr.s_addr & 0xFF) == 1); + assert(((addr.s_addr >> 8) & 0xFF) == 1); + assert(((addr.s_addr >> 16) & 0xFF) == 1); + assert(((addr.s_addr >> 24) & 0xFF) == 1); + + assert(!inet_pton(AF_INET, "256.999.1234.555", &addr)); + assert(!inet_pton(AF_INET, "a.b.c.d", &addr)); + return 0; +} + diff --git a/lib/mlibc/tests/posix/memrchr.c b/lib/mlibc/tests/posix/memrchr.c new file mode 100644 index 0000000..99e3e25 --- /dev/null +++ b/lib/mlibc/tests/posix/memrchr.c @@ -0,0 +1,25 @@ +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif +#include +#include +#include + +int main () { + char str[] = "The Last Supper by Leonardo da Vinci"; + char *str_temp; + + // Test strstr + str_temp = strstr(str, "Supper"); /* Find a substring in the string */ + assert(!strcmp(str_temp, "Supper by Leonardo da Vinci")); + + /* Following calls use memory APIs for the above tasks */ + // Test memchr + str_temp = (char *)memchr((void *)str, 'L', strlen(str)); + assert(!strcmp(str_temp, "Last Supper by Leonardo da Vinci")); + + // Test memrchr + str_temp = (char *)memrchr((void *)str, 'L', strlen(str)); + assert(!strcmp(str_temp, "Leonardo da Vinci")); + return 0; +} diff --git a/lib/mlibc/tests/posix/mkstemp.c b/lib/mlibc/tests/posix/mkstemp.c new file mode 100644 index 0000000..d06783e --- /dev/null +++ b/lib/mlibc/tests/posix/mkstemp.c @@ -0,0 +1,70 @@ +#include +#include +#include +#include +#include +#include +#include + +void validate_pattern(char *p) { + assert(memcmp(p, "XXXXXX", 6)); + assert(memchr(p, 0, 6) == NULL); + + for (int i = 0; i < 6; i++) { + assert(isalnum(p[i])); + } +} + +int main() { + int ret; + + // Make sure the patterns themselves cannot be chosen. This + // *could* happen on glibc, or if we widen the character set + // used for generating random names. Odds are 1 in 60 billion, + // but I'd rather not worry about this. + ret = open("prefixXXXXXX", O_RDWR | O_CREAT | O_EXCL, 0600); + assert(ret >= 0 || (ret == -1 && errno == EEXIST)); + ret = open("longprefixXXXXXXlongsuffix", O_RDWR | O_CREAT | O_EXCL, 0600); + assert(ret >= 0 || (ret == -1 && errno == EEXIST)); + + ret = mkstemp("short"); + assert(ret == -1); + assert(errno == EINVAL); + + ret = mkstemp("lessthan6XXX"); + assert(ret == -1); + assert(errno == EINVAL); + + ret = mkstemps("lessthan6XXXswithsuffix", 11); + assert(ret == -1); + assert(errno == EINVAL); + + char *p = strdup("prefixXXXXXX"); + ret = mkstemp(p); + // We can't really protect against EEXIST... + assert(ret >= 0 || (ret == -1 && errno == EEXIST)); + assert(!memcmp(p, "prefix", 6)); + assert(p[12] == 0); + validate_pattern(p + 6); + + if (ret >= 0) { + ret = close(ret); + assert(!ret); + } + free(p); + + p = strdup("longprefixXXXXXXlongsuffix"); + ret = mkstemps(p, 10); + // We can't really protect against EEXIST... + assert(ret >= 0 || (ret == -1 && errno == EEXIST)); + assert(!memcmp(p, "longprefix", 10)); + assert(!memcmp(p + 16, "longsuffix", 10)); + assert(p[26] == 0); + validate_pattern(p + 10); + + if (ret >= 0) { + ret = close(ret); + assert(!ret); + } + free(p); +} diff --git a/lib/mlibc/tests/posix/open_memstream.c b/lib/mlibc/tests/posix/open_memstream.c new file mode 100644 index 0000000..0347003 --- /dev/null +++ b/lib/mlibc/tests/posix/open_memstream.c @@ -0,0 +1,65 @@ +#include +#include +#include + +#define WRITE_NO 1024 + +int main() { + size_t size; + char *buf; + + FILE *fp = open_memstream(&buf, &size); + assert(fp); + + char c = 'A'; + for (size_t i = 0; i < WRITE_NO; i++) + assert(fwrite(&c, sizeof(char), 1, fp) == 1); + + // Flush the file to update the pointers. + assert(!fflush(fp)); + + assert(size == WRITE_NO); + for (size_t i = 0; i < size; i++) + assert(buf[i] == c); + + // Check if the stream maintains a null-bye at the end. + assert(buf[size] == '\0'); + + // Stream should be expanded, size should be == 2*WRITE_NO. + assert(!fseek(fp, WRITE_NO, SEEK_END)); + assert(!fflush(fp)); + assert(size == 2*WRITE_NO); + assert(buf[size] == '\0'); + + // Check if it's filled with zero's. + for (size_t i = WRITE_NO; i < size; i++) + assert(buf[i] == '\0'); + + // Go back and overwrite the 0's with 'B'. + assert(!fseek(fp, -WRITE_NO, SEEK_CUR)); + c = 'B'; + for (size_t i = 0; i < WRITE_NO; i++) + assert(fwrite(&c, sizeof(char), 1, fp) == 1); + + // Check if that happened. + assert(size == 2*WRITE_NO); + for (size_t i = WRITE_NO; i < size; i++) + assert(buf[i] == c); + assert(buf[size] == '\0'); + + // Go to the front and write 'B'. + assert(!fseek(fp, 0, SEEK_SET)); + for (size_t i = 0; i < WRITE_NO; i++) + assert(fwrite(&c, sizeof(char), 1, fp) == 1); + + // Check if that happened. + assert(size == 2*WRITE_NO); + for (size_t i = 0; i < size; i++) + assert(buf[i] == c); + assert(buf[size] == '\0'); + + // Close the file, we have tested everything. + assert(!fclose(fp)); + free(buf); + return 0; +} diff --git a/lib/mlibc/tests/posix/pause.c b/lib/mlibc/tests/posix/pause.c new file mode 100644 index 0000000..054c5a4 --- /dev/null +++ b/lib/mlibc/tests/posix/pause.c @@ -0,0 +1,49 @@ +#include +#include +#include +#include +#include +#include +#include + +static void noop(int x) { + (void)x; +} + +int main() { + signal(SIGUSR1, &noop); + + int pid; + switch(pid = fork()) { + case -1: + perror("fork"); + abort(); + case 0: + pause(); + assert(errno == EINTR); + return 0; + default: + while (1) { + usleep(100); + kill(pid, SIGUSR1); + usleep(100); + int status; + + errno = 0; + if (waitpid(-1, &status, WNOHANG) <= 0) { + if (errno && errno != EAGAIN) { + perror("wait"); + kill(pid, SIGKILL); + } + continue; + } + + if (!WIFEXITED(status)) { + printf("wait returned %x\n", status); + abort(); + } + + return WEXITSTATUS(status); + } + } +} diff --git a/lib/mlibc/tests/posix/popen.c b/lib/mlibc/tests/posix/popen.c new file mode 100644 index 0000000..87bbde2 --- /dev/null +++ b/lib/mlibc/tests/posix/popen.c @@ -0,0 +1,42 @@ +#include +#include +#include +#include + +#ifdef USE_HOST_LIBC +#define TEST_FILE "popen-host-libc.tmp" +#else +#define TEST_FILE "popen.tmp" +#endif + +#define TEST_STRING1 "the quick brown fox jumps over the lazy dog" +#define TEST_STRING1_LEN 43 +#define TEST_STRING2 "Lorem ipsum dolor sit amet, consectetur adipiscing elit" +#define TEST_STRING2_LEN 55 + +int main() { + // Test reading + FILE *f1 = popen("echo -n '" TEST_STRING1 "'", "r"); + assert(f1); + char buf1[TEST_STRING1_LEN]; + assert(fread(buf1, 1, TEST_STRING1_LEN, f1) == TEST_STRING1_LEN); + assert(memcmp(buf1, TEST_STRING1, TEST_STRING1_LEN) == 0); + pclose(f1); + + // Test writing + FILE *f2 = popen("cat - > " TEST_FILE, "w"); + assert(f2); + assert(fwrite(TEST_STRING2, 1, TEST_STRING2_LEN, f2) == TEST_STRING2_LEN); + pclose(f2); + + // Read test file back + FILE *test_file = fopen(TEST_FILE, "r"); + assert(test_file); + char buf2[TEST_STRING2_LEN]; + assert(fread(buf2, 1, TEST_STRING2_LEN, test_file) == TEST_STRING2_LEN); + assert(memcmp(buf2, TEST_STRING2, TEST_STRING2_LEN) == 0); + fclose(test_file); + assert(unlink(TEST_FILE) == 0); + + return 0; +} diff --git a/lib/mlibc/tests/posix/posix-timer.c b/lib/mlibc/tests/posix/posix-timer.c new file mode 100644 index 0000000..d097818 --- /dev/null +++ b/lib/mlibc/tests/posix/posix-timer.c @@ -0,0 +1,47 @@ +#include +#include +#include +#include +#include +#include +#include + +int main() { + struct sigevent evp; + memset(&evp, 0, sizeof(evp)); + + sigset_t set; + sigemptyset(&set); + sigaddset(&set, SIGUSR1); + sigprocmask(SIG_BLOCK, &set, 0); + evp.sigev_notify = SIGEV_SIGNAL; + evp.sigev_signo = SIGUSR1; + + struct timeval start; + gettimeofday(&start, NULL); + + timer_t timer; + if (timer_create(CLOCK_MONOTONIC, &evp, &timer)) { + perror("timer_create"); + exit(1); + } + + struct itimerspec spec; + memset(&spec, 0, sizeof(spec)); + spec.it_value.tv_sec = 1; + spec.it_value.tv_nsec = 0; + + int sig; + timer_settime(timer, 0, &spec, NULL); + sigwait(&set, &sig); + + struct timeval end; + gettimeofday(&end, NULL); + timer_delete(timer); + + double diff = end.tv_sec - start.tv_sec; + diff += (end.tv_usec - start.tv_usec) / 1000000.0; + assert(diff >= 1.0); + + return 0; +} diff --git a/lib/mlibc/tests/posix/posix_memalign.c b/lib/mlibc/tests/posix/posix_memalign.c new file mode 100644 index 0000000..34652b9 --- /dev/null +++ b/lib/mlibc/tests/posix/posix_memalign.c @@ -0,0 +1,21 @@ +#include +#include +#include +#include + +int main() { + void *p = NULL; + + // align must be a power of two + assert(posix_memalign(&p, 3, 1) == EINVAL && p == NULL); + + // align must be a multiple of sizeof(void *) + assert(posix_memalign(&p, sizeof(void *) / 2, 8) == EINVAL && p == NULL); + + assert(posix_memalign(&p, sizeof(void *), sizeof(void *)) == 0 && p != NULL && (uintptr_t)p % sizeof(void *) == 0); + free(p); + assert(posix_memalign(&p, 256, 1) == 0 && p != NULL && (uintptr_t)p % 256 == 0); + free(p); + assert(posix_memalign(&p, 256, 256) == 0 && p != NULL && (uintptr_t)p % 256 == 0); + free(p); +} diff --git a/lib/mlibc/tests/posix/posix_spawn.c b/lib/mlibc/tests/posix/posix_spawn.c new file mode 100644 index 0000000..cc5ccff --- /dev/null +++ b/lib/mlibc/tests/posix/posix_spawn.c @@ -0,0 +1,38 @@ +#include +#include +#include +#include + +#include +#include +#include + +extern char **environ; + +void run_cmd(char *cmd) +{ + pid_t pid; + char *argv[] = {"sh", "-c", cmd, NULL}; + int status; + printf("Run command: %s\n", cmd); + status = posix_spawn(&pid, "/bin/sh", NULL, NULL, argv, environ); + if(status == 0) { + printf("Child pid: %i\n", pid); + if(waitpid(pid, &status, 0) != -1) { + printf("Child exited with status %i\n", status); + printf("Child exit status: %i\n", WEXITSTATUS(status)); + assert(WEXITSTATUS(status) == 0); + } else { + perror("waitpid"); + assert(0 == 1); + } + } else { + printf("posix_spawn: %s\n", strerror(status)); + assert(0 == 1); + } +} + +int main() { + run_cmd(":"); + return 0; +} diff --git a/lib/mlibc/tests/posix/pthread_atfork.c b/lib/mlibc/tests/posix/pthread_atfork.c new file mode 100644 index 0000000..45be136 --- /dev/null +++ b/lib/mlibc/tests/posix/pthread_atfork.c @@ -0,0 +1,54 @@ +#include +#include +#include +#include +#include +#include +#include + +_Atomic int prepare_order = 0; +_Atomic int parent_order = 0; +_Atomic int child_order = 0; + +static void prepare1() { prepare_order = 1; } +static void prepare2() { prepare_order = 2; } + +static void parent1() { parent_order = 1; } +static void parent2() { parent_order = 2; } + +static void child1() { child_order = 1; } +static void child2() { child_order = 2; } + +int main() { + assert(!pthread_atfork(prepare1, parent1, child1)); + assert(!pthread_atfork(prepare2, parent2, child2)); + + pid_t pid = fork(); + assert(pid >= 0); + + if (!pid) { + assert(child_order == 2); + exit(0); + } else { + assert(prepare_order == 1); + assert(parent_order == 2); + + while (1) { + int status = 0; + + int ret = waitpid(pid, &status, 0); + + if (ret == -1 && errno == EINTR) + continue; + + assert(ret > 0); + + if (WIFSIGNALED(status) && WTERMSIG(status) == SIGABRT) + return 1; + + return WEXITSTATUS(status); + } + } + + return 0; +} diff --git a/lib/mlibc/tests/posix/pthread_attr.c b/lib/mlibc/tests/posix/pthread_attr.c new file mode 100644 index 0000000..c901a90 --- /dev/null +++ b/lib/mlibc/tests/posix/pthread_attr.c @@ -0,0 +1,157 @@ +#include +#include +#include +#include +#include +#include +#include + +static void test_detachstate() { + pthread_attr_t attr; + assert(!pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED)); + int detachstate; + assert(!pthread_attr_getdetachstate(&attr, &detachstate)); + assert(detachstate == PTHREAD_CREATE_DETACHED); + assert(pthread_attr_setdetachstate(&attr, 2* (PTHREAD_CREATE_DETACHED + + PTHREAD_CREATE_JOINABLE)) == EINVAL); +} + +static void *stacksize_worker(void *arg) { + size_t default_stacksize = (*(size_t*)arg); + size_t alloc_size = default_stacksize + default_stacksize/2; + void *area = alloca(alloc_size); + // If the allocated stack was not enough this will crash. + *(volatile int*)(area + alloc_size) = 1; + return NULL; +} + +static void test_stacksize() { + pthread_attr_t attr; + assert(!pthread_attr_init(&attr)); + size_t stacksize; + assert(!pthread_attr_getstacksize(&attr, &stacksize)); + assert(!pthread_attr_setstacksize(&attr, stacksize * 2)); + pthread_t thread; + assert(!pthread_create(&thread, &attr, stacksize_worker, &stacksize)); + assert(!pthread_join(thread, NULL)); +} + +static void test_guardsize() { + pthread_attr_t attr; + assert(!pthread_attr_init(&attr)); + assert(!pthread_attr_setguardsize(&attr, 0)); + size_t guardsize; + assert(!pthread_attr_getguardsize(&attr, &guardsize)); + assert(!guardsize); +} + +static void test_scope() { + pthread_attr_t attr; + assert(!pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM)); + int scope; + assert(!pthread_attr_getscope(&attr, &scope)); + assert(scope == PTHREAD_SCOPE_SYSTEM); + assert(pthread_attr_setscope(&attr, 2* (PTHREAD_SCOPE_SYSTEM + + PTHREAD_SCOPE_PROCESS)) == EINVAL); +} + +static void test_inheritsched() { + pthread_attr_t attr; + assert(!pthread_attr_setinheritsched(&attr, PTHREAD_INHERIT_SCHED)); + int inheritsched; + assert(!pthread_attr_getinheritsched(&attr, &inheritsched)); + assert(inheritsched == PTHREAD_INHERIT_SCHED); + assert(pthread_attr_setinheritsched(&attr, 2* (PTHREAD_INHERIT_SCHED + + PTHREAD_EXPLICIT_SCHED)) == EINVAL); +} + +static void test_schedparam() { + pthread_attr_t attr; + struct sched_param init_param = {0}; + assert(!pthread_attr_setschedparam(&attr, &init_param)); + struct sched_param param = {1}; + assert(!pthread_attr_getschedparam(&attr, ¶m)); + assert(param.sched_priority == init_param.sched_priority); +} + +static void test_schedpolicy() { + pthread_attr_t attr; + assert(!pthread_attr_setschedpolicy(&attr, SCHED_FIFO)); + int policy; + assert(!pthread_attr_getschedpolicy(&attr, &policy)); + assert(policy == SCHED_FIFO); + assert(pthread_attr_setinheritsched(&attr, 2* (SCHED_FIFO + SCHED_RR + + SCHED_OTHER)) == EINVAL); +} + +static void *stackaddr_worker(void *arg) { + void *addr = *(void**)arg; + + void *sp; +#if defined(__x86_64__) + asm volatile ("mov %%rsp, %0" : "=r"(sp)); +#elif defined(__i386__) + asm volatile ("mov %%esp, %0" : "=r"(sp)); +#elif defined(__aarch64__) + asm volatile ("mov %0, sp" : "=r"(sp)); +#elif defined (__riscv) + asm volatile ("mv %0, sp" : "=r"(sp)); +#else +# error Unknown architecture +#endif + + // Check if our stack pointer is in a sane range. + assert(sp > addr); + return NULL; +} +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" +static void test_stackaddr() { + pthread_attr_t attr; + assert(!pthread_attr_init(&attr)); + size_t size; + assert(!pthread_attr_getstacksize(&attr, &size)); + void *addr = mmap(NULL, size, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + assert(!pthread_attr_setstack(&attr, addr, size)); + assert(!pthread_attr_setguardsize(&attr, 0)); + void *new_addr; + size_t new_size; + assert(!pthread_attr_getstack(&attr, &new_addr, &new_size)); + assert(new_addr == addr); + assert(new_size == size); + + pthread_t thread; + assert(!pthread_create(&thread, &attr, stackaddr_worker, &addr)); + assert(!pthread_join(thread, NULL)); +} +#pragma GCC diagnostic pop + +#if !defined(USE_HOST_LIBC) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 32) +static void test_stack() { + pthread_attr_t attr; + void *stackaddr = (void*)1; + size_t stacksize = PTHREAD_STACK_MIN; + + assert(!pthread_attr_setstack(&attr, stackaddr, stacksize)); + void *new_addr; + size_t new_size; + assert(!pthread_attr_getstack(&attr, &new_addr, &new_size)); + assert(new_addr == stackaddr); + assert(new_size == stacksize); +} +#endif + +int main() { + test_detachstate(); + test_stacksize(); + test_guardsize(); + test_scope(); + test_inheritsched(); + test_schedparam(); + test_schedpolicy(); + test_stackaddr(); +#if !defined(USE_HOST_LIBC) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 32) + test_stack(); +#endif +} diff --git a/lib/mlibc/tests/posix/pthread_barrier.c b/lib/mlibc/tests/posix/pthread_barrier.c new file mode 100644 index 0000000..213ba8f --- /dev/null +++ b/lib/mlibc/tests/posix/pthread_barrier.c @@ -0,0 +1,56 @@ +#include +#include +#include + +pthread_barrier_t barrier; +_Atomic int hitBarrierCount, pastBarrierCount; + +static void *worker(void *arg) { + (void)arg; + hitBarrierCount++; + pthread_barrier_wait(&barrier); + pastBarrierCount++; + return NULL; +} + +int main() { + // pthread_barrierattr_t + pthread_barrierattr_t attr; + pthread_barrierattr_init(&attr); + + int pshared; + pthread_barrierattr_getpshared(&attr, &pshared); + assert(pshared == PTHREAD_PROCESS_PRIVATE); + + pthread_barrierattr_setpshared(&attr, PTHREAD_PROCESS_SHARED); + pthread_barrierattr_getpshared(&attr, &pshared); + assert(pshared == PTHREAD_PROCESS_SHARED); + + pthread_barrierattr_setpshared(&attr, PTHREAD_PROCESS_PRIVATE); + pthread_barrierattr_getpshared(&attr, &pshared); + assert(pshared == PTHREAD_PROCESS_PRIVATE); + + // pthread_barrier_t + pthread_barrier_init(&barrier, &attr, 3); + pthread_barrierattr_destroy(&attr); + + pthread_t thread1; + int ret = pthread_create(&thread1, NULL, &worker, NULL); + assert(!ret); + + pthread_t thread2; + ret = pthread_create(&thread2, NULL, &worker, NULL); + assert(!ret); + + sleep(1); + + // Make sure the barrier actually stops threads from proceeding. + assert(pastBarrierCount == 0); + assert(hitBarrierCount <= 2); + + hitBarrierCount++; + pthread_barrier_wait(&barrier); + assert(hitBarrierCount == 3); + + pthread_barrier_destroy(&barrier); +} diff --git a/lib/mlibc/tests/posix/pthread_cancel.c b/lib/mlibc/tests/posix/pthread_cancel.c new file mode 100644 index 0000000..ca4ca34 --- /dev/null +++ b/lib/mlibc/tests/posix/pthread_cancel.c @@ -0,0 +1,150 @@ +#include +#include +#include + +_Atomic int worker_ready = 0; +_Atomic int main_ready = 0; + +static void *worker1(void *arg) { + (void)arg; + assert(!pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL)); + assert(!pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL)); + + worker_ready = 1; + + while (1) sleep(1); + + return NULL; +} + +static void *worker2(void *arg) { + (void) arg; + assert(!pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL)); + + worker_ready = 1; + + while(!main_ready); + + // Cancellation point - we should cancel right now + sleep(1); + + assert(!"Expected to be cancelled!"); + __builtin_unreachable(); +} + +static void *worker3(void *arg) { + (void) arg; + assert(!pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL)); + + worker_ready = 1; + + while(!main_ready); + + // Cancellation point - we should cancel right now + pthread_testcancel(); + + assert(!"Expected to be cancelled!"); + __builtin_unreachable(); +} + +static void *worker4(void *arg) { + (void) arg; + assert(!pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL)); + + worker_ready = 1; + sleep(1); + + // We expect to be canceled during the sleep + + assert(!"Expected to be cancelled!"); + __builtin_unreachable(); +} + +static void *worker5(void *arg) { + assert(!pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL)); + + worker_ready = 1; + + while(!main_ready); + + // Cancellation point - we should NOT cancel right now + pthread_testcancel(); + + int *arg_int = (int*)arg; + *arg_int = 1; + + return NULL; +} + +static void check_result(pthread_t thread) { + + void *ret_val = NULL; + int ret = pthread_join(thread, &ret_val); + assert(!ret); + assert(ret_val == PTHREAD_CANCELED); +} + +int main() { + pthread_t thread; + int ret = pthread_create(&thread, NULL, &worker1, NULL); + assert(!ret); + + while (!worker_ready); + ret = pthread_cancel(thread); + assert(!ret); + check_result(thread); + + main_ready = 0; + worker_ready = 0; + main_ready = 0; + ret = pthread_create(&thread, NULL, &worker2, NULL); + assert(!ret); + + while(!worker_ready); + ret = pthread_cancel(thread); + assert(!ret); + main_ready = 1; + check_result(thread); + + main_ready = 0; + worker_ready = 0; + main_ready = 0; + ret = pthread_create(&thread, NULL, &worker3, NULL); + assert(!ret); + + while(!worker_ready); + ret = pthread_cancel(thread); + assert(!ret); + main_ready = 1; + check_result(thread); + + worker_ready = 0; + main_ready = 0; + ret = pthread_create(&thread, NULL, &worker4, NULL); + assert(!ret); + + while(!worker_ready); + ret = pthread_cancel(thread); + assert(!ret); + main_ready = 1; + check_result(thread); + + // Test for bug where pthread_testcancel() was not checking if + // cancellation was triggered properly. + worker_ready = 0; + int pthread_arg = 0; + main_ready = 0; + ret = pthread_create(&thread, NULL, &worker5, &pthread_arg); + assert(!ret); + + while(!worker_ready); + main_ready = 1; + + void *ret_val = NULL; + ret = pthread_join(thread, &ret_val); + assert(!ret); + assert(!ret_val); + assert(pthread_arg == 1); + + return 0; +} diff --git a/lib/mlibc/tests/posix/pthread_cleanup.c b/lib/mlibc/tests/posix/pthread_cleanup.c new file mode 100644 index 0000000..b6136aa --- /dev/null +++ b/lib/mlibc/tests/posix/pthread_cleanup.c @@ -0,0 +1,42 @@ +#include +#include +#include + +_Atomic uintptr_t cleanup_val = 0; + +static void cleanup(void *arg) { + cleanup_val = (uintptr_t)arg; +} + +static void *worker(void *arg) { + (void)arg; + + pthread_cleanup_push(cleanup, (void *)1); + pthread_cleanup_push(cleanup, (void *)2); + pthread_cleanup_push(cleanup, (void *)3); + pthread_cleanup_push(cleanup, (void *)4); + + pthread_cleanup_pop(1); + assert(cleanup_val == 4); + + pthread_cleanup_pop(0); + assert(cleanup_val == 4); + + pthread_exit(NULL); + + pthread_cleanup_pop(0); + pthread_cleanup_pop(0); + + return NULL; +} + +int main() { + pthread_t thread; + assert(!pthread_create(&thread, NULL, &worker, NULL)); + assert(!pthread_join(thread, NULL)); + + assert(cleanup_val == 1); + + return 0; +} + diff --git a/lib/mlibc/tests/posix/pthread_cond.c b/lib/mlibc/tests/posix/pthread_cond.c new file mode 100644 index 0000000..6203928 --- /dev/null +++ b/lib/mlibc/tests/posix/pthread_cond.c @@ -0,0 +1,106 @@ +#include +#include +#include +#include + +_Atomic int waiting, should_exit; +pthread_cond_t cond = PTHREAD_COND_INITIALIZER; +pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER; + +static void *worker(void *arg) { + (void)arg; + pthread_mutex_lock(&mtx); + ++waiting; + while (!should_exit) + pthread_cond_wait(&cond, &mtx); + pthread_mutex_unlock(&mtx); + return NULL; +} + +static void test_broadcast_wakes_all() { + pthread_t t1, t2; + pthread_create(&t1, NULL, &worker, NULL); + pthread_create(&t2, NULL, &worker, NULL); + + // Wait until the workers have actually entered the cond_wait + // before doing a broadcast. + while (waiting != 2 || pthread_mutex_trylock(&mtx) == EBUSY) + usleep(150000); // 150ms + + should_exit = 1; + assert(!pthread_cond_broadcast(&cond)); + pthread_mutex_unlock(&mtx); + + pthread_join(t1, NULL); + pthread_join(t2, NULL); +} + +static void test_timedwait_timedout() { + // Use CLOCK_MONOTONIC. + pthread_condattr_t attr; + pthread_condattr_init(&attr); + assert(!pthread_condattr_setclock(&attr, CLOCK_MONOTONIC)); + + struct timespec before_now; + assert(!clock_gettime(CLOCK_MONOTONIC, &before_now)); + before_now.tv_nsec -= 10000; + + pthread_mutex_lock(&mtx); + int e = pthread_cond_timedwait(&cond, &mtx, &before_now); + assert(e == ETIMEDOUT); + pthread_mutex_unlock(&mtx); + + long nanos_per_second = 1000000000; + struct timespec after_now; + assert(!clock_gettime(CLOCK_MONOTONIC, &after_now)); + after_now.tv_nsec += nanos_per_second / 10; // 100ms + if (after_now.tv_nsec >= nanos_per_second) { + after_now.tv_nsec -= nanos_per_second; + after_now.tv_sec++; + } + + pthread_mutex_lock(&mtx); + e = pthread_cond_timedwait(&cond, &mtx, &after_now); + assert(e == ETIMEDOUT); + pthread_mutex_unlock(&mtx); + + after_now.tv_nsec += nanos_per_second; + pthread_mutex_lock(&mtx); + e = pthread_cond_timedwait(&cond, &mtx, &after_now); + assert(e == EINVAL); + pthread_mutex_unlock(&mtx); +} + +static void test_attr() { + pthread_condattr_t attr; + pthread_condattr_init(&attr); + + clockid_t clock; + assert(!pthread_condattr_getclock(&attr, &clock)); + assert(clock == CLOCK_REALTIME); + assert(!pthread_condattr_setclock(&attr, CLOCK_MONOTONIC)); + assert(!pthread_condattr_getclock(&attr, &clock)); + assert(clock == CLOCK_MONOTONIC); + + int pshared; + assert(!pthread_condattr_getpshared(&attr, &pshared)); + assert(pshared == PTHREAD_PROCESS_PRIVATE); + assert(!pthread_condattr_setpshared(&attr, PTHREAD_PROCESS_SHARED)); + assert(!pthread_condattr_getpshared(&attr, &pshared)); + assert(pshared == PTHREAD_PROCESS_SHARED); + + pthread_condattr_destroy(&attr); + pthread_condattr_init(&attr); + + // Make sure that we can create a pthread_cond_t with an attr. + pthread_cond_t cond; + pthread_cond_init(&cond, &attr); + pthread_cond_destroy(&cond); + pthread_condattr_destroy(&attr); +} + +int main() { + test_attr(); + test_broadcast_wakes_all(); + test_timedwait_timedout(); +} diff --git a/lib/mlibc/tests/posix/pthread_create.c b/lib/mlibc/tests/posix/pthread_create.c new file mode 100644 index 0000000..b78674f --- /dev/null +++ b/lib/mlibc/tests/posix/pthread_create.c @@ -0,0 +1,22 @@ +#include +#include +#include + +int variable = 0; + +static void *worker(void *arg) { + (void) arg; + variable = 1; + return NULL; +} + +int main() { + pthread_t thread; + int ret = pthread_create(&thread, NULL, &worker, NULL); + assert(!ret); + + ret = pthread_join(thread, NULL); + assert(!ret); + assert(variable == 1); + return 0; +} diff --git a/lib/mlibc/tests/posix/pthread_key.c b/lib/mlibc/tests/posix/pthread_key.c new file mode 100644 index 0000000..40bd882 --- /dev/null +++ b/lib/mlibc/tests/posix/pthread_key.c @@ -0,0 +1,95 @@ +#include +#include +#include +#include + +_Atomic int dtors_entered = 0; +pthread_key_t key3; + +static void dtor1(void *arg) { + (void)arg; + dtors_entered++; + + // Set the key during destruction to trigger dtor2 (as it only runs if + // the key value is non-NULL). + assert(!pthread_setspecific(key3, &key3)); + assert(pthread_getspecific(key3) == &key3); +} + +static void dtor2(void *arg) { + (void)arg; + dtors_entered++; +} + +static void *worker1(void *arg) { + (void)arg; + + pthread_key_t key1, key2; + assert(!pthread_key_create(&key1, NULL)); + assert(!pthread_key_create(&key2, dtor1)); + assert(!pthread_key_create(&key3, dtor2)); + + assert(!pthread_setspecific(key1, &key1)); + assert(pthread_getspecific(key1) == &key1); + + assert(!pthread_setspecific(key2, &key2)); + assert(pthread_getspecific(key2) == &key2); + + pthread_exit(0); + return NULL; +} + +static void dtor3(void *arg) { + (void)arg; + + // Make sure that we can create and destroy keys inside the dtor. + pthread_key_t dtorKey; + assert(!pthread_key_create(&dtorKey, NULL)); + + assert(!pthread_setspecific(dtorKey, &dtorKey)); + assert(pthread_getspecific(dtorKey) == &dtorKey); + + assert(!pthread_key_delete(dtorKey)); +} + +static void *worker2(void *arg) { + (void)arg; + + pthread_key_t key; + assert(!pthread_key_create(&key, dtor3)); + + assert(!pthread_setspecific(key, &key)); + assert(pthread_getspecific(key) == &key); + + pthread_exit(0); + return NULL; +} + +int main() { + // NOTE that the EINVAL return from pthread_setspecific is mlibc-specific, + // POSIX specifies that accessing an invalid key is undefined behavior. + + assert(pthread_getspecific(PTHREAD_KEYS_MAX) == NULL); + assert(pthread_setspecific(PTHREAD_KEYS_MAX, NULL) == EINVAL); + + pthread_key_t key; + assert(!pthread_key_create(&key, NULL)); + assert(!pthread_setspecific(key, &key)); + assert(pthread_getspecific(key) == &key); + assert(!pthread_key_delete(key)); + + pthread_t thread; + assert(!pthread_create(&thread, NULL, &worker1, NULL)); + assert(!pthread_join(thread, NULL)); + + assert(pthread_getspecific(key) == NULL); + assert(!pthread_setspecific(key, &key)); + assert(pthread_getspecific(key) == &key); + + assert(dtors_entered == 2); + + assert(!pthread_create(&thread, NULL, &worker2, NULL)); + assert(!pthread_join(thread, NULL)); + + return 0; +} diff --git a/lib/mlibc/tests/posix/pthread_kill.c b/lib/mlibc/tests/posix/pthread_kill.c new file mode 100644 index 0000000..b740b70 --- /dev/null +++ b/lib/mlibc/tests/posix/pthread_kill.c @@ -0,0 +1,46 @@ +#include +#include +#include + +_Atomic int handler_ready = 0; +_Atomic int thread_signal_ran = 0; + +static void sig_handler(int sig, siginfo_t *info, void *ctx) { + (void)sig; + (void)info; + (void)ctx; + + thread_signal_ran = 1; +} + +static void *worker(void *arg) { + (void)arg; + + struct sigaction sa; + sigemptyset(&sa.sa_mask); + sa.sa_sigaction = sig_handler; + sa.sa_flags = SA_SIGINFO; + assert(!sigaction(SIGUSR1, &sa, NULL)); + + handler_ready = 1; + + while (!thread_signal_ran) + ; + + return NULL; +} + +int main() { + pthread_t thread; + assert(!pthread_create(&thread, NULL, &worker, NULL)); + + while (!handler_ready) + ; + + assert(!pthread_kill(thread, SIGUSR1)); + assert(!pthread_join(thread, NULL)); + + assert(thread_signal_ran); + + return 0; +} diff --git a/lib/mlibc/tests/posix/pthread_mutex.c b/lib/mlibc/tests/posix/pthread_mutex.c new file mode 100644 index 0000000..0a9b82f --- /dev/null +++ b/lib/mlibc/tests/posix/pthread_mutex.c @@ -0,0 +1,101 @@ +#include +#include +#include + +#define TEST_ATTR(attr, field, value) ({ \ + int x; \ + assert(!pthread_mutexattr_set ## field (&(attr), (value))); \ + assert(!pthread_mutexattr_get ## field (&(attr), &x)); \ + assert(x == (value)); \ + }) + +int variable; +pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; + +static void *worker(void *arg) { + (void)arg; + pthread_mutex_lock(&mutex); + variable = 1; + pthread_mutex_unlock(&mutex); + return NULL; +} + +static void testAttr() { + pthread_mutexattr_t attr; + pthread_mutexattr_init(&attr); + + TEST_ATTR(attr, type, PTHREAD_MUTEX_DEFAULT); + TEST_ATTR(attr, type, PTHREAD_MUTEX_NORMAL); + TEST_ATTR(attr, type, PTHREAD_MUTEX_ERRORCHECK); + TEST_ATTR(attr, type, PTHREAD_MUTEX_RECURSIVE); + + TEST_ATTR(attr, robust, PTHREAD_MUTEX_STALLED); + TEST_ATTR(attr, robust, PTHREAD_MUTEX_ROBUST); + + TEST_ATTR(attr, protocol, PTHREAD_PRIO_NONE); + TEST_ATTR(attr, protocol, PTHREAD_PRIO_INHERIT); + TEST_ATTR(attr, protocol, PTHREAD_PRIO_PROTECT); + + TEST_ATTR(attr, pshared, PTHREAD_PROCESS_PRIVATE); + TEST_ATTR(attr, pshared, PTHREAD_PROCESS_SHARED); + + // TODO: sched_get_priority* is unimplemented. + // int prio = sched_get_priority_max(SCHED_FIFO); + // TEST_ATTR(attr, prioceiling, prio); + + pthread_mutexattr_destroy(&attr); +} + +static void testNormal() { + pthread_mutexattr_t attr; + pthread_mutexattr_init(&attr); + pthread_mutex_init(&mutex, &attr); + pthread_mutexattr_destroy(&attr); + + pthread_mutex_lock(&mutex); + variable = 0; + + pthread_t thread; + int ret = pthread_create(&thread, NULL, &worker, NULL); + assert(!ret); + + assert(pthread_mutex_trylock(&mutex) == EBUSY); + pthread_mutex_unlock(&mutex); + + ret = pthread_join(thread, NULL); + assert(!ret); + assert(variable == 1); + + pthread_mutex_destroy(&mutex); +} + +static void testRecursive() { + pthread_mutexattr_t attr; + pthread_mutexattr_init(&attr); + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); + pthread_mutex_init(&mutex, &attr); + pthread_mutexattr_destroy(&attr); + + pthread_mutex_lock(&mutex); + variable = 0; + + pthread_t thread; + int ret = pthread_create(&thread, NULL, &worker, NULL); + assert(!ret); + + assert(pthread_mutex_trylock(&mutex) == 0); + pthread_mutex_unlock(&mutex); + pthread_mutex_unlock(&mutex); + + ret = pthread_join(thread, NULL); + assert(!ret); + assert(variable == 1); + + pthread_mutex_destroy(&mutex); +} + +int main() { + testAttr(); + testNormal(); + testRecursive(); +} diff --git a/lib/mlibc/tests/posix/pthread_rwlock.c b/lib/mlibc/tests/posix/pthread_rwlock.c new file mode 100644 index 0000000..5316372 --- /dev/null +++ b/lib/mlibc/tests/posix/pthread_rwlock.c @@ -0,0 +1,114 @@ +#include +#include +#include + +static void test_write_lock_unlock() { + int res; + pthread_rwlock_t rw = PTHREAD_RWLOCK_INITIALIZER; + res = pthread_rwlock_wrlock(&rw); + assert(!res); + res = pthread_rwlock_unlock(&rw); + assert(!res); +} + +static void test_read_lock_unlock() { + int res; + pthread_rwlock_t rw = PTHREAD_RWLOCK_INITIALIZER; + res = pthread_rwlock_rdlock(&rw); + assert(!res); + res = pthread_rwlock_unlock(&rw); + assert(!res); +} + +static void test_write_trylock_unlock() { + int res; + pthread_rwlock_t rw = PTHREAD_RWLOCK_INITIALIZER; + res = pthread_rwlock_trywrlock(&rw); + assert(!res); + res = pthread_rwlock_unlock(&rw); + assert(!res); +} + +static void test_read_trylock_unlock() { + int res; + pthread_rwlock_t rw = PTHREAD_RWLOCK_INITIALIZER; + res = pthread_rwlock_tryrdlock(&rw); + assert(!res); + res = pthread_rwlock_unlock(&rw); + assert(!res); +} + +static void test_write_prevents_read() { + int res; + pthread_rwlock_t rw = PTHREAD_RWLOCK_INITIALIZER; + res = pthread_rwlock_wrlock(&rw); + assert(!res); + res = pthread_rwlock_tryrdlock(&rw); + assert(res == EBUSY); + res = pthread_rwlock_unlock(&rw); + assert(!res); +} + +static void test_write_prevents_write() { + int res; + pthread_rwlock_t rw = PTHREAD_RWLOCK_INITIALIZER; + res = pthread_rwlock_wrlock(&rw); + assert(!res); + res = pthread_rwlock_trywrlock(&rw); + assert(res == EBUSY); + res = pthread_rwlock_unlock(&rw); + assert(!res); +} + +static void test_read_prevents_write() { + int res; + pthread_rwlock_t rw = PTHREAD_RWLOCK_INITIALIZER; + res = pthread_rwlock_rdlock(&rw); + assert(!res); + res = pthread_rwlock_trywrlock(&rw); + assert(res == EBUSY); + res = pthread_rwlock_unlock(&rw); + assert(!res); +} + +static void test_read_allows_read() { + int res; + pthread_rwlock_t rw = PTHREAD_RWLOCK_INITIALIZER; + res = pthread_rwlock_rdlock(&rw); + assert(!res); + res = pthread_rwlock_tryrdlock(&rw); + assert(!res); + res = pthread_rwlock_unlock(&rw); + assert(!res); +} + +static void test_attr() { + pthread_rwlockattr_t attr; + pthread_rwlockattr_init(&attr); + + int pshared; + pthread_rwlockattr_getpshared(&attr, &pshared); + assert(pshared == PTHREAD_PROCESS_PRIVATE); + + pthread_rwlockattr_setpshared(&attr, PTHREAD_PROCESS_SHARED); + pthread_rwlockattr_getpshared(&attr, &pshared); + assert(pshared == PTHREAD_PROCESS_SHARED); + + pthread_rwlockattr_setpshared(&attr, PTHREAD_PROCESS_PRIVATE); + pthread_rwlockattr_getpshared(&attr, &pshared); + assert(pshared == PTHREAD_PROCESS_PRIVATE); + + pthread_rwlockattr_destroy(&attr); +} + +int main() { + test_write_lock_unlock(); + test_read_lock_unlock(); + test_write_trylock_unlock(); + test_read_trylock_unlock(); + test_write_prevents_read(); + test_write_prevents_write(); + test_read_prevents_write(); + test_read_allows_read(); + test_attr(); +} diff --git a/lib/mlibc/tests/posix/pthread_schedparam.c b/lib/mlibc/tests/posix/pthread_schedparam.c new file mode 100644 index 0000000..dde70fb --- /dev/null +++ b/lib/mlibc/tests/posix/pthread_schedparam.c @@ -0,0 +1,32 @@ +#include +#include +#include +#include + +int main() { + struct sched_param param = { + .sched_priority = 100, + }; + + int policy = 0xDEADBEEF; + + int ret = pthread_getschedparam(pthread_self(), &policy, ¶m); + assert(policy == SCHED_OTHER); + assert(!ret); + + param.sched_priority = 10; + + ret = pthread_setschedparam(pthread_self(), SCHED_FIFO, ¶m); + assert(!ret || ret == EPERM); + + if(ret == EPERM) { + exit(0); + } + + param.sched_priority = 0xDEADBEEF; + + ret = pthread_getschedparam(pthread_self(), &policy, ¶m); + assert(policy == SCHED_FIFO); + assert(param.sched_priority == 10); + assert(!ret); +} diff --git a/lib/mlibc/tests/posix/pthread_thread_local.c b/lib/mlibc/tests/posix/pthread_thread_local.c new file mode 100644 index 0000000..90c6f72 --- /dev/null +++ b/lib/mlibc/tests/posix/pthread_thread_local.c @@ -0,0 +1,53 @@ +#include +#include +#include + +_Thread_local unsigned int counter = 9999; +_Thread_local unsigned int uninitialized; + +void *check_counter(void *arg) +{ + (void)arg; + fprintf(stderr, "counter for worker thread: %d, at %p\n", counter, &counter); + fflush(stderr); + assert(counter == 9999); + + fprintf(stderr, "uninitialized data for worker thread: %d, at %p\n", uninitialized, &uninitialized); + fflush(stderr); + assert(uninitialized == 0); + + ++counter; + ++uninitialized; + fprintf(stderr, "counter for worker thread: %d\n", counter); + fflush(stderr); + assert(counter == 10000); + assert(uninitialized == 1); + return NULL; +} + +int main() +{ + fprintf(stderr, "counter for main thread: %d, at %p\n", counter, &counter); + fflush(stderr); + assert(counter == 9999); + + fprintf(stderr, "uninitialized data for main thread: %d, at %p\n", uninitialized, &uninitialized); + fflush(stderr); + assert(uninitialized == 0); + + ++counter; + ++uninitialized; + fprintf(stderr, "counter for main: %d\n", counter); + fflush(stderr); + assert(counter == 10000); + assert(uninitialized == 1); + + pthread_t thd; + pthread_create(&thd, NULL, check_counter, NULL); + pthread_join(thd, NULL); + + fprintf(stderr, "counter for main: %d\n", counter); + fflush(stderr); + assert(counter == 10000); + assert(uninitialized == 1); +} diff --git a/lib/mlibc/tests/posix/pwd.c b/lib/mlibc/tests/posix/pwd.c new file mode 100644 index 0000000..a9ebd8e --- /dev/null +++ b/lib/mlibc/tests/posix/pwd.c @@ -0,0 +1,88 @@ +#include +#include +#include +#include +#include +#include +#include + +int main() +{ + struct passwd pwd, *result = NULL; + char *buf; + size_t bufsize; + int s; + + bufsize = sysconf(_SC_GETPW_R_SIZE_MAX); + assert(bufsize > 0 && bufsize < 0x100000); + + buf = malloc(bufsize); + assert(buf); + + s = getpwnam_r("root", &pwd, buf, bufsize, &result); + assert(!s); + assert(pwd.pw_uid == 0); + assert(!strcmp(pwd.pw_name, "root")); + assert(strlen(pwd.pw_passwd) <= 1000); + + s = getpwuid_r(0, &pwd, buf, bufsize, &result); + assert(!s); + assert(pwd.pw_uid == 0); + assert(!strcmp(pwd.pw_name, "root")); + assert(strlen(pwd.pw_passwd) <= 1000); + + result = getpwnam("root"); + assert(result); + assert(result->pw_uid == 0); + assert(!strcmp(result->pw_name, "root")); + assert(strlen(result->pw_passwd) <= 1000); + + result = getpwuid(0); + assert(result); + assert(result->pw_uid == 0); + assert(!strcmp(result->pw_name, "root")); + assert(strlen(result->pw_passwd) <= 1000); + + errno = 0; + setpwent(); + assert(errno == 0); + + errno = 0; + result = getpwent(); + assert(result); + + pwd = *result; + pwd.pw_name = strdup(result->pw_name); + pwd.pw_passwd = strdup(result->pw_passwd); + pwd.pw_gecos = strdup(result->pw_gecos); + pwd.pw_dir = strdup(result->pw_dir); + pwd.pw_shell = strdup(result->pw_shell); + assert(pwd.pw_name); + assert(pwd.pw_passwd); + assert(pwd.pw_gecos); + assert(pwd.pw_dir); + assert(pwd.pw_shell); + + errno = 0; + setpwent(); + assert(errno == 0); + + errno = 0; + result = getpwent(); + assert(result); + + assert(!strcmp(pwd.pw_name, result->pw_name)); + assert(!strcmp(pwd.pw_passwd, result->pw_passwd)); + assert(!strcmp(pwd.pw_gecos, result->pw_gecos)); + assert(!strcmp(pwd.pw_dir, result->pw_dir)); + assert(!strcmp(pwd.pw_shell, result->pw_shell)); + assert(pwd.pw_uid == result->pw_uid); + assert(pwd.pw_gid == result->pw_gid); + + free(buf); + free(pwd.pw_name); + free(pwd.pw_passwd); + free(pwd.pw_gecos); + free(pwd.pw_dir); + free(pwd.pw_shell); +} diff --git a/lib/mlibc/tests/posix/readv-writev.c b/lib/mlibc/tests/posix/readv-writev.c new file mode 100644 index 0000000..5025ce2 --- /dev/null +++ b/lib/mlibc/tests/posix/readv-writev.c @@ -0,0 +1,51 @@ +#include +#include +#include +#include +#include + +#ifdef USE_HOST_LIBC +#define TEST_FILE "readv-writev-host-libc.tmp" +#else +#define TEST_FILE "readv-writev.tmp" +#endif + +int main() { + // Make sure that it wasn't created by a previous test run + unlink(TEST_FILE); + + int fd = open(TEST_FILE, O_RDWR | O_CREAT, 0644); + assert(fd != -1); + + char str0[] = "hello "; + char str1[] = "world!"; + + struct iovec bufs[2] = { + { + .iov_base = &str0, + .iov_len = strlen(str0), + }, + { + .iov_base = &str1, + .iov_len = strlen(str1), + }, + }; + + ssize_t written = writev(fd, bufs, 2); + assert(written == 12); + + memset(&str0, 0, strlen(str0)); + memset(&str1, 0, strlen(str1)); + + assert(!lseek(fd, 0, SEEK_SET)); + + ssize_t read = readv(fd, bufs, 2); + assert(read == 12); + + assert(!strncmp(str0, "hello ", 7)); + assert(!strncmp(str1, "world!", 7)); + + assert(!close(fd)); + + unlink(TEST_FILE); +} diff --git a/lib/mlibc/tests/posix/realpath.c b/lib/mlibc/tests/posix/realpath.c new file mode 100644 index 0000000..e44de81 --- /dev/null +++ b/lib/mlibc/tests/posix/realpath.c @@ -0,0 +1,133 @@ +#include +#include +#include +#include +#include +#include +#include + +#ifdef USE_HOST_LIBC +#define TEST_BASE "/tmp/mlibc-realpath-host-libc" +#else +#define TEST_BASE "/tmp/mlibc-realpath" +#endif + +void prepare() { + assert(!mkdir(TEST_BASE "/", S_IRWXU)); + assert(!mkdir(TEST_BASE "/dir1", S_IRWXU)); + assert(!mkdir(TEST_BASE "/dir2", S_IRWXU)); + assert(!symlink(TEST_BASE "/dir2/", TEST_BASE "/dir1/abs-link")); + assert(!chdir(TEST_BASE "/dir1")); + assert(!symlink("../dir2/", TEST_BASE "/dir1/rel-link")); +} + +void cleanup(int do_assert) { + if (do_assert) { + assert(!unlink(TEST_BASE "/dir1/rel-link")); + assert(!unlink(TEST_BASE "/dir1/abs-link")); + assert(!rmdir(TEST_BASE "/dir2")); + assert(!rmdir(TEST_BASE "/dir1")); + assert(!rmdir(TEST_BASE "/")); + } else { + unlink(TEST_BASE "/dir1/rel-link"); + unlink(TEST_BASE "/dir1/abs-link"); + rmdir(TEST_BASE "/dir2"); + rmdir(TEST_BASE "/dir1"); + rmdir(TEST_BASE "/"); + } +} + +void signal_handler(int sig, siginfo_t *info, void *ctx) { + (void)sig; + (void)info; + (void)ctx; + + cleanup(0); + + struct sigaction sa; + sigemptyset(&sa.sa_mask); + sa.sa_handler = SIG_DFL; + sa.sa_flags = 0; + + sigaction(SIGABRT, &sa, NULL); + abort(); +} + +int main() { + char *path; + + struct sigaction sa; + sigemptyset(&sa.sa_mask); + sa.sa_sigaction = signal_handler; + sa.sa_flags = SA_SIGINFO; + sigaction(SIGABRT, &sa, NULL); + + prepare(); + + path = realpath(TEST_BASE "/dir1/", NULL); + assert(path); + assert(!strcmp(path, TEST_BASE "/dir1")); + free(path); + + path = realpath(TEST_BASE "/dir1/../dir2", NULL); + assert(path); + assert(!strcmp(path, TEST_BASE "/dir2")); + free(path); + + path = realpath(TEST_BASE "/dir1/abs-link/", NULL); + assert(path); + assert(!strcmp(path, TEST_BASE "/dir2")); + free(path); + + path = realpath(TEST_BASE "/dir1/rel-link/", NULL); + assert(path); + assert(!strcmp(path, TEST_BASE "/dir2")); + free(path); + + path = realpath(TEST_BASE "/dir1/abs-link/../", NULL); + assert(path); + assert(!strcmp(path, TEST_BASE "")); + free(path); + + path = realpath(TEST_BASE "/dir1/rel-link/../", NULL); + assert(path); + assert(!strcmp(path, TEST_BASE "")); + free(path); + + path = realpath(TEST_BASE "/dir1/abs-link/../dir1/abs-link/", NULL); + assert(path); + assert(!strcmp(path, TEST_BASE "/dir2")); + free(path); + + path = realpath(TEST_BASE "/dir1/rel-link/../dir1/rel-link/", NULL); + assert(path); + assert(!strcmp(path, TEST_BASE "/dir2")); + free(path); + + path = realpath(TEST_BASE "/dir1/abs-link/../dir1/rel-link/", NULL); + assert(path); + assert(!strcmp(path, TEST_BASE "/dir2")); + free(path); + + path = realpath(TEST_BASE "/dir1/rel-link/../dir1/abs-link/", NULL); + assert(path); + assert(!strcmp(path, TEST_BASE "/dir2")); + free(path); + + path = realpath("/tmp", NULL); + assert(path); + assert(!strcmp(path, "/tmp")); + free(path); + + path = realpath("/", NULL); + assert(path); + assert(!strcmp(path, "/")); + free(path); + + path = realpath("//", NULL); + assert(path); + assert(!strcmp(path, "/")); + free(path); + + cleanup(1); +} diff --git a/lib/mlibc/tests/posix/regex.c b/lib/mlibc/tests/posix/regex.c new file mode 100644 index 0000000..6c2ca3f --- /dev/null +++ b/lib/mlibc/tests/posix/regex.c @@ -0,0 +1,30 @@ +#include +#include +#include +#include + +int main(void) { + char *testString = "mlibc is the best best best libc"; + char *pattern = "\\(be[a-z]t\\) \\1"; + + regex_t reg; + int rc = regcomp(®, pattern, 0); + assert(!rc); + + regmatch_t matches[2]; + rc = regexec(®, testString, 2, matches, 0); + assert(!rc); + + printf("Whole pattern: \"%.*s\" at %zd-%zd.\n", + (int)(matches[0].rm_eo - matches[0].rm_so), &testString[matches[0].rm_so], + (ssize_t)matches[0].rm_so, (ssize_t)(matches[0].rm_eo - 1)); + assert(matches[0].rm_so == 13 && matches[0].rm_eo == 22); + + printf("Substring: \"%.*s\" at %zd-%zd.\n", + (int)(matches[1].rm_eo - matches[1].rm_so), &testString[matches[1].rm_so], + (ssize_t)matches[1].rm_so, (ssize_t)matches[1].rm_eo - 1); + assert(matches[1].rm_so == 13 && matches[1].rm_eo == 17); + + regfree(®); + return 0; +} diff --git a/lib/mlibc/tests/posix/rindex.c b/lib/mlibc/tests/posix/rindex.c new file mode 100644 index 0000000..0eb2f54 --- /dev/null +++ b/lib/mlibc/tests/posix/rindex.c @@ -0,0 +1,11 @@ +#include +#include + +int main() { + char str[] = "This is a sample string"; + char *pch; + pch = rindex(str, 's'); + // The last occurence of 's' is at position 18 + assert(pch - str + 1 == 18); + return 0; +} diff --git a/lib/mlibc/tests/posix/rlimits.c b/lib/mlibc/tests/posix/rlimits.c new file mode 100644 index 0000000..3565521 --- /dev/null +++ b/lib/mlibc/tests/posix/rlimits.c @@ -0,0 +1,26 @@ +#include +#include +#include +#include +#include + +int main() { + struct rlimit getlim, setlim; + + setlim.rlim_cur = 16; + setlim.rlim_max = 4096; + + int ret = setrlimit(RLIMIT_NOFILE, &setlim); + + if(ret == -1) { + fprintf(stderr, "%s\n", strerror(errno)); + assert(!ret); + } + + assert(!getrlimit(RLIMIT_NOFILE, &getlim)); + + assert(setlim.rlim_cur == getlim.rlim_cur); + assert(setlim.rlim_max == getlim.rlim_max); + + return 0; +} diff --git a/lib/mlibc/tests/posix/search.c b/lib/mlibc/tests/posix/search.c new file mode 100644 index 0000000..6b68ef9 --- /dev/null +++ b/lib/mlibc/tests/posix/search.c @@ -0,0 +1,51 @@ +#include +#include +#include +#include + +static int compare(const void *pa, const void *pb) { + if (*(int*)pa < *(int*) pb) + return -1; + if (*(int*)pa > *(int*) pb) + return 1; + return 0; +} + +static void check_key(int key, void *root) { + int keyp = key; + void *ret = tfind((void*) &keyp, &root, compare); + assert(ret); + assert(**((int **) ret) == key); +} + +static void free_key(void *key) { + free(key); +} + +int main() { + void *root = NULL; + for (int i = 0; i < 12; i++) { + int *ptr = malloc(sizeof(int)); + assert(ptr); + *ptr = i; + + void *ret = tsearch((void*) ptr, &root, compare); + assert(ret); + assert(**((int **) ret) == i); + } + + // Test a couple of keys + check_key(1, root); + check_key(5, root); + check_key(10, root); + + // Verify NULL on non-existent key + int key = -1; + void *ret = tfind((void*) &key, &root, compare); + assert(ret == NULL); + + // tdelete is not implemented yet (#351) + (void)free_key; + // tdestroy(root, free_key); + return 0; +} diff --git a/lib/mlibc/tests/posix/setpriority.c b/lib/mlibc/tests/posix/setpriority.c new file mode 100644 index 0000000..11cb7ed --- /dev/null +++ b/lib/mlibc/tests/posix/setpriority.c @@ -0,0 +1,27 @@ +#include +#include +#include +#include +#include +#include +#include + +int main() { + errno = 0; + int original_priority = getpriority(PRIO_PROCESS, getpid()); + + assert(original_priority != -1 || !errno); + + int ret = setpriority(PRIO_PROCESS, getpid(), original_priority + 1); + + if(ret) { + fprintf(stderr, "%s", strerror(errno)); + exit(1); + } + + errno = 0; + int new_priority = getpriority(PRIO_PROCESS, getpid()); + + assert(new_priority != -1 || !errno); + assert(new_priority == original_priority + 1); +} diff --git a/lib/mlibc/tests/posix/sigaltstack.c b/lib/mlibc/tests/posix/sigaltstack.c new file mode 100644 index 0000000..bebcc30 --- /dev/null +++ b/lib/mlibc/tests/posix/sigaltstack.c @@ -0,0 +1,55 @@ +#include +#include +#include +#include + +static jmp_buf env; +static char *sigStack; + +static void sig_handler(int sig, siginfo_t *info, void *ctx) { + (void)sig; + (void)info; + (void)ctx; + + longjmp(env, 1); +} + +int main() { + if (setjmp(env)) { + free(sigStack); + return 0; + } + + sigStack = malloc(SIGSTKSZ); + + stack_t ss; + ss.ss_sp = sigStack; + ss.ss_size = SIGSTKSZ; + ss.ss_flags = 0; + + assert(!sigaltstack(&ss, NULL)); + + struct sigaction sa; + sigemptyset(&sa.sa_mask); + sa.sa_flags = SA_SIGINFO | SA_ONSTACK; + sa.sa_sigaction = sig_handler; + + assert(!sigaction(SIGSEGV, &sa, NULL)); + + // This is used to trash the stack to ensure sigaltstack actually switched stacks. +#if defined(__x86_64__) + asm volatile ("mov $0, %rsp\n" + "\t" "push $0"); +#elif defined(__i386__) + asm volatile ("mov $0, %esp\n" + "\t" "push $0"); +#elif defined(__aarch64__) + asm volatile ("mov sp, %0\n" + "\t" "stp x0, x1, [sp, #-16]!" :: "r"((uint64_t)0)); +#elif defined(__riscv) && __riscv_xlen == 64 + asm volatile ("li sp, 0\n" + "\t" "sd zero, 0(sp)"); +#else +# error Unknown architecture +#endif +} diff --git a/lib/mlibc/tests/posix/sigsuspend.c b/lib/mlibc/tests/posix/sigsuspend.c new file mode 100644 index 0000000..09b9a1e --- /dev/null +++ b/lib/mlibc/tests/posix/sigsuspend.c @@ -0,0 +1,53 @@ +#include +#include +#include +#include +#include + +_Atomic int handler_ready = 0; +_Atomic int thread_signal_ran = 0; + +static void sig_handler(int sig, siginfo_t *info, void *ctx) { + (void)sig; + (void)info; + (void)ctx; + + thread_signal_ran = 1; +} + +static void *worker(void *arg) { + (void)arg; + + struct sigaction sa; + sigemptyset(&sa.sa_mask); + sa.sa_sigaction = sig_handler; + sa.sa_flags = SA_SIGINFO; + assert(!sigaction(SIGUSR1, &sa, NULL)); + + handler_ready = 1; + + sigset_t set; + sigfillset(&set); + sigdelset(&set, SIGUSR1); + + assert(sigsuspend(&set)); + assert(thread_signal_ran); + assert(errno == EINTR); + + return NULL; +} + +int main() { + pthread_t thread; + assert(!pthread_create(&thread, NULL, &worker, NULL)); + + while (!handler_ready) + ; + + sleep(1); + + assert(!pthread_kill(thread, SIGUSR1)); + assert(!pthread_join(thread, NULL)); + + return 0; +} diff --git a/lib/mlibc/tests/posix/sigtimedwait.c b/lib/mlibc/tests/posix/sigtimedwait.c new file mode 100644 index 0000000..4793fc1 --- /dev/null +++ b/lib/mlibc/tests/posix/sigtimedwait.c @@ -0,0 +1,91 @@ +#include + +#include +#include +#include +#include +#include + +pid_t parent; +pid_t child; + +int fds[2]; + +void parent_fn() { + int res; + + sigset_t set; + sigemptyset(&set); + sigaddset(&set, SIGUSR2); + sigprocmask(SIG_BLOCK, &set, NULL); + + res = write(fds[1], "!", 1); + assert(res == 1); + + siginfo_t info; + res = sigwaitinfo(&set, &info); + assert(res == SIGUSR2); + assert(info.si_signo == SIGUSR2); + + res = write(fds[1], "!", 1); + assert(res == 1); + + // XXX: This may not be long enough to get scheduled + struct timespec tout = {1, 0}; + res = sigtimedwait(&set, &info, &tout); + assert(res == SIGUSR2); + assert(info.si_signo == SIGUSR2); + + res = write(fds[1], "!", 1); + assert(res == 1); + + int sig; + res = sigwait(&set, &sig); + assert(res == 0); + assert(sig == SIGUSR2); + + res = write(fds[1], "!", 1); + assert(res == 1); + + res = sigtimedwait(&set, &info, &tout); + assert(res < 0); + assert(errno == EAGAIN); + + int wsts; + res = waitpid(child, &wsts, 0); + assert(res >= 0); +} + +void child_fn() { + int res; + char c; + + res = read(fds[0], &c, 1); + assert(res == 1); + kill(parent, SIGUSR2); + res = read(fds[0], &c, 1); + assert(res == 1); + kill(parent, SIGUSR2); + res = read(fds[0], &c, 1); + assert(res == 1); + kill(parent, SIGUSR2); + res = read(fds[0], &c, 1); + assert(res == 1); +} + +int main() { + int res; + + parent = getpid(); + assert(parent > 0); + + res = pipe(fds); + assert(res == 0); + + child = fork(); + assert(child >= 0); + if (child) + parent_fn(); + else + child_fn(); +} diff --git a/lib/mlibc/tests/posix/strdupa.c b/lib/mlibc/tests/posix/strdupa.c new file mode 100644 index 0000000..c79de8e --- /dev/null +++ b/lib/mlibc/tests/posix/strdupa.c @@ -0,0 +1,14 @@ +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif +#include +#include + +int main() { + char test[19] = "Hello mlibc World!"; + char *alloca_ed = strdupa(test); + assert(!strcmp(test, alloca_ed)); + + char *trimmed = strndupa(test, 5); + assert(!strcmp("Hello", trimmed)); +} diff --git a/lib/mlibc/tests/posix/string.c b/lib/mlibc/tests/posix/string.c new file mode 100644 index 0000000..9c6e036 --- /dev/null +++ b/lib/mlibc/tests/posix/string.c @@ -0,0 +1,29 @@ +#include +#include + +int main() { + char buf[4]; + + // stpncpy + assert(stpncpy(buf, "", 4) == buf); + assert(!strcmp(buf, "")); + + assert(stpncpy(buf, "123", 4) == buf + 3); + assert(!strcmp(buf, "123")); + + assert(stpncpy(buf, "12", 4) == buf + 2); + assert(buf[0] == '1' && buf[1] == '2' && buf[2] == '\0' && buf[3] == '\0'); + + assert(stpncpy(buf, "123456", 4) == buf + 4); + assert(buf[0] == '1' && buf[1] == '2' && buf[2] == '3' && buf[3] == '4'); + + // stpcpy + assert(stpcpy(buf, "") == buf); + assert(!strcmp(buf, "")); + + assert(stpcpy(buf, "12") == buf + 2); + assert(!strcmp(buf, "12")); + + assert(stpcpy(buf, "123") == buf + 3); + assert(!strcmp(buf, "123")); +} diff --git a/lib/mlibc/tests/posix/system.c b/lib/mlibc/tests/posix/system.c new file mode 100644 index 0000000..d5d6317 --- /dev/null +++ b/lib/mlibc/tests/posix/system.c @@ -0,0 +1,18 @@ +#include +#include +#include + +int main() { + int res; + + res = system("true"); + assert(WIFEXITED(res)); + assert(WEXITSTATUS(res) == 0); + + res = system("false"); + assert(WIFEXITED(res)); + assert(WEXITSTATUS(res) == 1); + + res = system(NULL); + assert(res == 1); +} diff --git a/lib/mlibc/tests/posix/time.c b/lib/mlibc/tests/posix/time.c new file mode 100644 index 0000000..add7b92 --- /dev/null +++ b/lib/mlibc/tests/posix/time.c @@ -0,0 +1,191 @@ +#include +#include +#include +#include +#include +#include + +#define BUF_SIZE 1024 + +int main() { + struct tm tm = {0}; + char buf[BUF_SIZE]; + + char *a = strptime("%", "%%", &tm); + assert(a != NULL); + assert(*a == '\0'); + assert(strftime(buf, BUF_SIZE, "%%", &tm) == 1); + assert(!strcmp(buf, "%")); + memset(&tm, 0, sizeof(tm)); + + a = strptime("1991-11-21", "%F", &tm); + assert(a != NULL); + assert(*a == '\0'); + assert(tm.tm_mday == 21); + assert(tm.tm_mon == 10); + assert(tm.tm_wday == 4); + assert(tm.tm_yday == 324); + assert(strftime(buf, BUF_SIZE, "%F", &tm) == 10); + assert(!strcmp(buf, "1991-11-21")); + memset(&tm, 0, sizeof(tm)); + + a = strptime("10/19/91", "%D", &tm); + assert(a != NULL); + assert(*a == '\0'); + assert(tm.tm_mday == 19); + assert(tm.tm_mon == 9); + assert(tm.tm_year == 91); + assert(tm.tm_wday == 6); + assert(tm.tm_yday == 291); + assert(strftime(buf, BUF_SIZE, "%D", &tm) == 8); + assert(!strcmp(buf, "10/19/91")); + memset(&tm, 0, sizeof(tm)); + + a = strptime("15:23", "%R", &tm); + assert(a != NULL); + assert(*a == '\0'); + assert(tm.tm_min == 23); + assert(tm.tm_hour == 15); + assert(strftime(buf, BUF_SIZE, "%R", &tm) == 5); + assert(!strcmp(buf, "15:23")); + memset(&tm, 0, sizeof(tm)); + + a = strptime("17:12:56", "%T", &tm); + assert(a != NULL); + assert(*a == '\0'); + assert(tm.tm_sec == 56); + assert(tm.tm_min == 12); + assert(tm.tm_hour == 17); + assert(strftime(buf, BUF_SIZE, "%T", &tm) == 8); + assert(!strcmp(buf, "17:12:56")); + memset(&tm, 0, sizeof(tm)); + + a = strptime("10", "%m", &tm); + assert(a != NULL); + assert(*a == '\0'); + assert(tm.tm_yday == 272); + assert(strftime(buf, BUF_SIZE, "%m", &tm) == 2); + assert(!strcmp(buf, "10")); + memset(&tm, 0, sizeof(tm)); + + a = strptime("14 83", "%C %y", &tm); + assert(a != NULL); + assert(*a == '\0'); + assert(tm.tm_year == -417); + assert(strftime(buf, BUF_SIZE, "%C %y", &tm) == 5); + assert(!strcmp(buf, "14 83")); + memset(&tm, 0, sizeof(tm)); + + a = strptime("32 16", "%y %C", &tm); + assert(a != NULL); + assert(*a == '\0'); + assert(tm.tm_year == -268); + assert(tm.tm_wday == 3); + assert(strftime(buf, BUF_SIZE, "%y %C", &tm) == 5); + assert(!strcmp(buf, "32 16")); + memset(&tm, 0, sizeof(tm)); + + a = strptime("12", "%C", &tm); + assert(a != NULL); + assert(*a == '\0'); + assert(tm.tm_year == -700); + assert(tm.tm_wday == 5); + assert(strftime(buf, BUF_SIZE, "%C", &tm) == 2); + assert(!strcmp(buf, "12")); + memset(&tm, 0, sizeof(tm)); + + a = strptime("1683-9-23", "%F", &tm); + assert(a != NULL); + assert(*a == '\0'); + assert(tm.tm_mday == 23); + assert(tm.tm_mon == 8); + assert(tm.tm_year == -217); + assert(tm.tm_wday == 4); + assert(tm.tm_yday == 265); + assert(strftime(buf, BUF_SIZE, "%F", &tm) == 10); + assert(!strcmp(buf, "1683-09-23")); + memset(&tm, 0, sizeof(tm)); + + a = strptime("14 53", "%H%t%S", &tm); + assert(a != NULL); + assert(*a == '\0'); + assert(tm.tm_sec == 53); + assert(tm.tm_hour == 14); + assert(strftime(buf, BUF_SIZE, "%H%t%S", &tm) == 5); + assert(!strcmp(buf, "14 53")); + memset(&tm, 0, sizeof(tm)); + + a = strptime("24", "%H", &tm); + assert(a == NULL); + memset(&tm, 0, sizeof(tm)); + + a = strptime("0", "%I", &tm); + assert(a == NULL); + memset(&tm, 0, sizeof(tm)); + + setlocale(LC_TIME, "en_US.UTF-8"); + a = strptime("10 21 PM", "%I %M %p", &tm); + assert(a != NULL); + assert(*a == '\0'); + assert(tm.tm_hour == 22); + assert(tm.tm_min == 21); + assert(strftime(buf, BUF_SIZE, "%I %M %p", &tm) == 8); + assert(!strcmp(buf, "10 21 PM")); + memset(&tm, 0, sizeof(tm)); + + tm.tm_min = 23; + assert(strftime(buf, BUF_SIZE, "%I %M", &tm) == 5); + assert(!strcmp(buf, "12 23")); + memset(&tm, 0, sizeof(tm)); + + a = strptime("January", "%h", &tm); + assert(a != NULL); + assert(*a == '\0'); + assert(tm.tm_mon == 0); + assert(strftime(buf, BUF_SIZE, "%h %b", &tm) == 7); + assert(!strcmp(buf, "Jan Jan")); + assert(strftime(buf, BUF_SIZE, "%B", &tm) == 7); + assert(!strcmp(buf, "January")); + memset(&tm, 0, sizeof(tm)); + + a = strptime("2", "%j", &tm); + assert(a != NULL); + assert(*a == '\0'); + assert(tm.tm_yday == 1); + assert(strftime(buf, BUF_SIZE, "%j", &tm) == 3); + assert(!strcmp(buf, "002")); + memset(&tm, 0, sizeof(tm)); + + a = strptime("Wednesday", "%A", &tm); + assert(a != NULL); + assert(*a == '\0'); + assert(tm.tm_wday == 3); + assert(strftime(buf, BUF_SIZE, "%A", &tm) == 9); + assert(!strcmp(buf, "Wednesday")); + memset(&tm, 0, sizeof(tm)); + + a = strptime("11:51:13 PM", "%r", &tm); + assert(a != NULL); + assert(*a == '\0'); + assert(tm.tm_hour == 23); + assert(tm.tm_min == 51); + assert(tm.tm_sec == 13); + assert(strftime(buf, BUF_SIZE, "%r", &tm) == 11); + assert(!strcmp(buf, "11:51:13 PM")); + memset(&tm, 0, sizeof(tm)); + + tm.tm_hour = 0; + tm.tm_min = 51; + tm.tm_sec = 13; + assert(strftime(buf, BUF_SIZE, "%r", &tm) == 11); + assert(!strcmp(buf, "12:51:13 AM")); + memset(&tm, 0, sizeof(tm)); + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wformat" + assert(strftime(buf, BUF_SIZE, "%", &tm) == 1); + fprintf(stderr, "%s\n", buf); + assert(!strcmp(buf, "%")); + memset(&tm, 0, sizeof(tm)); +#pragma GCC diagnostic pop +} diff --git a/lib/mlibc/tests/posix/timer.c b/lib/mlibc/tests/posix/timer.c new file mode 100644 index 0000000..f39e928 --- /dev/null +++ b/lib/mlibc/tests/posix/timer.c @@ -0,0 +1,25 @@ +#include +#include +#include + +int main() { + struct timeval a = {0, 0}; + struct timeval b = {0, 0}; + struct timeval res = {0, 0}; + a.tv_sec = 10; + assert(timerisset(&a) == 1); + timerclear(&a); + assert(timerisset(&a) == 0); + a.tv_sec = 40; + a.tv_usec = 500; + b.tv_sec = 10; + b.tv_usec = 20; + timeradd(&a, &b, &res); + assert(res.tv_sec == 50); + assert(res.tv_usec == 520); + timerclear(&res); + timersub(&a, &b, &res); + assert(res.tv_sec == 30); + assert(res.tv_usec == 480); + return 0; +} diff --git a/lib/mlibc/tests/posix/vfork.c b/lib/mlibc/tests/posix/vfork.c new file mode 100644 index 0000000..5f8b71d --- /dev/null +++ b/lib/mlibc/tests/posix/vfork.c @@ -0,0 +1,28 @@ +#include +#include +#include +#include +#include +#include + +void prevent_atforks(void){ + exit(1); +} + +int main() { + pid_t pid; + int status; + assert(!pthread_atfork(prevent_atforks, NULL, NULL)); + + switch (pid = vfork()) { + case -1: + perror("vfork"); + abort(); + case 0: + _exit(12); + default: break; + } + + assert(wait(&status) == pid); + assert(WIFEXITED(status) && WEXITSTATUS(status) == 12); +} diff --git a/lib/mlibc/tests/posix/waitid.c b/lib/mlibc/tests/posix/waitid.c new file mode 100644 index 0000000..e69b1ef --- /dev/null +++ b/lib/mlibc/tests/posix/waitid.c @@ -0,0 +1,20 @@ +#include +#include +#include +#include +#include + +siginfo_t si; + +int main() { + int pid = fork(); + + if(!pid) + exit(69); + + int ret = waitid(P_ALL, 0, &si, WEXITED); + assert(ret == 0); + assert(si.si_pid == pid); + assert(si.si_signo == SIGCHLD); + assert(si.si_code == CLD_EXITED); +} \ No newline at end of file diff --git a/lib/mlibc/tests/posix/wcwidth.c b/lib/mlibc/tests/posix/wcwidth.c new file mode 100644 index 0000000..2e6fc8c --- /dev/null +++ b/lib/mlibc/tests/posix/wcwidth.c @@ -0,0 +1,67 @@ +#include +#include +#include +#include +#include +#include +#include + +#if UINTPTR_MAX == UINT64_MAX +#define WCHAR_SPEC "" +#else +#define WCHAR_SPEC "l" +#endif + +/* + * The code in this test is taken from https://github.com/termux/wcwidth/, + * under the following license: + * + * Copyright (C) Fredrik Fornwall 2016. + * Distributed under the MIT License. + * + * Implementation of wcwidth(3) as a C port of: + * https://github.com/jquast/wcwidth + * + * Report issues at: + * https://github.com/termux/wcwidth + */ + +static int tests_run; +static int test_failures; + +void assertWidthIs(int expected_width, wchar_t c) { + tests_run++; + int actual_width = wcwidth(c); + if (actual_width != expected_width) { + fprintf(stderr, "ERROR: wcwidth(U+%04" WCHAR_SPEC "x, '%lc') returned %d, expected %d\n", c, (wint_t) c, actual_width, expected_width); + test_failures++; + } +} + +int main() { + setlocale(LC_CTYPE, "C.UTF-8"); + assertWidthIs(1, 'a'); + assertWidthIs(1, L'ö'); + + // Some wide: + assertWidthIs(2, L'A'); + assertWidthIs(2, L'B'); + assertWidthIs(2, L'C'); + assertWidthIs(2, L'中'); + assertWidthIs(2, L'文'); + assertWidthIs(2, 0x679C); + assertWidthIs(2, 0x679D); + assertWidthIs(2, 0x2070E); + assertWidthIs(2, 0x20731); + +#ifndef USE_HOST_LIBC + assertWidthIs(1, 0x11A3); +#endif + + assertWidthIs(2, 0x1F428); // Koala emoji. + assertWidthIs(2, 0x231a); // Watch emoji. + + if (test_failures > 0) printf("%d tests FAILED, ", test_failures); + printf("%d tests OK\n", tests_run - test_failures); + return (test_failures == 0) ? 0 : 1; +} diff --git a/lib/mlibc/tests/posix/wordexp.c b/lib/mlibc/tests/posix/wordexp.c new file mode 100644 index 0000000..063a374 --- /dev/null +++ b/lib/mlibc/tests/posix/wordexp.c @@ -0,0 +1,140 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static const char *wordexp_return_stringify(int val, int *should_free); + +struct we_test { + int expected_return; + const char *words; + int flags; + const char *wordv[16]; + size_t wordc; +} test_cases[] = { + /* (unbalanced) pairs */ + {WRDE_SYNTAX, "\\", 0, {NULL}, 0}, + {WRDE_SYNTAX, "\'", 0, {NULL}, 0}, + {0, "\'\'", 0, {""}, 1}, + {0, "\'\"\'", 0, {"\""}, 1}, + {WRDE_SYNTAX, "\"\'", 0, {NULL}, 0}, + + /* numbers & calculations */ + {0, "$((5+5))", 0, {"10"}, 1}, + {0, "$((-5+5))", 0, {"0"}, 1}, + {0, "$((010))", 0, {"8"}, 1}, + {0, "$((0x10))", 0, {"16"}, 1}, + + /* errant symbols */ + {WRDE_BADCHAR, "(string", WRDE_NOCMD, {NULL}, 0}, + {WRDE_BADCHAR, "string)", WRDE_NOCMD, {NULL}, 0}, + {WRDE_BADCHAR, "{string", WRDE_NOCMD, {NULL}, 0}, + {WRDE_BADCHAR, "string}", WRDE_NOCMD, {NULL}, 0}, + {WRDE_BADCHAR, "", WRDE_NOCMD, {NULL}, 0}, + {WRDE_BADCHAR, "string|", WRDE_NOCMD, {NULL}, 0}, + {WRDE_BADCHAR, "string;", WRDE_NOCMD, {NULL}, 0}, + {WRDE_BADCHAR, "string&", WRDE_NOCMD, {NULL}, 0}, + + /* command substitution with WRDE_NOCMD */ + {WRDE_CMDSUB, "$(pwd)", WRDE_NOCMD, {NULL}, 0}, + + /* env vars */ + {WRDE_BADVAL, "$DOES_NOT_EXIST", WRDE_UNDEF, {NULL}, 0}, + + /* normal arguments */ + {0, "arg1 arg2", 0, {"arg1", "arg2"}, 2}, + {-1, NULL, 0, {NULL}, 0}, +}; + +int main() { + wordexp_t we; + + wordexp("$(pwd)", &we, 0); + char *cwd = getcwd(NULL, 0); + assert(!strcmp(cwd, we.we_wordv[0])); + wordfree(&we); + free(cwd); + + char *home; + assert(asprintf(&home, "%s/.config", getenv("HOME")) != -1); + wordexp("$HOME ~ ~/.config", &we, WRDE_REUSE); + assert(!strcmp(getenv("HOME"), we.we_wordv[0])); + assert(!strcmp(getenv("HOME"), we.we_wordv[1])); + assert(!strcmp(home, we.we_wordv[2])); + free(home); + wordfree(&we); + + struct passwd *pw = getpwnam("root"); + assert(asprintf(&home, "%s/.config", pw->pw_dir) != -1); + wordexp("~root ~root/.config", &we, WRDE_REUSE); + assert(!strcmp(pw->pw_dir, we.we_wordv[0])); + assert(!strcmp(home, we.we_wordv[1])); + free(home); + wordfree(&we); + + size_t i = 0; + + for(struct we_test *test = &test_cases[i]; test->expected_return != -1; test = &test_cases[++i]) { + wordexp_t test_we; + + int should_free; + const char *expected = wordexp_return_stringify(test->expected_return, &should_free); + fprintf(stderr, "TESTCASE %zu: '%s' with flags %d expected to return %s\n", i, test->words, test->flags, expected); + int test_ret = wordexp(test->words, &test_we, test->flags); + + if(test_ret != test->expected_return) { + fprintf(stderr, "\twordexp() returned %s, but we expect %s\n", wordexp_return_stringify(test_ret, &should_free), wordexp_return_stringify(test->expected_return, &should_free)); + } + + assert(test_ret == test->expected_return); + + if(test_ret != 0) + continue; + + assert(test_we.we_wordc == test->wordc); + + for(size_t j = 0; j < 16 && j < test->wordc; j++) { + assert(test->wordv[j] && test_we.we_wordv[j]); + assert(!strcmp(test->wordv[j], test_we.we_wordv[j])); + } + + wordfree(&test_we); + if (should_free) + free((void *)expected); + } + + exit(EXIT_SUCCESS); +} + +struct wordexp_return_val { + int val; + const char *string; +} wordexp_return_vals[] = { + {0, "WRDE_SUCCESS"}, + {WRDE_BADCHAR, "WRDE_BADCHAR"}, + {WRDE_BADVAL, "WRDE_BADVAL"}, + {WRDE_CMDSUB, "WRDE_CMDSUB"}, + {WRDE_SYNTAX, "WRDE_SYNTAX"}, + {-1, NULL}, +}; + +static const char *wordexp_return_stringify(int val, int *should_free) { + for(size_t i = 0; wordexp_return_vals[i].val != -1 || wordexp_return_vals[i].string; i++) { + if(wordexp_return_vals[i].val == val) { + *should_free = 0; + return wordexp_return_vals[i].string; + } + } + + char *unknown; + assert(asprintf(&unknown, "unknown return value %d", val) != -1); + *should_free = 1; + + return unknown; +} diff --git a/lib/mlibc/tests/rtdl/dl_iterate_phdr/libbar.c b/lib/mlibc/tests/rtdl/dl_iterate_phdr/libbar.c new file mode 100644 index 0000000..41ccc56 --- /dev/null +++ b/lib/mlibc/tests/rtdl/dl_iterate_phdr/libbar.c @@ -0,0 +1,3 @@ +// Bar needs to have a relocation against foo in order to set DT_NEEDED. +int foo(void); +int bar() { return foo(); } diff --git a/lib/mlibc/tests/rtdl/dl_iterate_phdr/libfoo.c b/lib/mlibc/tests/rtdl/dl_iterate_phdr/libfoo.c new file mode 100644 index 0000000..9fe07f8 --- /dev/null +++ b/lib/mlibc/tests/rtdl/dl_iterate_phdr/libfoo.c @@ -0,0 +1 @@ +int foo() { return 0; } diff --git a/lib/mlibc/tests/rtdl/dl_iterate_phdr/meson.build b/lib/mlibc/tests/rtdl/dl_iterate_phdr/meson.build new file mode 100644 index 0000000..acb679e --- /dev/null +++ b/lib/mlibc/tests/rtdl/dl_iterate_phdr/meson.build @@ -0,0 +1,7 @@ +libfoo = shared_library('foo', 'libfoo.c') +libbar = shared_library('bar', 'libbar.c', build_rpath: test_rpath, link_with: libfoo) +test_depends = [libfoo, libbar] + +libfoo_native = shared_library('native-foo', 'libfoo.c', native: true) +libbar_native = shared_library('native-bar', 'libbar.c', build_rpath: test_rpath, link_with: libfoo_native, native: true) +test_native_depends = [libfoo_native, libbar_native] diff --git a/lib/mlibc/tests/rtdl/dl_iterate_phdr/test.c b/lib/mlibc/tests/rtdl/dl_iterate_phdr/test.c new file mode 100644 index 0000000..5d48a41 --- /dev/null +++ b/lib/mlibc/tests/rtdl/dl_iterate_phdr/test.c @@ -0,0 +1,91 @@ +#include +#include +#include +#include +#include + +#ifdef USE_HOST_LIBC +#define LDSO_PATTERN "ld-linux-" +#define LIBFOO "libnative-foo.so" +#define LIBBAR "libnative-bar.so" +#else +#define LDSO_PATTERN "ld.so" +#define LIBFOO "libfoo.so" +#define LIBBAR "libbar.so" +#endif + +struct result { + int found_ldso; + int found_self; + int found_foo; + int found_bar; +}; + +static int ends_with(const char *suffix, const char *s) { + size_t suffix_len = strlen(suffix); + size_t s_len = strlen(s); + if (s_len < suffix_len) + return 0; + else { + return !strcmp(suffix, s + s_len - suffix_len); + } +} + +static int contains(const char *pattern, const char *s) { + return !!strstr(s, pattern); +} + +static int callback(struct dl_phdr_info *info, size_t size, void *data) { + assert(size == sizeof(struct dl_phdr_info)); + struct result *found = (struct result *) data; + + printf("%s\n", info->dlpi_name); + fflush(stdout); + + if (ends_with("foo.so", info->dlpi_name)) + found->found_foo++; + if (ends_with("bar.so", info->dlpi_name)) + found->found_bar++; + if (contains(LDSO_PATTERN, info->dlpi_name)) + found->found_ldso++; + + if (!strcmp("", info->dlpi_name)) + found->found_self++; + + assert(info->dlpi_phdr); + return 0; +} + +int main() { + struct result found = { 0 }; + assert(!dl_iterate_phdr(callback, &found)); + assert(found.found_ldso == 1); + assert(found.found_self == 1); + assert(found.found_foo == 0); + assert(found.found_bar == 0); + printf("---\n"); + + memset(&found, 0, sizeof(found)); + void *bar = dlopen(LIBBAR, RTLD_LOCAL | RTLD_NOW); + assert(bar); + assert(!dl_iterate_phdr(callback, &found)); + assert(found.found_ldso == 1); + assert(found.found_self == 1); + assert(found.found_bar == 1); + assert(found.found_foo == 1); // Since bar depends on foo. + printf("---\n"); + + memset(&found, 0, sizeof(found)); + void *foo = dlopen(LIBFOO, RTLD_GLOBAL | RTLD_NOW); + assert(foo); + assert(!dl_iterate_phdr(callback, &found)); + assert(found.found_ldso == 1); + assert(found.found_self == 1); + assert(found.found_foo == 1); + assert(found.found_bar == 1); + printf("---\n"); + + dlclose(bar); + dlclose(foo); + return 0; +} diff --git a/lib/mlibc/tests/rtdl/dladdr_local/libfoo.c b/lib/mlibc/tests/rtdl/dladdr_local/libfoo.c new file mode 100644 index 0000000..2903a3d --- /dev/null +++ b/lib/mlibc/tests/rtdl/dladdr_local/libfoo.c @@ -0,0 +1 @@ +char foo_global[] = ""; diff --git a/lib/mlibc/tests/rtdl/dladdr_local/meson.build b/lib/mlibc/tests/rtdl/dladdr_local/meson.build new file mode 100644 index 0000000..4ae6bb3 --- /dev/null +++ b/lib/mlibc/tests/rtdl/dladdr_local/meson.build @@ -0,0 +1,5 @@ +libfoo = shared_library('foo', 'libfoo.c') +test_depends = [libfoo] + +libfoo_native = shared_library('native-foo', 'libfoo.c', native: true) +test_native_depends = [libfoo_native] diff --git a/lib/mlibc/tests/rtdl/dladdr_local/test.c b/lib/mlibc/tests/rtdl/dladdr_local/test.c new file mode 100644 index 0000000..c64d259 --- /dev/null +++ b/lib/mlibc/tests/rtdl/dladdr_local/test.c @@ -0,0 +1,21 @@ +#include +#include + +#ifdef USE_HOST_LIBC +#define LIBFOO "libnative-foo.so" +#else +#define LIBFOO "libfoo.so" +#endif + +int main() { + void *foo_handle = dlopen(LIBFOO, RTLD_LOCAL | RTLD_NOW); + assert(foo_handle); + + char *foo_global = (char *)dlsym(foo_handle, "foo_global"); + assert(foo_global); + + Dl_info info; + assert(dladdr((const void *)foo_global, &info) != 0); + + assert(dlclose(foo_handle) == 0); +} diff --git a/lib/mlibc/tests/rtdl/ld_library_path/libfoo.c b/lib/mlibc/tests/rtdl/ld_library_path/libfoo.c new file mode 100644 index 0000000..85e6cd8 --- /dev/null +++ b/lib/mlibc/tests/rtdl/ld_library_path/libfoo.c @@ -0,0 +1 @@ +void foo() {} diff --git a/lib/mlibc/tests/rtdl/ld_library_path/meson.build b/lib/mlibc/tests/rtdl/ld_library_path/meson.build new file mode 100644 index 0000000..95629be --- /dev/null +++ b/lib/mlibc/tests/rtdl/ld_library_path/meson.build @@ -0,0 +1,19 @@ +# Remove the RPATH and set the LD_LIBRARY_PATH environment variable +# instead when running tests to make sure the library can be found +# in a directory specified by the user at runtime + +test_rpath = '$ORIGIN/' + +test_ld_path = meson.build_root() / 'tests' / 'rtdl' / test_name +test_env += ['LD_LIBRARY_PATH=' + test_ld_path] +test_native_env += ['LD_LIBRARY_PATH=' + test_ld_path] + +libfoo = shared_library('foo', 'libfoo.c', + dependencies: libc_dep, + link_args: test_additional_link_args, +) + +libfoo_native = shared_library('native-foo', 'libfoo.c', + link_args: ['-ldl'] + test_additional_link_args, + native: true +) diff --git a/lib/mlibc/tests/rtdl/ld_library_path/test.c b/lib/mlibc/tests/rtdl/ld_library_path/test.c new file mode 100644 index 0000000..15ca200 --- /dev/null +++ b/lib/mlibc/tests/rtdl/ld_library_path/test.c @@ -0,0 +1,16 @@ +#include +#include +#include +#include + +#ifdef USE_HOST_LIBC +#define LIBFOO "libnative-foo.so" +#else +#define LIBFOO "libfoo.so" +#endif + +int main() { + void *foo = dlopen(LIBFOO, RTLD_NOW); + assert(foo); + dlclose(foo); +} diff --git a/lib/mlibc/tests/rtdl/meson.build b/lib/mlibc/tests/rtdl/meson.build new file mode 100644 index 0000000..1331899 --- /dev/null +++ b/lib/mlibc/tests/rtdl/meson.build @@ -0,0 +1,56 @@ +rtdl_test_cases = [ + 'dl_iterate_phdr', + 'dladdr_local', + 'ld_library_path', + 'noload-promote', + 'rtld_next', + 'soname', + 'preinit', + 'scope1', + 'scope2', + 'scope3', + 'scope4', + 'scope5', + 'tls_align', +] + +foreach test_name : rtdl_test_cases + test_rpath = meson.build_root() / 'tests' / 'rtdl' / test_name / '' + test_rpath += ':$ORIGIN/' # Workaround old and buggy qemu-user on CI + + test_env = [] + test_link_with = [] + test_depends = [] + test_native_env = [] + test_native_link_with = [] + test_native_depends = [] + test_additional_link_args = [] + + # Build the needed DSOs for the test. This sets the variables above. + subdir(test_name) + + exec = executable('rtdl-' + test_name, [test_name / 'test.c', test_sources], + link_with: test_link_with, + dependencies: libc_dep, + build_rpath: test_rpath, + override_options: test_override_options, + c_args: test_c_args, + link_args: test_link_args + test_additional_link_args, + ) + test(test_name, exec, env: test_env, suite: 'rtdl', depends: test_depends) + + if build_tests_host_libc and not host_libc_excluded_test_cases.contains(test_name) + exec = executable('host-libc-' + test_name, test_name / 'test.c', + link_with: test_native_link_with, + dependencies: rtlib_deps, + build_rpath: test_rpath, + # Don't use ASan here, due to a bug that breaks dlopen() + DT_RUNPATH: + # https://bugzilla.redhat.com/show_bug.cgi?id=1449604 + override_options: 'b_sanitize=undefined', + c_args: ['-D_GNU_SOURCE', '-DUSE_HOST_LIBC'], + link_args: ['-ldl'] + test_additional_link_args, + native: true, + ) + test(test_name, exec, env: test_native_env, suite: ['host-libc', 'rtdl'], depends: test_native_depends) + endif +endforeach diff --git a/lib/mlibc/tests/rtdl/noload-promote/libfoo.c b/lib/mlibc/tests/rtdl/noload-promote/libfoo.c new file mode 100644 index 0000000..85e6cd8 --- /dev/null +++ b/lib/mlibc/tests/rtdl/noload-promote/libfoo.c @@ -0,0 +1 @@ +void foo() {} diff --git a/lib/mlibc/tests/rtdl/noload-promote/meson.build b/lib/mlibc/tests/rtdl/noload-promote/meson.build new file mode 100644 index 0000000..4ae6bb3 --- /dev/null +++ b/lib/mlibc/tests/rtdl/noload-promote/meson.build @@ -0,0 +1,5 @@ +libfoo = shared_library('foo', 'libfoo.c') +test_depends = [libfoo] + +libfoo_native = shared_library('native-foo', 'libfoo.c', native: true) +test_native_depends = [libfoo_native] diff --git a/lib/mlibc/tests/rtdl/noload-promote/test.c b/lib/mlibc/tests/rtdl/noload-promote/test.c new file mode 100644 index 0000000..0a6c55c --- /dev/null +++ b/lib/mlibc/tests/rtdl/noload-promote/test.c @@ -0,0 +1,22 @@ +#include +#include +#include + +#ifdef USE_HOST_LIBC +#define LIBFOO "libnative-foo.so" +#else +#define LIBFOO "libfoo.so" +#endif + +int main() { + void *foo = dlopen(LIBFOO, RTLD_LOCAL | RTLD_NOW); + assert(foo); + + assert(dlsym(RTLD_DEFAULT, "foo") == NULL); + + // Opening a library with RTLD_NOLOAD | RTLD_GLOBAL should promote it to the global scope. + assert(dlopen(LIBFOO, RTLD_NOLOAD | RTLD_GLOBAL | RTLD_NOW) == foo); + assert(dlsym(RTLD_DEFAULT, "foo") != NULL); + + assert(dlopen("does-not-exist.so.1337", RTLD_NOLOAD | RTLD_GLOBAL | RTLD_NOW) == NULL); +} diff --git a/lib/mlibc/tests/rtdl/preinit/libfoo.c b/lib/mlibc/tests/rtdl/preinit/libfoo.c new file mode 100644 index 0000000..9c834ea --- /dev/null +++ b/lib/mlibc/tests/rtdl/preinit/libfoo.c @@ -0,0 +1,18 @@ +#include +#include + +int fooDone = 0; + +// DSOs do not support pre-initialization functions. + +__attribute__((constructor)) +void fooInit() { + dprintf(1, "initialization function called in foo\n"); + + assert(fooDone == 0); + fooDone++; +} + +int isFooDone() { + return fooDone; +} diff --git a/lib/mlibc/tests/rtdl/preinit/meson.build b/lib/mlibc/tests/rtdl/preinit/meson.build new file mode 100644 index 0000000..1a7f398 --- /dev/null +++ b/lib/mlibc/tests/rtdl/preinit/meson.build @@ -0,0 +1,18 @@ +if host_machine.cpu_family() == 'riscv64' + # gp isn't initialized until after crt1.o runs, so to access + # globals in our pre-initializers we must disable it. + test_additional_link_args = ['-Wl,--no-relax'] +endif + +libfoo = shared_library('foo', 'libfoo.c', + dependencies: libc_dep, + override_options: 'b_sanitize=none', + link_args: test_additional_link_args, +) +test_link_with = [libfoo] + +libfoo_native = shared_library('native-foo', 'libfoo.c', + link_args: ['-ldl'] + test_additional_link_args, + native: true +) +test_native_link_with = [libfoo_native] diff --git a/lib/mlibc/tests/rtdl/preinit/test.c b/lib/mlibc/tests/rtdl/preinit/test.c new file mode 100644 index 0000000..5b5d5e8 --- /dev/null +++ b/lib/mlibc/tests/rtdl/preinit/test.c @@ -0,0 +1,44 @@ +#include +#include + +int mainDone = 0; + +int isFooDone(); + +void preInit1() { + // Use dprintf because stdout might not be initialized yet. + dprintf(1, "pre-initialization function 1 called in main executable\n"); + + assert(isFooDone() == 0); + assert(mainDone == 0); + mainDone++; +} + +void preInit2() { + dprintf(1, "pre-initialization function 2 called in main executable\n"); + + assert(isFooDone() == 0); + assert(mainDone == 1); + mainDone++; +} + +__attribute__((constructor)) +void mainInit() { + dprintf(1, "initialization function called in main executable\n"); + + assert(isFooDone() == 1); + assert(mainDone == 2); + mainDone++; +} + +// Manually register the pre-initialization functions. +__attribute__((used, section(".preinit_array"))) +static void (*preinitFunctions[])(void) = { + &preInit1, + &preInit2, +}; + +int main() { + assert(isFooDone() == 1); + assert(mainDone == 3); +} diff --git a/lib/mlibc/tests/rtdl/rtld_next/libbar.c b/lib/mlibc/tests/rtdl/rtld_next/libbar.c new file mode 100644 index 0000000..c0950c5 --- /dev/null +++ b/lib/mlibc/tests/rtdl/rtld_next/libbar.c @@ -0,0 +1,16 @@ +#include + +typedef char *charFn(void); + +__attribute__((weak)) +char *definedInBoth() { + return "bar"; +} + +charFn *barGetDefault() { + return (charFn *)dlsym(RTLD_DEFAULT, "definedInBoth"); +} + +charFn *barGetNext() { + return (charFn *)dlsym(RTLD_NEXT, "definedInBoth"); +} diff --git a/lib/mlibc/tests/rtdl/rtld_next/libfoo.c b/lib/mlibc/tests/rtdl/rtld_next/libfoo.c new file mode 100644 index 0000000..1d46b73 --- /dev/null +++ b/lib/mlibc/tests/rtdl/rtld_next/libfoo.c @@ -0,0 +1,17 @@ +#include + +typedef char *charFn(void); + +__attribute__((weak)) +char *definedInBoth() { + return "foo"; +} + +charFn *fooGetDefault() { + return (charFn *)dlsym(RTLD_DEFAULT, "definedInBoth"); +} + +charFn *fooGetNext() { + return (charFn *)dlsym(RTLD_NEXT, "definedInBoth"); +} + diff --git a/lib/mlibc/tests/rtdl/rtld_next/meson.build b/lib/mlibc/tests/rtdl/rtld_next/meson.build new file mode 100644 index 0000000..d156c24 --- /dev/null +++ b/lib/mlibc/tests/rtdl/rtld_next/meson.build @@ -0,0 +1,25 @@ +# Prevent tail calls, as it breaks libc's 'calling object' detection. +no_tail_calls = '-fno-optimize-sibling-calls' + +libfoo = shared_library('foo', 'libfoo.c', + dependencies: libc_dep, + c_args: no_tail_calls, +) +libbar = shared_library('bar', 'libbar.c', + dependencies: libc_dep, + c_args: no_tail_calls, +) +test_link_with = [libfoo, libbar] # foo is linked before bar + +libfoo_native = shared_library('native-foo', 'libfoo.c', + c_args: [no_tail_calls, '-D_GNU_SOURCE'], + link_args: '-ldl', + native: true +) +libbar_native = shared_library('native-bar', 'libbar.c', + c_args: [no_tail_calls, '-D_GNU_SOURCE'], + link_args: '-ldl', + native: true +) +test_native_link_with = [libfoo_native, libbar_native] + diff --git a/lib/mlibc/tests/rtdl/rtld_next/test.c b/lib/mlibc/tests/rtdl/rtld_next/test.c new file mode 100644 index 0000000..3e90a63 --- /dev/null +++ b/lib/mlibc/tests/rtdl/rtld_next/test.c @@ -0,0 +1,26 @@ +#include +#include + +typedef char *charFn(void); +charFn *fooGetDefault(void); +charFn *fooGetNext(void); +charFn *barGetDefault(void); +charFn *barGetNext(void); + +int main() { + charFn *ret; + + ret = fooGetDefault(); + assert(ret != NULL); + assert(!strcmp(ret(), "foo")); + + ret = fooGetNext(); + assert(ret != NULL); + assert(!strcmp(ret(), "bar")); + + ret = barGetDefault(); + assert(ret != NULL); + assert(!strcmp(ret(), "foo")); + + assert(barGetNext() == NULL); +} diff --git a/lib/mlibc/tests/rtdl/scope1/libbar.c b/lib/mlibc/tests/rtdl/scope1/libbar.c new file mode 100644 index 0000000..ecf043e --- /dev/null +++ b/lib/mlibc/tests/rtdl/scope1/libbar.c @@ -0,0 +1,14 @@ +char *foo(void); +char *foo_global(void); + +char *bar() { + return "bar"; +} + +char *bar_calls_foo() { + return foo(); +} + +char *bar_calls_foo_global() { + return foo_global(); +} diff --git a/lib/mlibc/tests/rtdl/scope1/libfoo.c b/lib/mlibc/tests/rtdl/scope1/libfoo.c new file mode 100644 index 0000000..b4e1b8c --- /dev/null +++ b/lib/mlibc/tests/rtdl/scope1/libfoo.c @@ -0,0 +1,9 @@ +char *foo() { + return "foo"; +} + +char global[] = "foo global"; + +char *foo_global() { + return global; +} diff --git a/lib/mlibc/tests/rtdl/scope1/meson.build b/lib/mlibc/tests/rtdl/scope1/meson.build new file mode 100644 index 0000000..acb679e --- /dev/null +++ b/lib/mlibc/tests/rtdl/scope1/meson.build @@ -0,0 +1,7 @@ +libfoo = shared_library('foo', 'libfoo.c') +libbar = shared_library('bar', 'libbar.c', build_rpath: test_rpath, link_with: libfoo) +test_depends = [libfoo, libbar] + +libfoo_native = shared_library('native-foo', 'libfoo.c', native: true) +libbar_native = shared_library('native-bar', 'libbar.c', build_rpath: test_rpath, link_with: libfoo_native, native: true) +test_native_depends = [libfoo_native, libbar_native] diff --git a/lib/mlibc/tests/rtdl/scope1/test.c b/lib/mlibc/tests/rtdl/scope1/test.c new file mode 100644 index 0000000..c19915d --- /dev/null +++ b/lib/mlibc/tests/rtdl/scope1/test.c @@ -0,0 +1,90 @@ +#include +#include +#include +#include +#include + +#ifdef USE_HOST_LIBC +#define LIBFOO "libnative-foo.so" +#define LIBBAR "libnative-bar.so" +#else +#define LIBFOO "libfoo.so" +#define LIBBAR "libbar.so" +#endif + +typedef char *strfn(void); + +int main() { + // We haven't dlopen'd these libs yet, so symbol resolution should fail. + assert(dlsym(RTLD_DEFAULT, "foo") == NULL); + assert(dlsym(RTLD_DEFAULT, "bar") == NULL); + + assert(!dlopen(LIBFOO, RTLD_NOLOAD)); + assert(!dlopen(LIBBAR, RTLD_NOLOAD)); + + void *foo_handle = dlopen(LIBFOO, RTLD_LOCAL | RTLD_NOW); + assert(foo_handle); + assert(dlopen(LIBFOO, RTLD_NOLOAD | RTLD_NOW)); + + strfn *foo_sym = dlsym(foo_handle, "foo"); + assert(foo_sym); + assert(foo_sym()); + assert(!strcmp(foo_sym(), "foo")); + + strfn *foo_global_sym = dlsym(foo_handle, "foo_global"); + assert(foo_global_sym); + assert(foo_global_sym()); + assert(!strcmp(foo_global_sym(), "foo global")); + + assert(dlsym(foo_handle, "doesnotexist") == NULL); + + // Nested opening should work + assert(dlopen(LIBFOO, RTLD_LOCAL | RTLD_NOW) == foo_handle); + assert(dlopen(LIBFOO, RTLD_NOLOAD | RTLD_NOW)); + + // Since we've loaded the same library twice, the addresses should be the same + assert(dlsym(foo_handle, "foo") == foo_sym); + assert(dlsym(foo_handle, "foo_global") == foo_global_sym); + + // libfoo was opened with RTLD_LOCAL, so we shouldn't be able to lookup + // its symbols in the global namespace. + assert(dlsym(RTLD_DEFAULT, "foo") == NULL); + + { + void *bar_handle = dlopen(LIBBAR, RTLD_GLOBAL | RTLD_NOW); + assert(bar_handle); + assert(dlopen(LIBBAR, RTLD_NOLOAD | RTLD_NOW)); + + strfn *bar_sym = dlsym(bar_handle, "bar"); + assert(bar_sym); + assert(bar_sym()); + assert(!strcmp(bar_sym(), "bar")); + + strfn *bar_calls_foo_sym = dlsym(bar_handle, "bar_calls_foo"); + assert(bar_calls_foo_sym); + assert(bar_calls_foo_sym()); + assert(!strcmp(bar_calls_foo_sym(), "foo")); + + strfn *bar_calls_foo_global_sym = dlsym(bar_handle, "bar_calls_foo_global"); + assert(bar_calls_foo_global_sym); + assert(bar_calls_foo_global_sym()); + assert(!strcmp(bar_calls_foo_global_sym(), "foo global")); + + // libbar was opened with RTLD_GLOBAL, so we can find symbols by + // searching in the global scope. + strfn *new_bar_sym = dlsym(RTLD_DEFAULT, "bar"); + assert(new_bar_sym); + assert(new_bar_sym == bar_sym); + + // Note that we loaded libbar with RTLD_GLOBAL, which should pull + // in libfoo's symbols globally too. + strfn *new_foo_sym = dlsym(RTLD_DEFAULT, "foo"); + assert(new_foo_sym); + assert(new_foo_sym == foo_sym); + + assert(dlclose(bar_handle) == 0); + } + + assert(dlclose(foo_handle) == 0); + assert(dlclose(foo_handle) == 0); +} diff --git a/lib/mlibc/tests/rtdl/scope2/libbar.c b/lib/mlibc/tests/rtdl/scope2/libbar.c new file mode 100644 index 0000000..4783c58 --- /dev/null +++ b/lib/mlibc/tests/rtdl/scope2/libbar.c @@ -0,0 +1,5 @@ +char *foo_baz_conflict(void); + +char *bar_calls_foo_baz_conflict() { + return foo_baz_conflict(); +} diff --git a/lib/mlibc/tests/rtdl/scope2/libbaz.c b/lib/mlibc/tests/rtdl/scope2/libbaz.c new file mode 100644 index 0000000..fc73adc --- /dev/null +++ b/lib/mlibc/tests/rtdl/scope2/libbaz.c @@ -0,0 +1,3 @@ +char *foo_baz_conflict() { + return "resolved to baz"; +} diff --git a/lib/mlibc/tests/rtdl/scope2/libfoo.c b/lib/mlibc/tests/rtdl/scope2/libfoo.c new file mode 100644 index 0000000..9f7b881 --- /dev/null +++ b/lib/mlibc/tests/rtdl/scope2/libfoo.c @@ -0,0 +1,3 @@ +char *foo_baz_conflict() { + return "resolved to foo"; +} diff --git a/lib/mlibc/tests/rtdl/scope2/meson.build b/lib/mlibc/tests/rtdl/scope2/meson.build new file mode 100644 index 0000000..938272c --- /dev/null +++ b/lib/mlibc/tests/rtdl/scope2/meson.build @@ -0,0 +1,9 @@ +libfoo = shared_library('foo', 'libfoo.c') +libbar = shared_library('bar', 'libbar.c', build_rpath: test_rpath, link_with: libfoo) +libbaz = shared_library('baz', 'libbaz.c') +test_depends = [libfoo, libbar, libbaz] + +libfoo_native = shared_library('native-foo', 'libfoo.c', native: true) +libbar_native = shared_library('native-bar', 'libbar.c', build_rpath: test_rpath, link_with: libfoo_native, native: true) +libbaz_native = shared_library('native-baz', 'libbaz.c', native: true) +test_native_depends = [libfoo_native, libbar_native, libbaz_native] diff --git a/lib/mlibc/tests/rtdl/scope2/test.c b/lib/mlibc/tests/rtdl/scope2/test.c new file mode 100644 index 0000000..f4f42dc --- /dev/null +++ b/lib/mlibc/tests/rtdl/scope2/test.c @@ -0,0 +1,36 @@ +#include +#include +#include +#include +#include + +#ifdef USE_HOST_LIBC +#define LIBBAR "libnative-bar.so" +#define LIBBAZ "libnative-baz.so" +#else +#define LIBBAR "libbar.so" +#define LIBBAZ "libbaz.so" +#endif + +typedef char *strfn(void); + +int main() { + void *baz = dlopen(LIBBAZ, RTLD_LAZY | RTLD_GLOBAL); + assert(baz); + + // At this point, baz is loaded in the global scope. When we load bar locally, + // there is a relocation to `foo_baz_conflict` which is defined in both + // foo (which is a dependency of bar), and baz. In this case baz should win + // since we search the global scope first. + + void *bar = dlopen(LIBBAR, RTLD_LAZY | RTLD_LOCAL); + assert(bar); + + strfn *bfn = dlsym(bar, "bar_calls_foo_baz_conflict"); + assert(!strcmp(bfn(), "resolved to baz")); + + // TODO: Test RTLD_DEEPBIND and DT_SYMBOLIC once we implement it. + + dlclose(bar); + dlclose(baz); +} diff --git a/lib/mlibc/tests/rtdl/scope3/libbar.c b/lib/mlibc/tests/rtdl/scope3/libbar.c new file mode 100644 index 0000000..dc377b6 --- /dev/null +++ b/lib/mlibc/tests/rtdl/scope3/libbar.c @@ -0,0 +1,8 @@ +int g = 1; + +int call_foo(); + +int call_bar() { + return call_foo(); +} + diff --git a/lib/mlibc/tests/rtdl/scope3/libbaz.c b/lib/mlibc/tests/rtdl/scope3/libbaz.c new file mode 100644 index 0000000..32524cc --- /dev/null +++ b/lib/mlibc/tests/rtdl/scope3/libbaz.c @@ -0,0 +1,7 @@ +int g = 2; + +int call_foo(); + +int call_baz() { + return call_foo(); +} diff --git a/lib/mlibc/tests/rtdl/scope3/libfoo.c b/lib/mlibc/tests/rtdl/scope3/libfoo.c new file mode 100644 index 0000000..bc86319 --- /dev/null +++ b/lib/mlibc/tests/rtdl/scope3/libfoo.c @@ -0,0 +1,5 @@ +int g = 0; + +int call_foo() { + return g; +} diff --git a/lib/mlibc/tests/rtdl/scope3/meson.build b/lib/mlibc/tests/rtdl/scope3/meson.build new file mode 100644 index 0000000..0c98583 --- /dev/null +++ b/lib/mlibc/tests/rtdl/scope3/meson.build @@ -0,0 +1,9 @@ +libfoo = shared_library('foo', 'libfoo.c') +libbar = shared_library('bar', 'libbar.c', build_rpath: test_rpath, link_with: libfoo) +libbaz = shared_library('baz', 'libbaz.c', build_rpath: test_rpath, link_with: libfoo) +test_depends = [libfoo, libbar, libbaz] + +libfoo_native = shared_library('native-foo', 'libfoo.c', native: true) +libbar_native = shared_library('native-bar', 'libbar.c', build_rpath: test_rpath, link_with: libfoo_native, native: true) +libbaz_native = shared_library('native-baz', 'libbaz.c', build_rpath: test_rpath, link_with: libfoo_native, native: true) +test_native_depends = [libfoo_native, libbar_native, libbaz_native] diff --git a/lib/mlibc/tests/rtdl/scope3/test.c b/lib/mlibc/tests/rtdl/scope3/test.c new file mode 100644 index 0000000..30fc662 --- /dev/null +++ b/lib/mlibc/tests/rtdl/scope3/test.c @@ -0,0 +1,39 @@ +#include +#include +#include + +#ifdef USE_HOST_LIBC +#define LIBBAR "libnative-bar.so" +#define LIBBAZ "libnative-baz.so" +#else +#define LIBBAR "libbar.so" +#define LIBBAZ "libbaz.so" +#endif + +int main() { + // In this test, we have bar -> foo and baz -> foo (where -> means 'depends on'). + // All three objects contain a definition of a symbol g. Bar calls into foo to retrieve + // what foo thinks g is, but since bar appears earlier in the scope than foo, bar's copy + // of g wins. + // + // Next, we load baz, which is identical to bar. When baz calls into foo to retrieve g, + // foo still sees bar's definition of g, so bar's copy of g wins. + // + // Swapping the load order of bar and baz should therefore change the value of g which + // foo sees. This behaviour is why dlmopen exists. If we ever implement that, we should + // write a similar test and assert that the calls return different results. + + void *libbar = dlopen(LIBBAR, RTLD_LAZY | RTLD_LOCAL); + int (*call_bar)(void) = dlsym(libbar, "call_bar"); + printf("call_bar: %d\n", call_bar()); + assert(call_bar() == 1); + + void *libbaz = dlopen(LIBBAZ, RTLD_LAZY | RTLD_LOCAL); + int (*call_baz)(void) = dlsym(libbaz, "call_baz"); + printf("call_baz: %d\n", call_baz()); + assert(call_baz() == 1); + + + dlclose(libbar); + dlclose(libbaz); +} diff --git a/lib/mlibc/tests/rtdl/scope4/libbar.c b/lib/mlibc/tests/rtdl/scope4/libbar.c new file mode 100644 index 0000000..514e456 --- /dev/null +++ b/lib/mlibc/tests/rtdl/scope4/libbar.c @@ -0,0 +1,3 @@ +// Bar needs to have a relocation against foo in order to set DT_NEEDED. +void foo(void); +void bar() { foo(); } diff --git a/lib/mlibc/tests/rtdl/scope4/libbaz.c b/lib/mlibc/tests/rtdl/scope4/libbaz.c new file mode 100644 index 0000000..256a0e3 --- /dev/null +++ b/lib/mlibc/tests/rtdl/scope4/libbaz.c @@ -0,0 +1 @@ +void baz() {} diff --git a/lib/mlibc/tests/rtdl/scope4/libfoo.c b/lib/mlibc/tests/rtdl/scope4/libfoo.c new file mode 100644 index 0000000..6710db7 --- /dev/null +++ b/lib/mlibc/tests/rtdl/scope4/libfoo.c @@ -0,0 +1,3 @@ +// Foo needs to have a relocation against baz in order to set DT_NEEDED. +void baz(void); +void foo() { baz(); } diff --git a/lib/mlibc/tests/rtdl/scope4/meson.build b/lib/mlibc/tests/rtdl/scope4/meson.build new file mode 100644 index 0000000..804a40c --- /dev/null +++ b/lib/mlibc/tests/rtdl/scope4/meson.build @@ -0,0 +1,9 @@ +libbaz = shared_library('baz', 'libbaz.c') +libfoo = shared_library('foo', 'libfoo.c', build_rpath: test_rpath, link_with: libbaz) +libbar = shared_library('bar', 'libbar.c', build_rpath: test_rpath, link_with: libfoo) +test_depends = [libfoo, libbar, libbaz] + +libbaz_native = shared_library('native-baz', 'libbaz.c', native: true) +libfoo_native = shared_library('native-foo', 'libfoo.c', build_rpath: test_rpath, link_with: libbaz_native, native: true) +libbar_native = shared_library('native-bar', 'libbar.c', build_rpath: test_rpath, link_with: libfoo_native, native: true) +test_native_depends = [libfoo_native, libbar_native, libbaz_native] diff --git a/lib/mlibc/tests/rtdl/scope4/test.c b/lib/mlibc/tests/rtdl/scope4/test.c new file mode 100644 index 0000000..2365e26 --- /dev/null +++ b/lib/mlibc/tests/rtdl/scope4/test.c @@ -0,0 +1,36 @@ +#include +#include +#include + +#ifdef USE_HOST_LIBC +#define LIBFOO "libnative-foo.so" +#define LIBBAR "libnative-bar.so" +#define LIBBAZ "libnative-baz.so" +#else +#define LIBFOO "libfoo.so" +#define LIBBAR "libbar.so" +#define LIBBAZ "libbaz.so" +#endif + +int main() { + // In this test, we have foo -> baz, bar -> foo (where '->' means 'depends on'). + // We first load foo with RTLD_LOCAL, and then load bar with RTLD_GLOBAL. + // This should bring foo and bar into the global scope. + + void *foo = dlopen(LIBFOO, RTLD_LOCAL | RTLD_NOW); + assert(foo); + assert(dlsym(foo, "foo")); + assert(dlsym(foo, "baz")); + assert(!dlsym(RTLD_DEFAULT, "foo")); + assert(!dlsym(RTLD_DEFAULT, "baz")); + + void *bar = dlopen(LIBBAR, RTLD_GLOBAL | RTLD_NOW); + assert(bar); + assert(dlsym(bar, "bar")); + assert(dlsym(RTLD_DEFAULT, "bar")); + assert(dlsym(RTLD_DEFAULT, "foo")); + assert(dlsym(RTLD_DEFAULT, "baz")); + + dlclose(foo); + dlclose(bar); +} diff --git a/lib/mlibc/tests/rtdl/scope5/libfoo.c b/lib/mlibc/tests/rtdl/scope5/libfoo.c new file mode 100644 index 0000000..85e6cd8 --- /dev/null +++ b/lib/mlibc/tests/rtdl/scope5/libfoo.c @@ -0,0 +1 @@ +void foo() {} diff --git a/lib/mlibc/tests/rtdl/scope5/meson.build b/lib/mlibc/tests/rtdl/scope5/meson.build new file mode 100644 index 0000000..22ade5b --- /dev/null +++ b/lib/mlibc/tests/rtdl/scope5/meson.build @@ -0,0 +1,5 @@ +libfoo = shared_library('foo', 'libfoo.c') +test_link_with = [libfoo] + +libfoo_native = shared_library('native-foo', 'libfoo.c', native: true) +test_native_link_with = [libfoo_native] diff --git a/lib/mlibc/tests/rtdl/scope5/test.c b/lib/mlibc/tests/rtdl/scope5/test.c new file mode 100644 index 0000000..2c11c2e --- /dev/null +++ b/lib/mlibc/tests/rtdl/scope5/test.c @@ -0,0 +1,27 @@ +#include +#include +#include + +#ifdef USE_HOST_LIBC +#define LIBFOO "libnative-foo.so" +#else +#define LIBFOO "libfoo.so" +#endif + +// We need to have a relocation against foo for DT_NEEDED. +void foo(); +void bar() { foo(); } + +int main() { + // In this test, we have exec -> foo (where '->' means 'depends on'). + // This means that foo is in the global scope due to DT_NEEDED. + // We then dlopen it again with RTLD_LOCAL, which should just return + // the already-loaded object, but used to crash in the mlibc linker instead. + + void *foo = dlopen(LIBFOO, RTLD_LOCAL | RTLD_NOW); + assert(foo); + assert(dlsym(foo, "foo")); + assert(dlsym(RTLD_DEFAULT, "foo")); + + dlclose(foo); +} diff --git a/lib/mlibc/tests/rtdl/soname/libbar.c b/lib/mlibc/tests/rtdl/soname/libbar.c new file mode 100644 index 0000000..7f9f475 --- /dev/null +++ b/lib/mlibc/tests/rtdl/soname/libbar.c @@ -0,0 +1 @@ +char *name() { return "bar"; } diff --git a/lib/mlibc/tests/rtdl/soname/libfoo.c b/lib/mlibc/tests/rtdl/soname/libfoo.c new file mode 100644 index 0000000..abe0999 --- /dev/null +++ b/lib/mlibc/tests/rtdl/soname/libfoo.c @@ -0,0 +1 @@ +char *name() { return "foo"; } diff --git a/lib/mlibc/tests/rtdl/soname/meson.build b/lib/mlibc/tests/rtdl/soname/meson.build new file mode 100644 index 0000000..1eb97a8 --- /dev/null +++ b/lib/mlibc/tests/rtdl/soname/meson.build @@ -0,0 +1,17 @@ +# Create two libraries with the same SONAME. +bar_soname = '-Wl,-soname=libbar.so' + +libfoo = shared_library('foo', 'libfoo.c', link_args: '-Wl,-soname=libbar.so') +libbar = shared_library('bar', 'libbar.c', link_args: '-Wl,-soname=libbar.so') +test_depends = [libfoo, libbar] + +libfoo_native = shared_library('native-foo', 'libfoo.c', + link_args: ['-ldl', '-Wl,-soname=libnative-bar.so'], + native: true +) +libbar_native = shared_library('native-bar', 'libbar.c', + link_args: ['-ldl', '-Wl,-soname=libnative-bar.so'], + native: true +) +test_native_depends = [libfoo_native, libbar_native] + diff --git a/lib/mlibc/tests/rtdl/soname/test.c b/lib/mlibc/tests/rtdl/soname/test.c new file mode 100644 index 0000000..23e5b7a --- /dev/null +++ b/lib/mlibc/tests/rtdl/soname/test.c @@ -0,0 +1,33 @@ +#include +#include +#include +#include + +#ifdef USE_HOST_LIBC +#define LIBFOO "libnative-foo.so" +#define LIBBAR "libnative-bar.so" +#else +#define LIBFOO "libfoo.so" +#define LIBBAR "libbar.so" +#endif + +int main() { + void *foo = dlopen(LIBFOO, RTLD_NOW); + void *bar = dlopen(LIBBAR, RTLD_NOW); + assert(foo); + assert(bar); + + // Since these libraries have the same SONAME, they should return the same thing. + assert(foo == bar); + + char *(*fooSym)(void) = dlsym(foo, "name"); + char *(*barSym)(void) = dlsym(bar, "name"); + assert(fooSym && barSym); + assert(fooSym() && barSym()); + printf("foo: name() = \"%s\"\n", fooSym()); + printf("bar: name() = \"%s\"\n", barSym()); + assert(!strcmp(fooSym(), barSym())); + + dlclose(foo); + dlclose(bar); +} diff --git a/lib/mlibc/tests/rtdl/tls_align/libbar.c b/lib/mlibc/tests/rtdl/tls_align/libbar.c new file mode 100644 index 0000000..3f8d6a7 --- /dev/null +++ b/lib/mlibc/tests/rtdl/tls_align/libbar.c @@ -0,0 +1 @@ +_Thread_local __attribute__((aligned(8))) char bar_thread_local[8] = "Hello!"; diff --git a/lib/mlibc/tests/rtdl/tls_align/libfoo.c b/lib/mlibc/tests/rtdl/tls_align/libfoo.c new file mode 100644 index 0000000..8d98177 --- /dev/null +++ b/lib/mlibc/tests/rtdl/tls_align/libfoo.c @@ -0,0 +1 @@ +_Thread_local __attribute__((aligned(16))) char foo_thread_local[8] = "Hello!"; diff --git a/lib/mlibc/tests/rtdl/tls_align/meson.build b/lib/mlibc/tests/rtdl/tls_align/meson.build new file mode 100644 index 0000000..61d0fd9 --- /dev/null +++ b/lib/mlibc/tests/rtdl/tls_align/meson.build @@ -0,0 +1,7 @@ +libfoo = shared_library('foo', 'libfoo.c') +libbar = shared_library('bar', 'libbar.c') +test_link_with = [libfoo, libbar] + +libfoo_native = shared_library('native-foo', 'libfoo.c', native: true) +libbar_native = shared_library('native-bar', 'libbar.c', native: true) +test_native_link_with = [libfoo_native, libbar_native] diff --git a/lib/mlibc/tests/rtdl/tls_align/test.c b/lib/mlibc/tests/rtdl/tls_align/test.c new file mode 100644 index 0000000..4381831 --- /dev/null +++ b/lib/mlibc/tests/rtdl/tls_align/test.c @@ -0,0 +1,10 @@ +#include +#include + +extern _Thread_local char foo_thread_local[]; +extern _Thread_local char bar_thread_local[]; + +int main() { + assert(!((uintptr_t)foo_thread_local & (16 - 1))); + assert(!((uintptr_t)bar_thread_local & (8 - 1))); +} -- cgit v1.2.3